xref: /openbmc/linux/drivers/ata/ahci.c (revision 886ad09fc83342aa1c5a02a0b6d3298b78a8067f)
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 
5287943acfSDavid Milburn /* Enclosure Management Control */
5387943acfSDavid Milburn #define EM_CTRL_MSG_TYPE              0x000f0000
5487943acfSDavid Milburn 
5587943acfSDavid Milburn /* Enclosure Management LED Message Type */
5687943acfSDavid Milburn #define EM_MSG_LED_HBA_PORT           0x0000000f
5787943acfSDavid Milburn #define EM_MSG_LED_PMP_SLOT           0x0000ff00
5887943acfSDavid Milburn #define EM_MSG_LED_VALUE              0xffff0000
5987943acfSDavid Milburn #define EM_MSG_LED_VALUE_ACTIVITY     0x00070000
6087943acfSDavid Milburn #define EM_MSG_LED_VALUE_OFF          0xfff80000
6187943acfSDavid Milburn #define EM_MSG_LED_VALUE_ON           0x00010000
6287943acfSDavid Milburn 
63a22e6444STejun Heo static int ahci_skip_host_reset;
64a22e6444STejun Heo module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
65a22e6444STejun Heo MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
66a22e6444STejun Heo 
6731556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
6831556594SKristen Carlson Accardi 		enum link_pm policy);
6931556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap);
7018f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
7118f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
7218f7ba4cSKristen Carlson Accardi 			      size_t size);
7318f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
7418f7ba4cSKristen Carlson Accardi 					ssize_t size);
7518f7ba4cSKristen Carlson Accardi #define MAX_SLOTS 8
76c6fd2807SJeff Garzik 
77c6fd2807SJeff Garzik enum {
78c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
79648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
80c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
81c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
82c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
83c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
84c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
85c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
86c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
87c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
88c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
89c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
90c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
91c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
92c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
93c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
94c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
95c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
96c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
97c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
98c6fd2807SJeff Garzik 
99c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
1000291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
101c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
102c6fd2807SJeff Garzik 
103c6fd2807SJeff Garzik 	board_ahci		= 0,
1047a234affSTejun Heo 	board_ahci_vt8251	= 1,
1057a234affSTejun Heo 	board_ahci_ign_iferr	= 2,
1067a234affSTejun Heo 	board_ahci_sb600	= 3,
1077a234affSTejun Heo 	board_ahci_mv		= 4,
108e427fe04SShane Huang 	board_ahci_sb700	= 5, /* for SB700 and SB800 */
109e297d99eSTejun Heo 	board_ahci_mcp65	= 6,
1109a3b103cSTejun Heo 	board_ahci_nopmp	= 7,
111c6fd2807SJeff Garzik 
112c6fd2807SJeff Garzik 	/* global controller registers */
113c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
114c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
115c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
116c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
117c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
11818f7ba4cSKristen Carlson Accardi 	HOST_EM_LOC		= 0x1c, /* Enclosure Management location */
11918f7ba4cSKristen Carlson Accardi 	HOST_EM_CTL		= 0x20, /* Enclosure Management Control */
120c6fd2807SJeff Garzik 
121c6fd2807SJeff Garzik 	/* HOST_CTL bits */
122c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
123c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
124c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
125c6fd2807SJeff Garzik 
126c6fd2807SJeff Garzik 	/* HOST_CAP bits */
12718f7ba4cSKristen Carlson Accardi 	HOST_CAP_EMS		= (1 << 6),  /* Enclosure Management support */
128c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
1297d50b60bSTejun Heo 	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
130c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
13131556594SKristen Carlson Accardi 	HOST_CAP_ALPM		= (1 << 26), /* Aggressive Link PM support */
132c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
133203ef6c4STejun Heo 	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
134c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
135c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
136c6fd2807SJeff Garzik 
137c6fd2807SJeff Garzik 	/* registers for each SATA port */
138c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
139c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
140c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
141c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
142c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
143c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
144c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
145c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
146c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
147c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
148c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
149c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
150c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
151c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
152203ef6c4STejun Heo 	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
153c6fd2807SJeff Garzik 
154c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
155c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
156c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
157c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
158c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
159c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
160c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
161c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
162c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
163c6fd2807SJeff Garzik 
164c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
165c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
166c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
167c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
168c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
169c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
170c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
171c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
172c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
173c6fd2807SJeff Garzik 
174c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
175c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
176c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
177c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
1787d50b60bSTejun Heo 				  PORT_IRQ_UNK_FIS |
1797d50b60bSTejun Heo 				  PORT_IRQ_BAD_PMP,
180c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
181c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
182c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
183c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
184c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
185c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
186c6fd2807SJeff Garzik 
187c6fd2807SJeff Garzik 	/* PORT_CMD bits */
18831556594SKristen Carlson Accardi 	PORT_CMD_ASP		= (1 << 27), /* Aggressive Slumber/Partial */
18931556594SKristen Carlson Accardi 	PORT_CMD_ALPE		= (1 << 26), /* Aggressive Link PM enable */
190c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
1917d50b60bSTejun Heo 	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
192c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
193c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
194c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
195c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
196c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
197c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
198c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
199c6fd2807SJeff Garzik 
200c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
201c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
202c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
203c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
204c6fd2807SJeff Garzik 
205417a1a6dSTejun Heo 	/* hpriv->flags bits */
206417a1a6dSTejun Heo 	AHCI_HFLAG_NO_NCQ		= (1 << 0),
207417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
208417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
209417a1a6dSTejun Heo 	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
210417a1a6dSTejun Heo 	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
211417a1a6dSTejun Heo 	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
2126949b914STejun Heo 	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
21331556594SKristen Carlson Accardi 	AHCI_HFLAG_NO_HOTPLUG		= (1 << 7), /* ignore PxSERR.DIAG.N */
214a878539eSJeff Garzik 	AHCI_HFLAG_SECT255		= (1 << 8), /* max 255 sectors */
215e297d99eSTejun Heo 	AHCI_HFLAG_YES_NCQ		= (1 << 9), /* force NCQ cap on */
216417a1a6dSTejun Heo 
217c6fd2807SJeff Garzik 	/* ap->flags bits */
2181188c0d8STejun Heo 
2191188c0d8STejun Heo 	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
2201188c0d8STejun Heo 					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
22131556594SKristen Carlson Accardi 					  ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
22231556594SKristen Carlson Accardi 					  ATA_FLAG_IPM,
223c4f7792cSTejun Heo 
224c4f7792cSTejun Heo 	ICH_MAP				= 0x90, /* ICH MAP register */
22518f7ba4cSKristen Carlson Accardi 
22618f7ba4cSKristen Carlson Accardi 	/* em_ctl bits */
22718f7ba4cSKristen Carlson Accardi 	EM_CTL_RST			= (1 << 9), /* Reset */
22818f7ba4cSKristen Carlson Accardi 	EM_CTL_TM			= (1 << 8), /* Transmit Message */
22918f7ba4cSKristen Carlson Accardi 	EM_CTL_ALHD			= (1 << 26), /* Activity LED */
230c6fd2807SJeff Garzik };
231c6fd2807SJeff Garzik 
232c6fd2807SJeff Garzik struct ahci_cmd_hdr {
2334ca4e439SAl Viro 	__le32			opts;
2344ca4e439SAl Viro 	__le32			status;
2354ca4e439SAl Viro 	__le32			tbl_addr;
2364ca4e439SAl Viro 	__le32			tbl_addr_hi;
2374ca4e439SAl Viro 	__le32			reserved[4];
238c6fd2807SJeff Garzik };
239c6fd2807SJeff Garzik 
240c6fd2807SJeff Garzik struct ahci_sg {
2414ca4e439SAl Viro 	__le32			addr;
2424ca4e439SAl Viro 	__le32			addr_hi;
2434ca4e439SAl Viro 	__le32			reserved;
2444ca4e439SAl Viro 	__le32			flags_size;
245c6fd2807SJeff Garzik };
246c6fd2807SJeff Garzik 
24718f7ba4cSKristen Carlson Accardi struct ahci_em_priv {
24818f7ba4cSKristen Carlson Accardi 	enum sw_activity blink_policy;
24918f7ba4cSKristen Carlson Accardi 	struct timer_list timer;
25018f7ba4cSKristen Carlson Accardi 	unsigned long saved_activity;
25118f7ba4cSKristen Carlson Accardi 	unsigned long activity;
25218f7ba4cSKristen Carlson Accardi 	unsigned long led_state;
25318f7ba4cSKristen Carlson Accardi };
25418f7ba4cSKristen Carlson Accardi 
255c6fd2807SJeff Garzik struct ahci_host_priv {
256417a1a6dSTejun Heo 	unsigned int		flags;		/* AHCI_HFLAG_* */
257d447df14STejun Heo 	u32			cap;		/* cap to use */
258d447df14STejun Heo 	u32			port_map;	/* port map to use */
259d447df14STejun Heo 	u32			saved_cap;	/* saved initial cap */
260d447df14STejun Heo 	u32			saved_port_map;	/* saved initial port_map */
26118f7ba4cSKristen Carlson Accardi 	u32 			em_loc; /* enclosure management location */
262c6fd2807SJeff Garzik };
263c6fd2807SJeff Garzik 
264c6fd2807SJeff Garzik struct ahci_port_priv {
2657d50b60bSTejun Heo 	struct ata_link		*active_link;
266c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
267c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
268c6fd2807SJeff Garzik 	void			*cmd_tbl;
269c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
270c6fd2807SJeff Garzik 	void			*rx_fis;
271c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2720291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2730291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2740291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
275afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
276a7384925SKristen Carlson Accardi 	u32 			intr_mask;	/* interrupts to enable */
27718f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv	em_priv[MAX_SLOTS];/* enclosure management info
27818f7ba4cSKristen Carlson Accardi 					 	 * per PM slot */
279c6fd2807SJeff Garzik };
280c6fd2807SJeff Garzik 
28182ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
28282ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
283c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
284c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
2854c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
286c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
287c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
288c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
289c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
290c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
2917d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap);
2927d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap);
293a1efdabaSTejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class,
294a1efdabaSTejun Heo 			  unsigned long deadline);
295bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
296bd17243aSShane Huang 			  unsigned long deadline);
297a1efdabaSTejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
298a1efdabaSTejun Heo 			  unsigned long deadline);
299a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
300a1efdabaSTejun Heo 				 unsigned long deadline);
301a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
302a1efdabaSTejun Heo 				unsigned long deadline);
303a1efdabaSTejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class);
304c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
305c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
306df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
307a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev);
308dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
309dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
310dab632e8SJeff Garzik 			       u32 opts);
311438ac6d5STejun Heo #ifdef CONFIG_PM
312c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
313c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
314c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
315438ac6d5STejun Heo #endif
31618f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf);
31718f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev,
31818f7ba4cSKristen Carlson Accardi 				   enum sw_activity val);
31918f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link);
320c6fd2807SJeff Garzik 
321ee959b00STony Jones static struct device_attribute *ahci_shost_attrs[] = {
322ee959b00STony Jones 	&dev_attr_link_power_management_policy,
32318f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message_type,
32418f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message,
32518f7ba4cSKristen Carlson Accardi 	NULL
32618f7ba4cSKristen Carlson Accardi };
32718f7ba4cSKristen Carlson Accardi 
32818f7ba4cSKristen Carlson Accardi static struct device_attribute *ahci_sdev_attrs[] = {
32918f7ba4cSKristen Carlson Accardi 	&dev_attr_sw_activity,
33045fabbb7SElias Oltmanns 	&dev_attr_unload_heads,
33131556594SKristen Carlson Accardi 	NULL
33231556594SKristen Carlson Accardi };
33331556594SKristen Carlson Accardi 
334c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
33568d1d07bSTejun Heo 	ATA_NCQ_SHT(DRV_NAME),
336c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
337c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
338c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
33931556594SKristen Carlson Accardi 	.shost_attrs		= ahci_shost_attrs,
34018f7ba4cSKristen Carlson Accardi 	.sdev_attrs		= ahci_sdev_attrs,
341c6fd2807SJeff Garzik };
342c6fd2807SJeff Garzik 
343029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = {
344029cfd6bSTejun Heo 	.inherits		= &sata_pmp_port_ops,
345029cfd6bSTejun Heo 
3467d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
347c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
348c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
3494c9bf4e7STejun Heo 	.qc_fill_rtf		= ahci_qc_fill_rtf,
350c6fd2807SJeff Garzik 
351c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
352c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
353a1efdabaSTejun Heo 	.softreset		= ahci_softreset,
354a1efdabaSTejun Heo 	.hardreset		= ahci_hardreset,
355a1efdabaSTejun Heo 	.postreset		= ahci_postreset,
356071f44b1STejun Heo 	.pmp_softreset		= ahci_softreset,
357c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
358c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
359029cfd6bSTejun Heo 	.dev_config		= ahci_dev_config,
360c6fd2807SJeff Garzik 
361029cfd6bSTejun Heo 	.scr_read		= ahci_scr_read,
362029cfd6bSTejun Heo 	.scr_write		= ahci_scr_write,
3637d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
3647d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3657d50b60bSTejun Heo 
366029cfd6bSTejun Heo 	.enable_pm		= ahci_enable_alpm,
367029cfd6bSTejun Heo 	.disable_pm		= ahci_disable_alpm,
36818f7ba4cSKristen Carlson Accardi 	.em_show		= ahci_led_show,
36918f7ba4cSKristen Carlson Accardi 	.em_store		= ahci_led_store,
37018f7ba4cSKristen Carlson Accardi 	.sw_activity_show	= ahci_activity_show,
37118f7ba4cSKristen Carlson Accardi 	.sw_activity_store	= ahci_activity_store,
372438ac6d5STejun Heo #ifdef CONFIG_PM
373c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
374c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
375438ac6d5STejun Heo #endif
376c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
377c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
378c6fd2807SJeff Garzik };
379c6fd2807SJeff Garzik 
380029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
381029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
382a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
383ad616ffbSTejun Heo };
384ad616ffbSTejun Heo 
385029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
386029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
387a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
388edc93052STejun Heo };
389edc93052STejun Heo 
390bd17243aSShane Huang static struct ata_port_operations ahci_sb600_ops = {
391bd17243aSShane Huang 	.inherits		= &ahci_ops,
392bd17243aSShane Huang 	.softreset		= ahci_sb600_softreset,
393bd17243aSShane Huang 	.pmp_softreset		= ahci_sb600_softreset,
394bd17243aSShane Huang };
395bd17243aSShane Huang 
396417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
397417a1a6dSTejun Heo 
398c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
399c6fd2807SJeff Garzik 	/* board_ahci */
400c6fd2807SJeff Garzik 	{
4011188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
402c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
403469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
404c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
405c6fd2807SJeff Garzik 	},
406c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
407c6fd2807SJeff Garzik 	{
4086949b914STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
409417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
410c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
411469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
412ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
413c6fd2807SJeff Garzik 	},
41441669553STejun Heo 	/* board_ahci_ign_iferr */
41541669553STejun Heo 	{
416417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
417417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
41841669553STejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
419469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
42041669553STejun Heo 		.port_ops	= &ahci_ops,
42141669553STejun Heo 	},
42255a61604SConke Hu 	/* board_ahci_sb600 */
42355a61604SConke Hu 	{
424417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
42522b5e7a7STejun Heo 				 AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
426bd17243aSShane Huang 				 AHCI_HFLAG_SECT255),
427417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
42855a61604SConke Hu 		.pio_mask	= 0x1f, /* pio0-4 */
429469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
430bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
43155a61604SConke Hu 	},
432cd70c266SJeff Garzik 	/* board_ahci_mv */
433cd70c266SJeff Garzik 	{
434417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
43517248461STejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
436cd70c266SJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
437417a1a6dSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
438cd70c266SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
439cd70c266SJeff Garzik 		.udma_mask	= ATA_UDMA6,
440cd70c266SJeff Garzik 		.port_ops	= &ahci_ops,
441cd70c266SJeff Garzik 	},
442e427fe04SShane Huang 	/* board_ahci_sb700, for SB700 and SB800 */
443e39fc8c9SShane Huang 	{
444bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
445e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
446e39fc8c9SShane Huang 		.pio_mask	= 0x1f, /* pio0-4 */
447e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
448bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
449e39fc8c9SShane Huang 	},
450e297d99eSTejun Heo 	/* board_ahci_mcp65 */
451e297d99eSTejun Heo 	{
452e297d99eSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
453e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
454e297d99eSTejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
455e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
456e297d99eSTejun Heo 		.port_ops	= &ahci_ops,
457e297d99eSTejun Heo 	},
4589a3b103cSTejun Heo 	/* board_ahci_nopmp */
4599a3b103cSTejun Heo 	{
4609a3b103cSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP),
4619a3b103cSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
4629a3b103cSTejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
4639a3b103cSTejun Heo 		.udma_mask	= ATA_UDMA6,
4649a3b103cSTejun Heo 		.port_ops	= &ahci_ops,
4659a3b103cSTejun Heo 	},
466c6fd2807SJeff Garzik };
467c6fd2807SJeff Garzik 
468c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
469c6fd2807SJeff Garzik 	/* Intel */
47054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
47154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
47254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
47354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
47454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
47582490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
47654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
47754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
47854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
47954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
4807a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
4817a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
4827a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
4837a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
4847a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
4857a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
4867a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
4877a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
4887a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
4897a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
4907a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
4917a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
4927a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
4937a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
4947a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
4957a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
4967a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
497d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
498d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
49916ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
50016ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
501adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
5028e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
503adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
5048e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
505c6fd2807SJeff Garzik 
506e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
507e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
508e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
509c6fd2807SJeff Garzik 
510c6fd2807SJeff Garzik 	/* ATI */
511c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
512e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
513e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
514e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
515e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
516e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
517e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
518c6fd2807SJeff Garzik 
519c6fd2807SJeff Garzik 	/* VIA */
52054bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
521bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
522c6fd2807SJeff Garzik 
523c6fd2807SJeff Garzik 	/* NVIDIA */
524e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
525e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
526e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
527e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
528e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
529e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
530e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
531e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
5326fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci },		/* MCP67 */
5336fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci },		/* MCP67 */
5346fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci },		/* MCP67 */
5356fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci },		/* MCP67 */
536895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },		/* MCP67 */
537895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },		/* MCP67 */
538895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },		/* MCP67 */
539895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },		/* MCP67 */
540895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },		/* MCP67 */
541895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },		/* MCP67 */
542895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },		/* MCP67 */
543895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },		/* MCP67 */
5440522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci },		/* MCP73 */
5450522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci },		/* MCP73 */
5460522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci },		/* MCP73 */
5470522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci },		/* MCP73 */
5480522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci },		/* MCP73 */
5490522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci },		/* MCP73 */
5500522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci },		/* MCP73 */
5510522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci },		/* MCP73 */
5520522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci },		/* MCP73 */
5530522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci },		/* MCP73 */
5540522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci },		/* MCP73 */
5550522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci },		/* MCP73 */
5560522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },		/* MCP77 */
5570522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },		/* MCP77 */
5580522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },		/* MCP77 */
5590522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },		/* MCP77 */
5600522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },		/* MCP77 */
5610522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },		/* MCP77 */
5620522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },		/* MCP77 */
5630522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },		/* MCP77 */
5640522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },		/* MCP77 */
5650522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
5660522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
5670522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
5686ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci },		/* MCP79 */
5696ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci },		/* MCP79 */
5706ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci },		/* MCP79 */
5716ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci },		/* MCP79 */
5727100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
5737100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
5747100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
5757100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
5767100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
5777100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
5787100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
5797100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
58070d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci },		/* MCP7B */
58170d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci },		/* MCP7B */
58270d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci },		/* MCP7B */
58370d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci },		/* MCP7B */
58470d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci },		/* MCP7B */
58570d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci },		/* MCP7B */
58670d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci },		/* MCP7B */
58770d562cfSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci },		/* MCP7B */
5883072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci },		/* MCP7B */
5893072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci },		/* MCP7B */
5903072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci },		/* MCP7B */
5913072c379Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci },		/* MCP7B */
592c6fd2807SJeff Garzik 
593c6fd2807SJeff Garzik 	/* SiS */
59420e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
59520e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
59620e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
597c6fd2807SJeff Garzik 
598cd70c266SJeff Garzik 	/* Marvell */
599cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
600c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
601cd70c266SJeff Garzik 
602c77a036bSMark Nelson 	/* Promise */
603c77a036bSMark Nelson 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
604c77a036bSMark Nelson 
605415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
606415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
607c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
608415ae2b5SJeff Garzik 
609c6fd2807SJeff Garzik 	{ }	/* terminate list */
610c6fd2807SJeff Garzik };
611c6fd2807SJeff Garzik 
612c6fd2807SJeff Garzik 
613c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
614c6fd2807SJeff Garzik 	.name			= DRV_NAME,
615c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
616c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
61724dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
618438ac6d5STejun Heo #ifdef CONFIG_PM
619c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
620c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
621438ac6d5STejun Heo #endif
622c6fd2807SJeff Garzik };
623c6fd2807SJeff Garzik 
62418f7ba4cSKristen Carlson Accardi static int ahci_em_messages = 1;
62518f7ba4cSKristen Carlson Accardi module_param(ahci_em_messages, int, 0444);
62618f7ba4cSKristen Carlson Accardi /* add other LED protocol types when they become supported */
62718f7ba4cSKristen Carlson Accardi MODULE_PARM_DESC(ahci_em_messages,
62818f7ba4cSKristen Carlson Accardi 	"Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
629c6fd2807SJeff Garzik 
6305b66c829SAlan Cox #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
6315b66c829SAlan Cox static int marvell_enable;
6325b66c829SAlan Cox #else
6335b66c829SAlan Cox static int marvell_enable = 1;
6345b66c829SAlan Cox #endif
6355b66c829SAlan Cox module_param(marvell_enable, int, 0644);
6365b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
6375b66c829SAlan Cox 
6385b66c829SAlan Cox 
63998fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
64098fa4b60STejun Heo {
64198fa4b60STejun Heo 	return (cap & 0x1f) + 1;
64298fa4b60STejun Heo }
64398fa4b60STejun Heo 
644dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host,
645dab632e8SJeff Garzik 					     unsigned int port_no)
646dab632e8SJeff Garzik {
647dab632e8SJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
648dab632e8SJeff Garzik 
649dab632e8SJeff Garzik 	return mmio + 0x100 + (port_no * 0x80);
650dab632e8SJeff Garzik }
651dab632e8SJeff Garzik 
6524447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
653c6fd2807SJeff Garzik {
654dab632e8SJeff Garzik 	return __ahci_port_base(ap->host, ap->port_no);
655c6fd2807SJeff Garzik }
656c6fd2807SJeff Garzik 
657b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio)
658b710a1f4STejun Heo {
65915fe982eSTejun Heo 	int i;
660b710a1f4STejun Heo 	u32 tmp;
661b710a1f4STejun Heo 
662b710a1f4STejun Heo 	/* turn on AHCI_EN */
663b710a1f4STejun Heo 	tmp = readl(mmio + HOST_CTL);
66415fe982eSTejun Heo 	if (tmp & HOST_AHCI_EN)
66515fe982eSTejun Heo 		return;
66615fe982eSTejun Heo 
66715fe982eSTejun Heo 	/* Some controllers need AHCI_EN to be written multiple times.
66815fe982eSTejun Heo 	 * Try a few times before giving up.
66915fe982eSTejun Heo 	 */
67015fe982eSTejun Heo 	for (i = 0; i < 5; i++) {
671b710a1f4STejun Heo 		tmp |= HOST_AHCI_EN;
672b710a1f4STejun Heo 		writel(tmp, mmio + HOST_CTL);
673b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
67415fe982eSTejun Heo 		if (tmp & HOST_AHCI_EN)
67515fe982eSTejun Heo 			return;
67615fe982eSTejun Heo 		msleep(10);
677b710a1f4STejun Heo 	}
67815fe982eSTejun Heo 
67915fe982eSTejun Heo 	WARN_ON(1);
680b710a1f4STejun Heo }
681b710a1f4STejun Heo 
682d447df14STejun Heo /**
683d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
6844447d351STejun Heo  *	@pdev: target PCI device
6854447d351STejun Heo  *	@hpriv: host private area to store config values
686d447df14STejun Heo  *
687d447df14STejun Heo  *	Some registers containing configuration info might be setup by
688d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
689d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
690d447df14STejun Heo  *	can be restored after controller reset.
691d447df14STejun Heo  *
692d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
693d447df14STejun Heo  *
694d447df14STejun Heo  *	LOCKING:
695d447df14STejun Heo  *	None.
696d447df14STejun Heo  */
6974447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
6984447d351STejun Heo 				     struct ahci_host_priv *hpriv)
699d447df14STejun Heo {
7004447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
701d447df14STejun Heo 	u32 cap, port_map;
70217199b18STejun Heo 	int i;
703c40e7cb8SJose Alberto Reguero 	int mv;
704d447df14STejun Heo 
705b710a1f4STejun Heo 	/* make sure AHCI mode is enabled before accessing CAP */
706b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
707b710a1f4STejun Heo 
708d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
709d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
710d447df14STejun Heo 	 */
711d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
712d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
713d447df14STejun Heo 
714274c1fdeSTejun Heo 	/* some chips have errata preventing 64bit use */
715417a1a6dSTejun Heo 	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
716c7a42156STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
717c7a42156STejun Heo 			   "controller can't do 64bit DMA, forcing 32bit\n");
718c7a42156STejun Heo 		cap &= ~HOST_CAP_64;
719c7a42156STejun Heo 	}
720c7a42156STejun Heo 
721417a1a6dSTejun Heo 	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
722274c1fdeSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
723274c1fdeSTejun Heo 			   "controller can't do NCQ, turning off CAP_NCQ\n");
724274c1fdeSTejun Heo 		cap &= ~HOST_CAP_NCQ;
725274c1fdeSTejun Heo 	}
726274c1fdeSTejun Heo 
727e297d99eSTejun Heo 	if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
728e297d99eSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
729e297d99eSTejun Heo 			   "controller can do NCQ, turning on CAP_NCQ\n");
730e297d99eSTejun Heo 		cap |= HOST_CAP_NCQ;
731e297d99eSTejun Heo 	}
732e297d99eSTejun Heo 
733258cd846SRoel Kluin 	if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
7346949b914STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
7356949b914STejun Heo 			   "controller can't do PMP, turning off CAP_PMP\n");
7366949b914STejun Heo 		cap &= ~HOST_CAP_PMP;
7376949b914STejun Heo 	}
7386949b914STejun Heo 
739d799e083STejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
740d799e083STejun Heo 	    port_map != 1) {
741d799e083STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
742d799e083STejun Heo 			   "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
743d799e083STejun Heo 			   port_map, 1);
744d799e083STejun Heo 		port_map = 1;
745d799e083STejun Heo 	}
746d799e083STejun Heo 
747cd70c266SJeff Garzik 	/*
748cd70c266SJeff Garzik 	 * Temporary Marvell 6145 hack: PATA port presence
749cd70c266SJeff Garzik 	 * is asserted through the standard AHCI port
750cd70c266SJeff Garzik 	 * presence register, as bit 4 (counting from 0)
751cd70c266SJeff Garzik 	 */
752417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
753c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
754c40e7cb8SJose Alberto Reguero 			mv = 0x3;
755c40e7cb8SJose Alberto Reguero 		else
756c40e7cb8SJose Alberto Reguero 			mv = 0xf;
757cd70c266SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
758cd70c266SJeff Garzik 			   "MV_AHCI HACK: port_map %x -> %x\n",
759c40e7cb8SJose Alberto Reguero 			   port_map,
760c40e7cb8SJose Alberto Reguero 			   port_map & mv);
7615b66c829SAlan Cox 		dev_printk(KERN_ERR, &pdev->dev,
7625b66c829SAlan Cox 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
763cd70c266SJeff Garzik 
764c40e7cb8SJose Alberto Reguero 		port_map &= mv;
765cd70c266SJeff Garzik 	}
766cd70c266SJeff Garzik 
76717199b18STejun Heo 	/* cross check port_map and cap.n_ports */
7687a234affSTejun Heo 	if (port_map) {
769837f5f8fSTejun Heo 		int map_ports = 0;
77017199b18STejun Heo 
771837f5f8fSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS; i++)
772837f5f8fSTejun Heo 			if (port_map & (1 << i))
773837f5f8fSTejun Heo 				map_ports++;
77417199b18STejun Heo 
775837f5f8fSTejun Heo 		/* If PI has more ports than n_ports, whine, clear
776837f5f8fSTejun Heo 		 * port_map and let it be generated from n_ports.
77717199b18STejun Heo 		 */
778837f5f8fSTejun Heo 		if (map_ports > ahci_nr_ports(cap)) {
7794447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
780837f5f8fSTejun Heo 				   "implemented port map (0x%x) contains more "
781837f5f8fSTejun Heo 				   "ports than nr_ports (%u), using nr_ports\n",
782837f5f8fSTejun Heo 				   port_map, ahci_nr_ports(cap));
7837a234affSTejun Heo 			port_map = 0;
7847a234affSTejun Heo 		}
7857a234affSTejun Heo 	}
7867a234affSTejun Heo 
78717199b18STejun Heo 	/* fabricate port_map from cap.nr_ports */
7887a234affSTejun Heo 	if (!port_map) {
78917199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
7907a234affSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
7917a234affSTejun Heo 			   "forcing PORTS_IMPL to 0x%x\n", port_map);
7927a234affSTejun Heo 
7937a234affSTejun Heo 		/* write the fixed up value to the PI register */
7947a234affSTejun Heo 		hpriv->saved_port_map = port_map;
79517199b18STejun Heo 	}
79617199b18STejun Heo 
797d447df14STejun Heo 	/* record values to use during operation */
798d447df14STejun Heo 	hpriv->cap = cap;
799d447df14STejun Heo 	hpriv->port_map = port_map;
800d447df14STejun Heo }
801d447df14STejun Heo 
802d447df14STejun Heo /**
803d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
8044447d351STejun Heo  *	@host: target ATA host
805d447df14STejun Heo  *
806d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
807d447df14STejun Heo  *
808d447df14STejun Heo  *	LOCKING:
809d447df14STejun Heo  *	None.
810d447df14STejun Heo  */
8114447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
812d447df14STejun Heo {
8134447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
8144447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
8154447d351STejun Heo 
816d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
817d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
818d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
819d447df14STejun Heo }
820d447df14STejun Heo 
821203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
822c6fd2807SJeff Garzik {
823203ef6c4STejun Heo 	static const int offset[] = {
824203ef6c4STejun Heo 		[SCR_STATUS]		= PORT_SCR_STAT,
825203ef6c4STejun Heo 		[SCR_CONTROL]		= PORT_SCR_CTL,
826203ef6c4STejun Heo 		[SCR_ERROR]		= PORT_SCR_ERR,
827203ef6c4STejun Heo 		[SCR_ACTIVE]		= PORT_SCR_ACT,
828203ef6c4STejun Heo 		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
829203ef6c4STejun Heo 	};
830203ef6c4STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
831c6fd2807SJeff Garzik 
832203ef6c4STejun Heo 	if (sc_reg < ARRAY_SIZE(offset) &&
833203ef6c4STejun Heo 	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
834203ef6c4STejun Heo 		return offset[sc_reg];
835da3dbb17STejun Heo 	return 0;
836c6fd2807SJeff Garzik }
837c6fd2807SJeff Garzik 
83882ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
839c6fd2807SJeff Garzik {
84082ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
84182ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
842c6fd2807SJeff Garzik 
843203ef6c4STejun Heo 	if (offset) {
844203ef6c4STejun Heo 		*val = readl(port_mmio + offset);
845203ef6c4STejun Heo 		return 0;
846203ef6c4STejun Heo 	}
847da3dbb17STejun Heo 	return -EINVAL;
848c6fd2807SJeff Garzik }
849c6fd2807SJeff Garzik 
85082ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
851203ef6c4STejun Heo {
85282ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
85382ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
854203ef6c4STejun Heo 
855203ef6c4STejun Heo 	if (offset) {
856203ef6c4STejun Heo 		writel(val, port_mmio + offset);
857da3dbb17STejun Heo 		return 0;
858c6fd2807SJeff Garzik 	}
859203ef6c4STejun Heo 	return -EINVAL;
860203ef6c4STejun Heo }
861c6fd2807SJeff Garzik 
8624447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
863c6fd2807SJeff Garzik {
8644447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
865c6fd2807SJeff Garzik 	u32 tmp;
866c6fd2807SJeff Garzik 
867c6fd2807SJeff Garzik 	/* start DMA */
868c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
869c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
870c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
871c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
872c6fd2807SJeff Garzik }
873c6fd2807SJeff Garzik 
8744447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
875c6fd2807SJeff Garzik {
8764447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
877c6fd2807SJeff Garzik 	u32 tmp;
878c6fd2807SJeff Garzik 
879c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
880c6fd2807SJeff Garzik 
881c6fd2807SJeff Garzik 	/* check if the HBA is idle */
882c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
883c6fd2807SJeff Garzik 		return 0;
884c6fd2807SJeff Garzik 
885c6fd2807SJeff Garzik 	/* setting HBA to idle */
886c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
887c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
888c6fd2807SJeff Garzik 
889c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
890c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
891c6fd2807SJeff Garzik 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
892c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
893c6fd2807SJeff Garzik 		return -EIO;
894c6fd2807SJeff Garzik 
895c6fd2807SJeff Garzik 	return 0;
896c6fd2807SJeff Garzik }
897c6fd2807SJeff Garzik 
8984447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
899c6fd2807SJeff Garzik {
9004447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
9014447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
9024447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
903c6fd2807SJeff Garzik 	u32 tmp;
904c6fd2807SJeff Garzik 
905c6fd2807SJeff Garzik 	/* set FIS registers */
9064447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
9074447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
9084447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
9094447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
910c6fd2807SJeff Garzik 
9114447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
9124447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
9134447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
9144447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
915c6fd2807SJeff Garzik 
916c6fd2807SJeff Garzik 	/* enable FIS reception */
917c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
918c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
919c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
920c6fd2807SJeff Garzik 
921c6fd2807SJeff Garzik 	/* flush */
922c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
923c6fd2807SJeff Garzik }
924c6fd2807SJeff Garzik 
9254447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
926c6fd2807SJeff Garzik {
9274447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
928c6fd2807SJeff Garzik 	u32 tmp;
929c6fd2807SJeff Garzik 
930c6fd2807SJeff Garzik 	/* disable FIS reception */
931c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
932c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
933c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
934c6fd2807SJeff Garzik 
935c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
936c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
937c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
938c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
939c6fd2807SJeff Garzik 		return -EBUSY;
940c6fd2807SJeff Garzik 
941c6fd2807SJeff Garzik 	return 0;
942c6fd2807SJeff Garzik }
943c6fd2807SJeff Garzik 
9444447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
945c6fd2807SJeff Garzik {
9464447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
9474447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
948c6fd2807SJeff Garzik 	u32 cmd;
949c6fd2807SJeff Garzik 
950c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
951c6fd2807SJeff Garzik 
952c6fd2807SJeff Garzik 	/* spin up device */
9534447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
954c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
955c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
956c6fd2807SJeff Garzik 	}
957c6fd2807SJeff Garzik 
958c6fd2807SJeff Garzik 	/* wake up link */
959c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
960c6fd2807SJeff Garzik }
961c6fd2807SJeff Garzik 
96231556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap)
96331556594SKristen Carlson Accardi {
96431556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
96531556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
96631556594SKristen Carlson Accardi 	u32 cmd;
96731556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
96831556594SKristen Carlson Accardi 
96931556594SKristen Carlson Accardi 	/* IPM bits should be disabled by libata-core */
97031556594SKristen Carlson Accardi 	/* get the existing command bits */
97131556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
97231556594SKristen Carlson Accardi 
97331556594SKristen Carlson Accardi 	/* disable ALPM and ASP */
97431556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ASP;
97531556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ALPE;
97631556594SKristen Carlson Accardi 
97731556594SKristen Carlson Accardi 	/* force the interface back to active */
97831556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ICC_ACTIVE;
97931556594SKristen Carlson Accardi 
98031556594SKristen Carlson Accardi 	/* write out new cmd value */
98131556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
98231556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
98331556594SKristen Carlson Accardi 
98431556594SKristen Carlson Accardi 	/* wait 10ms to be sure we've come out of any low power state */
98531556594SKristen Carlson Accardi 	msleep(10);
98631556594SKristen Carlson Accardi 
98731556594SKristen Carlson Accardi 	/* clear out any PhyRdy stuff from interrupt status */
98831556594SKristen Carlson Accardi 	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
98931556594SKristen Carlson Accardi 
99031556594SKristen Carlson Accardi 	/* go ahead and clean out PhyRdy Change from Serror too */
99182ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
99231556594SKristen Carlson Accardi 
99331556594SKristen Carlson Accardi 	/*
99431556594SKristen Carlson Accardi  	 * Clear flag to indicate that we should ignore all PhyRdy
99531556594SKristen Carlson Accardi  	 * state changes
99631556594SKristen Carlson Accardi  	 */
99731556594SKristen Carlson Accardi 	hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
99831556594SKristen Carlson Accardi 
99931556594SKristen Carlson Accardi 	/*
100031556594SKristen Carlson Accardi  	 * Enable interrupts on Phy Ready.
100131556594SKristen Carlson Accardi  	 */
100231556594SKristen Carlson Accardi 	pp->intr_mask |= PORT_IRQ_PHYRDY;
100331556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
100431556594SKristen Carlson Accardi 
100531556594SKristen Carlson Accardi 	/*
100631556594SKristen Carlson Accardi  	 * don't change the link pm policy - we can be called
100731556594SKristen Carlson Accardi  	 * just to turn of link pm temporarily
100831556594SKristen Carlson Accardi  	 */
100931556594SKristen Carlson Accardi }
101031556594SKristen Carlson Accardi 
101131556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
101231556594SKristen Carlson Accardi 	enum link_pm policy)
101331556594SKristen Carlson Accardi {
101431556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
101531556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
101631556594SKristen Carlson Accardi 	u32 cmd;
101731556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
101831556594SKristen Carlson Accardi 	u32 asp;
101931556594SKristen Carlson Accardi 
102031556594SKristen Carlson Accardi 	/* Make sure the host is capable of link power management */
102131556594SKristen Carlson Accardi 	if (!(hpriv->cap & HOST_CAP_ALPM))
102231556594SKristen Carlson Accardi 		return -EINVAL;
102331556594SKristen Carlson Accardi 
102431556594SKristen Carlson Accardi 	switch (policy) {
102531556594SKristen Carlson Accardi 	case MAX_PERFORMANCE:
102631556594SKristen Carlson Accardi 	case NOT_AVAILABLE:
102731556594SKristen Carlson Accardi 		/*
102831556594SKristen Carlson Accardi  		 * if we came here with NOT_AVAILABLE,
102931556594SKristen Carlson Accardi  		 * it just means this is the first time we
103031556594SKristen Carlson Accardi  		 * have tried to enable - default to max performance,
103131556594SKristen Carlson Accardi  		 * and let the user go to lower power modes on request.
103231556594SKristen Carlson Accardi  		 */
103331556594SKristen Carlson Accardi 		ahci_disable_alpm(ap);
103431556594SKristen Carlson Accardi 		return 0;
103531556594SKristen Carlson Accardi 	case MIN_POWER:
103631556594SKristen Carlson Accardi 		/* configure HBA to enter SLUMBER */
103731556594SKristen Carlson Accardi 		asp = PORT_CMD_ASP;
103831556594SKristen Carlson Accardi 		break;
103931556594SKristen Carlson Accardi 	case MEDIUM_POWER:
104031556594SKristen Carlson Accardi 		/* configure HBA to enter PARTIAL */
104131556594SKristen Carlson Accardi 		asp = 0;
104231556594SKristen Carlson Accardi 		break;
104331556594SKristen Carlson Accardi 	default:
104431556594SKristen Carlson Accardi 		return -EINVAL;
104531556594SKristen Carlson Accardi 	}
104631556594SKristen Carlson Accardi 
104731556594SKristen Carlson Accardi 	/*
104831556594SKristen Carlson Accardi  	 * Disable interrupts on Phy Ready. This keeps us from
104931556594SKristen Carlson Accardi  	 * getting woken up due to spurious phy ready interrupts
105031556594SKristen Carlson Accardi 	 * TBD - Hot plug should be done via polling now, is
105131556594SKristen Carlson Accardi 	 * that even supported?
105231556594SKristen Carlson Accardi  	 */
105331556594SKristen Carlson Accardi 	pp->intr_mask &= ~PORT_IRQ_PHYRDY;
105431556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
105531556594SKristen Carlson Accardi 
105631556594SKristen Carlson Accardi 	/*
105731556594SKristen Carlson Accardi  	 * Set a flag to indicate that we should ignore all PhyRdy
105831556594SKristen Carlson Accardi  	 * state changes since these can happen now whenever we
105931556594SKristen Carlson Accardi  	 * change link state
106031556594SKristen Carlson Accardi  	 */
106131556594SKristen Carlson Accardi 	hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
106231556594SKristen Carlson Accardi 
106331556594SKristen Carlson Accardi 	/* get the existing command bits */
106431556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
106531556594SKristen Carlson Accardi 
106631556594SKristen Carlson Accardi 	/*
106731556594SKristen Carlson Accardi  	 * Set ASP based on Policy
106831556594SKristen Carlson Accardi  	 */
106931556594SKristen Carlson Accardi 	cmd |= asp;
107031556594SKristen Carlson Accardi 
107131556594SKristen Carlson Accardi 	/*
107231556594SKristen Carlson Accardi  	 * Setting this bit will instruct the HBA to aggressively
107331556594SKristen Carlson Accardi  	 * enter a lower power link state when it's appropriate and
107431556594SKristen Carlson Accardi  	 * based on the value set above for ASP
107531556594SKristen Carlson Accardi  	 */
107631556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ALPE;
107731556594SKristen Carlson Accardi 
107831556594SKristen Carlson Accardi 	/* write out new cmd value */
107931556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
108031556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
108131556594SKristen Carlson Accardi 
108231556594SKristen Carlson Accardi 	/* IPM bits should be set by libata-core */
108331556594SKristen Carlson Accardi 	return 0;
108431556594SKristen Carlson Accardi }
108531556594SKristen Carlson Accardi 
1086438ac6d5STejun Heo #ifdef CONFIG_PM
10874447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
1088c6fd2807SJeff Garzik {
10894447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
10904447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1091c6fd2807SJeff Garzik 	u32 cmd, scontrol;
1092c6fd2807SJeff Garzik 
10934447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
109407c53dacSTejun Heo 		return;
1095c6fd2807SJeff Garzik 
109607c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
1097c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
1098c6fd2807SJeff Garzik 	scontrol &= ~0xf;
1099c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
1100c6fd2807SJeff Garzik 
1101c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
110207c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1103c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
1104c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
1105c6fd2807SJeff Garzik }
1106438ac6d5STejun Heo #endif
1107c6fd2807SJeff Garzik 
1108df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap)
1109c6fd2807SJeff Garzik {
111018f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
111118f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
111218f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
111318f7ba4cSKristen Carlson Accardi 
1114c6fd2807SJeff Garzik 	/* enable FIS reception */
11154447d351STejun Heo 	ahci_start_fis_rx(ap);
1116c6fd2807SJeff Garzik 
1117c6fd2807SJeff Garzik 	/* enable DMA */
11184447d351STejun Heo 	ahci_start_engine(ap);
111918f7ba4cSKristen Carlson Accardi 
112018f7ba4cSKristen Carlson Accardi 	/* turn on LEDs */
112118f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_EM) {
11221eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE) {
112318f7ba4cSKristen Carlson Accardi 			emp = &pp->em_priv[link->pmp];
112418f7ba4cSKristen Carlson Accardi 			ahci_transmit_led_message(ap, emp->led_state, 4);
112518f7ba4cSKristen Carlson Accardi 		}
112618f7ba4cSKristen Carlson Accardi 	}
112718f7ba4cSKristen Carlson Accardi 
112818f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_SW_ACTIVITY)
11291eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE)
113018f7ba4cSKristen Carlson Accardi 			ahci_init_sw_activity(link);
113118f7ba4cSKristen Carlson Accardi 
1132c6fd2807SJeff Garzik }
1133c6fd2807SJeff Garzik 
11344447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
1135c6fd2807SJeff Garzik {
1136c6fd2807SJeff Garzik 	int rc;
1137c6fd2807SJeff Garzik 
1138c6fd2807SJeff Garzik 	/* disable DMA */
11394447d351STejun Heo 	rc = ahci_stop_engine(ap);
1140c6fd2807SJeff Garzik 	if (rc) {
1141c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
1142c6fd2807SJeff Garzik 		return rc;
1143c6fd2807SJeff Garzik 	}
1144c6fd2807SJeff Garzik 
1145c6fd2807SJeff Garzik 	/* disable FIS reception */
11464447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
1147c6fd2807SJeff Garzik 	if (rc) {
1148c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
1149c6fd2807SJeff Garzik 		return rc;
1150c6fd2807SJeff Garzik 	}
1151c6fd2807SJeff Garzik 
1152c6fd2807SJeff Garzik 	return 0;
1153c6fd2807SJeff Garzik }
1154c6fd2807SJeff Garzik 
11554447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
1156c6fd2807SJeff Garzik {
11574447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
115849f29090STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
11594447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1160d447df14STejun Heo 	u32 tmp;
1161c6fd2807SJeff Garzik 
11623cc3eb11SJeff Garzik 	/* we must be in AHCI mode, before using anything
11633cc3eb11SJeff Garzik 	 * AHCI-specific, such as HOST_RESET.
11643cc3eb11SJeff Garzik 	 */
1165b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
11663cc3eb11SJeff Garzik 
11673cc3eb11SJeff Garzik 	/* global controller reset */
1168a22e6444STejun Heo 	if (!ahci_skip_host_reset) {
1169b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);
1170c6fd2807SJeff Garzik 		if ((tmp & HOST_RESET) == 0) {
1171c6fd2807SJeff Garzik 			writel(tmp | HOST_RESET, mmio + HOST_CTL);
1172c6fd2807SJeff Garzik 			readl(mmio + HOST_CTL); /* flush */
1173c6fd2807SJeff Garzik 		}
1174c6fd2807SJeff Garzik 
117524920c8aSZhang Rui 		/*
117624920c8aSZhang Rui 		 * to perform host reset, OS should set HOST_RESET
117724920c8aSZhang Rui 		 * and poll until this bit is read to be "0".
117824920c8aSZhang Rui 		 * reset must complete within 1 second, or
1179c6fd2807SJeff Garzik 		 * the hardware should be considered fried.
1180c6fd2807SJeff Garzik 		 */
118124920c8aSZhang Rui 		tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
118224920c8aSZhang Rui 					HOST_RESET, 10, 1000);
1183c6fd2807SJeff Garzik 
1184c6fd2807SJeff Garzik 		if (tmp & HOST_RESET) {
11854447d351STejun Heo 			dev_printk(KERN_ERR, host->dev,
1186c6fd2807SJeff Garzik 				   "controller reset failed (0x%x)\n", tmp);
1187c6fd2807SJeff Garzik 			return -EIO;
1188c6fd2807SJeff Garzik 		}
1189c6fd2807SJeff Garzik 
119098fa4b60STejun Heo 		/* turn on AHCI mode */
1191b710a1f4STejun Heo 		ahci_enable_ahci(mmio);
119298fa4b60STejun Heo 
1193a22e6444STejun Heo 		/* Some registers might be cleared on reset.  Restore
1194a22e6444STejun Heo 		 * initial values.
1195a22e6444STejun Heo 		 */
11964447d351STejun Heo 		ahci_restore_initial_config(host);
1197a22e6444STejun Heo 	} else
1198a22e6444STejun Heo 		dev_printk(KERN_INFO, host->dev,
1199a22e6444STejun Heo 			   "skipping global host reset\n");
1200c6fd2807SJeff Garzik 
1201c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
1202c6fd2807SJeff Garzik 		u16 tmp16;
1203c6fd2807SJeff Garzik 
1204c6fd2807SJeff Garzik 		/* configure PCS */
1205c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
120649f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
120749f29090STejun Heo 			tmp16 |= hpriv->port_map;
1208c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
1209c6fd2807SJeff Garzik 		}
121049f29090STejun Heo 	}
1211c6fd2807SJeff Garzik 
1212c6fd2807SJeff Garzik 	return 0;
1213c6fd2807SJeff Garzik }
1214c6fd2807SJeff Garzik 
121518f7ba4cSKristen Carlson Accardi static void ahci_sw_activity(struct ata_link *link)
121618f7ba4cSKristen Carlson Accardi {
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 
122118f7ba4cSKristen Carlson Accardi 	if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
122218f7ba4cSKristen Carlson Accardi 		return;
122318f7ba4cSKristen Carlson Accardi 
122418f7ba4cSKristen Carlson Accardi 	emp->activity++;
122518f7ba4cSKristen Carlson Accardi 	if (!timer_pending(&emp->timer))
122618f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
122718f7ba4cSKristen Carlson Accardi }
122818f7ba4cSKristen Carlson Accardi 
122918f7ba4cSKristen Carlson Accardi static void ahci_sw_activity_blink(unsigned long arg)
123018f7ba4cSKristen Carlson Accardi {
123118f7ba4cSKristen Carlson Accardi 	struct ata_link *link = (struct ata_link *)arg;
123218f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
123318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
123418f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
123518f7ba4cSKristen Carlson Accardi 	unsigned long led_message = emp->led_state;
123618f7ba4cSKristen Carlson Accardi 	u32 activity_led_state;
1237eb40963cSDavid Milburn 	unsigned long flags;
123818f7ba4cSKristen Carlson Accardi 
123987943acfSDavid Milburn 	led_message &= EM_MSG_LED_VALUE;
124018f7ba4cSKristen Carlson Accardi 	led_message |= ap->port_no | (link->pmp << 8);
124118f7ba4cSKristen Carlson Accardi 
124218f7ba4cSKristen Carlson Accardi 	/* check to see if we've had activity.  If so,
124318f7ba4cSKristen Carlson Accardi 	 * toggle state of LED and reset timer.  If not,
124418f7ba4cSKristen Carlson Accardi 	 * turn LED to desired idle state.
124518f7ba4cSKristen Carlson Accardi 	 */
1246eb40963cSDavid Milburn 	spin_lock_irqsave(ap->lock, flags);
124718f7ba4cSKristen Carlson Accardi 	if (emp->saved_activity != emp->activity) {
124818f7ba4cSKristen Carlson Accardi 		emp->saved_activity = emp->activity;
124918f7ba4cSKristen Carlson Accardi 		/* get the current LED state */
125087943acfSDavid Milburn 		activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
125118f7ba4cSKristen Carlson Accardi 
125218f7ba4cSKristen Carlson Accardi 		if (activity_led_state)
125318f7ba4cSKristen Carlson Accardi 			activity_led_state = 0;
125418f7ba4cSKristen Carlson Accardi 		else
125518f7ba4cSKristen Carlson Accardi 			activity_led_state = 1;
125618f7ba4cSKristen Carlson Accardi 
125718f7ba4cSKristen Carlson Accardi 		/* clear old state */
125887943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
125918f7ba4cSKristen Carlson Accardi 
126018f7ba4cSKristen Carlson Accardi 		/* toggle state */
126118f7ba4cSKristen Carlson Accardi 		led_message |= (activity_led_state << 16);
126218f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
126318f7ba4cSKristen Carlson Accardi 	} else {
126418f7ba4cSKristen Carlson Accardi 		/* switch to idle */
126587943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
126618f7ba4cSKristen Carlson Accardi 		if (emp->blink_policy == BLINK_OFF)
126718f7ba4cSKristen Carlson Accardi 			led_message |= (1 << 16);
126818f7ba4cSKristen Carlson Accardi 	}
1269eb40963cSDavid Milburn 	spin_unlock_irqrestore(ap->lock, flags);
127018f7ba4cSKristen Carlson Accardi 	ahci_transmit_led_message(ap, led_message, 4);
127118f7ba4cSKristen Carlson Accardi }
127218f7ba4cSKristen Carlson Accardi 
127318f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link)
127418f7ba4cSKristen Carlson Accardi {
127518f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
127618f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
127718f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
127818f7ba4cSKristen Carlson Accardi 
127918f7ba4cSKristen Carlson Accardi 	/* init activity stats, setup timer */
128018f7ba4cSKristen Carlson Accardi 	emp->saved_activity = emp->activity = 0;
128118f7ba4cSKristen Carlson Accardi 	setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
128218f7ba4cSKristen Carlson Accardi 
128318f7ba4cSKristen Carlson Accardi 	/* check our blink policy and set flag for link if it's enabled */
128418f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
128518f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
128618f7ba4cSKristen Carlson Accardi }
128718f7ba4cSKristen Carlson Accardi 
128818f7ba4cSKristen Carlson Accardi static int ahci_reset_em(struct ata_host *host)
128918f7ba4cSKristen Carlson Accardi {
129018f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
129118f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
129218f7ba4cSKristen Carlson Accardi 
129318f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
129418f7ba4cSKristen Carlson Accardi 	if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
129518f7ba4cSKristen Carlson Accardi 		return -EINVAL;
129618f7ba4cSKristen Carlson Accardi 
129718f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
129818f7ba4cSKristen Carlson Accardi 	return 0;
129918f7ba4cSKristen Carlson Accardi }
130018f7ba4cSKristen Carlson Accardi 
130118f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
130218f7ba4cSKristen Carlson Accardi 					ssize_t size)
130318f7ba4cSKristen Carlson Accardi {
130418f7ba4cSKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
130518f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
130618f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
130718f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
130818f7ba4cSKristen Carlson Accardi 	u32 message[] = {0, 0};
130993082f0bSLinus Torvalds 	unsigned long flags;
131018f7ba4cSKristen Carlson Accardi 	int pmp;
131118f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
131218f7ba4cSKristen Carlson Accardi 
131318f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
131487943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
131518f7ba4cSKristen Carlson Accardi 	if (pmp < MAX_SLOTS)
131618f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
131718f7ba4cSKristen Carlson Accardi 	else
131818f7ba4cSKristen Carlson Accardi 		return -EINVAL;
131918f7ba4cSKristen Carlson Accardi 
132018f7ba4cSKristen Carlson Accardi 	spin_lock_irqsave(ap->lock, flags);
132118f7ba4cSKristen Carlson Accardi 
132218f7ba4cSKristen Carlson Accardi 	/*
132318f7ba4cSKristen Carlson Accardi 	 * if we are still busy transmitting a previous message,
132418f7ba4cSKristen Carlson Accardi 	 * do not allow
132518f7ba4cSKristen Carlson Accardi 	 */
132618f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
132718f7ba4cSKristen Carlson Accardi 	if (em_ctl & EM_CTL_TM) {
132818f7ba4cSKristen Carlson Accardi 		spin_unlock_irqrestore(ap->lock, flags);
132918f7ba4cSKristen Carlson Accardi 		return -EINVAL;
133018f7ba4cSKristen Carlson Accardi 	}
133118f7ba4cSKristen Carlson Accardi 
133218f7ba4cSKristen Carlson Accardi 	/*
133318f7ba4cSKristen Carlson Accardi 	 * create message header - this is all zero except for
133418f7ba4cSKristen Carlson Accardi 	 * the message size, which is 4 bytes.
133518f7ba4cSKristen Carlson Accardi 	 */
133618f7ba4cSKristen Carlson Accardi 	message[0] |= (4 << 8);
133718f7ba4cSKristen Carlson Accardi 
133818f7ba4cSKristen Carlson Accardi 	/* ignore 0:4 of byte zero, fill in port info yourself */
133987943acfSDavid Milburn 	message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
134018f7ba4cSKristen Carlson Accardi 
134118f7ba4cSKristen Carlson Accardi 	/* write message to EM_LOC */
134218f7ba4cSKristen Carlson Accardi 	writel(message[0], mmio + hpriv->em_loc);
134318f7ba4cSKristen Carlson Accardi 	writel(message[1], mmio + hpriv->em_loc+4);
134418f7ba4cSKristen Carlson Accardi 
134518f7ba4cSKristen Carlson Accardi 	/* save off new led state for port/slot */
134618f7ba4cSKristen Carlson Accardi 	emp->led_state = message[1];
134718f7ba4cSKristen Carlson Accardi 
134818f7ba4cSKristen Carlson Accardi 	/*
134918f7ba4cSKristen Carlson Accardi 	 * tell hardware to transmit the message
135018f7ba4cSKristen Carlson Accardi 	 */
135118f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
135218f7ba4cSKristen Carlson Accardi 
135318f7ba4cSKristen Carlson Accardi 	spin_unlock_irqrestore(ap->lock, flags);
135418f7ba4cSKristen Carlson Accardi 	return size;
135518f7ba4cSKristen Carlson Accardi }
135618f7ba4cSKristen Carlson Accardi 
135718f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
135818f7ba4cSKristen Carlson Accardi {
135918f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
136018f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
136118f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
136218f7ba4cSKristen Carlson Accardi 	int rc = 0;
136318f7ba4cSKristen Carlson Accardi 
13641eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE) {
136518f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[link->pmp];
136618f7ba4cSKristen Carlson Accardi 		rc += sprintf(buf, "%lx\n", emp->led_state);
136718f7ba4cSKristen Carlson Accardi 	}
136818f7ba4cSKristen Carlson Accardi 	return rc;
136918f7ba4cSKristen Carlson Accardi }
137018f7ba4cSKristen Carlson Accardi 
137118f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
137218f7ba4cSKristen Carlson Accardi 				size_t size)
137318f7ba4cSKristen Carlson Accardi {
137418f7ba4cSKristen Carlson Accardi 	int state;
137518f7ba4cSKristen Carlson Accardi 	int pmp;
137618f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
137718f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
137818f7ba4cSKristen Carlson Accardi 
137918f7ba4cSKristen Carlson Accardi 	state = simple_strtoul(buf, NULL, 0);
138018f7ba4cSKristen Carlson Accardi 
138118f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
138287943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
138318f7ba4cSKristen Carlson Accardi 	if (pmp < MAX_SLOTS)
138418f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
138518f7ba4cSKristen Carlson Accardi 	else
138618f7ba4cSKristen Carlson Accardi 		return -EINVAL;
138718f7ba4cSKristen Carlson Accardi 
138818f7ba4cSKristen Carlson Accardi 	/* mask off the activity bits if we are in sw_activity
138918f7ba4cSKristen Carlson Accardi 	 * mode, user should turn off sw_activity before setting
139018f7ba4cSKristen Carlson Accardi 	 * activity led through em_message
139118f7ba4cSKristen Carlson Accardi 	 */
139218f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
139387943acfSDavid Milburn 		state &= ~EM_MSG_LED_VALUE_ACTIVITY;
139418f7ba4cSKristen Carlson Accardi 
139518f7ba4cSKristen Carlson Accardi 	return ahci_transmit_led_message(ap, state, size);
139618f7ba4cSKristen Carlson Accardi }
139718f7ba4cSKristen Carlson Accardi 
139818f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
139918f7ba4cSKristen Carlson Accardi {
140018f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
140118f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
140218f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
140318f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
140418f7ba4cSKristen Carlson Accardi 	u32 port_led_state = emp->led_state;
140518f7ba4cSKristen Carlson Accardi 
140618f7ba4cSKristen Carlson Accardi 	/* save the desired Activity LED behavior */
140718f7ba4cSKristen Carlson Accardi 	if (val == OFF) {
140818f7ba4cSKristen Carlson Accardi 		/* clear LFLAG */
140918f7ba4cSKristen Carlson Accardi 		link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
141018f7ba4cSKristen Carlson Accardi 
141118f7ba4cSKristen Carlson Accardi 		/* set the LED to OFF */
141287943acfSDavid Milburn 		port_led_state &= EM_MSG_LED_VALUE_OFF;
141318f7ba4cSKristen Carlson Accardi 		port_led_state |= (ap->port_no | (link->pmp << 8));
141418f7ba4cSKristen Carlson Accardi 		ahci_transmit_led_message(ap, port_led_state, 4);
141518f7ba4cSKristen Carlson Accardi 	} else {
141618f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
141718f7ba4cSKristen Carlson Accardi 		if (val == BLINK_OFF) {
141818f7ba4cSKristen Carlson Accardi 			/* set LED to ON for idle */
141987943acfSDavid Milburn 			port_led_state &= EM_MSG_LED_VALUE_OFF;
142018f7ba4cSKristen Carlson Accardi 			port_led_state |= (ap->port_no | (link->pmp << 8));
142187943acfSDavid Milburn 			port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
142218f7ba4cSKristen Carlson Accardi 			ahci_transmit_led_message(ap, port_led_state, 4);
142318f7ba4cSKristen Carlson Accardi 		}
142418f7ba4cSKristen Carlson Accardi 	}
142518f7ba4cSKristen Carlson Accardi 	emp->blink_policy = val;
142618f7ba4cSKristen Carlson Accardi 	return 0;
142718f7ba4cSKristen Carlson Accardi }
142818f7ba4cSKristen Carlson Accardi 
142918f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
143018f7ba4cSKristen Carlson Accardi {
143118f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
143218f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
143318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
143418f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
143518f7ba4cSKristen Carlson Accardi 
143618f7ba4cSKristen Carlson Accardi 	/* display the saved value of activity behavior for this
143718f7ba4cSKristen Carlson Accardi 	 * disk.
143818f7ba4cSKristen Carlson Accardi 	 */
143918f7ba4cSKristen Carlson Accardi 	return sprintf(buf, "%d\n", emp->blink_policy);
144018f7ba4cSKristen Carlson Accardi }
144118f7ba4cSKristen Carlson Accardi 
14422bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
14432bcd866bSJeff Garzik 			   int port_no, void __iomem *mmio,
14442bcd866bSJeff Garzik 			   void __iomem *port_mmio)
1445c6fd2807SJeff Garzik {
1446c6fd2807SJeff Garzik 	const char *emsg = NULL;
14472bcd866bSJeff Garzik 	int rc;
14482bcd866bSJeff Garzik 	u32 tmp;
1449c6fd2807SJeff Garzik 
1450c6fd2807SJeff Garzik 	/* make sure port is not active */
14514447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1452c6fd2807SJeff Garzik 	if (rc)
1453c6fd2807SJeff Garzik 		dev_printk(KERN_WARNING, &pdev->dev,
1454c6fd2807SJeff Garzik 			   "%s (%d)\n", emsg, rc);
1455c6fd2807SJeff Garzik 
1456c6fd2807SJeff Garzik 	/* clear SError */
1457c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SCR_ERR);
1458c6fd2807SJeff Garzik 	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
1459c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_SCR_ERR);
1460c6fd2807SJeff Garzik 
1461c6fd2807SJeff Garzik 	/* clear port IRQ */
1462c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1463c6fd2807SJeff Garzik 	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1464c6fd2807SJeff Garzik 	if (tmp)
1465c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_IRQ_STAT);
1466c6fd2807SJeff Garzik 
14672bcd866bSJeff Garzik 	writel(1 << port_no, mmio + HOST_IRQ_STAT);
14682bcd866bSJeff Garzik }
14692bcd866bSJeff Garzik 
14702bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host)
14712bcd866bSJeff Garzik {
1472417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
14732bcd866bSJeff Garzik 	struct pci_dev *pdev = to_pci_dev(host->dev);
14742bcd866bSJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
14752bcd866bSJeff Garzik 	int i;
1476cd70c266SJeff Garzik 	void __iomem *port_mmio;
14772bcd866bSJeff Garzik 	u32 tmp;
1478c40e7cb8SJose Alberto Reguero 	int mv;
14792bcd866bSJeff Garzik 
1480417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
1481c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
1482c40e7cb8SJose Alberto Reguero 			mv = 2;
1483c40e7cb8SJose Alberto Reguero 		else
1484c40e7cb8SJose Alberto Reguero 			mv = 4;
1485c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
1486cd70c266SJeff Garzik 
1487cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
1488cd70c266SJeff Garzik 
1489cd70c266SJeff Garzik 		/* clear port IRQ */
1490cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
1491cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1492cd70c266SJeff Garzik 		if (tmp)
1493cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
1494cd70c266SJeff Garzik 	}
1495cd70c266SJeff Garzik 
14962bcd866bSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
14972bcd866bSJeff Garzik 		struct ata_port *ap = host->ports[i];
14982bcd866bSJeff Garzik 
1499cd70c266SJeff Garzik 		port_mmio = ahci_port_base(ap);
15002bcd866bSJeff Garzik 		if (ata_port_is_dummy(ap))
15012bcd866bSJeff Garzik 			continue;
15022bcd866bSJeff Garzik 
15032bcd866bSJeff Garzik 		ahci_port_init(pdev, ap, i, mmio, port_mmio);
1504c6fd2807SJeff Garzik 	}
1505c6fd2807SJeff Garzik 
1506c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1507c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1508c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
1509c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1510c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1511c6fd2807SJeff Garzik }
1512c6fd2807SJeff Garzik 
1513a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev)
1514a878539eSJeff Garzik {
1515a878539eSJeff Garzik 	struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
1516a878539eSJeff Garzik 
15174cde32fcSJeff Garzik 	if (hpriv->flags & AHCI_HFLAG_SECT255) {
1518a878539eSJeff Garzik 		dev->max_sectors = 255;
15194cde32fcSJeff Garzik 		ata_dev_printk(dev, KERN_INFO,
15204cde32fcSJeff Garzik 			       "SB600 AHCI: limiting to 255 sectors per cmd\n");
15214cde32fcSJeff Garzik 	}
1522a878539eSJeff Garzik }
1523a878539eSJeff Garzik 
1524c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
1525c6fd2807SJeff Garzik {
15264447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1527c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1528c6fd2807SJeff Garzik 	u32 tmp;
1529c6fd2807SJeff Garzik 
1530c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
1531c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
1532c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
1533c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
1534c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
1535c6fd2807SJeff Garzik 
1536c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
1537c6fd2807SJeff Garzik }
1538c6fd2807SJeff Garzik 
1539c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
1540c6fd2807SJeff Garzik 			       u32 opts)
1541c6fd2807SJeff Garzik {
1542c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
1543c6fd2807SJeff Garzik 
1544c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
1545c6fd2807SJeff Garzik 
1546c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
1547c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
1548c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
1549c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
1550c6fd2807SJeff Garzik }
1551c6fd2807SJeff Garzik 
1552d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart)
1553c6fd2807SJeff Garzik {
1554350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1555cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1556520d06f9STejun Heo 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1557c6fd2807SJeff Garzik 	u32 tmp;
1558d2e75dffSTejun Heo 	int busy, rc;
1559c6fd2807SJeff Garzik 
1560d2e75dffSTejun Heo 	/* do we need to kick the port? */
1561520d06f9STejun Heo 	busy = status & (ATA_BUSY | ATA_DRQ);
1562d2e75dffSTejun Heo 	if (!busy && !force_restart)
1563d2e75dffSTejun Heo 		return 0;
1564c6fd2807SJeff Garzik 
1565d2e75dffSTejun Heo 	/* stop engine */
1566d2e75dffSTejun Heo 	rc = ahci_stop_engine(ap);
1567d2e75dffSTejun Heo 	if (rc)
1568d2e75dffSTejun Heo 		goto out_restart;
1569d2e75dffSTejun Heo 
1570d2e75dffSTejun Heo 	/* need to do CLO? */
1571d2e75dffSTejun Heo 	if (!busy) {
1572d2e75dffSTejun Heo 		rc = 0;
1573d2e75dffSTejun Heo 		goto out_restart;
1574d2e75dffSTejun Heo 	}
1575d2e75dffSTejun Heo 
1576d2e75dffSTejun Heo 	if (!(hpriv->cap & HOST_CAP_CLO)) {
1577d2e75dffSTejun Heo 		rc = -EOPNOTSUPP;
1578d2e75dffSTejun Heo 		goto out_restart;
1579d2e75dffSTejun Heo 	}
1580d2e75dffSTejun Heo 
1581d2e75dffSTejun Heo 	/* perform CLO */
1582c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1583c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
1584c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1585c6fd2807SJeff Garzik 
1586d2e75dffSTejun Heo 	rc = 0;
1587c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1588c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
1589c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
1590d2e75dffSTejun Heo 		rc = -EIO;
1591c6fd2807SJeff Garzik 
1592d2e75dffSTejun Heo 	/* restart engine */
1593d2e75dffSTejun Heo  out_restart:
1594d2e75dffSTejun Heo 	ahci_start_engine(ap);
1595d2e75dffSTejun Heo 	return rc;
1596c6fd2807SJeff Garzik }
1597c6fd2807SJeff Garzik 
159891c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
159991c4a2e0STejun Heo 				struct ata_taskfile *tf, int is_cmd, u16 flags,
160091c4a2e0STejun Heo 				unsigned long timeout_msec)
160191c4a2e0STejun Heo {
160291c4a2e0STejun Heo 	const u32 cmd_fis_len = 5; /* five dwords */
160391c4a2e0STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
160491c4a2e0STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
160591c4a2e0STejun Heo 	u8 *fis = pp->cmd_tbl;
160691c4a2e0STejun Heo 	u32 tmp;
160791c4a2e0STejun Heo 
160891c4a2e0STejun Heo 	/* prep the command */
160991c4a2e0STejun Heo 	ata_tf_to_fis(tf, pmp, is_cmd, fis);
161091c4a2e0STejun Heo 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
161191c4a2e0STejun Heo 
161291c4a2e0STejun Heo 	/* issue & wait */
161391c4a2e0STejun Heo 	writel(1, port_mmio + PORT_CMD_ISSUE);
161491c4a2e0STejun Heo 
161591c4a2e0STejun Heo 	if (timeout_msec) {
161691c4a2e0STejun Heo 		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
161791c4a2e0STejun Heo 					1, timeout_msec);
161891c4a2e0STejun Heo 		if (tmp & 0x1) {
161991c4a2e0STejun Heo 			ahci_kick_engine(ap, 1);
162091c4a2e0STejun Heo 			return -EBUSY;
162191c4a2e0STejun Heo 		}
162291c4a2e0STejun Heo 	} else
162391c4a2e0STejun Heo 		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
162491c4a2e0STejun Heo 
162591c4a2e0STejun Heo 	return 0;
162691c4a2e0STejun Heo }
162791c4a2e0STejun Heo 
1628bd17243aSShane Huang static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1629bd17243aSShane Huang 			     int pmp, unsigned long deadline,
1630bd17243aSShane Huang 			     int (*check_ready)(struct ata_link *link))
1631c6fd2807SJeff Garzik {
1632cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1633c6fd2807SJeff Garzik 	const char *reason = NULL;
16342cbb79ebSTejun Heo 	unsigned long now, msecs;
1635c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1636c6fd2807SJeff Garzik 	int rc;
1637c6fd2807SJeff Garzik 
1638c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1639c6fd2807SJeff Garzik 
1640c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
1641d2e75dffSTejun Heo 	rc = ahci_kick_engine(ap, 1);
1642994056d7STejun Heo 	if (rc && rc != -EOPNOTSUPP)
1643cc0680a5STejun Heo 		ata_link_printk(link, KERN_WARNING,
1644994056d7STejun Heo 				"failed to reset engine (errno=%d)\n", rc);
1645c6fd2807SJeff Garzik 
1646cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1647c6fd2807SJeff Garzik 
1648c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
16492cbb79ebSTejun Heo 	msecs = 0;
16502cbb79ebSTejun Heo 	now = jiffies;
16512cbb79ebSTejun Heo 	if (time_after(now, deadline))
16522cbb79ebSTejun Heo 		msecs = jiffies_to_msecs(deadline - now);
16532cbb79ebSTejun Heo 
1654c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
1655a9cf5e85STejun Heo 	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
165691c4a2e0STejun Heo 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
1657c6fd2807SJeff Garzik 		rc = -EIO;
1658c6fd2807SJeff Garzik 		reason = "1st FIS failed";
1659c6fd2807SJeff Garzik 		goto fail;
1660c6fd2807SJeff Garzik 	}
1661c6fd2807SJeff Garzik 
1662c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
1663c6fd2807SJeff Garzik 	msleep(1);
1664c6fd2807SJeff Garzik 
1665c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
1666c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
1667a9cf5e85STejun Heo 	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1668c6fd2807SJeff Garzik 
1669705e76beSTejun Heo 	/* wait for link to become ready */
1670bd17243aSShane Huang 	rc = ata_wait_after_reset(link, deadline, check_ready);
16719b89391cSTejun Heo 	/* link occupied, -ENODEV too is an error */
16729b89391cSTejun Heo 	if (rc) {
1673c6fd2807SJeff Garzik 		reason = "device not ready";
1674c6fd2807SJeff Garzik 		goto fail;
1675c6fd2807SJeff Garzik 	}
1676c6fd2807SJeff Garzik 	*class = ahci_dev_classify(ap);
1677c6fd2807SJeff Garzik 
1678c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
1679c6fd2807SJeff Garzik 	return 0;
1680c6fd2807SJeff Garzik 
1681c6fd2807SJeff Garzik  fail:
1682cc0680a5STejun Heo 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
1683c6fd2807SJeff Garzik 	return rc;
1684c6fd2807SJeff Garzik }
1685c6fd2807SJeff Garzik 
1686bd17243aSShane Huang static int ahci_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 
1691bd17243aSShane Huang 	return ata_check_ready(status);
1692bd17243aSShane Huang }
1693bd17243aSShane Huang 
1694bd17243aSShane Huang static int ahci_softreset(struct ata_link *link, unsigned int *class,
1695bd17243aSShane Huang 			  unsigned long deadline)
1696bd17243aSShane Huang {
1697bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1698bd17243aSShane Huang 
1699bd17243aSShane Huang 	DPRINTK("ENTER\n");
1700bd17243aSShane Huang 
1701bd17243aSShane Huang 	return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
1702bd17243aSShane Huang }
1703bd17243aSShane Huang 
1704bd17243aSShane Huang static int ahci_sb600_check_ready(struct ata_link *link)
1705bd17243aSShane Huang {
1706bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1707bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1708bd17243aSShane Huang 	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
1709bd17243aSShane Huang 
1710bd17243aSShane Huang 	/*
1711bd17243aSShane Huang 	 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
1712bd17243aSShane Huang 	 * which can save timeout delay.
1713bd17243aSShane Huang 	 */
1714bd17243aSShane Huang 	if (irq_status & PORT_IRQ_BAD_PMP)
1715bd17243aSShane Huang 		return -EIO;
1716bd17243aSShane Huang 
1717bd17243aSShane Huang 	return ata_check_ready(status);
1718bd17243aSShane Huang }
1719bd17243aSShane Huang 
1720bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
1721bd17243aSShane Huang 				unsigned long deadline)
1722bd17243aSShane Huang {
1723bd17243aSShane Huang 	struct ata_port *ap = link->ap;
1724bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(ap);
1725bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1726bd17243aSShane Huang 	int rc;
1727bd17243aSShane Huang 	u32 irq_sts;
1728bd17243aSShane Huang 
1729bd17243aSShane Huang 	DPRINTK("ENTER\n");
1730bd17243aSShane Huang 
1731bd17243aSShane Huang 	rc = ahci_do_softreset(link, class, pmp, deadline,
1732bd17243aSShane Huang 			       ahci_sb600_check_ready);
1733bd17243aSShane Huang 
1734bd17243aSShane Huang 	/*
1735bd17243aSShane Huang 	 * Soft reset fails on some ATI chips with IPMS set when PMP
1736bd17243aSShane Huang 	 * is enabled but SATA HDD/ODD is connected to SATA port,
1737bd17243aSShane Huang 	 * do soft reset again to port 0.
1738bd17243aSShane Huang 	 */
1739bd17243aSShane Huang 	if (rc == -EIO) {
1740bd17243aSShane Huang 		irq_sts = readl(port_mmio + PORT_IRQ_STAT);
1741bd17243aSShane Huang 		if (irq_sts & PORT_IRQ_BAD_PMP) {
1742bd17243aSShane Huang 			ata_link_printk(link, KERN_WARNING,
1743bd17243aSShane Huang 					"failed due to HW bug, retry pmp=0\n");
1744bd17243aSShane Huang 			rc = ahci_do_softreset(link, class, 0, deadline,
1745bd17243aSShane Huang 					       ahci_check_ready);
1746bd17243aSShane Huang 		}
1747bd17243aSShane Huang 	}
1748bd17243aSShane Huang 
1749bd17243aSShane Huang 	return rc;
1750bd17243aSShane Huang }
1751bd17243aSShane Huang 
1752cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1753d4b2bab4STejun Heo 			  unsigned long deadline)
1754c6fd2807SJeff Garzik {
17559dadd45bSTejun Heo 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
1756cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1757c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1758c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1759c6fd2807SJeff Garzik 	struct ata_taskfile tf;
17609dadd45bSTejun Heo 	bool online;
1761c6fd2807SJeff Garzik 	int rc;
1762c6fd2807SJeff Garzik 
1763c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1764c6fd2807SJeff Garzik 
17654447d351STejun Heo 	ahci_stop_engine(ap);
1766c6fd2807SJeff Garzik 
1767c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1768cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1769dfd7a3dbSTejun Heo 	tf.command = 0x80;
17709977126cSTejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1771c6fd2807SJeff Garzik 
17729dadd45bSTejun Heo 	rc = sata_link_hardreset(link, timing, deadline, &online,
17739dadd45bSTejun Heo 				 ahci_check_ready);
1774c6fd2807SJeff Garzik 
17754447d351STejun Heo 	ahci_start_engine(ap);
1776c6fd2807SJeff Garzik 
17779dadd45bSTejun Heo 	if (online)
17789dadd45bSTejun Heo 		*class = ahci_dev_classify(ap);
1779c6fd2807SJeff Garzik 
1780c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1781c6fd2807SJeff Garzik 	return rc;
1782c6fd2807SJeff Garzik }
1783c6fd2807SJeff Garzik 
1784cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1785d4b2bab4STejun Heo 				 unsigned long deadline)
1786ad616ffbSTejun Heo {
1787cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
17889dadd45bSTejun Heo 	bool online;
1789ad616ffbSTejun Heo 	int rc;
1790ad616ffbSTejun Heo 
1791ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1792ad616ffbSTejun Heo 
17934447d351STejun Heo 	ahci_stop_engine(ap);
1794ad616ffbSTejun Heo 
1795cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
17969dadd45bSTejun Heo 				 deadline, &online, NULL);
1797ad616ffbSTejun Heo 
17984447d351STejun Heo 	ahci_start_engine(ap);
1799ad616ffbSTejun Heo 
1800ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1801ad616ffbSTejun Heo 
1802ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1803ad616ffbSTejun Heo 	 * request follow-up softreset.
1804ad616ffbSTejun Heo 	 */
18059dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
1806ad616ffbSTejun Heo }
1807ad616ffbSTejun Heo 
1808edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1809edc93052STejun Heo 				unsigned long deadline)
1810edc93052STejun Heo {
1811edc93052STejun Heo 	struct ata_port *ap = link->ap;
1812edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1813edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1814edc93052STejun Heo 	struct ata_taskfile tf;
18159dadd45bSTejun Heo 	bool online;
1816edc93052STejun Heo 	int rc;
1817edc93052STejun Heo 
1818edc93052STejun Heo 	ahci_stop_engine(ap);
1819edc93052STejun Heo 
1820edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
1821edc93052STejun Heo 	ata_tf_init(link->device, &tf);
1822edc93052STejun Heo 	tf.command = 0x80;
1823edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1824edc93052STejun Heo 
1825edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
18269dadd45bSTejun Heo 				 deadline, &online, NULL);
1827edc93052STejun Heo 
1828edc93052STejun Heo 	ahci_start_engine(ap);
1829edc93052STejun Heo 
1830edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
1831edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1832edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
1833edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
1834edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
1835edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1836edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1837edc93052STejun Heo 	 *
1838edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
1839edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
1840edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
1841edc93052STejun Heo 	 * suffice while making probing snappish enough.
1842edc93052STejun Heo 	 */
18439dadd45bSTejun Heo 	if (online) {
18449dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
18459dadd45bSTejun Heo 					  ahci_check_ready);
1846edc93052STejun Heo 		if (rc)
1847edc93052STejun Heo 			ahci_kick_engine(ap, 0);
18489dadd45bSTejun Heo 	}
18499dadd45bSTejun Heo 	return rc;
1850edc93052STejun Heo }
1851edc93052STejun Heo 
1852cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class)
1853c6fd2807SJeff Garzik {
1854cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
18554447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1856c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1857c6fd2807SJeff Garzik 
1858203c75b8STejun Heo 	ata_std_postreset(link, class);
1859c6fd2807SJeff Garzik 
1860c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1861c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1862c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1863c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
1864c6fd2807SJeff Garzik 	else
1865c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
1866c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
1867c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
1868c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
1869c6fd2807SJeff Garzik 	}
1870c6fd2807SJeff Garzik }
1871c6fd2807SJeff Garzik 
1872c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
1873c6fd2807SJeff Garzik {
1874c6fd2807SJeff Garzik 	struct scatterlist *sg;
1875ff2aeb1eSTejun Heo 	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
1876ff2aeb1eSTejun Heo 	unsigned int si;
1877c6fd2807SJeff Garzik 
1878c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1879c6fd2807SJeff Garzik 
1880c6fd2807SJeff Garzik 	/*
1881c6fd2807SJeff Garzik 	 * Next, the S/G list.
1882c6fd2807SJeff Garzik 	 */
1883ff2aeb1eSTejun Heo 	for_each_sg(qc->sg, sg, qc->n_elem, si) {
1884c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1885c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1886c6fd2807SJeff Garzik 
1887ff2aeb1eSTejun Heo 		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
1888ff2aeb1eSTejun Heo 		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
1889ff2aeb1eSTejun Heo 		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
1890c6fd2807SJeff Garzik 	}
1891c6fd2807SJeff Garzik 
1892ff2aeb1eSTejun Heo 	return si;
1893c6fd2807SJeff Garzik }
1894c6fd2807SJeff Garzik 
1895c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1896c6fd2807SJeff Garzik {
1897c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1898c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1899405e66b3STejun Heo 	int is_atapi = ata_is_atapi(qc->tf.protocol);
1900c6fd2807SJeff Garzik 	void *cmd_tbl;
1901c6fd2807SJeff Garzik 	u32 opts;
1902c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1903c6fd2807SJeff Garzik 	unsigned int n_elem;
1904c6fd2807SJeff Garzik 
1905c6fd2807SJeff Garzik 	/*
1906c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1907c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1908c6fd2807SJeff Garzik 	 */
1909c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1910c6fd2807SJeff Garzik 
19117d50b60bSTejun Heo 	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
1912c6fd2807SJeff Garzik 	if (is_atapi) {
1913c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1914c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1915c6fd2807SJeff Garzik 	}
1916c6fd2807SJeff Garzik 
1917c6fd2807SJeff Garzik 	n_elem = 0;
1918c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1919c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1920c6fd2807SJeff Garzik 
1921c6fd2807SJeff Garzik 	/*
1922c6fd2807SJeff Garzik 	 * Fill in command slot information.
1923c6fd2807SJeff Garzik 	 */
19247d50b60bSTejun Heo 	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
1925c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1926c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1927c6fd2807SJeff Garzik 	if (is_atapi)
1928c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1929c6fd2807SJeff Garzik 
1930c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1931c6fd2807SJeff Garzik }
1932c6fd2807SJeff Garzik 
1933c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1934c6fd2807SJeff Garzik {
1935417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1936c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
19377d50b60bSTejun Heo 	struct ata_eh_info *host_ehi = &ap->link.eh_info;
19387d50b60bSTejun Heo 	struct ata_link *link = NULL;
19397d50b60bSTejun Heo 	struct ata_queued_cmd *active_qc;
19407d50b60bSTejun Heo 	struct ata_eh_info *active_ehi;
1941c6fd2807SJeff Garzik 	u32 serror;
1942c6fd2807SJeff Garzik 
19437d50b60bSTejun Heo 	/* determine active link */
19441eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE)
19457d50b60bSTejun Heo 		if (ata_link_active(link))
19467d50b60bSTejun Heo 			break;
19477d50b60bSTejun Heo 	if (!link)
19487d50b60bSTejun Heo 		link = &ap->link;
19497d50b60bSTejun Heo 
19507d50b60bSTejun Heo 	active_qc = ata_qc_from_tag(ap, link->active_tag);
19517d50b60bSTejun Heo 	active_ehi = &link->eh_info;
19527d50b60bSTejun Heo 
19537d50b60bSTejun Heo 	/* record irq stat */
19547d50b60bSTejun Heo 	ata_ehi_clear_desc(host_ehi);
19557d50b60bSTejun Heo 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
1956c6fd2807SJeff Garzik 
1957c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
195882ef04fbSTejun Heo 	ahci_scr_read(&ap->link, SCR_ERROR, &serror);
195982ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, serror);
19607d50b60bSTejun Heo 	host_ehi->serror |= serror;
1961c6fd2807SJeff Garzik 
196241669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
1963417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
196441669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
196541669553STejun Heo 
196655a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
19677d50b60bSTejun Heo 		/* If qc is active, charge it; otherwise, the active
19687d50b60bSTejun Heo 		 * link.  There's no active qc on NCQ errors.  It will
19697d50b60bSTejun Heo 		 * be determined by EH by reading log page 10h.
19707d50b60bSTejun Heo 		 */
19717d50b60bSTejun Heo 		if (active_qc)
19727d50b60bSTejun Heo 			active_qc->err_mask |= AC_ERR_DEV;
19737d50b60bSTejun Heo 		else
19747d50b60bSTejun Heo 			active_ehi->err_mask |= AC_ERR_DEV;
19757d50b60bSTejun Heo 
1976417a1a6dSTejun Heo 		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
19777d50b60bSTejun Heo 			host_ehi->serror &= ~SERR_INTERNAL;
1978c6fd2807SJeff Garzik 	}
1979c6fd2807SJeff Garzik 
1980c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
1981c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
1982c6fd2807SJeff Garzik 
19837d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
1984cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
19857d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi,
19867d50b60bSTejun Heo 				  "unknown FIS %08x %08x %08x %08x" ,
1987c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
1988c6fd2807SJeff Garzik 	}
1989c6fd2807SJeff Garzik 
1990071f44b1STejun Heo 	if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
19917d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
1992cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
19937d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi, "incorrect PMP");
19947d50b60bSTejun Heo 	}
1995c6fd2807SJeff Garzik 
19967d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
19977d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_HOST_BUS;
1998cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
19997d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "host bus error");
20007d50b60bSTejun Heo 	}
20017d50b60bSTejun Heo 
20027d50b60bSTejun Heo 	if (irq_stat & PORT_IRQ_IF_ERR) {
20037d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_ATA_BUS;
2004cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
20057d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "interface fatal error");
20067d50b60bSTejun Heo 	}
20077d50b60bSTejun Heo 
20087d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
20097d50b60bSTejun Heo 		ata_ehi_hotplugged(host_ehi);
20107d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "%s",
20117d50b60bSTejun Heo 			irq_stat & PORT_IRQ_CONNECT ?
20127d50b60bSTejun Heo 			"connection status changed" : "PHY RDY changed");
20137d50b60bSTejun Heo 	}
20147d50b60bSTejun Heo 
20157d50b60bSTejun Heo 	/* okay, let's hand over to EH */
2016c6fd2807SJeff Garzik 
2017c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
2018c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2019c6fd2807SJeff Garzik 	else
2020c6fd2807SJeff Garzik 		ata_port_abort(ap);
2021c6fd2807SJeff Garzik }
2022c6fd2807SJeff Garzik 
2023df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap)
2024c6fd2807SJeff Garzik {
2025350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
20269af5c9c9STejun Heo 	struct ata_eh_info *ehi = &ap->link.eh_info;
20270291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
20285f226c6bSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
2029b06ce3e5STejun Heo 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
2030c6fd2807SJeff Garzik 	u32 status, qc_active;
2031459ad688STejun Heo 	int rc;
2032c6fd2807SJeff Garzik 
2033c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
2034c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
2035c6fd2807SJeff Garzik 
2036b06ce3e5STejun Heo 	/* ignore BAD_PMP while resetting */
2037b06ce3e5STejun Heo 	if (unlikely(resetting))
2038b06ce3e5STejun Heo 		status &= ~PORT_IRQ_BAD_PMP;
2039b06ce3e5STejun Heo 
204031556594SKristen Carlson Accardi 	/* If we are getting PhyRdy, this is
204131556594SKristen Carlson Accardi  	 * just a power state change, we should
204231556594SKristen Carlson Accardi  	 * clear out this, plus the PhyRdy/Comm
204331556594SKristen Carlson Accardi  	 * Wake bits from Serror
204431556594SKristen Carlson Accardi  	 */
204531556594SKristen Carlson Accardi 	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
204631556594SKristen Carlson Accardi 		(status & PORT_IRQ_PHYRDY)) {
204731556594SKristen Carlson Accardi 		status &= ~PORT_IRQ_PHYRDY;
204882ef04fbSTejun Heo 		ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
204931556594SKristen Carlson Accardi 	}
205031556594SKristen Carlson Accardi 
2051c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
2052c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
2053c6fd2807SJeff Garzik 		return;
2054c6fd2807SJeff Garzik 	}
2055c6fd2807SJeff Garzik 
20562f294968SKristen Carlson Accardi 	if (status & PORT_IRQ_SDB_FIS) {
20575f226c6bSTejun Heo 		/* If SNotification is available, leave notification
20585f226c6bSTejun Heo 		 * handling to sata_async_notification().  If not,
20595f226c6bSTejun Heo 		 * emulate it by snooping SDB FIS RX area.
20605f226c6bSTejun Heo 		 *
20615f226c6bSTejun Heo 		 * Snooping FIS RX area is probably cheaper than
20625f226c6bSTejun Heo 		 * poking SNotification but some constrollers which
20635f226c6bSTejun Heo 		 * implement SNotification, ICH9 for example, don't
20645f226c6bSTejun Heo 		 * store AN SDB FIS into receive area.
20655f226c6bSTejun Heo 		 */
20665f226c6bSTejun Heo 		if (hpriv->cap & HOST_CAP_SNTF)
20675f226c6bSTejun Heo 			sata_async_notification(ap);
20685f226c6bSTejun Heo 		else {
20695f226c6bSTejun Heo 			/* If the 'N' bit in word 0 of the FIS is set,
20705f226c6bSTejun Heo 			 * we just received asynchronous notification.
20715f226c6bSTejun Heo 			 * Tell libata about it.
20722f294968SKristen Carlson Accardi 			 */
20732f294968SKristen Carlson Accardi 			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
20742f294968SKristen Carlson Accardi 			u32 f0 = le32_to_cpu(f[0]);
20752f294968SKristen Carlson Accardi 
20767d77b247STejun Heo 			if (f0 & (1 << 15))
20777d77b247STejun Heo 				sata_async_notification(ap);
20782f294968SKristen Carlson Accardi 		}
20795f226c6bSTejun Heo 	}
20802f294968SKristen Carlson Accardi 
20817d50b60bSTejun Heo 	/* pp->active_link is valid iff any command is in flight */
20827d50b60bSTejun Heo 	if (ap->qc_active && pp->active_link->sactive)
2083c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
2084c6fd2807SJeff Garzik 	else
2085c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
2086c6fd2807SJeff Garzik 
208779f97dadSTejun Heo 	rc = ata_qc_complete_multiple(ap, qc_active);
2088b06ce3e5STejun Heo 
2089459ad688STejun Heo 	/* while resetting, invalid completions are expected */
2090459ad688STejun Heo 	if (unlikely(rc < 0 && !resetting)) {
2091c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
2092cf480626STejun Heo 		ehi->action |= ATA_EH_RESET;
2093c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2094c6fd2807SJeff Garzik 	}
2095c6fd2807SJeff Garzik }
2096c6fd2807SJeff Garzik 
20977d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
2098c6fd2807SJeff Garzik {
2099cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
2100c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
2101c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
2102c6fd2807SJeff Garzik 	void __iomem *mmio;
2103d28f87aaSTejun Heo 	u32 irq_stat, irq_masked;
2104c6fd2807SJeff Garzik 
2105c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2106c6fd2807SJeff Garzik 
2107cca3974eSJeff Garzik 	hpriv = host->private_data;
21080d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
2109c6fd2807SJeff Garzik 
2110c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
2111c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
2112c6fd2807SJeff Garzik 	if (!irq_stat)
2113c6fd2807SJeff Garzik 		return IRQ_NONE;
2114c6fd2807SJeff Garzik 
2115d28f87aaSTejun Heo 	irq_masked = irq_stat & hpriv->port_map;
2116d28f87aaSTejun Heo 
2117cca3974eSJeff Garzik 	spin_lock(&host->lock);
2118c6fd2807SJeff Garzik 
2119cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
2120c6fd2807SJeff Garzik 		struct ata_port *ap;
2121c6fd2807SJeff Garzik 
2122d28f87aaSTejun Heo 		if (!(irq_masked & (1 << i)))
2123c6fd2807SJeff Garzik 			continue;
2124c6fd2807SJeff Garzik 
2125cca3974eSJeff Garzik 		ap = host->ports[i];
2126c6fd2807SJeff Garzik 		if (ap) {
2127df69c9c5SJeff Garzik 			ahci_port_intr(ap);
2128c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
2129c6fd2807SJeff Garzik 		} else {
2130c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
2131c6fd2807SJeff Garzik 			if (ata_ratelimit())
2132cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
2133c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
2134c6fd2807SJeff Garzik 		}
2135c6fd2807SJeff Garzik 
2136c6fd2807SJeff Garzik 		handled = 1;
2137c6fd2807SJeff Garzik 	}
2138c6fd2807SJeff Garzik 
2139d28f87aaSTejun Heo 	/* HOST_IRQ_STAT behaves as level triggered latch meaning that
2140d28f87aaSTejun Heo 	 * it should be cleared after all the port events are cleared;
2141d28f87aaSTejun Heo 	 * otherwise, it will raise a spurious interrupt after each
2142d28f87aaSTejun Heo 	 * valid one.  Please read section 10.6.2 of ahci 1.1 for more
2143d28f87aaSTejun Heo 	 * information.
2144d28f87aaSTejun Heo 	 *
2145d28f87aaSTejun Heo 	 * Also, use the unmasked value to clear interrupt as spurious
2146d28f87aaSTejun Heo 	 * pending event on a dummy port might cause screaming IRQ.
2147d28f87aaSTejun Heo 	 */
2148ea0c62f7STejun Heo 	writel(irq_stat, mmio + HOST_IRQ_STAT);
2149ea0c62f7STejun Heo 
2150cca3974eSJeff Garzik 	spin_unlock(&host->lock);
2151c6fd2807SJeff Garzik 
2152c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
2153c6fd2807SJeff Garzik 
2154c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
2155c6fd2807SJeff Garzik }
2156c6fd2807SJeff Garzik 
2157c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
2158c6fd2807SJeff Garzik {
2159c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
21604447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
21617d50b60bSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
21627d50b60bSTejun Heo 
21637d50b60bSTejun Heo 	/* Keep track of the currently active link.  It will be used
21647d50b60bSTejun Heo 	 * in completion path to determine whether NCQ phase is in
21657d50b60bSTejun Heo 	 * progress.
21667d50b60bSTejun Heo 	 */
21677d50b60bSTejun Heo 	pp->active_link = qc->dev->link;
2168c6fd2807SJeff Garzik 
2169c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
2170c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
2171c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
2172c6fd2807SJeff Garzik 
217318f7ba4cSKristen Carlson Accardi 	ahci_sw_activity(qc->dev->link);
217418f7ba4cSKristen Carlson Accardi 
2175c6fd2807SJeff Garzik 	return 0;
2176c6fd2807SJeff Garzik }
2177c6fd2807SJeff Garzik 
21784c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
21794c9bf4e7STejun Heo {
21804c9bf4e7STejun Heo 	struct ahci_port_priv *pp = qc->ap->private_data;
21814c9bf4e7STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
21824c9bf4e7STejun Heo 
21834c9bf4e7STejun Heo 	ata_tf_from_fis(d2h_fis, &qc->result_tf);
21844c9bf4e7STejun Heo 	return true;
21854c9bf4e7STejun Heo }
21864c9bf4e7STejun Heo 
2187c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
2188c6fd2807SJeff Garzik {
21894447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2190c6fd2807SJeff Garzik 
2191c6fd2807SJeff Garzik 	/* turn IRQ off */
2192c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
2193c6fd2807SJeff Garzik }
2194c6fd2807SJeff Garzik 
2195c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
2196c6fd2807SJeff Garzik {
21970d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
21984447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2199c6fd2807SJeff Garzik 	u32 tmp;
2200a7384925SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
2201c6fd2807SJeff Garzik 
2202c6fd2807SJeff Garzik 	/* clear IRQ */
2203c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
2204c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
2205a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
2206c6fd2807SJeff Garzik 
22071c954a4dSTejun Heo 	/* turn IRQ back on */
22081c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
2209c6fd2807SJeff Garzik }
2210c6fd2807SJeff Garzik 
2211c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
2212c6fd2807SJeff Garzik {
2213c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
2214c6fd2807SJeff Garzik 		/* restart engine */
22154447d351STejun Heo 		ahci_stop_engine(ap);
22164447d351STejun Heo 		ahci_start_engine(ap);
2217c6fd2807SJeff Garzik 	}
2218c6fd2807SJeff Garzik 
2219a1efdabaSTejun Heo 	sata_pmp_error_handler(ap);
2220edc93052STejun Heo }
2221edc93052STejun Heo 
2222c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
2223c6fd2807SJeff Garzik {
2224c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
2225c6fd2807SJeff Garzik 
2226c6fd2807SJeff Garzik 	/* make DMA engine forget about the failed command */
2227d2e75dffSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED)
2228d2e75dffSTejun Heo 		ahci_kick_engine(ap, 1);
2229c6fd2807SJeff Garzik }
2230c6fd2807SJeff Garzik 
22317d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap)
22327d50b60bSTejun Heo {
22337d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22341c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22357d50b60bSTejun Heo 	u32 cmd;
22367d50b60bSTejun Heo 
22377d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
22387d50b60bSTejun Heo 	cmd |= PORT_CMD_PMP;
22397d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
22401c954a4dSTejun Heo 
22411c954a4dSTejun Heo 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
22421c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
22437d50b60bSTejun Heo }
22447d50b60bSTejun Heo 
22457d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap)
22467d50b60bSTejun Heo {
22477d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22481c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22497d50b60bSTejun Heo 	u32 cmd;
22507d50b60bSTejun Heo 
22517d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
22527d50b60bSTejun Heo 	cmd &= ~PORT_CMD_PMP;
22537d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
22541c954a4dSTejun Heo 
22551c954a4dSTejun Heo 	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
22561c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
22577d50b60bSTejun Heo }
22587d50b60bSTejun Heo 
2259028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap)
2260028a2596SAlexey Dobriyan {
2261028a2596SAlexey Dobriyan 	ahci_power_up(ap);
2262028a2596SAlexey Dobriyan 	ahci_start_port(ap);
2263028a2596SAlexey Dobriyan 
2264071f44b1STejun Heo 	if (sata_pmp_attached(ap))
22657d50b60bSTejun Heo 		ahci_pmp_attach(ap);
22667d50b60bSTejun Heo 	else
22677d50b60bSTejun Heo 		ahci_pmp_detach(ap);
22687d50b60bSTejun Heo 
2269028a2596SAlexey Dobriyan 	return 0;
2270028a2596SAlexey Dobriyan }
2271028a2596SAlexey Dobriyan 
2272438ac6d5STejun Heo #ifdef CONFIG_PM
2273c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
2274c6fd2807SJeff Garzik {
2275c6fd2807SJeff Garzik 	const char *emsg = NULL;
2276c6fd2807SJeff Garzik 	int rc;
2277c6fd2807SJeff Garzik 
22784447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
22798e16f941STejun Heo 	if (rc == 0)
22804447d351STejun Heo 		ahci_power_down(ap);
22818e16f941STejun Heo 	else {
2282c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
2283df69c9c5SJeff Garzik 		ahci_start_port(ap);
2284c6fd2807SJeff Garzik 	}
2285c6fd2807SJeff Garzik 
2286c6fd2807SJeff Garzik 	return rc;
2287c6fd2807SJeff Garzik }
2288c6fd2807SJeff Garzik 
2289c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
2290c6fd2807SJeff Garzik {
2291cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
22920d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2293c6fd2807SJeff Garzik 	u32 ctl;
2294c6fd2807SJeff Garzik 
22953a2d5b70SRafael J. Wysocki 	if (mesg.event & PM_EVENT_SLEEP) {
2296c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
2297c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
2298c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
2299c6fd2807SJeff Garzik 		 */
2300c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
2301c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
2302c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
2303c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
2304c6fd2807SJeff Garzik 	}
2305c6fd2807SJeff Garzik 
2306c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
2307c6fd2807SJeff Garzik }
2308c6fd2807SJeff Garzik 
2309c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
2310c6fd2807SJeff Garzik {
2311cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
2312c6fd2807SJeff Garzik 	int rc;
2313c6fd2807SJeff Garzik 
2314553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
2315553c4aa6STejun Heo 	if (rc)
2316553c4aa6STejun Heo 		return rc;
2317c6fd2807SJeff Garzik 
2318c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
23194447d351STejun Heo 		rc = ahci_reset_controller(host);
2320c6fd2807SJeff Garzik 		if (rc)
2321c6fd2807SJeff Garzik 			return rc;
2322c6fd2807SJeff Garzik 
23234447d351STejun Heo 		ahci_init_controller(host);
2324c6fd2807SJeff Garzik 	}
2325c6fd2807SJeff Garzik 
2326cca3974eSJeff Garzik 	ata_host_resume(host);
2327c6fd2807SJeff Garzik 
2328c6fd2807SJeff Garzik 	return 0;
2329c6fd2807SJeff Garzik }
2330438ac6d5STejun Heo #endif
2331c6fd2807SJeff Garzik 
2332c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
2333c6fd2807SJeff Garzik {
2334cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
2335c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
2336c6fd2807SJeff Garzik 	void *mem;
2337c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
2338c6fd2807SJeff Garzik 
233924dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
2340c6fd2807SJeff Garzik 	if (!pp)
2341c6fd2807SJeff Garzik 		return -ENOMEM;
2342c6fd2807SJeff Garzik 
234324dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
234424dc5f33STejun Heo 				  GFP_KERNEL);
234524dc5f33STejun Heo 	if (!mem)
2346c6fd2807SJeff Garzik 		return -ENOMEM;
2347c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
2348c6fd2807SJeff Garzik 
2349c6fd2807SJeff Garzik 	/*
2350c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
2351c6fd2807SJeff Garzik 	 * 32 bytes each in size
2352c6fd2807SJeff Garzik 	 */
2353c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
2354c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
2355c6fd2807SJeff Garzik 
2356c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
2357c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
2358c6fd2807SJeff Garzik 
2359c6fd2807SJeff Garzik 	/*
2360c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
2361c6fd2807SJeff Garzik 	 */
2362c6fd2807SJeff Garzik 	pp->rx_fis = mem;
2363c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
2364c6fd2807SJeff Garzik 
2365c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
2366c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
2367c6fd2807SJeff Garzik 
2368c6fd2807SJeff Garzik 	/*
2369c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
2370c6fd2807SJeff Garzik 	 * and its scatter-gather table
2371c6fd2807SJeff Garzik 	 */
2372c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
2373c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
2374c6fd2807SJeff Garzik 
2375a7384925SKristen Carlson Accardi 	/*
2376a7384925SKristen Carlson Accardi 	 * Save off initial list of interrupts to be enabled.
2377a7384925SKristen Carlson Accardi 	 * This could be changed later
2378a7384925SKristen Carlson Accardi 	 */
2379a7384925SKristen Carlson Accardi 	pp->intr_mask = DEF_PORT_IRQ;
2380a7384925SKristen Carlson Accardi 
2381c6fd2807SJeff Garzik 	ap->private_data = pp;
2382c6fd2807SJeff Garzik 
2383df69c9c5SJeff Garzik 	/* engage engines, captain */
2384df69c9c5SJeff Garzik 	return ahci_port_resume(ap);
2385c6fd2807SJeff Garzik }
2386c6fd2807SJeff Garzik 
2387c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
2388c6fd2807SJeff Garzik {
2389c6fd2807SJeff Garzik 	const char *emsg = NULL;
2390c6fd2807SJeff Garzik 	int rc;
2391c6fd2807SJeff Garzik 
2392c6fd2807SJeff Garzik 	/* de-initialize port */
23934447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
2394c6fd2807SJeff Garzik 	if (rc)
2395c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
2396c6fd2807SJeff Garzik }
2397c6fd2807SJeff Garzik 
23984447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
2399c6fd2807SJeff Garzik {
2400c6fd2807SJeff Garzik 	int rc;
2401c6fd2807SJeff Garzik 
2402c6fd2807SJeff Garzik 	if (using_dac &&
2403c6fd2807SJeff Garzik 	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
2404c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
2405c6fd2807SJeff Garzik 		if (rc) {
2406c6fd2807SJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
2407c6fd2807SJeff Garzik 			if (rc) {
2408c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
2409c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
2410c6fd2807SJeff Garzik 				return rc;
2411c6fd2807SJeff Garzik 			}
2412c6fd2807SJeff Garzik 		}
2413c6fd2807SJeff Garzik 	} else {
2414c6fd2807SJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
2415c6fd2807SJeff Garzik 		if (rc) {
2416c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2417c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
2418c6fd2807SJeff Garzik 			return rc;
2419c6fd2807SJeff Garzik 		}
2420c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
2421c6fd2807SJeff Garzik 		if (rc) {
2422c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2423c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
2424c6fd2807SJeff Garzik 			return rc;
2425c6fd2807SJeff Garzik 		}
2426c6fd2807SJeff Garzik 	}
2427c6fd2807SJeff Garzik 	return 0;
2428c6fd2807SJeff Garzik }
2429c6fd2807SJeff Garzik 
24304447d351STejun Heo static void ahci_print_info(struct ata_host *host)
2431c6fd2807SJeff Garzik {
24324447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
24334447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
24344447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2435c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
2436c6fd2807SJeff Garzik 	const char *speed_s;
2437c6fd2807SJeff Garzik 	u16 cc;
2438c6fd2807SJeff Garzik 	const char *scc_s;
2439c6fd2807SJeff Garzik 
2440c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
2441c6fd2807SJeff Garzik 	cap = hpriv->cap;
2442c6fd2807SJeff Garzik 	impl = hpriv->port_map;
2443c6fd2807SJeff Garzik 
2444c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
2445c6fd2807SJeff Garzik 	if (speed == 1)
2446c6fd2807SJeff Garzik 		speed_s = "1.5";
2447c6fd2807SJeff Garzik 	else if (speed == 2)
2448c6fd2807SJeff Garzik 		speed_s = "3";
24498522ee25SShane Huang 	else if (speed == 3)
24508522ee25SShane Huang 		speed_s = "6";
2451c6fd2807SJeff Garzik 	else
2452c6fd2807SJeff Garzik 		speed_s = "?";
2453c6fd2807SJeff Garzik 
2454c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
2455c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
2456c6fd2807SJeff Garzik 		scc_s = "IDE";
2457c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
2458c6fd2807SJeff Garzik 		scc_s = "SATA";
2459c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
2460c6fd2807SJeff Garzik 		scc_s = "RAID";
2461c6fd2807SJeff Garzik 	else
2462c6fd2807SJeff Garzik 		scc_s = "unknown";
2463c6fd2807SJeff Garzik 
2464c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2465c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
2466c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
2467c6fd2807SJeff Garzik 		,
2468c6fd2807SJeff Garzik 
2469c6fd2807SJeff Garzik 		(vers >> 24) & 0xff,
2470c6fd2807SJeff Garzik 		(vers >> 16) & 0xff,
2471c6fd2807SJeff Garzik 		(vers >> 8) & 0xff,
2472c6fd2807SJeff Garzik 		vers & 0xff,
2473c6fd2807SJeff Garzik 
2474c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
2475c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
2476c6fd2807SJeff Garzik 		speed_s,
2477c6fd2807SJeff Garzik 		impl,
2478c6fd2807SJeff Garzik 		scc_s);
2479c6fd2807SJeff Garzik 
2480c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2481c6fd2807SJeff Garzik 		"flags: "
2482203ef6c4STejun Heo 		"%s%s%s%s%s%s%s"
248318f7ba4cSKristen Carlson Accardi 		"%s%s%s%s%s%s%s"
248418f7ba4cSKristen Carlson Accardi 		"%s\n"
2485c6fd2807SJeff Garzik 		,
2486c6fd2807SJeff Garzik 
2487c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
2488c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
2489203ef6c4STejun Heo 		cap & (1 << 29) ? "sntf " : "",
2490c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
2491c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
2492c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
2493c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
2494c6fd2807SJeff Garzik 
2495c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
2496c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
2497c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
2498c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
2499c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
2500c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
250118f7ba4cSKristen Carlson Accardi 		cap & (1 << 13) ? "part " : "",
250218f7ba4cSKristen Carlson Accardi 		cap & (1 << 6) ? "ems ": ""
2503c6fd2807SJeff Garzik 		);
2504c6fd2807SJeff Garzik }
2505c6fd2807SJeff Garzik 
2506edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2507edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
2508edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
2509edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
2510edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
2511edc93052STejun Heo  * other configuration).
2512edc93052STejun Heo  *
2513edc93052STejun Heo  * When there's no device attached to the first downstream port of the
2514edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
2515edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
2516edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
2517edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2518edc93052STejun Heo  *
2519edc93052STejun Heo  * The following function works around the problem by always using
2520edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
2521edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
2522edc93052STejun Heo  * assumed without follow-up softreset.
2523edc93052STejun Heo  */
2524edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
2525edc93052STejun Heo {
2526edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
2527edc93052STejun Heo 		{
2528edc93052STejun Heo 			.ident = "P5W DH Deluxe",
2529edc93052STejun Heo 			.matches = {
2530edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
2531edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
2532edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2533edc93052STejun Heo 			},
2534edc93052STejun Heo 		},
2535edc93052STejun Heo 		{ }
2536edc93052STejun Heo 	};
2537edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
2538edc93052STejun Heo 
2539edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2540edc93052STejun Heo 	    dmi_check_system(sysids)) {
2541edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
2542edc93052STejun Heo 
2543edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2544edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
2545edc93052STejun Heo 
2546edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
2547edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2548edc93052STejun Heo 	}
2549edc93052STejun Heo }
2550edc93052STejun Heo 
2551c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2552c6fd2807SJeff Garzik {
2553c6fd2807SJeff Garzik 	static int printed_version;
2554e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
2555e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
25564447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
255724dc5f33STejun Heo 	struct device *dev = &pdev->dev;
2558c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
25594447d351STejun Heo 	struct ata_host *host;
2560837f5f8fSTejun Heo 	int n_ports, i, rc;
2561c6fd2807SJeff Garzik 
2562c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2563c6fd2807SJeff Garzik 
2564c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
2565c6fd2807SJeff Garzik 
2566c6fd2807SJeff Garzik 	if (!printed_version++)
2567c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
2568c6fd2807SJeff Garzik 
25695b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
25705b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
25715b66c829SAlan Cox 	   AHCI stays out of the way */
25725b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
25735b66c829SAlan Cox 		return -ENODEV;
25745b66c829SAlan Cox 
25754447d351STejun Heo 	/* acquire resources */
257624dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
2577c6fd2807SJeff Garzik 	if (rc)
2578c6fd2807SJeff Garzik 		return rc;
2579c6fd2807SJeff Garzik 
2580dea55137STejun Heo 	/* AHCI controllers often implement SFF compatible interface.
2581dea55137STejun Heo 	 * Grab all PCI BARs just in case.
2582dea55137STejun Heo 	 */
2583dea55137STejun Heo 	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
25840d5ff566STejun Heo 	if (rc == -EBUSY)
258524dc5f33STejun Heo 		pcim_pin_device(pdev);
25860d5ff566STejun Heo 	if (rc)
258724dc5f33STejun Heo 		return rc;
2588c6fd2807SJeff Garzik 
2589c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
2590c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
2591c4f7792cSTejun Heo 		u8 map;
2592c4f7792cSTejun Heo 
2593c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
2594c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
2595c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
2596c4f7792cSTejun Heo 		 */
2597c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
2598c4f7792cSTejun Heo 		if (map & 0x3) {
2599c4f7792cSTejun Heo 			dev_printk(KERN_INFO, &pdev->dev, "controller is in "
2600c4f7792cSTejun Heo 				   "combined mode, can't enable AHCI mode\n");
2601c4f7792cSTejun Heo 			return -ENODEV;
2602c4f7792cSTejun Heo 		}
2603c4f7792cSTejun Heo 	}
2604c4f7792cSTejun Heo 
260524dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
260624dc5f33STejun Heo 	if (!hpriv)
260724dc5f33STejun Heo 		return -ENOMEM;
2608417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
2609417a1a6dSTejun Heo 
2610e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
2611e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
2612e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
2613e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
2614e297d99eSTejun Heo 
2615e427fe04SShane Huang 	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
2616e427fe04SShane Huang 	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
2617e427fe04SShane Huang 		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
2618e427fe04SShane Huang 
2619417a1a6dSTejun Heo 	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
2620417a1a6dSTejun Heo 		pci_intx(pdev, 1);
2621c6fd2807SJeff Garzik 
26224447d351STejun Heo 	/* save initial config */
2623417a1a6dSTejun Heo 	ahci_save_initial_config(pdev, hpriv);
2624c6fd2807SJeff Garzik 
26254447d351STejun Heo 	/* prepare host */
2626274c1fdeSTejun Heo 	if (hpriv->cap & HOST_CAP_NCQ)
26274447d351STejun Heo 		pi.flags |= ATA_FLAG_NCQ;
26284447d351STejun Heo 
26297d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
26307d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
26317d50b60bSTejun Heo 
263218f7ba4cSKristen Carlson Accardi 	if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) {
263318f7ba4cSKristen Carlson Accardi 		u8 messages;
263418f7ba4cSKristen Carlson Accardi 		void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
263518f7ba4cSKristen Carlson Accardi 		u32 em_loc = readl(mmio + HOST_EM_LOC);
263618f7ba4cSKristen Carlson Accardi 		u32 em_ctl = readl(mmio + HOST_EM_CTL);
263718f7ba4cSKristen Carlson Accardi 
263887943acfSDavid Milburn 		messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
263918f7ba4cSKristen Carlson Accardi 
264018f7ba4cSKristen Carlson Accardi 		/* we only support LED message type right now */
264118f7ba4cSKristen Carlson Accardi 		if ((messages & 0x01) && (ahci_em_messages == 1)) {
264218f7ba4cSKristen Carlson Accardi 			/* store em_loc */
264318f7ba4cSKristen Carlson Accardi 			hpriv->em_loc = ((em_loc >> 16) * 4);
264418f7ba4cSKristen Carlson Accardi 			pi.flags |= ATA_FLAG_EM;
264518f7ba4cSKristen Carlson Accardi 			if (!(em_ctl & EM_CTL_ALHD))
264618f7ba4cSKristen Carlson Accardi 				pi.flags |= ATA_FLAG_SW_ACTIVITY;
264718f7ba4cSKristen Carlson Accardi 		}
264818f7ba4cSKristen Carlson Accardi 	}
264918f7ba4cSKristen Carlson Accardi 
2650837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
2651837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
2652837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
2653837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
2654837f5f8fSTejun Heo 	 */
2655837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
2656837f5f8fSTejun Heo 
2657837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
26584447d351STejun Heo 	if (!host)
26594447d351STejun Heo 		return -ENOMEM;
26604447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
26614447d351STejun Heo 	host->private_data = hpriv;
26624447d351STejun Heo 
2663*886ad09fSArjan van de Ven 	if (!(hpriv->cap & HOST_CAP_SSS))
2664*886ad09fSArjan van de Ven 		host->flags |= ATA_HOST_PARALLEL_SCAN;
2665*886ad09fSArjan van de Ven 
266618f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
266718f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
266818f7ba4cSKristen Carlson Accardi 
26694447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
26704447d351STejun Heo 		struct ata_port *ap = host->ports[i];
26714447d351STejun Heo 
2672cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
2673cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
2674cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
2675cbcdd875STejun Heo 
267631556594SKristen Carlson Accardi 		/* set initial link pm policy */
267731556594SKristen Carlson Accardi 		ap->pm_policy = NOT_AVAILABLE;
267831556594SKristen Carlson Accardi 
267918f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
268018f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
268118f7ba4cSKristen Carlson Accardi 			ap->em_message_type = ahci_em_messages;
268218f7ba4cSKristen Carlson Accardi 
268318f7ba4cSKristen Carlson Accardi 
2684dab632e8SJeff Garzik 		/* disabled/not-implemented port */
2685350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
2686dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
26874447d351STejun Heo 	}
2688c6fd2807SJeff Garzik 
2689edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
2690edc93052STejun Heo 	ahci_p5wdh_workaround(host);
2691edc93052STejun Heo 
2692c6fd2807SJeff Garzik 	/* initialize adapter */
26934447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
2694c6fd2807SJeff Garzik 	if (rc)
269524dc5f33STejun Heo 		return rc;
2696c6fd2807SJeff Garzik 
26974447d351STejun Heo 	rc = ahci_reset_controller(host);
26984447d351STejun Heo 	if (rc)
26994447d351STejun Heo 		return rc;
2700c6fd2807SJeff Garzik 
27014447d351STejun Heo 	ahci_init_controller(host);
27024447d351STejun Heo 	ahci_print_info(host);
2703c6fd2807SJeff Garzik 
27044447d351STejun Heo 	pci_set_master(pdev);
27054447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
27064447d351STejun Heo 				 &ahci_sht);
2707c6fd2807SJeff Garzik }
2708c6fd2807SJeff Garzik 
2709c6fd2807SJeff Garzik static int __init ahci_init(void)
2710c6fd2807SJeff Garzik {
2711c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
2712c6fd2807SJeff Garzik }
2713c6fd2807SJeff Garzik 
2714c6fd2807SJeff Garzik static void __exit ahci_exit(void)
2715c6fd2807SJeff Garzik {
2716c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
2717c6fd2807SJeff Garzik }
2718c6fd2807SJeff Garzik 
2719c6fd2807SJeff Garzik 
2720c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
2721c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
2722c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
2723c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
2724c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
2725c6fd2807SJeff Garzik 
2726c6fd2807SJeff Garzik module_init(ahci_init);
2727c6fd2807SJeff Garzik module_exit(ahci_exit);
2728