From NetBSD: (required for last change to scsi_base.c in case we get
authorbriggs <briggs@openbsd.org>
Sun, 14 Jan 1996 21:44:26 +0000 (21:44 +0000)
committerbriggs <briggs@openbsd.org>
Sun, 14 Jan 1996 21:44:26 +0000 (21:44 +0000)
      "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.

sys/scsi/cd.c
sys/scsi/scsi_base.c
sys/scsi/scsiconf.h
sys/scsi/sd.c

index 5645837..2b28df8 100644 (file)
@@ -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);
index 05a95a9..3539a0d 100644 (file)
@@ -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);
 }
 
index e485370..ef5e32a 100644 (file)
@@ -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 */ );
 };
 
 /*
index f67911b..d234fb0 100644 (file)
@@ -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);