Commit 13cc546b authored by Gwendal Grignou's avatar Gwendal Grignou Committed by Jeff Garzik

sata_sil24: prevent hba lockup when pass-through ATA commands are used

Fix commands timeout with Sil3124/3132 based HBA when pass-through ATA
commands [where ATA_QCFLAG_RESULT_TF is set] are used while other
commands are active on other devices connected to the same port with a
Port Multiplier.  Due to a hardware bug, these commands must be sent
alone, like ATAPI commands.
Signed-off-by: default avatarGwendal Grignou <gwendal@google.com>
Acked-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent fcb71f6f
...@@ -832,16 +832,31 @@ static int sil24_qc_defer(struct ata_queued_cmd *qc) ...@@ -832,16 +832,31 @@ static int sil24_qc_defer(struct ata_queued_cmd *qc)
struct ata_link *link = qc->dev->link; struct ata_link *link = qc->dev->link;
struct ata_port *ap = link->ap; struct ata_port *ap = link->ap;
u8 prot = qc->tf.protocol; u8 prot = qc->tf.protocol;
int is_atapi = (prot == ATA_PROT_ATAPI ||
prot == ATA_PROT_ATAPI_NODATA || /*
prot == ATA_PROT_ATAPI_DMA); * There is a bug in the chip:
* Port LRAM Causes the PRB/SGT Data to be Corrupted
/* ATAPI commands completing with CHECK_SENSE cause various * If the host issues a read request for LRAM and SActive registers
* weird problems if other commands are active. PMP DMA CS * while active commands are available in the port, PRB/SGT data in
* errata doesn't cover all and HSM violation occurs even with * the LRAM can become corrupted. This issue applies only when
* only one other device active. Always run an ATAPI command * reading from, but not writing to, the LRAM.
* by itself. *
*/ * Therefore, reading LRAM when there is no particular error [and
* other commands may be outstanding] is prohibited.
*
* To avoid this bug there are two situations where a command must run
* exclusive of any other commands on the port:
*
* - ATAPI commands which check the sense data
* - Passthrough ATA commands which always have ATA_QCFLAG_RESULT_TF
* set.
*
*/
int is_excl = (prot == ATA_PROT_ATAPI ||
prot == ATA_PROT_ATAPI_NODATA ||
prot == ATA_PROT_ATAPI_DMA ||
(qc->flags & ATA_QCFLAG_RESULT_TF));
if (unlikely(ap->excl_link)) { if (unlikely(ap->excl_link)) {
if (link == ap->excl_link) { if (link == ap->excl_link) {
if (ap->nr_active_links) if (ap->nr_active_links)
...@@ -849,7 +864,7 @@ static int sil24_qc_defer(struct ata_queued_cmd *qc) ...@@ -849,7 +864,7 @@ static int sil24_qc_defer(struct ata_queued_cmd *qc)
qc->flags |= ATA_QCFLAG_CLEAR_EXCL; qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
} else } else
return ATA_DEFER_PORT; return ATA_DEFER_PORT;
} else if (unlikely(is_atapi)) { } else if (unlikely(is_excl)) {
ap->excl_link = link; ap->excl_link = link;
if (ap->nr_active_links) if (ap->nr_active_links)
return ATA_DEFER_PORT; return ATA_DEFER_PORT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment