diff options
author | briggs <briggs@cvs.openbsd.org> | 1996-01-14 21:44:31 +0000 |
---|---|---|
committer | briggs <briggs@cvs.openbsd.org> | 1996-01-14 21:44:31 +0000 |
commit | 431724c0fbbfa636c72a978587ddc06d8ee3b114 (patch) | |
tree | 8d59958cac3ed495eefb18e2de35a93e99160db6 /sys/scsi | |
parent | 0fb02d5a856594b81d3674e5f3647302ff3689e5 (diff) |
From NetBSD: (required for last change to scsi_base.c in case we get
"command aborted" status)
Handle cases like the following:
- controller calls scsi_done() with error XS_TIMEOUT
- scsi_done() calls sddone()
- sddone() calls disk_unbusy()
- scsi_done() calls controller to retry command (missing the
call to disk_busy())
- controller calls scsi_done()
- scsi_done() calls sddone()
- sddone() calls disk_busy(), which panics because of the imbalance.
Bug noticed by Leo Weppleman, who also suggested this fix; pass an additional
boolean argument ("complete") to the device's "done" routine, with a
value of `0' passed from the previous call to "done", and add an additional
call to "done" when the xfer resources are freed.
Diffstat (limited to 'sys/scsi')
-rw-r--r-- | sys/scsi/cd.c | 9 | ||||
-rw-r--r-- | sys/scsi/scsi_base.c | 17 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 10 | ||||
-rw-r--r-- | sys/scsi/sd.c | 9 |
4 files changed, 33 insertions, 12 deletions
diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c index 5645837e2e1..2b28df87dd0 100644 --- a/sys/scsi/cd.c +++ b/sys/scsi/cd.c @@ -1,4 +1,4 @@ -/* $NetBSD: cd.c,v 1.79 1996/01/07 22:03:58 thorpej Exp $ */ +/* $NetBSD: cd.c,v 1.80 1996/01/12 22:43:26 thorpej Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -103,7 +103,7 @@ void cdgetdisklabel __P((struct cd_softc *)); int cd_get_parms __P((struct cd_softc *, int)); void cdstrategy __P((struct buf *)); void cdstart __P((struct cd_softc *)); -int cddone __P((struct scsi_xfer *)); +int cddone __P((struct scsi_xfer *, int)); struct dkdriver cddkdriver = { cdstrategy }; @@ -564,12 +564,13 @@ cdstart(cd) } int -cddone(xs) +cddone(xs, complete) struct scsi_xfer *xs; + int complete; { struct cd_softc *cd = xs->sc_link->device_softc; - if (xs->bp != NULL) + if (complete && (xs->bp != NULL)) disk_unbusy(&cd->sc_dk, (xs->bp->b_bcount - xs->bp->b_resid)); return (0); diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c index 05a95a99ca0..3539a0d1511 100644 --- a/sys/scsi/scsi_base.c +++ b/sys/scsi/scsi_base.c @@ -1,4 +1,4 @@ -/* $NetBSD: scsi_base.c,v 1.30 1995/09/26 19:26:55 thorpej Exp $ */ +/* $NetBSD: scsi_base.c,v 1.31 1996/01/12 22:43:29 thorpej Exp $ */ /* * Copyright (c) 1994, 1995 Charles Hannum. All rights reserved. @@ -335,10 +335,14 @@ scsi_done(xs) * If the device has it's own done routine, call it first. * If it returns a legit error value, return that, otherwise * it wants us to continue with normal processing. + * + * Make sure the upper-level driver knows that this might not + * actually be the last time they hear from us. We need to get + * status back. */ if (sc_link->device->done) { SC_DEBUG(sc_link, SDEV_DB2, ("calling private done()\n")); - error = (*sc_link->device->done) (xs); + error = (*sc_link->device->done)(xs, 0); if (error == EJUSTRETURN) goto done; SC_DEBUG(sc_link, SDEV_DB3, ("continuing with generic done()\n")); @@ -369,6 +373,15 @@ retry: } } done: + if (sc_link->device->done) { + /* + * Tell the device the operation is actually complete. + * No more will happen with this xfer. This for + * notification of the upper-level driver only; they + * won't be returning any meaningful information to us. + */ + (void)(*sc_link->device->done)(xs, 1); + } scsi_free_xs(xs, SCSI_NOSLEEP); } diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h index e48537042db..ef5e32aaa5a 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -1,4 +1,4 @@ -/* $NetBSD: scsiconf.h,v 1.25 1995/08/12 20:31:44 mycroft Exp $ */ +/* $NetBSD: scsiconf.h,v 1.26 1996/01/12 22:43:31 thorpej Exp $ */ /* * Copyright (c) 1993, 1994, 1995 Charles Hannum. All rights reserved. @@ -114,7 +114,13 @@ struct scsi_device { int (*err_handler)(); /* returns -1 to say err processing done */ void (*start)(); int (*async)(); - int (*done)(); /* returns -1 to say done processing done */ + /* + * When called with `0' as the second argument, we expect status + * back from the upper-level driver. When called with a `1', + * we're simply notifying the upper-level driver that the command + * is complete and expect no status back. + */ + int (*done)( /* struct scsi_xfer *, int */ ); }; /* diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index f67911b16ab..d234fb037e3 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,4 +1,4 @@ -/* $NetBSD: sd.c,v 1.84 1996/01/07 22:04:02 thorpej Exp $ */ +/* $NetBSD: sd.c,v 1.85 1996/01/12 22:43:33 thorpej Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -107,7 +107,7 @@ void sdgetdisklabel __P((struct sd_softc *)); int sd_get_parms __P((struct sd_softc *, int)); void sdstrategy __P((struct buf *)); void sdstart __P((struct sd_softc *)); -int sddone __P((struct scsi_xfer *)); +int sddone __P((struct scsi_xfer *, int)); void sdminphys __P((struct buf *)); struct dkdriver sddkdriver = { sdstrategy }; @@ -589,12 +589,13 @@ sdstart(sd) } int -sddone(xs) +sddone(xs, complete) struct scsi_xfer *xs; + int complete; { struct sd_softc *sd = xs->sc_link->device_softc; - if (xs->bp != NULL) + if (complete && (xs->bp != NULL)) disk_unbusy(&sd->sc_dk, (xs->bp->b_bcount - xs->bp->b_resid)); return (0); |