diff options
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 51 |
1 files changed, 46 insertions, 5 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index eb76ba055021..47dafe6b8a66 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1026,8 +1026,13 @@ static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd) /* flush requests don't perform I/O, zero the S/G table */ memset(&cmd->sdb, 0, sizeof(cmd->sdb)); - cmd->cmnd[0] = SYNCHRONIZE_CACHE; - cmd->cmd_len = 10; + if (cmd->device->use_16_for_sync) { + cmd->cmnd[0] = SYNCHRONIZE_CACHE_16; + cmd->cmd_len = 16; + } else { + cmd->cmnd[0] = SYNCHRONIZE_CACHE; + cmd->cmd_len = 10; + } cmd->transfersize = 0; cmd->allowed = sdkp->max_retries; @@ -1587,9 +1592,12 @@ static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr) sshdr = &my_sshdr; for (retries = 3; retries > 0; --retries) { - unsigned char cmd[10] = { 0 }; + unsigned char cmd[16] = { 0 }; - cmd[0] = SYNCHRONIZE_CACHE; + if (sdp->use_16_for_sync) + cmd[0] = SYNCHRONIZE_CACHE_16; + else + cmd[0] = SYNCHRONIZE_CACHE; /* * Leave the rest of the command zero to indicate * flush everything. @@ -1701,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) { @@ -1729,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, |