diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index bde15f855f700c8f420d22e22a7653849c542abe..34303ce67c14ad9a5660f665c007120c7ea3f624 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1955,6 +1955,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) ata_qc_for_each_raw(ap, qc, tag) { if (!(qc->flags & ATA_QCFLAG_FAILED) || + qc->flags & ATA_QCFLAG_RETRY || ata_dev_phys_link(qc->dev) != link) continue; diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 283ce1ab29cf01ecd8b962f364e8a539ebf1a9f4..18ef14e749a081b52c59fcfa02ed695e3be70bfe 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1476,6 +1476,33 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) } } + ata_qc_for_each_raw(ap, qc, tag) { + if (!(qc->flags & ATA_QCFLAG_FAILED) || + ata_dev_phys_link(qc->dev) != link) + continue; + + /* Skip the single QC which caused the NCQ error. */ + if (qc->err_mask) + continue; + + /* + * For SATA, the STATUS and ERROR fields are shared for all NCQ + * commands that were completed with the same SDB FIS. + * Therefore, we have to clear the ATA_ERR bit for all QCs + * except the one that caused the NCQ error. + */ + qc->result_tf.status &= ~ATA_ERR; + qc->result_tf.error = 0; + + /* + * If we get a NCQ error, that means that a single command was + * aborted. All other failed commands for our link should be + * retried and has no business of going though further scrutiny + * by ata_eh_link_autopsy(). + */ + qc->flags |= ATA_QCFLAG_RETRY; + } + ehc->i.err_mask &= ~AC_ERR_DEV; } EXPORT_SYMBOL_GPL(ata_eh_analyze_ncq_error);