Implement EH helper function ata_eh_finish_qcs(). This function is called after all EH actions are complete and finishes all the failed qcs. Depending on error status, a qc may be retried or completed. This function is also responsible for loading qc->tf with resulting TF values. Signed-off-by: Tejun Heo <htejun@xxxxxxxxx> --- drivers/scsi/libata-core.c | 1 + drivers/scsi/libata-eh.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 2 ++ 3 files changed, 48 insertions(+), 0 deletions(-) a47d957e6a718253b6ce1b6131da2dcbbbb52641 diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index cb174cf..7605313 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -5346,3 +5346,4 @@ EXPORT_SYMBOL_GPL(ata_eh_determine_qc); EXPORT_SYMBOL_GPL(ata_eh_autopsy); EXPORT_SYMBOL_GPL(ata_eh_report); EXPORT_SYMBOL_GPL(ata_eh_revive); +EXPORT_SYMBOL_GPL(ata_eh_finish_qcs); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 1d25d55..0d8a9cb 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -1124,3 +1124,48 @@ int ata_eh_revive(struct ata_port *ap, u return rc; } + +/** + * ata_eh_finish_qcs - complete or retry commands + * @ap: host port to finish qc's for + * @qc: the failed qc (can be NULL) + * @tf: taskfile register of the failed qc + * + * Retry or complete failed qc's. + * + * LOCKING: + * None. + */ +void ata_eh_finish_qcs(struct ata_port *ap, struct ata_queued_cmd *qc, + struct ata_taskfile *tf) +{ + struct ata_taskfile tmp_tf; + + if (qc) { + /* prevent infinite retry loop */ + if (!qc->err_mask && !(qc->flags & ATA_QCFLAG_SENSE_VALID)) { + printk(KERN_WARNING "ata%u: dev %u qc has no error " + "flag set after EH, forcing AC_ERR_OTHER\n", + ap->id, qc->dev->devno); + qc->err_mask |= AC_ERR_OTHER; + } + + /* FIXME: qc->tf will be used by completion callbacks + * to generate SCSI sense data. This is to share + * sense generation code with old-EH drivers. Once EH + * migration is complete, generate sense data in this + * function, considering both err_mask and tf. + */ + tmp_tf = *tf; + tmp_tf.flags = qc->tf.flags; + tmp_tf.protocol = qc->tf.protocol; + tmp_tf.ctl = qc->tf.ctl; + qc->tf = tmp_tf; + + if (qc->err_mask & AC_ERR_INVALID || + qc->flags & ATA_QCFLAG_SENSE_VALID) + ata_eh_qc_complete(qc); + else + ata_eh_qc_retry(qc); + } +} diff --git a/include/linux/libata.h b/include/linux/libata.h index 22472f6..7f626d2 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -700,6 +700,8 @@ extern void ata_eh_report(struct ata_por extern int ata_eh_revive(struct ata_port *ap, unsigned int action, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); +extern void ata_eh_finish_qcs(struct ata_port *ap, struct ata_queued_cmd *qc, + struct ata_taskfile *tf); static inline int -- 1.2.4 - : send the line "unsubscribe linux-ide" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html