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: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
fcf1bf1584
commit
c3c70c443c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue