Skip to content

Commit

Permalink
libata: support the ata host which implements a queue depth less than 32
Browse files Browse the repository at this point in the history
commit 1871ee1 upstream.

The sata on fsl mpc8315e is broken after the commit 8a4aeec
("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: 8a4aeec ("libata/ahci: accommodate tag ordered controllers")
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
haokexin authored and gregkh committed Jul 31, 2014
1 parent 696acd9 commit 6f0844c
Showing 1 changed file with 19 additions and 3 deletions.
22 changes: 19 additions & 3 deletions drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -4693,21 +4693,27 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
* ata_qc_new - Request an available ATA command, for queueing
* @ap: target port
*
* Some ATA host controllers may implement a queue depth which is less
* than ATA_MAX_QUEUE. So we shouldn't allocate a tag which is beyond
* the hardware limitation.
*
* LOCKING:
* None.
*/

static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
{
struct ata_queued_cmd *qc = NULL;
unsigned int i, tag;
unsigned int i, tag, max_queue;

max_queue = ap->scsi_host->can_queue;

/* no command while frozen */
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;

for (i = 0; i < ATA_MAX_QUEUE; i++) {
tag = (i + ap->last_tag + 1) % ATA_MAX_QUEUE;
for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) {
tag = tag < max_queue ? tag : 0;

/* the last tag is reserved for internal command. */
if (tag == ATA_TAG_INTERNAL)
Expand Down Expand Up @@ -6041,6 +6047,16 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
{
int i, rc;

/*
* The max queue supported by hardware must not be greater than
* ATA_MAX_QUEUE.
*/
if (sht->can_queue > ATA_MAX_QUEUE) {
dev_err(host->dev, "BUG: the hardware max queue is too large\n");
WARN_ON(1);
return -EINVAL;
}

/* host must have been started */
if (!(host->flags & ATA_HOST_STARTED)) {
dev_err(host->dev, "BUG: trying to register unstarted host\n");
Expand Down

0 comments on commit 6f0844c

Please sign in to comment.