Skip to content

Commit 45623d3

Browse files
committed
ata: libata-sata: Improve ata_change_queue_depth()
ata_change_queue_depth() implements different behaviors for ATA devices managed by libsas than for those managed by libata directly. Specifically, if a user attempts to set a device queue depth to a value larger than 32 (ATA_MAX_QUEUE), the queue depth is capped to the maximum and set to 32 for libsas managed devices whereas for libata managed devices, the queue depth is unchanged and an error returned to the user. This is due to the fact that for libsas devices, sdev->host->can_queue may indicate the host (HBA) maximum number of commands that can be queued rather than the device maximum queue depth. Change ata_change_queue_depth() to provide a consistent behavior for all devices by changing the queue depth capping code to a check that the user provided value does not exceed the device maximum queue depth. This check is moved before the code clearing or setting the ATA_DFLAG_NCQ_OFF flag to ensure that this flag is not modified when an invlaid queue depth is provided. While at it, two other small improvements are added: 1) Use ata_ncq_supported() instead of ata_ncq_enabled() and clear the ATA_DFLAG_NCQ_OFF flag only and only if needed. 2) If the user provided queue depth is equal to the current queue depth, do not return an error as that is useless. Overall, the behavior of ata_change_queue_depth() for libata managed devices is unchanged. The behavior with libsas managed devices becomes consistent with libata managed devices. Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Reviewed-by: John Garry <[email protected]> Reviewed-by: Johannes Thumshirn <[email protected]>
1 parent 371b74c commit 45623d3

File tree

1 file changed

+21
-10
lines changed

1 file changed

+21
-10
lines changed

drivers/ata/libata-sata.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,7 @@ int ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
10351035
{
10361036
struct ata_device *dev;
10371037
unsigned long flags;
1038+
int max_queue_depth;
10381039

10391040
spin_lock_irqsave(ap->lock, flags);
10401041

@@ -1044,22 +1045,32 @@ int ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
10441045
return sdev->queue_depth;
10451046
}
10461047

1047-
/* NCQ enabled? */
1048-
dev->flags &= ~ATA_DFLAG_NCQ_OFF;
1049-
if (queue_depth == 1 || !ata_ncq_enabled(dev)) {
1048+
/*
1049+
* Make sure that the queue depth requested does not exceed the device
1050+
* capabilities.
1051+
*/
1052+
max_queue_depth = min(ATA_MAX_QUEUE, sdev->host->can_queue);
1053+
max_queue_depth = min(max_queue_depth, ata_id_queue_depth(dev->id));
1054+
if (queue_depth > max_queue_depth) {
1055+
spin_unlock_irqrestore(ap->lock, flags);
1056+
return -EINVAL;
1057+
}
1058+
1059+
/*
1060+
* If NCQ is not supported by the device or if the target queue depth
1061+
* is 1 (to disable drive side command queueing), turn off NCQ.
1062+
*/
1063+
if (queue_depth == 1 || !ata_ncq_supported(dev)) {
10501064
dev->flags |= ATA_DFLAG_NCQ_OFF;
10511065
queue_depth = 1;
1066+
} else {
1067+
dev->flags &= ~ATA_DFLAG_NCQ_OFF;
10521068
}
10531069

10541070
spin_unlock_irqrestore(ap->lock, flags);
10551071

1056-
/* limit and apply queue depth */
1057-
queue_depth = min(queue_depth, sdev->host->can_queue);
1058-
queue_depth = min(queue_depth, ata_id_queue_depth(dev->id));
1059-
queue_depth = min(queue_depth, ATA_MAX_QUEUE);
1060-
1061-
if (sdev->queue_depth == queue_depth)
1062-
return -EINVAL;
1072+
if (queue_depth == sdev->queue_depth)
1073+
return sdev->queue_depth;
10631074

10641075
return scsi_change_queue_depth(sdev, queue_depth);
10651076
}

0 commit comments

Comments
 (0)