diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2010-12-29 03:55:10 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2010-12-29 03:55:10 +0000 |
commit | a111b498918d82e98e3bf5b7897b517c6e45acf6 (patch) | |
tree | 542ffdca10d81d2133e48c45dbd0470f81698ac3 /sys/dev | |
parent | 1dc8ea7c455d8d778b6ba59a7ba7fe85cef5aa6b (diff) |
implement timeouts of scsi commands.
timed out scsi commands get put on a list and an iohandler is
scheduled. that iohandler pulls the timed out scsi command off the
list and issues a task management request to kill all outstanding
io on the target with the timed out io.
all io killed as a result of this request will be returned to the
midlayer with their status set to XS_RESET, which in turn will cause
the midlayer to retry the command. this relies on the previous
commit.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/mpii.c | 87 |
1 files changed, 85 insertions, 2 deletions
diff --git a/sys/dev/pci/mpii.c b/sys/dev/pci/mpii.c index 92abdf11edb..c313a5bdbee 100644 --- a/sys/dev/pci/mpii.c +++ b/sys/dev/pci/mpii.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpii.c,v 1.36 2010/12/29 03:48:30 dlg Exp $ */ +/* $OpenBSD: mpii.c,v 1.37 2010/12/29 03:55:09 dlg Exp $ */ /* * Copyright (c) 2010 Mike Belopuhov <mkb@crypt.org.ru> * Copyright (c) 2009 James Giannoules @@ -1757,7 +1757,8 @@ struct mpii_ccb { volatile enum { MPII_CCB_FREE, MPII_CCB_READY, - MPII_CCB_QUEUED + MPII_CCB_QUEUED, + MPII_CCB_TIMEOUT } ccb_state; void (*ccb_done)(struct mpii_ccb *); @@ -1822,6 +1823,15 @@ struct mpii_softc { struct mpii_ccb_list sc_ccb_free; struct mutex sc_ccb_free_mtx; + struct mutex sc_ccb_mtx; + /* + * this protects the ccb state and list entry + * between mpii_scsi_cmd and scsidone. + */ + + struct mpii_ccb_list sc_ccb_tmos; + struct scsi_iohandler sc_ccb_tmo_handler; + struct scsi_iopool sc_iopool; struct mpii_dmamem *sc_requests; @@ -1894,6 +1904,10 @@ int mpii_alloc_queues(struct mpii_softc *); void mpii_push_reply(struct mpii_softc *, struct mpii_rcb *); void mpii_push_replies(struct mpii_softc *); +void mpii_scsi_cmd_tmo(void *); +void mpii_scsi_cmd_tmo_handler(void *, void *); +void mpii_scsi_cmd_tmo_done(struct mpii_ccb *); + int mpii_alloc_dev(struct mpii_softc *); int mpii_insert_dev(struct mpii_softc *, struct mpii_device *); int mpii_remove_dev(struct mpii_softc *, struct mpii_device *); @@ -4029,7 +4043,11 @@ mpii_alloc_ccbs(struct mpii_softc *sc) int i; SLIST_INIT(&sc->sc_ccb_free); + SLIST_INIT(&sc->sc_ccb_tmos); mtx_init(&sc->sc_ccb_free_mtx, IPL_BIO); + mtx_init(&sc->sc_ccb_mtx, IPL_BIO); + scsi_ioh_set(&sc->sc_ccb_tmo_handler, &sc->sc_iopool, + mpii_scsi_cmd_tmo_handler, sc); sc->sc_ccbs = malloc(sizeof(*ccb) * (sc->sc_request_depth-1), M_DEVBUF, M_NOWAIT | M_ZERO); @@ -4442,6 +4460,7 @@ mpii_scsi_cmd(struct scsi_xfer *xs) DNPRINTF(MPII_D_CMD, "%s: Offset0: 0x%02x\n", DEVNAME(sc), io->sgl_offset0); + timeout_set(&xs->stimeout, mpii_scsi_cmd_tmo, ccb); if (xs->flags & SCSI_POLL) { if (mpii_poll(sc, ccb) != 0) { xs->error = XS_DRIVER_STUFFUP; @@ -4453,10 +4472,66 @@ mpii_scsi_cmd(struct scsi_xfer *xs) DNPRINTF(MPII_D_CMD, "%s: mpii_scsi_cmd(): opcode: %02x " "datalen: %d\n", DEVNAME(sc), xs->cmd->opcode, xs->datalen); + timeout_add_msec(&xs->stimeout, xs->timeout); mpii_start(sc, ccb); } void +mpii_scsi_cmd_tmo(void *xccb) +{ + struct mpii_ccb *ccb = xccb; + struct mpii_softc *sc = ccb->ccb_sc; + + printf("%s: mpii_scsi_cmd_tmo\n", DEVNAME(sc)); + + mtx_enter(&sc->sc_ccb_mtx); + if (ccb->ccb_state == MPII_CCB_QUEUED) { + ccb->ccb_state = MPII_CCB_TIMEOUT; + SLIST_INSERT_HEAD(&sc->sc_ccb_tmos, ccb, ccb_link); + } + mtx_leave(&sc->sc_ccb_mtx); + + scsi_ioh_add(&sc->sc_ccb_tmo_handler); +} + +void +mpii_scsi_cmd_tmo_handler(void *cookie, void *io) +{ + struct mpii_softc *sc = cookie; + struct mpii_ccb *tccb = io; + struct mpii_ccb *ccb; + struct mpii_msg_scsi_task_request *stq; + + mtx_enter(&sc->sc_ccb_mtx); + ccb = SLIST_FIRST(&sc->sc_ccb_tmos); + if (ccb != NULL) { + SLIST_REMOVE_HEAD(&sc->sc_ccb_tmos, ccb_link); + ccb->ccb_state = MPII_CCB_QUEUED; + } + /* should remove any other ccbs for the same dev handle */ + mtx_leave(&sc->sc_ccb_mtx); + + if (ccb == NULL) { + scsi_io_put(&sc->sc_iopool, tccb); + return; + } + + stq = tccb->ccb_cmd; + stq->function = MPII_FUNCTION_SCSI_TASK_MGMT; + stq->task_type = MPII_SCSI_TASK_TARGET_RESET; + stq->dev_handle = htole16(ccb->ccb_dev_handle); + + tccb->ccb_done = mpii_scsi_cmd_tmo_done; + mpii_start(sc, tccb); +} + +void +mpii_scsi_cmd_tmo_done(struct mpii_ccb *tccb) +{ + mpii_scsi_cmd_tmo_handler(tccb->ccb_sc, tccb); +} + +void mpii_scsi_cmd_done(struct mpii_ccb *ccb) { struct mpii_msg_scsi_io_error *sie; @@ -4465,6 +4540,14 @@ mpii_scsi_cmd_done(struct mpii_ccb *ccb) struct mpii_ccb_bundle *mcb = ccb->ccb_cmd; bus_dmamap_t dmap = ccb->ccb_dmamap; + timeout_del(&xs->stimeout); + mtx_enter(&sc->sc_ccb_mtx); + if (ccb->ccb_state == MPII_CCB_TIMEOUT) + SLIST_REMOVE(&sc->sc_ccb_tmos, ccb, mpii_ccb, ccb_link); + + ccb->ccb_state = MPII_CCB_READY; + mtx_leave(&sc->sc_ccb_mtx); + if (xs->datalen != 0) { bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : |