Message ID | cover.1733876548.git.Thinh.Nguyen@synopsys.com (mailing list archive) |
---|---|
State | New |
Headers | show |
On Wed, Dec 11, 2024 at 12:31:30AM +0000, Thinh Nguyen wrote: > Apologies for the delay; after two years and multiple requests to resume this > series, I squeezed some time to push an update. This series applies on top of > Greg's usb-testing branch. > > If possible, please help test this series and get this merged as my resources > are nil for this work. You have many bugfixes in the first few commits of this series, but if I apply the whole series, those will not get into Linus's tree until 6.14-rc1. Is that ok or should they go separately into 6.13-final now? thanks, greg k-h
Hi Greg, On Wed, Dec 11, 2024, Greg Kroah-Hartman wrote: > On Wed, Dec 11, 2024 at 12:31:30AM +0000, Thinh Nguyen wrote: > > Apologies for the delay; after two years and multiple requests to resume this > > series, I squeezed some time to push an update. This series applies on top of > > Greg's usb-testing branch. > > > > If possible, please help test this series and get this merged as my resources > > are nil for this work. > > You have many bugfixes in the first few commits of this series, but if I > apply the whole series, those will not get into Linus's tree until > 6.14-rc1. Is that ok or should they go separately into 6.13-final now? > Yes, it should be ok for all of these to land in 6.14-rc1. With just the fix changes in this series will not make f_tcm any more usable because of interopability and performance issues. IMHO, adding the entire series in your next branch would allow more people to run proper tests. Splitting this means for a few weeks, until a rebase, neither the usb-linus branch or the usb-testing branch would have a proper working UASP driver. Thanks, Thinh
Hi Thinh, On 2024-12-11 0:31 UTC, Thinh Nguyen <Thinh.Nguyen@synopsys.com> wrote: > 1) Fix Data Corruption > ---------------------- > > Properly increment the "len" base on the command requested length instead of > the SG entry length. > > If you're using File backend, then you need to fix target_core_file. If you're > using other backend such as Ramdisk, then you need a similar fix there. I am trying to do some basic rw aging test with this serie on my gadget board. When it comes to target_core_iblock, the rw code is less similar to the one in target_core_file or ramdisk. Could you just spend some extra time explaining what cause the Data Corruption issue and how can this fix it ? So that I could perform similar fix in target_core_iblock on my own, so a full test could start soonner. B.R. H. Akemi
(Removed Cc invalid emails to Nicholas and Andrzej) Hi, On Fri, Dec 20, 2024, Homura Akemi wrote: > Hi Thinh, > > On 2024-12-11 0:31 UTC, Thinh Nguyen <Thinh.Nguyen@synopsys.com> wrote: > > 1) Fix Data Corruption > > ---------------------- > > > > Properly increment the "len" base on the command requested length instead of > > the SG entry length. > > > > If you're using File backend, then you need to fix target_core_file. If you're > > using other backend such as Ramdisk, then you need a similar fix there. > > I am trying to do some basic rw aging test with this serie on my gadget board. > When it comes to target_core_iblock, the rw code is less similar to the one in > target_core_file or ramdisk. > Could you just spend some extra time explaining what cause the Data > Corruption issue and how can this fix it ? So that I could perform > similar fix in > target_core_iblock on my own, so a full test could start soonner. > When we prepare a new generic command for read/write, we call to target_alloc_sgl(). This will allocate PAGE_SIZE SG entries enough to handle the se_cmd read/write base on its length. The total length of all the SG entries combine will be at least se_cmd->data_length. The typical block size is 512 byte. A page size is typically 4KB. So, the se_cmd->data_length may not be a multiple of PAGE_SiZE. In target_core_file, it execute_rw() with this logic: for_each_sg(sgl, sg, sgl_nents, i) { bvec_set_page(&aio_cmd->bvecs[i], sg_page(sg), sg->length, sg->offset); len += sg->length; } // It sets the length to be the iter to be total length of the // allocated SG entries and not the requested command length: iov_iter_bvec(&iter, is_write, aio_cmd->bvecs, sgl_nents, len); aio_cmd->cmd = cmd; aio_cmd->len = len; aio_cmd->iocb.ki_pos = cmd->t_task_lba * dev->dev_attrib.block_size; aio_cmd->iocb.ki_filp = file; aio_cmd->iocb.ki_complete = cmd_rw_aio_complete; aio_cmd->iocb.ki_flags = IOCB_DIRECT; if (is_write && (cmd->se_cmd_flags & SCF_FUA)) aio_cmd->iocb.ki_flags |= IOCB_DSYNC; // So when we do f_op read/write, we may do more than needed and may // write bogus data from the extra SG entry length. if (is_write) ret = file->f_op->write_iter(&aio_cmd->iocb, &iter); else ret = file->f_op->read_iter(&aio_cmd->iocb, &iter); I did not review target_core_iblock. It may or may not do things properly. BR, Thinh
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 2d78ef74633c..d9fc048c1734 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -283,7 +283,12 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, for_each_sg(sgl, sg, sgl_nents, i) { bvec_set_page(&aio_cmd->bvecs[i], sg_page(sg), sg->length, sg->offset); - len += sg->length; + if (len + sg->length >= cmd->data_length) { + len = cmd->data_length; + break; + } else { + len += sg->length; + } } iov_iter_bvec(&iter, is_write, aio_cmd->bvecs, sgl_nents, len); @@ -328,7 +333,12 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd, for_each_sg(sgl, sg, sgl_nents, i) { bvec_set_page(&bvec[i], sg_page(sg), sg->length, sg->offset); - len += sg->length; + if (len + sg->length >= data_length) { + len = data_length; + break; + } else { + len += sg->length; + } } iov_iter_bvec(&iter, is_write, bvec, sgl_nents, len); -- 2) Fix Sense Data Length ------------------------ The transport_get_sense_buffer() and transport_copy_sense_to_cmd() take sense data length to be the allocated sense buffer length TRANSPORT_SENSE_BUFFER. However, the sense data length is depending on the sense data description. Check the sense data to set the proper cmd->scsi_sense_length. See SPC4-r37 section 4.5.2.1. --- drivers/target/target_core_transport.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 8d8f4ad4f59e..da75d6873ab5 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -804,8 +804,6 @@ static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd) if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) return NULL; - cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; - pr_debug("HBA_[%u]_PLUG[%s]: Requesting sense for SAM STATUS: 0x%02x\n", dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status); return cmd->sense_buffer; @@ -824,7 +822,13 @@ void transport_copy_sense_to_cmd(struct se_cmd *cmd, unsigned char *sense) } cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; + + /* Sense data length = min sense data + additional sense data length */ + cmd->scsi_sense_length = min_t(u16, cmd_sense_buf[7] + 8, + TRANSPORT_SENSE_BUFFER); + memcpy(cmd_sense_buf, sense, cmd->scsi_sense_length); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); } EXPORT_SYMBOL(transport_copy_sense_to_cmd); @@ -3521,12 +3525,19 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; cmd->scsi_status = SAM_STAT_CHECK_CONDITION; - cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; + scsi_build_sense_buffer(desc_format, buffer, key, asc, ascq); if (sd->add_sense_info) WARN_ON_ONCE(scsi_set_sense_information(buffer, - cmd->scsi_sense_length, + TRANSPORT_SENSE_BUFFER, cmd->sense_info) < 0); + /* + * CHECK CONDITION returns sense data, and sense data is minimum 8 + * bytes long plus additional Sense Data Length. + * See SPC4-r37 section 4.5.2.1. + */ + cmd->scsi_sense_length = min_t(u16, buffer[7] + 8, + TRANSPORT_SENSE_BUFFER); } int