diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2009-11-10 10:19:00 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2009-11-10 10:19:00 +0000 |
commit | 2bc364095518d6bfab7adb9e51fd1eb72608ebd1 (patch) | |
tree | 395d53bc4c5323f085564e06604a57c65a8f11c7 /sys/scsi/sd.c | |
parent | bc4d3ed013d16c1d24634b9a6f8ca2df44f76137 (diff) |
fix the NO_CCB handling i broke when working on simplifying the midlayer.
marco@ discovered my rewrite retried commands rejected by an adapter
from a timeout, which was trivially starved by normal io going to
disks. this diff allows an xs to be marked as XS_NO_CCB, which will
cause it to be returned to the device driver to be retried as part
of the normal io queue.
tested by krw@ marco@ johan@
ok krw@ marco@
Diffstat (limited to 'sys/scsi/sd.c')
-rw-r--r-- | sys/scsi/sd.c | 45 |
1 files changed, 29 insertions, 16 deletions
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index 566847fae55..4ab8afe13d4 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sd.c,v 1.162 2009/11/10 10:13:08 dlg Exp $ */ +/* $OpenBSD: sd.c,v 1.163 2009/11/10 10:18:59 dlg Exp $ */ /* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */ /*- @@ -691,7 +691,9 @@ sdstart(void *v) SC_DEBUG(sc_link, SDEV_DB2, ("sdstart\n")); - while ((bp = sd_buf_dequeue(sc)) != NULL) { + CLR(sc->flags, SDF_WAITING); + while (!ISSET(sc->flags, SDF_WAITING) && + (bp = sd_buf_dequeue(sc)) != NULL) { /* * If the device has become invalid, abort all the * reads and writes until all files have been closed and @@ -755,27 +757,36 @@ sd_buf_done(struct scsi_xfer *xs) { struct sd_softc *sc = xs->sc_link->device_softc; struct buf *bp = xs->cookie; - int s; - disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid, + splassert(IPL_BIO); + + disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid, bp->b_flags & B_READ); - if (xs->error == XS_NOERROR) { + switch (xs->error) { + case XS_NOERROR: bp->b_error = 0; bp->b_resid = xs->resid; - } else { + break; + + case XS_NO_CCB: + /* The hardware is busy, requeue the buf and try it later. */ + sd_buf_requeue(sc, bp); + scsi_xs_put(xs); + SET(sc->flags, SDF_WAITING); /* break out of sdstart loop */ + timeout_add(&sc->sc_timeout, 1); + return; + + default: bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; + break; } - s = splbio(); biodone(bp); - splx(s); - scsi_xs_put(xs); - - sdstart(sc); /* XXX */ + sdstart(sc); /* restart io */ } void @@ -1456,11 +1467,13 @@ sd_flush(struct sd_softc *sc, int flags) xs->done = sd_flush_done; - scsi_xs_exec(xs); - if (!ISSET(xs->flags, SCSI_POLL)) { - while (!ISSET(xs->flags, ITSDONE)) - tsleep(xs, PRIBIO, "sdflush", 0); - } + do { + scsi_xs_exec(xs); + if (!ISSET(xs->flags, SCSI_POLL)) { + while (!ISSET(xs->flags, ITSDONE)) + tsleep(xs, PRIBIO, "sdflush", 0); + } + } while (xs->status == XS_NO_CCB); if (xs->error != XS_NOERROR) SC_DEBUG(sc_link, SDEV_DB1, ("cache sync failed\n")); |