Commit e59e80cf authored by Damien Le Moal's avatar Damien Le Moal Committed by Martin K. Petersen

scsi: sd: Set read/write command CDL index

Introduce the command duration limits helper function sd_cdl_dld() to set
the DLD bits of READ/WRITE 16 and READ/WRITE 32 commands to indicate to the
device the command duration limit descriptor to apply to the commands.

When command duration limits are enabled, sd_cdl_dld() obtains the index of
the descriptor to apply to the command using the hints field of the request
IO priority value (hints IOPRIO_HINT_DEV_DURATION_LIMIT_1 to
IOPRIO_HINT_DEV_DURATION_LIMIT_7).

If command duration limits is disabled (which is the default), the limit
index "0" is always used to indicate "no limit" for a command.
Signed-off-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Co-developed-by: default avatarNiklas Cassel <niklas.cassel@wdc.com>
Signed-off-by: default avatarNiklas Cassel <niklas.cassel@wdc.com>
Link: https://lore.kernel.org/r/20230511011356.227789-11-nks@flawful.orgSigned-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 1b22cfb1
...@@ -1041,13 +1041,14 @@ static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd) ...@@ -1041,13 +1041,14 @@ static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd)
static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write, static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write,
sector_t lba, unsigned int nr_blocks, sector_t lba, unsigned int nr_blocks,
unsigned char flags) unsigned char flags, unsigned int dld)
{ {
cmd->cmd_len = SD_EXT_CDB_SIZE; cmd->cmd_len = SD_EXT_CDB_SIZE;
cmd->cmnd[0] = VARIABLE_LENGTH_CMD; cmd->cmnd[0] = VARIABLE_LENGTH_CMD;
cmd->cmnd[7] = 0x18; /* Additional CDB len */ cmd->cmnd[7] = 0x18; /* Additional CDB len */
cmd->cmnd[9] = write ? WRITE_32 : READ_32; cmd->cmnd[9] = write ? WRITE_32 : READ_32;
cmd->cmnd[10] = flags; cmd->cmnd[10] = flags;
cmd->cmnd[11] = dld & 0x07;
put_unaligned_be64(lba, &cmd->cmnd[12]); put_unaligned_be64(lba, &cmd->cmnd[12]);
put_unaligned_be32(lba, &cmd->cmnd[20]); /* Expected Indirect LBA */ put_unaligned_be32(lba, &cmd->cmnd[20]); /* Expected Indirect LBA */
put_unaligned_be32(nr_blocks, &cmd->cmnd[28]); put_unaligned_be32(nr_blocks, &cmd->cmnd[28]);
...@@ -1057,12 +1058,12 @@ static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write, ...@@ -1057,12 +1058,12 @@ static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write,
static blk_status_t sd_setup_rw16_cmnd(struct scsi_cmnd *cmd, bool write, static blk_status_t sd_setup_rw16_cmnd(struct scsi_cmnd *cmd, bool write,
sector_t lba, unsigned int nr_blocks, sector_t lba, unsigned int nr_blocks,
unsigned char flags) unsigned char flags, unsigned int dld)
{ {
cmd->cmd_len = 16; cmd->cmd_len = 16;
cmd->cmnd[0] = write ? WRITE_16 : READ_16; cmd->cmnd[0] = write ? WRITE_16 : READ_16;
cmd->cmnd[1] = flags; cmd->cmnd[1] = flags | ((dld >> 2) & 0x01);
cmd->cmnd[14] = 0; cmd->cmnd[14] = (dld & 0x03) << 6;
cmd->cmnd[15] = 0; cmd->cmnd[15] = 0;
put_unaligned_be64(lba, &cmd->cmnd[2]); put_unaligned_be64(lba, &cmd->cmnd[2]);
put_unaligned_be32(nr_blocks, &cmd->cmnd[10]); put_unaligned_be32(nr_blocks, &cmd->cmnd[10]);
...@@ -1114,6 +1115,31 @@ static blk_status_t sd_setup_rw6_cmnd(struct scsi_cmnd *cmd, bool write, ...@@ -1114,6 +1115,31 @@ static blk_status_t sd_setup_rw6_cmnd(struct scsi_cmnd *cmd, bool write,
return BLK_STS_OK; return BLK_STS_OK;
} }
/*
* Check if a command has a duration limit set. If it does, and the target
* device supports CDL and the feature is enabled, return the limit
* descriptor index to use. Return 0 (no limit) otherwise.
*/
static int sd_cdl_dld(struct scsi_disk *sdkp, struct scsi_cmnd *scmd)
{
struct scsi_device *sdp = sdkp->device;
int hint;
if (!sdp->cdl_supported || !sdp->cdl_enable)
return 0;
/*
* Use "no limit" if the request ioprio does not specify a duration
* limit hint.
*/
hint = IOPRIO_PRIO_HINT(req_get_ioprio(scsi_cmd_to_rq(scmd)));
if (hint < IOPRIO_HINT_DEV_DURATION_LIMIT_1 ||
hint > IOPRIO_HINT_DEV_DURATION_LIMIT_7)
return 0;
return (hint - IOPRIO_HINT_DEV_DURATION_LIMIT_1) + 1;
}
static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd)
{ {
struct request *rq = scsi_cmd_to_rq(cmd); struct request *rq = scsi_cmd_to_rq(cmd);
...@@ -1125,6 +1151,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) ...@@ -1125,6 +1151,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd)
unsigned int mask = logical_to_sectors(sdp, 1) - 1; unsigned int mask = logical_to_sectors(sdp, 1) - 1;
bool write = rq_data_dir(rq) == WRITE; bool write = rq_data_dir(rq) == WRITE;
unsigned char protect, fua; unsigned char protect, fua;
unsigned int dld;
blk_status_t ret; blk_status_t ret;
unsigned int dif; unsigned int dif;
bool dix; bool dix;
...@@ -1174,6 +1201,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) ...@@ -1174,6 +1201,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd)
fua = rq->cmd_flags & REQ_FUA ? 0x8 : 0; fua = rq->cmd_flags & REQ_FUA ? 0x8 : 0;
dix = scsi_prot_sg_count(cmd); dix = scsi_prot_sg_count(cmd);
dif = scsi_host_dif_capable(cmd->device->host, sdkp->protection_type); dif = scsi_host_dif_capable(cmd->device->host, sdkp->protection_type);
dld = sd_cdl_dld(sdkp, cmd);
if (dif || dix) if (dif || dix)
protect = sd_setup_protect_cmnd(cmd, dix, dif); protect = sd_setup_protect_cmnd(cmd, dix, dif);
...@@ -1182,10 +1210,10 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) ...@@ -1182,10 +1210,10 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd)
if (protect && sdkp->protection_type == T10_PI_TYPE2_PROTECTION) { if (protect && sdkp->protection_type == T10_PI_TYPE2_PROTECTION) {
ret = sd_setup_rw32_cmnd(cmd, write, lba, nr_blocks, ret = sd_setup_rw32_cmnd(cmd, write, lba, nr_blocks,
protect | fua); protect | fua, dld);
} else if (sdp->use_16_for_rw || (nr_blocks > 0xffff)) { } else if (sdp->use_16_for_rw || (nr_blocks > 0xffff)) {
ret = sd_setup_rw16_cmnd(cmd, write, lba, nr_blocks, ret = sd_setup_rw16_cmnd(cmd, write, lba, nr_blocks,
protect | fua); protect | fua, dld);
} else if ((nr_blocks > 0xff) || (lba > 0x1fffff) || } else if ((nr_blocks > 0xff) || (lba > 0x1fffff) ||
sdp->use_10_for_rw || protect) { sdp->use_10_for_rw || protect) {
ret = sd_setup_rw10_cmnd(cmd, write, lba, nr_blocks, ret = sd_setup_rw10_cmnd(cmd, write, lba, nr_blocks,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment