mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-04 12:28:58 +00:00
Several fixes to the st driver, for density detection and selection. No
longer have to do the st -f /dev/rst0 blocksize 0 on dat drives!
This commit is contained in:
parent
101c9192f8
commit
57dd4ca1b2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=409
274
sys/scsi/st.c
274
sys/scsi/st.c
@ -21,13 +21,13 @@
|
||||
* 16 Feb 93 Julian Elischer ADDED for SCSI system
|
||||
* 1.15 is the last verion to support MACH and OSF/1
|
||||
*/
|
||||
/* $Revision: 1.25 $ */
|
||||
/* $Revision: 1.7 $ */
|
||||
|
||||
/*
|
||||
* 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: st.c,v 1.25 93/08/31 21:29:41 julian Exp Locker: julian $
|
||||
* $Id: st.c,v 1.7 1993/09/05 15:42:22 rgrimes Exp $
|
||||
*/
|
||||
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/malloc.h>
|
||||
@ -102,8 +103,9 @@ 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
|
||||
#define ST_Q_SNS_HLP 0x00008 /* must do READ for good MODE SENSE */
|
||||
#define ST_Q_IGNORE_LOADS 0x00010
|
||||
#define ST_Q_BLKSIZ 0x00020 /* variable-block media_blksiz > 0 */
|
||||
|
||||
static struct rogues gallery[] = /* ends with an all null entry */
|
||||
{
|
||||
@ -139,6 +141,14 @@ static struct rogues gallery[] = /* ends with an all null entry */
|
||||
{0,QIC_24} /* minor 12,13,14,15*/
|
||||
}
|
||||
},
|
||||
{ "Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????",
|
||||
0,
|
||||
{ {0,0}, /* minor 0,1,2,3*/
|
||||
{ST_Q_BLKSIZ,QIC_525}, /* minor 4,5,6,7*/
|
||||
{0,QIC_150}, /* minor 8,9,10,11*/
|
||||
{0,QIC_120} /* minor 12,13,14,15*/
|
||||
}
|
||||
},
|
||||
{(char *)0}
|
||||
};
|
||||
|
||||
@ -190,18 +200,24 @@ struct st_data
|
||||
#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_WRITTEN 0x10 /* data have been written, EOD needed */
|
||||
#define ST_FIXEDBLOCKS 0x20
|
||||
#define ST_AT_FILEMARK 0x40
|
||||
#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_FM_WRITTEN 0x400 /* EOF file mark written -- */
|
||||
/* used with ~ST_WRITTEN to indicate */
|
||||
/* that multiple file marks have been */
|
||||
/* written */
|
||||
#define ST_BLANK_READ 0x800 /* BLANK CHECK encountered already */
|
||||
#define ST_2FM_AT_EOD 0x1000 /* write 2 file marks at EOD */
|
||||
|
||||
#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING)
|
||||
#define ST_PER_OPEN (ST_OPEN | ST_PER_ACTION)
|
||||
#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
|
||||
#define ST_PER_OPEN ST_OPEN
|
||||
#define ST_PER_MEDIA (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
|
||||
ST_FIXEDBLOCKS | ST_AT_BOM | ST_READONLY | \
|
||||
ST_PER_ACTION)
|
||||
ST_FM_WRITTEN | ST_2FM_AT_EOD | ST_PER_ACTION)
|
||||
|
||||
static int next_st_unit = 0;
|
||||
/***********************************************************************\
|
||||
@ -387,7 +403,8 @@ int unit;
|
||||
/*******************************************************\
|
||||
* open the device. *
|
||||
\*******************************************************/
|
||||
stopen(dev)
|
||||
stopen(dev, flags)
|
||||
int dev, flags;
|
||||
{
|
||||
int unit,mode,dsty;
|
||||
int errno = 0;
|
||||
@ -576,6 +593,36 @@ bad: free(buf,M_TEMP);
|
||||
\*******************************************************/
|
||||
}
|
||||
|
||||
/***************************************************************\
|
||||
* Decide whether or not to write two file marks to signify end- *
|
||||
* of-data. Make the decision as a function of density. If *
|
||||
* the decision is not to use a second file mark, the SCSI BLANK *
|
||||
* CHECK condition code will be recognized as end-of-data when *
|
||||
* first read. *
|
||||
\***************************************************************/
|
||||
switch (st->density)
|
||||
{
|
||||
/* case 8 mm: What is the SCSI density code for 8 mm, anyway? */
|
||||
case QIC_11:
|
||||
case QIC_24:
|
||||
case QIC_120:
|
||||
case QIC_150:
|
||||
case QIC_525:
|
||||
case QIC_1320:
|
||||
st->flags &= ~ST_2FM_AT_EOD;
|
||||
break;
|
||||
default:
|
||||
st->flags |= ST_2FM_AT_EOD;
|
||||
}
|
||||
|
||||
/***************************************************************\
|
||||
* Make sure that a tape opened in write-only mode will have *
|
||||
* file marks written on it. This is the only way to write a *
|
||||
* zero-length file on tape. *
|
||||
\***************************************************************/
|
||||
if ((flags & O_ACCMODE) == FWRITE)
|
||||
st->flags |= ST_WRITTEN;
|
||||
|
||||
st->flags |= ST_INFO_VALID;
|
||||
|
||||
st_prevent(unit,PR_PREVENT,0); /* who cares if it fails? */
|
||||
@ -606,10 +653,6 @@ stclose(dev)
|
||||
if(scsi_debug & TRACEOPENS)
|
||||
printf("Closing device");
|
||||
#endif /*STDEBUG*/
|
||||
if(st->flags & ST_WRITTEN)
|
||||
{
|
||||
st_write_filemarks(unit,1,0);
|
||||
}
|
||||
switch(mode)
|
||||
{
|
||||
case 0:
|
||||
@ -618,9 +661,8 @@ stclose(dev)
|
||||
st->flags &= ~ST_PER_MEDIA;
|
||||
break;
|
||||
case 1: /*non rewind*/
|
||||
/* possibly space forward if not already at EOF? */
|
||||
/* (fixed block mode only) */
|
||||
|
||||
if((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
|
||||
st_write_filemarks(unit, 1, 0);
|
||||
break;
|
||||
case 2:
|
||||
st_rewind(unit,FALSE,SCSI_SILENT);
|
||||
@ -763,7 +805,8 @@ int unit, first_read;
|
||||
* fixed or variable-length blocks and block size according to *
|
||||
* what the drive found on the tape. *
|
||||
\***************************************************************/
|
||||
if (first_read)
|
||||
if (first_read && (!(st->quirks & ST_Q_BLKSIZ) || st->media_blksiz == 0
|
||||
|| st->media_blksiz == DEF_FIXED_BSIZE || st->media_blksiz == 1024))
|
||||
{
|
||||
if (st->media_blksiz == 0)
|
||||
st->flags &= ~ST_FIXEDBLOCKS;
|
||||
@ -912,8 +955,6 @@ dev_t dev;
|
||||
int cmd;
|
||||
caddr_t arg;
|
||||
{
|
||||
register i,j;
|
||||
unsigned int opri;
|
||||
int errcode = 0;
|
||||
unsigned char unit;
|
||||
int number,flags,dsty;
|
||||
@ -952,6 +993,7 @@ caddr_t arg;
|
||||
|
||||
case MTIOCTOP:
|
||||
{
|
||||
int nmarks;
|
||||
struct mtop *mt = (struct mtop *) arg;
|
||||
|
||||
#ifdef STDEBUG
|
||||
@ -969,17 +1011,20 @@ caddr_t arg;
|
||||
case MTWEOF: /* write an end-of-file record */
|
||||
errcode = st_write_filemarks(unit,number,flags);
|
||||
break;
|
||||
case MTFSF: /* forward space file */
|
||||
errcode = st_space(unit,number,SP_FILEMARKS,flags);
|
||||
break;
|
||||
case MTBSF: /* backward space file */
|
||||
errcode = st_space(unit,-number,SP_FILEMARKS,flags);
|
||||
break;
|
||||
case MTFSR: /* forward space record */
|
||||
errcode = st_space(unit,number,SP_BLKS,flags);
|
||||
number = -number;
|
||||
case MTFSF: /* forward space file */
|
||||
errcode = st_chkeod(unit, FALSE, &nmarks, flags);
|
||||
if (errcode == ESUCCESS)
|
||||
errcode = st_space(unit, number - nmarks,
|
||||
SP_FILEMARKS, flags);
|
||||
break;
|
||||
case MTBSR: /* backward space record */
|
||||
errcode = st_space(unit,-number,SP_BLKS,flags);
|
||||
number = -number;
|
||||
case MTFSR: /* forward space record */
|
||||
errcode = st_chkeod(unit, TRUE, &nmarks, flags);
|
||||
if (errcode == ESUCCESS)
|
||||
errcode = st_space(unit,number,SP_BLKS,flags);
|
||||
break;
|
||||
case MTREW: /* rewind */
|
||||
errcode = st_rewind(unit,FALSE,flags);
|
||||
@ -1000,7 +1045,7 @@ caddr_t arg;
|
||||
case MTCACHE: /* enable controller cache */
|
||||
case MTNOCACHE: /* disable controller cache */
|
||||
break;
|
||||
case MTSETBSIZ: /* Set block size for device */
|
||||
case MTSETBSIZ: /* Set block size for device */
|
||||
if (!(st->flags & ST_AT_BOM))
|
||||
{
|
||||
errcode = EINVAL;
|
||||
@ -1369,8 +1414,62 @@ int unit,number,what,flags;
|
||||
(error = st_decide_mode(unit, TRUE)))
|
||||
return (error);
|
||||
|
||||
/* if we are at a filemark now, we soon won't be*/
|
||||
st->flags &= ~ST_PER_ACTION;
|
||||
switch (what)
|
||||
{
|
||||
case SP_BLKS:
|
||||
if (st->flags & ST_PER_ACTION)
|
||||
{
|
||||
if (number > 0)
|
||||
{
|
||||
st->flags &= ~ST_PER_ACTION;
|
||||
return(EIO);
|
||||
}
|
||||
else if (number < 0)
|
||||
{
|
||||
if (st->flags & ST_AT_FILEMARK)
|
||||
{
|
||||
/*******************************\
|
||||
* Handling of ST_AT_FILEMARK *
|
||||
* in st_space will fill in the *
|
||||
* right file mark count. *
|
||||
\*******************************/
|
||||
error = st_space(unit, 0, SP_FILEMARKS,
|
||||
flags);
|
||||
if (error) return(error);
|
||||
}
|
||||
if (st->flags & ST_BLANK_READ)
|
||||
{
|
||||
st->flags &= ~ST_BLANK_READ;
|
||||
return(EIO);
|
||||
}
|
||||
st->flags &= ~ST_EIO_PENDING;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SP_FILEMARKS:
|
||||
if (st->flags & ST_EIO_PENDING)
|
||||
{
|
||||
if (number > 0)
|
||||
{
|
||||
st->flags &= ~ST_EIO_PENDING;
|
||||
return(EIO);
|
||||
}
|
||||
else if (number < 0)
|
||||
st->flags &= ~ST_EIO_PENDING;
|
||||
}
|
||||
if (st->flags & ST_AT_FILEMARK)
|
||||
{
|
||||
st->flags &= ~ST_AT_FILEMARK;
|
||||
number--;
|
||||
}
|
||||
if (st->flags & ST_BLANK_READ && number < 0)
|
||||
{
|
||||
st->flags &= ~ST_BLANK_READ;
|
||||
number++;
|
||||
}
|
||||
}
|
||||
if (number == 0)
|
||||
return(ESUCCESS);
|
||||
bzero(&scsi_cmd, sizeof(scsi_cmd));
|
||||
scsi_cmd.op_code = SPACE;
|
||||
scsi_cmd.byte2 = what & SS_CODE;
|
||||
@ -1406,11 +1505,25 @@ int unit,number,flags;
|
||||
* set medium access density, fixed or variable-blocks *
|
||||
* and, if fixed, the block size. *
|
||||
\*******************************************************/
|
||||
if (st->flags & ST_AT_BOM &&
|
||||
if (st->flags & ST_AT_BOM && number > 0 &&
|
||||
(error = st_decide_mode(unit, FALSE)))
|
||||
return (error);
|
||||
|
||||
st->flags &= ~(ST_AT_FILEMARK | ST_WRITTEN);
|
||||
switch (number)
|
||||
{
|
||||
case 0: /* really a command to sync the drive's buffers */
|
||||
break;
|
||||
case 1:
|
||||
if (st->flags & ST_FM_WRITTEN)
|
||||
st->flags &= ~ST_WRITTEN;
|
||||
else
|
||||
st->flags |= ST_FM_WRITTEN;
|
||||
st->flags &= ~ST_PER_ACTION;
|
||||
break;
|
||||
default:
|
||||
st->flags &= ~(ST_PER_ACTION | ST_WRITTEN);
|
||||
}
|
||||
|
||||
bzero(&scsi_cmd, sizeof(scsi_cmd));
|
||||
scsi_cmd.op_code = WRITE_FILEMARKS;
|
||||
lto3b(number,scsi_cmd.number);
|
||||
@ -1423,6 +1536,42 @@ int unit,number,flags;
|
||||
NULL,
|
||||
flags) );
|
||||
}
|
||||
|
||||
/***************************************************************\
|
||||
* Make sure the right number of file marks is on tape if the *
|
||||
* tape has been written. If the position argument is true, *
|
||||
* leave the tape positioned where it was originally. *
|
||||
* *
|
||||
* nmarks returns the number of marks to skip (or, if position *
|
||||
* true, which were skipped) to get back original position. *
|
||||
\***************************************************************/
|
||||
st_chkeod(unit, position, nmarks, flags)
|
||||
int unit;
|
||||
int position;
|
||||
int *nmarks;
|
||||
int flags;
|
||||
{
|
||||
int error;
|
||||
struct st_data *st = st_data[unit];
|
||||
|
||||
switch (st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD))
|
||||
{
|
||||
default:
|
||||
*nmarks = 0;
|
||||
return(ESUCCESS);
|
||||
case ST_WRITTEN:
|
||||
case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD:
|
||||
*nmarks = 1;
|
||||
break;
|
||||
case ST_WRITTEN | ST_2FM_AT_EOD:
|
||||
*nmarks = 2;
|
||||
}
|
||||
error = st_write_filemarks(unit, *nmarks, flags);
|
||||
if (position && error == ESUCCESS)
|
||||
error = st_space(unit, -*nmarks, SP_FILEMARKS, flags);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*******************************************************\
|
||||
* load/unload (with retension if true) *
|
||||
\*******************************************************/
|
||||
@ -1432,18 +1581,24 @@ int unit,type,flags;
|
||||
struct scsi_load scsi_cmd;
|
||||
struct st_data *st = st_data[unit];
|
||||
|
||||
st->flags &= ~ST_PER_ACTION;
|
||||
if(st->quirks & ST_Q_IGNORE_LOADS) return(0);
|
||||
st->flags &= ~ST_PER_MEDIA;
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
int error, nmarks;
|
||||
|
||||
error = st_chkeod(unit, FALSE, &nmarks, flags);
|
||||
if (error != ESUCCESS) return(error);
|
||||
st->flags &= ~ST_INFO_VALID;
|
||||
}
|
||||
if(st->quirks & ST_Q_IGNORE_LOADS) return(0);
|
||||
scsi_cmd.op_code = LOAD_UNLOAD;
|
||||
scsi_cmd.how |= type;
|
||||
return (st_scsi_cmd(unit,
|
||||
&scsi_cmd,
|
||||
sizeof(scsi_cmd),
|
||||
@ -1462,7 +1617,13 @@ int unit,type,flags;
|
||||
struct scsi_prevent scsi_cmd;
|
||||
|
||||
if (type == PR_ALLOW)
|
||||
{
|
||||
int error, nmarks;
|
||||
|
||||
error = st_chkeod(unit, TRUE, &nmarks, flags);
|
||||
if (error != ESUCCESS) return(error);
|
||||
st_data[unit]->flags &= ~ST_INFO_VALID;
|
||||
}
|
||||
bzero(&scsi_cmd, sizeof(scsi_cmd));
|
||||
scsi_cmd.op_code = PREVENT_ALLOW;
|
||||
scsi_cmd.how=type;
|
||||
@ -1483,7 +1644,10 @@ int unit,immed,flags;
|
||||
{
|
||||
struct scsi_rewind scsi_cmd;
|
||||
struct st_data *st = st_data[unit];
|
||||
int error, nmarks;
|
||||
|
||||
error = st_chkeod(unit, FALSE, &nmarks, flags);
|
||||
if (error != ESUCCESS) return(error);
|
||||
st->flags &= ~ST_PER_ACTION;
|
||||
st->flags |= ST_AT_BOM;
|
||||
bzero(&scsi_cmd, sizeof(scsi_cmd));
|
||||
@ -1562,12 +1726,25 @@ trynext:
|
||||
\*******************************************************/
|
||||
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 ((bp->b_flags & B_READ) == B_WRITE)
|
||||
{
|
||||
/***************************************\
|
||||
* Handling of ST_AT_FILEMARK in *
|
||||
* st_space will fill in the right file *
|
||||
* mark count. *
|
||||
\***************************************/
|
||||
if (st_space(unit, 0, SP_FILEMARKS, 0) !=
|
||||
ESUCCESS) goto badnews;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 *
|
||||
@ -1590,6 +1767,7 @@ trynext:
|
||||
if((bp->b_flags & B_READ) == B_WRITE)
|
||||
{
|
||||
cmd.op_code = WRITE_COMMAND_TAPE;
|
||||
st->flags &= ~ST_FM_WRITTEN;
|
||||
st->flags |= ST_WRITTEN;
|
||||
flags = SCSI_DATA_OUT;
|
||||
}
|
||||
@ -1626,6 +1804,7 @@ trynext:
|
||||
flags | SCSI_NOSLEEP ) != SUCCESSFULLY_QUEUED)
|
||||
|
||||
{
|
||||
badnews:
|
||||
printf("st%d: oops not queued\n",unit);
|
||||
bp->b_flags |= B_ERROR;
|
||||
bp->b_error = EIO;
|
||||
@ -2049,6 +2228,10 @@ struct scsi_xfer *xs;
|
||||
if(sense->ext.extended.flags & SSD_ILI)
|
||||
{
|
||||
st->flags |= ST_EIO_PENDING;
|
||||
if (sense->error_code & SSD_ERRCODE_VALID &&
|
||||
!silent)
|
||||
printf("st%d: %d-byte block wrong size"
|
||||
"\n", unit, xs->datalen - info);
|
||||
|
||||
/***************************************\
|
||||
* This quirk code helps the drive read *
|
||||
@ -2108,7 +2291,8 @@ struct scsi_xfer *xs;
|
||||
|
||||
key=sense->ext.extended.flags & SSD_KEY;
|
||||
|
||||
if (!silent && key > 0)
|
||||
if (!silent && key > 0 && (key != 0x8 ||
|
||||
st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ)))
|
||||
{
|
||||
printf("st%d: %s", unit, error_mes[key - 1]);
|
||||
if(sense->error_code & SSD_ERRCODE_VALID)
|
||||
@ -2164,6 +2348,12 @@ struct scsi_xfer *xs;
|
||||
{
|
||||
st->blksiz -= 512;
|
||||
}
|
||||
else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ)))
|
||||
{
|
||||
st->flags |= ST_BLANK_READ;
|
||||
xs->resid = xs->datalen;
|
||||
return(ESUCCESS);
|
||||
}
|
||||
default:
|
||||
return(EIO);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user