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@xxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> Reviewed-by: Chaitanya Kulkarni <kch@xxxxxxxxxx> --- drivers/scsi/sd.c | 35 ++++++++++++++++++++++++++++++++++- include/scsi/scsi.h | 1 + 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index eb76ba055021..bc60ec91dc8f 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1701,6 +1701,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) { @@ -1729,7 +1759,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, diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 3e46859774c8..ec093594ba53 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -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) -- 2.25.1