X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Fahci.c;h=ffba65656a838464bc0e05c48a6730821be54028;hb=7d14f145f839b5d0d221ea209b4998f93267e2ec;hp=98ce6bb62ff83a0d4f209185274f9308318a2368;hpb=c5014de8a74f442a4441f21f690d8aae5dc8b432;p=linux-2.6 diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 98ce6bb62f..ffba65656a 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -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,37 +505,175 @@ static unsigned int ahci_dev_classify(struct ata_port *ap) return ata_dev_classify(&tf); } -static void ahci_fill_cmd_slot(struct ata_port *ap, u32 opts) +static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts) { - struct ahci_port_priv *pp = ap->private_data; 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); } -static void ahci_phy_reset(struct ata_port *ap) +static int ahci_poll_register(void __iomem *reg, u32 mask, u32 val, + unsigned long interval_msec, + unsigned long timeout_msec) { - void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; - struct ata_device *dev = &ap->device[0]; - u32 new_tmp, tmp; + unsigned long timeout; + u32 tmp; - ahci_stop_engine(ap); - __sata_phy_reset(ap); + 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; @@ -547,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; @@ -606,7 +749,8 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0); 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); } n_elem = 0; @@ -620,9 +764,9 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_WRITE) opts |= AHCI_CMD_WRITE; if (is_atapi) - opts |= AHCI_CMD_ATAPI; + opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; - ahci_fill_cmd_slot(ap, opts); + ahci_fill_cmd_slot(pp, opts); } static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) @@ -703,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; } @@ -767,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);