Skip to content

Commit

Permalink
[scsi] Improve sense code parsing
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcb30 committed Jun 3, 2014
1 parent d630052 commit e047811
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 19 deletions.
34 changes: 31 additions & 3 deletions src/drivers/block/scsi.c
Expand Up @@ -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
Expand Down Expand Up @@ -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 );
Expand Down
11 changes: 6 additions & 5 deletions src/drivers/block/srp.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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 );
Expand Down
51 changes: 47 additions & 4 deletions src/include/ipxe/scsi.h
Expand Up @@ -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 */
Expand All @@ -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

Expand All @@ -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 );
Expand Down
5 changes: 2 additions & 3 deletions src/net/fcp.c
Expand Up @@ -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;

Expand Down Expand Up @@ -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.
Expand Down
11 changes: 7 additions & 4 deletions src/net/tcp/iscsi.c
Expand Up @@ -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;
}
Expand All @@ -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 */
Expand Down

0 comments on commit e047811

Please sign in to comment.