xref: /openbmc/linux/drivers/ata/ahci.c (revision 8e48b6b307085ce8a747cf94294742f7b7a11b18)
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);
5918f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
6018f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
6118f7ba4cSKristen Carlson Accardi 			      size_t size);
6218f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
6318f7ba4cSKristen Carlson Accardi 					ssize_t size);
6418f7ba4cSKristen Carlson Accardi #define MAX_SLOTS 8
65c6fd2807SJeff Garzik 
66c6fd2807SJeff Garzik enum {
67c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
68648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
69c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
70c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
71c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
72c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
73c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
74c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
75c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
76c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
77c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
78c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
79c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
80c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
81c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
82c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
83c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
84c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
85c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
86c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
87c6fd2807SJeff Garzik 
88c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
890291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
90c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
91c6fd2807SJeff Garzik 
92c6fd2807SJeff Garzik 	board_ahci		= 0,
937a234affSTejun Heo 	board_ahci_vt8251	= 1,
947a234affSTejun Heo 	board_ahci_ign_iferr	= 2,
957a234affSTejun Heo 	board_ahci_sb600	= 3,
967a234affSTejun Heo 	board_ahci_mv		= 4,
97e39fc8c9SShane Huang 	board_ahci_sb700	= 5,
98e297d99eSTejun Heo 	board_ahci_mcp65	= 6,
999a3b103cSTejun Heo 	board_ahci_nopmp	= 7,
100c6fd2807SJeff Garzik 
101c6fd2807SJeff Garzik 	/* global controller registers */
102c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
103c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
104c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
105c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
106c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
10718f7ba4cSKristen Carlson Accardi 	HOST_EM_LOC		= 0x1c, /* Enclosure Management location */
10818f7ba4cSKristen Carlson Accardi 	HOST_EM_CTL		= 0x20, /* Enclosure Management Control */
109c6fd2807SJeff Garzik 
110c6fd2807SJeff Garzik 	/* HOST_CTL bits */
111c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
112c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
113c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
114c6fd2807SJeff Garzik 
115c6fd2807SJeff Garzik 	/* HOST_CAP bits */
11618f7ba4cSKristen Carlson Accardi 	HOST_CAP_EMS		= (1 << 6),  /* Enclosure Management support */
117c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
1187d50b60bSTejun Heo 	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
119c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
12031556594SKristen Carlson Accardi 	HOST_CAP_ALPM		= (1 << 26), /* Aggressive Link PM support */
121c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
122203ef6c4STejun Heo 	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
123c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
124c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
125c6fd2807SJeff Garzik 
126c6fd2807SJeff Garzik 	/* registers for each SATA port */
127c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
128c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
129c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
130c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
131c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
132c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
133c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
134c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
135c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
136c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
137c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
138c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
139c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
140c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
141203ef6c4STejun Heo 	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
142c6fd2807SJeff Garzik 
143c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
144c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
145c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
146c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
147c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
148c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
149c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
150c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
151c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
152c6fd2807SJeff Garzik 
153c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
154c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
155c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
156c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
157c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
158c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
159c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
160c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
161c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
162c6fd2807SJeff Garzik 
163c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
164c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
165c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
166c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
1677d50b60bSTejun Heo 				  PORT_IRQ_UNK_FIS |
1687d50b60bSTejun Heo 				  PORT_IRQ_BAD_PMP,
169c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
170c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
171c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
172c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
173c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
174c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
175c6fd2807SJeff Garzik 
176c6fd2807SJeff Garzik 	/* PORT_CMD bits */
17731556594SKristen Carlson Accardi 	PORT_CMD_ASP		= (1 << 27), /* Aggressive Slumber/Partial */
17831556594SKristen Carlson Accardi 	PORT_CMD_ALPE		= (1 << 26), /* Aggressive Link PM enable */
179c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
1807d50b60bSTejun Heo 	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
181c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
182c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
183c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
184c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
185c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
186c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
187c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
188c6fd2807SJeff Garzik 
189c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
190c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
191c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
192c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
193c6fd2807SJeff Garzik 
194417a1a6dSTejun Heo 	/* hpriv->flags bits */
195417a1a6dSTejun Heo 	AHCI_HFLAG_NO_NCQ		= (1 << 0),
196417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
197417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
198417a1a6dSTejun Heo 	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
199417a1a6dSTejun Heo 	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
200417a1a6dSTejun Heo 	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
2016949b914STejun Heo 	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
20231556594SKristen Carlson Accardi 	AHCI_HFLAG_NO_HOTPLUG		= (1 << 7), /* ignore PxSERR.DIAG.N */
203a878539eSJeff Garzik 	AHCI_HFLAG_SECT255		= (1 << 8), /* max 255 sectors */
204e297d99eSTejun Heo 	AHCI_HFLAG_YES_NCQ		= (1 << 9), /* force NCQ cap on */
205417a1a6dSTejun Heo 
206c6fd2807SJeff Garzik 	/* ap->flags bits */
2071188c0d8STejun Heo 
2081188c0d8STejun Heo 	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
2091188c0d8STejun Heo 					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
21031556594SKristen Carlson Accardi 					  ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
21131556594SKristen Carlson Accardi 					  ATA_FLAG_IPM,
212c4f7792cSTejun Heo 
213c4f7792cSTejun Heo 	ICH_MAP				= 0x90, /* ICH MAP register */
21418f7ba4cSKristen Carlson Accardi 
21518f7ba4cSKristen Carlson Accardi 	/* em_ctl bits */
21618f7ba4cSKristen Carlson Accardi 	EM_CTL_RST			= (1 << 9), /* Reset */
21718f7ba4cSKristen Carlson Accardi 	EM_CTL_TM			= (1 << 8), /* Transmit Message */
21818f7ba4cSKristen Carlson Accardi 	EM_CTL_ALHD			= (1 << 26), /* Activity LED */
219c6fd2807SJeff Garzik };
220c6fd2807SJeff Garzik 
221c6fd2807SJeff Garzik struct ahci_cmd_hdr {
2224ca4e439SAl Viro 	__le32			opts;
2234ca4e439SAl Viro 	__le32			status;
2244ca4e439SAl Viro 	__le32			tbl_addr;
2254ca4e439SAl Viro 	__le32			tbl_addr_hi;
2264ca4e439SAl Viro 	__le32			reserved[4];
227c6fd2807SJeff Garzik };
228c6fd2807SJeff Garzik 
229c6fd2807SJeff Garzik struct ahci_sg {
2304ca4e439SAl Viro 	__le32			addr;
2314ca4e439SAl Viro 	__le32			addr_hi;
2324ca4e439SAl Viro 	__le32			reserved;
2334ca4e439SAl Viro 	__le32			flags_size;
234c6fd2807SJeff Garzik };
235c6fd2807SJeff Garzik 
23618f7ba4cSKristen Carlson Accardi struct ahci_em_priv {
23718f7ba4cSKristen Carlson Accardi 	enum sw_activity blink_policy;
23818f7ba4cSKristen Carlson Accardi 	struct timer_list timer;
23918f7ba4cSKristen Carlson Accardi 	unsigned long saved_activity;
24018f7ba4cSKristen Carlson Accardi 	unsigned long activity;
24118f7ba4cSKristen Carlson Accardi 	unsigned long led_state;
24218f7ba4cSKristen Carlson Accardi };
24318f7ba4cSKristen Carlson Accardi 
244c6fd2807SJeff Garzik struct ahci_host_priv {
245417a1a6dSTejun Heo 	unsigned int		flags;		/* AHCI_HFLAG_* */
246d447df14STejun Heo 	u32			cap;		/* cap to use */
247d447df14STejun Heo 	u32			port_map;	/* port map to use */
248d447df14STejun Heo 	u32			saved_cap;	/* saved initial cap */
249d447df14STejun Heo 	u32			saved_port_map;	/* saved initial port_map */
25018f7ba4cSKristen Carlson Accardi 	u32 			em_loc; /* enclosure management location */
251c6fd2807SJeff Garzik };
252c6fd2807SJeff Garzik 
253c6fd2807SJeff Garzik struct ahci_port_priv {
2547d50b60bSTejun Heo 	struct ata_link		*active_link;
255c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
256c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
257c6fd2807SJeff Garzik 	void			*cmd_tbl;
258c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
259c6fd2807SJeff Garzik 	void			*rx_fis;
260c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2610291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2620291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2630291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
264afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
265a7384925SKristen Carlson Accardi 	u32 			intr_mask;	/* interrupts to enable */
26618f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv	em_priv[MAX_SLOTS];/* enclosure management info
26718f7ba4cSKristen Carlson Accardi 					 	 * per PM slot */
268c6fd2807SJeff Garzik };
269c6fd2807SJeff Garzik 
270da3dbb17STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
271da3dbb17STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
272c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
273c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
2744c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
275c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
276c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
277c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
278c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
279c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
2807d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap);
2817d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap);
282a1efdabaSTejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class,
283a1efdabaSTejun Heo 			  unsigned long deadline);
284bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
285bd17243aSShane Huang 			  unsigned long deadline);
286a1efdabaSTejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
287a1efdabaSTejun Heo 			  unsigned long deadline);
288a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
289a1efdabaSTejun Heo 				 unsigned long deadline);
290a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
291a1efdabaSTejun Heo 				unsigned long deadline);
292a1efdabaSTejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class);
293c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
294c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
295df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
296a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev);
297dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
298dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
299dab632e8SJeff Garzik 			       u32 opts);
300438ac6d5STejun Heo #ifdef CONFIG_PM
301c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
302c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
303c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
304438ac6d5STejun Heo #endif
30518f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf);
30618f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev,
30718f7ba4cSKristen Carlson Accardi 				   enum sw_activity val);
30818f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link);
309c6fd2807SJeff Garzik 
310ee959b00STony Jones static struct device_attribute *ahci_shost_attrs[] = {
311ee959b00STony Jones 	&dev_attr_link_power_management_policy,
31218f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message_type,
31318f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message,
31418f7ba4cSKristen Carlson Accardi 	NULL
31518f7ba4cSKristen Carlson Accardi };
31618f7ba4cSKristen Carlson Accardi 
31718f7ba4cSKristen Carlson Accardi static struct device_attribute *ahci_sdev_attrs[] = {
31818f7ba4cSKristen Carlson Accardi 	&dev_attr_sw_activity,
31931556594SKristen Carlson Accardi 	NULL
32031556594SKristen Carlson Accardi };
32131556594SKristen Carlson Accardi 
322c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
32368d1d07bSTejun Heo 	ATA_NCQ_SHT(DRV_NAME),
324c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
325c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
326c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
32731556594SKristen Carlson Accardi 	.shost_attrs		= ahci_shost_attrs,
32818f7ba4cSKristen Carlson Accardi 	.sdev_attrs		= ahci_sdev_attrs,
329c6fd2807SJeff Garzik };
330c6fd2807SJeff Garzik 
331029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = {
332029cfd6bSTejun Heo 	.inherits		= &sata_pmp_port_ops,
333029cfd6bSTejun Heo 
3347d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
335c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
336c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
3374c9bf4e7STejun Heo 	.qc_fill_rtf		= ahci_qc_fill_rtf,
338c6fd2807SJeff Garzik 
339c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
340c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
341a1efdabaSTejun Heo 	.softreset		= ahci_softreset,
342a1efdabaSTejun Heo 	.hardreset		= ahci_hardreset,
343a1efdabaSTejun Heo 	.postreset		= ahci_postreset,
344071f44b1STejun Heo 	.pmp_softreset		= ahci_softreset,
345c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
346c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
347029cfd6bSTejun Heo 	.dev_config		= ahci_dev_config,
348c6fd2807SJeff Garzik 
349029cfd6bSTejun Heo 	.scr_read		= ahci_scr_read,
350029cfd6bSTejun Heo 	.scr_write		= ahci_scr_write,
3517d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
3527d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3537d50b60bSTejun Heo 
354029cfd6bSTejun Heo 	.enable_pm		= ahci_enable_alpm,
355029cfd6bSTejun Heo 	.disable_pm		= ahci_disable_alpm,
35618f7ba4cSKristen Carlson Accardi 	.em_show		= ahci_led_show,
35718f7ba4cSKristen Carlson Accardi 	.em_store		= ahci_led_store,
35818f7ba4cSKristen Carlson Accardi 	.sw_activity_show	= ahci_activity_show,
35918f7ba4cSKristen Carlson Accardi 	.sw_activity_store	= ahci_activity_store,
360438ac6d5STejun Heo #ifdef CONFIG_PM
361c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
362c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
363438ac6d5STejun Heo #endif
364c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
365c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
366c6fd2807SJeff Garzik };
367c6fd2807SJeff Garzik 
368029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
369029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
370a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
371ad616ffbSTejun Heo };
372ad616ffbSTejun Heo 
373029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
374029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
375a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
376edc93052STejun Heo };
377edc93052STejun Heo 
378bd17243aSShane Huang static struct ata_port_operations ahci_sb600_ops = {
379bd17243aSShane Huang 	.inherits		= &ahci_ops,
380bd17243aSShane Huang 	.softreset		= ahci_sb600_softreset,
381bd17243aSShane Huang 	.pmp_softreset		= ahci_sb600_softreset,
382bd17243aSShane Huang };
383bd17243aSShane Huang 
384417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
385417a1a6dSTejun Heo 
386c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
387c6fd2807SJeff Garzik 	/* board_ahci */
388c6fd2807SJeff Garzik 	{
3891188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
390c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
391469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
392c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
393c6fd2807SJeff Garzik 	},
394c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
395c6fd2807SJeff Garzik 	{
3966949b914STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
397417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
398c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
399469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
400ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
401c6fd2807SJeff Garzik 	},
40241669553STejun Heo 	/* board_ahci_ign_iferr */
40341669553STejun Heo 	{
404417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
405417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
40641669553STejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
407469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
40841669553STejun Heo 		.port_ops	= &ahci_ops,
40941669553STejun Heo 	},
41055a61604SConke Hu 	/* board_ahci_sb600 */
41155a61604SConke Hu 	{
412417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
41322b5e7a7STejun Heo 				 AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
414bd17243aSShane Huang 				 AHCI_HFLAG_SECT255),
415417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
41655a61604SConke Hu 		.pio_mask	= 0x1f, /* pio0-4 */
417469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
418bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
41955a61604SConke Hu 	},
420cd70c266SJeff Garzik 	/* board_ahci_mv */
421cd70c266SJeff Garzik 	{
422417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
42317248461STejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
424cd70c266SJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
425417a1a6dSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
426cd70c266SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
427cd70c266SJeff Garzik 		.udma_mask	= ATA_UDMA6,
428cd70c266SJeff Garzik 		.port_ops	= &ahci_ops,
429cd70c266SJeff Garzik 	},
430e39fc8c9SShane Huang 	/* board_ahci_sb700 */
431e39fc8c9SShane Huang 	{
432bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
433e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
434e39fc8c9SShane Huang 		.pio_mask	= 0x1f, /* pio0-4 */
435e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
436bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
437e39fc8c9SShane Huang 	},
438e297d99eSTejun Heo 	/* board_ahci_mcp65 */
439e297d99eSTejun Heo 	{
440e297d99eSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
441e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
442e297d99eSTejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
443e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
444e297d99eSTejun Heo 		.port_ops	= &ahci_ops,
445e297d99eSTejun Heo 	},
4469a3b103cSTejun Heo 	/* board_ahci_nopmp */
4479a3b103cSTejun Heo 	{
4489a3b103cSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP),
4499a3b103cSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
4509a3b103cSTejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
4519a3b103cSTejun Heo 		.udma_mask	= ATA_UDMA6,
4529a3b103cSTejun Heo 		.port_ops	= &ahci_ops,
4539a3b103cSTejun Heo 	},
454c6fd2807SJeff Garzik };
455c6fd2807SJeff Garzik 
456c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
457c6fd2807SJeff Garzik 	/* Intel */
45854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
45954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
46054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
46154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
46254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
46382490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
46454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
46554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
46654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
46754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
4687a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
4697a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
4707a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
4717a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
4727a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
4737a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
4747a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
4757a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
4767a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
4777a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
4787a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
4797a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
4807a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
4817a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
4827a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
4837a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
4847a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
485d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
486d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
48716ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
48816ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
489adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
490*8e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
491adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
492*8e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
493c6fd2807SJeff Garzik 
494e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
495e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
496e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
497c6fd2807SJeff Garzik 
498c6fd2807SJeff Garzik 	/* ATI */
499c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
500e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
501e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
502e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
503e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
504e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
505e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
506c6fd2807SJeff Garzik 
507c6fd2807SJeff Garzik 	/* VIA */
50854bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
509bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
510c6fd2807SJeff Garzik 
511c6fd2807SJeff Garzik 	/* NVIDIA */
512e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
513e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
514e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
515e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
516e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
517e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
518e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
519e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
5206fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci },		/* MCP67 */
5216fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci },		/* MCP67 */
5226fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci },		/* MCP67 */
5236fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci },		/* MCP67 */
524895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },		/* MCP67 */
525895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },		/* MCP67 */
526895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },		/* MCP67 */
527895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },		/* MCP67 */
528895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },		/* MCP67 */
529895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },		/* MCP67 */
530895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },		/* MCP67 */
531895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },		/* MCP67 */
5320522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci },		/* MCP73 */
5330522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci },		/* MCP73 */
5340522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci },		/* MCP73 */
5350522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci },		/* MCP73 */
5360522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci },		/* MCP73 */
5370522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci },		/* MCP73 */
5380522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci },		/* MCP73 */
5390522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci },		/* MCP73 */
5400522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci },		/* MCP73 */
5410522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci },		/* MCP73 */
5420522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci },		/* MCP73 */
5430522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci },		/* MCP73 */
5440522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },		/* MCP77 */
5450522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },		/* MCP77 */
5460522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },		/* MCP77 */
5470522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },		/* MCP77 */
5480522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },		/* MCP77 */
5490522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },		/* MCP77 */
5500522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },		/* MCP77 */
5510522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },		/* MCP77 */
5520522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },		/* MCP77 */
5530522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
5540522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
5550522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
5566ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci },		/* MCP79 */
5576ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci },		/* MCP79 */
5586ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci },		/* MCP79 */
5596ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci },		/* MCP79 */
5607100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
5617100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
5627100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
5637100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
5647100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
5657100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
5667100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
5677100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
56870d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci },		/* MCP7B */
56970d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci },		/* MCP7B */
57070d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci },		/* MCP7B */
57170d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci },		/* MCP7B */
57270d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci },		/* MCP7B */
57370d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci },		/* MCP7B */
57470d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci },		/* MCP7B */
57570d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci },		/* MCP7B */
5763072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci },		/* MCP7B */
5773072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci },		/* MCP7B */
5783072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci },		/* MCP7B */
5793072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci },		/* MCP7B */
580c6fd2807SJeff Garzik 
581c6fd2807SJeff Garzik 	/* SiS */
58220e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
58320e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
58420e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
585c6fd2807SJeff Garzik 
586cd70c266SJeff Garzik 	/* Marvell */
587cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
588c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
589cd70c266SJeff Garzik 
590415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
591415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
592c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
593415ae2b5SJeff Garzik 
594c6fd2807SJeff Garzik 	{ }	/* terminate list */
595c6fd2807SJeff Garzik };
596c6fd2807SJeff Garzik 
597c6fd2807SJeff Garzik 
598c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
599c6fd2807SJeff Garzik 	.name			= DRV_NAME,
600c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
601c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
60224dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
603438ac6d5STejun Heo #ifdef CONFIG_PM
604c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
605c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
606438ac6d5STejun Heo #endif
607c6fd2807SJeff Garzik };
608c6fd2807SJeff Garzik 
60918f7ba4cSKristen Carlson Accardi static int ahci_em_messages = 1;
61018f7ba4cSKristen Carlson Accardi module_param(ahci_em_messages, int, 0444);
61118f7ba4cSKristen Carlson Accardi /* add other LED protocol types when they become supported */
61218f7ba4cSKristen Carlson Accardi MODULE_PARM_DESC(ahci_em_messages,
61318f7ba4cSKristen Carlson Accardi 	"Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
614c6fd2807SJeff Garzik 
6155b66c829SAlan Cox #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
6165b66c829SAlan Cox static int marvell_enable;
6175b66c829SAlan Cox #else
6185b66c829SAlan Cox static int marvell_enable = 1;
6195b66c829SAlan Cox #endif
6205b66c829SAlan Cox module_param(marvell_enable, int, 0644);
6215b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
6225b66c829SAlan Cox 
6235b66c829SAlan Cox 
62498fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
62598fa4b60STejun Heo {
62698fa4b60STejun Heo 	return (cap & 0x1f) + 1;
62798fa4b60STejun Heo }
62898fa4b60STejun Heo 
629dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host,
630dab632e8SJeff Garzik 					     unsigned int port_no)
631dab632e8SJeff Garzik {
632dab632e8SJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
633dab632e8SJeff Garzik 
634dab632e8SJeff Garzik 	return mmio + 0x100 + (port_no * 0x80);
635dab632e8SJeff Garzik }
636dab632e8SJeff Garzik 
6374447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
638c6fd2807SJeff Garzik {
639dab632e8SJeff Garzik 	return __ahci_port_base(ap->host, ap->port_no);
640c6fd2807SJeff Garzik }
641c6fd2807SJeff Garzik 
642b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio)
643b710a1f4STejun Heo {
64415fe982eSTejun Heo 	int i;
645b710a1f4STejun Heo 	u32 tmp;
646b710a1f4STejun Heo 
647b710a1f4STejun Heo 	/* turn on AHCI_EN */
648b710a1f4STejun Heo 	tmp = readl(mmio + HOST_CTL);
64915fe982eSTejun Heo 	if (tmp & HOST_AHCI_EN)
65015fe982eSTejun Heo 		return;
65115fe982eSTejun Heo 
65215fe982eSTejun Heo 	/* Some controllers need AHCI_EN to be written multiple times.
65315fe982eSTejun Heo 	 * Try a few times before giving up.
65415fe982eSTejun Heo 	 */
65515fe982eSTejun Heo 	for (i = 0; i < 5; i++) {
656b710a1f4STejun Heo 		tmp |= HOST_AHCI_EN;
657b710a1f4STejun Heo 		writel(tmp, mmio + HOST_CTL);
658b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
65915fe982eSTejun Heo 		if (tmp & HOST_AHCI_EN)
66015fe982eSTejun Heo 			return;
66115fe982eSTejun Heo 		msleep(10);
662b710a1f4STejun Heo 	}
66315fe982eSTejun Heo 
66415fe982eSTejun Heo 	WARN_ON(1);
665b710a1f4STejun Heo }
666b710a1f4STejun Heo 
667d447df14STejun Heo /**
668d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
6694447d351STejun Heo  *	@pdev: target PCI device
6704447d351STejun Heo  *	@hpriv: host private area to store config values
671d447df14STejun Heo  *
672d447df14STejun Heo  *	Some registers containing configuration info might be setup by
673d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
674d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
675d447df14STejun Heo  *	can be restored after controller reset.
676d447df14STejun Heo  *
677d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
678d447df14STejun Heo  *
679d447df14STejun Heo  *	LOCKING:
680d447df14STejun Heo  *	None.
681d447df14STejun Heo  */
6824447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
6834447d351STejun Heo 				     struct ahci_host_priv *hpriv)
684d447df14STejun Heo {
6854447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
686d447df14STejun Heo 	u32 cap, port_map;
68717199b18STejun Heo 	int i;
688c40e7cb8SJose Alberto Reguero 	int mv;
689d447df14STejun Heo 
690b710a1f4STejun Heo 	/* make sure AHCI mode is enabled before accessing CAP */
691b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
692b710a1f4STejun Heo 
693d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
694d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
695d447df14STejun Heo 	 */
696d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
697d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
698d447df14STejun Heo 
699274c1fdeSTejun Heo 	/* some chips have errata preventing 64bit use */
700417a1a6dSTejun Heo 	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
701c7a42156STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
702c7a42156STejun Heo 			   "controller can't do 64bit DMA, forcing 32bit\n");
703c7a42156STejun Heo 		cap &= ~HOST_CAP_64;
704c7a42156STejun Heo 	}
705c7a42156STejun Heo 
706417a1a6dSTejun Heo 	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
707274c1fdeSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
708274c1fdeSTejun Heo 			   "controller can't do NCQ, turning off CAP_NCQ\n");
709274c1fdeSTejun Heo 		cap &= ~HOST_CAP_NCQ;
710274c1fdeSTejun Heo 	}
711274c1fdeSTejun Heo 
712e297d99eSTejun Heo 	if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
713e297d99eSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
714e297d99eSTejun Heo 			   "controller can do NCQ, turning on CAP_NCQ\n");
715e297d99eSTejun Heo 		cap |= HOST_CAP_NCQ;
716e297d99eSTejun Heo 	}
717e297d99eSTejun Heo 
718258cd846SRoel Kluin 	if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
7196949b914STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
7206949b914STejun Heo 			   "controller can't do PMP, turning off CAP_PMP\n");
7216949b914STejun Heo 		cap &= ~HOST_CAP_PMP;
7226949b914STejun Heo 	}
7236949b914STejun Heo 
724d799e083STejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
725d799e083STejun Heo 	    port_map != 1) {
726d799e083STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
727d799e083STejun Heo 			   "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
728d799e083STejun Heo 			   port_map, 1);
729d799e083STejun Heo 		port_map = 1;
730d799e083STejun Heo 	}
731d799e083STejun Heo 
732cd70c266SJeff Garzik 	/*
733cd70c266SJeff Garzik 	 * Temporary Marvell 6145 hack: PATA port presence
734cd70c266SJeff Garzik 	 * is asserted through the standard AHCI port
735cd70c266SJeff Garzik 	 * presence register, as bit 4 (counting from 0)
736cd70c266SJeff Garzik 	 */
737417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
738c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
739c40e7cb8SJose Alberto Reguero 			mv = 0x3;
740c40e7cb8SJose Alberto Reguero 		else
741c40e7cb8SJose Alberto Reguero 			mv = 0xf;
742cd70c266SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
743cd70c266SJeff Garzik 			   "MV_AHCI HACK: port_map %x -> %x\n",
744c40e7cb8SJose Alberto Reguero 			   port_map,
745c40e7cb8SJose Alberto Reguero 			   port_map & mv);
7465b66c829SAlan Cox 		dev_printk(KERN_ERR, &pdev->dev,
7475b66c829SAlan Cox 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
748cd70c266SJeff Garzik 
749c40e7cb8SJose Alberto Reguero 		port_map &= mv;
750cd70c266SJeff Garzik 	}
751cd70c266SJeff Garzik 
75217199b18STejun Heo 	/* cross check port_map and cap.n_ports */
7537a234affSTejun Heo 	if (port_map) {
754837f5f8fSTejun Heo 		int map_ports = 0;
75517199b18STejun Heo 
756837f5f8fSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS; i++)
757837f5f8fSTejun Heo 			if (port_map & (1 << i))
758837f5f8fSTejun Heo 				map_ports++;
75917199b18STejun Heo 
760837f5f8fSTejun Heo 		/* If PI has more ports than n_ports, whine, clear
761837f5f8fSTejun Heo 		 * port_map and let it be generated from n_ports.
76217199b18STejun Heo 		 */
763837f5f8fSTejun Heo 		if (map_ports > ahci_nr_ports(cap)) {
7644447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
765837f5f8fSTejun Heo 				   "implemented port map (0x%x) contains more "
766837f5f8fSTejun Heo 				   "ports than nr_ports (%u), using nr_ports\n",
767837f5f8fSTejun Heo 				   port_map, ahci_nr_ports(cap));
7687a234affSTejun Heo 			port_map = 0;
7697a234affSTejun Heo 		}
7707a234affSTejun Heo 	}
7717a234affSTejun Heo 
77217199b18STejun Heo 	/* fabricate port_map from cap.nr_ports */
7737a234affSTejun Heo 	if (!port_map) {
77417199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
7757a234affSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
7767a234affSTejun Heo 			   "forcing PORTS_IMPL to 0x%x\n", port_map);
7777a234affSTejun Heo 
7787a234affSTejun Heo 		/* write the fixed up value to the PI register */
7797a234affSTejun Heo 		hpriv->saved_port_map = port_map;
78017199b18STejun Heo 	}
78117199b18STejun Heo 
782d447df14STejun Heo 	/* record values to use during operation */
783d447df14STejun Heo 	hpriv->cap = cap;
784d447df14STejun Heo 	hpriv->port_map = port_map;
785d447df14STejun Heo }
786d447df14STejun Heo 
787d447df14STejun Heo /**
788d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
7894447d351STejun Heo  *	@host: target ATA host
790d447df14STejun Heo  *
791d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
792d447df14STejun Heo  *
793d447df14STejun Heo  *	LOCKING:
794d447df14STejun Heo  *	None.
795d447df14STejun Heo  */
7964447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
797d447df14STejun Heo {
7984447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
7994447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
8004447d351STejun Heo 
801d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
802d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
803d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
804d447df14STejun Heo }
805d447df14STejun Heo 
806203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
807c6fd2807SJeff Garzik {
808203ef6c4STejun Heo 	static const int offset[] = {
809203ef6c4STejun Heo 		[SCR_STATUS]		= PORT_SCR_STAT,
810203ef6c4STejun Heo 		[SCR_CONTROL]		= PORT_SCR_CTL,
811203ef6c4STejun Heo 		[SCR_ERROR]		= PORT_SCR_ERR,
812203ef6c4STejun Heo 		[SCR_ACTIVE]		= PORT_SCR_ACT,
813203ef6c4STejun Heo 		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
814203ef6c4STejun Heo 	};
815203ef6c4STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
816c6fd2807SJeff Garzik 
817203ef6c4STejun Heo 	if (sc_reg < ARRAY_SIZE(offset) &&
818203ef6c4STejun Heo 	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
819203ef6c4STejun Heo 		return offset[sc_reg];
820da3dbb17STejun Heo 	return 0;
821c6fd2807SJeff Garzik }
822c6fd2807SJeff Garzik 
823203ef6c4STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
824c6fd2807SJeff Garzik {
825203ef6c4STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
826203ef6c4STejun Heo 	int offset = ahci_scr_offset(ap, sc_reg);
827c6fd2807SJeff Garzik 
828203ef6c4STejun Heo 	if (offset) {
829203ef6c4STejun Heo 		*val = readl(port_mmio + offset);
830203ef6c4STejun Heo 		return 0;
831203ef6c4STejun Heo 	}
832da3dbb17STejun Heo 	return -EINVAL;
833c6fd2807SJeff Garzik }
834c6fd2807SJeff Garzik 
835203ef6c4STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
836203ef6c4STejun Heo {
837203ef6c4STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
838203ef6c4STejun Heo 	int offset = ahci_scr_offset(ap, sc_reg);
839203ef6c4STejun Heo 
840203ef6c4STejun Heo 	if (offset) {
841203ef6c4STejun Heo 		writel(val, port_mmio + offset);
842da3dbb17STejun Heo 		return 0;
843c6fd2807SJeff Garzik 	}
844203ef6c4STejun Heo 	return -EINVAL;
845203ef6c4STejun Heo }
846c6fd2807SJeff Garzik 
8474447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
848c6fd2807SJeff Garzik {
8494447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
850c6fd2807SJeff Garzik 	u32 tmp;
851c6fd2807SJeff Garzik 
852c6fd2807SJeff Garzik 	/* start DMA */
853c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
854c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
855c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
856c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
857c6fd2807SJeff Garzik }
858c6fd2807SJeff Garzik 
8594447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
860c6fd2807SJeff Garzik {
8614447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
862c6fd2807SJeff Garzik 	u32 tmp;
863c6fd2807SJeff Garzik 
864c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
865c6fd2807SJeff Garzik 
866c6fd2807SJeff Garzik 	/* check if the HBA is idle */
867c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
868c6fd2807SJeff Garzik 		return 0;
869c6fd2807SJeff Garzik 
870c6fd2807SJeff Garzik 	/* setting HBA to idle */
871c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
872c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
873c6fd2807SJeff Garzik 
874c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
875c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
876c6fd2807SJeff Garzik 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
877c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
878c6fd2807SJeff Garzik 		return -EIO;
879c6fd2807SJeff Garzik 
880c6fd2807SJeff Garzik 	return 0;
881c6fd2807SJeff Garzik }
882c6fd2807SJeff Garzik 
8834447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
884c6fd2807SJeff Garzik {
8854447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
8864447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
8874447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
888c6fd2807SJeff Garzik 	u32 tmp;
889c6fd2807SJeff Garzik 
890c6fd2807SJeff Garzik 	/* set FIS registers */
8914447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
8924447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
8934447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
8944447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
895c6fd2807SJeff Garzik 
8964447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
8974447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
8984447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
8994447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
900c6fd2807SJeff Garzik 
901c6fd2807SJeff Garzik 	/* enable FIS reception */
902c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
903c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
904c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
905c6fd2807SJeff Garzik 
906c6fd2807SJeff Garzik 	/* flush */
907c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
908c6fd2807SJeff Garzik }
909c6fd2807SJeff Garzik 
9104447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
911c6fd2807SJeff Garzik {
9124447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
913c6fd2807SJeff Garzik 	u32 tmp;
914c6fd2807SJeff Garzik 
915c6fd2807SJeff Garzik 	/* disable FIS reception */
916c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
917c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
918c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
919c6fd2807SJeff Garzik 
920c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
921c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
922c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
923c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
924c6fd2807SJeff Garzik 		return -EBUSY;
925c6fd2807SJeff Garzik 
926c6fd2807SJeff Garzik 	return 0;
927c6fd2807SJeff Garzik }
928c6fd2807SJeff Garzik 
9294447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
930c6fd2807SJeff Garzik {
9314447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
9324447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
933c6fd2807SJeff Garzik 	u32 cmd;
934c6fd2807SJeff Garzik 
935c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
936c6fd2807SJeff Garzik 
937c6fd2807SJeff Garzik 	/* spin up device */
9384447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
939c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
940c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
941c6fd2807SJeff Garzik 	}
942c6fd2807SJeff Garzik 
943c6fd2807SJeff Garzik 	/* wake up link */
944c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
945c6fd2807SJeff Garzik }
946c6fd2807SJeff Garzik 
94731556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap)
94831556594SKristen Carlson Accardi {
94931556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
95031556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
95131556594SKristen Carlson Accardi 	u32 cmd;
95231556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
95331556594SKristen Carlson Accardi 
95431556594SKristen Carlson Accardi 	/* IPM bits should be disabled by libata-core */
95531556594SKristen Carlson Accardi 	/* get the existing command bits */
95631556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
95731556594SKristen Carlson Accardi 
95831556594SKristen Carlson Accardi 	/* disable ALPM and ASP */
95931556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ASP;
96031556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ALPE;
96131556594SKristen Carlson Accardi 
96231556594SKristen Carlson Accardi 	/* force the interface back to active */
96331556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ICC_ACTIVE;
96431556594SKristen Carlson Accardi 
96531556594SKristen Carlson Accardi 	/* write out new cmd value */
96631556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
96731556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
96831556594SKristen Carlson Accardi 
96931556594SKristen Carlson Accardi 	/* wait 10ms to be sure we've come out of any low power state */
97031556594SKristen Carlson Accardi 	msleep(10);
97131556594SKristen Carlson Accardi 
97231556594SKristen Carlson Accardi 	/* clear out any PhyRdy stuff from interrupt status */
97331556594SKristen Carlson Accardi 	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
97431556594SKristen Carlson Accardi 
97531556594SKristen Carlson Accardi 	/* go ahead and clean out PhyRdy Change from Serror too */
97631556594SKristen Carlson Accardi 	ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
97731556594SKristen Carlson Accardi 
97831556594SKristen Carlson Accardi 	/*
97931556594SKristen Carlson Accardi  	 * Clear flag to indicate that we should ignore all PhyRdy
98031556594SKristen Carlson Accardi  	 * state changes
98131556594SKristen Carlson Accardi  	 */
98231556594SKristen Carlson Accardi 	hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
98331556594SKristen Carlson Accardi 
98431556594SKristen Carlson Accardi 	/*
98531556594SKristen Carlson Accardi  	 * Enable interrupts on Phy Ready.
98631556594SKristen Carlson Accardi  	 */
98731556594SKristen Carlson Accardi 	pp->intr_mask |= PORT_IRQ_PHYRDY;
98831556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
98931556594SKristen Carlson Accardi 
99031556594SKristen Carlson Accardi 	/*
99131556594SKristen Carlson Accardi  	 * don't change the link pm policy - we can be called
99231556594SKristen Carlson Accardi  	 * just to turn of link pm temporarily
99331556594SKristen Carlson Accardi  	 */
99431556594SKristen Carlson Accardi }
99531556594SKristen Carlson Accardi 
99631556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
99731556594SKristen Carlson Accardi 	enum link_pm policy)
99831556594SKristen Carlson Accardi {
99931556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
100031556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
100131556594SKristen Carlson Accardi 	u32 cmd;
100231556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
100331556594SKristen Carlson Accardi 	u32 asp;
100431556594SKristen Carlson Accardi 
100531556594SKristen Carlson Accardi 	/* Make sure the host is capable of link power management */
100631556594SKristen Carlson Accardi 	if (!(hpriv->cap & HOST_CAP_ALPM))
100731556594SKristen Carlson Accardi 		return -EINVAL;
100831556594SKristen Carlson Accardi 
100931556594SKristen Carlson Accardi 	switch (policy) {
101031556594SKristen Carlson Accardi 	case MAX_PERFORMANCE:
101131556594SKristen Carlson Accardi 	case NOT_AVAILABLE:
101231556594SKristen Carlson Accardi 		/*
101331556594SKristen Carlson Accardi  		 * if we came here with NOT_AVAILABLE,
101431556594SKristen Carlson Accardi  		 * it just means this is the first time we
101531556594SKristen Carlson Accardi  		 * have tried to enable - default to max performance,
101631556594SKristen Carlson Accardi  		 * and let the user go to lower power modes on request.
101731556594SKristen Carlson Accardi  		 */
101831556594SKristen Carlson Accardi 		ahci_disable_alpm(ap);
101931556594SKristen Carlson Accardi 		return 0;
102031556594SKristen Carlson Accardi 	case MIN_POWER:
102131556594SKristen Carlson Accardi 		/* configure HBA to enter SLUMBER */
102231556594SKristen Carlson Accardi 		asp = PORT_CMD_ASP;
102331556594SKristen Carlson Accardi 		break;
102431556594SKristen Carlson Accardi 	case MEDIUM_POWER:
102531556594SKristen Carlson Accardi 		/* configure HBA to enter PARTIAL */
102631556594SKristen Carlson Accardi 		asp = 0;
102731556594SKristen Carlson Accardi 		break;
102831556594SKristen Carlson Accardi 	default:
102931556594SKristen Carlson Accardi 		return -EINVAL;
103031556594SKristen Carlson Accardi 	}
103131556594SKristen Carlson Accardi 
103231556594SKristen Carlson Accardi 	/*
103331556594SKristen Carlson Accardi  	 * Disable interrupts on Phy Ready. This keeps us from
103431556594SKristen Carlson Accardi  	 * getting woken up due to spurious phy ready interrupts
103531556594SKristen Carlson Accardi 	 * TBD - Hot plug should be done via polling now, is
103631556594SKristen Carlson Accardi 	 * that even supported?
103731556594SKristen Carlson Accardi  	 */
103831556594SKristen Carlson Accardi 	pp->intr_mask &= ~PORT_IRQ_PHYRDY;
103931556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
104031556594SKristen Carlson Accardi 
104131556594SKristen Carlson Accardi 	/*
104231556594SKristen Carlson Accardi  	 * Set a flag to indicate that we should ignore all PhyRdy
104331556594SKristen Carlson Accardi  	 * state changes since these can happen now whenever we
104431556594SKristen Carlson Accardi  	 * change link state
104531556594SKristen Carlson Accardi  	 */
104631556594SKristen Carlson Accardi 	hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
104731556594SKristen Carlson Accardi 
104831556594SKristen Carlson Accardi 	/* get the existing command bits */
104931556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
105031556594SKristen Carlson Accardi 
105131556594SKristen Carlson Accardi 	/*
105231556594SKristen Carlson Accardi  	 * Set ASP based on Policy
105331556594SKristen Carlson Accardi  	 */
105431556594SKristen Carlson Accardi 	cmd |= asp;
105531556594SKristen Carlson Accardi 
105631556594SKristen Carlson Accardi 	/*
105731556594SKristen Carlson Accardi  	 * Setting this bit will instruct the HBA to aggressively
105831556594SKristen Carlson Accardi  	 * enter a lower power link state when it's appropriate and
105931556594SKristen Carlson Accardi  	 * based on the value set above for ASP
106031556594SKristen Carlson Accardi  	 */
106131556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ALPE;
106231556594SKristen Carlson Accardi 
106331556594SKristen Carlson Accardi 	/* write out new cmd value */
106431556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
106531556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
106631556594SKristen Carlson Accardi 
106731556594SKristen Carlson Accardi 	/* IPM bits should be set by libata-core */
106831556594SKristen Carlson Accardi 	return 0;
106931556594SKristen Carlson Accardi }
107031556594SKristen Carlson Accardi 
1071438ac6d5STejun Heo #ifdef CONFIG_PM
10724447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
1073c6fd2807SJeff Garzik {
10744447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
10754447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1076c6fd2807SJeff Garzik 	u32 cmd, scontrol;
1077c6fd2807SJeff Garzik 
10784447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
107907c53dacSTejun Heo 		return;
1080c6fd2807SJeff Garzik 
108107c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
1082c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
1083c6fd2807SJeff Garzik 	scontrol &= ~0xf;
1084c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
1085c6fd2807SJeff Garzik 
1086c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
108707c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1088c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
1089c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
1090c6fd2807SJeff Garzik }
1091438ac6d5STejun Heo #endif
1092c6fd2807SJeff Garzik 
1093df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap)
1094c6fd2807SJeff Garzik {
109518f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
109618f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
109718f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
109818f7ba4cSKristen Carlson Accardi 
1099c6fd2807SJeff Garzik 	/* enable FIS reception */
11004447d351STejun Heo 	ahci_start_fis_rx(ap);
1101c6fd2807SJeff Garzik 
1102c6fd2807SJeff Garzik 	/* enable DMA */
11034447d351STejun Heo 	ahci_start_engine(ap);
110418f7ba4cSKristen Carlson Accardi 
110518f7ba4cSKristen Carlson Accardi 	/* turn on LEDs */
110618f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_EM) {
110718f7ba4cSKristen Carlson Accardi 		ata_port_for_each_link(link, ap) {
110818f7ba4cSKristen Carlson Accardi 			emp = &pp->em_priv[link->pmp];
110918f7ba4cSKristen Carlson Accardi 			ahci_transmit_led_message(ap, emp->led_state, 4);
111018f7ba4cSKristen Carlson Accardi 		}
111118f7ba4cSKristen Carlson Accardi 	}
111218f7ba4cSKristen Carlson Accardi 
111318f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_SW_ACTIVITY)
111418f7ba4cSKristen Carlson Accardi 		ata_port_for_each_link(link, ap)
111518f7ba4cSKristen Carlson Accardi 			ahci_init_sw_activity(link);
111618f7ba4cSKristen Carlson Accardi 
1117c6fd2807SJeff Garzik }
1118c6fd2807SJeff Garzik 
11194447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
1120c6fd2807SJeff Garzik {
1121c6fd2807SJeff Garzik 	int rc;
1122c6fd2807SJeff Garzik 
1123c6fd2807SJeff Garzik 	/* disable DMA */
11244447d351STejun Heo 	rc = ahci_stop_engine(ap);
1125c6fd2807SJeff Garzik 	if (rc) {
1126c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
1127c6fd2807SJeff Garzik 		return rc;
1128c6fd2807SJeff Garzik 	}
1129c6fd2807SJeff Garzik 
1130c6fd2807SJeff Garzik 	/* disable FIS reception */
11314447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
1132c6fd2807SJeff Garzik 	if (rc) {
1133c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
1134c6fd2807SJeff Garzik 		return rc;
1135c6fd2807SJeff Garzik 	}
1136c6fd2807SJeff Garzik 
1137c6fd2807SJeff Garzik 	return 0;
1138c6fd2807SJeff Garzik }
1139c6fd2807SJeff Garzik 
11404447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
1141c6fd2807SJeff Garzik {
11424447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
114349f29090STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
11444447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1145d447df14STejun Heo 	u32 tmp;
1146c6fd2807SJeff Garzik 
11473cc3eb11SJeff Garzik 	/* we must be in AHCI mode, before using anything
11483cc3eb11SJeff Garzik 	 * AHCI-specific, such as HOST_RESET.
11493cc3eb11SJeff Garzik 	 */
1150b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
11513cc3eb11SJeff Garzik 
11523cc3eb11SJeff Garzik 	/* global controller reset */
1153a22e6444STejun Heo 	if (!ahci_skip_host_reset) {
1154b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);
1155c6fd2807SJeff Garzik 		if ((tmp & HOST_RESET) == 0) {
1156c6fd2807SJeff Garzik 			writel(tmp | HOST_RESET, mmio + HOST_CTL);
1157c6fd2807SJeff Garzik 			readl(mmio + HOST_CTL); /* flush */
1158c6fd2807SJeff Garzik 		}
1159c6fd2807SJeff Garzik 
116024920c8aSZhang Rui 		/*
116124920c8aSZhang Rui 		 * to perform host reset, OS should set HOST_RESET
116224920c8aSZhang Rui 		 * and poll until this bit is read to be "0".
116324920c8aSZhang Rui 		 * reset must complete within 1 second, or
1164c6fd2807SJeff Garzik 		 * the hardware should be considered fried.
1165c6fd2807SJeff Garzik 		 */
116624920c8aSZhang Rui 		tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
116724920c8aSZhang Rui 					HOST_RESET, 10, 1000);
1168c6fd2807SJeff Garzik 
1169c6fd2807SJeff Garzik 		if (tmp & HOST_RESET) {
11704447d351STejun Heo 			dev_printk(KERN_ERR, host->dev,
1171c6fd2807SJeff Garzik 				   "controller reset failed (0x%x)\n", tmp);
1172c6fd2807SJeff Garzik 			return -EIO;
1173c6fd2807SJeff Garzik 		}
1174c6fd2807SJeff Garzik 
117598fa4b60STejun Heo 		/* turn on AHCI mode */
1176b710a1f4STejun Heo 		ahci_enable_ahci(mmio);
117798fa4b60STejun Heo 
1178a22e6444STejun Heo 		/* Some registers might be cleared on reset.  Restore
1179a22e6444STejun Heo 		 * initial values.
1180a22e6444STejun Heo 		 */
11814447d351STejun Heo 		ahci_restore_initial_config(host);
1182a22e6444STejun Heo 	} else
1183a22e6444STejun Heo 		dev_printk(KERN_INFO, host->dev,
1184a22e6444STejun Heo 			   "skipping global host reset\n");
1185c6fd2807SJeff Garzik 
1186c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
1187c6fd2807SJeff Garzik 		u16 tmp16;
1188c6fd2807SJeff Garzik 
1189c6fd2807SJeff Garzik 		/* configure PCS */
1190c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
119149f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
119249f29090STejun Heo 			tmp16 |= hpriv->port_map;
1193c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
1194c6fd2807SJeff Garzik 		}
119549f29090STejun Heo 	}
1196c6fd2807SJeff Garzik 
1197c6fd2807SJeff Garzik 	return 0;
1198c6fd2807SJeff Garzik }
1199c6fd2807SJeff Garzik 
120018f7ba4cSKristen Carlson Accardi static void ahci_sw_activity(struct ata_link *link)
120118f7ba4cSKristen Carlson Accardi {
120218f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
120318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
120418f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
120518f7ba4cSKristen Carlson Accardi 
120618f7ba4cSKristen Carlson Accardi 	if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
120718f7ba4cSKristen Carlson Accardi 		return;
120818f7ba4cSKristen Carlson Accardi 
120918f7ba4cSKristen Carlson Accardi 	emp->activity++;
121018f7ba4cSKristen Carlson Accardi 	if (!timer_pending(&emp->timer))
121118f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
121218f7ba4cSKristen Carlson Accardi }
121318f7ba4cSKristen Carlson Accardi 
121418f7ba4cSKristen Carlson Accardi static void ahci_sw_activity_blink(unsigned long arg)
121518f7ba4cSKristen Carlson Accardi {
121618f7ba4cSKristen Carlson Accardi 	struct ata_link *link = (struct ata_link *)arg;
121718f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
121818f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
121918f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
122018f7ba4cSKristen Carlson Accardi 	unsigned long led_message = emp->led_state;
122118f7ba4cSKristen Carlson Accardi 	u32 activity_led_state;
122218f7ba4cSKristen Carlson Accardi 
122318f7ba4cSKristen Carlson Accardi 	led_message &= 0xffff0000;
122418f7ba4cSKristen Carlson Accardi 	led_message |= ap->port_no | (link->pmp << 8);
122518f7ba4cSKristen Carlson Accardi 
122618f7ba4cSKristen Carlson Accardi 	/* check to see if we've had activity.  If so,
122718f7ba4cSKristen Carlson Accardi 	 * toggle state of LED and reset timer.  If not,
122818f7ba4cSKristen Carlson Accardi 	 * turn LED to desired idle state.
122918f7ba4cSKristen Carlson Accardi 	 */
123018f7ba4cSKristen Carlson Accardi 	if (emp->saved_activity != emp->activity) {
123118f7ba4cSKristen Carlson Accardi 		emp->saved_activity = emp->activity;
123218f7ba4cSKristen Carlson Accardi 		/* get the current LED state */
123318f7ba4cSKristen Carlson Accardi 		activity_led_state = led_message & 0x00010000;
123418f7ba4cSKristen Carlson Accardi 
123518f7ba4cSKristen Carlson Accardi 		if (activity_led_state)
123618f7ba4cSKristen Carlson Accardi 			activity_led_state = 0;
123718f7ba4cSKristen Carlson Accardi 		else
123818f7ba4cSKristen Carlson Accardi 			activity_led_state = 1;
123918f7ba4cSKristen Carlson Accardi 
124018f7ba4cSKristen Carlson Accardi 		/* clear old state */
124118f7ba4cSKristen Carlson Accardi 		led_message &= 0xfff8ffff;
124218f7ba4cSKristen Carlson Accardi 
124318f7ba4cSKristen Carlson Accardi 		/* toggle state */
124418f7ba4cSKristen Carlson Accardi 		led_message |= (activity_led_state << 16);
124518f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
124618f7ba4cSKristen Carlson Accardi 	} else {
124718f7ba4cSKristen Carlson Accardi 		/* switch to idle */
124818f7ba4cSKristen Carlson Accardi 		led_message &= 0xfff8ffff;
124918f7ba4cSKristen Carlson Accardi 		if (emp->blink_policy == BLINK_OFF)
125018f7ba4cSKristen Carlson Accardi 			led_message |= (1 << 16);
125118f7ba4cSKristen Carlson Accardi 	}
125218f7ba4cSKristen Carlson Accardi 	ahci_transmit_led_message(ap, led_message, 4);
125318f7ba4cSKristen Carlson Accardi }
125418f7ba4cSKristen Carlson Accardi 
125518f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link)
125618f7ba4cSKristen Carlson Accardi {
125718f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
125818f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
125918f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
126018f7ba4cSKristen Carlson Accardi 
126118f7ba4cSKristen Carlson Accardi 	/* init activity stats, setup timer */
126218f7ba4cSKristen Carlson Accardi 	emp->saved_activity = emp->activity = 0;
126318f7ba4cSKristen Carlson Accardi 	setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
126418f7ba4cSKristen Carlson Accardi 
126518f7ba4cSKristen Carlson Accardi 	/* check our blink policy and set flag for link if it's enabled */
126618f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
126718f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
126818f7ba4cSKristen Carlson Accardi }
126918f7ba4cSKristen Carlson Accardi 
127018f7ba4cSKristen Carlson Accardi static int ahci_reset_em(struct ata_host *host)
127118f7ba4cSKristen Carlson Accardi {
127218f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
127318f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
127418f7ba4cSKristen Carlson Accardi 
127518f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
127618f7ba4cSKristen Carlson Accardi 	if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
127718f7ba4cSKristen Carlson Accardi 		return -EINVAL;
127818f7ba4cSKristen Carlson Accardi 
127918f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
128018f7ba4cSKristen Carlson Accardi 	return 0;
128118f7ba4cSKristen Carlson Accardi }
128218f7ba4cSKristen Carlson Accardi 
128318f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
128418f7ba4cSKristen Carlson Accardi 					ssize_t size)
128518f7ba4cSKristen Carlson Accardi {
128618f7ba4cSKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
128718f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
128818f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
128918f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
129018f7ba4cSKristen Carlson Accardi 	u32 message[] = {0, 0};
129193082f0bSLinus Torvalds 	unsigned long flags;
129218f7ba4cSKristen Carlson Accardi 	int pmp;
129318f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
129418f7ba4cSKristen Carlson Accardi 
129518f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
129618f7ba4cSKristen Carlson Accardi 	pmp = (state & 0x0000ff00) >> 8;
129718f7ba4cSKristen Carlson Accardi 	if (pmp < MAX_SLOTS)
129818f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
129918f7ba4cSKristen Carlson Accardi 	else
130018f7ba4cSKristen Carlson Accardi 		return -EINVAL;
130118f7ba4cSKristen Carlson Accardi 
130218f7ba4cSKristen Carlson Accardi 	spin_lock_irqsave(ap->lock, flags);
130318f7ba4cSKristen Carlson Accardi 
130418f7ba4cSKristen Carlson Accardi 	/*
130518f7ba4cSKristen Carlson Accardi 	 * if we are still busy transmitting a previous message,
130618f7ba4cSKristen Carlson Accardi 	 * do not allow
130718f7ba4cSKristen Carlson Accardi 	 */
130818f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
130918f7ba4cSKristen Carlson Accardi 	if (em_ctl & EM_CTL_TM) {
131018f7ba4cSKristen Carlson Accardi 		spin_unlock_irqrestore(ap->lock, flags);
131118f7ba4cSKristen Carlson Accardi 		return -EINVAL;
131218f7ba4cSKristen Carlson Accardi 	}
131318f7ba4cSKristen Carlson Accardi 
131418f7ba4cSKristen Carlson Accardi 	/*
131518f7ba4cSKristen Carlson Accardi 	 * create message header - this is all zero except for
131618f7ba4cSKristen Carlson Accardi 	 * the message size, which is 4 bytes.
131718f7ba4cSKristen Carlson Accardi 	 */
131818f7ba4cSKristen Carlson Accardi 	message[0] |= (4 << 8);
131918f7ba4cSKristen Carlson Accardi 
132018f7ba4cSKristen Carlson Accardi 	/* ignore 0:4 of byte zero, fill in port info yourself */
132118f7ba4cSKristen Carlson Accardi 	message[1] = ((state & 0xfffffff0) | ap->port_no);
132218f7ba4cSKristen Carlson Accardi 
132318f7ba4cSKristen Carlson Accardi 	/* write message to EM_LOC */
132418f7ba4cSKristen Carlson Accardi 	writel(message[0], mmio + hpriv->em_loc);
132518f7ba4cSKristen Carlson Accardi 	writel(message[1], mmio + hpriv->em_loc+4);
132618f7ba4cSKristen Carlson Accardi 
132718f7ba4cSKristen Carlson Accardi 	/* save off new led state for port/slot */
132818f7ba4cSKristen Carlson Accardi 	emp->led_state = message[1];
132918f7ba4cSKristen Carlson Accardi 
133018f7ba4cSKristen Carlson Accardi 	/*
133118f7ba4cSKristen Carlson Accardi 	 * tell hardware to transmit the message
133218f7ba4cSKristen Carlson Accardi 	 */
133318f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
133418f7ba4cSKristen Carlson Accardi 
133518f7ba4cSKristen Carlson Accardi 	spin_unlock_irqrestore(ap->lock, flags);
133618f7ba4cSKristen Carlson Accardi 	return size;
133718f7ba4cSKristen Carlson Accardi }
133818f7ba4cSKristen Carlson Accardi 
133918f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
134018f7ba4cSKristen Carlson Accardi {
134118f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
134218f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
134318f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
134418f7ba4cSKristen Carlson Accardi 	int rc = 0;
134518f7ba4cSKristen Carlson Accardi 
134618f7ba4cSKristen Carlson Accardi 	ata_port_for_each_link(link, ap) {
134718f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[link->pmp];
134818f7ba4cSKristen Carlson Accardi 		rc += sprintf(buf, "%lx\n", emp->led_state);
134918f7ba4cSKristen Carlson Accardi 	}
135018f7ba4cSKristen Carlson Accardi 	return rc;
135118f7ba4cSKristen Carlson Accardi }
135218f7ba4cSKristen Carlson Accardi 
135318f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
135418f7ba4cSKristen Carlson Accardi 				size_t size)
135518f7ba4cSKristen Carlson Accardi {
135618f7ba4cSKristen Carlson Accardi 	int state;
135718f7ba4cSKristen Carlson Accardi 	int pmp;
135818f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
135918f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
136018f7ba4cSKristen Carlson Accardi 
136118f7ba4cSKristen Carlson Accardi 	state = simple_strtoul(buf, NULL, 0);
136218f7ba4cSKristen Carlson Accardi 
136318f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
136418f7ba4cSKristen Carlson Accardi 	pmp = (state & 0x0000ff00) >> 8;
136518f7ba4cSKristen Carlson Accardi 	if (pmp < MAX_SLOTS)
136618f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
136718f7ba4cSKristen Carlson Accardi 	else
136818f7ba4cSKristen Carlson Accardi 		return -EINVAL;
136918f7ba4cSKristen Carlson Accardi 
137018f7ba4cSKristen Carlson Accardi 	/* mask off the activity bits if we are in sw_activity
137118f7ba4cSKristen Carlson Accardi 	 * mode, user should turn off sw_activity before setting
137218f7ba4cSKristen Carlson Accardi 	 * activity led through em_message
137318f7ba4cSKristen Carlson Accardi 	 */
137418f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
137518f7ba4cSKristen Carlson Accardi 		state &= 0xfff8ffff;
137618f7ba4cSKristen Carlson Accardi 
137718f7ba4cSKristen Carlson Accardi 	return ahci_transmit_led_message(ap, state, size);
137818f7ba4cSKristen Carlson Accardi }
137918f7ba4cSKristen Carlson Accardi 
138018f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
138118f7ba4cSKristen Carlson Accardi {
138218f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
138318f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
138418f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
138518f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
138618f7ba4cSKristen Carlson Accardi 	u32 port_led_state = emp->led_state;
138718f7ba4cSKristen Carlson Accardi 
138818f7ba4cSKristen Carlson Accardi 	/* save the desired Activity LED behavior */
138918f7ba4cSKristen Carlson Accardi 	if (val == OFF) {
139018f7ba4cSKristen Carlson Accardi 		/* clear LFLAG */
139118f7ba4cSKristen Carlson Accardi 		link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
139218f7ba4cSKristen Carlson Accardi 
139318f7ba4cSKristen Carlson Accardi 		/* set the LED to OFF */
139418f7ba4cSKristen Carlson Accardi 		port_led_state &= 0xfff80000;
139518f7ba4cSKristen Carlson Accardi 		port_led_state |= (ap->port_no | (link->pmp << 8));
139618f7ba4cSKristen Carlson Accardi 		ahci_transmit_led_message(ap, port_led_state, 4);
139718f7ba4cSKristen Carlson Accardi 	} else {
139818f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
139918f7ba4cSKristen Carlson Accardi 		if (val == BLINK_OFF) {
140018f7ba4cSKristen Carlson Accardi 			/* set LED to ON for idle */
140118f7ba4cSKristen Carlson Accardi 			port_led_state &= 0xfff80000;
140218f7ba4cSKristen Carlson Accardi 			port_led_state |= (ap->port_no | (link->pmp << 8));
140318f7ba4cSKristen Carlson Accardi 			port_led_state |= 0x00010000; /* check this */
140418f7ba4cSKristen Carlson Accardi 			ahci_transmit_led_message(ap, port_led_state, 4);
140518f7ba4cSKristen Carlson Accardi 		}
140618f7ba4cSKristen Carlson Accardi 	}
140718f7ba4cSKristen Carlson Accardi 	emp->blink_policy = val;
140818f7ba4cSKristen Carlson Accardi 	return 0;
140918f7ba4cSKristen Carlson Accardi }
141018f7ba4cSKristen Carlson Accardi 
141118f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
141218f7ba4cSKristen Carlson Accardi {
141318f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
141418f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
141518f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
141618f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
141718f7ba4cSKristen Carlson Accardi 
141818f7ba4cSKristen Carlson Accardi 	/* display the saved value of activity behavior for this
141918f7ba4cSKristen Carlson Accardi 	 * disk.
142018f7ba4cSKristen Carlson Accardi 	 */
142118f7ba4cSKristen Carlson Accardi 	return sprintf(buf, "%d\n", emp->blink_policy);
142218f7ba4cSKristen Carlson Accardi }
142318f7ba4cSKristen Carlson Accardi 
14242bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
14252bcd866bSJeff Garzik 			   int port_no, void __iomem *mmio,
14262bcd866bSJeff Garzik 			   void __iomem *port_mmio)
1427c6fd2807SJeff Garzik {
1428c6fd2807SJeff Garzik 	const char *emsg = NULL;
14292bcd866bSJeff Garzik 	int rc;
14302bcd866bSJeff Garzik 	u32 tmp;
1431c6fd2807SJeff Garzik 
1432c6fd2807SJeff Garzik 	/* make sure port is not active */
14334447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1434c6fd2807SJeff Garzik 	if (rc)
1435c6fd2807SJeff Garzik 		dev_printk(KERN_WARNING, &pdev->dev,
1436c6fd2807SJeff Garzik 			   "%s (%d)\n", emsg, rc);
1437c6fd2807SJeff Garzik 
1438c6fd2807SJeff Garzik 	/* clear SError */
1439c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SCR_ERR);
1440c6fd2807SJeff Garzik 	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
1441c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_SCR_ERR);
1442c6fd2807SJeff Garzik 
1443c6fd2807SJeff Garzik 	/* clear port IRQ */
1444c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1445c6fd2807SJeff Garzik 	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1446c6fd2807SJeff Garzik 	if (tmp)
1447c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_IRQ_STAT);
1448c6fd2807SJeff Garzik 
14492bcd866bSJeff Garzik 	writel(1 << port_no, mmio + HOST_IRQ_STAT);
14502bcd866bSJeff Garzik }
14512bcd866bSJeff Garzik 
14522bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host)
14532bcd866bSJeff Garzik {
1454417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
14552bcd866bSJeff Garzik 	struct pci_dev *pdev = to_pci_dev(host->dev);
14562bcd866bSJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
14572bcd866bSJeff Garzik 	int i;
1458cd70c266SJeff Garzik 	void __iomem *port_mmio;
14592bcd866bSJeff Garzik 	u32 tmp;
1460c40e7cb8SJose Alberto Reguero 	int mv;
14612bcd866bSJeff Garzik 
1462417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
1463c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
1464c40e7cb8SJose Alberto Reguero 			mv = 2;
1465c40e7cb8SJose Alberto Reguero 		else
1466c40e7cb8SJose Alberto Reguero 			mv = 4;
1467c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
1468cd70c266SJeff Garzik 
1469cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
1470cd70c266SJeff Garzik 
1471cd70c266SJeff Garzik 		/* clear port IRQ */
1472cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
1473cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1474cd70c266SJeff Garzik 		if (tmp)
1475cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
1476cd70c266SJeff Garzik 	}
1477cd70c266SJeff Garzik 
14782bcd866bSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
14792bcd866bSJeff Garzik 		struct ata_port *ap = host->ports[i];
14802bcd866bSJeff Garzik 
1481cd70c266SJeff Garzik 		port_mmio = ahci_port_base(ap);
14822bcd866bSJeff Garzik 		if (ata_port_is_dummy(ap))
14832bcd866bSJeff Garzik 			continue;
14842bcd866bSJeff Garzik 
14852bcd866bSJeff Garzik 		ahci_port_init(pdev, ap, i, mmio, port_mmio);
1486c6fd2807SJeff Garzik 	}
1487c6fd2807SJeff Garzik 
1488c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1489c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1490c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
1491c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1492c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1493c6fd2807SJeff Garzik }
1494c6fd2807SJeff Garzik 
1495a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev)
1496a878539eSJeff Garzik {
1497a878539eSJeff Garzik 	struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
1498a878539eSJeff Garzik 
14994cde32fcSJeff Garzik 	if (hpriv->flags & AHCI_HFLAG_SECT255) {
1500a878539eSJeff Garzik 		dev->max_sectors = 255;
15014cde32fcSJeff Garzik 		ata_dev_printk(dev, KERN_INFO,
15024cde32fcSJeff Garzik 			       "SB600 AHCI: limiting to 255 sectors per cmd\n");
15034cde32fcSJeff Garzik 	}
1504a878539eSJeff Garzik }
1505a878539eSJeff Garzik 
1506c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
1507c6fd2807SJeff Garzik {
15084447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1509c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1510c6fd2807SJeff Garzik 	u32 tmp;
1511c6fd2807SJeff Garzik 
1512c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
1513c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
1514c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
1515c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
1516c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
1517c6fd2807SJeff Garzik 
1518c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
1519c6fd2807SJeff Garzik }
1520c6fd2807SJeff Garzik 
1521c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
1522c6fd2807SJeff Garzik 			       u32 opts)
1523c6fd2807SJeff Garzik {
1524c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
1525c6fd2807SJeff Garzik 
1526c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
1527c6fd2807SJeff Garzik 
1528c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
1529c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
1530c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
1531c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
1532c6fd2807SJeff Garzik }
1533c6fd2807SJeff Garzik 
1534d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart)
1535c6fd2807SJeff Garzik {
1536350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1537cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1538520d06f9STejun Heo 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1539c6fd2807SJeff Garzik 	u32 tmp;
1540d2e75dffSTejun Heo 	int busy, rc;
1541c6fd2807SJeff Garzik 
1542d2e75dffSTejun Heo 	/* do we need to kick the port? */
1543520d06f9STejun Heo 	busy = status & (ATA_BUSY | ATA_DRQ);
1544d2e75dffSTejun Heo 	if (!busy && !force_restart)
1545d2e75dffSTejun Heo 		return 0;
1546c6fd2807SJeff Garzik 
1547d2e75dffSTejun Heo 	/* stop engine */
1548d2e75dffSTejun Heo 	rc = ahci_stop_engine(ap);
1549d2e75dffSTejun Heo 	if (rc)
1550d2e75dffSTejun Heo 		goto out_restart;
1551d2e75dffSTejun Heo 
1552d2e75dffSTejun Heo 	/* need to do CLO? */
1553d2e75dffSTejun Heo 	if (!busy) {
1554d2e75dffSTejun Heo 		rc = 0;
1555d2e75dffSTejun Heo 		goto out_restart;
1556d2e75dffSTejun Heo 	}
1557d2e75dffSTejun Heo 
1558d2e75dffSTejun Heo 	if (!(hpriv->cap & HOST_CAP_CLO)) {
1559d2e75dffSTejun Heo 		rc = -EOPNOTSUPP;
1560d2e75dffSTejun Heo 		goto out_restart;
1561d2e75dffSTejun Heo 	}
1562d2e75dffSTejun Heo 
1563d2e75dffSTejun Heo 	/* perform CLO */
1564c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1565c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
1566c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1567c6fd2807SJeff Garzik 
1568d2e75dffSTejun Heo 	rc = 0;
1569c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1570c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
1571c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
1572d2e75dffSTejun Heo 		rc = -EIO;
1573c6fd2807SJeff Garzik 
1574d2e75dffSTejun Heo 	/* restart engine */
1575d2e75dffSTejun Heo  out_restart:
1576d2e75dffSTejun Heo 	ahci_start_engine(ap);
1577d2e75dffSTejun Heo 	return rc;
1578c6fd2807SJeff Garzik }
1579c6fd2807SJeff Garzik 
158091c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
158191c4a2e0STejun Heo 				struct ata_taskfile *tf, int is_cmd, u16 flags,
158291c4a2e0STejun Heo 				unsigned long timeout_msec)
158391c4a2e0STejun Heo {
158491c4a2e0STejun Heo 	const u32 cmd_fis_len = 5; /* five dwords */
158591c4a2e0STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
158691c4a2e0STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
158791c4a2e0STejun Heo 	u8 *fis = pp->cmd_tbl;
158891c4a2e0STejun Heo 	u32 tmp;
158991c4a2e0STejun Heo 
159091c4a2e0STejun Heo 	/* prep the command */
159191c4a2e0STejun Heo 	ata_tf_to_fis(tf, pmp, is_cmd, fis);
159291c4a2e0STejun Heo 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
159391c4a2e0STejun Heo 
159491c4a2e0STejun Heo 	/* issue & wait */
159591c4a2e0STejun Heo 	writel(1, port_mmio + PORT_CMD_ISSUE);
159691c4a2e0STejun Heo 
159791c4a2e0STejun Heo 	if (timeout_msec) {
159891c4a2e0STejun Heo 		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
159991c4a2e0STejun Heo 					1, timeout_msec);
160091c4a2e0STejun Heo 		if (tmp & 0x1) {
160191c4a2e0STejun Heo 			ahci_kick_engine(ap, 1);
160291c4a2e0STejun Heo 			return -EBUSY;
160391c4a2e0STejun Heo 		}
160491c4a2e0STejun Heo 	} else
160591c4a2e0STejun Heo 		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
160691c4a2e0STejun Heo 
160791c4a2e0STejun Heo 	return 0;
160891c4a2e0STejun Heo }
160991c4a2e0STejun Heo 
1610bd17243aSShane Huang static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1611bd17243aSShane Huang 			     int pmp, unsigned long deadline,
1612bd17243aSShane Huang 			     int (*check_ready)(struct ata_link *link))
1613c6fd2807SJeff Garzik {
1614cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1615c6fd2807SJeff Garzik 	const char *reason = NULL;
16162cbb79ebSTejun Heo 	unsigned long now, msecs;
1617c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1618c6fd2807SJeff Garzik 	int rc;
1619c6fd2807SJeff Garzik 
1620c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1621c6fd2807SJeff Garzik 
1622c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
1623d2e75dffSTejun Heo 	rc = ahci_kick_engine(ap, 1);
1624994056d7STejun Heo 	if (rc && rc != -EOPNOTSUPP)
1625cc0680a5STejun Heo 		ata_link_printk(link, KERN_WARNING,
1626994056d7STejun Heo 				"failed to reset engine (errno=%d)\n", rc);
1627c6fd2807SJeff Garzik 
1628cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1629c6fd2807SJeff Garzik 
1630c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
16312cbb79ebSTejun Heo 	msecs = 0;
16322cbb79ebSTejun Heo 	now = jiffies;
16332cbb79ebSTejun Heo 	if (time_after(now, deadline))
16342cbb79ebSTejun Heo 		msecs = jiffies_to_msecs(deadline - now);
16352cbb79ebSTejun Heo 
1636c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
1637a9cf5e85STejun Heo 	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
163891c4a2e0STejun Heo 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
1639c6fd2807SJeff Garzik 		rc = -EIO;
1640c6fd2807SJeff Garzik 		reason = "1st FIS failed";
1641c6fd2807SJeff Garzik 		goto fail;
1642c6fd2807SJeff Garzik 	}
1643c6fd2807SJeff Garzik 
1644c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
1645c6fd2807SJeff Garzik 	msleep(1);
1646c6fd2807SJeff Garzik 
1647c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
1648c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
1649a9cf5e85STejun Heo 	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1650c6fd2807SJeff Garzik 
1651705e76beSTejun Heo 	/* wait for link to become ready */
1652bd17243aSShane Huang 	rc = ata_wait_after_reset(link, deadline, check_ready);
16539b89391cSTejun Heo 	/* link occupied, -ENODEV too is an error */
16549b89391cSTejun Heo 	if (rc) {
1655c6fd2807SJeff Garzik 		reason = "device not ready";
1656c6fd2807SJeff Garzik 		goto fail;
1657c6fd2807SJeff Garzik 	}
1658c6fd2807SJeff Garzik 	*class = ahci_dev_classify(ap);
1659c6fd2807SJeff Garzik 
1660c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
1661c6fd2807SJeff Garzik 	return 0;
1662c6fd2807SJeff Garzik 
1663c6fd2807SJeff Garzik  fail:
1664cc0680a5STejun Heo 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
1665c6fd2807SJeff Garzik 	return rc;
1666c6fd2807SJeff Garzik }
1667c6fd2807SJeff Garzik 
1668bd17243aSShane Huang static int ahci_check_ready(struct ata_link *link)
1669bd17243aSShane Huang {
1670bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1671bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1672bd17243aSShane Huang 
1673bd17243aSShane Huang 	return ata_check_ready(status);
1674bd17243aSShane Huang }
1675bd17243aSShane Huang 
1676bd17243aSShane Huang static int ahci_softreset(struct ata_link *link, unsigned int *class,
1677bd17243aSShane Huang 			  unsigned long deadline)
1678bd17243aSShane Huang {
1679bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1680bd17243aSShane Huang 
1681bd17243aSShane Huang 	DPRINTK("ENTER\n");
1682bd17243aSShane Huang 
1683bd17243aSShane Huang 	return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
1684bd17243aSShane Huang }
1685bd17243aSShane Huang 
1686bd17243aSShane Huang static int ahci_sb600_check_ready(struct ata_link *link)
1687bd17243aSShane Huang {
1688bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1689bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1690bd17243aSShane Huang 	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
1691bd17243aSShane Huang 
1692bd17243aSShane Huang 	/*
1693bd17243aSShane Huang 	 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
1694bd17243aSShane Huang 	 * which can save timeout delay.
1695bd17243aSShane Huang 	 */
1696bd17243aSShane Huang 	if (irq_status & PORT_IRQ_BAD_PMP)
1697bd17243aSShane Huang 		return -EIO;
1698bd17243aSShane Huang 
1699bd17243aSShane Huang 	return ata_check_ready(status);
1700bd17243aSShane Huang }
1701bd17243aSShane Huang 
1702bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
1703bd17243aSShane Huang 				unsigned long deadline)
1704bd17243aSShane Huang {
1705bd17243aSShane Huang 	struct ata_port *ap = link->ap;
1706bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(ap);
1707bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1708bd17243aSShane Huang 	int rc;
1709bd17243aSShane Huang 	u32 irq_sts;
1710bd17243aSShane Huang 
1711bd17243aSShane Huang 	DPRINTK("ENTER\n");
1712bd17243aSShane Huang 
1713bd17243aSShane Huang 	rc = ahci_do_softreset(link, class, pmp, deadline,
1714bd17243aSShane Huang 			       ahci_sb600_check_ready);
1715bd17243aSShane Huang 
1716bd17243aSShane Huang 	/*
1717bd17243aSShane Huang 	 * Soft reset fails on some ATI chips with IPMS set when PMP
1718bd17243aSShane Huang 	 * is enabled but SATA HDD/ODD is connected to SATA port,
1719bd17243aSShane Huang 	 * do soft reset again to port 0.
1720bd17243aSShane Huang 	 */
1721bd17243aSShane Huang 	if (rc == -EIO) {
1722bd17243aSShane Huang 		irq_sts = readl(port_mmio + PORT_IRQ_STAT);
1723bd17243aSShane Huang 		if (irq_sts & PORT_IRQ_BAD_PMP) {
1724bd17243aSShane Huang 			ata_link_printk(link, KERN_WARNING,
1725bd17243aSShane Huang 					"failed due to HW bug, retry pmp=0\n");
1726bd17243aSShane Huang 			rc = ahci_do_softreset(link, class, 0, deadline,
1727bd17243aSShane Huang 					       ahci_check_ready);
1728bd17243aSShane Huang 		}
1729bd17243aSShane Huang 	}
1730bd17243aSShane Huang 
1731bd17243aSShane Huang 	return rc;
1732bd17243aSShane Huang }
1733bd17243aSShane Huang 
1734cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1735d4b2bab4STejun Heo 			  unsigned long deadline)
1736c6fd2807SJeff Garzik {
17379dadd45bSTejun Heo 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
1738cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1739c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1740c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1741c6fd2807SJeff Garzik 	struct ata_taskfile tf;
17429dadd45bSTejun Heo 	bool online;
1743c6fd2807SJeff Garzik 	int rc;
1744c6fd2807SJeff Garzik 
1745c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1746c6fd2807SJeff Garzik 
17474447d351STejun Heo 	ahci_stop_engine(ap);
1748c6fd2807SJeff Garzik 
1749c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1750cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1751dfd7a3dbSTejun Heo 	tf.command = 0x80;
17529977126cSTejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1753c6fd2807SJeff Garzik 
17549dadd45bSTejun Heo 	rc = sata_link_hardreset(link, timing, deadline, &online,
17559dadd45bSTejun Heo 				 ahci_check_ready);
1756c6fd2807SJeff Garzik 
17574447d351STejun Heo 	ahci_start_engine(ap);
1758c6fd2807SJeff Garzik 
17599dadd45bSTejun Heo 	if (online)
17609dadd45bSTejun Heo 		*class = ahci_dev_classify(ap);
1761c6fd2807SJeff Garzik 
1762c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1763c6fd2807SJeff Garzik 	return rc;
1764c6fd2807SJeff Garzik }
1765c6fd2807SJeff Garzik 
1766cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1767d4b2bab4STejun Heo 				 unsigned long deadline)
1768ad616ffbSTejun Heo {
1769cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
17709dadd45bSTejun Heo 	bool online;
1771ad616ffbSTejun Heo 	int rc;
1772ad616ffbSTejun Heo 
1773ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1774ad616ffbSTejun Heo 
17754447d351STejun Heo 	ahci_stop_engine(ap);
1776ad616ffbSTejun Heo 
1777cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
17789dadd45bSTejun Heo 				 deadline, &online, NULL);
1779ad616ffbSTejun Heo 
17804447d351STejun Heo 	ahci_start_engine(ap);
1781ad616ffbSTejun Heo 
1782ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1783ad616ffbSTejun Heo 
1784ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1785ad616ffbSTejun Heo 	 * request follow-up softreset.
1786ad616ffbSTejun Heo 	 */
17879dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
1788ad616ffbSTejun Heo }
1789ad616ffbSTejun Heo 
1790edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1791edc93052STejun Heo 				unsigned long deadline)
1792edc93052STejun Heo {
1793edc93052STejun Heo 	struct ata_port *ap = link->ap;
1794edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1795edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1796edc93052STejun Heo 	struct ata_taskfile tf;
17979dadd45bSTejun Heo 	bool online;
1798edc93052STejun Heo 	int rc;
1799edc93052STejun Heo 
1800edc93052STejun Heo 	ahci_stop_engine(ap);
1801edc93052STejun Heo 
1802edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
1803edc93052STejun Heo 	ata_tf_init(link->device, &tf);
1804edc93052STejun Heo 	tf.command = 0x80;
1805edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1806edc93052STejun Heo 
1807edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
18089dadd45bSTejun Heo 				 deadline, &online, NULL);
1809edc93052STejun Heo 
1810edc93052STejun Heo 	ahci_start_engine(ap);
1811edc93052STejun Heo 
1812edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
1813edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1814edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
1815edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
1816edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
1817edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1818edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1819edc93052STejun Heo 	 *
1820edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
1821edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
1822edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
1823edc93052STejun Heo 	 * suffice while making probing snappish enough.
1824edc93052STejun Heo 	 */
18259dadd45bSTejun Heo 	if (online) {
18269dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
18279dadd45bSTejun Heo 					  ahci_check_ready);
1828edc93052STejun Heo 		if (rc)
1829edc93052STejun Heo 			ahci_kick_engine(ap, 0);
18309dadd45bSTejun Heo 	}
18319dadd45bSTejun Heo 	return rc;
1832edc93052STejun Heo }
1833edc93052STejun Heo 
1834cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class)
1835c6fd2807SJeff Garzik {
1836cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
18374447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1838c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1839c6fd2807SJeff Garzik 
1840203c75b8STejun Heo 	ata_std_postreset(link, class);
1841c6fd2807SJeff Garzik 
1842c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1843c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1844c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1845c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
1846c6fd2807SJeff Garzik 	else
1847c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
1848c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
1849c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
1850c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
1851c6fd2807SJeff Garzik 	}
1852c6fd2807SJeff Garzik }
1853c6fd2807SJeff Garzik 
1854c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
1855c6fd2807SJeff Garzik {
1856c6fd2807SJeff Garzik 	struct scatterlist *sg;
1857ff2aeb1eSTejun Heo 	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
1858ff2aeb1eSTejun Heo 	unsigned int si;
1859c6fd2807SJeff Garzik 
1860c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1861c6fd2807SJeff Garzik 
1862c6fd2807SJeff Garzik 	/*
1863c6fd2807SJeff Garzik 	 * Next, the S/G list.
1864c6fd2807SJeff Garzik 	 */
1865ff2aeb1eSTejun Heo 	for_each_sg(qc->sg, sg, qc->n_elem, si) {
1866c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1867c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1868c6fd2807SJeff Garzik 
1869ff2aeb1eSTejun Heo 		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
1870ff2aeb1eSTejun Heo 		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
1871ff2aeb1eSTejun Heo 		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
1872c6fd2807SJeff Garzik 	}
1873c6fd2807SJeff Garzik 
1874ff2aeb1eSTejun Heo 	return si;
1875c6fd2807SJeff Garzik }
1876c6fd2807SJeff Garzik 
1877c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1878c6fd2807SJeff Garzik {
1879c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1880c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1881405e66b3STejun Heo 	int is_atapi = ata_is_atapi(qc->tf.protocol);
1882c6fd2807SJeff Garzik 	void *cmd_tbl;
1883c6fd2807SJeff Garzik 	u32 opts;
1884c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1885c6fd2807SJeff Garzik 	unsigned int n_elem;
1886c6fd2807SJeff Garzik 
1887c6fd2807SJeff Garzik 	/*
1888c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1889c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1890c6fd2807SJeff Garzik 	 */
1891c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1892c6fd2807SJeff Garzik 
18937d50b60bSTejun Heo 	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
1894c6fd2807SJeff Garzik 	if (is_atapi) {
1895c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1896c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1897c6fd2807SJeff Garzik 	}
1898c6fd2807SJeff Garzik 
1899c6fd2807SJeff Garzik 	n_elem = 0;
1900c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1901c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1902c6fd2807SJeff Garzik 
1903c6fd2807SJeff Garzik 	/*
1904c6fd2807SJeff Garzik 	 * Fill in command slot information.
1905c6fd2807SJeff Garzik 	 */
19067d50b60bSTejun Heo 	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
1907c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1908c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1909c6fd2807SJeff Garzik 	if (is_atapi)
1910c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1911c6fd2807SJeff Garzik 
1912c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1913c6fd2807SJeff Garzik }
1914c6fd2807SJeff Garzik 
1915c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1916c6fd2807SJeff Garzik {
1917417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1918c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
19197d50b60bSTejun Heo 	struct ata_eh_info *host_ehi = &ap->link.eh_info;
19207d50b60bSTejun Heo 	struct ata_link *link = NULL;
19217d50b60bSTejun Heo 	struct ata_queued_cmd *active_qc;
19227d50b60bSTejun Heo 	struct ata_eh_info *active_ehi;
1923c6fd2807SJeff Garzik 	u32 serror;
1924c6fd2807SJeff Garzik 
19257d50b60bSTejun Heo 	/* determine active link */
19267d50b60bSTejun Heo 	ata_port_for_each_link(link, ap)
19277d50b60bSTejun Heo 		if (ata_link_active(link))
19287d50b60bSTejun Heo 			break;
19297d50b60bSTejun Heo 	if (!link)
19307d50b60bSTejun Heo 		link = &ap->link;
19317d50b60bSTejun Heo 
19327d50b60bSTejun Heo 	active_qc = ata_qc_from_tag(ap, link->active_tag);
19337d50b60bSTejun Heo 	active_ehi = &link->eh_info;
19347d50b60bSTejun Heo 
19357d50b60bSTejun Heo 	/* record irq stat */
19367d50b60bSTejun Heo 	ata_ehi_clear_desc(host_ehi);
19377d50b60bSTejun Heo 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
1938c6fd2807SJeff Garzik 
1939c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
1940da3dbb17STejun Heo 	ahci_scr_read(ap, SCR_ERROR, &serror);
1941c6fd2807SJeff Garzik 	ahci_scr_write(ap, SCR_ERROR, serror);
19427d50b60bSTejun Heo 	host_ehi->serror |= serror;
1943c6fd2807SJeff Garzik 
194441669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
1945417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
194641669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
194741669553STejun Heo 
194855a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
19497d50b60bSTejun Heo 		/* If qc is active, charge it; otherwise, the active
19507d50b60bSTejun Heo 		 * link.  There's no active qc on NCQ errors.  It will
19517d50b60bSTejun Heo 		 * be determined by EH by reading log page 10h.
19527d50b60bSTejun Heo 		 */
19537d50b60bSTejun Heo 		if (active_qc)
19547d50b60bSTejun Heo 			active_qc->err_mask |= AC_ERR_DEV;
19557d50b60bSTejun Heo 		else
19567d50b60bSTejun Heo 			active_ehi->err_mask |= AC_ERR_DEV;
19577d50b60bSTejun Heo 
1958417a1a6dSTejun Heo 		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
19597d50b60bSTejun Heo 			host_ehi->serror &= ~SERR_INTERNAL;
1960c6fd2807SJeff Garzik 	}
1961c6fd2807SJeff Garzik 
1962c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
1963c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
1964c6fd2807SJeff Garzik 
19657d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
1966cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
19677d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi,
19687d50b60bSTejun Heo 				  "unknown FIS %08x %08x %08x %08x" ,
1969c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
1970c6fd2807SJeff Garzik 	}
1971c6fd2807SJeff Garzik 
1972071f44b1STejun Heo 	if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
19737d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
1974cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
19757d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi, "incorrect PMP");
19767d50b60bSTejun Heo 	}
1977c6fd2807SJeff Garzik 
19787d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
19797d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_HOST_BUS;
1980cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
19817d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "host bus error");
19827d50b60bSTejun Heo 	}
19837d50b60bSTejun Heo 
19847d50b60bSTejun Heo 	if (irq_stat & PORT_IRQ_IF_ERR) {
19857d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_ATA_BUS;
1986cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
19877d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "interface fatal error");
19887d50b60bSTejun Heo 	}
19897d50b60bSTejun Heo 
19907d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
19917d50b60bSTejun Heo 		ata_ehi_hotplugged(host_ehi);
19927d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "%s",
19937d50b60bSTejun Heo 			irq_stat & PORT_IRQ_CONNECT ?
19947d50b60bSTejun Heo 			"connection status changed" : "PHY RDY changed");
19957d50b60bSTejun Heo 	}
19967d50b60bSTejun Heo 
19977d50b60bSTejun Heo 	/* okay, let's hand over to EH */
1998c6fd2807SJeff Garzik 
1999c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
2000c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2001c6fd2807SJeff Garzik 	else
2002c6fd2807SJeff Garzik 		ata_port_abort(ap);
2003c6fd2807SJeff Garzik }
2004c6fd2807SJeff Garzik 
2005df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap)
2006c6fd2807SJeff Garzik {
2007350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
20089af5c9c9STejun Heo 	struct ata_eh_info *ehi = &ap->link.eh_info;
20090291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
20105f226c6bSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
2011b06ce3e5STejun Heo 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
2012c6fd2807SJeff Garzik 	u32 status, qc_active;
2013459ad688STejun Heo 	int rc;
2014c6fd2807SJeff Garzik 
2015c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
2016c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
2017c6fd2807SJeff Garzik 
2018b06ce3e5STejun Heo 	/* ignore BAD_PMP while resetting */
2019b06ce3e5STejun Heo 	if (unlikely(resetting))
2020b06ce3e5STejun Heo 		status &= ~PORT_IRQ_BAD_PMP;
2021b06ce3e5STejun Heo 
202231556594SKristen Carlson Accardi 	/* If we are getting PhyRdy, this is
202331556594SKristen Carlson Accardi  	 * just a power state change, we should
202431556594SKristen Carlson Accardi  	 * clear out this, plus the PhyRdy/Comm
202531556594SKristen Carlson Accardi  	 * Wake bits from Serror
202631556594SKristen Carlson Accardi  	 */
202731556594SKristen Carlson Accardi 	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
202831556594SKristen Carlson Accardi 		(status & PORT_IRQ_PHYRDY)) {
202931556594SKristen Carlson Accardi 		status &= ~PORT_IRQ_PHYRDY;
203031556594SKristen Carlson Accardi 		ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
203131556594SKristen Carlson Accardi 	}
203231556594SKristen Carlson Accardi 
2033c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
2034c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
2035c6fd2807SJeff Garzik 		return;
2036c6fd2807SJeff Garzik 	}
2037c6fd2807SJeff Garzik 
20382f294968SKristen Carlson Accardi 	if (status & PORT_IRQ_SDB_FIS) {
20395f226c6bSTejun Heo 		/* If SNotification is available, leave notification
20405f226c6bSTejun Heo 		 * handling to sata_async_notification().  If not,
20415f226c6bSTejun Heo 		 * emulate it by snooping SDB FIS RX area.
20425f226c6bSTejun Heo 		 *
20435f226c6bSTejun Heo 		 * Snooping FIS RX area is probably cheaper than
20445f226c6bSTejun Heo 		 * poking SNotification but some constrollers which
20455f226c6bSTejun Heo 		 * implement SNotification, ICH9 for example, don't
20465f226c6bSTejun Heo 		 * store AN SDB FIS into receive area.
20475f226c6bSTejun Heo 		 */
20485f226c6bSTejun Heo 		if (hpriv->cap & HOST_CAP_SNTF)
20495f226c6bSTejun Heo 			sata_async_notification(ap);
20505f226c6bSTejun Heo 		else {
20515f226c6bSTejun Heo 			/* If the 'N' bit in word 0 of the FIS is set,
20525f226c6bSTejun Heo 			 * we just received asynchronous notification.
20535f226c6bSTejun Heo 			 * Tell libata about it.
20542f294968SKristen Carlson Accardi 			 */
20552f294968SKristen Carlson Accardi 			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
20562f294968SKristen Carlson Accardi 			u32 f0 = le32_to_cpu(f[0]);
20572f294968SKristen Carlson Accardi 
20587d77b247STejun Heo 			if (f0 & (1 << 15))
20597d77b247STejun Heo 				sata_async_notification(ap);
20602f294968SKristen Carlson Accardi 		}
20615f226c6bSTejun Heo 	}
20622f294968SKristen Carlson Accardi 
20637d50b60bSTejun Heo 	/* pp->active_link is valid iff any command is in flight */
20647d50b60bSTejun Heo 	if (ap->qc_active && pp->active_link->sactive)
2065c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
2066c6fd2807SJeff Garzik 	else
2067c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
2068c6fd2807SJeff Garzik 
206979f97dadSTejun Heo 	rc = ata_qc_complete_multiple(ap, qc_active);
2070b06ce3e5STejun Heo 
2071459ad688STejun Heo 	/* while resetting, invalid completions are expected */
2072459ad688STejun Heo 	if (unlikely(rc < 0 && !resetting)) {
2073c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
2074cf480626STejun Heo 		ehi->action |= ATA_EH_RESET;
2075c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2076c6fd2807SJeff Garzik 	}
2077c6fd2807SJeff Garzik }
2078c6fd2807SJeff Garzik 
20797d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
2080c6fd2807SJeff Garzik {
2081cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
2082c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
2083c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
2084c6fd2807SJeff Garzik 	void __iomem *mmio;
2085d28f87aaSTejun Heo 	u32 irq_stat, irq_masked;
2086c6fd2807SJeff Garzik 
2087c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2088c6fd2807SJeff Garzik 
2089cca3974eSJeff Garzik 	hpriv = host->private_data;
20900d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
2091c6fd2807SJeff Garzik 
2092c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
2093c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
2094c6fd2807SJeff Garzik 	if (!irq_stat)
2095c6fd2807SJeff Garzik 		return IRQ_NONE;
2096c6fd2807SJeff Garzik 
2097d28f87aaSTejun Heo 	irq_masked = irq_stat & hpriv->port_map;
2098d28f87aaSTejun Heo 
2099cca3974eSJeff Garzik 	spin_lock(&host->lock);
2100c6fd2807SJeff Garzik 
2101cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
2102c6fd2807SJeff Garzik 		struct ata_port *ap;
2103c6fd2807SJeff Garzik 
2104d28f87aaSTejun Heo 		if (!(irq_masked & (1 << i)))
2105c6fd2807SJeff Garzik 			continue;
2106c6fd2807SJeff Garzik 
2107cca3974eSJeff Garzik 		ap = host->ports[i];
2108c6fd2807SJeff Garzik 		if (ap) {
2109df69c9c5SJeff Garzik 			ahci_port_intr(ap);
2110c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
2111c6fd2807SJeff Garzik 		} else {
2112c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
2113c6fd2807SJeff Garzik 			if (ata_ratelimit())
2114cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
2115c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
2116c6fd2807SJeff Garzik 		}
2117c6fd2807SJeff Garzik 
2118c6fd2807SJeff Garzik 		handled = 1;
2119c6fd2807SJeff Garzik 	}
2120c6fd2807SJeff Garzik 
2121d28f87aaSTejun Heo 	/* HOST_IRQ_STAT behaves as level triggered latch meaning that
2122d28f87aaSTejun Heo 	 * it should be cleared after all the port events are cleared;
2123d28f87aaSTejun Heo 	 * otherwise, it will raise a spurious interrupt after each
2124d28f87aaSTejun Heo 	 * valid one.  Please read section 10.6.2 of ahci 1.1 for more
2125d28f87aaSTejun Heo 	 * information.
2126d28f87aaSTejun Heo 	 *
2127d28f87aaSTejun Heo 	 * Also, use the unmasked value to clear interrupt as spurious
2128d28f87aaSTejun Heo 	 * pending event on a dummy port might cause screaming IRQ.
2129d28f87aaSTejun Heo 	 */
2130ea0c62f7STejun Heo 	writel(irq_stat, mmio + HOST_IRQ_STAT);
2131ea0c62f7STejun Heo 
2132cca3974eSJeff Garzik 	spin_unlock(&host->lock);
2133c6fd2807SJeff Garzik 
2134c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
2135c6fd2807SJeff Garzik 
2136c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
2137c6fd2807SJeff Garzik }
2138c6fd2807SJeff Garzik 
2139c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
2140c6fd2807SJeff Garzik {
2141c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
21424447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
21437d50b60bSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
21447d50b60bSTejun Heo 
21457d50b60bSTejun Heo 	/* Keep track of the currently active link.  It will be used
21467d50b60bSTejun Heo 	 * in completion path to determine whether NCQ phase is in
21477d50b60bSTejun Heo 	 * progress.
21487d50b60bSTejun Heo 	 */
21497d50b60bSTejun Heo 	pp->active_link = qc->dev->link;
2150c6fd2807SJeff Garzik 
2151c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
2152c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
2153c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
2154c6fd2807SJeff Garzik 
215518f7ba4cSKristen Carlson Accardi 	ahci_sw_activity(qc->dev->link);
215618f7ba4cSKristen Carlson Accardi 
2157c6fd2807SJeff Garzik 	return 0;
2158c6fd2807SJeff Garzik }
2159c6fd2807SJeff Garzik 
21604c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
21614c9bf4e7STejun Heo {
21624c9bf4e7STejun Heo 	struct ahci_port_priv *pp = qc->ap->private_data;
21634c9bf4e7STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
21644c9bf4e7STejun Heo 
21654c9bf4e7STejun Heo 	ata_tf_from_fis(d2h_fis, &qc->result_tf);
21664c9bf4e7STejun Heo 	return true;
21674c9bf4e7STejun Heo }
21684c9bf4e7STejun Heo 
2169c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
2170c6fd2807SJeff Garzik {
21714447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2172c6fd2807SJeff Garzik 
2173c6fd2807SJeff Garzik 	/* turn IRQ off */
2174c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
2175c6fd2807SJeff Garzik }
2176c6fd2807SJeff Garzik 
2177c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
2178c6fd2807SJeff Garzik {
21790d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
21804447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2181c6fd2807SJeff Garzik 	u32 tmp;
2182a7384925SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
2183c6fd2807SJeff Garzik 
2184c6fd2807SJeff Garzik 	/* clear IRQ */
2185c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
2186c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
2187a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
2188c6fd2807SJeff Garzik 
21891c954a4dSTejun Heo 	/* turn IRQ back on */
21901c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
2191c6fd2807SJeff Garzik }
2192c6fd2807SJeff Garzik 
2193c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
2194c6fd2807SJeff Garzik {
2195c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
2196c6fd2807SJeff Garzik 		/* restart engine */
21974447d351STejun Heo 		ahci_stop_engine(ap);
21984447d351STejun Heo 		ahci_start_engine(ap);
2199c6fd2807SJeff Garzik 	}
2200c6fd2807SJeff Garzik 
2201a1efdabaSTejun Heo 	sata_pmp_error_handler(ap);
2202edc93052STejun Heo }
2203edc93052STejun Heo 
2204c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
2205c6fd2807SJeff Garzik {
2206c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
2207c6fd2807SJeff Garzik 
2208c6fd2807SJeff Garzik 	/* make DMA engine forget about the failed command */
2209d2e75dffSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED)
2210d2e75dffSTejun Heo 		ahci_kick_engine(ap, 1);
2211c6fd2807SJeff Garzik }
2212c6fd2807SJeff Garzik 
22137d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap)
22147d50b60bSTejun Heo {
22157d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22161c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22177d50b60bSTejun Heo 	u32 cmd;
22187d50b60bSTejun Heo 
22197d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
22207d50b60bSTejun Heo 	cmd |= PORT_CMD_PMP;
22217d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
22221c954a4dSTejun Heo 
22231c954a4dSTejun Heo 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
22241c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
22257d50b60bSTejun Heo }
22267d50b60bSTejun Heo 
22277d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap)
22287d50b60bSTejun Heo {
22297d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22301c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22317d50b60bSTejun Heo 	u32 cmd;
22327d50b60bSTejun Heo 
22337d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
22347d50b60bSTejun Heo 	cmd &= ~PORT_CMD_PMP;
22357d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
22361c954a4dSTejun Heo 
22371c954a4dSTejun Heo 	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
22381c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
22397d50b60bSTejun Heo }
22407d50b60bSTejun Heo 
2241028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap)
2242028a2596SAlexey Dobriyan {
2243028a2596SAlexey Dobriyan 	ahci_power_up(ap);
2244028a2596SAlexey Dobriyan 	ahci_start_port(ap);
2245028a2596SAlexey Dobriyan 
2246071f44b1STejun Heo 	if (sata_pmp_attached(ap))
22477d50b60bSTejun Heo 		ahci_pmp_attach(ap);
22487d50b60bSTejun Heo 	else
22497d50b60bSTejun Heo 		ahci_pmp_detach(ap);
22507d50b60bSTejun Heo 
2251028a2596SAlexey Dobriyan 	return 0;
2252028a2596SAlexey Dobriyan }
2253028a2596SAlexey Dobriyan 
2254438ac6d5STejun Heo #ifdef CONFIG_PM
2255c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
2256c6fd2807SJeff Garzik {
2257c6fd2807SJeff Garzik 	const char *emsg = NULL;
2258c6fd2807SJeff Garzik 	int rc;
2259c6fd2807SJeff Garzik 
22604447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
22618e16f941STejun Heo 	if (rc == 0)
22624447d351STejun Heo 		ahci_power_down(ap);
22638e16f941STejun Heo 	else {
2264c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
2265df69c9c5SJeff Garzik 		ahci_start_port(ap);
2266c6fd2807SJeff Garzik 	}
2267c6fd2807SJeff Garzik 
2268c6fd2807SJeff Garzik 	return rc;
2269c6fd2807SJeff Garzik }
2270c6fd2807SJeff Garzik 
2271c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
2272c6fd2807SJeff Garzik {
2273cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
22740d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2275c6fd2807SJeff Garzik 	u32 ctl;
2276c6fd2807SJeff Garzik 
22773a2d5b70SRafael J. Wysocki 	if (mesg.event & PM_EVENT_SLEEP) {
2278c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
2279c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
2280c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
2281c6fd2807SJeff Garzik 		 */
2282c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
2283c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
2284c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
2285c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
2286c6fd2807SJeff Garzik 	}
2287c6fd2807SJeff Garzik 
2288c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
2289c6fd2807SJeff Garzik }
2290c6fd2807SJeff Garzik 
2291c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
2292c6fd2807SJeff Garzik {
2293cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
2294c6fd2807SJeff Garzik 	int rc;
2295c6fd2807SJeff Garzik 
2296553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
2297553c4aa6STejun Heo 	if (rc)
2298553c4aa6STejun Heo 		return rc;
2299c6fd2807SJeff Garzik 
2300c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
23014447d351STejun Heo 		rc = ahci_reset_controller(host);
2302c6fd2807SJeff Garzik 		if (rc)
2303c6fd2807SJeff Garzik 			return rc;
2304c6fd2807SJeff Garzik 
23054447d351STejun Heo 		ahci_init_controller(host);
2306c6fd2807SJeff Garzik 	}
2307c6fd2807SJeff Garzik 
2308cca3974eSJeff Garzik 	ata_host_resume(host);
2309c6fd2807SJeff Garzik 
2310c6fd2807SJeff Garzik 	return 0;
2311c6fd2807SJeff Garzik }
2312438ac6d5STejun Heo #endif
2313c6fd2807SJeff Garzik 
2314c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
2315c6fd2807SJeff Garzik {
2316cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
2317c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
2318c6fd2807SJeff Garzik 	void *mem;
2319c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
2320c6fd2807SJeff Garzik 
232124dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
2322c6fd2807SJeff Garzik 	if (!pp)
2323c6fd2807SJeff Garzik 		return -ENOMEM;
2324c6fd2807SJeff Garzik 
232524dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
232624dc5f33STejun Heo 				  GFP_KERNEL);
232724dc5f33STejun Heo 	if (!mem)
2328c6fd2807SJeff Garzik 		return -ENOMEM;
2329c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
2330c6fd2807SJeff Garzik 
2331c6fd2807SJeff Garzik 	/*
2332c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
2333c6fd2807SJeff Garzik 	 * 32 bytes each in size
2334c6fd2807SJeff Garzik 	 */
2335c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
2336c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
2337c6fd2807SJeff Garzik 
2338c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
2339c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
2340c6fd2807SJeff Garzik 
2341c6fd2807SJeff Garzik 	/*
2342c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
2343c6fd2807SJeff Garzik 	 */
2344c6fd2807SJeff Garzik 	pp->rx_fis = mem;
2345c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
2346c6fd2807SJeff Garzik 
2347c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
2348c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
2349c6fd2807SJeff Garzik 
2350c6fd2807SJeff Garzik 	/*
2351c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
2352c6fd2807SJeff Garzik 	 * and its scatter-gather table
2353c6fd2807SJeff Garzik 	 */
2354c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
2355c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
2356c6fd2807SJeff Garzik 
2357a7384925SKristen Carlson Accardi 	/*
2358a7384925SKristen Carlson Accardi 	 * Save off initial list of interrupts to be enabled.
2359a7384925SKristen Carlson Accardi 	 * This could be changed later
2360a7384925SKristen Carlson Accardi 	 */
2361a7384925SKristen Carlson Accardi 	pp->intr_mask = DEF_PORT_IRQ;
2362a7384925SKristen Carlson Accardi 
2363c6fd2807SJeff Garzik 	ap->private_data = pp;
2364c6fd2807SJeff Garzik 
2365df69c9c5SJeff Garzik 	/* engage engines, captain */
2366df69c9c5SJeff Garzik 	return ahci_port_resume(ap);
2367c6fd2807SJeff Garzik }
2368c6fd2807SJeff Garzik 
2369c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
2370c6fd2807SJeff Garzik {
2371c6fd2807SJeff Garzik 	const char *emsg = NULL;
2372c6fd2807SJeff Garzik 	int rc;
2373c6fd2807SJeff Garzik 
2374c6fd2807SJeff Garzik 	/* de-initialize port */
23754447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
2376c6fd2807SJeff Garzik 	if (rc)
2377c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
2378c6fd2807SJeff Garzik }
2379c6fd2807SJeff Garzik 
23804447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
2381c6fd2807SJeff Garzik {
2382c6fd2807SJeff Garzik 	int rc;
2383c6fd2807SJeff Garzik 
2384c6fd2807SJeff Garzik 	if (using_dac &&
2385c6fd2807SJeff Garzik 	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
2386c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
2387c6fd2807SJeff Garzik 		if (rc) {
2388c6fd2807SJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
2389c6fd2807SJeff Garzik 			if (rc) {
2390c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
2391c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
2392c6fd2807SJeff Garzik 				return rc;
2393c6fd2807SJeff Garzik 			}
2394c6fd2807SJeff Garzik 		}
2395c6fd2807SJeff Garzik 	} else {
2396c6fd2807SJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
2397c6fd2807SJeff Garzik 		if (rc) {
2398c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2399c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
2400c6fd2807SJeff Garzik 			return rc;
2401c6fd2807SJeff Garzik 		}
2402c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
2403c6fd2807SJeff Garzik 		if (rc) {
2404c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2405c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
2406c6fd2807SJeff Garzik 			return rc;
2407c6fd2807SJeff Garzik 		}
2408c6fd2807SJeff Garzik 	}
2409c6fd2807SJeff Garzik 	return 0;
2410c6fd2807SJeff Garzik }
2411c6fd2807SJeff Garzik 
24124447d351STejun Heo static void ahci_print_info(struct ata_host *host)
2413c6fd2807SJeff Garzik {
24144447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
24154447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
24164447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2417c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
2418c6fd2807SJeff Garzik 	const char *speed_s;
2419c6fd2807SJeff Garzik 	u16 cc;
2420c6fd2807SJeff Garzik 	const char *scc_s;
2421c6fd2807SJeff Garzik 
2422c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
2423c6fd2807SJeff Garzik 	cap = hpriv->cap;
2424c6fd2807SJeff Garzik 	impl = hpriv->port_map;
2425c6fd2807SJeff Garzik 
2426c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
2427c6fd2807SJeff Garzik 	if (speed == 1)
2428c6fd2807SJeff Garzik 		speed_s = "1.5";
2429c6fd2807SJeff Garzik 	else if (speed == 2)
2430c6fd2807SJeff Garzik 		speed_s = "3";
2431c6fd2807SJeff Garzik 	else
2432c6fd2807SJeff Garzik 		speed_s = "?";
2433c6fd2807SJeff Garzik 
2434c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
2435c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
2436c6fd2807SJeff Garzik 		scc_s = "IDE";
2437c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
2438c6fd2807SJeff Garzik 		scc_s = "SATA";
2439c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
2440c6fd2807SJeff Garzik 		scc_s = "RAID";
2441c6fd2807SJeff Garzik 	else
2442c6fd2807SJeff Garzik 		scc_s = "unknown";
2443c6fd2807SJeff Garzik 
2444c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2445c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
2446c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
2447c6fd2807SJeff Garzik 		,
2448c6fd2807SJeff Garzik 
2449c6fd2807SJeff Garzik 		(vers >> 24) & 0xff,
2450c6fd2807SJeff Garzik 		(vers >> 16) & 0xff,
2451c6fd2807SJeff Garzik 		(vers >> 8) & 0xff,
2452c6fd2807SJeff Garzik 		vers & 0xff,
2453c6fd2807SJeff Garzik 
2454c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
2455c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
2456c6fd2807SJeff Garzik 		speed_s,
2457c6fd2807SJeff Garzik 		impl,
2458c6fd2807SJeff Garzik 		scc_s);
2459c6fd2807SJeff Garzik 
2460c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2461c6fd2807SJeff Garzik 		"flags: "
2462203ef6c4STejun Heo 		"%s%s%s%s%s%s%s"
246318f7ba4cSKristen Carlson Accardi 		"%s%s%s%s%s%s%s"
246418f7ba4cSKristen Carlson Accardi 		"%s\n"
2465c6fd2807SJeff Garzik 		,
2466c6fd2807SJeff Garzik 
2467c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
2468c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
2469203ef6c4STejun Heo 		cap & (1 << 29) ? "sntf " : "",
2470c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
2471c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
2472c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
2473c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
2474c6fd2807SJeff Garzik 
2475c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
2476c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
2477c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
2478c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
2479c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
2480c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
248118f7ba4cSKristen Carlson Accardi 		cap & (1 << 13) ? "part " : "",
248218f7ba4cSKristen Carlson Accardi 		cap & (1 << 6) ? "ems ": ""
2483c6fd2807SJeff Garzik 		);
2484c6fd2807SJeff Garzik }
2485c6fd2807SJeff Garzik 
2486edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2487edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
2488edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
2489edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
2490edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
2491edc93052STejun Heo  * other configuration).
2492edc93052STejun Heo  *
2493edc93052STejun Heo  * When there's no device attached to the first downstream port of the
2494edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
2495edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
2496edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
2497edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2498edc93052STejun Heo  *
2499edc93052STejun Heo  * The following function works around the problem by always using
2500edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
2501edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
2502edc93052STejun Heo  * assumed without follow-up softreset.
2503edc93052STejun Heo  */
2504edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
2505edc93052STejun Heo {
2506edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
2507edc93052STejun Heo 		{
2508edc93052STejun Heo 			.ident = "P5W DH Deluxe",
2509edc93052STejun Heo 			.matches = {
2510edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
2511edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
2512edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2513edc93052STejun Heo 			},
2514edc93052STejun Heo 		},
2515edc93052STejun Heo 		{ }
2516edc93052STejun Heo 	};
2517edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
2518edc93052STejun Heo 
2519edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2520edc93052STejun Heo 	    dmi_check_system(sysids)) {
2521edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
2522edc93052STejun Heo 
2523edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2524edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
2525edc93052STejun Heo 
2526edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
2527edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2528edc93052STejun Heo 	}
2529edc93052STejun Heo }
2530edc93052STejun Heo 
2531c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2532c6fd2807SJeff Garzik {
2533c6fd2807SJeff Garzik 	static int printed_version;
2534e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
2535e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
25364447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
253724dc5f33STejun Heo 	struct device *dev = &pdev->dev;
2538c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
25394447d351STejun Heo 	struct ata_host *host;
2540837f5f8fSTejun Heo 	int n_ports, i, rc;
2541c6fd2807SJeff Garzik 
2542c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2543c6fd2807SJeff Garzik 
2544c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
2545c6fd2807SJeff Garzik 
2546c6fd2807SJeff Garzik 	if (!printed_version++)
2547c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
2548c6fd2807SJeff Garzik 
25495b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
25505b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
25515b66c829SAlan Cox 	   AHCI stays out of the way */
25525b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
25535b66c829SAlan Cox 		return -ENODEV;
25545b66c829SAlan Cox 
25554447d351STejun Heo 	/* acquire resources */
255624dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
2557c6fd2807SJeff Garzik 	if (rc)
2558c6fd2807SJeff Garzik 		return rc;
2559c6fd2807SJeff Garzik 
2560dea55137STejun Heo 	/* AHCI controllers often implement SFF compatible interface.
2561dea55137STejun Heo 	 * Grab all PCI BARs just in case.
2562dea55137STejun Heo 	 */
2563dea55137STejun Heo 	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
25640d5ff566STejun Heo 	if (rc == -EBUSY)
256524dc5f33STejun Heo 		pcim_pin_device(pdev);
25660d5ff566STejun Heo 	if (rc)
256724dc5f33STejun Heo 		return rc;
2568c6fd2807SJeff Garzik 
2569c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
2570c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
2571c4f7792cSTejun Heo 		u8 map;
2572c4f7792cSTejun Heo 
2573c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
2574c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
2575c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
2576c4f7792cSTejun Heo 		 */
2577c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
2578c4f7792cSTejun Heo 		if (map & 0x3) {
2579c4f7792cSTejun Heo 			dev_printk(KERN_INFO, &pdev->dev, "controller is in "
2580c4f7792cSTejun Heo 				   "combined mode, can't enable AHCI mode\n");
2581c4f7792cSTejun Heo 			return -ENODEV;
2582c4f7792cSTejun Heo 		}
2583c4f7792cSTejun Heo 	}
2584c4f7792cSTejun Heo 
258524dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
258624dc5f33STejun Heo 	if (!hpriv)
258724dc5f33STejun Heo 		return -ENOMEM;
2588417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
2589417a1a6dSTejun Heo 
2590e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
2591e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
2592e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
2593e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
2594e297d99eSTejun Heo 
2595417a1a6dSTejun Heo 	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
2596417a1a6dSTejun Heo 		pci_intx(pdev, 1);
2597c6fd2807SJeff Garzik 
25984447d351STejun Heo 	/* save initial config */
2599417a1a6dSTejun Heo 	ahci_save_initial_config(pdev, hpriv);
2600c6fd2807SJeff Garzik 
26014447d351STejun Heo 	/* prepare host */
2602274c1fdeSTejun Heo 	if (hpriv->cap & HOST_CAP_NCQ)
26034447d351STejun Heo 		pi.flags |= ATA_FLAG_NCQ;
26044447d351STejun Heo 
26057d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
26067d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
26077d50b60bSTejun Heo 
260818f7ba4cSKristen Carlson Accardi 	if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) {
260918f7ba4cSKristen Carlson Accardi 		u8 messages;
261018f7ba4cSKristen Carlson Accardi 		void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
261118f7ba4cSKristen Carlson Accardi 		u32 em_loc = readl(mmio + HOST_EM_LOC);
261218f7ba4cSKristen Carlson Accardi 		u32 em_ctl = readl(mmio + HOST_EM_CTL);
261318f7ba4cSKristen Carlson Accardi 
261418f7ba4cSKristen Carlson Accardi 		messages = (em_ctl & 0x000f0000) >> 16;
261518f7ba4cSKristen Carlson Accardi 
261618f7ba4cSKristen Carlson Accardi 		/* we only support LED message type right now */
261718f7ba4cSKristen Carlson Accardi 		if ((messages & 0x01) && (ahci_em_messages == 1)) {
261818f7ba4cSKristen Carlson Accardi 			/* store em_loc */
261918f7ba4cSKristen Carlson Accardi 			hpriv->em_loc = ((em_loc >> 16) * 4);
262018f7ba4cSKristen Carlson Accardi 			pi.flags |= ATA_FLAG_EM;
262118f7ba4cSKristen Carlson Accardi 			if (!(em_ctl & EM_CTL_ALHD))
262218f7ba4cSKristen Carlson Accardi 				pi.flags |= ATA_FLAG_SW_ACTIVITY;
262318f7ba4cSKristen Carlson Accardi 		}
262418f7ba4cSKristen Carlson Accardi 	}
262518f7ba4cSKristen Carlson Accardi 
2626837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
2627837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
2628837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
2629837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
2630837f5f8fSTejun Heo 	 */
2631837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
2632837f5f8fSTejun Heo 
2633837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
26344447d351STejun Heo 	if (!host)
26354447d351STejun Heo 		return -ENOMEM;
26364447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
26374447d351STejun Heo 	host->private_data = hpriv;
26384447d351STejun Heo 
263918f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
264018f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
264118f7ba4cSKristen Carlson Accardi 
26424447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
26434447d351STejun Heo 		struct ata_port *ap = host->ports[i];
26444447d351STejun Heo 
2645cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
2646cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
2647cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
2648cbcdd875STejun Heo 
264931556594SKristen Carlson Accardi 		/* set initial link pm policy */
265031556594SKristen Carlson Accardi 		ap->pm_policy = NOT_AVAILABLE;
265131556594SKristen Carlson Accardi 
265218f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
265318f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
265418f7ba4cSKristen Carlson Accardi 			ap->em_message_type = ahci_em_messages;
265518f7ba4cSKristen Carlson Accardi 
265618f7ba4cSKristen Carlson Accardi 
2657dab632e8SJeff Garzik 		/* disabled/not-implemented port */
2658350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
2659dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
26604447d351STejun Heo 	}
2661c6fd2807SJeff Garzik 
2662edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
2663edc93052STejun Heo 	ahci_p5wdh_workaround(host);
2664edc93052STejun Heo 
2665c6fd2807SJeff Garzik 	/* initialize adapter */
26664447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
2667c6fd2807SJeff Garzik 	if (rc)
266824dc5f33STejun Heo 		return rc;
2669c6fd2807SJeff Garzik 
26704447d351STejun Heo 	rc = ahci_reset_controller(host);
26714447d351STejun Heo 	if (rc)
26724447d351STejun Heo 		return rc;
2673c6fd2807SJeff Garzik 
26744447d351STejun Heo 	ahci_init_controller(host);
26754447d351STejun Heo 	ahci_print_info(host);
2676c6fd2807SJeff Garzik 
26774447d351STejun Heo 	pci_set_master(pdev);
26784447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
26794447d351STejun Heo 				 &ahci_sht);
2680c6fd2807SJeff Garzik }
2681c6fd2807SJeff Garzik 
2682c6fd2807SJeff Garzik static int __init ahci_init(void)
2683c6fd2807SJeff Garzik {
2684c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
2685c6fd2807SJeff Garzik }
2686c6fd2807SJeff Garzik 
2687c6fd2807SJeff Garzik static void __exit ahci_exit(void)
2688c6fd2807SJeff Garzik {
2689c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
2690c6fd2807SJeff Garzik }
2691c6fd2807SJeff Garzik 
2692c6fd2807SJeff Garzik 
2693c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
2694c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
2695c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
2696c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
2697c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
2698c6fd2807SJeff Garzik 
2699c6fd2807SJeff Garzik module_init(ahci_init);
2700c6fd2807SJeff Garzik module_exit(ahci_exit);
2701