diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cd7aaf202397..e63773740fc2 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 91db4e7f4906..69fc0d2c2123 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 926d0d33cd29..cf993885d2b2 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 385ca23d5ad0..f679abd2e61f 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 */