[PATCH 10/14] scsi: sd: Move WRITE_ZEROES configuration to a separate function

Martin K. Petersen
2022-03-02T05:36:42Z

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@oracle.com>
---
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