aic7xxx.h:
authorPeter Avalos <pavalos@dragonflybsd.org>
Fri, 6 Jul 2007 05:45:52 +0000 (05:45 +0000)
committerPeter Avalos <pavalos@dragonflybsd.org>
Fri, 6 Jul 2007 05:45:52 +0000 (05:45 +0000)
        Add constants for SPI protocol delays that are needed for
        target mode.

aic7xxx.c:
        Correct a target mode issue that caused an occassional
        spurious REQ to be seen on the bus when performing manual
        message processing (e.g. transfer rate negotiation).

        Enforce phase change bus settle rules with explicit
        delays when performing manual message processing in
        target mode.  The sequencer already did this for
        "fast-path", target mode message processing.

Obtained-from: FreeBSD

sys/dev/disk/aic7xxx/aic7xxx.c
sys/dev/disk/aic7xxx/aic7xxx.h

index 2b78262..bca94b2 100644 (file)
@@ -39,8 +39,8 @@
  *
  * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#155 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.102 2004/08/17 00:14:30 gibbs Exp $
- * $DragonFly: src/sys/dev/disk/aic7xxx/aic7xxx.c,v 1.19 2007/07/06 04:56:22 pavalos Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.103 2004/10/19 20:48:05 gibbs Exp $
+ * $DragonFly: src/sys/dev/disk/aic7xxx/aic7xxx.c,v 1.20 2007/07/06 05:45:52 pavalos Exp $
  */
 
 #include "aic7xxx_osm.h"
@@ -2820,11 +2820,17 @@ reswitch:
        case MSG_TYPE_TARGET_MSGIN:
        {
                int msgdone;
-               int msgout_request;
 
                if (ahc->msgout_len == 0)
                        panic("Target MSGIN with no active message");
 
+#ifdef AHC_DEBUG
+               if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+                       ahc_print_devinfo(ahc, &devinfo);
+                       kprintf("TARGET_MSG_IN");
+               }
+#endif
+
                /*
                 * If we interrupted a mesgout session, the initiator
                 * will not know this until our first REQ.  So, we
@@ -2832,24 +2838,47 @@ reswitch:
                 * first byte.
                 */
                if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0
-                && ahc->msgout_index > 0)
-                       msgout_request = TRUE;
-               else
-                       msgout_request = FALSE;
-
-               if (msgout_request) {
+                && ahc->msgout_index > 0) {
 
                        /*
-                        * Change gears and see if
-                        * this messages is of interest to
-                        * us or should be passed back to
-                        * the sequencer.
+                        * Change gears and see if this messages is
+                        * of interest to us or should be passed back
+                        * to the sequencer.
                         */
+#ifdef AHC_DEBUG
+                       if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+                               kprintf(" Honoring ATN Request.\n");
+#endif
                        ahc->msg_type = MSG_TYPE_TARGET_MSGOUT;
+
+                       /*
+                        * Disable SCSI Programmed I/O during the
+                        * phase change so as to avoid phantom REQs.
+                        */
+                       ahc_outb(ahc, SXFRCTL0,
+                                ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
+
+                       /*
+                        * Since SPIORDY asserts when ACK is asserted
+                        * for P_MSGOUT, and SPIORDY's assertion triggered
+                        * our entry into this routine, wait for ACK to
+                        * *de-assert* before changing phases.
+                        */
+                       while ((ahc_inb(ahc, SCSISIGI) & ACKI) != 0)
+                               ;
+
                        ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO);
+
+                       /*
+                        * All phase line changes require a bus
+                        * settle delay before REQ is asserted.
+                        * [SCSI SPI4 10.7.1]
+                        */
+                       ahc_flush_device_writes(ahc);
+                       aic_delay(AHC_BUSSETTLE_DELAY);
+
                        ahc->msgin_index = 0;
-                       /* Dummy read to REQ for first byte */
-                       ahc_inb(ahc, SCSIDATL);
+                       /* Enable SCSI Programmed I/O to REQ for first byte */
                        ahc_outb(ahc, SXFRCTL0,
                                 ahc_inb(ahc, SXFRCTL0) | SPIOEN);
                        break;
@@ -2866,6 +2895,11 @@ reswitch:
                /*
                 * Present the next byte on the bus.
                 */
+#ifdef AHC_DEBUG
+               if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+                       kprintf(" byte 0x%x\n",
+                              ahc->msgout_buf[ahc->msgout_index]);
+#endif
                ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN);
                ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
                break;
@@ -2875,6 +2909,12 @@ reswitch:
                int lastbyte;
                int msgdone;
 
+#ifdef AHC_DEBUG
+               if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+                       ahc_print_devinfo(ahc, &devinfo);
+                       kprintf("TARGET_MSG_OUT");
+               }
+#endif
                /*
                 * The initiator signals that this is
                 * the last byte by dropping ATN.
@@ -2888,6 +2928,13 @@ reswitch:
                 */
                ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
                ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL);
+
+#ifdef AHC_DEBUG
+               if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+                       kprintf(" byte 0x%x\n",
+                              ahc->msgin_buf[ahc->msgin_index]);
+#endif
+
                msgdone = ahc_parse_msg(ahc, &devinfo);
                if (msgdone == MSGLOOP_TERMINATED) {
                        /*
@@ -2913,7 +2960,33 @@ reswitch:
                         * to the Message in phase and send it.
                         */
                        if (ahc->msgout_len != 0) {
+#ifdef AHC_DEBUG
+                               if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+                                       ahc_print_devinfo(ahc, &devinfo);
+                                       kprintf(" preparing response.\n");
+                               }
+#endif
                                ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO);
+
+                               /*
+                                * All phase line changes require a bus
+                                * settle delay before REQ is asserted.
+                                * [SCSI SPI4 10.7.1]  When transitioning
+                                * from an OUT to an IN phase, we must
+                                * also wait a data release delay to allow
+                                * the initiator time to release the data
+                                * lines. [SCSI SPI4 10.12]
+                                */
+                               ahc_flush_device_writes(ahc);
+                               aic_delay(AHC_BUSSETTLE_DELAY
+                                       + AHC_DATARELEASE_DELAY);
+
+                               /*
+                                * Enable SCSI Programmed I/O.  This will
+                                * immediately cause SPIORDY to assert,
+                                * and the sequencer will call our message
+                                * loop again.
+                                */
                                ahc_outb(ahc, SXFRCTL0,
                                         ahc_inb(ahc, SXFRCTL0) | SPIOEN);
                                ahc->msg_type = MSG_TYPE_TARGET_MSGIN;
@@ -7016,7 +7089,7 @@ bus_reset:
                        active_scb = ahc_lookup_scb(ahc, active_scb_index);
                        if (active_scb != scb) {
                                if (ahc_other_scb_timeout(ahc, scb,
-                                                         active_scb) != 0)
+                                                         active_scb) == 0)
                                        goto bus_reset;
                                continue;
                        } 
index f09eb03..584e678 100644 (file)
@@ -39,8 +39,8 @@
  *
  * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#85 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.52 2004/08/18 16:31:56 gibbs Exp $
- * $DragonFly: src/sys/dev/disk/aic7xxx/aic7xxx.h,v 1.4 2007/07/06 04:56:22 pavalos Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.53 2004/10/19 20:48:06 gibbs Exp $
+ * $DragonFly: src/sys/dev/disk/aic7xxx/aic7xxx.h,v 1.5 2007/07/06 05:45:52 pavalos Exp $
  */
 
 #ifndef _AIC7XXX_H_
@@ -182,6 +182,10 @@ struct seeprom_descriptor;
 /* Reset line assertion time in us */
 #define AHC_BUSRESET_DELAY     25
 
+/* Phase change constants used in target mode. */
+#define        AHC_BUSSETTLE_DELAY     400
+#define        AHC_DATARELEASE_DELAY   400
+
 /******************* Chip Characteristics/Operating Settings  *****************/
 /*
  * Chip Type