diff options
Diffstat (limited to 'sys/cam')
-rw-r--r-- | sys/cam/cam_ccb.h | 2 | ||||
-rw-r--r-- | sys/cam/cam_periph.c | 31 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_all.c | 1667 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_all.h | 878 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_cd.c | 12 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_da.c | 23 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_low.c | 16 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_sa.c | 53 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_targ_bh.c | 16 |
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; |