summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2011-04-21 23:10:09 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2011-04-21 23:10:09 +0000
commit9281bac9f50df7113c0424c1f685d6b37d279978 (patch)
treef3e6e521a66719c2226eed40df77ab7237702215 /sys/dev/ic
parent989816d8fc5b18f79f44f088cf52a45b02ee6b31 (diff)
A plausible iopoolification. Utter dearth of interested parties
after more than a year of grovelling emails shows further effort is pointless. ok matthew@ dlg@
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/cac.c104
-rw-r--r--sys/dev/ic/cacvar.h5
2 files changed, 71 insertions, 38 deletions
diff --git a/sys/dev/ic/cac.c b/sys/dev/ic/cac.c
index 0a2475cd736..98db3eab6a3 100644
--- a/sys/dev/ic/cac.c
+++ b/sys/dev/ic/cac.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cac.c,v 1.43 2011/04/05 19:54:35 jasper Exp $ */
+/* $OpenBSD: cac.c,v 1.44 2011/04/21 23:10:08 krw Exp $ */
/* $NetBSD: cac.c,v 1.15 2000/11/08 19:20:35 ad Exp $ */
/*
@@ -103,9 +103,9 @@ struct scsi_adapter cac_switch = {
cac_scsi_cmd, cacminphys, 0, 0,
};
-struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int);
+void *cac_ccb_alloc(void *);
void cac_ccb_done(struct cac_softc *, struct cac_ccb *);
-void cac_ccb_free(struct cac_softc *, struct cac_ccb *);
+void cac_ccb_free(void *, void *);
int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int);
int cac_ccb_start(struct cac_softc *, struct cac_ccb *);
int cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
@@ -156,6 +156,8 @@ cac_init(struct cac_softc *sc, int startfw)
SIMPLEQ_INIT(&sc->sc_ccb_free);
SIMPLEQ_INIT(&sc->sc_ccb_queue);
+ mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
+ scsi_iopool_init(&sc->sc_iopool, sc, cac_ccb_alloc, cac_ccb_free);
size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
@@ -204,7 +206,9 @@ cac_init(struct cac_softc *sc, int startfw)
}
ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
+ mtx_enter(&sc->sc_ccb_mtx);
SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
+ mtx_leave(&sc->sc_ccb_mtx);
}
/* Start firmware background tasks, if needed. */
@@ -245,6 +249,7 @@ cac_init(struct cac_softc *sc, int startfw)
sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits;
if (sc->sc_link.openings < 4 )
sc->sc_link.openings = 4;
+ sc->sc_link.pool = &sc->sc_iopool;
bzero(&saa, sizeof(saa));
saa.saa_sc_link = &sc->sc_link;
@@ -344,11 +349,18 @@ cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
command, drive, blkno, data, datasize, flags, xs);
#endif
- if ((ccb = cac_ccb_alloc(sc, 0)) == NULL) {
-#ifdef CAC_DEBUG
- printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
-#endif
- return (ENOMEM);
+ if (xs) {
+ ccb = xs->io;
+ /*
+ * The xs may have been restarted by the scsi layer, so
+ * ensure the ccb starts in the proper state.
+ */
+ ccb->ccb_flags = 0;
+ } else {
+ /* Internal command. Need to get our own ccb. */
+ ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL | SCSI_NOSLEEP);
+ if (ccb == NULL)
+ return (EBUSY);
}
if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
@@ -396,11 +408,9 @@ cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
ccb->ccb_xs = xs;
if (!xs || xs->flags & SCSI_POLL) {
-
/* Synchronous commands musn't wait. */
if ((*sc->sc_cl->cl_fifo_full)(sc)) {
- cac_ccb_free(sc, ccb);
- rv = ENOMEM; /* Causes XS_NO_CCB, i/o is retried. */
+ rv = EBUSY;
} else {
ccb->ccb_flags |= CAC_CCB_ACTIVE;
(*sc->sc_cl->cl_submit)(sc, ccb);
@@ -409,6 +419,9 @@ cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
} else
rv = cac_ccb_start(sc, ccb);
+ if (xs == NULL)
+ scsi_io_put(&sc->sc_iopool, ccb);
+
return (rv);
}
@@ -419,8 +432,9 @@ int
cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
{
struct cac_ccb *ccb;
- int s, t = timo * 100;
+ int t;
+ t = timo * 100;
do {
for (; t--; DELAY(10))
if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
@@ -429,9 +443,7 @@ cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
printf("%s: timeout\n", sc->sc_dv.dv_xname);
return (EBUSY);
}
- s = splbio();
cac_ccb_done(sc, ccb);
- splx(s);
} while (ccb != wantccb);
return (0);
@@ -439,17 +451,27 @@ cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
/*
* Enqueue the specified command (if any) and attempt to start all enqueued
- * commands. Must be called at splbio.
+ * commands.
*/
int
cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
{
- if (ccb != NULL)
+ if (ccb != NULL) {
+ mtx_enter(&sc->sc_ccb_mtx);
SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
+ mtx_leave(&sc->sc_ccb_mtx);
+ }
- while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL &&
- !(*sc->sc_cl->cl_fifo_full)(sc)) {
+ while (!(*sc->sc_cl->cl_fifo_full)(sc)) {
+ mtx_enter(&sc->sc_ccb_mtx);
+ if (SIMPLEQ_EMPTY(&sc->sc_ccb_queue)) {
+ mtx_leave(&sc->sc_ccb_mtx);
+ break;
+ }
+ ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue);
SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
+ mtx_leave(&sc->sc_ccb_mtx);
+
ccb->ccb_flags |= CAC_CCB_ACTIVE;
(*sc->sc_cl->cl_submit)(sc, ccb);
}
@@ -494,7 +516,6 @@ cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
printf("%s: invalid request\n", sc->sc_dv.dv_xname);
}
- cac_ccb_free(sc, ccb);
if (xs) {
if (error)
xs->error = XS_DRIVER_STUFFUP;
@@ -508,15 +529,24 @@ cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
/*
* Allocate a CCB.
*/
-struct cac_ccb *
-cac_ccb_alloc(struct cac_softc *sc, int nosleep)
+void *
+cac_ccb_alloc(void *xsc)
{
- struct cac_ccb *ccb;
+ struct cac_softc *sc = xsc;
+ struct cac_ccb *ccb = NULL;
- if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL)
+ mtx_enter(&sc->sc_ccb_mtx);
+ if ((*sc->sc_cl->cl_fifo_full)(sc) ||
+ SIMPLEQ_EMPTY(&sc->sc_ccb_free)) {
+#ifdef CAC_DEBUG
+ printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
+#endif
+ } else {
+ ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free);
SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
- else
- ccb = NULL;
+ }
+ mtx_leave(&sc->sc_ccb_mtx);
+
return (ccb);
}
@@ -524,11 +554,16 @@ cac_ccb_alloc(struct cac_softc *sc, int nosleep)
* Put a CCB onto the freelist.
*/
void
-cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb)
+cac_ccb_free(void *xsc, void *xccb)
{
+ struct cac_softc *sc = xsc;
+ struct cac_ccb *ccb = xccb;
ccb->ccb_flags = 0;
+
+ mtx_enter(&sc->sc_ccb_mtx);
SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
+ mtx_leave(&sc->sc_ccb_mtx);
}
int
@@ -708,18 +743,13 @@ cac_scsi_cmd(xs)
poll = xs->flags & SCSI_POLL;
if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
target, blockno, flags, xs))) {
-
- if (error == ENOMEM || error == EBUSY) {
- xs->error = XS_NO_CCB;
- scsi_done(xs);
- splx(s);
- return;
- } else {
+ splx(s);
+ if (error == EBUSY)
+ xs->error = XS_BUSY;
+ else
xs->error = XS_DRIVER_STUFFUP;
- scsi_done(xs);
- splx(s);
- return;
- }
+ scsi_done(xs);
+ return;
}
splx(s);
diff --git a/sys/dev/ic/cacvar.h b/sys/dev/ic/cacvar.h
index 51a307b1c1b..4026323d578 100644
--- a/sys/dev/ic/cacvar.h
+++ b/sys/dev/ic/cacvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cacvar.h,v 1.5 2008/10/29 21:17:15 brad Exp $ */
+/* $OpenBSD: cacvar.h,v 1.6 2011/04/21 23:10:08 krw Exp $ */
/* $NetBSD: cacvar.h,v 1.7 2000/10/19 14:28:47 ad Exp $ */
/*-
@@ -110,6 +110,9 @@ struct cac_softc {
int (*sc_ioctl)(struct device *, u_long, caddr_t);
struct ksensor *sc_sensors;
struct ksensordev sc_sensordev;
+
+ struct mutex sc_ccb_mtx; /* ccb queue protection */
+ struct scsi_iopool sc_iopool;
};
/* XXX These have to become spinlocks in case of fine SMP */