diff options
Diffstat (limited to 'drivers/ata')
30 files changed, 1035 insertions, 567 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 9bf2986a278..ae8494944c4 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -651,9 +651,17 @@ config PATA_WINBOND_VLB Support for the Winbond W83759A controller on Vesa Local Bus systems. +config HAVE_PATA_PLATFORM + bool + help + This is an internal configuration node for any machine that + uses pata-platform driver to enable the relevant driver in the + configuration structure without having to submit endless patches + to update the PATA_PLATFORM entry. + config PATA_PLATFORM tristate "Generic platform device PATA support" - depends on EMBEDDED || ARCH_RPC || PPC + depends on EMBEDDED || ARCH_RPC || PPC || HAVE_PATA_PLATFORM help This option enables support for generic directly connected ATA devices commonly found on embedded systems. diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 97f83fb2ee2..6a4a2a25d97 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -89,6 +89,8 @@ enum { board_ahci_sb600 = 3, board_ahci_mv = 4, board_ahci_sb700 = 5, + board_ahci_mcp65 = 6, + board_ahci_nopmp = 7, /* global controller registers */ HOST_CAP = 0x00, /* host capabilities */ @@ -190,6 +192,7 @@ enum { AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ + AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ /* ap->flags bits */ @@ -253,6 +256,8 @@ static void ahci_pmp_attach(struct ata_port *ap); static void ahci_pmp_detach(struct ata_port *ap); static int ahci_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline); +static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, @@ -329,6 +334,12 @@ static struct ata_port_operations ahci_p5wdh_ops = { .hardreset = ahci_p5wdh_hardreset, }; +static struct ata_port_operations ahci_sb600_ops = { + .inherits = &ahci_ops, + .softreset = ahci_sb600_softreset, + .pmp_softreset = ahci_sb600_softreset, +}; + #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) static const struct ata_port_info ahci_port_info[] = { @@ -359,11 +370,11 @@ static const struct ata_port_info ahci_port_info[] = { { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | - AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP), + AHCI_HFLAG_SECT255), .flags = AHCI_FLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, - .port_ops = &ahci_ops, + .port_ops = &ahci_sb600_ops, }, /* board_ahci_mv */ { @@ -377,8 +388,23 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_sb700 */ { - AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_NO_PMP), + AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), + .flags = AHCI_FLAG_COMMON, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_sb600_ops, + }, + /* board_ahci_mcp65 */ + { + AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), + .flags = AHCI_FLAG_COMMON, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, + /* board_ahci_nopmp */ + { + AHCI_HFLAGS (AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -438,14 +464,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ /* NVIDIA */ - { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 }, /* MCP65 */ { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ @@ -502,15 +528,15 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */ { PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */ { PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */ - { PCI_VDEVICE(NVIDIA, 0x0bd0), board_ahci }, /* MCP7B */ - { PCI_VDEVICE(NVIDIA, 0x0bd1), board_ahci }, /* MCP7B */ - { PCI_VDEVICE(NVIDIA, 0x0bd2), board_ahci }, /* MCP7B */ - { PCI_VDEVICE(NVIDIA, 0x0bd3), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */ + { PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */ /* SiS */ - { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ - { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ - { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ + { PCI_VDEVICE(SI, 0x1184), board_ahci_nopmp }, /* SiS 966 */ + { PCI_VDEVICE(SI, 0x1185), board_ahci_nopmp }, /* SiS 968 */ + { PCI_VDEVICE(SI, 0x0186), board_ahci_nopmp }, /* SiS 968 */ /* Marvell */ { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ @@ -624,12 +650,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev, cap &= ~HOST_CAP_NCQ; } + if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) { + dev_printk(KERN_INFO, &pdev->dev, + "controller can do NCQ, turning on CAP_NCQ\n"); + cap |= HOST_CAP_NCQ; + } + if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do PMP, turning off CAP_PMP\n"); cap &= ~HOST_CAP_PMP; } + if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 && + port_map != 1) { + dev_printk(KERN_INFO, &pdev->dev, + "JMB361 has only one port, port_map 0x%x -> 0x%x\n", + port_map, 1); + port_map = 1; + } + /* * Temporary Marvell 6145 hack: PATA port presence * is asserted through the standard AHCI port @@ -1262,19 +1302,11 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, return 0; } -static int ahci_check_ready(struct ata_link *link) -{ - void __iomem *port_mmio = ahci_port_base(link->ap); - u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; - - return ata_check_ready(status); -} - -static int ahci_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) +static int ahci_do_softreset(struct ata_link *link, unsigned int *class, + int pmp, unsigned long deadline, + int (*check_ready)(struct ata_link *link)) { struct ata_port *ap = link->ap; - int pmp = sata_srst_pmp(link); const char *reason = NULL; unsigned long now, msecs; struct ata_taskfile tf; @@ -1312,7 +1344,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class, ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); /* wait for link to become ready */ - rc = ata_wait_after_reset(link, deadline, ahci_check_ready); + rc = ata_wait_after_reset(link, deadline, check_ready); /* link occupied, -ENODEV too is an error */ if (rc) { reason = "device not ready"; @@ -1328,6 +1360,72 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class, return rc; } +static int ahci_check_ready(struct ata_link *link) +{ + void __iomem *port_mmio = ahci_port_base(link->ap); + u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; + + return ata_check_ready(status); +} + +static int ahci_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int pmp = sata_srst_pmp(link); + + DPRINTK("ENTER\n"); + + return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); +} + +static int ahci_sb600_check_ready(struct ata_link *link) +{ + void __iomem *port_mmio = ahci_port_base(link->ap); + u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; + u32 irq_status = readl(port_mmio + PORT_IRQ_STAT); + + /* + * There is no need to check TFDATA if BAD PMP is found due to HW bug, + * which can save timeout delay. + */ + if (irq_status & PORT_IRQ_BAD_PMP) + return -EIO; + + return ata_check_ready(status); +} + +static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + struct ata_port *ap = link->ap; + void __iomem *port_mmio = ahci_port_base(ap); + int pmp = sata_srst_pmp(link); + int rc; + u32 irq_sts; + + DPRINTK("ENTER\n"); + + rc = ahci_do_softreset(link, class, pmp, deadline, + ahci_sb600_check_ready); + + /* + * Soft reset fails on some ATI chips with IPMS set when PMP + * is enabled but SATA HDD/ODD is connected to SATA port, + * do soft reset again to port 0. + */ + if (rc == -EIO) { + irq_sts = readl(port_mmio + PORT_IRQ_STAT); + if (irq_sts & PORT_IRQ_BAD_PMP) { + ata_link_printk(link, KERN_WARNING, + "failed due to HW bug, retry pmp=0\n"); + rc = ahci_do_softreset(link, class, 0, deadline, + ahci_check_ready); + } + } + + return rc; +} + static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { @@ -2118,7 +2216,8 @@ static void ahci_p5wdh_workaround(struct ata_host *host) static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_port_info pi = ahci_port_info[ent->driver_data]; + unsigned int board_id = ent->driver_data; + struct ata_port_info pi = ahci_port_info[board_id]; const struct ata_port_info *ppi[] = { &pi, NULL }; struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; @@ -2167,6 +2266,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENOMEM; hpriv->flags |= (unsigned long)pi.private_data; + /* MCP65 revision A1 and A2 can't do MSI */ + if (board_id == board_ahci_mcp65 && + (pdev->revision == 0xa1 || pdev->revision == 0xa2)) + hpriv->flags |= AHCI_HFLAG_NO_MSI; + if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) pci_intx(pdev, 1); diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index a9027b8fbdd..a90ae03f56b 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -247,10 +247,11 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller 2 IDE (ICH8) */ { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, - /* Mobile SATA Controller IDE (ICH8M) */ - { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* Mobile SATA Controller IDE (ICH8M), Apple */ { 0x8086, 0x2828, 0x106b, 0x00a0, 0, 0, ich8m_apple_sata }, + { 0x8086, 0x2828, 0x106b, 0x00a1, 0, 0, ich8m_apple_sata }, + /* Mobile SATA Controller IDE (ICH8M) */ + { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller IDE (ICH9) */ { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller IDE (ICH9) */ @@ -526,7 +527,7 @@ static struct ata_port_info piix_port_info[] = { [ich8m_apple_sata] = { - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR, + .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -573,6 +574,8 @@ static const struct ich_laptop ich_laptop[] = { { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ + { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */ + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */ /* end marker */ { 0, } @@ -1040,6 +1043,13 @@ static int piix_broken_suspend(void) }, }, { + .ident = "TECRA M4", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M4"), + }, + }, + { .ident = "TECRA M5", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 70b77e0899a..3ff8b14420d 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -118,19 +118,82 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; } +static void ata_acpi_eject_device(acpi_handle handle) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", + &arg_list, NULL))) + printk(KERN_ERR "Failed to evaluate _EJ0!\n"); +} + +/* @ap and @dev are the same as ata_acpi_handle_hotplug() */ +static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) +{ + if (dev) + dev->flags |= ATA_DFLAG_DETACH; + else { + struct ata_link *tlink; + struct ata_device *tdev; + + ata_port_for_each_link(tlink, ap) + ata_link_for_each_dev(tdev, tlink) + tdev->flags |= ATA_DFLAG_DETACH; + } + + ata_port_schedule_eh(ap); +} + +/** + * ata_acpi_handle_hotplug - ACPI event handler backend + * @ap: ATA port ACPI event occurred + * @dev: ATA device ACPI event occurred (can be NULL) + * @event: ACPI event which occurred + * @is_dock_event: boolean indicating whether the event was a dock one + * + * All ACPI bay / device realted events end up in this function. If + * the event is port-wide @dev is NULL. If the event is specific to a + * device, @dev points to it. + * + * Hotplug (as opposed to unplug) notification is always handled as + * port-wide while unplug only kills the target device on device-wide + * event. + * + * LOCKING: + * ACPI notify handler context. May sleep. + */ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, - u32 event) + u32 event, int is_dock_event) { char event_string[12]; char *envp[] = { event_string, NULL }; - struct ata_eh_info *ehi; + struct ata_eh_info *ehi = &ap->link.eh_info; struct kobject *kobj = NULL; int wait = 0; unsigned long flags; + acpi_handle handle, tmphandle; + unsigned long sta; + acpi_status status; + + if (dev) { + if (dev->sdev) + kobj = &dev->sdev->sdev_gendev.kobj; + handle = dev->acpi_handle; + } else { + kobj = &ap->dev->kobj; + handle = ap->acpi_handle; + } - if (!ap) - ap = dev->link->ap; - ehi = &ap->link.eh_info; + status = acpi_get_handle(handle, "_EJ0", &tmphandle); + if (ACPI_FAILURE(status)) + /* This device does not support hotplug */ + return; spin_lock_irqsave(ap->lock, flags); @@ -138,57 +201,80 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: ata_ehi_push_desc(ehi, "ACPI event"); - ata_ehi_hotplugged(ehi); - ata_port_freeze(ap); - break; + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) { + ata_port_printk(ap, KERN_ERR, + "acpi: failed to determine bay status (0x%x)\n", + status); + break; + } + + if (sta) { + ata_ehi_hotplugged(ehi); + ata_port_freeze(ap); + } else { + /* The device has gone - unplug it */ + ata_acpi_detach_device(ap, dev); + wait = 1; + } + break; case ACPI_NOTIFY_EJECT_REQUEST: ata_ehi_push_desc(ehi, "ACPI event"); - if (dev) - dev->flags |= ATA_DFLAG_DETACH; - else { - struct ata_link *tlink; - struct ata_device *tdev; - - ata_port_for_each_link(tlink, ap) - ata_link_for_each_dev(tdev, tlink) - tdev->flags |= ATA_DFLAG_DETACH; - } - ata_port_schedule_eh(ap); + if (!is_dock_event) + break; + + /* undock event - immediate unplug */ + ata_acpi_detach_device(ap, dev); wait = 1; break; } - if (dev) { - if (dev->sdev) - kobj = &dev->sdev->sdev_gendev.kobj; - } else - kobj = &ap->dev->kobj; + /* make sure kobj doesn't go away while ap->lock is released */ + kobject_get(kobj); + + spin_unlock_irqrestore(ap->lock, flags); + + if (wait) { + ata_port_wait_eh(ap); + ata_acpi_eject_device(handle); + } - if (kobj) { + if (kobj && !is_dock_event) { sprintf(event_string, "BAY_EVENT=%d", event); kobject_uevent_env(kobj, KOBJ_CHANGE, envp); } - spin_unlock_irqrestore(ap->lock, flags); + kobject_put(kobj); +} - if (wait) - ata_port_wait_eh(ap); +static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) +{ + struct ata_device *dev = data; + + ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1); +} + +static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) +{ + struct ata_port *ap = data; + + ata_acpi_handle_hotplug(ap, NULL, event, 1); } static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) { struct ata_device *dev = data; - ata_acpi_handle_hotplug(NULL, dev, event); + ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0); } static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) { struct ata_port *ap = data; - ata_acpi_handle_hotplug(ap, NULL, event); + ata_acpi_handle_hotplug(ap, NULL, event, 0); } /** @@ -229,7 +315,7 @@ void ata_acpi_associate(struct ata_host *host) ata_acpi_ap_notify, ap); /* we might be on a docking station */ register_hotplug_dock_device(ap->acpi_handle, - ata_acpi_ap_notify, ap); + ata_acpi_ap_notify_dock, ap); } for (j = 0; j < ata_link_max_devices(&ap->link); j++) { @@ -241,7 +327,7 @@ void ata_acpi_associate(struct ata_host *host) ata_acpi_dev_notify, dev); /* we might be on a docking station */ register_hotplug_dock_device(dev->acpi_handle, - ata_acpi_dev_notify, dev); + ata_acpi_dev_notify_dock, dev); } } } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 927b692d723..303fc0d2b97 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2126,6 +2126,13 @@ int ata_dev_configure(struct ata_device *dev) dev->horkage |= ata_dev_blacklisted(dev); ata_force_horkage(dev); + if (dev->horkage & ATA_HORKAGE_DISABLE) { + ata_dev_printk(dev, KERN_INFO, + "unsupported device, disabling\n"); + ata_dev_disable(dev); + return 0; + } + /* let ACPI work its magic */ rc = ata_acpi_on_devcfg(dev); if (rc) @@ -3490,22 +3497,11 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, if ((rc = sata_link_debounce(link, params, deadline))) return rc; - /* Clear SError. PMP and some host PHYs require this to - * operate and clearing should be done before checking PHY - * online status to avoid race condition (hotplugging between - * link resume and status check). - */ + /* clear SError, some PHYs require this even for SRST to work */ if (!(rc = sata_scr_read(link, SCR_ERROR, &serror))) rc = sata_scr_write(link, SCR_ERROR, serror); - if (rc == 0 || rc == -EINVAL) { - unsigned long flags; - spin_lock_irqsave(link->ap->lock, flags); - link->eh_info.serror = 0; - spin_unlock_irqrestore(link->ap->lock, flags); - rc = 0; - } - return rc; + return rc != -EINVAL ? rc : 0; } /** @@ -3653,9 +3649,13 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, if (check_ready) rc = ata_wait_ready(link, deadline, check_ready); out: - if (rc && rc != -EAGAIN) + if (rc && rc != -EAGAIN) { + /* online is set iff link is online && reset succeeded */ + if (online) + *online = false; ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); + } DPRINTK("EXIT, rc=%d\n", rc); return rc; } @@ -3700,8 +3700,14 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, */ void ata_std_postreset(struct ata_link *link, unsigned int *classes) { + u32 serror; + DPRINTK("ENTER\n"); + /* reset complete, clear SError */ + if (!sata_scr_read(link, SCR_ERROR, &serror)) + sata_scr_write(link, SCR_ERROR, serror); + /* print link status */ sata_print_link_status(link); @@ -3894,8 +3900,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA }, { "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA }, /* Odd clown on sil3726/4726 PMPs */ - { "Config Disk", NULL, ATA_HORKAGE_NODMA | - ATA_HORKAGE_SKIP_PM }, + { "Config Disk", NULL, ATA_HORKAGE_DISABLE }, /* Weird ATAPI devices */ { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 }, @@ -4292,7 +4297,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc) } /** - * ata_check_atapi_dma - Check whether ATAPI DMA can be supported + * atapi_check_dma - Check whether ATAPI DMA can be supported * @qc: Metadata associated with taskfile to check * * Allow low-level driver to filter ATA PACKET commands, returning @@ -4305,7 +4310,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc) * RETURNS: 0 when ATAPI DMA can be used * nonzero otherwise */ -int ata_check_atapi_dma(struct ata_queued_cmd *qc) +int atapi_check_dma(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -5398,7 +5403,7 @@ static void ata_host_stop(struct device *gendev, void *res) */ static void ata_finalize_port_ops(struct ata_port_operations *ops) { - static spinlock_t lock = SPIN_LOCK_UNLOCKED; + static DEFINE_SPINLOCK(lock); const struct ata_port_operations *cur; void **begin = (void **)ops; void **end = (void **)&ops->inherits; @@ -5616,7 +5621,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) spin_lock_irqsave(ap->lock, flags); ehi->probe_mask |= ATA_ALL_DEVICES; - ehi->action |= ATA_EH_RESET; + ehi->action |= ATA_EH_RESET | ATA_EH_LPM; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; ap->pflags &= ~ATA_PFLAG_INITIALIZING; @@ -5649,7 +5654,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) struct ata_port *ap = host->ports[i]; ata_scsi_scan_host(ap, 1); - ata_lpm_schedule(ap, ap->pm_policy); } return 0; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 62e033146be..7894d83ea1e 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1308,12 +1308,7 @@ static void ata_eh_analyze_serror(struct ata_link *link) unsigned int err_mask = 0, action = 0; u32 hotplug_mask; - if (serror & SERR_PERSISTENT) { - err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_RESET; - } - if (serror & - (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) { + if (serror & (SERR_PERSISTENT | SERR_DATA)) { err_mask |= AC_ERR_ATA_BUS; action |= ATA_EH_RESET; } @@ -2047,19 +2042,11 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline) { struct ata_device *dev; - int rc; ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_UNKNOWN; - rc = reset(link, classes, deadline); - - /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */ - ata_link_for_each_dev(dev, link) - if (classes[dev->devno] == ATA_DEV_UNKNOWN) - classes[dev->devno] = ATA_DEV_NONE; - - return rc; + return reset(link, classes, deadline); } static int ata_eh_followup_srst_needed(struct ata_link *link, @@ -2096,9 +2083,11 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_reset_fn_t reset; unsigned long flags; u32 sstatus; - int rc; + int nr_known, rc; - /* about to reset */ + /* + * Prepare to reset + */ spin_lock_irqsave(ap->lock, flags); ap->pflags |= ATA_PFLAG_RESETTING; spin_unlock_irqrestore(ap->lock, flags); @@ -2124,16 +2113,8 @@ int ata_eh_reset(struct ata_link *link, int classify, ap->ops->set_piomode(ap, dev); } - if (!softreset && !hardreset) { - if (verbose) - ata_link_printk(link, KERN_INFO, "no reset method " - "available, skipping reset\n"); - if (!(lflags & ATA_LFLAG_ASSUME_CLASS)) - lflags |= ATA_LFLAG_ASSUME_ATA; - goto done; - } - /* prefer hardreset */ + reset = NULL; ehc->i.action &= ~ATA_EH_RESET; if (hardreset) { reset = hardreset; @@ -2141,11 +2122,6 @@ int ata_eh_reset(struct ata_link *link, int classify, } else if (softreset) { reset = softreset; ehc->i.action = ATA_EH_SOFTRESET; - } else { - ata_link_printk(link, KERN_ERR, "BUG: no reset method, " - "please report to linux-ide@vger.kernel.org\n"); - dump_stack(); - return -EINVAL; } if (prereset) { @@ -2165,55 +2141,71 @@ int ata_eh_reset(struct ata_link *link, int classify, "prereset failed (errno=%d)\n", rc); goto out; } - } - /* prereset() might have cleared ATA_EH_RESET */ - if (!(ehc->i.action & ATA_EH_RESET)) { - /* prereset told us not to reset, bang classes and return */ - ata_link_for_each_dev(dev, link) - classes[dev->devno] = ATA_DEV_NONE; - rc = 0; - goto out; + /* prereset() might have cleared ATA_EH_RESET. If so, + * bang classes and return. + */ + if (reset && !(ehc->i.action & ATA_EH_RESET)) { + ata_link_for_each_dev(dev, link) + classes[dev->devno] = ATA_DEV_NONE; + rc = 0; + goto out; + } } retry: + /* + * Perform reset + */ + if (ata_is_host_link(link)) + ata_eh_freeze_port(ap); + deadline = jiffies + ata_eh_reset_timeouts[try++]; - /* shut up during boot probing */ - if (verbose) - ata_link_printk(link, KERN_INFO, "%s resetting link\n", - reset == softreset ? "soft" : "hard"); + if (reset) { + if (verbose) + ata_link_printk(link, KERN_INFO, "%s resetting link\n", + reset == softreset ? "soft" : "hard"); - /* mark that this EH session started with reset */ - if (reset == hardreset) - ehc->i.flags |= ATA_EHI_DID_HARDRESET; - else - ehc->i.flags |= ATA_EHI_DID_SOFTRESET; + /* mark that this EH session started with reset */ |