]> err.no Git - linux-2.6/blobdiff - drivers/scsi/ahci.c
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[linux-2.6] / drivers / scsi / ahci.c
index fa01894fc41b90d297c4ba70693e79a6ff5bac53..ffba65656a838464bc0e05c48a6730821be54028 100644 (file)
@@ -66,6 +66,7 @@ enum {
        AHCI_IRQ_ON_SG          = (1 << 31),
        AHCI_CMD_ATAPI          = (1 << 5),
        AHCI_CMD_WRITE          = (1 << 6),
+       AHCI_CMD_PREFETCH       = (1 << 7),
        AHCI_CMD_RESET          = (1 << 8),
        AHCI_CMD_CLR_BUSY       = (1 << 10),
 
@@ -190,7 +191,7 @@ static void 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 irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static void ahci_phy_reset(struct ata_port *ap);
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void ahci_irq_clear(struct ata_port *ap);
 static void ahci_eng_timeout(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
@@ -206,12 +207,10 @@ static struct scsi_host_template ahci_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
-       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = AHCI_MAX_SG,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = AHCI_USE_CLUSTERING,
@@ -230,7 +229,7 @@ static const struct ata_port_operations ahci_ops = {
 
        .tf_read                = ahci_tf_read,
 
-       .phy_reset              = ahci_phy_reset,
+       .probe_reset            = ahci_probe_reset,
 
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
@@ -252,8 +251,7 @@ static const struct ata_port_info ahci_port_info[] = {
        {
                .sht            = &ahci_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
-                                 ATA_FLAG_PIO_DMA,
+                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
@@ -507,28 +505,175 @@ static unsigned int ahci_dev_classify(struct ata_port *ap)
        return ata_dev_classify(&tf);
 }
 
-static void ahci_phy_reset(struct ata_port *ap)
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
 {
-       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
-       struct ata_device *dev = &ap->device[0];
-       u32 new_tmp, tmp;
+       pp->cmd_slot[0].opts = cpu_to_le32(opts);
+       pp->cmd_slot[0].status = 0;
+       pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
+       pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+}
 
-       ahci_stop_engine(ap);
-       __sata_phy_reset(ap);
+static int ahci_poll_register(void __iomem *reg, u32 mask, u32 val,
+                             unsigned long interval_msec,
+                             unsigned long timeout_msec)
+{
+       unsigned long timeout;
+       u32 tmp;
+
+       timeout = jiffies + (timeout_msec * HZ) / 1000;
+       do {
+               tmp = readl(reg);
+               if ((tmp & mask) == val)
+                       return 0;
+               msleep(interval_msec);
+       } while (time_before(jiffies, timeout));
+
+       return -1;
+}
+
+static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
+       struct ahci_host_priv *hpriv = ap->host_set->private_data;
+       struct ahci_port_priv *pp = ap->private_data;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       const u32 cmd_fis_len = 5; /* five dwords */
+       const char *reason = NULL;
+       struct ata_taskfile tf;
+       u8 *fis;
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       /* prepare for SRST (AHCI-1.1 10.4.1) */
+       rc = ahci_stop_engine(ap);
+       if (rc) {
+               reason = "failed to stop engine";
+               goto fail_restart;
+       }
+
+       /* check BUSY/DRQ, perform Command List Override if necessary */
+       ahci_tf_read(ap, &tf);
+       if (tf.command & (ATA_BUSY | ATA_DRQ)) {
+               u32 tmp;
+
+               if (!(hpriv->cap & HOST_CAP_CLO)) {
+                       rc = -EIO;
+                       reason = "port busy but no CLO";
+                       goto fail_restart;
+               }
+
+               tmp = readl(port_mmio + PORT_CMD);
+               tmp |= PORT_CMD_CLO;
+               writel(tmp, port_mmio + PORT_CMD);
+               readl(port_mmio + PORT_CMD); /* flush */
+
+               if (ahci_poll_register(port_mmio + PORT_CMD, PORT_CMD_CLO, 0x0,
+                                      1, 500)) {
+                       rc = -EIO;
+                       reason = "CLO failed";
+                       goto fail_restart;
+               }
+       }
+
+       /* restart engine */
        ahci_start_engine(ap);
 
-       if (ap->flags & ATA_FLAG_PORT_DISABLED)
-               return;
+       ata_tf_init(ap, &tf, 0);
+       fis = pp->cmd_tbl;
 
-       dev->class = ahci_dev_classify(ap);
-       if (!ata_dev_present(dev)) {
-               ata_port_disable(ap);
-               return;
+       /* issue the first D2H Register FIS */
+       ahci_fill_cmd_slot(pp, cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+
+       tf.ctl |= ATA_SRST;
+       ata_tf_to_fis(&tf, fis, 0);
+       fis[1] &= ~(1 << 7);    /* turn off Command FIS bit */
+
+       writel(1, port_mmio + PORT_CMD_ISSUE);
+       readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
+
+       if (ahci_poll_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x0, 1, 500)) {
+               rc = -EIO;
+               reason = "1st FIS failed";
+               goto fail;
        }
 
+       /* spec says at least 5us, but be generous and sleep for 1ms */
+       msleep(1);
+
+       /* issue the second D2H Register FIS */
+       ahci_fill_cmd_slot(pp, cmd_fis_len);
+
+       tf.ctl &= ~ATA_SRST;
+       ata_tf_to_fis(&tf, fis, 0);
+       fis[1] &= ~(1 << 7);    /* turn off Command FIS bit */
+
+       writel(1, port_mmio + PORT_CMD_ISSUE);
+       readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
+
+       /* spec mandates ">= 2ms" before checking status.
+        * We wait 150ms, because that was the magic delay used for
+        * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+        * between when the ATA command register is written, and then
+        * status is checked.  Because waiting for "a while" before
+        * checking status is fine, post SRST, we perform this magic
+        * delay here as well.
+        */
+       msleep(150);
+
+       *class = ATA_DEV_NONE;
+       if (sata_dev_present(ap)) {
+               if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+                       rc = -EIO;
+                       reason = "device not ready";
+                       goto fail;
+               }
+               *class = ahci_dev_classify(ap);
+       }
+
+       DPRINTK("EXIT, class=%u\n", *class);
+       return 0;
+
+ fail_restart:
+       ahci_start_engine(ap);
+ fail:
+       if (verbose)
+               printk(KERN_ERR "ata%u: softreset failed (%s)\n",
+                      ap->id, reason);
+       else
+               DPRINTK("EXIT, rc=%d reason=\"%s\"\n", rc, reason);
+       return rc;
+}
+
+static int ahci_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       ahci_stop_engine(ap);
+       rc = sata_std_hardreset(ap, verbose, class);
+       ahci_start_engine(ap);
+
+       if (rc == 0)
+               *class = ahci_dev_classify(ap);
+       if (*class == ATA_DEV_UNKNOWN)
+               *class = ATA_DEV_NONE;
+
+       DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+       return rc;
+}
+
+static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+{
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+       u32 new_tmp, tmp;
+
+       ata_std_postreset(ap, class);
+
        /* Make sure port's ATAPI bit is set appropriately */
        new_tmp = tmp = readl(port_mmio + PORT_CMD);
-       if (dev->class == ATA_DEV_ATAPI)
+       if (*class == ATA_DEV_ATAPI)
                new_tmp |= PORT_CMD_ATAPI;
        else
                new_tmp &= ~PORT_CMD_ATAPI;
@@ -538,6 +683,13 @@ static void ahci_phy_reset(struct ata_port *ap)
        }
 }
 
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+       return ata_drive_probe_reset(ap, ata_std_probeinit,
+                                    ahci_softreset, ahci_hardreset,
+                                    ahci_postreset, classes);
+}
+
 static u8 ahci_check_status(struct ata_port *ap)
 {
        void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -585,42 +737,36 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct ahci_port_priv *pp = ap->private_data;
+       int is_atapi = is_atapi_taskfile(&qc->tf);
        u32 opts;
        const u32 cmd_fis_len = 5; /* five dwords */
        unsigned int n_elem;
 
-       /*
-        * Fill in command slot information (currently only one slot,
-        * slot 0, is currently since we don't do queueing)
-        */
-
-       opts = cmd_fis_len;
-       if (qc->tf.flags & ATA_TFLAG_WRITE)
-               opts |= AHCI_CMD_WRITE;
-       if (is_atapi_taskfile(&qc->tf))
-               opts |= AHCI_CMD_ATAPI;
-
-       pp->cmd_slot[0].opts = cpu_to_le32(opts);
-       pp->cmd_slot[0].status = 0;
-       pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
-       pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
-
        /*
         * Fill in command table information.  First, the header,
         * a SATA Register - Host to Device command FIS.
         */
        ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
-       if (opts & AHCI_CMD_ATAPI) {
+       if (is_atapi) {
                memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
-               memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, ap->cdb_len);
+               memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
+                      qc->dev->cdb_len);
        }
 
-       if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-               return;
+       n_elem = 0;
+       if (qc->flags & ATA_QCFLAG_DMAMAP)
+               n_elem = ahci_fill_sg(qc);
 
-       n_elem = ahci_fill_sg(qc);
+       /*
+        * Fill in command slot information.
+        */
+       opts = cmd_fis_len | n_elem << 16;
+       if (qc->tf.flags & ATA_TFLAG_WRITE)
+               opts |= AHCI_CMD_WRITE;
+       if (is_atapi)
+               opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
 
-       pp->cmd_slot[0].opts |= cpu_to_le32(n_elem << 16);
+       ahci_fill_cmd_slot(pp, opts);
 }
 
 static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
@@ -701,7 +847,7 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
        ci = readl(port_mmio + PORT_CMD_ISSUE);
        if (likely((ci & 0x1) == 0)) {
                if (qc) {
-                       assert(qc->err_mask == 0);
+                       WARN_ON(qc->err_mask);
                        ata_qc_complete(qc);
                        qc = NULL;
                }
@@ -765,23 +911,17 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
                        struct ata_queued_cmd *qc;
                        qc = ata_qc_from_tag(ap, ap->active_tag);
                        if (!ahci_host_intr(ap, qc))
-                               if (ata_ratelimit()) {
-                                       struct pci_dev *pdev =
-                                               to_pci_dev(ap->host_set->dev);
-                                       dev_printk(KERN_WARNING, &pdev->dev,
+                               if (ata_ratelimit())
+                                       dev_printk(KERN_WARNING, host_set->dev,
                                          "unhandled interrupt on port %u\n",
                                          i);
-                               }
 
                        VPRINTK("port %u\n", i);
                } else {
                        VPRINTK("port %u (no irq)\n", i);
-                       if (ata_ratelimit()) {
-                               struct pci_dev *pdev =
-                                       to_pci_dev(ap->host_set->dev);
-                               dev_printk(KERN_WARNING, &pdev->dev,
+                       if (ata_ratelimit())
+                               dev_printk(KERN_WARNING, host_set->dev,
                                        "interrupt on disabled port %u\n", i);
-                       }
                }
 
                irq_ack |= (1 << i);