[781] in linux-scsi channel archive
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