In preparation for adding support for the WRITE SAME(16) NDOB flag, move configuration of the WRITE_ZEROES operation to a separate function. This is done to facilitate fetching all VPD pages before choosing the appropriate zeroing method for a given device. The deferred configuration also allows us to mirror the discard behavior and permit the user to revert a device to the kernel default configuration by echoing "default" to the sysfs file. Signed-off-by: Martin K. Petersen <martin.petersen@xxxxxxxxxx> --- drivers/scsi/sd.c | 56 +++++++++++++++++++++++++++++++++-------------- drivers/scsi/sd.h | 7 ++++-- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index eae5c81ae515..ee4f4aea5f0f 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -101,6 +101,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC); #define SD_MINORS 16 static void sd_config_discard(struct scsi_disk *, enum sd_lbp_mode); +static void sd_config_write_zeroes(struct scsi_disk *, enum sd_zeroing_mode); static void sd_config_write_same(struct scsi_disk *); static int sd_revalidate_disk(struct gendisk *); static void sd_unlock_native_capacity(struct gendisk *disk); @@ -428,10 +429,12 @@ static DEVICE_ATTR_RW(provisioning_mode); /* sysfs_match_string() requires dense arrays */ static const char *zeroing_mode[] = { + [SD_ZERO_DEFAULT] = "default", [SD_ZERO_WRITE] = "write", [SD_ZERO_WS] = "writesame", [SD_ZERO_WS16_UNMAP] = "writesame_16_unmap", [SD_ZERO_WS10_UNMAP] = "writesame_10_unmap", + [SD_ZERO_DISABLE] = "disabled", }; static ssize_t @@ -457,7 +460,12 @@ zeroing_mode_store(struct device *dev, struct device_attribute *attr, if (mode < 0) return -EINVAL; - sdkp->zeroing_mode = mode; + if (mode == SD_ZERO_DEFAULT) + sdkp->zeroing_override = false; + else + sdkp->zeroing_override = true; + + sd_config_write_zeroes(sdkp, mode); return count; } @@ -1049,6 +1057,31 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd, return scsi_alloc_sgtables(cmd); } +static void sd_config_write_zeroes(struct scsi_disk *sdkp, + enum sd_zeroing_mode mode) +{ + struct request_queue *q = sdkp->disk->queue; + unsigned int logical_block_size = sdkp->device->sector_size; + + if (mode == SD_ZERO_DEFAULT && !sdkp->zeroing_override) { + if (sdkp->lbprz && sdkp->lbpws) + mode = SD_ZERO_WS16_UNMAP; + else if (sdkp->lbprz && sdkp->lbpws10) + mode = SD_ZERO_WS10_UNMAP; + else if (sdkp->max_ws_blocks) + mode = SD_ZERO_WS; + else + mode = SD_ZERO_WRITE; + } + + if (mode == SD_ZERO_DISABLE) + sdkp->zeroing_override = true; + + sdkp->zeroing_mode = mode; + blk_queue_max_write_zeroes_sectors(q, sdkp->max_ws_blocks * + (logical_block_size >> 9)); +} + static blk_status_t sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd) { struct request *rq = scsi_cmd_to_rq(cmd); @@ -1079,12 +1112,11 @@ static blk_status_t sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd) static void sd_config_write_same(struct scsi_disk *sdkp) { - struct request_queue *q = sdkp->disk->queue; unsigned int logical_block_size = sdkp->device->sector_size; if (sdkp->device->no_write_same) { sdkp->max_ws_blocks = 0; - goto out; + return; } /* Some devices can not handle block counts above 0xffff despite @@ -1103,15 +1135,6 @@ static void sd_config_write_same(struct scsi_disk *sdkp) sdkp->max_ws_blocks = 0; } - if (sdkp->lbprz && sdkp->lbpws) - sdkp->zeroing_mode = SD_ZERO_WS16_UNMAP; - else if (sdkp->lbprz && sdkp->lbpws10) - sdkp->zeroing_mode = SD_ZERO_WS10_UNMAP; - else if (sdkp->max_ws_blocks) - sdkp->zeroing_mode = SD_ZERO_WS; - else - sdkp->zeroing_mode = SD_ZERO_WRITE; - if (sdkp->max_ws_blocks && sdkp->physical_block_size > logical_block_size) { /* @@ -1131,10 +1154,6 @@ static void sd_config_write_same(struct scsi_disk *sdkp) bytes_to_logical(sdkp->device, sdkp->physical_block_size)); } - -out: - blk_queue_max_write_zeroes_sectors(q, sdkp->max_ws_blocks * - (logical_block_size >> 9)); } static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd) @@ -2126,6 +2145,8 @@ static int sd_done(struct scsi_cmnd *SCpnt) case WRITE_SAME: if (SCpnt->cmnd[1] & 8) { /* UNMAP */ sd_config_discard(sdkp, SD_LBP_DISABLE); + sd_config_write_zeroes(sdkp, + SD_ZERO_DISABLE); } else { sdkp->device->no_write_same = 1; sd_config_write_same(sdkp); @@ -3352,7 +3373,9 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_write_same(sdkp, buffer); sd_read_security(sdkp, buffer); sd_read_cpr(sdkp); + sd_config_write_same(sdkp); sd_config_discard(sdkp, SD_LBP_DEFAULT); + sd_config_write_zeroes(sdkp, SD_ZERO_DEFAULT); } /* @@ -3398,7 +3421,6 @@ static int sd_revalidate_disk(struct gendisk *disk) sdkp->first_scan = 0; set_capacity_and_notify(disk, logical_to_sectors(sdp, sdkp->capacity)); - sd_config_write_same(sdkp); kfree(buffer); /* diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 57a8241163c5..e0ee4215a3b4 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -61,11 +61,13 @@ enum sd_lbp_mode { SD_LBP_DISABLE, /* Discard disabled due to failed cmd */ }; -enum { - SD_ZERO_WRITE = 0, /* Use WRITE(10/16) command */ +enum sd_zeroing_mode { + SD_ZERO_DEFAULT = 0, /* Default mode based on what device reports */ + SD_ZERO_WRITE, /* Use WRITE(10/16) command */ SD_ZERO_WS, /* Use WRITE SAME(10/16) command */ SD_ZERO_WS16_UNMAP, /* Use WRITE SAME(16) with UNMAP */ SD_ZERO_WS10_UNMAP, /* Use WRITE SAME(10) with UNMAP */ + SD_ZERO_DISABLE, /* Write Zeroes disabled due to failed cmd */ }; struct scsi_disk { @@ -111,6 +113,7 @@ struct scsi_disk { u8 nr_actuators; /* Number of actuators */ bool lblvpd; bool provisioning_override; + bool zeroing_override; unsigned ATO : 1; /* state of disk ATO bit */ unsigned cache_override : 1; /* temp override of WCE,RCD */ unsigned WCE : 1; /* state of disk WCE bit */ -- 2.32.0