]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[scsi] Improve sense code parsing
authorMichael Brown <mcb30@ipxe.org>
Mon, 2 Jun 2014 01:17:28 +0000 (02:17 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 3 Jun 2014 01:04:46 +0000 (02:04 +0100)
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>
src/drivers/block/scsi.c
src/drivers/block/srp.c
src/include/ipxe/scsi.h
src/net/fcp.c
src/net/tcp/iscsi.c

index 4245f019b23dc2d792b2688ddc0ff0b06adf201d..64d692986c3d6c5dc4870279daaebbd411be66c9 100644 (file)
@@ -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 );
index 70a97b2f952566158939b0d4173761085a079aee..7edf69ace659d543d387a585f55eaba976628ce1 100644 (file)
@@ -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 );
index 6dfb7f1ea5e91b102c32b9e421eb9e15535604be..4428daac32bd2eb4bfa950082c9d5bb80d178ca5 100644 (file)
@@ -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 );
index 241b546385ae3df924d17d9a0a5734cbd3e81611..9c36a4c726c48c6e87cc5057fec6b44297df2ce7 100644 (file)
@@ -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.
index a6fcd251ba3e4ac508f3777a3f742aabc3a554b6..03c6d0f23e8c34c41f8ad64afcbe10c13d269f0d 100644 (file)
@@ -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 */