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 <bart.vanassche@sandisk.com>
This commit is contained in:
committed by
Ronnie Sahlberg
parent
fbc87ab12f
commit
8435f9722e
@@ -254,6 +254,16 @@ struct scsi_sense {
|
|||||||
unsigned char error_type;
|
unsigned char error_type;
|
||||||
enum scsi_sense_key key;
|
enum scsi_sense_key key;
|
||||||
int ascq;
|
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 {
|
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_datain_unmarshall(struct scsi_task *task);
|
||||||
EXTERN void *scsi_cdb_unmarshall(struct scsi_task *task, enum scsi_opcode opcode);
|
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_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_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);
|
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);
|
||||||
|
|||||||
@@ -340,6 +340,62 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
|
|||||||
return 0;
|
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
|
int
|
||||||
iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
||||||
struct iscsi_in_pdu *in)
|
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);
|
memcpy(task->datain.data, in->data, task->datain.size);
|
||||||
|
|
||||||
task->sense.error_type = task->datain.data[2] & 0x7f;
|
scsi_parse_sense_data(&task->sense, &task->datain.data[2]);
|
||||||
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;
|
|
||||||
}
|
|
||||||
iscsi_set_error(iscsi, "SENSE KEY:%s(%d) ASCQ:%s(0x%04x)",
|
iscsi_set_error(iscsi, "SENSE KEY:%s(%d) ASCQ:%s(0x%04x)",
|
||||||
scsi_sense_key_str(task->sense.key),
|
scsi_sense_key_str(task->sense.key),
|
||||||
task->sense.key,
|
task->sense.key,
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ scsi_inquiry_pagecode_to_str
|
|||||||
scsi_malloc
|
scsi_malloc
|
||||||
scsi_modesense_dataout_marshall
|
scsi_modesense_dataout_marshall
|
||||||
scsi_modesense_get_page
|
scsi_modesense_get_page
|
||||||
|
scsi_parse_sense_data
|
||||||
scsi_protocol_identifier_to_str
|
scsi_protocol_identifier_to_str
|
||||||
scsi_reportluns_cdb
|
scsi_reportluns_cdb
|
||||||
scsi_sense_ascq_str
|
scsi_sense_ascq_str
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ scsi_inquiry_pagecode_to_str
|
|||||||
scsi_malloc
|
scsi_malloc
|
||||||
scsi_modesense_dataout_marshall
|
scsi_modesense_dataout_marshall
|
||||||
scsi_modesense_get_page
|
scsi_modesense_get_page
|
||||||
|
scsi_parse_sense_data
|
||||||
scsi_protocol_identifier_to_str
|
scsi_protocol_identifier_to_str
|
||||||
scsi_reportluns_cdb
|
scsi_reportluns_cdb
|
||||||
scsi_sense_ascq_str
|
scsi_sense_ascq_str
|
||||||
|
|||||||
@@ -317,19 +317,7 @@ static struct scsi_task *send_scsi_command(struct scsi_device *sdev, struct scsi
|
|||||||
/* now for the error processing */
|
/* now for the error processing */
|
||||||
if(io_hdr.sb_len_wr > 0){
|
if(io_hdr.sb_len_wr > 0){
|
||||||
task->status = SCSI_STATUS_CHECK_CONDITION;
|
task->status = SCSI_STATUS_CHECK_CONDITION;
|
||||||
task->sense.error_type = sense[0] & 0x7f;
|
scsi_parse_sense_data(&task->sense, sense);
|
||||||
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;
|
|
||||||
}
|
|
||||||
sense_len=io_hdr.sb_len_wr;
|
sense_len=io_hdr.sb_len_wr;
|
||||||
snprintf(buf, sizeof(buf), "SENSE KEY:%s(%d) ASCQ:%s(0x%04x)",
|
snprintf(buf, sizeof(buf), "SENSE KEY:%s(%d) ASCQ:%s(0x%04x)",
|
||||||
scsi_sense_key_str(task->sense.key),
|
scsi_sense_key_str(task->sense.key),
|
||||||
|
|||||||
Reference in New Issue
Block a user