Re: [PATCH v5 18/19] ata: libata: set read/write commands CDL index

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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
> 



[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux