@@ -665,13 +665,37 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
return block;
}
+/*
+ * Set a taskfile CDL index.
+ */
+static inline void ata_set_tf_cdl(struct ata_queued_cmd *qc, int ioprio)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ int cdl;
+
+ if (IOPRIO_PRIO_CLASS(ioprio) != IOPRIO_CLASS_DL)
+ return;
+
+ cdl = IOPRIO_PRIO_DATA(ioprio) & 0x07;
+ if (!cdl)
+ return;
+
+ 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...
- * @class: IO priority class
+ * @ioprio: IO priority class and level
*
* LOCKING:
* None.
@@ -685,7 +709,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 ioprio)
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
@@ -722,13 +746,22 @@ int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
tf->device |= 1 << 7;
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED &&
- class == IOPRIO_CLASS_RT)
+ IOPRIO_PRIO_CLASS(ioprio) == IOPRIO_CLASS_RT)
tf->hob_nsect |= ATA_PRIO_HIGH << ATA_SHIFT_PRIO;
+
+ if (dev->flags & ATA_DFLAG_CDL_ENABLED)
+ ata_set_tf_cdl(qc, ioprio);
+
} 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)
+ ata_set_tf_cdl(qc, ioprio);
+
+ /* 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)) {
@@ -1549,7 +1549,6 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
struct scsi_cmnd *scmd = qc->scsicmd;
const u8 *cdb = scmd->cmnd;
struct request *rq = scsi_cmd_to_rq(scmd);
- int class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq));
unsigned int tf_flags = 0;
u64 block;
u32 n_block;
@@ -1625,7 +1624,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, req_get_ioprio(rq));
if (likely(rc == 0))
return 0;
@@ -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 ioprio);
extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
struct ata_device *dev);
extern unsigned ata_exec_internal(struct ata_device *dev,
@@ -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 */