xref: /openbmc/linux/drivers/ata/ahci.c (revision 25985edcedea6396277003854657b5f3cb31a628)
1c6fd2807SJeff Garzik /*
2c6fd2807SJeff Garzik  *  ahci.c - AHCI SATA support
3c6fd2807SJeff Garzik  *
4c6fd2807SJeff Garzik  *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
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/init.h>
39c6fd2807SJeff Garzik #include <linux/blkdev.h>
40c6fd2807SJeff Garzik #include <linux/delay.h>
41c6fd2807SJeff Garzik #include <linux/interrupt.h>
42c6fd2807SJeff Garzik #include <linux/dma-mapping.h>
43c6fd2807SJeff Garzik #include <linux/device.h>
44edc93052STejun Heo #include <linux/dmi.h>
455a0e3ad6STejun Heo #include <linux/gfp.h>
46c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
47c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
48c6fd2807SJeff Garzik #include <linux/libata.h>
49365cfa1eSAnton Vorontsov #include "ahci.h"
50c6fd2807SJeff Garzik 
51c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
527d50b60bSTejun Heo #define DRV_VERSION	"3.0"
53c6fd2807SJeff Garzik 
54c6fd2807SJeff Garzik enum {
55c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
56441577efSTejun Heo };
57c6fd2807SJeff Garzik 
58441577efSTejun Heo enum board_ids {
59441577efSTejun Heo 	/* board IDs by feature in alphabetical order */
60441577efSTejun Heo 	board_ahci,
61441577efSTejun Heo 	board_ahci_ign_iferr,
62441577efSTejun Heo 	board_ahci_nosntf,
635f173107STejun Heo 	board_ahci_yes_fbs,
64441577efSTejun Heo 
65441577efSTejun Heo 	/* board IDs for specific chipsets in alphabetical order */
66441577efSTejun Heo 	board_ahci_mcp65,
6783f2b963STejun Heo 	board_ahci_mcp77,
6883f2b963STejun Heo 	board_ahci_mcp89,
69441577efSTejun Heo 	board_ahci_mv,
70441577efSTejun Heo 	board_ahci_sb600,
71441577efSTejun Heo 	board_ahci_sb700,	/* for SB700 and SB800 */
72441577efSTejun Heo 	board_ahci_vt8251,
73441577efSTejun Heo 
74441577efSTejun Heo 	/* aliases */
75441577efSTejun Heo 	board_ahci_mcp_linux	= board_ahci_mcp65,
76441577efSTejun Heo 	board_ahci_mcp67	= board_ahci_mcp65,
77441577efSTejun Heo 	board_ahci_mcp73	= board_ahci_mcp65,
7883f2b963STejun Heo 	board_ahci_mcp79	= board_ahci_mcp77,
79c6fd2807SJeff Garzik };
80c6fd2807SJeff Garzik 
81c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
82bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
83bd17243aSShane Huang 			  unsigned long deadline);
84a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
85a1efdabaSTejun Heo 				 unsigned long deadline);
86a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
87a1efdabaSTejun Heo 				unsigned long deadline);
88438ac6d5STejun Heo #ifdef CONFIG_PM
89c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
90c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
91438ac6d5STejun Heo #endif
92c6fd2807SJeff Garzik 
93fad16e7aSTejun Heo static struct scsi_host_template ahci_sht = {
94fad16e7aSTejun Heo 	AHCI_SHT("ahci"),
95fad16e7aSTejun Heo };
96fad16e7aSTejun Heo 
97029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
98029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
99a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
100ad616ffbSTejun Heo };
101ad616ffbSTejun Heo 
102029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
103029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
104a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
105edc93052STejun Heo };
106edc93052STejun Heo 
107bd17243aSShane Huang static struct ata_port_operations ahci_sb600_ops = {
108bd17243aSShane Huang 	.inherits		= &ahci_ops,
109bd17243aSShane Huang 	.softreset		= ahci_sb600_softreset,
110bd17243aSShane Huang 	.pmp_softreset		= ahci_sb600_softreset,
111bd17243aSShane Huang };
112bd17243aSShane Huang 
113417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
114417a1a6dSTejun Heo 
115c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
116441577efSTejun Heo 	/* by features */
1174da646b7SJeff Garzik 	[board_ahci] =
118c6fd2807SJeff Garzik 	{
1191188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
12014bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
121469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
122c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
123c6fd2807SJeff Garzik 	},
1244da646b7SJeff Garzik 	[board_ahci_ign_iferr] =
12541669553STejun Heo 	{
126417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
127417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
12814bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
129469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
13041669553STejun Heo 		.port_ops	= &ahci_ops,
13141669553STejun Heo 	},
132441577efSTejun Heo 	[board_ahci_nosntf] =
133441577efSTejun Heo 	{
134441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_SNTF),
135441577efSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
136441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
137441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
138441577efSTejun Heo 		.port_ops	= &ahci_ops,
139441577efSTejun Heo 	},
1405f173107STejun Heo 	[board_ahci_yes_fbs] =
1415f173107STejun Heo 	{
1425f173107STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_FBS),
1435f173107STejun Heo 		.flags		= AHCI_FLAG_COMMON,
1445f173107STejun Heo 		.pio_mask	= ATA_PIO4,
1455f173107STejun Heo 		.udma_mask	= ATA_UDMA6,
1465f173107STejun Heo 		.port_ops	= &ahci_ops,
1475f173107STejun Heo 	},
148441577efSTejun Heo 	/* by chipsets */
149441577efSTejun Heo 	[board_ahci_mcp65] =
150441577efSTejun Heo 	{
15183f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
15283f2b963STejun Heo 				 AHCI_HFLAG_YES_NCQ),
15383f2b963STejun Heo 		.flags		= AHCI_FLAG_COMMON,
15483f2b963STejun Heo 		.pio_mask	= ATA_PIO4,
15583f2b963STejun Heo 		.udma_mask	= ATA_UDMA6,
15683f2b963STejun Heo 		.port_ops	= &ahci_ops,
15783f2b963STejun Heo 	},
15883f2b963STejun Heo 	[board_ahci_mcp77] =
15983f2b963STejun Heo 	{
16083f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP),
16183f2b963STejun Heo 		.flags		= AHCI_FLAG_COMMON,
16283f2b963STejun Heo 		.pio_mask	= ATA_PIO4,
16383f2b963STejun Heo 		.udma_mask	= ATA_UDMA6,
16483f2b963STejun Heo 		.port_ops	= &ahci_ops,
16583f2b963STejun Heo 	},
16683f2b963STejun Heo 	[board_ahci_mcp89] =
16783f2b963STejun Heo 	{
16883f2b963STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA),
169441577efSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
170441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
171441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
172441577efSTejun Heo 		.port_ops	= &ahci_ops,
173441577efSTejun Heo 	},
174441577efSTejun Heo 	[board_ahci_mv] =
175441577efSTejun Heo 	{
176441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
177441577efSTejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
1789cbe056fSSergei Shtylyov 		.flags		= ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
179441577efSTejun Heo 		.pio_mask	= ATA_PIO4,
180441577efSTejun Heo 		.udma_mask	= ATA_UDMA6,
181441577efSTejun Heo 		.port_ops	= &ahci_ops,
182441577efSTejun Heo 	},
1834da646b7SJeff Garzik 	[board_ahci_sb600] =
18455a61604SConke Hu 	{
185417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
1862fcad9d2STejun Heo 				 AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
1872fcad9d2STejun Heo 				 AHCI_HFLAG_32BIT_ONLY),
188417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
18914bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
190469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
191bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
19255a61604SConke Hu 	},
1934da646b7SJeff Garzik 	[board_ahci_sb700] =	/* for SB700 and SB800 */
194e39fc8c9SShane Huang 	{
195bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
196e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
19714bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
198e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
199bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
200e39fc8c9SShane Huang 	},
201441577efSTejun Heo 	[board_ahci_vt8251] =
202e297d99eSTejun Heo 	{
203441577efSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
204e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
20514bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
206e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
207441577efSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
2081b677afdSShaohua Li 	},
209c6fd2807SJeff Garzik };
210c6fd2807SJeff Garzik 
211c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
212c6fd2807SJeff Garzik 	/* Intel */
21354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
21454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
21554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
21654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
21754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
21882490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
21954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
22054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
22154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
22254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
2237a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
2241b677afdSShaohua Li 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8 */
2257a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
2267a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
2277a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
2287a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
2297a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
2307a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
2317a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
2327a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
2337a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
2347a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
2357a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
2367a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
2377a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
2387a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
2397a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
240d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
241d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
24216ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
243b2dde6afSMark Goodwin 	{ PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
24416ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
245c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
246c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
247adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
2488e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
249c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
250adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
2518e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
252c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
2535623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
2545623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
2555623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
2565623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
2575623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
2585623cab8SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
259992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
260992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */
261992b3fb9SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
26264a3903dSSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
263a4a461a6SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
264c6fd2807SJeff Garzik 
265e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
266e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
267e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
268c6fd2807SJeff Garzik 
269c6fd2807SJeff Garzik 	/* ATI */
270c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
271e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
272e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
273e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
274e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
275e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
276e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
277c6fd2807SJeff Garzik 
278e2dd90b1SShane Huang 	/* AMD */
2795deab536SShane Huang 	{ PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
280e2dd90b1SShane Huang 	/* AMD is using RAID class only for ahci controllers */
281e2dd90b1SShane Huang 	{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
282e2dd90b1SShane Huang 	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
283e2dd90b1SShane Huang 
284c6fd2807SJeff Garzik 	/* VIA */
28554bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
286bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
287c6fd2807SJeff Garzik 
288c6fd2807SJeff Garzik 	/* NVIDIA */
289e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
290e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
291e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
292e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
293e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
294e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
295e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
296e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
297441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_mcp67 },	/* MCP67 */
298441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_mcp67 },	/* MCP67 */
299441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_mcp67 },	/* MCP67 */
300441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_mcp67 },	/* MCP67 */
301441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_mcp67 },	/* MCP67 */
302441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_mcp67 },	/* MCP67 */
303441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_mcp67 },	/* MCP67 */
304441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_mcp67 },	/* MCP67 */
305441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_mcp67 },	/* MCP67 */
306441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_mcp67 },	/* MCP67 */
307441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_mcp67 },	/* MCP67 */
308441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_mcp67 },	/* MCP67 */
309441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_mcp_linux },	/* Linux ID */
310441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0581), board_ahci_mcp_linux },	/* Linux ID */
311441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0582), board_ahci_mcp_linux },	/* Linux ID */
312441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0583), board_ahci_mcp_linux },	/* Linux ID */
313441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0584), board_ahci_mcp_linux },	/* Linux ID */
314441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0585), board_ahci_mcp_linux },	/* Linux ID */
315441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0586), board_ahci_mcp_linux },	/* Linux ID */
316441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0587), board_ahci_mcp_linux },	/* Linux ID */
317441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0588), board_ahci_mcp_linux },	/* Linux ID */
318441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0589), board_ahci_mcp_linux },	/* Linux ID */
319441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058a), board_ahci_mcp_linux },	/* Linux ID */
320441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058b), board_ahci_mcp_linux },	/* Linux ID */
321441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058c), board_ahci_mcp_linux },	/* Linux ID */
322441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058d), board_ahci_mcp_linux },	/* Linux ID */
323441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058e), board_ahci_mcp_linux },	/* Linux ID */
324441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x058f), board_ahci_mcp_linux },	/* Linux ID */
325441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_mcp73 },	/* MCP73 */
326441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_mcp73 },	/* MCP73 */
327441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_mcp73 },	/* MCP73 */
328441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_mcp73 },	/* MCP73 */
329441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_mcp73 },	/* MCP73 */
330441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_mcp73 },	/* MCP73 */
331441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_mcp73 },	/* MCP73 */
332441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_mcp73 },	/* MCP73 */
333441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_mcp73 },	/* MCP73 */
334441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_mcp73 },	/* MCP73 */
335441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_mcp73 },	/* MCP73 */
336441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_mcp73 },	/* MCP73 */
337441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci_mcp77 },	/* MCP77 */
338441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci_mcp77 },	/* MCP77 */
339441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci_mcp77 },	/* MCP77 */
340441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci_mcp77 },	/* MCP77 */
341441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci_mcp77 },	/* MCP77 */
342441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci_mcp77 },	/* MCP77 */
343441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci_mcp77 },	/* MCP77 */
344441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci_mcp77 },	/* MCP77 */
345441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci_mcp77 },	/* MCP77 */
346441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci_mcp77 },	/* MCP77 */
347441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci_mcp77 },	/* MCP77 */
348441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci_mcp77 },	/* MCP77 */
349441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci_mcp79 },	/* MCP79 */
350441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci_mcp79 },	/* MCP79 */
351441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci_mcp79 },	/* MCP79 */
352441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci_mcp79 },	/* MCP79 */
353441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci_mcp79 },	/* MCP79 */
354441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci_mcp79 },	/* MCP79 */
355441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci_mcp79 },	/* MCP79 */
356441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci_mcp79 },	/* MCP79 */
357441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci_mcp79 },	/* MCP79 */
358441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci_mcp79 },	/* MCP79 */
359441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci_mcp79 },	/* MCP79 */
360441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci_mcp79 },	/* MCP79 */
361441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci_mcp89 },	/* MCP89 */
362441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci_mcp89 },	/* MCP89 */
363441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci_mcp89 },	/* MCP89 */
364441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci_mcp89 },	/* MCP89 */
365441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci_mcp89 },	/* MCP89 */
366441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci_mcp89 },	/* MCP89 */
367441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci_mcp89 },	/* MCP89 */
368441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci_mcp89 },	/* MCP89 */
369441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci_mcp89 },	/* MCP89 */
370441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci_mcp89 },	/* MCP89 */
371441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci_mcp89 },	/* MCP89 */
372441577efSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci_mcp89 },	/* MCP89 */
373c6fd2807SJeff Garzik 
374c6fd2807SJeff Garzik 	/* SiS */
37520e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
37620e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
37720e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
378c6fd2807SJeff Garzik 
379cd70c266SJeff Garzik 	/* Marvell */
380cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
381c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
3825f173107STejun Heo 	{ PCI_DEVICE(0x1b4b, 0x9123),
38310aca06cSAnssi Hannula 	  .class = PCI_CLASS_STORAGE_SATA_AHCI,
38410aca06cSAnssi Hannula 	  .class_mask = 0xffffff,
3855f173107STejun Heo 	  .driver_data = board_ahci_yes_fbs },			/* 88se9128 */
386467b41c6SPer Jessen 	{ PCI_DEVICE(0x1b4b, 0x9125),
387467b41c6SPer Jessen 	  .driver_data = board_ahci_yes_fbs },			/* 88se9125 */
38850be5e36STejun Heo 	{ PCI_DEVICE(0x1b4b, 0x91a3),
38950be5e36STejun Heo 	  .driver_data = board_ahci_yes_fbs },
390cd70c266SJeff Garzik 
391c77a036bSMark Nelson 	/* Promise */
392c77a036bSMark Nelson 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
393c77a036bSMark Nelson 
394415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
395415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
396c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
397415ae2b5SJeff Garzik 
398c6fd2807SJeff Garzik 	{ }	/* terminate list */
399c6fd2807SJeff Garzik };
400c6fd2807SJeff Garzik 
401c6fd2807SJeff Garzik 
402c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
403c6fd2807SJeff Garzik 	.name			= DRV_NAME,
404c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
405c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
40624dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
407438ac6d5STejun Heo #ifdef CONFIG_PM
408c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
409c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
410438ac6d5STejun Heo #endif
411c6fd2807SJeff Garzik };
412c6fd2807SJeff Garzik 
4135b66c829SAlan Cox #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
4145b66c829SAlan Cox static int marvell_enable;
4155b66c829SAlan Cox #else
4165b66c829SAlan Cox static int marvell_enable = 1;
4175b66c829SAlan Cox #endif
4185b66c829SAlan Cox module_param(marvell_enable, int, 0644);
4195b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
4205b66c829SAlan Cox 
4215b66c829SAlan Cox 
422394d6e53SAnton Vorontsov static void ahci_pci_save_initial_config(struct pci_dev *pdev,
423394d6e53SAnton Vorontsov 					 struct ahci_host_priv *hpriv)
424394d6e53SAnton Vorontsov {
425394d6e53SAnton Vorontsov 	unsigned int force_port_map = 0;
426394d6e53SAnton Vorontsov 	unsigned int mask_port_map = 0;
427394d6e53SAnton Vorontsov 
428394d6e53SAnton Vorontsov 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
429394d6e53SAnton Vorontsov 		dev_info(&pdev->dev, "JMB361 has only one port\n");
430394d6e53SAnton Vorontsov 		force_port_map = 1;
431394d6e53SAnton Vorontsov 	}
432394d6e53SAnton Vorontsov 
433394d6e53SAnton Vorontsov 	/*
434394d6e53SAnton Vorontsov 	 * Temporary Marvell 6145 hack: PATA port presence
435394d6e53SAnton Vorontsov 	 * is asserted through the standard AHCI port
436394d6e53SAnton Vorontsov 	 * presence register, as bit 4 (counting from 0)
437394d6e53SAnton Vorontsov 	 */
438394d6e53SAnton Vorontsov 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
439394d6e53SAnton Vorontsov 		if (pdev->device == 0x6121)
440394d6e53SAnton Vorontsov 			mask_port_map = 0x3;
441394d6e53SAnton Vorontsov 		else
442394d6e53SAnton Vorontsov 			mask_port_map = 0xf;
443394d6e53SAnton Vorontsov 		dev_info(&pdev->dev,
444394d6e53SAnton Vorontsov 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
445394d6e53SAnton Vorontsov 	}
446394d6e53SAnton Vorontsov 
4471d513358SAnton Vorontsov 	ahci_save_initial_config(&pdev->dev, hpriv, force_port_map,
4481d513358SAnton Vorontsov 				 mask_port_map);
449394d6e53SAnton Vorontsov }
450394d6e53SAnton Vorontsov 
4513303040dSAnton Vorontsov static int ahci_pci_reset_controller(struct ata_host *host)
4523303040dSAnton Vorontsov {
4533303040dSAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
4543303040dSAnton Vorontsov 
4553303040dSAnton Vorontsov 	ahci_reset_controller(host);
4563303040dSAnton Vorontsov 
457c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
4583303040dSAnton Vorontsov 		struct ahci_host_priv *hpriv = host->private_data;
459c6fd2807SJeff Garzik 		u16 tmp16;
460c6fd2807SJeff Garzik 
461c6fd2807SJeff Garzik 		/* configure PCS */
462c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
46349f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
46449f29090STejun Heo 			tmp16 |= hpriv->port_map;
465c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
466c6fd2807SJeff Garzik 		}
46749f29090STejun Heo 	}
468c6fd2807SJeff Garzik 
469c6fd2807SJeff Garzik 	return 0;
470c6fd2807SJeff Garzik }
471c6fd2807SJeff Garzik 
472781d6550SAnton Vorontsov static void ahci_pci_init_controller(struct ata_host *host)
473781d6550SAnton Vorontsov {
474781d6550SAnton Vorontsov 	struct ahci_host_priv *hpriv = host->private_data;
475781d6550SAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
476781d6550SAnton Vorontsov 	void __iomem *port_mmio;
477781d6550SAnton Vorontsov 	u32 tmp;
478c40e7cb8SJose Alberto Reguero 	int mv;
4792bcd866bSJeff Garzik 
480417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
481c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
482c40e7cb8SJose Alberto Reguero 			mv = 2;
483c40e7cb8SJose Alberto Reguero 		else
484c40e7cb8SJose Alberto Reguero 			mv = 4;
485c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
486cd70c266SJeff Garzik 
487cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
488cd70c266SJeff Garzik 
489cd70c266SJeff Garzik 		/* clear port IRQ */
490cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
491cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
492cd70c266SJeff Garzik 		if (tmp)
493cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
494cd70c266SJeff Garzik 	}
495cd70c266SJeff Garzik 
496781d6550SAnton Vorontsov 	ahci_init_controller(host);
497c6fd2807SJeff Garzik }
498c6fd2807SJeff Garzik 
499bd17243aSShane Huang static int ahci_sb600_check_ready(struct ata_link *link)
500bd17243aSShane Huang {
501bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
502bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
503bd17243aSShane Huang 	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
504bd17243aSShane Huang 
505bd17243aSShane Huang 	/*
506bd17243aSShane Huang 	 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
507bd17243aSShane Huang 	 * which can save timeout delay.
508bd17243aSShane Huang 	 */
509bd17243aSShane Huang 	if (irq_status & PORT_IRQ_BAD_PMP)
510bd17243aSShane Huang 		return -EIO;
511bd17243aSShane Huang 
512bd17243aSShane Huang 	return ata_check_ready(status);
513bd17243aSShane Huang }
514bd17243aSShane Huang 
515bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
516bd17243aSShane Huang 				unsigned long deadline)
517bd17243aSShane Huang {
518bd17243aSShane Huang 	struct ata_port *ap = link->ap;
519bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(ap);
520bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
521bd17243aSShane Huang 	int rc;
522bd17243aSShane Huang 	u32 irq_sts;
523bd17243aSShane Huang 
524bd17243aSShane Huang 	DPRINTK("ENTER\n");
525bd17243aSShane Huang 
526bd17243aSShane Huang 	rc = ahci_do_softreset(link, class, pmp, deadline,
527bd17243aSShane Huang 			       ahci_sb600_check_ready);
528bd17243aSShane Huang 
529bd17243aSShane Huang 	/*
530bd17243aSShane Huang 	 * Soft reset fails on some ATI chips with IPMS set when PMP
531bd17243aSShane Huang 	 * is enabled but SATA HDD/ODD is connected to SATA port,
532bd17243aSShane Huang 	 * do soft reset again to port 0.
533bd17243aSShane Huang 	 */
534bd17243aSShane Huang 	if (rc == -EIO) {
535bd17243aSShane Huang 		irq_sts = readl(port_mmio + PORT_IRQ_STAT);
536bd17243aSShane Huang 		if (irq_sts & PORT_IRQ_BAD_PMP) {
537bd17243aSShane Huang 			ata_link_printk(link, KERN_WARNING,
538b6931c1fSShane Huang 					"applying SB600 PMP SRST workaround "
539b6931c1fSShane Huang 					"and retrying\n");
540bd17243aSShane Huang 			rc = ahci_do_softreset(link, class, 0, deadline,
541bd17243aSShane Huang 					       ahci_check_ready);
542bd17243aSShane Huang 		}
543bd17243aSShane Huang 	}
544bd17243aSShane Huang 
545bd17243aSShane Huang 	return rc;
546bd17243aSShane Huang }
547bd17243aSShane Huang 
548cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
549d4b2bab4STejun Heo 				 unsigned long deadline)
550ad616ffbSTejun Heo {
551cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
5529dadd45bSTejun Heo 	bool online;
553ad616ffbSTejun Heo 	int rc;
554ad616ffbSTejun Heo 
555ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
556ad616ffbSTejun Heo 
5574447d351STejun Heo 	ahci_stop_engine(ap);
558ad616ffbSTejun Heo 
559cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
5609dadd45bSTejun Heo 				 deadline, &online, NULL);
561ad616ffbSTejun Heo 
5624447d351STejun Heo 	ahci_start_engine(ap);
563ad616ffbSTejun Heo 
564ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
565ad616ffbSTejun Heo 
566ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
567ad616ffbSTejun Heo 	 * request follow-up softreset.
568ad616ffbSTejun Heo 	 */
5699dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
570ad616ffbSTejun Heo }
571ad616ffbSTejun Heo 
572edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
573edc93052STejun Heo 				unsigned long deadline)
574edc93052STejun Heo {
575edc93052STejun Heo 	struct ata_port *ap = link->ap;
576edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
577edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
578edc93052STejun Heo 	struct ata_taskfile tf;
5799dadd45bSTejun Heo 	bool online;
580edc93052STejun Heo 	int rc;
581edc93052STejun Heo 
582edc93052STejun Heo 	ahci_stop_engine(ap);
583edc93052STejun Heo 
584edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
585edc93052STejun Heo 	ata_tf_init(link->device, &tf);
586edc93052STejun Heo 	tf.command = 0x80;
587edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
588edc93052STejun Heo 
589edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
5909dadd45bSTejun Heo 				 deadline, &online, NULL);
591edc93052STejun Heo 
592edc93052STejun Heo 	ahci_start_engine(ap);
593edc93052STejun Heo 
594edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
595edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
596edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
597edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
598edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
599edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
600edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
601edc93052STejun Heo 	 *
602edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
603edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
604edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
605edc93052STejun Heo 	 * suffice while making probing snappish enough.
606edc93052STejun Heo 	 */
6079dadd45bSTejun Heo 	if (online) {
6089dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
6099dadd45bSTejun Heo 					  ahci_check_ready);
610edc93052STejun Heo 		if (rc)
61178d5ae39SShane Huang 			ahci_kick_engine(ap);
6129dadd45bSTejun Heo 	}
6139dadd45bSTejun Heo 	return rc;
614edc93052STejun Heo }
615edc93052STejun Heo 
616438ac6d5STejun Heo #ifdef CONFIG_PM
617c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
618c6fd2807SJeff Garzik {
619cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
6209b10ae86STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
621d8993349SAnton Vorontsov 	void __iomem *mmio = hpriv->mmio;
622c6fd2807SJeff Garzik 	u32 ctl;
623c6fd2807SJeff Garzik 
6249b10ae86STejun Heo 	if (mesg.event & PM_EVENT_SUSPEND &&
6259b10ae86STejun Heo 	    hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
6269b10ae86STejun Heo 		dev_printk(KERN_ERR, &pdev->dev,
6279b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
6289b10ae86STejun Heo 		return -EIO;
6299b10ae86STejun Heo 	}
6309b10ae86STejun Heo 
6313a2d5b70SRafael J. Wysocki 	if (mesg.event & PM_EVENT_SLEEP) {
632c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
633c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
634c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
635c6fd2807SJeff Garzik 		 */
636c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
637c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
638c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
639c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
640c6fd2807SJeff Garzik 	}
641c6fd2807SJeff Garzik 
642c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
643c6fd2807SJeff Garzik }
644c6fd2807SJeff Garzik 
645c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
646c6fd2807SJeff Garzik {
647cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
648c6fd2807SJeff Garzik 	int rc;
649c6fd2807SJeff Garzik 
650553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
651553c4aa6STejun Heo 	if (rc)
652553c4aa6STejun Heo 		return rc;
653c6fd2807SJeff Garzik 
654c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
6553303040dSAnton Vorontsov 		rc = ahci_pci_reset_controller(host);
656c6fd2807SJeff Garzik 		if (rc)
657c6fd2807SJeff Garzik 			return rc;
658c6fd2807SJeff Garzik 
659781d6550SAnton Vorontsov 		ahci_pci_init_controller(host);
660c6fd2807SJeff Garzik 	}
661c6fd2807SJeff Garzik 
662cca3974eSJeff Garzik 	ata_host_resume(host);
663c6fd2807SJeff Garzik 
664c6fd2807SJeff Garzik 	return 0;
665c6fd2807SJeff Garzik }
666438ac6d5STejun Heo #endif
667c6fd2807SJeff Garzik 
6684447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
669c6fd2807SJeff Garzik {
670c6fd2807SJeff Garzik 	int rc;
671c6fd2807SJeff Garzik 
672c6fd2807SJeff Garzik 	if (using_dac &&
6736a35528aSYang Hongyang 	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
6746a35528aSYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
675c6fd2807SJeff Garzik 		if (rc) {
676284901a9SYang Hongyang 			rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
677c6fd2807SJeff Garzik 			if (rc) {
678c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
679c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
680c6fd2807SJeff Garzik 				return rc;
681c6fd2807SJeff Garzik 			}
682c6fd2807SJeff Garzik 		}
683c6fd2807SJeff Garzik 	} else {
684284901a9SYang Hongyang 		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
685c6fd2807SJeff Garzik 		if (rc) {
686c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
687c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
688c6fd2807SJeff Garzik 			return rc;
689c6fd2807SJeff Garzik 		}
690284901a9SYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
691c6fd2807SJeff Garzik 		if (rc) {
692c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
693c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
694c6fd2807SJeff Garzik 			return rc;
695c6fd2807SJeff Garzik 		}
696c6fd2807SJeff Garzik 	}
697c6fd2807SJeff Garzik 	return 0;
698c6fd2807SJeff Garzik }
699c6fd2807SJeff Garzik 
700439fcaecSAnton Vorontsov static void ahci_pci_print_info(struct ata_host *host)
701439fcaecSAnton Vorontsov {
702439fcaecSAnton Vorontsov 	struct pci_dev *pdev = to_pci_dev(host->dev);
703439fcaecSAnton Vorontsov 	u16 cc;
704439fcaecSAnton Vorontsov 	const char *scc_s;
705439fcaecSAnton Vorontsov 
706439fcaecSAnton Vorontsov 	pci_read_config_word(pdev, 0x0a, &cc);
707439fcaecSAnton Vorontsov 	if (cc == PCI_CLASS_STORAGE_IDE)
708439fcaecSAnton Vorontsov 		scc_s = "IDE";
709439fcaecSAnton Vorontsov 	else if (cc == PCI_CLASS_STORAGE_SATA)
710439fcaecSAnton Vorontsov 		scc_s = "SATA";
711439fcaecSAnton Vorontsov 	else if (cc == PCI_CLASS_STORAGE_RAID)
712439fcaecSAnton Vorontsov 		scc_s = "RAID";
713439fcaecSAnton Vorontsov 	else
714439fcaecSAnton Vorontsov 		scc_s = "unknown";
715439fcaecSAnton Vorontsov 
716439fcaecSAnton Vorontsov 	ahci_print_info(host, scc_s);
717439fcaecSAnton Vorontsov }
718439fcaecSAnton Vorontsov 
719edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
720edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
721edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
722edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
723edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
724edc93052STejun Heo  * other configuration).
725edc93052STejun Heo  *
726edc93052STejun Heo  * When there's no device attached to the first downstream port of the
727edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
728edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
729edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
730edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
731edc93052STejun Heo  *
732edc93052STejun Heo  * The following function works around the problem by always using
733edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
734edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
735edc93052STejun Heo  * assumed without follow-up softreset.
736edc93052STejun Heo  */
737edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
738edc93052STejun Heo {
739edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
740edc93052STejun Heo 		{
741edc93052STejun Heo 			.ident = "P5W DH Deluxe",
742edc93052STejun Heo 			.matches = {
743edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
744edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
745edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
746edc93052STejun Heo 			},
747edc93052STejun Heo 		},
748edc93052STejun Heo 		{ }
749edc93052STejun Heo 	};
750edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
751edc93052STejun Heo 
752edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
753edc93052STejun Heo 	    dmi_check_system(sysids)) {
754edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
755edc93052STejun Heo 
756edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
757edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
758edc93052STejun Heo 
759edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
760edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
761edc93052STejun Heo 	}
762edc93052STejun Heo }
763edc93052STejun Heo 
7642fcad9d2STejun Heo /* only some SB600 ahci controllers can do 64bit DMA */
7652fcad9d2STejun Heo static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
76658a09b38SShane Huang {
76758a09b38SShane Huang 	static const struct dmi_system_id sysids[] = {
76803d783bfSTejun Heo 		/*
76903d783bfSTejun Heo 		 * The oldest version known to be broken is 0901 and
77003d783bfSTejun Heo 		 * working is 1501 which was released on 2007-10-26.
7712fcad9d2STejun Heo 		 * Enable 64bit DMA on 1501 and anything newer.
7722fcad9d2STejun Heo 		 *
77303d783bfSTejun Heo 		 * Please read bko#9412 for more info.
77403d783bfSTejun Heo 		 */
77558a09b38SShane Huang 		{
77658a09b38SShane Huang 			.ident = "ASUS M2A-VM",
77758a09b38SShane Huang 			.matches = {
77858a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_VENDOR,
77958a09b38SShane Huang 					  "ASUSTeK Computer INC."),
78058a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
78158a09b38SShane Huang 			},
78203d783bfSTejun Heo 			.driver_data = "20071026",	/* yyyymmdd */
78358a09b38SShane Huang 		},
784e65cc194SMark Nelson 		/*
785e65cc194SMark Nelson 		 * All BIOS versions for the MSI K9A2 Platinum (MS-7376)
786e65cc194SMark Nelson 		 * support 64bit DMA.
787e65cc194SMark Nelson 		 *
788e65cc194SMark Nelson 		 * BIOS versions earlier than 1.5 had the Manufacturer DMI
789e65cc194SMark Nelson 		 * fields as "MICRO-STAR INTERANTIONAL CO.,LTD".
790e65cc194SMark Nelson 		 * This spelling mistake was fixed in BIOS version 1.5, so
791e65cc194SMark Nelson 		 * 1.5 and later have the Manufacturer as
792e65cc194SMark Nelson 		 * "MICRO-STAR INTERNATIONAL CO.,LTD".
793e65cc194SMark Nelson 		 * So try to match on DMI_BOARD_VENDOR of "MICRO-STAR INTER".
794e65cc194SMark Nelson 		 *
795e65cc194SMark Nelson 		 * BIOS versions earlier than 1.9 had a Board Product Name
796e65cc194SMark Nelson 		 * DMI field of "MS-7376". This was changed to be
797e65cc194SMark Nelson 		 * "K9A2 Platinum (MS-7376)" in version 1.9, but we can still
798e65cc194SMark Nelson 		 * match on DMI_BOARD_NAME of "MS-7376".
799e65cc194SMark Nelson 		 */
800e65cc194SMark Nelson 		{
801e65cc194SMark Nelson 			.ident = "MSI K9A2 Platinum",
802e65cc194SMark Nelson 			.matches = {
803e65cc194SMark Nelson 				DMI_MATCH(DMI_BOARD_VENDOR,
804e65cc194SMark Nelson 					  "MICRO-STAR INTER"),
805e65cc194SMark Nelson 				DMI_MATCH(DMI_BOARD_NAME, "MS-7376"),
806e65cc194SMark Nelson 			},
807e65cc194SMark Nelson 		},
80858a09b38SShane Huang 		{ }
80958a09b38SShane Huang 	};
81003d783bfSTejun Heo 	const struct dmi_system_id *match;
8112fcad9d2STejun Heo 	int year, month, date;
8122fcad9d2STejun Heo 	char buf[9];
81358a09b38SShane Huang 
81403d783bfSTejun Heo 	match = dmi_first_match(sysids);
81558a09b38SShane Huang 	if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
81603d783bfSTejun Heo 	    !match)
81758a09b38SShane Huang 		return false;
81858a09b38SShane Huang 
819e65cc194SMark Nelson 	if (!match->driver_data)
820e65cc194SMark Nelson 		goto enable_64bit;
821e65cc194SMark Nelson 
82203d783bfSTejun Heo 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
82303d783bfSTejun Heo 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
82403d783bfSTejun Heo 
825e65cc194SMark Nelson 	if (strcmp(buf, match->driver_data) >= 0)
826e65cc194SMark Nelson 		goto enable_64bit;
827e65cc194SMark Nelson 	else {
82803d783bfSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, "
82903d783bfSTejun Heo 			   "forcing 32bit DMA, update BIOS\n", match->ident);
8302fcad9d2STejun Heo 		return false;
8312fcad9d2STejun Heo 	}
832e65cc194SMark Nelson 
833e65cc194SMark Nelson enable_64bit:
834e65cc194SMark Nelson 	dev_printk(KERN_WARNING, &pdev->dev, "%s: enabling 64bit DMA\n",
835e65cc194SMark Nelson 		   match->ident);
836e65cc194SMark Nelson 	return true;
83758a09b38SShane Huang }
83858a09b38SShane Huang 
8391fd68434SRafael J. Wysocki static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
8401fd68434SRafael J. Wysocki {
8411fd68434SRafael J. Wysocki 	static const struct dmi_system_id broken_systems[] = {
8421fd68434SRafael J. Wysocki 		{
8431fd68434SRafael J. Wysocki 			.ident = "HP Compaq nx6310",
8441fd68434SRafael J. Wysocki 			.matches = {
8451fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
8461fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
8471fd68434SRafael J. Wysocki 			},
8481fd68434SRafael J. Wysocki 			/* PCI slot number of the controller */
8491fd68434SRafael J. Wysocki 			.driver_data = (void *)0x1FUL,
8501fd68434SRafael J. Wysocki 		},
851d2f9c061SMaciej Rutecki 		{
852d2f9c061SMaciej Rutecki 			.ident = "HP Compaq 6720s",
853d2f9c061SMaciej Rutecki 			.matches = {
854d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
855d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
856d2f9c061SMaciej Rutecki 			},
857d2f9c061SMaciej Rutecki 			/* PCI slot number of the controller */
858d2f9c061SMaciej Rutecki 			.driver_data = (void *)0x1FUL,
859d2f9c061SMaciej Rutecki 		},
8601fd68434SRafael J. Wysocki 
8611fd68434SRafael J. Wysocki 		{ }	/* terminate list */
8621fd68434SRafael J. Wysocki 	};
8631fd68434SRafael J. Wysocki 	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
8641fd68434SRafael J. Wysocki 
8651fd68434SRafael J. Wysocki 	if (dmi) {
8661fd68434SRafael J. Wysocki 		unsigned long slot = (unsigned long)dmi->driver_data;
8671fd68434SRafael J. Wysocki 		/* apply the quirk only to on-board controllers */
8681fd68434SRafael J. Wysocki 		return slot == PCI_SLOT(pdev->devfn);
8691fd68434SRafael J. Wysocki 	}
8701fd68434SRafael J. Wysocki 
8711fd68434SRafael J. Wysocki 	return false;
8721fd68434SRafael J. Wysocki }
8731fd68434SRafael J. Wysocki 
8749b10ae86STejun Heo static bool ahci_broken_suspend(struct pci_dev *pdev)
8759b10ae86STejun Heo {
8769b10ae86STejun Heo 	static const struct dmi_system_id sysids[] = {
8779b10ae86STejun Heo 		/*
8789b10ae86STejun Heo 		 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
8799b10ae86STejun Heo 		 * to the harddisk doesn't become online after
8809b10ae86STejun Heo 		 * resuming from STR.  Warn and fail suspend.
8819deb3431STejun Heo 		 *
8829deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=12276
8839deb3431STejun Heo 		 *
8849deb3431STejun Heo 		 * Use dates instead of versions to match as HP is
8859deb3431STejun Heo 		 * apparently recycling both product and version
8869deb3431STejun Heo 		 * strings.
8879deb3431STejun Heo 		 *
8889deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=15462
8899b10ae86STejun Heo 		 */
8909b10ae86STejun Heo 		{
8919b10ae86STejun Heo 			.ident = "dv4",
8929b10ae86STejun Heo 			.matches = {
8939b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
8949b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
8959b10ae86STejun Heo 					  "HP Pavilion dv4 Notebook PC"),
8969b10ae86STejun Heo 			},
8979deb3431STejun Heo 			.driver_data = "20090105",	/* F.30 */
8989b10ae86STejun Heo 		},
8999b10ae86STejun Heo 		{
9009b10ae86STejun Heo 			.ident = "dv5",
9019b10ae86STejun Heo 			.matches = {
9029b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
9039b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
9049b10ae86STejun Heo 					  "HP Pavilion dv5 Notebook PC"),
9059b10ae86STejun Heo 			},
9069deb3431STejun Heo 			.driver_data = "20090506",	/* F.16 */
9079b10ae86STejun Heo 		},
9089b10ae86STejun Heo 		{
9099b10ae86STejun Heo 			.ident = "dv6",
9109b10ae86STejun Heo 			.matches = {
9119b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
9129b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
9139b10ae86STejun Heo 					  "HP Pavilion dv6 Notebook PC"),
9149b10ae86STejun Heo 			},
9159deb3431STejun Heo 			.driver_data = "20090423",	/* F.21 */
9169b10ae86STejun Heo 		},
9179b10ae86STejun Heo 		{
9189b10ae86STejun Heo 			.ident = "HDX18",
9199b10ae86STejun Heo 			.matches = {
9209b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
9219b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
9229b10ae86STejun Heo 					  "HP HDX18 Notebook PC"),
9239b10ae86STejun Heo 			},
9249deb3431STejun Heo 			.driver_data = "20090430",	/* F.23 */
9259b10ae86STejun Heo 		},
926cedc9bf9STejun Heo 		/*
927cedc9bf9STejun Heo 		 * Acer eMachines G725 has the same problem.  BIOS
928cedc9bf9STejun Heo 		 * V1.03 is known to be broken.  V3.04 is known to
929*25985edcSLucas De Marchi 		 * work.  Between, there are V1.06, V2.06 and V3.03
930cedc9bf9STejun Heo 		 * that we don't have much idea about.  For now,
931cedc9bf9STejun Heo 		 * blacklist anything older than V3.04.
9329deb3431STejun Heo 		 *
9339deb3431STejun Heo 		 * http://bugzilla.kernel.org/show_bug.cgi?id=15104
934cedc9bf9STejun Heo 		 */
935cedc9bf9STejun Heo 		{
936cedc9bf9STejun Heo 			.ident = "G725",
937cedc9bf9STejun Heo 			.matches = {
938cedc9bf9STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "eMachines"),
939cedc9bf9STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "eMachines G725"),
940cedc9bf9STejun Heo 			},
9419deb3431STejun Heo 			.driver_data = "20091216",	/* V3.04 */
942cedc9bf9STejun Heo 		},
9439b10ae86STejun Heo 		{ }	/* terminate list */
9449b10ae86STejun Heo 	};
9459b10ae86STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
9469deb3431STejun Heo 	int year, month, date;
9479deb3431STejun Heo 	char buf[9];
9489b10ae86STejun Heo 
9499b10ae86STejun Heo 	if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
9509b10ae86STejun Heo 		return false;
9519b10ae86STejun Heo 
9529deb3431STejun Heo 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
9539deb3431STejun Heo 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
9549b10ae86STejun Heo 
9559deb3431STejun Heo 	return strcmp(buf, dmi->driver_data) < 0;
9569b10ae86STejun Heo }
9579b10ae86STejun Heo 
9585594639aSTejun Heo static bool ahci_broken_online(struct pci_dev *pdev)
9595594639aSTejun Heo {
9605594639aSTejun Heo #define ENCODE_BUSDEVFN(bus, slot, func)			\
9615594639aSTejun Heo 	(void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
9625594639aSTejun Heo 	static const struct dmi_system_id sysids[] = {
9635594639aSTejun Heo 		/*
9645594639aSTejun Heo 		 * There are several gigabyte boards which use
9655594639aSTejun Heo 		 * SIMG5723s configured as hardware RAID.  Certain
9665594639aSTejun Heo 		 * 5723 firmware revisions shipped there keep the link
9675594639aSTejun Heo 		 * online but fail to answer properly to SRST or
9685594639aSTejun Heo 		 * IDENTIFY when no device is attached downstream
9695594639aSTejun Heo 		 * causing libata to retry quite a few times leading
9705594639aSTejun Heo 		 * to excessive detection delay.
9715594639aSTejun Heo 		 *
9725594639aSTejun Heo 		 * As these firmwares respond to the second reset try
9735594639aSTejun Heo 		 * with invalid device signature, considering unknown
9745594639aSTejun Heo 		 * sig as offline works around the problem acceptably.
9755594639aSTejun Heo 		 */
9765594639aSTejun Heo 		{
9775594639aSTejun Heo 			.ident = "EP45-DQ6",
9785594639aSTejun Heo 			.matches = {
9795594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
9805594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
9815594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
9825594639aSTejun Heo 			},
9835594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
9845594639aSTejun Heo 		},
9855594639aSTejun Heo 		{
9865594639aSTejun Heo 			.ident = "EP45-DS5",
9875594639aSTejun Heo 			.matches = {
9885594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
9895594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
9905594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
9915594639aSTejun Heo 			},
9925594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
9935594639aSTejun Heo 		},
9945594639aSTejun Heo 		{ }	/* terminate list */
9955594639aSTejun Heo 	};
9965594639aSTejun Heo #undef ENCODE_BUSDEVFN
9975594639aSTejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
9985594639aSTejun Heo 	unsigned int val;
9995594639aSTejun Heo 
10005594639aSTejun Heo 	if (!dmi)
10015594639aSTejun Heo 		return false;
10025594639aSTejun Heo 
10035594639aSTejun Heo 	val = (unsigned long)dmi->driver_data;
10045594639aSTejun Heo 
10055594639aSTejun Heo 	return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
10065594639aSTejun Heo }
10075594639aSTejun Heo 
10088e513217SMarkus Trippelsdorf #ifdef CONFIG_ATA_ACPI
1009f80ae7e4STejun Heo static void ahci_gtf_filter_workaround(struct ata_host *host)
1010f80ae7e4STejun Heo {
1011f80ae7e4STejun Heo 	static const struct dmi_system_id sysids[] = {
1012f80ae7e4STejun Heo 		/*
1013f80ae7e4STejun Heo 		 * Aspire 3810T issues a bunch of SATA enable commands
1014f80ae7e4STejun Heo 		 * via _GTF including an invalid one and one which is
1015f80ae7e4STejun Heo 		 * rejected by the device.  Among the successful ones
1016f80ae7e4STejun Heo 		 * is FPDMA non-zero offset enable which when enabled
1017f80ae7e4STejun Heo 		 * only on the drive side leads to NCQ command
1018f80ae7e4STejun Heo 		 * failures.  Filter it out.
1019f80ae7e4STejun Heo 		 */
1020f80ae7e4STejun Heo 		{
1021f80ae7e4STejun Heo 			.ident = "Aspire 3810T",
1022f80ae7e4STejun Heo 			.matches = {
1023f80ae7e4STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
1024f80ae7e4STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
1025f80ae7e4STejun Heo 			},
1026f80ae7e4STejun Heo 			.driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
1027f80ae7e4STejun Heo 		},
1028f80ae7e4STejun Heo 		{ }
1029f80ae7e4STejun Heo 	};
1030f80ae7e4STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
1031f80ae7e4STejun Heo 	unsigned int filter;
1032f80ae7e4STejun Heo 	int i;
1033f80ae7e4STejun Heo 
1034f80ae7e4STejun Heo 	if (!dmi)
1035f80ae7e4STejun Heo 		return;
1036f80ae7e4STejun Heo 
1037f80ae7e4STejun Heo 	filter = (unsigned long)dmi->driver_data;
1038f80ae7e4STejun Heo 	dev_printk(KERN_INFO, host->dev,
1039f80ae7e4STejun Heo 		   "applying extra ACPI _GTF filter 0x%x for %s\n",
1040f80ae7e4STejun Heo 		   filter, dmi->ident);
1041f80ae7e4STejun Heo 
1042f80ae7e4STejun Heo 	for (i = 0; i < host->n_ports; i++) {
1043f80ae7e4STejun Heo 		struct ata_port *ap = host->ports[i];
1044f80ae7e4STejun Heo 		struct ata_link *link;
1045f80ae7e4STejun Heo 		struct ata_device *dev;
1046f80ae7e4STejun Heo 
1047f80ae7e4STejun Heo 		ata_for_each_link(link, ap, EDGE)
1048f80ae7e4STejun Heo 			ata_for_each_dev(dev, link, ALL)
1049f80ae7e4STejun Heo 				dev->gtf_filter |= filter;
1050f80ae7e4STejun Heo 	}
1051f80ae7e4STejun Heo }
10528e513217SMarkus Trippelsdorf #else
10538e513217SMarkus Trippelsdorf static inline void ahci_gtf_filter_workaround(struct ata_host *host)
10548e513217SMarkus Trippelsdorf {}
10558e513217SMarkus Trippelsdorf #endif
1056f80ae7e4STejun Heo 
1057c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1058c6fd2807SJeff Garzik {
1059c6fd2807SJeff Garzik 	static int printed_version;
1060e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
1061e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
10624447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
106324dc5f33STejun Heo 	struct device *dev = &pdev->dev;
1064c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
10654447d351STejun Heo 	struct ata_host *host;
1066837f5f8fSTejun Heo 	int n_ports, i, rc;
1067c6fd2807SJeff Garzik 
1068c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1069c6fd2807SJeff Garzik 
1070b429dd59SJustin P. Mattock 	WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS);
1071c6fd2807SJeff Garzik 
1072c6fd2807SJeff Garzik 	if (!printed_version++)
1073c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
1074c6fd2807SJeff Garzik 
10755b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
10765b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
10775b66c829SAlan Cox 	   AHCI stays out of the way */
10785b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
10795b66c829SAlan Cox 		return -ENODEV;
10805b66c829SAlan Cox 
1081c6353b45STejun Heo 	/*
1082c6353b45STejun Heo 	 * For some reason, MCP89 on MacBook 7,1 doesn't work with
1083c6353b45STejun Heo 	 * ahci, use ata_generic instead.
1084c6353b45STejun Heo 	 */
1085c6353b45STejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
1086c6353b45STejun Heo 	    pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
1087c6353b45STejun Heo 	    pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
1088c6353b45STejun Heo 	    pdev->subsystem_device == 0xcb89)
1089c6353b45STejun Heo 		return -ENODEV;
1090c6353b45STejun Heo 
10917a02267eSMark Nelson 	/* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
10927a02267eSMark Nelson 	 * At the moment, we can only use the AHCI mode. Let the users know
10937a02267eSMark Nelson 	 * that for SAS drives they're out of luck.
10947a02267eSMark Nelson 	 */
10957a02267eSMark Nelson 	if (pdev->vendor == PCI_VENDOR_ID_PROMISE)
10967a02267eSMark Nelson 		dev_printk(KERN_INFO, &pdev->dev, "PDC42819 "
10977a02267eSMark Nelson 			   "can only drive SATA devices with this driver\n");
10987a02267eSMark Nelson 
10994447d351STejun Heo 	/* acquire resources */
110024dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
1101c6fd2807SJeff Garzik 	if (rc)
1102c6fd2807SJeff Garzik 		return rc;
1103c6fd2807SJeff Garzik 
1104dea55137STejun Heo 	/* AHCI controllers often implement SFF compatible interface.
1105dea55137STejun Heo 	 * Grab all PCI BARs just in case.
1106dea55137STejun Heo 	 */
1107dea55137STejun Heo 	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
11080d5ff566STejun Heo 	if (rc == -EBUSY)
110924dc5f33STejun Heo 		pcim_pin_device(pdev);
11100d5ff566STejun Heo 	if (rc)
111124dc5f33STejun Heo 		return rc;
1112c6fd2807SJeff Garzik 
1113c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
1114c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
1115c4f7792cSTejun Heo 		u8 map;
1116c4f7792cSTejun Heo 
1117c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
1118c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
1119c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
1120c4f7792cSTejun Heo 		 */
1121c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
1122c4f7792cSTejun Heo 		if (map & 0x3) {
1123c4f7792cSTejun Heo 			dev_printk(KERN_INFO, &pdev->dev, "controller is in "
1124c4f7792cSTejun Heo 				   "combined mode, can't enable AHCI mode\n");
1125c4f7792cSTejun Heo 			return -ENODEV;
1126c4f7792cSTejun Heo 		}
1127c4f7792cSTejun Heo 	}
1128c4f7792cSTejun Heo 
112924dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
113024dc5f33STejun Heo 	if (!hpriv)
113124dc5f33STejun Heo 		return -ENOMEM;
1132417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
1133417a1a6dSTejun Heo 
1134e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
1135e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
1136e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
1137e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
1138e297d99eSTejun Heo 
1139e427fe04SShane Huang 	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
1140e427fe04SShane Huang 	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
1141e427fe04SShane Huang 		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
1142e427fe04SShane Huang 
11432fcad9d2STejun Heo 	/* only some SB600s can do 64bit DMA */
11442fcad9d2STejun Heo 	if (ahci_sb600_enable_64bit(pdev))
11452fcad9d2STejun Heo 		hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
114658a09b38SShane Huang 
114731b239adSTejun Heo 	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
114831b239adSTejun Heo 		pci_intx(pdev, 1);
1149c6fd2807SJeff Garzik 
1150d8993349SAnton Vorontsov 	hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
1151d8993349SAnton Vorontsov 
11524447d351STejun Heo 	/* save initial config */
1153394d6e53SAnton Vorontsov 	ahci_pci_save_initial_config(pdev, hpriv);
1154c6fd2807SJeff Garzik 
11554447d351STejun Heo 	/* prepare host */
1156453d3131SRobert Hancock 	if (hpriv->cap & HOST_CAP_NCQ) {
1157453d3131SRobert Hancock 		pi.flags |= ATA_FLAG_NCQ;
115883f2b963STejun Heo 		/*
115983f2b963STejun Heo 		 * Auto-activate optimization is supposed to be
116083f2b963STejun Heo 		 * supported on all AHCI controllers indicating NCQ
116183f2b963STejun Heo 		 * capability, but it seems to be broken on some
116283f2b963STejun Heo 		 * chipsets including NVIDIAs.
116383f2b963STejun Heo 		 */
116483f2b963STejun Heo 		if (!(hpriv->flags & AHCI_HFLAG_NO_FPDMA_AA))
1165453d3131SRobert Hancock 			pi.flags |= ATA_FLAG_FPDMA_AA;
1166453d3131SRobert Hancock 	}
11674447d351STejun Heo 
11687d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
11697d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
11707d50b60bSTejun Heo 
11710cbb0e77SAnton Vorontsov 	ahci_set_em_messages(hpriv, &pi);
117218f7ba4cSKristen Carlson Accardi 
11731fd68434SRafael J. Wysocki 	if (ahci_broken_system_poweroff(pdev)) {
11741fd68434SRafael J. Wysocki 		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
11751fd68434SRafael J. Wysocki 		dev_info(&pdev->dev,
11761fd68434SRafael J. Wysocki 			"quirky BIOS, skipping spindown on poweroff\n");
11771fd68434SRafael J. Wysocki 	}
11781fd68434SRafael J. Wysocki 
11799b10ae86STejun Heo 	if (ahci_broken_suspend(pdev)) {
11809b10ae86STejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
11819b10ae86STejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
11829b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
11839b10ae86STejun Heo 	}
11849b10ae86STejun Heo 
11855594639aSTejun Heo 	if (ahci_broken_online(pdev)) {
11865594639aSTejun Heo 		hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
11875594639aSTejun Heo 		dev_info(&pdev->dev,
11885594639aSTejun Heo 			 "online status unreliable, applying workaround\n");
11895594639aSTejun Heo 	}
11905594639aSTejun Heo 
1191837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
1192837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
1193837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
1194837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
1195837f5f8fSTejun Heo 	 */
1196837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
1197837f5f8fSTejun Heo 
1198837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
11994447d351STejun Heo 	if (!host)
12004447d351STejun Heo 		return -ENOMEM;
12014447d351STejun Heo 	host->private_data = hpriv;
12024447d351STejun Heo 
1203f3d7f23fSArjan van de Ven 	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
1204886ad09fSArjan van de Ven 		host->flags |= ATA_HOST_PARALLEL_SCAN;
1205f3d7f23fSArjan van de Ven 	else
1206f3d7f23fSArjan van de Ven 		printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
1207886ad09fSArjan van de Ven 
120818f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
120918f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
121018f7ba4cSKristen Carlson Accardi 
12114447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
12124447d351STejun Heo 		struct ata_port *ap = host->ports[i];
12134447d351STejun Heo 
1214cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
1215cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
1216cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
1217cbcdd875STejun Heo 
121818f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
121918f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
1220008dbd61SHarry Zhang 			ap->em_message_type = hpriv->em_msg_type;
122118f7ba4cSKristen Carlson Accardi 
122218f7ba4cSKristen Carlson Accardi 
1223dab632e8SJeff Garzik 		/* disabled/not-implemented port */
1224350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
1225dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
12264447d351STejun Heo 	}
1227c6fd2807SJeff Garzik 
1228edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
1229edc93052STejun Heo 	ahci_p5wdh_workaround(host);
1230edc93052STejun Heo 
1231f80ae7e4STejun Heo 	/* apply gtf filter quirk */
1232f80ae7e4STejun Heo 	ahci_gtf_filter_workaround(host);
1233f80ae7e4STejun Heo 
1234c6fd2807SJeff Garzik 	/* initialize adapter */
12354447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
1236c6fd2807SJeff Garzik 	if (rc)
123724dc5f33STejun Heo 		return rc;
1238c6fd2807SJeff Garzik 
12393303040dSAnton Vorontsov 	rc = ahci_pci_reset_controller(host);
12404447d351STejun Heo 	if (rc)
12414447d351STejun Heo 		return rc;
1242c6fd2807SJeff Garzik 
1243781d6550SAnton Vorontsov 	ahci_pci_init_controller(host);
1244439fcaecSAnton Vorontsov 	ahci_pci_print_info(host);
1245c6fd2807SJeff Garzik 
12464447d351STejun Heo 	pci_set_master(pdev);
12474447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
12484447d351STejun Heo 				 &ahci_sht);
1249c6fd2807SJeff Garzik }
1250c6fd2807SJeff Garzik 
1251c6fd2807SJeff Garzik static int __init ahci_init(void)
1252c6fd2807SJeff Garzik {
1253c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
1254c6fd2807SJeff Garzik }
1255c6fd2807SJeff Garzik 
1256c6fd2807SJeff Garzik static void __exit ahci_exit(void)
1257c6fd2807SJeff Garzik {
1258c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
1259c6fd2807SJeff Garzik }
1260c6fd2807SJeff Garzik 
1261c6fd2807SJeff Garzik 
1262c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
1263c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
1264c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
1265c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
1266c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
1267c6fd2807SJeff Garzik 
1268c6fd2807SJeff Garzik module_init(ahci_init);
1269c6fd2807SJeff Garzik module_exit(ahci_exit);
1270