mirror of https://github.com/ipxe/ipxe.git
[scsi] Improve sense code parsing
Parse the sense data to extract the reponse code, the sense key, the additional sense code, and the additional sense code qualifier. Originally-implemented-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/10/merge
parent
d630052e6f
commit
e047811c85
|
@ -132,6 +132,33 @@ int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse SCSI sense data
|
||||||
|
*
|
||||||
|
* @v data Raw sense data
|
||||||
|
* @v len Length of raw sense data
|
||||||
|
* @v sense Descriptor-format sense data to fill in
|
||||||
|
*/
|
||||||
|
void scsi_parse_sense ( const void *data, size_t len,
|
||||||
|
struct scsi_sns_descriptor *sense ) {
|
||||||
|
const union scsi_sns *sns = data;
|
||||||
|
|
||||||
|
/* Avoid returning uninitialised data */
|
||||||
|
memset ( sense, 0, sizeof ( *sense ) );
|
||||||
|
|
||||||
|
/* Copy, assuming descriptor-format data */
|
||||||
|
if ( len < sizeof ( sns->desc ) )
|
||||||
|
return;
|
||||||
|
memcpy ( sense, &sns->desc, sizeof ( *sense ) );
|
||||||
|
|
||||||
|
/* Convert fixed-format to descriptor-format, if applicable */
|
||||||
|
if ( len < sizeof ( sns->fixed ) )
|
||||||
|
return;
|
||||||
|
if ( ! SCSI_SENSE_FIXED ( sns->code ) )
|
||||||
|
return;
|
||||||
|
sense->additional = sns->fixed.additional;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* Interface methods
|
* Interface methods
|
||||||
|
@ -468,9 +495,10 @@ static void scsicmd_response ( struct scsi_command *scsicmd,
|
||||||
underrun = -(response->overrun);
|
underrun = -(response->overrun);
|
||||||
DBGC ( scsidev, " underrun -%zd", underrun );
|
DBGC ( scsidev, " underrun -%zd", underrun );
|
||||||
}
|
}
|
||||||
DBGC ( scsidev, " sense %02x:%02x:%08x\n",
|
DBGC ( scsidev, " sense %02x key %02x additional %04x\n",
|
||||||
response->sense.code, response->sense.key,
|
( response->sense.code & SCSI_SENSE_CODE_MASK ),
|
||||||
ntohl ( response->sense.info ) );
|
( response->sense.key & SCSI_SENSE_KEY_MASK ),
|
||||||
|
ntohs ( response->sense.additional ) );
|
||||||
|
|
||||||
/* Construct error number from sense data */
|
/* Construct error number from sense data */
|
||||||
rc = -EIO_SENSE ( response->sense.key & SCSI_SENSE_KEY_MASK );
|
rc = -EIO_SENSE ( response->sense.key & SCSI_SENSE_KEY_MASK );
|
||||||
|
|
|
@ -476,12 +476,14 @@ static int srp_rsp ( struct srp_device *srpdev,
|
||||||
const struct srp_rsp *rsp = data;
|
const struct srp_rsp *rsp = data;
|
||||||
struct srp_command *srpcmd;
|
struct srp_command *srpcmd;
|
||||||
struct scsi_rsp response;
|
struct scsi_rsp response;
|
||||||
const void *sense;
|
|
||||||
ssize_t data_out_residual_count;
|
ssize_t data_out_residual_count;
|
||||||
ssize_t data_in_residual_count;
|
ssize_t data_in_residual_count;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if ( len < sizeof ( *rsp ) ) {
|
if ( ( len < sizeof ( *rsp ) ) ||
|
||||||
|
( len < ( sizeof ( *rsp ) +
|
||||||
|
srp_rsp_response_data_len ( rsp ) +
|
||||||
|
srp_rsp_sense_data_len ( rsp ) ) ) ) {
|
||||||
DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
|
DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
|
||||||
srpdev, len );
|
srpdev, len );
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -523,9 +525,8 @@ static int srp_rsp ( struct srp_device *srpdev,
|
||||||
} else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
|
} else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
|
||||||
response.overrun = -(data_in_residual_count);
|
response.overrun = -(data_in_residual_count);
|
||||||
}
|
}
|
||||||
sense = srp_rsp_sense_data ( rsp );
|
scsi_parse_sense ( srp_rsp_sense_data ( rsp ),
|
||||||
if ( sense )
|
srp_rsp_sense_data_len ( rsp ), &response.sense );
|
||||||
memcpy ( &response.sense, sense, sizeof ( response.sense ) );
|
|
||||||
|
|
||||||
/* Report SCSI response */
|
/* Report SCSI response */
|
||||||
scsi_response ( &srpcmd->scsi, &response );
|
scsi_response ( &srpcmd->scsi, &response );
|
||||||
|
|
|
@ -267,8 +267,8 @@ struct scsi_cmd {
|
||||||
size_t data_in_len;
|
size_t data_in_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** SCSI sense data */
|
/** SCSI fixed-format sense data */
|
||||||
struct scsi_sns {
|
struct scsi_sns_fixed {
|
||||||
/** Response code */
|
/** Response code */
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
/** Reserved */
|
/** Reserved */
|
||||||
|
@ -277,8 +277,44 @@ struct scsi_sns {
|
||||||
uint8_t key;
|
uint8_t key;
|
||||||
/** Information */
|
/** Information */
|
||||||
uint32_t info;
|
uint32_t info;
|
||||||
|
/** Additional sense length */
|
||||||
|
uint8_t len;
|
||||||
|
/** Command-specific information */
|
||||||
|
uint32_t cs_info;
|
||||||
|
/** Additional sense code and qualifier */
|
||||||
|
uint16_t additional;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** SCSI descriptor-format sense data */
|
||||||
|
struct scsi_sns_descriptor {
|
||||||
|
/** Response code */
|
||||||
|
uint8_t code;
|
||||||
|
/** Sense key */
|
||||||
|
uint8_t key;
|
||||||
|
/** Additional sense code and qualifier */
|
||||||
|
uint16_t additional;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** SCSI sense data */
|
||||||
|
union scsi_sns {
|
||||||
|
/** Response code */
|
||||||
|
uint8_t code;
|
||||||
|
/** Fixed-format sense data */
|
||||||
|
struct scsi_sns_fixed fixed;
|
||||||
|
/** Descriptor-format sense data */
|
||||||
|
struct scsi_sns_descriptor desc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** SCSI sense response code mask */
|
||||||
|
#define SCSI_SENSE_CODE_MASK 0x7f
|
||||||
|
|
||||||
|
/** Test if SCSI sense data is in fixed format
|
||||||
|
*
|
||||||
|
* @v code Response code
|
||||||
|
* @ret is_fixed Sense data is in fixed format
|
||||||
|
*/
|
||||||
|
#define SCSI_SENSE_FIXED( code ) ( ( (code) & 0x7e ) == 0x70 )
|
||||||
|
|
||||||
/** SCSI sense key mask */
|
/** SCSI sense key mask */
|
||||||
#define SCSI_SENSE_KEY_MASK 0x0f
|
#define SCSI_SENSE_KEY_MASK 0x0f
|
||||||
|
|
||||||
|
@ -288,11 +324,18 @@ struct scsi_rsp {
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
/** Data overrun (or negative underrun) */
|
/** Data overrun (or negative underrun) */
|
||||||
ssize_t overrun;
|
ssize_t overrun;
|
||||||
/** Autosense data (if any) */
|
/** Autosense data (if any)
|
||||||
struct scsi_sns sense;
|
*
|
||||||
|
* To minimise code size, this is stored as the first four
|
||||||
|
* bytes of a descriptor-format sense data block (even if the
|
||||||
|
* response code indicates fixed-format sense data).
|
||||||
|
*/
|
||||||
|
struct scsi_sns_descriptor sense;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun );
|
extern int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun );
|
||||||
|
extern void scsi_parse_sense ( const void *data, size_t len,
|
||||||
|
struct scsi_sns_descriptor *sense );
|
||||||
|
|
||||||
extern int scsi_command ( struct interface *control, struct interface *data,
|
extern int scsi_command ( struct interface *control, struct interface *data,
|
||||||
struct scsi_cmd *command );
|
struct scsi_cmd *command );
|
||||||
|
|
|
@ -551,7 +551,6 @@ static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd,
|
||||||
struct fcp_device *fcpdev = fcpcmd->fcpdev;
|
struct fcp_device *fcpdev = fcpcmd->fcpdev;
|
||||||
struct scsi_cmd *command = &fcpcmd->command;
|
struct scsi_cmd *command = &fcpcmd->command;
|
||||||
struct fcp_rsp *rsp = iobuf->data;
|
struct fcp_rsp *rsp = iobuf->data;
|
||||||
struct scsi_sense *sense;
|
|
||||||
struct scsi_rsp response;
|
struct scsi_rsp response;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -607,8 +606,8 @@ static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd,
|
||||||
if ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN )
|
if ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN )
|
||||||
response.overrun = -response.overrun;
|
response.overrun = -response.overrun;
|
||||||
}
|
}
|
||||||
if ( ( sense = fcp_rsp_sense_data ( rsp ) ) != NULL )
|
scsi_parse_sense ( fcp_rsp_sense_data ( rsp ),
|
||||||
memcpy ( &response.sense, sense, sizeof ( response.sense ) );
|
fcp_rsp_sense_data_len ( rsp ), &response.sense );
|
||||||
|
|
||||||
/* Free buffer before sending response, to minimise
|
/* Free buffer before sending response, to minimise
|
||||||
* out-of-memory errors.
|
* out-of-memory errors.
|
||||||
|
|
|
@ -412,11 +412,12 @@ static int iscsi_rx_scsi_response ( struct iscsi_session *iscsi,
|
||||||
= &iscsi->rx_bhs.scsi_response;
|
= &iscsi->rx_bhs.scsi_response;
|
||||||
struct scsi_rsp rsp;
|
struct scsi_rsp rsp;
|
||||||
uint32_t residual_count;
|
uint32_t residual_count;
|
||||||
|
size_t data_len;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Buffer up the PDU data */
|
/* Buffer up the PDU data */
|
||||||
if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
|
if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
|
||||||
DBGC ( iscsi, "iSCSI %p could not buffer login response: %s\n",
|
DBGC ( iscsi, "iSCSI %p could not buffer SCSI response: %s\n",
|
||||||
iscsi, strerror ( rc ) );
|
iscsi, strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -432,9 +433,11 @@ static int iscsi_rx_scsi_response ( struct iscsi_session *iscsi,
|
||||||
} else if ( response->flags & ISCSI_DATA_FLAG_UNDERFLOW ) {
|
} else if ( response->flags & ISCSI_DATA_FLAG_UNDERFLOW ) {
|
||||||
rsp.overrun = -(residual_count);
|
rsp.overrun = -(residual_count);
|
||||||
}
|
}
|
||||||
if ( ISCSI_DATA_LEN ( response->lengths ) )
|
data_len = ISCSI_DATA_LEN ( response->lengths );
|
||||||
memcpy ( &rsp.sense, ( iscsi->rx_buffer + 2 ),
|
if ( data_len ) {
|
||||||
sizeof ( rsp.sense ) );
|
scsi_parse_sense ( ( iscsi->rx_buffer + 2 ), ( data_len - 2 ),
|
||||||
|
&rsp.sense );
|
||||||
|
}
|
||||||
iscsi_rx_buffered_data_done ( iscsi );
|
iscsi_rx_buffered_data_done ( iscsi );
|
||||||
|
|
||||||
/* Check for errors */
|
/* Check for errors */
|
||||||
|
|
Loading…
Reference in New Issue