diff options
Diffstat (limited to 'drivers/ata/ahci.c')
| -rw-r--r-- | drivers/ata/ahci.c | 103 |
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 { | |||
| 84 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); | 85 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); |
| 85 | static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, | 86 | static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, |
| 86 | unsigned long deadline); | 87 | unsigned long deadline); |
| 88 | static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, | ||
| 89 | unsigned long deadline); | ||
| 87 | static void ahci_mcp89_apple_enable(struct pci_dev *pdev); | 90 | static void ahci_mcp89_apple_enable(struct pci_dev *pdev); |
| 88 | static bool is_mcp89_apple(struct pci_dev *pdev); | 91 | static bool is_mcp89_apple(struct pci_dev *pdev); |
| 89 | static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, | 92 | static 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 | ||
| 113 | static struct ata_port_operations ahci_avn_ops = { | ||
| 114 | .inherits = &ahci_ops, | ||
| 115 | .hardreset = ahci_avn_hardreset, | ||
| 116 | }; | ||
| 117 | |||
| 110 | static const struct ata_port_info ahci_port_info[] = { | 118 | static 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 | */ | ||
| 702 | static 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 |
| 674 | static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) | 761 | static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) |
| 675 | { | 762 | { |
