summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/scsi/targets/st.c672
-rw-r--r--usr/src/uts/common/io/scsi/targets/st_conf.c40
-rw-r--r--usr/src/uts/common/io/warlock/scsa2usb_with_usba.wlcmd1
-rw-r--r--usr/src/uts/common/io/warlock/st.wlcmd3
-rw-r--r--usr/src/uts/common/io/warlock/st_with_esp.wlcmd3
-rw-r--r--usr/src/uts/common/io/warlock/st_with_fas.wlcmd3
-rw-r--r--usr/src/uts/common/io/warlock/st_with_glm.wlcmd3
-rw-r--r--usr/src/uts/common/io/warlock/st_with_isp.wlcmd3
-rw-r--r--usr/src/uts/common/sys/mtio.h1
-rw-r--r--usr/src/uts/common/sys/scsi/targets/stdef.h100
10 files changed, 728 insertions, 101 deletions
diff --git a/usr/src/uts/common/io/scsi/targets/st.c b/usr/src/uts/common/io/scsi/targets/st.c
index e8027714fc..9d5a181ec9 100644
--- a/usr/src/uts/common/io/scsi/targets/st.c
+++ b/usr/src/uts/common/io/scsi/targets/st.c
@@ -43,6 +43,7 @@
#include <sys/ddidmareq.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
+#include <sys/byteorder.h>
#define IOSP KSTAT_IO_PTR(un->un_stats)
/*
@@ -238,6 +239,16 @@ volatile int st_debug = 0;
#define ST_MT02_NAME "Emulex MT02 QIC-11/24 "
+static const struct vid_drivetype {
+ char *vid;
+ char type;
+} st_vid_dt[] = {
+ {"LTO-CVE ", MT_LTO},
+ {"QUANTUM ", MT_ISDLT},
+ {"SONY ", MT_ISAIT},
+ {"STK ", MT_ISSTK9840}
+};
+
static const struct driver_minor_data {
char *name;
int minor;
@@ -433,6 +444,14 @@ static int st_get_conf_from_st_dot_conf(struct scsi_tape *, char *,
struct st_drivetype *);
static int st_get_conf_from_st_conf_dot_c(struct scsi_tape *, char *,
struct st_drivetype *);
+static int st_get_conf_from_tape_drive(struct scsi_tape *, char *,
+ struct st_drivetype *);
+static int st_get_densities_from_tape_drive(struct scsi_tape *,
+ struct st_drivetype *);
+static int st_get_timeout_values_from_tape_drive(struct scsi_tape *,
+ struct st_drivetype *);
+static int st_get_timeouts_value(struct scsi_tape *, uchar_t, ushort_t *,
+ ushort_t);
static int st_get_default_conf(struct scsi_tape *, char *,
struct st_drivetype *);
static int st_rw(dev_t dev, struct uio *uio, int flag);
@@ -491,6 +510,12 @@ static int st_gen_mode_sense(struct scsi_tape *un, int page,
static int st_change_block_size(dev_t dev, uint32_t nblksz);
static int st_gen_mode_select(struct scsi_tape *un, struct seq_mode *page_data,
int page_size);
+static int st_read_block_limits(struct scsi_tape *un,
+ struct read_blklim *read_blk);
+static int st_report_density_support(struct scsi_tape *un,
+ uchar_t *density_data, size_t buflen);
+static int st_report_supported_operation(struct scsi_tape *un,
+ uchar_t *oper_data, uchar_t option_code, ushort_t service_action);
static int st_tape_init(dev_t dev);
static void st_flush(struct scsi_tape *un);
static void st_set_pe_errno(struct scsi_tape *un);
@@ -856,61 +881,6 @@ st_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
"st_attach: instance=%x\n", instance);
/*
- * find the drive type for this target
- */
- st_known_tape_type(un);
-
- for (node_ix = 0; node_ix < ST_NUM_MEMBERS(st_minor_data); node_ix++) {
- int minor;
- char *name;
-
- name = st_minor_data[node_ix].name;
- minor = st_minor_data[node_ix].minor;
-
- /*
- * For default devices set the density to the
- * preferred default density for this device.
- */
- if (node_ix <= DEF_BSD_NR) {
- minor |= un->un_dp->default_density;
- }
- minor |= MTMINOR(instance);
-
- if (ddi_create_minor_node(devi, name, S_IFCHR, minor,
- DDI_NT_TAPE, NULL) == DDI_SUCCESS) {
- continue;
- }
-
- ddi_remove_minor_node(devi, NULL);
- if (un) {
- cv_destroy(&un->un_clscv);
- cv_destroy(&un->un_sbuf_cv);
- cv_destroy(&un->un_queue_cv);
- cv_destroy(&un->un_state_cv);
- cv_destroy(&un->un_suspend_cv);
- cv_destroy(&un->un_tape_busy_cv);
-
- if (un->un_sbufp) {
- freerbuf(un->un_sbufp);
- }
- if (un->un_uscsi_rqs_buf) {
- kmem_free(un->un_uscsi_rqs_buf, SENSE_LENGTH);
- }
- if (un->un_mspl) {
- i_ddi_mem_free((caddr_t)un->un_mspl, NULL);
- }
- scsi_destroy_pkt(un->un_rqs);
- scsi_free_consistent_buf(un->un_rqs_bp);
- ddi_soft_state_free(st_state, instance);
- devp->sd_private = NULL;
- devp->sd_sense = NULL;
-
- }
- ddi_prop_remove_all(devi);
- return (DDI_FAILURE);
- }
-
- /*
* Add a zero-length attribute to tell the world we support
* kernel ioctls (for layered drivers)
*/
@@ -1044,6 +1014,74 @@ st_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
}
(void) st_create_errstats(un, instance);
+ /*
+ * find the drive type for this target
+ */
+ mutex_enter(ST_MUTEX);
+ un->un_dev = MT_TEM_DEV(instance);
+ st_known_tape_type(un);
+ un->un_dev = 0;
+ mutex_exit(ST_MUTEX);
+
+ for (node_ix = 0; node_ix < ST_NUM_MEMBERS(st_minor_data); node_ix++) {
+ int minor;
+ char *name;
+
+ name = st_minor_data[node_ix].name;
+ minor = st_minor_data[node_ix].minor;
+
+ /*
+ * For default devices set the density to the
+ * preferred default density for this device.
+ */
+ if (node_ix <= DEF_BSD_NR) {
+ minor |= un->un_dp->default_density;
+ }
+ minor |= MTMINOR(instance);
+
+ if (ddi_create_minor_node(devi, name, S_IFCHR, minor,
+ DDI_NT_TAPE, NULL) == DDI_SUCCESS) {
+ continue;
+ }
+
+ ddi_remove_minor_node(devi, NULL);
+
+ cv_destroy(&un->un_clscv);
+ cv_destroy(&un->un_sbuf_cv);
+ cv_destroy(&un->un_queue_cv);
+ cv_destroy(&un->un_state_cv);
+ cv_destroy(&un->un_suspend_cv);
+ cv_destroy(&un->un_tape_busy_cv);
+
+ if (un->un_sbufp) {
+ freerbuf(un->un_sbufp);
+ }
+ if (un->un_uscsi_rqs_buf) {
+ kmem_free(un->un_uscsi_rqs_buf, SENSE_LENGTH);
+ }
+ if (un->un_mspl) {
+ i_ddi_mem_free((caddr_t)un->un_mspl, NULL);
+ }
+ if (un->un_dp_size) {
+ kmem_free(un->un_dp, un->un_dp_size);
+ }
+ if (un->un_state) {
+ kstat_delete(un->un_stats);
+ }
+ if (un->un_errstats) {
+ kstat_delete(un->un_errstats);
+ }
+
+ scsi_destroy_pkt(un->un_rqs);
+ scsi_free_consistent_buf(un->un_rqs_bp);
+ ddi_soft_state_free(st_state, instance);
+ devp->sd_private = NULL;
+ devp->sd_sense = NULL;
+
+ ddi_prop_remove_all(devi);
+ return (DDI_FAILURE);
+ }
+
return (DDI_SUCCESS);
}
@@ -1637,6 +1675,7 @@ typedef int
static cfg_functp config_functs[] = {
st_get_conf_from_st_dot_conf,
st_get_conf_from_st_conf_dot_c,
+ st_get_conf_from_tape_drive,
st_get_default_conf
};
@@ -1665,6 +1704,7 @@ st_known_tape_type(struct scsi_tape *un)
dp = kmem_zalloc((size_t)un->un_dp_size, KM_SLEEP);
un->un_dp = dp;
+ un->un_dp->non_motion_timeout = st_io_time;
/*
* Loop through the configuration methods till one works.
*/
@@ -2026,6 +2066,416 @@ st_get_conf_from_st_conf_dot_c(struct scsi_tape *un, char *vidpid,
}
static int
+st_get_conf_from_tape_drive(struct scsi_tape *un, char *vidpid,
+ struct st_drivetype *dp)
+{
+ int bsize;
+ ulong_t maxbsize;
+ caddr_t buf;
+ struct st_drivetype *tem_dp;
+ struct read_blklim *blklim;
+ int rval;
+ int i;
+
+ ST_FUNC(ST_DEVINFO, st_get_conf_from_type_drive);
+
+ /*
+ * Determine the type of tape controller. Type is determined by
+ * sending SCSI commands to tape drive and deriving the type from
+ * the returned data.
+ */
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_conf_from_tape_drive(): asking tape drive\n");
+
+ tem_dp = kmem_zalloc(sizeof (struct st_drivetype), KM_SLEEP);
+
+ /*
+ * Make up a name
+ */
+ bcopy(vidpid, tem_dp->name, VIDPIDLEN);
+ tem_dp->name[VIDPIDLEN] = '\0';
+ tem_dp->length = min(strlen(ST_INQUIRY->inq_vid), (VIDPIDLEN - 1));
+ (void) strncpy(tem_dp->vid, ST_INQUIRY->inq_vid, tem_dp->length);
+ /*
+ * 'clean' vendor and product strings of non-printing chars
+ */
+ for (i = 0; i < VIDPIDLEN - 1; i ++) {
+ if (tem_dp->name[i] < ' ' || tem_dp->name[i] > '~') {
+ tem_dp->name[i] = '.';
+ }
+ }
+
+ /*
+ * MODE SENSE to determine block size.
+ */
+ un->un_dp->options |= ST_MODE_SEL_COMP;
+ if (st_modesense(un)) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_conf_from_tape_drive(): fail to mode sense\n");
+ un->un_dp->options &= ~ST_MODE_SEL_COMP;
+ kmem_free(tem_dp, sizeof (struct st_drivetype));
+ return (0);
+ }
+
+ /* Can mode sense page 0x10 or 0xf */
+ tem_dp->options |= ST_MODE_SEL_COMP;
+ bsize = (un->un_mspl->high_bl << 16) |
+ (un->un_mspl->mid_bl << 8) |
+ (un->un_mspl->low_bl);
+
+ if (bsize == 0) {
+ tem_dp->options |= ST_VARIABLE;
+ tem_dp->bsize = 0;
+ } else if (bsize > ST_MAXRECSIZE_FIXED) {
+ if (st_change_block_size(un->un_dev, 0) != 0) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_conf_from_tape_drive(): "
+ "Fixed record size is too large and"
+ "cannot switch to variable record size");
+ kmem_free(tem_dp, sizeof (struct st_drivetype));
+ return (0);
+ }
+ tem_dp->options |= ST_VARIABLE;
+ } else if (st_change_block_size(un->un_dev, 0) == 0) {
+ tem_dp->options |= ST_VARIABLE;
+ tem_dp->bsize = 0;
+ } else {
+ tem_dp->bsize = bsize;
+ }
+
+ /*
+ * If READ BLOCk LIMITS works and upper block size limit is
+ * more than 64K, ST_NO_RECSIZE_LIMIT is supported.
+ */
+ blklim = kmem_zalloc(sizeof (struct read_blklim), KM_SLEEP);
+ if (st_read_block_limits(un, blklim) != 0) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_conf_from_tape_drive(): "
+ "fail to read block limits.\n");
+ kmem_free(blklim, sizeof (struct read_blklim));
+ kmem_free(tem_dp, sizeof (struct st_drivetype));
+ return (0);
+ }
+ maxbsize = (blklim->max_hi << 16) +
+ (blklim->max_mid << 8) + blklim->max_lo;
+ if (maxbsize > ST_MAXRECSIZE_VARIABLE) {
+ tem_dp->options |= ST_NO_RECSIZE_LIMIT;
+ }
+ kmem_free(blklim, sizeof (struct read_blklim));
+
+ /*
+ * Inquiry VPD page 0xb0 to see if the tape drive supports WORM
+ */
+ buf = kmem_zalloc(6, KM_SLEEP);
+ rval = st_get_special_inquiry(un, 6, buf, 0xb0);
+ if (rval != 0) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_conf_from_tape_drive(): "
+ "fail to read vitial inquiry.\n");
+ kmem_free(buf, 6);
+ kmem_free(tem_dp, sizeof (struct st_drivetype));
+ return (0);
+ }
+ if (buf[4] & 1) {
+ tem_dp->options |= ST_WORMABLE;
+ }
+ kmem_free(buf, 6);
+
+ /* Assume BSD BSR KNOWS_EOD */
+ tem_dp->options |= ST_BSF | ST_BSR | ST_KNOWS_EOD | ST_UNLOADABLE;
+ tem_dp->max_rretries = -1;
+ tem_dp->max_wretries = -1;
+
+ /*
+ * Decide the densities supported by tape drive by sending
+ * REPORT DENSITY SUPPORT command.
+ */
+ if (st_get_densities_from_tape_drive(un, tem_dp) == 0) {
+ kmem_free(tem_dp, sizeof (struct st_drivetype));
+ return (0);
+ }
+
+ /*
+ * Decide the timeout values for several commands by sending
+ * REPORT SUPPORTED OPERATION CODES command.
+ */
+ if (st_get_timeout_values_from_tape_drive(un, tem_dp) == 0) {
+ kmem_free(tem_dp, sizeof (struct st_drivetype));
+ return (0);
+ }
+
+ bcopy(tem_dp, dp, sizeof (struct st_drivetype));
+ kmem_free(tem_dp, sizeof (struct st_drivetype));
+ return (1);
+}
+
+static int
+st_get_densities_from_tape_drive(struct scsi_tape *un,
+ struct st_drivetype *dp)
+{
+ int i, p;
+ size_t buflen;
+ ushort_t des_len;
+ uchar_t *den_header;
+ uchar_t num_den;
+ uchar_t den[NDENSITIES];
+ uchar_t deflt[NDENSITIES];
+ struct report_density_desc *den_desc;
+
+ ST_FUNC(ST_DEVINFO, st_get_densities_from_type_drive);
+
+ /*
+ * Since we have no idea how many densitiy support entries
+ * will be returned, we send the command firstly assuming
+ * there is only one. Then we can decide the number of
+ * entries by available density support length. If multiple
+ * entries exist, we will resend the command with enough
+ * buffer size.
+ */
+ buflen = sizeof (struct report_density_header) +
+ sizeof (struct report_density_desc);
+ den_header = kmem_zalloc(buflen, KM_SLEEP);
+ if (st_report_density_support(un, den_header, buflen) != 0) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_conf_from_tape_drive(): fail to report density.\n");
+ kmem_free(den_header, buflen);
+ return (0);
+ }
+ des_len =
+ BE_16(((struct report_density_header *)den_header)->ava_dens_len);
+ num_den = (des_len - 2) / sizeof (struct report_density_desc);
+
+ if (num_den > 1) {
+ kmem_free(den_header, buflen);
+ buflen = sizeof (struct report_density_header) +
+ sizeof (struct report_density_desc) * num_den;
+ den_header = kmem_zalloc(buflen, KM_SLEEP);
+ if (st_report_density_support(un, den_header, buflen) != 0) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_conf_from_tape_drive(): "
+ "fail to report density.\n");
+ kmem_free(den_header, buflen);
+ return (0);
+ }
+ }
+
+ den_desc = (struct report_density_desc *)(den_header
+ + sizeof (struct report_density_header));
+
+ /*
+ * Decide the drive type by assigning organization
+ */
+ for (i = 0; i < ST_NUM_MEMBERS(st_vid_dt); i ++) {
+ if (strncmp(st_vid_dt[i].vid, (char *)(den_desc->ass_org),
+ 8) == 0) {
+ dp->type = st_vid_dt[i].type;
+ break;
+ }
+ }
+ if (i == ST_NUM_MEMBERS(st_vid_dt)) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_conf_from_tape_drive(): "
+ "can't find match of assigned ort.\n");
+ kmem_free(den_header, buflen);
+ return (0);
+ }
+
+ /*
+ * The tape drive may support many tape formats, but the st driver
+ * supports only the four highest densities. Since density code
+ * values are returned by ascending sequence, we start from the
+ * last entry of density support data block descriptor.
+ */
+ p = 0;
+ den_desc += num_den - 1;
+ for (i = 0; i < num_den && p < NDENSITIES; i ++, den_desc --) {
+ if ((den_desc->pri_den != 0) && (den_desc->wrtok)) {
+ if (p != 0) {
+ if (den_desc->pri_den >= den[p - 1]) {
+ continue;
+ }
+ }
+ den[p] = den_desc->pri_den;
+ deflt[p] = den_desc->deflt;
+ p ++;
+ }
+ }
+
+ switch (p) {
+ case 0:
+ bzero(dp->densities, NDENSITIES);
+ dp->options |= ST_AUTODEN_OVERRIDE;
+ dp->default_density = MT_DENSITY4;
+ break;
+
+ case 1:
+ (void) memset(dp->densities, den[0], NDENSITIES);
+ dp->options |= ST_AUTODEN_OVERRIDE;
+ dp->default_density = MT_DENSITY4;
+ break;
+
+ case 2:
+ dp->densities[0] = den[1];
+ dp->densities[1] = den[1];
+ dp->densities[2] = den[0];
+ dp->densities[3] = den[0];
+ if (deflt[0]) {
+ dp->default_density = MT_DENSITY4;
+ } else {
+ dp->default_density = MT_DENSITY2;
+ }
+ break;
+
+ case 3:
+ dp->densities[0] = den[2];
+ dp->densities[1] = den[1];
+ dp->densities[2] = den[0];
+ dp->densities[3] = den[0];
+ if (deflt[0]) {
+ dp->default_density = MT_DENSITY4;
+ } else if (deflt[1]) {
+ dp->default_density = MT_DENSITY2;
+ } else {
+ dp->default_density = MT_DENSITY1;
+ }
+ break;
+
+ default:
+ for (i = p; i > p - NDENSITIES; i --) {
+ dp->densities[i - 1] = den[p - i];
+ }
+ if (deflt[0]) {
+ dp->default_density = MT_DENSITY4;
+ } else if (deflt[1]) {
+ dp->default_density = MT_DENSITY3;
+ } else if (deflt[2]) {
+ dp->default_density = MT_DENSITY2;
+ } else {
+ dp->default_density = MT_DENSITY1;
+ }
+ break;
+ }
+
+ bzero(dp->mediatype, NDENSITIES);
+
+ kmem_free(den_header, buflen);
+ return (1);
+}
+
+static int
+st_get_timeout_values_from_tape_drive(struct scsi_tape *un,
+ struct st_drivetype *dp)
+{
+ ushort_t timeout;
+
+ ST_FUNC(ST_DEVINFO, st_get_timeout_values_from_type_drive);
+
+ if (st_get_timeouts_value(un, SCMD_ERASE, &timeout, 0) != 0) {
+ return (0);
+ }
+ dp->erase_timeout = timeout;
+
+ if (st_get_timeouts_value(un, SCMD_READ, &timeout, 0) != 0) {
+ return (0);
+ }
+ dp->io_timeout = timeout;
+
+ if (st_get_timeouts_value(un, SCMD_WRITE, &timeout, 0) != 0) {
+ return (0);
+ }
+ dp->io_timeout = max(dp->io_timeout, timeout);
+
+ if (st_get_timeouts_value(un, SCMD_SPACE, &timeout, 0) != 0) {
+ return (0);
+ }
+ dp->space_timeout = timeout;
+
+ if (st_get_timeouts_value(un, SCMD_LOAD, &timeout, 0) != 0) {
+ return (0);
+ }
+ dp->load_timeout = timeout;
+ dp->unload_timeout = timeout;
+
+ if (st_get_timeouts_value(un, SCMD_REWIND, &timeout, 0) != 0) {
+ return (0);
+ }
+ dp->rewind_timeout = timeout;
+
+ if (st_get_timeouts_value(un, SCMD_INQUIRY, &timeout, 0) != 0) {
+ return (0);
+ }
+ dp->non_motion_timeout = timeout;
+
+ return (1);
+}
+
+static int
+st_get_timeouts_value(struct scsi_tape *un, uchar_t option_code,
+ ushort_t *timeout_value, ushort_t service_action)
+{
+ uchar_t *timeouts;
+ uchar_t *oper;
+ uchar_t support;
+ uchar_t cdbsize;
+ uchar_t ctdp;
+ size_t buflen;
+ int rval;
+
+ ST_FUNC(ST_DEVINFO, st_get_timeouts_value);
+
+ buflen = sizeof (struct one_com_des) +
+ sizeof (struct com_timeout_des);
+ oper = kmem_zalloc(buflen, KM_SLEEP);
+ rval = st_report_supported_operation(un, oper, option_code,
+ service_action);
+
+ if (rval != 0) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_timeouts_value(): "
+ "fail to timeouts value for command %d.\n", option_code);
+ kmem_free(oper, buflen);
+ return (rval);
+ }
+
+ support = ((struct one_com_des *)oper)->support;
+ if ((support != SUPPORT_VALUES_SUPPORT_SCSI) &&
+ (support != SUPPORT_VALUES_SUPPORT_VENDOR)) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_timeouts_value(): "
+ "command %d is not supported.\n", option_code);
+ kmem_free(oper, buflen);
+ return (-1);
+ }
+
+ ctdp = ((struct one_com_des *)oper)->ctdp;
+ if (!ctdp) {
+ ST_DEBUG2(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_timeouts_value(): "
+ "command timeout is not included.\n");
+ kmem_free(oper, buflen);
+ return (-1);
+ }
+
+ cdbsize = BE_16(((struct one_com_des *)oper)->cdb_size);
+ timeouts = (uchar_t *)(oper + cdbsize + 4);
+
+ /*
+ * Timeout value in seconds is 4 bytes, but we only support the lower 2
+ * bytes. If the higher 2 bytes are not zero, the timeout value is set
+ * to 0xFFFF.
+ */
+ if (*(timeouts + 8) != 0 || *(timeouts + 9) != 0) {
+ *timeout_value = USHRT_MAX;
+ } else {
+ *timeout_value = ((*(timeouts + 10)) << 8) |
+ (*(timeouts + 11));
+ }
+
+ kmem_free(oper, buflen);
+ return (0);
+}
+
+static int
st_get_default_conf(struct scsi_tape *un, char *vidpid, struct st_drivetype *dp)
{
int i;
@@ -2035,7 +2485,6 @@ st_get_default_conf(struct scsi_tape *un, char *vidpid, struct st_drivetype *dp)
ST_DEBUG6(ST_DEVINFO, st_label, SCSI_DEBUG,
"st_get_default_conf(): making drivetype from INQ cmd\n");
-
/*
* Make up a name
*/
@@ -7414,6 +7863,117 @@ st_gen_mode_select(struct scsi_tape *un, struct seq_mode *page_data,
return (r);
}
+static int
+st_read_block_limits(struct scsi_tape *un, struct read_blklim *read_blk)
+{
+ int rval;
+ char cdb[CDB_GROUP0];
+ struct uscsi_cmd *com;
+
+ ST_FUNC(ST_DEVINFO, st_read_block_limits);
+
+ com = kmem_zalloc(sizeof (*com), KM_SLEEP);
+
+ bzero(cdb, CDB_GROUP0);
+ cdb[0] = SCMD_READ_BLKLIM;
+
+ com->uscsi_cdb = cdb;
+ com->uscsi_cdblen = CDB_GROUP0;
+ com->uscsi_bufaddr = (caddr_t)read_blk;
+ com->uscsi_buflen = sizeof (struct read_blklim);
+ com->uscsi_timeout = un->un_dp->non_motion_timeout;
+ com->uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ;
+
+ rval = st_ioctl_cmd(un->un_dev, com, FKIOCTL);
+ if (com->uscsi_status || com->uscsi_resid) {
+ rval = -1;
+ }
+
+ kmem_free(com, sizeof (*com));
+ return (rval);
+}
+
+static int
+st_report_density_support(struct scsi_tape *un, uchar_t *density_data,
+ size_t buflen)
+{
+ int rval;
+ char cdb[CDB_GROUP1];
+ struct uscsi_cmd *com;
+
+ ST_FUNC(ST_DEVINFO, st_report_density_support);
+
+ com = kmem_zalloc(sizeof (*com), KM_SLEEP);
+
+ bzero(cdb, CDB_GROUP1);
+ cdb[0] = SCMD_REPORT_DENSITIES;
+ cdb[7] = (buflen & 0xff00) >> 8;
+ cdb[8] = buflen & 0xff;
+
+ com->uscsi_cdb = cdb;
+ com->uscsi_cdblen = CDB_GROUP1;
+ com->uscsi_bufaddr = (caddr_t)density_data;
+ com->uscsi_buflen = buflen;
+ com->uscsi_timeout = un->un_dp->non_motion_timeout;
+ com->uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ;
+
+ rval = st_ioctl_cmd(un->un_dev, com, FKIOCTL);
+ if (com->uscsi_status || com->uscsi_resid) {
+ rval = -1;
+ }
+
+ kmem_free(com, sizeof (*com));
+ return (rval);
+}
+
+static int
+st_report_supported_operation(struct scsi_tape *un, uchar_t *oper_data,
+ uchar_t option_code, ushort_t service_action)
+{
+ int rval;
+ char cdb[CDB_GROUP5];
+ struct uscsi_cmd *com;
+ uint32_t allo_length;
+
+ ST_FUNC(ST_DEVINFO, st_report_supported_operation);
+
+ allo_length = sizeof (struct one_com_des) +
+ sizeof (struct com_timeout_des);
+ com = kmem_zalloc(sizeof (*com), KM_SLEEP);
+
+ bzero(cdb, CDB_GROUP5);
+ cdb[0] = (char)SCMD_REPORT_TARGET_PORT_GROUPS;
+ cdb[1] = 0x0c; /* service action */
+ if (service_action) {
+ cdb[2] = (char)(ONE_COMMAND_DATA_FORMAT | 0x80); /* RCTD */
+ cdb[4] = (service_action & 0xff00) >> 8;
+ cdb[5] = service_action & 0xff;
+ } else {
+ cdb[2] = (char)(ONE_COMMAND_NO_SERVICE_DATA_FORMAT |
+ 0x80); /* RCTD */
+ }
+ cdb[3] = option_code;
+ cdb[6] = (allo_length & 0xff000000) >> 24;
+ cdb[7] = (allo_length & 0xff0000) >> 16;
+ cdb[8] = (allo_length & 0xff00) >> 8;
+ cdb[9] = allo_length & 0xff;
+
+ com->uscsi_cdb = cdb;
+ com->uscsi_cdblen = CDB_GROUP5;
+ com->uscsi_bufaddr = (caddr_t)oper_data;
+ com->uscsi_buflen = allo_length;
+ com->uscsi_timeout = un->un_dp->non_motion_timeout;
+ com->uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT | USCSI_READ;
+
+ rval = st_ioctl_cmd(un->un_dev, com, FKIOCTL);
+ if (com->uscsi_status) {
+ rval = -1;
+ }
+
+ kmem_free(com, sizeof (*com));
+ return (rval);
+}
+
/*
* Changes devices blocksize and bsize to requested blocksize nblksz.
* Returns returned value from first failed call or zero on success.
diff --git a/usr/src/uts/common/io/scsi/targets/st_conf.c b/usr/src/uts/common/io/scsi/targets/st_conf.c
index ae292f6856..2868db903b 100644
--- a/usr/src/uts/common/io/scsi/targets/st_conf.c
+++ b/usr/src/uts/common/io/scsi/targets/st_conf.c
@@ -2226,46 +2226,6 @@ const struct st_drivetype st_drivetypes[] =
},
/*
- * STC 3490 1/2" cartridge
- *
- * NOTES
- * -----
- * o This is an unsupported drive.
- *
- * o This is the generic StorageTek (STK) entry. Any special or drive
- * specific entries must be placed ahead of this entry in the file, to
- * ensure that the driver will "see" and use them; otherwise this entry
- * will be used as the default.
- *
- * [1] The STC 3490 uses 0 or "default" for the desnity code.
- * [2] The STC 3490 has only one speed (if the driver ever cares).
- * [3] max_rretries and max_wretries are driver anachronisms.
- */
- { /* Structure member Description */
- /* ---------------- ----------- */
- "STK 1/2\" Cartridge", /* .name Display ("pretty") name */
- 3, /* .length Length of next item... */
- "STK", /* .vid Vendor-product ID string */
- ST_TYPE_STC3490, /* .type Numeric type (cf. mtio.h) */
- 0, /* .bsize Block size (0 = variable) */
- ST_VARIABLE | /* 00001 Supports variable length */
- ST_REEL | /* 00004 1/2-inch reel tape device */
- ST_BSF | /* 00008 Supports SPACE block fwd */
- ST_BSR | /* 00010 Supports SPACE block rev */
- ST_LONG_ERASE | /* 00020 Needs extra time to erase */
- ST_UNLOADABLE | /* 00400 Driver can be unloaded */
- ST_NO_RECSIZE_LIMIT | /* 08000 Supports blocks > 64KB */
- ST_MODE_SEL_COMP, /* 10000 [Note 1] */
- /* ----- */
- /* 1843D */
- 400, /* .max_rretries [Note 3] */
- 400, /* .max_wretries [Note 3] */
- {0x00, 0x00, 0x00, 0x00}, /* .densities Density codes [Note 1] */
- MT_DENSITY1, /* .default_density (.densities[x]) */
- {0, 0, 0, 0} /* .speeds Speed codes [Note 2] */
- },
-
- /*
* Sony SAIT
*
* Only looking at part of the product ID so it will match SDZ-100 and
diff --git a/usr/src/uts/common/io/warlock/scsa2usb_with_usba.wlcmd b/usr/src/uts/common/io/warlock/scsa2usb_with_usba.wlcmd
index 115d9934dc..1d6d3b0638 100644
--- a/usr/src/uts/common/io/warlock/scsa2usb_with_usba.wlcmd
+++ b/usr/src/uts/common/io/warlock/scsa2usb_with_usba.wlcmd
@@ -229,6 +229,7 @@ add __ddi_xbuf_attr::xa_strategy targets sd_xbuf_strategy
add st.c:st_known_tape_type/config_funct targets \
st_get_conf_from_st_dot_conf \
st_get_conf_from_st_conf_dot_c \
+ st_get_conf_from_tape_drive \
st_get_default_conf
diff --git a/usr/src/uts/common/io/warlock/st.wlcmd b/usr/src/uts/common/io/warlock/st.wlcmd
index 6df65de5c2..051c0608ef 100644
--- a/usr/src/uts/common/io/warlock/st.wlcmd
+++ b/usr/src/uts/common/io/warlock/st.wlcmd
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -39,6 +39,7 @@ add scsi_watch_request::swr_callback targets st_media_watch_cb
add st.c:st_known_tape_type/config_funct targets \
st_get_conf_from_st_dot_conf \
st_get_conf_from_st_conf_dot_c \
+ st_get_conf_from_tape_drive \
st_get_default_conf
root scsi_hba_bus_power
diff --git a/usr/src/uts/common/io/warlock/st_with_esp.wlcmd b/usr/src/uts/common/io/warlock/st_with_esp.wlcmd
index c1b88dc88b..8826920ac6 100644
--- a/usr/src/uts/common/io/warlock/st_with_esp.wlcmd
+++ b/usr/src/uts/common/io/warlock/st_with_esp.wlcmd
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -35,6 +35,7 @@ add esp_cmd::cmd_pkt.pkt_comp targets \
add st.c:st_known_tape_type/config_funct targets \
st_get_conf_from_st_dot_conf \
st_get_conf_from_st_conf_dot_c \
+ st_get_conf_from_tape_drive \
st_get_default_conf
one scsi_device
diff --git a/usr/src/uts/common/io/warlock/st_with_fas.wlcmd b/usr/src/uts/common/io/warlock/st_with_fas.wlcmd
index e93a3adfd3..cd1deb4379 100644
--- a/usr/src/uts/common/io/warlock/st_with_fas.wlcmd
+++ b/usr/src/uts/common/io/warlock/st_with_fas.wlcmd
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -47,6 +47,7 @@ add notify_entry::callback target warlock_dummy
add st.c:st_known_tape_type/config_funct targets \
st_get_conf_from_st_dot_conf \
st_get_conf_from_st_conf_dot_c \
+ st_get_conf_from_tape_drive \
st_get_default_conf
one scsi_device
diff --git a/usr/src/uts/common/io/warlock/st_with_glm.wlcmd b/usr/src/uts/common/io/warlock/st_with_glm.wlcmd
index 428eab11af..d31bbdc0e2 100644
--- a/usr/src/uts/common/io/warlock/st_with_glm.wlcmd
+++ b/usr/src/uts/common/io/warlock/st_with_glm.wlcmd
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -49,6 +49,7 @@ add notify_entry::callback target warlock_dummy
add st.c:st_known_tape_type/config_funct targets \
st_get_conf_from_st_dot_conf \
st_get_conf_from_st_conf_dot_c \
+ st_get_conf_from_tape_drive \
st_get_default_conf
one scsi_device
diff --git a/usr/src/uts/common/io/warlock/st_with_isp.wlcmd b/usr/src/uts/common/io/warlock/st_with_isp.wlcmd
index 8a96fe195a..ca91257e19 100644
--- a/usr/src/uts/common/io/warlock/st_with_isp.wlcmd
+++ b/usr/src/uts/common/io/warlock/st_with_isp.wlcmd
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -35,6 +35,7 @@ add scsi_pkt::pkt_comp targets \
add st.c:st_known_tape_type/config_funct targets \
st_get_conf_from_st_dot_conf \
st_get_conf_from_st_conf_dot_c \
+ st_get_conf_from_tape_drive \
st_get_default_conf
one scsi_device
diff --git a/usr/src/uts/common/sys/mtio.h b/usr/src/uts/common/sys/mtio.h
index 4d1969027e..baa210fc6a 100644
--- a/usr/src/uts/common/sys/mtio.h
+++ b/usr/src/uts/common/sys/mtio.h
@@ -348,6 +348,7 @@ enum mtio_state { MTIO_NONE, MTIO_EJECTED, MTIO_INSERTED };
#define MT_BSD (1 <<6) /* BSD behavior on close */
#define MT_DENSITY(dev) ((getminor(dev) & MT_DENSITY_MASK) >> 3)
+#define MT_TEM_DEV(inst) (((inst) & 0x3) | (((inst) & 0xfc) << 5))
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/scsi/targets/stdef.h b/usr/src/uts/common/sys/scsi/targets/stdef.h
index 3b928223df..76ff9172ab 100644
--- a/usr/src/uts/common/sys/scsi/targets/stdef.h
+++ b/usr/src/uts/common/sys/scsi/targets/stdef.h
@@ -567,6 +567,106 @@ struct seq_mode {
};
/*
+ * One_command parameter data for REPORT SUPPORTED OPERATION CODES.
+ */
+struct one_com_des {
+#if defined(_BIT_FIELDS_LTOH)
+ uchar_t reserved0;
+ uchar_t support: 3, /* support value */
+ reserved1: 4,
+ ctdp: 1; /* cmd timeouts descriptor present */
+ ushort_t cdb_size; /* cdb size */
+ uchar_t usage[CDB_GROUP4]; /* 16 bytes, the largest CDB group */
+#elif defined(_BIT_FIELDS_HTOL)
+ uchar_t reserved0;
+ uchar_t ctdp: 1, /* cmd timeouts descriptor present */
+ reserved1: 4,
+ support: 3; /* support value */
+ ushort_t cdb_size; /* cdb size */
+ uchar_t usage[CDB_GROUP4]; /* 16 bytes, the largest CDB group */
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif /* _BIT_FIELDS_LTOH */
+};
+
+/*
+ * Command timeouts descriptor
+ */
+struct com_timeout_des {
+ ushort_t des_len; /* descriptor length */
+ uchar_t reserved;
+ uchar_t com_spe; /* command specific */
+ uint_t nom_timeout; /* nominal command processing timeout */
+ uint_t rec_timeout; /* recommended command timeout */
+};
+
+/*
+ * Reporting options
+ */
+#define ALL_COMMAND_DATA_FORMAT 0
+#define ONE_COMMAND_NO_SERVICE_DATA_FORMAT 1
+#define ONE_COMMAND_DATA_FORMAT 2
+
+/*
+ * Support values in One_command parameter data
+ */
+#define SUPPORT_VALUES_NOT_AVAILABLE 0
+#define SUPPORT_VALUES_NOT_SUPPORT 1
+#define SUPPORT_VALUES_SUPPORT_SCSI 3
+#define SUPPORT_VALUES_SUPPORT_VENDOR 5
+
+/*
+ * Parameter data for REPORT DENSITY SUPPORT command
+ */
+struct report_density_header {
+ ushort_t ava_dens_len; /* available density support length */
+ uchar_t reserved0;
+ uchar_t reserved1;
+};
+
+struct report_density_desc {
+#if defined(_BIT_FIELDS_LTOH)
+ uchar_t pri_den; /* primary density code */
+ uchar_t sec_den; /* secondary density code */
+ uchar_t dlv:1; /* descriptor length valid */
+ uchar_t reserved:4;
+ uchar_t deflt:1; /* is default density */
+ uchar_t dup:1; /* pri density has one descriptor */
+ uchar_t wrtok:1; /* support writing to media */
+ uchar_t desc_len_hi; /* descriptor length high */
+ uchar_t desc_len_low; /* descriptor length low */
+ uchar_t bits_per_mm[3]; /* bits per mm */
+ uchar_t media_width_hi; /* media width high */
+ uchar_t media_width_low; /* media width low */
+ ushort_t tracks; /* tracks */
+ uint_t capacity; /* capacity */
+ uchar_t ass_org[8]; /* assigning organization */
+ uchar_t den_name[8]; /* density name */
+ uchar_t description[20]; /* description */
+#elif defined(_BIT_FIELDS_HTOL)
+ uchar_t pri_den; /* primary density code */
+ uchar_t sec_den; /* secondary density code */
+ uchar_t wrtok:1; /* support writing to media */
+ uchar_t dup:1; /* pri density has one descriptor */
+ uchar_t deflt:1; /* is default density */
+ uchar_t reserved:4;
+ uchar_t dlv:1; /* descriptor length valid */
+ uchar_t desc_len_hi; /* descriptor length high */
+ uchar_t desc_len_low; /* descriptor length low */
+ uchar_t bits_per_mm[3]; /* bits per mm */
+ uchar_t media_width_hi; /* media width high */
+ uchar_t media_width_low; /* media width low */
+ ushort_t tracks; /* tracks */
+ uint_t capacity; /* capacity */
+ uchar_t ass_org[8]; /* assigning organization */
+ uchar_t den_name[8]; /* density name */
+ uchar_t description[20]; /* description */
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif /* _BIT_FIELDS_LTOH */
+};
+
+/*
* Data returned from the READ BLOCK LIMITS command.
*/