Author: marius
Date: Mon Aug  6 08:58:54 2012
New Revision: 239089
URL: http://svn.freebsd.org/changeset/base/239089

Log:
  - Merge from NetBSD:
    When issuing a non-DMA command, make sure to set the "remaining length of
    command to be transferred via DMA" (sc_cmdlen) to zero up-front, otherwise
    we might get confused on command competition interrupt (no DMA active but
    still data left to transfer).
  - Implement handling of MSG_IGN_WIDE_RESIDUE which some targets produce, as
    just rejecting these leads to a resend and disconnect loop.
    Reported and tested by: mjacob
  
  MFC after:    3 days

Modified:
  head/sys/dev/esp/ncr53c9x.c

Modified: head/sys/dev/esp/ncr53c9x.c
==============================================================================
--- head/sys/dev/esp/ncr53c9x.c Mon Aug  6 08:54:06 2012        (r239088)
+++ head/sys/dev/esp/ncr53c9x.c Mon Aug  6 08:58:54 2012        (r239089)
@@ -26,7 +26,7 @@
  *
  */
 
-/*     $NetBSD: ncr53c9x.c,v 1.143 2011/07/31 18:39:00 jakllsch Exp $  */
+/*     $NetBSD: ncr53c9x.c,v 1.145 2012/06/18 21:23:56 martin Exp $    */
 
 /*-
  * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
@@ -256,7 +256,7 @@ ncr53c9x_attach(struct ncr53c9x_softc *s
                return (EINVAL);
        }
 
-       device_printf(sc->sc_dev, "%s, %dMHz, SCSI ID %d\n",
+       device_printf(sc->sc_dev, "%s, %d MHz, SCSI ID %d\n",
            ncr53c9x_variant_names[sc->sc_rev], sc->sc_freq, sc->sc_id);
 
        sc->sc_ntarg = (sc->sc_rev == NCR_VARIANT_FAS366) ? 16 : 8;
@@ -890,11 +890,8 @@ ncr53c9x_select(struct ncr53c9x_softc *s
                sc->sc_cmdp = cmd;
                error = NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0,
                    &dmasize);
-               if (error != 0) {
-                       sc->sc_cmdlen = 0;
-                       sc->sc_cmdp = NULL;
+               if (error != 0)
                        goto cmd;
-               }
 
                /* Program the SCSI counter. */
                NCR_SET_COUNT(sc, dmasize);
@@ -920,6 +917,7 @@ cmd:
         */
 
        /* Now get the command into the FIFO. */
+       sc->sc_cmdlen = 0;
        ncr53c9x_wrfifo(sc, cmd, clen);
 
        /* And get the target's attention. */
@@ -1771,7 +1769,7 @@ ncr53c9x_msgin(struct ncr53c9x_softc *sc
        struct ncr53c9x_linfo *li;
        struct ncr53c9x_tinfo *ti;
        uint8_t *pb;
-       int lun, plen;
+       int len, lun;
 
        NCR_LOCK_ASSERT(sc, MA_OWNED);
 
@@ -1818,15 +1816,15 @@ ncr53c9x_msgin(struct ncr53c9x_softc *sc
                 */
                case NCR_RESELECTED:
                        pb = sc->sc_imess + 1;
-                       plen = sc->sc_imlen - 1;
+                       len = sc->sc_imlen - 1;
                        break;
 
                default:
                        pb = sc->sc_imess;
-                       plen = sc->sc_imlen;
+                       len = sc->sc_imlen;
                }
 
-               if (__verify_msg_format(pb, plen))
+               if (__verify_msg_format(pb, len))
                        goto gotit;
        }
 
@@ -1963,6 +1961,29 @@ gotit:
                        sc->sc_dleft = ecb->dleft;
                        break;
 
+               case MSG_IGN_WIDE_RESIDUE:
+                       NCR_MSGS(("ignore wide residue (%d bytes)",
+                           sc->sc_imess[1]));
+                       if (sc->sc_imess[1] != 1) {
+                               xpt_print_path(ecb->ccb->ccb_h.path);
+                               printf("unexpected MESSAGE IGNORE WIDE "
+                                   "RESIDUE (%d bytes); sending REJECT\n",
+                                   sc->sc_imess[1]);
+                               goto reject;
+                       }
+                       /*
+                        * If there was a last transfer of an even number of
+                        * bytes, wipe the "done" memory and adjust by one
+                        * byte (sc->sc_imess[1]).
+                        */
+                       len = sc->sc_dleft - ecb->dleft;
+                       if (len != 0 && (len & 1) == 0) {
+                               ecb->flags &= ~ECB_TENTATIVE_DONE;
+                               sc->sc_dp = (char *)sc->sc_dp - 1;
+                               sc->sc_dleft--;
+                       }
+                       break;
+
                case MSG_EXTENDED:
                        NCR_MSGS(("extended(%x) ", sc->sc_imess[2]));
                        switch (sc->sc_imess[2]) {
@@ -2272,6 +2293,7 @@ cmd:
        /*
         * XXX FIFO size
         */
+       sc->sc_cmdlen = 0;
        ncr53c9x_flushfifo(sc);
        ncr53c9x_wrfifo(sc, sc->sc_omp, sc->sc_omlen);
        NCRCMD(sc, NCRCMD_TRANS);
@@ -2811,9 +2833,10 @@ again:
                                 * (Timing problems?)
                                 */
                                if (sc->sc_features & NCR_F_DMASELECT) {
-                                       if (sc->sc_cmdlen == 0)
+                                       if (sc->sc_cmdlen == 0) {
                                                /* Hope for the best... */
                                                break;
+                                       }
                                } else if ((NCR_READ_REG(sc, NCR_FFLAG) &
                                    NCRFIFO_FF) == 0) {
                                        /* Hope for the best... */
@@ -2986,11 +3009,8 @@ msgin:
                        sc->sc_cmdp = (void *)&ecb->cmd.cmd;
                        error = NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen,
                            0, &size);
-                       if (error != 0) {
-                               sc->sc_cmdlen = 0;
-                               sc->sc_cmdp = NULL;
+                       if (error != 0)
                                goto cmd;
-                       }
 
                        /* Program the SCSI counter. */
                        NCR_SET_COUNT(sc, size);
@@ -3005,6 +3025,7 @@ msgin:
                        break;
                }
 cmd:
+               sc->sc_cmdlen = 0;
                ncr53c9x_wrfifo(sc, (uint8_t *)&ecb->cmd.cmd, ecb->clen);
                NCRCMD(sc, NCRCMD_TRANS);
                sc->sc_prevphase = COMMAND_PHASE;
@@ -3046,7 +3067,7 @@ setup_xfer:
                        goto finish;
                }
 
-               /* Target returned to data phase: wipe "done" memory */
+               /* Target returned to data phase: wipe "done" memory. */
                ecb->flags &= ~ECB_TENTATIVE_DONE;
 
                /* Program the SCSI counter. */
@@ -3105,8 +3126,8 @@ shortcut:
         * overhead to pay.  For example, selecting, sending a message
         * and command and then doing some work can be done in one "pass".
         *
-        * The delay is a heuristic.  It is 2 when at 20MHz, 2 at 25MHz and 1
-        * at 40MHz. This needs testing.
+        * The delay is a heuristic.  It is 2 when at 20 MHz, 2 at 25 MHz and
+        * 1 at 40 MHz.  This needs testing.
         */
        microtime(&wait);
        wait.tv_usec += 50 / sc->sc_freq;
@@ -3191,8 +3212,7 @@ ncr53c9x_callout(void *arg)
                ncr53c9x_abort(sc, ecb);
 
                /* Disable sync mode if stuck in a data phase. */
-               if (ecb == sc->sc_nexus &&
-                   ti->curr.offset != 0 &&
+               if (ecb == sc->sc_nexus && ti->curr.offset != 0 &&
                    (sc->sc_phase & (MSGI | CDI)) == 0) {
                        /* XXX ASYNC CALLBACK! */
                        ti->goal.offset = 0;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to