]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ata/ahci.c
[SCSI] libiscsi regression in 2.6.25: fix nop timer handling
[linux-2.6-omap-h63xx.git] / drivers / ata / ahci.c
index 1389c64e0027c4d7c088cb08ee19d45f2a6fa82d..97f83fb2ee2eef25af748297cb474c859ba6545e 100644 (file)
@@ -243,11 +243,10 @@ static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
 static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
+static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
-static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void ahci_qc_prep(struct ata_queued_cmd *qc);
-static u8 ahci_check_status(struct ata_port *ap);
 static void ahci_freeze(struct ata_port *ap);
 static void ahci_thaw(struct ata_port *ap);
 static void ahci_pmp_attach(struct ata_port *ap);
@@ -261,8 +260,6 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
 static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
                                unsigned long deadline);
 static void ahci_postreset(struct ata_link *link, unsigned int *class);
-static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
-                             unsigned long deadline);
 static void ahci_error_handler(struct ata_port *ap);
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
 static int ahci_port_resume(struct ata_port *ap);
@@ -276,8 +273,8 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
 static int ahci_pci_device_resume(struct pci_dev *pdev);
 #endif
 
-static struct class_device_attribute *ahci_shost_attrs[] = {
-       &class_device_attr_link_power_management_policy,
+static struct device_attribute *ahci_shost_attrs[] = {
+       &dev_attr_link_power_management_policy,
        NULL
 };
 
@@ -292,20 +289,17 @@ static struct scsi_host_template ahci_sht = {
 static struct ata_port_operations ahci_ops = {
        .inherits               = &sata_pmp_port_ops,
 
-       .sff_check_status       = ahci_check_status,
-       .sff_check_altstatus    = ahci_check_status,
-
-       .sff_tf_read            = ahci_tf_read,
        .qc_defer               = sata_pmp_qc_defer_cmd_switch,
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
+       .qc_fill_rtf            = ahci_qc_fill_rtf,
 
        .freeze                 = ahci_freeze,
        .thaw                   = ahci_thaw,
        .softreset              = ahci_softreset,
        .hardreset              = ahci_hardreset,
        .postreset              = ahci_postreset,
-       .pmp_softreset          = ahci_pmp_softreset,
+       .pmp_softreset          = ahci_softreset,
        .error_handler          = ahci_error_handler,
        .post_internal_cmd      = ahci_post_internal_cmd,
        .dev_config             = ahci_dev_config,
@@ -364,7 +358,7 @@ static const struct ata_port_info ahci_port_info[] = {
        /* board_ahci_sb600 */
        {
                AHCI_HFLAGS     (AHCI_HFLAG_IGN_SERR_INTERNAL |
-                                AHCI_HFLAG_32BIT_ONLY |
+                                AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
                                 AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP),
                .flags          = AHCI_FLAG_COMMON,
                .pio_mask       = 0x1f, /* pio0-4 */
@@ -562,16 +556,27 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
 
 static void ahci_enable_ahci(void __iomem *mmio)
 {
+       int i;
        u32 tmp;
 
        /* turn on AHCI_EN */
        tmp = readl(mmio + HOST_CTL);
-       if (!(tmp & HOST_AHCI_EN)) {
+       if (tmp & HOST_AHCI_EN)
+               return;
+
+       /* Some controllers need AHCI_EN to be written multiple times.
+        * Try a few times before giving up.
+        */
+       for (i = 0; i < 5; i++) {
                tmp |= HOST_AHCI_EN;
                writel(tmp, mmio + HOST_CTL);
                tmp = readl(mmio + HOST_CTL);   /* flush && sanity check */
-               WARN_ON(!(tmp & HOST_AHCI_EN));
+               if (tmp & HOST_AHCI_EN)
+                       return;
+               msleep(10);
        }
+
+       WARN_ON(1);
 }
 
 /**
@@ -1183,13 +1188,14 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
 
 static int ahci_kick_engine(struct ata_port *ap, int force_restart)
 {
-       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+       void __iomem *port_mmio = ahci_port_base(ap);
        struct ahci_host_priv *hpriv = ap->host->private_data;
+       u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
        u32 tmp;
        int busy, rc;
 
        /* do we need to kick the port? */
-       busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+       busy = status & (ATA_BUSY | ATA_DRQ);
        if (!busy && !force_restart)
                return 0;
 
@@ -1258,18 +1264,17 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
 
 static int ahci_check_ready(struct ata_link *link)
 {
-       void __iomem *mmio = link->ap->ioaddr.cmd_addr;
-       u8 status = readl(mmio + PORT_TFDATA) & 0xFF;
+       void __iomem *port_mmio = ahci_port_base(link->ap);
+       u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
 
-       if (!(status & ATA_BUSY))
-               return 1;
-       return 0;
+       return ata_check_ready(status);
 }
 
-static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
-                            int pmp, unsigned long deadline)
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
+                         unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
+       int pmp = sata_srst_pmp(link);
        const char *reason = NULL;
        unsigned long now, msecs;
        struct ata_taskfile tf;
@@ -1277,12 +1282,6 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
 
        DPRINTK("ENTER\n");
 
-       if (ata_link_offline(link)) {
-               DPRINTK("PHY reports no device\n");
-               *class = ATA_DEV_NONE;
-               return 0;
-       }
-
        /* prepare for SRST (AHCI-1.1 10.4.1) */
        rc = ahci_kick_engine(ap, 1);
        if (rc && rc != -EOPNOTSUPP)
@@ -1329,17 +1328,6 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
        return rc;
 }
 
-static int ahci_softreset(struct ata_link *link, unsigned int *class,
-                         unsigned long deadline)
-{
-       int pmp = 0;
-
-       if (link->ap->flags & ATA_FLAG_PMP)
-               pmp = SATA_PMP_CTRL_PORT;
-
-       return ahci_do_softreset(link, class, pmp, deadline);
-}
-
 static int ahci_hardreset(struct ata_link *link, unsigned int *class,
                          unsigned long deadline)
 {
@@ -1460,27 +1448,6 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class)
        }
 }
 
-static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
-                             unsigned long deadline)
-{
-       return ahci_do_softreset(link, class, link->pmp, deadline);
-}
-
-static u8 ahci_check_status(struct ata_port *ap)
-{
-       void __iomem *mmio = ap->ioaddr.cmd_addr;
-
-       return readl(mmio + PORT_TFDATA) & 0xFF;
-}
-
-static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
-       struct ahci_port_priv *pp = ap->private_data;
-       u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
-
-       ata_tf_from_fis(d2h_fis, tf);
-}
-
 static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
 {
        struct scatterlist *sg;
@@ -1599,7 +1566,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
                                  unk[0], unk[1], unk[2], unk[3]);
        }
 
-       if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) {
+       if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
                active_ehi->err_mask |= AC_ERR_HSM;
                active_ehi->action |= ATA_EH_RESET;
                ata_ehi_push_desc(active_ehi, "incorrect PMP");
@@ -1634,7 +1601,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 
 static void ahci_port_intr(struct ata_port *ap)
 {
-       void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+       void __iomem *port_mmio = ahci_port_base(ap);
        struct ata_eh_info *ehi = &ap->link.eh_info;
        struct ahci_port_priv *pp = ap->private_data;
        struct ahci_host_priv *hpriv = ap->host->private_data;
@@ -1779,6 +1746,15 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
        return 0;
 }
 
+static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+       struct ahci_port_priv *pp = qc->ap->private_data;
+       u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+
+       ata_tf_from_fis(d2h_fis, &qc->result_tf);
+       return true;
+}
+
 static void ahci_freeze(struct ata_port *ap)
 {
        void __iomem *port_mmio = ahci_port_base(ap);
@@ -1856,7 +1832,7 @@ static int ahci_port_resume(struct ata_port *ap)
        ahci_power_up(ap);
        ahci_start_port(ap);
 
-       if (ap->nr_pmp_links)
+       if (sata_pmp_attached(ap))
                ahci_pmp_attach(ap);
        else
                ahci_pmp_detach(ap);
@@ -2219,7 +2195,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
-               void __iomem *port_mmio = ahci_port_base(ap);
 
                ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
                ata_port_pbar_desc(ap, AHCI_PCI_BAR,
@@ -2228,12 +2203,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                /* set initial link pm policy */
                ap->pm_policy = NOT_AVAILABLE;
 
-               /* standard SATA port setup */
-               if (hpriv->port_map & (1 << i))
-                       ap->ioaddr.cmd_addr = port_mmio;
-
                /* disabled/not-implemented port */
-               else
+               if (!(hpriv->port_map & (1 << i)))
                        ap->ops = &ata_dummy_port_ops;
        }