Skip to content

Commit 4f53138

Browse files
bvanasschemartinkpetersen
authored andcommitted
scsi: sd: Translate data lifetime information
Recently T10 standardized SBC constrained streams. This mechanism allows to pass data lifetime information to SCSI devices in the group number field. Add support for translating write hint information into a permanent stream number in the sd driver. Use WRITE(10) instead of WRITE(6) if data lifetime information is present because the WRITE(6) command does not have a GROUP NUMBER field. Cc: Martin K. Petersen <martin.petersen@oracle.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Damien Le Moal <dlemoal@kernel.org> Signed-off-by: Bart Van Assche <bvanassche@acm.org> Link: https://lore.kernel.org/r/20240130214911.1863909-12-bvanassche@acm.org Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 4977c0f commit 4f53138

File tree

2 files changed

+98
-4
lines changed

2 files changed

+98
-4
lines changed

drivers/scsi/sd.c

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <linux/blkpg.h>
4848
#include <linux/blk-pm.h>
4949
#include <linux/delay.h>
50+
#include <linux/rw_hint.h>
5051
#include <linux/major.h>
5152
#include <linux/mutex.h>
5253
#include <linux/string_helpers.h>
@@ -1080,12 +1081,38 @@ static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd)
10801081
return BLK_STS_OK;
10811082
}
10821083

1084+
/**
1085+
* sd_group_number() - Compute the GROUP NUMBER field
1086+
* @cmd: SCSI command for which to compute the value of the six-bit GROUP NUMBER
1087+
* field.
1088+
*
1089+
* From SBC-5 r05 (https://www.t10.org/cgi-bin/ac.pl?t=f&f=sbc5r05.pdf):
1090+
* 0: no relative lifetime.
1091+
* 1: shortest relative lifetime.
1092+
* 2: second shortest relative lifetime.
1093+
* 3 - 0x3d: intermediate relative lifetimes.
1094+
* 0x3e: second longest relative lifetime.
1095+
* 0x3f: longest relative lifetime.
1096+
*/
1097+
static u8 sd_group_number(struct scsi_cmnd *cmd)
1098+
{
1099+
const struct request *rq = scsi_cmd_to_rq(cmd);
1100+
struct scsi_disk *sdkp = scsi_disk(rq->q->disk);
1101+
1102+
if (!sdkp->rscs)
1103+
return 0;
1104+
1105+
return min3((u32)rq->write_hint, (u32)sdkp->permanent_stream_count,
1106+
0x3fu);
1107+
}
1108+
10831109
static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write,
10841110
sector_t lba, unsigned int nr_blocks,
10851111
unsigned char flags, unsigned int dld)
10861112
{
10871113
cmd->cmd_len = SD_EXT_CDB_SIZE;
10881114
cmd->cmnd[0] = VARIABLE_LENGTH_CMD;
1115+
cmd->cmnd[6] = sd_group_number(cmd);
10891116
cmd->cmnd[7] = 0x18; /* Additional CDB len */
10901117
cmd->cmnd[9] = write ? WRITE_32 : READ_32;
10911118
cmd->cmnd[10] = flags;
@@ -1104,7 +1131,7 @@ static blk_status_t sd_setup_rw16_cmnd(struct scsi_cmnd *cmd, bool write,
11041131
cmd->cmd_len = 16;
11051132
cmd->cmnd[0] = write ? WRITE_16 : READ_16;
11061133
cmd->cmnd[1] = flags | ((dld >> 2) & 0x01);
1107-
cmd->cmnd[14] = (dld & 0x03) << 6;
1134+
cmd->cmnd[14] = ((dld & 0x03) << 6) | sd_group_number(cmd);
11081135
cmd->cmnd[15] = 0;
11091136
put_unaligned_be64(lba, &cmd->cmnd[2]);
11101137
put_unaligned_be32(nr_blocks, &cmd->cmnd[10]);
@@ -1119,7 +1146,7 @@ static blk_status_t sd_setup_rw10_cmnd(struct scsi_cmnd *cmd, bool write,
11191146
cmd->cmd_len = 10;
11201147
cmd->cmnd[0] = write ? WRITE_10 : READ_10;
11211148
cmd->cmnd[1] = flags;
1122-
cmd->cmnd[6] = 0;
1149+
cmd->cmnd[6] = sd_group_number(cmd);
11231150
cmd->cmnd[9] = 0;
11241151
put_unaligned_be32(lba, &cmd->cmnd[2]);
11251152
put_unaligned_be16(nr_blocks, &cmd->cmnd[7]);
@@ -1256,7 +1283,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd)
12561283
ret = sd_setup_rw16_cmnd(cmd, write, lba, nr_blocks,
12571284
protect | fua, dld);
12581285
} else if ((nr_blocks > 0xff) || (lba > 0x1fffff) ||
1259-
sdp->use_10_for_rw || protect) {
1286+
sdp->use_10_for_rw || protect || rq->write_hint) {
12601287
ret = sd_setup_rw10_cmnd(cmd, write, lba, nr_blocks,
12611288
protect | fua);
12621289
} else {
@@ -3001,6 +3028,70 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
30013028
sdkp->DPOFUA = 0;
30023029
}
30033030

3031+
static bool sd_is_perm_stream(struct scsi_disk *sdkp, unsigned int stream_id)
3032+
{
3033+
u8 cdb[16] = { SERVICE_ACTION_IN_16, SAI_GET_STREAM_STATUS };
3034+
struct {
3035+
struct scsi_stream_status_header h;
3036+
struct scsi_stream_status s;
3037+
} buf;
3038+
struct scsi_device *sdev = sdkp->device;
3039+
struct scsi_sense_hdr sshdr;
3040+
const struct scsi_exec_args exec_args = {
3041+
.sshdr = &sshdr,
3042+
};
3043+
int res;
3044+
3045+
put_unaligned_be16(stream_id, &cdb[4]);
3046+
put_unaligned_be32(sizeof(buf), &cdb[10]);
3047+
3048+
res = scsi_execute_cmd(sdev, cdb, REQ_OP_DRV_IN, &buf, sizeof(buf),
3049+
SD_TIMEOUT, sdkp->max_retries, &exec_args);
3050+
if (res < 0)
3051+
return false;
3052+
if (scsi_status_is_check_condition(res) && scsi_sense_valid(&sshdr))
3053+
sd_print_sense_hdr(sdkp, &sshdr);
3054+
if (res)
3055+
return false;
3056+
if (get_unaligned_be32(&buf.h.len) < sizeof(struct scsi_stream_status))
3057+
return false;
3058+
return buf.h.stream_status[0].perm;
3059+
}
3060+
3061+
static void sd_read_io_hints(struct scsi_disk *sdkp, unsigned char *buffer)
3062+
{
3063+
struct scsi_device *sdp = sdkp->device;
3064+
const struct scsi_io_group_descriptor *desc, *start, *end;
3065+
struct scsi_sense_hdr sshdr;
3066+
struct scsi_mode_data data;
3067+
int res;
3068+
3069+
res = scsi_mode_sense(sdp, /*dbd=*/0x8, /*modepage=*/0x0a,
3070+
/*subpage=*/0x05, buffer, SD_BUF_SIZE, SD_TIMEOUT,
3071+
sdkp->max_retries, &data, &sshdr);
3072+
if (res < 0)
3073+
return;
3074+
start = (void *)buffer + data.header_length + 16;
3075+
end = (void *)buffer + ALIGN_DOWN(data.header_length + data.length,
3076+
sizeof(*end));
3077+
/*
3078+
* From "SBC-5 Constrained Streams with Data Lifetimes": Device severs
3079+
* should assign the lowest numbered stream identifiers to permanent
3080+
* streams.
3081+
*/
3082+
for (desc = start; desc < end; desc++)
3083+
if (!desc->st_enble || !sd_is_perm_stream(sdkp, desc - start))
3084+
break;
3085+
sdkp->permanent_stream_count = desc - start;
3086+
if (sdkp->rscs && sdkp->permanent_stream_count < 2)
3087+
sd_printk(KERN_INFO, sdkp,
3088+
"Unexpected: RSCS has been set and the permanent stream count is %u\n",
3089+
sdkp->permanent_stream_count);
3090+
else if (sdkp->permanent_stream_count)
3091+
sd_printk(KERN_INFO, sdkp, "permanent stream count = %d\n",
3092+
sdkp->permanent_stream_count);
3093+
}
3094+
30043095
/*
30053096
* The ATO bit indicates whether the DIF application tag is available
30063097
* for use by the operating system.
@@ -3481,6 +3572,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
34813572

34823573
sd_read_write_protect_flag(sdkp, buffer);
34833574
sd_read_cache_type(sdkp, buffer);
3575+
sd_read_io_hints(sdkp, buffer);
34843576
sd_read_app_tag_own(sdkp, buffer);
34853577
sd_read_write_same(sdkp, buffer);
34863578
sd_read_security(sdkp, buffer);

drivers/scsi/sd.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ struct scsi_disk {
125125
unsigned int physical_block_size;
126126
unsigned int max_medium_access_timeouts;
127127
unsigned int medium_access_timed_out;
128+
/* number of permanent streams */
129+
u16 permanent_stream_count;
128130
u8 media_present;
129131
u8 write_prot;
130132
u8 protection_type;/* Data Integrity Field */
@@ -151,7 +153,7 @@ struct scsi_disk {
151153
unsigned urswrz : 1;
152154
unsigned security : 1;
153155
unsigned ignore_medium_access_errors : 1;
154-
bool rscs : 1; /* reduced stream control support */
156+
unsigned rscs : 1; /* reduced stream control support */
155157
};
156158
#define to_scsi_disk(obj) container_of(obj, struct scsi_disk, disk_dev)
157159

0 commit comments

Comments
 (0)