diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index eafcadc6ef07..94ff279b3b4a 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -4608,6 +4608,70 @@ static int resp_read_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) return 0; } +/* + * Returns 0 upon success or -1 with *scsi_status set to a SCSI status code upon + * failure. + */ +static int __resp_read_dt0_dix(struct scsi_cmnd *scp, u64 lba, u32 num, + u32 ei_lba, int *scsi_status) +{ + const u8 *const cmd = scp->cmnd; + + switch (prot_verify_read(scp, lba, num, ei_lba)) { + case 1: /* Guard tag error */ + if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ + mk_sense_buffer(scp, ABORTED_COMMAND, + LOGICAL_BLOCK_GUARD_CHECK_FAILED); + *scsi_status = check_condition_result; + return -1; + } + if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + LOGICAL_BLOCK_GUARD_CHECK_FAILED); + *scsi_status = illegal_condition_result; + return -1; + } + break; + case 3: /* Reference tag error */ + if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ + mk_sense_buffer(scp, ABORTED_COMMAND, + LOGICAL_BLOCK_REFERENCE_TAG_CHECK_FAILED); + *scsi_status = check_condition_result; + return -1; + } + if (scp->prot_flags & SCSI_PROT_REF_CHECK) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + LOGICAL_BLOCK_REFERENCE_TAG_CHECK_FAILED); + *scsi_status = illegal_condition_result; + return -1; + } + break; + } + return 0; +} + +/* + * Returns the number of bytes transferred, or -1 with *scsi_status set to a + * SCSI status code on failure. + */ +static int __resp_read_dt0(struct scsi_cmnd *scp, struct sdeb_store_info *sip, + u64 lba, u32 num, u32 ei_lba, int *scsi_status) +{ + int ret; + + /* DIX + T10 DIF */ + if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { + ret = __resp_read_dt0_dix(scp, lba, num, ei_lba, scsi_status); + if (ret < 0) + return ret; + } + + ret = do_device_access(sip, scp, 0, lba, num, 0, false, false); + if (ret < 0) + *scsi_status = DID_ERROR << 16; + return ret; +} + static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { bool check_prot; @@ -4617,7 +4681,7 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) u64 lba; struct sdeb_store_info *sip = devip2sip(devip, true); u8 *cmd = scp->cmnd; - bool meta_data_locked = false; + int scsi_status; switch (cmd[0]) { case READ_16: @@ -4699,48 +4763,16 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) } if (sdebug_dev_is_zoned(devip) || - (sdebug_dix && scsi_prot_sg_count(scp))) { + (sdebug_dix && scsi_prot_sg_count(scp))) { sdeb_meta_read_lock(sip); - meta_data_locked = true; - } - - /* DIX + T10 DIF */ - if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { - switch (prot_verify_read(scp, lba, num, ei_lba)) { - case 1: /* Guard tag error */ - if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ - sdeb_meta_read_unlock(sip); - mk_sense_buffer(scp, ABORTED_COMMAND, - LOGICAL_BLOCK_GUARD_CHECK_FAILED); - return check_condition_result; - } else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { - sdeb_meta_read_unlock(sip); - mk_sense_buffer(scp, ILLEGAL_REQUEST, - LOGICAL_BLOCK_GUARD_CHECK_FAILED); - return illegal_condition_result; - } - break; - case 3: /* Reference tag error */ - if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ - sdeb_meta_read_unlock(sip); - mk_sense_buffer(scp, ABORTED_COMMAND, - LOGICAL_BLOCK_REFERENCE_TAG_CHECK_FAILED); - return check_condition_result; - } else if (scp->prot_flags & SCSI_PROT_REF_CHECK) { - sdeb_meta_read_unlock(sip); - mk_sense_buffer(scp, ILLEGAL_REQUEST, - LOGICAL_BLOCK_REFERENCE_TAG_CHECK_FAILED); - return illegal_condition_result; - } - break; - } - } - - ret = do_device_access(sip, scp, 0, lba, num, 0, false, false); - if (meta_data_locked) + ret = __resp_read_dt0(scp, sip, lba, num, ei_lba, &scsi_status); sdeb_meta_read_unlock(sip); - if (unlikely(ret == -1)) - return DID_ERROR << 16; + } else { + ret = __resp_read_dt0(scp, sip, lba, num, ei_lba, &scsi_status); + } + + if (unlikely(ret < 0)) + return scsi_status; scsi_set_resid(scp, scsi_bufflen(scp) - ret);