On Tue, Apr 04, 2023 at 08:24:23PM +0200, Niklas Cassel wrote: > From: Damien Le Moal <damien.lemoal@xxxxxxxxxxxxxxxxxx> > > For devices supporting the command duration limits feature, translate > the dld field of read and write operation to set the command duration > limit index field of the command task file when the duration limit > feature is enabled. > > The function ata_set_tf_cdl() is introduced to do this. For unqueued > (non NCQ) read and write operations, this function sets the command > duration limit index set as the lower 2 bits of the feature field. > For queued NCQ read/write commands, the index is set as the lower > 2 bits of the auxiliary field. CDL index is lower 3 bits, not 2 bits. > > The flag ATA_QCFLAG_HAS_CDL is introduced to indicate that a command > taskfile has a non zero cdl field. > > Signed-off-by: Damien Le Moal <damien.lemoal@xxxxxxxxxxxxxxxxxx> > Co-developed-by: Niklas Cassel <niklas.cassel@xxxxxxx> > Signed-off-by: Niklas Cassel <niklas.cassel@xxxxxxx> > --- > drivers/ata/libata-core.c | 32 +++++++++++++++++++++++++++++--- > drivers/ata/libata-scsi.c | 16 +++++++++++++++- > drivers/ata/libata.h | 2 +- > include/linux/libata.h | 1 + > 4 files changed, 46 insertions(+), 5 deletions(-) Reviewed-by: Igor Pylypiv <ipylypiv@xxxxxxxxxx> Thanks, Igor > > diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c > index 62e100fa90e2..c68e7b684a87 100644 > --- a/drivers/ata/libata-core.c > +++ b/drivers/ata/libata-core.c > @@ -665,12 +665,29 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev) > return block; > } > > +/* > + * Set a taskfile command duration limit index. > + */ > +static inline void ata_set_tf_cdl(struct ata_queued_cmd *qc, int cdl) > +{ > + struct ata_taskfile *tf = &qc->tf; > + > + if (tf->protocol == ATA_PROT_NCQ) > + tf->auxiliary |= cdl; > + else > + tf->feature |= cdl; > + > + /* Mark this command as having a CDL */ > + qc->flags |= ATA_QCFLAG_HAS_CDL; > +} > + > /** > * ata_build_rw_tf - Build ATA taskfile for given read/write request > * @qc: Metadata associated with the taskfile to build > * @block: Block address > * @n_block: Number of blocks > * @tf_flags: RW/FUA etc... > + * @cdl: Command duration limit index > * @class: IO priority class > * > * LOCKING: > @@ -685,7 +702,7 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev) > * -EINVAL if the request is invalid. > */ > int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block, > - unsigned int tf_flags, int class) > + unsigned int tf_flags, int cdl, int class) > { > struct ata_taskfile *tf = &qc->tf; > struct ata_device *dev = qc->dev; > @@ -724,11 +741,20 @@ int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block, > if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED && > class == IOPRIO_CLASS_RT) > tf->hob_nsect |= ATA_PRIO_HIGH << ATA_SHIFT_PRIO; > + > + if ((dev->flags & ATA_DFLAG_CDL_ENABLED) && cdl) > + ata_set_tf_cdl(qc, cdl); > + > } else if (dev->flags & ATA_DFLAG_LBA) { > tf->flags |= ATA_TFLAG_LBA; > > - /* We need LBA48 for FUA writes */ > - if (!(tf->flags & ATA_TFLAG_FUA) && lba_28_ok(block, n_block)) { > + if ((dev->flags & ATA_DFLAG_CDL_ENABLED) && cdl) > + ata_set_tf_cdl(qc, cdl); > + > + /* Both FUA writes and a CDL index require 48-bit commands */ > + if (!(tf->flags & ATA_TFLAG_FUA) && > + !(qc->flags & ATA_QCFLAG_HAS_CDL) && > + lba_28_ok(block, n_block)) { > /* use LBA28 */ > tf->device |= (block >> 24) & 0xf; > } else if (lba_48_ok(block, n_block)) { > diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c > index 8dde1cede5ca..05bde27947a2 100644 > --- a/drivers/ata/libata-scsi.c > +++ b/drivers/ata/libata-scsi.c > @@ -1380,6 +1380,18 @@ static inline void scsi_16_lba_len(const u8 *cdb, u64 *plba, u32 *plen) > *plen = get_unaligned_be32(&cdb[10]); > } > > +/** > + * scsi_dld - Get duration limit descriptor index > + * @cdb: SCSI command to translate > + * > + * Returns the dld bits indicating the index of a command duration limit > + * descriptor. > + */ > +static inline int scsi_dld(const u8 *cdb) > +{ > + return ((cdb[1] & 0x01) << 2) | ((cdb[14] >> 6) & 0x03); > +} > + > /** > * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one > * @qc: Storage for translated ATA taskfile > @@ -1548,6 +1560,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) > struct request *rq = scsi_cmd_to_rq(scmd); > int class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq)); > unsigned int tf_flags = 0; > + int dld = 0; > u64 block; > u32 n_block; > int rc; > @@ -1598,6 +1611,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) > goto invalid_fld; > } > scsi_16_lba_len(cdb, &block, &n_block); > + dld = scsi_dld(cdb); > if (cdb[1] & (1 << 3)) > tf_flags |= ATA_TFLAG_FUA; > if (!ata_check_nblocks(scmd, n_block)) > @@ -1622,7 +1636,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) > qc->flags |= ATA_QCFLAG_IO; > qc->nbytes = n_block * scmd->device->sector_size; > > - rc = ata_build_rw_tf(qc, block, n_block, tf_flags, class); > + rc = ata_build_rw_tf(qc, block, n_block, tf_flags, dld, class); > if (likely(rc == 0)) > return 0; > > diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h > index 2cd6124a01e8..73dd2ebc277c 100644 > --- a/drivers/ata/libata.h > +++ b/drivers/ata/libata.h > @@ -45,7 +45,7 @@ static inline void ata_force_cbl(struct ata_port *ap) { } > extern u64 ata_tf_to_lba(const struct ata_taskfile *tf); > extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf); > extern int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block, > - unsigned int tf_flags, int class); > + unsigned int tf_flags, int dld, int class); > extern u64 ata_tf_read_block(const struct ata_taskfile *tf, > struct ata_device *dev); > extern unsigned ata_exec_internal(struct ata_device *dev, > diff --git a/include/linux/libata.h b/include/linux/libata.h > index d7fe735e6322..ab8b62036c12 100644 > --- a/include/linux/libata.h > +++ b/include/linux/libata.h > @@ -209,6 +209,7 @@ enum { > ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ > ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */ > ATA_QCFLAG_RETRY = (1 << 7), /* retry after failure */ > + ATA_QCFLAG_HAS_CDL = (1 << 8), /* qc has CDL a descriptor set */ > > ATA_QCFLAG_EH = (1 << 16), /* cmd aborted and owned by EH */ > ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ > -- > 2.39.2 >