xref: /openbmc/linux/drivers/ata/ahci.c (revision dbfe8ef5599a5370abc441fcdbb382b656563eb4)
1c6fd2807SJeff Garzik /*
2c6fd2807SJeff Garzik  *  ahci.c - AHCI SATA support
3c6fd2807SJeff Garzik  *
48c3d3d4bSTejun Heo  *  Maintained by:  Tejun Heo <tj@kernel.org>
5c6fd2807SJeff Garzik  *    		    Please ALWAYS copy linux-ide@vger.kernel.org
6c6fd2807SJeff Garzik  *		    on emails.
7c6fd2807SJeff Garzik  *
8c6fd2807SJeff Garzik  *  Copyright 2004-2005 Red Hat, Inc.
9c6fd2807SJeff Garzik  *
10c6fd2807SJeff Garzik  *
11c6fd2807SJeff Garzik  *  This program is free software; you can redistribute it and/or modify
12c6fd2807SJeff Garzik  *  it under the terms of the GNU General Public License as published by
13c6fd2807SJeff Garzik  *  the Free Software Foundation; either version 2, or (at your option)
14c6fd2807SJeff Garzik  *  any later version.
15c6fd2807SJeff Garzik  *
16c6fd2807SJeff Garzik  *  This program is distributed in the hope that it will be useful,
17c6fd2807SJeff Garzik  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18c6fd2807SJeff Garzik  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19c6fd2807SJeff Garzik  *  GNU General Public License for more details.
20c6fd2807SJeff Garzik  *
21c6fd2807SJeff Garzik  *  You should have received a copy of the GNU General Public License
22c6fd2807SJeff Garzik  *  along with this program; see the file COPYING.  If not, write to
23c6fd2807SJeff Garzik  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24c6fd2807SJeff Garzik  *
25c6fd2807SJeff Garzik  *
26c6fd2807SJeff Garzik  * libata documentation is available via 'make {ps|pdf}docs',
27c6fd2807SJeff Garzik  * as Documentation/DocBook/libata.*
28c6fd2807SJeff Garzik  *
29c6fd2807SJeff Garzik  * AHCI hardware documentation:
30c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
31c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
32c6fd2807SJeff Garzik  *
33c6fd2807SJeff Garzik  */
34c6fd2807SJeff Garzik 
35c6fd2807SJeff Garzik #include <linux/kernel.h>
36c6fd2807SJeff Garzik #include <linux/module.h>
37c6fd2807SJeff Garzik #include <linux/pci.h>
38c6fd2807SJeff Garzik #include <linux/blkdev.h>
39c6fd2807SJeff Garzik #include <linux/delay.h>
40c6fd2807SJeff Garzik #include <linux/interrupt.h>
41c6fd2807SJeff Garzik #include <linux/dma-mapping.h>
42c6fd2807SJeff Garzik #include <linux/device.h>
43edc93052STejun Heo #include <linux/dmi.h>
445a0e3ad6STejun Heo #include <linux/gfp.h>
45c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
46c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
47c6fd2807SJeff Garzik #include <linux/libata.h>
48365cfa1eSAnton Vorontsov #include "ahci.h"
49c6fd2807SJeff Garzik 
50c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
517d50b60bSTejun Heo #define DRV_VERSION	"3.0"
52c6fd2807SJeff Garzik 
53c6fd2807SJeff Garzik enum {
54318893e1SAlessandro Rubini 	AHCI_PCI_BAR_STA2X11	= 0,
557f9c9f8eSHugh Daschbach 	AHCI_PCI_BAR_ENMOTUS	= 2,
56318893e1SAlessandro Rubini 	AHCI_PCI_BAR_STANDARD	= 5,
57441577efSTejun Heo };
58c6fd2807SJeff Garzik 
59441577efSTejun Heo enum board_ids {
60441577efSTejun Heo 	/* board IDs by feature in alphabetical order */
61441577efSTejun Heo 	board_ahci,
62441577efSTejun Heo 	board_ahci_ign_iferr,
6366a7cbc3STejun Heo 	board_ahci_nomsi,
6467809f85SLevente Kurusa 	board_ahci_noncq,
65441577efSTejun Heo 	board_ahci_nosntf,
665f173107STejun Heo 	board_ahci_yes_fbs,
67441577efSTejun Heo 
68441577efSTejun Heo 	/* board IDs for specific chipsets in alphabetical order */
69*dbfe8ef5SDan Williams 	board_ahci_avn,
70441577efSTejun Heo 	board_ahci_mcp65,
7183f2b963STejun Heo 	board_ahci_mcp77,
7283f2b963STejun Heo 	board_ahci_mcp89,
73441577efSTejun Heo 	board_ahci_mv,
74441577efSTejun Heo 	board_ahci_sb600,
75441577efSTejun Heo 	board_ahci_sb700,	/* for SB700 and SB800 */
76441577efSTejun Heo 	board_ahci_vt8251,
77441577efSTejun Heo 
78441577efSTejun Heo 	/* aliases */
79441577efSTejun Heo 	board_ahci_mcp_linux	= board_ahci_mcp65,
80441577efSTejun Heo 	board_ahci_mcp67	= board_ahci_mcp65,
81441577efSTejun Heo 	board_ahci_mcp73	= board_ahci_mcp65,
8283f2b963STejun Heo 	board_ahci_mcp79	= board_ahci_mcp77,
83c6fd2807SJeff Garzik };
84c6fd2807SJeff Garzik 
85c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
86a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
87a1efdabaSTejun Heo 				 unsigned long deadline);
88*dbfe8ef5SDan Williams static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
89*dbfe8ef5SDan Williams 			      unsigned long deadline);
90cb85696dSJames Laird static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
91cb85696dSJames Laird static bool is_mcp89_apple(struct pci_dev *pdev);
92a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
93a1efdabaSTejun Heo 				unsigned long deadline);
94438ac6d5STejun Heo #ifdef CONFIG_PM
95c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
96c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
97438ac6d5STejun Heo #endif
98c6fd2807SJeff Garzik 
99fad16e7aSTejun Heo static struct scsi_host_template ahci_sht = {
100fad16e7aSTejun Heo 	AHCI_SHT("ahci"),
101fad16e7aSTejun Heo };
102fad16e7aSTejun Heo 
103029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
104029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
105a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
106ad616ffbSTejun Heo };
107ad616ffbSTejun Heo 
108029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
109029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
110a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
111edc93052STejun Heo };
112edc93052STejun Heo 
113*dbfe8ef5SDan Williams static struct ata_port_operations ahci_avn_ops = {
114*dbfe8ef5SDan Williams 	.inherits		= &ahci_ops,
115*dbfe8ef5SDan Williams 	.hardreset		= ahci_avn_hardreset,
116*dbfe8ef5SDan Williams };
117*dbfe8ef5SDan Williams 
118c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
119441577efSTejun Heo 	/* by features */
120facb8fa6SJeffrin Jose 	[board_ahci] = {
1211188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
12214bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
123469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
124c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
125c6fd2807SJeff Garzik 	},
126facb8fa6SJeffrin Jose 	[board_ahci_ign_iferr] = {
127417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
128417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
12914bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
130469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
13141669553STejun Heo 		.port_ops	= &ahci_ops,
13241669553STejun Heo 	},
13366a7cbc3STejun Heo 	[board_ahci_nomsi] = {
13466a7cbc3STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_MSI),
13566a7cbc3STejun Heo 		.flags		= AHCI_FLAG_COMMON,
13666a7cbc3STejun Heo 		.pio_mask	= ATA_PIO4,
13766a7cbc3STejun Heo 		.udma_mask	= ATA_UDMA6,
13866a7cbc3STejun Heo 		.port_ops	= &ahci_ops,
13966a7cbc3STejun Heo 	},
14067809f85SLevente Kurusa 	[board_ahci_noncq] = {
14167809f85SLevente Kurusa 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ),
14267809f85SLevente Kurusa 		.flags		= AHCI_FLAG_COMMON,
14367809f85SLevente Kurusa 		.pio_mask	= ATA_PIO4,
14467809f85SLevente Kurusa 		.udma_mask	= ATA_UDMA6,
14567809f85SLevente Kurusa 		.port_ops	= &ahci_ops,
14667809f85SLevente Kurusa 	},
147facb8fa6SJeffrin Jose 	[board_ahci_nosntf] = {
148441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_SNTF),
149441577efSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
150441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
151441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
152441577efSTejun Heo 		.port_ops	= &ahci_ops,
153441577efSTejun Heo 	},
154facb8fa6SJeffrin Jose 	[board_ahci_yes_fbs] = {
1555f173107STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_FBS),
1565f173107STejun Heo 		.flags		= AHCI_FLAG_COMMON,
1575f173107STejun Heo 		.pio_mask	= ATA_PIO4,
1585f173107STejun Heo 		.udma_mask	= ATA_UDMA6,
1595f173107STejun Heo 		.port_ops	= &ahci_ops,
1605f173107STejun Heo 	},
161441577efSTejun Heo 	/* by chipsets */
162*dbfe8ef5SDan Williams 	[board_ahci_avn] = {
163*dbfe8ef5SDan Williams 		.flags		= AHCI_FLAG_COMMON,
164*dbfe8ef5SDan Williams 		.pio_mask	= ATA_PIO4,
165*dbfe8ef5SDan Williams 		.udma_mask	= ATA_UDMA6,
166*dbfe8ef5SDan Williams 		.port_ops	= &ahci_avn_ops,
167*dbfe8ef5SDan Williams 	},
168facb8fa6SJeffrin Jose 	[board_ahci_mcp65] = {
16983f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
17083f2b963STejun Heo 				 AHCI_HFLAG_YES_NCQ),
171ae01b249STejun Heo 		.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
17283f2b963STejun Heo 		.pio_mask	= ATA_PIO4,
17383f2b963STejun Heo 		.udma_mask	= ATA_UDMA6,
17483f2b963STejun Heo 		.port_ops	= &ahci_ops,
17583f2b963STejun Heo 	},
176facb8fa6SJeffrin Jose 	[board_ahci_mcp77] = {
17783f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP),
17883f2b963STejun Heo 		.flags		= AHCI_FLAG_COMMON,
17983f2b963STejun Heo 		.pio_mask	= ATA_PIO4,
18083f2b963STejun Heo 		.udma_mask	= ATA_UDMA6,
18183f2b963STejun Heo 		.port_ops	= &ahci_ops,
18283f2b963STejun Heo 	},
183facb8fa6SJeffrin Jose 	[board_ahci_mcp89] = {
18483f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA),
185441577efSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
186441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
187441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
188441577efSTejun Heo 		.port_ops	= &ahci_ops,
189441577efSTejun Heo 	},
190facb8fa6SJeffrin Jose 	[board_ahci_mv] = {
191441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
192441577efSTejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
1939cbe056fSSergei Shtylyov 		.flags		= ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
194441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
195441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
196441577efSTejun Heo 		.port_ops	= &ahci_ops,
197441577efSTejun Heo 	},
198facb8fa6SJeffrin Jose 	[board_ahci_sb600] = {
199417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
2002fcad9d2STejun Heo 				 AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
2012fcad9d2STejun Heo 				 AHCI_HFLAG_32BIT_ONLY),
202417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
20314bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
204469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
205345347c5SYuan-Hsin Chen 		.port_ops	= &ahci_pmp_retry_srst_ops,
20655a61604SConke Hu 	},
207facb8fa6SJeffrin Jose 	[board_ahci_sb700] = {	/* for SB700 and SB800 */
208bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
209e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
21014bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
211e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
212345347c5SYuan-Hsin Chen 		.port_ops	= &ahci_pmp_retry_srst_ops,
213e39fc8c9SShane Huang 	},
214facb8fa6SJeffrin Jose 	[board_ahci_vt8251] = {
215441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
216e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
21714bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
218e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
219441577efSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
2201b677afdSShaohua Li 	},
221c6fd2807SJeff Garzik };
222c6fd2807SJeff Garzik 
223c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
224c6fd2807SJeff Garzik 	/* Intel */
22554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
22654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
22754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
22854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
22954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
23082490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
23154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
23254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
23354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
23454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
2357a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
2361b677afdSShaohua Li 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8 */
2377a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
2387a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
2397a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
2407a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
2417a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
2427a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
2437a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
2447a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
2457a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
2467a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
2477a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
2487a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
2497a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
2507a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
2517a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
252d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
253d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
25416ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
255b2dde6afSMark Goodwin 	{ PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
25616ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
257c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
258c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
259adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
2608e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
261c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
262adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
2638e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
264c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
2655623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
2665623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
2675623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
2685623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
2695623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
2705623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
271992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
272992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */
273992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
27464a3903dSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
275a4a461a6SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
276181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
277181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
278181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
279181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
280181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
281181e3ceaSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
2822cab7a4cSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
283ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
284ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
285ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
286ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
287ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
288ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
289ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
290ea4ace66SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
29177b12bc9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
29277b12bc9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
29377b12bc9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
29477b12bc9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c05), board_ahci }, /* Lynx Point-LP RAID */
29577b12bc9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c06), board_ahci }, /* Lynx Point-LP RAID */
29677b12bc9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c07), board_ahci }, /* Lynx Point-LP RAID */
29777b12bc9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c0e), board_ahci }, /* Lynx Point-LP RAID */
29877b12bc9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c0f), board_ahci }, /* Lynx Point-LP RAID */
29929e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */
30029e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */
30129e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */
30229e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f25), board_ahci }, /* Avoton RAID */
30329e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f26), board_ahci }, /* Avoton RAID */
30429e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
30529e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
30629e674ddSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
307*dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f32), board_ahci_avn }, /* Avoton AHCI */
308*dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f33), board_ahci_avn }, /* Avoton AHCI */
309*dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f34), board_ahci_avn }, /* Avoton RAID */
310*dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f35), board_ahci_avn }, /* Avoton RAID */
311*dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f36), board_ahci_avn }, /* Avoton RAID */
312*dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
313*dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
314*dbfe8ef5SDan Williams 	{ PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
315efda332cSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */
316efda332cSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */
317151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
318151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d04), board_ahci }, /* Wellsburg RAID */
319151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d06), board_ahci }, /* Wellsburg RAID */
320151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d0e), board_ahci }, /* Wellsburg RAID */
321151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d62), board_ahci }, /* Wellsburg AHCI */
322151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
323151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
324151743fdSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
3251cfc7df3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
3269f961a5fSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c83), board_ahci }, /* Wildcat Point-LP AHCI */
3279f961a5fSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c85), board_ahci }, /* Wildcat Point-LP RAID */
3289f961a5fSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
3299f961a5fSJames Ralston 	{ PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
3301b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
3311b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
3321b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
3331b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
3341b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
3351b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
3361b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
3371b071a09SJames Ralston 	{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
338249cd0a1SDevin Ryles 	{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
339249cd0a1SDevin Ryles 	{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
340249cd0a1SDevin Ryles 	{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
341690000b9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
342690000b9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
343690000b9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
344690000b9SJames Ralston 	{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
345c6fd2807SJeff Garzik 
346e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
347e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
348e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
3491fefb8fdSBen Hutchings 	/* JMicron 362B and 362C have an AHCI function with IDE class code */
3501fefb8fdSBen Hutchings 	{ PCI_VDEVICE(JMICRON, 0x2362), board_ahci_ign_iferr },
3511fefb8fdSBen Hutchings 	{ PCI_VDEVICE(JMICRON, 0x236f), board_ahci_ign_iferr },
352c6fd2807SJeff Garzik 
353c6fd2807SJeff Garzik 	/* ATI */
354c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
355e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
356e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
357e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
358e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
359e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
360e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
361c6fd2807SJeff Garzik 
362e2dd90b1SShane Huang 	/* AMD */
3635deab536SShane Huang 	{ PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
364fafe5c3dSShane Huang 	{ PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */
365e2dd90b1SShane Huang 	/* AMD is using RAID class only for ahci controllers */
366e2dd90b1SShane Huang 	{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
367e2dd90b1SShane Huang 	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
368e2dd90b1SShane Huang 
369c6fd2807SJeff Garzik 	/* VIA */
37054bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
371bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
372c6fd2807SJeff Garzik 
373c6fd2807SJeff Garzik 	/* NVIDIA */
374e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
375e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
376e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
377e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
378e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
379e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
380e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
381e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
382441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_mcp67 },	/* MCP67 */
383441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_mcp67 },	/* MCP67 */
384441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_mcp67 },	/* MCP67 */
385441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_mcp67 },	/* MCP67 */
386441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_mcp67 },	/* MCP67 */
387441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_mcp67 },	/* MCP67 */
388441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_mcp67 },	/* MCP67 */
389441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_mcp67 },	/* MCP67 */
390441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_mcp67 },	/* MCP67 */
391441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_mcp67 },	/* MCP67 */
392441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_mcp67 },	/* MCP67 */
393441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_mcp67 },	/* MCP67 */
394441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_mcp_linux },	/* Linux ID */
395441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0581), board_ahci_mcp_linux },	/* Linux ID */
396441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0582), board_ahci_mcp_linux },	/* Linux ID */
397441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0583), board_ahci_mcp_linux },	/* Linux ID */
398441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0584), board_ahci_mcp_linux },	/* Linux ID */
399441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0585), board_ahci_mcp_linux },	/* Linux ID */
400441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0586), board_ahci_mcp_linux },	/* Linux ID */
401441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0587), board_ahci_mcp_linux },	/* Linux ID */
402441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0588), board_ahci_mcp_linux },	/* Linux ID */
403441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0589), board_ahci_mcp_linux },	/* Linux ID */
404441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058a), board_ahci_mcp_linux },	/* Linux ID */
405441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058b), board_ahci_mcp_linux },	/* Linux ID */
406441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058c), board_ahci_mcp_linux },	/* Linux ID */
407441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058d), board_ahci_mcp_linux },	/* Linux ID */
408441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058e), board_ahci_mcp_linux },	/* Linux ID */
409441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058f), board_ahci_mcp_linux },	/* Linux ID */
410441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_mcp73 },	/* MCP73 */
411441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_mcp73 },	/* MCP73 */
412441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_mcp73 },	/* MCP73 */
413441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_mcp73 },	/* MCP73 */
414441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_mcp73 },	/* MCP73 */
415441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_mcp73 },	/* MCP73 */
416441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_mcp73 },	/* MCP73 */
417441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_mcp73 },	/* MCP73 */
418441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_mcp73 },	/* MCP73 */
419441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_mcp73 },	/* MCP73 */
420441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_mcp73 },	/* MCP73 */
421441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_mcp73 },	/* MCP73 */
422441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci_mcp77 },	/* MCP77 */
423441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci_mcp77 },	/* MCP77 */
424441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci_mcp77 },	/* MCP77 */
425441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci_mcp77 },	/* MCP77 */
426441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci_mcp77 },	/* MCP77 */
427441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci_mcp77 },	/* MCP77 */
428441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci_mcp77 },	/* MCP77 */
429441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci_mcp77 },	/* MCP77 */
430441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci_mcp77 },	/* MCP77 */
431441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci_mcp77 },	/* MCP77 */
432441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci_mcp77 },	/* MCP77 */
433441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci_mcp77 },	/* MCP77 */
434441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci_mcp79 },	/* MCP79 */
435441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci_mcp79 },	/* MCP79 */
436441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci_mcp79 },	/* MCP79 */
437441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci_mcp79 },	/* MCP79 */
438441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci_mcp79 },	/* MCP79 */
439441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci_mcp79 },	/* MCP79 */
440441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci_mcp79 },	/* MCP79 */
441441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci_mcp79 },	/* MCP79 */
442441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci_mcp79 },	/* MCP79 */
443441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci_mcp79 },	/* MCP79 */
444441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci_mcp79 },	/* MCP79 */
445441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci_mcp79 },	/* MCP79 */
446441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci_mcp89 },	/* MCP89 */
447441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci_mcp89 },	/* MCP89 */
448441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci_mcp89 },	/* MCP89 */
449441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci_mcp89 },	/* MCP89 */
450441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci_mcp89 },	/* MCP89 */
451441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci_mcp89 },	/* MCP89 */
452441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci_mcp89 },	/* MCP89 */
453441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci_mcp89 },	/* MCP89 */
454441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci_mcp89 },	/* MCP89 */
455441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci_mcp89 },	/* MCP89 */
456441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci_mcp89 },	/* MCP89 */
457441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci_mcp89 },	/* MCP89 */
458c6fd2807SJeff Garzik 
459c6fd2807SJeff Garzik 	/* SiS */
46020e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
46120e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
46220e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
463c6fd2807SJeff Garzik 
464318893e1SAlessandro Rubini 	/* ST Microelectronics */
465318893e1SAlessandro Rubini 	{ PCI_VDEVICE(STMICRO, 0xCC06), board_ahci },		/* ST ConneXt */
466318893e1SAlessandro Rubini 
467cd70c266SJeff Garzik 	/* Marvell */
468cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
469c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
47069fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9123),
47110aca06cSAnssi Hannula 	  .class = PCI_CLASS_STORAGE_SATA_AHCI,
47210aca06cSAnssi Hannula 	  .class_mask = 0xffffff,
4735f173107STejun Heo 	  .driver_data = board_ahci_yes_fbs },			/* 88se9128 */
47469fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
475467b41c6SPer Jessen 	  .driver_data = board_ahci_yes_fbs },			/* 88se9125 */
476e098f5cbSSimon Guinot 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178,
477e098f5cbSSimon Guinot 			 PCI_VENDOR_ID_MARVELL_EXT, 0x9170),
478e098f5cbSSimon Guinot 	  .driver_data = board_ahci_yes_fbs },			/* 88se9170 */
47969fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
480642d8925SMatt Johnson 	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */
481fcce9a35SGeorge Spelvin 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
482c5edfff9SMurali Karicheri 	  .driver_data = board_ahci_yes_fbs },			/* 88se9182 */
483c5edfff9SMurali Karicheri 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9182),
484fcce9a35SGeorge Spelvin 	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 */
48569fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
48617c60c6bSAlan Cox 	  .driver_data = board_ahci_yes_fbs },			/* 88se9172 on some Gigabyte */
487754a292fSAndreas Schrägle 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0),
488754a292fSAndreas Schrägle 	  .driver_data = board_ahci_yes_fbs },
48969fd3157SMyron Stowe 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
49050be5e36STejun Heo 	  .driver_data = board_ahci_yes_fbs },
4916d5278a6SSamir Benmendil 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
4926d5278a6SSamir Benmendil 	  .driver_data = board_ahci_yes_fbs },
493d2518365SJérôme Carretero 	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642),
494d2518365SJérôme Carretero 	  .driver_data = board_ahci_yes_fbs },
495cd70c266SJeff Garzik 
496c77a036bSMark Nelson 	/* Promise */
497c77a036bSMark Nelson 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
498b32bfc06SRomain Degez 	{ PCI_VDEVICE(PROMISE, 0x3781), board_ahci },   /* FastTrak TX8660 ahci-mode */
499c77a036bSMark Nelson 
500c9703765SKeng-Yu Lin 	/* Asmedia */
5017b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci },	/* ASM1060 */
5027b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci },	/* ASM1060 */
5037b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci },	/* ASM1061 */
5047b4f6ecaSAlan Cox 	{ PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },	/* ASM1062 */
505c9703765SKeng-Yu Lin 
50667809f85SLevente Kurusa 	/*
50766a7cbc3STejun Heo 	 * Samsung SSDs found on some macbooks.  NCQ times out if MSI is
50866a7cbc3STejun Heo 	 * enabled.  https://bugzilla.kernel.org/show_bug.cgi?id=60731
50967809f85SLevente Kurusa 	 */
51066a7cbc3STejun Heo 	{ PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi },
5112b21ef0aSTejun Heo 	{ PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi },
51267809f85SLevente Kurusa 
5137f9c9f8eSHugh Daschbach 	/* Enmotus */
5147f9c9f8eSHugh Daschbach 	{ PCI_DEVICE(0x1c44, 0x8000), board_ahci },
5157f9c9f8eSHugh Daschbach 
516415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
517415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
518c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
519415ae2b5SJeff Garzik 
520c6fd2807SJeff Garzik 	{ }	/* terminate list */
521c6fd2807SJeff Garzik };
522c6fd2807SJeff Garzik 
523c6fd2807SJeff Garzik 
524c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
525c6fd2807SJeff Garzik 	.name			= DRV_NAME,
526c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
527c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
52824dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
529438ac6d5STejun Heo #ifdef CONFIG_PM
530c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
531c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
532438ac6d5STejun Heo #endif
533c6fd2807SJeff Garzik };
534c6fd2807SJeff Garzik 
5355b66c829SAlan Cox #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
5365b66c829SAlan Cox static int marvell_enable;
5375b66c829SAlan Cox #else
5385b66c829SAlan Cox static int marvell_enable = 1;
5395b66c829SAlan Cox #endif
5405b66c829SAlan Cox module_param(marvell_enable, int, 0644);
5415b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
5425b66c829SAlan Cox 
5435b66c829SAlan Cox 
544394d6e53SAnton Vorontsov static void ahci_pci_save_initial_config(struct pci_dev *pdev,
545394d6e53SAnton Vorontsov 					 struct ahci_host_priv *hpriv)
546394d6e53SAnton Vorontsov {
547394d6e53SAnton Vorontsov 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
548394d6e53SAnton Vorontsov 		dev_info(&pdev->dev, "JMB361 has only one port\n");
5499a23c1d6SAntoine Tenart 		hpriv->force_port_map = 1;
550394d6e53SAnton Vorontsov 	}
551394d6e53SAnton Vorontsov 
552394d6e53SAnton Vorontsov 	/*
553394d6e53SAnton Vorontsov 	 * Temporary Marvell 6145 hack: PATA port presence
554394d6e53SAnton Vorontsov 	 * is asserted through the standard AHCI port
555394d6e53SAnton Vorontsov 	 * presence register, as bit 4 (counting from 0)
556394d6e53SAnton Vorontsov 	 */
557394d6e53SAnton Vorontsov 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
558394d6e53SAnton Vorontsov 		if (pdev->device == 0x6121)
5599a23c1d6SAntoine Tenart 			hpriv->mask_port_map = 0x3;
560394d6e53SAnton Vorontsov 		else
5619a23c1d6SAntoine Tenart 			hpriv->mask_port_map = 0xf;
562394d6e53SAnton Vorontsov 		dev_info(&pdev->dev,
563394d6e53SAnton Vorontsov 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
564394d6e53SAnton Vorontsov 	}
565394d6e53SAnton Vorontsov 
566725c7b57SAntoine Ténart 	ahci_save_initial_config(&pdev->dev, hpriv);
567394d6e53SAnton Vorontsov }
568394d6e53SAnton Vorontsov 
5693303040dSAnton Vorontsov static int ahci_pci_reset_controller(struct ata_host *host)
5703303040dSAnton Vorontsov {
5713303040dSAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
5723303040dSAnton Vorontsov 
5733303040dSAnton Vorontsov 	ahci_reset_controller(host);
5743303040dSAnton Vorontsov 
575c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
5763303040dSAnton Vorontsov 		struct ahci_host_priv *hpriv = host->private_data;
577c6fd2807SJeff Garzik 		u16 tmp16;
578c6fd2807SJeff Garzik 
579c6fd2807SJeff Garzik 		/* configure PCS */
580c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
58149f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
58249f29090STejun Heo 			tmp16 |= hpriv->port_map;
583c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
584c6fd2807SJeff Garzik 		}
58549f29090STejun Heo 	}
586c6fd2807SJeff Garzik 
587c6fd2807SJeff Garzik 	return 0;
588c6fd2807SJeff Garzik }
589c6fd2807SJeff Garzik 
590781d6550SAnton Vorontsov static void ahci_pci_init_controller(struct ata_host *host)
591781d6550SAnton Vorontsov {
592781d6550SAnton Vorontsov 	struct ahci_host_priv *hpriv = host->private_data;
593781d6550SAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
594781d6550SAnton Vorontsov 	void __iomem *port_mmio;
595781d6550SAnton Vorontsov 	u32 tmp;
596c40e7cb8SJose Alberto Reguero 	int mv;
5972bcd866bSJeff Garzik 
598417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
599c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
600c40e7cb8SJose Alberto Reguero 			mv = 2;
601c40e7cb8SJose Alberto Reguero 		else
602c40e7cb8SJose Alberto Reguero 			mv = 4;
603c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
604cd70c266SJeff Garzik 
605cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
606cd70c266SJeff Garzik 
607cd70c266SJeff Garzik 		/* clear port IRQ */
608cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
609cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
610cd70c266SJeff Garzik 		if (tmp)
611cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
612cd70c266SJeff Garzik 	}
613cd70c266SJeff Garzik 
614781d6550SAnton Vorontsov 	ahci_init_controller(host);
615c6fd2807SJeff Garzik }
616c6fd2807SJeff Garzik 
617cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
618d4b2bab4STejun Heo 				 unsigned long deadline)
619ad616ffbSTejun Heo {
620cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
621039ece38SHans de Goede 	struct ahci_host_priv *hpriv = ap->host->private_data;
6229dadd45bSTejun Heo 	bool online;
623ad616ffbSTejun Heo 	int rc;
624ad616ffbSTejun Heo 
625ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
626ad616ffbSTejun Heo 
6274447d351STejun Heo 	ahci_stop_engine(ap);
628ad616ffbSTejun Heo 
629cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
6309dadd45bSTejun Heo 				 deadline, &online, NULL);
631ad616ffbSTejun Heo 
632039ece38SHans de Goede 	hpriv->start_engine(ap);
633ad616ffbSTejun Heo 
634ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
635ad616ffbSTejun Heo 
636ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
637ad616ffbSTejun Heo 	 * request follow-up softreset.
638ad616ffbSTejun Heo 	 */
6399dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
640ad616ffbSTejun Heo }
641ad616ffbSTejun Heo 
642edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
643edc93052STejun Heo 				unsigned long deadline)
644edc93052STejun Heo {
645edc93052STejun Heo 	struct ata_port *ap = link->ap;
646edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
647039ece38SHans de Goede 	struct ahci_host_priv *hpriv = ap->host->private_data;
648edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
649edc93052STejun Heo 	struct ata_taskfile tf;
6509dadd45bSTejun Heo 	bool online;
651edc93052STejun Heo 	int rc;
652edc93052STejun Heo 
653edc93052STejun Heo 	ahci_stop_engine(ap);
654edc93052STejun Heo 
655edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
656edc93052STejun Heo 	ata_tf_init(link->device, &tf);
6579bbb1b0eSSergei Shtylyov 	tf.command = ATA_BUSY;
658edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
659edc93052STejun Heo 
660edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
6619dadd45bSTejun Heo 				 deadline, &online, NULL);
662edc93052STejun Heo 
663039ece38SHans de Goede 	hpriv->start_engine(ap);
664edc93052STejun Heo 
665edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
666edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
667edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
668edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
669edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
670edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
671edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
672edc93052STejun Heo 	 *
673edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
674edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
675edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
676edc93052STejun Heo 	 * suffice while making probing snappish enough.
677edc93052STejun Heo 	 */
6789dadd45bSTejun Heo 	if (online) {
6799dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
6809dadd45bSTejun Heo 					  ahci_check_ready);
681edc93052STejun Heo 		if (rc)
68278d5ae39SShane Huang 			ahci_kick_engine(ap);
6839dadd45bSTejun Heo 	}
6849dadd45bSTejun Heo 	return rc;
685edc93052STejun Heo }
686edc93052STejun Heo 
687*dbfe8ef5SDan Williams /*
688*dbfe8ef5SDan Williams  * ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports.
689*dbfe8ef5SDan Williams  *
690*dbfe8ef5SDan Williams  * It has been observed with some SSDs that the timing of events in the
691*dbfe8ef5SDan Williams  * link synchronization phase can leave the port in a state that can not
692*dbfe8ef5SDan Williams  * be recovered by a SATA-hard-reset alone.  The failing signature is
693*dbfe8ef5SDan Williams  * SStatus.DET stuck at 1 ("Device presence detected but Phy
694*dbfe8ef5SDan Williams  * communication not established").  It was found that unloading and
695*dbfe8ef5SDan Williams  * reloading the driver when this problem occurs allows the drive
696*dbfe8ef5SDan Williams  * connection to be recovered (DET advanced to 0x3).  The critical
697*dbfe8ef5SDan Williams  * component of reloading the driver is that the port state machines are
698*dbfe8ef5SDan Williams  * reset by bouncing "port enable" in the AHCI PCS configuration
699*dbfe8ef5SDan Williams  * register.  So, reproduce that effect by bouncing a port whenever we
700*dbfe8ef5SDan Williams  * see DET==1 after a reset.
701*dbfe8ef5SDan Williams  */
702*dbfe8ef5SDan Williams static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
703*dbfe8ef5SDan Williams 			      unsigned long deadline)
704*dbfe8ef5SDan Williams {
705*dbfe8ef5SDan Williams 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
706*dbfe8ef5SDan Williams 	struct ata_port *ap = link->ap;
707*dbfe8ef5SDan Williams 	struct ahci_port_priv *pp = ap->private_data;
708*dbfe8ef5SDan Williams 	struct ahci_host_priv *hpriv = ap->host->private_data;
709*dbfe8ef5SDan Williams 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
710*dbfe8ef5SDan Williams 	unsigned long tmo = deadline - jiffies;
711*dbfe8ef5SDan Williams 	struct ata_taskfile tf;
712*dbfe8ef5SDan Williams 	bool online;
713*dbfe8ef5SDan Williams 	int rc, i;
714*dbfe8ef5SDan Williams 
715*dbfe8ef5SDan Williams 	DPRINTK("ENTER\n");
716*dbfe8ef5SDan Williams 
717*dbfe8ef5SDan Williams 	ahci_stop_engine(ap);
718*dbfe8ef5SDan Williams 
719*dbfe8ef5SDan Williams 	for (i = 0; i < 2; i++) {
720*dbfe8ef5SDan Williams 		u16 val;
721*dbfe8ef5SDan Williams 		u32 sstatus;
722*dbfe8ef5SDan Williams 		int port = ap->port_no;
723*dbfe8ef5SDan Williams 		struct ata_host *host = ap->host;
724*dbfe8ef5SDan Williams 		struct pci_dev *pdev = to_pci_dev(host->dev);
725*dbfe8ef5SDan Williams 
726*dbfe8ef5SDan Williams 		/* clear D2H reception area to properly wait for D2H FIS */
727*dbfe8ef5SDan Williams 		ata_tf_init(link->device, &tf);
728*dbfe8ef5SDan Williams 		tf.command = ATA_BUSY;
729*dbfe8ef5SDan Williams 		ata_tf_to_fis(&tf, 0, 0, d2h_fis);
730*dbfe8ef5SDan Williams 
731*dbfe8ef5SDan Williams 		rc = sata_link_hardreset(link, timing, deadline, &online,
732*dbfe8ef5SDan Williams 				ahci_check_ready);
733*dbfe8ef5SDan Williams 
734*dbfe8ef5SDan Williams 		if (sata_scr_read(link, SCR_STATUS, &sstatus) != 0 ||
735*dbfe8ef5SDan Williams 				(sstatus & 0xf) != 1)
736*dbfe8ef5SDan Williams 			break;
737*dbfe8ef5SDan Williams 
738*dbfe8ef5SDan Williams 		ata_link_printk(link, KERN_INFO, "avn bounce port%d\n",
739*dbfe8ef5SDan Williams 				port);
740*dbfe8ef5SDan Williams 
741*dbfe8ef5SDan Williams 		pci_read_config_word(pdev, 0x92, &val);
742*dbfe8ef5SDan Williams 		val &= ~(1 << port);
743*dbfe8ef5SDan Williams 		pci_write_config_word(pdev, 0x92, val);
744*dbfe8ef5SDan Williams 		ata_msleep(ap, 1000);
745*dbfe8ef5SDan Williams 		val |= 1 << port;
746*dbfe8ef5SDan Williams 		pci_write_config_word(pdev, 0x92, val);
747*dbfe8ef5SDan Williams 		deadline += tmo;
748*dbfe8ef5SDan Williams 	}
749*dbfe8ef5SDan Williams 
750*dbfe8ef5SDan Williams 	hpriv->start_engine(ap);
751*dbfe8ef5SDan Williams 
752*dbfe8ef5SDan Williams 	if (online)
753*dbfe8ef5SDan Williams 		*class = ahci_dev_classify(ap);
754*dbfe8ef5SDan Williams 
755*dbfe8ef5SDan Williams 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
756*dbfe8ef5SDan Williams 	return rc;
757*dbfe8ef5SDan Williams }
758*dbfe8ef5SDan Williams 
759*dbfe8ef5SDan Williams 
760438ac6d5STejun Heo #ifdef CONFIG_PM
761c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
762c6fd2807SJeff Garzik {
7630a86e1c8SJingoo Han 	struct ata_host *host = pci_get_drvdata(pdev);
7649b10ae86STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
765d8993349SAnton Vorontsov 	void __iomem *mmio = hpriv->mmio;
766c6fd2807SJeff Garzik 	u32 ctl;
767c6fd2807SJeff Garzik 
7689b10ae86STejun Heo 	if (mesg.event & PM_EVENT_SUSPEND &&
7699b10ae86STejun Heo 	    hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
770a44fec1fSJoe Perches 		dev_err(&pdev->dev,
7719b10ae86STejun Heo 			"BIOS update required for suspend/resume\n");
7729b10ae86STejun Heo 		return -EIO;
7739b10ae86STejun Heo 	}
7749b10ae86STejun Heo 
7753a2d5b70SRafael J. Wysocki 	if (mesg.event & PM_EVENT_SLEEP) {
776c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
777c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
778c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
779c6fd2807SJeff Garzik 		 */
780c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
781c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
782c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
783c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
784c6fd2807SJeff Garzik 	}
785c6fd2807SJeff Garzik 
786c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
787c6fd2807SJeff Garzik }
788c6fd2807SJeff Garzik 
789c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
790c6fd2807SJeff Garzik {
7910a86e1c8SJingoo Han 	struct ata_host *host = pci_get_drvdata(pdev);
792c6fd2807SJeff Garzik 	int rc;
793c6fd2807SJeff Garzik 
794553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
795553c4aa6STejun Heo 	if (rc)
796553c4aa6STejun Heo 		return rc;
797c6fd2807SJeff Garzik 
798cb85696dSJames Laird 	/* Apple BIOS helpfully mangles the registers on resume */
799cb85696dSJames Laird 	if (is_mcp89_apple(pdev))
800cb85696dSJames Laird 		ahci_mcp89_apple_enable(pdev);
801cb85696dSJames Laird 
802c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
8033303040dSAnton Vorontsov 		rc = ahci_pci_reset_controller(host);
804c6fd2807SJeff Garzik 		if (rc)
805c6fd2807SJeff Garzik 			return rc;
806c6fd2807SJeff Garzik 
807781d6550SAnton Vorontsov 		ahci_pci_init_controller(host);
808c6fd2807SJeff Garzik 	}
809c6fd2807SJeff Garzik 
810cca3974eSJeff Garzik 	ata_host_resume(host);
811c6fd2807SJeff Garzik 
812c6fd2807SJeff Garzik 	return 0;
813c6fd2807SJeff Garzik }
814438ac6d5STejun Heo #endif
815c6fd2807SJeff Garzik 
8164447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
817c6fd2807SJeff Garzik {
818c6fd2807SJeff Garzik 	int rc;
819c6fd2807SJeff Garzik 
820318893e1SAlessandro Rubini 	/*
821318893e1SAlessandro Rubini 	 * If the device fixup already set the dma_mask to some non-standard
822318893e1SAlessandro Rubini 	 * value, don't extend it here. This happens on STA2X11, for example.
823318893e1SAlessandro Rubini 	 */
824318893e1SAlessandro Rubini 	if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
825318893e1SAlessandro Rubini 		return 0;
826318893e1SAlessandro Rubini 
827c6fd2807SJeff Garzik 	if (using_dac &&
828c54c719bSQuentin Lambert 	    !dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
829c54c719bSQuentin Lambert 		rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
830c6fd2807SJeff Garzik 		if (rc) {
831c54c719bSQuentin Lambert 			rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
832c6fd2807SJeff Garzik 			if (rc) {
833a44fec1fSJoe Perches 				dev_err(&pdev->dev,
834c6fd2807SJeff Garzik 					"64-bit DMA enable failed\n");
835c6fd2807SJeff Garzik 				return rc;
836c6fd2807SJeff Garzik 			}
837c6fd2807SJeff Garzik 		}
838c6fd2807SJeff Garzik 	} else {
839c54c719bSQuentin Lambert 		rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
840c6fd2807SJeff Garzik 		if (rc) {
841a44fec1fSJoe Perches 			dev_err(&pdev->dev, "32-bit DMA enable failed\n");
842c6fd2807SJeff Garzik 			return rc;
843c6fd2807SJeff Garzik 		}
844c54c719bSQuentin Lambert 		rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
845c6fd2807SJeff Garzik 		if (rc) {
846a44fec1fSJoe Perches 			dev_err(&pdev->dev,
847c6fd2807SJeff Garzik 				"32-bit consistent DMA enable failed\n");
848c6fd2807SJeff Garzik 			return rc;
849c6fd2807SJeff Garzik 		}
850c6fd2807SJeff Garzik 	}
851c6fd2807SJeff Garzik 	return 0;
852c6fd2807SJeff Garzik }
853c6fd2807SJeff Garzik 
854439fcaecSAnton Vorontsov static void ahci_pci_print_info(struct ata_host *host)
855439fcaecSAnton Vorontsov {
856439fcaecSAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
857439fcaecSAnton Vorontsov 	u16 cc;
858439fcaecSAnton Vorontsov 	const char *scc_s;
859439fcaecSAnton Vorontsov 
860439fcaecSAnton Vorontsov 	pci_read_config_word(pdev, 0x0a, &cc);
861439fcaecSAnton Vorontsov 	if (cc == PCI_CLASS_STORAGE_IDE)
862439fcaecSAnton Vorontsov 		scc_s = "IDE";
863439fcaecSAnton Vorontsov 	else if (cc == PCI_CLASS_STORAGE_SATA)
864439fcaecSAnton Vorontsov 		scc_s = "SATA";
865439fcaecSAnton Vorontsov 	else if (cc == PCI_CLASS_STORAGE_RAID)
866439fcaecSAnton Vorontsov 		scc_s = "RAID";
867439fcaecSAnton Vorontsov 	else
868439fcaecSAnton Vorontsov 		scc_s = "unknown";
869439fcaecSAnton Vorontsov 
870439fcaecSAnton Vorontsov 	ahci_print_info(host, scc_s);
871439fcaecSAnton Vorontsov }
872439fcaecSAnton Vorontsov 
873edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
874edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
875edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
876edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
877edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
878edc93052STejun Heo  * other configuration).
879edc93052STejun Heo  *
880edc93052STejun Heo  * When there's no device attached to the first downstream port of the
881edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
882edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
883edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
884edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
885edc93052STejun Heo  *
886edc93052STejun Heo  * The following function works around the problem by always using
887edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
888edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
889edc93052STejun Heo  * assumed without follow-up softreset.
890edc93052STejun Heo  */
891edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
892edc93052STejun Heo {
8931bd06867SMathias Krause 	static const struct dmi_system_id sysids[] = {
894edc93052STejun Heo 		{
895edc93052STejun Heo 			.ident = "P5W DH Deluxe",
896edc93052STejun Heo 			.matches = {
897edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
898edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
899edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
900edc93052STejun Heo 			},
901edc93052STejun Heo 		},
902edc93052STejun Heo 		{ }
903edc93052STejun Heo 	};
904edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
905edc93052STejun Heo 
906edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
907edc93052STejun Heo 	    dmi_check_system(sysids)) {
908edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
909edc93052STejun Heo 
910a44fec1fSJoe Perches 		dev_info(&pdev->dev,
911a44fec1fSJoe Perches 			 "enabling ASUS P5W DH Deluxe on-board SIMG4726 workaround\n");
912edc93052STejun Heo 
913edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
914edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
915edc93052STejun Heo 	}
916edc93052STejun Heo }
917edc93052STejun Heo 
918cb85696dSJames Laird /*
919cb85696dSJames Laird  * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when
920cb85696dSJames Laird  * booting in BIOS compatibility mode.  We restore the registers but not ID.
921cb85696dSJames Laird  */
922cb85696dSJames Laird static void ahci_mcp89_apple_enable(struct pci_dev *pdev)
923cb85696dSJames Laird {
924cb85696dSJames Laird 	u32 val;
925cb85696dSJames Laird 
926cb85696dSJames Laird 	printk(KERN_INFO "ahci: enabling MCP89 AHCI mode\n");
927cb85696dSJames Laird 
928cb85696dSJames Laird 	pci_read_config_dword(pdev, 0xf8, &val);
929cb85696dSJames Laird 	val |= 1 << 0x1b;
930cb85696dSJames Laird 	/* the following changes the device ID, but appears not to affect function */
931cb85696dSJames Laird 	/* val = (val & ~0xf0000000) | 0x80000000; */
932cb85696dSJames Laird 	pci_write_config_dword(pdev, 0xf8, val);
933cb85696dSJames Laird 
934cb85696dSJames Laird 	pci_read_config_dword(pdev, 0x54c, &val);
935cb85696dSJames Laird 	val |= 1 << 0xc;
936cb85696dSJames Laird 	pci_write_config_dword(pdev, 0x54c, val);
937cb85696dSJames Laird 
938cb85696dSJames Laird 	pci_read_config_dword(pdev, 0x4a4, &val);
939cb85696dSJames Laird 	val &= 0xff;
940cb85696dSJames Laird 	val |= 0x01060100;
941cb85696dSJames Laird 	pci_write_config_dword(pdev, 0x4a4, val);
942cb85696dSJames Laird 
943cb85696dSJames Laird 	pci_read_config_dword(pdev, 0x54c, &val);
944cb85696dSJames Laird 	val &= ~(1 << 0xc);
945cb85696dSJames Laird 	pci_write_config_dword(pdev, 0x54c, val);
946cb85696dSJames Laird 
947cb85696dSJames Laird 	pci_read_config_dword(pdev, 0xf8, &val);
948cb85696dSJames Laird 	val &= ~(1 << 0x1b);
949cb85696dSJames Laird 	pci_write_config_dword(pdev, 0xf8, val);
950cb85696dSJames Laird }
951cb85696dSJames Laird 
952cb85696dSJames Laird static bool is_mcp89_apple(struct pci_dev *pdev)
953cb85696dSJames Laird {
954cb85696dSJames Laird 	return pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
955cb85696dSJames Laird 		pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
956cb85696dSJames Laird 		pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
957cb85696dSJames Laird 		pdev->subsystem_device == 0xcb89;
958cb85696dSJames Laird }
959cb85696dSJames Laird 
9602fcad9d2STejun Heo /* only some SB600 ahci controllers can do 64bit DMA */
9612fcad9d2STejun Heo static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
96258a09b38SShane Huang {
96358a09b38SShane Huang 	static const struct dmi_system_id sysids[] = {
96403d783bfSTejun Heo 		/*
96503d783bfSTejun Heo 		 * The oldest version known to be broken is 0901 and
96603d783bfSTejun Heo 		 * working is 1501 which was released on 2007-10-26.
9672fcad9d2STejun Heo 		 * Enable 64bit DMA on 1501 and anything newer.
9682fcad9d2STejun Heo 		 *
96903d783bfSTejun Heo 		 * Please read bko#9412 for more info.
97003d783bfSTejun Heo 		 */
97158a09b38SShane Huang 		{
97258a09b38SShane Huang 			.ident = "ASUS M2A-VM",
97358a09b38SShane Huang 			.matches = {
97458a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_VENDOR,
97558a09b38SShane Huang 					  "ASUSTeK Computer INC."),
97658a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
97758a09b38SShane Huang 			},
97803d783bfSTejun Heo 			.driver_data = "20071026",	/* yyyymmdd */
97958a09b38SShane Huang 		},
980e65cc194SMark Nelson 		/*
981e65cc194SMark Nelson 		 * All BIOS versions for the MSI K9A2 Platinum (MS-7376)
982e65cc194SMark Nelson 		 * support 64bit DMA.
983e65cc194SMark Nelson 		 *
984e65cc194SMark Nelson 		 * BIOS versions earlier than 1.5 had the Manufacturer DMI
985e65cc194SMark Nelson 		 * fields as "MICRO-STAR INTERANTIONAL CO.,LTD".
986e65cc194SMark Nelson 		 * This spelling mistake was fixed in BIOS version 1.5, so
987e65cc194SMark Nelson 		 * 1.5 and later have the Manufacturer as
988e65cc194SMark Nelson 		 * "MICRO-STAR INTERNATIONAL CO.,LTD".
989e65cc194SMark Nelson 		 * So try to match on DMI_BOARD_VENDOR of "MICRO-STAR INTER".
990e65cc194SMark Nelson 		 *
991e65cc194SMark Nelson 		 * BIOS versions earlier than 1.9 had a Board Product Name
992e65cc194SMark Nelson 		 * DMI field of "MS-7376". This was changed to be
993e65cc194SMark Nelson 		 * "K9A2 Platinum (MS-7376)" in version 1.9, but we can still
994e65cc194SMark Nelson 		 * match on DMI_BOARD_NAME of "MS-7376".
995e65cc194SMark Nelson 		 */
996e65cc194SMark Nelson 		{
997e65cc194SMark Nelson 			.ident = "MSI K9A2 Platinum",
998e65cc194SMark Nelson 			.matches = {
999e65cc194SMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
1000e65cc194SMark Nelson 					  "MICRO-STAR INTER"),
1001e65cc194SMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "MS-7376"),
1002e65cc194SMark Nelson 			},
1003e65cc194SMark Nelson 		},
10043c4aa91fSMark Nelson 		/*
1005ff0173c1SMark Nelson 		 * All BIOS versions for the MSI K9AGM2 (MS-7327) support
1006ff0173c1SMark Nelson 		 * 64bit DMA.
1007ff0173c1SMark Nelson 		 *
1008ff0173c1SMark Nelson 		 * This board also had the typo mentioned above in the
1009ff0173c1SMark Nelson 		 * Manufacturer DMI field (fixed in BIOS version 1.5), so
1010ff0173c1SMark Nelson 		 * match on DMI_BOARD_VENDOR of "MICRO-STAR INTER" again.
1011ff0173c1SMark Nelson 		 */
1012ff0173c1SMark Nelson 		{
1013ff0173c1SMark Nelson 			.ident = "MSI K9AGM2",
1014ff0173c1SMark Nelson 			.matches = {
1015ff0173c1SMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
1016ff0173c1SMark Nelson 					  "MICRO-STAR INTER"),
1017ff0173c1SMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "MS-7327"),
1018ff0173c1SMark Nelson 			},
1019ff0173c1SMark Nelson 		},
1020ff0173c1SMark Nelson 		/*
10213c4aa91fSMark Nelson 		 * All BIOS versions for the Asus M3A support 64bit DMA.
10223c4aa91fSMark Nelson 		 * (all release versions from 0301 to 1206 were tested)
10233c4aa91fSMark Nelson 		 */
10243c4aa91fSMark Nelson 		{
10253c4aa91fSMark Nelson 			.ident = "ASUS M3A",
10263c4aa91fSMark Nelson 			.matches = {
10273c4aa91fSMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
10283c4aa91fSMark Nelson 					  "ASUSTeK Computer INC."),
10293c4aa91fSMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "M3A"),
10303c4aa91fSMark Nelson 			},
10313c4aa91fSMark Nelson 		},
103258a09b38SShane Huang 		{ }
103358a09b38SShane Huang 	};
103403d783bfSTejun Heo 	const struct dmi_system_id *match;
10352fcad9d2STejun Heo 	int year, month, date;
10362fcad9d2STejun Heo 	char buf[9];
103758a09b38SShane Huang 
103803d783bfSTejun Heo 	match = dmi_first_match(sysids);
103958a09b38SShane Huang 	if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
104003d783bfSTejun Heo 	    !match)
104158a09b38SShane Huang 		return false;
104258a09b38SShane Huang 
1043e65cc194SMark Nelson 	if (!match->driver_data)
1044e65cc194SMark Nelson 		goto enable_64bit;
1045e65cc194SMark Nelson 
104603d783bfSTejun Heo 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
104703d783bfSTejun Heo 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
104803d783bfSTejun Heo 
1049e65cc194SMark Nelson 	if (strcmp(buf, match->driver_data) >= 0)
1050e65cc194SMark Nelson 		goto enable_64bit;
1051e65cc194SMark Nelson 	else {
1052a44fec1fSJoe Perches 		dev_warn(&pdev->dev,
1053a44fec1fSJoe Perches 			 "%s: BIOS too old, forcing 32bit DMA, update BIOS\n",
1054a44fec1fSJoe Perches 			 match->ident);
10552fcad9d2STejun Heo 		return false;
10562fcad9d2STejun Heo 	}
1057e65cc194SMark Nelson 
1058e65cc194SMark Nelson enable_64bit:
1059a44fec1fSJoe Perches 	dev_warn(&pdev->dev, "%s: enabling 64bit DMA\n", match->ident);
1060e65cc194SMark Nelson 	return true;
106158a09b38SShane Huang }
106258a09b38SShane Huang 
10631fd68434SRafael J. Wysocki static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
10641fd68434SRafael J. Wysocki {
10651fd68434SRafael J. Wysocki 	static const struct dmi_system_id broken_systems[] = {
10661fd68434SRafael J. Wysocki 		{
10671fd68434SRafael J. Wysocki 			.ident = "HP Compaq nx6310",
10681fd68434SRafael J. Wysocki 			.matches = {
10691fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
10701fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
10711fd68434SRafael J. Wysocki 			},
10721fd68434SRafael J. Wysocki 			/* PCI slot number of the controller */
10731fd68434SRafael J. Wysocki 			.driver_data = (void *)0x1FUL,
10741fd68434SRafael J. Wysocki 		},
1075d2f9c061SMaciej Rutecki 		{
1076d2f9c061SMaciej Rutecki 			.ident = "HP Compaq 6720s",
1077d2f9c061SMaciej Rutecki 			.matches = {
1078d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1079d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
1080d2f9c061SMaciej Rutecki 			},
1081d2f9c061SMaciej Rutecki 			/* PCI slot number of the controller */
1082d2f9c061SMaciej Rutecki 			.driver_data = (void *)0x1FUL,
1083d2f9c061SMaciej Rutecki 		},
10841fd68434SRafael J. Wysocki 
10851fd68434SRafael J. Wysocki 		{ }	/* terminate list */
10861fd68434SRafael J. Wysocki 	};
10871fd68434SRafael J. Wysocki 	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
10881fd68434SRafael J. Wysocki 
10891fd68434SRafael J. Wysocki 	if (dmi) {
10901fd68434SRafael J. Wysocki 		unsigned long slot = (unsigned long)dmi->driver_data;
10911fd68434SRafael J. Wysocki 		/* apply the quirk only to on-board controllers */
10921fd68434SRafael J. Wysocki 		return slot == PCI_SLOT(pdev->devfn);
10931fd68434SRafael J. Wysocki 	}
10941fd68434SRafael J. Wysocki 
10951fd68434SRafael J. Wysocki 	return false;
10961fd68434SRafael J. Wysocki }
10971fd68434SRafael J. Wysocki 
10989b10ae86STejun Heo static bool ahci_broken_suspend(struct pci_dev *pdev)
10999b10ae86STejun Heo {
11009b10ae86STejun Heo 	static const struct dmi_system_id sysids[] = {
11019b10ae86STejun Heo 		/*
11029b10ae86STejun Heo 		 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
11039b10ae86STejun Heo 		 * to the harddisk doesn't become online after
11049b10ae86STejun Heo 		 * resuming from STR.  Warn and fail suspend.
11059deb3431STejun Heo 		 *
11069deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=12276
11079deb3431STejun Heo 		 *
11089deb3431STejun Heo 		 * Use dates instead of versions to match as HP is
11099deb3431STejun Heo 		 * apparently recycling both product and version
11109deb3431STejun Heo 		 * strings.
11119deb3431STejun Heo 		 *
11129deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=15462
11139b10ae86STejun Heo 		 */
11149b10ae86STejun Heo 		{
11159b10ae86STejun Heo 			.ident = "dv4",
11169b10ae86STejun Heo 			.matches = {
11179b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
11189b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
11199b10ae86STejun Heo 					  "HP Pavilion dv4 Notebook PC"),
11209b10ae86STejun Heo 			},
11219deb3431STejun Heo 			.driver_data = "20090105",	/* F.30 */
11229b10ae86STejun Heo 		},
11239b10ae86STejun Heo 		{
11249b10ae86STejun Heo 			.ident = "dv5",
11259b10ae86STejun Heo 			.matches = {
11269b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
11279b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
11289b10ae86STejun Heo 					  "HP Pavilion dv5 Notebook PC"),
11299b10ae86STejun Heo 			},
11309deb3431STejun Heo 			.driver_data = "20090506",	/* F.16 */
11319b10ae86STejun Heo 		},
11329b10ae86STejun Heo 		{
11339b10ae86STejun Heo 			.ident = "dv6",
11349b10ae86STejun Heo 			.matches = {
11359b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
11369b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
11379b10ae86STejun Heo 					  "HP Pavilion dv6 Notebook PC"),
11389b10ae86STejun Heo 			},
11399deb3431STejun Heo 			.driver_data = "20090423",	/* F.21 */
11409b10ae86STejun Heo 		},
11419b10ae86STejun Heo 		{
11429b10ae86STejun Heo 			.ident = "HDX18",
11439b10ae86STejun Heo 			.matches = {
11449b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
11459b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
11469b10ae86STejun Heo 					  "HP HDX18 Notebook PC"),
11479b10ae86STejun Heo 			},
11489deb3431STejun Heo 			.driver_data = "20090430",	/* F.23 */
11499b10ae86STejun Heo 		},
1150cedc9bf9STejun Heo 		/*
1151cedc9bf9STejun Heo 		 * Acer eMachines G725 has the same problem.  BIOS
1152cedc9bf9STejun Heo 		 * V1.03 is known to be broken.  V3.04 is known to
115325985edcSLucas De Marchi 		 * work.  Between, there are V1.06, V2.06 and V3.03
1154cedc9bf9STejun Heo 		 * that we don't have much idea about.  For now,
1155cedc9bf9STejun Heo 		 * blacklist anything older than V3.04.
11569deb3431STejun Heo 		 *
11579deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=15104
1158cedc9bf9STejun Heo 		 */
1159cedc9bf9STejun Heo 		{
1160cedc9bf9STejun Heo 			.ident = "G725",
1161cedc9bf9STejun Heo 			.matches = {
1162cedc9bf9STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "eMachines"),
1163cedc9bf9STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "eMachines G725"),
1164cedc9bf9STejun Heo 			},
11659deb3431STejun Heo 			.driver_data = "20091216",	/* V3.04 */
1166cedc9bf9STejun Heo 		},
11679b10ae86STejun Heo 		{ }	/* terminate list */
11689b10ae86STejun Heo 	};
11699b10ae86STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
11709deb3431STejun Heo 	int year, month, date;
11719deb3431STejun Heo 	char buf[9];
11729b10ae86STejun Heo 
11739b10ae86STejun Heo 	if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
11749b10ae86STejun Heo 		return false;
11759b10ae86STejun Heo 
11769deb3431STejun Heo 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
11779deb3431STejun Heo 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
11789b10ae86STejun Heo 
11799deb3431STejun Heo 	return strcmp(buf, dmi->driver_data) < 0;
11809b10ae86STejun Heo }
11819b10ae86STejun Heo 
11825594639aSTejun Heo static bool ahci_broken_online(struct pci_dev *pdev)
11835594639aSTejun Heo {
11845594639aSTejun Heo #define ENCODE_BUSDEVFN(bus, slot, func)			\
11855594639aSTejun Heo 	(void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
11865594639aSTejun Heo 	static const struct dmi_system_id sysids[] = {
11875594639aSTejun Heo 		/*
11885594639aSTejun Heo 		 * There are several gigabyte boards which use
11895594639aSTejun Heo 		 * SIMG5723s configured as hardware RAID.  Certain
11905594639aSTejun Heo 		 * 5723 firmware revisions shipped there keep the link
11915594639aSTejun Heo 		 * online but fail to answer properly to SRST or
11925594639aSTejun Heo 		 * IDENTIFY when no device is attached downstream
11935594639aSTejun Heo 		 * causing libata to retry quite a few times leading
11945594639aSTejun Heo 		 * to excessive detection delay.
11955594639aSTejun Heo 		 *
11965594639aSTejun Heo 		 * As these firmwares respond to the second reset try
11975594639aSTejun Heo 		 * with invalid device signature, considering unknown
11985594639aSTejun Heo 		 * sig as offline works around the problem acceptably.
11995594639aSTejun Heo 		 */
12005594639aSTejun Heo 		{
12015594639aSTejun Heo 			.ident = "EP45-DQ6",
12025594639aSTejun Heo 			.matches = {
12035594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
12045594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
12055594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
12065594639aSTejun Heo 			},
12075594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
12085594639aSTejun Heo 		},
12095594639aSTejun Heo 		{
12105594639aSTejun Heo 			.ident = "EP45-DS5",
12115594639aSTejun Heo 			.matches = {
12125594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
12135594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
12145594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
12155594639aSTejun Heo 			},
12165594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
12175594639aSTejun Heo 		},
12185594639aSTejun Heo 		{ }	/* terminate list */
12195594639aSTejun Heo 	};
12205594639aSTejun Heo #undef ENCODE_BUSDEVFN
12215594639aSTejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
12225594639aSTejun Heo 	unsigned int val;
12235594639aSTejun Heo 
12245594639aSTejun Heo 	if (!dmi)
12255594639aSTejun Heo 		return false;
12265594639aSTejun Heo 
12275594639aSTejun Heo 	val = (unsigned long)dmi->driver_data;
12285594639aSTejun Heo 
12295594639aSTejun Heo 	return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
12305594639aSTejun Heo }
12315594639aSTejun Heo 
12320cf4a7d6SJacob Pan static bool ahci_broken_devslp(struct pci_dev *pdev)
12330cf4a7d6SJacob Pan {
12340cf4a7d6SJacob Pan 	/* device with broken DEVSLP but still showing SDS capability */
12350cf4a7d6SJacob Pan 	static const struct pci_device_id ids[] = {
12360cf4a7d6SJacob Pan 		{ PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */
12370cf4a7d6SJacob Pan 		{}
12380cf4a7d6SJacob Pan 	};
12390cf4a7d6SJacob Pan 
12400cf4a7d6SJacob Pan 	return pci_match_id(ids, pdev);
12410cf4a7d6SJacob Pan }
12420cf4a7d6SJacob Pan 
12438e513217SMarkus Trippelsdorf #ifdef CONFIG_ATA_ACPI
1244f80ae7e4STejun Heo static void ahci_gtf_filter_workaround(struct ata_host *host)
1245f80ae7e4STejun Heo {
1246f80ae7e4STejun Heo 	static const struct dmi_system_id sysids[] = {
1247f80ae7e4STejun Heo 		/*
1248f80ae7e4STejun Heo 		 * Aspire 3810T issues a bunch of SATA enable commands
1249f80ae7e4STejun Heo 		 * via _GTF including an invalid one and one which is
1250f80ae7e4STejun Heo 		 * rejected by the device.  Among the successful ones
1251f80ae7e4STejun Heo 		 * is FPDMA non-zero offset enable which when enabled
1252f80ae7e4STejun Heo 		 * only on the drive side leads to NCQ command
1253f80ae7e4STejun Heo 		 * failures.  Filter it out.
1254f80ae7e4STejun Heo 		 */
1255f80ae7e4STejun Heo 		{
1256f80ae7e4STejun Heo 			.ident = "Aspire 3810T",
1257f80ae7e4STejun Heo 			.matches = {
1258f80ae7e4STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
1259f80ae7e4STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
1260f80ae7e4STejun Heo 			},
1261f80ae7e4STejun Heo 			.driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
1262f80ae7e4STejun Heo 		},
1263f80ae7e4STejun Heo 		{ }
1264f80ae7e4STejun Heo 	};
1265f80ae7e4STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
1266f80ae7e4STejun Heo 	unsigned int filter;
1267f80ae7e4STejun Heo 	int i;
1268f80ae7e4STejun Heo 
1269f80ae7e4STejun Heo 	if (!dmi)
1270f80ae7e4STejun Heo 		return;
1271f80ae7e4STejun Heo 
1272f80ae7e4STejun Heo 	filter = (unsigned long)dmi->driver_data;
1273a44fec1fSJoe Perches 	dev_info(host->dev, "applying extra ACPI _GTF filter 0x%x for %s\n",
1274f80ae7e4STejun Heo 		 filter, dmi->ident);
1275f80ae7e4STejun Heo 
1276f80ae7e4STejun Heo 	for (i = 0; i < host->n_ports; i++) {
1277f80ae7e4STejun Heo 		struct ata_port *ap = host->ports[i];
1278f80ae7e4STejun Heo 		struct ata_link *link;
1279f80ae7e4STejun Heo 		struct ata_device *dev;
1280f80ae7e4STejun Heo 
1281f80ae7e4STejun Heo 		ata_for_each_link(link, ap, EDGE)
1282f80ae7e4STejun Heo 			ata_for_each_dev(dev, link, ALL)
1283f80ae7e4STejun Heo 				dev->gtf_filter |= filter;
1284f80ae7e4STejun Heo 	}
1285f80ae7e4STejun Heo }
12868e513217SMarkus Trippelsdorf #else
12878e513217SMarkus Trippelsdorf static inline void ahci_gtf_filter_workaround(struct ata_host *host)
12888e513217SMarkus Trippelsdorf {}
12898e513217SMarkus Trippelsdorf #endif
1290f80ae7e4STejun Heo 
1291e1ba8459SLinus Torvalds static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
12927b92b4f6SAlexander Gordeev 				struct ahci_host_priv *hpriv)
12935ca72c4fSAlexander Gordeev {
1294ccf8f53cSAlexander Gordeev 	int rc, nvec;
12955ca72c4fSAlexander Gordeev 
12967b92b4f6SAlexander Gordeev 	if (hpriv->flags & AHCI_HFLAG_NO_MSI)
12977b92b4f6SAlexander Gordeev 		goto intx;
12987b92b4f6SAlexander Gordeev 
1299fc061d96SAlexander Gordeev 	nvec = pci_msi_vec_count(pdev);
1300fc061d96SAlexander Gordeev 	if (nvec < 0)
13017b92b4f6SAlexander Gordeev 		goto intx;
13027b92b4f6SAlexander Gordeev 
13035ca72c4fSAlexander Gordeev 	/*
13047b92b4f6SAlexander Gordeev 	 * If number of MSIs is less than number of ports then Sharing Last
13057b92b4f6SAlexander Gordeev 	 * Message mode could be enforced. In this case assume that advantage
13067b92b4f6SAlexander Gordeev 	 * of multipe MSIs is negated and use single MSI mode instead.
13075ca72c4fSAlexander Gordeev 	 */
1308fc061d96SAlexander Gordeev 	if (nvec < n_ports)
13097b92b4f6SAlexander Gordeev 		goto single_msi;
13105ca72c4fSAlexander Gordeev 
1311ccf8f53cSAlexander Gordeev 	rc = pci_enable_msi_exact(pdev, nvec);
1312ccf8f53cSAlexander Gordeev 	if (rc == -ENOSPC)
1313fc40363bSAlexander Gordeev 		goto single_msi;
1314ccf8f53cSAlexander Gordeev 	else if (rc < 0)
1315fc061d96SAlexander Gordeev 		goto intx;
1316ab0f9e78SAlexander Gordeev 
1317ab0f9e78SAlexander Gordeev 	/* fallback to single MSI mode if the controller enforced MRSM mode */
1318ab0f9e78SAlexander Gordeev 	if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) {
1319ab0f9e78SAlexander Gordeev 		pci_disable_msi(pdev);
1320ab0f9e78SAlexander Gordeev 		printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n");
1321ab0f9e78SAlexander Gordeev 		goto single_msi;
1322ab0f9e78SAlexander Gordeev 	}
13237b92b4f6SAlexander Gordeev 
1324c3ebd6a9SAlexander Gordeev 	if (nvec > 1)
1325c3ebd6a9SAlexander Gordeev 		hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
1326c3ebd6a9SAlexander Gordeev 
13277b92b4f6SAlexander Gordeev 	return nvec;
13287b92b4f6SAlexander Gordeev 
13297b92b4f6SAlexander Gordeev single_msi:
1330fc061d96SAlexander Gordeev 	if (pci_enable_msi(pdev))
13317b92b4f6SAlexander Gordeev 		goto intx;
13327b92b4f6SAlexander Gordeev 	return 1;
13337b92b4f6SAlexander Gordeev 
13347b92b4f6SAlexander Gordeev intx:
13355ca72c4fSAlexander Gordeev 	pci_intx(pdev, 1);
13365ca72c4fSAlexander Gordeev 	return 0;
13375ca72c4fSAlexander Gordeev }
13385ca72c4fSAlexander Gordeev 
1339c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1340c6fd2807SJeff Garzik {
1341e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
1342e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
13434447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
134424dc5f33STejun Heo 	struct device *dev = &pdev->dev;
1345c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
13464447d351STejun Heo 	struct ata_host *host;
1347c3ebd6a9SAlexander Gordeev 	int n_ports, i, rc;
1348318893e1SAlessandro Rubini 	int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
1349c6fd2807SJeff Garzik 
1350c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1351c6fd2807SJeff Garzik 
1352b429dd59SJustin P. Mattock 	WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS);
1353c6fd2807SJeff Garzik 
135406296a1eSJoe Perches 	ata_print_version_once(&pdev->dev, DRV_VERSION);
1355c6fd2807SJeff Garzik 
13565b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
13575b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
13585b66c829SAlan Cox 	   AHCI stays out of the way */
13595b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
13605b66c829SAlan Cox 		return -ENODEV;
13615b66c829SAlan Cox 
1362cb85696dSJames Laird 	/* Apple BIOS on MCP89 prevents us using AHCI */
1363cb85696dSJames Laird 	if (is_mcp89_apple(pdev))
1364cb85696dSJames Laird 		ahci_mcp89_apple_enable(pdev);
1365c6353b45STejun Heo 
13667a02267eSMark Nelson 	/* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
13677a02267eSMark Nelson 	 * At the moment, we can only use the AHCI mode. Let the users know
13687a02267eSMark Nelson 	 * that for SAS drives they're out of luck.
13697a02267eSMark Nelson 	 */
13707a02267eSMark Nelson 	if (pdev->vendor == PCI_VENDOR_ID_PROMISE)
1371a44fec1fSJoe Perches 		dev_info(&pdev->dev,
1372a44fec1fSJoe Perches 			 "PDC42819 can only drive SATA devices with this driver\n");
13737a02267eSMark Nelson 
13747f9c9f8eSHugh Daschbach 	/* Both Connext and Enmotus devices use non-standard BARs */
1375318893e1SAlessandro Rubini 	if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
1376318893e1SAlessandro Rubini 		ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
13777f9c9f8eSHugh Daschbach 	else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
13787f9c9f8eSHugh Daschbach 		ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
1379318893e1SAlessandro Rubini 
1380e6b7e41cSChuansheng Liu 	/*
1381e6b7e41cSChuansheng Liu 	 * The JMicron chip 361/363 contains one SATA controller and one
1382e6b7e41cSChuansheng Liu 	 * PATA controller,for powering on these both controllers, we must
1383e6b7e41cSChuansheng Liu 	 * follow the sequence one by one, otherwise one of them can not be
1384e6b7e41cSChuansheng Liu 	 * powered on successfully, so here we disable the async suspend
1385e6b7e41cSChuansheng Liu 	 * method for these chips.
1386e6b7e41cSChuansheng Liu 	 */
1387e6b7e41cSChuansheng Liu 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON &&
1388e6b7e41cSChuansheng Liu 		(pdev->device == PCI_DEVICE_ID_JMICRON_JMB363 ||
1389e6b7e41cSChuansheng Liu 		pdev->device == PCI_DEVICE_ID_JMICRON_JMB361))
1390e6b7e41cSChuansheng Liu 		device_disable_async_suspend(&pdev->dev);
1391e6b7e41cSChuansheng Liu 
13924447d351STejun Heo 	/* acquire resources */
139324dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
1394c6fd2807SJeff Garzik 	if (rc)
1395c6fd2807SJeff Garzik 		return rc;
1396c6fd2807SJeff Garzik 
1397c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
1398c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
1399c4f7792cSTejun Heo 		u8 map;
1400c4f7792cSTejun Heo 
1401c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
1402c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
1403c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
1404c4f7792cSTejun Heo 		 */
1405c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
1406c4f7792cSTejun Heo 		if (map & 0x3) {
1407a44fec1fSJoe Perches 			dev_info(&pdev->dev,
1408a44fec1fSJoe Perches 				 "controller is in combined mode, can't enable AHCI mode\n");
1409c4f7792cSTejun Heo 			return -ENODEV;
1410c4f7792cSTejun Heo 		}
1411c4f7792cSTejun Heo 	}
1412c4f7792cSTejun Heo 
14136fec8871SPaul Bolle 	/* AHCI controllers often implement SFF compatible interface.
14146fec8871SPaul Bolle 	 * Grab all PCI BARs just in case.
14156fec8871SPaul Bolle 	 */
14166fec8871SPaul Bolle 	rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
14176fec8871SPaul Bolle 	if (rc == -EBUSY)
14186fec8871SPaul Bolle 		pcim_pin_device(pdev);
14196fec8871SPaul Bolle 	if (rc)
14206fec8871SPaul Bolle 		return rc;
14216fec8871SPaul Bolle 
142224dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
142324dc5f33STejun Heo 	if (!hpriv)
142424dc5f33STejun Heo 		return -ENOMEM;
1425417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
1426417a1a6dSTejun Heo 
1427e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
1428e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
1429e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
1430e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
1431e297d99eSTejun Heo 
1432e427fe04SShane Huang 	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
1433e427fe04SShane Huang 	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
1434e427fe04SShane Huang 		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
1435e427fe04SShane Huang 
14362fcad9d2STejun Heo 	/* only some SB600s can do 64bit DMA */
14372fcad9d2STejun Heo 	if (ahci_sb600_enable_64bit(pdev))
14382fcad9d2STejun Heo 		hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
143958a09b38SShane Huang 
1440318893e1SAlessandro Rubini 	hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
1441d8993349SAnton Vorontsov 
14420cf4a7d6SJacob Pan 	/* must set flag prior to save config in order to take effect */
14430cf4a7d6SJacob Pan 	if (ahci_broken_devslp(pdev))
14440cf4a7d6SJacob Pan 		hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
14450cf4a7d6SJacob Pan 
14464447d351STejun Heo 	/* save initial config */
1447394d6e53SAnton Vorontsov 	ahci_pci_save_initial_config(pdev, hpriv);
1448c6fd2807SJeff Garzik 
14494447d351STejun Heo 	/* prepare host */
1450453d3131SRobert Hancock 	if (hpriv->cap & HOST_CAP_NCQ) {
1451453d3131SRobert Hancock 		pi.flags |= ATA_FLAG_NCQ;
145283f2b963STejun Heo 		/*
145383f2b963STejun Heo 		 * Auto-activate optimization is supposed to be
145483f2b963STejun Heo 		 * supported on all AHCI controllers indicating NCQ
145583f2b963STejun Heo 		 * capability, but it seems to be broken on some
145683f2b963STejun Heo 		 * chipsets including NVIDIAs.
145783f2b963STejun Heo 		 */
145883f2b963STejun Heo 		if (!(hpriv->flags & AHCI_HFLAG_NO_FPDMA_AA))
1459453d3131SRobert Hancock 			pi.flags |= ATA_FLAG_FPDMA_AA;
146040fb59e7SMarc Carino 
146140fb59e7SMarc Carino 		/*
146240fb59e7SMarc Carino 		 * All AHCI controllers should be forward-compatible
146340fb59e7SMarc Carino 		 * with the new auxiliary field. This code should be
146440fb59e7SMarc Carino 		 * conditionalized if any buggy AHCI controllers are
146540fb59e7SMarc Carino 		 * encountered.
146640fb59e7SMarc Carino 		 */
146740fb59e7SMarc Carino 		pi.flags |= ATA_FLAG_FPDMA_AUX;
1468453d3131SRobert Hancock 	}
14694447d351STejun Heo 
14707d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
14717d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
14727d50b60bSTejun Heo 
14730cbb0e77SAnton Vorontsov 	ahci_set_em_messages(hpriv, &pi);
147418f7ba4cSKristen Carlson Accardi 
14751fd68434SRafael J. Wysocki 	if (ahci_broken_system_poweroff(pdev)) {
14761fd68434SRafael J. Wysocki 		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
14771fd68434SRafael J. Wysocki 		dev_info(&pdev->dev,
14781fd68434SRafael J. Wysocki 			"quirky BIOS, skipping spindown on poweroff\n");
14791fd68434SRafael J. Wysocki 	}
14801fd68434SRafael J. Wysocki 
14819b10ae86STejun Heo 	if (ahci_broken_suspend(pdev)) {
14829b10ae86STejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
1483a44fec1fSJoe Perches 		dev_warn(&pdev->dev,
14849b10ae86STejun Heo 			 "BIOS update required for suspend/resume\n");
14859b10ae86STejun Heo 	}
14869b10ae86STejun Heo 
14875594639aSTejun Heo 	if (ahci_broken_online(pdev)) {
14885594639aSTejun Heo 		hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
14895594639aSTejun Heo 		dev_info(&pdev->dev,
14905594639aSTejun Heo 			 "online status unreliable, applying workaround\n");
14915594639aSTejun Heo 	}
14925594639aSTejun Heo 
1493837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
1494837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
1495837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
1496837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
1497837f5f8fSTejun Heo 	 */
1498837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
1499837f5f8fSTejun Heo 
1500c3ebd6a9SAlexander Gordeev 	ahci_init_interrupts(pdev, n_ports, hpriv);
15017b92b4f6SAlexander Gordeev 
1502837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
15034447d351STejun Heo 	if (!host)
15044447d351STejun Heo 		return -ENOMEM;
15054447d351STejun Heo 	host->private_data = hpriv;
15064447d351STejun Heo 
1507f3d7f23fSArjan van de Ven 	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
1508886ad09fSArjan van de Ven 		host->flags |= ATA_HOST_PARALLEL_SCAN;
1509f3d7f23fSArjan van de Ven 	else
1510d2782d96SJingoo Han 		dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");
1511886ad09fSArjan van de Ven 
151218f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
151318f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
151418f7ba4cSKristen Carlson Accardi 
15154447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
15164447d351STejun Heo 		struct ata_port *ap = host->ports[i];
15174447d351STejun Heo 
1518318893e1SAlessandro Rubini 		ata_port_pbar_desc(ap, ahci_pci_bar, -1, "abar");
1519318893e1SAlessandro Rubini 		ata_port_pbar_desc(ap, ahci_pci_bar,
1520cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
1521cbcdd875STejun Heo 
152218f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
152318f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
1524008dbd61SHarry Zhang 			ap->em_message_type = hpriv->em_msg_type;
152518f7ba4cSKristen Carlson Accardi 
152618f7ba4cSKristen Carlson Accardi 
1527dab632e8SJeff Garzik 		/* disabled/not-implemented port */
1528350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
1529dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
15304447d351STejun Heo 	}
1531c6fd2807SJeff Garzik 
1532edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
1533edc93052STejun Heo 	ahci_p5wdh_workaround(host);
1534edc93052STejun Heo 
1535f80ae7e4STejun Heo 	/* apply gtf filter quirk */
1536f80ae7e4STejun Heo 	ahci_gtf_filter_workaround(host);
1537f80ae7e4STejun Heo 
1538c6fd2807SJeff Garzik 	/* initialize adapter */
15394447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
1540c6fd2807SJeff Garzik 	if (rc)
154124dc5f33STejun Heo 		return rc;
1542c6fd2807SJeff Garzik 
15433303040dSAnton Vorontsov 	rc = ahci_pci_reset_controller(host);
15444447d351STejun Heo 	if (rc)
15454447d351STejun Heo 		return rc;
1546c6fd2807SJeff Garzik 
1547781d6550SAnton Vorontsov 	ahci_pci_init_controller(host);
1548439fcaecSAnton Vorontsov 	ahci_pci_print_info(host);
1549c6fd2807SJeff Garzik 
15504447d351STejun Heo 	pci_set_master(pdev);
15515ca72c4fSAlexander Gordeev 
1552a6849b9fSAlexander Gordeev 	return ahci_host_activate(host, pdev->irq, &ahci_sht);
1553c6fd2807SJeff Garzik }
1554c6fd2807SJeff Garzik 
15552fc75da0SAxel Lin module_pci_driver(ahci_pci_driver);
1556c6fd2807SJeff Garzik 
1557c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
1558c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
1559c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
1560c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
1561c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
1562