diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 94ff279b3b4a..98e4ffaa8b06 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -5094,6 +5094,85 @@ static int corrupt_lbas(struct sdebug_dev_info *devip, u64 lba, u32 num, return error; } +/* + * Returns 0 upon success or -1 with *scsi_status set to a SCSI status code upon + * failure. + */ +static int __resp_write_dt0_dix(struct scsi_cmnd *scp, + u64 lba, u32 num, + u32 ei_lba, int *scsi_status) +{ + switch (prot_verify_write(scp, lba, num, ei_lba)) { + case 1: /* Guard tag error */ + 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; + } + if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ + mk_sense_buffer(scp, ABORTED_COMMAND, + LOGICAL_BLOCK_GUARD_CHECK_FAILED); + *scsi_status = check_condition_result; + return -1; + } + break; + case 3: /* Reference tag error */ + 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; + } + if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ + mk_sense_buffer(scp, ABORTED_COMMAND, + LOGICAL_BLOCK_REFERENCE_TAG_CHECK_FAILED); + *scsi_status = check_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_write_dt0(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip, + struct sdeb_store_info *sip, u64 lba, u32 num, + u32 ei_lba, u8 group, bool lbp, int *scsi_status) +{ + int ret; + + *scsi_status = check_device_access_params(scp, lba, num, true); + if (*scsi_status) + return -1; + + /* DIX + T10 DIF */ + if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { + ret = __resp_write_dt0_dix(scp, lba, num, ei_lba, + scsi_status); + if (ret < 0) + return ret; + } + + ret = do_device_access(sip, scp, 0, lba, num, group, true, false); + if (ret < 0) + *scsi_status = DID_ERROR << 16; + + if (unlikely(lbp)) + map_region(sip, lba, num); + + /* If ZBC zone then bump its write pointer */ + if (sdebug_dev_is_zoned(devip) && ret > 0) + zbc_inc_wp(devip, lba, ret >> ilog2(sdebug_sector_size)); + + return ret; +} + static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { bool check_prot; @@ -5104,7 +5183,7 @@ static int resp_write_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 = DID_ERROR << 16; bool lbp = scsi_debug_lbp(); if (unlikely(sdebug_opts & SDEBUG_OPT_UNALIGNED_WRITE && @@ -5174,60 +5253,16 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) if (sdebug_dev_is_zoned(devip) || (sdebug_dix && scsi_prot_sg_count(scp)) || lbp) { sdeb_meta_write_lock(sip); - meta_data_locked = true; - } - - ret = check_device_access_params(scp, lba, num, true); - if (ret) { - if (meta_data_locked) - sdeb_meta_write_unlock(sip); - return ret; - } - - /* DIX + T10 DIF */ - if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { - switch (prot_verify_write(scp, lba, num, ei_lba)) { - case 1: /* Guard tag error */ - if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { - sdeb_meta_write_unlock(sip); - mk_sense_buffer(scp, ILLEGAL_REQUEST, - LOGICAL_BLOCK_GUARD_CHECK_FAILED); - return illegal_condition_result; - } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ - sdeb_meta_write_unlock(sip); - mk_sense_buffer(scp, ABORTED_COMMAND, - LOGICAL_BLOCK_GUARD_CHECK_FAILED); - return check_condition_result; - } - break; - case 3: /* Reference tag error */ - if (scp->prot_flags & SCSI_PROT_REF_CHECK) { - sdeb_meta_write_unlock(sip); - mk_sense_buffer(scp, ILLEGAL_REQUEST, - LOGICAL_BLOCK_REFERENCE_TAG_CHECK_FAILED); - return illegal_condition_result; - } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ - sdeb_meta_write_unlock(sip); - mk_sense_buffer(scp, ABORTED_COMMAND, - LOGICAL_BLOCK_REFERENCE_TAG_CHECK_FAILED); - return check_condition_result; - } - break; - } - } - - ret = do_device_access(sip, scp, 0, lba, num, group, true, false); - if (unlikely(lbp)) - map_region(sip, lba, num); - - /* If ZBC zone then bump its write pointer over the data written */ - if (sdebug_dev_is_zoned(devip) && ret > 0) - zbc_inc_wp(devip, lba, ret >> ilog2(sdebug_sector_size)); - if (meta_data_locked) + ret = __resp_write_dt0(scp, devip, sip, lba, num, ei_lba, group, + lbp, &scsi_status); sdeb_meta_write_unlock(sip); + } else { + ret = __resp_write_dt0(scp, devip, sip, lba, num, ei_lba, group, + lbp, &scsi_status); + } if (unlikely(-1 == ret)) - return DID_ERROR << 16; + return scsi_status; else if (unlikely(sdebug_verbose && (ret < (num * sdebug_sector_size)))) sdev_printk(KERN_INFO, scp->device,