diff options
author | Mark Lord <liml@rtr.ca> | 2007-11-07 16:54:15 +0100 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-11-08 19:08:41 +0100 |
commit | 6004bda1cce51273ac9e71a39e680831b9ff4503 (patch) | |
tree | c1a27e4485f7ec2c06aeaaec8b0878a0dd115398 /drivers | |
parent | libata sata_qstor workaround for spurious interrupts (diff) | |
download | linux-6004bda1cce51273ac9e71a39e680831b9ff4503.tar.xz linux-6004bda1cce51273ac9e71a39e680831b9ff4503.zip |
libata sata_qstor conversion to new error handling (EH).
sata_qstor conversion to new error handling (EH).
Convert sata_qstor to use the newer libata EH mechanisms.
Based on earlier work by Jeff Garzik.
Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/sata_qstor.c | 65 |
1 files changed, 51 insertions, 14 deletions
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 7446a335fc92..2f1de6ec044c 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -116,14 +116,15 @@ static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int qs_port_start(struct ata_port *ap); static void qs_host_stop(struct ata_host *host); -static void qs_phy_reset(struct ata_port *ap); static void qs_qc_prep(struct ata_queued_cmd *qc); static unsigned int qs_qc_issue(struct ata_queued_cmd *qc); static int qs_check_atapi_dma(struct ata_queued_cmd *qc); static void qs_bmdma_stop(struct ata_queued_cmd *qc); static u8 qs_bmdma_status(struct ata_port *ap); static void qs_irq_clear(struct ata_port *ap); -static void qs_eng_timeout(struct ata_port *ap); +static void qs_freeze(struct ata_port *ap); +static void qs_thaw(struct ata_port *ap); +static void qs_error_handler(struct ata_port *ap); static struct scsi_host_template qs_ata_sht = { .module = THIS_MODULE, @@ -150,11 +151,12 @@ static const struct ata_port_operations qs_ata_ops = { .check_atapi_dma = qs_check_atapi_dma, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, - .phy_reset = qs_phy_reset, .qc_prep = qs_qc_prep, .qc_issue = qs_qc_issue, .data_xfer = ata_data_xfer, - .eng_timeout = qs_eng_timeout, + .freeze = qs_freeze, + .thaw = qs_thaw, + .error_handler = qs_error_handler, .irq_clear = qs_irq_clear, .irq_on = ata_irq_on, .scr_read = qs_scr_read, @@ -169,8 +171,6 @@ static const struct ata_port_info qs_port_info[] = { /* board_2068_idx */ { .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | - //FIXME ATA_FLAG_SRST | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ .udma_mask = ATA_UDMA6, @@ -235,16 +235,28 @@ static inline void qs_reset_channel_logic(struct ata_port *ap) qs_enter_reg_mode(ap); } -static void qs_phy_reset(struct ata_port *ap) +static void qs_freeze(struct ata_port *ap) { - qs_reset_channel_logic(ap); - sata_phy_reset(ap); + u8 __iomem *mmio_base = qs_mmio_base(ap->host); + + writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ + qs_enter_reg_mode(ap); +} + +static void qs_thaw(struct ata_port *ap) +{ + u8 __iomem *mmio_base = qs_mmio_base(ap->host); + + qs_enter_reg_mode(ap); + writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */ } -static void qs_eng_timeout(struct ata_port *ap) +static int qs_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; + qs_reset_channel_logic(ap); - ata_eng_timeout(ap); + return ata_std_prereset(link, deadline); } static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) @@ -255,6 +267,13 @@ static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) return 0; } +static void qs_error_handler(struct ata_port *ap) +{ + qs_enter_reg_mode(ap); + ata_do_eh(ap, qs_prereset, ata_std_softreset, NULL, + ata_std_postreset); +} + static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) @@ -353,7 +372,6 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) switch (qc->tf.protocol) { case ATA_PROT_DMA: - pp->state = qs_state_pkt; qs_packet_start(qc); return 0; @@ -370,6 +388,26 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } +static void qs_do_or_die(struct ata_queued_cmd *qc, u8 status) +{ + qc->err_mask |= ac_err_mask(status); + + if (!qc->err_mask) { + ata_qc_complete(qc); + } else { + struct ata_port *ap = qc->ap; + struct ata_eh_info *ehi = &ap->link.eh_info; + + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "status 0x%02X", status); + + if (qc->err_mask == AC_ERR_DEV) + ata_port_abort(ap); + else + ata_port_freeze(ap); + } +} + static inline unsigned int qs_intr_pkt(struct ata_host *host) { unsigned int handled = 0; @@ -402,8 +440,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host) case 0: /* successful CPB */ case 3: /* device error */ qs_enter_reg_mode(qc->ap); - qc->err_mask |= ac_err_mask(sDST); - ata_qc_complete(qc); + qs_do_or_die(qc, sDST); break; default: break; |