u_char min_length_0; /* Least significant */
};
+/* See SCSI-II spec 9.3.3.1 */
+struct scsi_tape_dev_conf_page {
+ u_char pagecode; /* 0x10 */
+ u_char pagelength; /* 0x0e */
+ u_char byte2;
+#define SMT_CAP 0x40 /* change active partition */
+#define SMT_CAF 0x20 /* change active format */
+#define SMT_AFMASK 0x1f /* active format mask */
+ u_char active_partition;
+ u_char wb_full_ratio;
+ u_char rb_empty_ratio;
+ u_char wrdelay_time_1; /* MSB */
+ u_char wrdelay_time_0; /* LSB */
+ u_char byte8;
+#define SMT_DBR 0x80 /* data buffer recovery */
+#define SMT_BIS 0x40 /* block identifiers supported */
+#define SMT_RSMK 0x20 /* report setmarks */
+#define SMT_AVC 0x10 /* automatic velocity control */
+#define SMT_SOCF_MASK 0xc0 /* stop on consecutive formats */
+#define SMT_RBO 0x20 /* recover buffer order */
+#define SMT_REW 0x10 /* report early warning */
+ u_char gap_size;
+ u_char byte10;
+#define SMT_EODDEFINED 0xe0 /* EOD defined */
+#define SMT_EEG 0x10 /* enable EOD generation */
+#define SMT_SEW 0x80 /* synchronize at early warning */
+ u_char ew_bufsize_2; /* MSB */
+ u_char ew_bufsize_1; /* ... */
+ u_char ew_bufsize_0; /* LSB */
+ u_char sel_comp_alg;
+#define SMT_COMP_NONE 0x00
+#define SMT_COMP_DEFAULT 0x01
+ u_char reserved;
+};
+
/* defines for the device specific byte in the mode select/sense header */
#define SMH_DSP_SPEED 0x0F
#define SMH_DSP_BUFF_MODE 0x70
int st_write_filemarks __P((struct st_softc *, int number, int flags));
int st_load __P((struct st_softc *, u_int type, int flags));
int st_mode_select __P((struct st_softc *, int flags));
-void ststrategy();
-int st_check_eod();
-void ststart();
-void st_unmount();
-int st_mount_tape();
-void st_loadquirks();
-void st_identify_drive();
-int st_interpret_sense();
+void ststrategy __P((struct buf *));
+int st_check_eod __P((struct st_softc *, boolean, int *, int));
+void ststart __P((struct st_softc *));
+void st_unmount __P((struct st_softc *, boolean));
+int st_mount_tape __P((dev_t, int));
+void st_loadquirks __P((struct st_softc *));
+void st_identify_drive __P((struct st_softc *, struct scsi_inquiry_data *));
+int st_interpret_sense __P((struct scsi_xfer *));
struct scsi_device st_switch = {
st_interpret_sense,
#define ST_BLANK_READ 0x0200 /* BLANK CHECK encountered already */
#define ST_2FM_AT_EOD 0x0400 /* write 2 file marks at EOD */
#define ST_MOUNTED 0x0800 /* Device is presently mounted */
+#define ST_DONTBUFFER 0x1000 /* Disable buffering/caching */
#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
if (!error)
error = st_space(st, number, SP_BLKS, flags);
break;
- case MTERASE: /* erase */
- error = st_erase(st, FALSE, flags);
- break;
case MTREW: /* rewind */
error = st_rewind(st, 0, flags);
break;
error = st_space(st, 1, SP_EOM, flags);
break;
case MTCACHE: /* enable controller cache */
+ st->flags &= ~ST_DONTBUFFER;
+ goto try_new_value;
case MTNOCACHE: /* disable controller cache */
+ st->flags |= ST_DONTBUFFER;
+ goto try_new_value;
+ case MTERASE: /* erase volume */
+ error = st_erase(st, number, flags);
break;
case MTSETBSIZ: /* Set block size for device */
#ifdef NOTYET
goto try_new_value;
case MTSETDNSTY: /* Set density for device and mode */
- if (number > SCSI_2_MAX_DENSITY_CODE)
+ if (number > SCSI_2_MAX_DENSITY_CODE) {
error = EINVAL;
- else
+ break;
+ } else
st->density = number;
goto try_new_value;
bzero(&scsi_select, scsi_select_len);
scsi_select.header.blk_desc_len = sizeof(struct scsi_blk_desc);
- scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
+ scsi_select.header.dev_spec &= ~SMH_DSP_BUFF_MODE;
scsi_select.blk_desc.density = st->density;
+ if (st->flags & ST_DONTBUFFER)
+ scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_OFF;
+ else
+ scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
if (st->flags & ST_FIXEDBLOCKS)
lto3b(st->blksize, scsi_select.blk_desc.blklen);
if (st->page_0_size)
ST_RETRIES, 5000, NULL, flags | SCSI_DATA_OUT);
}
+/*
+ * issue an erase command
+ */
+int
+st_erase(st, full, flags)
+ struct st_softc *st;
+ int full, flags;
+{
+ struct scsi_erase cmd;
+
+ /*
+ * Full erase means set LONG bit in erase command, which asks
+ * the drive to erase the entire unit. Without this bit, we're
+ * asking the drive to write an erase gap.
+ */
+ bzero(&cmd, sizeof(cmd));
+ cmd.opcode = ERASE;
+ if (full)
+ cmd.byte2 = SE_IMMED|SE_LONG;
+ else
+ cmd.byte2 = SE_IMMED;
+
+ /*
+ * XXX We always do this asynchronously, for now. How long should
+ * we wait if we want to (eventually) to it synchronously?
+ */
+ return (scsi_scsi_cmd(st->sc_link, (struct scsi_generic *)&cmd,
+ sizeof(cmd), 0, 0, ST_RETRIES, 5000, NULL, flags));
+}
+
/*
* skip N blocks/filemarks/seq filemarks/eom
*/
flags);
}
-/*
- * Erase the tape
- */
-int
-st_erase(st, immediate, flags)
- struct st_softc *st;
- u_int immediate;
- int flags;
-{
- struct scsi_erase scsi_cmd;
- int error;
- int nmarks;
-
- error = st_check_eod(st, FALSE, &nmarks, flags);
- if (error)
- return (error);
- /*
- * Archive Viper 2525 technical manual 5.7 (ERASE 19h):
- * tape has to be positioned to BOT first before erase command
- * is issued or command is rejected. So we rewind the tape first
- * and exit with an error, if the tape can't be rewinded.
- */
- error = st_rewind(st, FALSE, SCSI_SILENT);
- if (error)
- return (error);
- st->flags &= ~ST_PER_ACTION;
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.opcode = ERASE;
- scsi_cmd.byte2 = SE_LONG | (immediate ? SE_IMMED : 0);
- return (scsi_scsi_cmd(st->sc_link, (struct scsi_generic *) &scsi_cmd,
- sizeof(scsi_cmd), 0, 0, ST_RETRIES,
- immediate ? 5000 : 300000, /* 5 sec or 5 min */
- NULL, flags));
-}
-
/*
* Look at the returned sense and act on the error and detirmine
* The unix error number to pass back... (0 = report no error)