Subject: Linux-Development Digest #405
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:     Mon, 24 Jan 94 02:13:09 EST

Linux-Development Digest #405, Volume #1         Mon, 24 Jan 94 02:13:09 EST

Contents:
  Re: Success with PAS16 SCSI with hard drives? (Drew Eckhardt)

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

From: drew@kinglear.cs.colorado.edu (Drew Eckhardt)
Subject: Re: Success with PAS16 SCSI with hard drives?
Date: Mon, 24 Jan 1994 06:14:33 GMT

In article <2hv9gt$7i3@tut.msstate.edu>,
David Simmons <simmons@EE.MsState.Edu> wrote:
>Has anybody been successful in getting a hard drive to work with the
>ProAudioSpectrum-16 SCSI port, after recompiling the kernel for it?

Yes.

>With networking at the same time?  

Unknown.

>Is the PAS16 SCSI code in the kernel
>intended just for CD-ROMS?

No. 

Note that you really don't want to run a hard drive on the board,
due to the low performance you'll experience (CPU usage will be 100%,
and if you don't use my patches and need to use polled transfers instead
of pseudo-DMA, expect throughput of at most 120K/sec).

These are the patches I submitted to Linus for inclusion in the 
new kernel, along with a description of the bugs that should be 
fixed.

If the hard disk support still doesn't work for you after applying 
these patches, undefine PSEUDO_DMA in pas16.c in the SCSI directory
(this will kill performance)

====================================================================

The following patches fix several nasty bugs that were in the 
NCR5380 core, thus affecting the Trantor T128 and PAS16 SCSI 
support : 

1.  When multiple SCSI devices were being used, sometimes a device
        wouldn't drop the bus soon enough, and the selection code
        would return an error.

2.  When buffered SCSI devices were used on a NCR5380 based board
        using the data-book's so-called Pseudo-DMA mode,
        a race condition resulted in an extra byte of data being 
        transfered to the chip and dropped on reads, and the 
        chip's drivers being deactivated before the last byte of 
        data being sent on writes in some cases.

They also have various hooks that make real DMA work, ie for 
Dave Platt's port of my driver to the Richoh boards, but I really
don't care to dig those non-essential parts out, especially since
they aren't enabled for any of the "officially" supported boards.

The WD7000 patch adds an additional permissible address to
look for a BIOS signature at, I'm not convinced that the Adaptec 
1520 or WD7000 drivers should be doing a BIOS check, since they
aren't memory mapped boards and don't need that hack to locate
the registers, and they don't have the future domain problem where
HDIO_GETGEO should return different results based on the BIOS 
revision used and even use different ID's.

The diffs are against .99.14t

--- 1.1 1994/01/15 06:00:54
+++ linux/drivers/scsi/NCR5380.c        1994/01/24 05:37:42
@@ -3,13 +3,15 @@
  *     to implement 5380 SCSI drivers under Linux with a non-trantor
  *     architecture.
  *
+ *     Note that these routines also work with NR53c400 family chips.
+ *
  * Copyright 1993, Drew Eckhardt
  *     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,6 +28,19 @@
 
 /*
  * $Log: NCR5380.c,v $
+ * Revision 1.5  1994/01/19  09:14:57  drew
+ * Fixed udelay() hack that was being used on DATAOUT phases
+ * instead of a propper wait for the final handshake.
+ *
+ * Revision 1.4  1994/01/19  06:44:25  drew
+ * *** empty log message ***
+ *
+ * Revision 1.3  1994/01/19  05:24:40  drew
+ * Added support for TCR LAST_BYTE_SENT bit.
+ *
+ * Revision 1.2  1994/01/15  06:14:11  drew
+ * REAL DMA support, bug fixes.
+ *
  * Revision 1.1  1994/01/15  06:00:54  drew
  * Initial revision
  *
@@ -33,14 +48,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 +71,11 @@
 #undef REAL_DMA
 #endif
 
+#ifdef REAL_DMA_POLL
+#undef READ_OVERRUNS
+#define READ_OVERRUNS
+#endif
+
 /*
  * Design
  * Issues :
@@ -171,6 +198,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 +242,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 +665,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
@@ -683,6 +724,7 @@
     hostdata->connected = NULL;
     hostdata->issue_queue = NULL;
     hostdata->disconnected_queue = NULL;
+    hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
 
     if (!the_template) {
        the_template = instance->hostt;
@@ -920,6 +962,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 +974,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 +989,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 +1001,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 w
ith no connected cmd\n",
+                                   instance->hostno);
+
+                           transfered = (hostdata->dmalen - NCR5380_dma_residu
al(instance));
+                           hostdata->connected->SCp.this_residual -= transferr
ed;
+                           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 +1428,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 +1457,42 @@
     register unsigned char *d = *data;
     unsigned char tmp;
     int foo;
+#if defined(REAL_DMA_POLL)
+    int cnt, toPIO;
+    unsigned char saved_data = 0, overrun = 0, residue;
+#endif
+
+    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) 
+       instance->hostdata;
+
     NCR5380_setup(instance);
 
-#ifdef REAL_DMA 
-    instance->dmalen = c;
-    if (p & SR_IO)
-       NCR5380_dma_read_setup(d, c);
-    else
-       NCR5380_dma_write_setup(d, c);
-#endif
-    
-    
     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_MO
NITOR_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 +1500,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 +1517,200 @@
        NCR5380_write(START_DMA_SEND_REG, 0);
     }
 
-#ifdef REAL_DMA
+#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.  
+            */
+           if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) {
+               timeout = 20000;
+#if 1
+#if 1
+               while (!(NCR5380_read(BUS_AND_STATUS_REG) & 
+                       BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) &
+                       BASR_PHASE_MATCH));
 #else
-    foo = ((p & SR_IO) ? NCR5380_pread(instance, d, c) : 
-       NCR5380_pwrite(instance, d, c));
-    NCR5380_write(MODE_REG, MR_BASE);
+               if (NCR5380_read(STATUS_REG) & SR_REQ) {
+                   for (; timeout && 
+                       !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); 
+                       --timeout);
+                   for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ);
+                       --timeout);
+               } 
+#endif
+       
+
+#if (NDEBUG & NDEBUG_LAST_BYTE_SENT)
+               if (!timeout) 
+                   printk("scsi%d : timed out on last byte\n",
+                           instance->host_no);
+#endif
+
+
+               if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) {
+                   hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT;
+                   if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) 
{
+                       hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;
+#if (NDEBUG & NDEBUG_LAST_BYTE_SENT)
+                       printk("scsi%d : last bit sent works\n", 
+                           instance->host_no);
+#endif
+                   }
+               }
+           } else 
+               while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)
);
+#else
+           udelay (5);
+#endif
+       }
+    }
+
     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 +1738,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 +1792,17 @@
                 * 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 &&
+                   (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 +1816,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 +1830,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 +1890,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 origina
l
+                    * and the failure code of the REQUEST sense - the obvious
+                    * case is success, where we fall through and leave the res
ult
+                    * code unchanged.
+                    * 
+                    * The non-obvious place is where the REQUEST SENSE failed 
                     */
 
                    if (cmd->cmnd[0] != REQUEST_SENSE) 
@@ -1619,6 +1909,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 +1942,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 +1973,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 +1996,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 +2121,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 +2246,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 +2258,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 +2299,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 +2422,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 1994/01/15 06:00:54
+++ linux/drivers/scsi/NCR5380.h        1994/01/19 06:44:28
@@ -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,6 +23,15 @@
 
 /*
  * $Log: NCR5380.h,v $
+ * Revision 1.3  1994/01/19  05:24:40  drew
+ * Added support for TCR LAST_BYTE_SENT bit.
+ *
+ * Revision 1.3  1994/01/19  05:24:40  drew
+ * Added support for TCR LAST_BYTE_SENT bit.
+ *
+ * Revision 1.2  1994/01/15  06:14:11  drew
+ * REAL DMA support, bug fixes.
+ *
  * Revision 1.1  1994/01/15  06:00:54  drew
  * Initial revision
  *
@@ -31,7 +40,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
@@ -50,6 +59,7 @@
 #define NDEBUG_RESELECTION     0x4000
 #define NDEBUG_SELECTION       0x8000
 #define NDEBUG_USLEEP          0x10000
+#define NDEBUG_LAST_BYTE_SENT  0x20000
 
 /* 
  * The contents of the OUTPUT DATA register are asserted on the bus when
@@ -144,7 +154,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 +205,17 @@
                                 */
 
 /*
- * 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
 
+#define FLAG_HAS_LAST_BYTE_SENT                1       /* NCR53c81 or better *
/
+#define FLAG_CHECK_LAST_BYTE_SENT      2       /* Only test once */
 
 #ifndef ASM
 struct NCR5380_hostdata {
@@ -208,7 +222,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 */
@@ -215,6 +229,7 @@
     volatile Scsi_Cmnd *connected;             /* currently connected command 
*/
     volatile Scsi_Cmnd *issue_queue;           /* waiting to be issued */
     volatile Scsi_Cmnd *disconnected_queue;    /* waiting for reconnect */
+    int flags;
 #ifdef USLEEP
     unsigned long time_expires;                        /* in jiffies, set prio
r to sleeping */
     struct Scsi_Host *next_timer;
@@ -239,7 +254,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 +263,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 +270,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 */
--- 1.1 1994/01/15 06:02:10
+++ linux/drivers/scsi/wd7000.c 1994/01/15 06:14:38
@@ -1,4 +1,4 @@
-/* $Id: wd7000.c,v 1.1 1994/01/15 06:02:10 drew Exp $
+/* $Id: wd7000.c,v 1.2 1994/01/15 06:02:32 drew Exp $
  *  linux/kernel/wd7000.c
  *
  *  Copyright (C) 1992  Thomas Wuensche
@@ -508,7 +508,8 @@
 }
 
 
-static const char *wd_bases[] = {(char *)0xce000};
+static const char *wd_bases[] = {(char *)0xce000,(char *)d8000};
+
 typedef struct {
     char * signature;
     unsigned offset;






        


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


** 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
******************************
