diff --git a/sys/dev/scsipi/st.c b/sys/dev/scsipi/st.c index 9e0fe1169c41..c953d485f3aa 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 -__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; } @@ -1252,6 +1260,11 @@ ststart(periph) } 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 */ @@ -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. + * 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. */ - 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)); 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 78fe809d6e6d..d79cb99fa7d8 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));