summaryrefslogtreecommitdiffstats
path: root/sys/scsi/st.c
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1993-11-18 05:03:27 +0000
committerrgrimes <rgrimes@FreeBSD.org>1993-11-18 05:03:27 +0000
commit73dd2628a2d9f88e008196681e15c6d3a0dc11be (patch)
tree6d93e911e7337a8936028ed9a12d64183f6766d3 /sys/scsi/st.c
parentdbf6b5a2db39d182aba158f88c9cd5005db5d6e0 (diff)
downloadFreeBSD-src-73dd2628a2d9f88e008196681e15c6d3a0dc11be.zip
FreeBSD-src-73dd2628a2d9f88e008196681e15c6d3a0dc11be.tar.gz
New version of scsi code from Julian
Diffstat (limited to 'sys/scsi/st.c')
-rw-r--r--sys/scsi/st.c3439
1 files changed, 1498 insertions, 1941 deletions
diff --git a/sys/scsi/st.c b/sys/scsi/st.c
index e367389..08c8d467 100644
--- a/sys/scsi/st.c
+++ b/sys/scsi/st.c
@@ -12,13 +12,24 @@
* 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 version to support MACH and OSF/1
+ */
+/* $Revision: 2.6 $ */
+
+/*
* 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.11 1993/10/16 17:21:10 rgrimes Exp $
+ * $Id: st.c,v 2.6 93/10/21 03:24:38 julian Exp Locker: julian $
*/
-
/*
* To do:
* work out some better way of guessing what a good timeout is going
@@ -41,886 +52,882 @@
#include <sys/user.h>
#include <sys/mtio.h>
-
#include <scsi/scsi_all.h>
#include <scsi/scsi_tape.h>
#include <scsi/scsiconf.h>
-
-long int ststrats,stqueues;
+u_int32 ststrats, stqueues;
/* Defines for device specific stuff */
#define PAGE_0_SENSE_DATA_SIZE 12
#define PAGESIZ 4096
#define DEF_FIXED_BSIZE 512
-#define STQSIZE 4
-#define ST_RETRIES 4
-
+#define ST_RETRIES 4 /* only on non IO commands */
#define MODE(z) ( (minor(z) & 0x03) )
#define DSTY(z) ( ((minor(z) >> 2) & 0x03) )
#define UNIT(z) ( (minor(z) >> 4) )
-
-#define DSTY3 3
-#define DSTY2 2
-#define DSTY1 1
+#define CTLMODE 3
#define SCSI_2_MAX_DENSITY_CODE 0x17 /* maximum density code specified
- in SCSI II spec. */
-/***************************************************************\
-* Define various devices that we know mis-behave in some way, *
-* and note how they are bad, so we can correct for them *
-\***************************************************************/
-struct modes
-{
- int quirks; /* same definitions as in rogues */
- char density;
- char spare[3];
+ * in SCSI II spec. */
+/*
+ * Define various devices that we know mis-behave in some way,
+ * and note how they are bad, so we can correct for them
+ */
+struct modes {
+ u_int32 blksiz;
+ u_int32 quirks; /* same definitions as in rogues */
+ char density;
+ char spare[3];
};
-struct rogues
-{
- char *name;
- char *manu;
- char *model;
- char *version;
- int quirks; /* valid for all modes */
- struct modes modes[4];
+
+struct rogues {
+ char *name;
+ char *manu;
+ char *model;
+ char *version;
+ u_int32 quirks; /* valid for all modes */
+ struct modes modes[4];
};
/* define behaviour codes (quirks) */
#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 /* must do READ for good MODE SENSE */
+#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 */
+#define ST_Q_BLKSIZ 0x00020 /* variable-block media_blksiz > 0 */
-static struct rogues gallery[] = /* ends with an all null entry */
+static struct rogues gallery[] = /* ends with an all-null entry */
{
- { "Such an old device ", "pre-scsi", " unknown model ","????",
- 0,
- { {ST_Q_FORCE_FIXED_MODE,0}, /* minor 0,1,2,3 */
- {ST_Q_FORCE_FIXED_MODE,QIC_24}, /* minor 4,5,6,7 */
- {ST_Q_FORCE_VAR_MODE,HALFINCH_1600}, /* minor 8,9,10,11*/
- {ST_Q_FORCE_VAR_MODE,HALFINCH_6250} /* minor 12,13,14,15*/
- }
- },
- { "Tandberg tdc3600", "TANDBERG", " TDC 3600","????",
- ST_Q_NEEDS_PAGE_0,
- { {0,0}, /* minor 0,1,2,3*/
- {ST_Q_FORCE_VAR_MODE,QIC_525}, /* minor 4,5,6,7*/
- {0,QIC_150}, /* minor 8,9,10,11*/
- {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*/
- {0,QIC_150}, /* minor 4,5,6,7*/
- {0,QIC_120}, /* minor 8,9,10,11*/
- {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}
+ {"Such an old device ", "pre-scsi", " unknown model ", "????",
+ 0,
+ {
+ {512, ST_Q_FORCE_FIXED_MODE, 0}, /* minor 0,1,2,3 */
+ {512, ST_Q_FORCE_FIXED_MODE, QIC_24}, /* minor 4,5,6,7 */
+ {0, ST_Q_FORCE_VAR_MODE, HALFINCH_1600}, /* minor 8,9,10,11 */
+ {0, ST_Q_FORCE_VAR_MODE, HALFINCH_6250} /* minor 12,13,14,15 */
+ }
+ },
+ {"Tandberg tdc3600", "TANDBERG", " TDC 3600", "????",
+ ST_Q_NEEDS_PAGE_0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {0, ST_Q_FORCE_VAR_MODE, QIC_525}, /* minor 4,5,6,7 */
+ {0, 0, QIC_150}, /* minor 8,9,10,11 */
+ {0, 0, QIC_120} /* minor 12,13,14,15 */
+ }
+ },
+ {"Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462", "-005",
+ 0,
+ {
+ {0, ST_Q_SNS_HLP, 0}, /* minor 0,1,2,3 */
+ {0, ST_Q_SNS_HLP, QIC_525}, /* minor 4,5,6,7 */
+ {0, 0, QIC_150}, /* minor 8,9,10,11 */
+ {0, 0, QIC_120} /* minor 12,13,14,15 */
+ }
+ },
+ {"Archive Viper 150", "ARCHIVE ", "VIPER 150", "????",
+ ST_Q_NEEDS_PAGE_0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {0, 0, QIC_150}, /* minor 4,5,6,7 */
+ {0, 0, QIC_120}, /* minor 8,9,10,11 */
+ {0, 0, QIC_24} /* minor 12,13,14,15 */
+ }
+ },
+ {"Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????",
+ 0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {0, ST_Q_BLKSIZ, QIC_525}, /* minor 4,5,6,7 */
+ {0, 0, QIC_150}, /* minor 8,9,10,11 */
+ {0, 0, QIC_120} /* minor 12,13,14,15 */
+ }
+ },
+ {"WangDAT model 1300", "WangDAT ", "Model 1300", "????",
+ 0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {512, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 4,5,6,7 */
+ {1024, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 8,9,10,11 */
+ {0, ST_Q_FORCE_VAR_MODE, 0x13} /* minor 12,13,14,15 */
+ }
+ },
+ {(char *) 0}
};
-
-int ststrategy();
-void stminphys();
+errval st_space __P((u_int32 unit, int32 number, u_int32 what, u_int32 flags));
+errval st_rewind __P((u_int32 unit, boolean immed, u_int32 flags));
+errval st_mode_sense __P((u_int32 unit, u_int32 flags));
+errval st_decide_mode __P((u_int32 unit, boolean first_read));
+errval st_rd_blk_lim __P((u_int32 unit, u_int32 flags));
+errval st_touch_tape __P((u_int32 unit));
+errval st_write_filemarks __P((u_int32 unit, int32 number, u_int32 flags));
+errval st_load __P((u_int32 unit, u_int32 type, u_int32 flags));
+errval st_mode_select __P((u_int32 unit, u_int32 flags));
+void ststrategy();
+void stminphys();
+int32 st_chkeod();
+errval stattach();
+void ststart();
+void st_unmount();
+errval st_mount_tape();
+void st_loadquirks();
+void st_identify_drive();
+errval st_interpret_sense();
#define ESUCCESS 0
+#define NOEJECT 0
+#define EJECT 1
-#ifdef STDEBUG
-int st_debug = 1;
-#endif /*STDEBUG*/
-
-int stattach();
-int st_done();
-
-struct st_data
+struct scsi_device st_switch =
{
+ st_interpret_sense, /* check errors with us first */
+ ststart, /* we have a queue, and this is how we service it */
+ NULL,
+ NULL, /* use the default 'done' routine */
+ "st",
+ 0,
+ { 0, 0 }
+};
+
+struct st_data {
/*--------------------present operating parameters, flags etc.----------------*/
- int flags; /* see below */
- int blksiz; /* blksiz we are using */
- int density; /* present density */
- int quirks; /* quirks for the open mode */
- int last_dsty; /* last density used */
+ u_int32 flags; /* see below */
+ u_int32 blksiz; /* blksiz we are using */
+ u_int32 density; /* present density */
+ u_int32 quirks; /* quirks for the open mode */
+ u_int32 last_dsty; /* last density openned */
/*--------------------device/scsi parameters----------------------------------*/
- struct scsi_switch *sc_sw; /* address of scsi low level switch */
- int ctlr; /* so they know which one we want */
- int targ; /* our scsi target ID */
- int lu; /* our scsi lu */
+ struct scsi_link *sc_link; /* our link to the adpter etc. */
/*--------------------parameters reported by the device ----------------------*/
- int blkmin; /* min blk size */
- int blkmax; /* max blk size */
+ u_int32 blkmin; /* min blk size */
+ u_int32 blkmax; /* max blk size */
+ struct rogues *rogues; /* if we have a rogue entry */
/*--------------------parameters reported by the device for this media--------*/
- int numblks; /* nominal blocks capacity */
- int media_blksiz; /* 0 if not ST_FIXEDBLOCKS */
- int media_density; /* this is what it said when asked */
+ u_int32 numblks; /* nominal blocks capacity */
+ u_int32 media_blksiz; /* 0 if not ST_FIXEDBLOCKS */
+ u_int32 media_density; /* this is what it said when asked */
/*--------------------quirks for the whole drive------------------------------*/
- int drive_quirks; /* quirks of this drive */
+ u_int32 drive_quirks; /* quirks of this drive */
/*--------------------How we should set up when openning each minor device----*/
- struct modes modes[4]; /* plus more for each mode */
+ struct modes modes[4]; /* plus more for each mode */
+ u_int8 modeflags[4]; /* flags for the modes */
+#define DENSITY_SET_BY_USER 0x01
+#define DENSITY_SET_BY_QUIRK 0x02
+#define BLKSIZE_SET_BY_USER 0x04
+#define BLKSIZE_SET_BY_QUIRK 0x08
/*--------------------storage for sense data returned by the drive------------*/
- unsigned char sense_data[12]; /* additional sense data needed */
- /* for mode sense/select. */
- 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];
+ unsigned char sense_data[12]; /*
+ * additional sense data needed
+ * for mode sense/select.
+ */
+ struct buf *buf_queue; /* the queue of pending IO operations */
+ struct scsi_xfer scsi_xfer; /* scsi xfer struct for this drive */
+ u_int32 xfer_block_wait; /* 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 /* data have been written, EOD needed */
+#define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */
+#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_EIO_PENDING 0x80 /* we couldn't report it then (had data) */
+#define ST_NEW_MOUNT 0x100 /* still need to decide mode */
+#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_MOUNTED 0x2000 /* Device is presently mounted */
#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 | \
+#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
+ ST_FIXEDBLOCKS | ST_READONLY | \
ST_FM_WRITTEN | ST_2FM_AT_EOD | ST_PER_ACTION)
-static int next_st_unit = 0;
-/***********************************************************************\
-* The routine called by the low level scsi routine when it discovers *
-* A device suitable for this driver *
-\***********************************************************************/
+static u_int32 next_st_unit = 0;
-int stattach(ctlr,targ,lu,scsi_switch)
-struct scsi_switch *scsi_switch;
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * A device suitable for this driver
+ */
+
+errval
+stattach(sc_link)
+ struct scsi_link *sc_link;
{
- int unit,i;
+ u_int32 unit;
struct st_data *st;
-#ifdef STDEBUG
- if(scsi_debug & PRINTROUTINES) printf("stattach: ");
-#endif /*STDEBUG*/
- /*******************************************************\
- * Check we have the resources for another drive *
- \*******************************************************/
+ SC_DEBUG(sc_link, SDEV_DB2, ("stattach: "));
+ /*
+ * Check we have the resources for another drive
+ */
unit = next_st_unit++;
- if( unit >= NST)
- {
+
+ if (unit >= NST) {
printf("Too many scsi tapes..(%d > %d) reconfigure kernel\n",
- (unit + 1),NST);
- return(0);
+ (unit + 1), NST);
+ return 0;
}
- if(st_data[unit])
- {
- printf("st%d: Already has storage!\n",unit);
- return(0);
+ 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);
+ sc_link->device = &st_switch;
+ sc_link->dev_unit = unit;
+ 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;
}
- bzero(st,sizeof(struct st_data));
-
- /*******************************************************\
- * Store information needed to contact our base driver *
- \*******************************************************/
- st->sc_sw = scsi_switch;
- st->ctlr = ctlr;
- st->targ = targ;
- st->lu = lu;
-
- /*******************************************************\
- * Store information about default densities *
- \*******************************************************/
- st->modes[DSTY1].density = QIC_525;
- st->modes[DSTY2].density = QIC_150;
- st->modes[DSTY3].density = QIC_120;
-
- /*******************************************************\
- * Check if the drive is a known criminal and take *
- * Any steps needed to bring it into line *
- \*******************************************************/
+ bzero(st, sizeof(struct st_data));
+
+ /*
+ * Store information needed to contact our base driver
+ */
+ st->sc_link = sc_link;
+
+ /*
+ * Check if the drive is a known criminal and take
+ * Any steps needed to bring it into line
+ */
st_identify_drive(unit);
- /*******************************************************\
- * Use the subdriver to request information regarding *
- * the drive. We cannot use interrupts yet, so the *
- * request must specify this. *
- \*******************************************************/
- if(st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT))
- {
+ /*
+ * Use the subdriver to request information regarding
+ * the drive. We cannot use interrupts yet, so the
+ * request must specify this.
+ */
+ if (st_mode_sense(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: density code 0x%x, ",
- unit, st->media_density);
- if (st->media_blksiz)
- {
+ } else {
+ printf("st%d: density code 0x%x, ", unit, st->media_density);
+ if (!scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
+ if (st->media_blksiz) {
printf("%d-byte", st->media_blksiz);
- }
- else
- {
+ } else {
printf("variable");
}
printf(" blocks, write-%s\n",
- st->flags & ST_READONLY ? "protected" : "enabled");
- }
- else
- {
- printf("st%d: drive empty\n", unit);
+ (st->flags & ST_READONLY) ? "protected" : "enabled");
+ } else {
+ printf(" drive empty\n");
}
}
- /*******************************************************\
- * Set up the bufs for this device *
- \*******************************************************/
- st->buf_queue = 0;
-
-
+ /*
+ * Set up the buf queue for this device
+ */
+ st->buf_queue = 0;
st->flags |= ST_INITIALIZED;
- return;
-
+ return 0;
}
-/***********************************************************************\
-* Use the identify routine in 'scsiconf' to get drive info so we can *
-* Further tailor our behaviour. *
-\***********************************************************************/
-
+/*
+ * Use the inquiry routine in 'scsi_base' to get drive info so we can
+ * Further tailor our behaviour.
+ */
+void
st_identify_drive(unit)
-int unit;
+ u_int32 unit;
{
-
- struct st_data *st = st_data[unit];
- struct scsi_inquiry_data inqbuf;
- struct rogues *finger;
- char manu[32];
- char model[32];
- char model2[32];
- char version[32];
- int model_len;
-
-
- /*******************************************************\
- * Get the device type information *
- \*******************************************************/
- if (scsi_inquire(st->ctlr, st->targ, st->lu, st->sc_sw, &inqbuf,
- SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != COMPLETE)
- {
+ struct st_data *st = st_data[unit];
+ struct scsi_inquiry_data inqbuf;
+ struct rogues *finger;
+ char manu[32];
+ char model[32];
+ char model2[32];
+ char version[32];
+ u_int32 model_len;
+
+ /*
+ * Get the device type information
+ */
+ if (scsi_inquire(st->sc_link, &inqbuf,
+ SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != 0) {
printf("st%d: couldn't get device type, using default\n", unit);
return;
}
- if((inqbuf.version & SID_ANSII) == 0)
- {
- /***********************************************\
- * If not advanced enough, use default values *
- \***********************************************/
- strncpy(manu,"pre-scsi",8);manu[8]=0;
- strncpy(model," unknown model ",16);model[16]=0;
- strncpy(version,"????",4);version[4]=0;
+ if ((inqbuf.version & SID_ANSII) == 0) {
+ /*
+ * If not advanced enough, use default values
+ */
+ strncpy(manu, "pre-scsi", 8);
+ manu[8] = 0;
+ strncpy(model, " unknown model ", 16);
+ model[16] = 0;
+ strncpy(version, "????", 4);
+ version[4] = 0;
+ } else {
+ strncpy(manu, inqbuf.vendor, 8);
+ manu[8] = 0;
+ strncpy(model, inqbuf.product, 16);
+ model[16] = 0;
+ strncpy(version, inqbuf.revision, 4);
+ version[4] = 0;
}
- else
- {
- strncpy(manu,inqbuf.vendor,8);manu[8]=0;
- strncpy(model,inqbuf.product,16);model[16]=0;
- strncpy(version,inqbuf.revision,4);version[4]=0;
- }
-
- /*******************************************************\
- * Load the parameters for this kind of device, so we *
- * treat it as appropriate for each operating mode *
- * Only check the number of characters in the array's *
- * model entry, not the entire model string returned. *
- \*******************************************************/
+
+ /*
+ * Load the parameters for this kind of device, so we
+ * treat it as appropriate for each operating mode.
+ * Only check the number of characters in the array's
+ * model entry, not the entire model string returned.
+ */
finger = gallery;
- while(finger->name)
- {
+ while (finger->name) {
model_len = 0;
- while(finger->model[model_len] && (model_len < 32))
- {
+ while (finger->model[model_len] && (model_len < 32)) {
model2[model_len] = model[model_len];
model_len++;
}
model2[model_len] = 0;
- if ((strcmp(manu, finger->manu) == 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];
- st->modes[1] = finger->modes[1];
- st->modes[2] = finger->modes[2];
- st->modes[3] = finger->modes[3];
- st->drive_quirks= finger->quirks;
- st->quirks = finger->quirks; /*start value*/
+ if ((strcmp(manu, finger->manu) == 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->rogues = finger;
+ st->drive_quirks = finger->quirks;
+ st->quirks = finger->quirks; /*start value */
+ st_loadquirks(st);
break;
- }
- else
- {
+ } else {
finger++; /* go to next suspect */
}
}
}
-/*******************************************************\
-* open the device. *
-\*******************************************************/
+/*
+ * initialise the subdevices to the default (QUIRK) state.
+ * this will remove any setting made by the system operator or previous
+ * operations.
+ */
+void
+st_loadquirks(st)
+ struct st_data *st;
+{
+ int i;
+ struct modes *mode;
+ struct modes *mode2;
+
+ if (!st->rogues)
+ return;
+ mode = st->rogues->modes;
+ mode2 = st->modes;
+ for (i = 0; i < 4; i++) {
+ bzero(mode2, sizeof(struct modes));
+ st->modeflags[i] &= ~(BLKSIZE_SET_BY_QUIRK
+ | DENSITY_SET_BY_QUIRK
+ | BLKSIZE_SET_BY_USER
+ | DENSITY_SET_BY_USER);
+ if (mode->blksiz && ((mode->quirks | st->drive_quirks)
+ & (ST_Q_FORCE_FIXED_MODE))) {
+ mode2->blksiz = mode->blksiz;
+ st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK;
+ } else {
+ if ((mode->quirks | st->drive_quirks)
+ & ST_Q_FORCE_VAR_MODE) {
+ mode2->blksiz = 0;
+ st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK;
+ }
+ }
+ if (mode->density) {
+ mode2->density = mode->density;
+ st->modeflags[i] |= DENSITY_SET_BY_QUIRK;
+ }
+ mode++;
+ mode2++;
+ }
+}
+
+/*
+ * open the device.
+ */
+errval
stopen(dev, flags)
-int dev, flags;
+ dev_t dev;
+ u_int32 flags;
{
- int unit,mode,dsty;
- int errno = 0;
+ u_int32 unit, mode, dsty;
+ errval errno = 0;
struct st_data *st;
+ struct scsi_link *sc_link;
unit = UNIT(dev);
mode = MODE(dev);
dsty = DSTY(dev);
- /*******************************************************\
- * Check the unit is legal *
- \*******************************************************/
- if ( unit >= NST )
- {
- return(ENXIO);
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= NST) {
+ return (ENXIO);
}
st = st_data[unit];
- /*******************************************************\
- * Make sure the device has been initialised *
- \*******************************************************/
+ /*
+ * Make sure the device has been initialised
+ */
if ((st == NULL) || (!(st->flags & ST_INITIALIZED)))
- return(ENXIO);
-
- /*******************************************************\
- * Only allow one at a time *
- \*******************************************************/
- if(st->flags & ST_OPEN)
- {
- return(ENXIO);
+ return (ENXIO);
+
+ sc_link = st->sc_link;
+ SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n"
+ ,dev, unit, NST));
+ /*
+ * Only allow one at a time
+ */
+ if (st->flags & ST_OPEN) {
+ 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, SCSI_SILENT);
-
- /***************************************************************\
- * 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);
+ /*
+ * 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)
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ sc_link->flags |= SDEV_OPEN; /* unit attn are now errors */
+ /*
+ * If the mode is 3 (e.g. minor = 3,7,11,15)
+ * then the device has been openned to set defaults
+ * This mode does NOT ALLOW I/O, only ioctls
+ */
+ if (mode == CTLMODE)
+ return 0;
+
+ /*
+ * Check that the device is ready to use (media loaded?)
+ * This time take notice of the return result
+ */
+ if (errno = (scsi_test_unit_ready(sc_link, 0))) {
+ printf("st%d: not ready\n", unit);
+ st_unmount(unit, NOEJECT);
+ 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 || !(st->flags & ST_INFO_VALID))
- {
- st->flags &= ~ST_INFO_VALID;
- st->last_dsty = dsty;
- st->quirks = st->drive_quirks | st->modes[dsty].quirks;
- st->density = st->modes[dsty].density;
+ /*
+ * if it's a different mode, or if the media has been
+ * invalidated, unmount the tape from the previous
+ * session but continue with open processing
+ */
+ if ((st->last_dsty != dsty)
+ || (!(sc_link->flags & SDEV_MEDIA_LOADED))) {
+ st_unmount(unit, NOEJECT);
}
- st->flags &= ~ST_PER_OPEN;
-
-#ifdef STDEBUG
- if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
- printf("stopen: dev=0x%x (unit %d (of %d))\n"
- , dev, unit, NST);
-#endif /*STDEBUG*/
- /***************************************************************\
- * If the media is new, then make sure we give it a chance to *
- * to do a 'load' instruction. *
- \***************************************************************/
- if(!(st->flags & ST_INFO_VALID)) /* is media new? */
- {
- if(errno = st_load(unit,LD_LOAD,0))
- {
- return(errno);
- }
- st_test_ready(unit,0);
- 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 large *
- * fixed-block state (user-specified density and *
- * 1024-byte blocks), then read and rewind to *
- * get it to sense the tape. If that doesn't *
- * work, try 512-byte fixed blocks. If that *
- * doesn't work, as a last resort, try variable- *
- * length blocks. 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. *
- * *
- * The rest of the code for this quirk is in ILI *
- * processing and BLANK CHECK error processing, *
- * both part of st_interpret_sense. *
- \***********************************************/
- char *buf;
- int readsiz;
-
- buf = malloc(1024,M_TEMP,M_NOWAIT);
- if(!buf) return(ENOMEM);
-
- if (errno = st_mode_sense(unit, 0))
- {
- goto bad;
- }
- st->blksiz = 1024;
- do {
- switch (st->blksiz)
- {
- case 512:
- case 1024:
- readsiz = st->blksiz;
- st->flags |= ST_FIXEDBLOCKS;
- break;
- default:
- readsiz = 1;
- st->flags &= ~ST_FIXEDBLOCKS;
- }
- if (errno = st_mode_select(unit, 0))
- {
- goto bad;
- }
- st->flags &= ~ST_AT_BOM;
- st_read(unit, buf, readsiz, SCSI_SILENT);
- if (errno = st_rewind(unit, FALSE, 0))
- {
-bad: free(buf,M_TEMP);
- return(errno);
- }
- } while (readsiz != 1 && readsiz > st->blksiz);
- free(buf,M_TEMP);
- }
- }
-
- /*******************************************************\
- * Load the physical device parameters *
- * loads: blkmin, blkmax *
- \*******************************************************/
- if(errno = st_rd_blk_lim(unit,0))
- {
- return(errno);
- }
-
- /*******************************************************\
- * Load the media dependent parameters *
- * includes: media_blksiz,media_density,numblks *
- \*******************************************************/
- if(errno = st_mode_sense(unit,0))
- {
- return(errno);
- }
-
- if (!(st->flags & ST_INFO_VALID) && dsty == 0)
- {
- /*******************************************************\
- * If the user defaulted the density, use the drive's *
- * opinion of it. *
- \*******************************************************/
- st->quirks = st->drive_quirks;
- 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. *
- \*******************************************************/
- }
-
- /***************************************************************\
- * 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;
+ /*
+ * If we are not mounted, then we should start a new
+ * mount session.
+ */
+ if (!(st->flags & ST_MOUNTED)) {
+ st_mount_tape(dev, flags);
+ st->last_dsty = dsty;
}
-
- /***************************************************************\
- * 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. *
- \***************************************************************/
+ /*
+ * Make sure that a tape opened in write-only mode will have
+ * file marks written on it when closed, even if not written to.
+ * This is for SUN compatibility
+ */
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? */
-
-#ifdef STDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("Params loaded ");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB2, ("Open complete\n"));
st->flags |= ST_OPEN;
- return(0);
+ return (0);
}
-/*******************************************************\
-* close the device.. only called if we are the LAST *
-* occurence of an open device *
-\*******************************************************/
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval
stclose(dev)
+ dev_t dev;
{
- unsigned char unit,mode;
- struct st_data *st;
+ unsigned char unit, mode;
+ struct st_data *st;
+ struct scsi_link *sc_link;
unit = UNIT(dev);
mode = MODE(dev);
st = st_data[unit];
-
-#ifdef STDEBUG
- if(scsi_debug & TRACEOPENS)
- printf("Closing device");
-#endif /*STDEBUG*/
- 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: /*non rewind*/
- if((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
- st_write_filemarks(unit, 1, 0);
+ sc_link = st->sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("closing\n"));
+ if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
+ st_write_filemarks(unit, 1, 0);
+ switch (mode & 0x3) {
+ case 0:
+ case 3: /* for now */
+ st_unmount(unit, NOEJECT);
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;
+ case 1: /*leave mounted unless media seems to have been removed */
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ st_unmount(unit, NOEJECT);
+ }
break;
- 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;
+ case 2:
+ st_unmount(unit, EJECT);
break;
- default:
- printf("st%d: close: Bad mode (minor number)%d how's it open?\n"
- ,unit,mode);
- return(EINVAL);
}
- st->flags &= ~ST_PER_OPEN;
- return(0);
+ sc_link->flags &= ~SDEV_OPEN;
+ st->flags &= ~ST_OPEN;
+ return (0);
}
-/***************************************************************\
-* 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, first_read)
-int unit, first_read;
+/*
+ * Start a new mount session.
+ * Copy in all the default parameters from the selected device mode.
+ * and try guess any that seem to be defaulted.
+ */
+errval
+st_mount_tape(dev, flags)
+ dev_t dev;
+ u_int32 flags;
{
- int dsty, error;
- struct st_data *st = st_data[unit];
+ u_int32 unit, mode, dsty;
+ struct st_data *st;
+ struct scsi_link *sc_link;
+ errval errno = 0;
- /***************************************************************\
- * 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;
+ unit = UNIT(dev);
+ mode = MODE(dev);
+ dsty = DSTY(dev);
+ st = st_data[unit];
+ sc_link = st->sc_link;
+
+ if (st->flags & ST_MOUNTED)
+ return 0;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("mounting\n "));
+ st->flags |= ST_NEW_MOUNT;
+ st->quirks = st->drive_quirks | st->modes[dsty].quirks;
+ /*
+ * If the media is new, then make sure we give it a chance to
+ * to do a 'load' instruction. ( We assume it is new)
+ */
+ if (errno = st_load(unit, LD_LOAD, 0)) {
+ return (errno);
}
-#ifdef STDEBUG
- if(st_debug) printf("starting mode decision\n");
-#endif /*STDEBUG*/
-
- /***************************************************************\
- * 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 mode\n",
- st->flags & ST_FIXEDBLOCKS ? "fixed" : "variable");
-#endif /*STDEBUG*/
- goto done;
+ /*
+ * Throw another dummy instruction to catch
+ * 'Unit attention' errors. Some drives appear to give
+ * these after doing a Load instruction.
+ * (noteably some DAT drives)
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ /*
+ * Some devices can't tell you much until they have been
+ * asked to look at the media. This quirk does this.
+ */
+ if (st->quirks & ST_Q_SNS_HLP) {
+ if (errno = st_touch_tape(unit))
+ return errno;
+ }
+ /*
+ * Load the physical device parameters
+ * loads: blkmin, blkmax
+ */
+ if (errno = st_rd_blk_lim(unit, 0)) {
+ return errno;
+ }
+ /*
+ * Load the media dependent parameters
+ * includes: media_blksiz,media_density,numblks
+ * As we have a tape in, it should be reflected here.
+ * If not you may need the "quirk" above.
+ */
+ if (errno = st_mode_sense(unit, 0)) {
+ return errno;
+ }
+ /*
+ * If we have gained a permanent density from somewhere,
+ * then use it in preference to the one supplied by
+ * default by the driver.
+ */
+ if (st->modeflags[dsty] & (DENSITY_SET_BY_QUIRK | DENSITY_SET_BY_USER)) {
+ st->density = st->modes[dsty].density;
+ } else {
+ st->density = st->media_density;
+ }
+ /*
+ * If we have gained a permanent blocksize
+ * then use it in preference to the one supplied by
+ * default by the driver.
+ */
+ st->flags &= ~ST_FIXEDBLOCKS;
+ if (st->modeflags[dsty] & (BLKSIZE_SET_BY_QUIRK | BLKSIZE_SET_BY_USER)) {
+ st->blksiz = st->modes[dsty].blksiz;
+ if (st->blksiz) {
+ st->flags |= ST_FIXEDBLOCKS;
+ }
+ } else {
+ if (errno = st_decide_mode(unit, FALSE)) {
+ return errno;
+ }
+ }
+ if (errno = st_mode_select(unit, 0)) {
+ printf("st%d: Cannot set selected mode", unit);
+ return errno;
}
+ scsi_prevent(sc_link, PR_PREVENT, 0); /* who cares if it fails? */
+ st->flags &= ~ST_NEW_MOUNT;
+ st->flags |= ST_MOUNTED;
+ sc_link->flags |= SDEV_MEDIA_LOADED; /* move earlier? */
- /***************************************************************\
- * 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 0;
+}
+
+/*
+ * End the present mount session.
+ * Rewind, and optionally eject the tape.
+ * Reset various flags to indicate that all new
+ * operations require another mount operation
+ */
+void
+st_unmount(int unit, boolean eject)
+{
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
+ int32 nmarks;
+
+ if (!(st->flags & ST_MOUNTED))
+ return;
+ SC_DEBUG(sc_link, SDEV_DB1, ("unmounting\n"));
+ st_chkeod(unit, FALSE, &nmarks, SCSI_SILENT);
+ st_rewind(unit, FALSE, SCSI_SILENT);
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
+ if (eject) {
+ st_load(unit, LD_UNLOAD, SCSI_SILENT);
+ }
+ st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT);
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+}
+
+/*
+ * Given all we know about the device, media, mode, 'quirks' and
+ * initial operation, make a decision as to how we should be set
+ * to run (regarding blocking and EOD marks)
+ */
+errval
+st_decide_mode(unit, first_read)
+ u_int32 unit;
+ boolean first_read;
+{
+ struct st_data *st = st_data[unit];
+#ifdef SCSIDEBUG
+ struct scsi_link *sc_link = st->sc_link;
+#endif
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("starting block mode decision\n"));
+
+ /*
+ * 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:
+ case ST_Q_FORCE_FIXED_MODE: /*specified fixed, but not what size */
st->flags |= ST_FIXEDBLOCKS;
if (st->blkmin && (st->blkmin == st->blkmax))
st->blksiz = st->blkmin;
- else if(st->media_blksiz > 0)
+ else if (st->media_blksiz > 0)
st->blksiz = st->media_blksiz;
else
st->blksiz = DEF_FIXED_BSIZE;
-#ifdef STDEBUG
- if(st_debug) printf("Quirks force fixed mode\n");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force fixed mode(%d)\n",
+ st->blksiz));
goto done;
- case ST_Q_FORCE_VAR_MODE:
+ case ST_Q_FORCE_VAR_MODE:
st->flags &= ~ST_FIXEDBLOCKS;
st->blksiz = 0;
-#ifdef STDEBUG
- if(st_debug) printf("Quirks force variable mode\n");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force variable mode\n"));
goto done;
}
-
- /***************************************************************\
- * 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))
- {
+ /*
+ * 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*/
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("blkmin == blkmax of %d\n", st->blkmin));
goto done;
}
-
- /***************************************************************\
- * 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:
- case DDS:
+ /*
+ * If the tape density mandates (or even suggests) use of fixed
+ * or variable-length blocks, comply.
+ */
+ switch (st->density) {
+ case HALFINCH_800:
+ case HALFINCH_1600:
+ case HALFINCH_6250:
+ case DDS:
st->flags &= ~ST_FIXEDBLOCKS;
st->blksiz = 0;
-#ifdef STDEBUG
- if(st_debug) printf("density specified variable\n");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3, ("density specified variable\n"));
goto done;
- case QIC_11:
- case QIC_24:
- case QIC_120:
- case QIC_150:
+ case QIC_11:
+ case QIC_24:
+ case QIC_120:
+ case QIC_150:
+ case QIC_525:
+ case QIC_1320:
st->flags |= ST_FIXEDBLOCKS;
- if (st->media_blksiz > 0)
+ if (st->media_blksiz > 0) {
st->blksiz = st->media_blksiz;
- else
+ } else {
st->blksiz = DEF_FIXED_BSIZE;
-#ifdef STDEBUG
- if(st_debug) printf("density specified fixed\n");
-#endif /*STDEBUG*/
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("density specified fixed\n"));
goto done;
}
-
- /***************************************************************\
- * 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. *
- \***************************************************************/
- 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)
+ /*
+ * 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.
+ */
+ 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;
- else
+ } 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*/
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("Used media_blksiz of %d\n", st->media_blksiz));
goto done;
}
-
- /***************************************************************\
- * We're getting no hints from any direction. Choose variable- *
- * length blocks arbitrarily. *
- \***************************************************************/
+ /*
+ * We're getting no hints from any direction. Choose variable-
+ * length blocks arbitrarily.
+ */
st->flags &= ~ST_FIXEDBLOCKS;
st->blksiz = 0;
-#ifdef STDEBUG
- if(st_debug) printf("Give up and default to variable mode\n");
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3, ("Give up and default to variable mode\n"));
done:
- st->flags &= ~ST_AT_BOM;
- return (st_mode_select(unit, 0));
+
+ /*
+ * 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.
+ * (I think this should be a by-product of fixed/variable..julian)
+ */
+ 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;
+ }
+ return 0;
}
-/*******************************************************\
-* trim the size of the transfer if needed, *
-* called by physio *
-* basically the smaller of our min and the scsi driver's*
-* minphys *
-\*******************************************************/
-void stminphys(bp)
-struct buf *bp;
+/*
+ * trim the size of the transfer if needed,
+ * called by physio
+ * basically the smaller of our min and the scsi driver's
+ * minphys
+ */
+void
+stminphys(bp)
+ struct buf *bp;
{
- (*(st_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp);
+ (*(st_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
}
-/*******************************************************\
-* Actually translate the requested transfer into *
-* one the physical driver can understand *
-* The transfer is described by a buf and will include *
-* only one physical transfer. *
-\*******************************************************/
-
-int ststrategy(bp)
-struct buf *bp;
+/*
+ * Actually translate the requested transfer into
+ * one the physical driver can understand
+ * The transfer is described by a buf and will include
+ * only one physical transfer.
+ */
+void
+ststrategy(bp)
+ struct buf *bp;
{
- struct buf **dp;
+ struct buf **dp;
unsigned char unit;
- unsigned int opri;
+ u_int32 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 *
- \*******************************************************/
- if (bp->b_bcount == 0)
- {
+ SC_DEBUG(st->sc_link, SDEV_DB1,
+ (" strategy: %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno));
+ /*
+ * If it's a null transfer, return immediatly
+ */
+ if (bp->b_bcount == 0) {
goto done;
}
-
- /*******************************************************\
- * 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->flags & ST_FIXEDBLOCKS)
- {
- if(bp->b_bcount % st->blksiz)
- {
+ /*
+ * Odd sized request on fixed drives are verboten
+ */
+ if (st->flags & ST_FIXEDBLOCKS) {
+ if (bp->b_bcount % st->blksiz) {
printf("st%d: bad request, must be multiple of %d\n",
- unit, st->blksiz);
+ unit, st->blksiz);
bp->b_error = EIO;
goto bad;
}
}
- /*******************************************************\
- * as are out-of-range requests on variable drives. *
- \*******************************************************/
- else if(bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax)
- {
+ /*
+ * as are out-of-range requests on variable drives.
+ */
+ else if (bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax) {
printf("st%d: bad request, must be between %d and %d\n",
- unit, st->blkmin, st->blkmax);
+ unit, st->blkmin, st->blkmax);
bp->b_error = EIO;
goto bad;
}
-
stminphys(bp);
opri = splbio();
- /*******************************************************\
- * 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() )) *
- \*******************************************************/
+ /*
+ * 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() ))
+ */
dp = &(st->buf_queue);
- while (*dp)
- {
+ while (*dp) {
dp = &((*dp)->b_actf);
- }
+ }
*dp = bp;
bp->b_actf = NULL;
- /*******************************************************\
- * Tell the device to get going on the transfer if it's *
- * not doing anything, otherwise just wait for completion*
- * (All a bit silly if we're only allowing 1 open but..) *
- \*******************************************************/
+ /*
+ * Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion
+ * (All a bit silly if we're only allowing 1 open but..)
+ */
ststart(unit);
splx(opri);
@@ -928,1443 +935,993 @@ struct buf *bp;
bad:
bp->b_flags |= B_ERROR;
done:
- /*******************************************************\
- * Correctly set the buf to indicate a completed xfer *
- \*******************************************************/
+ /*
+ * Correctly set the buf to indicate a completed xfer
+ */
iodone(bp);
return;
}
+/*
+ * 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 dequeues the buf and creates a scsi command to perform the
+ * transfer required. The transfer request will call scsi_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
+ */
+void
+ststart(unit)
+ u_int32 unit;
+{
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
+ register struct buf *bp = 0;
+ struct scsi_rw_tape cmd;
+ u_int32 flags;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("ststart "));
+ /*
+ * See if there is a buf to do and we are not already
+ * doing one
+ */
+ while (sc_link->opennings != 0) {
+
+ /* if a special awaits, let it proceed first */
+ if (sc_link->flags & SDEV_WAITING) {
+ wakeup((caddr_t)sc_link);
+ return;
+ }
+ if ((bp = st->buf_queue) == NULL) {
+ return; /* no work to bother with */
+ }
+ st->buf_queue = bp->b_actf;
+
+ /*
+ * if the device has been unmounted byt the user
+ * then throw away all requests until done
+ */
+ if ((!(st->flags & ST_MOUNTED))
+ || (!(sc_link->flags & SDEV_MEDIA_LOADED))) {
+ /* make sure that one implies the other.. */
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+ goto badnews;
+ }
+ /*
+ * 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) {
+ if ((bp->b_flags & B_READ) == B_WRITE) {
+ /*
+ * Handling of ST_AT_FILEMARK in
+ * st_space will fill in the right file
+ * mark count.
+ * Back up over filemark
+ */
+ 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);
+ continue; /* seek more work */
+ }
+ }
+ /*
+ * 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);
+ continue; /* seek more work */
+ }
+ }
+ /*
+ * 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_FM_WRITTEN;
+ 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) {
+ cmd.byte2 |= SRWT_FIXED;
+ lto3b(bp->b_bcount / st->blksiz, cmd.len);
+ } else {
+ lto3b(bp->b_bcount, cmd.len);
+ }
+ /*
+ * go ask the adapter to do all this for us
+ */
+ if (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &cmd,
+ sizeof(cmd),
+ (u_char *) bp->b_un.b_addr,
+ bp->b_bcount,
+ 0, /* can't retry a read on a tape really */
+ 100000,
+ bp,
+ flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) {
+ stqueues++;
+ } else {
+badnews:
+ printf("st%d: oops not queued\n", unit);
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ biodone(bp);
+ }
+ } /* go back and see if we can cram more work in.. */
+}
-
-/*******************************************************\
-* Perform special action on behalf of the user *
-* Knows about the internals of this device *
-\*******************************************************/
-stioctl(dev, cmd, arg, mode)
-dev_t dev;
-int cmd;
-caddr_t arg;
+/*
+ * Perform special action on behalf of the user;
+ * knows about the internals of this device
+ */
+errval
+stioctl(dev, cmd, arg, flag)
+ dev_t dev;
+ int cmd;
+ caddr_t arg;
+ int flag;
{
- int errcode = 0;
+ errval errcode = 0;
unsigned char unit;
- int number,flags,dsty;
- struct st_data *st;
-
-
- /*******************************************************\
- * Find the device that the user is talking about *
- \*******************************************************/
- flags = 0; /* give error messages, act on errors etc. */
+ u_int32 number, flags, dsty;
+ struct st_data *st;
+ u_int32 hold_blksiz;
+ u_int32 hold_density;
+ int32 nmarks;
+ struct mtop *mt = (struct mtop *) arg;
+
+ /*
+ * Find the device that the user is talking about
+ */
+ flags = 0; /* give error messages, act on errors etc. */
unit = UNIT(dev);
dsty = DSTY(dev);
- st = st_data[unit];
+ st = st_data[unit];
+ hold_blksiz = st->blksiz;
+ hold_density = st->density;
- switch(cmd)
- {
+ switch (cmd) {
case MTIOCGET:
- {
- struct mtget *g = (struct mtget *) arg;
-
- bzero(g, sizeof(struct mtget));
- g->mt_type = 0x7; /* Ultrix compat */ /*?*/
- if (st->flags & ST_FIXEDBLOCKS) {
- g->mt_bsiz = st->blksiz;
- } else {
- g->mt_bsiz = 0;
- }
- g->mt_dns_dflt = st->modes[0].density;
- g->mt_dns_dsty1 = st->modes[DSTY1].density;
- g->mt_dns_dsty2 = st->modes[DSTY2].density;
- g->mt_dns_dsty3 = st->modes[DSTY3].density;
- break;
- }
-
-
+ {
+ struct mtget *g = (struct mtget *) arg;
+
+ SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: get status]\n"));
+ bzero(g, sizeof(struct mtget));
+ g->mt_type = 0x7; /* Ultrix compat *//*? */
+ g->mt_density = st->density;
+ g->mt_blksiz = st->blksiz;
+ g->mt_density0 = st->modes[0].density;
+ g->mt_density1 = st->modes[1].density;
+ g->mt_density2 = st->modes[2].density;
+ g->mt_density3 = st->modes[3].density;
+ g->mt_blksiz0 = st->modes[0].blksiz;
+ g->mt_blksiz1 = st->modes[1].blksiz;
+ g->mt_blksiz2 = st->modes[2].blksiz;
+ g->mt_blksiz3 = st->modes[3].blksiz;
+ break;
+ }
case MTIOCTOP:
- {
- int nmarks;
- 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*/
-
+ {
+ SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: op=0x%x count=0x%x]\n",
+ mt->mt_op, mt->mt_count));
- /* compat: in U*x it is a short */
- number = mt->mt_count;
- switch ((short)(mt->mt_op))
- {
- case MTWEOF: /* write an end-of-file record */
- errcode = st_write_filemarks(unit,number,flags);
- break;
- case MTBSF: /* backward space file */
- 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 */
- 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);
- break;
- case MTOFFL: /* rewind and put the drive offline */
- if(st_rewind(unit,FALSE,flags))
- {
- printf("st%d: rewind failed, unit still loaded\n",
- unit);
- }
- else
- {
- st_prevent(unit,PR_ALLOW,0);
- st_load(unit,LD_UNLOAD,flags);
- }
- break;
- case MTNOP: /* no operation, sets status only */
- case MTCACHE: /* enable controller cache */
- case MTNOCACHE: /* disable controller cache */
- break;
- case MTSETBSIZ: /* Set block size for device */
- if (!(st->flags & ST_AT_BOM))
- {
- errcode = EINVAL;
+ /* compat: in U*x it is a short */
+ number = mt->mt_count;
+ switch ((short) (mt->mt_op)) {
+ case MTWEOF: /* write an end-of-file record */
+ errcode = st_write_filemarks(unit, number, flags);
break;
- }
- if (number == 0)
- {
- st->flags &= ~ST_FIXEDBLOCKS;
- }
- else
- {
- if ((st->blkmin || st->blkmax) /* they exist */
- && ((number < st->blkmin
- || number > st->blkmax)))
- {
+ case MTBSF: /* backward space file */
+ 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 */
+ 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);
+ break;
+ case MTOFFL: /* rewind and put the drive offline */
+ st_unmount(unit, EJECT);
+ break;
+ case MTNOP: /* no operation, sets status only */
+ case MTCACHE: /* enable controller cache */
+ case MTNOCACHE: /* disable controller cache */
+ break;
+ case MTSETBSIZ: /* Set block size for device */
+#ifdef NOTYET
+ if (!(st->flags & ST_NEW_MOUNT)) {
+ uprintf("re-mount tape before changing blocksize");
errcode = EINVAL;
break;
}
- st->flags |= ST_FIXEDBLOCKS;
- }
- st->blksiz = number;
- st->flags |= ST_BLOCK_SET;
- break;
+#endif
+ if (number == 0) {
+ st->flags &= ~ST_FIXEDBLOCKS;
+ } else {
+ if ((st->blkmin || st->blkmax) /* they exist */
+ &&((number < st->blkmin
+ || number > st->blkmax))) {
+ errcode = EINVAL;
+ break;
+ }
+ st->flags |= ST_FIXEDBLOCKS;
+ }
+ st->blksiz = number;
+ st->flags |= ST_BLOCK_SET; /*XXX */
+ goto try_new_value;
- /* How do we check that the drive can handle
- the requested density ? */
+ case MTSETDNSTY: /* Set density for device and mode */
+ if (number > SCSI_2_MAX_DENSITY_CODE) {
+ errcode = EINVAL;
+ } else {
+ st->density = number;
+ }
+ goto try_new_value;
- case MTSETDNSTY: /* Set density for device and mode */
- if (number < 0 || number > SCSI_2_MAX_DENSITY_CODE)
- {
+ default:
errcode = EINVAL;
}
- else
- {
- st->modes[dsty].density = number;
- }
break;
-
- default:
- errcode = EINVAL;
}
- break;
- }
case MTIOCIEOT:
case MTIOCEEOT:
break;
default:
- errcode = EINVAL;
+ if(MODE(dev) == CTLMODE)
+ errcode = scsi_do_ioctl(st->sc_link,cmd,arg,flag);
+ else
+ errcode = ENOTTY;
+ break;
}
-
return errcode;
+/*-----------------------------*/
+try_new_value:
+ /*
+ * Check that the mode being asked for is aggreeable to the
+ * drive. If not, put it back the way it was.
+ */
+ if (errcode = st_mode_select(unit, 0)) { /* put it back as it was */
+ printf("st%d: Cannot set selected mode", unit);
+ st->density = hold_density;
+ st->blksiz = hold_blksiz;
+ if (st->blksiz) {
+ st->flags |= ST_FIXEDBLOCKS;
+ } else {
+ st->flags &= ~ST_FIXEDBLOCKS;
+ }
+ return (errcode);
+ }
+ /*
+ * As the drive liked it, if we are setting a new default,
+ * set it into the structures as such.
+ *
+ * The means for deciding this are not finalised yet
+ */
+ if (MODE(dev) == 0x03) {
+ /* special mode */
+ /* XXX */
+ switch ((short) (mt->mt_op)) {
+ case MTSETBSIZ:
+ st->modes[dsty].blksiz = st->blksiz;
+ st->modeflags[dsty] |= BLKSIZE_SET_BY_USER;
+ break;
+ case MTSETDNSTY:
+ st->modes[dsty].density = st->density;
+ st->modeflags[dsty] |= DENSITY_SET_BY_USER;
+ break;
+ }
+ }
+ return 0;
}
-/*******************************************************\
-* Do a synchronous read. *
-\*******************************************************/
-int st_read(unit, buf, size, flags)
-int unit, size, flags;
-char *buf;
+/*
+ * Do a synchronous read.
+ */
+errval
+st_read(unit, buf, size, flags)
+ u_int32 unit, size, flags;
+ char *buf;
{
- int error;
struct scsi_rw_tape scsi_cmd;
struct st_data *st = st_data[unit];
- /*******************************************************\
- * If it's a null transfer, return immediatly *
- \*******************************************************/
- if (size == 0)
- {
- return(ESUCCESS);
+ /*
+ * If it's a null transfer, return immediatly
+ */
+ if (size == 0) {
+ return (ESUCCESS);
}
-
- /*******************************************************\
- * 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),
- buf,
- size,
- 100000,
- NULL,
- flags | SCSI_DATA_IN));
-}
-
-/*******************************************************\
-* Get scsi driver to send a "are you ready" command *
-\*******************************************************/
-st_test_ready(unit,flags)
-int unit,flags;
-{
- struct scsi_test_unit_ready scsi_cmd;
-
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.op_code = TEST_UNIT_READY;
-
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 100000,
- NULL,
- flags));
+ if (st->flags & ST_FIXEDBLOCKS) {
+ scsi_cmd.byte2 |= SRWT_FIXED;
+ lto3b(size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE),
+ scsi_cmd.len);
+ } else {
+ lto3b(size, scsi_cmd.len);
+ }
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) buf,
+ size,
+ 0, /* not on io commands */
+ 100000,
+ NULL,
+ flags | SCSI_DATA_IN));
}
-
-
#ifdef __STDC__
#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
#else
#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 )
#endif
-/*******************************************************\
-* Ask the drive what it's min and max blk sizes are. *
-\*******************************************************/
+/*
+ * Ask the drive what it's min and max blk sizes are.
+ */
+errval
st_rd_blk_lim(unit, flags)
-int unit,flags;
+ u_int32 unit, flags;
{
- struct scsi_blk_limits scsi_cmd;
+ struct scsi_blk_limits scsi_cmd;
struct scsi_blk_limits_data scsi_blkl;
struct st_data *st = st_data[unit];
- int errno;
-
- /*******************************************************\
- * First check if we have it all loaded *
- \*******************************************************/
- if ((st->flags & ST_INFO_VALID)) return 0;
-
- /*******************************************************\
- * do a 'Read Block Limits' *
- \*******************************************************/
+ errval errno;
+ struct scsi_link *sc_link = st->sc_link;
+
+ /*
+ * First check if we have it all loaded
+ */
+ if ((sc_link->flags & SDEV_MEDIA_LOADED))
+ return 0;
+
+ /*
+ * do a 'Read Block Limits'
+ */
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = READ_BLK_LIMITS;
- /*******************************************************\
- * do the command, update the global values *
- \*******************************************************/
- if ( errno = st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- &scsi_blkl,
- sizeof(scsi_blkl),
- 5000,
- NULL,
- flags | SCSI_DATA_IN))
- {
+ /*
+ * do the command, update the global values
+ */
+ if (errno = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & scsi_blkl,
+ sizeof(scsi_blkl),
+ ST_RETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_IN)) {
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);
- }
-#endif /*STDEBUG*/
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax));
return 0;
}
-/*******************************************************\
-* Get the scsi driver to send a full inquiry to the *
-* device and use the results to fill out the global *
-* parameter structure. *
-* *
-* called from: *
-* attach *
-* open *
-* ioctl (to reset original blksize) *
-\*******************************************************/
+/*
+ * Get the scsi driver to send a full inquiry to the
+ * device and use the results to fill out the global
+ * parameter structure.
+ *
+ * called from:
+ * attach
+ * open
+ * ioctl (to reset original blksize)
+ */
+errval
st_mode_sense(unit, flags)
-int unit,flags;
+ u_int32 unit, flags;
{
- int scsi_sense_len;
- int errno;
- char *scsi_sense_ptr;
- struct scsi_mode_sense scsi_cmd;
- struct scsi_sense
- {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- }scsi_sense;
+ u_int32 scsi_sense_len;
+ errval errno;
+ char *scsi_sense_ptr;
+ struct scsi_mode_sense scsi_cmd;
+ struct scsi_sense {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ } scsi_sense;
+
+ struct scsi_sense_page_0 {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
+ /* Tandberg tape drives returns page 00
+ * with the sense data, whether or not
+ * you want it( ie the don't like you
+ * saying you want anything less!!!!!
+ * They also expect page 00
+ * back when you issue a mode select
+ */
+ } scsi_sense_page_0;
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
- struct scsi_sense_page_0
- {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
- /* Tandberg tape drives returns page 00 */
- /* with the sense data, whether or not */
- /* you want it( ie the don't like you */
- /* saying you want anything less!!!!! */
- /* They also expect page 00 */
- /* back when you issue a mode select */
- }scsi_sense_page_0;
- struct st_data *st = st_data[unit];
-
- /*******************************************************\
- * First check if we have it all loaded *
- \*******************************************************/
- if ((st->flags & ST_INFO_VALID)) return 0;
-
- /*******************************************************\
- * Define what sort of structure we're working with *
- \*******************************************************/
- if (st->quirks & ST_Q_NEEDS_PAGE_0)
- {
+ /*
+ * Define what sort of structure we're working with
+ */
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
scsi_sense_len = sizeof(scsi_sense_page_0);
scsi_sense_ptr = (char *) &scsi_sense_page_0;
- }
- else
- {
+ } else {
scsi_sense_len = sizeof(scsi_sense);
scsi_sense_ptr = (char *) &scsi_sense;
}
-
- /*******************************************************\
- * Set up a mode sense *
- \*******************************************************/
+ /*
+ * Set up a mode sense
+ */
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = MODE_SENSE;
scsi_cmd.length = scsi_sense_len;
- /*******************************************************\
- * do the command, but we don't need the results *
- * just print them for our interest's sake, if asked, *
- * or if we need it as a template for the mode select *
- * store it away. *
- \*******************************************************/
- if (errno = st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- scsi_sense_ptr,
- scsi_sense_len,
- 5000,
- NULL,
- flags | SCSI_DATA_IN) )
- {
+ /*
+ * do the command, but we don't need the results
+ * just print them for our interest's sake, if asked,
+ * or if we need it as a template for the mode select
+ * store it away.
+ */
+ if (errno = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) scsi_sense_ptr,
+ scsi_sense_len,
+ ST_RETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_IN)) {
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->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("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));
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("density code 0x%x, %d-byte blocks, write-%s, ",
+ st->media_density, st->media_blksiz,
+ st->flags & ST_READONLY ? "protected" : "enabled"));
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("%sbuffered\n",
+ ((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec
+ & SMH_DSP_BUFF_MODE ? "" : "un"));
+ 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));
}
+ sc_link->flags |= SDEV_MEDIA_LOADED;
return 0;
}
-/*******************************************************\
-* Send a filled out parameter structure to the drive to *
-* set it into the desire modes etc. *
-\*******************************************************/
+/*
+ * Send a filled out parameter structure to the drive to
+ * set it into the desire modes etc.
+ */
+errval
st_mode_select(unit, flags)
-int unit, flags;
+ u_int32 unit, flags;
{
- int dat_len;
- char *dat_ptr;
+ u_int32 dat_len;
+ char *dat_ptr;
struct scsi_mode_select scsi_cmd;
- struct dat
- {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- }dat;
- struct dat_page_0
- {
- struct scsi_mode_header header;
- struct blk_desc blk_desc;
- unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
- }dat_page_0;
- struct st_data *st = st_data[unit];
-
- /*******************************************************\
- * Define what sort of structure we're working with *
- \*******************************************************/
- if (st->quirks & ST_Q_NEEDS_PAGE_0)
- {
+ struct dat {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ } dat;
+ struct dat_page_0 {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
+ } dat_page_0;
+ struct st_data *st = st_data[unit];
+
+ /*
+ * Define what sort of structure we're working with
+ */
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
dat_len = sizeof(dat_page_0);
dat_ptr = (char *) &dat_page_0;
- }
- else
- {
+ } else {
dat_len = sizeof(dat);
dat_ptr = (char *) &dat;
}
-
- /*******************************************************\
- * Set up for a mode select *
- \*******************************************************/
+ /*
+ * Set up for a mode select
+ */
bzero(dat_ptr, dat_len);
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = MODE_SELECT;
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 = st->density;
- if(st->flags & ST_FIXEDBLOCKS)
- {
- lto3b( st->blksiz , ((struct dat *)dat_ptr)->blk_desc.blklen);
+ ((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 = st->density;
+ if (st->flags & ST_FIXEDBLOCKS) {
+ lto3b(st->blksiz, ((struct dat *) dat_ptr)->blk_desc.blklen);
}
- if (st->quirks & ST_Q_NEEDS_PAGE_0)
- {
- bcopy(st->sense_data, ((struct dat_page_0 *)dat_ptr)->sense_data,
- sizeof(((struct dat_page_0 *)dat_ptr)->sense_data));
- /* the Tandberg tapes need the block size to */
- /* be set on each mode sense/select. */
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
+ bcopy(st->sense_data, ((struct dat_page_0 *) dat_ptr)->sense_data,
+ sizeof(((struct dat_page_0 *) dat_ptr)->sense_data));
+ /* the Tandberg tapes need the block size to */
+ /* be set on each mode sense/select. */
}
- /*******************************************************\
- * do the command *
- \*******************************************************/
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- dat_ptr,
- dat_len,
- 5000,
- NULL,
- flags | SCSI_DATA_OUT) );
+ /*
+ * do the command
+ */
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) dat_ptr,
+ dat_len,
+ ST_RETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_OUT));
}
-/*******************************************************\
-* skip N blocks/filemarks/seq filemarks/eom *
-\*******************************************************/
-st_space(unit,number,what,flags)
-int unit,number,what,flags;
+/*
+ * skip N blocks/filemarks/seq filemarks/eom
+ */
+errval
+st_space(unit, number, what, flags)
+ u_int32 unit, what, flags;
+ int32 number;
{
- int error;
+ errval 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);
+ struct st_data *st = st_data[unit];
- switch (what)
- {
- case SP_BLKS:
- if (st->flags & ST_PER_ACTION)
- {
- if (number > 0)
- {
+ 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. *
- \*******************************/
+ 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 (error)
+ return (error);
}
- if (st->flags & ST_BLANK_READ)
- {
+ if (st->flags & ST_BLANK_READ) {
st->flags &= ~ST_BLANK_READ;
- return(EIO);
+ return (EIO);
}
st->flags &= ~ST_EIO_PENDING;
}
}
break;
- case SP_FILEMARKS:
- if (st->flags & ST_EIO_PENDING)
- {
- if (number > 0)
- {
+ case SP_FILEMARKS:
+ if (st->flags & ST_EIO_PENDING) {
+ if (number > 0) { /* pretend we just discover the error */
st->flags &= ~ST_EIO_PENDING;
- return(EIO);
- }
- else if (number < 0)
+ return (EIO);
+ } else if (number < 0) { /* back away from the error */
st->flags &= ~ST_EIO_PENDING;
+ }
}
- if (st->flags & ST_AT_FILEMARK)
- {
+ if (st->flags & ST_AT_FILEMARK) {
st->flags &= ~ST_AT_FILEMARK;
number--;
}
- if (st->flags & ST_BLANK_READ && number < 0)
- {
+ if ((st->flags & ST_BLANK_READ) && (number < 0)) { /* back away from unwritten tape */
st->flags &= ~ST_BLANK_READ;
- number++;
+ number++; /* dubious */
}
}
- if (number == 0)
- return(ESUCCESS);
+ if (number == 0) {
+ return (ESUCCESS);
+ }
bzero(&scsi_cmd, sizeof(scsi_cmd));
scsi_cmd.op_code = SPACE;
scsi_cmd.byte2 = what & SS_CODE;
- lto3b(number,scsi_cmd.number);
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 600000, /* 10 mins enough? */
- NULL,
- flags));
+ lto3b(number, scsi_cmd.number);
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 0, /* no retries please , just fail */
+ 600000, /* 10 mins enough? */
+ NULL,
+ flags));
}
-/*******************************************************\
-* write N filemarks *
-\*******************************************************/
-st_write_filemarks(unit,number,flags)
-int unit,number,flags;
+
+/*
+ * write N filemarks
+ */
+errval
+st_write_filemarks(unit, number, flags)
+ u_int32 unit, flags;
+ int32 number;
{
- 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);
-
- /*******************************************************\
- * 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 && number > 0 &&
- (error = st_decide_mode(unit, FALSE)))
- return (error);
+ struct st_data *st = st_data[unit];
- switch (number)
- {
- case 0: /* really a command to sync the drive's buffers */
+ /*
+ * It's hard to write a negative number of file marks.
+ * Don't try.
+ */
+ if (number < 0) {
+ return EINVAL;
+ }
+ switch (number) {
+ case 0: /* really a command to sync the drive's buffers */
break;
- case 1:
- if (st->flags & ST_FM_WRITTEN)
+ case 1:
+ if (st->flags & ST_FM_WRITTEN) { /* already have one down */
st->flags &= ~ST_WRITTEN;
- else
+ } 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);
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 100000, /* 10 secs.. (may need to repos head )*/
- NULL,
- flags) );
+ lto3b(number, scsi_cmd.number);
+ return scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 0, /* no retries, just fail */
+ 100000, /* 10 secs.. (may need to repos head ) */
+ 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. *
-\***************************************************************/
+/*
+ * 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.
+ */
+int32
st_chkeod(unit, position, nmarks, flags)
-int unit;
-int position;
-int *nmarks;
-int flags;
+ u_int32 unit;
+ boolean position;
+ int32 *nmarks;
+ u_int32 flags;
{
- int error;
- struct st_data *st = st_data[unit];
+ errval error;
+ struct st_data *st = st_data[unit];
- switch (st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD))
- {
+ 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:
+ 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:
+ case ST_WRITTEN | ST_2FM_AT_EOD:
*nmarks = 2;
}
error = st_write_filemarks(unit, *nmarks, flags);
- if (position && error == ESUCCESS)
+ if (position && (error == ESUCCESS))
error = st_space(unit, -*nmarks, SP_FILEMARKS, flags);
return (error);
}
-/*******************************************************\
-* load/unload (with retension if true) *
-\*******************************************************/
-st_load(unit,type,flags)
-int unit,type,flags;
+/*
+ * load/unload (with retension if true)
+ */
+errval
+st_load(unit, type, flags)
+ u_int32 unit, type, flags;
{
- struct scsi_load scsi_cmd;
- struct st_data *st = st_data[unit];
+ struct scsi_load scsi_cmd;
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
- st->flags &= ~ST_PER_MEDIA;
bzero(&scsi_cmd, sizeof(scsi_cmd));
- if (type == LD_LOAD)
- {
- /*scsi_cmd.how |= LD_RETEN;*/
- st->flags |= ST_AT_BOM;
- }
- else
- {
- int error, nmarks;
+ if (type != LD_LOAD) {
+ errval error;
+ int32 nmarks;
error = st_chkeod(unit, FALSE, &nmarks, flags);
- if (error != ESUCCESS) return(error);
- st->flags &= ~ST_INFO_VALID;
+ if (error != ESUCCESS)
+ return (error);
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
}
- if(st->quirks & ST_Q_IGNORE_LOADS) return(0);
+ 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),
- 0,
- 0,
- 300000, /* 5 min */
- NULL,
- flags));
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ ST_RETRIES,
+ 300000, /* 5 min */
+ NULL,
+ flags));
}
-/*******************************************************\
-* Prevent or allow the user to remove the tape *
-\*******************************************************/
-st_prevent(unit,type,flags)
-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;
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- 5000,
- NULL,
- flags));
-}
-/*******************************************************\
-* Rewind the device *
-\*******************************************************/
-st_rewind(unit,immed,flags)
-int unit,immed,flags;
+/*
+ * Rewind the device
+ */
+errval
+st_rewind(unit, immed, flags)
+ u_int32 unit, flags;
+ boolean immed;
{
- struct scsi_rewind scsi_cmd;
- struct st_data *st = st_data[unit];
- int error, nmarks;
+ struct scsi_rewind scsi_cmd;
+ struct st_data *st = st_data[unit];
+ errval error;
+ int32 nmarks;
error = st_chkeod(unit, FALSE, &nmarks, flags);
- if (error != ESUCCESS) return(error);
+ if (error != ESUCCESS)
+ return (error);
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;
- return (st_scsi_cmd(unit,
- &scsi_cmd,
- sizeof(scsi_cmd),
- 0,
- 0,
- immed?5000:300000, /* 5 sec or 5 min */
- 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)
- {
- 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 *
- * 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_FM_WRITTEN;
- 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)
- {
- cmd.byte2 |= SRWT_FIXED;
- lto3b(bp->b_bcount/st->blksiz,cmd.len);
- }
- 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)
-
- {
-badnews:
- printf("st%d: oops not queued\n",unit);
- bp->b_flags |= B_ERROR;
- bp->b_error = EIO;
- biodone(bp);
- return;
- }
- stqueues++;
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ ST_RETRIES,
+ immed ? 5000 : 300000, /* 5 sec or 5 min */
+ NULL,
+ flags));
}
-/*******************************************************\
-* 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;
+#ifdef NETBSD
+#define SIGNAL_SHORT_READ
#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 */
-}
-
-
+#define SIGNAL_SHORT_READ bp->b_flags |= B_ERROR;
+#endif
-/*******************************************************\
-* ask the scsi driver to perform a command for us. *
-* Call it through the switch table, and tell it which *
-* sub-unit we want, and what target and lu we wish to *
-* talk to. Also tell it where to find the command *
-* how long int is. *
-* 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,bp,flags)
-
-int unit,flags;
-struct scsi_generic *scsi_cmd;
-int cmdlen;
-int timeout;
-u_char *data_addr;
-struct buf *bp;
-int datalen;
+/*
+ * Look at the returned sense and act on the error and detirmine
+ * The unix error number to pass back... (0 = report no error)
+ * (-1 = continue processing)
+ */
+errval
+st_interpret_sense(xs)
+ struct scsi_xfer *xs;
{
- struct scsi_xfer *xs;
- int retval;
- int s;
- struct st_data *st = st_data[unit];
-
-#ifdef STDEBUG
- if(scsi_debug & PRINTROUTINES) printf("\nst_scsi_cmd%d ",unit);
-#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);
+ struct scsi_link *sc_link = xs->sc_link;
+ struct scsi_sense_data *sense = &(xs->sense);
+ boolean silent = xs->flags & SCSI_SILENT;
+ struct buf *bp = xs->bp;
+ u_int32 unit = sc_link->dev_unit;
+ struct st_data *st = st_data[unit];
+ u_int32 key;
+ int32 info;
+
+ /*
+ * Get the sense fields and work out what code
+ */
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ info = ntohl(*((int32 *) sense->ext.extended.info));
+ } else {
+ info = xs->datalen; /* bad choice if fixed blocks */
}
-#endif /*PARANOID*/
-
- 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);
+ if ((sense->error_code & SSD_ERRCODE) != 0x70) {
+ return (-1); /* let the generic code handle it */
}
- 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 = 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 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
- {
- xs->error = XS_NOERROR;
- retval = ESUCCESS;
- }
- break;
- case XS_DRIVER_STUFFUP:
- retval = EIO;
- break;
- case XS_BUSY:
- /* should sleep 1 sec here */
- case XS_TIMEOUT:
- if(xs->retries-- )
- {
- xs->flags &= ~ITSDONE;
- goto retry;
+ if (st->flags & ST_FIXEDBLOCKS) {
+ xs->resid = info * st->blksiz;
+ if (sense->ext.extended.flags & SSD_EOM) {
+ st->flags |= ST_EIO_PENDING;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
}
- retval = EIO;
- 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;
}
- retval = EIO;
- break;
- default:
- retval = EIO;
- }
- xs->flags = 0; /* it's free! */
- ststart(unit);
- return(retval);
-}
-/***************************************************************\
-* Look at the returned sense and act on the error and detirmine *
-* The unix error number to pass back... (0 = report no error) *
-\***************************************************************/
-
-int st_interpret_sense(unit,xs)
-int unit;
-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;
- static char *error_mes[] = { "soft error (corrected)",
- "not ready", "medium error",
- "non-media hardware failure", "illegal request",
- "unit attention", "tape is write-protected",
- "no data found", "vendor unique",
- "copy aborted", "command aborted",
- "search returned equal", "volume overflow",
- "verify miscompare", "unknown error key"
- };
-
- /***************************************************************\
- * If errors are ok, report a success *
- \***************************************************************/
- if(xs->flags & SCSI_ERR_OK) return(ESUCCESS);
-
- /***************************************************************\
- * Get the sense fields and work out what code *
- \***************************************************************/
- sense = &(xs->sense);
-#ifdef STDEBUG
- if(st_debug)
- {
- int count = 0;
- printf("code%x valid%x\n"
- ,sense->error_code & SSD_ERRCODE
- ,sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
- printf("seg%x key%x ili%x eom%x fmark%x\n"
- ,sense->ext.extended.segment
- ,sense->ext.extended.flags & SSD_KEY
- ,sense->ext.extended.flags & SSD_ILI ? 1 : 0
- ,sense->ext.extended.flags & SSD_EOM ? 1 : 0
- ,sense->ext.extended.flags & SSD_FILEMARK ? 1 : 0);
- printf("info: %x %x %x %x followed by %d extra bytes\n"
- ,sense->ext.extended.info[0]
- ,sense->ext.extended.info[1]
- ,sense->ext.extended.info[2]
- ,sense->ext.extended.info[3]
- ,sense->ext.extended.extra_len);
- printf("extra: ");
- while(count < sense->ext.extended.extra_len)
- {
- printf ("%x ",sense->ext.extended.extra_bytes[count++]);
+ if (sense->ext.extended.flags & SSD_FILEMARK) {
+ st->flags |= ST_AT_FILEMARK;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
+ }
}
- 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 code 70, use the extended stuff and interpret the key *
- \***************************************************************/
- case 0x70:
- if(st->flags & ST_FIXEDBLOCKS)
- {
- xs->resid = info * st->blksiz;
- if(sense->ext.extended.flags & SSD_EOM)
- {
- st->flags |= ST_EIO_PENDING;
+ if (sense->ext.extended.flags & SSD_ILI) {
+ st->flags |= ST_EIO_PENDING;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
}
- if(sense->ext.extended.flags & SSD_FILEMARK)
- {
- st->flags |= ST_AT_FILEMARK;
+ if (sense->error_code & SSD_ERRCODE_VALID &&
+ !silent)
+ printf("st%d: block wrong size"
+ ", %d blocks residual\n", unit
+ ,info);
+
+ /*
+ * This quirk code helps the drive read
+ * the first tape block, regardless of
+ * format. That is required for these
+ * drives to return proper MODE SENSE
+ * information.
+ */
+ if ((st->quirks & ST_Q_SNS_HLP) &&
+ !(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ st->blksiz -= 512;
}
- 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 *
- * the first tape block, regardless of *
- * format. That is required for these *
- * drives to return proper MODE SENSE *
- * information. *
- \***************************************/
- if ((st->quirks & ST_Q_SNS_HLP) &&
- !(st->flags & ST_INFO_VALID))
- {
- st->blksiz -= 512;
- }
+ }
+ /*
+ * If no data was tranfered, do it immediatly
+ */
+ if (xs->resid >= xs->datalen) {
+ if (st->flags & ST_EIO_PENDING) {
+ return EIO;
}
- /***********************************************\
- * 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 (st->flags & ST_AT_FILEMARK) {
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
}
+ return 0;
}
}
- else
- {
- xs->resid = xs->datalen; /* to be sure */
- if(sense->ext.extended.flags & SSD_EOM)
- {
- return(EIO);
+ } else { /* must be variable mode */
+ xs->resid = xs->datalen; /* to be sure */
+ if (sense->ext.extended.flags & SSD_EOM) {
+ return (EIO);
+ }
+ if (sense->ext.extended.flags & SSD_FILEMARK) {
+ if (bp)
+ bp->b_resid = bp->b_bcount;
+ return 0;
+ }
+ if (sense->ext.extended.flags & SSD_ILI) {
+ if (info < 0) {
+ /*
+ * the record was bigger than the read
+ */
+ if (!silent)
+ printf("st%d: %d-byte record "
+ "too big\n", unit,
+ xs->datalen - info);
+ return (EIO);
}
- if(sense->ext.extended.flags & SSD_FILEMARK)
- {
- return 0;
+ xs->resid = info;
+ if (bp) {
+ bp->b_resid = info;
+ SIGNAL_SHORT_READ
}
- if(sense->ext.extended.flags & SSD_ILI)
- {
- if(info < 0)
- /***************************************\
- * the record was bigger than the read *
- \***************************************/
- {
- if (!silent)
- printf("st%d: %d-byte record "
- "too big\n", unit,
- xs->datalen - info);
- return(EIO);
- }
- xs->resid = info;
+ }
+ }
+ key = sense->ext.extended.flags & SSD_KEY;
+
+ if (key == 0x8) {
+ /*
+ * This quirk code helps the drive read the
+ * first tape block, regardless of format. That
+ * is required for these drives to return proper
+ * MODE SENSE information.
+ */
+ if ((st->quirks & ST_Q_SNS_HLP) &&
+ !(sc_link->flags & SDEV_MEDIA_LOADED)) { /* still starting */
+ st->blksiz -= 512;
+ } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) {
+ st->flags |= ST_BLANK_READ;
+ xs->resid = xs->datalen;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ /*return an EOF */
}
- }/* there may be some other error. check the rest */
+ return (ESUCCESS);
+ }
+ }
+ return (-1); /* let the default/generic handler handle it */
+}
- key=sense->ext.extended.flags & SSD_KEY;
+/*
+ * 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 large fixed-block state (user-specified
+ * density and 1024-byte blocks), then read and rewind to get it to sense the
+ * tape. If that doesn't work, try 512-byte fixed blocks. If that doesn't
+ * work, as a last resort, try variable- length blocks. The result will be
+ * the ability to do an accurate st_mode_sense.
+ *
+ * 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.
+ *
+ * The rest of the code for this quirk is in ILI processing and BLANK CHECK
+ * error processing, both part of st_interpret_sense.
+ */
+errval
+st_touch_tape(unit)
+ u_int32 unit;
+{
+ struct st_data *st = st_data[unit];
+ char *buf;
+ u_int32 readsiz;
+ errval errno;
- 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)
- {
- switch (key)
- {
- case 0x2: /* NOT READY */
- case 0x5: /* ILLEGAL REQUEST */
- case 0x6: /* UNIT ATTENTION */
- case 0x7: /* DATA PROTECT */
- break;
- case 0x8: /* BLANK CHECK */
- printf(", requested size: %d (decimal)",
- info);
- break;
- default:
- printf(", info = %d (decimal)", info);
- }
- }
- printf("\n");
- }
+ buf = malloc(1024, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return (ENOMEM);
- switch (key)
- {
- case 0x0: /* NO SENSE */
- case 0x1: /* RECOVERED ERROR */
- if(xs->resid == xs->datalen) xs->resid = 0;
- case 0xc: /* EQUAL */
- return(ESUCCESS);
- case 0x2: /* NOT READY */
- return(ENODEV);
- case 0x5: /* ILLEGAL REQUEST */
- return(EINVAL);
- case 0x6: /* UNIT ATTENTION */
- st->flags &= ~ST_PER_MEDIA;
- if (st->flags & ST_OPEN) /* TEMP!!!! */
- return(EIO);
- else
- return(ESUCCESS);
- case 0x7: /* DATA PROTECT */
- return(EACCES);
- case 0xd: /* VOLUME OVERFLOW */
- return(ENOSPC);
- case 0x8: /* BLANK CHECK */
- /***********************************************\
- * This quirk code helps the drive read the *
- * first tape block, regardless of format. That *
- * is required for these drives to return proper *
- * MODE SENSE information. *
- \***********************************************/
- if ((st->quirks & ST_Q_SNS_HLP) &&
- !(st->flags & ST_INFO_VALID))
- {
- 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);
- }
+ if (errno = st_mode_sense(unit, 0)) {
+ goto bad;
+ }
+ st->blksiz = 1024;
+ do {
+ switch (st->blksiz) {
+ case 512:
+ case 1024:
+ readsiz = st->blksiz;
+ st->flags |= ST_FIXEDBLOCKS;
+ break;
default:
- return(EIO);
+ readsiz = 1;
+ st->flags &= ~ST_FIXEDBLOCKS;
+ } if (errno = st_mode_select(unit, 0)) {
+ goto bad;
}
- /***************************************************************\
- * If it's NOT code 70, just report it. *
- \***************************************************************/
- default:
- if (!silent)
- {
- printf("st%d: error code %d", unit,
- sense->error_code & SSD_ERRCODE);
- if(sense->error_code & SSD_ERRCODE_VALID)
- {
- printf(" at block no. %d (decimal)",
- (sense->ext.unextended.blockhi << 16) +
- (sense->ext.unextended.blockmed << 8) +
- sense->ext.unextended.blocklow);
- }
- printf("\n");
+ st_read(unit, buf, readsiz, SCSI_SILENT);
+ if (errno = st_rewind(unit, FALSE, 0)) {
+bad: free(buf, M_TEMP);
+ return (errno);
}
- return(EIO);
- }
+ } while (readsiz != 1 && readsiz > st->blksiz);
+ free(buf, M_TEMP);
+ return 0;
}
OpenPOWER on IntegriCloud