xref: /openbmc/linux/drivers/ata/ahci.c (revision e297d99e103f951a71fcb1534f1ff3480dd3a851)
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>
45c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
46c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
47c6fd2807SJeff Garzik #include <linux/libata.h>
48c6fd2807SJeff Garzik 
49c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
507d50b60bSTejun Heo #define DRV_VERSION	"3.0"
51c6fd2807SJeff Garzik 
52a22e6444STejun Heo static int ahci_skip_host_reset;
53a22e6444STejun Heo module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
54a22e6444STejun Heo MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
55a22e6444STejun Heo 
5631556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
5731556594SKristen Carlson Accardi 		enum link_pm policy);
5831556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap);
59c6fd2807SJeff Garzik 
60c6fd2807SJeff Garzik enum {
61c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
62648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
63c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
64c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
65c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
66c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
67c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
68c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
69c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
70c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
71c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
72c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
73c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
74c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
75c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
76c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
77c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
78c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
79c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
80c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
81c6fd2807SJeff Garzik 
82c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
830291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
84c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
85c6fd2807SJeff Garzik 
86c6fd2807SJeff Garzik 	board_ahci		= 0,
877a234affSTejun Heo 	board_ahci_vt8251	= 1,
887a234affSTejun Heo 	board_ahci_ign_iferr	= 2,
897a234affSTejun Heo 	board_ahci_sb600	= 3,
907a234affSTejun Heo 	board_ahci_mv		= 4,
91e39fc8c9SShane Huang 	board_ahci_sb700	= 5,
92*e297d99eSTejun Heo 	board_ahci_mcp65	= 6,
93c6fd2807SJeff Garzik 
94c6fd2807SJeff Garzik 	/* global controller registers */
95c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
96c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
97c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
98c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
99c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
100c6fd2807SJeff Garzik 
101c6fd2807SJeff Garzik 	/* HOST_CTL bits */
102c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
103c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
104c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
105c6fd2807SJeff Garzik 
106c6fd2807SJeff Garzik 	/* HOST_CAP bits */
107c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
1087d50b60bSTejun Heo 	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
109c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
11031556594SKristen Carlson Accardi 	HOST_CAP_ALPM		= (1 << 26), /* Aggressive Link PM support */
111c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
112203ef6c4STejun Heo 	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
113c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
114c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
115c6fd2807SJeff Garzik 
116c6fd2807SJeff Garzik 	/* registers for each SATA port */
117c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
118c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
119c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
120c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
121c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
122c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
123c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
124c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
125c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
126c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
127c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
128c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
129c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
130c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
131203ef6c4STejun Heo 	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
132c6fd2807SJeff Garzik 
133c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
134c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
135c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
136c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
137c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
138c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
139c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
140c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
141c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
142c6fd2807SJeff Garzik 
143c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
144c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
145c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
146c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
147c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
148c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
149c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
150c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
151c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
152c6fd2807SJeff Garzik 
153c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
154c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
155c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
156c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
1577d50b60bSTejun Heo 				  PORT_IRQ_UNK_FIS |
1587d50b60bSTejun Heo 				  PORT_IRQ_BAD_PMP,
159c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
160c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
161c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
162c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
163c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
164c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
165c6fd2807SJeff Garzik 
166c6fd2807SJeff Garzik 	/* PORT_CMD bits */
16731556594SKristen Carlson Accardi 	PORT_CMD_ASP		= (1 << 27), /* Aggressive Slumber/Partial */
16831556594SKristen Carlson Accardi 	PORT_CMD_ALPE		= (1 << 26), /* Aggressive Link PM enable */
169c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
1707d50b60bSTejun Heo 	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
171c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
172c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
173c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
174c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
175c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
176c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
177c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
178c6fd2807SJeff Garzik 
179c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
180c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
181c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
182c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
183c6fd2807SJeff Garzik 
184417a1a6dSTejun Heo 	/* hpriv->flags bits */
185417a1a6dSTejun Heo 	AHCI_HFLAG_NO_NCQ		= (1 << 0),
186417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
187417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
188417a1a6dSTejun Heo 	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
189417a1a6dSTejun Heo 	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
190417a1a6dSTejun Heo 	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
1916949b914STejun Heo 	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
19231556594SKristen Carlson Accardi 	AHCI_HFLAG_NO_HOTPLUG		= (1 << 7), /* ignore PxSERR.DIAG.N */
193a878539eSJeff Garzik 	AHCI_HFLAG_SECT255		= (1 << 8), /* max 255 sectors */
194*e297d99eSTejun Heo 	AHCI_HFLAG_YES_NCQ		= (1 << 9), /* force NCQ cap on */
195417a1a6dSTejun Heo 
196c6fd2807SJeff Garzik 	/* ap->flags bits */
1971188c0d8STejun Heo 
1981188c0d8STejun Heo 	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
1991188c0d8STejun Heo 					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
20031556594SKristen Carlson Accardi 					  ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
20131556594SKristen Carlson Accardi 					  ATA_FLAG_IPM,
202c4f7792cSTejun Heo 
203c4f7792cSTejun Heo 	ICH_MAP				= 0x90, /* ICH MAP register */
204c6fd2807SJeff Garzik };
205c6fd2807SJeff Garzik 
206c6fd2807SJeff Garzik struct ahci_cmd_hdr {
2074ca4e439SAl Viro 	__le32			opts;
2084ca4e439SAl Viro 	__le32			status;
2094ca4e439SAl Viro 	__le32			tbl_addr;
2104ca4e439SAl Viro 	__le32			tbl_addr_hi;
2114ca4e439SAl Viro 	__le32			reserved[4];
212c6fd2807SJeff Garzik };
213c6fd2807SJeff Garzik 
214c6fd2807SJeff Garzik struct ahci_sg {
2154ca4e439SAl Viro 	__le32			addr;
2164ca4e439SAl Viro 	__le32			addr_hi;
2174ca4e439SAl Viro 	__le32			reserved;
2184ca4e439SAl Viro 	__le32			flags_size;
219c6fd2807SJeff Garzik };
220c6fd2807SJeff Garzik 
221c6fd2807SJeff Garzik struct ahci_host_priv {
222417a1a6dSTejun Heo 	unsigned int		flags;		/* AHCI_HFLAG_* */
223d447df14STejun Heo 	u32			cap;		/* cap to use */
224d447df14STejun Heo 	u32			port_map;	/* port map to use */
225d447df14STejun Heo 	u32			saved_cap;	/* saved initial cap */
226d447df14STejun Heo 	u32			saved_port_map;	/* saved initial port_map */
227c6fd2807SJeff Garzik };
228c6fd2807SJeff Garzik 
229c6fd2807SJeff Garzik struct ahci_port_priv {
2307d50b60bSTejun Heo 	struct ata_link		*active_link;
231c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
232c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
233c6fd2807SJeff Garzik 	void			*cmd_tbl;
234c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
235c6fd2807SJeff Garzik 	void			*rx_fis;
236c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2370291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2380291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2390291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
240afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
241a7384925SKristen Carlson Accardi 	u32 			intr_mask;	/* interrupts to enable */
242c6fd2807SJeff Garzik };
243c6fd2807SJeff Garzik 
244da3dbb17STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
245da3dbb17STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
246c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
247c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
2484c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
249c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
250c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
251c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
252c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
253c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
2547d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap);
2557d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap);
256a1efdabaSTejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class,
257a1efdabaSTejun Heo 			  unsigned long deadline);
258a1efdabaSTejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
259a1efdabaSTejun Heo 			  unsigned long deadline);
260a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
261a1efdabaSTejun Heo 				 unsigned long deadline);
262a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
263a1efdabaSTejun Heo 				unsigned long deadline);
264a1efdabaSTejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class);
265c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
266c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
267df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
268a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev);
269dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
270dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
271dab632e8SJeff Garzik 			       u32 opts);
272438ac6d5STejun Heo #ifdef CONFIG_PM
273c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
274c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
275c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
276438ac6d5STejun Heo #endif
277c6fd2807SJeff Garzik 
278ee959b00STony Jones static struct device_attribute *ahci_shost_attrs[] = {
279ee959b00STony Jones 	&dev_attr_link_power_management_policy,
28031556594SKristen Carlson Accardi 	NULL
28131556594SKristen Carlson Accardi };
28231556594SKristen Carlson Accardi 
283c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
28468d1d07bSTejun Heo 	ATA_NCQ_SHT(DRV_NAME),
285c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
286c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
287c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
28831556594SKristen Carlson Accardi 	.shost_attrs		= ahci_shost_attrs,
289c6fd2807SJeff Garzik };
290c6fd2807SJeff Garzik 
291029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = {
292029cfd6bSTejun Heo 	.inherits		= &sata_pmp_port_ops,
293029cfd6bSTejun Heo 
2947d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
295c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
296c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
2974c9bf4e7STejun Heo 	.qc_fill_rtf		= ahci_qc_fill_rtf,
298c6fd2807SJeff Garzik 
299c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
300c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
301a1efdabaSTejun Heo 	.softreset		= ahci_softreset,
302a1efdabaSTejun Heo 	.hardreset		= ahci_hardreset,
303a1efdabaSTejun Heo 	.postreset		= ahci_postreset,
304071f44b1STejun Heo 	.pmp_softreset		= ahci_softreset,
305c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
306c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
307029cfd6bSTejun Heo 	.dev_config		= ahci_dev_config,
308c6fd2807SJeff Garzik 
309029cfd6bSTejun Heo 	.scr_read		= ahci_scr_read,
310029cfd6bSTejun Heo 	.scr_write		= ahci_scr_write,
3117d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
3127d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3137d50b60bSTejun Heo 
314029cfd6bSTejun Heo 	.enable_pm		= ahci_enable_alpm,
315029cfd6bSTejun Heo 	.disable_pm		= ahci_disable_alpm,
316438ac6d5STejun Heo #ifdef CONFIG_PM
317c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
318c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
319438ac6d5STejun Heo #endif
320c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
321c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
322c6fd2807SJeff Garzik };
323c6fd2807SJeff Garzik 
324029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
325029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
326a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
327ad616ffbSTejun Heo };
328ad616ffbSTejun Heo 
329029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
330029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
331a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
332edc93052STejun Heo };
333edc93052STejun Heo 
334417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
335417a1a6dSTejun Heo 
336c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
337c6fd2807SJeff Garzik 	/* board_ahci */
338c6fd2807SJeff Garzik 	{
3391188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
340c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
341469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
342c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
343c6fd2807SJeff Garzik 	},
344c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
345c6fd2807SJeff Garzik 	{
3466949b914STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
347417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
348c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
349469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
350ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
351c6fd2807SJeff Garzik 	},
35241669553STejun Heo 	/* board_ahci_ign_iferr */
35341669553STejun Heo 	{
354417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
355417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
35641669553STejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
357469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
35841669553STejun Heo 		.port_ops	= &ahci_ops,
35941669553STejun Heo 	},
36055a61604SConke Hu 	/* board_ahci_sb600 */
36155a61604SConke Hu 	{
362417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
36322b5e7a7STejun Heo 				 AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
364a878539eSJeff Garzik 				 AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP),
365417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
36655a61604SConke Hu 		.pio_mask	= 0x1f, /* pio0-4 */
367469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
36855a61604SConke Hu 		.port_ops	= &ahci_ops,
36955a61604SConke Hu 	},
370cd70c266SJeff Garzik 	/* board_ahci_mv */
371cd70c266SJeff Garzik 	{
372417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
373417a1a6dSTejun Heo 				 AHCI_HFLAG_MV_PATA),
374cd70c266SJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
375417a1a6dSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
376cd70c266SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
377cd70c266SJeff Garzik 		.udma_mask	= ATA_UDMA6,
378cd70c266SJeff Garzik 		.port_ops	= &ahci_ops,
379cd70c266SJeff Garzik 	},
380e39fc8c9SShane Huang 	/* board_ahci_sb700 */
381e39fc8c9SShane Huang 	{
382e39fc8c9SShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
383e39fc8c9SShane Huang 				 AHCI_HFLAG_NO_PMP),
384e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
385e39fc8c9SShane Huang 		.pio_mask	= 0x1f, /* pio0-4 */
386e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
387e39fc8c9SShane Huang 		.port_ops	= &ahci_ops,
388e39fc8c9SShane Huang 	},
389*e297d99eSTejun Heo 	/* board_ahci_mcp65 */
390*e297d99eSTejun Heo 	{
391*e297d99eSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
392*e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
393*e297d99eSTejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
394*e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
395*e297d99eSTejun Heo 		.port_ops	= &ahci_ops,
396*e297d99eSTejun Heo 	},
397c6fd2807SJeff Garzik };
398c6fd2807SJeff Garzik 
399c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
400c6fd2807SJeff Garzik 	/* Intel */
40154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
40254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
40354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
40454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
40554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
40682490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
40754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
40854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
40954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
41054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
4117a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
4127a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
4137a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
4147a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
4157a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
4167a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
4177a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
4187a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
4197a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
4207a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
4217a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
4227a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
4237a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
4247a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
4257a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
4267a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
4277a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
428d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
429d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
43016ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
43116ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
432c6fd2807SJeff Garzik 
433e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
434e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
435e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
436c6fd2807SJeff Garzik 
437c6fd2807SJeff Garzik 	/* ATI */
438c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
439e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
440e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
441e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
442e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
443e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
444e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
445c6fd2807SJeff Garzik 
446c6fd2807SJeff Garzik 	/* VIA */
44754bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
448bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
449c6fd2807SJeff Garzik 
450c6fd2807SJeff Garzik 	/* NVIDIA */
451*e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
452*e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
453*e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
454*e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
455*e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
456*e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
457*e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
458*e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
4596fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci },		/* MCP67 */
4606fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci },		/* MCP67 */
4616fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci },		/* MCP67 */
4626fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci },		/* MCP67 */
463895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },		/* MCP67 */
464895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },		/* MCP67 */
465895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },		/* MCP67 */
466895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },		/* MCP67 */
467895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },		/* MCP67 */
468895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },		/* MCP67 */
469895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },		/* MCP67 */
470895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },		/* MCP67 */
4710522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci },		/* MCP73 */
4720522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci },		/* MCP73 */
4730522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci },		/* MCP73 */
4740522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci },		/* MCP73 */
4750522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci },		/* MCP73 */
4760522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci },		/* MCP73 */
4770522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci },		/* MCP73 */
4780522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci },		/* MCP73 */
4790522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci },		/* MCP73 */
4800522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci },		/* MCP73 */
4810522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci },		/* MCP73 */
4820522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci },		/* MCP73 */
4830522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },		/* MCP77 */
4840522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },		/* MCP77 */
4850522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },		/* MCP77 */
4860522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },		/* MCP77 */
4870522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },		/* MCP77 */
4880522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },		/* MCP77 */
4890522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },		/* MCP77 */
4900522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },		/* MCP77 */
4910522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },		/* MCP77 */
4920522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
4930522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
4940522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
4956ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci },		/* MCP79 */
4966ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci },		/* MCP79 */
4976ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci },		/* MCP79 */
4986ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci },		/* MCP79 */
4997100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
5007100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
5017100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
5027100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
5037100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
5047100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
5057100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
5067100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
50770d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci },		/* MCP7B */
50870d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci },		/* MCP7B */
50970d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci },		/* MCP7B */
51070d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci },		/* MCP7B */
51170d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci },		/* MCP7B */
51270d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci },		/* MCP7B */
51370d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci },		/* MCP7B */
51470d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci },		/* MCP7B */
5153072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci },		/* MCP7B */
5163072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci },		/* MCP7B */
5173072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci },		/* MCP7B */
5183072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci },		/* MCP7B */
519c6fd2807SJeff Garzik 
520c6fd2807SJeff Garzik 	/* SiS */
52154bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
52254bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
52354bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
524c6fd2807SJeff Garzik 
525cd70c266SJeff Garzik 	/* Marvell */
526cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
527c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
528cd70c266SJeff Garzik 
529415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
530415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
531c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
532415ae2b5SJeff Garzik 
533c6fd2807SJeff Garzik 	{ }	/* terminate list */
534c6fd2807SJeff Garzik };
535c6fd2807SJeff Garzik 
536c6fd2807SJeff Garzik 
537c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
538c6fd2807SJeff Garzik 	.name			= DRV_NAME,
539c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
540c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
54124dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
542438ac6d5STejun Heo #ifdef CONFIG_PM
543c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
544c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
545438ac6d5STejun Heo #endif
546c6fd2807SJeff Garzik };
547c6fd2807SJeff Garzik 
548c6fd2807SJeff Garzik 
54998fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
55098fa4b60STejun Heo {
55198fa4b60STejun Heo 	return (cap & 0x1f) + 1;
55298fa4b60STejun Heo }
55398fa4b60STejun Heo 
554dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host,
555dab632e8SJeff Garzik 					     unsigned int port_no)
556dab632e8SJeff Garzik {
557dab632e8SJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
558dab632e8SJeff Garzik 
559dab632e8SJeff Garzik 	return mmio + 0x100 + (port_no * 0x80);
560dab632e8SJeff Garzik }
561dab632e8SJeff Garzik 
5624447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
563c6fd2807SJeff Garzik {
564dab632e8SJeff Garzik 	return __ahci_port_base(ap->host, ap->port_no);
565c6fd2807SJeff Garzik }
566c6fd2807SJeff Garzik 
567b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio)
568b710a1f4STejun Heo {
56915fe982eSTejun Heo 	int i;
570b710a1f4STejun Heo 	u32 tmp;
571b710a1f4STejun Heo 
572b710a1f4STejun Heo 	/* turn on AHCI_EN */
573b710a1f4STejun Heo 	tmp = readl(mmio + HOST_CTL);
57415fe982eSTejun Heo 	if (tmp & HOST_AHCI_EN)
57515fe982eSTejun Heo 		return;
57615fe982eSTejun Heo 
57715fe982eSTejun Heo 	/* Some controllers need AHCI_EN to be written multiple times.
57815fe982eSTejun Heo 	 * Try a few times before giving up.
57915fe982eSTejun Heo 	 */
58015fe982eSTejun Heo 	for (i = 0; i < 5; i++) {
581b710a1f4STejun Heo 		tmp |= HOST_AHCI_EN;
582b710a1f4STejun Heo 		writel(tmp, mmio + HOST_CTL);
583b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
58415fe982eSTejun Heo 		if (tmp & HOST_AHCI_EN)
58515fe982eSTejun Heo 			return;
58615fe982eSTejun Heo 		msleep(10);
587b710a1f4STejun Heo 	}
58815fe982eSTejun Heo 
58915fe982eSTejun Heo 	WARN_ON(1);
590b710a1f4STejun Heo }
591b710a1f4STejun Heo 
592d447df14STejun Heo /**
593d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
5944447d351STejun Heo  *	@pdev: target PCI device
5954447d351STejun Heo  *	@hpriv: host private area to store config values
596d447df14STejun Heo  *
597d447df14STejun Heo  *	Some registers containing configuration info might be setup by
598d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
599d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
600d447df14STejun Heo  *	can be restored after controller reset.
601d447df14STejun Heo  *
602d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
603d447df14STejun Heo  *
604d447df14STejun Heo  *	LOCKING:
605d447df14STejun Heo  *	None.
606d447df14STejun Heo  */
6074447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
6084447d351STejun Heo 				     struct ahci_host_priv *hpriv)
609d447df14STejun Heo {
6104447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
611d447df14STejun Heo 	u32 cap, port_map;
61217199b18STejun Heo 	int i;
613c40e7cb8SJose Alberto Reguero 	int mv;
614d447df14STejun Heo 
615b710a1f4STejun Heo 	/* make sure AHCI mode is enabled before accessing CAP */
616b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
617b710a1f4STejun Heo 
618d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
619d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
620d447df14STejun Heo 	 */
621d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
622d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
623d447df14STejun Heo 
624274c1fdeSTejun Heo 	/* some chips have errata preventing 64bit use */
625417a1a6dSTejun Heo 	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
626c7a42156STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
627c7a42156STejun Heo 			   "controller can't do 64bit DMA, forcing 32bit\n");
628c7a42156STejun Heo 		cap &= ~HOST_CAP_64;
629c7a42156STejun Heo 	}
630c7a42156STejun Heo 
631417a1a6dSTejun Heo 	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
632274c1fdeSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
633274c1fdeSTejun Heo 			   "controller can't do NCQ, turning off CAP_NCQ\n");
634274c1fdeSTejun Heo 		cap &= ~HOST_CAP_NCQ;
635274c1fdeSTejun Heo 	}
636274c1fdeSTejun Heo 
637*e297d99eSTejun Heo 	if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
638*e297d99eSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
639*e297d99eSTejun Heo 			   "controller can do NCQ, turning on CAP_NCQ\n");
640*e297d99eSTejun Heo 		cap |= HOST_CAP_NCQ;
641*e297d99eSTejun Heo 	}
642*e297d99eSTejun Heo 
643258cd846SRoel Kluin 	if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
6446949b914STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
6456949b914STejun Heo 			   "controller can't do PMP, turning off CAP_PMP\n");
6466949b914STejun Heo 		cap &= ~HOST_CAP_PMP;
6476949b914STejun Heo 	}
6486949b914STejun Heo 
649cd70c266SJeff Garzik 	/*
650cd70c266SJeff Garzik 	 * Temporary Marvell 6145 hack: PATA port presence
651cd70c266SJeff Garzik 	 * is asserted through the standard AHCI port
652cd70c266SJeff Garzik 	 * presence register, as bit 4 (counting from 0)
653cd70c266SJeff Garzik 	 */
654417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
655c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
656c40e7cb8SJose Alberto Reguero 			mv = 0x3;
657c40e7cb8SJose Alberto Reguero 		else
658c40e7cb8SJose Alberto Reguero 			mv = 0xf;
659cd70c266SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
660cd70c266SJeff Garzik 			   "MV_AHCI HACK: port_map %x -> %x\n",
661c40e7cb8SJose Alberto Reguero 			   port_map,
662c40e7cb8SJose Alberto Reguero 			   port_map & mv);
663cd70c266SJeff Garzik 
664c40e7cb8SJose Alberto Reguero 		port_map &= mv;
665cd70c266SJeff Garzik 	}
666cd70c266SJeff Garzik 
66717199b18STejun Heo 	/* cross check port_map and cap.n_ports */
6687a234affSTejun Heo 	if (port_map) {
669837f5f8fSTejun Heo 		int map_ports = 0;
67017199b18STejun Heo 
671837f5f8fSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS; i++)
672837f5f8fSTejun Heo 			if (port_map & (1 << i))
673837f5f8fSTejun Heo 				map_ports++;
67417199b18STejun Heo 
675837f5f8fSTejun Heo 		/* If PI has more ports than n_ports, whine, clear
676837f5f8fSTejun Heo 		 * port_map and let it be generated from n_ports.
67717199b18STejun Heo 		 */
678837f5f8fSTejun Heo 		if (map_ports > ahci_nr_ports(cap)) {
6794447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
680837f5f8fSTejun Heo 				   "implemented port map (0x%x) contains more "
681837f5f8fSTejun Heo 				   "ports than nr_ports (%u), using nr_ports\n",
682837f5f8fSTejun Heo 				   port_map, ahci_nr_ports(cap));
6837a234affSTejun Heo 			port_map = 0;
6847a234affSTejun Heo 		}
6857a234affSTejun Heo 	}
6867a234affSTejun Heo 
68717199b18STejun Heo 	/* fabricate port_map from cap.nr_ports */
6887a234affSTejun Heo 	if (!port_map) {
68917199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
6907a234affSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
6917a234affSTejun Heo 			   "forcing PORTS_IMPL to 0x%x\n", port_map);
6927a234affSTejun Heo 
6937a234affSTejun Heo 		/* write the fixed up value to the PI register */
6947a234affSTejun Heo 		hpriv->saved_port_map = port_map;
69517199b18STejun Heo 	}
69617199b18STejun Heo 
697d447df14STejun Heo 	/* record values to use during operation */
698d447df14STejun Heo 	hpriv->cap = cap;
699d447df14STejun Heo 	hpriv->port_map = port_map;
700d447df14STejun Heo }
701d447df14STejun Heo 
702d447df14STejun Heo /**
703d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
7044447d351STejun Heo  *	@host: target ATA host
705d447df14STejun Heo  *
706d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
707d447df14STejun Heo  *
708d447df14STejun Heo  *	LOCKING:
709d447df14STejun Heo  *	None.
710d447df14STejun Heo  */
7114447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
712d447df14STejun Heo {
7134447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
7144447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
7154447d351STejun Heo 
716d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
717d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
718d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
719d447df14STejun Heo }
720d447df14STejun Heo 
721203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
722c6fd2807SJeff Garzik {
723203ef6c4STejun Heo 	static const int offset[] = {
724203ef6c4STejun Heo 		[SCR_STATUS]		= PORT_SCR_STAT,
725203ef6c4STejun Heo 		[SCR_CONTROL]		= PORT_SCR_CTL,
726203ef6c4STejun Heo 		[SCR_ERROR]		= PORT_SCR_ERR,
727203ef6c4STejun Heo 		[SCR_ACTIVE]		= PORT_SCR_ACT,
728203ef6c4STejun Heo 		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
729203ef6c4STejun Heo 	};
730203ef6c4STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
731c6fd2807SJeff Garzik 
732203ef6c4STejun Heo 	if (sc_reg < ARRAY_SIZE(offset) &&
733203ef6c4STejun Heo 	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
734203ef6c4STejun Heo 		return offset[sc_reg];
735da3dbb17STejun Heo 	return 0;
736c6fd2807SJeff Garzik }
737c6fd2807SJeff Garzik 
738203ef6c4STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
739c6fd2807SJeff Garzik {
740203ef6c4STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
741203ef6c4STejun Heo 	int offset = ahci_scr_offset(ap, sc_reg);
742c6fd2807SJeff Garzik 
743203ef6c4STejun Heo 	if (offset) {
744203ef6c4STejun Heo 		*val = readl(port_mmio + offset);
745203ef6c4STejun Heo 		return 0;
746203ef6c4STejun Heo 	}
747da3dbb17STejun Heo 	return -EINVAL;
748c6fd2807SJeff Garzik }
749c6fd2807SJeff Garzik 
750203ef6c4STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
751203ef6c4STejun Heo {
752203ef6c4STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
753203ef6c4STejun Heo 	int offset = ahci_scr_offset(ap, sc_reg);
754203ef6c4STejun Heo 
755203ef6c4STejun Heo 	if (offset) {
756203ef6c4STejun Heo 		writel(val, port_mmio + offset);
757da3dbb17STejun Heo 		return 0;
758c6fd2807SJeff Garzik 	}
759203ef6c4STejun Heo 	return -EINVAL;
760203ef6c4STejun Heo }
761c6fd2807SJeff Garzik 
7624447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
763c6fd2807SJeff Garzik {
7644447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
765c6fd2807SJeff Garzik 	u32 tmp;
766c6fd2807SJeff Garzik 
767c6fd2807SJeff Garzik 	/* start DMA */
768c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
769c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
770c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
771c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
772c6fd2807SJeff Garzik }
773c6fd2807SJeff Garzik 
7744447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
775c6fd2807SJeff Garzik {
7764447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
777c6fd2807SJeff Garzik 	u32 tmp;
778c6fd2807SJeff Garzik 
779c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
780c6fd2807SJeff Garzik 
781c6fd2807SJeff Garzik 	/* check if the HBA is idle */
782c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
783c6fd2807SJeff Garzik 		return 0;
784c6fd2807SJeff Garzik 
785c6fd2807SJeff Garzik 	/* setting HBA to idle */
786c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
787c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
788c6fd2807SJeff Garzik 
789c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
790c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
791c6fd2807SJeff Garzik 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
792c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
793c6fd2807SJeff Garzik 		return -EIO;
794c6fd2807SJeff Garzik 
795c6fd2807SJeff Garzik 	return 0;
796c6fd2807SJeff Garzik }
797c6fd2807SJeff Garzik 
7984447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
799c6fd2807SJeff Garzik {
8004447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
8014447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
8024447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
803c6fd2807SJeff Garzik 	u32 tmp;
804c6fd2807SJeff Garzik 
805c6fd2807SJeff Garzik 	/* set FIS registers */
8064447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
8074447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
8084447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
8094447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
810c6fd2807SJeff Garzik 
8114447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
8124447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
8134447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
8144447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
815c6fd2807SJeff Garzik 
816c6fd2807SJeff Garzik 	/* enable FIS reception */
817c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
818c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
819c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
820c6fd2807SJeff Garzik 
821c6fd2807SJeff Garzik 	/* flush */
822c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
823c6fd2807SJeff Garzik }
824c6fd2807SJeff Garzik 
8254447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
826c6fd2807SJeff Garzik {
8274447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
828c6fd2807SJeff Garzik 	u32 tmp;
829c6fd2807SJeff Garzik 
830c6fd2807SJeff Garzik 	/* disable FIS reception */
831c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
832c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
833c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
834c6fd2807SJeff Garzik 
835c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
836c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
837c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
838c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
839c6fd2807SJeff Garzik 		return -EBUSY;
840c6fd2807SJeff Garzik 
841c6fd2807SJeff Garzik 	return 0;
842c6fd2807SJeff Garzik }
843c6fd2807SJeff Garzik 
8444447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
845c6fd2807SJeff Garzik {
8464447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
8474447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
848c6fd2807SJeff Garzik 	u32 cmd;
849c6fd2807SJeff Garzik 
850c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
851c6fd2807SJeff Garzik 
852c6fd2807SJeff Garzik 	/* spin up device */
8534447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
854c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
855c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
856c6fd2807SJeff Garzik 	}
857c6fd2807SJeff Garzik 
858c6fd2807SJeff Garzik 	/* wake up link */
859c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
860c6fd2807SJeff Garzik }
861c6fd2807SJeff Garzik 
86231556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap)
86331556594SKristen Carlson Accardi {
86431556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
86531556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
86631556594SKristen Carlson Accardi 	u32 cmd;
86731556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
86831556594SKristen Carlson Accardi 
86931556594SKristen Carlson Accardi 	/* IPM bits should be disabled by libata-core */
87031556594SKristen Carlson Accardi 	/* get the existing command bits */
87131556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
87231556594SKristen Carlson Accardi 
87331556594SKristen Carlson Accardi 	/* disable ALPM and ASP */
87431556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ASP;
87531556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ALPE;
87631556594SKristen Carlson Accardi 
87731556594SKristen Carlson Accardi 	/* force the interface back to active */
87831556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ICC_ACTIVE;
87931556594SKristen Carlson Accardi 
88031556594SKristen Carlson Accardi 	/* write out new cmd value */
88131556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
88231556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
88331556594SKristen Carlson Accardi 
88431556594SKristen Carlson Accardi 	/* wait 10ms to be sure we've come out of any low power state */
88531556594SKristen Carlson Accardi 	msleep(10);
88631556594SKristen Carlson Accardi 
88731556594SKristen Carlson Accardi 	/* clear out any PhyRdy stuff from interrupt status */
88831556594SKristen Carlson Accardi 	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
88931556594SKristen Carlson Accardi 
89031556594SKristen Carlson Accardi 	/* go ahead and clean out PhyRdy Change from Serror too */
89131556594SKristen Carlson Accardi 	ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
89231556594SKristen Carlson Accardi 
89331556594SKristen Carlson Accardi 	/*
89431556594SKristen Carlson Accardi  	 * Clear flag to indicate that we should ignore all PhyRdy
89531556594SKristen Carlson Accardi  	 * state changes
89631556594SKristen Carlson Accardi  	 */
89731556594SKristen Carlson Accardi 	hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
89831556594SKristen Carlson Accardi 
89931556594SKristen Carlson Accardi 	/*
90031556594SKristen Carlson Accardi  	 * Enable interrupts on Phy Ready.
90131556594SKristen Carlson Accardi  	 */
90231556594SKristen Carlson Accardi 	pp->intr_mask |= PORT_IRQ_PHYRDY;
90331556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
90431556594SKristen Carlson Accardi 
90531556594SKristen Carlson Accardi 	/*
90631556594SKristen Carlson Accardi  	 * don't change the link pm policy - we can be called
90731556594SKristen Carlson Accardi  	 * just to turn of link pm temporarily
90831556594SKristen Carlson Accardi  	 */
90931556594SKristen Carlson Accardi }
91031556594SKristen Carlson Accardi 
91131556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
91231556594SKristen Carlson Accardi 	enum link_pm policy)
91331556594SKristen Carlson Accardi {
91431556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
91531556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
91631556594SKristen Carlson Accardi 	u32 cmd;
91731556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
91831556594SKristen Carlson Accardi 	u32 asp;
91931556594SKristen Carlson Accardi 
92031556594SKristen Carlson Accardi 	/* Make sure the host is capable of link power management */
92131556594SKristen Carlson Accardi 	if (!(hpriv->cap & HOST_CAP_ALPM))
92231556594SKristen Carlson Accardi 		return -EINVAL;
92331556594SKristen Carlson Accardi 
92431556594SKristen Carlson Accardi 	switch (policy) {
92531556594SKristen Carlson Accardi 	case MAX_PERFORMANCE:
92631556594SKristen Carlson Accardi 	case NOT_AVAILABLE:
92731556594SKristen Carlson Accardi 		/*
92831556594SKristen Carlson Accardi  		 * if we came here with NOT_AVAILABLE,
92931556594SKristen Carlson Accardi  		 * it just means this is the first time we
93031556594SKristen Carlson Accardi  		 * have tried to enable - default to max performance,
93131556594SKristen Carlson Accardi  		 * and let the user go to lower power modes on request.
93231556594SKristen Carlson Accardi  		 */
93331556594SKristen Carlson Accardi 		ahci_disable_alpm(ap);
93431556594SKristen Carlson Accardi 		return 0;
93531556594SKristen Carlson Accardi 	case MIN_POWER:
93631556594SKristen Carlson Accardi 		/* configure HBA to enter SLUMBER */
93731556594SKristen Carlson Accardi 		asp = PORT_CMD_ASP;
93831556594SKristen Carlson Accardi 		break;
93931556594SKristen Carlson Accardi 	case MEDIUM_POWER:
94031556594SKristen Carlson Accardi 		/* configure HBA to enter PARTIAL */
94131556594SKristen Carlson Accardi 		asp = 0;
94231556594SKristen Carlson Accardi 		break;
94331556594SKristen Carlson Accardi 	default:
94431556594SKristen Carlson Accardi 		return -EINVAL;
94531556594SKristen Carlson Accardi 	}
94631556594SKristen Carlson Accardi 
94731556594SKristen Carlson Accardi 	/*
94831556594SKristen Carlson Accardi  	 * Disable interrupts on Phy Ready. This keeps us from
94931556594SKristen Carlson Accardi  	 * getting woken up due to spurious phy ready interrupts
95031556594SKristen Carlson Accardi 	 * TBD - Hot plug should be done via polling now, is
95131556594SKristen Carlson Accardi 	 * that even supported?
95231556594SKristen Carlson Accardi  	 */
95331556594SKristen Carlson Accardi 	pp->intr_mask &= ~PORT_IRQ_PHYRDY;
95431556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
95531556594SKristen Carlson Accardi 
95631556594SKristen Carlson Accardi 	/*
95731556594SKristen Carlson Accardi  	 * Set a flag to indicate that we should ignore all PhyRdy
95831556594SKristen Carlson Accardi  	 * state changes since these can happen now whenever we
95931556594SKristen Carlson Accardi  	 * change link state
96031556594SKristen Carlson Accardi  	 */
96131556594SKristen Carlson Accardi 	hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
96231556594SKristen Carlson Accardi 
96331556594SKristen Carlson Accardi 	/* get the existing command bits */
96431556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
96531556594SKristen Carlson Accardi 
96631556594SKristen Carlson Accardi 	/*
96731556594SKristen Carlson Accardi  	 * Set ASP based on Policy
96831556594SKristen Carlson Accardi  	 */
96931556594SKristen Carlson Accardi 	cmd |= asp;
97031556594SKristen Carlson Accardi 
97131556594SKristen Carlson Accardi 	/*
97231556594SKristen Carlson Accardi  	 * Setting this bit will instruct the HBA to aggressively
97331556594SKristen Carlson Accardi  	 * enter a lower power link state when it's appropriate and
97431556594SKristen Carlson Accardi  	 * based on the value set above for ASP
97531556594SKristen Carlson Accardi  	 */
97631556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ALPE;
97731556594SKristen Carlson Accardi 
97831556594SKristen Carlson Accardi 	/* write out new cmd value */
97931556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
98031556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
98131556594SKristen Carlson Accardi 
98231556594SKristen Carlson Accardi 	/* IPM bits should be set by libata-core */
98331556594SKristen Carlson Accardi 	return 0;
98431556594SKristen Carlson Accardi }
98531556594SKristen Carlson Accardi 
986438ac6d5STejun Heo #ifdef CONFIG_PM
9874447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
988c6fd2807SJeff Garzik {
9894447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
9904447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
991c6fd2807SJeff Garzik 	u32 cmd, scontrol;
992c6fd2807SJeff Garzik 
9934447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
99407c53dacSTejun Heo 		return;
995c6fd2807SJeff Garzik 
99607c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
997c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
998c6fd2807SJeff Garzik 	scontrol &= ~0xf;
999c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
1000c6fd2807SJeff Garzik 
1001c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
100207c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1003c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
1004c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
1005c6fd2807SJeff Garzik }
1006438ac6d5STejun Heo #endif
1007c6fd2807SJeff Garzik 
1008df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap)
1009c6fd2807SJeff Garzik {
1010c6fd2807SJeff Garzik 	/* enable FIS reception */
10114447d351STejun Heo 	ahci_start_fis_rx(ap);
1012c6fd2807SJeff Garzik 
1013c6fd2807SJeff Garzik 	/* enable DMA */
10144447d351STejun Heo 	ahci_start_engine(ap);
1015c6fd2807SJeff Garzik }
1016c6fd2807SJeff Garzik 
10174447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
1018c6fd2807SJeff Garzik {
1019c6fd2807SJeff Garzik 	int rc;
1020c6fd2807SJeff Garzik 
1021c6fd2807SJeff Garzik 	/* disable DMA */
10224447d351STejun Heo 	rc = ahci_stop_engine(ap);
1023c6fd2807SJeff Garzik 	if (rc) {
1024c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
1025c6fd2807SJeff Garzik 		return rc;
1026c6fd2807SJeff Garzik 	}
1027c6fd2807SJeff Garzik 
1028c6fd2807SJeff Garzik 	/* disable FIS reception */
10294447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
1030c6fd2807SJeff Garzik 	if (rc) {
1031c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
1032c6fd2807SJeff Garzik 		return rc;
1033c6fd2807SJeff Garzik 	}
1034c6fd2807SJeff Garzik 
1035c6fd2807SJeff Garzik 	return 0;
1036c6fd2807SJeff Garzik }
1037c6fd2807SJeff Garzik 
10384447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
1039c6fd2807SJeff Garzik {
10404447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
104149f29090STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
10424447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1043d447df14STejun Heo 	u32 tmp;
1044c6fd2807SJeff Garzik 
10453cc3eb11SJeff Garzik 	/* we must be in AHCI mode, before using anything
10463cc3eb11SJeff Garzik 	 * AHCI-specific, such as HOST_RESET.
10473cc3eb11SJeff Garzik 	 */
1048b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
10493cc3eb11SJeff Garzik 
10503cc3eb11SJeff Garzik 	/* global controller reset */
1051a22e6444STejun Heo 	if (!ahci_skip_host_reset) {
1052b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);
1053c6fd2807SJeff Garzik 		if ((tmp & HOST_RESET) == 0) {
1054c6fd2807SJeff Garzik 			writel(tmp | HOST_RESET, mmio + HOST_CTL);
1055c6fd2807SJeff Garzik 			readl(mmio + HOST_CTL); /* flush */
1056c6fd2807SJeff Garzik 		}
1057c6fd2807SJeff Garzik 
1058c6fd2807SJeff Garzik 		/* reset must complete within 1 second, or
1059c6fd2807SJeff Garzik 		 * the hardware should be considered fried.
1060c6fd2807SJeff Garzik 		 */
1061c6fd2807SJeff Garzik 		ssleep(1);
1062c6fd2807SJeff Garzik 
1063c6fd2807SJeff Garzik 		tmp = readl(mmio + HOST_CTL);
1064c6fd2807SJeff Garzik 		if (tmp & HOST_RESET) {
10654447d351STejun Heo 			dev_printk(KERN_ERR, host->dev,
1066c6fd2807SJeff Garzik 				   "controller reset failed (0x%x)\n", tmp);
1067c6fd2807SJeff Garzik 			return -EIO;
1068c6fd2807SJeff Garzik 		}
1069c6fd2807SJeff Garzik 
107098fa4b60STejun Heo 		/* turn on AHCI mode */
1071b710a1f4STejun Heo 		ahci_enable_ahci(mmio);
107298fa4b60STejun Heo 
1073a22e6444STejun Heo 		/* Some registers might be cleared on reset.  Restore
1074a22e6444STejun Heo 		 * initial values.
1075a22e6444STejun Heo 		 */
10764447d351STejun Heo 		ahci_restore_initial_config(host);
1077a22e6444STejun Heo 	} else
1078a22e6444STejun Heo 		dev_printk(KERN_INFO, host->dev,
1079a22e6444STejun Heo 			   "skipping global host reset\n");
1080c6fd2807SJeff Garzik 
1081c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
1082c6fd2807SJeff Garzik 		u16 tmp16;
1083c6fd2807SJeff Garzik 
1084c6fd2807SJeff Garzik 		/* configure PCS */
1085c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
108649f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
108749f29090STejun Heo 			tmp16 |= hpriv->port_map;
1088c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
1089c6fd2807SJeff Garzik 		}
109049f29090STejun Heo 	}
1091c6fd2807SJeff Garzik 
1092c6fd2807SJeff Garzik 	return 0;
1093c6fd2807SJeff Garzik }
1094c6fd2807SJeff Garzik 
10952bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
10962bcd866bSJeff Garzik 			   int port_no, void __iomem *mmio,
10972bcd866bSJeff Garzik 			   void __iomem *port_mmio)
1098c6fd2807SJeff Garzik {
1099c6fd2807SJeff Garzik 	const char *emsg = NULL;
11002bcd866bSJeff Garzik 	int rc;
11012bcd866bSJeff Garzik 	u32 tmp;
1102c6fd2807SJeff Garzik 
1103c6fd2807SJeff Garzik 	/* make sure port is not active */
11044447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1105c6fd2807SJeff Garzik 	if (rc)
1106c6fd2807SJeff Garzik 		dev_printk(KERN_WARNING, &pdev->dev,
1107c6fd2807SJeff Garzik 			   "%s (%d)\n", emsg, rc);
1108c6fd2807SJeff Garzik 
1109c6fd2807SJeff Garzik 	/* clear SError */
1110c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SCR_ERR);
1111c6fd2807SJeff Garzik 	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
1112c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_SCR_ERR);
1113c6fd2807SJeff Garzik 
1114c6fd2807SJeff Garzik 	/* clear port IRQ */
1115c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1116c6fd2807SJeff Garzik 	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1117c6fd2807SJeff Garzik 	if (tmp)
1118c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_IRQ_STAT);
1119c6fd2807SJeff Garzik 
11202bcd866bSJeff Garzik 	writel(1 << port_no, mmio + HOST_IRQ_STAT);
11212bcd866bSJeff Garzik }
11222bcd866bSJeff Garzik 
11232bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host)
11242bcd866bSJeff Garzik {
1125417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
11262bcd866bSJeff Garzik 	struct pci_dev *pdev = to_pci_dev(host->dev);
11272bcd866bSJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
11282bcd866bSJeff Garzik 	int i;
1129cd70c266SJeff Garzik 	void __iomem *port_mmio;
11302bcd866bSJeff Garzik 	u32 tmp;
1131c40e7cb8SJose Alberto Reguero 	int mv;
11322bcd866bSJeff Garzik 
1133417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
1134c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
1135c40e7cb8SJose Alberto Reguero 			mv = 2;
1136c40e7cb8SJose Alberto Reguero 		else
1137c40e7cb8SJose Alberto Reguero 			mv = 4;
1138c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
1139cd70c266SJeff Garzik 
1140cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
1141cd70c266SJeff Garzik 
1142cd70c266SJeff Garzik 		/* clear port IRQ */
1143cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
1144cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1145cd70c266SJeff Garzik 		if (tmp)
1146cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
1147cd70c266SJeff Garzik 	}
1148cd70c266SJeff Garzik 
11492bcd866bSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
11502bcd866bSJeff Garzik 		struct ata_port *ap = host->ports[i];
11512bcd866bSJeff Garzik 
1152cd70c266SJeff Garzik 		port_mmio = ahci_port_base(ap);
11532bcd866bSJeff Garzik 		if (ata_port_is_dummy(ap))
11542bcd866bSJeff Garzik 			continue;
11552bcd866bSJeff Garzik 
11562bcd866bSJeff Garzik 		ahci_port_init(pdev, ap, i, mmio, port_mmio);
1157c6fd2807SJeff Garzik 	}
1158c6fd2807SJeff Garzik 
1159c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1160c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1161c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
1162c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1163c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1164c6fd2807SJeff Garzik }
1165c6fd2807SJeff Garzik 
1166a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev)
1167a878539eSJeff Garzik {
1168a878539eSJeff Garzik 	struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
1169a878539eSJeff Garzik 
11704cde32fcSJeff Garzik 	if (hpriv->flags & AHCI_HFLAG_SECT255) {
1171a878539eSJeff Garzik 		dev->max_sectors = 255;
11724cde32fcSJeff Garzik 		ata_dev_printk(dev, KERN_INFO,
11734cde32fcSJeff Garzik 			       "SB600 AHCI: limiting to 255 sectors per cmd\n");
11744cde32fcSJeff Garzik 	}
1175a878539eSJeff Garzik }
1176a878539eSJeff Garzik 
1177c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
1178c6fd2807SJeff Garzik {
11794447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1180c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1181c6fd2807SJeff Garzik 	u32 tmp;
1182c6fd2807SJeff Garzik 
1183c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
1184c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
1185c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
1186c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
1187c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
1188c6fd2807SJeff Garzik 
1189c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
1190c6fd2807SJeff Garzik }
1191c6fd2807SJeff Garzik 
1192c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
1193c6fd2807SJeff Garzik 			       u32 opts)
1194c6fd2807SJeff Garzik {
1195c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
1196c6fd2807SJeff Garzik 
1197c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
1198c6fd2807SJeff Garzik 
1199c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
1200c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
1201c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
1202c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
1203c6fd2807SJeff Garzik }
1204c6fd2807SJeff Garzik 
1205d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart)
1206c6fd2807SJeff Garzik {
1207350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1208cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1209520d06f9STejun Heo 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1210c6fd2807SJeff Garzik 	u32 tmp;
1211d2e75dffSTejun Heo 	int busy, rc;
1212c6fd2807SJeff Garzik 
1213d2e75dffSTejun Heo 	/* do we need to kick the port? */
1214520d06f9STejun Heo 	busy = status & (ATA_BUSY | ATA_DRQ);
1215d2e75dffSTejun Heo 	if (!busy && !force_restart)
1216d2e75dffSTejun Heo 		return 0;
1217c6fd2807SJeff Garzik 
1218d2e75dffSTejun Heo 	/* stop engine */
1219d2e75dffSTejun Heo 	rc = ahci_stop_engine(ap);
1220d2e75dffSTejun Heo 	if (rc)
1221d2e75dffSTejun Heo 		goto out_restart;
1222d2e75dffSTejun Heo 
1223d2e75dffSTejun Heo 	/* need to do CLO? */
1224d2e75dffSTejun Heo 	if (!busy) {
1225d2e75dffSTejun Heo 		rc = 0;
1226d2e75dffSTejun Heo 		goto out_restart;
1227d2e75dffSTejun Heo 	}
1228d2e75dffSTejun Heo 
1229d2e75dffSTejun Heo 	if (!(hpriv->cap & HOST_CAP_CLO)) {
1230d2e75dffSTejun Heo 		rc = -EOPNOTSUPP;
1231d2e75dffSTejun Heo 		goto out_restart;
1232d2e75dffSTejun Heo 	}
1233d2e75dffSTejun Heo 
1234d2e75dffSTejun Heo 	/* perform CLO */
1235c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1236c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
1237c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1238c6fd2807SJeff Garzik 
1239d2e75dffSTejun Heo 	rc = 0;
1240c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1241c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
1242c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
1243d2e75dffSTejun Heo 		rc = -EIO;
1244c6fd2807SJeff Garzik 
1245d2e75dffSTejun Heo 	/* restart engine */
1246d2e75dffSTejun Heo  out_restart:
1247d2e75dffSTejun Heo 	ahci_start_engine(ap);
1248d2e75dffSTejun Heo 	return rc;
1249c6fd2807SJeff Garzik }
1250c6fd2807SJeff Garzik 
125191c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
125291c4a2e0STejun Heo 				struct ata_taskfile *tf, int is_cmd, u16 flags,
125391c4a2e0STejun Heo 				unsigned long timeout_msec)
125491c4a2e0STejun Heo {
125591c4a2e0STejun Heo 	const u32 cmd_fis_len = 5; /* five dwords */
125691c4a2e0STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
125791c4a2e0STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
125891c4a2e0STejun Heo 	u8 *fis = pp->cmd_tbl;
125991c4a2e0STejun Heo 	u32 tmp;
126091c4a2e0STejun Heo 
126191c4a2e0STejun Heo 	/* prep the command */
126291c4a2e0STejun Heo 	ata_tf_to_fis(tf, pmp, is_cmd, fis);
126391c4a2e0STejun Heo 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
126491c4a2e0STejun Heo 
126591c4a2e0STejun Heo 	/* issue & wait */
126691c4a2e0STejun Heo 	writel(1, port_mmio + PORT_CMD_ISSUE);
126791c4a2e0STejun Heo 
126891c4a2e0STejun Heo 	if (timeout_msec) {
126991c4a2e0STejun Heo 		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
127091c4a2e0STejun Heo 					1, timeout_msec);
127191c4a2e0STejun Heo 		if (tmp & 0x1) {
127291c4a2e0STejun Heo 			ahci_kick_engine(ap, 1);
127391c4a2e0STejun Heo 			return -EBUSY;
127491c4a2e0STejun Heo 		}
127591c4a2e0STejun Heo 	} else
127691c4a2e0STejun Heo 		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
127791c4a2e0STejun Heo 
127891c4a2e0STejun Heo 	return 0;
127991c4a2e0STejun Heo }
128091c4a2e0STejun Heo 
1281a89611e8STejun Heo static int ahci_check_ready(struct ata_link *link)
1282a89611e8STejun Heo {
1283350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
1284350756f6STejun Heo 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1285a89611e8STejun Heo 
128678ab88f0STejun Heo 	return ata_check_ready(status);
1287a89611e8STejun Heo }
1288a89611e8STejun Heo 
1289071f44b1STejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class,
1290071f44b1STejun Heo 			  unsigned long deadline)
1291c6fd2807SJeff Garzik {
1292cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1293071f44b1STejun Heo 	int pmp = sata_srst_pmp(link);
1294c6fd2807SJeff Garzik 	const char *reason = NULL;
12952cbb79ebSTejun Heo 	unsigned long now, msecs;
1296c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1297c6fd2807SJeff Garzik 	int rc;
1298c6fd2807SJeff Garzik 
1299c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1300c6fd2807SJeff Garzik 
1301c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
1302d2e75dffSTejun Heo 	rc = ahci_kick_engine(ap, 1);
1303994056d7STejun Heo 	if (rc && rc != -EOPNOTSUPP)
1304cc0680a5STejun Heo 		ata_link_printk(link, KERN_WARNING,
1305994056d7STejun Heo 				"failed to reset engine (errno=%d)\n", rc);
1306c6fd2807SJeff Garzik 
1307cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1308c6fd2807SJeff Garzik 
1309c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
13102cbb79ebSTejun Heo 	msecs = 0;
13112cbb79ebSTejun Heo 	now = jiffies;
13122cbb79ebSTejun Heo 	if (time_after(now, deadline))
13132cbb79ebSTejun Heo 		msecs = jiffies_to_msecs(deadline - now);
13142cbb79ebSTejun Heo 
1315c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
1316a9cf5e85STejun Heo 	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
131791c4a2e0STejun Heo 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
1318c6fd2807SJeff Garzik 		rc = -EIO;
1319c6fd2807SJeff Garzik 		reason = "1st FIS failed";
1320c6fd2807SJeff Garzik 		goto fail;
1321c6fd2807SJeff Garzik 	}
1322c6fd2807SJeff Garzik 
1323c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
1324c6fd2807SJeff Garzik 	msleep(1);
1325c6fd2807SJeff Garzik 
1326c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
1327c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
1328a9cf5e85STejun Heo 	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1329c6fd2807SJeff Garzik 
1330705e76beSTejun Heo 	/* wait for link to become ready */
1331a89611e8STejun Heo 	rc = ata_wait_after_reset(link, deadline, ahci_check_ready);
13329b89391cSTejun Heo 	/* link occupied, -ENODEV too is an error */
13339b89391cSTejun Heo 	if (rc) {
1334c6fd2807SJeff Garzik 		reason = "device not ready";
1335c6fd2807SJeff Garzik 		goto fail;
1336c6fd2807SJeff Garzik 	}
1337c6fd2807SJeff Garzik 	*class = ahci_dev_classify(ap);
1338c6fd2807SJeff Garzik 
1339c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
1340c6fd2807SJeff Garzik 	return 0;
1341c6fd2807SJeff Garzik 
1342c6fd2807SJeff Garzik  fail:
1343cc0680a5STejun Heo 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
1344c6fd2807SJeff Garzik 	return rc;
1345c6fd2807SJeff Garzik }
1346c6fd2807SJeff Garzik 
1347cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1348d4b2bab4STejun Heo 			  unsigned long deadline)
1349c6fd2807SJeff Garzik {
13509dadd45bSTejun Heo 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
1351cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1352c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1353c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1354c6fd2807SJeff Garzik 	struct ata_taskfile tf;
13559dadd45bSTejun Heo 	bool online;
1356c6fd2807SJeff Garzik 	int rc;
1357c6fd2807SJeff Garzik 
1358c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1359c6fd2807SJeff Garzik 
13604447d351STejun Heo 	ahci_stop_engine(ap);
1361c6fd2807SJeff Garzik 
1362c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1363cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1364dfd7a3dbSTejun Heo 	tf.command = 0x80;
13659977126cSTejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1366c6fd2807SJeff Garzik 
13679dadd45bSTejun Heo 	rc = sata_link_hardreset(link, timing, deadline, &online,
13689dadd45bSTejun Heo 				 ahci_check_ready);
1369c6fd2807SJeff Garzik 
13704447d351STejun Heo 	ahci_start_engine(ap);
1371c6fd2807SJeff Garzik 
13729dadd45bSTejun Heo 	if (online)
13739dadd45bSTejun Heo 		*class = ahci_dev_classify(ap);
1374c6fd2807SJeff Garzik 
1375c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1376c6fd2807SJeff Garzik 	return rc;
1377c6fd2807SJeff Garzik }
1378c6fd2807SJeff Garzik 
1379cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1380d4b2bab4STejun Heo 				 unsigned long deadline)
1381ad616ffbSTejun Heo {
1382cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
13839dadd45bSTejun Heo 	bool online;
1384ad616ffbSTejun Heo 	int rc;
1385ad616ffbSTejun Heo 
1386ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1387ad616ffbSTejun Heo 
13884447d351STejun Heo 	ahci_stop_engine(ap);
1389ad616ffbSTejun Heo 
1390cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
13919dadd45bSTejun Heo 				 deadline, &online, NULL);
1392ad616ffbSTejun Heo 
13934447d351STejun Heo 	ahci_start_engine(ap);
1394ad616ffbSTejun Heo 
1395ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1396ad616ffbSTejun Heo 
1397ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1398ad616ffbSTejun Heo 	 * request follow-up softreset.
1399ad616ffbSTejun Heo 	 */
14009dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
1401ad616ffbSTejun Heo }
1402ad616ffbSTejun Heo 
1403edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1404edc93052STejun Heo 				unsigned long deadline)
1405edc93052STejun Heo {
1406edc93052STejun Heo 	struct ata_port *ap = link->ap;
1407edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1408edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1409edc93052STejun Heo 	struct ata_taskfile tf;
14109dadd45bSTejun Heo 	bool online;
1411edc93052STejun Heo 	int rc;
1412edc93052STejun Heo 
1413edc93052STejun Heo 	ahci_stop_engine(ap);
1414edc93052STejun Heo 
1415edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
1416edc93052STejun Heo 	ata_tf_init(link->device, &tf);
1417edc93052STejun Heo 	tf.command = 0x80;
1418edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1419edc93052STejun Heo 
1420edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
14219dadd45bSTejun Heo 				 deadline, &online, NULL);
1422edc93052STejun Heo 
1423edc93052STejun Heo 	ahci_start_engine(ap);
1424edc93052STejun Heo 
1425edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
1426edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1427edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
1428edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
1429edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
1430edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1431edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1432edc93052STejun Heo 	 *
1433edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
1434edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
1435edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
1436edc93052STejun Heo 	 * suffice while making probing snappish enough.
1437edc93052STejun Heo 	 */
14389dadd45bSTejun Heo 	if (online) {
14399dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
14409dadd45bSTejun Heo 					  ahci_check_ready);
1441edc93052STejun Heo 		if (rc)
1442edc93052STejun Heo 			ahci_kick_engine(ap, 0);
14439dadd45bSTejun Heo 	}
14449dadd45bSTejun Heo 	return rc;
1445edc93052STejun Heo }
1446edc93052STejun Heo 
1447cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class)
1448c6fd2807SJeff Garzik {
1449cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
14504447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1451c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1452c6fd2807SJeff Garzik 
1453203c75b8STejun Heo 	ata_std_postreset(link, class);
1454c6fd2807SJeff Garzik 
1455c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1456c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1457c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1458c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
1459c6fd2807SJeff Garzik 	else
1460c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
1461c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
1462c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
1463c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
1464c6fd2807SJeff Garzik 	}
1465c6fd2807SJeff Garzik }
1466c6fd2807SJeff Garzik 
1467c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
1468c6fd2807SJeff Garzik {
1469c6fd2807SJeff Garzik 	struct scatterlist *sg;
1470ff2aeb1eSTejun Heo 	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
1471ff2aeb1eSTejun Heo 	unsigned int si;
1472c6fd2807SJeff Garzik 
1473c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1474c6fd2807SJeff Garzik 
1475c6fd2807SJeff Garzik 	/*
1476c6fd2807SJeff Garzik 	 * Next, the S/G list.
1477c6fd2807SJeff Garzik 	 */
1478ff2aeb1eSTejun Heo 	for_each_sg(qc->sg, sg, qc->n_elem, si) {
1479c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1480c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1481c6fd2807SJeff Garzik 
1482ff2aeb1eSTejun Heo 		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
1483ff2aeb1eSTejun Heo 		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
1484ff2aeb1eSTejun Heo 		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
1485c6fd2807SJeff Garzik 	}
1486c6fd2807SJeff Garzik 
1487ff2aeb1eSTejun Heo 	return si;
1488c6fd2807SJeff Garzik }
1489c6fd2807SJeff Garzik 
1490c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1491c6fd2807SJeff Garzik {
1492c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1493c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1494405e66b3STejun Heo 	int is_atapi = ata_is_atapi(qc->tf.protocol);
1495c6fd2807SJeff Garzik 	void *cmd_tbl;
1496c6fd2807SJeff Garzik 	u32 opts;
1497c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1498c6fd2807SJeff Garzik 	unsigned int n_elem;
1499c6fd2807SJeff Garzik 
1500c6fd2807SJeff Garzik 	/*
1501c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1502c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1503c6fd2807SJeff Garzik 	 */
1504c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1505c6fd2807SJeff Garzik 
15067d50b60bSTejun Heo 	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
1507c6fd2807SJeff Garzik 	if (is_atapi) {
1508c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1509c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1510c6fd2807SJeff Garzik 	}
1511c6fd2807SJeff Garzik 
1512c6fd2807SJeff Garzik 	n_elem = 0;
1513c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1514c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1515c6fd2807SJeff Garzik 
1516c6fd2807SJeff Garzik 	/*
1517c6fd2807SJeff Garzik 	 * Fill in command slot information.
1518c6fd2807SJeff Garzik 	 */
15197d50b60bSTejun Heo 	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
1520c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1521c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1522c6fd2807SJeff Garzik 	if (is_atapi)
1523c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1524c6fd2807SJeff Garzik 
1525c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1526c6fd2807SJeff Garzik }
1527c6fd2807SJeff Garzik 
1528c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1529c6fd2807SJeff Garzik {
1530417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1531c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
15327d50b60bSTejun Heo 	struct ata_eh_info *host_ehi = &ap->link.eh_info;
15337d50b60bSTejun Heo 	struct ata_link *link = NULL;
15347d50b60bSTejun Heo 	struct ata_queued_cmd *active_qc;
15357d50b60bSTejun Heo 	struct ata_eh_info *active_ehi;
1536c6fd2807SJeff Garzik 	u32 serror;
1537c6fd2807SJeff Garzik 
15387d50b60bSTejun Heo 	/* determine active link */
15397d50b60bSTejun Heo 	ata_port_for_each_link(link, ap)
15407d50b60bSTejun Heo 		if (ata_link_active(link))
15417d50b60bSTejun Heo 			break;
15427d50b60bSTejun Heo 	if (!link)
15437d50b60bSTejun Heo 		link = &ap->link;
15447d50b60bSTejun Heo 
15457d50b60bSTejun Heo 	active_qc = ata_qc_from_tag(ap, link->active_tag);
15467d50b60bSTejun Heo 	active_ehi = &link->eh_info;
15477d50b60bSTejun Heo 
15487d50b60bSTejun Heo 	/* record irq stat */
15497d50b60bSTejun Heo 	ata_ehi_clear_desc(host_ehi);
15507d50b60bSTejun Heo 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
1551c6fd2807SJeff Garzik 
1552c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
1553da3dbb17STejun Heo 	ahci_scr_read(ap, SCR_ERROR, &serror);
1554c6fd2807SJeff Garzik 	ahci_scr_write(ap, SCR_ERROR, serror);
15557d50b60bSTejun Heo 	host_ehi->serror |= serror;
1556c6fd2807SJeff Garzik 
155741669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
1558417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
155941669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
156041669553STejun Heo 
156155a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
15627d50b60bSTejun Heo 		/* If qc is active, charge it; otherwise, the active
15637d50b60bSTejun Heo 		 * link.  There's no active qc on NCQ errors.  It will
15647d50b60bSTejun Heo 		 * be determined by EH by reading log page 10h.
15657d50b60bSTejun Heo 		 */
15667d50b60bSTejun Heo 		if (active_qc)
15677d50b60bSTejun Heo 			active_qc->err_mask |= AC_ERR_DEV;
15687d50b60bSTejun Heo 		else
15697d50b60bSTejun Heo 			active_ehi->err_mask |= AC_ERR_DEV;
15707d50b60bSTejun Heo 
1571417a1a6dSTejun Heo 		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
15727d50b60bSTejun Heo 			host_ehi->serror &= ~SERR_INTERNAL;
1573c6fd2807SJeff Garzik 	}
1574c6fd2807SJeff Garzik 
1575c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
1576c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
1577c6fd2807SJeff Garzik 
15787d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
1579cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
15807d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi,
15817d50b60bSTejun Heo 				  "unknown FIS %08x %08x %08x %08x" ,
1582c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
1583c6fd2807SJeff Garzik 	}
1584c6fd2807SJeff Garzik 
1585071f44b1STejun Heo 	if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
15867d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
1587cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
15887d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi, "incorrect PMP");
15897d50b60bSTejun Heo 	}
1590c6fd2807SJeff Garzik 
15917d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
15927d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_HOST_BUS;
1593cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
15947d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "host bus error");
15957d50b60bSTejun Heo 	}
15967d50b60bSTejun Heo 
15977d50b60bSTejun Heo 	if (irq_stat & PORT_IRQ_IF_ERR) {
15987d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_ATA_BUS;
1599cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
16007d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "interface fatal error");
16017d50b60bSTejun Heo 	}
16027d50b60bSTejun Heo 
16037d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
16047d50b60bSTejun Heo 		ata_ehi_hotplugged(host_ehi);
16057d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "%s",
16067d50b60bSTejun Heo 			irq_stat & PORT_IRQ_CONNECT ?
16077d50b60bSTejun Heo 			"connection status changed" : "PHY RDY changed");
16087d50b60bSTejun Heo 	}
16097d50b60bSTejun Heo 
16107d50b60bSTejun Heo 	/* okay, let's hand over to EH */
1611c6fd2807SJeff Garzik 
1612c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
1613c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1614c6fd2807SJeff Garzik 	else
1615c6fd2807SJeff Garzik 		ata_port_abort(ap);
1616c6fd2807SJeff Garzik }
1617c6fd2807SJeff Garzik 
1618df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap)
1619c6fd2807SJeff Garzik {
1620350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
16219af5c9c9STejun Heo 	struct ata_eh_info *ehi = &ap->link.eh_info;
16220291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
16235f226c6bSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1624b06ce3e5STejun Heo 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
1625c6fd2807SJeff Garzik 	u32 status, qc_active;
1626459ad688STejun Heo 	int rc;
1627c6fd2807SJeff Garzik 
1628c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
1629c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
1630c6fd2807SJeff Garzik 
1631b06ce3e5STejun Heo 	/* ignore BAD_PMP while resetting */
1632b06ce3e5STejun Heo 	if (unlikely(resetting))
1633b06ce3e5STejun Heo 		status &= ~PORT_IRQ_BAD_PMP;
1634b06ce3e5STejun Heo 
163531556594SKristen Carlson Accardi 	/* If we are getting PhyRdy, this is
163631556594SKristen Carlson Accardi  	 * just a power state change, we should
163731556594SKristen Carlson Accardi  	 * clear out this, plus the PhyRdy/Comm
163831556594SKristen Carlson Accardi  	 * Wake bits from Serror
163931556594SKristen Carlson Accardi  	 */
164031556594SKristen Carlson Accardi 	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
164131556594SKristen Carlson Accardi 		(status & PORT_IRQ_PHYRDY)) {
164231556594SKristen Carlson Accardi 		status &= ~PORT_IRQ_PHYRDY;
164331556594SKristen Carlson Accardi 		ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
164431556594SKristen Carlson Accardi 	}
164531556594SKristen Carlson Accardi 
1646c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
1647c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
1648c6fd2807SJeff Garzik 		return;
1649c6fd2807SJeff Garzik 	}
1650c6fd2807SJeff Garzik 
16512f294968SKristen Carlson Accardi 	if (status & PORT_IRQ_SDB_FIS) {
16525f226c6bSTejun Heo 		/* If SNotification is available, leave notification
16535f226c6bSTejun Heo 		 * handling to sata_async_notification().  If not,
16545f226c6bSTejun Heo 		 * emulate it by snooping SDB FIS RX area.
16555f226c6bSTejun Heo 		 *
16565f226c6bSTejun Heo 		 * Snooping FIS RX area is probably cheaper than
16575f226c6bSTejun Heo 		 * poking SNotification but some constrollers which
16585f226c6bSTejun Heo 		 * implement SNotification, ICH9 for example, don't
16595f226c6bSTejun Heo 		 * store AN SDB FIS into receive area.
16605f226c6bSTejun Heo 		 */
16615f226c6bSTejun Heo 		if (hpriv->cap & HOST_CAP_SNTF)
16625f226c6bSTejun Heo 			sata_async_notification(ap);
16635f226c6bSTejun Heo 		else {
16645f226c6bSTejun Heo 			/* If the 'N' bit in word 0 of the FIS is set,
16655f226c6bSTejun Heo 			 * we just received asynchronous notification.
16665f226c6bSTejun Heo 			 * Tell libata about it.
16672f294968SKristen Carlson Accardi 			 */
16682f294968SKristen Carlson Accardi 			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
16692f294968SKristen Carlson Accardi 			u32 f0 = le32_to_cpu(f[0]);
16702f294968SKristen Carlson Accardi 
16717d77b247STejun Heo 			if (f0 & (1 << 15))
16727d77b247STejun Heo 				sata_async_notification(ap);
16732f294968SKristen Carlson Accardi 		}
16745f226c6bSTejun Heo 	}
16752f294968SKristen Carlson Accardi 
16767d50b60bSTejun Heo 	/* pp->active_link is valid iff any command is in flight */
16777d50b60bSTejun Heo 	if (ap->qc_active && pp->active_link->sactive)
1678c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
1679c6fd2807SJeff Garzik 	else
1680c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
1681c6fd2807SJeff Garzik 
168279f97dadSTejun Heo 	rc = ata_qc_complete_multiple(ap, qc_active);
1683b06ce3e5STejun Heo 
1684459ad688STejun Heo 	/* while resetting, invalid completions are expected */
1685459ad688STejun Heo 	if (unlikely(rc < 0 && !resetting)) {
1686c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
1687cf480626STejun Heo 		ehi->action |= ATA_EH_RESET;
1688c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1689c6fd2807SJeff Garzik 	}
1690c6fd2807SJeff Garzik }
1691c6fd2807SJeff Garzik 
16927d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1693c6fd2807SJeff Garzik {
1694cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
1695c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1696c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
1697c6fd2807SJeff Garzik 	void __iomem *mmio;
1698c6fd2807SJeff Garzik 	u32 irq_stat, irq_ack = 0;
1699c6fd2807SJeff Garzik 
1700c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1701c6fd2807SJeff Garzik 
1702cca3974eSJeff Garzik 	hpriv = host->private_data;
17030d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
1704c6fd2807SJeff Garzik 
1705c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
1706c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
1707c6fd2807SJeff Garzik 	irq_stat &= hpriv->port_map;
1708c6fd2807SJeff Garzik 	if (!irq_stat)
1709c6fd2807SJeff Garzik 		return IRQ_NONE;
1710c6fd2807SJeff Garzik 
1711cca3974eSJeff Garzik 	spin_lock(&host->lock);
1712c6fd2807SJeff Garzik 
1713cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
1714c6fd2807SJeff Garzik 		struct ata_port *ap;
1715c6fd2807SJeff Garzik 
1716c6fd2807SJeff Garzik 		if (!(irq_stat & (1 << i)))
1717c6fd2807SJeff Garzik 			continue;
1718c6fd2807SJeff Garzik 
1719cca3974eSJeff Garzik 		ap = host->ports[i];
1720c6fd2807SJeff Garzik 		if (ap) {
1721df69c9c5SJeff Garzik 			ahci_port_intr(ap);
1722c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
1723c6fd2807SJeff Garzik 		} else {
1724c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
1725c6fd2807SJeff Garzik 			if (ata_ratelimit())
1726cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
1727c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
1728c6fd2807SJeff Garzik 		}
1729c6fd2807SJeff Garzik 
1730c6fd2807SJeff Garzik 		irq_ack |= (1 << i);
1731c6fd2807SJeff Garzik 	}
1732c6fd2807SJeff Garzik 
1733c6fd2807SJeff Garzik 	if (irq_ack) {
1734c6fd2807SJeff Garzik 		writel(irq_ack, mmio + HOST_IRQ_STAT);
1735c6fd2807SJeff Garzik 		handled = 1;
1736c6fd2807SJeff Garzik 	}
1737c6fd2807SJeff Garzik 
1738cca3974eSJeff Garzik 	spin_unlock(&host->lock);
1739c6fd2807SJeff Garzik 
1740c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1741c6fd2807SJeff Garzik 
1742c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
1743c6fd2807SJeff Garzik }
1744c6fd2807SJeff Garzik 
1745c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
1746c6fd2807SJeff Garzik {
1747c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
17484447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
17497d50b60bSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
17507d50b60bSTejun Heo 
17517d50b60bSTejun Heo 	/* Keep track of the currently active link.  It will be used
17527d50b60bSTejun Heo 	 * in completion path to determine whether NCQ phase is in
17537d50b60bSTejun Heo 	 * progress.
17547d50b60bSTejun Heo 	 */
17557d50b60bSTejun Heo 	pp->active_link = qc->dev->link;
1756c6fd2807SJeff Garzik 
1757c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
1758c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
1759c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
1760c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
1761c6fd2807SJeff Garzik 
1762c6fd2807SJeff Garzik 	return 0;
1763c6fd2807SJeff Garzik }
1764c6fd2807SJeff Garzik 
17654c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
17664c9bf4e7STejun Heo {
17674c9bf4e7STejun Heo 	struct ahci_port_priv *pp = qc->ap->private_data;
17684c9bf4e7STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
17694c9bf4e7STejun Heo 
17704c9bf4e7STejun Heo 	ata_tf_from_fis(d2h_fis, &qc->result_tf);
17714c9bf4e7STejun Heo 	return true;
17724c9bf4e7STejun Heo }
17734c9bf4e7STejun Heo 
1774c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
1775c6fd2807SJeff Garzik {
17764447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1777c6fd2807SJeff Garzik 
1778c6fd2807SJeff Garzik 	/* turn IRQ off */
1779c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
1780c6fd2807SJeff Garzik }
1781c6fd2807SJeff Garzik 
1782c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
1783c6fd2807SJeff Garzik {
17840d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
17854447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1786c6fd2807SJeff Garzik 	u32 tmp;
1787a7384925SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
1788c6fd2807SJeff Garzik 
1789c6fd2807SJeff Garzik 	/* clear IRQ */
1790c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1791c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
1792a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
1793c6fd2807SJeff Garzik 
17941c954a4dSTejun Heo 	/* turn IRQ back on */
17951c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
1796c6fd2807SJeff Garzik }
1797c6fd2807SJeff Garzik 
1798c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
1799c6fd2807SJeff Garzik {
1800c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1801c6fd2807SJeff Garzik 		/* restart engine */
18024447d351STejun Heo 		ahci_stop_engine(ap);
18034447d351STejun Heo 		ahci_start_engine(ap);
1804c6fd2807SJeff Garzik 	}
1805c6fd2807SJeff Garzik 
1806a1efdabaSTejun Heo 	sata_pmp_error_handler(ap);
1807edc93052STejun Heo }
1808edc93052STejun Heo 
1809c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
1810c6fd2807SJeff Garzik {
1811c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1812c6fd2807SJeff Garzik 
1813c6fd2807SJeff Garzik 	/* make DMA engine forget about the failed command */
1814d2e75dffSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED)
1815d2e75dffSTejun Heo 		ahci_kick_engine(ap, 1);
1816c6fd2807SJeff Garzik }
1817c6fd2807SJeff Garzik 
18187d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap)
18197d50b60bSTejun Heo {
18207d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
18211c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
18227d50b60bSTejun Heo 	u32 cmd;
18237d50b60bSTejun Heo 
18247d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
18257d50b60bSTejun Heo 	cmd |= PORT_CMD_PMP;
18267d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
18271c954a4dSTejun Heo 
18281c954a4dSTejun Heo 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
18291c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
18307d50b60bSTejun Heo }
18317d50b60bSTejun Heo 
18327d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap)
18337d50b60bSTejun Heo {
18347d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
18351c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
18367d50b60bSTejun Heo 	u32 cmd;
18377d50b60bSTejun Heo 
18387d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
18397d50b60bSTejun Heo 	cmd &= ~PORT_CMD_PMP;
18407d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
18411c954a4dSTejun Heo 
18421c954a4dSTejun Heo 	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
18431c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
18447d50b60bSTejun Heo }
18457d50b60bSTejun Heo 
1846028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap)
1847028a2596SAlexey Dobriyan {
1848028a2596SAlexey Dobriyan 	ahci_power_up(ap);
1849028a2596SAlexey Dobriyan 	ahci_start_port(ap);
1850028a2596SAlexey Dobriyan 
1851071f44b1STejun Heo 	if (sata_pmp_attached(ap))
18527d50b60bSTejun Heo 		ahci_pmp_attach(ap);
18537d50b60bSTejun Heo 	else
18547d50b60bSTejun Heo 		ahci_pmp_detach(ap);
18557d50b60bSTejun Heo 
1856028a2596SAlexey Dobriyan 	return 0;
1857028a2596SAlexey Dobriyan }
1858028a2596SAlexey Dobriyan 
1859438ac6d5STejun Heo #ifdef CONFIG_PM
1860c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
1861c6fd2807SJeff Garzik {
1862c6fd2807SJeff Garzik 	const char *emsg = NULL;
1863c6fd2807SJeff Garzik 	int rc;
1864c6fd2807SJeff Garzik 
18654447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
18668e16f941STejun Heo 	if (rc == 0)
18674447d351STejun Heo 		ahci_power_down(ap);
18688e16f941STejun Heo 	else {
1869c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
1870df69c9c5SJeff Garzik 		ahci_start_port(ap);
1871c6fd2807SJeff Garzik 	}
1872c6fd2807SJeff Garzik 
1873c6fd2807SJeff Garzik 	return rc;
1874c6fd2807SJeff Garzik }
1875c6fd2807SJeff Garzik 
1876c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
1877c6fd2807SJeff Garzik {
1878cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
18790d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1880c6fd2807SJeff Garzik 	u32 ctl;
1881c6fd2807SJeff Garzik 
18823a2d5b70SRafael J. Wysocki 	if (mesg.event & PM_EVENT_SLEEP) {
1883c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
1884c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
1885c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
1886c6fd2807SJeff Garzik 		 */
1887c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
1888c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
1889c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
1890c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
1891c6fd2807SJeff Garzik 	}
1892c6fd2807SJeff Garzik 
1893c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
1894c6fd2807SJeff Garzik }
1895c6fd2807SJeff Garzik 
1896c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
1897c6fd2807SJeff Garzik {
1898cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
1899c6fd2807SJeff Garzik 	int rc;
1900c6fd2807SJeff Garzik 
1901553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
1902553c4aa6STejun Heo 	if (rc)
1903553c4aa6STejun Heo 		return rc;
1904c6fd2807SJeff Garzik 
1905c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
19064447d351STejun Heo 		rc = ahci_reset_controller(host);
1907c6fd2807SJeff Garzik 		if (rc)
1908c6fd2807SJeff Garzik 			return rc;
1909c6fd2807SJeff Garzik 
19104447d351STejun Heo 		ahci_init_controller(host);
1911c6fd2807SJeff Garzik 	}
1912c6fd2807SJeff Garzik 
1913cca3974eSJeff Garzik 	ata_host_resume(host);
1914c6fd2807SJeff Garzik 
1915c6fd2807SJeff Garzik 	return 0;
1916c6fd2807SJeff Garzik }
1917438ac6d5STejun Heo #endif
1918c6fd2807SJeff Garzik 
1919c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
1920c6fd2807SJeff Garzik {
1921cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
1922c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
1923c6fd2807SJeff Garzik 	void *mem;
1924c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
1925c6fd2807SJeff Garzik 
192624dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
1927c6fd2807SJeff Garzik 	if (!pp)
1928c6fd2807SJeff Garzik 		return -ENOMEM;
1929c6fd2807SJeff Garzik 
193024dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
193124dc5f33STejun Heo 				  GFP_KERNEL);
193224dc5f33STejun Heo 	if (!mem)
1933c6fd2807SJeff Garzik 		return -ENOMEM;
1934c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
1935c6fd2807SJeff Garzik 
1936c6fd2807SJeff Garzik 	/*
1937c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
1938c6fd2807SJeff Garzik 	 * 32 bytes each in size
1939c6fd2807SJeff Garzik 	 */
1940c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
1941c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
1942c6fd2807SJeff Garzik 
1943c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
1944c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
1945c6fd2807SJeff Garzik 
1946c6fd2807SJeff Garzik 	/*
1947c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
1948c6fd2807SJeff Garzik 	 */
1949c6fd2807SJeff Garzik 	pp->rx_fis = mem;
1950c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
1951c6fd2807SJeff Garzik 
1952c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
1953c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
1954c6fd2807SJeff Garzik 
1955c6fd2807SJeff Garzik 	/*
1956c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
1957c6fd2807SJeff Garzik 	 * and its scatter-gather table
1958c6fd2807SJeff Garzik 	 */
1959c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
1960c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
1961c6fd2807SJeff Garzik 
1962a7384925SKristen Carlson Accardi 	/*
1963a7384925SKristen Carlson Accardi 	 * Save off initial list of interrupts to be enabled.
1964a7384925SKristen Carlson Accardi 	 * This could be changed later
1965a7384925SKristen Carlson Accardi 	 */
1966a7384925SKristen Carlson Accardi 	pp->intr_mask = DEF_PORT_IRQ;
1967a7384925SKristen Carlson Accardi 
1968c6fd2807SJeff Garzik 	ap->private_data = pp;
1969c6fd2807SJeff Garzik 
1970df69c9c5SJeff Garzik 	/* engage engines, captain */
1971df69c9c5SJeff Garzik 	return ahci_port_resume(ap);
1972c6fd2807SJeff Garzik }
1973c6fd2807SJeff Garzik 
1974c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
1975c6fd2807SJeff Garzik {
1976c6fd2807SJeff Garzik 	const char *emsg = NULL;
1977c6fd2807SJeff Garzik 	int rc;
1978c6fd2807SJeff Garzik 
1979c6fd2807SJeff Garzik 	/* de-initialize port */
19804447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1981c6fd2807SJeff Garzik 	if (rc)
1982c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
1983c6fd2807SJeff Garzik }
1984c6fd2807SJeff Garzik 
19854447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
1986c6fd2807SJeff Garzik {
1987c6fd2807SJeff Garzik 	int rc;
1988c6fd2807SJeff Garzik 
1989c6fd2807SJeff Garzik 	if (using_dac &&
1990c6fd2807SJeff Garzik 	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
1991c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
1992c6fd2807SJeff Garzik 		if (rc) {
1993c6fd2807SJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1994c6fd2807SJeff Garzik 			if (rc) {
1995c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
1996c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
1997c6fd2807SJeff Garzik 				return rc;
1998c6fd2807SJeff Garzik 			}
1999c6fd2807SJeff Garzik 		}
2000c6fd2807SJeff Garzik 	} else {
2001c6fd2807SJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
2002c6fd2807SJeff Garzik 		if (rc) {
2003c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2004c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
2005c6fd2807SJeff Garzik 			return rc;
2006c6fd2807SJeff Garzik 		}
2007c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
2008c6fd2807SJeff Garzik 		if (rc) {
2009c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2010c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
2011c6fd2807SJeff Garzik 			return rc;
2012c6fd2807SJeff Garzik 		}
2013c6fd2807SJeff Garzik 	}
2014c6fd2807SJeff Garzik 	return 0;
2015c6fd2807SJeff Garzik }
2016c6fd2807SJeff Garzik 
20174447d351STejun Heo static void ahci_print_info(struct ata_host *host)
2018c6fd2807SJeff Garzik {
20194447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
20204447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
20214447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2022c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
2023c6fd2807SJeff Garzik 	const char *speed_s;
2024c6fd2807SJeff Garzik 	u16 cc;
2025c6fd2807SJeff Garzik 	const char *scc_s;
2026c6fd2807SJeff Garzik 
2027c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
2028c6fd2807SJeff Garzik 	cap = hpriv->cap;
2029c6fd2807SJeff Garzik 	impl = hpriv->port_map;
2030c6fd2807SJeff Garzik 
2031c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
2032c6fd2807SJeff Garzik 	if (speed == 1)
2033c6fd2807SJeff Garzik 		speed_s = "1.5";
2034c6fd2807SJeff Garzik 	else if (speed == 2)
2035c6fd2807SJeff Garzik 		speed_s = "3";
2036c6fd2807SJeff Garzik 	else
2037c6fd2807SJeff Garzik 		speed_s = "?";
2038c6fd2807SJeff Garzik 
2039c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
2040c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
2041c6fd2807SJeff Garzik 		scc_s = "IDE";
2042c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
2043c6fd2807SJeff Garzik 		scc_s = "SATA";
2044c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
2045c6fd2807SJeff Garzik 		scc_s = "RAID";
2046c6fd2807SJeff Garzik 	else
2047c6fd2807SJeff Garzik 		scc_s = "unknown";
2048c6fd2807SJeff Garzik 
2049c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2050c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
2051c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
2052c6fd2807SJeff Garzik 		,
2053c6fd2807SJeff Garzik 
2054c6fd2807SJeff Garzik 		(vers >> 24) & 0xff,
2055c6fd2807SJeff Garzik 		(vers >> 16) & 0xff,
2056c6fd2807SJeff Garzik 		(vers >> 8) & 0xff,
2057c6fd2807SJeff Garzik 		vers & 0xff,
2058c6fd2807SJeff Garzik 
2059c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
2060c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
2061c6fd2807SJeff Garzik 		speed_s,
2062c6fd2807SJeff Garzik 		impl,
2063c6fd2807SJeff Garzik 		scc_s);
2064c6fd2807SJeff Garzik 
2065c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2066c6fd2807SJeff Garzik 		"flags: "
2067203ef6c4STejun Heo 		"%s%s%s%s%s%s%s"
2068c6fd2807SJeff Garzik 		"%s%s%s%s%s%s%s\n"
2069c6fd2807SJeff Garzik 		,
2070c6fd2807SJeff Garzik 
2071c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
2072c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
2073203ef6c4STejun Heo 		cap & (1 << 29) ? "sntf " : "",
2074c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
2075c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
2076c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
2077c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
2078c6fd2807SJeff Garzik 
2079c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
2080c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
2081c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
2082c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
2083c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
2084c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
2085c6fd2807SJeff Garzik 		cap & (1 << 13) ? "part " : ""
2086c6fd2807SJeff Garzik 		);
2087c6fd2807SJeff Garzik }
2088c6fd2807SJeff Garzik 
2089edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2090edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
2091edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
2092edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
2093edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
2094edc93052STejun Heo  * other configuration).
2095edc93052STejun Heo  *
2096edc93052STejun Heo  * When there's no device attached to the first downstream port of the
2097edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
2098edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
2099edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
2100edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2101edc93052STejun Heo  *
2102edc93052STejun Heo  * The following function works around the problem by always using
2103edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
2104edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
2105edc93052STejun Heo  * assumed without follow-up softreset.
2106edc93052STejun Heo  */
2107edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
2108edc93052STejun Heo {
2109edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
2110edc93052STejun Heo 		{
2111edc93052STejun Heo 			.ident = "P5W DH Deluxe",
2112edc93052STejun Heo 			.matches = {
2113edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
2114edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
2115edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2116edc93052STejun Heo 			},
2117edc93052STejun Heo 		},
2118edc93052STejun Heo 		{ }
2119edc93052STejun Heo 	};
2120edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
2121edc93052STejun Heo 
2122edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2123edc93052STejun Heo 	    dmi_check_system(sysids)) {
2124edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
2125edc93052STejun Heo 
2126edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2127edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
2128edc93052STejun Heo 
2129edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
2130edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2131edc93052STejun Heo 	}
2132edc93052STejun Heo }
2133edc93052STejun Heo 
2134c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2135c6fd2807SJeff Garzik {
2136c6fd2807SJeff Garzik 	static int printed_version;
2137*e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
2138*e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
21394447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
214024dc5f33STejun Heo 	struct device *dev = &pdev->dev;
2141c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
21424447d351STejun Heo 	struct ata_host *host;
2143837f5f8fSTejun Heo 	int n_ports, i, rc;
2144c6fd2807SJeff Garzik 
2145c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2146c6fd2807SJeff Garzik 
2147c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
2148c6fd2807SJeff Garzik 
2149c6fd2807SJeff Garzik 	if (!printed_version++)
2150c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
2151c6fd2807SJeff Garzik 
21524447d351STejun Heo 	/* acquire resources */
215324dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
2154c6fd2807SJeff Garzik 	if (rc)
2155c6fd2807SJeff Garzik 		return rc;
2156c6fd2807SJeff Garzik 
2157dea55137STejun Heo 	/* AHCI controllers often implement SFF compatible interface.
2158dea55137STejun Heo 	 * Grab all PCI BARs just in case.
2159dea55137STejun Heo 	 */
2160dea55137STejun Heo 	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
21610d5ff566STejun Heo 	if (rc == -EBUSY)
216224dc5f33STejun Heo 		pcim_pin_device(pdev);
21630d5ff566STejun Heo 	if (rc)
216424dc5f33STejun Heo 		return rc;
2165c6fd2807SJeff Garzik 
2166c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
2167c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
2168c4f7792cSTejun Heo 		u8 map;
2169c4f7792cSTejun Heo 
2170c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
2171c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
2172c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
2173c4f7792cSTejun Heo 		 */
2174c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
2175c4f7792cSTejun Heo 		if (map & 0x3) {
2176c4f7792cSTejun Heo 			dev_printk(KERN_INFO, &pdev->dev, "controller is in "
2177c4f7792cSTejun Heo 				   "combined mode, can't enable AHCI mode\n");
2178c4f7792cSTejun Heo 			return -ENODEV;
2179c4f7792cSTejun Heo 		}
2180c4f7792cSTejun Heo 	}
2181c4f7792cSTejun Heo 
218224dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
218324dc5f33STejun Heo 	if (!hpriv)
218424dc5f33STejun Heo 		return -ENOMEM;
2185417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
2186417a1a6dSTejun Heo 
2187*e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
2188*e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
2189*e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
2190*e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
2191*e297d99eSTejun Heo 
2192417a1a6dSTejun Heo 	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
2193417a1a6dSTejun Heo 		pci_intx(pdev, 1);
2194c6fd2807SJeff Garzik 
21954447d351STejun Heo 	/* save initial config */
2196417a1a6dSTejun Heo 	ahci_save_initial_config(pdev, hpriv);
2197c6fd2807SJeff Garzik 
21984447d351STejun Heo 	/* prepare host */
2199274c1fdeSTejun Heo 	if (hpriv->cap & HOST_CAP_NCQ)
22004447d351STejun Heo 		pi.flags |= ATA_FLAG_NCQ;
22014447d351STejun Heo 
22027d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
22037d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
22047d50b60bSTejun Heo 
2205837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
2206837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
2207837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
2208837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
2209837f5f8fSTejun Heo 	 */
2210837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
2211837f5f8fSTejun Heo 
2212837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
22134447d351STejun Heo 	if (!host)
22144447d351STejun Heo 		return -ENOMEM;
22154447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
22164447d351STejun Heo 	host->private_data = hpriv;
22174447d351STejun Heo 
22184447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
22194447d351STejun Heo 		struct ata_port *ap = host->ports[i];
22204447d351STejun Heo 
2221cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
2222cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
2223cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
2224cbcdd875STejun Heo 
222531556594SKristen Carlson Accardi 		/* set initial link pm policy */
222631556594SKristen Carlson Accardi 		ap->pm_policy = NOT_AVAILABLE;
222731556594SKristen Carlson Accardi 
2228dab632e8SJeff Garzik 		/* disabled/not-implemented port */
2229350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
2230dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
22314447d351STejun Heo 	}
2232c6fd2807SJeff Garzik 
2233edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
2234edc93052STejun Heo 	ahci_p5wdh_workaround(host);
2235edc93052STejun Heo 
2236c6fd2807SJeff Garzik 	/* initialize adapter */
22374447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
2238c6fd2807SJeff Garzik 	if (rc)
223924dc5f33STejun Heo 		return rc;
2240c6fd2807SJeff Garzik 
22414447d351STejun Heo 	rc = ahci_reset_controller(host);
22424447d351STejun Heo 	if (rc)
22434447d351STejun Heo 		return rc;
2244c6fd2807SJeff Garzik 
22454447d351STejun Heo 	ahci_init_controller(host);
22464447d351STejun Heo 	ahci_print_info(host);
2247c6fd2807SJeff Garzik 
22484447d351STejun Heo 	pci_set_master(pdev);
22494447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
22504447d351STejun Heo 				 &ahci_sht);
2251c6fd2807SJeff Garzik }
2252c6fd2807SJeff Garzik 
2253c6fd2807SJeff Garzik static int __init ahci_init(void)
2254c6fd2807SJeff Garzik {
2255c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
2256c6fd2807SJeff Garzik }
2257c6fd2807SJeff Garzik 
2258c6fd2807SJeff Garzik static void __exit ahci_exit(void)
2259c6fd2807SJeff Garzik {
2260c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
2261c6fd2807SJeff Garzik }
2262c6fd2807SJeff Garzik 
2263c6fd2807SJeff Garzik 
2264c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
2265c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
2266c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
2267c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
2268c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
2269c6fd2807SJeff Garzik 
2270c6fd2807SJeff Garzik module_init(ahci_init);
2271c6fd2807SJeff Garzik module_exit(ahci_exit);
2272