Commit c3c70c44 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

libata: fix ata_scsi_change_queue_depth()

Fix ata_scsi_change_queue_depth() such that...

* NCQ on/off is exactly determined using the same logic as the issue path.

* queue depth is adjusted to 1 if NCQ is not enabled.

* -EINVAL is returned if requested action is ignored due to limitations.

This fixes the bug which allows queue depth to be increased on
blacklisted NCQ hosts/devices.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent fcf1bf15
...@@ -987,29 +987,32 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) ...@@ -987,29 +987,32 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev; struct ata_device *dev;
unsigned long flags; unsigned long flags;
int max_depth;
if (queue_depth < 1) if (queue_depth < 1 || queue_depth == sdev->queue_depth)
return sdev->queue_depth; return sdev->queue_depth;
dev = ata_scsi_find_dev(ap, sdev); dev = ata_scsi_find_dev(ap, sdev);
if (!dev || !ata_dev_enabled(dev)) if (!dev || !ata_dev_enabled(dev))
return sdev->queue_depth; return sdev->queue_depth;
max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id)); /* NCQ enabled? */
max_depth = min(ATA_MAX_QUEUE - 1, max_depth);
if (queue_depth > max_depth)
queue_depth = max_depth;
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
spin_lock_irqsave(ap->lock, flags); spin_lock_irqsave(ap->lock, flags);
if (queue_depth > 1) dev->flags &= ~ATA_DFLAG_NCQ_OFF;
dev->flags &= ~ATA_DFLAG_NCQ_OFF; if (queue_depth == 1 || !ata_ncq_enabled(dev)) {
else
dev->flags |= ATA_DFLAG_NCQ_OFF; dev->flags |= ATA_DFLAG_NCQ_OFF;
queue_depth = 1;
}
spin_unlock_irqrestore(ap->lock, flags); 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 - 1);
if (sdev->queue_depth == queue_depth)
return -EINVAL;
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
return queue_depth; return queue_depth;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment