libahci: fix result_tf handling after an ATA PIO data-in command

ATA devices don't send D2H Reg FIS after an successful ATA PIO data-in
command. The host is supposed to take the TF and E_Status of the
preceding PIO Setup FIS. Update ahci_qc_fill_rtf() such that it takes
TF + E_Status from PIO Setup FIS after a successful ATA PIO data-in
command.

Without this patch, result_tf for such a command is filled with the
content of the previous D2H Reg FIS which belongs to a previous
command, which can make the command incorrectly seen as failed.

* Patch updated to grab the whole TF + E_Status from PIO Setup FIS
instead of just E_Status as suggested by Robert Hancock.

Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: Mark Lord <kernel@teksavvy.com>
Cc: Robert Hancock <hancockrwd@gmail.com>
Cc: stable@kernel.org
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

authored by Tejun Heo and committed by Jeff Garzik 6ad60195 f7a437dd

+16 -3
+1
drivers/ata/ahci.h
··· 72 72 AHCI_CMD_RESET = (1 << 8), 73 73 AHCI_CMD_CLR_BUSY = (1 << 10), 74 74 75 + RX_FIS_PIO_SETUP = 0x20, /* offset of PIO Setup FIS data */ 75 76 RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ 76 77 RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ 77 78 RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
+15 -3
drivers/ata/libahci.c
··· 1752 1752 static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) 1753 1753 { 1754 1754 struct ahci_port_priv *pp = qc->ap->private_data; 1755 - u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; 1755 + u8 *rx_fis = pp->rx_fis; 1756 1756 1757 1757 if (pp->fbs_enabled) 1758 - d2h_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; 1758 + rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; 1759 1759 1760 - ata_tf_from_fis(d2h_fis, &qc->result_tf); 1760 + /* 1761 + * After a successful execution of an ATA PIO data-in command, 1762 + * the device doesn't send D2H Reg FIS to update the TF and 1763 + * the host should take TF and E_Status from the preceding PIO 1764 + * Setup FIS. 1765 + */ 1766 + if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE && 1767 + !(qc->flags & ATA_QCFLAG_FAILED)) { 1768 + ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf); 1769 + qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15]; 1770 + } else 1771 + ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); 1772 + 1761 1773 return true; 1762 1774 } 1763 1775