Subject: Linux-Development Digest #317
From: Digestifier <Linux-Development-Request@senator-bedfellow.MIT.EDU>
To: Linux-Development@senator-bedfellow.MIT.EDU
Reply-To: Linux-Development@senator-bedfellow.MIT.EDU
Date:     Sun, 19 Dec 93 19:13:06 EST

Linux-Development Digest #317, Volume #1         Sun, 19 Dec 93 19:13:06 EST

Contents:
  NCR5380 patch, probably fixes PAS-16 SCSI port HD problems (Drew Eckhardt)

----------------------------------------------------------------------------

From: drew@kinglear.cs.colorado.edu (Drew Eckhardt)
Subject: NCR5380 patch, probably fixes PAS-16 SCSI port HD problems
Date: 20 Dec 1993 02:00:26 +0200

[ Note: This is the full announcement that I chopped down for 
  comp.os.linux.announce.  The difference is that this version contains
  the patch.  I didn't put that in c.o.l.a because it is a bit too
  big for that group.  --Lars Wirzenius ]

I've been hearing a fair amount of yacking from people that have 
been unable to use hard drives on their PAS-16 SCSI port although
they had no problems with CDs.

Unfortunately, I was unable to reproduce the problem on my system
until just recently when I picked up an old Syquest 555.  That
gave me a buffered device that didn't stop transfering during the 
inter-sector gaps, uncovering a minor race condition, and also gave
me two devices on my SCSI bus which let take care of the one kink
that was causing problems with multiple target support.

Dave Platt had a workarround in his Ricoh port of the driver, but 
I didn't really think anything of it at the time.

See the RCS log if you want more specifics.

These diffs are gainst .99.13p, are a little ugly, etc, but if 
you can get them in, they should fix the PAS-16 problem.

--- 1.1 1993/11/11 05:01:16
+++ NCR5380.c   1993/12/15 07:33:13
@@ -7,9 +7,9 @@
  *     Visionary Computing 
  *     (Unix and Linux consulting and custom programming)
  *     drew@colorado.edu
- *     +1 (303) 440-4894
+ *     +1 (303) 666-5836
  *
- * DISTRIBUTION REALEASE 3. 
+ * DISTRIBUTION REALEASE 4. 
  *
  * For more information, please consult 
  *
@@ -26,7 +26,34 @@
 
 /*
  * $Log: NCR5380.c,v $
- * Revision 1.1  1993/11/11  05:01:16  drew
+ * Revision 1.7  1993/12/15  07:32:54  drew
+ * Added pseudo-DMA code to insure transfer of the last byte on
+ * DMA sends.
+ *
+ * Revision 1.6  1993/12/12  14:34:30  drew
+ * Fixed race condition in pseudo-DMA code where SCSI REQ was
+ * being asserted before we took the chip out of DMA mode and
+ * an extra byte was being loaded.
+ *
+ * Revision 1.4  1993/12/11  08:38:20  drew
+ * Added a wait for BUS FREE whenver we should be going into
+ * BUS FREE (ie, uppon receipt of COMMAND COMPLETE and DISCONNECT
+ * messages) so that we don't runinto problems where
+ *
+ * Device A has the bus, releases it and the information transfer function
+ * returns.
+ *
+ * The select function is unable to arbitrate for the bus.
+ * and device B gets a DID_BAD_TARGET error.
+ *
+ * Revision 1.3  1993/12/11  05:31:46  drew
+ * Added Dave Platt's patches to fix DMA.
+ *
+ * Revision 1.2  1993/10/16  23:17:35  drew
+ * Fixed request sense bug, added preliminary support for NCR5380
+ * REAL_DMA_POLL mode.
+ *
+ * Revision 1.1  1993/10/16  22:43:42  drew
  * Initial revision
  *
  */
@@ -33,14 +60,21 @@
 
 /*
  * Furthur development / testing that should be done : 
- * 1.  Test USLEEP code 
- * 2.  Test SCSI-II tagged queueing (I have no devices which support 
+ * 1.  Cleanup the NCR5380_transfer_dma function and DMA operation complete
+ *     code so that everything does the same thing that's done at the 
+ *     end of a pseudo-DMA read operation.
+ *
+ * 2.  Fix REAL_DMA (interrupt driven, polled works fine) -
+ *     basically, transfer size needs to be reduced by one 
+ *     and the last byte read as is done with PSEUDO_DMA.
+ * 
+ * 3.  Test USLEEP code 
+ *
+ * 4.  Test SCSI-II tagged queueing (I have no devices which support 
  *     tagged queueing)
- * 3.  Flesh out REAL_DMA code (my sample board doesn't support this)
- *     Perhaps some of the 680x0 porting crew can help out here?
- * 4.  Test linked command handling code after Eric is ready with 
+ *
+ * 5.  Test linked command handling code after Eric is ready with 
  *      the high level code.
- * 5.  Tie instance handling into Eric's multi-host patches
  */
 
 #ifndef notyet
@@ -49,6 +83,11 @@
 #undef REAL_DMA
 #endif
 
+#ifdef REAL_DMA_POLL
+#undef READ_OVERRUNS
+#define READ_OVERRUNS
+#endif
+
 /*
  * Design
  * Issues :
@@ -171,6 +210,10 @@
  *
  * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
  *
+ * REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't
+ *     rely on phase mismatch and EOP interrupts to determine end 
+ *     of phase.
+ *
  * SCSI2 - if defined, SCSI-2 tagged queing is used where possible
  *
  * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
@@ -211,9 +254,16 @@
  * Either real DMA *or* pseudo DMA may be implemented
  * REAL functions : 
  * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * Note that the DMA setup functions should return the number of bytes 
+ *     that they were able to program the controller for.
+ *
+ * Also note that generic i386/PC versions of these macros are 
+ *     available as NCR5380_i386_dma_write_setup,
+ *     NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
  * NCR5380_dma_write_setup(instance, src, count) - initialize
  * NCR5380_dma_read_setup(instance, dst, count) - initialize
- * NCR5380_dma_residual(); - residual count
+ * NCR5380_dma_residual(instance); - residual count
  *
  * PSEUDO functions :
  * NCR5380_pwrite(instance, src, count)
@@ -627,9 +677,12 @@
 #ifdef DIFFERENTIAL
     " DIFFERENTIAL"
 #endif
-#ifdef REALDMA
+#ifdef REAL_DMA
     " REAL DMA"
 #endif
+#ifdef REAL_DMA_POLL
+    " REAL DMA POLL"
+#endif
 #ifdef PARITY
     " PARITY"
 #endif
@@ -920,6 +973,7 @@
     NCR5380_local_declare(); 
     struct Scsi_Host *instance;
     int done;
+    unsigned char basr;
 #if (NDEBUG & NDEBUG_INTR)
     printk("scsi : NCR5380 irq %d triggered\n", irq);
 #endif
@@ -931,8 +985,9 @@
                
                /* Look for pending interrupts */
                NCR5380_setup(instance);
+               basr = NCR5380_read(BUS_AND_STATUS_REG);
                /* XXX dispatch to appropriate routine if found and done=0 */
-               if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) {
+               if (basr & BASR_IRQ) {
 #if (NDEBUG & NDEBUG_INTR)
                    NCR5380_print(instance);
 #endif
@@ -945,7 +1000,7 @@
 #endif
                        NCR5380_reselect(instance);
                        (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-                   } else if (NCR5380_read(BUS_AND_STATUS_REG) & 
+                   } else if (basr & 
                        BASR_PARITY_ERROR) {
 #if (NDEBUG & NDEBUG_INTR)
                        printk("scsi%d : PARITY interrupt\n", instance->host_no);
@@ -957,11 +1012,40 @@
  * DMA transfer, which I haven't gotten arround to fixing yet.
  */
 
-#if defined(REAL_DMA) 
+#if defined(REAL_DMA)
+                   /*
+                    * We should only get PHASE MISMATCH and EOP interrupts
+                    * if we have DMA enabled, so do a sanity check based on
+                    * the current setting of the MODE register.
+                    */
+
+                       if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & 
+                           BASR_END_DMA_TRANSFER) || 
+                           !(basr & BASR_PHASE_MATCH))) {
+                           int transfered;
+
+                           if (!hostdata->connected) 
+                               panic("scsi%d : recieved 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;
+
+                           (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+                           while (NCR5380_read(BUS_AND_STATUS_REG) & 
+                               BASR_ACK));
+
+                           NCR5380_write(MODE_REG, MR_BASE);
+                           NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+                       }
 #else
 #if (NDEBUG & NDEBUG_INTR)
-                       printk("scsi : unknown interrupt\n");
+                   printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
 #endif
+                   (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 #endif
                    } 
                } /* if BASR_IRQ */
@@ -1355,7 +1439,7 @@
        return -1;
 }
 
-#if defined(REAL_DMA) | defined(PSEUDO_DMA)
+#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)
 /* 
  * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
  *      unsigned char *phase, int *count, unsigned char **data)
@@ -1384,26 +1468,44 @@
     register unsigned char *d = *data;
     unsigned char tmp;
     int foo;
-    NCR5380_setup(instance);
+#if defined(REAL_DMA_POLL)
+    int cnt, toPIO;
+    unsigned char saved_data = 0, overrun = 0, residue;
+#endif
 
-#ifdef REAL_DMA 
-    instance->dmalen = c;
-    if (p & SR_IO)
-       NCR5380_dma_read_setup(d, c);
-    else
-       NCR5380_dma_write_setup(d, c);
+#if defined(REAL_DMA_POLL) || defined(REAL_DMA)
+    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) 
+       instance->hostdata;
 #endif
-    
-    
+
+    NCR5380_setup(instance);
+
     if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
         *phase = tmp;
         return -1;
     }
+#if defined(REAL_DMA) || defined(REAL_DMA_POLL) 
+#ifdef READ_OVERRUNS
+     if (p & SR_IO) {
+       c -= 2;
+     }
+#endif
+#if (NDEBUG & NDEBUG_DMA)
+    printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n",
+       instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" :
+       "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
+#endif
+    hostdata->dma_len = (p & SR_IO) ?
+       NCR5380_dma_read_setup(instance, d, c) : 
+       NCR5380_dma_write_setup(instance, d, c);
+#endif
 
     NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
 
 #ifdef REAL_DMA
     NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+#elif defined(REAL_DMA_POLL)
+    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
 #else
     /*
      * Note : on my sample board, watch-dog timeouts occured when interrupts
@@ -1411,10 +1513,14 @@
      * before the setting of DMA mode to after transfer of the last byte.
      */
 
-#ifndef UNSAFE
+#if defined(PSEUDO_DMA) && !defined(UNSAFE)
     cli();
 #endif
     NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+#endif /* def REAL_DMA */
+
+#if (NDEBUG & NDEBUG_DMA) & 0
+    printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG));
 #endif
 
     if (p & SR_IO)
@@ -1424,19 +1530,169 @@
        NCR5380_write(START_DMA_SEND_REG, 0);
     }
 
-#ifdef REAL_DMA
-    return 0;
-#else
-    foo = ((p & SR_IO) ? NCR5380_pread(instance, d, c) : 
-       NCR5380_pwrite(instance, d, c));
+#if defined(REAL_DMA_POLL)
+    do {
+       tmp = NCR5380_read(BUS_AND_STATUS_REG);
+    } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | 
+       BASR_END_DMA_TRANSFER)));
+
+/*
+  At this point, either we've completed DMA, or we have a phase mismatch,
+  or we've unexpectedly lost BUSY (which is a real error).
+
+  For write DMAs, we want to wait until the last byte has been
+  transferred out over the bus before we turn off DMA mode.  Alas, there
+  seems to be no terribly good way of doing this on a 5380 under all
+  conditions.  For non-scatter-gather operations, we can wait until REQ
+  and ACK both go false, or until a phase mismatch occurs.  Gather-writes
+  are nastier, since the device will be expecting more data than we
+  are prepared to send it, and REQ will remain asserted.  On a 53C8[01] we
+  could test LAST BIT SENT to assure transfer (I imagine this is precisely
+  why this signal was added to the newer chips) but on the older 538[01]
+  this signal does not exist.  The workaround for this lack is a watchdog;
+  we bail out of the wait-loop after a modest amount of wait-time if
+  the usual exit conditions are not met.  Not a terribly clean or
+  correct solution :-%
+
+  Reads are equally tricky due to a nasty characteristic of the NCR5380.
+  If the chip is in DMA mode for an READ, it will respond to a target's
+  REQ by latching the SCSI data into the INPUT DATA register and asserting
+  ACK, even if it has _already_ been notified by the DMA controller that
+  the current DMA transfer has completed!  If the NCR5380 is then taken
+  out of DMA mode, this already-acknowledged byte is lost.
+
+  This is not a problem for "one DMA transfer per command" reads, because
+  the situation will never arise... either all of the data is DMA'ed
+  properly, or the target switches to MESSAGE IN phase to signal a
+  disconnection (either operation bringing the DMA to a clean halt).
+  However, in order to handle scatter-reads, we must work around the
+  problem.  The chosen fix is to DMA N-2 bytes, then check for the
+  condition before taking the NCR5380 out of DMA mode.  One or two extra
+  bytes are tranferred via PIO as necessary to fill out the original
+  request.
+*/
+
+    if (p & SR_IO) {
+#ifdef READ_OVERRUNS
+      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_REGISTER);
+        overrun = 1;
+      }
+#endif
+    } else {
+      int limit = 100;
+      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;
+      }
+    }
+
+
+#if (NDEBUG & NDEBUG_DMA)
+    printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n",
+          instance->host_no, tmp, NCR5380_read(STATUS_REG));
+#endif
+
     NCR5380_write(MODE_REG, MR_BASE);
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    residue = NCR5380_dma_residual(instance);
+    c -= residue;
+    *count -= c;
+    *data += c;
+    *phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
+
+#ifdef READ_OVERRUNS
+    if (*phase == p && (p & SR_IO) && residue == 0) {
+      if (overrun) {
+#if (NDEBUG & NDEBUG_DMA)
+        printk("Got an input overrun, using saved byte\n");
+#endif
+        **data = saved_data;
+        *data += 1;
+        *count -= 1;
+        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, *data);
+#endif
+      NCR5380_transfer_pio(instance, phase, &cnt, data);
+      *count -= toPIO - cnt;
+    }
+#endif        
+
+#if (NDEBUG & NDEBUG_DMA)
+     printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n",
+           *data, *count, *(*data+*count-1), *(*data+*count));
+#endif
+     return 0;
+     
+#elif defined(REAL_DMA)
+    return 0;
+#else /* defined(REAL_DMA_POLL) */
+    if (p & SR_IO) {
+       if (!(foo = NCR5380_pread(instance, d, c - 1))) {
+           /*
+            * We can't disable DMA mode after successfully transfering 
+            * what we plan to be the last byte, since that would open up
+            * a race condition where if the target asserted REQ before 
+            * we got the DMA mode reset, the NCR5380 would have latched
+            * an additional byte into the INPUT DATA register and we'd
+            * have dropped it.
+            * 
+            * The workarround was to transfer one fewer bytes than we 
+            * intended to with the pseudo-DMA read function, wait for 
+            * the chip to latch the last byte, read it, and then disable
+            * pseudo-DMA mode.
+            * 
+            * After REQ is asserted, the NCR5380 asserts DRQ and ACK.
+            * REQ is deasserted when ACK is asserted, and not reasserted
+            * until ACK goes false.  Since the NCR5380 won't lower ACK
+            * until DACK is asserted, which won't happen unless we twiddle
+            * the DMA port or we take the NCR5380 out of DMA mode, we 
+            * can gurantee that we won't handshake another extra 
+            * byte.
+            */
+
+           while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
+           /* Wait for clean handshake */
+           while (NCR5380_read(STATUS_REG) & SR_REQ);
+           d[c - 1] = NCR5380_read(INPUT_DATA_REG);
+       }
+    } else {
+       int timeout;
+       if (!(foo = NCR5380_pwrite(instance, d, c))) {
+           /*
+            * Wait for the last byte to be sent.  If REQ is being asserted for 
+            * the byte we're interested, we'll ACK it and it will go false.  
+            */
+
+           /*
+           for (timeout = 100; timeout && (NCR5380_read(STATUS_REG) & SR_REQ);
+               --timeout);
+
+           while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
+           */
+
+           udelay(10); /* Should be enough ? */
+       }
+    }
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+    NCR5380_write(MODE_REG, MR_BASE);
+
     *data = d + c;
     *count = 0;
     *phase = (NCR5380_read(STATUS_REG & PHASE_MASK));
-#ifndef UNSAFE
+#if defined(PSEUDO_DMA) && !defined(UNSAFE)
     sti();
-#endif
+#endif /* defined(REAL_DMA_POLL) */
     return foo;
 #endif /* def REAL_DMA */
 }
@@ -1464,7 +1720,7 @@
     struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) 
        instance->hostdata;
     unsigned char msgout = NOP;
-    int len;
+    int len, transfersize;
     unsigned char *data;
     unsigned char phase, tmp, old_phase=0xff;
     Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
@@ -1518,11 +1774,18 @@
                 * in an unconditional loop.
                 */
 
-#if (defined(PSEUDO_DMA))
-               if (!scsi_devices[cmd->index].borken && cmd->transfersize && 
+#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
+#ifdef NCR5380_dma_xfer_len
+               if (!scsi_devices[cmd->index].borken &&
+                   (cmd->cmnd[0] != WRITE && cmd->cmnd[0] != WRITE_10) &&
+                   (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
+#else
+               if (!scsi_devices[cmd->index].borken && 
+                   (transfersize = cmd->transfersize) && 
                    cmd->SCp.this_residual && !(cmd->SCp.this_residual % 
-                   cmd->transfersize)) {
-                   len = cmd->transfersize;
+                   transfersize)) {
+#endif
+                   len = transfersize;
                    if (NCR5380_transfer_dma(instance, &phase,
                        &len, (unsigned char **) &cmd->SCp.ptr)) {
                        /*
@@ -1536,12 +1799,12 @@
                            ICR_ASSERT_ATN);
                        msgout = ABORT;
                    } else
-                       cmd->SCp.this_residual -= cmd->transfersize;
+                       cmd->SCp.this_residual -= transfersize - len;
                } else
-#endif /* (defined(REAL_DMA) || defined(PSEUDO_DMA)) */
-                   NCR5380_transfer_pio(instance, &phase, 
-                       (int *) &cmd->SCp.this_residual, (unsigned char **)
-                       &cmd->SCp.ptr);
+#endif /* defined(REAL_DMA) || defined(REAL_DMA_POLL) */
+                 NCR5380_transfer_pio(instance, &phase, 
+                   (int *) &cmd->SCp.this_residual, (unsigned char **)
+                   &cmd->SCp.ptr);
                break;
            case PHASE_MSGIN:
                /* 
@@ -1550,7 +1813,6 @@
                 * for tagged queuing, and the host should initiate any 
                 * negotiations for sync. SCSI, etc.
                 */
-
                len = 1;
                data = &tmp;
                NCR5380_transfer_pio(instance, &phase, &len, &data);
@@ -1611,8 +1873,19 @@
                    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
 
                    /* 
-                    * Use the status and message bytes from the original 
-                    * command.
+                    * I'm not sure what the correct thing to do here is : 
+                    * 
+                    * If the command that just executed is NOT a request 
+                    * sense, the obvious thing to do is to set the result
+                    * code to the values of the stored parameters.
+                    * 
+                    * If it was a REQUEST SENSE command, we need some way 
+                    * to differentiate between the failure code of the original
+                    * and the failure code of the REQUEST sense - the obvious
+                    * case is success, where we fall through and leave the result
+                    * code unchanged.
+                    * 
+                    * The non-obvious place is where the REQUEST SENSE failed 
                     */
 
                    if (cmd->cmnd[0] != REQUEST_SENSE) 
@@ -1619,6 +1892,7 @@
                        cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
                    else if (cmd->SCp.Status != GOOD)
                        cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+                   
 #ifdef AUTOSENSE
                    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
                        (cmd->SCp.Status == CHECK_CONDITION)) {
@@ -1651,6 +1925,9 @@
                        cmd->scsi_done(cmd);
 
                    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+                   
+                   while ((NCR5380_read(STATUS_REG) & SR_BSY) && 
+                       !hostdata->connected);
                    return;
                case MESSAGE_REJECT:
                    switch (hostdata->last_message) {
@@ -1679,6 +1956,9 @@
 
                    /* Enable reselect interupts */
                    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+                   /* Wait for bus free to avoid nasty timeouts */
+                   while ((NCR5380_read(STATUS_REG) & SR_BSY) && 
+                       !hostdata->connected);
                    return;
                /* 
                 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
@@ -1699,6 +1979,8 @@
  * since ATN should be raised before ACK goes false when we reject a message
  */
 
+                   printk("Unknown message!\n");
+
 #ifdef notyet
                /* 
                 * If we get something wierd that we aren't expecting, 
@@ -1822,6 +2104,7 @@
      */
 
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+    
     while (NCR5380_read(STATUS_REG) & SR_SEL);
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
@@ -1946,7 +2229,7 @@
      * not available on the 5380/5381 (only the various CMOS chips)
      */
 
-    while (NCR5380_read(STATUS_REG) & SR_ACK);
+    while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
 
     NCR5380_write(MODE_REG, MR_BASE);
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -1958,7 +2241,7 @@
      */
 
     if (!(hostdata->connected->SCp.phase & SR_CD)) {
-       transferred = instance->dma_len - NCR5380_dma_residual();
+       transferred = instance->dmalen - NCR5380_dma_residual();
        hostdata->connected->SCp.this_residual -= transferred;
        hostdata->connected->SCp.ptr += transferred;
     }
@@ -1999,6 +2282,8 @@
     
 #if (NDEBUG & NDEBUG_ABORT)
     printk("scsi%d : abort called\n", instance->host_no);
+    printk("        basr 0x%X, sr 0x%X\n", 
+          NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG));
 #endif
 /* 
  * Case 1 : If the command hasn't been issued yet, we simply remove it 
@@ -2120,28 +2405,26 @@
 
 
 /* 
- * Function : int NCR5380_reset (struct Scsi_Cmnd *)
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
  * 
  * Purpose : reset the SCSI bus.
  *
  * Returns : 0
+ *
  */ 
 
 #ifndef NCR5380_reset
 static
 #endif
-int NCR5380_reset (Scsi_Cmnd * SCpnt) {
+int NCR5380_reset (Scsi_Cmnd *cmd) {
     NCR5380_local_declare();
-    struct Scsi_Host *instance;
-    cli();
+    NCR5380_setup(cmd->host);
 
-    instance = SCpnt->host;
-    NCR5380_setup(instance);
+    cli();
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
     udelay(1);
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
     sti();
-    if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
+
     return 0;
 }
--- 1.1 1993/11/11 05:01:16
+++ NCR5380.h   1993/12/12 14:27:25
@@ -5,9 +5,9 @@
  *     Visionary Computing
  *     (Unix consulting and custom programming)
  *     drew@colorado.edu
- *      +1 (303) 440-4894
+ *      +1 (303) 666-5836
  *
- * DISTRIBUTION RELEASE 3
+ * DISTRIBUTION RELEASE 4
  *
  * For more information, please consult 
  *
@@ -23,7 +23,13 @@
 
 /*
  * $Log: NCR5380.h,v $
- * Revision 1.1  1993/11/11  05:01:16  drew
+ * Revision 1.3  1993/12/11  05:32:21  drew
+ * Fixed DMA.
+ *
+ * Revision 1.2  1993/11/26  05:05:45  drew
+ * *** empty log message ***
+ *
+ * Revision 1.1  1993/10/16  22:43:42  drew
  * Initial revision
  *
  */
@@ -31,7 +37,7 @@
 #ifndef NCR5380_H
 #define NCR5380_H
 
-#define NCR5380_PUBLIC_RELEASE 3
+#define NCR5380_PUBLIC_RELEASE 4
 
 #define NDEBUG_ARBITRATION     0x1
 #define NDEBUG_AUTOSENSE       0x2
@@ -144,7 +150,7 @@
  * Used in DMA transfer mode, data is latched from the SCSI bus on
  * the falling edge of REQ (ini) or ACK (tgt)
  */
-#define INPUT_DATA_REGISTER    6       /* ro */
+#define INPUT_DATA_REG                 6       /* ro */
 
 /* Write any value to this register to start a DMA recieve */
 #define START_DMA_TARGET_RECIEVE_REG   6       /* wo */
@@ -195,13 +201,14 @@
                                 */
 
 /*
- * These are "special" values for the irq field of the instance structure
- * and returns from NCR5380_probe_irq.
+ * These are "special" values for the irq and dma_channel fields of the 
+ * Scsi_Host structure
  */
 
 #define IRQ_NONE       255
+#define DMA_NONE       255
 #define IRQ_AUTO       254
-
+#define DMA_AUTO       254
 
 #ifndef ASM
 struct NCR5380_hostdata {
@@ -208,7 +215,7 @@
     NCR5380_implementation_fields;             /* implmenentation specific */
     unsigned char id_mask, id_higher_mask;     /* 1 << id, all bits greater */
     volatile unsigned char busy[8];            /* index = target, bit = lun */
-#ifdef REAL_DMA
+#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
     volatile int dma_len;                      /* requested length of DMA */
 #endif
     volatile unsigned char last_message;       /* last message OUT */
@@ -239,7 +246,7 @@
 #ifndef NCR5380_reset
 static
 #endif
-int NCR5380_reset (Scsi_Cmnd *);
+int NCR5380_reset (Scsi_Cmnd *cmd);
 #ifndef NCR5380_queue_command
 static 
 #endif
@@ -248,7 +255,7 @@
 
 static void NCR5380_reselect (struct Scsi_Host *instance);
 static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag);
-#if defined(PSEUDO_DMA) || defined(REAL_DMA)
+#if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
 static int NCR5380_transfer_dma (struct Scsi_Host *instance,
         unsigned char *phase, int *count, unsigned char **data);
 #endif
@@ -255,6 +262,55 @@
 static int NCR5380_transfer_pio (struct Scsi_Host *instance,
         unsigned char *phase, int *count, unsigned char **data);
 
+#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386)
+static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
+       unsigned char *ptr, unsigned int count, unsigned char mode) {
+    unsigned limit;
+
+    if (instance->dma_channel <=3) {
+       if (count > 65536)
+           count = 65536;
+       limit = 65536 - (((unsigned) ptr) & 0xFFFF);
+    } else {
+       if (count > 65536 * 2) 
+           count = 65536 * 2;
+       limit = 65536* 2 - (((unsigned) ptr) & 0x1FFFF);
+    }
+
+    if (count > limit) count = limit;
+
+    if ((count & 1) || (((unsigned) ptr) & 1))
+       panic ("scsi%d : attmpted unaligned DMA transfer\n", instance->host_no);
+    cli();
+    disable_dma(instance->dma_channel);
+    clear_dma_ff(instance->dma_channel);
+    set_dma_addr(instance->dma_channel, (unsigned int) ptr);
+    set_dma_count(instance->dma_channel, count);
+    set_dma_mode(instance->dma_channel, mode);
+    enable_dma(instance->dma_channel);
+    sti();
+    return count;
+}
+
+static __inline__ int NCR5380_i386_dma_write_setup (struct Scsi_Host *instance,
+    unsigned char *src, unsigned int count) {
+    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_WRITE);
+}
+
+static __inline__ int NCR5380_i386_dma_read_setup (struct Scsi_Host *instance,
+    unsigned char *src, unsigned int count) {
+    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_READ);
+}
+
+static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) {
+    register int tmp;
+    cli();
+    clear_dma_ff(instance->dma_channel);
+    tmp = get_dma_residue(instance->dma_channel);
+    sti();
+    return tmp;
+}
+#endif /* defined(REAL_DMA) && defined(i386)  */
 #endif __KERNEL_
 #endif /* ndef ASM */
 #endif /* NCR5380_H */


------------------------------


** FOR YOUR REFERENCE **

The service address, to which questions about the list itself and requests
to be added to or deleted from it should be directed, is:

    Internet: Linux-Development-Request@NEWS-DIGESTS.MIT.EDU

You can send mail to the entire list (and comp.os.linux.development) via:

    Internet: Linux-Development@NEWS-DIGESTS.MIT.EDU

Linux may be obtained via one of these FTP sites:
    nic.funet.fi				pub/OS/Linux
    tsx-11.mit.edu				pub/linux
    sunsite.unc.edu				pub/Linux

End of Linux-Development Digest
******************************
