diff options
author | Tejun Heo <htejun@gmail.com> | 2007-02-20 09:31:22 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-02-21 04:58:19 -0500 |
commit | c3c70c443c2ef1fce31f201a93780c884b903993 (patch) | |
tree | cfb23ec2831ad4f10c87f6362573db9eb6a33cbd /drivers/ata/libata-scsi.c | |
parent | fcf1bf1584647f9fd864c193fee81840c4c5ce41 (diff) |
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>
Diffstat (limited to 'drivers/ata/libata-scsi.c')
-rw-r--r-- | drivers/ata/libata-scsi.c | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index aa6cb6dcec41..48e388800f5a 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -987,29 +987,32 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) | |||
987 | struct ata_port *ap = ata_shost_to_port(sdev->host); | 987 | struct ata_port *ap = ata_shost_to_port(sdev->host); |
988 | struct ata_device *dev; | 988 | struct ata_device *dev; |
989 | unsigned long flags; | 989 | unsigned long flags; |
990 | int max_depth; | ||
991 | 990 | ||
992 | if (queue_depth < 1) | 991 | if (queue_depth < 1 || queue_depth == sdev->queue_depth) |
993 | return sdev->queue_depth; | 992 | return sdev->queue_depth; |
994 | 993 | ||
995 | dev = ata_scsi_find_dev(ap, sdev); | 994 | dev = ata_scsi_find_dev(ap, sdev); |
996 | if (!dev || !ata_dev_enabled(dev)) | 995 | if (!dev || !ata_dev_enabled(dev)) |
997 | return sdev->queue_depth; | 996 | return sdev->queue_depth; |
998 | 997 | ||
999 | max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id)); | 998 | /* NCQ enabled? */ |
1000 | max_depth = min(ATA_MAX_QUEUE - 1, max_depth); | ||
1001 | if (queue_depth > max_depth) | ||
1002 | queue_depth = max_depth; | ||
1003 | |||
1004 | scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth); | ||
1005 | |||
1006 | spin_lock_irqsave(ap->lock, flags); | 999 | spin_lock_irqsave(ap->lock, flags); |
1007 | if (queue_depth > 1) | 1000 | dev->flags &= ~ATA_DFLAG_NCQ_OFF; |
1008 | dev->flags &= ~ATA_DFLAG_NCQ_OFF; | 1001 | if (queue_depth == 1 || !ata_ncq_enabled(dev)) { |
1009 | else | ||
1010 | dev->flags |= ATA_DFLAG_NCQ_OFF; | 1002 | dev->flags |= ATA_DFLAG_NCQ_OFF; |
1003 | queue_depth = 1; | ||
1004 | } | ||
1011 | spin_unlock_irqrestore(ap->lock, flags); | 1005 | spin_unlock_irqrestore(ap->lock, flags); |
1012 | 1006 | ||
1007 | /* limit and apply queue depth */ | ||
1008 | queue_depth = min(queue_depth, sdev->host->can_queue); | ||
1009 | queue_depth = min(queue_depth, ata_id_queue_depth(dev->id)); | ||
1010 | queue_depth = min(queue_depth, ATA_MAX_QUEUE - 1); | ||
1011 | |||
1012 | if (sdev->queue_depth == queue_depth) | ||
1013 | return -EINVAL; | ||
1014 | |||
1015 | scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth); | ||
1013 | return queue_depth; | 1016 | return queue_depth; |
1014 | } | 1017 | } |
1015 | 1018 | ||