From e047811c859bd11777c9a01d7ca89ca948567199 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 2 Jun 2014 02:17:28 +0100 Subject: [PATCH] [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 Signed-off-by: Michael Brown --- src/drivers/block/scsi.c | 34 ++++++++++++++++++++++++--- src/drivers/block/srp.c | 11 +++++---- src/include/ipxe/scsi.h | 51 ++++++++++++++++++++++++++++++++++++---- src/net/fcp.c | 5 ++-- src/net/tcp/iscsi.c | 11 +++++---- 5 files changed, 93 insertions(+), 19 deletions(-) diff --git a/src/drivers/block/scsi.c b/src/drivers/block/scsi.c index 4245f019..64d69298 100644 --- a/src/drivers/block/scsi.c +++ b/src/drivers/block/scsi.c @@ -132,6 +132,33 @@ int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun ) { 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 @@ -468,9 +495,10 @@ static void scsicmd_response ( struct scsi_command *scsicmd, underrun = -(response->overrun); DBGC ( scsidev, " underrun -%zd", underrun ); } - DBGC ( scsidev, " sense %02x:%02x:%08x\n", - response->sense.code, response->sense.key, - ntohl ( response->sense.info ) ); + DBGC ( scsidev, " sense %02x key %02x additional %04x\n", + ( response->sense.code & SCSI_SENSE_CODE_MASK ), + ( response->sense.key & SCSI_SENSE_KEY_MASK ), + ntohs ( response->sense.additional ) ); /* Construct error number from sense data */ rc = -EIO_SENSE ( response->sense.key & SCSI_SENSE_KEY_MASK ); diff --git a/src/drivers/block/srp.c b/src/drivers/block/srp.c index 70a97b2f..7edf69ac 100644 --- a/src/drivers/block/srp.c +++ b/src/drivers/block/srp.c @@ -476,12 +476,14 @@ static int srp_rsp ( struct srp_device *srpdev, const struct srp_rsp *rsp = data; struct srp_command *srpcmd; struct scsi_rsp response; - const void *sense; ssize_t data_out_residual_count; ssize_t data_in_residual_count; /* 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", srpdev, len ); return -EINVAL; @@ -523,9 +525,8 @@ static int srp_rsp ( struct srp_device *srpdev, } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) { response.overrun = -(data_in_residual_count); } - sense = srp_rsp_sense_data ( rsp ); - if ( sense ) - memcpy ( &response.sense, sense, sizeof ( response.sense ) ); + scsi_parse_sense ( srp_rsp_sense_data ( rsp ), + srp_rsp_sense_data_len ( rsp ), &response.sense ); /* Report SCSI response */ scsi_response ( &srpcmd->scsi, &response ); diff --git a/src/include/ipxe/scsi.h b/src/include/ipxe/scsi.h index 6dfb7f1e..4428daac 100644 --- a/src/include/ipxe/scsi.h +++ b/src/include/ipxe/scsi.h @@ -267,8 +267,8 @@ struct scsi_cmd { size_t data_in_len; }; -/** SCSI sense data */ -struct scsi_sns { +/** SCSI fixed-format sense data */ +struct scsi_sns_fixed { /** Response code */ uint8_t code; /** Reserved */ @@ -277,8 +277,44 @@ struct scsi_sns { uint8_t key; /** Information */ 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 */ #define SCSI_SENSE_KEY_MASK 0x0f @@ -288,11 +324,18 @@ struct scsi_rsp { uint8_t status; /** Data overrun (or negative underrun) */ ssize_t overrun; - /** Autosense data (if any) */ - struct scsi_sns sense; + /** Autosense data (if any) + * + * 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 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, struct scsi_cmd *command ); diff --git a/src/net/fcp.c b/src/net/fcp.c index 241b5463..9c36a4c7 100644 --- a/src/net/fcp.c +++ b/src/net/fcp.c @@ -551,7 +551,6 @@ static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd, struct fcp_device *fcpdev = fcpcmd->fcpdev; struct scsi_cmd *command = &fcpcmd->command; struct fcp_rsp *rsp = iobuf->data; - struct scsi_sense *sense; struct scsi_rsp response; int rc; @@ -607,8 +606,8 @@ static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd, if ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN ) response.overrun = -response.overrun; } - if ( ( sense = fcp_rsp_sense_data ( rsp ) ) != NULL ) - memcpy ( &response.sense, sense, sizeof ( response.sense ) ); + scsi_parse_sense ( fcp_rsp_sense_data ( rsp ), + fcp_rsp_sense_data_len ( rsp ), &response.sense ); /* Free buffer before sending response, to minimise * out-of-memory errors. diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index a6fcd251..03c6d0f2 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -412,11 +412,12 @@ static int iscsi_rx_scsi_response ( struct iscsi_session *iscsi, = &iscsi->rx_bhs.scsi_response; struct scsi_rsp rsp; uint32_t residual_count; + size_t data_len; int rc; /* Buffer up the PDU data */ 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 ) ); return rc; } @@ -432,9 +433,11 @@ static int iscsi_rx_scsi_response ( struct iscsi_session *iscsi, } else if ( response->flags & ISCSI_DATA_FLAG_UNDERFLOW ) { rsp.overrun = -(residual_count); } - if ( ISCSI_DATA_LEN ( response->lengths ) ) - memcpy ( &rsp.sense, ( iscsi->rx_buffer + 2 ), - sizeof ( rsp.sense ) ); + data_len = ISCSI_DATA_LEN ( response->lengths ); + if ( data_len ) { + scsi_parse_sense ( ( iscsi->rx_buffer + 2 ), ( data_len - 2 ), + &rsp.sense ); + } iscsi_rx_buffered_data_done ( iscsi ); /* Check for errors */