diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-10 14:26:04 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-10 14:26:04 -0800 |
commit | 487350e4434610e31b71eac5d6a9714b72fa32f6 (patch) | |
tree | bf09b2cd0e09091784eac9fc8041358c69ac3c7c | |
parent | 1da63a2131b0185f64a4c623a0e0b030479185fe (diff) | |
parent | 037f6bb79f753c014bc84bca0de9bf98bb5ab169 (diff) | |
download | linux-487350e4434610e31b71eac5d6a9714b72fa32f6.tar.gz linux-487350e4434610e31b71eac5d6a9714b72fa32f6.tar.bz2 linux-487350e4434610e31b71eac5d6a9714b72fa32f6.zip |
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev:
libata: Don't fail device revalidation for bad _GTF methods
libata: port and host should be stopped before hardware resources are released
libata: skip 0xff polling for PATA controllers
libata: pata_platform: Support polling-mode configuration.
libata: Support PIO polling-only hosts.
libata sata_qstor conversion to new error handling (EH).
libata sata_qstor workaround for spurious interrupts
libata sata_qstor nuke idle state
nv_hardreset: update dangling reference to bugzilla entry
ata_piix: add SATELLITE PRO U200 to broken suspend list
-rw-r--r-- | drivers/ata/ata_piix.c | 7 | ||||
-rw-r--r-- | drivers/ata/libata-acpi.c | 10 | ||||
-rw-r--r-- | drivers/ata/libata-core.c | 78 | ||||
-rw-r--r-- | drivers/ata/pata_platform.c | 35 | ||||
-rw-r--r-- | drivers/ata/sata_nv.c | 2 | ||||
-rw-r--r-- | drivers/ata/sata_qstor.c | 114 |
6 files changed, 172 insertions, 74 deletions
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index f08cca21702c..328ce8a08426 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -960,6 +960,13 @@ static int piix_broken_suspend(void) }, }, { + .ident = "Satellite Pro U200", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE PRO U200"), + }, + }, + { .ident = "Satellite U205", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 08a52dd45fb6..545ea865ceb5 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -312,7 +312,7 @@ EXPORT_SYMBOL_GPL(ata_acpi_stm); * * RETURNS: * Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't - * contain valid data. -errno on other errors. + * contain valid data. */ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, void **ptr_to_free) @@ -339,7 +339,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, ata_dev_printk(dev, KERN_WARNING, "_GTF evaluation failed (AE 0x%x)\n", status); - rc = -EIO; } goto out_free; } @@ -359,7 +358,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, ata_dev_printk(dev, KERN_WARNING, "_GTF unexpected object type 0x%x\n", out_obj->type); - rc = -EINVAL; goto out_free; } @@ -367,7 +365,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, ata_dev_printk(dev, KERN_WARNING, "unexpected _GTF length (%d)\n", out_obj->buffer.length); - rc = -EINVAL; goto out_free; } @@ -511,10 +508,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev) int gtf_count, i, rc; /* get taskfiles */ - rc = ata_dev_get_GTF(dev, >f, &ptr_to_free); - if (rc < 0) - return rc; - gtf_count = rc; + gtf_count = ata_dev_get_GTF(dev, >f, &ptr_to_free); /* execute them */ for (i = 0, rc = 0; i < gtf_count; i++) { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ec3ce120a517..81898036dbca 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3373,14 +3373,20 @@ void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline) * to clear 0xff after reset. For example, HHD424020F7SV00 * iVDR needs >= 800ms while. Quantum GoVault needs even more * than that. + * + * Note that some PATA controllers (pata_ali) explode if + * status register is read more than once when there's no + * device attached. */ - while (1) { - u8 status = ata_chk_status(ap); + if (ap->flags & ATA_FLAG_SATA) { + while (1) { + u8 status = ata_chk_status(ap); - if (status != 0xff || time_after(jiffies, deadline)) - return; + if (status != 0xff || time_after(jiffies, deadline)) + return; - msleep(50); + msleep(50); + } } } @@ -6821,19 +6827,6 @@ static void ata_host_release(struct device *gendev, void *res) if (!ap) continue; - if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop) - ap->ops->port_stop(ap); - } - - if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop) - host->ops->host_stop(host); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - if (!ap) - continue; - if (ap->scsi_host) scsi_host_put(ap->scsi_host); @@ -6960,6 +6953,24 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, return host; } +static void ata_host_stop(struct device *gendev, void *res) +{ + struct ata_host *host = dev_get_drvdata(gendev); + int i; + + WARN_ON(!(host->flags & ATA_HOST_STARTED)); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->ops->port_stop) + ap->ops->port_stop(ap); + } + + if (host->ops->host_stop) + host->ops->host_stop(host); +} + /** * ata_host_start - start and freeze ports of an ATA host * @host: ATA host to start ports for @@ -6978,6 +6989,8 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, */ int ata_host_start(struct ata_host *host) { + int have_stop = 0; + void *start_dr = NULL; int i, rc; if (host->flags & ATA_HOST_STARTED) @@ -6989,6 +7002,22 @@ int ata_host_start(struct ata_host *host) if (!host->ops && !ata_port_is_dummy(ap)) host->ops = ap->ops; + if (ap->ops->port_stop) + have_stop = 1; + } + + if (host->ops->host_stop) + have_stop = 1; + + if (have_stop) { + start_dr = devres_alloc(ata_host_stop, 0, GFP_KERNEL); + if (!start_dr) + return -ENOMEM; + } + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + if (ap->ops->port_start) { rc = ap->ops->port_start(ap); if (rc) { @@ -7001,6 +7030,8 @@ int ata_host_start(struct ata_host *host) ata_eh_freeze_port(ap); } + if (start_dr) + devres_add(host->dev, start_dr); host->flags |= ATA_HOST_STARTED; return 0; @@ -7011,6 +7042,7 @@ int ata_host_start(struct ata_host *host) if (ap->ops->port_stop) ap->ops->port_stop(ap); } + devres_free(start_dr); return rc; } @@ -7178,6 +7210,10 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) * request IRQ and register it. This helper takes necessasry * arguments and performs the three steps in one go. * + * An invalid IRQ skips the IRQ registration and expects the host to + * have set polling mode on the port. In this case, @irq_handler + * should be NULL. + * * LOCKING: * Inherited from calling layer (may sleep). * @@ -7194,6 +7230,12 @@ int ata_host_activate(struct ata_host *host, int irq, if (rc) return rc; + /* Special case for polling mode */ + if (!irq) { + WARN_ON(irq_handler); + return ata_host_register(host, sht); + } + rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags, dev_driver_string(host->dev), host); if (rc) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index fc72a965643d..ac03a90a6168 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -1,7 +1,7 @@ /* * Generic platform device PATA driver * - * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006 - 2007 Paul Mundt * * Based on pata_pcmcia: * @@ -22,7 +22,7 @@ #include <linux/pata_platform.h> #define DRV_NAME "pata_platform" -#define DRV_VERSION "1.1" +#define DRV_VERSION "1.2" static int pio_mask = 1; @@ -120,15 +120,20 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr, * Register a platform bus IDE interface. Such interfaces are PIO and we * assume do not support IRQ sharing. * - * Platform devices are expected to contain 3 resources per port: + * Platform devices are expected to contain at least 2 resources per port: * * - I/O Base (IORESOURCE_IO or IORESOURCE_MEM) * - CTL Base (IORESOURCE_IO or IORESOURCE_MEM) + * + * and optionally: + * * - IRQ (IORESOURCE_IRQ) * * If the base resources are both mem types, the ioremap() is handled * here. For IORESOURCE_IO, it's assumed that there's no remapping * necessary. + * + * If no IRQ resource is present, PIO polling mode is used instead. */ static int __devinit pata_platform_probe(struct platform_device *pdev) { @@ -137,11 +142,12 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) struct ata_port *ap; struct pata_platform_info *pp_info; unsigned int mmio; + int irq; /* * Simple resource validation .. */ - if (unlikely(pdev->num_resources != 3)) { + if ((pdev->num_resources != 3) && (pdev->num_resources != 2)) { dev_err(&pdev->dev, "invalid number of resources\n"); return -EINVAL; } @@ -173,6 +179,13 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) (ctl_res->flags == IORESOURCE_MEM)); /* + * And the IRQ + */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + irq = 0; /* no irq */ + + /* * Now that that's out of the way, wire up the port.. */ host = ata_host_alloc(&pdev->dev, 1); @@ -185,6 +198,14 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) ap->flags |= ATA_FLAG_SLAVE_POSS; /* + * Use polling mode if there's no IRQ + */ + if (!irq) { + ap->flags |= ATA_FLAG_PIO_POLLING; + ata_port_desc(ap, "no IRQ, using PIO polling"); + } + + /* * Handle the MMIO case */ if (mmio) { @@ -213,9 +234,9 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) (unsigned long long)ctl_res->start); /* activate */ - return ata_host_activate(host, platform_get_irq(pdev, 0), - ata_interrupt, pp_info ? pp_info->irq_flags - : 0, &pata_platform_sht); + return ata_host_activate(host, irq, irq ? ata_interrupt : NULL, + pp_info ? pp_info->irq_flags : 0, + &pata_platform_sht); } /** diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 35b2df297527..44f9e5d9e362 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1629,7 +1629,7 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class, /* SATA hardreset fails to retrieve proper device signature on * some controllers. Don't classify on hardreset. For more - * info, see http://bugme.osdl.org/show_bug.cgi?id=3352 + * info, see http://bugzilla.kernel.org/show_bug.cgi?id=3352 */ return sata_std_hardreset(link, &dummy, deadline); } diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 6d43ba79e154..2f1de6ec044c 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -103,7 +103,7 @@ enum { QS_DMA_BOUNDARY = ~0UL }; -typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t; +typedef enum { qs_state_mmio, qs_state_pkt } qs_state_t; struct qs_port_priv { u8 *pkt; @@ -116,14 +116,15 @@ static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int qs_port_start(struct ata_port *ap); static void qs_host_stop(struct ata_host *host); -static void qs_phy_reset(struct ata_port *ap); static void qs_qc_prep(struct ata_queued_cmd *qc); static unsigned int qs_qc_issue(struct ata_queued_cmd *qc); static int qs_check_atapi_dma(struct ata_queued_cmd *qc); static void qs_bmdma_stop(struct ata_queued_cmd *qc); static u8 qs_bmdma_status(struct ata_port *ap); static void qs_irq_clear(struct ata_port *ap); -static void qs_eng_timeout(struct ata_port *ap); +static void qs_freeze(struct ata_port *ap); +static void qs_thaw(struct ata_port *ap); +static void qs_error_handler(struct ata_port *ap); static struct scsi_host_template qs_ata_sht = { .module = THIS_MODULE, @@ -150,11 +151,12 @@ static const struct ata_port_operations qs_ata_ops = { .check_atapi_dma = qs_check_atapi_dma, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, - .phy_reset = qs_phy_reset, .qc_prep = qs_qc_prep, .qc_issue = qs_qc_issue, .data_xfer = ata_data_xfer, - .eng_timeout = qs_eng_timeout, + .freeze = qs_freeze, + .thaw = qs_thaw, + .error_handler = qs_error_handler, .irq_clear = qs_irq_clear, .irq_on = ata_irq_on, .scr_read = qs_scr_read, @@ -169,8 +171,6 @@ static const struct ata_port_info qs_port_info[] = { /* board_2068_idx */ { .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | - //FIXME ATA_FLAG_SRST | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ .udma_mask = ATA_UDMA6, @@ -219,7 +219,9 @@ static void qs_irq_clear(struct ata_port *ap) static inline void qs_enter_reg_mode(struct ata_port *ap) { u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); + struct qs_port_priv *pp = ap->private_data; + pp->state = qs_state_mmio; writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); readb(chan + QS_CCT_CTR0); /* flush */ } @@ -233,23 +235,28 @@ static inline void qs_reset_channel_logic(struct ata_port *ap) qs_enter_reg_mode(ap); } -static void qs_phy_reset(struct ata_port *ap) +static void qs_freeze(struct ata_port *ap) { - struct qs_port_priv *pp = ap->private_data; + u8 __iomem *mmio_base = qs_mmio_base(ap->host); - pp->state = qs_state_idle; - qs_reset_channel_logic(ap); - sata_phy_reset(ap); + writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ + qs_enter_reg_mode(ap); } -static void qs_eng_timeout(struct ata_port *ap) +static void qs_thaw(struct ata_port *ap) { - struct qs_port_priv *pp = ap->private_data; + u8 __iomem *mmio_base = qs_mmio_base(ap->host); + + qs_enter_reg_mode(ap); + writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */ +} + +static int qs_prereset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; - if (pp->state != qs_state_idle) /* healthy paranoia */ - pp->state = qs_state_mmio; qs_reset_channel_logic(ap); - ata_eng_timeout(ap); + return ata_std_prereset(link, deadline); } static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) @@ -260,6 +267,13 @@ static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) return 0; } +static void qs_error_handler(struct ata_port *ap) +{ + qs_enter_reg_mode(ap); + ata_do_eh(ap, qs_prereset, ata_std_softreset, NULL, + ata_std_postreset); +} + static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) @@ -358,7 +372,6 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) switch (qc->tf.protocol) { case ATA_PROT_DMA: - pp->state = qs_state_pkt; qs_packet_start(qc); return 0; @@ -375,6 +388,26 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } +static void qs_do_or_die(struct ata_queued_cmd *qc, u8 status) +{ + qc->err_mask |= ac_err_mask(status); + + if (!qc->err_mask) { + ata_qc_complete(qc); + } else { + struct ata_port *ap = qc->ap; + 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); + } +} + static inline unsigned int qs_intr_pkt(struct ata_host *host) { unsigned int handled = 0; @@ -406,10 +439,8 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host) switch (sHST) { case 0: /* successful CPB */ case 3: /* device error */ - pp->state = qs_state_idle; qs_enter_reg_mode(qc->ap); - qc->err_mask |= ac_err_mask(sDST); - ata_qc_complete(qc); + qs_do_or_die(qc, sDST); break; default: break; @@ -431,25 +462,27 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - struct qs_port_priv *pp = ap->private_data; - if (!pp || pp->state != qs_state_mmio) - continue; + struct qs_port_priv *pp; qc = ata_qc_from_tag(ap, ap->link.active_tag); - if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { - - /* check main status, clearing INTRQ */ - u8 status = ata_check_status(ap); - if ((status & ATA_BUSY)) - continue; - DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", - ap->print_id, qc->tf.protocol, status); - - /* complete taskfile transaction */ - pp->state = qs_state_idle; - qc->err_mask |= ac_err_mask(status); - ata_qc_complete(qc); + if (!qc || !(qc->flags & ATA_QCFLAG_ACTIVE)) { + /* + * The qstor hardware generates spurious + * interrupts from time to time when switching + * in and out of packet mode. + * There's no obvious way to know if we're + * here now due to that, so just ack the irq + * and pretend we knew it was ours.. (ugh). + * This does not affect packet mode. + */ + ata_check_status(ap); handled = 1; + continue; } + pp = ap->private_data; + if (!pp || pp->state != qs_state_mmio) + continue; + if (!(qc->tf.flags & ATA_TFLAG_POLLING)) + handled |= ata_host_intr(ap, qc); } } return handled; @@ -459,12 +492,13 @@ static irqreturn_t qs_intr(int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int handled = 0; + unsigned long flags; VPRINTK("ENTER\n"); - spin_lock(&host->lock); + spin_lock_irqsave(&host->lock, flags); handled = qs_intr_pkt(host) | qs_intr_mmio(host); - spin_unlock(&host->lock); + spin_unlock_irqrestore(&host->lock, flags); VPRINTK("EXIT\n"); @@ -501,7 +535,6 @@ static int qs_port_start(struct ata_port *ap) rc = ata_port_start(ap); if (rc) return rc; - qs_enter_reg_mode(ap); pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); if (!pp) return -ENOMEM; @@ -512,6 +545,7 @@ static int qs_port_start(struct ata_port *ap) memset(pp->pkt, 0, QS_PKT_BYTES); ap->private_data = pp; + qs_enter_reg_mode(ap); addr = (u64)pp->pkt_dma; writel((u32) addr, chan + QS_CCF_CPBA); writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4); |