Bad Day
Today was a bad day at work. I didn't get much sleep because I was up late
finishing up the st driver patch, and then it was just radically hectic at
work. Blech.
Patch is done. I've submitted a note to Theo offering it. We'll see if
he bites. Here it is:
--- /usr/src/sys/scsi/t/st.c Sun Oct 20 16:24:21 2002
+++ /usr/src/sys/scsi/st.c Wed Oct 23 14:52:40 2002
@@ -1,4 +1,4 @@
-/* $OpenBSD: st.c,v 1.29 2001/06/22 14:35:43 deraadt Exp $ */
+/* $OpenBSD: st.c,v 1.29 2002/23/10 sallot Exp $ */
/* $NetBSD: st.c,v 1.71 1997/02/21 23:03:49 thorpej Exp $ */
/*
@@ -54,6 +54,12 @@
* to be depending on whether we expect to retension or not.
*/
+/*
+ * filenumber/block support added for fsf/bsf, open, close, write, read, and eom.
+ *
+ */
+
+
#include
#include
#include
@@ -81,6 +87,11 @@
#define STUNIT(z) ((minor(z) >> 4) )
#define CTLMODE 3
+#define NORMAL_MODE 0
+#define NOREW_MODE 1
+#define EJECT_MODE 2
+#define CTRL_MODE 3
+
#define ST_IO_TIME (3 * 60 * 1000) /* 3 minutes */
#define ST_CTL_TIME (30 * 1000) /* 30 seconds */
#define ST_SPC_TIME (4 * 60 * 60 * 1000) /* 4 hours */
@@ -107,6 +118,9 @@
#define ST_Q_IGNORE_LOADS 0x0004
#define ST_Q_BLKSIZE 0x0008 /* variable-block media_blksize > 0 */
#define ST_Q_UNIMODAL 0x0010 /* unimode drive rejects mode select */
+#define ST_Q_NOPREVENT 0x0020 /* does not support PREVENT */
+#define ST_Q_ERASE_NOIMM 0x0040 /* drive rejects ERASE/w Immed bit */
+#define ST_Q_NOFILEMARKS 0x0080 /* can only write 0 filemarks */
u_int page_0_size;
#define MAX_PAGE_0_SIZE 64
struct modes modes[4];
@@ -259,6 +273,12 @@
u_int last_dsty; /* last density opened */
short mt_resid; /* last (short) resid */
short mt_erreg; /* last error (sense key) seen */
+ /* relative to beginning of tape */
+ daddr_t fileno; /* current file number */
+ daddr_t blkno;
+ int32_t last_io_resid;
+ int32_t last_ctl_resid;
+
/*--------------------device/scsi parameters----------------------------------*/
struct scsi_link *sc_link; /* our link to the adpter etc. */
/*--------------------parameters reported by the device ----------------------*/
@@ -340,11 +360,15 @@
#define ST_2FM_AT_EOD 0x0400 /* write 2 file marks at EOD */
#define ST_MOUNTED 0x0800 /* Device is presently mounted */
#define ST_DONTBUFFER 0x1000 /* Disable buffering/caching */
+#define ST_EARLYWARN 0x2000 /* Do (deferred) EOM for variable mode */
+
+#define ST_POSUPDATED 0x8000 /* tape position has been updated */
#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_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_EARLYWARN)
+#define ST_INIT_FLAGS ST_EARLYWARN
struct scsi_inquiry_pattern st_patterns[] = {
{T_SEQUENTIAL, T_REMOV,
@@ -388,6 +412,8 @@
sc_link->device_softc = st;
sc_link->openings = 1;
+ st->flags = ST_INIT_FLAGS;
+
/*
* Check if the drive is a known criminal and take
* Any steps needed to bring it into line
@@ -558,7 +584,8 @@
* mount session.
*/
if (!(st->flags & ST_MOUNTED)) {
- st_mount_tape(dev, flags);
+ if ((error = st_mount_tape(dev, flags)) !=0 )
+ goto bad;
st->last_dsty = dsty;
}
@@ -590,30 +617,80 @@
int mode;
struct proc *p;
{
+ int stxx, error=0;
struct st_softc *st = st_cd.cd_devs[STUNIT(dev)];
+ struct scsi_link *sclink = st->sc_link;
+
+
+ /*
+ * Make sure that a tape opened in write-only mode will have
+ * file marks written on it when closed, even if not written to.
+ *
+ * This is for SUN compatibility. Actually, the Sun way of
+ * things is to:
+ *
+ * only write filemarks if there are fmks to be written and
+ * - open for write (possibly read/write)
+ * - the last operation was a write
+ * or:
+ * - opened for wronly
+ * - no data was written (including filemarks)
+ */
+
+ stxx = st->flags & (ST_WRITTEN | ST_FM_WRITTEN);
+ if (((flags & FWRITE) && stxx == ST_WRITTEN) ||
+ ((flags & O_ACCMODE) == FWRITE && stxx == 0)) {
+ int nm;
+ error = st_check_eod(st, FALSE, &nm, 0);
+ }
- SC_DEBUG(st->sc_link, SDEV_DB1, ("closing\n"));
- if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
- st_write_filemarks(st, 1, 0);
switch (STMODE(dev)) {
- case 0: /* normal */
+ case NORMAL_MODE:
st_unmount(st, NOEJECT, DOREWIND);
break;
- case 3: /* eject, no rewind */
- st_unmount(st, EJECT, NOREWIND);
- break;
- case 1: /* no rewind */
- /* leave mounted unless media seems to have been removed */
- if (!(st->sc_link->flags & SDEV_MEDIA_LOADED))
- st_unmount(st, NOEJECT, NOREWIND);
+ case NOREW_MODE:
+ case CTRL_MODE:
+ /*
+ * Leave mounted unless media seems to have been removed.
+ *
+ * Otherwise, if we're to terminate a tape with more than one
+ * filemark [ and because we're not rewinding here ], backspace
+ * one filemark so that later appends will see an unbroken
+ * sequence of:
+ *
+ * file - FMK - file - FMK ... file - FMK FMK (EOM)
+ */
+ if ((sclink->flags & SDEV_MEDIA_LOADED) == 0) {
+ st_unmount(st, NOEJECT,DOREWIND);
+ } else if (error == 0) {
+ /*
+ * ST_WRITTEN was preserved from above.
+ *
+ * All we need to know here is:
+ *
+ * Were we writing this tape and was the last
+ * operation a write?
+ *
+ * Are there supposed to be 2FM at EOD?
+ *
+ * If both statements are true, then we backspace
+ * one filemark.
+ */
+ stxx |= (st->flags & ST_2FM_AT_EOD);
+ if ((flags & FWRITE) != 0 &&
+ (stxx == (ST_2FM_AT_EOD|ST_WRITTEN))) {
+ error = st_space(st, -1, SP_FILEMARKS, 0);
+ }
+ }
break;
- case 2: /* rewind, eject */
- st_unmount(st, EJECT, DOREWIND);
+ case EJECT_MODE:
+ st_unmount(st, EJECT,DOREWIND);
break;
}
- st->sc_link->flags &= ~SDEV_OPEN;
- return 0;
+ sclink->flags &= ~SDEV_OPEN;
+
+ return (error);
}
/*
@@ -715,6 +792,7 @@
st->flags &= ~ST_NEW_MOUNT;
st->flags |= ST_MOUNTED;
sc_link->flags |= SDEV_MEDIA_LOADED; /* move earlier? */
+ st->blkno = st->fileno = (daddr_t) 0;
return 0;
}
@@ -741,8 +819,12 @@
st_rewind(st, 0, SCSI_IGNORE_NOT_READY);
scsi_prevent(sc_link, PR_ALLOW,
SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY);
- if (eject)
+ if (eject) {
st_load(st, LD_UNLOAD, SCSI_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);
sc_link->flags &= ~SDEV_MEDIA_LOADED;
}
@@ -1065,6 +1147,8 @@
_lto3b(bp->b_bcount / st->blksize, cmd.len);
} else
_lto3b(bp->b_bcount, cmd.len);
+ /* clear position updated indicator */
+ st->flags &= ~ST_POSUPDATED;
/*
* go ask the adapter to do all this for us
@@ -1113,7 +1197,7 @@
struct proc *p;
{
int error = 0;
- int unit;
+ int unit,count;
int number, nmarks, dsty;
int flags;
struct st_softc *st;
@@ -1156,6 +1240,8 @@
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)
@@ -1183,11 +1269,11 @@
case MTBSF: /* backward space file */
number = -number;
case MTFSF: /* forward space file */
- error = st_check_eod(st, FALSE, &nmarks, flags);
- if (!error)
- error = st_space(st, number - nmarks,
- SP_FILEMARKS, flags);
- break;
+ error = st_check_eod(st, FALSE, &nmarks, flags);
+ if (!error)
+ error = st_space(st, number - nmarks,
+ SP_FILEMARKS, flags);
+ break;
case MTBSR: /* backward space record */
number = -number;
case MTFSR: /* forward space record */
@@ -1208,10 +1294,27 @@
if (!error)
error = st_load(st, LD_LOAD, flags);
break;
- case MTEOM: /* forward space to end of media */
- error = st_check_eod(st, FALSE, &nmarks, flags);
- if (!error)
- error = st_space(st, 1, SP_EOM, flags);
+ case MTEOM: /* rather than call SP_EOM and lose
+ * the file count, we'll just FSF once
+ * per file until we reach the end of the
+ * tape.
+ */
+ error=0;
+ count=0;
+ while ( (error==0) && (count<2000) ) {
+ /* do we think there'll be more than 2k filesets on a tape?? god I hope not */
+ error = st_check_eod(st, FALSE, &nmarks, flags);
+ if (!error)
+ error = st_space(st, 1, SP_FILEMARKS, flags);
+ count++;
+ }
+ if (error==EIO) /*
+ * good, we hit the end of the tape, BUT
+ * we don't want to produce an error output
+ * just for doing what we're supposed to..
+ *
+ */
+ error=0;
break;
case MTCACHE: /* enable controller cache */
st->flags &= ~ST_DONTBUFFER;
@@ -1575,7 +1678,7 @@
{
struct scsi_space cmd;
int error;
-
+
switch (what) {
case SP_BLKS:
if (st->flags & ST_PER_ACTION) {
@@ -1603,7 +1706,7 @@
}
break;
case SP_FILEMARKS:
- if (st->flags & ST_EIO_PENDING) {
+ if (st->flags & ST_EIO_PENDING) { /* check scsi_base */
if (number > 0) {
/* pretend we just discovered the error */
st->flags &= ~ST_EIO_PENDING;
@@ -1641,8 +1744,47 @@
cmd.byte2 = what;
_lto3b(number, cmd.number);
- return scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
+ st->flags &= ~ST_POSUPDATED;
+ st->last_ctl_resid = 0;
+
+ error=scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
sizeof(cmd), 0, 0, 0, ST_SPC_TIME, NULL, flags);
+
+ if ( (error == 0) || ((error==EIO) && (number<0)) ) {
+ /* requests still in command queue */
+ if (number>0) { /* we're counting forward */
+ number = number - st->last_ctl_resid;
+ } else if (number<0) { /* we're counting down sir! */
+ number = number + st->last_ctl_resid;
+ }
+ if (what == SP_BLKS) {
+ if (st->blkno != -1) {
+ st->blkno += number;
+ }
+ } else if (what == SP_FILEMARKS) { /* was != -1 */
+ 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.
+ * But, we should never be here.
+ */
+ st->fileno = st->blkno = -1;
+ }
+ if (st->flags & ST_POSUPDATED) { /* if we're here, there's an error. most likely end of tape data */
+ error=EIO;
+ }
+
+ }
+
+ return (error);
+
}
/*
@@ -1654,6 +1796,7 @@
int flags;
int number;
{
+ int error;
struct scsi_write_filemarks cmd;
/*
@@ -1680,8 +1823,13 @@
cmd.opcode = WRITE_FILEMARKS;
_lto3b(number, cmd.number);
- return scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
+ error=scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
sizeof(cmd), 0, 0, 0, ST_IO_TIME * 4, NULL, flags);
+ if (error == 0 && st->fileno != -1) {
+ st->fileno += number;
+ }
+ return (error);
+
}
/*
@@ -1778,9 +1926,20 @@
cmd.opcode = REWIND;
cmd.byte2 = immediate;
- return scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
+ error=scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &cmd,
sizeof(cmd), 0, 0, ST_RETRIES,
immediate ? ST_CTL_TIME: ST_SPC_TIME, NULL, 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);
+
+
}
/*
@@ -1806,19 +1965,39 @@
info = _4btol(sense->info);
else
info = xs->datalen; /* bad choice if fixed blocks */
- if ((sense->error_code & SSD_ERRCODE) != 0x70)
- return SCSIRET_CONTINUE; /* let the generic code handle it */
+
+ if ((sense->error_code & SSD_ERRCODE) != 0x70) {
+
+ return SCSIRET_CONTINUE; /* let the generic code handle it */
+ }
+
+ xs->resid = info;
+
if (st->flags & ST_FIXEDBLOCKS) {
- xs->resid = info * st->blksize;
+ if (bp) {
+ xs->resid *= st->blksize;
+ st->last_io_resid = xs->resid;
+ } else {
+ st->last_ctl_resid = xs->resid;
+ }
+
if (sense->flags & SSD_EOM) {
- st->flags |= ST_EIO_PENDING;
- if (bp)
+ st->flags |= ST_EIO_PENDING;
+ if (bp) {
bp->b_resid = xs->resid;
+ st->last_io_resid = xs->resid;
+ } else {
+ st->last_ctl_resid = xs->resid;
+ }
}
if (sense->flags & SSD_FILEMARK) {
st->flags |= ST_AT_FILEMARK;
- if (bp)
+ if (bp) {
bp->b_resid = xs->resid;
+ st->last_io_resid = xs->resid;
+ } else {
+ st->last_ctl_resid = xs->resid;
+ }
}
if (sense->flags & SSD_ILI) {
st->flags |= ST_EIO_PENDING;
@@ -1840,6 +2019,19 @@
!(sc_link->flags & SDEV_MEDIA_LOADED))
st->blksize -= 512;
}
+ if (sense->flags & SSD_EOM) {
+ st->flags |= ST_EIO_PENDING;
+ if (bp) {
+ /*
+ * 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;
+ }
+ }
/*
* If no data was tranfered, do it immediatly
*/
@@ -1853,20 +2045,36 @@
}
}
} else { /* must be variable mode */
- xs->resid = xs->datalen; /* to be sure */
- if (sense->flags & SSD_EOM)
+
+ if (bp) {
+ st->last_io_resid = xs->resid;
+ } else {
+ st->last_ctl_resid = xs->resid;
+ }
+
+ if (sense->flags & SSD_EOM) {
return EIO;
+ }
+
+ /* xs->resid = xs->datalen; */ /* to be sure we've lost our mind.. */
+
if (sense->flags & SSD_FILEMARK) {
if (bp)
bp->b_resid = bp->b_bcount;
+ if (st->fileno != (daddr_t) -1) {
+ st->fileno++;
+ st->blkno=0;
+ st->flags |= ST_POSUPDATED;
+ }
return 0;
}
+
if (sense->flags & SSD_ILI) {
if (info < 0) {
/*
* the record was bigger than the read
*/
- if ((xs->flags & SCSI_SILENT) == 0)
+ if ((xs->flags & SCSI_SILENT) == 0)
printf("%s: %d-byte record too big\n",
st->sc_dev.dv_xname,
xs->datalen - info);
@@ -1882,8 +2090,15 @@
xs->datalen);
return (EIO);
}
+ } else {
+ if (st->blkno != (daddr_t) -1) {
+ st->blkno++;
+ st->flags |= ST_POSUPDATED;
+ }
}
- xs->resid = info;
+ /* let's go ahead and corrupt the results why don't we?? */
+ /* xs->resid=info; */
+
if (bp)
bp->b_resid = info;
return 0;
@@ -1892,6 +2107,7 @@
key = sense->flags & SSD_KEY;
if (key == 0x8) {
+ printf("key = 0x8\n");
/*
* This quirk code helps the drive read the
* first tape block, regardless of format. That
@@ -1905,13 +2121,28 @@
} else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) {
st->flags |= ST_BLANK_READ;
xs->resid = xs->datalen;
+ if (st->blkno != (daddr_t) -1) {
+ if (st->blksize>0) {
+ st->blkno += (xs->datalen / st->blksize);
+ st->flags |= ST_POSUPDATED;
+ }
+ }
if (bp) {
bp->b_resid = xs->resid;
/* return an EOF */
}
+ /* lost position */
+ st->fileno = st->blkno = -1;
return 0;
}
}
+
+ /* trap this before it gets ugly. */
+ if (sense->error_code & SSD_EOM) {
+ st->flags &= ~ST_EIO_PENDING;
+ st->flags |= ST_POSUPDATED;
+ }
+
return SCSIRET_CONTINUE;
}
@@ -1981,3 +2212,4 @@
/* Not implemented. */
return ENXIO;
}
+
Well, Jim Greenlee's in town. I'm supposed to grab dinner with him, so I
better call it a night..
Posted at: 22:49 on 23/10/2002
[ / ]
#