diff options
author | Kevin Hao <haokexin@gmail.com> | 2014-07-12 00:08:24 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-07-14 12:38:20 -0400 |
commit | 1871ee134b73fb4cadab75752a7152ed2813c751 (patch) | |
tree | 180fb7f61c21c9edafa9bf78f1cf7b5ec9cb0301 /drivers/ata | |
parent | 7188b067576db95445bf4e9498f1bdb2e612dd2f (diff) |
libata: support the ata host which implements a queue depth less than 32
The sata on fsl mpc8315e is broken after the commit 8a4aeec8d2d6
("libata/ahci: accommodate tag ordered controllers"). The reason is
that the ata controller on this SoC only implement a queue depth of
16. When issuing the commands in tag order, all the commands in tag
16 ~ 31 are mapped to tag 0 unconditionally and then causes the sata
malfunction. It makes no senses to use a 32 queue in software while
the hardware has less queue depth. So consider the queue depth
implemented by the hardware when requesting a command tag.
Fixes: 8a4aeec8d2d6 ("libata/ahci: accommodate tag ordered controllers")
Cc: stable@vger.kernel.org
Signed-off-by: Kevin Hao <haokexin@gmail.com>
Acked-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-core.c | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 18d97d5c7d90..d19c37a7abc9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -4787,6 +4787,10 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) | |||
4787 | * ata_qc_new - Request an available ATA command, for queueing | 4787 | * ata_qc_new - Request an available ATA command, for queueing |
4788 | * @ap: target port | 4788 | * @ap: target port |
4789 | * | 4789 | * |
4790 | * Some ATA host controllers may implement a queue depth which is less | ||
4791 | * than ATA_MAX_QUEUE. So we shouldn't allocate a tag which is beyond | ||
4792 | * the hardware limitation. | ||
4793 | * | ||
4790 | * LOCKING: | 4794 | * LOCKING: |
4791 | * None. | 4795 | * None. |
4792 | */ | 4796 | */ |
@@ -4794,14 +4798,16 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) | |||
4794 | static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) | 4798 | static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) |
4795 | { | 4799 | { |
4796 | struct ata_queued_cmd *qc = NULL; | 4800 | struct ata_queued_cmd *qc = NULL; |
4797 | unsigned int i, tag; | 4801 | unsigned int i, tag, max_queue; |
4802 | |||
4803 | max_queue = ap->scsi_host->can_queue; | ||
4798 | 4804 | ||
4799 | /* no command while frozen */ | 4805 | /* no command while frozen */ |
4800 | if (unlikely(ap->pflags & ATA_PFLAG_FROZEN)) | 4806 | if (unlikely(ap->pflags & ATA_PFLAG_FROZEN)) |
4801 | return NULL; | 4807 | return NULL; |
4802 | 4808 | ||
4803 | for (i = 0; i < ATA_MAX_QUEUE; i++) { | 4809 | for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) { |
4804 | tag = (i + ap->last_tag + 1) % ATA_MAX_QUEUE; | 4810 | tag = tag < max_queue ? tag : 0; |
4805 | 4811 | ||
4806 | /* the last tag is reserved for internal command. */ | 4812 | /* the last tag is reserved for internal command. */ |
4807 | if (tag == ATA_TAG_INTERNAL) | 4813 | if (tag == ATA_TAG_INTERNAL) |
@@ -6169,6 +6175,16 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) | |||
6169 | { | 6175 | { |
6170 | int i, rc; | 6176 | int i, rc; |
6171 | 6177 | ||
6178 | /* | ||
6179 | * The max queue supported by hardware must not be greater than | ||
6180 | * ATA_MAX_QUEUE. | ||
6181 | */ | ||
6182 | if (sht->can_queue > ATA_MAX_QUEUE) { | ||
6183 | dev_err(host->dev, "BUG: the hardware max queue is too large\n"); | ||
6184 | WARN_ON(1); | ||
6185 | return -EINVAL; | ||
6186 | } | ||
6187 | |||
6172 | /* host must have been started */ | 6188 | /* host must have been started */ |
6173 | if (!(host->flags & ATA_HOST_STARTED)) { | 6189 | if (!(host->flags & ATA_HOST_STARTED)) { |
6174 | dev_err(host->dev, "BUG: trying to register unstarted host\n"); | 6190 | dev_err(host->dev, "BUG: trying to register unstarted host\n"); |