Skip to content

Commit eafe804

Browse files
damien-lemoalmartinkpetersen
authored andcommitted
scsi: ata: libata: Set read/write commands CDL index
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 3 bits of the feature field. For queued NCQ read/write commands, the index is set as the lower 3 bits of the auxiliary field. 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 <[email protected]> Reviewed-by: Igor Pylypiv <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Co-developed-by: Niklas Cassel <[email protected]> Signed-off-by: Niklas Cassel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
1 parent df60f9c commit eafe804

File tree

4 files changed

+46
-5
lines changed

4 files changed

+46
-5
lines changed

drivers/ata/libata-core.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -665,12 +665,29 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
665665
return block;
666666
}
667667

668+
/*
669+
* Set a taskfile command duration limit index.
670+
*/
671+
static inline void ata_set_tf_cdl(struct ata_queued_cmd *qc, int cdl)
672+
{
673+
struct ata_taskfile *tf = &qc->tf;
674+
675+
if (tf->protocol == ATA_PROT_NCQ)
676+
tf->auxiliary |= cdl;
677+
else
678+
tf->feature |= cdl;
679+
680+
/* Mark this command as having a CDL */
681+
qc->flags |= ATA_QCFLAG_HAS_CDL;
682+
}
683+
668684
/**
669685
* ata_build_rw_tf - Build ATA taskfile for given read/write request
670686
* @qc: Metadata associated with the taskfile to build
671687
* @block: Block address
672688
* @n_block: Number of blocks
673689
* @tf_flags: RW/FUA etc...
690+
* @cdl: Command duration limit index
674691
* @class: IO priority class
675692
*
676693
* LOCKING:
@@ -685,7 +702,7 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
685702
* -EINVAL if the request is invalid.
686703
*/
687704
int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
688-
unsigned int tf_flags, int class)
705+
unsigned int tf_flags, int cdl, int class)
689706
{
690707
struct ata_taskfile *tf = &qc->tf;
691708
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,
724741
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED &&
725742
class == IOPRIO_CLASS_RT)
726743
tf->hob_nsect |= ATA_PRIO_HIGH << ATA_SHIFT_PRIO;
744+
745+
if ((dev->flags & ATA_DFLAG_CDL_ENABLED) && cdl)
746+
ata_set_tf_cdl(qc, cdl);
747+
727748
} else if (dev->flags & ATA_DFLAG_LBA) {
728749
tf->flags |= ATA_TFLAG_LBA;
729750

730-
/* We need LBA48 for FUA writes */
731-
if (!(tf->flags & ATA_TFLAG_FUA) && lba_28_ok(block, n_block)) {
751+
if ((dev->flags & ATA_DFLAG_CDL_ENABLED) && cdl)
752+
ata_set_tf_cdl(qc, cdl);
753+
754+
/* Both FUA writes and a CDL index require 48-bit commands */
755+
if (!(tf->flags & ATA_TFLAG_FUA) &&
756+
!(qc->flags & ATA_QCFLAG_HAS_CDL) &&
757+
lba_28_ok(block, n_block)) {
732758
/* use LBA28 */
733759
tf->device |= (block >> 24) & 0xf;
734760
} else if (lba_48_ok(block, n_block)) {

drivers/ata/libata-scsi.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,18 @@ static inline void scsi_16_lba_len(const u8 *cdb, u64 *plba, u32 *plen)
13801380
*plen = get_unaligned_be32(&cdb[10]);
13811381
}
13821382

1383+
/**
1384+
* scsi_dld - Get duration limit descriptor index
1385+
* @cdb: SCSI command to translate
1386+
*
1387+
* Returns the dld bits indicating the index of a command duration limit
1388+
* descriptor.
1389+
*/
1390+
static inline int scsi_dld(const u8 *cdb)
1391+
{
1392+
return ((cdb[1] & 0x01) << 2) | ((cdb[14] >> 6) & 0x03);
1393+
}
1394+
13831395
/**
13841396
* ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
13851397
* @qc: Storage for translated ATA taskfile
@@ -1548,6 +1560,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
15481560
struct request *rq = scsi_cmd_to_rq(scmd);
15491561
int class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq));
15501562
unsigned int tf_flags = 0;
1563+
int dld = 0;
15511564
u64 block;
15521565
u32 n_block;
15531566
int rc;
@@ -1598,6 +1611,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
15981611
goto invalid_fld;
15991612
}
16001613
scsi_16_lba_len(cdb, &block, &n_block);
1614+
dld = scsi_dld(cdb);
16011615
if (cdb[1] & (1 << 3))
16021616
tf_flags |= ATA_TFLAG_FUA;
16031617
if (!ata_check_nblocks(scmd, n_block))
@@ -1622,7 +1636,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
16221636
qc->flags |= ATA_QCFLAG_IO;
16231637
qc->nbytes = n_block * scmd->device->sector_size;
16241638

1625-
rc = ata_build_rw_tf(qc, block, n_block, tf_flags, class);
1639+
rc = ata_build_rw_tf(qc, block, n_block, tf_flags, dld, class);
16261640
if (likely(rc == 0))
16271641
return 0;
16281642

drivers/ata/libata.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ static inline void ata_force_cbl(struct ata_port *ap) { }
4545
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
4646
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
4747
extern int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
48-
unsigned int tf_flags, int class);
48+
unsigned int tf_flags, int dld, int class);
4949
extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
5050
struct ata_device *dev);
5151
extern unsigned ata_exec_internal(struct ata_device *dev,

include/linux/libata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ enum {
209209
ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */
210210
ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */
211211
ATA_QCFLAG_RETRY = (1 << 7), /* retry after failure */
212+
ATA_QCFLAG_HAS_CDL = (1 << 8), /* qc has CDL a descriptor set */
212213

213214
ATA_QCFLAG_EH = (1 << 16), /* cmd aborted and owned by EH */
214215
ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */

0 commit comments

Comments
 (0)