[781] in linux-scsi channel archive

home help back first fref pref prev next nref lref last post

interrupt driven real-DMA for NCR5380.c (linux 1.3.37)

daemon@ATHENA.MIT.EDU (Stefan Voigt)
Wed Nov 8 14:30:18 1995

Date: Tue, 7 Nov 95 18:48 MET
From: Stefan Voigt <voigt@pirx.franken.de>
To: linux-scsi@vger.rutgers.edu
cc: Drew Eckhardt <drew@poohsticks.org>


Hi

a few days ago, i've spent some time with the GSI8 driver and
the linux NCR5380 driver . At the end of this message i included 
a patch as a result of this work. Mainly i updated 
NCR5380_dma_complete and a few names of variables (e.g. dmalen).
So far it works perfect for me. I saved over 1 gigabyte of data
to a streamer, no fuzz, no nothing.
Oh, btw, the patch is against linux 1.3.37.

CU
   Stefan


--- NCR5380.c.old	Thu Nov  2 20:54:17 1995
+++ NCR5380.c	Sat Nov  4 12:12:35 1995
@@ -71,3 +71,3 @@
 #undef USLEEP
-#undef REAL_DMA
+/*#undef REAL_DMA*/
 #endif
@@ -788,3 +788,3 @@
 #ifdef REAL_DMA
-    hostdata->dmalen = 0;
+    hostdata->dma_len = 0;
 #endif
@@ -999,3 +999,3 @@
 #ifdef REAL_DMA
-		&& !hostdata->dmalen
+		&& !hostdata->dma_len
 #endif
@@ -1036,2 +1036,3 @@
     struct Scsi_Host *instance;
+    struct NCR5380_hostdata *hostdata;
     int done;
@@ -1074,3 +1075,3 @@
 			(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-		    } else {
+		    }
 /*  
@@ -1087,3 +1088,3 @@
 
-			if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & 
+			else if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && ((basr & 
 			    BASR_END_DMA_TRANSFER) || 
@@ -1094,9 +1095,5 @@
 				panic("scsi%d : received end of DMA interrupt with no connected cmd\n",
-				    instance->hostno);
-
-			    transfered = (hostdata->dmalen - NCR5380_dma_residual(instance));
-			    hostdata->connected->SCp.this_residual -= transferred;
-			    hostdata->connected->SCp.ptr += transferred;
-			    hostdata->dmalen = 0;
+				    instance->host_no);
 
+			    NCR5380_dma_complete(instance);
 			    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
@@ -1118,4 +1115,6 @@
 			    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+			    done = 0;
 			}
-#else
+#endif
+                    else {
 #if (NDEBUG & NDEBUG_INTR)
@@ -1124,3 +1123,2 @@
 		    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-#endif
 		    } 
@@ -1740,3 +1738,3 @@
 	   (BASR_PHASE_MATCH | BASR_ACK))) {
-	saved_data = NCR5380_read(INPUT_DATA_REGISTER);
+	saved_data = NCR5380_read(INPUT_DATA_REG);
 	overrun = 1;
@@ -2517,19 +2515,42 @@
 #ifdef REAL_DMA
-static void NCR5380_dma_complete (NCR5380_instance *instance) {
+static void NCR5380_dma_complete (struct Scsi_Host *instance) {
     NCR5380_local_declare();
-    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *
-	instance->hostdata);
-    int transferred;
+    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
+	instance->hostdata;
+    Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+    int c = hostdata->dma_len;
+    unsigned char *d = cmd->SCp.ptr;
+    unsigned char p = cmd->SCp.phase;
+    unsigned char saved_data = 0, overrun = 0, residue;
+    unsigned int cnt, toPIO;
     NCR5380_setup(instance);
-    
-    /*
-     * XXX this might not be right.
-     *
-     * Wait for final byte to transfer, ie wait for ACK to go false.
-     *
-     * We should use the Last Byte Sent bit, unfortunately this is 
-     * not available on the 5380/5381 (only the various CMOS chips)
-     */
 
-    while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
+#if (NDEBUG & NDEBUG_DMA)
+    printk("DMA of %d bytes completed\n", c);
+#endif
+
+     if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH) {
+/*
+  DMA finished and we're still in PHASE MATCH.
+*/
+#if (NDEBUG & NDEBUG_DMA)
+       printk("PHASE MATCH still true\n");
+#endif
+       if (p & SR_IO) {
+         udelay(10);
+         if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH|BASR_ACK)) ==
+  	    (BASR_PHASE_MATCH | BASR_ACK))) {
+           saved_data = NCR5380_read(INPUT_DATA_REG);
+           overrun = 1;
+         }
+       } else {
+         int limit = 100;
+         unsigned char tmp;
+         while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) ||
+                (NCR5380_read(STATUS_REG) & SR_REQ)) {
+           if (!(tmp & BASR_PHASE_MATCH)) break;
+           if (--limit < 0) break;
+         }
+       }
+    }
 
@@ -2538,13 +2559,34 @@
 
-    /*
-     * The only places we should see a phase mismatch and have to send
-     * data from the same set of pointers will be the data transfer
-     * phases.  So, residual, requested length are only important here.
-     */
+    residue = NCR5380_dma_residual(instance);
+
+#if (NDEBUG & NDEBUG_DMA)
+    printk("Residue is %d\n", residue);
+#endif
 
-    if (!(hostdata->connected->SCp.phase & SR_CD)) {
-	transferred = instance->dmalen - NCR5380_dma_residual();
-	hostdata->connected->SCp.this_residual -= transferred;
-	hostdata->connected->SCp.ptr += transferred;
+    c -= residue;
+    cmd->SCp.this_residual -= c;
+    d += c;
+
+#ifdef READ_OVERRUNS
+    if ((p & SR_IO) && residue == 0) {
+      if (overrun) {
+#if (NDEBUG & NDEBUG_DMA)
+        printk("Got an input overrun, using saved byte\n");
+#endif
+        *d++ = saved_data;
+        cmd->SCp.this_residual --;
+        cnt = toPIO = 1;
+      } else {
+        printk("No overrun??\n");
+        cnt = toPIO = 2;
+      }
+#if (NDEBUG & NDEBUG_DMA)
+      printk("Doing %d-byte PIO to 0x%X\n", cnt, d);
+#endif
+      NCR5380_transfer_pio(instance, &p, &cnt, &d);
+      cmd->SCp.this_residual -= toPIO - cnt;
     }
+#endif /* READ_OVERRUNS */
+    cmd->SCp.ptr = d;
+    hostdata->dma_len = 0;
 }

-- 
Stefan Voigt        voigt@pirx.franken.de 
Hesselbergring 13   PGP fingerprint: (key 13EEBE91 / 1024)
90449 Nürnberg      64C5 7939 BAF7 825E  85CD 063D 1F0A B53E


home help back first fref pref prev next nref lref last post