diff options
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 46 |
1 files changed, 27 insertions, 19 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index d7ec4ab2b111..8b89fab7c420 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -581,16 +581,36 @@ static bool scsi_end_request(struct request *req, blk_status_t error, return false; } +static inline u8 get_scsi_ml_byte(int result) +{ + return (result >> 8) & 0xff; +} + /** * scsi_result_to_blk_status - translate a SCSI result code into blk_status_t - * @cmd: SCSI command * @result: scsi error code * - * Translate a SCSI result code into a blk_status_t value. May reset the host - * byte of @cmd->result. + * Translate a SCSI result code into a blk_status_t value. */ -static blk_status_t scsi_result_to_blk_status(struct scsi_cmnd *cmd, int result) +static blk_status_t scsi_result_to_blk_status(int result) { + /* + * Check the scsi-ml byte first in case we converted a host or status + * byte. + */ + switch (get_scsi_ml_byte(result)) { + case SCSIML_STAT_OK: + break; + case SCSIML_STAT_RESV_CONFLICT: + return BLK_STS_NEXUS; + case SCSIML_STAT_NOSPC: + return BLK_STS_NOSPC; + case SCSIML_STAT_MED_ERROR: + return BLK_STS_MEDIUM; + case SCSIML_STAT_TGT_FAILURE: + return BLK_STS_TARGET; + } + switch (host_byte(result)) { case DID_OK: if (scsi_status_is_good(result)) @@ -599,18 +619,6 @@ static blk_status_t scsi_result_to_blk_status(struct scsi_cmnd *cmd, int result) case DID_TRANSPORT_FAILFAST: case DID_TRANSPORT_MARGINAL: return BLK_STS_TRANSPORT; - case DID_TARGET_FAILURE: - set_host_byte(cmd, DID_OK); - return BLK_STS_TARGET; - case DID_NEXUS_FAILURE: - set_host_byte(cmd, DID_OK); - return BLK_STS_NEXUS; - case DID_ALLOC_FAILURE: - set_host_byte(cmd, DID_OK); - return BLK_STS_NOSPC; - case DID_MEDIUM_ERROR: - set_host_byte(cmd, DID_OK); - return BLK_STS_MEDIUM; default: return BLK_STS_IOERR; } @@ -697,7 +705,7 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) if (sense_valid) sense_current = !scsi_sense_is_deferred(&sshdr); - blk_stat = scsi_result_to_blk_status(cmd, result); + blk_stat = scsi_result_to_blk_status(result); if (host_byte(result) == DID_RESET) { /* Third party bus reset or reset for error recovery @@ -878,14 +886,14 @@ static int scsi_io_completion_nz_result(struct scsi_cmnd *cmd, int result, SCSI_SENSE_BUFFERSIZE); } if (sense_current) - *blk_statp = scsi_result_to_blk_status(cmd, result); + *blk_statp = scsi_result_to_blk_status(result); } else if (blk_rq_bytes(req) == 0 && sense_current) { /* * Flush commands do not transfers any data, and thus cannot use * good_bytes != blk_rq_bytes(req) as the signal for an error. * This sets *blk_statp explicitly for the problem case. */ - *blk_statp = scsi_result_to_blk_status(cmd, result); + *blk_statp = scsi_result_to_blk_status(result); } /* * Recovered errors need reporting, but they're always treated as |