linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] g_NCR5380: Fix PDMA transfer size
  2017-06-15 12:17 [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Finn Thain
@ 2017-06-15 12:17 ` Finn Thain
  2017-06-15 12:17 ` [PATCH 2/4] g_NCR5380: End PDMA transfer correctly on target disconnection Finn Thain
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Finn Thain @ 2017-06-15 12:17 UTC (permalink / raw)
  To: James E.J. Bottomley, Martin K. Petersen, Ondrej Zary
  Cc: linux-scsi, linux-kernel, Michael Schmitz

From: Ondrej Zary <linux@rainbow-software.org>

generic_NCR5380_dma_xfer_len() incorrectly uses cmd->transfersize
which causes rescan-scsi-bus and CD-ROM access to hang the system.
Use cmd->SCp.this_residual instead, like other NCR5380 drivers.

Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
 drivers/scsi/g_NCR5380.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 67c8dac321ad..14ef4e8c4713 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -76,6 +76,7 @@
 #define IRQ_AUTO 254
 
 #define MAX_CARDS 8
+#define DMA_MAX_SIZE 32768
 
 /* old-style parameters for compatibility */
 static int ncr_irq = -1;
@@ -629,23 +630,16 @@ static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
 static int generic_NCR5380_dma_xfer_len(struct NCR5380_hostdata *hostdata,
                                         struct scsi_cmnd *cmd)
 {
-	int transfersize = cmd->transfersize;
+	int transfersize = cmd->SCp.this_residual;
 
 	if (hostdata->flags & FLAG_NO_PSEUDO_DMA)
 		return 0;
 
-	/* Limit transfers to 32K, for xx400 & xx406
-	 * pseudoDMA that transfers in 128 bytes blocks.
-	 */
-	if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
-	    !(cmd->SCp.this_residual % transfersize))
-		transfersize = 32 * 1024;
-
 	/* 53C400 datasheet: non-modulo-128-byte transfers should use PIO */
 	if (transfersize % 128)
 		transfersize = 0;
 
-	return transfersize;
+	return min(transfersize, DMA_MAX_SIZE);
 }
 
 /*
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/4] g_NCR5380: Limit sg_tablesize to avoid PDMA read overruns on DTC436
  2017-06-15 12:17 [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Finn Thain
  2017-06-15 12:17 ` [PATCH 1/4] g_NCR5380: Fix PDMA transfer size Finn Thain
  2017-06-15 12:17 ` [PATCH 2/4] g_NCR5380: End PDMA transfer correctly on target disconnection Finn Thain
@ 2017-06-15 12:17 ` Finn Thain
  2017-06-15 12:17 ` [PATCH 4/4] g_NCR5380: Cleanup comments and whitespace Finn Thain
  2017-06-22 21:11 ` [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Ondrej Zary
  4 siblings, 0 replies; 10+ messages in thread
From: Finn Thain @ 2017-06-15 12:17 UTC (permalink / raw)
  To: James E.J. Bottomley, Martin K. Petersen, Ondrej Zary
  Cc: linux-scsi, linux-kernel, Michael Schmitz

Back-to-back DMA receive transfers can lose a byte due to a 5380
flaw. This makes scatter-receive difficult or impossible on affected
hardware, so limit the scatter/gather tablesize to 1.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
 drivers/scsi/g_NCR5380.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 1e1cf7ca86fa..784913193ea5 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -247,6 +247,7 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt,
 	case BOARD_DTC3181E:
 		ports = dtc_3181e_ports;
 		magic = ncr_53c400a_magic;
+		tpnt->sg_tablesize = 1;
 		break;
 	}
 
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup
@ 2017-06-15 12:17 Finn Thain
  2017-06-15 12:17 ` [PATCH 1/4] g_NCR5380: Fix PDMA transfer size Finn Thain
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Finn Thain @ 2017-06-15 12:17 UTC (permalink / raw)
  To: James E.J. Bottomley, Martin K. Petersen, Ondrej Zary
  Cc: linux-scsi, linux-kernel, Michael Schmitz

Ondrej, would you please test this patch series? One of your patches
has been modified slightly and the two I wrote are untested.


Finn Thain (2):
  g_NCR5380: Limit sg_tablesize to avoid PDMA read overruns on DTC436
  g_NCR5380: Cleanup comments and whitespace

Ondrej Zary (2):
  g_NCR5380: Fix PDMA transfer size
  g_NCR5380: End PDMA transfer correctly on target disconnection

 drivers/scsi/g_NCR5380.c | 111 +++++++++++++++++++++++------------------------
 1 file changed, 54 insertions(+), 57 deletions(-)

-- 
2.13.0

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/4] g_NCR5380: End PDMA transfer correctly on target disconnection
  2017-06-15 12:17 [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Finn Thain
  2017-06-15 12:17 ` [PATCH 1/4] g_NCR5380: Fix PDMA transfer size Finn Thain
@ 2017-06-15 12:17 ` Finn Thain
  2017-06-15 12:17 ` [PATCH 3/4] g_NCR5380: Limit sg_tablesize to avoid PDMA read overruns on DTC436 Finn Thain
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Finn Thain @ 2017-06-15 12:17 UTC (permalink / raw)
  To: James E.J. Bottomley, Martin K. Petersen, Ondrej Zary
  Cc: linux-scsi, linux-kernel, Michael Schmitz

From: Ondrej Zary <linux@rainbow-software.org>

When an IRQ arrives during PDMA transfer, pread() and pwrite() return
without waiting for the 53C80 registers to be ready and this ends up
messing up the chip state. This was observed with SONY CDU-55S which is
slow enough to disconnect during 4096-byte reads.

IRQ during PDMA is not an error so don't return -1. Instead, store the
remaining byte count for use by NCR5380_dma_residual().

[Modified to improve the BASR_END_DMA_TRANSFER error message rather
than remove it -- F.T.]

Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
 drivers/scsi/g_NCR5380.c | 37 ++++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 14ef4e8c4713..1e1cf7ca86fa 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -44,12 +44,13 @@
 	int c400_ctl_status; \
 	int c400_blk_cnt; \
 	int c400_host_buf; \
-	int io_width
+	int io_width; \
+	int pdma_residual
 
 #define NCR5380_dma_xfer_len            generic_NCR5380_dma_xfer_len
 #define NCR5380_dma_recv_setup          generic_NCR5380_pread
 #define NCR5380_dma_send_setup          generic_NCR5380_pwrite
-#define NCR5380_dma_residual            NCR5380_dma_residual_none
+#define NCR5380_dma_residual            generic_NCR5380_dma_residual
 
 #define NCR5380_intr                    generic_NCR5380_intr
 #define NCR5380_queue_command           generic_NCR5380_queue_command
@@ -500,10 +501,8 @@ static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
 	while (1) {
 		if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
 			break;
-		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
-			printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
-			return -1;
-		}
+		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ)
+			goto out_wait;
 		while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
 			; /* FIXME - no timeout */
 
@@ -542,13 +541,16 @@ static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
 	if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ))
 		printk("53C400r: no 53C80 gated irq after transfer");
 
+out_wait:
 	/* wait for 53C80 registers to be available */
 	while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG))
 		;
 
 	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
-		printk(KERN_ERR "53C400r: no end dma signal\n");
-		
+		pr_err("%s: No end dma signal (%d/%d)\n", __func__, start, len);
+
+	hostdata->pdma_residual = len - start;
+
 	return 0;
 }
 
@@ -571,10 +573,8 @@ static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
 	NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
 	NCR5380_write(hostdata->c400_blk_cnt, blocks);
 	while (1) {
-		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
-			printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
-			return -1;
-		}
+		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ)
+			goto out_wait;
 
 		if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
 			break;
@@ -612,15 +612,17 @@ static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
 		blocks--;
 	}
 
+out_wait:
 	/* wait for 53C80 registers to be available */
 	while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
 		udelay(4); /* DTC436 chip hangs without this */
 		/* FIXME - no timeout */
 	}
 
-	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
-		printk(KERN_ERR "53C400w: no end dma signal\n");
-	}
+	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
+		pr_err("%s: No end dma signal (%d/%d)\n", __func__, start, len);
+
+	hostdata->pdma_residual = len - start;
 
 	while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
 		; 	// TIMEOUT
@@ -642,6 +644,11 @@ static int generic_NCR5380_dma_xfer_len(struct NCR5380_hostdata *hostdata,
 	return min(transfersize, DMA_MAX_SIZE);
 }
 
+static int generic_NCR5380_dma_residual(struct NCR5380_hostdata *hostdata)
+{
+	return hostdata->pdma_residual;
+}
+
 /*
  *	Include the NCR5380 core code that we build our driver around	
  */
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/4] g_NCR5380: Cleanup comments and whitespace
  2017-06-15 12:17 [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Finn Thain
                   ` (2 preceding siblings ...)
  2017-06-15 12:17 ` [PATCH 3/4] g_NCR5380: Limit sg_tablesize to avoid PDMA read overruns on DTC436 Finn Thain
@ 2017-06-15 12:17 ` Finn Thain
  2017-06-22 21:11 ` [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Ondrej Zary
  4 siblings, 0 replies; 10+ messages in thread
From: Finn Thain @ 2017-06-15 12:17 UTC (permalink / raw)
  To: James E.J. Bottomley, Martin K. Petersen, Ondrej Zary
  Cc: linux-scsi, linux-kernel, Michael Schmitz

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
 drivers/scsi/g_NCR5380.c | 61 ++++++++++++++++++++++--------------------------
 1 file changed, 28 insertions(+), 33 deletions(-)

diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 784913193ea5..e9a942d86865 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -1,17 +1,17 @@
 /*
  * Generic Generic NCR5380 driver
- *	
+ *
  * Copyright 1993, Drew Eckhardt
- *	Visionary Computing
- *	(Unix and Linux consulting and custom programming)
- *	drew@colorado.edu
- *      +1 (303) 440-4894
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 440-4894
  *
  * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
- *    K.Lentin@cs.monash.edu.au
+ * K.Lentin@cs.monash.edu.au
  *
  * NCR53C400A extensions (c) 1996, Ingmar Baumgart
- *    ingmar@gonzo.schwaben.de
+ * ingmar@gonzo.schwaben.de
  *
  * DTC3181E extensions (c) 1997, Ronald van Cuijlenborg
  * ronald.van.cuijlenborg@tip.nl or nutty@dds.nl
@@ -482,15 +482,14 @@ static void generic_NCR5380_release_resources(struct Scsi_Host *instance)
 }
 
 /**
- *	generic_NCR5380_pread - pseudo DMA read
- *	@hostdata: scsi host private data
- *	@dst: buffer to read into
- *	@len: buffer length
+ * generic_NCR5380_pread - pseudo DMA receive
+ * @hostdata: scsi host private data
+ * @dst: buffer to write into
+ * @len: transfer size
  *
- *	Perform a pseudo DMA mode read from an NCR53C400 or equivalent
- *	controller
+ * Perform a pseudo DMA mode receive from a 53C400 or equivalent device.
  */
- 
+
 static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
                                         unsigned char *dst, int len)
 {
@@ -509,10 +508,10 @@ static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
 
 		if (hostdata->io_port && hostdata->io_width == 2)
 			insw(hostdata->io_port + hostdata->c400_host_buf,
-							dst + start, 64);
+			     dst + start, 64);
 		else if (hostdata->io_port)
 			insb(hostdata->io_port + hostdata->c400_host_buf,
-							dst + start, 128);
+			     dst + start, 128);
 		else
 			memcpy_fromio(dst + start,
 				hostdata->io + NCR53C400_host_buffer, 128);
@@ -556,13 +555,12 @@ static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
 }
 
 /**
- *	generic_NCR5380_pwrite - pseudo DMA write
- *	@hostdata: scsi host private data
- *	@dst: buffer to read into
- *	@len: buffer length
+ * generic_NCR5380_pwrite - pseudo DMA send
+ * @hostdata: scsi host private data
+ * @src: buffer to read from
+ * @len: transfer size
  *
- *	Perform a pseudo DMA mode read from an NCR53C400 or equivalent
- *	controller
+ * Perform a pseudo DMA mode send to a 53C400 or equivalent device.
  */
 
 static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
@@ -601,10 +599,10 @@ static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
 
 		if (hostdata->io_port && hostdata->io_width == 2)
 			outsw(hostdata->io_port + hostdata->c400_host_buf,
-							src + start, 64);
+			      src + start, 64);
 		else if (hostdata->io_port)
 			outsb(hostdata->io_port + hostdata->c400_host_buf,
-							src + start, 128);
+			      src + start, 128);
 		else
 			memcpy_toio(hostdata->io + NCR53C400_host_buffer,
 			            src + start, 128);
@@ -650,10 +648,8 @@ static int generic_NCR5380_dma_residual(struct NCR5380_hostdata *hostdata)
 	return hostdata->pdma_residual;
 }
 
-/*
- *	Include the NCR5380 core code that we build our driver around	
- */
- 
+/* Include the core driver code. */
+
 #include "NCR5380.c"
 
 static struct scsi_host_template driver_template = {
@@ -673,11 +669,10 @@ static struct scsi_host_template driver_template = {
 	.max_sectors		= 128,
 };
 
-
 static int generic_NCR5380_isa_match(struct device *pdev, unsigned int ndev)
 {
 	int ret = generic_NCR5380_init_one(&driver_template, pdev, base[ndev],
-					  irq[ndev], card[ndev]);
+	                                   irq[ndev], card[ndev]);
 	if (ret) {
 		if (base[ndev])
 			printk(KERN_WARNING "Card not found at address 0x%03x\n",
@@ -689,7 +684,7 @@ static int generic_NCR5380_isa_match(struct device *pdev, unsigned int ndev)
 }
 
 static int generic_NCR5380_isa_remove(struct device *pdev,
-				   unsigned int ndev)
+                                      unsigned int ndev)
 {
 	generic_NCR5380_release_resources(dev_get_drvdata(pdev));
 	dev_set_drvdata(pdev, NULL);
@@ -712,7 +707,7 @@ static struct pnp_device_id generic_NCR5380_pnp_ids[] = {
 MODULE_DEVICE_TABLE(pnp, generic_NCR5380_pnp_ids);
 
 static int generic_NCR5380_pnp_probe(struct pnp_dev *pdev,
-			       const struct pnp_device_id *id)
+                                     const struct pnp_device_id *id)
 {
 	int base, irq;
 
@@ -723,7 +718,7 @@ static int generic_NCR5380_pnp_probe(struct pnp_dev *pdev,
 	irq = pnp_irq(pdev, 0);
 
 	return generic_NCR5380_init_one(&driver_template, &pdev->dev, base, irq,
-				       id->driver_data);
+	                                id->driver_data);
 }
 
 static void generic_NCR5380_pnp_remove(struct pnp_dev *pdev)
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup
  2017-06-15 12:17 [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Finn Thain
                   ` (3 preceding siblings ...)
  2017-06-15 12:17 ` [PATCH 4/4] g_NCR5380: Cleanup comments and whitespace Finn Thain
@ 2017-06-22 21:11 ` Ondrej Zary
  2017-06-23  1:06   ` Finn Thain
  4 siblings, 1 reply; 10+ messages in thread
From: Ondrej Zary @ 2017-06-22 21:11 UTC (permalink / raw)
  To: Finn Thain
  Cc: James E.J. Bottomley, Martin K. Petersen, linux-scsi,
	linux-kernel, Michael Schmitz

On Thursday 15 June 2017 14:17:56 Finn Thain wrote:
> Ondrej, would you please test this patch series? One of your patches
> has been modified slightly and the two I wrote are untested.

Works only with HDD on non-DTC chips. CD-ROM hangs. DTC hangs even with HDD.
The PDMA code really needs to be fixed.

-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup
  2017-06-22 21:11 ` [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Ondrej Zary
@ 2017-06-23  1:06   ` Finn Thain
  2017-06-23 11:01     ` Finn Thain
  0 siblings, 1 reply; 10+ messages in thread
From: Finn Thain @ 2017-06-23  1:06 UTC (permalink / raw)
  To: Ondrej Zary
  Cc: James E.J. Bottomley, Martin K. Petersen, linux-scsi,
	linux-kernel, Michael Schmitz


On Thu, 22 Jun 2017, Ondrej Zary wrote:

> Works only with HDD on non-DTC chips. CD-ROM hangs. DTC hangs even with 
> HDD. The PDMA code really needs to be fixed.
> 

Does this patch help? It should be applied on top of this series of 4.

diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 4c31cb316a38..95ae8edbecbc 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -481,6 +481,30 @@ static void generic_NCR5380_release_resources(struct Scsi_Host *instance)
 		release_mem_region(base, region_size);
 }
 
+/* wait_for_53c80_access - wait for 53C80 registers to become accessible
+ * @hostdata: scsi host private data
+ *
+ * The registers within the 53C80 logic block are inaccessible until
+ * bit 7 in the 53C400 control status register gets asserted.
+ */
+
+static int wait_for_53c80_access(struct NCR5380_hostdata *hostdata)
+{
+	int count = 10000;
+
+	do {
+		udelay(4); /* DTC436 chip hangs without this */
+		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)
+			return 0;
+	} while (--count > 0);
+
+	scmd_printk(KERN_ERR, hostdata->connected,
+	            "53c80 registers not accessible, device will be reset\n");
+	NCR5380_write(hostdata->c400_ctl_status, CSR_RESET);
+	NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
+	return -1;
+}
+
 /**
  * generic_NCR5380_pread - pseudo DMA receive
  * @hostdata: scsi host private data
@@ -493,33 +517,19 @@ static void generic_NCR5380_release_resources(struct Scsi_Host *instance)
 static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
                                         unsigned char *dst, int len)
 {
-	int start, retries;
-	u8 csr, basr;
+	int result;
+	int start;
 
 	NCR5380_write(hostdata->c400_ctl_status, CSR_BASE | CSR_TRANS_DIR);
 	NCR5380_write(hostdata->c400_blk_cnt, len / 128);
 
 	for (start = 0; start < len; start += 128) {
-		retries = 10000;
-		while (1) {	/* monitor IRQ while waiting for host buffer */
-			csr = NCR5380_read(hostdata->c400_ctl_status);
-			if (!(csr & CSR_HOST_BUF_NOT_RDY))
-				break;
-			if (csr & CSR_GATED_53C80_IRQ) {
-				basr = NCR5380_read(BUS_AND_STATUS_REG);
-				if (!(basr & BASR_PHASE_MATCH) ||
-				    (basr & BASR_BUSY_ERROR)) {
-					printk("basr=0x%02x csr=0x%02x at start=%d\n", basr, csr, start);
-					goto out_wait;
-				}
-			}
-			if (retries-- < 1) {
-				shost_printk(KERN_ERR, hostdata->host, "53C400r: host buffer not ready in time\n");
-				NCR5380_write(hostdata->c400_ctl_status, CSR_RESET);
-				NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
-				goto out_wait;
-			}
-		}
+		if (NCR5380_poll_politely2(hostdata, hostdata->c400_ctl_status,
+		                           CSR_HOST_BUF_NOT_RDY, 0,
+		                           hostdata->c400_ctl_status,
+		                           CSR_GATED_53C80_IRQ,
+		                           CSR_GATED_53C80_IRQ, HZ / 64) < 0)
+			break;
 
 		if (hostdata->io_port && hostdata->io_width == 2)
 			insw(hostdata->io_port + hostdata->c400_host_buf,
@@ -532,24 +542,14 @@ static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
 				hostdata->io + NCR53C400_host_buffer, 128);
 	}
 
-out_wait:
-	/* wait for 53C80 registers to be available */
-	retries = 10000;
-	while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
-		if (retries-- < 1) {
-			shost_printk(KERN_ERR, hostdata->host, "53C400r: 53C80 registers not ready in time\n");
-			NCR5380_write(hostdata->c400_ctl_status, CSR_RESET);
-			NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
-			break;
-		}
-	}
+	result = wait_for_53c80_access(hostdata);
 
 	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
 		pr_err("%s: No end dma signal (%d/%d)\n", __func__, start, len);
 
-	hostdata->pdma_residual = len - start;
+	hostdata->pdma_residual = NCR5380_read(hostdata->c400_blk_cnt) * 128;
 
-	return 0;
+	return result;
 }
 
 /**
@@ -564,41 +564,19 @@ static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
 static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
                                          unsigned char *src, int len)
 {
-	int start, retries;
-	u8 csr, basr;
+	int result;
+	int start;
 
 	NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
 	NCR5380_write(hostdata->c400_blk_cnt, len / 128);
 
 	for (start = 0; start < len; start += 128) {
-		retries = 10000;
-		while (1) {	/* monitor IRQ while waiting for host buffer */
-			csr = NCR5380_read(hostdata->c400_ctl_status);
-			if (!(csr & CSR_HOST_BUF_NOT_RDY))
-				break;
-			if (csr & CSR_GATED_53C80_IRQ) {
-				basr = NCR5380_read(BUS_AND_STATUS_REG);
-				if (!(basr & BASR_PHASE_MATCH) ||
-				    (basr & BASR_BUSY_ERROR)) {
-					printk("w basr=0x%02x csr=0x%02x at start=%d\n", basr, csr, start);
-					/* the previous block was not written properly */
-					start -= 2 * 128;
-					if (start < 0)
-						start = 0;
-					goto out_wait;
-				}
-			}
-			if (retries-- < 1) {
-				shost_printk(KERN_ERR, hostdata->host, "53C400w: host buffer not ready in time\n");
-				NCR5380_write(hostdata->c400_ctl_status, CSR_RESET);
-				NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
-				/* the previous block was not written properly */
-				start -= 2 * 128;
-				if (start < 0)
-					start = 0;
-				goto out_wait;
-			}
-		}
+		if (NCR5380_poll_politely2(hostdata, hostdata->c400_ctl_status,
+		                           CSR_HOST_BUF_NOT_RDY, 0,
+		                           hostdata->c400_ctl_status,
+		                           CSR_GATED_53C80_IRQ,
+		                           CSR_GATED_53C80_IRQ, HZ / 64) < 0)
+			break;
 
 		if (hostdata->io_port && hostdata->io_width == 2)
 			outsw(hostdata->io_port + hostdata->c400_host_buf,
@@ -611,24 +589,12 @@ static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
 			            src + start, 128);
 	}
 
-out_wait:
-	/* wait for 53C80 registers to be available */
-	udelay(4); /* DTC436 chip hangs without this */
-	retries = 10000;
-	while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
-		udelay(4); /* DTC436 chip hangs without this */
-		if (retries-- < 1) {
-			shost_printk(KERN_ERR, hostdata->host, "53C400w: 53C80 registers not ready in time, start=%d, len=%d\n", start, len);
-			NCR5380_write(hostdata->c400_ctl_status, CSR_RESET);
-			NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
-			break;
-		}
-	}
+	result = wait_for_53c80_access(hostdata);
 
 	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
 		pr_err("%s: No end dma signal (%d/%d)\n", __func__, start, len);
 
-	hostdata->pdma_residual = len - start;
+	hostdata->pdma_residual = NCR5380_read(hostdata->c400_blk_cnt) * 128;
 
 	if (hostdata->pdma_residual == 0 &&
 	    NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
@@ -637,7 +603,7 @@ static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
 		scmd_printk(KERN_ERR, hostdata->connected,
 		            "%s: Last Byte Sent timeout\n", __func__);
 
-	return 0;
+	return result;
 }
 
 static int generic_NCR5380_dma_xfer_len(struct NCR5380_hostdata *hostdata,

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup
  2017-06-23  1:06   ` Finn Thain
@ 2017-06-23 11:01     ` Finn Thain
  2017-06-23 20:13       ` Ondrej Zary
  0 siblings, 1 reply; 10+ messages in thread
From: Finn Thain @ 2017-06-23 11:01 UTC (permalink / raw)
  To: Ondrej Zary
  Cc: James E.J. Bottomley, Martin K. Petersen, linux-scsi,
	linux-kernel, Michael Schmitz


On Fri, 23 Jun 2017, I wrote:

> 
> Does this patch help? It should be applied on top of this series of 4.
> 

Sorry, I sent the wrong diff. Please try this patch instead.

diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index e9a942d86865..95ae8edbecbc 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -481,6 +481,30 @@ static void generic_NCR5380_release_resources(struct Scsi_Host *instance)
 		release_mem_region(base, region_size);
 }
 
+/* wait_for_53c80_access - wait for 53C80 registers to become accessible
+ * @hostdata: scsi host private data
+ *
+ * The registers within the 53C80 logic block are inaccessible until
+ * bit 7 in the 53C400 control status register gets asserted.
+ */
+
+static int wait_for_53c80_access(struct NCR5380_hostdata *hostdata)
+{
+	int count = 10000;
+
+	do {
+		udelay(4); /* DTC436 chip hangs without this */
+		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)
+			return 0;
+	} while (--count > 0);
+
+	scmd_printk(KERN_ERR, hostdata->connected,
+	            "53c80 registers not accessible, device will be reset\n");
+	NCR5380_write(hostdata->c400_ctl_status, CSR_RESET);
+	NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
+	return -1;
+}
+
 /**
  * generic_NCR5380_pread - pseudo DMA receive
  * @hostdata: scsi host private data
@@ -493,18 +517,19 @@ static void generic_NCR5380_release_resources(struct Scsi_Host *instance)
 static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
                                         unsigned char *dst, int len)
 {
-	int blocks = len / 128;
-	int start = 0;
+	int result;
+	int start;
 
 	NCR5380_write(hostdata->c400_ctl_status, CSR_BASE | CSR_TRANS_DIR);
-	NCR5380_write(hostdata->c400_blk_cnt, blocks);
-	while (1) {
-		if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
+	NCR5380_write(hostdata->c400_blk_cnt, len / 128);
+
+	for (start = 0; start < len; start += 128) {
+		if (NCR5380_poll_politely2(hostdata, hostdata->c400_ctl_status,
+		                           CSR_HOST_BUF_NOT_RDY, 0,
+		                           hostdata->c400_ctl_status,
+		                           CSR_GATED_53C80_IRQ,
+		                           CSR_GATED_53C80_IRQ, HZ / 64) < 0)
 			break;
-		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ)
-			goto out_wait;
-		while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
-			; /* FIXME - no timeout */
 
 		if (hostdata->io_port && hostdata->io_width == 2)
 			insw(hostdata->io_port + hostdata->c400_host_buf,
@@ -515,43 +540,16 @@ static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
 		else
 			memcpy_fromio(dst + start,
 				hostdata->io + NCR53C400_host_buffer, 128);
-
-		start += 128;
-		blocks--;
-	}
-
-	if (blocks) {
-		while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
-			; /* FIXME - no timeout */
-
-		if (hostdata->io_port && hostdata->io_width == 2)
-			insw(hostdata->io_port + hostdata->c400_host_buf,
-							dst + start, 64);
-		else if (hostdata->io_port)
-			insb(hostdata->io_port + hostdata->c400_host_buf,
-							dst + start, 128);
-		else
-			memcpy_fromio(dst + start,
-				hostdata->io + NCR53C400_host_buffer, 128);
-
-		start += 128;
-		blocks--;
 	}
 
-	if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ))
-		printk("53C400r: no 53C80 gated irq after transfer");
-
-out_wait:
-	/* wait for 53C80 registers to be available */
-	while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG))
-		;
+	result = wait_for_53c80_access(hostdata);
 
 	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
 		pr_err("%s: No end dma signal (%d/%d)\n", __func__, start, len);
 
-	hostdata->pdma_residual = len - start;
+	hostdata->pdma_residual = NCR5380_read(hostdata->c400_blk_cnt) * 128;
 
-	return 0;
+	return result;
 }
 
 /**
@@ -566,36 +564,19 @@ static inline int generic_NCR5380_pread(struct NCR5380_hostdata *hostdata,
 static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
                                          unsigned char *src, int len)
 {
-	int blocks = len / 128;
-	int start = 0;
+	int result;
+	int start;
 
 	NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
-	NCR5380_write(hostdata->c400_blk_cnt, blocks);
-	while (1) {
-		if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ)
-			goto out_wait;
-
-		if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
+	NCR5380_write(hostdata->c400_blk_cnt, len / 128);
+
+	for (start = 0; start < len; start += 128) {
+		if (NCR5380_poll_politely2(hostdata, hostdata->c400_ctl_status,
+		                           CSR_HOST_BUF_NOT_RDY, 0,
+		                           hostdata->c400_ctl_status,
+		                           CSR_GATED_53C80_IRQ,
+		                           CSR_GATED_53C80_IRQ, HZ / 64) < 0)
 			break;
-		while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
-			; // FIXME - timeout
-
-		if (hostdata->io_port && hostdata->io_width == 2)
-			outsw(hostdata->io_port + hostdata->c400_host_buf,
-							src + start, 64);
-		else if (hostdata->io_port)
-			outsb(hostdata->io_port + hostdata->c400_host_buf,
-							src + start, 128);
-		else
-			memcpy_toio(hostdata->io + NCR53C400_host_buffer,
-			            src + start, 128);
-
-		start += 128;
-		blocks--;
-	}
-	if (blocks) {
-		while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
-			; // FIXME - no timeout
 
 		if (hostdata->io_port && hostdata->io_width == 2)
 			outsw(hostdata->io_port + hostdata->c400_host_buf,
@@ -606,26 +587,23 @@ static inline int generic_NCR5380_pwrite(struct NCR5380_hostdata *hostdata,
 		else
 			memcpy_toio(hostdata->io + NCR53C400_host_buffer,
 			            src + start, 128);
-
-		start += 128;
-		blocks--;
 	}
 
-out_wait:
-	/* wait for 53C80 registers to be available */
-	while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
-		udelay(4); /* DTC436 chip hangs without this */
-		/* FIXME - no timeout */
-	}
+	result = wait_for_53c80_access(hostdata);
 
 	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
 		pr_err("%s: No end dma signal (%d/%d)\n", __func__, start, len);
 
-	hostdata->pdma_residual = len - start;
+	hostdata->pdma_residual = NCR5380_read(hostdata->c400_blk_cnt) * 128;
 
-	while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
-		; 	// TIMEOUT
-	return 0;
+	if (hostdata->pdma_residual == 0 &&
+	    NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
+	                          TCR_LAST_BYTE_SENT, TCR_LAST_BYTE_SENT,
+	                          HZ / 64) < 0)
+		scmd_printk(KERN_ERR, hostdata->connected,
+		            "%s: Last Byte Sent timeout\n", __func__);
+
+	return result;
 }
 
 static int generic_NCR5380_dma_xfer_len(struct NCR5380_hostdata *hostdata,

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup
  2017-06-23 11:01     ` Finn Thain
@ 2017-06-23 20:13       ` Ondrej Zary
  2017-06-24  2:50         ` Finn Thain
  0 siblings, 1 reply; 10+ messages in thread
From: Ondrej Zary @ 2017-06-23 20:13 UTC (permalink / raw)
  To: Finn Thain
  Cc: James E.J. Bottomley, Martin K. Petersen, linux-scsi,
	linux-kernel, Michael Schmitz

On Friday 23 June 2017 13:01:53 Finn Thain wrote:
> On Fri, 23 Jun 2017, I wrote:
> > Does this patch help? It should be applied on top of this series of 4.
>
> Sorry, I sent the wrong diff. Please try this patch instead.

Thanks, much better now: both HDD and CD-ROM seem to work on DTC and non-DTC 
chips. I get many of these messages with CD-ROM:
[  912.397076] generic_NCR5380_pread: No end dma signal (4096/4096)
[  913.141225] generic_NCR5380_pread: No end dma signal (4096/4096)

Maybe just remove this error message as in my original patch?

-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup
  2017-06-23 20:13       ` Ondrej Zary
@ 2017-06-24  2:50         ` Finn Thain
  0 siblings, 0 replies; 10+ messages in thread
From: Finn Thain @ 2017-06-24  2:50 UTC (permalink / raw)
  To: Ondrej Zary
  Cc: James E.J. Bottomley, Martin K. Petersen, linux-scsi,
	linux-kernel, Michael Schmitz

On Fri, 23 Jun 2017, Ondrej Zary wrote:

> On Friday 23 June 2017 13:01:53 Finn Thain wrote:
> > On Fri, 23 Jun 2017, I wrote:
> > > Does this patch help? It should be applied on top of this series of 4.
> >
> > Sorry, I sent the wrong diff. Please try this patch instead.
> 
> Thanks, much better now: both HDD and CD-ROM seem to work on DTC and non-DTC 
> chips. I get many of these messages with CD-ROM:
> [  912.397076] generic_NCR5380_pread: No end dma signal (4096/4096)
> [  913.141225] generic_NCR5380_pread: No end dma signal (4096/4096)
> 
> Maybe just remove this error message as in my original patch?
> 

The "data loop" algorithm in the datasheet syas that if End of DMA doesn't 
become asserted after a transfer, this is an error condition.

Your log (above) shows 4096/4096 bytes so I think that End of DMA is 
tested too soon: the datasheet says that End of DMA takes 100 ns to become 
asserted even after all of the relevant signals reach their final state.

I'll re-do the series to account for this.

Thanks for testing.

-- 

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-06-24  2:49 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-15 12:17 [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Finn Thain
2017-06-15 12:17 ` [PATCH 1/4] g_NCR5380: Fix PDMA transfer size Finn Thain
2017-06-15 12:17 ` [PATCH 2/4] g_NCR5380: End PDMA transfer correctly on target disconnection Finn Thain
2017-06-15 12:17 ` [PATCH 3/4] g_NCR5380: Limit sg_tablesize to avoid PDMA read overruns on DTC436 Finn Thain
2017-06-15 12:17 ` [PATCH 4/4] g_NCR5380: Cleanup comments and whitespace Finn Thain
2017-06-22 21:11 ` [PATCH 0/4] g_NCR5380: PDMA fixes and cleanup Ondrej Zary
2017-06-23  1:06   ` Finn Thain
2017-06-23 11:01     ` Finn Thain
2017-06-23 20:13       ` Ondrej Zary
2017-06-24  2:50         ` Finn Thain

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).