diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1993-08-28 03:08:59 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1993-08-28 03:08:59 +0000 |
commit | bb7686bc5d8502daf5555b4de12d8a81926fb13a (patch) | |
tree | 96b769956a4e8f8c1e7b98ca459e2817ea02e56a /sys/scsi/st.c | |
parent | f4f821656d5e9b5c905d1efd765f180be84a7e56 (diff) | |
download | FreeBSD-src-bb7686bc5d8502daf5555b4de12d8a81926fb13a.zip FreeBSD-src-bb7686bc5d8502daf5555b4de12d8a81926fb13a.tar.gz |
Revised drivers from Julian. Support for generic scsi. Fixed scsi tape (st.c)
problems with respect to multiple tar files on one tape. Now uses malloc
of data structures to reduce static kernel size.
Diffstat (limited to 'sys/scsi/st.c')
-rw-r--r-- | sys/scsi/st.c | 2065 |
1 files changed, 1108 insertions, 957 deletions
diff --git a/sys/scsi/st.c b/sys/scsi/st.c index e355967..75f994b 100644 --- a/sys/scsi/st.c +++ b/sys/scsi/st.c @@ -12,12 +12,25 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * 1.15 is the last verion to support MACH and OSF/1 + */ +/* $Revision: 1.23 $ */ + +/* * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993 * - * $Id$ + * $Id: st.c,v 1.23 93/08/26 21:09:51 julian Exp Locker: julian $ */ + /* * To do: * work out some better way of guessing what a good timeout is going @@ -33,14 +46,12 @@ #include <sys/errno.h> #include <sys/ioctl.h> +#include <sys/malloc.h> #include <sys/buf.h> #include <sys/proc.h> #include <sys/user.h> #include <sys/mtio.h> -#if defined(OSF) -#define SECSIZE 512 -#endif /* defined(OSF) */ #include <scsi/scsi_all.h> #include <scsi/scsi_tape.h> @@ -91,6 +102,7 @@ struct rogues #define ST_Q_NEEDS_PAGE_0 0x00001 #define ST_Q_FORCE_FIXED_MODE 0x00002 #define ST_Q_FORCE_VAR_MODE 0x00004 +#define ST_Q_SNS_HLP 0x00008 static struct rogues gallery[] = /* ends with an all null entry */ { @@ -110,6 +122,14 @@ static struct rogues gallery[] = /* ends with an all null entry */ {0,QIC_120} /* minor 12,13,14,15*/ } }, + { "Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462","-005", + 0, + { {ST_Q_SNS_HLP,0}, /* minor 0,1,2,3*/ + {ST_Q_SNS_HLP,QIC_525}, /* minor 4,5,6,7*/ + {0,QIC_150}, /* minor 8,9,10,11*/ + {0,QIC_120} /* minor 12,13,14,15*/ + } + }, { "Archive Viper 150", "ARCHIVE ", "VIPER 150","????", ST_Q_NEEDS_PAGE_0, { {0,0}, /* minor 0,1,2,3*/ @@ -118,28 +138,26 @@ static struct rogues gallery[] = /* ends with an all null entry */ {0,QIC_24} /* minor 12,13,14,15*/ } }, + { "Wangdat Dat (1.3GB)", "WangDAT ", "Model 1300","????", + 0, + { {ST_Q_FORCE_VAR_MODE,0}, /* minor 0,1,2,3*/ + {ST_Q_SNS_HLP,0}, /* minor 4,5,6,7*/ + {ST_Q_FORCE_FIXED_MODE,0}, /* minor 8,9,10,11*/ + {ST_Q_FORCE_VAR_MODE,0} /* minor 12,13,14,15*/ + } + }, {(char *)0} }; -#ifndef __386BSD__ -struct buf stbuf[NST][STQSIZE]; /* buffer for raw io (one per device) */ -struct buf *stbuf_free[NST]; /* queue of free buffers for raw io */ -#endif __386BSD__ -struct buf st_buf_queue[NST]; int ststrategy(); void stminphys(); -struct scsi_xfer st_scsi_xfer[NST]; -int st_xfer_block_wait[NST]; -#if defined(OSF) -caddr_t st_window[NST]; -#endif /* defined(OSF) */ -#ifndef MACH #define ESUCCESS 0 -#endif MACH -int st_debug = 0; +#ifdef STDEBUG +int st_debug = 1; +#endif /*STDEBUG*/ int stattach(); int st_done(); @@ -171,18 +189,26 @@ struct st_data /*--------------------storage for sense data returned by the drive------------*/ unsigned char sense_data[12]; /* additional sense data needed */ /* for mode sense/select. */ -}st_data[NST]; + struct buf *buf_queue; /* the queue of pending IO operations */ + struct scsi_xfer scsi_xfer; /* The scsi xfer struct for this drive*/ + int xfer_block_wait; /* whether there is a process waiting */ +}*st_data[NST]; #define ST_INITIALIZED 0x01 #define ST_INFO_VALID 0x02 #define ST_OPEN 0x04 +#define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */ #define ST_WRITTEN 0x10 #define ST_FIXEDBLOCKS 0x20 #define ST_AT_FILEMARK 0x40 -#define ST_AT_EOM 0x80 +#define ST_EIO_PENDING 0x80 /* we couldn't report it then (had data)*/ +#define ST_AT_BOM 0x100 /* ops history suggests Beg of Medium */ +#define ST_READONLY 0x200 /* st_mode_sense says write protected */ -#define ST_PER_ACTION (ST_AT_FILEMARK | ST_AT_EOM) -#define ST_PER_OPEN (ST_OPEN | ST_WRITTEN | ST_PER_ACTION) -#define ST_PER_MEDIA ST_FIXEDBLOCKS +#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING) +#define ST_PER_OPEN (ST_OPEN | ST_PER_ACTION) +#define ST_PER_MEDIA (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \ + ST_FIXEDBLOCKS | ST_AT_BOM | ST_READONLY | \ + ST_PER_ACTION) static int next_st_unit = 0; /***********************************************************************\ @@ -196,7 +222,9 @@ struct scsi_switch *scsi_switch; int unit,i; struct st_data *st; +#ifdef STDEBUG if(scsi_debug & PRINTROUTINES) printf("stattach: "); +#endif /*STDEBUG*/ /*******************************************************\ * Check we have the resources for another drive * \*******************************************************/ @@ -207,7 +235,17 @@ struct scsi_switch *scsi_switch; (unit + 1),NST); return(0); } - st = st_data + unit; + if(st_data[unit]) + { + printf("st%d: Already has storage!\n",unit); + return(0); + } + st = st_data[unit] = malloc(sizeof(struct st_data),M_DEVBUF,M_NOWAIT); + if(!st) + { + printf("st%d: malloc failed in st.c\n",unit); + return(0); + } /*******************************************************\ * Store information needed to contact our base driver * \*******************************************************/ @@ -236,37 +274,35 @@ struct scsi_switch *scsi_switch; \*******************************************************/ if(st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { - if(st_test_ready(unit,SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) + printf("st%d: drive offline\n", unit); + } + else + { + if(!st_test_ready(unit,SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { - printf("st%d: tape present: %d blocks of %d bytes\n", - unit, st->numblks, st->media_blksiz); + printf("st%d: density code 0x%x, ", + unit, st->media_density); + if (st->media_blksiz) + { + printf("%d-byte", st->media_blksiz); + } + else + { + printf("variable"); + } + printf(" blocks, write-%s\n", + st->flags & ST_READONLY ? "protected" : "enabled"); } else { printf("st%d: drive empty\n", unit); } } - else - { - printf("st%d: drive offline\n", unit); - } /*******************************************************\ * Set up the bufs for this device * \*******************************************************/ -#ifndef __386BSD__ - stbuf_free[unit] = (struct buf *)0; - for (i = 1; i < STQSIZE; i++) - { - stbuf[unit][i].b_forw = stbuf_free[unit]; - stbuf_free[unit]=&stbuf[unit][i]; - } -#endif __386BSD__ - st_buf_queue[unit].b_active = 0; - st_buf_queue[unit].b_actf = st_buf_queue[unit].b_actl = 0; + st->buf_queue = 0; -#if defined(OSF) - st_window[unit] = (caddr_t)alloc_kva(SECSIZE*256+PAGESIZ); -#endif /* defined(OSF) */ st->flags |= ST_INITIALIZED; return; @@ -282,7 +318,7 @@ st_identify_drive(unit) int unit; { - struct st_data *st; + struct st_data *st = st_data[unit]; struct scsi_inquiry_data inqbuf; struct rogues *finger; char manu[32]; @@ -292,7 +328,6 @@ int unit; int model_len; - st = st_data + unit; /*******************************************************\ * Get the device type information * \*******************************************************/ @@ -335,7 +370,10 @@ int unit; } model2[model_len] = 0; if ((strcmp(manu, finger->manu) == 0 ) - && (strcmp(model2, finger->model) == 0 )) + && (strcmp(model2, finger->model) == 0 || + strcmp("????????????????", finger->model) == 0) + && (strcmp(version, finger->version) == 0 || + strcmp("????", finger->version) == 0)) { printf("st%d: %s is a known rogue\n", unit,finger->name); st->modes[0] = finger->modes[0]; @@ -359,11 +397,11 @@ int unit; stopen(dev) { int unit,mode,dsty; + int errno = 0; struct st_data *st; unit = UNIT(dev); mode = MODE(dev); dsty = DSTY(dev); - st = st_data + unit; /*******************************************************\ * Check the unit is legal * @@ -372,6 +410,13 @@ stopen(dev) { return(ENXIO); } + st = st_data[unit]; + /*******************************************************\ + * Make sure the device has been initialised * + \*******************************************************/ + if ((st == NULL) || (!(st->flags & ST_INITIALIZED))) + return(ENXIO); + /*******************************************************\ * Only allow one at a time * \*******************************************************/ @@ -379,103 +424,151 @@ stopen(dev) { return(ENXIO); } + + /*******************************************************\ + * Throw out a dummy instruction to catch 'Unit attention* + * errors (the error handling will invalidate all our * + * device info if we get one, but otherwise, ignore it * + \*******************************************************/ + st_test_ready(unit, 0); + + /***************************************************************\ + * Check that the device is ready to use (media loaded?) * + * This time take notice of the return result * + \***************************************************************/ + if(errno = (st_test_ready(unit,0))) + { + printf("st%d: not ready\n",unit); + return(errno); + } + /*******************************************************\ * Set up the mode flags according to the minor number * * ensure all open flags are in a known state * * if it's a different mode, dump all cached parameters * \*******************************************************/ - if(st->last_dsty != dsty) + if(st->last_dsty != dsty || !(st->flags & ST_INFO_VALID)) + { st->flags &= ~ST_INFO_VALID; - st->last_dsty = dsty; + st->last_dsty = dsty; + st->quirks = st->drive_quirks | st->modes[dsty].quirks; + st->density = st->modes[dsty].density; + } st->flags &= ~ST_PER_OPEN; - st->quirks = st->drive_quirks | st->modes[dsty].quirks; - st->density = st->modes[dsty].density; +#ifdef STDEBUG if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) printf("stopen: dev=0x%x (unit %d (of %d))\n" , dev, unit, NST); - /*******************************************************\ - * Make sure the device has been initialised * - \*******************************************************/ - if (!(st->flags & ST_INITIALIZED)) - return(ENXIO); - - /*******************************************************\ - * Check that it is still responding and ok. * - \*******************************************************/ -#ifdef removing_this - if(scsi_debug & TRACEOPENS) - printf("device is "); - if (!(st_req_sense(unit, 0))) /* may get a 'unit attention' if new */ - { - if(scsi_debug & TRACEOPENS) - printf("not responding\n"); - return(ENXIO); - } - if(scsi_debug & TRACEOPENS) - printf("ok\n"); -#endif - if(!(st_test_ready(unit,0))) - { - printf("st%d: not ready\n",unit); - return(EIO); - } - if(!(st_test_ready(unit,0))) /* first may get 'unit attn' */ - { - printf("st%d: not ready\n",unit); - return(EIO); - } - +#endif /*STDEBUG*/ /***************************************************************\ * If the media is new, then make sure we give it a chance to * - * to do a 'load' instruction. Possibly the test ready * - * may not read true until this is done.. check this! XXX * + * to do a 'load' instruction. * \***************************************************************/ if(!(st->flags & ST_INFO_VALID)) /* is media new? */ { - if(!st_load(unit,LD_LOAD,0)) + if(errno = st_load(unit,LD_LOAD,0)) { - return(EIO); + return(errno); + } + if(st->quirks & ST_Q_SNS_HLP) + { + /***********************************************\ + * The quirk here is that the drive returns some * + * value to st_mode_sense incorrectly until the * + * tape has actually passed by the head. * + * * + * The method is to set the drive to fixed-block * + * state (user-specified density and 512-byte * + * blocks), then read and rewind to get it to * + * sense the tape. If the sense interpretation * + * code determines that the tape contains * + * variable-length blocks, set to variable-block * + * state and try again. The result will be the * + * ability to do an accurate st_mode_sense. * + * * + * We pretend not to be at beginning of medium * + * to keep st_read from calling st_decide_mode. * + * * + * We know we can do a rewind because we just * + * did a load, which implies rewind. Rewind * + * seems preferable to space backward if we have * + * a virgin tape. * + * * + * This is really a check fr 512 byte records * + * Needs more thought * + \***********************************************/ + char *buf; + + buf = malloc(DEF_FIXED_BSIZE,M_TEMP,M_NOWAIT); + if(!buf) return(ENOMEM); + + if (errno = st_mode_sense(unit, 0)) + { + free(buf,M_TEMP); + return(errno); + } + st->blksiz = DEF_FIXED_BSIZE; + st->flags = ~ST_AT_BOM & st->flags | ST_FIXEDBLOCKS; + if (errno = st_mode_select(unit, 0)) + { + free(buf,M_TEMP); + return(errno); + } + st_read(unit, buf, DEF_FIXED_BSIZE, 0); + if (errno = st_rewind(unit, FALSE, 0)) + { + free(buf,M_TEMP); + return(errno); + } + if (st->blksiz == 0) /* set it back the way it was */ + { + st->flags &= ~(ST_FIXEDBLOCKS | ST_AT_BOM); + if (errno = st_mode_select(unit, 0)) + { + free(buf,M_TEMP); + return(errno); + } + st_read(unit, buf, 1, 0); + if (errno = st_rewind(unit, FALSE, 0)) + { + free(buf,M_TEMP); + return(errno); + } + } + free(buf,M_TEMP); } } +#ifdef removing_this +#endif removing_this + /*******************************************************\ * Load the physical device parameters * * loads: blkmin, blkmax * \*******************************************************/ - if(!st_rd_blk_lim(unit,0)) + if(errno = st_rd_blk_lim(unit,0)) { - return(EIO); + return(errno); } /*******************************************************\ * Load the media dependent parameters * * includes: media_blksiz,media_density,numblks * \*******************************************************/ - if(!st_mode_sense(unit,0)) + if(errno = st_mode_sense(unit,0)) { - return(EIO); - } - - /*******************************************************\ - * From media parameters, device parameters and quirks, * - * work out how we should be setting outselves up * - \*******************************************************/ - if(! st_decide_mode(unit)) - return(ENXIO); - - if(!st_mode_select(unit,0,st->density)) - { - return(EIO); + return(errno); } st->flags |= ST_INFO_VALID; st_prevent(unit,PR_PREVENT,0); /* who cares if it fails? */ +#ifdef STDEBUG if(scsi_debug & TRACEOPENS) printf("Params loaded "); - +#endif /*STDEBUG*/ st->flags |= ST_OPEN; return(0); @@ -492,35 +585,41 @@ stclose(dev) unit = UNIT(dev); mode = MODE(dev); - st = st_data + unit; + st = st_data[unit]; +#ifdef STDEBUG if(scsi_debug & TRACEOPENS) printf("Closing device"); +#endif /*STDEBUG*/ if(st->flags & ST_WRITTEN) { st_write_filemarks(unit,1,0); } - st->flags &= ~ST_WRITTEN; switch(mode) { case 0: st_rewind(unit,FALSE,SCSI_SILENT); st_prevent(unit,PR_ALLOW,SCSI_SILENT); + st->flags &= ~ST_PER_MEDIA; break; - case 1: - st_prevent(unit,PR_ALLOW,SCSI_SILENT); + case 1: /*non rewind*/ + /* possibly space forward if not already at EOF? */ + /* (fixed block mode only) */ + break; case 2: st_rewind(unit,FALSE,SCSI_SILENT); st_prevent(unit,PR_ALLOW,SCSI_SILENT); st_load(unit,LD_UNLOAD,SCSI_SILENT); + st->flags &= ~ST_PER_MEDIA; break; - case 3: + case 3:/* a bit silly really */ st_prevent(unit,PR_ALLOW,SCSI_SILENT); st_load(unit,LD_UNLOAD,SCSI_SILENT); + st->flags &= ~ST_PER_MEDIA; break; default: - printf("st%d:close: Bad mode (minor number)%d how's it open?\n" + printf("st%d: close: Bad mode (minor number)%d how's it open?\n" ,unit,mode); return(EINVAL); } @@ -529,137 +628,207 @@ stclose(dev) } /***************************************************************\ -* Given all we know about the device, media, mode and 'quirks', * -* make a decision as to how we should be set up. * +* Given all we know about the device, media, mode, 'quirks' and * +* initial operation, make a decision as to how we should be set * +* up. First, choose the density, then variable/fixed blocks. * \***************************************************************/ -st_decide_mode(unit) -int unit; +st_decide_mode(unit, first_read) +int unit, first_read; { - struct st_data *st = st_data + unit; + int dsty, error; + struct st_data *st = st_data[unit]; - if(st->flags & ST_INFO_VALID) return TRUE; + /***************************************************************\ + * First, if our information about the tape is out of date, get * + * new information. * + \***************************************************************/ + if (!(st->flags & ST_INFO_VALID)) + { + if (error = st_mode_sense(unit, 0)) + return (error); + st->flags |= ST_INFO_VALID; + } +#ifdef STDEBUG + if(st_debug) printf("starting mode decision\n"); +#endif /*STDEBUG*/ - switch(st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE)) + /***************************************************************\ + * Second, set the density, and set the quirk flags as a * + * function of the density. * + \***************************************************************/ + st->quirks = st->drive_quirks; + dsty = st->last_dsty; /* set in the open call */ + if (dsty > 0) + { + /*******************************************************\ + * If the user specified the density, believe him. * + \*******************************************************/ + st->density = st->modes[dsty].density; + st->quirks |= st->modes[dsty].quirks; + } + else { - case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE): - printf("st%d: bad quirks\n",unit); - return FALSE; - case 0: - switch(st->density) - { - case QIC_120: - case QIC_150: - goto fixed; - case HALFINCH_800: - case HALFINCH_1600: - case HALFINCH_6250: - case QIC_525: - goto var; - default: - break; - } /*******************************************************\ - * There was once a reason that the tests below were * - * deemed insufficient, but I can't remember why.. * - * If your drive needs these added to, let me know * - * and/or add a rogue entry. * + * If the user defaulted the density, use the drive's * + * opinion of it. * \*******************************************************/ - if(st->blkmin && (st->blkmin == st->blkmax)) - goto fixed; - if(st->blkmin != st->blkmax) - goto var; + st->density = st->media_density; + do { + if (st->density == st->modes[dsty].density) + { + st->quirks |= st->modes[dsty].quirks; +#ifdef STDEBUG + if(st_debug) printf("selected density %d\n",dsty); +#endif /*STDEBUG*/ + break; /* only out of the loop*/ + } + } while (++dsty < 4); + /*******************************************************\ + * If dsty got to 4, the drive must have reported a * + * density which isn't in our density list (e.g. QIC-24 * + * for a default drive). We can handle that, except * + * there'd better be no density-specific quirks in the * + * drive's behavior. * + \*******************************************************/ + } + + /***************************************************************\ + * If the user has already specified fixed or variable-length * + * blocks using an ioctl, just believe him. OVERRIDE ALL * + \***************************************************************/ + if (st->flags & ST_BLOCK_SET) + { +#ifdef STDEBUG + if(st_debug) printf("user has specified %s\n", + st->flags & ST_FIXEDBLOCKS ? "variable mode" : "fixed mode"); +#endif /*STDEBUG*/ + goto done; + } + /***************************************************************\ + * If the user hasn't already specified fixed or variable-length * + * blocks and the block size (zero if variable-length), we'll * + * have to try to figure them out ourselves. * + * * + * Our first shot at a method is, "The quirks made me do it!" * + \***************************************************************/ + switch (st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE)) + { + case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE): + printf("st%d: bad quirks\n",unit); + return (EINVAL); case ST_Q_FORCE_FIXED_MODE: -fixed: st->flags |= ST_FIXEDBLOCKS; - if(st->media_blksiz) - { + if (st->blkmin && st->blkmin == st->blkmax) + st->blksiz = st->blkmin; + else if(st->media_blksiz > 0) st->blksiz = st->media_blksiz; - } else - { - if(st->blkmin) - { - st->blksiz = st->blkmin; /* just to make sure */ - } - else - { - st->blksiz = DEF_FIXED_BSIZE; - } - } - break; + st->blksiz = DEF_FIXED_BSIZE; +#ifdef STDEBUG + if(st_debug) printf("Quirks force fixed mode\n"); +#endif /*STDEBUG*/ + goto done; case ST_Q_FORCE_VAR_MODE: -var: st->flags &= ~ST_FIXEDBLOCKS; st->blksiz = 0; - break; +#ifdef STDEBUG + if(st_debug) printf("Quirks force variable mode\n"); +#endif /*STDEBUG*/ + goto done; } - return(TRUE); -} -#ifndef __386BSD__ -/*******************************************************\ -* Get ownership of this unit's buf * -* If need be, sleep on it, until it comes free * -\*******************************************************/ -struct buf * -st_get_buf(unit) { - struct buf *rc; - - while (!(rc = stbuf_free[unit])) - sleep((caddr_t)&stbuf_free[unit], PRIBIO+1); - stbuf_free[unit] = stbuf_free[unit]->b_forw; - rc->b_error = 0; - rc->b_resid = 0; - rc->b_flags = 0; - return(rc); -} -/*******************************************************\ -* Free this unit's buf, wake processes waiting for it * -\*******************************************************/ -st_free_buf(unit,bp) -struct buf *bp; -{ - if (!stbuf_free[unit]) - wakeup((caddr_t)&stbuf_free[unit]); - bp->b_forw = stbuf_free[unit]; - stbuf_free[unit] = bp; -} - + /***************************************************************\ + * If the drive can only handle fixed-length blocks and only at * + * one size, perhaps we should just do that. * + \***************************************************************/ + if (st->blkmin && (st->blkmin == st->blkmax)) + { + st->flags |= ST_FIXEDBLOCKS; + st->blksiz = st->blkmin; +#ifdef STDEBUG + if(st_debug) printf("blkmin == blkmax of %d\n",st->blkmin); +#endif /*STDEBUG*/ + goto done; + } -/*******************************************************\ -* Get the buf for this unit and use physio to do it * -\*******************************************************/ -stread(dev,uio) -register short dev; -struct uio *uio; -{ - int unit = UNIT(dev); - struct buf *bp = st_get_buf(unit); - int rc; - rc = physio(ststrategy, bp, dev, B_READ, stminphys, uio); - st_free_buf(unit,bp); - return(rc); -} + /***************************************************************\ + * If the tape density mandates use of fixed or variable-length * + * blocks, comply. * + \***************************************************************/ + switch (st->density) + { + case HALFINCH_800: + case HALFINCH_1600: + case HALFINCH_6250: + st->flags &= ~ST_FIXEDBLOCKS; + st->blksiz = 0; +#ifdef STDEBUG + if(st_debug) printf("density specified variable\n"); +#endif /*STDEBUG*/ + goto done; + case QIC_11: + case QIC_24: + case QIC_120: + case QIC_150: + st->flags |= ST_FIXEDBLOCKS; + if (st->media_blksiz > 0) + st->blksiz = st->media_blksiz; + else + st->blksiz = DEF_FIXED_BSIZE; +#ifdef STDEBUG + if(st_debug) printf("density specified fixed\n"); +#endif /*STDEBUG*/ + goto done; + } -/*******************************************************\ -* Get the buf for this unit and use physio to do it * -\*******************************************************/ -stwrite(dev,uio) -dev_t dev; -struct uio *uio; -{ - int unit = UNIT(dev); - struct buf *bp = st_get_buf(unit); - int rc; + /***************************************************************\ + * If we're about to read the tape, perhaps we should choose * + * fixed or variable-length blocks and block size according to * + * what the drive found on the tape. * + * ****though it probably hasn't looked yet!**** * + \***************************************************************/ + if (first_read) + { + if (st->media_blksiz == 0) + st->flags &= ~ST_FIXEDBLOCKS; + else + st->flags |= ST_FIXEDBLOCKS; + st->blksiz = st->media_blksiz; +#ifdef STDEBUG + if(st_debug) printf("Used media_blksiz of %d\n",st->media_blksiz); +#endif /*STDEBUG*/ + goto done; + } - rc = physio(ststrategy, bp, dev, B_WRITE, stminphys, uio); - st_free_buf(unit,bp); - return(rc); -} + /***************************************************************\ + * If the drive says it can handle variable size blocks * + * and nothing has been specified until now, hey let's do it * + \***************************************************************/ + if (st->blkmin != st->blkmax) + { + st->flags &= ~ST_FIXEDBLOCKS; + st->blksiz = 0; +#ifdef STDEBUG + if(st_debug) printf("blkmin != blkmax\n, select variable\n"); +#endif /*STDEBUG*/ + goto done; + } + /***************************************************************\ + * We're getting no hints from any direction. Choose fixed- * + * length blocks arbitrarily. * + \***************************************************************/ + st->flags |= ST_FIXEDBLOCKS; + st->blksiz = DEF_FIXED_BSIZE; +#ifdef STDEBUG + if(st_debug) printf("Give up and default to fixed mode\n"); +#endif /*STDEBUG*/ +done: + st->flags &= ~ST_AT_BOM; + return (st_mode_select(unit, 0)); +} -#endif __386BSD__ /*******************************************************\ * trim the size of the transfer if needed, * * called by physio * @@ -669,7 +838,7 @@ struct uio *uio; void stminphys(bp) struct buf *bp; { - (*(st_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); + (*(st_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp); } /*******************************************************\ @@ -682,15 +851,19 @@ struct buf *bp; int ststrategy(bp) struct buf *bp; { - struct buf *dp; + struct buf **dp; unsigned char unit; unsigned int opri; + struct st_data *st; ststrats++; unit = UNIT((bp->b_dev)); + st = st_data[unit]; +#ifdef STDEBUG if(scsi_debug & PRINTROUTINES) printf("\nststrategy "); if(scsi_debug & SHOWREQUESTS) printf("st%d: %d bytes @ blk%d\n", unit,bp->b_bcount,bp->b_blkno); +#endif /*STDEBUG*/ /*******************************************************\ * If it's a null transfer, return immediatly * \*******************************************************/ @@ -700,45 +873,53 @@ struct buf *bp; } /*******************************************************\ + * If we're at beginning of medium, now is the time to * + * set medium access density, fixed or variable-blocks * + * and, if fixed, the block size. * + \*******************************************************/ + if (st->flags & ST_AT_BOM && + (bp->b_error = st_decide_mode(unit, (bp->b_flags & B_READ) != 0))) + goto bad; + + /*******************************************************\ * Odd sized request on fixed drives are verboten * \*******************************************************/ - if(st_data[unit].flags & ST_FIXEDBLOCKS) + if(st->flags & ST_FIXEDBLOCKS) { - if(bp->b_bcount % st_data[unit].blksiz) + if(bp->b_bcount % st->blksiz) { printf("st%d: bad request, must be multiple of %d\n", - unit, st_data[unit].blksiz); + unit, st->blksiz); bp->b_error = EIO; goto bad; } } /*******************************************************\ - * as are too-short requests on variable length drives. * + * as are out-of-range requests on variable drives. * \*******************************************************/ - else if(bp->b_bcount < st_data[unit].blkmin) + else if(bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax) { - printf("st%d: bad request, must not be less than %d\n", - unit, st_data[unit].blkmin); + printf("st%d: bad request, must be between %d and %d\n", + unit, st->blkmin, st->blkmax); bp->b_error = EIO; goto bad; } -#ifdef __386BSD__ stminphys(bp); -#endif __386BSD__ opri = splbio(); - dp = &st_buf_queue[unit]; /*******************************************************\ - * Place it in the queue of disk activities for this tape* - * at the end * + * Place it in the queue of activities for this tape * + * at the end (a bit silly because we only have on user..* + * (but it could fork() )) * \*******************************************************/ - while ( dp->b_actf) + dp = &(st->buf_queue); + while (*dp) { - dp = dp->b_actf; + dp = &((*dp)->b_actf); } - dp->b_actf = bp; - bp->b_actf = NULL; + *dp = bp; + bp->b_actf = NULL, /*******************************************************\ * Tell the device to get going on the transfer if it's * @@ -760,371 +941,7 @@ done: } -/***************************************************************\ -* ststart looks to see if there is a buf waiting for the device * -* and that the device is not already busy. If both are true, * -* It deques the buf and creates a scsi command to perform the * -* transfer in the buf. The transfer request will call st_done * -* on completion, which will in turn call this routine again * -* so that the next queued transfer is performed. * -* The bufs are queued by the strategy routine (ststrategy) * -* * -* This routine is also called after other non-queued requests * -* have been made of the scsi driver, to ensure that the queue * -* continues to be drained. * -\***************************************************************/ -/* ststart() is called at splbio */ -ststart(unit) -{ - int drivecount; - register struct buf *bp = 0; - register struct buf *dp; - struct scsi_xfer *xs; - struct scsi_rw_tape cmd; - int blkno, nblk; - struct st_data *st; - - - st = st_data + unit; - - if(scsi_debug & PRINTROUTINES) printf("ststart%d ",unit); - /*******************************************************\ - * See if there is a buf to do and we are not already * - * doing one * - \*******************************************************/ - xs=&st_scsi_xfer[unit]; - if(xs->flags & INUSE) - { - return; /* unit already underway */ - } -trynext: - if(st_xfer_block_wait[unit]) /* a special awaits, let it proceed first */ - { - wakeup(&st_xfer_block_wait[unit]); - return; - } - - dp = &st_buf_queue[unit]; - if ((bp = dp->b_actf) != NULL) - { - dp->b_actf = bp->b_actf; - } - else /* no work to do */ - { - return; - } - xs->flags = INUSE; /* Now ours */ - - - /*******************************************************\ - * We have a buf, now we should move the data into * - * a scsi_xfer definition and try start it * - \*******************************************************/ - - /*******************************************************\ - * If we are at a filemark but have not reported it yet * - * then we should report it now * - \*******************************************************/ - if(st->flags & ST_AT_FILEMARK) - { - bp->b_error = 0; - bp->b_flags |= B_ERROR; /* EOF*/ - st->flags &= ~ST_AT_FILEMARK; - biodone(bp); - xs->flags = 0; /* won't need it now */ - goto trynext; - } - /*******************************************************\ - * If we are at EOM but have not reported it yet * - * then we should report it now * - \*******************************************************/ - if(st->flags & ST_AT_EOM) - { - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - st->flags &= ~ST_AT_EOM; - biodone(bp); - xs->flags = 0; /* won't need it now */ - goto trynext; - } - /*******************************************************\ - * Fill out the scsi command * - \*******************************************************/ - bzero(&cmd, sizeof(cmd)); - if((bp->b_flags & B_READ) == B_WRITE) - { - st->flags |= ST_WRITTEN; - xs->flags |= SCSI_DATA_OUT; - } - else - { - xs->flags |= SCSI_DATA_IN; - } - cmd.op_code = (bp->b_flags & B_READ) - ? READ_COMMAND_TAPE - : WRITE_COMMAND_TAPE; - - /*******************************************************\ - * Handle "fixed-block-mode" tape drives by using the * - * block count instead of the length. * - \*******************************************************/ - if(st->flags & ST_FIXEDBLOCKS) - { - cmd.byte2 |= SRWT_FIXED; - lto3b(bp->b_bcount/st->blksiz,cmd.len); - } - else - { - lto3b(bp->b_bcount,cmd.len); - } - - /*******************************************************\ - * Fill out the scsi_xfer structure * - * Note: we cannot sleep as we may be an interrupt * - \*******************************************************/ - xs->flags |= SCSI_NOSLEEP; - xs->adapter = st->ctlr; - xs->targ = st->targ; - xs->lu = st->lu; - xs->retries = 1; /* can't retry on tape*/ - xs->timeout = 100000; /* allow 100 secs for retension */ - xs->cmd = (struct scsi_generic *)&cmd; - xs->cmdlen = sizeof(cmd); - xs->data = (u_char *)bp->b_un.b_addr; - xs->datalen = bp->b_bcount; - xs->resid = bp->b_bcount; - xs->when_done = st_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; - xs->error = XS_NOERROR; - xs->bp = bp; - /*******************************************************\ - * Pass all this info to the scsi driver. * - \*******************************************************/ - - -#if defined(OSF)||defined(FIX_ME) - if (bp->b_flags & B_PHYS) { - xs->data = (u_char*)map_pva_kva(bp->b_proc, bp->b_un.b_addr, - bp->b_bcount, st_window[unit], - (bp->b_flags&B_READ)?B_WRITE:B_READ); - } else { - xs->data = (u_char*)bp->b_un.b_addr; - } -#endif /* defined(OSF) */ - - if ( (*(st->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) - { - printf("st%d: oops not queued",unit); - xs->error = XS_DRIVER_STUFFUP; - st_done(unit,xs); - } - stqueues++; -} - -/*******************************************************\ -* This routine is called by the scsi interrupt when * -* the transfer is complete. -\*******************************************************/ -int st_done(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct buf *bp; - int retval; - - if(scsi_debug & PRINTROUTINES) printf("st_done%d ",unit); - if (! (xs->flags & INUSE)) - panic("scsi_xfer not in use!"); - if(bp = xs->bp) - { - switch(xs->error) - { - case XS_NOERROR: - bp->b_flags &= ~B_ERROR; - bp->b_error = 0; - bp->b_resid = 0; - break; - case XS_SENSE: - retval = (st_interpret_sense(unit,xs)); - if(retval) - { - /***************************************\ - * We have a real error, the bit should * - * be set to indicate this. The return * - * value will contain the unix error code* - * that the error interpretation routine * - * thought was suitable, so pass this * - * value back in the buf structure. * - * Furthermore we return information * - * saying that no data was transferred * - \***************************************/ - bp->b_flags |= B_ERROR; - bp->b_error = retval; - bp->b_resid = bp->b_bcount; - st_data[unit].flags - &= ~(ST_AT_FILEMARK|ST_AT_EOM); - } - else - { - /***********************************************\ - * The error interpretation code has declared * - * that it wasn't a real error, or at least that * - * we should be ignoring it if it was. * - \***********************************************/ - if(!(xs->resid)) - { - /***************************************\ - * we apparently had a corrected error * - * or something. * - * pretend the error never happenned * - \***************************************/ - bp->b_flags &= ~B_ERROR; - bp->b_error = 0; - bp->b_resid = 0; - break; - } - if ( xs->resid != xs->datalen ) - { - /***************************************\ - * Here we have the tricky part.. * - * We successfully read less data than * - * we requested. (but not 0) * - *------for variable blocksize tapes:----* - * UNDER 386BSD: * - * We should legitimatly have the error * - * bit set, with the error value set to * - * zero.. This is to indicate to the * - * physio code that while we didn't get * - * as much information as was requested, * - * we did reach the end of the record * - * and so physio should not call us * - * again for more data... we have it all * - * SO SET THE ERROR BIT! * - * * - * UNDER MACH (CMU) and NetBSD: * - * To indicate the same as above, we * - * need only have a non 0 resid that is * - * less than the b_bcount, but the * - * ERROR BIT MUST BE CLEAR! (sigh) * - * * - * UNDER OSF1: * - * To indicate the same as above, we * - * need to have a non 0 resid that is * - * less than the b_bcount, but the * - * ERROR BIT MUST BE SET! (gasp)(sigh) * - * * - *-------for fixed blocksize device------* - * We could have read some successful * - * records before hitting * - * the EOF or EOT. These must be passed * - * to the user, before we report the * - * EOx. Only if there is no data for the * - * user do we report it now. (via an EIO * - * for EOM and resid == count for EOF). * - * We will report the EOx NEXT time.. * - \***************************************/ -/* how do I distinguish NetBSD? at present it's wrong for NetBsd */ -#ifdef MACH /*osf and cmu varieties */ -#ifdef OSF - bp->b_flags |= B_ERROR; -#else OSF - bp->b_flags &= ~B_ERROR; -#endif OSF -#endif MACH -#ifdef __386BSD__ - bp->b_flags |= B_ERROR; -#endif __386BSD__ - bp->b_error = 0; - bp->b_resid = xs->resid; - if((st_data[unit].flags & ST_FIXEDBLOCKS)) - { - bp->b_resid *= st_data[unit].blksiz; - if( (st_data[unit].flags & ST_AT_EOM) - && (bp->b_resid == bp->b_bcount)) - { - bp->b_error = EIO; - st_data[unit].flags - &= ~ST_AT_EOM; - } - } - xs->error = XS_NOERROR; - break; - } - else - { - /***************************************\ - * We have come out of the error handler * - * with no error code.. we have also * - * not had an ili (would have gone to * - * the previous clause). Now we need to * - * distiguish between succesful read of * - * no data (EOF or EOM) and successfull * - * read of all requested data. * - * At least all o/s agree that: * - * 0 bytes read with no error is EOF * - * 0 bytes read with an EIO is EOM * - \***************************************/ - - bp->b_resid = bp->b_bcount; - if(st_data[unit].flags & ST_AT_FILEMARK) - { - st_data[unit].flags &= ~ST_AT_FILEMARK; - bp->b_flags &= ~B_ERROR; - bp->b_error = 0; - break; - } - if(st_data[unit].flags & ST_AT_EOM) - { - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - st_data[unit].flags &= ~ST_AT_EOM; - break; - } - } - } - break; - - case XS_TIMEOUT: - printf("st%d timeout\n",unit); - break; - - case XS_BUSY: /* should retry */ /* how? */ - /************************************************/ - /* SHOULD put buf back at head of queue */ - /* and decrement retry count in (*xs) */ - /* HOWEVER, this should work as a kludge */ - /************************************************/ - if(xs->retries--) - { - xs->flags &= ~ITSDONE; - xs->error = XS_NOERROR; - if ( (*(st_data[unit].sc_sw->scsi_cmd))(xs) - == SUCCESSFULLY_QUEUED) - { /* don't wake the job, ok? */ - return; - } - printf("st%d: device busy\n", unit); - xs->flags |= ITSDONE; - } - case XS_DRIVER_STUFFUP: - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - default: - printf("st%d: unknown error category from scsi driver\n" - ,unit); - } - biodone(bp); - xs->flags = 0; /* no longer in use */ - ststart(unit); /* If there's another waiting.. do it */ - } - else - { - wakeup(xs); - } -} /*******************************************************\ * Perform special action on behalf of the user * * Knows about the internals of this device * @@ -1146,7 +963,7 @@ caddr_t arg; \*******************************************************/ flags = 0; /* give error messages, act on errors etc. */ unit = UNIT(dev); - st = st_data + unit; + st = st_data[unit]; switch(cmd) { @@ -1173,9 +990,11 @@ caddr_t arg; { struct mtop *mt = (struct mtop *) arg; +#ifdef STDEBUG if (st_debug) printf("[sctape_sstatus: %x %x]\n", mt->mt_op, mt->mt_count); +#endif /*STDEBUG*/ @@ -1184,34 +1003,33 @@ caddr_t arg; switch ((short)(mt->mt_op)) { case MTWEOF: /* write an end-of-file record */ - if(!st_write_filemarks(unit,number,flags)) errcode = EIO; - st_data[unit].flags &= ~ST_WRITTEN; + errcode = st_write_filemarks(unit,number,flags); break; case MTFSF: /* forward space file */ - if(!st_space(unit,number,SP_FILEMARKS,flags)) errcode = EIO; + errcode = st_space(unit,number,SP_FILEMARKS,flags); break; case MTBSF: /* backward space file */ - if(!st_space(unit,-number,SP_FILEMARKS,flags)) errcode = EIO; + errcode = st_space(unit,-number,SP_FILEMARKS,flags); break; case MTFSR: /* forward space record */ - if(!st_space(unit,number,SP_BLKS,flags)) errcode = EIO; + errcode = st_space(unit,number,SP_BLKS,flags); break; case MTBSR: /* backward space record */ - if(!st_space(unit,-number,SP_BLKS,flags)) errcode = EIO; + errcode = st_space(unit,-number,SP_BLKS,flags); break; case MTREW: /* rewind */ - if(!st_rewind(unit,FALSE,flags)) errcode = EIO; + errcode = st_rewind(unit,FALSE,flags); break; case MTOFFL: /* rewind and put the drive offline */ if(st_rewind(unit,FALSE,flags)) { - st_prevent(unit,PR_ALLOW,0); - st_load(unit,LD_UNLOAD,flags); + printf("st%d: rewind failed, unit still loaded\n", + unit); } else { - printf("st%d: rewind failed, unit still loaded\n", - unit); + st_prevent(unit,PR_ALLOW,0); + st_load(unit,LD_UNLOAD,flags); } break; case MTNOP: /* no operation, sets status only */ @@ -1219,33 +1037,23 @@ caddr_t arg; case MTNOCACHE: /* disable controller cache */ break; case MTSETBSIZ: /* Set block size for device */ - if (st->blkmin == st->blkmax) + if (st->blkmin && st->blkmin == st->blkmax || + st->quirks & ST_Q_FORCE_FIXED_MODE) + /* Per definition in mtio.h, this is a */ + /* no-op for a real fixed block device */ + break; + if (!(st->flags & ST_AT_BOM) || number < 0 || number > 0 + && (number < st->blkmin || number > st->blkmax)) { - /* This doesn't make sense for a */ - /* real fixed block device */ errcode = EINVAL; - } + break; + } + if (number == 0) + st->flags &= ~ST_FIXEDBLOCKS; else - { - if ( number == 0 ) - { - /* Restoring original block size */ - st->flags &= ~ST_FIXEDBLOCKS; /*XXX*/ - st->blksiz = st->media_blksiz; - } - else - { - if (number < st->blkmin || number > st->blkmax) - { - errcode = EINVAL; - } - else - { - st->blksiz = number; - st->flags |= ST_FIXEDBLOCKS; - } - } - } + st->flags |= ST_FIXEDBLOCKS; + st->blksiz = number; + st->flags |= ST_BLOCK_SET; break; /* How do we check that the drive can handle @@ -1299,35 +1107,49 @@ caddr_t arg; return errcode; } - -#ifdef removing_this /*******************************************************\ -* Check with the device that it is ok, (via scsi driver)* +* Do a synchronous read. * \*******************************************************/ -st_req_sense(unit, flags) -int flags; +int st_read(unit, buf, size, flags) +int unit, size, flags; +char *buf; { - struct scsi_sense_data sense; - struct scsi_sense scsi_cmd; + int error; + struct scsi_rw_tape scsi_cmd; + struct st_data *st = st_data[unit]; - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = REQUEST_SENSE; - scsi_cmd.length = sizeof(sense); + /*******************************************************\ + * If it's a null transfer, return immediatly * + \*******************************************************/ + if (size == 0) + { + return(ESUCCESS); + } - if (st_scsi_cmd(unit, + /*******************************************************\ + * If we're at beginning of medium, now is the time to * + * set medium access density, fixed or variable-blocks * + * and, if fixed, the block size. * + \*******************************************************/ + if (st->flags & ST_AT_BOM && (error = st_decide_mode(unit, TRUE))) + return (error); + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = READ_COMMAND_TAPE; + scsi_cmd.byte2 |= st->flags & ST_FIXEDBLOCKS ? SRWT_FIXED : 0; + lto3b(scsi_cmd.byte2 & SRWT_FIXED ? + size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE) : size, + scsi_cmd.len); + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), - &sense, - sizeof(sense), + buf, + size, 100000, - flags | SCSI_DATA_IN) != 0) - { - return(FALSE); - } - return(TRUE); + NULL, + flags | SCSI_DATA_IN)); } -#endif /*******************************************************\ * Get scsi driver to send a "are you ready" command * \*******************************************************/ @@ -1339,17 +1161,14 @@ int unit,flags; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = TEST_UNIT_READY; - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, 100000, - flags) != 0) - { - return(FALSE); - } - return(TRUE); + NULL, + flags)); } @@ -1367,11 +1186,13 @@ int unit,flags; { struct scsi_blk_limits scsi_cmd; struct scsi_blk_limits_data scsi_blkl; - struct st_data *st = st_data + unit; + struct st_data *st = st_data[unit]; + int errno; + /*******************************************************\ * First check if we have it all loaded * \*******************************************************/ - if ((st->flags & ST_INFO_VALID)) return TRUE; + if ((st->flags & ST_INFO_VALID)) return 0; /*******************************************************\ * do a 'Read Block Limits' * @@ -1382,26 +1203,27 @@ int unit,flags; /*******************************************************\ * do the command, update the global values * \*******************************************************/ - if (st_scsi_cmd(unit, + if ( errno = st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), &scsi_blkl, sizeof(scsi_blkl), 5000, - flags | SCSI_DATA_IN) != 0) + NULL, + flags | SCSI_DATA_IN)) { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not get blk limits\n", unit); - st->flags &= ~ST_INFO_VALID; - return(FALSE); + return errno; } st->blkmin = b2tol(scsi_blkl.min_length); st->blkmax = _3btol(&scsi_blkl.max_length_2); +#ifdef STDEBUG if (st_debug) { - printf(" (%d <= blksiz <= %d\n) ",st->blkmin,st->blkmax); + printf("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax); } +#endif /*STDEBUG*/ + return 0; } /*******************************************************\ @@ -1418,6 +1240,7 @@ st_mode_sense(unit, flags) int unit,flags; { int scsi_sense_len; + int errno; char *scsi_sense_ptr; struct scsi_mode_sense scsi_cmd; struct scsi_sense @@ -1438,12 +1261,12 @@ int unit,flags; /* They also expect page 00 */ /* back when you issue a mode select */ }scsi_sense_page_0; - struct st_data *st = st_data + unit; + struct st_data *st = st_data[unit]; /*******************************************************\ * First check if we have it all loaded * \*******************************************************/ - if ((st->flags & ST_INFO_VALID)) return(TRUE); + if ((st->flags & ST_INFO_VALID)) return 0; /*******************************************************\ * Define what sort of structure we're working with * @@ -1472,51 +1295,49 @@ int unit,flags; * or if we need it as a template for the mode select * * store it away. * \*******************************************************/ - if (st_scsi_cmd(unit, + if (errno = st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), scsi_sense_ptr, scsi_sense_len, 5000, - flags | SCSI_DATA_IN) != 0) + NULL, + flags | SCSI_DATA_IN) ) { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not mode sense\n", unit); - st->flags &= ~ST_INFO_VALID; - return(FALSE); + return errno; } st->numblks = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks)); st->media_blksiz = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen)); st->media_density = ((struct scsi_sense *)scsi_sense_ptr)->blk_desc.density; + if (((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec & + SMH_DSP_WRITE_PROT) + st->flags |= ST_READONLY; +#ifdef STDEBUG if (st_debug) { - printf("unit %d: %d blocks of %d bytes, write %s, %sbuffered", - unit, - st->numblks, - st->media_blksiz, - ((((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec - & SMH_DSP_WRITE_PROT) ? - "protected" : "enabled"), - ((((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec - & SMH_DSP_BUFF_MODE)? - "" : "un") - ); + printf("st%d: density code 0x%x, %d-byte blocks, write-%s, ", + unit, st->media_density, st->media_blksiz, + st->flags & ST_READONLY ? "protected" : "enabled"); + printf("%sbuffered\n", + ((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec + & SMH_DSP_BUFF_MODE ? "" : "un"); } +#endif /*STDEBUG*/ if (st->quirks & ST_Q_NEEDS_PAGE_0) { bcopy(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data, st->sense_data, sizeof(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data)); } - return(TRUE); + return 0; } /*******************************************************\ * Send a filled out parameter structure to the drive to * * set it into the desire modes etc. * \*******************************************************/ -st_mode_select(unit, flags, dsty_code) -int unit,flags,dsty_code; +st_mode_select(unit, flags) +int unit, flags; { int dat_len; char *dat_ptr; @@ -1532,7 +1353,7 @@ int unit,flags,dsty_code; struct blk_desc blk_desc; unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; }dat_page_0; - struct st_data *st = st_data + unit; + struct st_data *st = st_data[unit]; /*******************************************************\ * Define what sort of structure we're working with * @@ -1557,7 +1378,7 @@ int unit,flags,dsty_code; scsi_cmd.length = dat_len; ((struct dat *)dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc); ((struct dat *)dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON; - ((struct dat *)dat_ptr)->blk_desc.density = dsty_code; + ((struct dat *)dat_ptr)->blk_desc.density = st->density; if(st->flags & ST_FIXEDBLOCKS) { lto3b( st->blksiz , ((struct dat *)dat_ptr)->blk_desc.blklen); @@ -1572,20 +1393,14 @@ int unit,flags,dsty_code; /*******************************************************\ * do the command * \*******************************************************/ - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), dat_ptr, dat_len, 5000, - flags | SCSI_DATA_OUT) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not mode select\n", unit); - st->flags &= ~ST_INFO_VALID; - return(FALSE); - } - return(TRUE); + NULL, + flags | SCSI_DATA_OUT) ); } /*******************************************************\ @@ -1594,28 +1409,33 @@ int unit,flags,dsty_code; st_space(unit,number,what,flags) int unit,number,what,flags; { + int error; struct scsi_space scsi_cmd; + struct st_data *st = st_data[unit]; + + /*******************************************************\ + * If we're at beginning of medium, now is the time to * + * set medium access density, fixed or variable-blocks * + * and, if fixed, the block size. * + \*******************************************************/ + if (st->flags & ST_AT_BOM && + (error = st_decide_mode(unit, TRUE))) + return (error); /* if we are at a filemark now, we soon won't be*/ - st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM); + st->flags &= ~ST_PER_ACTION; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = SPACE; scsi_cmd.byte2 = what & SS_CODE; lto3b(number,scsi_cmd.number); - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, 600000, /* 10 mins enough? */ - flags) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not space\n", unit); - st_data[unit].flags &= ~ST_INFO_VALID; - return(FALSE); - } - return(TRUE); + NULL, + flags)); } /*******************************************************\ * write N filemarks * @@ -1623,57 +1443,67 @@ int unit,number,what,flags; st_write_filemarks(unit,number,flags) int unit,number,flags; { + int error; struct scsi_write_filemarks scsi_cmd; + struct st_data *st = st_data[unit]; + + /*******************************************************\ + * It's hard to write a negative number of file marks. * + * Don't try. * + \*******************************************************/ + if (number < 0) + return (EINVAL); - st_data[unit].flags &= ~(ST_AT_FILEMARK); + /*******************************************************\ + * If we're at beginning of medium, now is the time to * + * set medium access density, fixed or variable-blocks * + * and, if fixed, the block size. * + \*******************************************************/ + if (st->flags & ST_AT_BOM && + (error = st_decide_mode(unit, FALSE))) + return (error); + + st->flags &= ~(ST_AT_FILEMARK | ST_WRITTEN); bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = WRITE_FILEMARKS; lto3b(number,scsi_cmd.number); - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, 100000, /* 10 secs.. (may need to repos head )*/ - flags) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not write_filemarks\n", unit); - st_data[unit].flags &= ~ST_INFO_VALID; - return(FALSE); - } - return(TRUE); + NULL, + flags) ); } /*******************************************************\ -* load /unload (with retension if true) * +* load/unload (with retension if true) * \*******************************************************/ st_load(unit,type,flags) int unit,type,flags; { struct scsi_load scsi_cmd; + struct st_data *st = st_data[unit]; - st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM); + st->flags &= ~ST_PER_ACTION; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = LOAD_UNLOAD; scsi_cmd.how=type; if (type == LD_LOAD) { /*scsi_cmd.how |= LD_RETEN;*/ + st->flags |= ST_AT_BOM; } - if (st_scsi_cmd(unit, + else + st->flags &= ~ST_INFO_VALID; + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, - 30000, /* 30 secs */ - flags) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("cannot load/unload st%d\n", unit); - return(FALSE); - st_data[unit].flags &= ~ST_INFO_VALID; - } - return(TRUE); + 300000, /* 5 min */ + NULL, + flags)); } /*******************************************************\ * Prevent or allow the user to remove the tape * @@ -1683,23 +1513,19 @@ int unit,type,flags; { struct scsi_prevent scsi_cmd; + if (type == PR_ALLOW) + st_data[unit]->flags &= ~ST_INFO_VALID; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = PREVENT_ALLOW; scsi_cmd.how=type; - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, 5000, - flags) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("st%d: cannot prevent/allow\n", unit); - st_data[unit].flags &= ~ST_INFO_VALID; - return(FALSE); - } - return(TRUE); + NULL, + flags)); } /*******************************************************\ * Rewind the device * @@ -1708,26 +1534,330 @@ st_rewind(unit,immed,flags) int unit,immed,flags; { struct scsi_rewind scsi_cmd; + struct st_data *st = st_data[unit]; - st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM); + st->flags &= ~ST_PER_ACTION; + st->flags |= ST_AT_BOM; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = REWIND; - scsi_cmd.byte2=immed?SR_IMMED:0?SR_IMMED:0; - if (st_scsi_cmd(unit, + scsi_cmd.byte2 = immed ? SR_IMMED : 0; + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, immed?5000:300000, /* 5 sec or 5 min */ - flags) != 0) + NULL, + flags)); +} + +/***************************************************************\ +* ststart looks to see if there is a buf waiting for the device * +* and that the device is not already busy. If both are true, * +* It deques the buf and creates a scsi command to perform the * +* transfer in the buf. The transfer request will call st_done * +* on completion, which will in turn call this routine again * +* so that the next queued transfer is performed. * +* The bufs are queued by the strategy routine (ststrategy) * +* * +* This routine is also called after other non-queued requests * +* have been made of the scsi driver, to ensure that the queue * +* continues to be drained. * +\***************************************************************/ +/* ststart() is called at splbio */ +ststart(unit) +{ + int drivecount; + register struct buf *bp = 0; + register struct buf *dp; + struct scsi_rw_tape cmd; + int blkno, nblk; + struct st_data *st = st_data[unit]; + int flags; + + + +#ifdef STDEBUG + if(scsi_debug & PRINTROUTINES) printf("ststart%d ",unit); +#endif /*STDEBUG*/ + /*******************************************************\ + * See if there is a buf to do and we are not already * + * doing one * + \*******************************************************/ + if(st->scsi_xfer.flags & INUSE) + { + return; /* unit already underway */ + } +trynext: + if(st->xfer_block_wait) /* a special awaits, let it proceed first */ + { + wakeup(&(st->xfer_block_wait)); + return; + } + + if ((bp = st->buf_queue) == NULL) + { + return; /* no work to bother with */ + } + st->buf_queue = bp->b_actf; + + + + /*******************************************************\ + * only FIXEDBLOCK devices have pending operations * + \*******************************************************/ + if(st->flags & ST_FIXEDBLOCKS) + { + /*******************************************************\ + * If we are at a filemark but have not reported it yet * + * then we should report it now * + \*******************************************************/ + if(st->flags & ST_AT_FILEMARK) + { + bp->b_resid = bp->b_bcount; + bp->b_error = 0; + bp->b_flags &= ~B_ERROR; + st->flags &= ~ST_AT_FILEMARK; + biodone(bp); + goto trynext; + } + /*******************************************************\ + * If we are at EIO (e.g. EOM) but have not reported it * + * yet then we should report it now * + \*******************************************************/ + if(st->flags & ST_EIO_PENDING) + { + bp->b_resid = bp->b_bcount; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + st->flags &= ~ST_EIO_PENDING; + biodone(bp); + goto trynext; + } + } + /*******************************************************\ + * Fill out the scsi command * + \*******************************************************/ + bzero(&cmd, sizeof(cmd)); + if((bp->b_flags & B_READ) == B_WRITE) + { + cmd.op_code = WRITE_COMMAND_TAPE; + st->flags |= ST_WRITTEN; + flags = SCSI_DATA_OUT; + } + else + { + cmd.op_code = READ_COMMAND_TAPE; + flags = SCSI_DATA_IN; + } + + /*******************************************************\ + * Handle "fixed-block-mode" tape drives by using the * + * block count instead of the length. * + \*******************************************************/ + if(st->flags & ST_FIXEDBLOCKS) { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not rewind\n", unit); - st_data[unit].flags &= ~ST_INFO_VALID; - return(FALSE); + cmd.byte2 |= SRWT_FIXED; + lto3b(bp->b_bcount/st->blksiz,cmd.len); } - return(TRUE); + else + { + lto3b(bp->b_bcount,cmd.len); + } + + /*******************************************************\ + * go ask the adapter to do all this for us * + \*******************************************************/ + if (st_scsi_cmd(unit, + &cmd, + sizeof(cmd), + (u_char *)bp->b_un.b_addr, + bp->b_bcount, + 100000, + bp, + flags | SCSI_NOSLEEP ) != SUCCESSFULLY_QUEUED) + + { + printf("st%d: oops not queued\n",unit); + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + biodone(bp); + return; + } + stqueues++; +} + +/*******************************************************\ +* This routine is called by the scsi interrupt when * +* the transfer is complete. +\*******************************************************/ +int st_done(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct buf *bp; + int retval; + struct st_data *st = st_data[unit]; + +#ifdef STDEBUG + if(scsi_debug & PRINTROUTINES) printf("st_done%d ",unit); +#endif /*STDEBUG*/ +#ifdef PARANOID + if (! (xs->flags & INUSE)) + panic("scsi_xfer not in use!"); +#endif /*PARANOID*/ + if((bp = xs->bp)== NULL) + { + wakeup(xs); + return; + } + switch(xs->error) + { + case XS_NOERROR: + bp->b_flags &= ~B_ERROR; + bp->b_error = 0; + bp->b_resid = 0; + break; + case XS_SENSE: + retval = (st_interpret_sense(unit,xs)); + bp->b_resid = xs->resid; /* already multiplied by blksiz */ + if(retval) + { + /***************************************\ + * We have a real error, the bit should * + * be set to indicate this. The return * + * value will contain the unix error code* + * that the error interpretation routine * + * thought was suitable, so pass this * + * value back in the buf structure. * + * Furthermore we return information * + * saying that no data was transferred * + * All status is now suspect * + \***************************************/ + bp->b_flags |= B_ERROR; + bp->b_error = retval; + bp->b_resid = bp->b_bcount; + st->flags &= ~ST_PER_ACTION; + } + else + { + /***********************************************\ + * The error interpretation code has declared * + * that it wasn't a real error, or at least that * + * we should be ignoring it if it was. * + \***********************************************/ + if(xs->resid == 0) + { + /***************************************\ + * we apparently had a corrected error * + * or something. * + * pretend the error never happenned * + \***************************************/ + bp->b_flags &= ~B_ERROR; + bp->b_error = 0; + break; + } + if ( xs->resid != xs->datalen ) + { + /***************************************\ + * Here we have the tricky part.. * + * We successfully read less data than * + * we requested. (but not 0) * + *------for variable blocksize tapes:----* + * UNDER 386BSD: * + * We should legitimatly have the error * + * bit set, with the error value set to * + * zero.. This is to indicate to the * + * physio code that while we didn't get * + * as much information as was requested, * + * we did reach the end of the record * + * and so physio should not call us * + * again for more data... we have it all * + * SO SET THE ERROR BIT! * + * * + * UNDER NetBSD: * + * To indicate the same as above, we * + * need only have a non 0 resid that is * + * less than the b_bcount, but the * + * ERROR BIT MUST BE CLEAR! (sigh) * + * * + *-------for fixed blocksize device------* + * We read some successful records * + * before hitting the EOF or EOT. These * + * must be passed to the user, before we * + * report the EOx. We will report the * + * EOx NEXT time. * + \***************************************/ +#ifdef NETBSD + bp->b_flags &= ~B_ERROR; +#else + bp->b_flags |= B_ERROR; +#endif + bp->b_error = 0; + xs->error = XS_NOERROR; + break; + } + else + { + /***************************************\ + * We have come out of the error handler * + * with no error code. We have also not * + * transferred any data (would have gone * + * to the previous clause). * + * This must be an EOF * + * Any caller request to read no * + * data would have been short-circuited * + * at st_read or ststrategy. * + * * + * At least all o/s agree that: * + * 0 bytes read with no error is EOF * + \***************************************/ + + bp->b_error = 0; + bp->b_flags &= ~B_ERROR; + st->flags &= ~ST_AT_FILEMARK; + break; + } + } + break; + + case XS_TIMEOUT: + printf("st%d timeout\n",unit); + + case XS_BUSY: /* should retry */ /* how? */ + /************************************************/ + /* SHOULD put buf back at head of queue */ + /* and decrement retry count in (*xs) */ + /* HOWEVER, this should work as a kludge */ + /************************************************/ + if(xs->retries--) + { + xs->flags &= ~ITSDONE; + xs->error = XS_NOERROR; + if ( (*(st->sc_sw->scsi_cmd))(xs) + == SUCCESSFULLY_QUEUED) + { /* don't wake the job, ok? */ + return; + } + printf("st%d: device busy\n",unit); + xs->flags |= ITSDONE; + } + + case XS_DRIVER_STUFFUP: + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + break; + default: + printf("st%d: unknown error category from scsi driver\n" + ,unit); + } + biodone(bp); + xs->flags = 0; /* no longer in use */ + ststart(unit); /* If there's another waiting.. do it */ } + + + /*******************************************************\ * ask the scsi driver to perform a command for us. * * Call it through the switch table, and tell it which * @@ -1737,115 +1867,120 @@ int unit,immed,flags; * Also tell it where to read/write the data, and how * * long the data is supposed to be * \*******************************************************/ -int st_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) +int st_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags) int unit,flags; struct scsi_generic *scsi_cmd; int cmdlen; int timeout; u_char *data_addr; +struct buf *bp; int datalen; { struct scsi_xfer *xs; int retval; int s; - struct st_data *st = st_data + unit; + struct st_data *st = st_data[unit]; +#ifdef STDEBUG if(scsi_debug & PRINTROUTINES) printf("\nst_scsi_cmd%d ",unit); - if(st->sc_sw) /* If we have a scsi driver */ +#endif /*STDEBUG*/ +#ifdef PARANOID + if(st->sc_sw == NULL) /* If we have no scsi driver */ { + printf("st%d: not set up\n",unit); + return(EINVAL); + } +#endif /*PARANOID*/ - xs = &(st_scsi_xfer[unit]); - if(!(flags & SCSI_NOMASK)) - s = splbio(); - st_xfer_block_wait[unit]++; /* there is someone waiting */ - while (xs->flags & INUSE) - { - sleep(&st_xfer_block_wait[unit],PRIBIO+1); - } - st_xfer_block_wait[unit]--; - xs->flags = INUSE; - if(!(flags & SCSI_NOMASK)) - splx(s); + xs = &(st->scsi_xfer); + if(!(flags & SCSI_NOMASK)) + s = splbio(); + st->xfer_block_wait++; /* there is someone waiting */ + while (xs->flags & INUSE) + { + if(flags & SCSI_NOSLEEP) + return EBUSY; + sleep(&(st->xfer_block_wait),PRIBIO+1); + } + st->xfer_block_wait--; + xs->flags = INUSE; + if(!(flags & SCSI_NOMASK)) + splx(s); - /*******************************************************\ - * Fill out the scsi_xfer structure * - \*******************************************************/ - xs->flags |= flags; - xs->adapter = st->ctlr; - xs->targ = st->targ; - xs->lu = st->lu; - xs->retries = ST_RETRIES; - xs->timeout = timeout; - xs->cmd = scsi_cmd; - xs->cmdlen = cmdlen; - xs->data = data_addr; - xs->datalen = datalen; - xs->resid = datalen; - xs->when_done = (flags & SCSI_NOMASK) - ?(int (*)())0 - :st_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; -retry: xs->error = XS_NOERROR; - xs->bp = 0; - retval = (*(st->sc_sw->scsi_cmd))(xs); - switch(retval) + /*******************************************************\ + * Fill out the scsi_xfer structure * + \*******************************************************/ + xs->flags |= flags; + xs->adapter = st->ctlr; + xs->targ = st->targ; + xs->lu = st->lu; + xs->retries = bp?0:ST_RETRIES;/*can't retry on IO*/ + xs->timeout = timeout; + xs->cmd = scsi_cmd; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->resid = datalen; + xs->when_done = st_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; + xs->bp = bp; +retry: xs->error = XS_NOERROR; + + /***********************************************\ + * Ask the adapter to do the command for us * + \***********************************************/ + retval = (*(st->sc_sw->scsi_cmd))(xs); + + /***********************************************\ + * IO operations are handled differently.. * + * Physio does the sleep, and error handling is * + * Done in st_done at interrupt time * + \***********************************************/ + if(bp) return retval; + + /***********************************************\ + * Wait for the result if queued, or handle the * + * error if it was rejected.. * + \***********************************************/ + switch(retval) + { + case SUCCESSFULLY_QUEUED: + s = splbio(); + while(!(xs->flags & ITSDONE)) + sleep(xs,PRIBIO+1); + splx(s); + /*******************************\ + * finished.. check for failure * + * Fall through...... * + \*******************************/ + case HAD_ERROR: + case COMPLETE: + switch(xs->error) { - case SUCCESSFULLY_QUEUED: - s = splbio(); - while(!(xs->flags & ITSDONE)) - sleep(xs,PRIBIO+1); - splx(s); - - case HAD_ERROR: - case COMPLETE: - switch(xs->error) + case XS_NOERROR: + retval = ESUCCESS; + break; + case XS_SENSE: + retval = (st_interpret_sense(unit,xs)); + /* only useful for reads *//* why did I say that?*/ + if (retval) + { /* error... don't care about filemarks */ + st->flags &= ~ST_PER_ACTION; + } + else { - case XS_NOERROR: + xs->error = XS_NOERROR; retval = ESUCCESS; - break; - case XS_SENSE: - retval = (st_interpret_sense(unit,xs)); - /* only useful for reads */ - if (retval) - { /* error... don't care about filemarks */ - st->flags &= ~(ST_AT_FILEMARK - | ST_AT_EOM); - } - else - { - xs->error = XS_NOERROR; - retval = ESUCCESS; - } - break; - case XS_DRIVER_STUFFUP: - retval = EIO; - break; - case XS_TIMEOUT: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - case XS_BUSY: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - default: - retval = EIO; - printf("st%d: unknown error category from scsi driver\n" - ,unit); - break; - } + } break; - case TRY_AGAIN_LATER: + case XS_DRIVER_STUFFUP: + retval = EIO; + break; + case XS_BUSY: + /* should sleep 1 sec here */ + case XS_TIMEOUT: if(xs->retries-- ) { xs->flags &= ~ITSDONE; @@ -1855,15 +1990,25 @@ retry: xs->error = XS_NOERROR; break; default: retval = EIO; + printf("st%d: unknown error category from scsi driver\n" + ,unit); + break; + } + break; + case TRY_AGAIN_LATER: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + /* should delay here */ + goto retry; } - xs->flags = 0; /* it's free! */ - ststart(unit); - } - else - { - printf("st%d: not set up\n",unit); - return(EINVAL); + retval = EIO; + break; + default: + retval = EIO; } + xs->flags = 0; /* it's free! */ + ststart(unit); return(retval); } /***************************************************************\ @@ -1878,6 +2023,9 @@ struct scsi_xfer *xs; struct scsi_sense_data *sense; int key; int silent = xs->flags & SCSI_SILENT; + struct st_data *st = st_data[unit]; + int info; + int errno = 0;/* default error */ /***************************************************************\ * If errors are ok, report a success * @@ -1885,9 +2033,10 @@ struct scsi_xfer *xs; if(xs->flags & SCSI_ERR_OK) return(ESUCCESS); /***************************************************************\ - * Get the sense fields and work out what CLASS * + * Get the sense fields and work out what code * \***************************************************************/ sense = &(xs->sense); +#ifdef STDEBUG if(st_debug) { int count = 0; @@ -1913,51 +2062,98 @@ struct scsi_xfer *xs; } printf("\n"); } +#endif /*STDEBUG*/ + if(sense->error_code & SSD_ERRCODE_VALID) + { + info = ntohl(*((long *)sense->ext.extended.info)); + } + else + { + info = xs->datalen; /* bad choice if fixed blocks */ + } + + switch(sense->error_code & SSD_ERRCODE) { /***************************************************************\ - * If it's class 7, use the extended stuff and interpret the key * + * If it's code 70, use the extended stuff and interpret the key * \***************************************************************/ case 0x70: { - if(sense->ext.extended.flags & SSD_EOM) + if(st->flags & ST_FIXEDBLOCKS) { - st_data[unit].flags |= ST_AT_EOM; - } + xs->resid = info * st->blksiz; + if(sense->ext.extended.flags & SSD_EOM) + { + st->flags |= ST_EIO_PENDING; + } + if(sense->ext.extended.flags & SSD_FILEMARK) + { + st->flags |= ST_AT_FILEMARK; + } + if(sense->ext.extended.flags & SSD_ILI) + { + st->flags |= ST_EIO_PENDING; + /*******************************************************\ + * The following quirk code deals with the fact that the * + * value of media_blksiz returned by the drive in * + * response to an st_mode_sense call doesn't reflect the * + * tape's format. * + * * + * The method is to try a fixed-length block read and * + * let this code determine whether the tape has fixed or * + * variable-length blocks, by seeing if we get an ILI * + * * + * Since the quirk code is the only place that calls the * + * board without the INFO_VALID set, catch that case * + * and handle it here (no other way of catching it * + * because resid info can't get passed without a buf) * + \*******************************************************/ - if(sense->ext.extended.flags & SSD_FILEMARK) - { - st_data[unit].flags |= ST_AT_FILEMARK; + if ((st->quirks & ST_Q_SNS_HLP) + && !(st->flags & ST_INFO_VALID)) + { + st->blksiz = 0; + } + } + /***********************************************\ + * If no data was tranfered, do it immediatly * + \***********************************************/ + if(xs->resid == xs->datalen) + { + if(st->flags & ST_EIO_PENDING) + { + return EIO; + } + if(st->flags & ST_AT_FILEMARK) + { + return 0; + } + } } - - if(sense->ext.extended.flags & SSD_ILI) + else { - if(sense->error_code & SSD_ERRCODE_VALID) + xs->resid = xs->datalen; /* to be sure */ + if(sense->ext.extended.flags & SSD_EOM) { - /*******************************\ - * In all ili cases, note that * - * the resid is non-0 AND not * - * unchanged. * - \*******************************/ - xs->resid - = ntohl(*((long *)sense->ext.extended.info)); - if(xs->bp) - { - if(xs->resid < 0) - { /* never on block devices */ - /***********************\ - * it's only really bad * - * if we have lost data * - * (the record was * - * bigger than the read) * - \***********************/ - return(EIO); - } - } + return(EIO); } - else - { /* makes no sense.. complain */ - printf("st%d: BAD length error?\n", unit); + if(sense->ext.extended.flags & SSD_FILEMARK) + { + return 0; + } + if(sense->ext.extended.flags & SSD_ILI) + { + if(info < 0) + /***************************************\ + * the record was bigger than the read * + \***************************************/ + { + printf("st%d: record of %d bytes too big\n", + unit, xs->datalen - info); + return(EIO); + } + xs->resid = info; } }/* there may be some other error. check the rest */ @@ -1965,25 +2161,20 @@ struct scsi_xfer *xs; switch(key) { case 0x0: - if(!(sense->ext.extended.flags & SSD_ILI)) - xs->resid = 0; /* XXX check this */ + if(xs->resid == xs->datalen) xs->resid = 0; return(ESUCCESS); case 0x1: + if(xs->resid == xs->datalen) xs->resid = 0; if(!silent) { - printf("st%d: soft error(corrected) ", unit); + printf("st%d: soft error(corrected)", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("info = %d (decimal)", + info); } printf("\n"); } - if(!(sense->ext.extended.flags & SSD_ILI)) - xs->resid = 0; /* XXX check this */ return(ESUCCESS); case 0x2: if(!silent) printf("st%d: not ready\n", unit); @@ -1991,14 +2182,11 @@ struct scsi_xfer *xs; case 0x3: if(!silent) { - printf("st%d: medium error ", unit); + printf("st%d: medium error", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf(" block no. %d (decimal)", + info); } printf("\n"); } @@ -2011,53 +2199,37 @@ struct scsi_xfer *xs; if(!silent) printf("st%d: illegal request\n", unit); return(EINVAL); case 0x6: - if(!silent) printf("st%d: Unit attention.\n", unit); - st_data[unit].flags &= ~(ST_AT_FILEMARK|ST_AT_EOM); - st_data[unit].flags &= ~ST_INFO_VALID; - if (st_data[unit].flags & ST_OPEN) /* TEMP!!!! */ + if(!silent) printf("st%d: Unit attention\n", unit); + st->flags &= ~ST_PER_MEDIA; + if (st->flags & ST_OPEN) /* TEMP!!!! */ return(EIO); else return(ESUCCESS); case 0x7: if(!silent) - { - printf("st%d: attempted protection violation", - unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - } - printf("\n"); - } + printf("st%d: tape is write protected\n", unit); return(EACCES); case 0x8: if(!silent) { - printf("st%d: fixed block wrong size", - unit); + printf("st%d: no data found", unit); if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" requested size: %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - } + printf(": requested size: %d (decimal)", + info); printf("\n"); } return(EIO); case 0x9: - if(!silent) printf("st%d: vendor unique\n", unit); + if(!silent) printf("st%d: vendor unique\n", + unit); return(EIO); case 0xa: - if(!silent) printf("st%d: copy aborted\n", unit); + if(!silent) printf("st%d: copy aborted\n", + unit); return(EIO); case 0xb: - if(!silent) printf("st%d: command aborted\n", unit); + if(!silent) printf("st%d: command aborted\n", + unit); return(EIO); case 0xc: if(!silent) @@ -2066,16 +2238,14 @@ struct scsi_xfer *xs; if(sense->error_code & SSD_ERRCODE_VALID) { printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + info); } printf("\n"); } return(ESUCCESS); case 0xd: - if(!silent) printf("st%d: volume overflow\n ", unit); + if(!silent) printf("st%d: volume overflow\n", + unit); return(ENOSPC); case 0xe: if(!silent) @@ -2084,22 +2254,20 @@ struct scsi_xfer *xs; if(sense->error_code & SSD_ERRCODE_VALID) { printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + info); } printf("\n"); } return(EIO); case 0xf: - if(!silent) printf("st%d: unknown error key\n", unit); + if(!silent) printf("st%d: unknown error key\n", + unit); return(EIO); } break; } /***************************************************************\ - * If it's NOT class 7, just report it. * + * If it's NOT code 70, just report it. * \***************************************************************/ default: { @@ -2121,20 +2289,3 @@ struct scsi_xfer *xs; return(EIO); } } - -#if defined(OSF) - -stsize(dev_t dev) -{ - printf("stsize() -- not implemented\n"); - return(0); -} - -stdump() -{ - printf("stdump() -- not implemented\n"); - return(-1); -} - -#endif /* defined(OSF) */ - |