summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorchristos <christos@NetBSD.org>2002-03-20 14:53:59 +0000
committerchristos <christos@NetBSD.org>2002-03-20 14:53:59 +0000
commite5160e810ec951fdff6c5f2b7c8acbdc2069d887 (patch)
tree262bb970370d203f363b8db98a8eedc484a2b6a2 /sys/dev
parent748ed9bd8fb5257954f1b0e2442589c535172168 (diff)
Add the ability to report file number/block number. From Matt Jacob.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/scsipi/st.c203
-rw-r--r--sys/dev/scsipi/stvar.h10
2 files changed, 169 insertions, 44 deletions
diff --git a/sys/dev/scsipi/st.c b/sys/dev/scsipi/st.c
index 9e0fe1169c4..c953d485f3a 100644
--- a/sys/dev/scsipi/st.c
+++ b/sys/dev/scsipi/st.c
@@ -1,4 +1,4 @@
-/* $NetBSD: st.c,v 1.149 2002/01/12 20:30:11 bouyer Exp $ */
+/* $NetBSD: st.c,v 1.150 2002/03/20 14:53:59 christos Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -57,7 +57,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: st.c,v 1.149 2002/01/12 20:30:11 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: st.c,v 1.150 2002/03/20 14:53:59 christos Exp $");
#include "opt_scsi.h"
@@ -689,6 +689,10 @@ stopen(dev, flags, mode, p)
goto bad;
st->last_dsty = dsty;
}
+ if (!(st->quirks & ST_Q_NOPREVENT)) {
+ scsipi_prevent(periph, PR_PREVENT,
+ XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_NOT_READY);
+ }
SC_DEBUG(periph, SCSIPI_DB2, ("open complete\n"));
return (0);
@@ -740,6 +744,12 @@ stclose(dev, flags, mode, p)
error = st_check_eod(st, FALSE, &nm, 0);
}
+ /*
+ * Allow robots to eject tape if needed.
+ */
+ scsipi_prevent(periph, PR_ALLOW,
+ XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_NOT_READY);
+
switch (STMODE(dev)) {
case NORMAL_MODE:
st_unmount(st, NOEJECT);
@@ -886,14 +896,10 @@ st_mount_tape(dev, flags)
return (error);
}
}
- if (!(st->quirks & ST_Q_NOPREVENT)) {
- scsipi_prevent(periph, PR_PREVENT,
- XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_NOT_READY);
- }
st->flags &= ~ST_NEW_MOUNT;
st->flags |= ST_MOUNTED;
periph->periph_flags |= PERIPH_MEDIA_LOADED; /* move earlier? */
-
+ st->blkno = st->fileno = (daddr_t) 0;
return (0);
}
@@ -933,10 +939,12 @@ st_unmount(st, eject)
st->sc_dev.dv_xname);
}
- scsipi_prevent(periph, PR_ALLOW,
- XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_NOT_READY);
- if (eject)
+ if (eject) {
st_load(st, LD_UNLOAD, XS_CTL_IGNORE_NOT_READY);
+ st->blkno = st->fileno = (daddr_t) -1;
+ } else {
+ st->blkno = st->fileno = (daddr_t) 0;
+ }
st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT);
periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
}
@@ -1253,6 +1261,11 @@ ststart(periph)
_lto3b(bp->b_bcount, cmd.len);
/*
+ * Clear 'position updated' indicator
+ */
+ st->flags &= ~ST_POSUPDATED;
+
+ /*
* go ask the adapter to do all this for us
*/
error = scsipi_command(periph,
@@ -1281,6 +1294,19 @@ stdone(xs)
#if NRND > 0
rnd_add_uint32(&st->rnd_source, xs->bp->b_blkno);
#endif
+
+ if ((st->flags & ST_POSUPDATED) == 0) {
+ if (xs->bp->b_flags & B_ERROR) {
+ st->fileno = st->blkno = -1;
+ } else if (st->blkno != -1) {
+ if (st->flags & ST_FIXEDBLOCKS) {
+ st->blkno +=
+ (xs->bp->b_bcount / st->blksize);
+ } else {
+ st->blkno++;
+ }
+ }
+ }
}
}
@@ -1369,6 +1395,8 @@ stioctl(dev, cmd, arg, flag, p)
g->mt_mdensity[1] = st->modes[1].density;
g->mt_mdensity[2] = st->modes[2].density;
g->mt_mdensity[3] = st->modes[3].density;
+ g->mt_fileno = st->fileno;
+ g->mt_blkno = st->blkno;
if (st->flags & ST_READONLY)
g->mt_dsreg |= MT_DS_RDONLY;
if (st->flags & ST_MOUNTED)
@@ -1713,9 +1741,35 @@ st_space(st, number, what, flags)
cmd.byte2 = what;
_lto3b(number, cmd.number);
- return (scsipi_command(st->sc_periph,
+ st->flags &= ~ST_POSUPDATED;
+ st->last_ctl_resid = 0;
+ error = scsipi_command(st->sc_periph,
(struct scsipi_generic *)&cmd, sizeof(cmd),
- 0, 0, 0, ST_SPC_TIME, NULL, flags));
+ 0, 0, 0, ST_SPC_TIME, NULL, flags);
+
+ if (error == 0 && (st->flags & ST_POSUPDATED) == 0) {
+ number = number - st->last_ctl_resid;
+ if (what == SP_BLKS) {
+ if (st->blkno != -1) {
+ st->blkno += number;
+ }
+ } else if (what == SP_FILEMARKS) {
+ if (st->fileno != -1) {
+ st->fileno += number;
+ if (number > 0) {
+ st->blkno = 0;
+ } else if (number < 0) {
+ st->blkno = -1;
+ }
+ }
+ } else if (what == SP_EOM) {
+ /*
+ * This loses us relative position.
+ */
+ st->fileno = st->blkno = -1;
+ }
+ }
+ return (error);
}
/*
@@ -1727,6 +1781,7 @@ st_write_filemarks(st, number, flags)
int flags;
int number;
{
+ int error;
struct scsi_write_filemarks cmd;
/*
@@ -1760,9 +1815,14 @@ st_write_filemarks(st, number, flags)
if ((st->quirks & ST_Q_NOFILEMARKS) == 0)
_lto3b(number, cmd.number);
- return (scsipi_command(st->sc_periph,
+ /* XXX WE NEED TO BE ABLE TO GET A RESIDIUAL XXX */
+ error = scsipi_command(st->sc_periph,
(struct scsipi_generic *)&cmd, sizeof(cmd),
- 0, 0, 0, ST_IO_TIME * 4, NULL, flags));
+ 0, 0, 0, ST_IO_TIME * 4, NULL, flags);
+ if (error == 0 && st->fileno != -1) {
+ st->fileno += number;
+ }
+ return (error);
}
/*
@@ -1884,6 +1944,10 @@ st_rewind(st, immediate, flags)
if (error) {
printf("%s: error %d trying to rewind\n",
st->sc_dev.dv_xname, error);
+ /* lost position */
+ st->fileno = st->blkno = -1;
+ } else {
+ st->fileno = st->blkno = 0;
}
return (error);
}
@@ -1899,17 +1963,28 @@ st_rdpos(st, hard, blkptr)
struct scsi_tape_read_position cmd;
/*
- * First flush any pending writes...
+ * We try and flush any buffered writes here if we were writing
+ * and we're trying to get hardware block position. It eats
+ * up performance substantially, but I'm wary of drive firmware.
+ *
+ * I think that *logical* block position is probably okay-
+ * but hardware block position might have to wait for data
+ * to hit media to be valid. Caveat Emptor.
*/
- error = st_write_filemarks(st, 0, XS_CTL_SILENT);
- /*
- * The latter case is for 'write protected' tapes
- * which are too stupid to recognize a zero count
- * for writing filemarks as a no-op.
- */
- if (error != 0 && error != EACCES && error != EROFS)
- return (error);
+ if (hard && (st->flags & ST_WRITTEN)) {
+ /*
+ * First flush any pending writes...
+ */
+ error = st_write_filemarks(st, 0, XS_CTL_SILENT);
+ /*
+ * The latter case is for 'write protected' tapes
+ * which are too stupid to recognize a zero count
+ * for writing filemarks as a no-op.
+ */
+ if (error != 0 && error != EACCES && error != EROFS)
+ return (error);
+ }
memset(&cmd, 0, sizeof(cmd));
memset(&posdata, 0, sizeof(posdata));
@@ -1947,19 +2022,14 @@ st_setpos(st, hard, blkptr)
struct scsi_tape_locate cmd;
/*
- * First flush any pending writes. Strictly speaking,
- * we're not supposed to have to worry about this,
- * but let's be untrusting.
- */
- error = st_write_filemarks(st, 0, XS_CTL_SILENT);
-
- /*
- * The latter case is for 'write protected' tapes
- * which are too stupid to recognize a zero count
- * for writing filemarks as a no-op.
+ * We used to try and flush any buffered writes here.
+ * Now we push this onto user applications to either
+ * flush the pending writes themselves (via a zero count
+ * WRITE FILEMARKS command) or they can trust their tape
+ * drive to do this correctly for them.
+ *
+ * There are very ugly performance limitations otherwise.
*/
- if (error != 0 && error != EACCES && error != EROFS)
- return (error);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = LOCATE;
@@ -1970,9 +2040,10 @@ st_setpos(st, hard, blkptr)
(struct scsipi_generic *)&cmd, sizeof(cmd),
NULL, 0, ST_RETRIES, ST_SPC_TIME, NULL, 0);
/*
- * XXX: Note file && block number position now unknown (if
- * XXX: these things ever start being maintained in this driver)
+ * Note file && block number position now unknown (if
+ * these things ever start being maintained in this driver)
*/
+ st->fileno = st->blkno = -1;
return (error);
}
@@ -2030,20 +2101,45 @@ st_interpret_sense(xs)
return (retval);
}
-
+ xs->resid = info;
if (st->flags & ST_FIXEDBLOCKS) {
- xs->resid = info * st->blksize;
- if (sense->flags & SSD_EOM) {
+ if (bp) {
+ xs->resid *= st->blksize;
+ st->last_io_resid = xs->resid;
+ } else {
+ st->last_ctl_resid = xs->resid;
+ }
+ if (key == SKEY_VOLUME_OVERFLOW) {
+ st->flags |= ST_EIO_PENDING;
+ if (bp)
+ bp->b_resid = xs->resid;
+ } else if (sense->flags & SSD_EOM) {
if ((st->flags & ST_EARLYWARN) == 0)
st->flags |= ST_EIO_PENDING;
st->flags |= ST_EOM_PENDING;
- if (bp)
+ if (bp) {
+#if 0
bp->b_resid = xs->resid;
+#else
+ /*
+ * Grotesque as it seems, the few times
+ * I've actually seen a non-zero resid,
+ * the tape drive actually lied and had
+ * written all the data!
+ */
+ bp->b_resid = 0;
+#endif
+ }
}
if (sense->flags & SSD_FILEMARK) {
st->flags |= ST_AT_FILEMARK;
if (bp)
bp->b_resid = xs->resid;
+ if (st->fileno != (daddr_t) -1) {
+ st->fileno++;
+ st->blkno = 0;
+ st->flags |= ST_POSUPDATED;
+ }
}
if (sense->flags & SSD_ILI) {
st->flags |= ST_EIO_PENDING;
@@ -2064,6 +2160,13 @@ st_interpret_sense(xs)
if ((st->quirks & ST_Q_SENSE_HELP) &&
(periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)
st->blksize -= 512;
+ else if ((st->flags & ST_POSUPDATED) == 0) {
+ if (st->blkno != (daddr_t) -1) {
+ st->blkno +=
+ (xs->datalen / st->blksize);
+ st->flags |= ST_POSUPDATED;
+ }
+ }
}
/*
* If data wanted and no data was transferred, do it immediately
@@ -2078,6 +2181,11 @@ st_interpret_sense(xs)
}
}
} else { /* must be variable mode */
+ if (bp) {
+ st->last_io_resid = xs->resid;
+ } else {
+ st->last_ctl_resid = xs->resid;
+ }
if (sense->flags & SSD_EOM) {
/*
* The current semantics of this
@@ -2103,6 +2211,11 @@ st_interpret_sense(xs)
}
} else if (sense->flags & SSD_FILEMARK) {
retval = 0;
+ if (st->fileno != (daddr_t) -1) {
+ st->fileno++;
+ st->blkno = 0;
+ st->flags |= ST_POSUPDATED;
+ }
} else if (sense->flags & SSD_ILI) {
if (info < 0) {
/*
@@ -2118,9 +2231,12 @@ st_interpret_sense(xs)
retval = EIO;
} else {
retval = 0;
+ if (st->blkno != (daddr_t) -1) {
+ st->blkno++;
+ st->flags |= ST_POSUPDATED;
+ }
}
}
- xs->resid = info;
if (bp)
bp->b_resid = info;
}
@@ -2148,6 +2264,8 @@ st_interpret_sense(xs)
/* return an EOF */
}
retval = 0;
+ /* lost position */
+ st->fileno = st->blkno = -1;
}
}
@@ -2171,6 +2289,7 @@ st_interpret_sense(xs)
case SKEY_UNIT_ATTENTION:
case SKEY_WRITE_PROTECT:
break;
+ case SKEY_VOLUME_OVERFLOW:
case SKEY_BLANK_CHECK:
printf(", requested size: %d (decimal)", info);
break;
diff --git a/sys/dev/scsipi/stvar.h b/sys/dev/scsipi/stvar.h
index 78fe809d6e6..d79cb99fa7d 100644
--- a/sys/dev/scsipi/stvar.h
+++ b/sys/dev/scsipi/stvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: stvar.h,v 1.4 2001/12/07 11:26:31 yamt Exp $ */
+/* $NetBSD: stvar.h,v 1.5 2002/03/20 14:54:00 christos Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -114,6 +114,11 @@ struct st_softc {
u_int last_dsty; /* last density opened */
short mt_resid; /* last (short) resid */
short mt_erreg; /* last error (sense key) seen */
+ /* relative to BOT location */
+ daddr_t fileno;
+ daddr_t blkno;
+ int32_t last_io_resid;
+ int32_t last_ctl_resid;
#define mt_key mt_erreg
u_int8_t asc; /* last asc code seen */
u_int8_t ascq; /* last asc code seen */
@@ -167,12 +172,13 @@ struct st_softc {
#define ST_DONTBUFFER 0x1000 /* Disable buffering/caching */
#define ST_EARLYWARN 0x2000 /* Do (deferred) EOM for variable mode */
#define ST_EOM_PENDING 0x4000 /* EOM reporting deferred until next op */
+#define ST_POSUPDATED 0x8000 /* tape position already updated */
#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_EOM_PENDING | \
ST_BLANK_READ)
#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
ST_FIXEDBLOCKS | ST_READONLY | ST_FM_WRITTEN | \
- ST_2FM_AT_EOD | ST_PER_ACTION)
+ ST_2FM_AT_EOD | ST_PER_ACTION | ST_POSUPDATED)
void stattach __P((struct device *, struct st_softc *, void *));
int stactivate __P((struct device *, enum devact));