Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-2]: src/sys/dev/ic Pull up following revision(s) (requested by it...



details:   https://anonhg.NetBSD.org/src/rev/35ab8534efba
branches:  netbsd-2
changeset: 564630:35ab8534efba
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Mon Nov 19 20:40:03 2007 +0000

description:
Pull up following revision(s) (requested by itohy in ticket #11391):
        sys/dev/ic/ninjascsi32.c: revisions 1.13, 1.14
        sys/dev/ic/ninjascsi32var.h: revision 1.4
Fix problem where targets with ID 0, 1, or 2 couldn't be reconnected.
It seems I have always tested with targets those ID >= 3,
and that I am the only user of this driver.
- Reset the bus if a Bus Reset condition is detected to make sure
  all devices on the bus are really reset.
- Block interrupts on Bus Reset, and check it periodically until the
  reset is released.  On some 32UDE devices (probably the earlier ones)
  the RST line looks unstable without the termination power and may
  suffer ~continuous Bus Reset interrupts.
- Change number of scatter/gather segments from 16 to 17, to allow
  non-page-aligned 64KB transfer on 4KB/page platforms.

diffstat:

 sys/dev/ic/ninjascsi32.c    |  114 +++++++++++++++++++++++++++++++------------
 sys/dev/ic/ninjascsi32var.h |   22 +++++---
 2 files changed, 95 insertions(+), 41 deletions(-)

diffs (299 lines):

diff -r 3d8f66dd5c10 -r 35ab8534efba sys/dev/ic/ninjascsi32.c
--- a/sys/dev/ic/ninjascsi32.c  Mon Nov 19 20:35:42 2007 +0000
+++ b/sys/dev/ic/ninjascsi32.c  Mon Nov 19 20:40:03 2007 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: ninjascsi32.c,v 1.2.2.3.2.1 2006/01/20 22:17:12 tron Exp $     */
+/*     $NetBSD: ninjascsi32.c,v 1.2.2.3.2.2 2007/11/19 20:40:03 bouyer Exp $   */
 
 /*-
- * Copyright (c) 2004, 2006 The NetBSD Foundation, Inc.
+ * Copyright (c) 2004, 2006, 2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ninjascsi32.c,v 1.2.2.3.2.1 2006/01/20 22:17:12 tron Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ninjascsi32.c,v 1.2.2.3.2.2 2007/11/19 20:40:03 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -121,10 +121,10 @@
 static void    njsc32_run_xfer(struct njsc32_softc *, struct scsipi_xfer *);
 static void    njsc32_end_cmd(struct njsc32_softc *, struct njsc32_cmd *,
                    scsipi_xfer_result_t);
+static void    njsc32_wait_reset_release(void *);
 static void    njsc32_reset_bus(struct njsc32_softc *);
 static void    njsc32_clear_cmds(struct njsc32_softc *,
                    scsipi_xfer_result_t);
-static void    njsc32_reset_detected(struct njsc32_softc *);
 static void    njsc32_set_ptr(struct njsc32_softc *, struct njsc32_cmd *,
                    u_int32_t);
 static void    njsc32_assert_ack(struct njsc32_softc *);
@@ -330,6 +330,7 @@
 njsc32_init(struct njsc32_softc *sc, int nosleep)
 {
        u_int16_t intstat;
+       int i;
 
        /* block all interrupts */
        njsc32_write_2(sc, NJSC32_REG_IRQ, NJSC32_IRQ_MASK_ALL);
@@ -339,9 +340,8 @@
        njsc32_write_4(sc, NJSC32_REG_BM_CNT, 0);
 
        /* make sure interrupts are cleared */
-       /* XXX loop forever? */
-       while ((intstat = njsc32_read_2(sc, NJSC32_REG_IRQ)) &
-           NJSC32_IRQ_INTR_PENDING) {
+       for (i = 0; ((intstat = njsc32_read_2(sc, NJSC32_REG_IRQ))
+           & NJSC32_IRQ_INTR_PENDING) && i < 5 /* just not forever */; i++) {
                DPRINTF(("%s: njsc32_init: intr pending: %#x\n",
                    sc->sc_dev.dv_xname, intstat));
        }
@@ -373,7 +373,7 @@
            NJSC32_MISC_BMSTOP_CHANGE2_NONDATA_PHASE);
 
        /*
-        * Check for termination power (32Bi only?).
+        * Check for termination power (32Bi and some versions of 32UDE).
         */
        if (!nosleep || cold) {
                DPRINTF(("%s: njsc32_init: checking TERMPWR\n",
@@ -440,8 +440,7 @@
        */
            NJSC32_IRQSEL_AUTO_SCSI_SEQ);
 
-       /* unblock interrupts */
-       njsc32_write_2(sc, NJSC32_REG_IRQ, 0);
+       /* interrupts will be unblocked later after bus reset */
 
        /* turn LED off */
        njsc32_ireg_write_1(sc, NJSC32_IREG_EXT_PORT_DDR,
@@ -588,6 +587,7 @@
        /* init */
        TAILQ_INIT(&sc->sc_freecmd);
        TAILQ_INIT(&sc->sc_reqcmd);
+       callout_init(&sc->sc_callout);
 
 #if 1  /* test */
        /*
@@ -675,14 +675,10 @@
 
        sc->sc_curcmd = NULL;
        sc->sc_nusedcmds = 0;
-       sc->sc_stat = NJSC32_STAT_IDLE;
 
        sc->sc_sync_max = 1;    /* XXX look up EEPROM configuration? */
 
-       /* initialize target structure */
-       njsc32_init_targets(sc);
-
-       /* initialize hardware */
+       /* initialize hardware and target structure */
        njsc32_init(sc, cold);
 
        /* setup adapter */
@@ -713,6 +709,8 @@
        int i, s;
        struct njsc32_cmd *cmd;
 
+       callout_stop(&sc->sc_callout);
+
        s = splbio();
 
        /* clear running/disconnected commands */
@@ -1334,6 +1332,53 @@
        minphys(bp);
 }
 
+/*
+ * On some versions of 32UDE (probably the earlier ones), the controller
+ * detects continuous bus reset when the termination power is absent.
+ * Make sure the system won't hang on such situation.
+ */
+static void
+njsc32_wait_reset_release(void *arg)
+{
+       struct njsc32_softc *sc = arg;
+       struct njsc32_cmd *cmd;
+
+       /* clear pending commands */
+       while ((cmd = TAILQ_FIRST(&sc->sc_reqcmd)) != NULL) {
+               TAILQ_REMOVE(&sc->sc_reqcmd, cmd, c_q);
+               njsc32_end_cmd(sc, cmd, XS_RESET);
+       }
+
+       /* If Bus Reset is not released yet, schedule recheck. */
+       if (njsc32_read_2(sc, NJSC32_REG_IRQ) & NJSC32_IRQ_SCSIRESET) {
+               switch (sc->sc_stat) {
+               case NJSC32_STAT_RESET:
+                       sc->sc_stat = NJSC32_STAT_RESET1;
+                       break;
+               case NJSC32_STAT_RESET1:
+                       /* print message if Bus Reset is detected twice */
+                       sc->sc_stat = NJSC32_STAT_RESET2;
+                       printf("%s: detected excessive bus reset --- missing termination power?\n",
+                           sc->sc_dev.dv_xname);
+                       break;
+               default:
+                       break;
+               }
+               callout_reset(&sc->sc_callout,
+                   hz * 2      /* poll every 2s */,
+                   njsc32_wait_reset_release, sc);
+               return;
+       }
+
+       if (sc->sc_stat == NJSC32_STAT_RESET2)
+               printf("%s: bus reset is released\n", sc->sc_dev.dv_xname);
+
+       /* unblock interrupts */
+       njsc32_write_2(sc, NJSC32_REG_IRQ, 0);
+
+       sc->sc_stat = NJSC32_STAT_IDLE;
+}
+
 static void
 njsc32_reset_bus(struct njsc32_softc *sc)
 {
@@ -1341,15 +1386,29 @@
 
        DPRINTF(("%s: njsc32_reset_bus:\n", sc->sc_dev.dv_xname));
 
-       /* SCSI bus reset */
+       /* block interrupts */
+       njsc32_write_2(sc, NJSC32_REG_IRQ, NJSC32_IRQ_MASK_ALL);
+
+       sc->sc_stat = NJSC32_STAT_RESET;
+
+       /* hold SCSI bus reset */
        njsc32_write_1(sc, NJSC32_REG_SCSI_BUS_CONTROL, NJSC32_SBCTL_RST);
        delay(NJSC32_RESET_HOLD_TIME);
-       njsc32_write_1(sc, NJSC32_REG_SCSI_BUS_CONTROL, 0);
 
        /* clear transfer */
+       njsc32_clear_cmds(sc, XS_RESET);
+
+       /* initialize target structure */
+       njsc32_init_targets(sc);
+
        s = splbio();
-       njsc32_reset_detected(sc);
+       scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_RESET, NULL);
        splx(s);
+
+       /* release SCSI bus reset */
+       njsc32_write_1(sc, NJSC32_REG_SCSI_BUS_CONTROL, 0);
+
+       njsc32_wait_reset_release(sc);
 }
 
 /*
@@ -1387,17 +1446,6 @@
        }
 }
 
-static void
-njsc32_reset_detected(struct njsc32_softc *sc)
-{
-
-       njsc32_clear_cmds(sc, XS_RESET);
-       njsc32_init_targets(sc);
-       sc->sc_stat = NJSC32_STAT_IDLE;
-       KASSERT(sc->sc_nusedcmds == 0);
-       scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_RESET, NULL);
-}
-
 static int
 njsc32_scsipi_ioctl(struct scsipi_channel *chan, u_long cmd, caddr_t addr,
     int flag, struct proc *p)
@@ -2331,8 +2379,8 @@
 
        if (intr & NJSC32_IRQ_SCSIRESET) {
                printf("%s: detected bus reset\n", sc->sc_dev.dv_xname);
-               /* clear current request */
-               njsc32_reset_detected(sc);
+               /* make sure all devices on the bus are certainly reset  */
+               njsc32_reset_bus(sc);
                goto out;
        }
 
@@ -2386,8 +2434,8 @@
 
                idbit = njsc32_read_1(sc, NJSC32_REG_RESELECT_ID);
                if ((idbit & (1 << NJSC32_INITIATOR_ID)) == 0 ||
-                   (sc->sc_reselid = ffs(idbit & ~NJSC32_INITIATOR_ID) -1)
-                   < 0) {
+                   (sc->sc_reselid =
+                    ffs(idbit & ~(1 << NJSC32_INITIATOR_ID)) - 1) < 0) {
                        printf("%s: invalid reselection (id: %#x)\n",
                            sc->sc_dev.dv_xname, idbit);
                        sc->sc_stat = NJSC32_STAT_IDLE; /* XXX ? */
diff -r 3d8f66dd5c10 -r 35ab8534efba sys/dev/ic/ninjascsi32var.h
--- a/sys/dev/ic/ninjascsi32var.h       Mon Nov 19 20:35:42 2007 +0000
+++ b/sys/dev/ic/ninjascsi32var.h       Mon Nov 19 20:40:03 2007 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: ninjascsi32var.h,v 1.2.2.3 2004/08/30 09:54:17 tron Exp $      */
+/*     $NetBSD: ninjascsi32var.h,v 1.2.2.3.2.1 2007/11/19 20:40:03 bouyer Exp $        */
 
 /*-
- * Copyright (c) 2004 The NetBSD Foundation, Inc.
+ * Copyright (c) 2004, 2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -54,17 +54,17 @@
 
 /* in microseconds */
 #define NJSC32_REQ_TIMEOUT             10000   /* 10ms */
-#define NJSC32_RESET_HOLD_TIME         30      /* 25us min */
+#define NJSC32_RESET_HOLD_TIME         26      /* 25us min */
 
 /*
  * DMA page
  */
 #ifdef NJSC32_AUTOPARAM
-#define NJSC32_NUM_CMD 15      /* # simultaneous commands */
+#define NJSC32_NUM_CMD 14      /* # simultaneous commands */
 #else
-#define NJSC32_NUM_CMD 16      /* # simultaneous commands */
+#define NJSC32_NUM_CMD 15      /* # simultaneous commands */
 #endif
-#define NJSC32_NUM_SG  16      /* # scatter/gather table entries per command */
+#define NJSC32_NUM_SG  17      /* # scatter/gather table entries per command */
 
 struct njsc32_dma_page {
        /*
@@ -121,8 +121,8 @@
        bus_dmamap_t            c_dmamap_xfer;
 };
 
-/* XXX? */
-#define NJSC32_MAX_XFER        (NJSC32_NUM_SG << PGSHIFT)
+/* -1 for unaligned acccess */
+#define NJSC32_MAX_XFER        ((NJSC32_NUM_SG - 1) << PGSHIFT)
 
 struct njsc32_softc {
        struct device   sc_dev;
@@ -155,6 +155,9 @@
                NJSC32_STAT_RESEL,      /* a target did Reselection */
                NJSC32_STAT_RESEL_LUN,  /* received Identify message */
                NJSC32_STAT_RECONNECT,  /* command is active (reconnection) */
+               NJSC32_STAT_RESET,      /* resetting bus */
+               NJSC32_STAT_RESET1,     /* waiting for bus reset release */
+               NJSC32_STAT_RESET2,     /* waiting for bus reset release */
                NJSC32_STAT_DETACH      /* detaching */
        } sc_stat;
 
@@ -175,6 +178,9 @@
        u_int32_t               sc_ap_dma;      /* autoparam DMA address */
 #endif
 
+       /* for monitoring bus reset */
+       struct callout          sc_callout;
+
        /*
         * command control structure
         */



Home | Main Index | Thread Index | Old Index