summaryrefslogtreecommitdiff
path: root/sys/scsi/scsi_base.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2010-09-14 01:39:45 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2010-09-14 01:39:45 +0000
commite608ae4fa52e5c4c7fa3bb2cd69920040d244dcf (patch)
tree41895d40c09d2f90c144664a525a4c01bf88e028 /sys/scsi/scsi_base.c
parent83869b13d617de819b3677377ce544704d8a1364 (diff)
the openings member of scsi_link is the maximum number of commands that a
scsi device can have in flight. instead of counting users of openings on the bus by taking away from the openings value, count the number of pending commands on the bus in a new pending variable. this lets us know how many outstanding commands there are. we can then use that to make sure that all commands a device has generated get completed before detaching the device. this helps avoid resource leaks and use after frees. tested by me on pci ehci/umass, fc mpi, and sas mpi. tested by jakemsr on cardbus ohci umass. it found issues in sas mpi which were fixed as a result of this diff. ok krw@
Diffstat (limited to 'sys/scsi/scsi_base.c')
-rw-r--r--sys/scsi/scsi_base.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c
index 167faf4d357..d13c2017556 100644
--- a/sys/scsi/scsi_base.c
+++ b/sys/scsi/scsi_base.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_base.c,v 1.194 2010/09/08 11:04:39 dlg Exp $ */
+/* $OpenBSD: scsi_base.c,v 1.195 2010/09/14 01:39:44 dlg Exp $ */
/* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */
/*
@@ -527,7 +527,9 @@ scsi_xsh_del(struct scsi_xshandler *xsh)
break;
case RUNQ_POOLQ:
TAILQ_REMOVE(&link->pool->queue, &xsh->ioh, q_entry);
- link->openings++;
+ link->pending--;
+ if (ISSET(link->state, SDEV_S_DYING) && link->pending == 0)
+ wakeup_one(&link->pending);
break;
default:
panic("unexpected xsh state %u", xsh->ioh.q_state);
@@ -552,9 +554,10 @@ scsi_xsh_runqueue(struct scsi_link *link)
runq = 0;
mtx_enter(&link->pool->mtx);
- while (!ISSET(link->state, SDEV_S_DYING) && link->openings &&
+ while (!ISSET(link->state, SDEV_S_DYING) &&
+ link->pending < link->openings &&
((ioh = TAILQ_FIRST(&link->queue)) != NULL)) {
- link->openings--;
+ link->pending++;
TAILQ_REMOVE(&link->queue, ioh, q_entry);
TAILQ_INSERT_TAIL(&link->pool->queue, ioh, q_entry);
@@ -681,11 +684,14 @@ scsi_link_shutdown(struct scsi_link *link)
xsh->link == link) {
TAILQ_REMOVE(&iopl->queue, &xsh->ioh, q_entry);
xsh->ioh.q_state = RUNQ_IDLE;
- link->openings++;
+ link->pending--;
TAILQ_INSERT_TAIL(&sleepers, &xsh->ioh, q_entry);
}
}
+
+ while (link->pending > 0)
+ msleep(&link->pending, &iopl->mtx, PRIBIO, "pendxs", 0);
mtx_leave(&iopl->mtx);
while ((ioh = TAILQ_FIRST(&sleepers)) != NULL) {
@@ -700,8 +706,8 @@ scsi_link_open(struct scsi_link *link)
int open = 0;
mtx_enter(&link->pool->mtx);
- if (link->openings) {
- link->openings--;
+ if (link->pending < link->openings) {
+ link->pending++;
open = 1;
}
mtx_leave(&link->pool->mtx);
@@ -713,7 +719,9 @@ void
scsi_link_close(struct scsi_link *link)
{
mtx_enter(&link->pool->mtx);
- link->openings++;
+ link->pending--;
+ if (ISSET(link->state, SDEV_S_DYING) && link->pending == 0)
+ wakeup_one(&link->pending);
mtx_leave(&link->pool->mtx);
scsi_xsh_runqueue(link);