Overhaul the tz SCSI tape driver:

+ Add a quirk table.
 + Assume all else is a modern drive that can do variable block
   lengths (this is the main reason for this work - the old driver
   only ever seemed to write 512 byte blocks!).
 + Keep track of values for mtget's mt_fileno, mt_blkno.
 + Handle a few extra MTIOCTOP commands.

Ideas gleaned from our MI scsi tape driver and the FreeBSD CAM tape
driver.  Tested on a TKZ09 (DEC badged Exabyte 8500), a TLZ06 (DEC
DAT) and TK50.

Many thanks to Pierre Bergdolt for helping with testing.
This commit is contained in:
simonb 1999-09-07 13:53:36 +00:00
parent 1e99130f2e
commit a68944cfca
1 changed files with 315 additions and 242 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: tz.c,v 1.20 1999/08/31 01:12:52 simonb Exp $ */
/* $NetBSD: tz.c,v 1.21 1999/09/07 13:53:36 simonb Exp $ */
/*
* Copyright (c) 1992, 1993
@ -65,11 +65,12 @@
#include <pmax/dev/device.h>
#include <pmax/dev/scsi.h>
int tzprobe __P(( void *sd /*struct pmax_scsi_device *sd*/));
int tzcommand __P((dev_t dev, int command, int code,
static int tzprobe __P((void *sd /*struct pmax_scsi_device *sd*/));
static int tzcommand __P((dev_t dev, int command, int code,
int count, caddr_t data));
void tzstart __P((int unit));
void tzdone __P((int unit, int error, int resid, int status));
static void tzstart __P((int unit));
static void tzdone __P((int unit, int error, int resid, int status));
static int tzmount __P((dev_t dev));
struct pmax_driver tzdriver = {
"tz", tzprobe,
@ -77,14 +78,37 @@ struct pmax_driver tzdriver = {
tzdone,
};
struct tzmodes {
u_int quirks;
u_int8_t density;
};
struct tzquirk {
char *product;
u_int page_0_size;
u_int quirks;
int blklen;
struct tzmodes modes[2]; /* low density, high density */
};
#define TZ_Q_FORCE_BLKSIZE 0x0001
#define TZ_Q_SENSE_HELP 0x0002 /* must do READ for good MODE SENSE */
#define TZ_Q_IGNORE_LOADS 0x0004
#define TZ_Q_BLKSIZE 0x0008 /* variable-block media_blksize > 0 */
#define TZ_Q_UNIMODAL 0x0010 /* unimode drive rejects mode select */
#define TZ_Q_DENSITY 0x0020 /* density codes valid */
#define MAX_PAGE_0_SIZE 64
struct tz_softc {
struct device sc_dev; /* new config glue */
struct pmax_scsi_device *sc_sd; /* physical unit info */
int sc_flags; /* see below */
int sc_tapeid; /* tape drive id */
int sc_blklen; /* 0 = variable len records */
long sc_numblks; /* number of blocks on tape */
tpr_t sc_ctty; /* terminal for error messages */
daddr_t sc_fileno; /* file number of current position */
daddr_t sc_blkno; /* block number of current position */
struct buf sc_tab; /* queue of pending operations */
struct buf sc_buf; /* buf for doing I/O */
struct buf sc_errbuf; /* buf for doing REQUEST_SENSE */
@ -94,16 +118,21 @@ struct tz_softc {
struct scsi_fmt_sense sc_sense; /* sense data from last cmd */
struct ScsiTapeModeSelectHdr sc_mode; /* SCSI_MODE_SENSE data */
char sc_modelen; /* SCSI_MODE_SENSE data length */
struct tzquirk *sc_quirks; /* quirks for this drive */
} tz_softc[NTZ];
/* sc_flags values */
#define TZF_ALIVE 0x01 /* drive found and ready */
#define TZF_SENSEINPROGRESS 0x02 /* REQUEST_SENSE command in progress */
#define TZF_ALTCMD 0x04 /* alternate command in progress */
#define TZF_WRITTEN 0x08 /* tape has been written to */
#define TZF_OPEN 0x10 /* device is open */
#define TZF_WAIT 0x20 /* waiting for sc_tab to drain */
#define TZF_SEENEOF 0x40 /* seen file mark on read */
#define TZF_ALIVE 0x001 /* drive found and ready */
#define TZF_MOUNTED 0x002 /* device is presently mounted */
#define TZF_OPEN 0x004 /* device is open */
#define TZF_SENSEINPROGRESS 0x008 /* REQUEST_SENSE command in progress */
#define TZF_ALTCMD 0x010 /* alternate command in progress */
#define TZF_WRITTEN 0x020 /* tape has been written to */
#define TZF_WAIT 0x040 /* waiting for sc_tab to drain */
#define TZF_SEENEOF 0x080 /* seen file mark on read */
#define TZF_RDONLY 0x100 /* mode sense says write protected */
#define TZF_DONTCOUNT 0x200 /* operation isn't to be counted for sc_blkno */
/* bits in minor device */
#define tzunit(x) (minor(x) >> 4) /* tz%d unit number */
@ -117,19 +146,58 @@ int tzdebug = 0;
#endif
struct tzquirk tz_quirk_table[] = {
{ "EXB-8200", 17, 0, 0, {
{ 0, 0,},
{ 0, 0,}
}},
{ "TZK08", 17, 0, 0, {
{ 0, 0,},
{ 0, 0,}
}},
{ "EXB-8500", 17, 0, 0, {
{ 0, 0,},
{ 0, 0,}
}},
{ "TKZ09", 17, 0, 0, {
{ 0, 0,},
{ 0, 0,}
}},
{ "VIPER 150", 0, TZ_Q_FORCE_BLKSIZE, 512, {
{ 0, 0, },
{ 0, 0, }
}},
{ "5150ES SCSI", 0, TZ_Q_FORCE_BLKSIZE, 512, {
{ 0, 0, },
{ 0, 0, }
}},
/* The next two product ids are faked up in tzprobe() */
{ "TK50 0x30", 14, 0, 0, {
{ 0, 0,},
{ 0, 0,}
}},
{ "MT02", 0, 0, 0, {
{ TZ_Q_DENSITY, 0x4 },
{ TZ_Q_DENSITY, 0 }
}},
};
#define NQUIRKS (sizeof(tz_quirk_table) / sizeof(tz_quirk_table[0]))
/*
* Test to see if device is present.
* Return true if found and initialized ok.
*/
int
static int
tzprobe(xxxsd)
void *xxxsd;
{
struct pmax_scsi_device *sd = xxxsd;
struct tz_softc *sc = &tz_softc[sd->sd_unit];
int i;
char vid[9], pid[17], revl[5];
struct pmax_scsi_device *sd = xxxsd;
struct tz_softc *sc = &tz_softc[sd->sd_unit];
ScsiInquiryData inqbuf;
if (sd->sd_unit >= NTZ)
@ -148,6 +216,9 @@ tzprobe(xxxsd)
sc->sc_dev.dv_unit = sd->sd_unit; /* XXX */
sc->sc_dev.dv_class = DV_TAPE; /* XXX */
sc->sc_fileno = -1;
sc->sc_blkno = -1;
/* try to find out what type of device this is */
sc->sc_flags = TZF_ALTCMD; /* force use of sc_cdb */
sc->sc_cdb.len = sizeof(ScsiGroup0Cmd);
@ -189,21 +260,19 @@ tzprobe(xxxsd)
sd->sd_slave);
if (i == 5 && inqbuf.version == 1 && (inqbuf.qualifier == 0x50 ||
inqbuf.qualifier == 0x30)) {
printf(" TK50\n");
sc->sc_tapeid = MT_ISTK50;
strcpy(pid, "TK50");
printf(" %s\n", pid);
if (inqbuf.qualifier == 0x30)
sc->sc_modelen = 14;
strcpy(pid, "TK50 0x30");
} else if (i >= 5 && inqbuf.version == 1 && inqbuf.qualifier == 0 &&
inqbuf.length == 0) {
/* assume Emultex MT02 controller */
printf(" MT02\n");
sc->sc_tapeid = MT_ISMT02;
strcpy(pid, "MT02");
printf(" %s\n", pid);
} else if (inqbuf.version > 2 || i < 36) {
printf(" GENERIC SCSI tape device: qual 0x%x, ver %d\n",
inqbuf.qualifier, inqbuf.version);
sc->sc_tapeid = 0;
} else {
char vid[9], pid[17], revl[5];
bcopy((caddr_t)inqbuf.vendorID, (caddr_t)vid, 8);
bcopy((caddr_t)inqbuf.productID, (caddr_t)pid, 16);
@ -221,28 +290,19 @@ tzprobe(xxxsd)
break;
revl[i+1] = 0;
printf(" %s %s rev %s\n", vid, pid, revl);
}
if (bcmp("EXB-8200", pid, 8) == 0) {
sc->sc_tapeid = MT_ISEXABYTE;
sc->sc_modelen = 17;
} else if (bcmp("VIPER 150", pid, 9) == 0) {
sc->sc_tapeid = MT_ISVIPER1;
} else if (bcmp("5150ES SCSI", pid, 11)) {
sc->sc_tapeid = MT_ISVIPER1;
} else if (bcmp("Python 25501", pid, 12) == 0) {
sc->sc_tapeid = MT_ISPYTHON;
} else if (bcmp("HP35450A", pid, 8) == 0) {
#if 0
/* XXX "extra" stat makes the HP drive happy at boot time */
stat = scsi_test_unit_rdy(ctlr, slave, unit);
#endif
sc->sc_tapeid = MT_ISHPDAT;
} else if (bcmp("123107 SCSI", pid, 11) == 0) {
sc->sc_tapeid = MT_ISMFOUR;
} else {
printf("tz%d: assuming GENERIC SCSI tape device\n",
sd->sd_unit);
sc->sc_tapeid = 0;
sc->sc_quirks = NULL;
for (i = 0; i < NQUIRKS; i++) {
if (bcmp(pid, tz_quirk_table[i].product,
strlen(tz_quirk_table[i].product)) == 0) {
sc->sc_quirks = &tz_quirk_table[i];
if (tz_quirk_table[i].quirks & TZ_Q_FORCE_BLKSIZE)
sc->sc_blklen = tz_quirk_table[i].blklen;
if (tz_quirk_table[i].page_0_size > 0) {
sc->sc_modelen = tz_quirk_table[i].page_0_size;
}
break;
}
}
@ -261,7 +321,7 @@ bad:
/*
* Perform a special tape command on a SCSI Tape drive.
*/
int
static int
tzcommand(dev, command, code, count, data)
dev_t dev;
int command;
@ -279,6 +339,7 @@ tzcommand(dev, command, code, count, data)
sc->sc_flags |= TZF_WAIT;
sleep(&sc->sc_flags, PZERO);
}
sc->sc_flags |= TZF_DONTCOUNT; /* don't count any operations in blkno */
sc->sc_flags |= TZF_ALTCMD; /* force use of sc_cdb */
sc->sc_cdb.len = sizeof(ScsiGroup0Cmd);
c = (ScsiGroup0Cmd *)sc->sc_cdb.cdb;
@ -293,11 +354,6 @@ tzcommand(dev, command, code, count, data)
sc->sc_buf.b_flags = B_BUSY;
else {
sc->sc_buf.b_flags = B_BUSY | B_READ;
#if 0
/* this seems to work but doesn't give us a speed advantage */
if (command == SCSI_TEST_UNIT_READY)
sc->sc_cmd.flags |= SCSICMD_USE_SYNC;
#endif
}
sc->sc_buf.b_bcount = data ? count : 0;
sc->sc_buf.b_un.b_addr = data;
@ -307,23 +363,55 @@ tzcommand(dev, command, code, count, data)
sc->sc_tab.b_actb = &sc->sc_buf.b_actf;
tzstart(sc->sc_sd->sd_unit);
error = biowait(&sc->sc_buf);
sc->sc_flags &= ~TZF_DONTCOUNT; /* clear don't count flag */
sc->sc_flags &= ~TZF_ALTCMD; /* force use of sc_cdb */
sc->sc_buf.b_flags = 0;
sc->sc_cmd.flags = 0;
if (sc->sc_buf.b_resid)
printf("tzcommand: resid %ld\n", sc->sc_buf.b_resid); /* XXX */
if (error == 0)
if (error == 0) {
switch (command) {
case SCSI_SPACE:
if (sc->sc_blkno != -1) {
if (code == 0) {
sc->sc_blkno += count;
} else {
sc->sc_fileno += count;
sc->sc_blkno = 0;
}
}
sc->sc_flags &= ~TZF_SEENEOF;
break;
case SCSI_WRITE_EOF:
if (sc->sc_blkno != -1) {
sc->sc_fileno += count;
sc->sc_blkno = 0;
}
sc->sc_flags &= ~TZF_SEENEOF;
break;
case SCSI_LOAD_UNLOAD:
case SCSI_REWIND:
sc->sc_fileno = 0;
sc->sc_blkno = 0;
sc->sc_flags &= ~TZF_SEENEOF;
break;
}
} else {
switch (command) {
case SCSI_SPACE:
case SCSI_WRITE_EOF:
case SCSI_LOAD_UNLOAD:
case SCSI_REWIND:
sc->sc_flags &= ~TZF_SEENEOF;
sc->sc_fileno = -1;
sc->sc_blkno = -1;
}
}
splx(s);
return (error);
}
void
static void
tzstart(unit)
int unit;
{
@ -380,7 +468,7 @@ tzstart(unit)
/*
* This is called by the controller driver when the command is done.
*/
void
static void
tzdone(unit, error, resid, status)
int unit;
int error; /* error number from errno.h */
@ -441,6 +529,12 @@ tzdone(unit, error, resid, status)
bp->b_resid = resid;
break;
}
if (sp->fileMark) {
if (sc->sc_fileno != -1) {
sc->sc_fileno++;
sc->sc_blkno = 0;
}
}
if (sc->sc_blklen && sp->badBlockLen) {
tprintf(sc->sc_ctty,
"tz%d: Incorrect Block Length, expected %d got %ld\n",
@ -520,6 +614,12 @@ tzdone(unit, error, resid, status)
} else {
sc->sc_sense.status = status;
bp->b_resid = resid;
if (!(sc->sc_flags & TZF_DONTCOUNT) && sc->sc_blkno != -1) {
if (sc->sc_blklen != 0)
sc->sc_blkno += bp->b_bcount / sc->sc_blklen;
else
sc->sc_blkno++;
}
}
if ((dp = bp->b_actf) != 0)
@ -539,6 +639,98 @@ tzdone(unit, error, resid, status)
}
}
static int
tzmount(dev)
dev_t dev;
{
int unit = tzunit(dev);
struct tz_softc *sc = &tz_softc[unit];
int densmode, error;
/* clear UNIT_ATTENTION */
error = tzcommand(dev, SCSI_TEST_UNIT_READY, 0, 0, 0);
while (error) {
ScsiClass7Sense *sp = (ScsiClass7Sense *)sc->sc_sense.sense;
/* return error if last error was not UNIT_ATTENTION */
if (!(sc->sc_sense.status & SCSI_STATUS_CHECKCOND) ||
sp->error7 != 0x70 || sp->key != SCSI_CLASS7_UNIT_ATTN)
return (error);
/*
* Try it again just to be sure and
* try to negotiate synchonous transfers.
*/
error = tzcommand(dev, SCSI_TEST_UNIT_READY, 0, 0, 0);
}
if ((sc->sc_flags & TZF_MOUNTED) == 0) {
/* get the current mode settings */
error = tzcommand(dev, SCSI_MODE_SENSE, 0,
sc->sc_modelen, (caddr_t)&sc->sc_mode);
if (error)
return (error);
sc->sc_flags = TZF_ALIVE;
/* *Very* first off, make sure we're loaded to BOT. */
error = tzcommand(dev, SCSI_LOAD_UNLOAD, 0, SCSI_LD_LOAD, 0);
/* In case this doesn't work, do a REWIND instead */
if (error)
error = tzcommand(dev, SCSI_REWIND, 0, 0, 0);
if (error)
return (error);
/* check for write protected tape */
if (sc->sc_mode.writeprot)
sc->sc_flags |= TZF_RDONLY;
else
sc->sc_flags &= ~TZF_RDONLY;
#if 0 /* XXX not the right place! Do we need to check at all? */
if ((flags & FWRITE) && sc->sc_mode.writeprot) {
uprintf("tz%d: write protected\n", unit);
return (EACCES);
}
#endif
/* save total number of blocks on tape */
sc->sc_numblks = (sc->sc_mode.blocks_2 << 16) |
(sc->sc_mode.blocks_1 << 8) | sc->sc_mode.blocks_0;
/* setup for mode select */
sc->sc_mode.len = 0;
sc->sc_mode.media = 0;
sc->sc_mode.bufferedMode = 1;
sc->sc_mode.blocks_0 = 0;
sc->sc_mode.blocks_1 = 0;
sc->sc_mode.blocks_2 = 0;
sc->sc_mode.block_size0 = sc->sc_blklen >> 16;
sc->sc_mode.block_size1 = sc->sc_blklen >> 8;
sc->sc_mode.block_size2 = sc->sc_blklen;
/* check for tape density changes */
densmode = (minor(dev) & TZ_HIDENSITY) ? 1 : 0;
if ((sc->sc_quirks != NULL) &&
(sc->sc_quirks->modes[densmode].quirks & TZ_Q_DENSITY))
sc->sc_mode.density = sc->sc_quirks->modes[densmode].density;
else {
if (densmode != 0)
uprintf("tz%d: Only one density supported\n", unit);
}
/* set the current mode settings */
error = tzcommand(dev, SCSI_MODE_SELECT, 0,
sc->sc_modelen, (caddr_t)&sc->sc_mode);
if (error == 0) {
sc->sc_flags |= TZF_MOUNTED;
sc->sc_fileno = 0;
sc->sc_blkno = 0;
}
}
return(error);
}
/* ARGSUSED */
int
tzopen(dev, flags, type, p)
@ -560,138 +752,12 @@ tzopen(dev, flags, type, p)
if (sc->sc_flags & TZF_OPEN)
return (EBUSY);
/* clear UNIT_ATTENTION */
error = tzcommand(dev, SCSI_TEST_UNIT_READY, 0, 0, 0);
while (error) {
ScsiClass7Sense *sp = (ScsiClass7Sense *)sc->sc_sense.sense;
/* return error if last error was not UNIT_ATTENTION */
if (!(sc->sc_sense.status & SCSI_STATUS_CHECKCOND) ||
sp->error7 != 0x70 || sp->key != SCSI_CLASS7_UNIT_ATTN)
return (error);
/*
* Try it again just to be sure and
* try to negotiate synchonous transfers.
*/
error = tzcommand(dev, SCSI_TEST_UNIT_READY, 0, 0, 0);
}
/* get the current mode settings */
error = tzcommand(dev, SCSI_MODE_SENSE, 0,
sc->sc_modelen, (caddr_t)&sc->sc_mode);
if (error)
return (error);
/* check for write protected tape */
if ((flags & FWRITE) && sc->sc_mode.writeprot) {
uprintf("tz%d: write protected\n", unit);
return (EACCES);
}
/* set record length */
switch (sc->sc_tapeid) {
case MT_ISAR:
case MT_ISHPDAT:
case MT_ISVIPER1:
sc->sc_blklen = 512;
break;
case MT_ISEXABYTE:
#if 0
if (minor(dev) & TZ_FIXEDBLK)
sc->sc_blklen = 1024;
else
sc->sc_blklen = st_exblklen;
#endif
break;
case MT_ISPYTHON:
case MT_ISMFOUR:
case MT_ISTK50:
sc->sc_blklen = 0;
break;
default:
sc->sc_blklen = (sc->sc_mode.block_size2 << 16) |
(sc->sc_mode.block_size1 << 8) | sc->sc_mode.block_size0;
}
/* save total number of blocks on tape */
sc->sc_numblks = (sc->sc_mode.blocks_2 << 16) |
(sc->sc_mode.blocks_1 << 8) | sc->sc_mode.blocks_0;
/* setup for mode select */
sc->sc_mode.len = 0;
sc->sc_mode.media = 0;
sc->sc_mode.bufferedMode = 1;
sc->sc_mode.blocks_0 = 0;
sc->sc_mode.blocks_1 = 0;
sc->sc_mode.blocks_2 = 0;
sc->sc_mode.block_size0 = sc->sc_blklen >> 16;
sc->sc_mode.block_size1 = sc->sc_blklen >> 8;
sc->sc_mode.block_size2 = sc->sc_blklen;
/* check for tape density changes */
switch (sc->sc_tapeid) {
case MT_ISAR:
if (minor(dev) & TZ_HIDENSITY)
sc->sc_mode.density = 0x5;
else {
if (flags & FWRITE) {
uprintf("Can only write QIC-24\n");
return (EIO);
}
sc->sc_mode.density = 0x4;
}
break;
case MT_ISMT02:
/*
* The tape density is set automatically when the tape
* is loaded. We only need to change it if we are writing.
*/
if (flags & FWRITE) {
if (minor(dev) & TZ_HIDENSITY)
sc->sc_mode.density = 0;
else
sc->sc_mode.density = 0x4;
}
break;
case MT_ISEXABYTE:
#if 0
if (minor(dev) & TZ_HIDENSITY)
uprintf("EXB-8200 density support only\n");
sc->sc_mode.vupb = (u_char)st_exvup;
sc->sc_mode.rsvd5 = 0;
sc->sc_mode.p5 = 0;
sc->sc_mode.motionthres = (u_char)st_exmotthr;
sc->sc_mode.reconthres = (u_char)st_exreconthr;
sc->sc_mode.gapthres = (u_char)st_exgapthr;
#endif
break;
case MT_ISHPDAT:
case MT_ISVIPER1:
case MT_ISPYTHON:
case MT_ISTK50:
if (minor(dev) & TZ_HIDENSITY)
uprintf("tz%d: Only one density supported\n", unit);
break;
case MT_ISMFOUR:
break; /* XXX could do density select? */
}
/* set the current mode settings */
error = tzcommand(dev, SCSI_MODE_SELECT, 0,
sc->sc_modelen, (caddr_t)&sc->sc_mode);
error = tzmount(dev);
if (error)
return (error);
sc->sc_ctty = tprintf_open(p);
sc->sc_flags = TZF_ALIVE | TZF_OPEN;
sc->sc_flags |= TZF_OPEN;
return (0);
}
@ -708,24 +774,8 @@ tzclose(dev, flag, mode, p)
if (!(sc->sc_flags & TZF_OPEN))
return (0);
if (flag == FWRITE ||
((flag & FWRITE) && (sc->sc_flags & TZF_WRITTEN))) {
((flag & FWRITE) && (sc->sc_flags & TZF_WRITTEN)))
error = tzcommand(dev, SCSI_WRITE_EOF, 0, 1, 0);
#if 0
/*
* Cartridge tapes don't do double EOFs on EOT.
*/
switch (sc->sc_tapeid) {
case MT_ISAR:
case MT_ISMT02:
break;
default:
error = tzcommand(dev, SCSI_WRITE_EOF, 0, 1, 0);
if (minor(dev) & TZ_NOREWIND)
(void) tzcommand(dev, SCSI_SPACE, 0, -1, 0);
}
#endif
}
if ((minor(dev) & TZ_NOREWIND) == 0)
(void) tzcommand(dev, SCSI_REWIND, 0, 0, 0);
sc->sc_flags &= ~(TZF_OPEN | TZF_WRITTEN);
@ -739,19 +789,8 @@ tzread(dev, uio, iomode)
struct uio *uio;
int iomode;
{
#if 0
/*XXX*/ /* check for hardware write-protect? */
struct tz_softc *sc = &tz_softc[tzunit(dev)];
if (sc->sc_type == SCSI_ROM_TYPE)
return (EROFS);
if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid)
return (EPERM);
#endif
return (physio(tzstrategy, (struct buf *)0, dev,
B_READ, minphys, uio));
return (physio(tzstrategy, NULL, dev, B_READ, minphys, uio));
}
int
@ -760,15 +799,9 @@ tzwrite(dev, uio, iomode)
struct uio *uio;
int iomode;
{
#if 0
struct tz_softc *sc = &tz_softc[tzunit(dev)];
if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid)
return (EPERM);
#endif
return (physio(tzstrategy, (struct buf *)0, dev,
B_WRITE, minphys, uio));
/* XXX: check for hardware write-protect? */
return (physio(tzstrategy, NULL, dev, B_WRITE, minphys, uio));
}
int
@ -784,54 +817,78 @@ tzioctl(dev, cmd, data, flag, p)
struct mtget *mtget;
int code, count;
static int tzops[] = {
SCSI_WRITE_EOF, SCSI_SPACE, SCSI_SPACE, SCSI_SPACE, SCSI_SPACE,
SCSI_REWIND, SCSI_LOAD_UNLOAD, SCSI_TEST_UNIT_READY
SCSI_WRITE_EOF, /* MTWEOF */
SCSI_SPACE, /* MTFSF */
SCSI_SPACE, /* MTBSF */
SCSI_SPACE, /* MTFSR */
SCSI_SPACE, /* MTBSR */
SCSI_REWIND, /* MTREW */
SCSI_LOAD_UNLOAD, /* MTOFFL */
SCSI_TEST_UNIT_READY, /* MTNOP */
SCSI_LOAD_UNLOAD, /* MTRETEN */
SCSI_ERASE_TAPE, /* MTERASE */
MTEOM, /* MTEOM */
MTNBSF, /* MTNBSF */
SCSI_TEST_UNIT_READY, /* MTCACHE */
SCSI_TEST_UNIT_READY, /* MTNOCACHE */
MTSETBSIZ, /* MTSETBSIZ */
MTSETDNSTY, /* MTSETDNSTY */
MTCMPRESS, /* MTCMPRESS */
MTEWARN /* MTEWARN */
};
switch (cmd) {
case MTIOCTOP: /* tape operation */
mtop = (struct mtop *)data;
count = mtop->mt_count;
code = 0;
if ((unsigned)mtop->mt_op < MTREW && mtop->mt_count <= 0)
return (EINVAL);
switch (mtop->mt_op) {
case MTWEOF:
code = 0;
count = mtop->mt_count;
break;
case MTFSF:
code = 1;
count = mtop->mt_count;
if (sc->sc_blkno != -1) {
sc->sc_fileno += count;
sc->sc_blkno = 0;
}
break;
case MTBSF:
count = -count;
/* FALLTHROUGH */
case MTFSF:
code = 1;
count = -mtop->mt_count;
break;
case MTFSR:
code = 0;
count = mtop->mt_count;
if (sc->sc_blkno != -1) {
sc->sc_fileno += count;
sc->sc_blkno = 0;
}
break;
case MTBSR:
code = 0;
count = -mtop->mt_count;
count = -count;
/* FALLTHROUGH */
case MTFSR:
if (sc->sc_blkno != -1)
sc->sc_blkno += count;
break;
case MTREW:
case MTNOP:
code = 0;
case MTCACHE:
case MTNOCACHE:
count = 0;
break;
case MTOFFL:
code = 0;
count = SCSI_LD_UNLOAD;
break;
case MTRETEN:
count = SCSI_LD_RETENSION;
break;
default:
return (EINVAL);
}
@ -839,10 +896,25 @@ tzioctl(dev, cmd, data, flag, p)
case MTIOCGET:
mtget = (struct mtget *)data;
mtget->mt_type = MT_ISAR; /* "GENERIC" SCSI */
mtget->mt_dsreg = 0;
if (sc->sc_flags & TZF_RDONLY)
mtget->mt_dsreg |= MT_DS_RDONLY;
if (sc->sc_flags & TZF_MOUNTED)
mtget->mt_dsreg |= MT_DS_MOUNTED;
mtget->mt_erreg = sc->sc_sense.status;
mtget->mt_resid = 0;
mtget->mt_type = 0;
mtget->mt_resid = sc->sc_buf.b_resid;
mtget->mt_fileno = sc->sc_fileno;
mtget->mt_blkno = sc->sc_blkno;
/* clear latched errors */
sc->sc_sense.status = 0;
sc->sc_buf.b_resid = 0;
break;
case MTIOCIEOT:
case MTIOCEEOT:
break;
default:
@ -888,6 +960,7 @@ tzdump(dev, blkno, va, size)
caddr_t va;
size_t size;
{
/* Not implemented. */
return (ENXIO);
}