From 8435f9722ef57363f1f4a5e2e3559a098a89741c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 21 Apr 2015 14:13:15 +0200 Subject: [PATCH] lib: Parse sense specific descriptor Extend struct scsi_sense with sense specific descriptor information, introduce the function scsi_parse_sense_data() and let that function parse the sense specific descriptor. Signed-off-by: Bart Van Assche --- include/scsi-lowlevel.h | 12 +++++++ lib/iscsi-command.c | 72 +++++++++++++++++++++++++++++++-------- lib/libiscsi.def | 1 + lib/libiscsi.syms | 1 + test-tool/iscsi-support.c | 14 +------- 5 files changed, 72 insertions(+), 28 deletions(-) diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index ca0e66e..307f12f 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -254,6 +254,16 @@ struct scsi_sense { unsigned char error_type; enum scsi_sense_key key; int ascq; + + /* + * Sense specific descriptor. See also paragraph "Sense key specific + * sense data descriptor" in SPC. + */ + unsigned sense_specific:1; + unsigned ill_param_in_cdb:1; + unsigned bit_pointer_valid:1; + unsigned char bit_pointer; + uint16_t field_pointer; }; struct scsi_data { @@ -1051,6 +1061,8 @@ EXTERN int scsi_datain_getfullsize(struct scsi_task *task); EXTERN void *scsi_datain_unmarshall(struct scsi_task *task); EXTERN void *scsi_cdb_unmarshall(struct scsi_task *task, enum scsi_opcode opcode); +EXTERN void scsi_parse_sense_data(struct scsi_sense *sense, const uint8_t *sb); + EXTERN struct scsi_task *scsi_cdb_compareandwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_get_lba_status(uint64_t starting_lba, uint32_t alloc_len); EXTERN struct scsi_task *scsi_cdb_orwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrprotect, int dpo, int fua, int fua_nv, int group_number); diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 81ed4f8..aefa327 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -340,6 +340,62 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, return 0; } +/* Parse a sense key specific sense data descriptor */ +static void parse_sense_spec(struct scsi_sense *sense, const uint8_t inf[3]) +{ + if (!(inf[0] & 0x80)) /* SKSV */ + return; + + sense->sense_specific = 1; + sense->ill_param_in_cdb = !!(inf[0] & 0x40); /* C/D flag */ + if (inf[0] & 8) { /* BPV */ + sense->bit_pointer_valid = 1; + sense->bit_pointer = inf[0] & 7; + } + sense->field_pointer = scsi_get_uint16(&inf[1]); +} + +/* Parse descriptor format sense data */ +static void parse_sense_descriptors(struct scsi_sense *sense, const uint8_t *sb, + unsigned sb_len) +{ + const unsigned char *p, *const end = sb + sb_len; + + for (p = sb; p < end; p += p[1]) { + if (p[1] < 4) /* length */ + break; + if (!(p[2] & 0x80)) /* VALID bit */ + break; + switch (p[0]) { + case 2: + /* Sense key specific sense data descriptor */ + parse_sense_spec(sense, p + 4); + break; + } + } +} + +void scsi_parse_sense_data(struct scsi_sense *sense, const uint8_t *sb) +{ + sense->error_type = sb[0] & 0x7f; + switch (sense->error_type) { + case 0x70: + case 0x71: + /* Fixed format */ + sense->key = sb[2] & 0x0f; + sense->ascq = scsi_get_uint16(&sb[12]); + parse_sense_spec(sense, sb + 15); + break; + case 0x72: + case 0x73: + /* Descriptor format */ + sense->key = sb[1] & 0x0f; + sense->ascq = scsi_get_uint16(&sb[2]); + parse_sense_descriptors(sense, sb + 8, sb[7]); + break; + } +} + int iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) @@ -416,21 +472,7 @@ iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, } memcpy(task->datain.data, in->data, task->datain.size); - task->sense.error_type = task->datain.data[2] & 0x7f; - switch (task->sense.error_type) { - case 0x70: - case 0x71: - task->sense.key = task->datain.data[4] & 0x0f; - task->sense.ascq = scsi_get_uint16( - &(task->datain.data[14])); - break; - case 0x72: - case 0x73: - task->sense.key = task->datain.data[3] & 0x0f; - task->sense.ascq = scsi_get_uint16( - &(task->datain.data[4])); - break; - } + scsi_parse_sense_data(&task->sense, &task->datain.data[2]); iscsi_set_error(iscsi, "SENSE KEY:%s(%d) ASCQ:%s(0x%04x)", scsi_sense_key_str(task->sense.key), task->sense.key, diff --git a/lib/libiscsi.def b/lib/libiscsi.def index fa37fc2..1491666 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -216,6 +216,7 @@ scsi_inquiry_pagecode_to_str scsi_malloc scsi_modesense_dataout_marshall scsi_modesense_get_page +scsi_parse_sense_data scsi_protocol_identifier_to_str scsi_reportluns_cdb scsi_sense_ascq_str diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index 5ca3acf..7b8a051 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -214,6 +214,7 @@ scsi_inquiry_pagecode_to_str scsi_malloc scsi_modesense_dataout_marshall scsi_modesense_get_page +scsi_parse_sense_data scsi_protocol_identifier_to_str scsi_reportluns_cdb scsi_sense_ascq_str diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 1421518..655d562 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -317,19 +317,7 @@ static struct scsi_task *send_scsi_command(struct scsi_device *sdev, struct scsi /* now for the error processing */ if(io_hdr.sb_len_wr > 0){ task->status = SCSI_STATUS_CHECK_CONDITION; - task->sense.error_type = sense[0] & 0x7f; - switch (task->sense.error_type) { - case 0x70: - case 0x71: - task->sense.key = sense[2] & 0x0f; - task->sense.ascq = scsi_get_uint16(&sense[12]); - break; - case 0x72: - case 0x73: - task->sense.key = sense[1] & 0x0f; - task->sense.ascq = scsi_get_uint16(&sense[2]); - break; - } + scsi_parse_sense_data(&task->sense, sense); sense_len=io_hdr.sb_len_wr; snprintf(buf, sizeof(buf), "SENSE KEY:%s(%d) ASCQ:%s(0x%04x)", scsi_sense_key_str(task->sense.key),