X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=drivers%2Fata%2Fpdc_adma.c;h=8d1b03d5bcb1e65d63c5b67121791e8fe1eee77a;hb=65a6ec0d72a07f16719e9b7a96e1c4bae044b591;hp=5c79271401afc29ecb216ab46b6c46b7b82ff1a5;hpb=b21010ed6498391c0f359f2a89c907533fe07fec;p=cascardo%2Flinux.git diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 5c79271401af..8d1b03d5bcb1 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -92,6 +92,8 @@ enum { /* CPB bits */ cDONE = (1 << 0), + cATERR = (1 << 3), + cVLD = (1 << 0), cDAT = (1 << 2), cIEN = (1 << 3), @@ -131,14 +133,15 @@ static int adma_ata_init_one (struct pci_dev *pdev, static int adma_port_start(struct ata_port *ap); static void adma_host_stop(struct ata_host *host); static void adma_port_stop(struct ata_port *ap); -static void adma_phy_reset(struct ata_port *ap); static void adma_qc_prep(struct ata_queued_cmd *qc); static unsigned int adma_qc_issue(struct ata_queued_cmd *qc); static int adma_check_atapi_dma(struct ata_queued_cmd *qc); static void adma_bmdma_stop(struct ata_queued_cmd *qc); static u8 adma_bmdma_status(struct ata_port *ap); static void adma_irq_clear(struct ata_port *ap); -static void adma_eng_timeout(struct ata_port *ap); +static void adma_freeze(struct ata_port *ap); +static void adma_thaw(struct ata_port *ap); +static void adma_error_handler(struct ata_port *ap); static struct scsi_host_template adma_ata_sht = { .module = THIS_MODULE, @@ -159,21 +162,20 @@ static struct scsi_host_template adma_ata_sht = { }; static const struct ata_port_operations adma_ata_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, .check_status = ata_check_status, .dev_select = ata_std_dev_select, - .phy_reset = adma_phy_reset, .check_atapi_dma = adma_check_atapi_dma, .data_xfer = ata_data_xfer, .qc_prep = adma_qc_prep, .qc_issue = adma_qc_issue, - .eng_timeout = adma_eng_timeout, + .freeze = adma_freeze, + .thaw = adma_thaw, + .error_handler = adma_error_handler, .irq_clear = adma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = adma_port_start, .port_stop = adma_port_stop, .host_stop = adma_host_stop, @@ -184,7 +186,7 @@ static const struct ata_port_operations adma_ata_ops = { static struct ata_port_info adma_port_info[] = { /* board_1841_idx */ { - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ @@ -273,24 +275,42 @@ static inline void adma_enter_reg_mode(struct ata_port *ap) readb(chan + ADMA_STATUS); /* flush */ } -static void adma_phy_reset(struct ata_port *ap) +static void adma_freeze(struct ata_port *ap) { - struct adma_port_priv *pp = ap->private_data; + void __iomem *chan = ADMA_PORT_REGS(ap); + + /* mask/clear ATA interrupts */ + writeb(ATA_NIEN, ap->ioaddr.ctl_addr); + ata_check_status(ap); - pp->state = adma_state_idle; + /* reset ADMA to idle state */ + writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); + udelay(2); + writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL); + udelay(2); +} + +static void adma_thaw(struct ata_port *ap) +{ adma_reinit_engine(ap); - ata_port_probe(ap); - ata_bus_reset(ap); } -static void adma_eng_timeout(struct ata_port *ap) +static int adma_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct adma_port_priv *pp = ap->private_data; if (pp->state != adma_state_idle) /* healthy paranoia */ pp->state = adma_state_mmio; adma_reinit_engine(ap); - ata_eng_timeout(ap); + + return ata_std_prereset(link, deadline); +} + +static void adma_error_handler(struct ata_port *ap) +{ + ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL, + ata_std_postreset); } static int adma_fill_sg(struct ata_queued_cmd *qc) @@ -464,14 +484,33 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) pp = ap->private_data; if (!pp || pp->state != adma_state_pkt) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { - if ((status & (aPERR | aPSD | aUIRQ))) + if (status & aPERR) + qc->err_mask |= AC_ERR_HOST_BUS; + else if ((status & (aPSD | aUIRQ))) qc->err_mask |= AC_ERR_OTHER; + + if (pp->pkt[0] & cATERR) + qc->err_mask |= AC_ERR_DEV; else if (pp->pkt[0] != cDONE) qc->err_mask |= AC_ERR_OTHER; - ata_qc_complete(qc); + if (!qc->err_mask) + ata_qc_complete(qc); + else { + struct ata_eh_info *ehi = &ap->link.eh_info; + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, + "ADMA-status 0x%02X", status); + ata_ehi_push_desc(ehi, + "pkt[0] 0x%02X", pp->pkt[0]); + + if (qc->err_mask == AC_ERR_DEV) + ata_port_abort(ap); + else + ata_port_freeze(ap); + } } } return handled; @@ -489,7 +528,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) struct adma_port_priv *pp = ap->private_data; if (!pp || pp->state != adma_state_mmio) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ @@ -502,7 +541,20 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) /* complete taskfile transaction */ pp->state = adma_state_idle; qc->err_mask |= ac_err_mask(status); - ata_qc_complete(qc); + if (!qc->err_mask) + ata_qc_complete(qc); + else { + 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); + } handled = 1; } } @@ -652,9 +704,16 @@ static int adma_ata_init_one(struct pci_dev *pdev, if (rc) return rc; - for (port_no = 0; port_no < ADMA_PORTS; ++port_no) - adma_ata_setup_port(&host->ports[port_no]->ioaddr, - ADMA_ATA_REGS(mmio_base, port_no)); + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) { + struct ata_port *ap = host->ports[port_no]; + void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no); + unsigned int offset = port_base - mmio_base; + + adma_ata_setup_port(&ap->ioaddr, port_base); + + ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port"); + } /* initialize adapter */ adma_host_init(host, board_idx);