> > Recently T10 standardized SBC constrained streams. This mechanism enables > passing 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. > > Cc: Martin K. Petersen <martin.petersen@xxxxxxxxxx> > Cc: Christoph Hellwig <hch@xxxxxx> > Cc: Damien Le Moal <dlemoal@xxxxxxxxxx> > Signed-off-by: Bart Van Assche <bvanassche@xxxxxxx> > --- > drivers/scsi/sd.c | 65 ++++++++++++++++++++++++++++++++++++++++++++- > -- > drivers/scsi/sd.h | 1 + > 2 files changed, 63 insertions(+), 3 deletions(-) > > diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c > index 879edbc1a065..7bbc58cd99d1 100644 > --- a/drivers/scsi/sd.c > +++ b/drivers/scsi/sd.c > @@ -1001,12 +1001,38 @@ static blk_status_t sd_setup_flush_cmnd(struct > scsi_cmnd *cmd) > return BLK_STS_OK; > } > > +/** > + * sd_group_number() - Compute the GROUP NUMBER field > + * @cmd: SCSI command for which to compute the value of the six-bit > GROUP NUMBER > + * field. > + * > + * From "SBC-5 Constrained Streams with Data Lifetimes" > + * (https://www.t10.org/cgi-bin/ac.pl?t=d&f=23-024r3.pdf): > + * 0: no relative lifetime. > + * 1: shortest relative lifetime. > + * 2: second shortest relative lifetime. > + * 3 - 0x3d: intermediate relative lifetimes. > + * 0x3e: second longest relative lifetime. > + * 0x3f: longest relative lifetime. > + */ > +static u8 sd_group_number(struct scsi_cmnd *cmd) > +{ > + const struct request *rq = scsi_cmd_to_rq(cmd); > + struct scsi_disk *sdkp = scsi_disk(rq->q->disk); > + const int max_gn = min_t(u16, sdkp->permanent_stream_count, 0x3f); > + > + if (!sdkp->rscs || rq->write_hint == WRITE_LIFE_NOT_SET) > + return 0; > + return min(rq->write_hint - WRITE_LIFE_NONE, max_gn); > +} > + > static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write, > sector_t lba, unsigned int nr_blocks, > unsigned char flags, unsigned int dld) > { > cmd->cmd_len = SD_EXT_CDB_SIZE; > cmd->cmnd[0] = VARIABLE_LENGTH_CMD; > + cmd->cmnd[6] = sd_group_number(cmd); > cmd->cmnd[7] = 0x18; /* Additional CDB len */ > cmd->cmnd[9] = write ? WRITE_32 : READ_32; > cmd->cmnd[10] = flags; > @@ -1025,7 +1051,7 @@ static blk_status_t sd_setup_rw16_cmnd(struct > scsi_cmnd *cmd, bool write, > cmd->cmd_len = 16; > cmd->cmnd[0] = write ? WRITE_16 : READ_16; > cmd->cmnd[1] = flags | ((dld >> 2) & 0x01); > - cmd->cmnd[14] = (dld & 0x03) << 6; > + cmd->cmnd[14] = ((dld & 0x03) << 6) | sd_group_number(cmd); > cmd->cmnd[15] = 0; > put_unaligned_be64(lba, &cmd->cmnd[2]); > put_unaligned_be32(nr_blocks, &cmd->cmnd[10]); > @@ -1040,7 +1066,7 @@ static blk_status_t sd_setup_rw10_cmnd(struct > scsi_cmnd *cmd, bool write, > cmd->cmd_len = 10; > cmd->cmnd[0] = write ? WRITE_10 : READ_10; > cmd->cmnd[1] = flags; > - cmd->cmnd[6] = 0; > + cmd->cmnd[6] = sd_group_number(cmd); > cmd->cmnd[9] = 0; > put_unaligned_be32(lba, &cmd->cmnd[2]); > put_unaligned_be16(nr_blocks, &cmd->cmnd[7]); > @@ -1177,7 +1203,8 @@ static blk_status_t > sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) > ret = sd_setup_rw16_cmnd(cmd, write, lba, nr_blocks, > protect | fua, dld); > } else if ((nr_blocks > 0xff) || (lba > 0x1fffff) || > - sdp->use_10_for_rw || protect) { > + sdp->use_10_for_rw || protect || > + rq->write_hint != WRITE_LIFE_NOT_SET) { Is this a typo? > ret = sd_setup_rw10_cmnd(cmd, write, lba, nr_blocks, > protect | fua); > } else { > @@ -2912,6 +2939,37 @@ sd_read_cache_type(struct scsi_disk *sdkp, > unsigned char *buffer) > sdkp->DPOFUA = 0; > } > > +static void sd_read_io_hints(struct scsi_disk *sdkp, unsigned char *buffer) > +{ > + struct scsi_device *sdp = sdkp->device; > + const struct scsi_io_group_descriptor *desc, *start, *end; > + struct scsi_sense_hdr sshdr; > + struct scsi_mode_data data; > + int res; > + > + res = scsi_mode_sense(sdp, /*dbd=*/0x8, /*modepage=*/0x0a, > + /*subpage=*/0x05, buffer, SD_BUF_SIZE, > + SD_TIMEOUT, sdkp->max_retries, &data, &sshdr); > + if (res < 0) > + return; > + start = (void *)buffer + data.header_length + 16; > + end = (void *)buffer + ((data.header_length + data.length) > + & ~(sizeof(*end) - 1)); > + /* > + * From "SBC-5 Constrained Streams with Data Lifetimes": Device severs > + * should assign the lowest numbered stream identifiers to permanent > + * streams. > + */ > + for (desc = start; desc < end; desc++) > + if (!desc->st_enble) > + break; I don't see how you can conclude that the stream is permanent, without reading the perm bit from the stream status descriptor. > + sdkp->permanent_stream_count = desc - start; > + if (sdkp->rscs && sdkp->permanent_stream_count < 2) > + sdev_printk(KERN_INFO, sdp, > + "Unexpected: RSCS has been set and the permanent stream > count is %u\n", > + sdkp->permanent_stream_count); > +} > + > /* > * The ATO bit indicates whether the DIF application tag is available > * for use by the operating system. > @@ -3395,6 +3453,7 @@ static int sd_revalidate_disk(struct gendisk *disk) > > sd_read_write_protect_flag(sdkp, buffer); > sd_read_cache_type(sdkp, buffer); > + sd_read_io_hints(sdkp, buffer); > sd_read_app_tag_own(sdkp, buffer); > sd_read_write_same(sdkp, buffer); > sd_read_security(sdkp, buffer); > diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h > index 84685168b6e0..1863de5ebae4 100644 > --- a/drivers/scsi/sd.h > +++ b/drivers/scsi/sd.h > @@ -125,6 +125,7 @@ struct scsi_disk { > unsigned int physical_block_size; > unsigned int max_medium_access_timeouts; > unsigned int medium_access_timed_out; > + u16 permanent_stream_count; /* maximum number of streams > */ This comment is a bit misleading: The Block Limits Extension VPD page has a "maximum number of streams" field. Maybe avoid the unnecessary confusion? Thanks, Avri > u8 media_present; > u8 write_prot; > u8 protection_type;/* Data Integrity Field */