From: Tejun Heo Date: Mon, 15 May 2006 11:59:29 +0000 (+0900) Subject: [PATCH] libata: fix irq-pio merge X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=c17ea20d9a689d7335e97e09354865cdd9f873e1;p=openwrt%2Fstaging%2Fblogic.git [PATCH] libata: fix irq-pio merge * kill ata_poll_qc_complete() and implement/use ata_hsm_qc_complete() which completes qcs in new EH compliant manner from HSM * don't print error message from ata_hsm_move(). it's responsibility of EH. * kill ATA_FLAG_NOINTR usage in bmdma EH Signed-off-by: Tejun Heo --- diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 49eff18a67e3..6d30d2c52960 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c @@ -726,7 +726,6 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset, /* reset PIO HSM and stop DMA engine */ spin_lock_irqsave(&host_set->lock, flags); - ap->flags &= ~ATA_FLAG_NOINTR; ap->hsm_task_state = HSM_ST_IDLE; if (qc && (qc->tf.protocol == ATA_PROT_DMA || diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index c859b96b891a..487b8f22981f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3461,40 +3461,6 @@ skip_map: return 0; } -/** - * ata_poll_qc_complete - turn irq back on and finish qc - * @qc: Command to complete - * @err_mask: ATA status register content - * - * LOCKING: - * None. (grabs host lock) - */ -void ata_poll_qc_complete(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - unsigned long flags; - - spin_lock_irqsave(&ap->host_set->lock, flags); - - if (ap->ops->error_handler) { - /* EH might have kicked in while host_set lock is released */ - qc = ata_qc_from_tag(ap, qc->tag); - if (qc) { - if (!(qc->err_mask & AC_ERR_HSM)) { - ata_irq_on(ap); - ata_qc_complete(qc); - } else - ata_port_freeze(ap); - } - } else { - /* old EH */ - ata_irq_on(ap); - ata_qc_complete(qc); - } - - spin_unlock_irqrestore(&ap->host_set->lock, flags); -} - /** * swap_buf_le16 - swap halves of 16-bit words in place * @buf: Buffer to swap @@ -3917,6 +3883,56 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *q return 0; } +/** + * ata_hsm_qc_complete - finish a qc running on standard HSM + * @qc: Command to complete + * @in_wq: 1 if called from workqueue, 0 otherwise + * + * Finish @qc which is running on standard HSM. + * + * LOCKING: + * If @in_wq is zero, spin_lock_irqsave(host_set lock). + * Otherwise, none on entry and grabs host lock. + */ +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + unsigned long flags; + + if (ap->ops->error_handler) { + if (in_wq) { + spin_lock_irqsave(&ap->host_set->lock, flags); + + /* EH might have kicked in while host_set lock + * is released. + */ + qc = ata_qc_from_tag(ap, qc->tag); + if (qc) { + if (likely(!(qc->err_mask & AC_ERR_HSM))) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else + ata_port_freeze(ap); + } + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + } else { + if (likely(!(qc->err_mask & AC_ERR_HSM))) + ata_qc_complete(qc); + else + ata_port_freeze(ap); + } + } else { + if (in_wq) { + spin_lock_irqsave(&ap->host_set->lock, flags); + ata_irq_on(ap); + ata_qc_complete(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + } else + ata_qc_complete(qc); + } +} + /** * ata_hsm_move - move the HSM to the next state. * @ap: the target ata_port @@ -4108,19 +4124,12 @@ fsm_start: ap->hsm_task_state = HSM_ST_IDLE; /* complete taskfile transaction */ - if (in_wq) - ata_poll_qc_complete(qc); - else - ata_qc_complete(qc); + ata_hsm_qc_complete(qc, in_wq); poll_next = 0; break; case HSM_ST_ERR: - if (qc->tf.command != ATA_CMD_PACKET) - printk(KERN_ERR "ata%u: dev %u command error, drv_stat 0x%x\n", - ap->id, qc->dev->devno, status); - /* make sure qc->err_mask is available to * know what's wrong and recover */ @@ -4129,10 +4138,7 @@ fsm_start: ap->hsm_task_state = HSM_ST_IDLE; /* complete taskfile transaction */ - if (in_wq) - ata_poll_qc_complete(qc); - else - ata_qc_complete(qc); + ata_hsm_qc_complete(qc, in_wq); poll_next = 0; break;