OSDN Git Service

scsi: sd: Convert SCSI errors to PR errors
authorMike Christie <michael.christie@oracle.com>
Tue, 22 Nov 2022 03:26:02 +0000 (21:26 -0600)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 1 Dec 2022 03:22:23 +0000 (03:22 +0000)
This converts the SCSI errors we commonly see during PR handling to PR_STS
errors or -Exyz errors. pr_ops callers can then handle SCSI and NVMe errors
without knowing the device types.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
Link: https://lore.kernel.org/r/20221122032603.32766-4-michael.christie@oracle.com
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/sd.c
include/scsi/scsi.h

index faa2b55..47dafe6 100644 (file)
@@ -1709,6 +1709,36 @@ static char sd_pr_type(enum pr_type type)
        }
 };
 
+static int sd_scsi_to_pr_err(struct scsi_sense_hdr *sshdr, int result)
+{
+       switch (host_byte(result)) {
+       case DID_TRANSPORT_MARGINAL:
+       case DID_TRANSPORT_DISRUPTED:
+       case DID_BUS_BUSY:
+               return PR_STS_RETRY_PATH_FAILURE;
+       case DID_NO_CONNECT:
+               return PR_STS_PATH_FAILED;
+       case DID_TRANSPORT_FAILFAST:
+               return PR_STS_PATH_FAST_FAILED;
+       }
+
+       switch (status_byte(result)) {
+       case SAM_STAT_RESERVATION_CONFLICT:
+               return PR_STS_RESERVATION_CONFLICT;
+       case SAM_STAT_CHECK_CONDITION:
+               if (!scsi_sense_valid(sshdr))
+                       return PR_STS_IOERR;
+
+               if (sshdr->sense_key == ILLEGAL_REQUEST &&
+                   (sshdr->asc == 0x26 || sshdr->asc == 0x24))
+                       return -EINVAL;
+
+               fallthrough;
+       default:
+               return PR_STS_IOERR;
+       }
+}
+
 static int sd_pr_command(struct block_device *bdev, u8 sa,
                u64 key, u64 sa_key, u8 type, u8 flags)
 {
@@ -1737,7 +1767,10 @@ static int sd_pr_command(struct block_device *bdev, u8 sa,
                scsi_print_sense_hdr(sdev, NULL, &sshdr);
        }
 
-       return result;
+       if (result <= 0)
+               return result;
+
+       return sd_scsi_to_pr_err(&sshdr, result);
 }
 
 static int sd_pr_register(struct block_device *bdev, u64 old_key, u64 new_key,
index 3e46859..ec09359 100644 (file)
@@ -121,6 +121,7 @@ enum scsi_disposition {
  *      msg_byte    (unused)
  *      host_byte   = set by low-level driver to indicate status.
  */
+#define status_byte(result) (result & 0xff)
 #define host_byte(result)   (((result) >> 16) & 0xff)
 
 #define sense_class(sense)  (((sense) >> 4) & 0x7)