summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/scsi/sd.c35
-rw-r--r--sys/scsi/sdvar.h3
2 files changed, 36 insertions, 2 deletions
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
index 275e17e93af..e7b8ed619f1 100644
--- a/sys/scsi/sd.c
+++ b/sys/scsi/sd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sd.c,v 1.244 2012/10/15 16:29:07 deraadt Exp $ */
+/* $OpenBSD: sd.c,v 1.245 2012/12/19 19:52:11 kettenis Exp $ */
/* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */
/*-
@@ -87,6 +87,7 @@ int sddetach(struct device *, int);
void sdminphys(struct buf *);
int sdgetdisklabel(dev_t, struct sd_softc *, struct disklabel *, int);
void sdstart(struct scsi_xfer *);
+void sd_shutdown(void *);
int sd_interpret_sense(struct scsi_xfer *);
int sd_read_cap_10(struct sd_softc *, int);
int sd_read_cap_16(struct sd_softc *, int);
@@ -259,6 +260,19 @@ sdattach(struct device *parent, struct device *self, void *aux)
sd_ioctl_cache(sc, DIOCSCACHE, &dkc);
}
+ /*
+ * Establish a shutdown hook so that we can ensure that
+ * our data has actually made it onto the platter at
+ * shutdown time. Note that this relies on the fact
+ * that the shutdown hook code puts us at the head of
+ * the list (thus guaranteeing that our hook runs before
+ * our ancestors').
+ */
+ if ((sc->sc_sdhook =
+ shutdownhook_establish(sd_shutdown, sc)) == NULL)
+ printf("%s: WARNING: unable to establish shutdown hook\n",
+ sc->sc_dev.dv_xname);
+
/* Attach disk. */
disk_attach(&sc->sc_dev, &sc->sc_dk);
}
@@ -311,6 +325,10 @@ sddetach(struct device *self, int flags)
disk_gone(sdopen, self->dv_unit);
+ /* Get rid of the shutdown hook. */
+ if (sc->sc_sdhook != NULL)
+ shutdownhook_disestablish(sc->sc_sdhook);
+
/* Detach disk. */
bufq_destroy(&sc->sc_bufq);
disk_detach(&sc->sc_dk);
@@ -1109,6 +1127,21 @@ sdgetdisklabel(dev_t dev, struct sd_softc *sc, struct disklabel *lp,
return readdisklabel(DISKLABELDEV(dev), sdstrategy, lp, spoofonly);
}
+
+void
+sd_shutdown(void *arg)
+{
+ struct sd_softc *sc = (struct sd_softc *)arg;
+
+ /*
+ * If the disk cache needs to be flushed, and the disk supports
+ * it, flush it. We're cold at this point, so we poll for
+ * completion.
+ */
+ if ((sc->flags & SDF_DIRTY) != 0)
+ sd_flush(sc, SCSI_AUTOCONF);
+}
+
/*
* Check Errors
*/
diff --git a/sys/scsi/sdvar.h b/sys/scsi/sdvar.h
index 4e2accdfde1..220190965ad 100644
--- a/sys/scsi/sdvar.h
+++ b/sys/scsi/sdvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdvar.h,v 1.39 2012/10/08 21:47:51 deraadt Exp $ */
+/* $OpenBSD: sdvar.h,v 1.40 2012/12/19 19:52:11 kettenis Exp $ */
/* $NetBSD: sdvar.h,v 1.7 1998/08/17 00:49:03 mycroft Exp $ */
/*-
@@ -69,6 +69,7 @@ struct sd_softc {
u_int32_t unmap_sectors; /* maximum sectors/unmap */
u_int32_t unmap_descs; /* maximum descriptors/unmap */
} params;
+ void *sc_sdhook; /* our shutdown hook */
struct timeout sc_timeout;
struct scsi_xshandler sc_xsh;