summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2010-08-25 00:31:36 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2010-08-25 00:31:36 +0000
commit022571935a9eb32548666c143a95ed20e356a556 (patch)
tree0c3526e179f9f88298b65fbaae8d7291f8865451
parente087583e1d5fc4be76015df58e5e66aab8552843 (diff)
add scsi_iopool_destroy and scsi_link_shutdown. when a link or
device are going away, this will walk the pool and link queues and wake up processes that are sleeping while waiting for an io or xs. they will return NULL to the scsi_{xs,io}_get callers, which should then check if they device is still alive. all other handlers that are registered on the queues should be removed by their owners before the destroy/shutdown funcs are called. lots of help and discussion with matthew@ ok matthew@
-rw-r--r--sys/scsi/scsi_base.c180
-rw-r--r--sys/scsi/scsiconf.c19
-rw-r--r--sys/scsi/scsiconf.h4
3 files changed, 163 insertions, 40 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)
{
diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c
index e88a63809c8..4c9b23e62e4 100644
--- a/sys/scsi/scsiconf.c
+++ b/sys/scsi/scsiconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.c,v 1.162 2010/07/24 04:01:52 matthew Exp $ */
+/* $OpenBSD: scsiconf.c,v 1.163 2010/08/25 00:31:35 dlg Exp $ */
/* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */
/*
@@ -487,9 +487,12 @@ scsi_detach_lun(struct scsibus_softc *sc, int target, int lun, int flags)
if (((flags & DETACH_FORCE) == 0) && (link->flags & SDEV_OPEN))
return (EBUSY);
- /* detaching a device from scsibus is a four step process... */
+ /* detaching a device from scsibus is a five step process... */
- /* 1. detach the device */
+ /* 1. wake up processes sleeping for an xs */
+ scsi_link_shutdown(link);
+
+ /* 2. detach the device */
#if NMPATH > 0
if (link->device_softc == NULL)
rv = mpath_path_detach(link, flags);
@@ -500,15 +503,17 @@ scsi_detach_lun(struct scsibus_softc *sc, int target, int lun, int flags)
if (rv != 0)
return (rv);
- /* 2. if its using the openings io allocator, clean it up */
- if (ISSET(link->flags, SDEV_OWN_IOPL))
+ /* 3. if its using the openings io allocator, clean it up */
+ if (ISSET(link->flags, SDEV_OWN_IOPL)) {
+ scsi_iopool_destroy(link->pool);
free(link->pool, M_DEVBUF);
+ }
- /* 3. free up its state in the adapter */
+ /* 4. free up its state in the adapter */
if (alink->adapter->dev_free != NULL)
alink->adapter->dev_free(link);
- /* 4. free up its state in the midlayer */
+ /* 5. free up its state in the midlayer */
if (link->id != NULL)
devid_free(link->id);
scsi_remove_link(sc, link);
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index ed462cb840a..5d5e074dfef 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.h,v 1.135 2010/07/27 04:41:56 matthew Exp $ */
+/* $OpenBSD: scsiconf.h,v 1.136 2010/08/25 00:31:35 dlg Exp $ */
/* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */
/*
@@ -599,6 +599,8 @@ void scsi_sense_print_debug(struct scsi_xfer *);
*/
void scsi_iopool_init(struct scsi_iopool *, void *,
void *(*)(void *), void (*)(void *, void *));
+void scsi_iopool_destroy(struct scsi_iopool *);
+void scsi_link_shutdown(struct scsi_link *);
void * scsi_io_get(struct scsi_iopool *, int);
void scsi_io_put(struct scsi_iopool *, void *);