diff options
Diffstat (limited to 'drivers/ata/ahci.c')
| -rw-r--r-- | drivers/ata/ahci.c | 79 |
1 files changed, 74 insertions, 5 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 958c1fa41900..fe3eba5d6b3e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
| @@ -219,6 +219,8 @@ enum { | |||
| 219 | AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ | 219 | AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ |
| 220 | AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ | 220 | AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ |
| 221 | AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ | 221 | AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ |
| 222 | AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as | ||
| 223 | link offline */ | ||
| 222 | 224 | ||
| 223 | /* ap->flags bits */ | 225 | /* ap->flags bits */ |
| 224 | 226 | ||
| @@ -1663,6 +1665,7 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, | |||
| 1663 | int (*check_ready)(struct ata_link *link)) | 1665 | int (*check_ready)(struct ata_link *link)) |
| 1664 | { | 1666 | { |
| 1665 | struct ata_port *ap = link->ap; | 1667 | struct ata_port *ap = link->ap; |
| 1668 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
| 1666 | const char *reason = NULL; | 1669 | const char *reason = NULL; |
| 1667 | unsigned long now, msecs; | 1670 | unsigned long now, msecs; |
| 1668 | struct ata_taskfile tf; | 1671 | struct ata_taskfile tf; |
| @@ -1701,12 +1704,21 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, | |||
| 1701 | 1704 | ||
| 1702 | /* wait for link to become ready */ | 1705 | /* wait for link to become ready */ |
| 1703 | rc = ata_wait_after_reset(link, deadline, check_ready); | 1706 | rc = ata_wait_after_reset(link, deadline, check_ready); |
| 1704 | /* link occupied, -ENODEV too is an error */ | 1707 | if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) { |
| 1705 | if (rc) { | 1708 | /* |
| 1709 | * Workaround for cases where link online status can't | ||
| 1710 | * be trusted. Treat device readiness timeout as link | ||
| 1711 | * offline. | ||
| 1712 | */ | ||
| 1713 | ata_link_printk(link, KERN_INFO, | ||
| 1714 | "device not ready, treating as offline\n"); | ||
| 1715 | *class = ATA_DEV_NONE; | ||
| 1716 | } else if (rc) { | ||
| 1717 | /* link occupied, -ENODEV too is an error */ | ||
| 1706 | reason = "device not ready"; | 1718 | reason = "device not ready"; |
| 1707 | goto fail; | 1719 | goto fail; |
| 1708 | } | 1720 | } else |
| 1709 | *class = ahci_dev_classify(ap); | 1721 | *class = ahci_dev_classify(ap); |
| 1710 | 1722 | ||
| 1711 | DPRINTK("EXIT, class=%u\n", *class); | 1723 | DPRINTK("EXIT, class=%u\n", *class); |
| 1712 | return 0; | 1724 | return 0; |
| @@ -1773,7 +1785,8 @@ static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, | |||
| 1773 | irq_sts = readl(port_mmio + PORT_IRQ_STAT); | 1785 | irq_sts = readl(port_mmio + PORT_IRQ_STAT); |
| 1774 | if (irq_sts & PORT_IRQ_BAD_PMP) { | 1786 | if (irq_sts & PORT_IRQ_BAD_PMP) { |
| 1775 | ata_link_printk(link, KERN_WARNING, | 1787 | ata_link_printk(link, KERN_WARNING, |
| 1776 | "failed due to HW bug, retry pmp=0\n"); | 1788 | "applying SB600 PMP SRST workaround " |
| 1789 | "and retrying\n"); | ||
| 1777 | rc = ahci_do_softreset(link, class, 0, deadline, | 1790 | rc = ahci_do_softreset(link, class, 0, deadline, |
| 1778 | ahci_check_ready); | 1791 | ahci_check_ready); |
| 1779 | } | 1792 | } |
| @@ -2726,6 +2739,56 @@ static bool ahci_broken_suspend(struct pci_dev *pdev) | |||
| 2726 | return !ver || strcmp(ver, dmi->driver_data) < 0; | 2739 | return !ver || strcmp(ver, dmi->driver_data) < 0; |
| 2727 | } | 2740 | } |
| 2728 | 2741 | ||
| 2742 | static bool ahci_broken_online(struct pci_dev *pdev) | ||
| 2743 | { | ||
| 2744 | #define ENCODE_BUSDEVFN(bus, slot, func) \ | ||
| 2745 | (void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func))) | ||
| 2746 | static const struct dmi_system_id sysids[] = { | ||
| 2747 | /* | ||
| 2748 | * There are several gigabyte boards which use | ||
| 2749 | * SIMG5723s configured as hardware RAID. Certain | ||
| 2750 | * 5723 firmware revisions shipped there keep the link | ||
| 2751 | * online but fail to answer properly to SRST or | ||
| 2752 | * IDENTIFY when no device is attached downstream | ||
| 2753 | * causing libata to retry quite a few times leading | ||
| 2754 | * to excessive detection delay. | ||
| 2755 | * | ||
| 2756 | * As these firmwares respond to the second reset try | ||
| 2757 | * with invalid device signature, considering unknown | ||
| 2758 | * sig as offline works around the problem acceptably. | ||
| 2759 | */ | ||
| 2760 | { | ||
| 2761 | .ident = "EP45-DQ6", | ||
| 2762 | .matches = { | ||
| 2763 | DMI_MATCH(DMI_BOARD_VENDOR, | ||
| 2764 | "Gigabyte Technology Co., Ltd."), | ||
| 2765 | DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"), | ||
| 2766 | }, | ||
| 2767 | .driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0), | ||
| 2768 | }, | ||
| 2769 | { | ||
| 2770 | .ident = "EP45-DS5", | ||
| 2771 | .matches = { | ||
| 2772 | DMI_MATCH(DMI_BOARD_VENDOR, | ||
| 2773 | "Gigabyte Technology Co., Ltd."), | ||
| 2774 | DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"), | ||
| 2775 | }, | ||
| 2776 | .driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0), | ||
| 2777 | }, | ||
| 2778 | { } /* terminate list */ | ||
| 2779 | }; | ||
| 2780 | #undef ENCODE_BUSDEVFN | ||
| 2781 | const struct dmi_system_id *dmi = dmi_first_match(sysids); | ||
| 2782 | unsigned int val; | ||
| 2783 | |||
| 2784 | if (!dmi) | ||
| 2785 | return false; | ||
| 2786 | |||
| 2787 | val = (unsigned long)dmi->driver_data; | ||
| 2788 | |||
| 2789 | return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff); | ||
| 2790 | } | ||
| 2791 | |||
| 2729 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 2792 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 2730 | { | 2793 | { |
| 2731 | static int printed_version; | 2794 | static int printed_version; |
| @@ -2841,6 +2904,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 2841 | "BIOS update required for suspend/resume\n"); | 2904 | "BIOS update required for suspend/resume\n"); |
| 2842 | } | 2905 | } |
| 2843 | 2906 | ||
| 2907 | if (ahci_broken_online(pdev)) { | ||
| 2908 | hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE; | ||
| 2909 | dev_info(&pdev->dev, | ||
| 2910 | "online status unreliable, applying workaround\n"); | ||
| 2911 | } | ||
| 2912 | |||
| 2844 | /* CAP.NP sometimes indicate the index of the last enabled | 2913 | /* CAP.NP sometimes indicate the index of the last enabled |
| 2845 | * port, at other times, that of the last possible port, so | 2914 | * port, at other times, that of the last possible port, so |
| 2846 | * determining the maximum port number requires looking at | 2915 | * determining the maximum port number requires looking at |
