This has been posted a few times with no feedback I can remember. This is a last chance to test before you become involuntary testers! It will be committed very soon, with c2k11 on the horizon to deal with any fallout.
.... Ken Index: ic/cac.c =================================================================== RCS file: /cvs/src/sys/dev/ic/cac.c,v retrieving revision 1.42 diff -u -p -r1.42 cac.c --- ic/cac.c 12 Oct 2010 00:53:32 -0000 1.42 +++ ic/cac.c 13 Oct 2010 11:09:09 -0000 @@ -103,9 +103,9 @@ struct scsi_adapter cac_switch = { cac_scsi_cmd, cacminphys, 0, 0, }; -struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int); +void *cac_ccb_alloc(void *); void cac_ccb_done(struct cac_softc *, struct cac_ccb *); -void cac_ccb_free(struct cac_softc *, struct cac_ccb *); +void cac_ccb_free(void *, void *); int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int); int cac_ccb_start(struct cac_softc *, struct cac_ccb *); int cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, @@ -156,6 +156,8 @@ cac_init(struct cac_softc *sc, int start SIMPLEQ_INIT(&sc->sc_ccb_free); SIMPLEQ_INIT(&sc->sc_ccb_queue); + mtx_init(&sc->sc_ccb_mtx, IPL_BIO); + scsi_iopool_init(&sc->sc_iopool, sc, cac_ccb_alloc, cac_ccb_free); size = sizeof(struct cac_ccb) * CAC_MAX_CCBS; @@ -204,7 +206,9 @@ cac_init(struct cac_softc *sc, int start } ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb); + mtx_enter(&sc->sc_ccb_mtx); SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain); + mtx_leave(&sc->sc_ccb_mtx); } /* Start firmware background tasks, if needed. */ @@ -245,6 +249,7 @@ cac_init(struct cac_softc *sc, int start sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits; if (sc->sc_link.openings < 4 ) sc->sc_link.openings = 4; + sc->sc_link.pool = &sc->sc_iopool; bzero(&saa, sizeof(saa)); saa.saa_sc_link = &sc->sc_link; @@ -344,11 +349,18 @@ cac_cmd(struct cac_softc *sc, int comman command, drive, blkno, data, datasize, flags, xs); #endif - if ((ccb = cac_ccb_alloc(sc, 0)) == NULL) { -#ifdef CAC_DEBUG - printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname); -#endif - return (ENOMEM); + if (xs) { + ccb = xs->io; + /* + * The xs may have been restarted by the scsi layer, so + * ensure the ccb starts in the proper state. + */ + ccb->ccb_flags = 0; + } else { + /* Internal command. Need to get our own ccb. */ + ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL | SCSI_NOSLEEP); + if (ccb == NULL) + return (EBUSY); } if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { @@ -396,11 +408,9 @@ cac_cmd(struct cac_softc *sc, int comman ccb->ccb_xs = xs; if (!xs || xs->flags & SCSI_POLL) { - /* Synchronous commands musn't wait. */ if ((*sc->sc_cl->cl_fifo_full)(sc)) { - cac_ccb_free(sc, ccb); - rv = ENOMEM; /* Causes XS_NO_CCB, i/o is retried. */ + rv = EBUSY; } else { ccb->ccb_flags |= CAC_CCB_ACTIVE; (*sc->sc_cl->cl_submit)(sc, ccb); @@ -409,6 +419,9 @@ cac_cmd(struct cac_softc *sc, int comman } else rv = cac_ccb_start(sc, ccb); + if (xs == NULL) + scsi_io_put(&sc->sc_iopool, ccb); + return (rv); } @@ -419,8 +432,9 @@ int cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo) { struct cac_ccb *ccb; - int s, t = timo * 100; + int t; + t = timo * 100; do { for (; t--; DELAY(10)) if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) @@ -429,9 +443,7 @@ cac_ccb_poll(struct cac_softc *sc, struc printf("%s: timeout\n", sc->sc_dv.dv_xname); return (EBUSY); } - s = splbio(); cac_ccb_done(sc, ccb); - splx(s); } while (ccb != wantccb); return (0); @@ -439,17 +451,27 @@ cac_ccb_poll(struct cac_softc *sc, struc /* * Enqueue the specified command (if any) and attempt to start all enqueued - * commands. Must be called at splbio. + * commands. */ int cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb) { - if (ccb != NULL) + if (ccb != NULL) { + mtx_enter(&sc->sc_ccb_mtx); SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain); + mtx_leave(&sc->sc_ccb_mtx); + } - while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL && - !(*sc->sc_cl->cl_fifo_full)(sc)) { + while (!(*sc->sc_cl->cl_fifo_full)(sc)) { + mtx_enter(&sc->sc_ccb_mtx); + if (SIMPLEQ_EMPTY(&sc->sc_ccb_queue)) { + mtx_leave(&sc->sc_ccb_mtx); + break; + } + ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue); SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain); + mtx_leave(&sc->sc_ccb_mtx); + ccb->ccb_flags |= CAC_CCB_ACTIVE; (*sc->sc_cl->cl_submit)(sc, ccb); } @@ -494,7 +516,6 @@ cac_ccb_done(struct cac_softc *sc, struc printf("%s: invalid request\n", sc->sc_dv.dv_xname); } - cac_ccb_free(sc, ccb); if (xs) { if (error) xs->error = XS_DRIVER_STUFFUP; @@ -508,15 +529,24 @@ cac_ccb_done(struct cac_softc *sc, struc /* * Allocate a CCB. */ -struct cac_ccb * -cac_ccb_alloc(struct cac_softc *sc, int nosleep) +void * +cac_ccb_alloc(void *xsc) { - struct cac_ccb *ccb; + struct cac_softc *sc = xsc; + struct cac_ccb *ccb = NULL; - if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) + mtx_enter(&sc->sc_ccb_mtx); + if ((*sc->sc_cl->cl_fifo_full)(sc) || + SIMPLEQ_EMPTY(&sc->sc_ccb_free)) { +#ifdef CAC_DEBUG + printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname); +#endif + } else { + ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free); SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain); - else - ccb = NULL; + } + mtx_leave(&sc->sc_ccb_mtx); + return (ccb); } @@ -524,11 +554,16 @@ cac_ccb_alloc(struct cac_softc *sc, int * Put a CCB onto the freelist. */ void -cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb) +cac_ccb_free(void *xsc, void *xccb) { + struct cac_softc *sc = xsc; + struct cac_ccb *ccb = xccb; ccb->ccb_flags = 0; + + mtx_enter(&sc->sc_ccb_mtx); SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); + mtx_leave(&sc->sc_ccb_mtx); } int @@ -708,18 +743,13 @@ cac_scsi_cmd(xs) poll = xs->flags & SCSI_POLL; if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE, target, blockno, flags, xs))) { - - if (error == ENOMEM || error == EBUSY) { - xs->error = XS_NO_CCB; - scsi_done(xs); - splx(s); - return; - } else { + splx(s); + if (error == EBUSY) + xs->error = XS_BUSY; + else xs->error = XS_DRIVER_STUFFUP; - scsi_done(xs); - splx(s); - return; - } + scsi_done(xs); + return; } splx(s); Index: ic/cacvar.h =================================================================== RCS file: /cvs/src/sys/dev/ic/cacvar.h,v retrieving revision 1.5 diff -u -p -r1.5 cacvar.h --- ic/cacvar.h 29 Oct 2008 21:17:15 -0000 1.5 +++ ic/cacvar.h 23 Sep 2010 05:59:31 -0000 @@ -110,6 +110,9 @@ struct cac_softc { int (*sc_ioctl)(struct device *, u_long, caddr_t); struct ksensor *sc_sensors; struct ksensordev sc_sensordev; + + struct mutex sc_ccb_mtx; /* ccb queue protection */ + struct scsi_iopool sc_iopool; }; /* XXX These have to become spinlocks in case of fine SMP */