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:
parent
1e99130f2e
commit
a68944cfca
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue