summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authorken <ken@FreeBSD.org>2011-10-03 20:32:55 +0000
committerken <ken@FreeBSD.org>2011-10-03 20:32:55 +0000
commit949394e8e0224cfa99b2f84509def2a178ec0cf4 (patch)
tree7b282ccd4d59d892882bbd5ce805d71ea69df7bd /sys/cam
parentad1a755394fe964557e221bb8167258557383a9d (diff)
downloadFreeBSD-src-949394e8e0224cfa99b2f84509def2a178ec0cf4.zip
FreeBSD-src-949394e8e0224cfa99b2f84509def2a178ec0cf4.tar.gz
Add descriptor sense support to CAM, and honor sense residuals properly in
CAM. Desriptor sense is a new sense data format that originated in SPC-3. Among other things, it allows for an 8-byte info field, which is necessary to pass back block numbers larger than 4 bytes. This change adds a number of new functions to scsi_all.c (and therefore libcam) that abstract out most access to sense data. This includes a bump of CAM_VERSION, because the CCB ABI has changed. Userland programs that use the CAM pass(4) driver will need to be recompiled. camcontrol.c: Change uses of scsi_extract_sense() to use scsi_extract_sense_len(). Use scsi_get_sks() instead of accessing sense key specific data directly. scsi_modes: Update the control mode page to the latest version (SPC-4). scsi_cmds.c, scsi_target.c: Change references to struct scsi_sense_data to struct scsi_sense_data_fixed. This should be changed to allow the user to specify fixed or descriptor sense, and then use scsi_set_sense_data() to build the sense data. ps3cdrom.c: Use scsi_set_sense_data() instead of setting sense data manually. cam_periph.c: Use scsi_extract_sense_len() instead of using scsi_extract_sense() or accessing sense data directly. cam_ccb.h: Bump the CAM_VERSION from 0x15 to 0x16. The change of struct scsi_sense_data from 32 to 252 bytes changes the size of struct ccb_scsiio, but not the size of union ccb. So the version must be bumped to prevent structure mis-matches. scsi_all.h: Lots of updated SCSI sense data and other structures. Add function prototypes for the new sense data functions. Take out the inline implementation of scsi_extract_sense(). It is now too large to put in a header file. Add macros to calculate whether fields are present and filled in fixed and descriptor sense data scsi_all.c: In scsi_op_desc(), allow the user to pass in NULL inquiry data, and we'll assume a direct access device in that case. Changed the SCSI RESERVED sense key name and description to COMPLETED, as it is now defined in the spec. Change the error recovery action for a number of read errors to prevent lots of retries when the drive has said that the block isn't accessible. This speeds up reconstruction of the block by any RAID software running on top of the drive (e.g. ZFS). In scsi_sense_desc(), allow for invalid sense key numbers. This allows calling this routine without checking the input values first. Change scsi_error_action() to use scsi_extract_sense_len(), and handle things when invalid asc/ascq values are encountered. Add a new routine, scsi_desc_iterate(), that will call the supplied function for every descriptor in descriptor format sense data. Add scsi_set_sense_data(), and scsi_set_sense_data_va(), which build descriptor and fixed format sense data. They currently default to fixed format sense data. Add a number of scsi_get_*() functions, which get different types of sense data fields from either fixed or descriptor format sense data, if the data is present. Add a number of scsi_*_sbuf() functions, which print formatted versions of various sense data fields. These functions work for either fixed or descriptor sense. Add a number of scsi_sense_*_sbuf() functions, which have a standard calling interface and print the indicated field. These functions take descriptors only. Add scsi_sense_desc_sbuf(), which will print a formatted version of the given sense descriptor. Pull out a majority of the scsi_sense_sbuf() function and put it into scsi_sense_only_sbuf(). This allows callers that don't use struct ccb_scsiio to easily utilize the printing routines. Revamp that function to handle descriptor sense and use the new sense fetching and printing routines. Move scsi_extract_sense() into scsi_all.c, and implement it in terms of the new function, scsi_extract_sense_len(). The _len() version takes a length (which should be the sense length - residual) and can indicate which fields are present and valid in the sense data. Add a couple of new scsi_get_*() routines to get the sense key, asc, and ascq only. mly.c: Rename struct scsi_sense_data to struct scsi_sense_data_fixed. sbp_targ.c: Use the new sense fetching routines to get sense data instead of accessing it directly. sbp.c: Change the firewire/SCSI sense data transformation code to use struct scsi_sense_data_fixed instead of struct scsi_sense_data. This should be changed later to use scsi_set_sense_data(). ciss.c: Calculate the sense residual properly. Use scsi_get_sense_key() to fetch the sense key. mps_sas.c, mpt_cam.c: Set the sense residual properly. iir.c: Use scsi_set_sense_data() instead of building sense data by hand. iscsi_subr.c: Use scsi_extract_sense_len() instead of grabbing sense data directly. umass.c: Use scsi_set_sense_data() to build sense data. Grab the sense key using scsi_get_sense_key(). Calculate the sense residual properly. isp_freebsd.h: Use scsi_get_*() routines to grab asc, ascq, and sense key values. Calculate and set the sense residual. MFC after: 3 days Sponsored by: Spectra Logic Corporation
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/cam_ccb.h2
-rw-r--r--sys/cam/cam_periph.c31
-rw-r--r--sys/cam/scsi/scsi_all.c1667
-rw-r--r--sys/cam/scsi/scsi_all.h878
-rw-r--r--sys/cam/scsi/scsi_cd.c12
-rw-r--r--sys/cam/scsi/scsi_da.c23
-rw-r--r--sys/cam/scsi/scsi_low.c16
-rw-r--r--sys/cam/scsi/scsi_sa.c53
-rw-r--r--sys/cam/scsi/scsi_targ_bh.c16
9 files changed, 2433 insertions, 265 deletions
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index ed2a890..0d51482 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -539,7 +539,7 @@ struct ccb_dev_match {
/*
* Definitions for the path inquiry CCB fields.
*/
-#define CAM_VERSION 0x15 /* Hex value for current version */
+#define CAM_VERSION 0x16 /* Hex value for current version */
typedef enum {
PI_MDP_ABLE = 0x80, /* Supports MDP message */
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 67c2d01..80dba39 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -1085,7 +1085,6 @@ camperiphsensedone(struct cam_periph *periph, union ccb *done_ccb)
union ccb *saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
cam_status status;
int frozen = 0;
- u_int sense_key;
int depth = done_ccb->ccb_h.recovery_depth;
status = done_ccb->ccb_h.status;
@@ -1101,22 +1100,25 @@ camperiphsensedone(struct cam_periph *periph, union ccb *done_ccb)
switch (status) {
case CAM_REQ_CMP:
{
+ int error_code, sense_key, asc, ascq;
+
+ scsi_extract_sense_len(&saved_ccb->csio.sense_data,
+ saved_ccb->csio.sense_len -
+ saved_ccb->csio.sense_resid,
+ &error_code, &sense_key, &asc, &ascq,
+ /*show_errors*/ 1);
/*
* If we manually retrieved sense into a CCB and got
* something other than "NO SENSE" send the updated CCB
* back to the client via xpt_done() to be processed via
* the error recovery code again.
*/
- sense_key = saved_ccb->csio.sense_data.flags;
- sense_key &= SSD_KEY;
- if (sense_key != SSD_KEY_NO_SENSE) {
- saved_ccb->ccb_h.status |=
- CAM_AUTOSNS_VALID;
+ if ((sense_key != -1)
+ && (sense_key != SSD_KEY_NO_SENSE)) {
+ saved_ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
} else {
- saved_ccb->ccb_h.status &=
- ~CAM_STATUS_MASK;
- saved_ccb->ccb_h.status |=
- CAM_AUTOSENSE_FAIL;
+ saved_ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ saved_ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
}
saved_ccb->csio.sense_resid = done_ccb->csio.resid;
bcopy(saved_ccb, done_ccb, sizeof(union ccb));
@@ -1198,12 +1200,15 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
if (status & CAM_AUTOSNS_VALID) {
struct ccb_getdev cgd;
struct scsi_sense_data *sense;
- int error_code, sense_key, asc, ascq;
+ int error_code, sense_key, asc, ascq, sense_len;
scsi_sense_action err_action;
sense = &done_ccb->csio.sense_data;
- scsi_extract_sense(sense, &error_code,
- &sense_key, &asc, &ascq);
+ sense_len = done_ccb->csio.sense_len -
+ done_ccb->csio.sense_resid;
+ scsi_extract_sense_len(sense, sense_len, &error_code,
+ &sense_key, &asc, &ascq,
+ /*show_errors*/ 1);
/*
* Grab the inquiry data for this device.
*/
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
index 7361c42..5ec287b 100644
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -31,6 +31,8 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stdint.h>
#ifdef _KERNEL
#include <opt_scsi.h>
@@ -54,6 +56,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sbuf.h>
#ifndef _KERNEL
#include <camlib.h>
+#include <stddef.h>
#ifndef FALSE
#define FALSE 0
@@ -608,14 +611,24 @@ scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data)
struct op_table_entry *table[2];
int num_tables;
- pd_type = SID_TYPE(inq_data);
+ /*
+ * If we've got inquiry data, use it to determine what type of
+ * device we're dealing with here. Otherwise, assume direct
+ * access.
+ */
+ if (inq_data == NULL) {
+ pd_type = T_DIRECT;
+ match = NULL;
+ } else {
+ pd_type = SID_TYPE(inq_data);
- match = cam_quirkmatch((caddr_t)inq_data,
- (caddr_t)scsi_op_quirk_table,
- sizeof(scsi_op_quirk_table)/
- sizeof(*scsi_op_quirk_table),
- sizeof(*scsi_op_quirk_table),
- scsi_inquiry_match);
+ match = cam_quirkmatch((caddr_t)inq_data,
+ (caddr_t)scsi_op_quirk_table,
+ sizeof(scsi_op_quirk_table)/
+ sizeof(*scsi_op_quirk_table),
+ sizeof(*scsi_op_quirk_table),
+ scsi_inquiry_match);
+ }
if (match != NULL) {
table[0] = ((struct scsi_op_quirk_entry *)match)->op_table;
@@ -699,7 +712,7 @@ const struct sense_key_table_entry sense_key_table[] =
{ SSD_KEY_EQUAL, SS_NOP, "EQUAL" },
{ SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" },
{ SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" },
- { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" }
+ { SSD_KEY_COMPLETED, SS_NOP, "COMPLETED" }
};
const int sense_key_table_size =
@@ -1062,25 +1075,25 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x10, 0x03, SS_RDEF, /* XXX TBD */
"Logical block reference tag check failed") },
/* DT WRO BK */
- { SST(0x11, 0x00, SS_RDEF,
+ { SST(0x11, 0x00, SS_FATAL|EIO,
"Unrecovered read error") },
/* DT WRO BK */
- { SST(0x11, 0x01, SS_RDEF,
+ { SST(0x11, 0x01, SS_FATAL|EIO,
"Read retries exhausted") },
/* DT WRO BK */
- { SST(0x11, 0x02, SS_RDEF,
+ { SST(0x11, 0x02, SS_FATAL|EIO,
"Error too long to correct") },
/* DT W O BK */
- { SST(0x11, 0x03, SS_RDEF,
+ { SST(0x11, 0x03, SS_FATAL|EIO,
"Multiple read errors") },
/* D W O BK */
- { SST(0x11, 0x04, SS_RDEF,
+ { SST(0x11, 0x04, SS_FATAL|EIO,
"Unrecovered read error - auto reallocate failed") },
/* WRO B */
- { SST(0x11, 0x05, SS_RDEF,
+ { SST(0x11, 0x05, SS_FATAL|EIO,
"L-EC uncorrectable error") },
/* WRO B */
- { SST(0x11, 0x06, SS_RDEF,
+ { SST(0x11, 0x06, SS_FATAL|EIO,
"CIRC unrecovered error") },
/* W O B */
{ SST(0x11, 0x07, SS_RDEF,
@@ -1095,10 +1108,10 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x11, 0x0A, SS_RDEF,
"Miscorrected error") },
/* D W O BK */
- { SST(0x11, 0x0B, SS_RDEF,
+ { SST(0x11, 0x0B, SS_FATAL|EIO,
"Unrecovered read error - recommend reassignment") },
/* D W O BK */
- { SST(0x11, 0x0C, SS_RDEF,
+ { SST(0x11, 0x0C, SS_FATAL|EIO,
"Unrecovered read error - recommend rewrite the data") },
/* DT WRO B */
{ SST(0x11, 0x0D, SS_RDEF,
@@ -2790,7 +2803,10 @@ scsi_sense_desc(int sense_key, int asc, int ascq,
&sense_entry,
&asc_entry);
- *sense_key_desc = sense_entry->desc;
+ if (sense_entry != NULL)
+ *sense_key_desc = sense_entry->desc;
+ else
+ *sense_key_desc = "Invalid Sense Key";
if (asc_entry != NULL)
*asc_desc = asc_entry->desc;
@@ -2816,10 +2832,12 @@ scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
int error_code, sense_key, asc, ascq;
scsi_sense_action action;
- scsi_extract_sense(&csio->sense_data, &error_code,
- &sense_key, &asc, &ascq);
+ scsi_extract_sense_len(&csio->sense_data, csio->sense_len -
+ csio->sense_resid, &error_code,
+ &sense_key, &asc, &ascq, /*show_errors*/ 1);
- if (error_code == SSD_DEFERRED_ERROR) {
+ if ((error_code == SSD_DEFERRED_ERROR)
+ || (error_code == SSD_DESC_DEFERRED_ERROR)) {
/*
* XXX dufault@FreeBSD.org
* This error doesn't relate to the command associated
@@ -2857,8 +2875,10 @@ scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
if (asc_entry != NULL
&& (asc != 0 || ascq != 0))
action = asc_entry->action;
- else
+ else if (sense_entry != NULL)
action = sense_entry->action;
+ else
+ action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE;
if (sense_key == SSD_KEY_RECOVERED_ERROR) {
/*
@@ -3040,6 +3060,1346 @@ scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio,
return(0);
}
+/*
+ * Iterate over sense descriptors. Each descriptor is passed into iter_func().
+ * If iter_func() returns 0, list traversal continues. If iter_func()
+ * returns non-zero, list traversal is stopped.
+ */
+void
+scsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len,
+ int (*iter_func)(struct scsi_sense_data_desc *sense,
+ u_int, struct scsi_sense_desc_header *,
+ void *), void *arg)
+{
+ int cur_pos;
+ int desc_len;
+
+ /*
+ * First make sure the extra length field is present.
+ */
+ if (SSD_DESC_IS_PRESENT(sense, sense_len, extra_len) == 0)
+ return;
+
+ /*
+ * The length of data actually returned may be different than the
+ * extra_len recorded in the sturcture.
+ */
+ desc_len = sense_len -offsetof(struct scsi_sense_data_desc, sense_desc);
+
+ /*
+ * Limit this further by the extra length reported, and the maximum
+ * allowed extra length.
+ */
+ desc_len = MIN(desc_len, MIN(sense->extra_len, SSD_EXTRA_MAX));
+
+ /*
+ * Subtract the size of the header from the descriptor length.
+ * This is to ensure that we have at least the header left, so we
+ * don't have to check that inside the loop. This can wind up
+ * being a negative value.
+ */
+ desc_len -= sizeof(struct scsi_sense_desc_header);
+
+ for (cur_pos = 0; cur_pos < desc_len;) {
+ struct scsi_sense_desc_header *header;
+
+ header = (struct scsi_sense_desc_header *)
+ &sense->sense_desc[cur_pos];
+
+ /*
+ * Check to make sure we have the entire descriptor. We
+ * don't call iter_func() unless we do.
+ *
+ * Note that although cur_pos is at the beginning of the
+ * descriptor, desc_len already has the header length
+ * subtracted. So the comparison of the length in the
+ * header (which does not include the header itself) to
+ * desc_len - cur_pos is correct.
+ */
+ if (header->length > (desc_len - cur_pos))
+ break;
+
+ if (iter_func(sense, sense_len, header, arg) != 0)
+ break;
+
+ cur_pos += sizeof(*header) + header->length;
+ }
+}
+
+struct scsi_find_desc_info {
+ uint8_t desc_type;
+ struct scsi_sense_desc_header *header;
+};
+
+static int
+scsi_find_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len,
+ struct scsi_sense_desc_header *header, void *arg)
+{
+ struct scsi_find_desc_info *desc_info;
+
+ desc_info = (struct scsi_find_desc_info *)arg;
+
+ if (header->desc_type == desc_info->desc_type) {
+ desc_info->header = header;
+
+ /* We found the descriptor, tell the iterator to stop. */
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * Given a descriptor type, return a pointer to it if it is in the sense
+ * data and not truncated. Avoiding truncating sense data will simplify
+ * things significantly for the caller.
+ */
+uint8_t *
+scsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len,
+ uint8_t desc_type)
+{
+ struct scsi_find_desc_info desc_info;
+
+ desc_info.desc_type = desc_type;
+ desc_info.header = NULL;
+
+ scsi_desc_iterate(sense, sense_len, scsi_find_desc_func, &desc_info);
+
+ return ((uint8_t *)desc_info.header);
+}
+
+/*
+ * Fill in SCSI sense data with the specified parameters. This routine can
+ * fill in either fixed or descriptor type sense data.
+ */
+void
+scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
+ scsi_sense_data_type sense_format, int current_error,
+ int sense_key, int asc, int ascq, va_list ap)
+{
+ int descriptor_sense;
+ scsi_sense_elem_type elem_type;
+
+ /*
+ * Determine whether to return fixed or descriptor format sense
+ * data. If the user specifies SSD_TYPE_NONE for some reason,
+ * they'll just get fixed sense data.
+ */
+ if (sense_format == SSD_TYPE_DESC)
+ descriptor_sense = 1;
+ else
+ descriptor_sense = 0;
+
+ /*
+ * Zero the sense data, so that we don't pass back any garbage data
+ * to the user.
+ */
+ memset(sense_data, 0, sizeof(*sense_data));
+
+ if (descriptor_sense != 0) {
+ struct scsi_sense_data_desc *sense;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+ /*
+ * The descriptor sense format eliminates the use of the
+ * valid bit.
+ */
+ if (current_error != 0)
+ sense->error_code = SSD_DESC_CURRENT_ERROR;
+ else
+ sense->error_code = SSD_DESC_DEFERRED_ERROR;
+ sense->sense_key = sense_key;
+ sense->add_sense_code = asc;
+ sense->add_sense_code_qual = ascq;
+ /*
+ * Start off with no extra length, since the above data
+ * fits in the standard descriptor sense information.
+ */
+ sense->extra_len = 0;
+ while ((elem_type = (scsi_sense_elem_type)va_arg(ap,
+ scsi_sense_elem_type)) != SSD_ELEM_NONE) {
+ int sense_len, len_to_copy;
+ uint8_t *data;
+
+ if (elem_type >= SSD_ELEM_MAX) {
+ printf("%s: invalid sense type %d\n", __func__,
+ elem_type);
+ break;
+ }
+
+ sense_len = (int)va_arg(ap, int);
+ len_to_copy = MIN(sense_len, SSD_EXTRA_MAX -
+ sense->extra_len);
+ data = (uint8_t *)va_arg(ap, uint8_t *);
+
+ /*
+ * We've already consumed the arguments for this one.
+ */
+ if (elem_type == SSD_ELEM_SKIP)
+ continue;
+
+ switch (elem_type) {
+ case SSD_ELEM_DESC: {
+
+ /*
+ * This is a straight descriptor. All we
+ * need to do is copy the data in.
+ */
+ bcopy(data, &sense->sense_desc[
+ sense->extra_len], len_to_copy);
+ sense->extra_len += len_to_copy;
+ break;
+ }
+ case SSD_ELEM_SKS: {
+ struct scsi_sense_sks sks;
+
+ bzero(&sks, sizeof(sks));
+
+ /*
+ * This is already-formatted sense key
+ * specific data. We just need to fill out
+ * the header and copy everything in.
+ */
+ bcopy(data, &sks.sense_key_spec,
+ MIN(len_to_copy,
+ sizeof(sks.sense_key_spec)));
+
+ sks.desc_type = SSD_DESC_SKS;
+ sks.length = sizeof(sks) -
+ offsetof(struct scsi_sense_sks, reserved1);
+ bcopy(&sks,&sense->sense_desc[sense->extra_len],
+ sizeof(sks));
+ sense->extra_len += sizeof(sks);
+ break;
+ }
+ case SSD_ELEM_INFO:
+ case SSD_ELEM_COMMAND: {
+ struct scsi_sense_command cmd;
+ struct scsi_sense_info info;
+ uint8_t *data_dest;
+ uint8_t *descriptor;
+ int descriptor_size, i, copy_len;
+
+ bzero(&cmd, sizeof(cmd));
+ bzero(&info, sizeof(info));
+
+ /*
+ * Command or information data. The
+ * operate in pretty much the same way.
+ */
+ if (elem_type == SSD_ELEM_COMMAND) {
+ len_to_copy = MIN(len_to_copy,
+ sizeof(cmd.command_info));
+ descriptor = (uint8_t *)&cmd;
+ descriptor_size = sizeof(cmd);
+ data_dest =(uint8_t *)&cmd.command_info;
+ cmd.desc_type = SSD_DESC_COMMAND;
+ cmd.length = sizeof(cmd) -
+ offsetof(struct scsi_sense_command,
+ reserved);
+ } else {
+ len_to_copy = MIN(len_to_copy,
+ sizeof(info.info));
+ descriptor = (uint8_t *)&info;
+ descriptor_size = sizeof(cmd);
+ data_dest = (uint8_t *)&info.info;
+ info.desc_type = SSD_DESC_INFO;
+ info.byte2 = SSD_INFO_VALID;
+ info.length = sizeof(info) -
+ offsetof(struct scsi_sense_info,
+ byte2);
+ }
+
+ /*
+ * Copy this in reverse because the spec
+ * (SPC-4) says that when 4 byte quantities
+ * are stored in this 8 byte field, the
+ * first four bytes shall be 0.
+ *
+ * So we fill the bytes in from the end, and
+ * if we have less than 8 bytes to copy,
+ * the initial, most significant bytes will
+ * be 0.
+ */
+ for (i = sense_len - 1; i >= 0 &&
+ len_to_copy > 0; i--, len_to_copy--)
+ data_dest[len_to_copy - 1] = data[i];
+
+ /*
+ * This calculation looks much like the
+ * initial len_to_copy calculation, but
+ * we have to do it again here, because
+ * we're looking at a larger amount that
+ * may or may not fit. It's not only the
+ * data the user passed in, but also the
+ * rest of the descriptor.
+ */
+ copy_len = MIN(descriptor_size,
+ SSD_EXTRA_MAX - sense->extra_len);
+ bcopy(descriptor, &sense->sense_desc[
+ sense->extra_len], copy_len);
+ sense->extra_len += copy_len;
+ break;
+ }
+ case SSD_ELEM_FRU: {
+ struct scsi_sense_fru fru;
+ int copy_len;
+
+ bzero(&fru, sizeof(fru));
+
+ fru.desc_type = SSD_DESC_FRU;
+ fru.length = sizeof(fru) -
+ offsetof(struct scsi_sense_fru, reserved);
+ fru.fru = *data;
+
+ copy_len = MIN(sizeof(fru), SSD_EXTRA_MAX -
+ sense->extra_len);
+ bcopy(&fru, &sense->sense_desc[
+ sense->extra_len], copy_len);
+ sense->extra_len += copy_len;
+ break;
+ }
+ case SSD_ELEM_STREAM: {
+ struct scsi_sense_stream stream_sense;
+ int copy_len;
+
+ bzero(&stream_sense, sizeof(stream_sense));
+ stream_sense.desc_type = SSD_DESC_STREAM;
+ stream_sense.length = sizeof(stream_sense) -
+ offsetof(struct scsi_sense_stream, reserved);
+ stream_sense.byte3 = *data;
+
+ copy_len = MIN(sizeof(stream_sense),
+ SSD_EXTRA_MAX - sense->extra_len);
+ bcopy(&stream_sense, &sense->sense_desc[
+ sense->extra_len], copy_len);
+ sense->extra_len += copy_len;
+ break;
+ }
+ default:
+ /*
+ * We shouldn't get here, but if we do, do
+ * nothing. We've already consumed the
+ * arguments above.
+ */
+ break;
+ }
+ }
+ } else {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if (current_error != 0)
+ sense->error_code = SSD_CURRENT_ERROR;
+ else
+ sense->error_code = SSD_DEFERRED_ERROR;
+
+ sense->flags = sense_key;
+ sense->add_sense_code = asc;
+ sense->add_sense_code_qual = ascq;
+ /*
+ * We've set the ASC and ASCQ, so we have 6 more bytes of
+ * valid data. If we wind up setting any of the other
+ * fields, we'll bump this to 10 extra bytes.
+ */
+ sense->extra_len = 6;
+
+ while ((elem_type = (scsi_sense_elem_type)va_arg(ap,
+ scsi_sense_elem_type)) != SSD_ELEM_NONE) {
+ int sense_len, len_to_copy;
+ uint8_t *data;
+
+ if (elem_type >= SSD_ELEM_MAX) {
+ printf("%s: invalid sense type %d\n", __func__,
+ elem_type);
+ break;
+ }
+ /*
+ * If we get in here, just bump the extra length to
+ * 10 bytes. That will encompass anything we're
+ * going to set here.
+ */
+ sense->extra_len = 10;
+ sense_len = (int)va_arg(ap, int);
+ len_to_copy = MIN(sense_len, SSD_EXTRA_MAX -
+ sense->extra_len);
+ data = (uint8_t *)va_arg(ap, uint8_t *);
+
+ switch (elem_type) {
+ case SSD_ELEM_SKS:
+ /*
+ * The user passed in pre-formatted sense
+ * key specific data.
+ */
+ bcopy(data, &sense->sense_key_spec[0],
+ MIN(sizeof(sense->sense_key_spec),
+ sense_len));
+ break;
+ case SSD_ELEM_INFO:
+ case SSD_ELEM_COMMAND: {
+ uint8_t *data_dest;
+ int i;
+
+ if (elem_type == SSD_ELEM_COMMAND)
+ data_dest = &sense->cmd_spec_info[0];
+ else {
+ data_dest = &sense->info[0];
+ /*
+ * We're setting the info field, so
+ * set the valid bit.
+ */
+ sense->error_code |= SSD_ERRCODE_VALID;
+ }
+
+ /*
+ * Copy this in reverse so that if we have
+ * less than 4 bytes to fill, the least
+ * significant bytes will be at the end.
+ * If we have more than 4 bytes, only the
+ * least significant bytes will be included.
+ */
+ for (i = sense_len - 1; i >= 0 &&
+ len_to_copy > 0; i--, len_to_copy--)
+ data_dest[len_to_copy - 1] = data[i];
+
+ break;
+ }
+ case SSD_ELEM_FRU:
+ sense->fru = *data;
+ break;
+ case SSD_ELEM_STREAM:
+ sense->flags |= *data;
+ break;
+ case SSD_ELEM_DESC:
+ default:
+
+ /*
+ * If the user passes in descriptor sense,
+ * we can't handle that in fixed format.
+ * So just skip it, and any unknown argument
+ * types.
+ */
+ break;
+ }
+ }
+ }
+}
+
+void
+scsi_set_sense_data(struct scsi_sense_data *sense_data,
+ scsi_sense_data_type sense_format, int current_error,
+ int sense_key, int asc, int ascq, ...)
+{
+ va_list ap;
+
+ va_start(ap, ascq);
+ scsi_set_sense_data_va(sense_data, sense_format, current_error,
+ sense_key, asc, ascq, ap);
+ va_end(ap);
+}
+
+/*
+ * Get sense information for three similar sense data types.
+ */
+int
+scsi_get_sense_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ uint8_t info_type, uint64_t *info, int64_t *signed_info)
+{
+ scsi_sense_data_type sense_type;
+
+ if (sense_len == 0)
+ goto bailout;
+
+ sense_type = scsi_sense_type(sense_data);
+
+ switch (sense_type) {
+ case SSD_TYPE_DESC: {
+ struct scsi_sense_data_desc *sense;
+ uint8_t *desc;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ desc = scsi_find_desc(sense, sense_len, info_type);
+ if (desc == NULL)
+ goto bailout;
+
+ switch (info_type) {
+ case SSD_DESC_INFO: {
+ struct scsi_sense_info *info_desc;
+
+ info_desc = (struct scsi_sense_info *)desc;
+ *info = scsi_8btou64(info_desc->info);
+ if (signed_info != NULL)
+ *signed_info = *info;
+ break;
+ }
+ case SSD_DESC_COMMAND: {
+ struct scsi_sense_command *cmd_desc;
+
+ cmd_desc = (struct scsi_sense_command *)desc;
+
+ *info = scsi_8btou64(cmd_desc->command_info);
+ if (signed_info != NULL)
+ *signed_info = *info;
+ break;
+ }
+ case SSD_DESC_FRU: {
+ struct scsi_sense_fru *fru_desc;
+
+ fru_desc = (struct scsi_sense_fru *)desc;
+
+ *info = fru_desc->fru;
+ if (signed_info != NULL)
+ *signed_info = (int8_t)fru_desc->fru;
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+ break;
+ }
+ case SSD_TYPE_FIXED: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ switch (info_type) {
+ case SSD_DESC_INFO: {
+ uint32_t info_val;
+
+ if ((sense->error_code & SSD_ERRCODE_VALID) == 0)
+ goto bailout;
+
+ if (SSD_FIXED_IS_PRESENT(sense, sense_len, info) == 0)
+ goto bailout;
+
+ info_val = scsi_4btoul(sense->info);
+
+ *info = info_val;
+ if (signed_info != NULL)
+ *signed_info = (int32_t)info_val;
+ break;
+ }
+ case SSD_DESC_COMMAND: {
+ uint32_t cmd_val;
+
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len,
+ cmd_spec_info) == 0)
+ || (SSD_FIXED_IS_FILLED(sense, cmd_spec_info) == 0))
+ goto bailout;
+
+ cmd_val = scsi_4btoul(sense->cmd_spec_info);
+ if (cmd_val == 0)
+ goto bailout;
+
+ *info = cmd_val;
+ if (signed_info != NULL)
+ *signed_info = (int32_t)cmd_val;
+ break;
+ }
+ case SSD_DESC_FRU:
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len, fru) == 0)
+ || (SSD_FIXED_IS_FILLED(sense, fru) == 0))
+ goto bailout;
+
+ if (sense->fru == 0)
+ goto bailout;
+
+ *info = sense->fru;
+ if (signed_info != NULL)
+ *signed_info = (int8_t)sense->fru;
+ break;
+ default:
+ goto bailout;
+ break;
+ }
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+
+ return (0);
+bailout:
+ return (1);
+}
+
+int
+scsi_get_sks(struct scsi_sense_data *sense_data, u_int sense_len, uint8_t *sks)
+{
+ scsi_sense_data_type sense_type;
+
+ if (sense_len == 0)
+ goto bailout;
+
+ sense_type = scsi_sense_type(sense_data);
+
+ switch (sense_type) {
+ case SSD_TYPE_DESC: {
+ struct scsi_sense_data_desc *sense;
+ struct scsi_sense_sks *desc;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ desc = (struct scsi_sense_sks *)scsi_find_desc(sense, sense_len,
+ SSD_DESC_SKS);
+ if (desc == NULL)
+ goto bailout;
+
+ /*
+ * No need to check the SKS valid bit for descriptor sense.
+ * If the descriptor is present, it is valid.
+ */
+ bcopy(desc->sense_key_spec, sks, sizeof(desc->sense_key_spec));
+ break;
+ }
+ case SSD_TYPE_FIXED: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len, sense_key_spec)== 0)
+ || (SSD_FIXED_IS_FILLED(sense, sense_key_spec) == 0))
+ goto bailout;
+
+ if ((sense->sense_key_spec[0] & SSD_SCS_VALID) == 0)
+ goto bailout;
+
+ bcopy(sense->sense_key_spec, sks,sizeof(sense->sense_key_spec));
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+ return (0);
+bailout:
+ return (1);
+}
+
+/*
+ * Provide a common interface for fixed and descriptor sense to detect
+ * whether we have block-specific sense information. It is clear by the
+ * presence of the block descriptor in descriptor mode, but we have to
+ * infer from the inquiry data and ILI bit in fixed mode.
+ */
+int
+scsi_get_block_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ struct scsi_inquiry_data *inq_data, uint8_t *block_bits)
+{
+ scsi_sense_data_type sense_type;
+
+ if (inq_data != NULL) {
+ switch (SID_TYPE(inq_data)) {
+ case T_DIRECT:
+ case T_RBC:
+ break;
+ default:
+ goto bailout;
+ break;
+ }
+ }
+
+ sense_type = scsi_sense_type(sense_data);
+
+ switch (sense_type) {
+ case SSD_TYPE_DESC: {
+ struct scsi_sense_data_desc *sense;
+ struct scsi_sense_block *block;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ block = (struct scsi_sense_block *)scsi_find_desc(sense,
+ sense_len, SSD_DESC_BLOCK);
+ if (block == NULL)
+ goto bailout;
+
+ *block_bits = block->byte3;
+ break;
+ }
+ case SSD_TYPE_FIXED: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0)
+ goto bailout;
+
+ if ((sense->flags & SSD_ILI) == 0)
+ goto bailout;
+
+ *block_bits = sense->flags & SSD_ILI;
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+ return (0);
+bailout:
+ return (1);
+}
+
+int
+scsi_get_stream_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ struct scsi_inquiry_data *inq_data, uint8_t *stream_bits)
+{
+ scsi_sense_data_type sense_type;
+
+ if (inq_data != NULL) {
+ switch (SID_TYPE(inq_data)) {
+ case T_SEQUENTIAL:
+ break;
+ default:
+ goto bailout;
+ break;
+ }
+ }
+
+ sense_type = scsi_sense_type(sense_data);
+
+ switch (sense_type) {
+ case SSD_TYPE_DESC: {
+ struct scsi_sense_data_desc *sense;
+ struct scsi_sense_stream *stream;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ stream = (struct scsi_sense_stream *)scsi_find_desc(sense,
+ sense_len, SSD_DESC_STREAM);
+ if (stream == NULL)
+ goto bailout;
+
+ *stream_bits = stream->byte3;
+ break;
+ }
+ case SSD_TYPE_FIXED: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags) == 0)
+ goto bailout;
+
+ if ((sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK)) == 0)
+ goto bailout;
+
+ *stream_bits = sense->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK);
+ break;
+ }
+ default:
+ goto bailout;
+ break;
+ }
+ return (0);
+bailout:
+ return (1);
+}
+
+void
+scsi_info_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data, uint64_t info)
+{
+ sbuf_printf(sb, "Info: %#jx", info);
+}
+
+void
+scsi_command_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data, uint64_t csi)
+{
+ sbuf_printf(sb, "Command Specific Info: %#jx", csi);
+}
+
+
+void
+scsi_progress_sbuf(struct sbuf *sb, uint16_t progress)
+{
+ sbuf_printf(sb, "Progress: %d%% (%d/%d) complete",
+ (progress * 100) / SSD_SKS_PROGRESS_DENOM,
+ progress, SSD_SKS_PROGRESS_DENOM);
+}
+
+/*
+ * Returns 1 for failure (i.e. SKS isn't valid) and 0 for success.
+ */
+int
+scsi_sks_sbuf(struct sbuf *sb, int sense_key, uint8_t *sks)
+{
+ if ((sks[0] & SSD_SKS_VALID) == 0)
+ return (1);
+
+ switch (sense_key) {
+ case SSD_KEY_ILLEGAL_REQUEST: {
+ struct scsi_sense_sks_field *field;
+ int bad_command;
+ char tmpstr[40];
+
+ /*Field Pointer*/
+ field = (struct scsi_sense_sks_field *)sks;
+
+ if (field->byte0 & SSD_SKS_FIELD_CMD)
+ bad_command = 1;
+ else
+ bad_command = 0;
+
+ tmpstr[0] = '\0';
+
+ /* Bit pointer is valid */
+ if (field->byte0 & SSD_SKS_BPV)
+ snprintf(tmpstr, sizeof(tmpstr), "bit %d ",
+ field->byte0 & SSD_SKS_BIT_VALUE);
+
+ sbuf_printf(sb, "%s byte %d %sis invalid",
+ bad_command ? "Command" : "Data",
+ scsi_2btoul(field->field), tmpstr);
+ break;
+ }
+ case SSD_KEY_UNIT_ATTENTION: {
+ struct scsi_sense_sks_overflow *overflow;
+
+ overflow = (struct scsi_sense_sks_overflow *)sks;
+
+ /*UA Condition Queue Overflow*/
+ sbuf_printf(sb, "Unit Attention Condition Queue %s",
+ (overflow->byte0 & SSD_SKS_OVERFLOW_SET) ?
+ "Overflowed" : "Did Not Overflow??");
+ break;
+ }
+ case SSD_KEY_RECOVERED_ERROR:
+ case SSD_KEY_HARDWARE_ERROR:
+ case SSD_KEY_MEDIUM_ERROR: {
+ struct scsi_sense_sks_retry *retry;
+
+ /*Actual Retry Count*/
+ retry = (struct scsi_sense_sks_retry *)sks;
+
+ sbuf_printf(sb, "Actual Retry Count: %d",
+ scsi_2btoul(retry->actual_retry_count));
+ break;
+ }
+ case SSD_KEY_NO_SENSE:
+ case SSD_KEY_NOT_READY: {
+ struct scsi_sense_sks_progress *progress;
+ int progress_val;
+
+ /*Progress Indication*/
+ progress = (struct scsi_sense_sks_progress *)sks;
+ progress_val = scsi_2btoul(progress->progress);
+
+ scsi_progress_sbuf(sb, progress_val);
+ break;
+ }
+ case SSD_KEY_COPY_ABORTED: {
+ struct scsi_sense_sks_segment *segment;
+ char tmpstr[40];
+
+ /*Segment Pointer*/
+ segment = (struct scsi_sense_sks_segment *)sks;
+
+ tmpstr[0] = '\0';
+
+ if (segment->byte0 & SSD_SKS_SEGMENT_BPV)
+ snprintf(tmpstr, sizeof(tmpstr), "bit %d ",
+ segment->byte0 & SSD_SKS_SEGMENT_BITPTR);
+
+ sbuf_printf(sb, "%s byte %d %sis invalid", (segment->byte0 &
+ SSD_SKS_SEGMENT_SD) ? "Segment" : "Data",
+ scsi_2btoul(segment->field), tmpstr);
+ break;
+ }
+ default:
+ sbuf_printf(sb, "Sense Key Specific: %#x,%#x", sks[0],
+ scsi_2btoul(&sks[1]));
+ break;
+ }
+
+ return (0);
+}
+
+void
+scsi_fru_sbuf(struct sbuf *sb, uint64_t fru)
+{
+ sbuf_printf(sb, "Field Replaceable Unit: %d", (int)fru);
+}
+
+void
+scsi_stream_sbuf(struct sbuf *sb, uint8_t stream_bits, uint64_t info)
+{
+ int need_comma;
+
+ need_comma = 0;
+ /*
+ * XXX KDM this needs more descriptive decoding.
+ */
+ if (stream_bits & SSD_DESC_STREAM_FM) {
+ sbuf_printf(sb, "Filemark");
+ need_comma = 1;
+ }
+
+ if (stream_bits & SSD_DESC_STREAM_EOM) {
+ sbuf_printf(sb, "%sEOM", (need_comma) ? "," : "");
+ need_comma = 1;
+ }
+
+ if (stream_bits & SSD_DESC_STREAM_ILI)
+ sbuf_printf(sb, "%sILI", (need_comma) ? "," : "");
+
+ sbuf_printf(sb, ": Info: %#jx", (uintmax_t) info);
+}
+
+void
+scsi_block_sbuf(struct sbuf *sb, uint8_t block_bits, uint64_t info)
+{
+ if (block_bits & SSD_DESC_BLOCK_ILI)
+ sbuf_printf(sb, "ILI: residue %#jx", (uintmax_t) info);
+}
+
+void
+scsi_sense_info_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_info *info;
+
+ info = (struct scsi_sense_info *)header;
+
+ scsi_info_sbuf(sb, cdb, cdb_len, inq_data, scsi_8btou64(info->info));
+}
+
+void
+scsi_sense_command_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_command *command;
+
+ command = (struct scsi_sense_command *)header;
+
+ scsi_command_sbuf(sb, cdb, cdb_len, inq_data,
+ scsi_8btou64(command->command_info));
+}
+
+void
+scsi_sense_sks_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_sks *sks;
+ int error_code, sense_key, asc, ascq;
+
+ sks = (struct scsi_sense_sks *)header;
+
+ scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key,
+ &asc, &ascq, /*show_errors*/ 1);
+
+ scsi_sks_sbuf(sb, sense_key, sks->sense_key_spec);
+}
+
+void
+scsi_sense_fru_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_fru *fru;
+
+ fru = (struct scsi_sense_fru *)header;
+
+ scsi_fru_sbuf(sb, (uint64_t)fru->fru);
+}
+
+void
+scsi_sense_stream_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_stream *stream;
+ uint64_t info;
+
+ stream = (struct scsi_sense_stream *)header;
+ info = 0;
+
+ scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, NULL);
+
+ scsi_stream_sbuf(sb, stream->byte3, info);
+}
+
+void
+scsi_sense_block_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_block *block;
+ uint64_t info;
+
+ block = (struct scsi_sense_block *)header;
+ info = 0;
+
+ scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &info, NULL);
+
+ scsi_block_sbuf(sb, block->byte3, info);
+}
+
+void
+scsi_sense_progress_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ struct scsi_sense_progress *progress;
+ const char *sense_key_desc;
+ const char *asc_desc;
+ int progress_val;
+
+ progress = (struct scsi_sense_progress *)header;
+
+ /*
+ * Get descriptions for the sense key, ASC, and ASCQ in the
+ * progress descriptor. These could be different than the values
+ * in the overall sense data.
+ */
+ scsi_sense_desc(progress->sense_key, progress->add_sense_code,
+ progress->add_sense_code_qual, inq_data,
+ &sense_key_desc, &asc_desc);
+
+ progress_val = scsi_2btoul(progress->progress);
+
+ /*
+ * The progress indicator is for the operation described by the
+ * sense key, ASC, and ASCQ in the descriptor.
+ */
+ sbuf_cat(sb, sense_key_desc);
+ sbuf_printf(sb, " asc:%x,%x (%s): ", progress->add_sense_code,
+ progress->add_sense_code_qual, asc_desc);
+ scsi_progress_sbuf(sb, progress_val);
+}
+
+/*
+ * Generic sense descriptor printing routine. This is used when we have
+ * not yet implemented a specific printing routine for this descriptor.
+ */
+void
+scsi_sense_generic_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ int i;
+ uint8_t *buf_ptr;
+
+ sbuf_printf(sb, "Descriptor %#x:", header->desc_type);
+
+ buf_ptr = (uint8_t *)&header[1];
+
+ for (i = 0; i < header->length; i++, buf_ptr++)
+ sbuf_printf(sb, " %02x", *buf_ptr);
+}
+
+/*
+ * Keep this list in numeric order. This speeds the array traversal.
+ */
+struct scsi_sense_desc_printer {
+ uint8_t desc_type;
+ /*
+ * The function arguments here are the superset of what is needed
+ * to print out various different descriptors. Command and
+ * information descriptors need inquiry data and command type.
+ * Sense key specific descriptors need the sense key.
+ *
+ * The sense, cdb, and inquiry data arguments may be NULL, but the
+ * information printed may not be fully decoded as a result.
+ */
+ void (*print_func)(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+} scsi_sense_printers[] = {
+ {SSD_DESC_INFO, scsi_sense_info_sbuf},
+ {SSD_DESC_COMMAND, scsi_sense_command_sbuf},
+ {SSD_DESC_SKS, scsi_sense_sks_sbuf},
+ {SSD_DESC_FRU, scsi_sense_fru_sbuf},
+ {SSD_DESC_STREAM, scsi_sense_stream_sbuf},
+ {SSD_DESC_BLOCK, scsi_sense_block_sbuf},
+ {SSD_DESC_PROGRESS, scsi_sense_progress_sbuf}
+};
+
+void
+scsi_sense_desc_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header)
+{
+ int i, found;
+
+ for (i = 0, found = 0; i < (sizeof(scsi_sense_printers) /
+ sizeof(scsi_sense_printers[0])); i++) {
+ struct scsi_sense_desc_printer *printer;
+
+ printer = &scsi_sense_printers[i];
+
+ /*
+ * The list is sorted, so quit if we've passed our
+ * descriptor number.
+ */
+ if (printer->desc_type > header->desc_type)
+ break;
+
+ if (printer->desc_type != header->desc_type)
+ continue;
+
+ printer->print_func(sb, sense, sense_len, cdb, cdb_len,
+ inq_data, header);
+
+ return;
+ }
+
+ /*
+ * No specific printing routine, so use the generic routine.
+ */
+ scsi_sense_generic_sbuf(sb, sense, sense_len, cdb, cdb_len,
+ inq_data, header);
+}
+
+scsi_sense_data_type
+scsi_sense_type(struct scsi_sense_data *sense_data)
+{
+ switch (sense_data->error_code & SSD_ERRCODE) {
+ case SSD_DESC_CURRENT_ERROR:
+ case SSD_DESC_DEFERRED_ERROR:
+ return (SSD_TYPE_DESC);
+ break;
+ case SSD_CURRENT_ERROR:
+ case SSD_DEFERRED_ERROR:
+ return (SSD_TYPE_FIXED);
+ break;
+ default:
+ break;
+ }
+
+ return (SSD_TYPE_NONE);
+}
+
+struct scsi_print_sense_info {
+ struct sbuf *sb;
+ char *path_str;
+ uint8_t *cdb;
+ int cdb_len;
+ struct scsi_inquiry_data *inq_data;
+};
+
+static int
+scsi_print_desc_func(struct scsi_sense_data_desc *sense, u_int sense_len,
+ struct scsi_sense_desc_header *header, void *arg)
+{
+ struct scsi_print_sense_info *print_info;
+
+ print_info = (struct scsi_print_sense_info *)arg;
+
+ switch (header->desc_type) {
+ case SSD_DESC_INFO:
+ case SSD_DESC_FRU:
+ case SSD_DESC_COMMAND:
+ case SSD_DESC_SKS:
+ case SSD_DESC_BLOCK:
+ case SSD_DESC_STREAM:
+ /*
+ * We have already printed these descriptors, if they are
+ * present.
+ */
+ break;
+ default: {
+ sbuf_printf(print_info->sb, "%s", print_info->path_str);
+ scsi_sense_desc_sbuf(print_info->sb,
+ (struct scsi_sense_data *)sense, sense_len,
+ print_info->cdb, print_info->cdb_len,
+ print_info->inq_data, header);
+ sbuf_printf(print_info->sb, "\n");
+ break;
+ }
+ }
+
+ /*
+ * Tell the iterator that we want to see more descriptors if they
+ * are present.
+ */
+ return (0);
+}
+
+void
+scsi_sense_only_sbuf(struct scsi_sense_data *sense, u_int sense_len,
+ struct sbuf *sb, char *path_str,
+ struct scsi_inquiry_data *inq_data, uint8_t *cdb,
+ int cdb_len)
+{
+ int error_code, sense_key, asc, ascq;
+
+ sbuf_cat(sb, path_str);
+
+ scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key,
+ &asc, &ascq, /*show_errors*/ 1);
+
+ sbuf_printf(sb, "SCSI sense: ");
+ switch (error_code) {
+ case SSD_DEFERRED_ERROR:
+ case SSD_DESC_DEFERRED_ERROR:
+ sbuf_printf(sb, "Deferred error: ");
+
+ /* FALLTHROUGH */
+ case SSD_CURRENT_ERROR:
+ case SSD_DESC_CURRENT_ERROR:
+ {
+ struct scsi_sense_data_desc *desc_sense;
+ struct scsi_print_sense_info print_info;
+ const char *sense_key_desc;
+ const char *asc_desc;
+ uint8_t sks[3];
+ uint64_t val;
+ int info_valid;
+
+ /*
+ * Get descriptions for the sense key, ASC, and ASCQ. If
+ * these aren't present in the sense data (i.e. the sense
+ * data isn't long enough), the -1 values that
+ * scsi_extract_sense_len() returns will yield default
+ * or error descriptions.
+ */
+ scsi_sense_desc(sense_key, asc, ascq, inq_data,
+ &sense_key_desc, &asc_desc);
+
+ /*
+ * We first print the sense key and ASC/ASCQ.
+ */
+ sbuf_cat(sb, sense_key_desc);
+ sbuf_printf(sb, " asc:%x,%x (%s)\n", asc, ascq, asc_desc);
+
+ /*
+ * Get the info field if it is valid.
+ */
+ if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO,
+ &val, NULL) == 0)
+ info_valid = 1;
+ else
+ info_valid = 0;
+
+ if (info_valid != 0) {
+ uint8_t bits;
+
+ /*
+ * Determine whether we have any block or stream
+ * device-specific information.
+ */
+ if (scsi_get_block_info(sense, sense_len, inq_data,
+ &bits) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_block_sbuf(sb, bits, val);
+ sbuf_printf(sb, "\n");
+ } else if (scsi_get_stream_info(sense, sense_len,
+ inq_data, &bits) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_stream_sbuf(sb, bits, val);
+ sbuf_printf(sb, "\n");
+ } else if (val != 0) {
+ /*
+ * The information field can be valid but 0.
+ * If the block or stream bits aren't set,
+ * and this is 0, it isn't terribly useful
+ * to print it out.
+ */
+ sbuf_cat(sb, path_str);
+ scsi_info_sbuf(sb, cdb, cdb_len, inq_data, val);
+ sbuf_printf(sb, "\n");
+ }
+ }
+
+ /*
+ * Print the FRU.
+ */
+ if (scsi_get_sense_info(sense, sense_len, SSD_DESC_FRU,
+ &val, NULL) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_fru_sbuf(sb, val);
+ sbuf_printf(sb, "\n");
+ }
+
+ /*
+ * Print any command-specific information.
+ */
+ if (scsi_get_sense_info(sense, sense_len, SSD_DESC_COMMAND,
+ &val, NULL) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_command_sbuf(sb, cdb, cdb_len, inq_data, val);
+ sbuf_printf(sb, "\n");
+ }
+
+ /*
+ * Print out any sense-key-specific information.
+ */
+ if (scsi_get_sks(sense, sense_len, sks) == 0) {
+ sbuf_cat(sb, path_str);
+ scsi_sks_sbuf(sb, sense_key, sks);
+ sbuf_printf(sb, "\n");
+ }
+
+ /*
+ * If this is fixed sense, we're done. If we have
+ * descriptor sense, we might have more information
+ * available.
+ */
+ if (scsi_sense_type(sense) != SSD_TYPE_DESC)
+ break;
+
+ desc_sense = (struct scsi_sense_data_desc *)sense;
+
+ print_info.sb = sb;
+ print_info.path_str = path_str;
+ print_info.cdb = cdb;
+ print_info.cdb_len = cdb_len;
+ print_info.inq_data = inq_data;
+
+ /*
+ * Print any sense descriptors that we have not already printed.
+ */
+ scsi_desc_iterate(desc_sense, sense_len, scsi_print_desc_func,
+ &print_info);
+ break;
+
+ }
+ case -1:
+ /*
+ * scsi_extract_sense_len() sets values to -1 if the
+ * show_errors flag is set and they aren't present in the
+ * sense data. This means that sense_len is 0.
+ */
+ sbuf_printf(sb, "No sense data present\n");
+ break;
+ default: {
+ sbuf_printf(sb, "Error code 0x%x", error_code);
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ struct scsi_sense_data_fixed *fixed_sense;
+
+ fixed_sense = (struct scsi_sense_data_fixed *)sense;
+
+ if (SSD_FIXED_IS_PRESENT(fixed_sense, sense_len, info)){
+ uint32_t info;
+
+ info = scsi_4btoul(fixed_sense->info);
+
+ sbuf_printf(sb, " at block no. %d (decimal)",
+ info);
+ }
+ }
+ sbuf_printf(sb, "\n");
+ break;
+ }
+ }
+}
/*
* scsi_sense_sbuf() returns 0 for success and -1 for failure.
@@ -3059,11 +4419,8 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
#ifdef _KERNEL
struct ccb_getdev *cgd;
#endif /* _KERNEL */
- u_int32_t info;
- int error_code;
- int sense_key;
- int asc, ascq;
char path_str[64];
+ uint8_t *cdb;
#ifndef _KERNEL
if (device == NULL)
@@ -3161,129 +4518,14 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
sense = &csio->sense_data;
}
+ if (csio->ccb_h.flags & CAM_CDB_POINTER)
+ cdb = csio->cdb_io.cdb_ptr;
+ else
+ cdb = csio->cdb_io.cdb_bytes;
- sbuf_cat(sb, path_str);
-
- error_code = sense->error_code & SSD_ERRCODE;
- sense_key = sense->flags & SSD_KEY;
-
- sbuf_printf(sb, "SCSI sense: ");
- switch (error_code) {
- case SSD_DEFERRED_ERROR:
- sbuf_printf(sb, "Deferred error: ");
-
- /* FALLTHROUGH */
- case SSD_CURRENT_ERROR:
- {
- const char *sense_key_desc;
- const char *asc_desc;
-
- asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
- ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
- scsi_sense_desc(sense_key, asc, ascq, inq_data,
- &sense_key_desc, &asc_desc);
- sbuf_cat(sb, sense_key_desc);
-
- info = scsi_4btoul(sense->info);
-
- if (sense->error_code & SSD_ERRCODE_VALID) {
-
- switch (sense_key) {
- case SSD_KEY_NOT_READY:
- case SSD_KEY_ILLEGAL_REQUEST:
- case SSD_KEY_UNIT_ATTENTION:
- case SSD_KEY_DATA_PROTECT:
- break;
- case SSD_KEY_BLANK_CHECK:
- sbuf_printf(sb, " req sz: %d (decimal)", info);
- break;
- default:
- if (info) {
- if (sense->flags & SSD_ILI) {
- sbuf_printf(sb, " ILI (length "
- "mismatch): %d", info);
-
- } else {
- sbuf_printf(sb, " info:%x",
- info);
- }
- }
- }
- } else if (info) {
- sbuf_printf(sb, " info?:%x", info);
- }
-
- if (sense->extra_len >= 4) {
- if (bcmp(sense->cmd_spec_info, "\0\0\0\0", 4)) {
- sbuf_printf(sb, " csi:%x,%x,%x,%x",
- sense->cmd_spec_info[0],
- sense->cmd_spec_info[1],
- sense->cmd_spec_info[2],
- sense->cmd_spec_info[3]);
- }
- }
-
- sbuf_printf(sb, " asc:%x,%x (%s)", asc, ascq, asc_desc);
-
- if (sense->extra_len >= 7 && sense->fru) {
- sbuf_printf(sb, " field replaceable unit: %x",
- sense->fru);
- }
-
- if ((sense->extra_len >= 10)
- && (sense->sense_key_spec[0] & SSD_SCS_VALID) != 0) {
- switch(sense_key) {
- case SSD_KEY_ILLEGAL_REQUEST: {
- int bad_command;
- char tmpstr2[40];
-
- if (sense->sense_key_spec[0] & 0x40)
- bad_command = 1;
- else
- bad_command = 0;
-
- tmpstr2[0] = '\0';
-
- /* Bit pointer is valid */
- if (sense->sense_key_spec[0] & 0x08)
- snprintf(tmpstr2, sizeof(tmpstr2),
- "bit %d ",
- sense->sense_key_spec[0] & 0x7);
- sbuf_printf(sb, ": %s byte %d %sis invalid",
- bad_command ? "Command" : "Data",
- scsi_2btoul(
- &sense->sense_key_spec[1]),
- tmpstr2);
- break;
- }
- case SSD_KEY_RECOVERED_ERROR:
- case SSD_KEY_HARDWARE_ERROR:
- case SSD_KEY_MEDIUM_ERROR:
- sbuf_printf(sb, " actual retry count: %d",
- scsi_2btoul(
- &sense->sense_key_spec[1]));
- break;
- default:
- sbuf_printf(sb, " sks:%#x,%#x",
- sense->sense_key_spec[0],
- scsi_2btoul(
- &sense->sense_key_spec[1]));
- break;
- }
- }
- break;
-
- }
- default:
- sbuf_printf(sb, "Error code 0x%x", sense->error_code);
- if (sense->error_code & SSD_ERRCODE_VALID) {
- sbuf_printf(sb, " at block no. %d (decimal)",
- info = scsi_4btoul(sense->info));
- }
- }
-
- sbuf_printf(sb, "\n");
-
+ scsi_sense_only_sbuf(sense, csio->sense_len - csio->sense_resid, sb,
+ path_str, inq_data, cdb, csio->cdb_len);
+
#ifdef _KERNEL
xpt_free_ccb((union ccb*)cgd);
#endif /* _KERNEL/!_KERNEL */
@@ -3355,6 +4597,135 @@ scsi_sense_print(struct cam_device *device, struct ccb_scsiio *csio,
#endif /* _KERNEL/!_KERNEL */
/*
+ * Extract basic sense information. This is backward-compatible with the
+ * previous implementation. For new implementations,
+ * scsi_extract_sense_len() is recommended.
+ */
+void
+scsi_extract_sense(struct scsi_sense_data *sense_data, int *error_code,
+ int *sense_key, int *asc, int *ascq)
+{
+ scsi_extract_sense_len(sense_data, sizeof(*sense_data), error_code,
+ sense_key, asc, ascq, /*show_errors*/ 0);
+}
+
+/*
+ * Extract basic sense information. If show_errors is set, sense values
+ * will be set to -1 if they are not present.
+ */
+void
+scsi_extract_sense_len(struct scsi_sense_data *sense_data, u_int sense_len,
+ int *error_code, int *sense_key, int *asc, int *ascq,
+ int show_errors)
+{
+ /*
+ * If we have no length, we have no sense.
+ */
+ if (sense_len == 0) {
+ if (show_errors == 0) {
+ *error_code = 0;
+ *sense_key = 0;
+ *asc = 0;
+ *ascq = 0;
+ } else {
+ *error_code = -1;
+ *sense_key = -1;
+ *asc = -1;
+ *ascq = -1;
+ }
+ return;
+ }
+
+ *error_code = sense_data->error_code & SSD_ERRCODE;
+
+ switch (*error_code) {
+ case SSD_DESC_CURRENT_ERROR:
+ case SSD_DESC_DEFERRED_ERROR: {
+ struct scsi_sense_data_desc *sense;
+
+ sense = (struct scsi_sense_data_desc *)sense_data;
+
+ if (SSD_DESC_IS_PRESENT(sense, sense_len, sense_key))
+ *sense_key = sense->sense_key & SSD_KEY;
+ else
+ *sense_key = (show_errors) ? -1 : 0;
+
+ if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code))
+ *asc = sense->add_sense_code;
+ else
+ *asc = (show_errors) ? -1 : 0;
+
+ if (SSD_DESC_IS_PRESENT(sense, sense_len, add_sense_code_qual))
+ *ascq = sense->add_sense_code_qual;
+ else
+ *ascq = (show_errors) ? -1 : 0;
+ break;
+ }
+ case SSD_CURRENT_ERROR:
+ case SSD_DEFERRED_ERROR:
+ default: {
+ struct scsi_sense_data_fixed *sense;
+
+ sense = (struct scsi_sense_data_fixed *)sense_data;
+
+ if (SSD_FIXED_IS_PRESENT(sense, sense_len, flags))
+ *sense_key = sense->flags & SSD_KEY;
+ else
+ *sense_key = (show_errors) ? -1 : 0;
+
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len, add_sense_code))
+ && (SSD_FIXED_IS_FILLED(sense, add_sense_code)))
+ *asc = sense->add_sense_code;
+ else
+ *asc = (show_errors) ? -1 : 0;
+
+ if ((SSD_FIXED_IS_PRESENT(sense, sense_len,add_sense_code_qual))
+ && (SSD_FIXED_IS_FILLED(sense, add_sense_code_qual)))
+ *ascq = sense->add_sense_code_qual;
+ else
+ *ascq = (show_errors) ? -1 : 0;
+ break;
+ }
+ }
+}
+
+int
+scsi_get_sense_key(struct scsi_sense_data *sense_data, u_int sense_len,
+ int show_errors)
+{
+ int error_code, sense_key, asc, ascq;
+
+ scsi_extract_sense_len(sense_data, sense_len, &error_code,
+ &sense_key, &asc, &ascq, show_errors);
+
+ return (sense_key);
+}
+
+int
+scsi_get_asc(struct scsi_sense_data *sense_data, u_int sense_len,
+ int show_errors)
+{
+ int error_code, sense_key, asc, ascq;
+
+ scsi_extract_sense_len(sense_data, sense_len, &error_code,
+ &sense_key, &asc, &ascq, show_errors);
+
+ return (asc);
+}
+
+int
+scsi_get_ascq(struct scsi_sense_data *sense_data, u_int sense_len,
+ int show_errors)
+{
+ int error_code, sense_key, asc, ascq;
+
+ scsi_extract_sense_len(sense_data, sense_len, &error_code,
+ &sense_key, &asc, &ascq, show_errors);
+
+ return (ascq);
+}
+
+/*
* This function currently requires at least 36 bytes, or
* SHORT_INQUIRY_LENGTH, worth of data to function properly. If this
* function needs more or less data in the future, another length should be
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index 93b11d5..3bcc623 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -25,6 +25,7 @@
#define _SCSI_SCSI_ALL_H 1
#include <sys/cdefs.h>
+#include <machine/stdarg.h>
#ifdef _KERNEL
/*
@@ -171,7 +172,8 @@ struct scsi_inquiry
{
u_int8_t opcode;
u_int8_t byte2;
-#define SI_EVPD 0x01
+#define SI_EVPD 0x01
+#define SI_CMDDT 0x02
u_int8_t page_code;
u_int8_t reserved;
u_int8_t length;
@@ -200,7 +202,9 @@ struct scsi_mode_sense_6
#define SMS_PAGE_CTRL_CHANGEABLE 0x40
#define SMS_PAGE_CTRL_DEFAULT 0x80
#define SMS_PAGE_CTRL_SAVED 0xC0
- u_int8_t unused;
+ u_int8_t subpage;
+#define SMS_SUBPAGE_PAGE_0 0x00
+#define SMS_SUBPAGE_ALL 0xff
u_int8_t length;
u_int8_t control;
};
@@ -209,8 +213,10 @@ struct scsi_mode_sense_10
{
u_int8_t opcode;
u_int8_t byte2; /* same bits as small version */
+#define SMS10_LLBAA 0x10
u_int8_t page; /* same bits as small version */
- u_int8_t unused[4];
+ u_int8_t subpage;
+ u_int8_t unused[3];
u_int8_t length[2];
u_int8_t control;
};
@@ -263,6 +269,120 @@ struct scsi_mode_block_descr
u_int8_t block_len[3];
};
+struct scsi_per_res_in
+{
+ u_int8_t opcode;
+ u_int8_t action;
+#define SPRI_RK 0x00
+#define SPRI_RR 0x01
+#define SPRI_RC 0x02
+#define SPRI_RS 0x03
+ u_int8_t reserved[5];
+ u_int8_t length[2];
+ u_int8_t control;
+};
+
+struct scsi_per_res_in_header
+{
+ u_int8_t generation[4];
+ u_int8_t length[4];
+};
+
+struct scsi_per_res_key
+{
+ u_int8_t key[8];
+};
+
+struct scsi_per_res_in_keys
+{
+ struct scsi_per_res_in_header header;
+ struct scsi_per_res_key keys[0];
+};
+
+struct scsi_per_res_cap
+{
+ uint8_t length[2];
+ uint8_t flags1;
+#define SPRI_CRH 0x10
+#define SPRI_SIP_C 0x08
+#define SPRI_ATP_C 0x04
+#define SPRI_PTPL_C 0x01
+ uint8_t flags2;
+#define SPRI_TMV 0x80
+#define SPRI_PTPL_A 0x01
+ uint8_t type_mask[2];
+#define SPRI_TM_WR_EX_AR 0x8000
+#define SPRI_TM_EX_AC_RO 0x4000
+#define SPRI_TM_WR_EX_RO 0x2000
+#define SPRI_TM_EX_AC 0x0800
+#define SPRI_TM_WR_EX 0x0200
+#define SPRI_TM_EX_AC_AR 0x0001
+ uint8_t reserved[2];
+};
+
+struct scsi_per_res_in_rsrv_data
+{
+ uint8_t reservation[8];
+ uint8_t obsolete1[4];
+ uint8_t reserved;
+ uint8_t scopetype;
+#define SPRT_WE 0x01
+#define SPRT_EA 0x03
+#define SPRT_WERO 0x05
+#define SPRT_EARO 0x06
+#define SPRT_WEAR 0x07
+#define SPRT_EAAR 0x08
+ uint8_t obsolete2[2];
+};
+
+struct scsi_per_res_in_rsrv
+{
+ struct scsi_per_res_in_header header;
+ struct scsi_per_res_in_rsrv_data data;
+};
+
+struct scsi_per_res_out
+{
+ u_int8_t opcode;
+ u_int8_t action;
+#define SPRO_REGISTER 0x00
+#define SPRO_RESERVE 0x01
+#define SPRO_RELEASE 0x02
+#define SPRO_CLEAR 0x03
+#define SPRO_PREEMPT 0x04
+#define SPRO_PRE_ABO 0x05
+#define SPRO_REG_IGNO 0x06
+#define SPRO_REG_MOVE 0x07
+#define SPRO_ACTION_MASK 0x1f
+ u_int8_t scope_type;
+#define SPR_SCOPE_MASK 0xf0
+#define SPR_LU_SCOPE 0x00
+#define SPR_TYPE_MASK 0x0f
+#define SPR_TYPE_WR_EX 0x01
+#define SPR_TYPE_EX_AC 0x03
+#define SPR_TYPE_WR_EX_RO 0x05
+#define SPR_TYPE_EX_AC_RO 0x06
+#define SPR_TYPE_WR_EX_AR 0x07
+#define SPR_TYPE_EX_AC_AR 0x08
+ u_int8_t reserved[2];
+ u_int8_t length[4];
+ u_int8_t control;
+};
+
+struct scsi_per_res_out_parms
+{
+ struct scsi_per_res_key res_key;
+ u_int8_t serv_act_res_key[8];
+ u_int8_t obsolete1[4];
+ u_int8_t flags;
+#define SPR_SPEC_I_PT 0x08
+#define SPR_ALL_TG_PT 0x04
+#define SPR_APTPL 0x01
+ u_int8_t reserved1;
+ u_int8_t obsolete2[2];
+};
+
+
struct scsi_log_sense
{
u_int8_t opcode;
@@ -337,7 +457,16 @@ struct scsi_control_page {
u_int8_t page_code;
u_int8_t page_length;
u_int8_t rlec;
-#define SCB_RLEC 0x01 /*Report Log Exception Cond*/
+#define SCP_RLEC 0x01 /*Report Log Exception Cond*/
+#define SCP_GLTSD 0x02 /*Global Logging target
+ save disable */
+#define SCP_DSENSE 0x04 /*Descriptor Sense */
+#define SCP_DPICZ 0x08 /*Disable Prot. Info Check
+ if Prot. Field is Zero */
+#define SCP_TMF_ONLY 0x10 /*TM Functions Only*/
+#define SCP_TST_MASK 0xE0 /*Task Set Type Mask*/
+#define SCP_TST_ONE 0x00 /*One Task Set*/
+#define SCP_TST_SEPARATE 0x20 /*Separate Task Sets*/
u_int8_t queue_flags;
#define SCP_QUEUE_ALG_MASK 0xF0
#define SCP_QUEUE_ALG_RESTRICTED 0x00
@@ -368,6 +497,41 @@ struct scsi_cache_page {
u_int8_t max_prefetch_ceil[2];
};
+/*
+ * XXX KDM
+ * Updated version of the cache page, as of SBC. Update this to SBC-3 and
+ * rationalize the two.
+ */
+struct scsi_caching_page {
+ uint8_t page_code;
+#define SMS_CACHING_PAGE 0x08
+ uint8_t page_length;
+ uint8_t flags1;
+#define SCP_IC 0x80
+#define SCP_ABPF 0x40
+#define SCP_CAP 0x20
+#define SCP_DISC 0x10
+#define SCP_SIZE 0x08
+#define SCP_WCE 0x04
+#define SCP_MF 0x02
+#define SCP_RCD 0x01
+ uint8_t ret_priority;
+ uint8_t disable_pf_transfer_len[2];
+ uint8_t min_prefetch[2];
+ uint8_t max_prefetch[2];
+ uint8_t max_pf_ceiling[2];
+ uint8_t flags2;
+#define SCP_FSW 0x80
+#define SCP_LBCSS 0x40
+#define SCP_DRA 0x20
+#define SCP_VS1 0x10
+#define SCP_VS2 0x08
+ uint8_t cache_segments;
+ uint8_t cache_seg_size[2];
+ uint8_t reserved;
+ uint8_t non_cache_seg_size[3];
+};
+
struct scsi_info_exceptions_page {
u_int8_t page_code;
#define SIEP_PAGE_SAVABLE 0x80 /* Page is savable */
@@ -406,20 +570,49 @@ struct scsi_reserve
{
u_int8_t opcode;
u_int8_t byte2;
- u_int8_t unused[2];
- u_int8_t length;
+#define SR_EXTENT 0x01
+#define SR_ID_MASK 0x0e
+#define SR_3RDPTY 0x10
+#define SR_LUN_MASK 0xe0
+ u_int8_t resv_id;
+ u_int8_t length[2];
u_int8_t control;
};
+struct scsi_reserve_10 {
+ uint8_t opcode;
+ uint8_t byte2;
+#define SR10_3RDPTY 0x10
+#define SR10_LONGID 0x02
+#define SR10_EXTENT 0x01
+ uint8_t resv_id;
+ uint8_t thirdparty_id;
+ uint8_t reserved[3];
+ uint8_t length[2];
+ uint8_t control;
+};
+
+
struct scsi_release
{
u_int8_t opcode;
u_int8_t byte2;
- u_int8_t unused[2];
+ u_int8_t resv_id;
+ u_int8_t unused[1];
u_int8_t length;
u_int8_t control;
};
+struct scsi_release_10 {
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t resv_id;
+ uint8_t thirdparty_id;
+ uint8_t reserved[3];
+ uint8_t length[2];
+ uint8_t control;
+};
+
struct scsi_prevent
{
u_int8_t opcode;
@@ -435,12 +628,60 @@ struct scsi_sync_cache
{
u_int8_t opcode;
u_int8_t byte2;
+#define SSC_IMMED 0x02
+#define SSC_RELADR 0x01
u_int8_t begin_lba[4];
u_int8_t reserved;
u_int8_t lb_count[2];
u_int8_t control;
};
+struct scsi_sync_cache_16
+{
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t begin_lba[8];
+ uint8_t lb_count[4];
+ uint8_t reserved;
+ uint8_t control;
+};
+
+struct scsi_format {
+ uint8_t opcode;
+ uint8_t byte2;
+#define SF_LONGLIST 0x20
+#define SF_FMTDATA 0x10
+#define SF_CMPLIST 0x08
+#define SF_FORMAT_MASK 0x07
+#define SF_FORMAT_BLOCK 0x00
+#define SF_FORMAT_LONG_BLOCK 0x03
+#define SF_FORMAT_BFI 0x04
+#define SF_FORMAT_PHYS 0x05
+ uint8_t vendor;
+ uint8_t interleave[2];
+ uint8_t control;
+};
+
+struct scsi_format_header_short {
+ uint8_t reserved;
+#define SF_DATA_FOV 0x80
+#define SF_DATA_DPRY 0x40
+#define SF_DATA_DCRT 0x20
+#define SF_DATA_STPF 0x10
+#define SF_DATA_IP 0x08
+#define SF_DATA_DSP 0x04
+#define SF_DATA_IMMED 0x02
+#define SF_DATA_VS 0x01
+ uint8_t byte2;
+ uint8_t defect_list_len[2];
+};
+
+struct scsi_format_header_long {
+ uint8_t reserved;
+ uint8_t byte2;
+ uint8_t reserved2[2];
+ uint8_t defect_list_len[4];
+};
struct scsi_changedef
{
@@ -459,6 +700,7 @@ struct scsi_read_buffer
u_int8_t byte2;
#define RWB_MODE 0x07
#define RWB_MODE_HDR_DATA 0x00
+#define RWB_MODE_VENDOR 0x01
#define RWB_MODE_DATA 0x02
#define RWB_MODE_DOWNLOAD 0x04
#define RWB_MODE_DOWNLOAD_SAVE 0x05
@@ -529,6 +771,40 @@ struct scsi_rw_16
u_int8_t control;
};
+struct scsi_write_verify_10
+{
+ uint8_t opcode;
+ uint8_t byte2;
+#define SWV_BYTCHK 0x02
+#define SWV_DPO 0x10
+#define SWV_WRPROECT_MASK 0xe0
+ uint8_t addr[4];
+ uint8_t group;
+ uint8_t length[2];
+ uint8_t control;
+};
+
+struct scsi_write_verify_12
+{
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t addr[4];
+ uint8_t length[4];
+ uint8_t group;
+ uint8_t control;
+};
+
+struct scsi_write_verify_16
+{
+ uint8_t opcode;
+ uint8_t byte2;
+ uint8_t addr[8];
+ uint8_t length[4];
+ uint8_t group;
+ uint8_t control;
+};
+
+
struct scsi_start_stop_unit
{
u_int8_t opcode;
@@ -538,6 +814,14 @@ struct scsi_start_stop_unit
u_int8_t how;
#define SSS_START 0x01
#define SSS_LOEJ 0x02
+#define SSS_PC_MASK 0xf0
+#define SSS_PC_START_VALID 0x00
+#define SSS_PC_ACTIVE 0x10
+#define SSS_PC_IDLE 0x20
+#define SSS_PC_STANDBY 0x30
+#define SSS_PC_LU_CONTROL 0x70
+#define SSS_PC_FORCE_IDLE_0 0xa0
+#define SSS_PC_FORCE_STANDBY_0 0xb0
u_int8_t control;
};
@@ -562,6 +846,18 @@ struct ata_pass_12 {
u_int8_t control;
};
+struct scsi_maintenance_in
+{
+ uint8_t opcode;
+ uint8_t byte2;
+#define SERVICE_ACTION_MASK 0x1f
+#define SA_RPRT_TRGT_GRP 0x0a
+ uint8_t reserved[4];
+ uint8_t length[4];
+ uint8_t reserved1;
+ uint8_t control;
+};
+
struct ata_pass_16 {
u_int8_t opcode;
u_int8_t protocol;
@@ -607,6 +903,7 @@ struct ata_pass_16 {
#define READ_10 0x28
#define WRITE_10 0x2A
#define POSITION_TO_ELEMENT 0x2B
+#define WRITE_VERIFY_10 0x2E
#define SYNCHRONIZE_CACHE 0x35
#define READ_DEFECT_DATA_10 0x37
#define WRITE_BUFFER 0x3B
@@ -615,10 +912,16 @@ struct ata_pass_16 {
#define LOG_SELECT 0x4C
#define LOG_SENSE 0x4D
#define MODE_SELECT_10 0x55
+#define RESERVE_10 0x56
+#define RELEASE_10 0x57
#define MODE_SENSE_10 0x5A
+#define PERSISTENT_RES_IN 0x5E
+#define PERSISTENT_RES_OUT 0x5F
#define ATA_PASS_16 0x85
#define READ_16 0x88
#define WRITE_16 0x8A
+#define WRITE_VERIFY_16 0x8E
+#define SYNCHRONIZE_CACHE_16 0x91
#define SERVICE_ACTION_IN 0x9E
#define REPORT_LUNS 0xA0
#define ATA_PASS_12 0xA1
@@ -627,6 +930,7 @@ struct ata_pass_16 {
#define MOVE_MEDIUM 0xA5
#define READ_12 0xA8
#define WRITE_12 0xAA
+#define WRITE_VERIFY_12 0xAE
#define READ_ELEMENT_STATUS 0xB8
/* Maintenance In Service Action Codes */
@@ -737,10 +1041,12 @@ struct scsi_inquiry_data
u_int8_t response_format;
#define SID_AENC 0x80
#define SID_TrmIOP 0x40
+#define SID_NormACA 0x20
+#define SID_HiSup 0x10
u_int8_t additional_length;
#define SID_ADDITIONAL_LENGTH(iqd) \
((iqd)->additional_length + \
- offsetof(struct scsi_inquiry_data, additional_length) + 1)
+ __offsetof(struct scsi_inquiry_data, additional_length) + 1)
u_int8_t spc3_flags;
#define SPC3_SID_PROTECT 0x01
#define SPC3_SID_3PC 0x08
@@ -750,6 +1056,7 @@ struct scsi_inquiry_data
#define SPC3_SID_ACC 0x40
#define SPC3_SID_SCCS 0x80
u_int8_t spc2_flags;
+#define SPC2_SID_ADDR16 0x01
#define SPC2_SID_MChngr 0x08
#define SPC2_SID_MultiP 0x10
#define SPC2_SID_EncServ 0x40
@@ -809,6 +1116,10 @@ struct scsi_inquiry_data
u_int8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE];
};
+/*
+ * This structure is more suited to initiator operation, because the
+ * maximum number of supported pages is already allocated.
+ */
struct scsi_vpd_supported_page_list
{
u_int8_t device;
@@ -852,11 +1163,11 @@ struct scsi_vpd_device_id
u_int8_t device;
u_int8_t page_code;
#define SVPD_DEVICE_ID 0x83
-#define SVPD_DEVICE_ID_MAX_SIZE 0xffff
-#define SVPD_DEVICE_ID_HDR_LEN 4
-#define SVPD_DEVICE_ID_DESC_HDR_LEN 4
+#define SVPD_DEVICE_ID_MAX_SIZE 252
+#define SVPD_DEVICE_ID_HDR_LEN \
+ __offsetof(struct scsi_vpd_device_id, desc_list)
u_int8_t length[2];
- u_int8_t desc_list[0];
+ u_int8_t desc_list[];
};
struct scsi_vpd_id_descriptor
@@ -872,11 +1183,13 @@ struct scsi_vpd_id_descriptor
#define SVPD_ID_PROTO_SHIFT 4
#define SVPD_ID_CODESET_BINARY 0x01
#define SVPD_ID_CODESET_ASCII 0x02
+#define SVPD_ID_CODESET_MASK 0x0f
u_int8_t id_type;
#define SVPD_ID_PIV 0x80
#define SVPD_ID_ASSOC_LUN 0x00
#define SVPD_ID_ASSOC_PORT 0x10
#define SVPD_ID_ASSOC_TARGET 0x20
+#define SVPD_ID_ASSOC_MASK 0x30
#define SVPD_ID_TYPE_VENDOR 0x00
#define SVPD_ID_TYPE_T10 0x01
#define SVPD_ID_TYPE_EUI64 0x02
@@ -889,7 +1202,9 @@ struct scsi_vpd_id_descriptor
#define SVPD_ID_TYPE_MASK 0x0f
u_int8_t reserved;
u_int8_t length;
- u_int8_t identifier[0];
+#define SVPD_DEVICE_ID_DESC_HDR_LEN \
+ __offsetof(struct scsi_vpd_id_descriptor, identifier)
+ u_int8_t identifier[];
};
struct scsi_vpd_id_t10
@@ -990,12 +1305,23 @@ struct scsi_vpd_id_scsi_name
uint8_t name_string[256];
};
+struct scsi_service_action_in
+{
+ uint8_t opcode;
+ uint8_t service_action;
+ uint8_t action_dependent[13];
+ uint8_t control;
+};
+
struct scsi_read_capacity
{
u_int8_t opcode;
u_int8_t byte2;
+#define SRC_RELADR 0x01
u_int8_t addr[4];
- u_int8_t unused[3];
+ u_int8_t unused[2];
+ u_int8_t pmi;
+#define SRC_PMI 0x01
u_int8_t control;
};
@@ -1038,18 +1364,11 @@ struct scsi_report_luns
uint8_t control;
};
-struct scsi_report_luns_data {
- u_int8_t length[4]; /* length of LUN inventory, in bytes */
- u_int8_t reserved[4]; /* unused */
- /*
- * LUN inventory- we only support the type zero form for now.
- */
- struct {
- u_int8_t lundata[8];
- } luns[0];
-};
+struct scsi_report_luns_lundata {
+ uint8_t lundata[8];
#define RPL_LUNDATA_PERIPH_BUS_MASK 0x3f
#define RPL_LUNDATA_FLAT_LUN_MASK 0x3f
+#define RPL_LUNDATA_FLAT_LUN_BITS 0x06
#define RPL_LUNDATA_LUN_TARG_MASK 0x3f
#define RPL_LUNDATA_LUN_BUS_MASK 0xe0
#define RPL_LUNDATA_LUN_LUN_MASK 0x1f
@@ -1062,6 +1381,16 @@ struct scsi_report_luns_data {
#define RPL_LUNDATA_ATYP_FLAT 0x40
#define RPL_LUNDATA_ATYP_LUN 0x80
#define RPL_LUNDATA_ATYP_EXTLUN 0xc0
+};
+
+struct scsi_report_luns_data {
+ u_int8_t length[4]; /* length of LUN inventory, in bytes */
+ u_int8_t reserved[4]; /* unused */
+ /*
+ * LUN inventory- we only support the type zero form for now.
+ */
+ struct scsi_report_luns_lundata luns[0];
+};
struct scsi_target_group
{
@@ -1103,6 +1432,9 @@ struct scsi_target_port_group_descriptor {
uint8_t target_port_group[2];
uint8_t reserved;
uint8_t status;
+#define TPG_UNAVLBL 0
+#define TPG_SET_BY_STPG 0x01
+#define TPG_IMPLICIT 0x02
uint8_t vendor_specific;
uint8_t target_port_count;
struct scsi_target_port_descriptor descriptors[];
@@ -1122,8 +1454,49 @@ struct scsi_target_group_data_extended {
};
+typedef enum {
+ SSD_TYPE_NONE,
+ SSD_TYPE_FIXED,
+ SSD_TYPE_DESC
+} scsi_sense_data_type;
+
+typedef enum {
+ SSD_ELEM_NONE,
+ SSD_ELEM_SKIP,
+ SSD_ELEM_DESC,
+ SSD_ELEM_SKS,
+ SSD_ELEM_COMMAND,
+ SSD_ELEM_INFO,
+ SSD_ELEM_FRU,
+ SSD_ELEM_STREAM,
+ SSD_ELEM_MAX
+} scsi_sense_elem_type;
+
+
struct scsi_sense_data
{
+ uint8_t error_code;
+ /*
+ * SPC-4 says that the maximum length of sense data is 252 bytes.
+ * So this structure is exactly 252 bytes log.
+ */
+#define SSD_FULL_SIZE 252
+ uint8_t sense_buf[SSD_FULL_SIZE - 1];
+ /*
+ * XXX KDM is this still a reasonable minimum size?
+ */
+#define SSD_MIN_SIZE 18
+ /*
+ * Maximum value for the extra_len field in the sense data.
+ */
+#define SSD_EXTRA_MAX 244
+};
+
+/*
+ * Fixed format sense data.
+ */
+struct scsi_sense_data_fixed
+{
u_int8_t error_code;
#define SSD_ERRCODE 0x7F
#define SSD_CURRENT_ERROR 0x70
@@ -1147,7 +1520,7 @@ struct scsi_sense_data
#define SSD_KEY_EQUAL 0x0c
#define SSD_KEY_VOLUME_OVERFLOW 0x0d
#define SSD_KEY_MISCOMPARE 0x0e
-#define SSD_KEY_RESERVED 0x0f
+#define SSD_KEY_COMPLETED 0x0f
#define SSD_ILI 0x20
#define SSD_EOM 0x40
#define SSD_FILEMARK 0x80
@@ -1162,9 +1535,313 @@ struct scsi_sense_data
#define SSD_FIELDPTR_CMD 0x40
#define SSD_BITPTR_VALID 0x08
#define SSD_BITPTR_VALUE 0x07
-#define SSD_MIN_SIZE 18
u_int8_t extra_bytes[14];
-#define SSD_FULL_SIZE sizeof(struct scsi_sense_data)
+#define SSD_FIXED_IS_PRESENT(sense, length, field) \
+ ((length >= (offsetof(struct scsi_sense_data_fixed, field) + \
+ sizeof(sense->field))) ? 1 :0)
+#define SSD_FIXED_IS_FILLED(sense, field) \
+ ((((offsetof(struct scsi_sense_data_fixed, field) + \
+ sizeof(sense->field)) - \
+ (offsetof(struct scsi_sense_data_fixed, extra_len) + \
+ sizeof(sense->extra_len))) <= sense->extra_len) ? 1 : 0)
+};
+
+/*
+ * Descriptor format sense data definitions.
+ * Introduced in SPC-3.
+ */
+struct scsi_sense_data_desc
+{
+ uint8_t error_code;
+#define SSD_DESC_CURRENT_ERROR 0x72
+#define SSD_DESC_DEFERRED_ERROR 0x73
+ uint8_t sense_key;
+ uint8_t add_sense_code;
+ uint8_t add_sense_code_qual;
+ uint8_t reserved[3];
+ /*
+ * Note that SPC-4, section 4.5.2.1 says that the extra_len field
+ * must be less than or equal to 244.
+ */
+ uint8_t extra_len;
+ uint8_t sense_desc[0];
+#define SSD_DESC_IS_PRESENT(sense, length, field) \
+ ((length >= (offsetof(struct scsi_sense_data_desc, field) + \
+ sizeof(sense->field))) ? 1 :0)
+};
+
+struct scsi_sense_desc_header
+{
+ uint8_t desc_type;
+ uint8_t length;
+};
+/*
+ * The information provide in the Information descriptor is device type or
+ * command specific information, and defined in a command standard.
+ *
+ * Note that any changes to the field names or positions in this structure,
+ * even reserved fields, should be accompanied by an examination of the
+ * code in ctl_set_sense() that uses them.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_info
+{
+ uint8_t desc_type;
+#define SSD_DESC_INFO 0x00
+ uint8_t length;
+ uint8_t byte2;
+#define SSD_INFO_VALID 0x80
+ uint8_t reserved;
+ uint8_t info[8];
+};
+
+/*
+ * Command-specific information depends on the command for which the
+ * reported condition occured.
+ *
+ * Note that any changes to the field names or positions in this structure,
+ * even reserved fields, should be accompanied by an examination of the
+ * code in ctl_set_sense() that uses them.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_command
+{
+ uint8_t desc_type;
+#define SSD_DESC_COMMAND 0x01
+ uint8_t length;
+ uint8_t reserved[2];
+ uint8_t command_info[8];
+};
+
+/*
+ * Sense key specific descriptor. The sense key specific data format
+ * depends on the sense key in question.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_sks
+{
+ uint8_t desc_type;
+#define SSD_DESC_SKS 0x02
+ uint8_t length;
+ uint8_t reserved1[2];
+ uint8_t sense_key_spec[3];
+#define SSD_SKS_VALID 0x80
+ uint8_t reserved2;
+};
+
+/*
+ * This is used for the Illegal Request sense key (0x05) only.
+ */
+struct scsi_sense_sks_field
+{
+ uint8_t byte0;
+#define SSD_SKS_FIELD_VALID 0x80
+#define SSD_SKS_FIELD_CMD 0x40
+#define SSD_SKS_BPV 0x08
+#define SSD_SKS_BIT_VALUE 0x07
+ uint8_t field[2];
+};
+
+
+/*
+ * This is used for the Hardware Error (0x04), Medium Error (0x03) and
+ * Recovered Error (0x01) sense keys.
+ */
+struct scsi_sense_sks_retry
+{
+ uint8_t byte0;
+#define SSD_SKS_RETRY_VALID 0x80
+ uint8_t actual_retry_count[2];
+};
+
+/*
+ * Used with the NO Sense (0x00) or Not Ready (0x02) sense keys.
+ */
+struct scsi_sense_sks_progress
+{
+ uint8_t byte0;
+#define SSD_SKS_PROGRESS_VALID 0x80
+ uint8_t progress[2];
+#define SSD_SKS_PROGRESS_DENOM 0x10000
+};
+
+/*
+ * Used with the Copy Aborted (0x0a) sense key.
+ */
+struct scsi_sense_sks_segment
+{
+ uint8_t byte0;
+#define SSD_SKS_SEGMENT_VALID 0x80
+#define SSD_SKS_SEGMENT_SD 0x20
+#define SSD_SKS_SEGMENT_BPV 0x08
+#define SSD_SKS_SEGMENT_BITPTR 0x07
+ uint8_t field[2];
+};
+
+/*
+ * Used with the Unit Attention (0x06) sense key.
+ *
+ * This is currently used to indicate that the unit attention condition
+ * queue has overflowed (when the overflow bit is set).
+ */
+struct scsi_sense_sks_overflow
+{
+ uint8_t byte0;
+#define SSD_SKS_OVERFLOW_VALID 0x80
+#define SSD_SKS_OVERFLOW_SET 0x01
+ uint8_t reserved[2];
+};
+
+/*
+ * This specifies which component is associated with the sense data. There
+ * is no standard meaning for the fru value.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_fru
+{
+ uint8_t desc_type;
+#define SSD_DESC_FRU 0x03
+ uint8_t length;
+ uint8_t reserved;
+ uint8_t fru;
+};
+
+/*
+ * Used for Stream commands, defined in SSC-4.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+
+struct scsi_sense_stream
+{
+ uint8_t desc_type;
+#define SSD_DESC_STREAM 0x04
+ uint8_t length;
+ uint8_t reserved;
+ uint8_t byte3;
+#define SSD_DESC_STREAM_FM 0x80
+#define SSD_DESC_STREAM_EOM 0x40
+#define SSD_DESC_STREAM_ILI 0x20
+};
+
+/*
+ * Used for Block commands, defined in SBC-3.
+ *
+ * This is currently (as of SBC-3) only used for the Incorrect Length
+ * Indication (ILI) bit, which says that the data length requested in the
+ * READ LONG or WRITE LONG command did not match the length of the logical
+ * block.
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_block
+{
+ uint8_t desc_type;
+#define SSD_DESC_BLOCK 0x05
+ uint8_t length;
+ uint8_t reserved;
+ uint8_t byte3;
+#define SSD_DESC_BLOCK_ILI 0x20
+};
+
+/*
+ * Used for Object-Based Storage Devices (OSD-3).
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_osd_objid
+{
+ uint8_t desc_type;
+#define SSD_DESC_OSD_OBJID 0x06
+ uint8_t length;
+ uint8_t reserved[6];
+ /*
+ * XXX KDM provide the bit definitions here? There are a lot of
+ * them, and we don't have an OSD driver yet.
+ */
+ uint8_t not_init_cmds[4];
+ uint8_t completed_cmds[4];
+ uint8_t partition_id[8];
+ uint8_t object_id[8];
+};
+
+/*
+ * Used for Object-Based Storage Devices (OSD-3).
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_osd_integrity
+{
+ uint8_t desc_type;
+#define SSD_DESC_OSD_INTEGRITY 0x07
+ uint8_t length;
+ uint8_t integ_check_val[32];
+};
+
+/*
+ * Used for Object-Based Storage Devices (OSD-3).
+ *
+ * Maximum descriptors allowed: 1 (as of SPC-4)
+ */
+struct scsi_sense_osd_attr_id
+{
+ uint8_t desc_type;
+#define SSD_DESC_OSD_ATTR_ID 0x08
+ uint8_t length;
+ uint8_t reserved[2];
+ uint8_t attr_desc[0];
+};
+
+/*
+ * Used with Sense keys No Sense (0x00) and Not Ready (0x02).
+ *
+ * Maximum descriptors allowed: 32 (as of SPC-4)
+ */
+struct scsi_sense_progress
+{
+ uint8_t desc_type;
+#define SSD_DESC_PROGRESS 0x0a
+ uint8_t length;
+ uint8_t sense_key;
+ uint8_t add_sense_code;
+ uint8_t add_sense_code_qual;
+ uint8_t reserved;
+ uint8_t progress[2];
+};
+
+/*
+ * This is typically forwarded as the result of an EXTENDED COPY command.
+ *
+ * Maximum descriptors allowed: 2 (as of SPC-4)
+ */
+struct scsi_sense_forwarded
+{
+ uint8_t desc_type;
+#define SSD_DESC_FORWARDED 0x0c
+ uint8_t length;
+ uint8_t byte2;
+#define SSD_FORWARDED_FSDT 0x80
+#define SSD_FORWARDED_SDS_MASK 0x0f
+#define SSD_FORWARDED_SDS_UNK 0x00
+#define SSD_FORWARDED_SDS_EXSRC 0x01
+#define SSD_FORWARDED_SDS_EXDST 0x02
+};
+
+/*
+ * Vendor-specific sense descriptor. The desc_type field will be in the
+ * range bewteen MIN and MAX inclusive.
+ */
+struct scsi_sense_vendor
+{
+ uint8_t desc_type;
+#define SSD_DESC_VENDOR_MIN 0x80
+#define SSD_DESC_VENDOR_MAX 0xff
+ uint8_t length;
+ uint8_t data[0];
};
struct scsi_mode_header_6
@@ -1187,9 +1864,20 @@ struct scsi_mode_header_10
struct scsi_mode_page_header
{
u_int8_t page_code;
+#define SMPH_PS 0x80
+#define SMPH_SPF 0x40
+#define SMPH_PC_MASK 0x3f
u_int8_t page_length;
};
+struct scsi_mode_page_header_sp
+{
+ uint8_t page_code;
+ uint8_t subpage;
+ uint8_t page_length[2];
+};
+
+
struct scsi_mode_blk_desc
{
u_int8_t density;
@@ -1292,6 +1980,84 @@ scsi_sense_action scsi_error_action(struct ccb_scsiio* csio,
struct scsi_inquiry_data *inq_data,
u_int32_t sense_flags);
const char * scsi_status_string(struct ccb_scsiio *csio);
+
+void scsi_desc_iterate(struct scsi_sense_data_desc *sense, u_int sense_len,
+ int (*iter_func)(struct scsi_sense_data_desc *sense,
+ u_int, struct scsi_sense_desc_header *,
+ void *), void *arg);
+uint8_t *scsi_find_desc(struct scsi_sense_data_desc *sense, u_int sense_len,
+ uint8_t desc_type);
+void scsi_set_sense_data(struct scsi_sense_data *sense_data,
+ scsi_sense_data_type sense_format, int current_error,
+ int sense_key, int asc, int ascq, ...) ;
+void scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
+ scsi_sense_data_type sense_format,
+ int current_error, int sense_key, int asc,
+ int ascq, va_list ap);
+int scsi_get_sense_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ uint8_t info_type, uint64_t *info,
+ int64_t *signed_info);
+int scsi_get_sks(struct scsi_sense_data *sense_data, u_int sense_len,
+ uint8_t *sks);
+int scsi_get_block_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ struct scsi_inquiry_data *inq_data,
+ uint8_t *block_bits);
+int scsi_get_stream_info(struct scsi_sense_data *sense_data, u_int sense_len,
+ struct scsi_inquiry_data *inq_data,
+ uint8_t *stream_bits);
+void scsi_info_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data, uint64_t info);
+void scsi_command_sbuf(struct sbuf *sb, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data, uint64_t csi);
+void scsi_progress_sbuf(struct sbuf *sb, uint16_t progress);
+int scsi_sks_sbuf(struct sbuf *sb, int sense_key, uint8_t *sks);
+void scsi_fru_sbuf(struct sbuf *sb, uint64_t fru);
+void scsi_stream_sbuf(struct sbuf *sb, uint8_t stream_bits, uint64_t info);
+void scsi_block_sbuf(struct sbuf *sb, uint8_t block_bits, uint64_t info);
+void scsi_sense_info_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+
+void scsi_sense_command_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_sks_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_fru_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_stream_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_block_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_progress_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_generic_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+void scsi_sense_desc_sbuf(struct sbuf *sb, struct scsi_sense_data *sense,
+ u_int sense_len, uint8_t *cdb, int cdb_len,
+ struct scsi_inquiry_data *inq_data,
+ struct scsi_sense_desc_header *header);
+scsi_sense_data_type scsi_sense_type(struct scsi_sense_data *sense_data);
+
+void scsi_sense_only_sbuf(struct scsi_sense_data *sense, u_int sense_len,
+ struct sbuf *sb, char *path_str,
+ struct scsi_inquiry_data *inq_data, uint8_t *cdb,
+ int cdb_len);
+
#ifdef _KERNEL
int scsi_command_string(struct ccb_scsiio *csio, struct sbuf *sb);
int scsi_sense_sbuf(struct ccb_scsiio *csio, struct sbuf *sb,
@@ -1497,31 +2263,29 @@ int scsi_static_inquiry_match(caddr_t inqbuffer,
int scsi_devid_match(uint8_t *rhs, size_t rhs_len,
uint8_t *lhs, size_t lhs_len);
-static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
- int *error_code, int *sense_key,
- int *asc, int *ascq);
+void scsi_extract_sense(struct scsi_sense_data *sense, int *error_code,
+ int *sense_key, int *asc, int *ascq);
+void scsi_extract_sense_len(struct scsi_sense_data *sense,
+ u_int sense_len, int *error_code, int *sense_key,
+ int *asc, int *ascq, int show_errors);
+int scsi_get_sense_key(struct scsi_sense_data *sense, u_int sense_len,
+ int show_errors);
+int scsi_get_asc(struct scsi_sense_data *sense, u_int sense_len,
+ int show_errors);
+int scsi_get_ascq(struct scsi_sense_data *sense, u_int sense_len,
+ int show_errors);
static __inline void scsi_ulto2b(u_int32_t val, u_int8_t *bytes);
static __inline void scsi_ulto3b(u_int32_t val, u_int8_t *bytes);
static __inline void scsi_ulto4b(u_int32_t val, u_int8_t *bytes);
static __inline void scsi_u64to8b(u_int64_t val, u_int8_t *bytes);
-static __inline u_int32_t scsi_2btoul(u_int8_t *bytes);
-static __inline u_int32_t scsi_3btoul(u_int8_t *bytes);
-static __inline int32_t scsi_3btol(u_int8_t *bytes);
-static __inline u_int32_t scsi_4btoul(u_int8_t *bytes);
-static __inline u_int64_t scsi_8btou64(u_int8_t *bytes);
+static __inline uint32_t scsi_2btoul(const uint8_t *bytes);
+static __inline uint32_t scsi_3btoul(const uint8_t *bytes);
+static __inline int32_t scsi_3btol(const uint8_t *bytes);
+static __inline uint32_t scsi_4btoul(const uint8_t *bytes);
+static __inline uint64_t scsi_8btou64(const uint8_t *bytes);
static __inline void *find_mode_page_6(struct scsi_mode_header_6 *mode_header);
static __inline void *find_mode_page_10(struct scsi_mode_header_10 *mode_header);
-static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
- int *error_code, int *sense_key,
- int *asc, int *ascq)
-{
- *error_code = sense->error_code & SSD_ERRCODE;
- *sense_key = sense->flags & SSD_KEY;
- *asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
- *ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
-}
-
static __inline void
scsi_ulto2b(u_int32_t val, u_int8_t *bytes)
{
@@ -1563,20 +2327,20 @@ scsi_u64to8b(u_int64_t val, u_int8_t *bytes)
bytes[7] = val & 0xff;
}
-static __inline u_int32_t
-scsi_2btoul(u_int8_t *bytes)
+static __inline uint32_t
+scsi_2btoul(const uint8_t *bytes)
{
- u_int32_t rv;
+ uint32_t rv;
rv = (bytes[0] << 8) |
bytes[1];
return (rv);
}
-static __inline u_int32_t
-scsi_3btoul(u_int8_t *bytes)
+static __inline uint32_t
+scsi_3btoul(const uint8_t *bytes)
{
- u_int32_t rv;
+ uint32_t rv;
rv = (bytes[0] << 16) |
(bytes[1] << 8) |
@@ -1585,9 +2349,9 @@ scsi_3btoul(u_int8_t *bytes)
}
static __inline int32_t
-scsi_3btol(u_int8_t *bytes)
+scsi_3btol(const uint8_t *bytes)
{
- u_int32_t rc = scsi_3btoul(bytes);
+ uint32_t rc = scsi_3btoul(bytes);
if (rc & 0x00800000)
rc |= 0xff000000;
@@ -1595,10 +2359,10 @@ scsi_3btol(u_int8_t *bytes)
return (int32_t) rc;
}
-static __inline u_int32_t
-scsi_4btoul(u_int8_t *bytes)
+static __inline uint32_t
+scsi_4btoul(const uint8_t *bytes)
{
- u_int32_t rv;
+ uint32_t rv;
rv = (bytes[0] << 24) |
(bytes[1] << 16) |
@@ -1608,7 +2372,7 @@ scsi_4btoul(u_int8_t *bytes)
}
static __inline uint64_t
-scsi_8btou64(uint8_t *bytes)
+scsi_8btou64(const uint8_t *bytes)
{
uint64_t rv;
diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
index 91384b7..53d352e 100644
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -1691,9 +1691,10 @@ cddone(struct cam_periph *periph, union ccb *done_ccb)
if (have_sense) {
sense = &csio->sense_data;
- scsi_extract_sense(sense, &error_code,
- &sense_key,
- &asc, &ascq);
+ scsi_extract_sense_len(sense,
+ csio->sense_len - csio->sense_resid,
+ &error_code, &sense_key, &asc,
+ &ascq, /*show_errors*/ 1);
}
/*
* Attach to anything that claims to be a
@@ -3126,8 +3127,9 @@ cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
&& ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
int sense_key, error_code, asc, ascq;
- scsi_extract_sense(&ccb->csio.sense_data,
- &error_code, &sense_key, &asc, &ascq);
+ scsi_extract_sense_len(&ccb->csio.sense_data,
+ ccb->csio.sense_len - ccb->csio.sense_resid, &error_code,
+ &sense_key, &asc, &ascq, /*show_errors*/ 1);
if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
error = cd6byteworkaround(ccb);
}
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index a436318..ab46cf6 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -753,10 +753,10 @@ daclose(struct disk *dp)
int asc, ascq;
int sense_key, error_code;
- scsi_extract_sense(&ccb->csio.sense_data,
- &error_code,
- &sense_key,
- &asc, &ascq);
+ scsi_extract_sense_len(&ccb->csio.sense_data,
+ ccb->csio.sense_len - ccb->csio.sense_resid,
+ &error_code, &sense_key, &asc, &ascq,
+ /*show_errors*/ 1);
if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
scsi_sense_print(&ccb->csio);
} else {
@@ -916,10 +916,10 @@ dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t leng
int asc, ascq;
int sense_key, error_code;
- scsi_extract_sense(&csio.sense_data,
- &error_code,
- &sense_key,
- &asc, &ascq);
+ scsi_extract_sense_len(&csio.sense_data,
+ csio.sense_len - csio.sense_resid,
+ &error_code, &sense_key, &asc, &ascq,
+ /*show_errors*/ 1);
if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
scsi_sense_print(&csio);
} else {
@@ -1802,9 +1802,10 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
if (have_sense) {
sense = &csio->sense_data;
- scsi_extract_sense(sense, &error_code,
- &sense_key,
- &asc, &ascq);
+ scsi_extract_sense_len(sense,
+ csio->sense_len - csio->sense_resid,
+ &error_code, &sense_key, &asc,
+ &ascq, /*show_errors*/ 1);
}
/*
* Attach to anything that claims to be a
diff --git a/sys/cam/scsi/scsi_low.c b/sys/cam/scsi/scsi_low.c
index 1b2f4f6..60253cd 100644
--- a/sys/cam/scsi/scsi_low.c
+++ b/sys/cam/scsi/scsi_low.c
@@ -2577,12 +2577,16 @@ resume:
#ifdef SCSI_LOW_DEBUG
if (scsi_low_debug & SCSI_LOW_DEBUG_SENSE)
{
- printf("SENSE: [%x][%x][%x][%x][%x]\n",
- (u_int) cb->ccb_sense.error_code,
- (u_int) cb->ccb_sense.segment,
- (u_int) cb->ccb_sense.flags,
- (u_int) cb->ccb_sense.add_sense_code,
- (u_int) cb->ccb_sense.add_sense_code_qual);
+ int error_code, sense_key, asc, ascq;
+
+ scsi_extract_sense(&cb->ccb_sense,
+ &error_code,
+ &sense_key,
+ &asc,
+ &ascq);
+ printf("SENSE: [%x][%x][%x][%x]\n",
+ error_code, sense_key, asc,
+ ascq);
}
#endif /* SCSI_LOW_DEBUG */
}
diff --git a/sys/cam/scsi/scsi_sa.c b/sys/cam/scsi/scsi_sa.c
index 0d3ef1a..9a504b5 100644
--- a/sys/cam/scsi/scsi_sa.c
+++ b/sys/cam/scsi/scsi_sa.c
@@ -235,10 +235,10 @@ struct sa_softc {
*/
struct {
struct scsi_sense_data _last_io_sense;
- u_int32_t _last_io_resid;
+ u_int64_t _last_io_resid;
u_int8_t _last_io_cdb[CAM_MAX_CDBLEN];
struct scsi_sense_data _last_ctl_sense;
- u_int32_t _last_ctl_resid;
+ u_int64_t _last_ctl_resid;
u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN];
#define last_io_sense errinfo._last_io_sense
#define last_io_resid errinfo._last_io_resid
@@ -849,8 +849,10 @@ saioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
*/
if ((periph->flags & CAM_PERIPH_LOCKED) == 0) {
error = cam_periph_hold(periph, PRIBIO|PCATCH);
- if (error != 0)
+ if (error != 0) {
+ cam_periph_unlock(periph);
return (error);
+ }
didlockperiph = 1;
}
break;
@@ -884,12 +886,15 @@ saioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
* access to data structures.
*/
error = cam_periph_hold(periph, PRIBIO|PCATCH);
- if (error != 0)
+ if (error != 0) {
+ cam_periph_unlock(periph);
return (error);
+ }
didlockperiph = 1;
break;
default:
+ cam_periph_unlock(periph);
return (EINVAL);
}
}
@@ -2322,17 +2327,28 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
struct sa_softc *softc;
struct ccb_scsiio *csio;
struct scsi_sense_data *sense;
- u_int32_t resid = 0;
- int32_t info = 0;
+ uint64_t resid = 0;
+ int64_t info = 0;
cam_status status;
- int error_code, sense_key, asc, ascq, error, aqvalid;
+ int error_code, sense_key, asc, ascq, error, aqvalid, stream_valid;
+ int sense_len;
+ uint8_t stream_bits;
periph = xpt_path_periph(ccb->ccb_h.path);
softc = (struct sa_softc *)periph->softc;
csio = &ccb->csio;
sense = &csio->sense_data;
- scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq);
- aqvalid = sense->extra_len >= 6;
+ sense_len = csio->sense_len - csio->sense_resid;
+ scsi_extract_sense_len(sense, sense_len, &error_code, &sense_key,
+ &asc, &ascq, /*show_errors*/ 1);
+ if (asc != -1 && ascq != -1)
+ aqvalid = 1;
+ else
+ aqvalid = 0;
+ if (scsi_get_stream_info(sense, sense_len, NULL, &stream_bits) == 0)
+ stream_valid = 1;
+ else
+ stream_valid = 0;
error = 0;
status = csio->ccb_h.status & CAM_STATUS_MASK;
@@ -2343,9 +2359,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
* unit.
*/
if (status == CAM_SCSI_STATUS_ERROR) {
- if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
- info = (int32_t) scsi_4btoul(sense->info);
- resid = info;
+ if (scsi_get_sense_info(sense, sense_len, SSD_DESC_INFO, &resid,
+ &info) == 0) {
if ((softc->flags & SA_FLAG_FIXED) != 0)
resid *= softc->media_blksize;
} else {
@@ -2372,10 +2387,11 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
softc->last_resid_was_io = 0;
}
CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("CDB[0]=0x%x Key 0x%x "
- "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %d "
+ "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %jd "
"dxfer_len %d\n", csio->cdb_io.cdb_bytes[0] & 0xff,
sense_key, asc, ascq, status,
- sense->flags & ~SSD_KEY_RESERVED, resid, csio->dxfer_len));
+ (stream_valid) ? stream_bits : 0, (intmax_t)resid,
+ csio->dxfer_len));
} else {
CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
("Cam Status 0x%x\n", status));
@@ -2431,7 +2447,7 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
if (sense_key == SSD_KEY_VOLUME_OVERFLOW) {
csio->resid = resid;
error = ENOSPC;
- } else if (sense->flags & SSD_EOM) {
+ } else if ((stream_valid != 0) && (stream_bits & SSD_EOM)) {
softc->flags |= SA_FLAG_EOM_PENDING;
/*
* Grotesque as it seems, the few times
@@ -2450,7 +2466,7 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
} else {
error = EIO;
}
- } else if (sense->flags & SSD_FILEMARK) {
+ } else if ((stream_valid != 0) && (stream_bits & SSD_FILEMARK)){
if (softc->flags & SA_FLAG_FIXED) {
error = -1;
softc->flags |= SA_FLAG_EOF_PENDING;
@@ -2470,7 +2486,7 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
/*
* Incorrect Length usually applies to read, but can apply to writes.
*/
- if (error == 0 && (sense->flags & SSD_ILI)) {
+ if (error == 0 && (stream_valid != 0) && (stream_bits & SSD_ILI)) {
if (info < 0) {
xpt_print(csio->ccb_h.path, toobig,
csio->dxfer_len - info);
@@ -2485,7 +2501,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
* Bump the block number if we hadn't seen a filemark.
* Do this independent of errors (we've moved anyway).
*/
- if ((sense->flags & SSD_FILEMARK) == 0) {
+ if ((stream_valid == 0) ||
+ (stream_bits & SSD_FILEMARK) == 0) {
if (softc->blkno != (daddr_t) -1) {
softc->blkno++;
csio->ccb_h.ccb_pflags |=
diff --git a/sys/cam/scsi/scsi_targ_bh.c b/sys/cam/scsi/scsi_targ_bh.c
index b8c2379..d5887a1 100644
--- a/sys/cam/scsi/scsi_targ_bh.c
+++ b/sys/cam/scsi/scsi_targ_bh.c
@@ -112,20 +112,20 @@ static struct scsi_inquiry_data no_lun_inq_data =
/* version */2, /* format version */2
};
-static struct scsi_sense_data no_lun_sense_data =
+static struct scsi_sense_data_fixed no_lun_sense_data =
{
SSD_CURRENT_ERROR|SSD_ERRCODE_VALID,
0,
SSD_KEY_NOT_READY,
{ 0, 0, 0, 0 },
- /*extra_len*/offsetof(struct scsi_sense_data, fru)
- - offsetof(struct scsi_sense_data, extra_len),
+ /*extra_len*/offsetof(struct scsi_sense_data_fixed, fru)
+ - offsetof(struct scsi_sense_data_fixed, extra_len),
{ 0, 0, 0, 0 },
/* Logical Unit Not Supported */
/*ASC*/0x25, /*ASCQ*/0
};
-static const int request_sense_size = offsetof(struct scsi_sense_data, fru);
+static const int request_sense_size = offsetof(struct scsi_sense_data_fixed, fru);
static periph_init_t targbhinit;
static void targbhasync(void *callback_arg, u_int32_t code,
@@ -587,7 +587,9 @@ targbhdone(struct cam_periph *periph, union ccb *done_ccb)
* This needs to have other than a
* no_lun_sense_data response.
*/
- atio->sense_data = no_lun_sense_data;
+ bcopy(&no_lun_sense_data, &atio->sense_data,
+ min(sizeof(no_lun_sense_data),
+ sizeof(atio->sense_data)));
atio->sense_len = sizeof(no_lun_sense_data);
descr->data_resid = 0;
descr->data_increment = 0;
@@ -630,7 +632,9 @@ targbhdone(struct cam_periph *periph, union ccb *done_ccb)
/* Direction is always relative to the initator */
atio->ccb_h.flags &= ~CAM_DIR_MASK;
atio->ccb_h.flags |= CAM_DIR_NONE;
- atio->sense_data = no_lun_sense_data;
+ bcopy(&no_lun_sense_data, &atio->sense_data,
+ min(sizeof(no_lun_sense_data),
+ sizeof(atio->sense_data)));
atio->sense_len = sizeof (no_lun_sense_data);
descr->data_resid = 0;
descr->data_increment = 0;
OpenPOWER on IntegriCloud