summaryrefslogtreecommitdiff
path: root/sys/scsi
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2007-11-16 11:28:35 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2007-11-16 11:28:35 +0000
commit2543f607b8d1a1fbbb7a035b5cd301fb2e9c7605 (patch)
tree3ae51c7ecf2b4ecc89e1a87351af5e1dd4a446bd /sys/scsi
parent5109b2fb3d6cda0a022db618385432ba06798248 (diff)
convert code over from sd.c, to let tapes discollect. Lucas Stefanutti
of pr 5635 confirms this works for him. similar diff authored by krw who was unaware i wrote this and mailed it to Lucas...
Diffstat (limited to 'sys/scsi')
-rw-r--r--sys/scsi/st.c117
1 files changed, 106 insertions, 11 deletions
diff --git a/sys/scsi/st.c b/sys/scsi/st.c
index c64f4623cbe..f59332646fc 100644
--- a/sys/scsi/st.c
+++ b/sys/scsi/st.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: st.c,v 1.76 2007/09/16 15:54:52 krw Exp $ */
+/* $OpenBSD: st.c,v 1.77 2007/11/16 11:28:34 deraadt Exp $ */
/* $NetBSD: st.c,v 1.71 1997/02/21 23:03:49 thorpej Exp $ */
/*
@@ -69,6 +69,7 @@
#include <sys/mtio.h>
#include <sys/device.h>
#include <sys/conf.h>
+#include <sys/vnode.h>
#include <scsi/scsi_all.h>
#include <scsi/scsi_tape.h>
@@ -187,35 +188,35 @@ const struct st_quirk_inquiry_pattern st_quirk_patterns[] = {
struct st_softc {
struct device sc_dev;
-/*--------------------present operating parameters, flags etc.----------------*/
+
int flags; /* see below */
u_int quirks; /* quirks for the open mode */
int blksize; /* blksize we are using */
u_int8_t density; /* present density */
short mt_resid; /* last (short) resid */
short mt_erreg; /* last error (sense key) seen */
-/*--------------------device/scsi parameters----------------------------------*/
+
struct scsi_link *sc_link; /* our link to the adpter etc. */
-/*--------------------parameters reported by the device ----------------------*/
+
int blkmin; /* min blk size */
int blkmax; /* max blk size */
const struct quirkdata *quirkdata; /* if we have a rogue entry */
-/*--------------------parameters reported by the device for this media--------*/
+
u_int64_t numblks; /* nominal blocks capacity */
u_int32_t media_blksize; /* 0 if not ST_FIXEDBLOCKS */
u_int32_t media_density; /* this is what it said when asked */
int media_fileno; /* relative to BOT. -1 means unknown. */
int media_blkno; /* relative to BOF. -1 means unknown. */
-/*--------------------quirks for the whole drive------------------------------*/
+
u_int drive_quirks; /* quirks of this drive */
-/*--------------------How we should set up when opening each minor device----*/
+
struct modes modes; /* plus more for each mode */
u_int8_t modeflags; /* flags for the modes */
#define DENSITY_SET_BY_USER 0x01
#define DENSITY_SET_BY_QUIRK 0x02
#define BLKSIZE_SET_BY_USER 0x04
#define BLKSIZE_SET_BY_QUIRK 0x08
-/*--------------------storage for sense data returned by the drive------------*/
+
struct buf buf_queue; /* the queue of pending IO operations */
struct timeout sc_timeout;
};
@@ -223,6 +224,10 @@ struct st_softc {
int stmatch(struct device *, void *, void *);
void stattach(struct device *, struct device *, void *);
+int stactivate(struct device *, enum devact);
+int stdetach(struct device *, int);
+
+void st_kill_buffers(struct st_softc *);
void st_identify_drive(struct st_softc *, struct scsi_inquiry_data *);
void st_loadquirks(struct st_softc *);
int st_mount_tape(dev_t, int);
@@ -244,7 +249,8 @@ int st_touch_tape(struct st_softc *);
int st_erase(struct st_softc *, int, int);
struct cfattach st_ca = {
- sizeof(struct st_softc), stmatch, stattach
+ sizeof(struct st_softc), stmatch, stattach,
+ stdetach, stactivate
};
struct cfdriver st_cd = {
@@ -270,6 +276,7 @@ struct scsi_device st_switch = {
* ~ST_WRITTEN to indicate that multiple file
* marks have been written
*/
+#define ST_DYING 0x40 /* dying, when deactivated */
#define ST_BLANK_READ 0x0200 /* BLANK CHECK encountered already */
#define ST_2FM_AT_EOD 0x0400 /* write 2 file marks at EOD */
#define ST_MOUNTED 0x0800 /* Device is presently mounted */
@@ -349,6 +356,54 @@ stattach(parent, self, aux)
sc_link->flags &= ~SDEV_MEDIA_LOADED;
}
+int
+stactivate(struct device *self, enum devact act)
+{
+ struct st_softc *st = (struct st_softc *)self;
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ break;
+
+ case DVACT_DEACTIVATE:
+ st->flags |= ST_DYING;
+ st_kill_buffers(st);
+ break;
+ }
+
+ return (rv);
+}
+
+int
+stdetach(struct device *self, int flags)
+{
+ struct st_softc *st = (struct st_softc *)self;
+ int bmaj, cmaj, mn;
+
+ st_kill_buffers(st);
+
+ /* Locate the lowest minor number to be detached. */
+ mn = STUNIT(self->dv_unit);
+
+ for (bmaj = 0; bmaj < nblkdev; bmaj++)
+ if (bdevsw[bmaj].d_open == sdopen) {
+ vdevgone(bmaj, mn, mn + 0, VBLK);
+ vdevgone(bmaj, mn, mn + 1, VBLK);
+ vdevgone(bmaj, mn, mn + 2, VBLK);
+ vdevgone(bmaj, mn, mn + 3, VBLK);
+ }
+ for (cmaj = 0; cmaj < nchrdev; cmaj++)
+ if (cdevsw[cmaj].d_open == sdopen) {
+ vdevgone(cmaj, mn, mn + 0, VCHR);
+ vdevgone(cmaj, mn, mn + 1, VCHR);
+ vdevgone(cmaj, mn, mn + 2, VCHR);
+ vdevgone(cmaj, mn, mn + 3, VCHR);
+ }
+
+ return (0);
+}
+
/*
* Use the inquiry routine in 'scsi_base' to get drive info so we can
* Further tailor our behaviour.
@@ -421,6 +476,10 @@ stopen(dev, flags, fmt, p)
st = st_cd.cd_devs[unit];
if (!st)
return (ENXIO);
+ if ((st->flags & ST_DYING)) {
+ device_unref(&st->sc_dev);
+ return (ENXIO);
+ }
sc_link = st->sc_link;
@@ -491,6 +550,10 @@ stclose(dev, flags, mode, p)
struct st_softc *st = st_cd.cd_devs[STUNIT(dev)];
SC_DEBUG(st->sc_link, SDEV_DB1, ("closing\n"));
+ if (st->flags & ST_DYING) {
+ device_unref(&st->sc_dev);
+ return (ENXIO);
+ }
if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
st_write_filemarks(st, 1, 0);
switch (STMODE(dev)) {
@@ -777,6 +840,11 @@ ststrategy(bp)
SC_DEBUG(st->sc_link, SDEV_DB2, ("ststrategy: %ld bytes @ blk %d\n",
bp->b_bcount, bp->b_blkno));
+
+ if (st->flags & ST_DYING) {
+ bp->b_error = ENXIO;
+ goto bad;
+ }
/*
* If it's a null transfer, return immediately.
*/
@@ -863,6 +931,9 @@ ststart(v)
SC_DEBUG(sc_link, SDEV_DB2, ("ststart\n"));
+ if (st->flags & ST_DYING)
+ return;
+
splassert(IPL_BIO);
/*
@@ -1059,6 +1130,11 @@ stioctl(dev, cmd, arg, flag, p)
struct mtop *mt = (struct mtop *) arg;
int number;
+ if (st->flags & ST_DYING) {
+ device_unref(&st->sc_dev);
+ return (ENXIO);
+ }
+
/*
* Find the device that the user is talking about
*/
@@ -1210,7 +1286,6 @@ stioctl(dev, cmd, arg, flag, p)
break;
}
return error;
-/*-----------------------------*/
try_new_value:
/*
* Check that the mode being asked for is aggreeable to the
@@ -1825,7 +1900,7 @@ st_interpret_sense(xs)
* in this case we do not allow xs->retries to be decremented
* only on the "Unit Becoming Ready" case. This is because tape
* drives report "Unit Becoming Ready" when loading media, etc.
- * and can take a long time. Rather than having a massive timeout
+ * and can take a long time. Rather than having a massive timeout
* for all operations (which would cause other problems) we allow
* operations to wait (but be interruptable with Ctrl-C) forever
* as long as the drive is reporting that it is becoming ready.
@@ -2042,3 +2117,23 @@ stdump(dev, blkno, va, size)
/* Not implemented. */
return ENXIO;
}
+
+/*
+ * Remove unprocessed buffers from queue.
+ */
+void
+st_kill_buffers(struct st_softc *st)
+{
+ struct buf *dp, *bp;
+ int s;
+
+ s = splbio();
+ for (dp = &st->buf_queue; (bp = dp->b_actf) != NULL; ) {
+ dp->b_actf = bp->b_actf;
+
+ bp->b_error = ENXIO;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ }
+ splx(s);
+}