summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorbz211116 <none@none>2007-09-17 16:36:08 -0700
committerbz211116 <none@none>2007-09-17 16:36:08 -0700
commitfa4c0ec88d821f9e87d85b91dc865065b1ec2b52 (patch)
treeee42d1da5cab7d89ae6136aafbfa17cf717afb52 /usr/src
parent3aedfe0b5d40c671717b8bec3135984b90d27349 (diff)
downloadillumos-joyent-fa4c0ec88d821f9e87d85b91dc865065b1ec2b52.tar.gz
PSARC/2007/469 MTIOCGETERROR
6540759 New IOCTL interfaces needed in st for SMMS
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/scsi/targets/st.c352
-rw-r--r--usr/src/uts/common/sys/mtio.h37
-rw-r--r--usr/src/uts/common/sys/scsi/targets/stdef.h2
3 files changed, 388 insertions, 3 deletions
diff --git a/usr/src/uts/common/io/scsi/targets/st.c b/usr/src/uts/common/io/scsi/targets/st.c
index 1d9a42ead9..7deb82e1ff 100644
--- a/usr/src/uts/common/io/scsi/targets/st.c
+++ b/usr/src/uts/common/io/scsi/targets/st.c
@@ -475,7 +475,11 @@ static int st_check_error(struct scsi_tape *un, struct scsi_pkt *pkt);
static int st_handle_sense(struct scsi_tape *un, struct buf *bp);
static int st_handle_autosense(struct scsi_tape *un, struct buf *bp);
static int st_decode_sense(struct scsi_tape *un, struct buf *bp, int amt,
- struct scsi_status *);
+ struct scsi_status *);
+static int st_get_error_entry(struct scsi_tape *un, intptr_t arg, int flag);
+static void st_update_error_stack(struct scsi_tape *un, struct scsi_pkt *pkt,
+ struct scsi_arq_status *cmd);
+static void st_empty_error_stack(struct scsi_tape *un);
static int st_report_soft_errors(dev_t dev, int flag);
static void st_delayed_cv_broadcast(void *arg);
static int st_check_media(dev_t dev, enum mtio_state state);
@@ -939,7 +943,6 @@ st_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
((scsi_ifsetcap(ROUTE, "auto-rqsense", 1, 1) == 1) ? 1 : 0);
}
-
ST_DEBUG(devi, st_label, SCSI_DEBUG, "auto request sense %s\n",
(un->un_arq_enabled ? "enabled" : "disabled"));
@@ -2150,6 +2153,11 @@ st_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
*/
un->un_state = ST_STATE_OPENING;
+ /*
+ * Clear error entry stack
+ */
+ st_empty_error_stack(un);
+
rval = st_tape_init(dev);
if ((rval == EACCES) && (un->un_read_only & WORM)) {
un->un_state = ST_STATE_OPEN_PENDING_IO;
@@ -3102,6 +3110,11 @@ st_rw(dev_t dev, struct uio *uio, int flag)
mutex_enter(ST_MUTEX);
/*
+ * Clear error entry stack
+ */
+ st_empty_error_stack(un);
+
+ /*
* If in fixed block size mode and requested read or write
* is not an even multiple of that block size.
*/
@@ -3987,6 +4000,15 @@ st_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
}
/*
+ * We clear error entry stack except command
+ * MTIOCGETERROR and MTIOCGET
+ */
+ if ((cmd != MTIOCGETERROR) &&
+ (cmd != MTIOCGET)) {
+ st_empty_error_stack(un);
+ }
+
+ /*
* wait for all outstanding commands to complete, or be dequeued.
* And because ioctl's are synchronous commands, any return value
* after this, will be in order
@@ -4157,6 +4179,17 @@ check_commands:
break;
}
+ case MTIOCGETERROR:
+ /*
+ * get error entry from error stack
+ */
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_ioctl: MTIOCGETERROR\n");
+
+ rval = st_get_error_entry(un, arg, flag);
+
+ break;
+
case MTIOCSTATE:
{
/*
@@ -8816,10 +8849,305 @@ exit:
return (rval);
}
+/*
+ * To get one error entry from error stack
+ */
+static int
+st_get_error_entry(struct scsi_tape *un, intptr_t arg, int flag)
+{
+#ifdef _MULTI_DATAMODEL
+ /*
+ * For use when a 32 bit app makes a call into a
+ * 64 bit ioctl
+ */
+ struct mterror_entry32 err_entry32;
+#endif /* _MULTI_DATAMODEL */
+
+ int rval = 0;
+ struct mterror_entry err_entry;
+ struct mterror_entry_stack *err_link_entry_p;
+ size_t arq_status_len_in, arq_status_len_kr;
+
+ ST_FUNC(ST_DEVINFO, st_get_error_entry);
+
+ ASSERT(mutex_owned(ST_MUTEX));
+
+ ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry()\n");
+
+ /*
+ * if error record stack empty, return ENXIO
+ */
+ if (un->un_error_entry_stk == NULL) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: Error Entry Stack Empty!\n");
+ rval = ENXIO;
+ goto ret;
+ }
+
+ /*
+ * get the top entry from stack
+ */
+ err_link_entry_p = un->un_error_entry_stk;
+ arq_status_len_kr =
+ err_link_entry_p->mtees_entry.mtee_arq_status_len;
+
+#ifdef _MULTI_DATAMODEL
+ switch (ddi_model_convert_from(flag & FMODELS)) {
+ case DDI_MODEL_ILP32:
+ if (ddi_copyin((void *)arg, &err_entry32,
+ MTERROR_ENTRY_SIZE_32, flag)) {
+ rval = EFAULT;
+ goto ret;
+ }
+
+ arq_status_len_in =
+ (size_t)err_entry32.mtee_arq_status_len;
+
+ err_entry32.mtee_cdb_len =
+ (size32_t)err_link_entry_p->mtees_entry.mtee_cdb_len;
+
+ if (arq_status_len_in > arq_status_len_kr)
+ err_entry32.mtee_arq_status_len =
+ (size32_t)arq_status_len_kr;
+
+ if (ddi_copyout(
+ err_link_entry_p->mtees_entry.mtee_cdb_buf,
+ (void *)(uintptr_t)err_entry32.mtee_cdb_buf,
+ err_entry32.mtee_cdb_len, flag)) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: Copy cdb buffer error!");
+ rval = EFAULT;
+ }
+
+ if (ddi_copyout(
+ err_link_entry_p->mtees_entry.mtee_arq_status,
+ (void *)(uintptr_t)err_entry32.mtee_arq_status,
+ err_entry32.mtee_arq_status_len, flag)) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: copy arq status error!");
+ rval = EFAULT;
+ }
+
+ if (ddi_copyout(&err_entry32, (void *)arg,
+ MTERROR_ENTRY_SIZE_32, flag)) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: copy arq status out error!");
+ rval = EFAULT;
+ }
+ break;
+
+ case DDI_MODEL_NONE:
+ if (ddi_copyin((void *)arg, &err_entry,
+ MTERROR_ENTRY_SIZE_64, flag)) {
+ rval = EFAULT;
+ goto ret;
+ }
+ arq_status_len_in = err_entry.mtee_arq_status_len;
+
+ err_entry.mtee_cdb_len =
+ err_link_entry_p->mtees_entry.mtee_cdb_len;
+
+ if (arq_status_len_in > arq_status_len_kr)
+ err_entry.mtee_arq_status_len =
+ arq_status_len_kr;
+
+ if (ddi_copyout(
+ err_link_entry_p->mtees_entry.mtee_cdb_buf,
+ err_entry.mtee_cdb_buf,
+ err_entry.mtee_cdb_len, flag)) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: Copy cdb buffer error!");
+ rval = EFAULT;
+ }
+
+ if (ddi_copyout(
+ err_link_entry_p->mtees_entry.mtee_arq_status,
+ err_entry.mtee_arq_status,
+ err_entry.mtee_arq_status_len, flag)) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: copy arq status error!");
+ rval = EFAULT;
+ }
+
+ if (ddi_copyout(&err_entry, (void *)arg,
+ MTERROR_ENTRY_SIZE_64, flag)) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: copy arq status out error!");
+ rval = EFAULT;
+ }
+ break;
+ }
+#else /* _MULTI_DATAMODEL */
+ if (ddi_copyin((void *)arg, &err_entry,
+ MTERROR_ENTRY_SIZE_64, flag)) {
+ rval = EFAULT;
+ goto ret;
+ }
+ arq_status_len_in = err_entry.mtee_arq_status_len;
+
+ err_entry.mtee_cdb_len =
+ err_link_entry_p->mtees_entry.mtee_cdb_len;
+
+ if (arq_status_len_in > arq_status_len_kr)
+ err_entry.mtee_arq_status_len =
+ arq_status_len_kr;
+
+ if (ddi_copyout(
+ err_link_entry_p->mtees_entry.mtee_cdb_buf,
+ err_entry.mtee_cdb_buf,
+ err_entry.mtee_cdb_len, flag)) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: Copy cdb buffer error!");
+ rval = EFAULT;
+ }
+
+ if (ddi_copyout(
+ err_link_entry_p->mtees_entry.mtee_arq_status,
+ err_entry.mtee_arq_status,
+ err_entry.mtee_arq_status_len, flag)) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: copy arq status buffer error!");
+ rval = EFAULT;
+ }
+
+ if (ddi_copyout(&err_entry, (void *)arg,
+ MTERROR_ENTRY_SIZE_64, flag)) {
+ ST_DEBUG4(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_get_error_entry: copy arq status out error!");
+ rval = EFAULT;
+ }
+#endif /* _MULTI_DATAMODEL */
+
+ /*
+ * update stack
+ */
+ un->un_error_entry_stk = err_link_entry_p->mtees_nextp;
+
+ kmem_free(err_link_entry_p->mtees_entry.mtee_cdb_buf,
+ err_link_entry_p->mtees_entry.mtee_cdb_len);
+ err_link_entry_p->mtees_entry.mtee_cdb_buf = NULL;
+
+ kmem_free(err_link_entry_p->mtees_entry.mtee_arq_status,
+ SECMDS_STATUS_SIZE);
+ err_link_entry_p->mtees_entry.mtee_arq_status = NULL;
+
+ kmem_free(err_link_entry_p, MTERROR_LINK_ENTRY_SIZE);
+ err_link_entry_p = NULL;
+ret:
+ return (rval);
+}
+
+/*
+ * MTIOCGETERROR ioctl needs to retrieve the current sense data along with
+ * the scsi CDB command which causes the error and generates sense data and
+ * the scsi status.
+ *
+ * error-record stack
+ *
+ *
+ * TOP BOTTOM
+ * ------------------------------------------
+ * | 0 | 1 | 2 | ... | n |
+ * ------------------------------------------
+ * ^
+ * |
+ * pointer to error entry
+ *
+ * when st driver generates one sense data record, it creates a error-entry
+ * and pushes it onto the stack.
+ *
+ */
+
+static void
+st_update_error_stack(struct scsi_tape *un,
+ struct scsi_pkt *pkt,
+ struct scsi_arq_status *cmd)
+{
+ struct mterror_entry_stack *err_entry_tmp;
+ uchar_t *cdbp = (uchar_t *)pkt->pkt_cdbp;
+ size_t cdblen = scsi_cdb_size[CDB_GROUPID(cdbp[0])];
+
+ ST_FUNC(ST_DEVINFO, st_update_error_stack);
+
+ ASSERT(mutex_owned(ST_MUTEX));
+
+ ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_update_error_stack()\n");
+
+ ASSERT(cmd);
+ ASSERT(cdbp);
+ if (cdblen == 0) {
+ ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_update_error_stack: CDB length error!\n");
+ return;
+ }
+
+ err_entry_tmp = kmem_alloc(MTERROR_LINK_ENTRY_SIZE, KM_SLEEP);
+ ASSERT(err_entry_tmp != NULL);
+
+ err_entry_tmp->mtees_entry.mtee_cdb_buf =
+ kmem_alloc(cdblen, KM_SLEEP);
+ ASSERT(err_entry_tmp->mtees_entry.mtee_cdb_buf != NULL);
+
+ err_entry_tmp->mtees_entry.mtee_arq_status =
+ kmem_alloc(SECMDS_STATUS_SIZE, KM_SLEEP);
+ ASSERT(err_entry_tmp->mtees_entry.mtee_arq_status != NULL);
+
+ /*
+ * copy cdb command & length to current error entry
+ */
+ err_entry_tmp->mtees_entry.mtee_cdb_len = cdblen;
+ bcopy(cdbp, err_entry_tmp->mtees_entry.mtee_cdb_buf, cdblen);
+
+ /*
+ * copy scsi status length to current error entry
+ */
+ err_entry_tmp->mtees_entry.mtee_arq_status_len =
+ SECMDS_STATUS_SIZE;
+
+ /*
+ * copy sense data and scsi status to current error entry
+ */
+ bcopy(cmd, err_entry_tmp->mtees_entry.mtee_arq_status,
+ SECMDS_STATUS_SIZE);
+
+ err_entry_tmp->mtees_nextp = un->un_error_entry_stk;
+ un->un_error_entry_stk = err_entry_tmp;
+
+}
+
+/*
+ * Empty all the error entry in stack
+ */
+static void
+st_empty_error_stack(struct scsi_tape *un)
+{
+ struct mterror_entry_stack *linkp;
+
+ ST_FUNC(ST_DEVINFO, st_empty_error_stack);
+
+ ASSERT(mutex_owned(ST_MUTEX));
+
+ ST_DEBUG3(ST_DEVINFO, st_label, SCSI_DEBUG,
+ "st_empty_entry_stack()\n");
+
+ while (un->un_error_entry_stk != NULL) {
+ linkp = un->un_error_entry_stk;
+ un->un_error_entry_stk =
+ un->un_error_entry_stk->mtees_nextp;
+ kmem_free(linkp, MTERROR_LINK_ENTRY_SIZE);
+ linkp = NULL;
+ }
+}
+
static int
st_handle_sense(struct scsi_tape *un, struct buf *bp)
{
+ struct scsi_pkt *pkt = BP_PKT(bp);
struct scsi_pkt *rqpkt = un->un_rqs;
+ struct scsi_arq_status arqstat;
+
int rval = COMMAND_DONE_ERROR;
int amt;
@@ -8851,6 +9179,21 @@ st_handle_sense(struct scsi_tape *un, struct buf *bp)
"REQUEST SENSE couldn't get sense data\n");
return (rval);
}
+
+ bcopy(SCBP(pkt), &arqstat.sts_status,
+ sizeof (struct scsi_status));
+ bcopy(SCBP(rqpkt), &arqstat.sts_rqpkt_status,
+ sizeof (struct scsi_status));
+ arqstat.sts_rqpkt_reason = rqpkt->pkt_reason;
+ arqstat.sts_rqpkt_resid = rqpkt->pkt_resid;
+ arqstat.sts_rqpkt_state = rqpkt->pkt_state;
+ arqstat.sts_rqpkt_statistics = rqpkt->pkt_statistics;
+ bcopy(ST_RQSENSE, &arqstat.sts_sensedata, SENSE_LENGTH);
+
+ /*
+ * copy one arqstat entry in the sense data buffer
+ */
+ st_update_error_stack(un, pkt, &arqstat);
return (st_decode_sense(un, bp, amt, SCBP(rqpkt)));
}
@@ -8917,6 +9260,11 @@ st_handle_autosense(struct scsi_tape *un, struct buf *bp)
return (rval);
}
+ /*
+ * copy one arqstat entry in the sense data buffer
+ */
+ st_update_error_stack(un, pkt, arqstat);
+
bcopy(&arqstat->sts_sensedata, ST_RQSENSE, SENSE_LENGTH);
return (st_decode_sense(un, bp, amt, &arqstat->sts_rqpkt_status));
diff --git a/usr/src/uts/common/sys/mtio.h b/usr/src/uts/common/sys/mtio.h
index 3c81ed51ef..4d1969027e 100644
--- a/usr/src/uts/common/sys/mtio.h
+++ b/usr/src/uts/common/sys/mtio.h
@@ -153,6 +153,41 @@ struct mtdrivetype {
ushort_t erase_timeout; /* erase timeout. seconds */
};
+/*
+ * struct for MTIOCGETERROR - get recent error entry command
+ */
+struct mterror_entry {
+ size_t mtee_cdb_len; /* CDB length */
+ uchar_t *mtee_cdb_buf; /* CDB sent to the device */
+ size_t mtee_arq_status_len; /* length of scsi arq status */
+ struct scsi_arq_status *mtee_arq_status;
+ /* scsi arq status buffer */
+};
+
+#define MTERROR_ENTRY_SIZE_64 (sizeof (struct mterror_entry))
+
+#if defined(_SYSCALL32)
+struct mterror_entry32 {
+ size32_t mtee_cdb_len; /* CDB length */
+ caddr32_t mtee_cdb_buf; /* CDB sent to the device */
+ size32_t mtee_arq_status_len; /* length of scsi arq status */
+ caddr32_t mtee_arq_status;
+ /* scsi arq status buffer */
+};
+
+#define MTERROR_ENTRY_SIZE_32 (sizeof (struct mterror_entry32))
+
+#endif /* _SYSCALL32 */
+
+/*
+ * error entry stack
+ */
+struct mterror_entry_stack {
+ struct mterror_entry mtees_entry;
+ struct mterror_entry_stack *mtees_nextp;
+};
+
+#define MTERROR_LINK_ENTRY_SIZE (sizeof (struct mterror_entry_stack))
struct mtdrivetype_request {
int size;
@@ -267,7 +302,7 @@ struct mt_tape_info {
#define MTIOCRESERVE (MTIOC|8) /* preserve reserve */
#define MTIOCRELEASE (MTIOC|9) /* turnoff preserve reserve */
#define MTIOCFORCERESERVE (MTIOC|10) /* break reservation drive */
-
+#define MTIOCGETERROR (MTIOC|11) /* Get recently error record */
#define MTIOCSTATE (MTIOC|13) /* Inquire insert/eject state */
#define MTIOCREADIGNOREILI (MTIOC|14) /* Enable/Disable ILI */
diff --git a/usr/src/uts/common/sys/scsi/targets/stdef.h b/usr/src/uts/common/sys/scsi/targets/stdef.h
index 7c76c153c2..e521704001 100644
--- a/usr/src/uts/common/sys/scsi/targets/stdef.h
+++ b/usr/src/uts/common/sys/scsi/targets/stdef.h
@@ -875,6 +875,8 @@ struct scsi_tape {
int un_max_cdb_sz; /* max cdb size to use */
read_p_types un_read_pos_type;
read_pos_data_t *un_read_pos_data;
+ struct mterror_entry_stack *un_error_entry_stk;
+ /* latest sense cmd buffer */
#if defined(__i386) || defined(__amd64)
ddi_dma_handle_t un_contig_mem_hdl;