if you have a twe, let me first say how sorry i am for you. this cuts twe over to using iopools. it gets the usual benefits of more reliable ioctl paths, better io scheduling between volumes and the pt busses, and a removal of NO_CCB.
it is a bit more than a straight conversion, it also moves the draining of the async event notification over to iohandlers. this simplifies them a bit and makes them reliable when the controller is under load. i dont have an twe, so i cant test this. id like more than an ok from gcc before committing this. Index: twe.c =================================================================== RCS file: /cvs/src/sys/dev/ic/twe.c,v retrieving revision 1.38 diff -u -p -r1.38 twe.c --- twe.c 20 Sep 2010 06:17:49 -0000 1.38 +++ twe.c 3 Apr 2011 14:23:55 -0000 @@ -70,8 +70,8 @@ struct scsi_adapter twe_switch = { twe_scsi_cmd, tweminphys, 0, 0, }; -static __inline struct twe_ccb *twe_get_ccb(struct twe_softc *sc); -static __inline void twe_put_ccb(struct twe_ccb *ccb); +void *twe_get_ccb(void *); +void twe_put_ccb(void *, void *); void twe_dispose(struct twe_softc *sc); int twe_cmd(struct twe_ccb *ccb, int flags, int wait); int twe_start(struct twe_ccb *ccb, int wait); @@ -80,28 +80,33 @@ int twe_done(struct twe_softc *sc, stru void twe_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size); void twe_thread_create(void *v); void twe_thread(void *v); +void twe_aen(void *, void *); - -static __inline struct twe_ccb * -twe_get_ccb(sc) - struct twe_softc *sc; +void * +twe_get_ccb(void *xsc) { + struct twe_softc *sc = xsc; struct twe_ccb *ccb; + mtx_enter(&sc->sc_ccb_mtx); ccb = TAILQ_LAST(&sc->sc_free_ccb, twe_queue_head); - if (ccb) + if (ccb != NULL) TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_link); - return ccb; + mtx_leave(&sc->sc_ccb_mtx); + + return (ccb); } -static __inline void -twe_put_ccb(ccb) - struct twe_ccb *ccb; +void +twe_put_ccb(void *xsc, void *xccb) { - struct twe_softc *sc = ccb->ccb_sc; + struct twe_softc *sc = xsc; + struct twe_ccb *ccb = xccb; ccb->ccb_state = TWE_CCB_FREE; + mtx_enter(&sc->sc_ccb_mtx); TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link); + mtx_leave(&sc->sc_ccb_mtx); } void @@ -176,6 +181,10 @@ twe_attach(sc) TAILQ_INIT(&sc->sc_ccbq); TAILQ_INIT(&sc->sc_free_ccb); TAILQ_INIT(&sc->sc_done_ccb); + mtx_init(&sc->sc_ccb_mtx, IPL_BIO); + scsi_iopool_init(&sc->sc_iopool, sc, twe_get_ccb, twe_put_ccb); + + scsi_ioh_set(&sc->sc_aen, &sc->sc_iopool, twe_aen, sc); pa = sc->sc_cmdmap->dm_segs[0].ds_addr + sizeof(struct twe_cmd) * (TWE_MAXCMDS - 1); @@ -238,9 +247,10 @@ twe_attach(sc) /* drain aen queue */ for (veseen_srst = 0, aen = -1; aen != TWE_AEN_QEMPTY; ) { - if ((ccb = twe_get_ccb(sc)) == NULL) { + ccb = scsi_io_get(&sc->sc_iopool, 0); + if (ccb == NULL) { errstr = ": out of ccbs\n"; - continue; + break; } ccb->ccb_xs = NULL; @@ -256,10 +266,13 @@ twe_attach(sc) pb->param_id = 2; pb->param_size = 2; - if (twe_cmd(ccb, BUS_DMA_NOWAIT, 1)) { + error = twe_cmd(ccb, BUS_DMA_NOWAIT, 1); + scsi_io_put(&sc->sc_iopool, ccb); + if (error) { errstr = ": error draining attention queue\n"; break; } + aen = *(u_int16_t *)pb->data; TWE_DPRINTF(TWE_D_AEN, ("aen=%x ", aen)); if (aen == TWE_AEN_SRST) @@ -305,7 +318,8 @@ twe_attach(sc) return 1; } - if ((ccb = twe_get_ccb(sc)) == NULL) { + ccb = scsi_io_get(&sc->sc_iopool, 0); + if (ccb == NULL) { printf(": out of ccbs\n"); twe_dispose(sc); return 1; @@ -323,7 +337,10 @@ twe_attach(sc) pb->table_id = TWE_PARAM_UC; pb->param_id = TWE_PARAM_UC; pb->param_size = TWE_MAX_UNITS; - if (twe_cmd(ccb, BUS_DMA_NOWAIT, 1)) { + + error = twe_cmd(ccb, BUS_DMA_NOWAIT, 1); + scsi_io_put(&sc->sc_iopool, ccb); + if (error) { printf(": failed to fetch unit parameters\n"); twe_dispose(sc); return 1; @@ -336,7 +353,8 @@ twe_attach(sc) if (pb->data[i] == 0) continue; - if ((ccb = twe_get_ccb(sc)) == NULL) { + ccb = scsi_io_get(&sc->sc_iopool, 0); + if (ccb == NULL) { printf(": out of ccbs\n"); twe_dispose(sc); return 1; @@ -354,14 +372,16 @@ twe_attach(sc) cap->table_id = TWE_PARAM_UI + i; cap->param_id = 4; cap->param_size = 4; /* 4 bytes */ + lock = TWE_LOCK(sc); - if (twe_cmd(ccb, BUS_DMA_NOWAIT, 1)) { - TWE_UNLOCK(sc, lock); + twe_cmd(ccb, BUS_DMA_NOWAIT, 1); + TWE_UNLOCK(sc, lock); + scsi_io_put(&sc->sc_iopool, ccb); + if (error) { printf("%s: error fetching capacity for unit %d\n", sc->sc_dev.dv_xname, i); continue; } - TWE_UNLOCK(sc, lock); nunits++; sc->sc_hdr[i].hd_present = 1; @@ -381,6 +401,7 @@ twe_attach(sc) sc->sc_link.adapter_target = TWE_MAX_UNITS; sc->sc_link.openings = TWE_MAXCMDS / nunits; sc->sc_link.adapter_buswidth = TWE_MAX_UNITS; + sc->sc_link.pool = &sc->sc_iopool; bzero(&saa, sizeof(saa)); saa.saa_sc_link = &sc->sc_link; @@ -493,7 +514,6 @@ twe_cmd(ccb, flags, wait) BUS_DMA_NOWAIT); if (error) { TWE_DPRINTF(TWE_D_DMA, ("2buf alloc failed(%d) ", error)); - twe_put_ccb(ccb); return (ENOMEM); } @@ -502,7 +522,6 @@ twe_cmd(ccb, flags, wait) if (error) { TWE_DPRINTF(TWE_D_DMA, ("2buf map failed(%d) ", error)); bus_dmamem_free(sc->dmat, ccb->ccb_2bseg, ccb->ccb_2nseg); - twe_put_ccb(ccb); return (ENOMEM); } bcopy(ccb->ccb_realdata, ccb->ccb_data, ccb->ccb_length); @@ -528,7 +547,6 @@ twe_cmd(ccb, flags, wait) bus_dmamem_free(sc->dmat, ccb->ccb_2bseg, ccb->ccb_2nseg); } - twe_put_ccb(ccb); return error; } /* load addresses into command */ @@ -579,7 +597,6 @@ twe_cmd(ccb, flags, wait) bus_dmamem_free(sc->dmat, ccb->ccb_2bseg, ccb->ccb_2nseg); } - twe_put_ccb(ccb); return (error); } @@ -728,7 +745,6 @@ twe_done(sc, ccb) } lock = TWE_LOCK(sc); - twe_put_ccb(ccb); if (xs) { xs->resid = 0; @@ -771,7 +787,7 @@ twe_scsi_cmd(xs) { struct scsi_link *link = xs->sc_link; struct twe_softc *sc = link->adapter_softc; - struct twe_ccb *ccb; + struct twe_ccb *ccb = xs->io; struct twe_cmd *cmd; struct scsi_inquiry_data inq; struct scsi_sense_data sd; @@ -893,13 +909,6 @@ twe_scsi_cmd(xs) default: op = TWE_CMD_NOP; break; } - if ((ccb = twe_get_ccb(sc)) == NULL) { - xs->error = XS_NO_CCB; - scsi_done(xs); - TWE_UNLOCK(sc, lock); - return; - } - ccb->ccb_xs = xs; ccb->ccb_data = xs->data; ccb->ccb_length = xs->datalen; @@ -940,9 +949,7 @@ twe_intr(v) { struct twe_softc *sc = v; struct twe_ccb *ccb; - struct twe_cmd *cmd; u_int32_t status; - twe_lock_t lock; int rv = 0; status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS); @@ -993,8 +1000,6 @@ twe_intr(v) wakeup(sc); if (status & TWE_STAT_ATTNI) { - u_int16_t aen; - /* * we know no attentions of interest right now. * one of those would be mirror degradation i think. @@ -1004,37 +1009,52 @@ twe_intr(v) bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL, TWE_CTRL_CATTNI); - lock = TWE_LOCK(sc); - for (aen = -1; aen != TWE_AEN_QEMPTY; ) { - u_int8_t param_buf[2 * TWE_SECTOR_SIZE + TWE_ALIGN - 1]; - struct twe_param *pb = (void *) (((u_long)param_buf + - TWE_ALIGN - 1) & ~(TWE_ALIGN - 1)); + scsi_ioh_add(&sc->sc_aen); + } - if ((ccb = twe_get_ccb(sc)) == NULL) - break; + return rv; +} - ccb->ccb_xs = NULL; - ccb->ccb_data = pb; - ccb->ccb_length = TWE_SECTOR_SIZE; - ccb->ccb_state = TWE_CCB_READY; - cmd = ccb->ccb_cmd; - cmd->cmd_unit_host = TWE_UNITHOST(0, 0); - cmd->cmd_op = TWE_CMD_GPARAM; - cmd->cmd_flags = 0; - cmd->cmd_param.count = 1; +void +twe_aen(void *cookie, void *io) +{ + struct twe_softc *sc = cookie; + struct twe_ccb *ccb = io; + struct twe_cmd *cmd = ccb->ccb_cmd; - pb->table_id = TWE_PARAM_AEN; - pb->param_id = 2; - pb->param_size = 2; - if (twe_cmd(ccb, BUS_DMA_NOWAIT, 1)) { - printf(": error draining attention queue\n"); - break; - } - aen = *(u_int16_t *)pb->data; - TWE_DPRINTF(TWE_D_AEN, ("aen=%x ", aen)); - } - TWE_UNLOCK(sc, lock); + u_int8_t param_buf[2 * TWE_SECTOR_SIZE + TWE_ALIGN - 1]; + struct twe_param *pb = (void *) (((u_long)param_buf + + TWE_ALIGN - 1) & ~(TWE_ALIGN - 1)); + u_int16_t aen; + + twe_lock_t lock; + int error; + + ccb->ccb_xs = NULL; + ccb->ccb_data = pb; + ccb->ccb_length = TWE_SECTOR_SIZE; + ccb->ccb_state = TWE_CCB_READY; + cmd->cmd_unit_host = TWE_UNITHOST(0, 0); + cmd->cmd_op = TWE_CMD_GPARAM; + cmd->cmd_flags = 0; + cmd->cmd_param.count = 1; + + pb->table_id = TWE_PARAM_AEN; + pb->param_id = 2; + pb->param_size = 2; + + lock = TWE_LOCK(sc); + error = twe_cmd(ccb, BUS_DMA_NOWAIT, 1); + TWE_UNLOCK(sc, lock); + scsi_io_put(&sc->sc_iopool, ccb); + + if (error) { + printf("%s: error draining attention queue\n", + sc->sc_dev.dv_xname); + return; } - return rv; + aen = *(u_int16_t *)pb->data; + if (aen != TWE_AEN_QEMPTY) + scsi_ioh_add(&sc->sc_aen); } Index: twevar.h =================================================================== RCS file: /cvs/src/sys/dev/ic/twevar.h,v retrieving revision 1.9 diff -u -p -r1.9 twevar.h --- twevar.h 16 Feb 2009 21:19:07 -0000 1.9 +++ twevar.h 3 Apr 2011 14:23:55 -0000 @@ -67,8 +67,12 @@ struct twe_softc { twe_queue_head sc_ccbq; twe_queue_head sc_ccb2q; twe_queue_head sc_done_ccb; + struct mutex sc_ccb_mtx; + struct scsi_iopool sc_iopool; struct timeout sc_enqueue_tmo; + + struct scsi_iohandler sc_aen; struct { int hd_present;