Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-block.git] / drivers / scsi / scsi_lib.c
index d7ec4ab2b1117f3fb9cb50479fb1dc4a4e805d18..8b89fab7c4206353e419dbf1f6e56771a17699f9 100644 (file)
@@ -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