aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2015-05-08 15:23:55 -0400
committerTejun Heo <tj@kernel.org>2015-05-10 11:39:16 -0400
commitdbfe8ef5599a5370abc441fcdbb382b656563eb4 (patch)
treeb2cae946e43f9796870f4f7d5f07d023000d7bb1
parent11fa7df1e12f19571bdce4580cbc63a8cb3e9e85 (diff)
ahci: avoton port-disable reset-quirk
Avoton AHCI occasionally sees drive probe timeouts at driver load time. When this happens SCR_STATUS indicates device detected, but no D2H FIS reception. Reset the internal link state machines by bouncing port-enable in the PCS register when this occurs. Cc: <stable@vger.kernel.org> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--drivers/ata/ahci.c103
1 files changed, 95 insertions, 8 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c7a92a743ed0..65ee94454bbd 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -66,6 +66,7 @@ enum board_ids {
66 board_ahci_yes_fbs, 66 board_ahci_yes_fbs,
67 67
68 /* board IDs for specific chipsets in alphabetical order */ 68 /* board IDs for specific chipsets in alphabetical order */
69 board_ahci_avn,
69 board_ahci_mcp65, 70 board_ahci_mcp65,
70 board_ahci_mcp77, 71 board_ahci_mcp77,
71 board_ahci_mcp89, 72 board_ahci_mcp89,
@@ -84,6 +85,8 @@ enum board_ids {
84static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 85static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
85static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 86static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
86 unsigned long deadline); 87 unsigned long deadline);
88static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
89 unsigned long deadline);
87static void ahci_mcp89_apple_enable(struct pci_dev *pdev); 90static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
88static bool is_mcp89_apple(struct pci_dev *pdev); 91static bool is_mcp89_apple(struct pci_dev *pdev);
89static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, 92static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
@@ -107,6 +110,11 @@ static struct ata_port_operations ahci_p5wdh_ops = {
107 .hardreset = ahci_p5wdh_hardreset, 110 .hardreset = ahci_p5wdh_hardreset,
108}; 111};
109 112
113static struct ata_port_operations ahci_avn_ops = {
114 .inherits = &ahci_ops,
115 .hardreset = ahci_avn_hardreset,
116};
117
110static const struct ata_port_info ahci_port_info[] = { 118static const struct ata_port_info ahci_port_info[] = {
111 /* by features */ 119 /* by features */
112 [board_ahci] = { 120 [board_ahci] = {
@@ -151,6 +159,12 @@ static const struct ata_port_info ahci_port_info[] = {
151 .port_ops = &ahci_ops, 159 .port_ops = &ahci_ops,
152 }, 160 },
153 /* by chipsets */ 161 /* by chipsets */
162 [board_ahci_avn] = {
163 .flags = AHCI_FLAG_COMMON,
164 .pio_mask = ATA_PIO4,
165 .udma_mask = ATA_UDMA6,
166 .port_ops = &ahci_avn_ops,
167 },
154 [board_ahci_mcp65] = { 168 [board_ahci_mcp65] = {
155 AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP | 169 AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
156 AHCI_HFLAG_YES_NCQ), 170 AHCI_HFLAG_YES_NCQ),
@@ -290,14 +304,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
290 { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */ 304 { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
291 { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */ 305 { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
292 { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */ 306 { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
293 { PCI_VDEVICE(INTEL, 0x1f32), board_ahci }, /* Avoton AHCI */ 307 { PCI_VDEVICE(INTEL, 0x1f32), board_ahci_avn }, /* Avoton AHCI */
294 { PCI_VDEVICE(INTEL, 0x1f33), board_ahci }, /* Avoton AHCI */ 308 { PCI_VDEVICE(INTEL, 0x1f33), board_ahci_avn }, /* Avoton AHCI */
295 { PCI_VDEVICE(INTEL, 0x1f34), board_ahci }, /* Avoton RAID */ 309 { PCI_VDEVICE(INTEL, 0x1f34), board_ahci_avn }, /* Avoton RAID */
296 { PCI_VDEVICE(INTEL, 0x1f35), board_ahci }, /* Avoton RAID */ 310 { PCI_VDEVICE(INTEL, 0x1f35), board_ahci_avn }, /* Avoton RAID */
297 { PCI_VDEVICE(INTEL, 0x1f36), board_ahci }, /* Avoton RAID */ 311 { PCI_VDEVICE(INTEL, 0x1f36), board_ahci_avn }, /* Avoton RAID */
298 { PCI_VDEVICE(INTEL, 0x1f37), board_ahci }, /* Avoton RAID */ 312 { PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
299 { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci }, /* Avoton RAID */ 313 { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
300 { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci }, /* Avoton RAID */ 314 { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
301 { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */ 315 { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */
302 { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */ 316 { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */
303 { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */ 317 { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
@@ -670,6 +684,79 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
670 return rc; 684 return rc;
671} 685}
672 686
687/*
688 * ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports.
689 *
690 * It has been observed with some SSDs that the timing of events in the
691 * link synchronization phase can leave the port in a state that can not
692 * be recovered by a SATA-hard-reset alone. The failing signature is
693 * SStatus.DET stuck at 1 ("Device presence detected but Phy
694 * communication not established"). It was found that unloading and
695 * reloading the driver when this problem occurs allows the drive
696 * connection to be recovered (DET advanced to 0x3). The critical
697 * component of reloading the driver is that the port state machines are
698 * reset by bouncing "port enable" in the AHCI PCS configuration
699 * register. So, reproduce that effect by bouncing a port whenever we
700 * see DET==1 after a reset.
701 */
702static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
703 unsigned long deadline)
704{
705 const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
706 struct ata_port *ap = link->ap;
707 struct ahci_port_priv *pp = ap->private_data;
708 struct ahci_host_priv *hpriv = ap->host->private_data;
709 u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
710 unsigned long tmo = deadline - jiffies;
711 struct ata_taskfile tf;
712 bool online;
713 int rc, i;
714
715 DPRINTK("ENTER\n");
716
717 ahci_stop_engine(ap);
718
719 for (i = 0; i < 2; i++) {
720 u16 val;
721 u32 sstatus;
722 int port = ap->port_no;
723 struct ata_host *host = ap->host;
724 struct pci_dev *pdev = to_pci_dev(host->dev);
725
726 /* clear D2H reception area to properly wait for D2H FIS */
727 ata_tf_init(link->device, &tf);
728 tf.command = ATA_BUSY;
729 ata_tf_to_fis(&tf, 0, 0, d2h_fis);
730
731 rc = sata_link_hardreset(link, timing, deadline, &online,
732 ahci_check_ready);
733
734 if (sata_scr_read(link, SCR_STATUS, &sstatus) != 0 ||
735 (sstatus & 0xf) != 1)
736 break;
737
738 ata_link_printk(link, KERN_INFO, "avn bounce port%d\n",
739 port);
740
741 pci_read_config_word(pdev, 0x92, &val);
742 val &= ~(1 << port);
743 pci_write_config_word(pdev, 0x92, val);
744 ata_msleep(ap, 1000);
745 val |= 1 << port;
746 pci_write_config_word(pdev, 0x92, val);
747 deadline += tmo;
748 }
749
750 hpriv->start_engine(ap);
751
752 if (online)
753 *class = ahci_dev_classify(ap);
754
755 DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
756 return rc;
757}
758
759
673#ifdef CONFIG_PM 760#ifdef CONFIG_PM
674static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) 761static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
675{ 762{