Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ahci: add workaround for on-board 5723s on some gigabyte boards

Some gigabytes have on-board SIMG5723s connected to JMB ahcis. These
are used to implement hardware raid. Unfortunately some firmware
revisions on these 5723s don't bring the link down when all the
downstream ports are unoccupied while not responding to reset protocol
which makes libata think that there's device attached to the port but
is not responding and retry. This results in painfully wrong boot
detection time for these ports when they're empty.

This patch quirks those boards such that ahci gives up after the
initial timeout. Combined with parallel probing, this gives quick
enough probing and also is safe because SIMG5723 will respond to the
first try if any of the downstream ports is occupied.

Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: Marc Bowes <marcbowes@gmail.com>
Reported-by: Nicolas Mailhot <Nicolas.Mailhot@LaPoste.net>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

authored by

Tejun Heo and committed by
Jeff Garzik
5594639a b6931c1f

+72 -4
+72 -4
drivers/ata/ahci.c
··· 219 219 AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ 220 220 AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ 221 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 225 /* ap->flags bits */ 224 226 ··· 1665 1663 int (*check_ready)(struct ata_link *link)) 1666 1664 { 1667 1665 struct ata_port *ap = link->ap; 1666 + struct ahci_host_priv *hpriv = ap->host->private_data; 1668 1667 const char *reason = NULL; 1669 1668 unsigned long now, msecs; 1670 1669 struct ata_taskfile tf; ··· 1704 1701 1705 1702 /* wait for link to become ready */ 1706 1703 rc = ata_wait_after_reset(link, deadline, check_ready); 1707 - /* link occupied, -ENODEV too is an error */ 1708 - if (rc) { 1704 + if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) { 1705 + /* 1706 + * Workaround for cases where link online status can't 1707 + * be trusted. Treat device readiness timeout as link 1708 + * offline. 1709 + */ 1710 + ata_link_printk(link, KERN_INFO, 1711 + "device not ready, treating as offline\n"); 1712 + *class = ATA_DEV_NONE; 1713 + } else if (rc) { 1714 + /* link occupied, -ENODEV too is an error */ 1709 1715 reason = "device not ready"; 1710 1716 goto fail; 1711 - } 1712 - *class = ahci_dev_classify(ap); 1717 + } else 1718 + *class = ahci_dev_classify(ap); 1713 1719 1714 1720 DPRINTK("EXIT, class=%u\n", *class); 1715 1721 return 0; ··· 2739 2727 return !ver || strcmp(ver, dmi->driver_data) < 0; 2740 2728 } 2741 2729 2730 + static bool ahci_broken_online(struct pci_dev *pdev) 2731 + { 2732 + #define ENCODE_BUSDEVFN(bus, slot, func) \ 2733 + (void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func))) 2734 + static const struct dmi_system_id sysids[] = { 2735 + /* 2736 + * There are several gigabyte boards which use 2737 + * SIMG5723s configured as hardware RAID. Certain 2738 + * 5723 firmware revisions shipped there keep the link 2739 + * online but fail to answer properly to SRST or 2740 + * IDENTIFY when no device is attached downstream 2741 + * causing libata to retry quite a few times leading 2742 + * to excessive detection delay. 2743 + * 2744 + * As these firmwares respond to the second reset try 2745 + * with invalid device signature, considering unknown 2746 + * sig as offline works around the problem acceptably. 2747 + */ 2748 + { 2749 + .ident = "EP45-DQ6", 2750 + .matches = { 2751 + DMI_MATCH(DMI_BOARD_VENDOR, 2752 + "Gigabyte Technology Co., Ltd."), 2753 + DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"), 2754 + }, 2755 + .driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0), 2756 + }, 2757 + { 2758 + .ident = "EP45-DS5", 2759 + .matches = { 2760 + DMI_MATCH(DMI_BOARD_VENDOR, 2761 + "Gigabyte Technology Co., Ltd."), 2762 + DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"), 2763 + }, 2764 + .driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0), 2765 + }, 2766 + { } /* terminate list */ 2767 + }; 2768 + #undef ENCODE_BUSDEVFN 2769 + const struct dmi_system_id *dmi = dmi_first_match(sysids); 2770 + unsigned int val; 2771 + 2772 + if (!dmi) 2773 + return false; 2774 + 2775 + val = (unsigned long)dmi->driver_data; 2776 + 2777 + return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff); 2778 + } 2779 + 2742 2780 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2743 2781 { 2744 2782 static int printed_version; ··· 2902 2840 hpriv->flags |= AHCI_HFLAG_NO_SUSPEND; 2903 2841 dev_printk(KERN_WARNING, &pdev->dev, 2904 2842 "BIOS update required for suspend/resume\n"); 2843 + } 2844 + 2845 + if (ahci_broken_online(pdev)) { 2846 + hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE; 2847 + dev_info(&pdev->dev, 2848 + "online status unreliable, applying workaround\n"); 2905 2849 } 2906 2850 2907 2851 /* CAP.NP sometimes indicate the index of the last enabled