diff options
Diffstat (limited to 'sys/scsi/scsi_base.c')
-rw-r--r-- | sys/scsi/scsi_base.c | 180 |
1 files changed, 148 insertions, 32 deletions
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c index 687c3b04bac..830abeb87ae 100644 --- a/sys/scsi/scsi_base.c +++ b/sys/scsi/scsi_base.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_base.c,v 1.191 2010/08/07 03:50:02 krw Exp $ */ +/* $OpenBSD: scsi_base.c,v 1.192 2010/08/25 00:31:35 dlg Exp $ */ /* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */ /* @@ -92,17 +92,23 @@ int scsi_sem_enter(struct mutex *, u_int *); int scsi_sem_leave(struct mutex *, u_int *); /* ioh/xsh queue state */ -#define RUNQ_IDLE 0 -#define RUNQ_LINKQ 1 -#define RUNQ_POOLQ 2 +#define RUNQ_IDLE 0 +#define RUNQ_LINKQ 1 +#define RUNQ_POOLQ 2 /* synchronous api for allocating an io. */ struct scsi_io_mover { struct mutex mtx; void *io; + u_int done; }; +#define SCSI_IO_MOVER_INITIALIZER { MUTEX_INITIALIZER(IPL_BIO), NULL, 0 } + +void scsi_move(struct scsi_io_mover *); +void scsi_move_done(void *, void *); void scsi_io_get_done(void *, void *); +void scsi_xs_get_done(void *, void *); /* * Called when a scsibus is attached to initialize global data. @@ -235,6 +241,32 @@ scsi_iopool_init(struct scsi_iopool *iopl, void *iocookie, mtx_init(&iopl->mtx, IPL_BIO); } +void +scsi_iopool_destroy(struct scsi_iopool *iopl) +{ + struct scsi_runq sleepers = TAILQ_HEAD_INITIALIZER(sleepers); + struct scsi_iohandler *ioh = NULL; + + mtx_enter(&iopl->mtx); + while ((ioh = TAILQ_FIRST(&iopl->queue)) != NULL) { + TAILQ_REMOVE(&iopl->queue, ioh, q_entry); + ioh->q_state = RUNQ_IDLE; + + if (ioh->handler == scsi_io_get_done) + TAILQ_INSERT_TAIL(&sleepers, ioh, q_entry); +#ifdef DIAGNOSTIC + else + panic("scsi_iopool_destroy: scsi_iohandler on pool"); +#endif + } + mtx_leave(&iopl->mtx); + + while ((ioh = TAILQ_FIRST(&sleepers)) != NULL) { + TAILQ_REMOVE(&sleepers, ioh, q_entry); + ioh->handler(ioh->cookie, NULL); + } +} + void * scsi_default_get(void *iocookie) { @@ -368,13 +400,38 @@ scsi_ioh_runqueue(struct scsi_iopool *iopl) } /* + * move an io from a runq to a proc thats waiting for an io. + */ + +void +scsi_move(struct scsi_io_mover *m) +{ + mtx_enter(&m->mtx); + while (!m->done) + msleep(m, &m->mtx, PRIBIO, "scsiiomv", 0); + mtx_leave(&m->mtx); +} + +void +scsi_move_done(void *cookie, void *io) +{ + struct scsi_io_mover *m = cookie; + + mtx_enter(&m->mtx); + m->io = io; + m->done = 1; + wakeup_one(m); + mtx_leave(&m->mtx); +} + +/* * synchronous api for allocating an io. */ void * scsi_io_get(struct scsi_iopool *iopl, int flags) { - struct scsi_io_mover m = { MUTEX_INITIALIZER(IPL_BIO), NULL }; + struct scsi_io_mover m = SCSI_IO_MOVER_INITIALIZER; struct scsi_iohandler ioh; void *io; @@ -388,11 +445,7 @@ scsi_io_get(struct scsi_iopool *iopl, int flags) /* otherwise sleep until we get one */ scsi_ioh_set(&ioh, iopl, scsi_io_get_done, &m); scsi_ioh_add(&ioh); - - mtx_enter(&m.mtx); - while (m.io == NULL) - msleep(&m, &m.mtx, PRIBIO, "scsiio", 0); - mtx_leave(&m.mtx); + scsi_move(&m); return (m.io); } @@ -400,12 +453,7 @@ scsi_io_get(struct scsi_iopool *iopl, int flags) void scsi_io_get_done(void *cookie, void *io) { - struct scsi_io_mover *m = cookie; - - mtx_enter(&m->mtx); - m->io = io; - wakeup_one(m); - mtx_leave(&m->mtx); + scsi_move_done(cookie, io); } void @@ -434,6 +482,9 @@ scsi_xsh_add(struct scsi_xshandler *xsh) { struct scsi_link *link = xsh->link; + if (ISSET(link->state, SDEV_S_DYING)) + return; + mtx_enter(&link->pool->mtx); if (xsh->ioh.q_state == RUNQ_IDLE) { TAILQ_INSERT_TAIL(&link->queue, &xsh->ioh, q_entry); @@ -484,7 +535,7 @@ scsi_xsh_runqueue(struct scsi_link *link) runq = 0; mtx_enter(&link->pool->mtx); - while (link->openings && + while (!ISSET(link->state, SDEV_S_DYING) && link->openings && ((ioh = TAILQ_FIRST(&link->queue)) != NULL)) { link->openings--; @@ -532,28 +583,38 @@ struct scsi_xfer * scsi_xs_get(struct scsi_link *link, int flags) { struct scsi_xshandler xsh; - struct scsi_io_mover m = { MUTEX_INITIALIZER(IPL_BIO), NULL }; + struct scsi_io_mover m = SCSI_IO_MOVER_INITIALIZER; + + struct scsi_iopool *iopl = link->pool; void *io; - if (scsi_link_open(link)) { - io = scsi_io_get(link->pool, flags); - if (io == NULL) { - scsi_link_close(link); - return (NULL); - } - } else { + if (ISSET(link->state, SDEV_S_DYING)) + return (NULL); + + /* really custom xs handler to avoid scsi_xsh_ioh */ + scsi_ioh_set(&xsh.ioh, iopl, scsi_xs_get_done, &m); + xsh.link = link; + + if (!scsi_link_open(link)) { if (ISSET(flags, SCSI_NOSLEEP)) return (NULL); - /* really custom xs handler to avoid scsi_xsh_ioh */ - scsi_ioh_set(&xsh.ioh, link->pool, scsi_io_get_done, &m); - xsh.link = link; scsi_xsh_add(&xsh); + scsi_move(&m); + if (m.io == NULL) + return (NULL); + + io = m.io; + } else if ((io = iopl->io_get(iopl->iocookie)) == NULL) { + if (ISSET(flags, SCSI_NOSLEEP)) { + scsi_link_close(link); + return (NULL); + } - mtx_enter(&m.mtx); - while (m.io == NULL) - msleep(&m, &m.mtx, PRIBIO, "scsixs", 0); - mtx_leave(&m.mtx); + scsi_ioh_add(&xsh.ioh); + scsi_move(&m); + if (m.io == NULL) + return (NULL); io = m.io; } @@ -561,6 +622,61 @@ scsi_xs_get(struct scsi_link *link, int flags) return (scsi_xs_io(link, io, flags)); } +void +scsi_xs_get_done(void *cookie, void *io) +{ + scsi_move_done(cookie, io); +} + +void +scsi_link_shutdown(struct scsi_link *link) +{ + struct scsi_runq sleepers = TAILQ_HEAD_INITIALIZER(sleepers); + struct scsi_iopool *iopl = link->pool; + struct scsi_iohandler *ioh; + struct scsi_xshandler *xsh; + + mtx_enter(&iopl->mtx); + while ((ioh = TAILQ_FIRST(&link->queue)) != NULL) { + TAILQ_REMOVE(&link->queue, ioh, q_entry); + ioh->q_state = RUNQ_IDLE; + + if (ioh->handler == scsi_xs_get_done) + TAILQ_INSERT_TAIL(&sleepers, ioh, q_entry); +#ifdef DIAGNOSTIC + else + panic("scsi_link_shutdown: scsi_xshandler on link"); +#endif + } + + ioh = TAILQ_FIRST(&iopl->queue); + while (ioh != NULL) { + xsh = (struct scsi_xshandler *)ioh; + ioh = TAILQ_NEXT(ioh, q_entry); + +#ifdef DIAGNOSTIC + if (xsh->ioh.handler == scsi_xsh_ioh && + xsh->link == link) + panic("scsi_link_shutdown: scsi_xshandler on pool"); +#endif + + if (xsh->ioh.handler == scsi_xs_get_done && + xsh->link == link) { + TAILQ_REMOVE(&iopl->queue, &xsh->ioh, q_entry); + xsh->ioh.q_state = RUNQ_IDLE; + link->openings++; + + TAILQ_INSERT_TAIL(&sleepers, &xsh->ioh, q_entry); + } + } + mtx_leave(&iopl->mtx); + + while ((ioh = TAILQ_FIRST(&sleepers)) != NULL) { + TAILQ_REMOVE(&sleepers, ioh, q_entry); + ioh->handler(ioh->cookie, NULL); + } +} + int scsi_link_open(struct scsi_link *link) { |