aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2014-06-02 02:17:28 +0100
committerMichael Brown <mcb30@ipxe.org>2014-06-03 02:04:46 +0100
commite047811c859bd11777c9a01d7ca89ca948567199 (patch)
treec84557d88a049527dfc80631dcc3d9cb3bed2380 /src
parentd630052e6f44ce215503fb7f20819a1382ebfa9b (diff)
downloadipxe-e047811c859bd11777c9a01d7ca89ca948567199.tar.gz
[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>
Diffstat (limited to 'src')
-rw-r--r--src/drivers/block/scsi.c34
-rw-r--r--src/drivers/block/srp.c11
-rw-r--r--src/include/ipxe/scsi.h51
-rw-r--r--src/net/fcp.c5
-rw-r--r--src/net/tcp/iscsi.c11
5 files changed, 93 insertions, 19 deletions
diff --git a/src/drivers/block/scsi.c b/src/drivers/block/scsi.c
index 4245f019b..64d692986 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 70a97b2f9..7edf69ace 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 6dfb7f1ea..4428daac3 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 241b54638..9c36a4c72 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 a6fcd251b..03c6d0f23 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 */