diff options
-rw-r--r-- | sys/dev/ic/ami.c | 271 | ||||
-rw-r--r-- | sys/dev/ic/amivar.h | 10 |
2 files changed, 95 insertions, 186 deletions
diff --git a/sys/dev/ic/ami.c b/sys/dev/ic/ami.c index 614df98ce38..3038dc6ae72 100644 --- a/sys/dev/ic/ami.c +++ b/sys/dev/ic/ami.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ami.c,v 1.207 2010/06/21 11:43:38 dlg Exp $ */ +/* $OpenBSD: ami.c,v 1.208 2010/06/23 03:46:25 dlg Exp $ */ /* * Copyright (c) 2001 Michael Shalayeff @@ -114,8 +114,6 @@ struct scsi_device ami_raw_dev = { NULL, NULL, NULL, NULL }; -void ami_remove_runq(struct ami_ccb *); -void ami_insert_runq(struct ami_ccb *); struct ami_ccb *ami_get_ccb(struct ami_softc *); void ami_put_ccb(struct ami_softc *, struct ami_ccb *); @@ -131,7 +129,6 @@ int ami_alloc_ccbs(struct ami_softc *, int); int ami_poll(struct ami_softc *, struct ami_ccb *); void ami_start(struct ami_softc *, struct ami_ccb *); void ami_complete(struct ami_softc *, struct ami_ccb *, int); -int ami_done(struct ami_softc *, int, int); void ami_runqueue_tick(void *); void ami_runqueue(struct ami_softc *); @@ -141,7 +138,6 @@ void ami_done_xs(struct ami_softc *, struct ami_ccb *); void ami_done_pt(struct ami_softc *, struct ami_ccb *); void ami_done_flush(struct ami_softc *, struct ami_ccb *); void ami_done_sysflush(struct ami_softc *, struct ami_ccb *); -void ami_stimeout(void *); void ami_done_dummy(struct ami_softc *, struct ami_ccb *); void ami_done_ioctl(struct ami_softc *, struct ami_ccb *); @@ -180,24 +176,6 @@ void ami_refresh_sensors(void *); #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) -void -ami_remove_runq(struct ami_ccb *ccb) -{ - splassert(IPL_BIO); - - TAILQ_REMOVE(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link); - if (ccb->ccb_sc->sc_drainio && TAILQ_EMPTY(&ccb->ccb_sc->sc_ccb_runq)) - wakeup(ccb->ccb_sc); -} - -void -ami_insert_runq(struct ami_ccb *ccb) -{ - splassert(IPL_BIO); - - TAILQ_INSERT_TAIL(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link); -} - struct ami_ccb * ami_get_ccb(struct ami_softc *sc) { @@ -404,7 +382,8 @@ ami_attach(struct ami_softc *sc) struct ami_fc_prodinfo *pi; const char *p; paddr_t pa; - int s; + + mtx_init(&sc->sc_cmd_mtx, IPL_BIO); am = ami_allocmem(sc, NBPG); if (am == NULL) { @@ -431,8 +410,6 @@ ami_attach(struct ami_softc *sc) (sc->sc_init)(sc); - s = splbio(); - /* try FC inquiry first */ cmd->acc_cmd = AMI_FCOP; cmd->acc_io.aio_channel = AMI_FC_EINQ3; @@ -479,7 +456,6 @@ ami_attach(struct ami_softc *sc) cmd->acc_io.aio_param = 0; cmd->acc_io.aio_data = pa; if (ami_poll(sc, &iccb) != 0) { - splx(s); printf(": cannot do inquiry\n"); goto free_mbox; } @@ -525,8 +501,6 @@ ami_attach(struct ami_softc *sc) sc->sc_link.openings = sc->sc_maxcmds; } - splx(s); - ami_freemem(sc, am); if (ami_alloc_ccbs(sc, AMI_MAXCMDS + 1) != 0) { @@ -962,76 +936,66 @@ ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox) void ami_start_xs(struct ami_softc *sc, struct ami_ccb *ccb, struct scsi_xfer *xs) { - timeout_set(&xs->stimeout, ami_stimeout, ccb); - - if (xs->flags & SCSI_POLL) { + if (xs->flags & SCSI_POLL) ami_complete(sc, ccb, xs->timeout); - return; - } - - /* XXX way wrong, this timeout needs to be set later */ - timeout_add_sec(&xs->stimeout, 61); - ami_start(sc, ccb); + else + ami_start(sc, ccb); } void ami_start(struct ami_softc *sc, struct ami_ccb *ccb) { - int s; - - s = splbio(); + mtx_enter(&sc->sc_cmd_mtx); ccb->ccb_state = AMI_CCB_PREQUEUED; TAILQ_INSERT_TAIL(&sc->sc_ccb_preq, ccb, ccb_link); + mtx_leave(&sc->sc_cmd_mtx); + ami_runqueue(sc); - splx(s); } void ami_runqueue_tick(void *arg) { - struct ami_softc *sc = arg; - int s; - - s = splbio(); - ami_runqueue(sc); - splx(s); + ami_runqueue(arg); } void ami_runqueue(struct ami_softc *sc) { struct ami_ccb *ccb; + int add = 0; - splassert(IPL_BIO); - - if (sc->sc_drainio) - return; + mtx_enter(&sc->sc_cmd_mtx); + if (!sc->sc_drainio) { + while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) { + if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) { + add = 1; + break; + } - while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) { - if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) { - timeout_add(&sc->sc_run_tmo, 1); - break; + TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link); + ccb->ccb_state = AMI_CCB_QUEUED; + TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link); } - - TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link); - ccb->ccb_state = AMI_CCB_QUEUED; - ami_insert_runq(ccb); } + mtx_leave(&sc->sc_cmd_mtx); + + if (add) + timeout_add(&sc->sc_run_tmo, 1); } int ami_poll(struct ami_softc *sc, struct ami_ccb *ccb) { int error; - int s; - s = splbio(); + mtx_enter(&sc->sc_cmd_mtx); error = sc->sc_poll(sc, &ccb->ccb_cmd); if (error == -1) ccb->ccb_flags |= AMI_CCB_F_ERR; + mtx_leave(&sc->sc_cmd_mtx); ccb->ccb_done(sc, ccb); - splx(s); return (error); } @@ -1039,27 +1003,36 @@ ami_poll(struct ami_softc *sc, struct ami_ccb *ccb) void ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout) { - struct ami_iocmd mbox; - int i = 0, j, done = 0; - int s, ready; + void (*done)(struct ami_softc *, struct ami_ccb *); + int ready; + int i; + int s; - s = splbio(); + done = ccb->ccb_done; + ccb->ccb_done = ami_done_dummy; /* * since exec will return if the mbox is busy we have to busy wait * ourselves. once its in, jam it into the runq. */ + mtx_enter(&sc->sc_cmd_mtx); while (i < AMI_MAX_BUSYWAIT) { if (sc->sc_exec(sc, &ccb->ccb_cmd) == 0) { ccb->ccb_state = AMI_CCB_QUEUED; - ami_insert_runq(ccb); + TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link); break; } DELAY(1000); i++; } - if (ccb->ccb_state != AMI_CCB_QUEUED) - goto err; + ready = (ccb->ccb_state == AMI_CCB_QUEUED); + mtx_leave(&sc->sc_cmd_mtx); + + if (!ready) { + ccb->ccb_flags |= AMI_CCB_F_ERR; + ccb->ccb_state = AMI_CCB_READY; + goto done; + } /* * Override timeout for PERC3. The first command triggers a chip @@ -1068,97 +1041,27 @@ ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout) * firmware to be up again. After the first two commands the * timeouts are as expected. */ - i = 0; - while (i < 30000 /* timeout */) { - if (sc->sc_done(sc, &mbox) != 0) { - for (j = 0; j < mbox.acc_nstat; j++) { - ready = mbox.acc_cmplidl[j]; - ami_done(sc, ready, mbox.acc_status); - if (ready == ccb->ccb_cmd.acc_id) - done = 1; - } - if (done) - break; - } + timeout = MAX(30000, timeout); /* timeout */ - DELAY(1000); - i++; - } - if (!done) { - printf("%s: timeout ccb %d\n", DEVNAME(sc), - ccb->ccb_cmd.acc_id); - ami_remove_runq(ccb); - goto err; - } - - /* start the runqueue again */ - ami_runqueue(sc); - - splx(s); - - return; - -err: - ccb->ccb_flags |= AMI_CCB_F_ERR; - ccb->ccb_state = AMI_CCB_READY; - ccb->ccb_done(sc, ccb); - splx(s); -} - -void -ami_stimeout(void *v) -{ - struct ami_ccb *ccb = v; - struct ami_softc *sc = ccb->ccb_sc; - struct ami_iocmd *cmd = &ccb->ccb_cmd; - int s; - - s = splbio(); - switch (ccb->ccb_state) { - case AMI_CCB_PREQUEUED: - /* command never ran, cleanup is easy */ - TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link); - ccb->ccb_flags |= AMI_CCB_F_ERR; - ccb->ccb_done(sc, ccb); - break; - - case AMI_CCB_QUEUED: - /* - * ccb has taken more than a minute to finish. we can't take - * it off the hardware in case it finishes later, but we can - * warn the user to look at what is happening. - */ - AMI_DPRINTF(AMI_D_CMD, ("%s: stimeout ccb %d, check volume " - "state\n", DEVNAME(sc), cmd->acc_id)); - break; - - default: - panic("%s: ami_stimeout(%d) botch", DEVNAME(sc), cmd->acc_id); - } - - splx(s); -} - -int -ami_done(struct ami_softc *sc, int idx, int status) -{ - struct ami_ccb *ccb = &sc->sc_ccbs[idx - 1]; - - AMI_DPRINTF(AMI_D_CMD, ("done(%d) ", ccb->ccb_cmd.acc_id)); + while (ccb->ccb_state == AMI_CCB_QUEUED) { + s = splbio(); /* interrupt handlers are called at their IPL */ + ready = ami_intr(sc); + splx(s); + + if (ready == 0) { + if (timeout-- == 0) { + /* XXX */ + printf("%s: timeout\n", DEVNAME(sc)); + return; + } - if (ccb->ccb_state != AMI_CCB_QUEUED) { - printf("%s: unqueued ccb %d ready, state = %d\n", - DEVNAME(sc), idx, ccb->ccb_state); - return (1); + delay(1000); + continue; + } } - ccb->ccb_state = AMI_CCB_READY; - ccb->ccb_status = status; - ami_remove_runq(ccb); - - ccb->ccb_done(sc, ccb); - - return (0); +done: + done(sc, ccb); } void @@ -1182,7 +1085,6 @@ ami_done_pt(struct ami_softc *sc, struct ami_ccb *ccb) bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); } - timeout_del(&xs->stimeout); xs->resid = 0; if (ccb->ccb_flags & AMI_CCB_F_ERR) @@ -1220,7 +1122,6 @@ ami_done_xs(struct ami_softc *sc, struct ami_ccb *ccb) bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); } - timeout_del(&xs->stimeout); xs->resid = 0; if (ccb->ccb_flags & AMI_CCB_F_ERR) @@ -1236,7 +1137,6 @@ ami_done_flush(struct ami_softc *sc, struct ami_ccb *ccb) struct scsi_xfer *xs = ccb->ccb_xs; struct ami_iocmd *cmd = &ccb->ccb_cmd; - timeout_del(&xs->stimeout); if (ccb->ccb_flags & AMI_CCB_F_ERR) { xs->error = XS_DRIVER_STUFFUP; xs->resid = 0; @@ -1258,7 +1158,6 @@ ami_done_sysflush(struct ami_softc *sc, struct ami_ccb *ccb) { struct scsi_xfer *xs = ccb->ccb_xs; - timeout_del(&xs->stimeout); xs->resid = 0; if (ccb->ccb_flags & AMI_CCB_F_ERR) xs->error = XS_DRIVER_STUFFUP; @@ -1627,28 +1526,36 @@ ami_scsi_cmd(struct scsi_xfer *xs) int ami_intr(void *v) { - struct ami_softc *sc = v; struct ami_iocmd mbox; + struct ami_softc *sc = v; + struct ami_ccb *ccb; int i, rv = 0, ready; - splassert(IPL_BIO); - - if (TAILQ_EMPTY(&sc->sc_ccb_runq)) - return (0); - - AMI_DPRINTF(AMI_D_INTR, ("intr ")); - - while ((sc->sc_done)(sc, &mbox)) { + mtx_enter(&sc->sc_cmd_mtx); + while (!TAILQ_EMPTY(&sc->sc_ccb_runq) && sc->sc_done(sc, &mbox)) { AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat)); for (i = 0; i < mbox.acc_nstat; i++ ) { - ready = mbox.acc_cmplidl[i]; + ready = mbox.acc_cmplidl[i] - 1; AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready)); - if (!ami_done(sc, ready, mbox.acc_status)) - rv |= 1; + + ccb = &sc->sc_ccbs[ready]; + ccb->ccb_status = mbox.acc_status; + ccb->ccb_state = AMI_CCB_READY; + TAILQ_REMOVE(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link); + + mtx_leave(&sc->sc_cmd_mtx); + ccb->ccb_done(sc, ccb); + mtx_enter(&sc->sc_cmd_mtx); + + rv = 1; } } + ready = (sc->sc_drainio && TAILQ_EMPTY(&sc->sc_ccb_runq)); + mtx_leave(&sc->sc_cmd_mtx); - if (rv) + if (ready) + wakeup(sc); + else if (rv) ami_runqueue(sc); AMI_DPRINTF(AMI_D_INTR, ("exit ")); @@ -1856,7 +1763,7 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2, struct ami_iocmd *cmd; struct ami_mem *am = NULL; char *idata = NULL; - int s, error = 0; + int error = 0; rw_enter_write(&sc->sc_lock); @@ -1900,17 +1807,17 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2, if (opcode != AMI_CHSTATE) { ami_start(sc, ccb); - s = splbio(); + mtx_enter(&sc->sc_cmd_mtx); while (ccb->ccb_state != AMI_CCB_READY) - tsleep(ccb, PRIBIO,"ami_mgmt", 0); - splx(s); + msleep(ccb, &sc->sc_cmd_mtx, PRIBIO,"ami_mgmt", 0); + mtx_leave(&sc->sc_cmd_mtx); } else { /* change state must be run with id 0xfe and MUST be polled */ - s = splbio(); + mtx_enter(&sc->sc_cmd_mtx); sc->sc_drainio = 1; while (!TAILQ_EMPTY(&sc->sc_ccb_runq)) { - if (tsleep(sc, PRIBIO, "ami_mgmt_drain", hz * 60) == - EWOULDBLOCK) { + if (msleep(sc, &sc->sc_cmd_mtx, PRIBIO, + "amimgmt", hz * 60) == EWOULDBLOCK) { printf("%s: drain io timeout\n", DEVNAME(sc)); ccb->ccb_flags |= AMI_CCB_F_ERR; goto restartio; @@ -1924,8 +1831,8 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2, restartio: /* restart io */ sc->sc_drainio = 0; + mtx_leave(&sc->sc_cmd_mtx); ami_runqueue(sc); - splx(s); } if (ccb->ccb_flags & AMI_CCB_F_ERR) diff --git a/sys/dev/ic/amivar.h b/sys/dev/ic/amivar.h index f7a531dbc5c..2fb3e8f8843 100644 --- a/sys/dev/ic/amivar.h +++ b/sys/dev/ic/amivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: amivar.h,v 1.56 2010/06/21 11:43:38 dlg Exp $ */ +/* $OpenBSD: amivar.h,v 1.57 2010/06/23 03:46:25 dlg Exp $ */ /* * Copyright (c) 2001 Michael Shalayeff @@ -107,14 +107,16 @@ struct ami_softc { bus_space_handle_t sc_ioh; bus_dma_tag_t sc_dmat; + struct ami_ccb *sc_ccbs; + struct ami_ccb_list sc_ccb_freeq; + struct mutex sc_ccb_freeq_mtx; + struct ami_mem *sc_mbox_am; volatile struct ami_iocmd *sc_mbox; paddr_t sc_mbox_pa; - struct ami_ccb *sc_ccbs; - struct ami_ccb_list sc_ccb_freeq; - struct mutex sc_ccb_freeq_mtx; struct ami_ccb_list sc_ccb_preq, sc_ccb_runq; + struct mutex sc_cmd_mtx; struct ami_mem *sc_ccbmem_am; |