summaryrefslogtreecommitdiff
path: root/sys/scsi
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2010-01-02 23:28:52 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2010-01-02 23:28:52 +0000
commitf810d7ce65c2aa4c6906749ce6f29fd031b0f846 (patch)
tree1a098a2c793f85dc83159ccfec12921567024459 /sys/scsi
parentc659e107d06ed65114e6fdb1be2dde76d5b3da41 (diff)
move the buf handling from using scsi_scsi_cmd over to scsi_xs_exec. i
think this is the last chunk of code using a buf pointer in the scsi_xfer now. this has not been tested due to a lack of hardware anywhere. if there are problems please report them as soon as possible. ok krw@ miod@
Diffstat (limited to 'sys/scsi')
-rw-r--r--sys/scsi/ss.c186
-rw-r--r--sys/scsi/ss_mustek.c86
-rw-r--r--sys/scsi/ss_scanjet.c93
-rw-r--r--sys/scsi/ssvar.h13
4 files changed, 282 insertions, 96 deletions
diff --git a/sys/scsi/ss.c b/sys/scsi/ss.c
index 40a8cedffa7..e1c09979613 100644
--- a/sys/scsi/ss.c
+++ b/sys/scsi/ss.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ss.c,v 1.64 2010/01/01 06:30:27 dlg Exp $ */
+/* $OpenBSD: ss.c,v 1.65 2010/01/02 23:28:51 dlg Exp $ */
/* $NetBSD: ss.c,v 1.10 1996/05/05 19:52:55 christos Exp $ */
/*
@@ -113,6 +113,7 @@ struct quirkdata ss_gen_quirks = {
void ssstrategy(struct buf *);
void ssstart(void *);
+void ssdone(struct scsi_xfer *);
void ssminphys(struct buf *);
void ss_identify_scanner(struct ss_softc *, struct scsi_inquiry_data*);
@@ -353,6 +354,11 @@ ssattach(parent, self, aux)
/* XXX fill in the rest of the scan_io struct by calling the
compute_sizes routine */
+ mtx_init(&ss->queue_mtx, IPL_BIO);
+ mtx_init(&ss->start_mtx, IPL_BIO);
+
+ timeout_set(&ss->timeout, ssstart, ss);
+
/*
* Set up the buf queue for this device
*/
@@ -559,7 +565,6 @@ ssstrategy(bp)
struct buf *bp;
{
struct ss_softc *ss = ss_cd.cd_devs[SSUNIT(bp->b_dev)];
- struct buf *dp;
int s;
SC_DEBUG(ss->sc_link, SDEV_DB2, ("ssstrategy: %ld bytes @ blk %d\n",
@@ -574,18 +579,12 @@ ssstrategy(bp)
if (bp->b_bcount == 0)
goto done;
- s = splbio();
-
/*
* Place it in the queue of activities for this scanner
* at the end (a bit silly because we only have on user..)
* (but it could fork() or dup())
*/
- dp = &ss->buf_queue;
- bp->b_actf = NULL;
- bp->b_actb = dp->b_actb;
- *dp->b_actb = bp;
- dp->b_actb = &bp->b_actf;
+ ss_buf_enqueue(ss, bp);
/*
* Tell the device to get going on the transfer if it's
@@ -594,7 +593,6 @@ ssstrategy(bp)
*/
ssstart(ss);
- splx(s);
return;
done:
@@ -607,6 +605,48 @@ done:
splx(s);
}
+void
+ss_buf_enqueue(struct ss_softc *ss, struct buf *bp)
+{
+ struct buf *dp;
+
+ mtx_enter(&ss->queue_mtx);
+ dp = &ss->buf_queue;
+ bp->b_actf = NULL;
+ bp->b_actb = dp->b_actb;
+ *dp->b_actb = bp;
+ dp->b_actb = &bp->b_actf;
+ mtx_leave(&ss->queue_mtx);
+}
+
+struct buf *
+ss_buf_dequeue(struct ss_softc *ss)
+{
+ struct buf *bp;
+
+ mtx_enter(&ss->queue_mtx);
+ bp = ss->buf_queue.b_actf;
+ if (bp != NULL)
+ ss->buf_queue.b_actf = bp->b_actf;
+ if (ss->buf_queue.b_actf == NULL)
+ ss->buf_queue.b_actb = &ss->buf_queue.b_actf;
+ mtx_leave(&ss->queue_mtx);
+
+ return (bp);
+}
+
+void
+ss_buf_requeue(struct ss_softc *ss, struct buf *bp)
+{
+ mtx_enter(&ss->queue_mtx);
+ bp->b_actf = ss->buf_queue.b_actf;
+ ss->buf_queue.b_actf = bp;
+ if (bp->b_actf == NULL)
+ ss->buf_queue.b_actb = &bp->b_actf;
+ mtx_leave(&ss->queue_mtx);
+}
+
+
/*
* ssstart looks to see if there is a buf waiting for the device
* and that the device is not already busy. If both are true,
@@ -627,55 +667,99 @@ ssstart(v)
{
struct ss_softc *ss = v;
struct scsi_link *sc_link = ss->sc_link;
- struct buf *bp, *dp;
- struct scsi_r_scanner read_cmd;
- int flags;
+ struct scsi_xfer *xs;
+ struct buf *bp;
+ struct scsi_r_scanner *cdb;
SC_DEBUG(sc_link, SDEV_DB2, ("ssstart\n"));
- /*
- * See if there is a buf to do and we are not already
- * doing one
- */
- while (sc_link->openings > 0) {
- /* if a special awaits, let it proceed first */
- mtx_enter(&sc_link->mtx);
- if (ISSET(sc_link->state, SDEV_S_WAITING)) {
- atomic_clearbits_int(&sc_link->state, SDEV_S_WAITING);
- wakeup((caddr_t)sc_link);
- mtx_leave(&sc_link->mtx);
- return;
- }
- mtx_leave(&sc_link->mtx);
- /*
- * See if there is a buf with work for us to do..
- */
- dp = &ss->buf_queue;
- if ((bp = dp->b_actf) == NULL)
- return;
- if ((dp = bp->b_actf) != NULL)
- dp->b_actb = bp->b_actb;
- else
- ss->buf_queue.b_actb = bp->b_actb;
- *bp->b_actb = dp;
+ mtx_enter(&ss->start_mtx);
+ if (ISSET(ss->flags, SSF_STARTING)) {
+ mtx_leave(&ss->start_mtx);
+ return;
+ }
+
+ SET(ss->flags, SSF_STARTING);
+ mtx_leave(&ss->start_mtx);
+
+ CLR(ss->flags, SSF_WAITING);
+ while (!ISSET(ss->flags, SSF_WAITING) &&
+ (bp = ss_buf_dequeue(ss)) != NULL) {
+
+ xs = scsi_xs_get(sc_link, SCSI_NOSLEEP);
+ if (xs == NULL)
+ break;
if (ss->special.read) {
- (ss->special.read)(ss, bp);
+ (ss->special.read)(ss, xs, bp);
} else {
- /* generic scsi2 scanner read */
- bzero(&read_cmd, sizeof(read_cmd));
- read_cmd.opcode = READ_BIG;
- _lto3b(bp->b_bcount, read_cmd.len);
- flags = SCSI_DATA_IN;
- /*
- * go ask the adapter to do all this for us
- */
- if (scsi_scsi_cmd(sc_link, (struct scsi_generic *)
- &read_cmd, sizeof(read_cmd), (u_char *) bp->b_data,
- bp->b_bcount, 0, 100000, bp, flags | SCSI_NOSLEEP))
- printf("%s: not queued\n", ss->sc_dev.dv_xname);
+ cdb = (struct scsi_r_scanner *)xs->cmd;
+ xs->cmdlen = sizeof(*cdb);
+
+ cdb->opcode = READ_BIG;
+ _lto3b(bp->b_bcount, cdb->len);
+
+ xs->data = bp->b_data;
+ xs->datalen = bp->b_bcount;
+ xs->flags |= SCSI_DATA_IN;
+ xs->retries = 0;
+ xs->timeout = 100000;
+ xs->done = ssdone;
+ xs->cookie = bp;
+
+ scsi_xs_exec(xs);
}
}
+ mtx_enter(&ss->start_mtx);
+ CLR(ss->flags, SSF_STARTING);
+ mtx_leave(&ss->start_mtx);
+}
+
+void
+ssdone(struct scsi_xfer *xs)
+{
+ struct ss_softc *ss = xs->sc_link->device_softc;
+ struct buf *bp = xs->cookie;
+
+ splassert(IPL_BIO);
+
+ switch (xs->error) {
+ case XS_NOERROR:
+ bp->b_error = 0;
+ bp->b_resid = xs->resid;
+ break;
+
+ case XS_NO_CCB:
+ /* The adapter is busy, requeue the buf and try it later. */
+ ss_buf_requeue(ss, bp);
+ scsi_xs_put(xs);
+ SET(ss->flags, SSF_WAITING); /* break out of cdstart loop */
+ timeout_add(&ss->timeout, 1);
+ return;
+
+ case XS_SENSE:
+ case XS_SHORTSENSE:
+ if (scsi_interpret_sense(xs) != ERESTART)
+ xs->retries = 0;
+
+ /* FALLTHROUGH */
+ case XS_BUSY:
+ case XS_TIMEOUT:
+ if (xs->retries--) {
+ scsi_xs_exec(xs);
+ return;
+ }
+
+ /* FALLTHROUGH */
+ default:
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ bp->b_resid = bp->b_bcount;
+ break;
+ }
+
+ biodone(bp);
+ scsi_xs_put(xs);
}
/*
diff --git a/sys/scsi/ss_mustek.c b/sys/scsi/ss_mustek.c
index 5246a8b7dc5..621fb78d2d1 100644
--- a/sys/scsi/ss_mustek.c
+++ b/sys/scsi/ss_mustek.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ss_mustek.c,v 1.16 2008/06/22 16:32:05 krw Exp $ */
+/* $OpenBSD: ss_mustek.c,v 1.17 2010/01/02 23:28:51 dlg Exp $ */
/* $NetBSD: ss_mustek.c,v 1.4 1996/05/05 19:52:57 christos Exp $ */
/*
@@ -69,7 +69,8 @@
int mustek_set_params(struct ss_softc *, struct scan_io *);
int mustek_trigger_scanner(struct ss_softc *);
void mustek_minphys(struct ss_softc *, struct buf *);
-int mustek_read(struct ss_softc *, struct buf *);
+int mustek_read(struct ss_softc *, struct scsi_xfer *xs, struct buf *);
+void mustek_read_done(struct scsi_xfer *);
int mustek_rewind_scanner(struct ss_softc *);
/* only used internally */
@@ -433,39 +434,88 @@ mustek_rewind_scanner(ss)
* read the requested number of bytes/lines from the scanner
*/
int
-mustek_read(ss, bp)
+mustek_read(ss, xs, bp)
struct ss_softc *ss;
+ struct scsi_xfer *xs;
struct buf *bp;
{
- struct mustek_read_cmd cmd;
- struct scsi_link *sc_link = ss->sc_link;
+ struct mustek_read_cmd *cdb;
u_long lines_to_read;
SC_DEBUG(sc_link, SDEV_DB1, ("mustek_read: start\n"));
- bzero(&cmd, sizeof(cmd));
- cmd.opcode = MUSTEK_READ;
+ cdb = (struct mustek_read_cmd *)xs->cmd;
+ xs->cmdlen = sizeof(*cdb);
+
+ cdb->opcode = MUSTEK_READ;
/* instead of the bytes, the mustek wants the number of lines */
lines_to_read = bp->b_bcount /
((ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel) / 8);
SC_DEBUG(sc_link, SDEV_DB1, ("mustek_read: read %ld lines\n",
lines_to_read));
- _lto3b(lines_to_read, cmd.length);
+ _lto3b(lines_to_read, cdb->length);
- /*
- * go ask the adapter to do all this for us
- */
- if (scsi_scsi_cmd(sc_link, (struct scsi_generic *) &cmd, sizeof(cmd),
- (u_char *) bp->b_data, bp->b_bcount, SCSI_RETRIES, 10000, bp,
- SCSI_NOSLEEP | SCSI_DATA_IN) != SUCCESSFULLY_QUEUED)
- printf("%s: not queued\n", ss->sc_dev.dv_xname);
- else {
- ss->sio.scan_lines -= lines_to_read;
+ xs->data = bp->b_data;
+ xs->datalen = bp->b_bcount;
+ xs->flags |= SCSI_DATA_IN;
+ xs->done = mustek_read_done;
+ xs->cookie = bp;
+
+ scsi_xs_exec(xs);
+
+ return (0);
+}
+
+void
+mustek_read_done(struct scsi_xfer *xs)
+{
+ struct ss_softc *ss = xs->sc_link->device_softc;
+ struct buf *bp = xs->cookie;
+
+ splassert(IPL_BIO);
+
+ switch (xs->error) {
+ case XS_NOERROR:
+ ss->sio.scan_lines -= bp->b_bcount /
+ ((ss->sio.scan_pixels_per_line *
+ ss->sio.scan_bits_per_pixel) / 8);
ss->sio.scan_window_size -= bp->b_bcount;
+ bp->b_error = 0;
+ bp->b_resid = xs->resid;
+ break;
+
+ case XS_NO_CCB:
+ /* The adapter is busy, requeue the buf and try it later. */
+ ss_buf_requeue(ss, bp);
+ scsi_xs_put(xs);
+ SET(ss->flags, SSF_WAITING); /* break out of cdstart loop */
+ timeout_add(&ss->timeout, 1);
+ return;
+
+ case XS_SENSE:
+ case XS_SHORTSENSE:
+ if (scsi_interpret_sense(xs) != ERESTART)
+ xs->retries = 0;
+
+ /* FALLTHROUGH */
+ case XS_BUSY:
+ case XS_TIMEOUT:
+ if (xs->retries--) {
+ scsi_xs_exec(xs);
+ return;
+ }
+
+ /* FALLTHROUGH */
+ default:
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ bp->b_resid = bp->b_bcount;
+ break;
}
- return (0);
+ biodone(bp);
+ scsi_xs_put(xs);
}
/*
diff --git a/sys/scsi/ss_scanjet.c b/sys/scsi/ss_scanjet.c
index ccf789fedf9..3777494300b 100644
--- a/sys/scsi/ss_scanjet.c
+++ b/sys/scsi/ss_scanjet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ss_scanjet.c,v 1.33 2008/06/22 16:32:05 krw Exp $ */
+/* $OpenBSD: ss_scanjet.c,v 1.34 2010/01/02 23:28:51 dlg Exp $ */
/* $NetBSD: ss_scanjet.c,v 1.6 1996/05/18 22:58:01 christos Exp $ */
/*
@@ -54,7 +54,8 @@
int scanjet_set_params(struct ss_softc *, struct scan_io *);
int scanjet_trigger_scanner(struct ss_softc *);
-int scanjet_read(struct ss_softc *, struct buf *);
+int scanjet_read(struct ss_softc *, struct scsi_xfer *, struct buf *);
+void scanjet_read_done(struct scsi_xfer *);
/* only used internally */
int scanjet_ctl_write(struct ss_softc *, char *, u_int, int);
@@ -276,43 +277,85 @@ scanjet_trigger_scanner(ss)
}
int
-scanjet_read(ss, bp)
+scanjet_read(ss, xs, bp)
struct ss_softc *ss;
+ struct scsi_xfer *xs;
struct buf *bp;
{
- struct scsi_rw_scanner cmd;
- struct scsi_link *sc_link = ss->sc_link;
+ struct scsi_rw_scanner *cdb;
- /*
- * Fill out the scsi command
- */
- bzero(&cmd, sizeof(cmd));
- cmd.opcode = READ;
+ SC_DEBUG(sc_link, SDEV_DB1, ("scanjet_read: start\n"));
- /*
- * Handle "fixed-block-mode" tape drives by using the
- * block count instead of the length.
- */
- _lto3b(bp->b_bcount, cmd.len);
+ cdb = (struct scsi_rw_scanner *)xs->cmd;
+ xs->cmdlen = sizeof(*cdb);
- /*
- * go ask the adapter to do all this for us
- */
- if (scsi_scsi_cmd(sc_link, (struct scsi_generic *) &cmd, sizeof(cmd),
- (u_char *) bp->b_data, bp->b_bcount, SCSI_RETRIES, 100000, bp,
- SCSI_NOSLEEP | SCSI_DATA_IN) != SUCCESSFULLY_QUEUED)
- printf("%s: not queued\n", ss->sc_dev.dv_xname);
- else {
+ cdb->opcode = READ;
+ _lto3b(bp->b_bcount, cdb->len);
+
+ xs->data = bp->b_data;
+ xs->datalen = bp->b_bcount;
+ xs->flags |= SCSI_DATA_IN;
+ xs->timeout = 100000;
+ xs->done = scanjet_read_done;
+ xs->cookie = bp;
+
+ scsi_xs_exec(xs);
+
+ return (0);
+}
+
+void
+scanjet_read_done(struct scsi_xfer *xs)
+{
+ struct ss_softc *ss = xs->sc_link->device_softc;
+ struct buf *bp = xs->cookie;
+
+ splassert(IPL_BIO);
+
+ switch (xs->error) {
+ case XS_NOERROR:
if (bp->b_bcount >= ss->sio.scan_window_size)
ss->sio.scan_window_size = 0;
else
ss->sio.scan_window_size -= bp->b_bcount;
+
+ bp->b_error = 0;
+ bp->b_resid = xs->resid;
+ break;
+
+ case XS_NO_CCB:
+ /* The adapter is busy, requeue the buf and try it later. */
+ ss_buf_requeue(ss, bp);
+ scsi_xs_put(xs);
+ SET(ss->flags, SSF_WAITING); /* break out of cdstart loop */
+ timeout_add(&ss->timeout, 1);
+ return;
+
+ case XS_SENSE:
+ case XS_SHORTSENSE:
+ if (scsi_interpret_sense(xs) != ERESTART)
+ xs->retries = 0;
+
+ /* FALLTHROUGH */
+ case XS_BUSY:
+ case XS_TIMEOUT:
+ if (xs->retries--) {
+ scsi_xs_exec(xs);
+ return;
+ }
+
+ /* FALLTHROUGH */
+ default:
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ bp->b_resid = bp->b_bcount;
+ break;
}
- return (0);
+ biodone(bp);
+ scsi_xs_put(xs);
}
-
/*
* Do a synchronous write. Used to send control messages.
*/
diff --git a/sys/scsi/ssvar.h b/sys/scsi/ssvar.h
index 0c5d39546b3..441e0e0ba80 100644
--- a/sys/scsi/ssvar.h
+++ b/sys/scsi/ssvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssvar.h,v 1.12 2008/11/10 18:04:41 deraadt Exp $ */
+/* $OpenBSD: ssvar.h,v 1.13 2010/01/02 23:28:51 dlg Exp $ */
/* $NetBSD: ssvar.h,v 1.2 1996/03/30 21:47:11 christos Exp $ */
/*
@@ -51,7 +51,7 @@ struct ss_special {
int (*get_params)(struct ss_softc *);
/* some scanners only send line-multiples */
void (*minphys)(struct ss_softc *, struct buf *);
- int (*read)(struct ss_softc *, struct buf *);
+ int (*read)(struct ss_softc *, struct scsi_xfer *, struct buf *);
int (*rewind_scanner)(struct ss_softc *);
int (*load_adf)(struct ss_softc *);
int (*unload_adf)(struct ss_softc *);
@@ -67,13 +67,22 @@ struct ss_softc {
int flags;
#define SSF_TRIGGERED 0x01 /* read operation has been primed */
#define SSF_LOADED 0x02 /* parameters loaded */
+#define SSF_WAITING 0x04
+#define SSF_STARTING 0x08
struct scsi_link *sc_link; /* contains our targ, lun, etc. */
struct scan_io sio;
struct buf buf_queue; /* the queue of pending IO operations */
const struct quirkdata *quirkdata; /* if we have a rogue entry */
struct ss_special special; /* special handlers for spec. devices */
+ struct timeout timeout;
+ struct mutex queue_mtx;
+ struct mutex start_mtx;
};
+struct buf *ss_buf_dequeue(struct ss_softc *);
+void ss_buf_enqueue(struct ss_softc *, struct buf *);
+void ss_buf_requeue(struct ss_softc *, struct buf *);
+
/*
* define the special attach routines if configured
*/