aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorDamien Le Moal <dlemoal@kernel.org>2023-06-05 08:39:12 +0900
committerDamien Le Moal <dlemoal@kernel.org>2023-06-05 20:00:36 +0900
commit45623d33bfc055d8a9d53eded5dc9c1c977036ed (patch)
treefd4d2230113277e69db8d2c1ffbbb24db4bb17cc /drivers/ata
parent371b74c8ba8fa588ab9ba10d0504acf495b3490e (diff)
downloadlinux-45623d33bfc055d8a9d53eded5dc9c1c977036ed.tar.gz
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 <dlemoal@kernel.org> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: John Garry <john.g.garry@oracle.com> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-sata.c31
1 files changed, 21 insertions, 10 deletions
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
index e3c9cb6170481..6c07025011ed6 100644
--- a/drivers/ata/libata-sata.c
+++ b/drivers/ata/libata-sata.c
@@ -1035,6 +1035,7 @@ int ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
{
struct ata_device *dev;
unsigned long flags;
+ int max_queue_depth;
spin_lock_irqsave(ap->lock, flags);
@@ -1044,22 +1045,32 @@ int ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
return sdev->queue_depth;
}
- /* NCQ enabled? */
- dev->flags &= ~ATA_DFLAG_NCQ_OFF;
- if (queue_depth == 1 || !ata_ncq_enabled(dev)) {
+ /*
+ * Make sure that the queue depth requested does not exceed the device
+ * capabilities.
+ */
+ max_queue_depth = min(ATA_MAX_QUEUE, sdev->host->can_queue);
+ max_queue_depth = min(max_queue_depth, ata_id_queue_depth(dev->id));
+ if (queue_depth > max_queue_depth) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return -EINVAL;
+ }
+
+ /*
+ * If NCQ is not supported by the device or if the target queue depth
+ * is 1 (to disable drive side command queueing), turn off NCQ.
+ */
+ if (queue_depth == 1 || !ata_ncq_supported(dev)) {
dev->flags |= ATA_DFLAG_NCQ_OFF;
queue_depth = 1;
+ } else {
+ dev->flags &= ~ATA_DFLAG_NCQ_OFF;
}
spin_unlock_irqrestore(ap->lock, flags);
- /* limit and apply queue depth */
- queue_depth = min(queue_depth, sdev->host->can_queue);
- queue_depth = min(queue_depth, ata_id_queue_depth(dev->id));
- queue_depth = min(queue_depth, ATA_MAX_QUEUE);
-
- if (sdev->queue_depth == queue_depth)
- return -EINVAL;
+ if (queue_depth == sdev->queue_depth)
+ return sdev->queue_depth;
return scsi_change_queue_depth(sdev, queue_depth);
}