diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2010-01-02 23:28:52 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2010-01-02 23:28:52 +0000 |
commit | f810d7ce65c2aa4c6906749ce6f29fd031b0f846 (patch) | |
tree | 1a098a2c793f85dc83159ccfec12921567024459 /sys | |
parent | c659e107d06ed65114e6fdb1be2dde76d5b3da41 (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')
-rw-r--r-- | sys/scsi/ss.c | 186 | ||||
-rw-r--r-- | sys/scsi/ss_mustek.c | 86 | ||||
-rw-r--r-- | sys/scsi/ss_scanjet.c | 93 | ||||
-rw-r--r-- | sys/scsi/ssvar.h | 13 |
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 */ |