Message ID | 20211104064634.4481-3-chaitanyak@nvidia.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | block: add support for REQ_OP_VERIFY | expand |
On 2021/11/04 15:46, Chaitanya Kulkarni wrote: > From: Chaitanya Kulkarni <kch@nvidia.com> > > Signed-off-by: Chaitanya Kulkarni <kch@nvidia.com> > --- > drivers/scsi/sd.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ > drivers/scsi/sd.h | 1 + > 2 files changed, 53 insertions(+) > > diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c > index a3d2d4bc4a3d..7f2c4eb98cf8 100644 > --- a/drivers/scsi/sd.c > +++ b/drivers/scsi/sd.c > @@ -106,6 +106,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC); > > static void sd_config_discard(struct scsi_disk *, unsigned int); > static void sd_config_write_same(struct scsi_disk *); > +static void sd_config_verify(struct scsi_disk *sdkp); > static int sd_revalidate_disk(struct gendisk *); > static void sd_unlock_native_capacity(struct gendisk *disk); > static int sd_probe(struct device *); > @@ -995,6 +996,41 @@ static blk_status_t sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd) > return sd_setup_write_same10_cmnd(cmd, false); > } > > +static void sd_config_verify(struct scsi_disk *sdkp) > +{ > + struct request_queue *q = sdkp->disk->queue; > + > + /* XXX: use same pattern as sd_config_write_same(). */ > + blk_queue_max_verify_sectors(q, UINT_MAX >> 9); VERIFY 10, 12, 16 and 32 commands are optional and may not be implemented by a device. So setting this unconditionally is wrong. At the very least you must have an "if (sdkp->verify_16)" here, and call "blk_queue_max_verify_sectors(q, 0);" if the device does not support verify. > +} > + > +static blk_status_t sd_setup_verify_cmnd(struct scsi_cmnd *cmd) > +{ > + struct request *rq = cmd->request; > + struct scsi_device *sdp = cmd->device; > + struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); > + u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq)); > + u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); > + > + if (!sdkp->verify_16) > + return BLK_STS_NOTSUPP; I think this should be "return BLK_STS_TARGET;" > + > + cmd->cmd_len = 16; > + cmd->cmnd[0] = VERIFY_16; And what if the device supports VERIFY 10 or 12 but not VERIFY 16 ? > + /* skip veprotect / dpo / bytchk */ > + cmd->cmnd[1] = 0; > + put_unaligned_be64(lba, &cmd->cmnd[2]); > + put_unaligned_be32(nr_blocks, &cmd->cmnd[10]); > + cmd->cmnd[14] = 0; > + cmd->cmnd[15] = 0; > + > + cmd->allowed = SD_MAX_RETRIES; > + cmd->sc_data_direction = DMA_NONE; > + cmd->transfersize = 0; > + > + return BLK_STS_OK; > +} > + > static void sd_config_write_same(struct scsi_disk *sdkp) > { > struct request_queue *q = sdkp->disk->queue; > @@ -1345,6 +1381,8 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd) > } > case REQ_OP_WRITE_ZEROES: > return sd_setup_write_zeroes_cmnd(cmd); > + case REQ_OP_VERIFY: > + return sd_setup_verify_cmnd(cmd); > case REQ_OP_WRITE_SAME: > return sd_setup_write_same_cmnd(cmd); > case REQ_OP_FLUSH: > @@ -2029,6 +2067,7 @@ static int sd_done(struct scsi_cmnd *SCpnt) > switch (req_op(req)) { > case REQ_OP_DISCARD: > case REQ_OP_WRITE_ZEROES: > + case REQ_OP_VERIFY: > case REQ_OP_WRITE_SAME: > case REQ_OP_ZONE_RESET: > case REQ_OP_ZONE_RESET_ALL: > @@ -3096,6 +3135,17 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) > sdkp->ws10 = 1; > } > > +static void sd_read_verify(struct scsi_disk *sdkp, unsigned char *buffer) > +{ > + struct scsi_device *sdev = sdkp->device; > + > + sd_printk(KERN_INFO, sdkp, "VERIFY16 check.\n"); Remove this message please. > + if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, VERIFY_16) == 1) { > + sd_printk(KERN_INFO, sdkp, " VERIFY16 in ON .\n"); And this one too. > + sdkp->verify_16 = 1; Why not checking for VERIFY 10 and 12 if VERIFY 16 is not supported ? Also, why don't you call "blk_queue_max_verify_sectors(q, UINT_MAX >> 9);" here instead of adding the not so useful sd_config_verify() helper ? > + } > +} > + > static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer) > { > struct scsi_device *sdev = sdkp->device; > @@ -3224,6 +3274,7 @@ static int sd_revalidate_disk(struct gendisk *disk) > sd_read_cache_type(sdkp, buffer); > sd_read_app_tag_own(sdkp, buffer); > sd_read_write_same(sdkp, buffer); > + sd_read_verify(sdkp, buffer); > sd_read_security(sdkp, buffer); > } > > @@ -3265,6 +3316,7 @@ static int sd_revalidate_disk(struct gendisk *disk) > > set_capacity_and_notify(disk, logical_to_sectors(sdp, sdkp->capacity)); > sd_config_write_same(sdkp); > + sd_config_verify(sdkp); > kfree(buffer); > > /* > diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h > index b59136c4125b..94a86bf6dac4 100644 > --- a/drivers/scsi/sd.h > +++ b/drivers/scsi/sd.h > @@ -120,6 +120,7 @@ struct scsi_disk { > unsigned lbpvpd : 1; > unsigned ws10 : 1; > unsigned ws16 : 1; > + unsigned verify_16 : 1; See right above this line how write same supports the 10 and 16 variants. I think you need the same here. And very likely, you also need the 32 version in case the device has DIF/DIX (type 2 protection). > unsigned rc_basis: 2; > unsigned zoned: 2; > unsigned urswrz : 1; >
On 11/4/2021 5:33 AM, Damien Le Moal wrote: > External email: Use caution opening links or attachments > > > On 2021/11/04 15:46, Chaitanya Kulkarni wrote: >> From: Chaitanya Kulkarni <kch@nvidia.com> >> >> Signed-off-by: Chaitanya Kulkarni <kch@nvidia.com> >> --- >> drivers/scsi/sd.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ >> drivers/scsi/sd.h | 1 + >> 2 files changed, 53 insertions(+) >> >> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c >> index a3d2d4bc4a3d..7f2c4eb98cf8 100644 >> --- a/drivers/scsi/sd.c >> +++ b/drivers/scsi/sd.c >> @@ -106,6 +106,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC); >> >> static void sd_config_discard(struct scsi_disk *, unsigned int); >> static void sd_config_write_same(struct scsi_disk *); >> +static void sd_config_verify(struct scsi_disk *sdkp); >> static int sd_revalidate_disk(struct gendisk *); >> static void sd_unlock_native_capacity(struct gendisk *disk); >> static int sd_probe(struct device *); >> @@ -995,6 +996,41 @@ static blk_status_t sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd) >> return sd_setup_write_same10_cmnd(cmd, false); >> } >> >> +static void sd_config_verify(struct scsi_disk *sdkp) >> +{ >> + struct request_queue *q = sdkp->disk->queue; >> + >> + /* XXX: use same pattern as sd_config_write_same(). */ >> + blk_queue_max_verify_sectors(q, UINT_MAX >> 9); > > VERIFY 10, 12, 16 and 32 commands are optional and may not be implemented by a > device. So setting this unconditionally is wrong. > At the very least you must have an "if (sdkp->verify_16)" here, and call > "blk_queue_max_verify_sectors(q, 0);" if the device does not support verify. > Yes, I put it together for the RFC, this needs to consider the device unsupported case just like what we do for write zeroes and emulate the same. >> +} >> + >> +static blk_status_t sd_setup_verify_cmnd(struct scsi_cmnd *cmd) >> +{ >> + struct request *rq = cmd->request; >> + struct scsi_device *sdp = cmd->device; >> + struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); >> + u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq)); >> + u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); >> + >> + if (!sdkp->verify_16) >> + return BLK_STS_NOTSUPP; > > I think this should be "return BLK_STS_TARGET;" > >> + >> + cmd->cmd_len = 16; >> + cmd->cmnd[0] = VERIFY_16; > > And what if the device supports VERIFY 10 or 12 but not VERIFY 16 ? For first implementation we can only VERIFY 16, later we can add cases for VERIFY 10-12 versions. > >> + /* skip veprotect / dpo / bytchk */ >> + cmd->cmnd[1] = 0; >> + put_unaligned_be64(lba, &cmd->cmnd[2]); >> + put_unaligned_be32(nr_blocks, &cmd->cmnd[10]); >> + cmd->cmnd[14] = 0; >> + cmd->cmnd[15] = 0; >> + >> + cmd->allowed = SD_MAX_RETRIES; >> + cmd->sc_data_direction = DMA_NONE; >> + cmd->transfersize = 0; >> + >> + return BLK_STS_OK; >> +} >> + >> static void sd_config_write_same(struct scsi_disk *sdkp) >> { >> struct request_queue *q = sdkp->disk->queue; >> @@ -1345,6 +1381,8 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd) >> } >> case REQ_OP_WRITE_ZEROES: >> return sd_setup_write_zeroes_cmnd(cmd); >> + case REQ_OP_VERIFY: >> + return sd_setup_verify_cmnd(cmd); >> case REQ_OP_WRITE_SAME: >> return sd_setup_write_same_cmnd(cmd); >> case REQ_OP_FLUSH: >> @@ -2029,6 +2067,7 @@ static int sd_done(struct scsi_cmnd *SCpnt) >> switch (req_op(req)) { >> case REQ_OP_DISCARD: >> case REQ_OP_WRITE_ZEROES: >> + case REQ_OP_VERIFY: >> case REQ_OP_WRITE_SAME: >> case REQ_OP_ZONE_RESET: >> case REQ_OP_ZONE_RESET_ALL: >> @@ -3096,6 +3135,17 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) >> sdkp->ws10 = 1; >> } >> >> +static void sd_read_verify(struct scsi_disk *sdkp, unsigned char *buffer) >> +{ >> + struct scsi_device *sdev = sdkp->device; >> + >> + sd_printk(KERN_INFO, sdkp, "VERIFY16 check.\n"); > > Remove this message please. > >> + if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, VERIFY_16) == 1) { >> + sd_printk(KERN_INFO, sdkp, " VERIFY16 in ON .\n"); > > And this one too. > >> + sdkp->verify_16 = 1; > > Why not checking for VERIFY 10 and 12 if VERIFY 16 is not supported ? > Also, why don't you call "blk_queue_max_verify_sectors(q, UINT_MAX >> 9);" here > instead of adding the not so useful sd_config_verify() helper ? > Okay, let me see if I can add that in V1. >> + } >> +} >> + >> static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer) >> { >> struct scsi_device *sdev = sdkp->device; >> @@ -3224,6 +3274,7 @@ static int sd_revalidate_disk(struct gendisk *disk) >> sd_read_cache_type(sdkp, buffer); >> sd_read_app_tag_own(sdkp, buffer); >> sd_read_write_same(sdkp, buffer); >> + sd_read_verify(sdkp, buffer); >> sd_read_security(sdkp, buffer); >> } >> >> @@ -3265,6 +3316,7 @@ static int sd_revalidate_disk(struct gendisk *disk) >> >> set_capacity_and_notify(disk, logical_to_sectors(sdp, sdkp->capacity)); >> sd_config_write_same(sdkp); >> + sd_config_verify(sdkp); >> kfree(buffer); >> >> /* >> diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h >> index b59136c4125b..94a86bf6dac4 100644 >> --- a/drivers/scsi/sd.h >> +++ b/drivers/scsi/sd.h >> @@ -120,6 +120,7 @@ struct scsi_disk { >> unsigned lbpvpd : 1; >> unsigned ws10 : 1; >> unsigned ws16 : 1; >> + unsigned verify_16 : 1; > > See right above this line how write same supports the 10 and 16 variants. I > think you need the same here. And very likely, you also need the 32 version in > case the device has DIF/DIX (type 2 protection). > Agree with write same 10/16 versions, let me see if I can add that for V1. >> unsigned rc_basis: 2; >> unsigned zoned: 2; >> unsigned urswrz : 1; >> > > > -- > Damien Le Moal > Western Digital Research > Thanks for the comments Damien.
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a3d2d4bc4a3d..7f2c4eb98cf8 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -106,6 +106,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC); static void sd_config_discard(struct scsi_disk *, unsigned int); static void sd_config_write_same(struct scsi_disk *); +static void sd_config_verify(struct scsi_disk *sdkp); static int sd_revalidate_disk(struct gendisk *); static void sd_unlock_native_capacity(struct gendisk *disk); static int sd_probe(struct device *); @@ -995,6 +996,41 @@ static blk_status_t sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd) return sd_setup_write_same10_cmnd(cmd, false); } +static void sd_config_verify(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + + /* XXX: use same pattern as sd_config_write_same(). */ + blk_queue_max_verify_sectors(q, UINT_MAX >> 9); +} + +static blk_status_t sd_setup_verify_cmnd(struct scsi_cmnd *cmd) +{ + struct request *rq = cmd->request; + struct scsi_device *sdp = cmd->device; + struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); + u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq)); + u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); + + if (!sdkp->verify_16) + return BLK_STS_NOTSUPP; + + cmd->cmd_len = 16; + cmd->cmnd[0] = VERIFY_16; + /* skip veprotect / dpo / bytchk */ + cmd->cmnd[1] = 0; + put_unaligned_be64(lba, &cmd->cmnd[2]); + put_unaligned_be32(nr_blocks, &cmd->cmnd[10]); + cmd->cmnd[14] = 0; + cmd->cmnd[15] = 0; + + cmd->allowed = SD_MAX_RETRIES; + cmd->sc_data_direction = DMA_NONE; + cmd->transfersize = 0; + + return BLK_STS_OK; +} + static void sd_config_write_same(struct scsi_disk *sdkp) { struct request_queue *q = sdkp->disk->queue; @@ -1345,6 +1381,8 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd) } case REQ_OP_WRITE_ZEROES: return sd_setup_write_zeroes_cmnd(cmd); + case REQ_OP_VERIFY: + return sd_setup_verify_cmnd(cmd); case REQ_OP_WRITE_SAME: return sd_setup_write_same_cmnd(cmd); case REQ_OP_FLUSH: @@ -2029,6 +2067,7 @@ static int sd_done(struct scsi_cmnd *SCpnt) switch (req_op(req)) { case REQ_OP_DISCARD: case REQ_OP_WRITE_ZEROES: + case REQ_OP_VERIFY: case REQ_OP_WRITE_SAME: case REQ_OP_ZONE_RESET: case REQ_OP_ZONE_RESET_ALL: @@ -3096,6 +3135,17 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) sdkp->ws10 = 1; } +static void sd_read_verify(struct scsi_disk *sdkp, unsigned char *buffer) +{ + struct scsi_device *sdev = sdkp->device; + + sd_printk(KERN_INFO, sdkp, "VERIFY16 check.\n"); + if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, VERIFY_16) == 1) { + sd_printk(KERN_INFO, sdkp, " VERIFY16 in ON .\n"); + sdkp->verify_16 = 1; + } +} + static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer) { struct scsi_device *sdev = sdkp->device; @@ -3224,6 +3274,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_cache_type(sdkp, buffer); sd_read_app_tag_own(sdkp, buffer); sd_read_write_same(sdkp, buffer); + sd_read_verify(sdkp, buffer); sd_read_security(sdkp, buffer); } @@ -3265,6 +3316,7 @@ static int sd_revalidate_disk(struct gendisk *disk) set_capacity_and_notify(disk, logical_to_sectors(sdp, sdkp->capacity)); sd_config_write_same(sdkp); + sd_config_verify(sdkp); kfree(buffer); /* diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index b59136c4125b..94a86bf6dac4 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -120,6 +120,7 @@ struct scsi_disk { unsigned lbpvpd : 1; unsigned ws10 : 1; unsigned ws16 : 1; + unsigned verify_16 : 1; unsigned rc_basis: 2; unsigned zoned: 2; unsigned urswrz : 1;