libata: implement drain buffers
[safe/jmp/linux-2.6] / drivers / ata / pata_icside.c
index c791a46..f97068b 100644 (file)
@@ -70,6 +70,8 @@ struct pata_icside_info {
        unsigned int            mwdma_mask;
        unsigned int            nr_ports;
        const struct portinfo   *port[2];
+       unsigned long           raw_base;
+       unsigned long           raw_ioc_base;
 };
 
 #define ICS_TYPE_A3IN  0
@@ -222,6 +224,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
        struct pata_icside_state *state = ap->host->private_data;
        struct scatterlist *sg, *rsg = state->sg;
        unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE;
+       unsigned int si;
 
        /*
         * We are simplex; BUG if we try to fiddle with DMA
@@ -232,7 +235,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
        /*
         * Copy ATAs scattered sg list into a contiguous array of sg
         */
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                memcpy(rsg, sg, sizeof(*sg));
                rsg++;
        }
@@ -301,12 +304,6 @@ static int icside_dma_init(struct pata_icside_info *info)
 }
 
 
-static int pata_icside_port_start(struct ata_port *ap)
-{
-       /* No PRD to alloc */
-       return ata_pad_alloc(ap, ap->dev);
-}
-
 static struct scsi_host_template pata_icside_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -330,17 +327,13 @@ static void ata_dummy_noret(struct ata_port *port)
 {
 }
 
-/*
- * We need to shut down unused ports to prevent spurious interrupts.
- * FIXME: the libata core doesn't call this function for PATA interfaces.
- */
-static void pata_icside_port_disable(struct ata_port *ap)
+static void pata_icside_postreset(struct ata_link *link, unsigned int *classes)
 {
+       struct ata_port *ap = link->ap;
        struct pata_icside_state *state = ap->host->private_data;
 
-       ata_port_printk(ap, KERN_ERR, "disabling icside port\n");
-
-       ata_port_disable(ap);
+       if (classes[0] != ATA_DEV_NONE || classes[1] != ATA_DEV_NONE)
+               return ata_std_postreset(link, classes);
 
        state->port[ap->port_no].disabled = 1;
 
@@ -356,26 +349,13 @@ static void pata_icside_port_disable(struct ata_port *ap)
        }
 }
 
-static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+static void pata_icside_error_handler(struct ata_port *ap)
 {
-       unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
-       u8 status;
-
-       status = ata_busy_wait(ap, bits, 1000);
-       if (status & bits)
-               if (ata_msg_err(ap))
-                       printk(KERN_ERR "abnormal status 0x%X\n", status);
-
-       if (ata_msg_intr(ap))
-               printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n",
-                       __FUNCTION__, status);
-
-       return status;
+       ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
+                          pata_icside_postreset);
 }
 
 static struct ata_port_operations pata_icside_port_ops = {
-       .port_disable           = pata_icside_port_disable,
-
        .set_dmamode            = pata_icside_set_dmamode,
 
        .tf_load                = ata_tf_load,
@@ -397,39 +377,45 @@ static struct ata_port_operations pata_icside_port_ops = {
 
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
-       .error_handler          = ata_bmdma_error_handler,
+       .error_handler          = pata_icside_error_handler,
        .post_internal_cmd      = pata_icside_bmdma_stop,
 
        .irq_clear              = ata_dummy_noret,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = pata_icside_irq_ack,
-
-       .port_start             = pata_icside_port_start,
 
        .bmdma_stop             = pata_icside_bmdma_stop,
        .bmdma_status           = pata_icside_bmdma_status,
 };
 
 static void __devinit
-pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
-                        const struct portinfo *info)
+pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
+                        struct pata_icside_info *info,
+                        const struct portinfo *port)
 {
-       void __iomem *cmd = base + info->dataoffset;
+       struct ata_ioports *ioaddr = &ap->ioaddr;
+       void __iomem *cmd = base + port->dataoffset;
 
        ioaddr->cmd_addr        = cmd;
-       ioaddr->data_addr       = cmd + (ATA_REG_DATA    << info->stepping);
-       ioaddr->error_addr      = cmd + (ATA_REG_ERR     << info->stepping);
-       ioaddr->feature_addr    = cmd + (ATA_REG_FEATURE << info->stepping);
-       ioaddr->nsect_addr      = cmd + (ATA_REG_NSECT   << info->stepping);
-       ioaddr->lbal_addr       = cmd + (ATA_REG_LBAL    << info->stepping);
-       ioaddr->lbam_addr       = cmd + (ATA_REG_LBAM    << info->stepping);
-       ioaddr->lbah_addr       = cmd + (ATA_REG_LBAH    << info->stepping);
-       ioaddr->device_addr     = cmd + (ATA_REG_DEVICE  << info->stepping);
-       ioaddr->status_addr     = cmd + (ATA_REG_STATUS  << info->stepping);
-       ioaddr->command_addr    = cmd + (ATA_REG_CMD     << info->stepping);
-
-       ioaddr->ctl_addr        = base + info->ctrloffset;
+       ioaddr->data_addr       = cmd + (ATA_REG_DATA    << port->stepping);
+       ioaddr->error_addr      = cmd + (ATA_REG_ERR     << port->stepping);
+       ioaddr->feature_addr    = cmd + (ATA_REG_FEATURE << port->stepping);
+       ioaddr->nsect_addr      = cmd + (ATA_REG_NSECT   << port->stepping);
+       ioaddr->lbal_addr       = cmd + (ATA_REG_LBAL    << port->stepping);
+       ioaddr->lbam_addr       = cmd + (ATA_REG_LBAM    << port->stepping);
+       ioaddr->lbah_addr       = cmd + (ATA_REG_LBAH    << port->stepping);
+       ioaddr->device_addr     = cmd + (ATA_REG_DEVICE  << port->stepping);
+       ioaddr->status_addr     = cmd + (ATA_REG_STATUS  << port->stepping);
+       ioaddr->command_addr    = cmd + (ATA_REG_CMD     << port->stepping);
+
+       ioaddr->ctl_addr        = base + port->ctrloffset;
        ioaddr->altstatus_addr  = ioaddr->ctl_addr;
+
+       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+                     info->raw_base + port->dataoffset,
+                     info->raw_base + port->ctrloffset);
+
+       if (info->raw_ioc_base)
+               ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);
 }
 
 static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
@@ -450,6 +436,8 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
        info->nr_ports = 1;
        info->port[0] = &pata_icside_portinfo_v5;
 
+       info->raw_base = ecard_resource_start(info->ec, ECARD_RES_MEMC);
+
        return 0;
 }
 
@@ -484,19 +472,15 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
        state->port[0].port_sel = sel;
        state->port[1].port_sel = sel | 1;
 
-       /*
-        * FIXME: work around libata's aversion to calling port_disable.
-        * This permanently disables interrupts on port 0 - bad luck if
-        * you have a drive on that port.
-        */
-       state->port[0].disabled = 1;
-
        info->base = easi_base;
        info->irqops = &pata_icside_ops_arcin_v6;
        info->nr_ports = 2;
        info->port[0] = &pata_icside_portinfo_v6_1;
        info->port[1] = &pata_icside_portinfo_v6_2;
 
+       info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI);
+       info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+
        return icside_dma_init(info);
 }
 
@@ -530,10 +514,10 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
 
                ap->pio_mask = 0x1f;
                ap->mwdma_mask = info->mwdma_mask;
-               ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+               ap->flags |= ATA_FLAG_SLAVE_POSS;
                ap->ops = &pata_icside_port_ops;
 
-               pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]);
+               pata_icside_setup_ioaddr(ap, info->base, info, info->port[i]);
        }
 
        return ata_host_activate(host, ec->irq, ata_interrupt, 0,