xref: /openbmc/linux/drivers/ata/ahci.c (revision 78d5ae39af19a02a3d16213c0f62930d9a5d25f7)
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;
64f3d7f23fSArjan van de Ven static int ahci_ignore_sss;
65f3d7f23fSArjan van de Ven 
66a22e6444STejun Heo module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
67a22e6444STejun Heo MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
68a22e6444STejun Heo 
69f3d7f23fSArjan van de Ven module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
70f3d7f23fSArjan van de Ven MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
71f3d7f23fSArjan van de Ven 
7231556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
7331556594SKristen Carlson Accardi 		enum link_pm policy);
7431556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap);
7518f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
7618f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
7718f7ba4cSKristen Carlson Accardi 			      size_t size);
7818f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
7918f7ba4cSKristen Carlson Accardi 					ssize_t size);
80c6fd2807SJeff Garzik 
81c6fd2807SJeff Garzik enum {
82c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
83648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
84c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
85c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
86c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
87c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
88c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
89c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
90c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
91c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
92c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
93c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
94c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
95c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
96c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
97c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
98c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
99c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
100c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
101c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
102c6fd2807SJeff Garzik 
103c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
1040291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
105c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
106c6fd2807SJeff Garzik 
107c6fd2807SJeff Garzik 	board_ahci		= 0,
1087a234affSTejun Heo 	board_ahci_vt8251	= 1,
1097a234affSTejun Heo 	board_ahci_ign_iferr	= 2,
1107a234affSTejun Heo 	board_ahci_sb600	= 3,
1117a234affSTejun Heo 	board_ahci_mv		= 4,
112e427fe04SShane Huang 	board_ahci_sb700	= 5, /* for SB700 and SB800 */
113e297d99eSTejun Heo 	board_ahci_mcp65	= 6,
1149a3b103cSTejun Heo 	board_ahci_nopmp	= 7,
115aa431dd3STejun Heo 	board_ahci_yesncq	= 8,
116c6fd2807SJeff Garzik 
117c6fd2807SJeff Garzik 	/* global controller registers */
118c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
119c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
120c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
121c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
122c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
12318f7ba4cSKristen Carlson Accardi 	HOST_EM_LOC		= 0x1c, /* Enclosure Management location */
12418f7ba4cSKristen Carlson Accardi 	HOST_EM_CTL		= 0x20, /* Enclosure Management Control */
125c6fd2807SJeff Garzik 
126c6fd2807SJeff Garzik 	/* HOST_CTL bits */
127c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
128c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
129c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
130c6fd2807SJeff Garzik 
131c6fd2807SJeff Garzik 	/* HOST_CAP bits */
13218f7ba4cSKristen Carlson Accardi 	HOST_CAP_EMS		= (1 << 6),  /* Enclosure Management support */
133c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
1347d50b60bSTejun Heo 	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
135c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
13631556594SKristen Carlson Accardi 	HOST_CAP_ALPM		= (1 << 26), /* Aggressive Link PM support */
137c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
138203ef6c4STejun Heo 	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
139c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
140c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
141c6fd2807SJeff Garzik 
142c6fd2807SJeff Garzik 	/* registers for each SATA port */
143c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
144c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
145c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
146c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
147c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
148c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
149c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
150c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
151c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
152c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
153c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
154c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
155c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
156c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
157203ef6c4STejun Heo 	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
158c6fd2807SJeff Garzik 
159c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
160c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
161c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
162c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
163c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
164c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
165c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
166c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
167c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
168c6fd2807SJeff Garzik 
169c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
170c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
171c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
172c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
173c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
174c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
175c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
176c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
177c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
178c6fd2807SJeff Garzik 
179c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
180c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
181c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
182c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
1837d50b60bSTejun Heo 				  PORT_IRQ_UNK_FIS |
1847d50b60bSTejun Heo 				  PORT_IRQ_BAD_PMP,
185c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
186c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
187c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
188c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
189c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
190c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
191c6fd2807SJeff Garzik 
192c6fd2807SJeff Garzik 	/* PORT_CMD bits */
19331556594SKristen Carlson Accardi 	PORT_CMD_ASP		= (1 << 27), /* Aggressive Slumber/Partial */
19431556594SKristen Carlson Accardi 	PORT_CMD_ALPE		= (1 << 26), /* Aggressive Link PM enable */
195c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
1967d50b60bSTejun Heo 	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
197c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
198c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
199c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
200c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
201c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
202c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
203c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
204c6fd2807SJeff Garzik 
205c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
206c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
207c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
208c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
209c6fd2807SJeff Garzik 
210417a1a6dSTejun Heo 	/* hpriv->flags bits */
211417a1a6dSTejun Heo 	AHCI_HFLAG_NO_NCQ		= (1 << 0),
212417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
213417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
214417a1a6dSTejun Heo 	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
215417a1a6dSTejun Heo 	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
216417a1a6dSTejun Heo 	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
2176949b914STejun Heo 	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
21831556594SKristen Carlson Accardi 	AHCI_HFLAG_NO_HOTPLUG		= (1 << 7), /* ignore PxSERR.DIAG.N */
219a878539eSJeff Garzik 	AHCI_HFLAG_SECT255		= (1 << 8), /* max 255 sectors */
220e297d99eSTejun Heo 	AHCI_HFLAG_YES_NCQ		= (1 << 9), /* force NCQ cap on */
2219b10ae86STejun Heo 	AHCI_HFLAG_NO_SUSPEND		= (1 << 10), /* don't suspend */
2225594639aSTejun Heo 	AHCI_HFLAG_SRST_TOUT_IS_OFFLINE	= (1 << 11), /* treat SRST timeout as
2235594639aSTejun Heo 							link offline */
224417a1a6dSTejun Heo 
225c6fd2807SJeff Garzik 	/* ap->flags bits */
2261188c0d8STejun Heo 
2271188c0d8STejun Heo 	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
2281188c0d8STejun Heo 					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
22931556594SKristen Carlson Accardi 					  ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
23031556594SKristen Carlson Accardi 					  ATA_FLAG_IPM,
231c4f7792cSTejun Heo 
232c4f7792cSTejun Heo 	ICH_MAP				= 0x90, /* ICH MAP register */
23318f7ba4cSKristen Carlson Accardi 
234d50ce07dSTejun Heo 	/* em constants */
235d50ce07dSTejun Heo 	EM_MAX_SLOTS			= 8,
236d50ce07dSTejun Heo 	EM_MAX_RETRY			= 5,
237d50ce07dSTejun Heo 
23818f7ba4cSKristen Carlson Accardi 	/* em_ctl bits */
23918f7ba4cSKristen Carlson Accardi 	EM_CTL_RST			= (1 << 9), /* Reset */
24018f7ba4cSKristen Carlson Accardi 	EM_CTL_TM			= (1 << 8), /* Transmit Message */
24118f7ba4cSKristen Carlson Accardi 	EM_CTL_ALHD			= (1 << 26), /* Activity LED */
242c6fd2807SJeff Garzik };
243c6fd2807SJeff Garzik 
244c6fd2807SJeff Garzik struct ahci_cmd_hdr {
2454ca4e439SAl Viro 	__le32			opts;
2464ca4e439SAl Viro 	__le32			status;
2474ca4e439SAl Viro 	__le32			tbl_addr;
2484ca4e439SAl Viro 	__le32			tbl_addr_hi;
2494ca4e439SAl Viro 	__le32			reserved[4];
250c6fd2807SJeff Garzik };
251c6fd2807SJeff Garzik 
252c6fd2807SJeff Garzik struct ahci_sg {
2534ca4e439SAl Viro 	__le32			addr;
2544ca4e439SAl Viro 	__le32			addr_hi;
2554ca4e439SAl Viro 	__le32			reserved;
2564ca4e439SAl Viro 	__le32			flags_size;
257c6fd2807SJeff Garzik };
258c6fd2807SJeff Garzik 
25918f7ba4cSKristen Carlson Accardi struct ahci_em_priv {
26018f7ba4cSKristen Carlson Accardi 	enum sw_activity blink_policy;
26118f7ba4cSKristen Carlson Accardi 	struct timer_list timer;
26218f7ba4cSKristen Carlson Accardi 	unsigned long saved_activity;
26318f7ba4cSKristen Carlson Accardi 	unsigned long activity;
26418f7ba4cSKristen Carlson Accardi 	unsigned long led_state;
26518f7ba4cSKristen Carlson Accardi };
26618f7ba4cSKristen Carlson Accardi 
267c6fd2807SJeff Garzik struct ahci_host_priv {
268417a1a6dSTejun Heo 	unsigned int		flags;		/* AHCI_HFLAG_* */
269d447df14STejun Heo 	u32			cap;		/* cap to use */
270d447df14STejun Heo 	u32			port_map;	/* port map to use */
271d447df14STejun Heo 	u32			saved_cap;	/* saved initial cap */
272d447df14STejun Heo 	u32			saved_port_map;	/* saved initial port_map */
27318f7ba4cSKristen Carlson Accardi 	u32 			em_loc; /* enclosure management location */
274c6fd2807SJeff Garzik };
275c6fd2807SJeff Garzik 
276c6fd2807SJeff Garzik struct ahci_port_priv {
2777d50b60bSTejun Heo 	struct ata_link		*active_link;
278c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
279c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
280c6fd2807SJeff Garzik 	void			*cmd_tbl;
281c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
282c6fd2807SJeff Garzik 	void			*rx_fis;
283c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2840291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2850291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2860291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
287afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
288a7384925SKristen Carlson Accardi 	u32 			intr_mask;	/* interrupts to enable */
289d50ce07dSTejun Heo 	/* enclosure management info per PM slot */
290d50ce07dSTejun Heo 	struct ahci_em_priv	em_priv[EM_MAX_SLOTS];
291c6fd2807SJeff Garzik };
292c6fd2807SJeff Garzik 
29382ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
29482ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
295c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
296c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
2974c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
298c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
299c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
300c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
301c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
302c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
3037d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap);
3047d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap);
305a1efdabaSTejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class,
306a1efdabaSTejun Heo 			  unsigned long deadline);
307bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
308bd17243aSShane Huang 			  unsigned long deadline);
309a1efdabaSTejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
310a1efdabaSTejun Heo 			  unsigned long deadline);
311a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
312a1efdabaSTejun Heo 				 unsigned long deadline);
313a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
314a1efdabaSTejun Heo 				unsigned long deadline);
315a1efdabaSTejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class);
316c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
317c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
318df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
319a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev);
320dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
321dab632e8SJeff Garzik 			       u32 opts);
322438ac6d5STejun Heo #ifdef CONFIG_PM
323c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
324c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
325c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
326438ac6d5STejun Heo #endif
32718f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf);
32818f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev,
32918f7ba4cSKristen Carlson Accardi 				   enum sw_activity val);
33018f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link);
331c6fd2807SJeff Garzik 
33277cdec1aSMatthew Garrett static ssize_t ahci_show_host_caps(struct device *dev,
33377cdec1aSMatthew Garrett 				   struct device_attribute *attr, char *buf);
33477cdec1aSMatthew Garrett static ssize_t ahci_show_host_version(struct device *dev,
33577cdec1aSMatthew Garrett 				      struct device_attribute *attr, char *buf);
33677cdec1aSMatthew Garrett static ssize_t ahci_show_port_cmd(struct device *dev,
33777cdec1aSMatthew Garrett 				  struct device_attribute *attr, char *buf);
33877cdec1aSMatthew Garrett 
33977cdec1aSMatthew Garrett DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
34077cdec1aSMatthew Garrett DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
34177cdec1aSMatthew Garrett DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
34277cdec1aSMatthew Garrett 
343ee959b00STony Jones static struct device_attribute *ahci_shost_attrs[] = {
344ee959b00STony Jones 	&dev_attr_link_power_management_policy,
34518f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message_type,
34618f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message,
34777cdec1aSMatthew Garrett 	&dev_attr_ahci_host_caps,
34877cdec1aSMatthew Garrett 	&dev_attr_ahci_host_version,
34977cdec1aSMatthew Garrett 	&dev_attr_ahci_port_cmd,
35018f7ba4cSKristen Carlson Accardi 	NULL
35118f7ba4cSKristen Carlson Accardi };
35218f7ba4cSKristen Carlson Accardi 
35318f7ba4cSKristen Carlson Accardi static struct device_attribute *ahci_sdev_attrs[] = {
35418f7ba4cSKristen Carlson Accardi 	&dev_attr_sw_activity,
35545fabbb7SElias Oltmanns 	&dev_attr_unload_heads,
35631556594SKristen Carlson Accardi 	NULL
35731556594SKristen Carlson Accardi };
35831556594SKristen Carlson Accardi 
359c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
36068d1d07bSTejun Heo 	ATA_NCQ_SHT(DRV_NAME),
361c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
362c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
363c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
36431556594SKristen Carlson Accardi 	.shost_attrs		= ahci_shost_attrs,
36518f7ba4cSKristen Carlson Accardi 	.sdev_attrs		= ahci_sdev_attrs,
366c6fd2807SJeff Garzik };
367c6fd2807SJeff Garzik 
368029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = {
369029cfd6bSTejun Heo 	.inherits		= &sata_pmp_port_ops,
370029cfd6bSTejun Heo 
3717d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
372c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
373c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
3744c9bf4e7STejun Heo 	.qc_fill_rtf		= ahci_qc_fill_rtf,
375c6fd2807SJeff Garzik 
376c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
377c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
378a1efdabaSTejun Heo 	.softreset		= ahci_softreset,
379a1efdabaSTejun Heo 	.hardreset		= ahci_hardreset,
380a1efdabaSTejun Heo 	.postreset		= ahci_postreset,
381071f44b1STejun Heo 	.pmp_softreset		= ahci_softreset,
382c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
383c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
384029cfd6bSTejun Heo 	.dev_config		= ahci_dev_config,
385c6fd2807SJeff Garzik 
386029cfd6bSTejun Heo 	.scr_read		= ahci_scr_read,
387029cfd6bSTejun Heo 	.scr_write		= ahci_scr_write,
3887d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
3897d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3907d50b60bSTejun Heo 
391029cfd6bSTejun Heo 	.enable_pm		= ahci_enable_alpm,
392029cfd6bSTejun Heo 	.disable_pm		= ahci_disable_alpm,
39318f7ba4cSKristen Carlson Accardi 	.em_show		= ahci_led_show,
39418f7ba4cSKristen Carlson Accardi 	.em_store		= ahci_led_store,
39518f7ba4cSKristen Carlson Accardi 	.sw_activity_show	= ahci_activity_show,
39618f7ba4cSKristen Carlson Accardi 	.sw_activity_store	= ahci_activity_store,
397438ac6d5STejun Heo #ifdef CONFIG_PM
398c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
399c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
400438ac6d5STejun Heo #endif
401c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
402c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
403c6fd2807SJeff Garzik };
404c6fd2807SJeff Garzik 
405029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
406029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
407a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
408ad616ffbSTejun Heo };
409ad616ffbSTejun Heo 
410029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
411029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
412a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
413edc93052STejun Heo };
414edc93052STejun Heo 
415bd17243aSShane Huang static struct ata_port_operations ahci_sb600_ops = {
416bd17243aSShane Huang 	.inherits		= &ahci_ops,
417bd17243aSShane Huang 	.softreset		= ahci_sb600_softreset,
418bd17243aSShane Huang 	.pmp_softreset		= ahci_sb600_softreset,
419bd17243aSShane Huang };
420bd17243aSShane Huang 
421417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
422417a1a6dSTejun Heo 
423c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
4244da646b7SJeff Garzik 	[board_ahci] =
425c6fd2807SJeff Garzik 	{
4261188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
42714bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
428469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
429c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
430c6fd2807SJeff Garzik 	},
4314da646b7SJeff Garzik 	[board_ahci_vt8251] =
432c6fd2807SJeff Garzik 	{
4336949b914STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
434417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
43514bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
436469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
437ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
438c6fd2807SJeff Garzik 	},
4394da646b7SJeff Garzik 	[board_ahci_ign_iferr] =
44041669553STejun Heo 	{
441417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
442417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
44314bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
444469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
44541669553STejun Heo 		.port_ops	= &ahci_ops,
44641669553STejun Heo 	},
4474da646b7SJeff Garzik 	[board_ahci_sb600] =
44855a61604SConke Hu 	{
449417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
45058a09b38SShane Huang 				 AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255),
451417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
45214bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
453469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
454bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
45555a61604SConke Hu 	},
4564da646b7SJeff Garzik 	[board_ahci_mv] =
457cd70c266SJeff Garzik 	{
458417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
45917248461STejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
460cd70c266SJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
461417a1a6dSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
46214bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
463cd70c266SJeff Garzik 		.udma_mask	= ATA_UDMA6,
464cd70c266SJeff Garzik 		.port_ops	= &ahci_ops,
465cd70c266SJeff Garzik 	},
4664da646b7SJeff Garzik 	[board_ahci_sb700] =	/* for SB700 and SB800 */
467e39fc8c9SShane Huang 	{
468bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
469e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
47014bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
471e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
472bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
473e39fc8c9SShane Huang 	},
4744da646b7SJeff Garzik 	[board_ahci_mcp65] =
475e297d99eSTejun Heo 	{
476e297d99eSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
477e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
47814bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
479e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
480e297d99eSTejun Heo 		.port_ops	= &ahci_ops,
481e297d99eSTejun Heo 	},
4824da646b7SJeff Garzik 	[board_ahci_nopmp] =
4839a3b103cSTejun Heo 	{
4849a3b103cSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP),
4859a3b103cSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
48614bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
4879a3b103cSTejun Heo 		.udma_mask	= ATA_UDMA6,
4889a3b103cSTejun Heo 		.port_ops	= &ahci_ops,
4899a3b103cSTejun Heo 	},
490aa431dd3STejun Heo 	/* board_ahci_yesncq */
491aa431dd3STejun Heo 	{
492aa431dd3STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
493aa431dd3STejun Heo 		.flags		= AHCI_FLAG_COMMON,
494aa431dd3STejun Heo 		.pio_mask	= ATA_PIO4,
495aa431dd3STejun Heo 		.udma_mask	= ATA_UDMA6,
496aa431dd3STejun Heo 		.port_ops	= &ahci_ops,
497aa431dd3STejun Heo 	},
498c6fd2807SJeff Garzik };
499c6fd2807SJeff Garzik 
500c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
501c6fd2807SJeff Garzik 	/* Intel */
50254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
50354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
50454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
50554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
50654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
50782490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
50854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
50954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
51054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
51154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
5127a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
5137a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
5147a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
5157a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
5167a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
5177a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
5187a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
5197a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
5207a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
5217a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
5227a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
5237a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
5247a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
5257a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
5267a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
5277a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
5287a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
529d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
530d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
53116ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
532b2dde6afSMark Goodwin 	{ PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
53316ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
534c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
535c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
536adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
5378e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
538c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
539adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
5408e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
541c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
542c6fd2807SJeff Garzik 
543e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
544e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
545e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
546c6fd2807SJeff Garzik 
547c6fd2807SJeff Garzik 	/* ATI */
548c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
549e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
550e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
551e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
552e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
553e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
554e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
555c6fd2807SJeff Garzik 
556e2dd90b1SShane Huang 	/* AMD */
557e2dd90b1SShane Huang 	{ PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD SB900 */
558e2dd90b1SShane Huang 	/* AMD is using RAID class only for ahci controllers */
559e2dd90b1SShane Huang 	{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
560e2dd90b1SShane Huang 	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
561e2dd90b1SShane Huang 
562c6fd2807SJeff Garzik 	/* VIA */
56354bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
564bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
565c6fd2807SJeff Garzik 
566c6fd2807SJeff Garzik 	/* NVIDIA */
567e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
568e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
569e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
570e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
571e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
572e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
573e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
574e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
575aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq },	/* MCP67 */
576aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq },	/* MCP67 */
577aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq },	/* MCP67 */
578aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq },	/* MCP67 */
579aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq },	/* MCP67 */
580aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq },	/* MCP67 */
581aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq },	/* MCP67 */
582aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq },	/* MCP67 */
583aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq },	/* MCP67 */
584aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq },	/* MCP67 */
585aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq },	/* MCP67 */
586aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq },	/* MCP67 */
587aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq },	/* MCP73 */
588aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq },	/* MCP73 */
589aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq },	/* MCP73 */
590aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq },	/* MCP73 */
591aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq },	/* MCP73 */
592aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq },	/* MCP73 */
593aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq },	/* MCP73 */
594aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq },	/* MCP73 */
595aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq },	/* MCP73 */
596aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq },	/* MCP73 */
597aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq },	/* MCP73 */
598aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq },	/* MCP73 */
5990522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },		/* MCP77 */
6000522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },		/* MCP77 */
6010522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },		/* MCP77 */
6020522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },		/* MCP77 */
6030522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },		/* MCP77 */
6040522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },		/* MCP77 */
6050522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },		/* MCP77 */
6060522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },		/* MCP77 */
6070522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },		/* MCP77 */
6080522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
6090522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
6100522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
6116ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci },		/* MCP79 */
6126ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci },		/* MCP79 */
6136ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci },		/* MCP79 */
6146ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci },		/* MCP79 */
6157100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
6167100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
6177100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
6187100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
6197100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
6207100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
6217100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
6227100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
6237adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci },		/* MCP89 */
6247adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci },		/* MCP89 */
6257adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci },		/* MCP89 */
6267adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci },		/* MCP89 */
6277adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci },		/* MCP89 */
6287adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci },		/* MCP89 */
6297adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci },		/* MCP89 */
6307adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci },		/* MCP89 */
6317adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci },		/* MCP89 */
6327adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci },		/* MCP89 */
6337adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci },		/* MCP89 */
6347adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci },		/* MCP89 */
635c6fd2807SJeff Garzik 
636c6fd2807SJeff Garzik 	/* SiS */
63720e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
63820e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
63920e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
640c6fd2807SJeff Garzik 
641cd70c266SJeff Garzik 	/* Marvell */
642cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
643c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
644cd70c266SJeff Garzik 
645c77a036bSMark Nelson 	/* Promise */
646c77a036bSMark Nelson 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
647c77a036bSMark Nelson 
648415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
649415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
650c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
651415ae2b5SJeff Garzik 
652c6fd2807SJeff Garzik 	{ }	/* terminate list */
653c6fd2807SJeff Garzik };
654c6fd2807SJeff Garzik 
655c6fd2807SJeff Garzik 
656c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
657c6fd2807SJeff Garzik 	.name			= DRV_NAME,
658c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
659c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
66024dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
661438ac6d5STejun Heo #ifdef CONFIG_PM
662c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
663c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
664438ac6d5STejun Heo #endif
665c6fd2807SJeff Garzik };
666c6fd2807SJeff Garzik 
66718f7ba4cSKristen Carlson Accardi static int ahci_em_messages = 1;
66818f7ba4cSKristen Carlson Accardi module_param(ahci_em_messages, int, 0444);
66918f7ba4cSKristen Carlson Accardi /* add other LED protocol types when they become supported */
67018f7ba4cSKristen Carlson Accardi MODULE_PARM_DESC(ahci_em_messages,
67118f7ba4cSKristen Carlson Accardi 	"Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
672c6fd2807SJeff Garzik 
6735b66c829SAlan Cox #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
6745b66c829SAlan Cox static int marvell_enable;
6755b66c829SAlan Cox #else
6765b66c829SAlan Cox static int marvell_enable = 1;
6775b66c829SAlan Cox #endif
6785b66c829SAlan Cox module_param(marvell_enable, int, 0644);
6795b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
6805b66c829SAlan Cox 
6815b66c829SAlan Cox 
68298fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
68398fa4b60STejun Heo {
68498fa4b60STejun Heo 	return (cap & 0x1f) + 1;
68598fa4b60STejun Heo }
68698fa4b60STejun Heo 
687dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host,
688dab632e8SJeff Garzik 					     unsigned int port_no)
689dab632e8SJeff Garzik {
690dab632e8SJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
691dab632e8SJeff Garzik 
692dab632e8SJeff Garzik 	return mmio + 0x100 + (port_no * 0x80);
693dab632e8SJeff Garzik }
694dab632e8SJeff Garzik 
6954447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
696c6fd2807SJeff Garzik {
697dab632e8SJeff Garzik 	return __ahci_port_base(ap->host, ap->port_no);
698c6fd2807SJeff Garzik }
699c6fd2807SJeff Garzik 
700b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio)
701b710a1f4STejun Heo {
70215fe982eSTejun Heo 	int i;
703b710a1f4STejun Heo 	u32 tmp;
704b710a1f4STejun Heo 
705b710a1f4STejun Heo 	/* turn on AHCI_EN */
706b710a1f4STejun Heo 	tmp = readl(mmio + HOST_CTL);
70715fe982eSTejun Heo 	if (tmp & HOST_AHCI_EN)
70815fe982eSTejun Heo 		return;
70915fe982eSTejun Heo 
71015fe982eSTejun Heo 	/* Some controllers need AHCI_EN to be written multiple times.
71115fe982eSTejun Heo 	 * Try a few times before giving up.
71215fe982eSTejun Heo 	 */
71315fe982eSTejun Heo 	for (i = 0; i < 5; i++) {
714b710a1f4STejun Heo 		tmp |= HOST_AHCI_EN;
715b710a1f4STejun Heo 		writel(tmp, mmio + HOST_CTL);
716b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
71715fe982eSTejun Heo 		if (tmp & HOST_AHCI_EN)
71815fe982eSTejun Heo 			return;
71915fe982eSTejun Heo 		msleep(10);
720b710a1f4STejun Heo 	}
72115fe982eSTejun Heo 
72215fe982eSTejun Heo 	WARN_ON(1);
723b710a1f4STejun Heo }
724b710a1f4STejun Heo 
72577cdec1aSMatthew Garrett static ssize_t ahci_show_host_caps(struct device *dev,
72677cdec1aSMatthew Garrett 				   struct device_attribute *attr, char *buf)
72777cdec1aSMatthew Garrett {
72877cdec1aSMatthew Garrett 	struct Scsi_Host *shost = class_to_shost(dev);
72977cdec1aSMatthew Garrett 	struct ata_port *ap = ata_shost_to_port(shost);
73077cdec1aSMatthew Garrett 	struct ahci_host_priv *hpriv = ap->host->private_data;
73177cdec1aSMatthew Garrett 
73277cdec1aSMatthew Garrett 	return sprintf(buf, "%x\n", hpriv->cap);
73377cdec1aSMatthew Garrett }
73477cdec1aSMatthew Garrett 
73577cdec1aSMatthew Garrett static ssize_t ahci_show_host_version(struct device *dev,
73677cdec1aSMatthew Garrett 				   struct device_attribute *attr, char *buf)
73777cdec1aSMatthew Garrett {
73877cdec1aSMatthew Garrett 	struct Scsi_Host *shost = class_to_shost(dev);
73977cdec1aSMatthew Garrett 	struct ata_port *ap = ata_shost_to_port(shost);
74077cdec1aSMatthew Garrett 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
74177cdec1aSMatthew Garrett 
74277cdec1aSMatthew Garrett 	return sprintf(buf, "%x\n", readl(mmio + HOST_VERSION));
74377cdec1aSMatthew Garrett }
74477cdec1aSMatthew Garrett 
74577cdec1aSMatthew Garrett static ssize_t ahci_show_port_cmd(struct device *dev,
74677cdec1aSMatthew Garrett 				  struct device_attribute *attr, char *buf)
74777cdec1aSMatthew Garrett {
74877cdec1aSMatthew Garrett 	struct Scsi_Host *shost = class_to_shost(dev);
74977cdec1aSMatthew Garrett 	struct ata_port *ap = ata_shost_to_port(shost);
75077cdec1aSMatthew Garrett 	void __iomem *port_mmio = ahci_port_base(ap);
75177cdec1aSMatthew Garrett 
75277cdec1aSMatthew Garrett 	return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD));
75377cdec1aSMatthew Garrett }
75477cdec1aSMatthew Garrett 
755d447df14STejun Heo /**
756d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
7574447d351STejun Heo  *	@pdev: target PCI device
7584447d351STejun Heo  *	@hpriv: host private area to store config values
759d447df14STejun Heo  *
760d447df14STejun Heo  *	Some registers containing configuration info might be setup by
761d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
762d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
763d447df14STejun Heo  *	can be restored after controller reset.
764d447df14STejun Heo  *
765d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
766d447df14STejun Heo  *
767d447df14STejun Heo  *	LOCKING:
768d447df14STejun Heo  *	None.
769d447df14STejun Heo  */
7704447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
7714447d351STejun Heo 				     struct ahci_host_priv *hpriv)
772d447df14STejun Heo {
7734447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
774d447df14STejun Heo 	u32 cap, port_map;
77517199b18STejun Heo 	int i;
776c40e7cb8SJose Alberto Reguero 	int mv;
777d447df14STejun Heo 
778b710a1f4STejun Heo 	/* make sure AHCI mode is enabled before accessing CAP */
779b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
780b710a1f4STejun Heo 
781d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
782d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
783d447df14STejun Heo 	 */
784d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
785d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
786d447df14STejun Heo 
787274c1fdeSTejun Heo 	/* some chips have errata preventing 64bit use */
788417a1a6dSTejun Heo 	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
789c7a42156STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
790c7a42156STejun Heo 			   "controller can't do 64bit DMA, forcing 32bit\n");
791c7a42156STejun Heo 		cap &= ~HOST_CAP_64;
792c7a42156STejun Heo 	}
793c7a42156STejun Heo 
794417a1a6dSTejun Heo 	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
795274c1fdeSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
796274c1fdeSTejun Heo 			   "controller can't do NCQ, turning off CAP_NCQ\n");
797274c1fdeSTejun Heo 		cap &= ~HOST_CAP_NCQ;
798274c1fdeSTejun Heo 	}
799274c1fdeSTejun Heo 
800e297d99eSTejun Heo 	if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
801e297d99eSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
802e297d99eSTejun Heo 			   "controller can do NCQ, turning on CAP_NCQ\n");
803e297d99eSTejun Heo 		cap |= HOST_CAP_NCQ;
804e297d99eSTejun Heo 	}
805e297d99eSTejun Heo 
806258cd846SRoel Kluin 	if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
8076949b914STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
8086949b914STejun Heo 			   "controller can't do PMP, turning off CAP_PMP\n");
8096949b914STejun Heo 		cap &= ~HOST_CAP_PMP;
8106949b914STejun Heo 	}
8116949b914STejun Heo 
812d799e083STejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
813d799e083STejun Heo 	    port_map != 1) {
814d799e083STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
815d799e083STejun Heo 			   "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
816d799e083STejun Heo 			   port_map, 1);
817d799e083STejun Heo 		port_map = 1;
818d799e083STejun Heo 	}
819d799e083STejun Heo 
820cd70c266SJeff Garzik 	/*
821cd70c266SJeff Garzik 	 * Temporary Marvell 6145 hack: PATA port presence
822cd70c266SJeff Garzik 	 * is asserted through the standard AHCI port
823cd70c266SJeff Garzik 	 * presence register, as bit 4 (counting from 0)
824cd70c266SJeff Garzik 	 */
825417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
826c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
827c40e7cb8SJose Alberto Reguero 			mv = 0x3;
828c40e7cb8SJose Alberto Reguero 		else
829c40e7cb8SJose Alberto Reguero 			mv = 0xf;
830cd70c266SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
831cd70c266SJeff Garzik 			   "MV_AHCI HACK: port_map %x -> %x\n",
832c40e7cb8SJose Alberto Reguero 			   port_map,
833c40e7cb8SJose Alberto Reguero 			   port_map & mv);
8345b66c829SAlan Cox 		dev_printk(KERN_ERR, &pdev->dev,
8355b66c829SAlan Cox 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
836cd70c266SJeff Garzik 
837c40e7cb8SJose Alberto Reguero 		port_map &= mv;
838cd70c266SJeff Garzik 	}
839cd70c266SJeff Garzik 
84017199b18STejun Heo 	/* cross check port_map and cap.n_ports */
8417a234affSTejun Heo 	if (port_map) {
842837f5f8fSTejun Heo 		int map_ports = 0;
84317199b18STejun Heo 
844837f5f8fSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS; i++)
845837f5f8fSTejun Heo 			if (port_map & (1 << i))
846837f5f8fSTejun Heo 				map_ports++;
84717199b18STejun Heo 
848837f5f8fSTejun Heo 		/* If PI has more ports than n_ports, whine, clear
849837f5f8fSTejun Heo 		 * port_map and let it be generated from n_ports.
85017199b18STejun Heo 		 */
851837f5f8fSTejun Heo 		if (map_ports > ahci_nr_ports(cap)) {
8524447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
853837f5f8fSTejun Heo 				   "implemented port map (0x%x) contains more "
854837f5f8fSTejun Heo 				   "ports than nr_ports (%u), using nr_ports\n",
855837f5f8fSTejun Heo 				   port_map, ahci_nr_ports(cap));
8567a234affSTejun Heo 			port_map = 0;
8577a234affSTejun Heo 		}
8587a234affSTejun Heo 	}
8597a234affSTejun Heo 
86017199b18STejun Heo 	/* fabricate port_map from cap.nr_ports */
8617a234affSTejun Heo 	if (!port_map) {
86217199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
8637a234affSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
8647a234affSTejun Heo 			   "forcing PORTS_IMPL to 0x%x\n", port_map);
8657a234affSTejun Heo 
8667a234affSTejun Heo 		/* write the fixed up value to the PI register */
8677a234affSTejun Heo 		hpriv->saved_port_map = port_map;
86817199b18STejun Heo 	}
86917199b18STejun Heo 
870d447df14STejun Heo 	/* record values to use during operation */
871d447df14STejun Heo 	hpriv->cap = cap;
872d447df14STejun Heo 	hpriv->port_map = port_map;
873d447df14STejun Heo }
874d447df14STejun Heo 
875d447df14STejun Heo /**
876d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
8774447d351STejun Heo  *	@host: target ATA host
878d447df14STejun Heo  *
879d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
880d447df14STejun Heo  *
881d447df14STejun Heo  *	LOCKING:
882d447df14STejun Heo  *	None.
883d447df14STejun Heo  */
8844447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
885d447df14STejun Heo {
8864447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
8874447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
8884447d351STejun Heo 
889d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
890d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
891d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
892d447df14STejun Heo }
893d447df14STejun Heo 
894203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
895c6fd2807SJeff Garzik {
896203ef6c4STejun Heo 	static const int offset[] = {
897203ef6c4STejun Heo 		[SCR_STATUS]		= PORT_SCR_STAT,
898203ef6c4STejun Heo 		[SCR_CONTROL]		= PORT_SCR_CTL,
899203ef6c4STejun Heo 		[SCR_ERROR]		= PORT_SCR_ERR,
900203ef6c4STejun Heo 		[SCR_ACTIVE]		= PORT_SCR_ACT,
901203ef6c4STejun Heo 		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
902203ef6c4STejun Heo 	};
903203ef6c4STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
904c6fd2807SJeff Garzik 
905203ef6c4STejun Heo 	if (sc_reg < ARRAY_SIZE(offset) &&
906203ef6c4STejun Heo 	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
907203ef6c4STejun Heo 		return offset[sc_reg];
908da3dbb17STejun Heo 	return 0;
909c6fd2807SJeff Garzik }
910c6fd2807SJeff Garzik 
91182ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
912c6fd2807SJeff Garzik {
91382ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
91482ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
915c6fd2807SJeff Garzik 
916203ef6c4STejun Heo 	if (offset) {
917203ef6c4STejun Heo 		*val = readl(port_mmio + offset);
918203ef6c4STejun Heo 		return 0;
919203ef6c4STejun Heo 	}
920da3dbb17STejun Heo 	return -EINVAL;
921c6fd2807SJeff Garzik }
922c6fd2807SJeff Garzik 
92382ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
924203ef6c4STejun Heo {
92582ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
92682ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
927203ef6c4STejun Heo 
928203ef6c4STejun Heo 	if (offset) {
929203ef6c4STejun Heo 		writel(val, port_mmio + offset);
930da3dbb17STejun Heo 		return 0;
931c6fd2807SJeff Garzik 	}
932203ef6c4STejun Heo 	return -EINVAL;
933203ef6c4STejun Heo }
934c6fd2807SJeff Garzik 
9354447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
936c6fd2807SJeff Garzik {
9374447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
938c6fd2807SJeff Garzik 	u32 tmp;
939c6fd2807SJeff Garzik 
940c6fd2807SJeff Garzik 	/* start DMA */
941c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
942c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
943c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
944c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
945c6fd2807SJeff Garzik }
946c6fd2807SJeff Garzik 
9474447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
948c6fd2807SJeff Garzik {
9494447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
950c6fd2807SJeff Garzik 	u32 tmp;
951c6fd2807SJeff Garzik 
952c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
953c6fd2807SJeff Garzik 
954c6fd2807SJeff Garzik 	/* check if the HBA is idle */
955c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
956c6fd2807SJeff Garzik 		return 0;
957c6fd2807SJeff Garzik 
958c6fd2807SJeff Garzik 	/* setting HBA to idle */
959c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
960c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
961c6fd2807SJeff Garzik 
962c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
963c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
964c6fd2807SJeff Garzik 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
965c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
966c6fd2807SJeff Garzik 		return -EIO;
967c6fd2807SJeff Garzik 
968c6fd2807SJeff Garzik 	return 0;
969c6fd2807SJeff Garzik }
970c6fd2807SJeff Garzik 
9714447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
972c6fd2807SJeff Garzik {
9734447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
9744447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
9754447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
976c6fd2807SJeff Garzik 	u32 tmp;
977c6fd2807SJeff Garzik 
978c6fd2807SJeff Garzik 	/* set FIS registers */
9794447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
9804447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
9814447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
9824447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
983c6fd2807SJeff Garzik 
9844447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
9854447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
9864447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
9874447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
988c6fd2807SJeff Garzik 
989c6fd2807SJeff Garzik 	/* enable FIS reception */
990c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
991c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
992c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
993c6fd2807SJeff Garzik 
994c6fd2807SJeff Garzik 	/* flush */
995c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
996c6fd2807SJeff Garzik }
997c6fd2807SJeff Garzik 
9984447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
999c6fd2807SJeff Garzik {
10004447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1001c6fd2807SJeff Garzik 	u32 tmp;
1002c6fd2807SJeff Garzik 
1003c6fd2807SJeff Garzik 	/* disable FIS reception */
1004c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1005c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
1006c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1007c6fd2807SJeff Garzik 
1008c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
1009c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
1010c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
1011c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
1012c6fd2807SJeff Garzik 		return -EBUSY;
1013c6fd2807SJeff Garzik 
1014c6fd2807SJeff Garzik 	return 0;
1015c6fd2807SJeff Garzik }
1016c6fd2807SJeff Garzik 
10174447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
1018c6fd2807SJeff Garzik {
10194447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
10204447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1021c6fd2807SJeff Garzik 	u32 cmd;
1022c6fd2807SJeff Garzik 
1023c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1024c6fd2807SJeff Garzik 
1025c6fd2807SJeff Garzik 	/* spin up device */
10264447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
1027c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
1028c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
1029c6fd2807SJeff Garzik 	}
1030c6fd2807SJeff Garzik 
1031c6fd2807SJeff Garzik 	/* wake up link */
1032c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
1033c6fd2807SJeff Garzik }
1034c6fd2807SJeff Garzik 
103531556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap)
103631556594SKristen Carlson Accardi {
103731556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
103831556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
103931556594SKristen Carlson Accardi 	u32 cmd;
104031556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
104131556594SKristen Carlson Accardi 
104231556594SKristen Carlson Accardi 	/* IPM bits should be disabled by libata-core */
104331556594SKristen Carlson Accardi 	/* get the existing command bits */
104431556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
104531556594SKristen Carlson Accardi 
104631556594SKristen Carlson Accardi 	/* disable ALPM and ASP */
104731556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ASP;
104831556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ALPE;
104931556594SKristen Carlson Accardi 
105031556594SKristen Carlson Accardi 	/* force the interface back to active */
105131556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ICC_ACTIVE;
105231556594SKristen Carlson Accardi 
105331556594SKristen Carlson Accardi 	/* write out new cmd value */
105431556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
105531556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
105631556594SKristen Carlson Accardi 
105731556594SKristen Carlson Accardi 	/* wait 10ms to be sure we've come out of any low power state */
105831556594SKristen Carlson Accardi 	msleep(10);
105931556594SKristen Carlson Accardi 
106031556594SKristen Carlson Accardi 	/* clear out any PhyRdy stuff from interrupt status */
106131556594SKristen Carlson Accardi 	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
106231556594SKristen Carlson Accardi 
106331556594SKristen Carlson Accardi 	/* go ahead and clean out PhyRdy Change from Serror too */
106482ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
106531556594SKristen Carlson Accardi 
106631556594SKristen Carlson Accardi 	/*
106731556594SKristen Carlson Accardi  	 * Clear flag to indicate that we should ignore all PhyRdy
106831556594SKristen Carlson Accardi  	 * state changes
106931556594SKristen Carlson Accardi  	 */
107031556594SKristen Carlson Accardi 	hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
107131556594SKristen Carlson Accardi 
107231556594SKristen Carlson Accardi 	/*
107331556594SKristen Carlson Accardi  	 * Enable interrupts on Phy Ready.
107431556594SKristen Carlson Accardi  	 */
107531556594SKristen Carlson Accardi 	pp->intr_mask |= PORT_IRQ_PHYRDY;
107631556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
107731556594SKristen Carlson Accardi 
107831556594SKristen Carlson Accardi 	/*
107931556594SKristen Carlson Accardi  	 * don't change the link pm policy - we can be called
108031556594SKristen Carlson Accardi  	 * just to turn of link pm temporarily
108131556594SKristen Carlson Accardi  	 */
108231556594SKristen Carlson Accardi }
108331556594SKristen Carlson Accardi 
108431556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
108531556594SKristen Carlson Accardi 	enum link_pm policy)
108631556594SKristen Carlson Accardi {
108731556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
108831556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
108931556594SKristen Carlson Accardi 	u32 cmd;
109031556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
109131556594SKristen Carlson Accardi 	u32 asp;
109231556594SKristen Carlson Accardi 
109331556594SKristen Carlson Accardi 	/* Make sure the host is capable of link power management */
109431556594SKristen Carlson Accardi 	if (!(hpriv->cap & HOST_CAP_ALPM))
109531556594SKristen Carlson Accardi 		return -EINVAL;
109631556594SKristen Carlson Accardi 
109731556594SKristen Carlson Accardi 	switch (policy) {
109831556594SKristen Carlson Accardi 	case MAX_PERFORMANCE:
109931556594SKristen Carlson Accardi 	case NOT_AVAILABLE:
110031556594SKristen Carlson Accardi 		/*
110131556594SKristen Carlson Accardi  		 * if we came here with NOT_AVAILABLE,
110231556594SKristen Carlson Accardi  		 * it just means this is the first time we
110331556594SKristen Carlson Accardi  		 * have tried to enable - default to max performance,
110431556594SKristen Carlson Accardi  		 * and let the user go to lower power modes on request.
110531556594SKristen Carlson Accardi  		 */
110631556594SKristen Carlson Accardi 		ahci_disable_alpm(ap);
110731556594SKristen Carlson Accardi 		return 0;
110831556594SKristen Carlson Accardi 	case MIN_POWER:
110931556594SKristen Carlson Accardi 		/* configure HBA to enter SLUMBER */
111031556594SKristen Carlson Accardi 		asp = PORT_CMD_ASP;
111131556594SKristen Carlson Accardi 		break;
111231556594SKristen Carlson Accardi 	case MEDIUM_POWER:
111331556594SKristen Carlson Accardi 		/* configure HBA to enter PARTIAL */
111431556594SKristen Carlson Accardi 		asp = 0;
111531556594SKristen Carlson Accardi 		break;
111631556594SKristen Carlson Accardi 	default:
111731556594SKristen Carlson Accardi 		return -EINVAL;
111831556594SKristen Carlson Accardi 	}
111931556594SKristen Carlson Accardi 
112031556594SKristen Carlson Accardi 	/*
112131556594SKristen Carlson Accardi  	 * Disable interrupts on Phy Ready. This keeps us from
112231556594SKristen Carlson Accardi  	 * getting woken up due to spurious phy ready interrupts
112331556594SKristen Carlson Accardi 	 * TBD - Hot plug should be done via polling now, is
112431556594SKristen Carlson Accardi 	 * that even supported?
112531556594SKristen Carlson Accardi  	 */
112631556594SKristen Carlson Accardi 	pp->intr_mask &= ~PORT_IRQ_PHYRDY;
112731556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
112831556594SKristen Carlson Accardi 
112931556594SKristen Carlson Accardi 	/*
113031556594SKristen Carlson Accardi  	 * Set a flag to indicate that we should ignore all PhyRdy
113131556594SKristen Carlson Accardi  	 * state changes since these can happen now whenever we
113231556594SKristen Carlson Accardi  	 * change link state
113331556594SKristen Carlson Accardi  	 */
113431556594SKristen Carlson Accardi 	hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
113531556594SKristen Carlson Accardi 
113631556594SKristen Carlson Accardi 	/* get the existing command bits */
113731556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
113831556594SKristen Carlson Accardi 
113931556594SKristen Carlson Accardi 	/*
114031556594SKristen Carlson Accardi  	 * Set ASP based on Policy
114131556594SKristen Carlson Accardi  	 */
114231556594SKristen Carlson Accardi 	cmd |= asp;
114331556594SKristen Carlson Accardi 
114431556594SKristen Carlson Accardi 	/*
114531556594SKristen Carlson Accardi  	 * Setting this bit will instruct the HBA to aggressively
114631556594SKristen Carlson Accardi  	 * enter a lower power link state when it's appropriate and
114731556594SKristen Carlson Accardi  	 * based on the value set above for ASP
114831556594SKristen Carlson Accardi  	 */
114931556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ALPE;
115031556594SKristen Carlson Accardi 
115131556594SKristen Carlson Accardi 	/* write out new cmd value */
115231556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
115331556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
115431556594SKristen Carlson Accardi 
115531556594SKristen Carlson Accardi 	/* IPM bits should be set by libata-core */
115631556594SKristen Carlson Accardi 	return 0;
115731556594SKristen Carlson Accardi }
115831556594SKristen Carlson Accardi 
1159438ac6d5STejun Heo #ifdef CONFIG_PM
11604447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
1161c6fd2807SJeff Garzik {
11624447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
11634447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1164c6fd2807SJeff Garzik 	u32 cmd, scontrol;
1165c6fd2807SJeff Garzik 
11664447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
116707c53dacSTejun Heo 		return;
1168c6fd2807SJeff Garzik 
116907c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
1170c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
1171c6fd2807SJeff Garzik 	scontrol &= ~0xf;
1172c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
1173c6fd2807SJeff Garzik 
1174c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
117507c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1176c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
1177c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
1178c6fd2807SJeff Garzik }
1179438ac6d5STejun Heo #endif
1180c6fd2807SJeff Garzik 
1181df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap)
1182c6fd2807SJeff Garzik {
118318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
118418f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
118518f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
11864c1e9aa4SDavid Milburn 	ssize_t rc;
11874c1e9aa4SDavid Milburn 	int i;
118818f7ba4cSKristen Carlson Accardi 
1189c6fd2807SJeff Garzik 	/* enable FIS reception */
11904447d351STejun Heo 	ahci_start_fis_rx(ap);
1191c6fd2807SJeff Garzik 
1192c6fd2807SJeff Garzik 	/* enable DMA */
11934447d351STejun Heo 	ahci_start_engine(ap);
119418f7ba4cSKristen Carlson Accardi 
119518f7ba4cSKristen Carlson Accardi 	/* turn on LEDs */
119618f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_EM) {
11971eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE) {
119818f7ba4cSKristen Carlson Accardi 			emp = &pp->em_priv[link->pmp];
11994c1e9aa4SDavid Milburn 
12004c1e9aa4SDavid Milburn 			/* EM Transmit bit maybe busy during init */
1201d50ce07dSTejun Heo 			for (i = 0; i < EM_MAX_RETRY; i++) {
12024c1e9aa4SDavid Milburn 				rc = ahci_transmit_led_message(ap,
12034c1e9aa4SDavid Milburn 							       emp->led_state,
12044c1e9aa4SDavid Milburn 							       4);
12054c1e9aa4SDavid Milburn 				if (rc == -EBUSY)
1206d50ce07dSTejun Heo 					msleep(1);
12074c1e9aa4SDavid Milburn 				else
12084c1e9aa4SDavid Milburn 					break;
12094c1e9aa4SDavid Milburn 			}
121018f7ba4cSKristen Carlson Accardi 		}
121118f7ba4cSKristen Carlson Accardi 	}
121218f7ba4cSKristen Carlson Accardi 
121318f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_SW_ACTIVITY)
12141eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE)
121518f7ba4cSKristen Carlson Accardi 			ahci_init_sw_activity(link);
121618f7ba4cSKristen Carlson Accardi 
1217c6fd2807SJeff Garzik }
1218c6fd2807SJeff Garzik 
12194447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
1220c6fd2807SJeff Garzik {
1221c6fd2807SJeff Garzik 	int rc;
1222c6fd2807SJeff Garzik 
1223c6fd2807SJeff Garzik 	/* disable DMA */
12244447d351STejun Heo 	rc = ahci_stop_engine(ap);
1225c6fd2807SJeff Garzik 	if (rc) {
1226c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
1227c6fd2807SJeff Garzik 		return rc;
1228c6fd2807SJeff Garzik 	}
1229c6fd2807SJeff Garzik 
1230c6fd2807SJeff Garzik 	/* disable FIS reception */
12314447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
1232c6fd2807SJeff Garzik 	if (rc) {
1233c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
1234c6fd2807SJeff Garzik 		return rc;
1235c6fd2807SJeff Garzik 	}
1236c6fd2807SJeff Garzik 
1237c6fd2807SJeff Garzik 	return 0;
1238c6fd2807SJeff Garzik }
1239c6fd2807SJeff Garzik 
12404447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
1241c6fd2807SJeff Garzik {
12424447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
124349f29090STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
12444447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1245d447df14STejun Heo 	u32 tmp;
1246c6fd2807SJeff Garzik 
12473cc3eb11SJeff Garzik 	/* we must be in AHCI mode, before using anything
12483cc3eb11SJeff Garzik 	 * AHCI-specific, such as HOST_RESET.
12493cc3eb11SJeff Garzik 	 */
1250b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
12513cc3eb11SJeff Garzik 
12523cc3eb11SJeff Garzik 	/* global controller reset */
1253a22e6444STejun Heo 	if (!ahci_skip_host_reset) {
1254b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);
1255c6fd2807SJeff Garzik 		if ((tmp & HOST_RESET) == 0) {
1256c6fd2807SJeff Garzik 			writel(tmp | HOST_RESET, mmio + HOST_CTL);
1257c6fd2807SJeff Garzik 			readl(mmio + HOST_CTL); /* flush */
1258c6fd2807SJeff Garzik 		}
1259c6fd2807SJeff Garzik 
126024920c8aSZhang Rui 		/*
126124920c8aSZhang Rui 		 * to perform host reset, OS should set HOST_RESET
126224920c8aSZhang Rui 		 * and poll until this bit is read to be "0".
126324920c8aSZhang Rui 		 * reset must complete within 1 second, or
1264c6fd2807SJeff Garzik 		 * the hardware should be considered fried.
1265c6fd2807SJeff Garzik 		 */
126624920c8aSZhang Rui 		tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
126724920c8aSZhang Rui 					HOST_RESET, 10, 1000);
1268c6fd2807SJeff Garzik 
1269c6fd2807SJeff Garzik 		if (tmp & HOST_RESET) {
12704447d351STejun Heo 			dev_printk(KERN_ERR, host->dev,
1271c6fd2807SJeff Garzik 				   "controller reset failed (0x%x)\n", tmp);
1272c6fd2807SJeff Garzik 			return -EIO;
1273c6fd2807SJeff Garzik 		}
1274c6fd2807SJeff Garzik 
127598fa4b60STejun Heo 		/* turn on AHCI mode */
1276b710a1f4STejun Heo 		ahci_enable_ahci(mmio);
127798fa4b60STejun Heo 
1278a22e6444STejun Heo 		/* Some registers might be cleared on reset.  Restore
1279a22e6444STejun Heo 		 * initial values.
1280a22e6444STejun Heo 		 */
12814447d351STejun Heo 		ahci_restore_initial_config(host);
1282a22e6444STejun Heo 	} else
1283a22e6444STejun Heo 		dev_printk(KERN_INFO, host->dev,
1284a22e6444STejun Heo 			   "skipping global host reset\n");
1285c6fd2807SJeff Garzik 
1286c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
1287c6fd2807SJeff Garzik 		u16 tmp16;
1288c6fd2807SJeff Garzik 
1289c6fd2807SJeff Garzik 		/* configure PCS */
1290c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
129149f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
129249f29090STejun Heo 			tmp16 |= hpriv->port_map;
1293c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
1294c6fd2807SJeff Garzik 		}
129549f29090STejun Heo 	}
1296c6fd2807SJeff Garzik 
1297c6fd2807SJeff Garzik 	return 0;
1298c6fd2807SJeff Garzik }
1299c6fd2807SJeff Garzik 
130018f7ba4cSKristen Carlson Accardi static void ahci_sw_activity(struct ata_link *link)
130118f7ba4cSKristen Carlson Accardi {
130218f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
130318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
130418f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
130518f7ba4cSKristen Carlson Accardi 
130618f7ba4cSKristen Carlson Accardi 	if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
130718f7ba4cSKristen Carlson Accardi 		return;
130818f7ba4cSKristen Carlson Accardi 
130918f7ba4cSKristen Carlson Accardi 	emp->activity++;
131018f7ba4cSKristen Carlson Accardi 	if (!timer_pending(&emp->timer))
131118f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
131218f7ba4cSKristen Carlson Accardi }
131318f7ba4cSKristen Carlson Accardi 
131418f7ba4cSKristen Carlson Accardi static void ahci_sw_activity_blink(unsigned long arg)
131518f7ba4cSKristen Carlson Accardi {
131618f7ba4cSKristen Carlson Accardi 	struct ata_link *link = (struct ata_link *)arg;
131718f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
131818f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
131918f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
132018f7ba4cSKristen Carlson Accardi 	unsigned long led_message = emp->led_state;
132118f7ba4cSKristen Carlson Accardi 	u32 activity_led_state;
1322eb40963cSDavid Milburn 	unsigned long flags;
132318f7ba4cSKristen Carlson Accardi 
132487943acfSDavid Milburn 	led_message &= EM_MSG_LED_VALUE;
132518f7ba4cSKristen Carlson Accardi 	led_message |= ap->port_no | (link->pmp << 8);
132618f7ba4cSKristen Carlson Accardi 
132718f7ba4cSKristen Carlson Accardi 	/* check to see if we've had activity.  If so,
132818f7ba4cSKristen Carlson Accardi 	 * toggle state of LED and reset timer.  If not,
132918f7ba4cSKristen Carlson Accardi 	 * turn LED to desired idle state.
133018f7ba4cSKristen Carlson Accardi 	 */
1331eb40963cSDavid Milburn 	spin_lock_irqsave(ap->lock, flags);
133218f7ba4cSKristen Carlson Accardi 	if (emp->saved_activity != emp->activity) {
133318f7ba4cSKristen Carlson Accardi 		emp->saved_activity = emp->activity;
133418f7ba4cSKristen Carlson Accardi 		/* get the current LED state */
133587943acfSDavid Milburn 		activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
133618f7ba4cSKristen Carlson Accardi 
133718f7ba4cSKristen Carlson Accardi 		if (activity_led_state)
133818f7ba4cSKristen Carlson Accardi 			activity_led_state = 0;
133918f7ba4cSKristen Carlson Accardi 		else
134018f7ba4cSKristen Carlson Accardi 			activity_led_state = 1;
134118f7ba4cSKristen Carlson Accardi 
134218f7ba4cSKristen Carlson Accardi 		/* clear old state */
134387943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
134418f7ba4cSKristen Carlson Accardi 
134518f7ba4cSKristen Carlson Accardi 		/* toggle state */
134618f7ba4cSKristen Carlson Accardi 		led_message |= (activity_led_state << 16);
134718f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
134818f7ba4cSKristen Carlson Accardi 	} else {
134918f7ba4cSKristen Carlson Accardi 		/* switch to idle */
135087943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
135118f7ba4cSKristen Carlson Accardi 		if (emp->blink_policy == BLINK_OFF)
135218f7ba4cSKristen Carlson Accardi 			led_message |= (1 << 16);
135318f7ba4cSKristen Carlson Accardi 	}
1354eb40963cSDavid Milburn 	spin_unlock_irqrestore(ap->lock, flags);
135518f7ba4cSKristen Carlson Accardi 	ahci_transmit_led_message(ap, led_message, 4);
135618f7ba4cSKristen Carlson Accardi }
135718f7ba4cSKristen Carlson Accardi 
135818f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link)
135918f7ba4cSKristen Carlson Accardi {
136018f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
136118f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
136218f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
136318f7ba4cSKristen Carlson Accardi 
136418f7ba4cSKristen Carlson Accardi 	/* init activity stats, setup timer */
136518f7ba4cSKristen Carlson Accardi 	emp->saved_activity = emp->activity = 0;
136618f7ba4cSKristen Carlson Accardi 	setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
136718f7ba4cSKristen Carlson Accardi 
136818f7ba4cSKristen Carlson Accardi 	/* check our blink policy and set flag for link if it's enabled */
136918f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
137018f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
137118f7ba4cSKristen Carlson Accardi }
137218f7ba4cSKristen Carlson Accardi 
137318f7ba4cSKristen Carlson Accardi static int ahci_reset_em(struct ata_host *host)
137418f7ba4cSKristen Carlson Accardi {
137518f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
137618f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
137718f7ba4cSKristen Carlson Accardi 
137818f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
137918f7ba4cSKristen Carlson Accardi 	if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
138018f7ba4cSKristen Carlson Accardi 		return -EINVAL;
138118f7ba4cSKristen Carlson Accardi 
138218f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
138318f7ba4cSKristen Carlson Accardi 	return 0;
138418f7ba4cSKristen Carlson Accardi }
138518f7ba4cSKristen Carlson Accardi 
138618f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
138718f7ba4cSKristen Carlson Accardi 					ssize_t size)
138818f7ba4cSKristen Carlson Accardi {
138918f7ba4cSKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
139018f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
139118f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
139218f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
139318f7ba4cSKristen Carlson Accardi 	u32 message[] = {0, 0};
139493082f0bSLinus Torvalds 	unsigned long flags;
139518f7ba4cSKristen Carlson Accardi 	int pmp;
139618f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
139718f7ba4cSKristen Carlson Accardi 
139818f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
139987943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
1400d50ce07dSTejun Heo 	if (pmp < EM_MAX_SLOTS)
140118f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
140218f7ba4cSKristen Carlson Accardi 	else
140318f7ba4cSKristen Carlson Accardi 		return -EINVAL;
140418f7ba4cSKristen Carlson Accardi 
140518f7ba4cSKristen Carlson Accardi 	spin_lock_irqsave(ap->lock, flags);
140618f7ba4cSKristen Carlson Accardi 
140718f7ba4cSKristen Carlson Accardi 	/*
140818f7ba4cSKristen Carlson Accardi 	 * if we are still busy transmitting a previous message,
140918f7ba4cSKristen Carlson Accardi 	 * do not allow
141018f7ba4cSKristen Carlson Accardi 	 */
141118f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
141218f7ba4cSKristen Carlson Accardi 	if (em_ctl & EM_CTL_TM) {
141318f7ba4cSKristen Carlson Accardi 		spin_unlock_irqrestore(ap->lock, flags);
14144c1e9aa4SDavid Milburn 		return -EBUSY;
141518f7ba4cSKristen Carlson Accardi 	}
141618f7ba4cSKristen Carlson Accardi 
141718f7ba4cSKristen Carlson Accardi 	/*
141818f7ba4cSKristen Carlson Accardi 	 * create message header - this is all zero except for
141918f7ba4cSKristen Carlson Accardi 	 * the message size, which is 4 bytes.
142018f7ba4cSKristen Carlson Accardi 	 */
142118f7ba4cSKristen Carlson Accardi 	message[0] |= (4 << 8);
142218f7ba4cSKristen Carlson Accardi 
142318f7ba4cSKristen Carlson Accardi 	/* ignore 0:4 of byte zero, fill in port info yourself */
142487943acfSDavid Milburn 	message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
142518f7ba4cSKristen Carlson Accardi 
142618f7ba4cSKristen Carlson Accardi 	/* write message to EM_LOC */
142718f7ba4cSKristen Carlson Accardi 	writel(message[0], mmio + hpriv->em_loc);
142818f7ba4cSKristen Carlson Accardi 	writel(message[1], mmio + hpriv->em_loc+4);
142918f7ba4cSKristen Carlson Accardi 
143018f7ba4cSKristen Carlson Accardi 	/* save off new led state for port/slot */
1431208f2a88SDavid Milburn 	emp->led_state = state;
143218f7ba4cSKristen Carlson Accardi 
143318f7ba4cSKristen Carlson Accardi 	/*
143418f7ba4cSKristen Carlson Accardi 	 * tell hardware to transmit the message
143518f7ba4cSKristen Carlson Accardi 	 */
143618f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
143718f7ba4cSKristen Carlson Accardi 
143818f7ba4cSKristen Carlson Accardi 	spin_unlock_irqrestore(ap->lock, flags);
143918f7ba4cSKristen Carlson Accardi 	return size;
144018f7ba4cSKristen Carlson Accardi }
144118f7ba4cSKristen Carlson Accardi 
144218f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
144318f7ba4cSKristen Carlson Accardi {
144418f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
144518f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
144618f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
144718f7ba4cSKristen Carlson Accardi 	int rc = 0;
144818f7ba4cSKristen Carlson Accardi 
14491eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE) {
145018f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[link->pmp];
145118f7ba4cSKristen Carlson Accardi 		rc += sprintf(buf, "%lx\n", emp->led_state);
145218f7ba4cSKristen Carlson Accardi 	}
145318f7ba4cSKristen Carlson Accardi 	return rc;
145418f7ba4cSKristen Carlson Accardi }
145518f7ba4cSKristen Carlson Accardi 
145618f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
145718f7ba4cSKristen Carlson Accardi 				size_t size)
145818f7ba4cSKristen Carlson Accardi {
145918f7ba4cSKristen Carlson Accardi 	int state;
146018f7ba4cSKristen Carlson Accardi 	int pmp;
146118f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
146218f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
146318f7ba4cSKristen Carlson Accardi 
146418f7ba4cSKristen Carlson Accardi 	state = simple_strtoul(buf, NULL, 0);
146518f7ba4cSKristen Carlson Accardi 
146618f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
146787943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
1468d50ce07dSTejun Heo 	if (pmp < EM_MAX_SLOTS)
146918f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
147018f7ba4cSKristen Carlson Accardi 	else
147118f7ba4cSKristen Carlson Accardi 		return -EINVAL;
147218f7ba4cSKristen Carlson Accardi 
147318f7ba4cSKristen Carlson Accardi 	/* mask off the activity bits if we are in sw_activity
147418f7ba4cSKristen Carlson Accardi 	 * mode, user should turn off sw_activity before setting
147518f7ba4cSKristen Carlson Accardi 	 * activity led through em_message
147618f7ba4cSKristen Carlson Accardi 	 */
147718f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
147887943acfSDavid Milburn 		state &= ~EM_MSG_LED_VALUE_ACTIVITY;
147918f7ba4cSKristen Carlson Accardi 
148018f7ba4cSKristen Carlson Accardi 	return ahci_transmit_led_message(ap, state, size);
148118f7ba4cSKristen Carlson Accardi }
148218f7ba4cSKristen Carlson Accardi 
148318f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
148418f7ba4cSKristen Carlson Accardi {
148518f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
148618f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
148718f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
148818f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
148918f7ba4cSKristen Carlson Accardi 	u32 port_led_state = emp->led_state;
149018f7ba4cSKristen Carlson Accardi 
149118f7ba4cSKristen Carlson Accardi 	/* save the desired Activity LED behavior */
149218f7ba4cSKristen Carlson Accardi 	if (val == OFF) {
149318f7ba4cSKristen Carlson Accardi 		/* clear LFLAG */
149418f7ba4cSKristen Carlson Accardi 		link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
149518f7ba4cSKristen Carlson Accardi 
149618f7ba4cSKristen Carlson Accardi 		/* set the LED to OFF */
149787943acfSDavid Milburn 		port_led_state &= EM_MSG_LED_VALUE_OFF;
149818f7ba4cSKristen Carlson Accardi 		port_led_state |= (ap->port_no | (link->pmp << 8));
149918f7ba4cSKristen Carlson Accardi 		ahci_transmit_led_message(ap, port_led_state, 4);
150018f7ba4cSKristen Carlson Accardi 	} else {
150118f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
150218f7ba4cSKristen Carlson Accardi 		if (val == BLINK_OFF) {
150318f7ba4cSKristen Carlson Accardi 			/* set LED to ON for idle */
150487943acfSDavid Milburn 			port_led_state &= EM_MSG_LED_VALUE_OFF;
150518f7ba4cSKristen Carlson Accardi 			port_led_state |= (ap->port_no | (link->pmp << 8));
150687943acfSDavid Milburn 			port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
150718f7ba4cSKristen Carlson Accardi 			ahci_transmit_led_message(ap, port_led_state, 4);
150818f7ba4cSKristen Carlson Accardi 		}
150918f7ba4cSKristen Carlson Accardi 	}
151018f7ba4cSKristen Carlson Accardi 	emp->blink_policy = val;
151118f7ba4cSKristen Carlson Accardi 	return 0;
151218f7ba4cSKristen Carlson Accardi }
151318f7ba4cSKristen Carlson Accardi 
151418f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
151518f7ba4cSKristen Carlson Accardi {
151618f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
151718f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
151818f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
151918f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
152018f7ba4cSKristen Carlson Accardi 
152118f7ba4cSKristen Carlson Accardi 	/* display the saved value of activity behavior for this
152218f7ba4cSKristen Carlson Accardi 	 * disk.
152318f7ba4cSKristen Carlson Accardi 	 */
152418f7ba4cSKristen Carlson Accardi 	return sprintf(buf, "%d\n", emp->blink_policy);
152518f7ba4cSKristen Carlson Accardi }
152618f7ba4cSKristen Carlson Accardi 
15272bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
15282bcd866bSJeff Garzik 			   int port_no, void __iomem *mmio,
15292bcd866bSJeff Garzik 			   void __iomem *port_mmio)
1530c6fd2807SJeff Garzik {
1531c6fd2807SJeff Garzik 	const char *emsg = NULL;
15322bcd866bSJeff Garzik 	int rc;
15332bcd866bSJeff Garzik 	u32 tmp;
1534c6fd2807SJeff Garzik 
1535c6fd2807SJeff Garzik 	/* make sure port is not active */
15364447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1537c6fd2807SJeff Garzik 	if (rc)
1538c6fd2807SJeff Garzik 		dev_printk(KERN_WARNING, &pdev->dev,
1539c6fd2807SJeff Garzik 			   "%s (%d)\n", emsg, rc);
1540c6fd2807SJeff Garzik 
1541c6fd2807SJeff Garzik 	/* clear SError */
1542c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SCR_ERR);
1543c6fd2807SJeff Garzik 	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
1544c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_SCR_ERR);
1545c6fd2807SJeff Garzik 
1546c6fd2807SJeff Garzik 	/* clear port IRQ */
1547c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1548c6fd2807SJeff Garzik 	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1549c6fd2807SJeff Garzik 	if (tmp)
1550c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_IRQ_STAT);
1551c6fd2807SJeff Garzik 
15522bcd866bSJeff Garzik 	writel(1 << port_no, mmio + HOST_IRQ_STAT);
15532bcd866bSJeff Garzik }
15542bcd866bSJeff Garzik 
15552bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host)
15562bcd866bSJeff Garzik {
1557417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
15582bcd866bSJeff Garzik 	struct pci_dev *pdev = to_pci_dev(host->dev);
15592bcd866bSJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
15602bcd866bSJeff Garzik 	int i;
1561cd70c266SJeff Garzik 	void __iomem *port_mmio;
15622bcd866bSJeff Garzik 	u32 tmp;
1563c40e7cb8SJose Alberto Reguero 	int mv;
15642bcd866bSJeff Garzik 
1565417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
1566c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
1567c40e7cb8SJose Alberto Reguero 			mv = 2;
1568c40e7cb8SJose Alberto Reguero 		else
1569c40e7cb8SJose Alberto Reguero 			mv = 4;
1570c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
1571cd70c266SJeff Garzik 
1572cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
1573cd70c266SJeff Garzik 
1574cd70c266SJeff Garzik 		/* clear port IRQ */
1575cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
1576cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1577cd70c266SJeff Garzik 		if (tmp)
1578cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
1579cd70c266SJeff Garzik 	}
1580cd70c266SJeff Garzik 
15812bcd866bSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
15822bcd866bSJeff Garzik 		struct ata_port *ap = host->ports[i];
15832bcd866bSJeff Garzik 
1584cd70c266SJeff Garzik 		port_mmio = ahci_port_base(ap);
15852bcd866bSJeff Garzik 		if (ata_port_is_dummy(ap))
15862bcd866bSJeff Garzik 			continue;
15872bcd866bSJeff Garzik 
15882bcd866bSJeff Garzik 		ahci_port_init(pdev, ap, i, mmio, port_mmio);
1589c6fd2807SJeff Garzik 	}
1590c6fd2807SJeff Garzik 
1591c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1592c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1593c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
1594c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1595c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1596c6fd2807SJeff Garzik }
1597c6fd2807SJeff Garzik 
1598a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev)
1599a878539eSJeff Garzik {
1600a878539eSJeff Garzik 	struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
1601a878539eSJeff Garzik 
16024cde32fcSJeff Garzik 	if (hpriv->flags & AHCI_HFLAG_SECT255) {
1603a878539eSJeff Garzik 		dev->max_sectors = 255;
16044cde32fcSJeff Garzik 		ata_dev_printk(dev, KERN_INFO,
16054cde32fcSJeff Garzik 			       "SB600 AHCI: limiting to 255 sectors per cmd\n");
16064cde32fcSJeff Garzik 	}
1607a878539eSJeff Garzik }
1608a878539eSJeff Garzik 
1609c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
1610c6fd2807SJeff Garzik {
16114447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1612c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1613c6fd2807SJeff Garzik 	u32 tmp;
1614c6fd2807SJeff Garzik 
1615c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
1616c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
1617c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
1618c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
1619c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
1620c6fd2807SJeff Garzik 
1621c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
1622c6fd2807SJeff Garzik }
1623c6fd2807SJeff Garzik 
1624c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
1625c6fd2807SJeff Garzik 			       u32 opts)
1626c6fd2807SJeff Garzik {
1627c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
1628c6fd2807SJeff Garzik 
1629c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
1630c6fd2807SJeff Garzik 
1631c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
1632c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
1633c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
1634c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
1635c6fd2807SJeff Garzik }
1636c6fd2807SJeff Garzik 
1637*78d5ae39SShane Huang static int ahci_kick_engine(struct ata_port *ap)
1638c6fd2807SJeff Garzik {
1639350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1640cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1641520d06f9STejun Heo 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1642c6fd2807SJeff Garzik 	u32 tmp;
1643d2e75dffSTejun Heo 	int busy, rc;
1644c6fd2807SJeff Garzik 
1645d2e75dffSTejun Heo 	/* stop engine */
1646d2e75dffSTejun Heo 	rc = ahci_stop_engine(ap);
1647d2e75dffSTejun Heo 	if (rc)
1648d2e75dffSTejun Heo 		goto out_restart;
1649d2e75dffSTejun Heo 
1650*78d5ae39SShane Huang 	/* need to do CLO?
1651*78d5ae39SShane Huang 	 * always do CLO if PMP is attached (AHCI-1.3 9.2)
1652*78d5ae39SShane Huang 	 */
1653*78d5ae39SShane Huang 	busy = status & (ATA_BUSY | ATA_DRQ);
1654*78d5ae39SShane Huang 	if (!busy && !sata_pmp_attached(ap)) {
1655d2e75dffSTejun Heo 		rc = 0;
1656d2e75dffSTejun Heo 		goto out_restart;
1657d2e75dffSTejun Heo 	}
1658d2e75dffSTejun Heo 
1659d2e75dffSTejun Heo 	if (!(hpriv->cap & HOST_CAP_CLO)) {
1660d2e75dffSTejun Heo 		rc = -EOPNOTSUPP;
1661d2e75dffSTejun Heo 		goto out_restart;
1662d2e75dffSTejun Heo 	}
1663d2e75dffSTejun Heo 
1664d2e75dffSTejun Heo 	/* perform CLO */
1665c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1666c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
1667c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1668c6fd2807SJeff Garzik 
1669d2e75dffSTejun Heo 	rc = 0;
1670c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1671c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
1672c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
1673d2e75dffSTejun Heo 		rc = -EIO;
1674c6fd2807SJeff Garzik 
1675d2e75dffSTejun Heo 	/* restart engine */
1676d2e75dffSTejun Heo  out_restart:
1677d2e75dffSTejun Heo 	ahci_start_engine(ap);
1678d2e75dffSTejun Heo 	return rc;
1679c6fd2807SJeff Garzik }
1680c6fd2807SJeff Garzik 
168191c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
168291c4a2e0STejun Heo 				struct ata_taskfile *tf, int is_cmd, u16 flags,
168391c4a2e0STejun Heo 				unsigned long timeout_msec)
168491c4a2e0STejun Heo {
168591c4a2e0STejun Heo 	const u32 cmd_fis_len = 5; /* five dwords */
168691c4a2e0STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
168791c4a2e0STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
168891c4a2e0STejun Heo 	u8 *fis = pp->cmd_tbl;
168991c4a2e0STejun Heo 	u32 tmp;
169091c4a2e0STejun Heo 
169191c4a2e0STejun Heo 	/* prep the command */
169291c4a2e0STejun Heo 	ata_tf_to_fis(tf, pmp, is_cmd, fis);
169391c4a2e0STejun Heo 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
169491c4a2e0STejun Heo 
169591c4a2e0STejun Heo 	/* issue & wait */
169691c4a2e0STejun Heo 	writel(1, port_mmio + PORT_CMD_ISSUE);
169791c4a2e0STejun Heo 
169891c4a2e0STejun Heo 	if (timeout_msec) {
169991c4a2e0STejun Heo 		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
170091c4a2e0STejun Heo 					1, timeout_msec);
170191c4a2e0STejun Heo 		if (tmp & 0x1) {
1702*78d5ae39SShane Huang 			ahci_kick_engine(ap);
170391c4a2e0STejun Heo 			return -EBUSY;
170491c4a2e0STejun Heo 		}
170591c4a2e0STejun Heo 	} else
170691c4a2e0STejun Heo 		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
170791c4a2e0STejun Heo 
170891c4a2e0STejun Heo 	return 0;
170991c4a2e0STejun Heo }
171091c4a2e0STejun Heo 
1711bd17243aSShane Huang static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1712bd17243aSShane Huang 			     int pmp, unsigned long deadline,
1713bd17243aSShane Huang 			     int (*check_ready)(struct ata_link *link))
1714c6fd2807SJeff Garzik {
1715cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
17165594639aSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1717c6fd2807SJeff Garzik 	const char *reason = NULL;
17182cbb79ebSTejun Heo 	unsigned long now, msecs;
1719c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1720c6fd2807SJeff Garzik 	int rc;
1721c6fd2807SJeff Garzik 
1722c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1723c6fd2807SJeff Garzik 
1724c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
1725*78d5ae39SShane Huang 	rc = ahci_kick_engine(ap);
1726994056d7STejun Heo 	if (rc && rc != -EOPNOTSUPP)
1727cc0680a5STejun Heo 		ata_link_printk(link, KERN_WARNING,
1728994056d7STejun Heo 				"failed to reset engine (errno=%d)\n", rc);
1729c6fd2807SJeff Garzik 
1730cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1731c6fd2807SJeff Garzik 
1732c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
17332cbb79ebSTejun Heo 	msecs = 0;
17342cbb79ebSTejun Heo 	now = jiffies;
17352cbb79ebSTejun Heo 	if (time_after(now, deadline))
17362cbb79ebSTejun Heo 		msecs = jiffies_to_msecs(deadline - now);
17372cbb79ebSTejun Heo 
1738c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
1739a9cf5e85STejun Heo 	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
174091c4a2e0STejun Heo 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
1741c6fd2807SJeff Garzik 		rc = -EIO;
1742c6fd2807SJeff Garzik 		reason = "1st FIS failed";
1743c6fd2807SJeff Garzik 		goto fail;
1744c6fd2807SJeff Garzik 	}
1745c6fd2807SJeff Garzik 
1746c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
1747c6fd2807SJeff Garzik 	msleep(1);
1748c6fd2807SJeff Garzik 
1749c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
1750c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
1751a9cf5e85STejun Heo 	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1752c6fd2807SJeff Garzik 
1753705e76beSTejun Heo 	/* wait for link to become ready */
1754bd17243aSShane Huang 	rc = ata_wait_after_reset(link, deadline, check_ready);
17555594639aSTejun Heo 	if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) {
17565594639aSTejun Heo 		/*
17575594639aSTejun Heo 		 * Workaround for cases where link online status can't
17585594639aSTejun Heo 		 * be trusted.  Treat device readiness timeout as link
17595594639aSTejun Heo 		 * offline.
17605594639aSTejun Heo 		 */
17615594639aSTejun Heo 		ata_link_printk(link, KERN_INFO,
17625594639aSTejun Heo 				"device not ready, treating as offline\n");
17635594639aSTejun Heo 		*class = ATA_DEV_NONE;
17645594639aSTejun Heo 	} else if (rc) {
17659b89391cSTejun Heo 		/* link occupied, -ENODEV too is an error */
1766c6fd2807SJeff Garzik 		reason = "device not ready";
1767c6fd2807SJeff Garzik 		goto fail;
17685594639aSTejun Heo 	} else
1769c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
1770c6fd2807SJeff Garzik 
1771c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
1772c6fd2807SJeff Garzik 	return 0;
1773c6fd2807SJeff Garzik 
1774c6fd2807SJeff Garzik  fail:
1775cc0680a5STejun Heo 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
1776c6fd2807SJeff Garzik 	return rc;
1777c6fd2807SJeff Garzik }
1778c6fd2807SJeff Garzik 
1779bd17243aSShane Huang static int ahci_check_ready(struct ata_link *link)
1780bd17243aSShane Huang {
1781bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1782bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1783bd17243aSShane Huang 
1784bd17243aSShane Huang 	return ata_check_ready(status);
1785bd17243aSShane Huang }
1786bd17243aSShane Huang 
1787bd17243aSShane Huang static int ahci_softreset(struct ata_link *link, unsigned int *class,
1788bd17243aSShane Huang 			  unsigned long deadline)
1789bd17243aSShane Huang {
1790bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1791bd17243aSShane Huang 
1792bd17243aSShane Huang 	DPRINTK("ENTER\n");
1793bd17243aSShane Huang 
1794bd17243aSShane Huang 	return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
1795bd17243aSShane Huang }
1796bd17243aSShane Huang 
1797bd17243aSShane Huang static int ahci_sb600_check_ready(struct ata_link *link)
1798bd17243aSShane Huang {
1799bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1800bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1801bd17243aSShane Huang 	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
1802bd17243aSShane Huang 
1803bd17243aSShane Huang 	/*
1804bd17243aSShane Huang 	 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
1805bd17243aSShane Huang 	 * which can save timeout delay.
1806bd17243aSShane Huang 	 */
1807bd17243aSShane Huang 	if (irq_status & PORT_IRQ_BAD_PMP)
1808bd17243aSShane Huang 		return -EIO;
1809bd17243aSShane Huang 
1810bd17243aSShane Huang 	return ata_check_ready(status);
1811bd17243aSShane Huang }
1812bd17243aSShane Huang 
1813bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
1814bd17243aSShane Huang 				unsigned long deadline)
1815bd17243aSShane Huang {
1816bd17243aSShane Huang 	struct ata_port *ap = link->ap;
1817bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(ap);
1818bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1819bd17243aSShane Huang 	int rc;
1820bd17243aSShane Huang 	u32 irq_sts;
1821bd17243aSShane Huang 
1822bd17243aSShane Huang 	DPRINTK("ENTER\n");
1823bd17243aSShane Huang 
1824bd17243aSShane Huang 	rc = ahci_do_softreset(link, class, pmp, deadline,
1825bd17243aSShane Huang 			       ahci_sb600_check_ready);
1826bd17243aSShane Huang 
1827bd17243aSShane Huang 	/*
1828bd17243aSShane Huang 	 * Soft reset fails on some ATI chips with IPMS set when PMP
1829bd17243aSShane Huang 	 * is enabled but SATA HDD/ODD is connected to SATA port,
1830bd17243aSShane Huang 	 * do soft reset again to port 0.
1831bd17243aSShane Huang 	 */
1832bd17243aSShane Huang 	if (rc == -EIO) {
1833bd17243aSShane Huang 		irq_sts = readl(port_mmio + PORT_IRQ_STAT);
1834bd17243aSShane Huang 		if (irq_sts & PORT_IRQ_BAD_PMP) {
1835bd17243aSShane Huang 			ata_link_printk(link, KERN_WARNING,
1836b6931c1fSShane Huang 					"applying SB600 PMP SRST workaround "
1837b6931c1fSShane Huang 					"and retrying\n");
1838bd17243aSShane Huang 			rc = ahci_do_softreset(link, class, 0, deadline,
1839bd17243aSShane Huang 					       ahci_check_ready);
1840bd17243aSShane Huang 		}
1841bd17243aSShane Huang 	}
1842bd17243aSShane Huang 
1843bd17243aSShane Huang 	return rc;
1844bd17243aSShane Huang }
1845bd17243aSShane Huang 
1846cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1847d4b2bab4STejun Heo 			  unsigned long deadline)
1848c6fd2807SJeff Garzik {
18499dadd45bSTejun Heo 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
1850cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1851c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1852c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1853c6fd2807SJeff Garzik 	struct ata_taskfile tf;
18549dadd45bSTejun Heo 	bool online;
1855c6fd2807SJeff Garzik 	int rc;
1856c6fd2807SJeff Garzik 
1857c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1858c6fd2807SJeff Garzik 
18594447d351STejun Heo 	ahci_stop_engine(ap);
1860c6fd2807SJeff Garzik 
1861c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1862cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1863dfd7a3dbSTejun Heo 	tf.command = 0x80;
18649977126cSTejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1865c6fd2807SJeff Garzik 
18669dadd45bSTejun Heo 	rc = sata_link_hardreset(link, timing, deadline, &online,
18679dadd45bSTejun Heo 				 ahci_check_ready);
1868c6fd2807SJeff Garzik 
18694447d351STejun Heo 	ahci_start_engine(ap);
1870c6fd2807SJeff Garzik 
18719dadd45bSTejun Heo 	if (online)
18729dadd45bSTejun Heo 		*class = ahci_dev_classify(ap);
1873c6fd2807SJeff Garzik 
1874c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1875c6fd2807SJeff Garzik 	return rc;
1876c6fd2807SJeff Garzik }
1877c6fd2807SJeff Garzik 
1878cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1879d4b2bab4STejun Heo 				 unsigned long deadline)
1880ad616ffbSTejun Heo {
1881cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
18829dadd45bSTejun Heo 	bool online;
1883ad616ffbSTejun Heo 	int rc;
1884ad616ffbSTejun Heo 
1885ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1886ad616ffbSTejun Heo 
18874447d351STejun Heo 	ahci_stop_engine(ap);
1888ad616ffbSTejun Heo 
1889cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
18909dadd45bSTejun Heo 				 deadline, &online, NULL);
1891ad616ffbSTejun Heo 
18924447d351STejun Heo 	ahci_start_engine(ap);
1893ad616ffbSTejun Heo 
1894ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1895ad616ffbSTejun Heo 
1896ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1897ad616ffbSTejun Heo 	 * request follow-up softreset.
1898ad616ffbSTejun Heo 	 */
18999dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
1900ad616ffbSTejun Heo }
1901ad616ffbSTejun Heo 
1902edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1903edc93052STejun Heo 				unsigned long deadline)
1904edc93052STejun Heo {
1905edc93052STejun Heo 	struct ata_port *ap = link->ap;
1906edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1907edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1908edc93052STejun Heo 	struct ata_taskfile tf;
19099dadd45bSTejun Heo 	bool online;
1910edc93052STejun Heo 	int rc;
1911edc93052STejun Heo 
1912edc93052STejun Heo 	ahci_stop_engine(ap);
1913edc93052STejun Heo 
1914edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
1915edc93052STejun Heo 	ata_tf_init(link->device, &tf);
1916edc93052STejun Heo 	tf.command = 0x80;
1917edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1918edc93052STejun Heo 
1919edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
19209dadd45bSTejun Heo 				 deadline, &online, NULL);
1921edc93052STejun Heo 
1922edc93052STejun Heo 	ahci_start_engine(ap);
1923edc93052STejun Heo 
1924edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
1925edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1926edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
1927edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
1928edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
1929edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1930edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1931edc93052STejun Heo 	 *
1932edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
1933edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
1934edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
1935edc93052STejun Heo 	 * suffice while making probing snappish enough.
1936edc93052STejun Heo 	 */
19379dadd45bSTejun Heo 	if (online) {
19389dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
19399dadd45bSTejun Heo 					  ahci_check_ready);
1940edc93052STejun Heo 		if (rc)
1941*78d5ae39SShane Huang 			ahci_kick_engine(ap);
19429dadd45bSTejun Heo 	}
19439dadd45bSTejun Heo 	return rc;
1944edc93052STejun Heo }
1945edc93052STejun Heo 
1946cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class)
1947c6fd2807SJeff Garzik {
1948cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
19494447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1950c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1951c6fd2807SJeff Garzik 
1952203c75b8STejun Heo 	ata_std_postreset(link, class);
1953c6fd2807SJeff Garzik 
1954c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1955c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1956c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1957c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
1958c6fd2807SJeff Garzik 	else
1959c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
1960c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
1961c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
1962c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
1963c6fd2807SJeff Garzik 	}
1964c6fd2807SJeff Garzik }
1965c6fd2807SJeff Garzik 
1966c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
1967c6fd2807SJeff Garzik {
1968c6fd2807SJeff Garzik 	struct scatterlist *sg;
1969ff2aeb1eSTejun Heo 	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
1970ff2aeb1eSTejun Heo 	unsigned int si;
1971c6fd2807SJeff Garzik 
1972c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1973c6fd2807SJeff Garzik 
1974c6fd2807SJeff Garzik 	/*
1975c6fd2807SJeff Garzik 	 * Next, the S/G list.
1976c6fd2807SJeff Garzik 	 */
1977ff2aeb1eSTejun Heo 	for_each_sg(qc->sg, sg, qc->n_elem, si) {
1978c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1979c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1980c6fd2807SJeff Garzik 
1981ff2aeb1eSTejun Heo 		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
1982ff2aeb1eSTejun Heo 		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
1983ff2aeb1eSTejun Heo 		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
1984c6fd2807SJeff Garzik 	}
1985c6fd2807SJeff Garzik 
1986ff2aeb1eSTejun Heo 	return si;
1987c6fd2807SJeff Garzik }
1988c6fd2807SJeff Garzik 
1989c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1990c6fd2807SJeff Garzik {
1991c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1992c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1993405e66b3STejun Heo 	int is_atapi = ata_is_atapi(qc->tf.protocol);
1994c6fd2807SJeff Garzik 	void *cmd_tbl;
1995c6fd2807SJeff Garzik 	u32 opts;
1996c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1997c6fd2807SJeff Garzik 	unsigned int n_elem;
1998c6fd2807SJeff Garzik 
1999c6fd2807SJeff Garzik 	/*
2000c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
2001c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
2002c6fd2807SJeff Garzik 	 */
2003c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
2004c6fd2807SJeff Garzik 
20057d50b60bSTejun Heo 	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
2006c6fd2807SJeff Garzik 	if (is_atapi) {
2007c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
2008c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
2009c6fd2807SJeff Garzik 	}
2010c6fd2807SJeff Garzik 
2011c6fd2807SJeff Garzik 	n_elem = 0;
2012c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
2013c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
2014c6fd2807SJeff Garzik 
2015c6fd2807SJeff Garzik 	/*
2016c6fd2807SJeff Garzik 	 * Fill in command slot information.
2017c6fd2807SJeff Garzik 	 */
20187d50b60bSTejun Heo 	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
2019c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
2020c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
2021c6fd2807SJeff Garzik 	if (is_atapi)
2022c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
2023c6fd2807SJeff Garzik 
2024c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
2025c6fd2807SJeff Garzik }
2026c6fd2807SJeff Garzik 
2027c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
2028c6fd2807SJeff Garzik {
2029417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
2030c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
20317d50b60bSTejun Heo 	struct ata_eh_info *host_ehi = &ap->link.eh_info;
20327d50b60bSTejun Heo 	struct ata_link *link = NULL;
20337d50b60bSTejun Heo 	struct ata_queued_cmd *active_qc;
20347d50b60bSTejun Heo 	struct ata_eh_info *active_ehi;
2035c6fd2807SJeff Garzik 	u32 serror;
2036c6fd2807SJeff Garzik 
20377d50b60bSTejun Heo 	/* determine active link */
20381eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE)
20397d50b60bSTejun Heo 		if (ata_link_active(link))
20407d50b60bSTejun Heo 			break;
20417d50b60bSTejun Heo 	if (!link)
20427d50b60bSTejun Heo 		link = &ap->link;
20437d50b60bSTejun Heo 
20447d50b60bSTejun Heo 	active_qc = ata_qc_from_tag(ap, link->active_tag);
20457d50b60bSTejun Heo 	active_ehi = &link->eh_info;
20467d50b60bSTejun Heo 
20477d50b60bSTejun Heo 	/* record irq stat */
20487d50b60bSTejun Heo 	ata_ehi_clear_desc(host_ehi);
20497d50b60bSTejun Heo 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
2050c6fd2807SJeff Garzik 
2051c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
205282ef04fbSTejun Heo 	ahci_scr_read(&ap->link, SCR_ERROR, &serror);
205382ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, serror);
20547d50b60bSTejun Heo 	host_ehi->serror |= serror;
2055c6fd2807SJeff Garzik 
205641669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
2057417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
205841669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
205941669553STejun Heo 
206055a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
20617d50b60bSTejun Heo 		/* If qc is active, charge it; otherwise, the active
20627d50b60bSTejun Heo 		 * link.  There's no active qc on NCQ errors.  It will
20637d50b60bSTejun Heo 		 * be determined by EH by reading log page 10h.
20647d50b60bSTejun Heo 		 */
20657d50b60bSTejun Heo 		if (active_qc)
20667d50b60bSTejun Heo 			active_qc->err_mask |= AC_ERR_DEV;
20677d50b60bSTejun Heo 		else
20687d50b60bSTejun Heo 			active_ehi->err_mask |= AC_ERR_DEV;
20697d50b60bSTejun Heo 
2070417a1a6dSTejun Heo 		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
20717d50b60bSTejun Heo 			host_ehi->serror &= ~SERR_INTERNAL;
2072c6fd2807SJeff Garzik 	}
2073c6fd2807SJeff Garzik 
2074c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
2075c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
2076c6fd2807SJeff Garzik 
20777d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
2078cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
20797d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi,
20807d50b60bSTejun Heo 				  "unknown FIS %08x %08x %08x %08x" ,
2081c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
2082c6fd2807SJeff Garzik 	}
2083c6fd2807SJeff Garzik 
2084071f44b1STejun Heo 	if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
20857d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
2086cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
20877d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi, "incorrect PMP");
20887d50b60bSTejun Heo 	}
2089c6fd2807SJeff Garzik 
20907d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
20917d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_HOST_BUS;
2092cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
20937d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "host bus error");
20947d50b60bSTejun Heo 	}
20957d50b60bSTejun Heo 
20967d50b60bSTejun Heo 	if (irq_stat & PORT_IRQ_IF_ERR) {
20977d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_ATA_BUS;
2098cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
20997d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "interface fatal error");
21007d50b60bSTejun Heo 	}
21017d50b60bSTejun Heo 
21027d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
21037d50b60bSTejun Heo 		ata_ehi_hotplugged(host_ehi);
21047d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "%s",
21057d50b60bSTejun Heo 			irq_stat & PORT_IRQ_CONNECT ?
21067d50b60bSTejun Heo 			"connection status changed" : "PHY RDY changed");
21077d50b60bSTejun Heo 	}
21087d50b60bSTejun Heo 
21097d50b60bSTejun Heo 	/* okay, let's hand over to EH */
2110c6fd2807SJeff Garzik 
2111c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
2112c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2113c6fd2807SJeff Garzik 	else
2114c6fd2807SJeff Garzik 		ata_port_abort(ap);
2115c6fd2807SJeff Garzik }
2116c6fd2807SJeff Garzik 
2117df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap)
2118c6fd2807SJeff Garzik {
2119350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
21209af5c9c9STejun Heo 	struct ata_eh_info *ehi = &ap->link.eh_info;
21210291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
21225f226c6bSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
2123b06ce3e5STejun Heo 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
2124c6fd2807SJeff Garzik 	u32 status, qc_active;
2125459ad688STejun Heo 	int rc;
2126c6fd2807SJeff Garzik 
2127c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
2128c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
2129c6fd2807SJeff Garzik 
2130b06ce3e5STejun Heo 	/* ignore BAD_PMP while resetting */
2131b06ce3e5STejun Heo 	if (unlikely(resetting))
2132b06ce3e5STejun Heo 		status &= ~PORT_IRQ_BAD_PMP;
2133b06ce3e5STejun Heo 
213431556594SKristen Carlson Accardi 	/* If we are getting PhyRdy, this is
213531556594SKristen Carlson Accardi  	 * just a power state change, we should
213631556594SKristen Carlson Accardi  	 * clear out this, plus the PhyRdy/Comm
213731556594SKristen Carlson Accardi  	 * Wake bits from Serror
213831556594SKristen Carlson Accardi  	 */
213931556594SKristen Carlson Accardi 	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
214031556594SKristen Carlson Accardi 		(status & PORT_IRQ_PHYRDY)) {
214131556594SKristen Carlson Accardi 		status &= ~PORT_IRQ_PHYRDY;
214282ef04fbSTejun Heo 		ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
214331556594SKristen Carlson Accardi 	}
214431556594SKristen Carlson Accardi 
2145c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
2146c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
2147c6fd2807SJeff Garzik 		return;
2148c6fd2807SJeff Garzik 	}
2149c6fd2807SJeff Garzik 
21502f294968SKristen Carlson Accardi 	if (status & PORT_IRQ_SDB_FIS) {
21515f226c6bSTejun Heo 		/* If SNotification is available, leave notification
21525f226c6bSTejun Heo 		 * handling to sata_async_notification().  If not,
21535f226c6bSTejun Heo 		 * emulate it by snooping SDB FIS RX area.
21545f226c6bSTejun Heo 		 *
21555f226c6bSTejun Heo 		 * Snooping FIS RX area is probably cheaper than
21565f226c6bSTejun Heo 		 * poking SNotification but some constrollers which
21575f226c6bSTejun Heo 		 * implement SNotification, ICH9 for example, don't
21585f226c6bSTejun Heo 		 * store AN SDB FIS into receive area.
21595f226c6bSTejun Heo 		 */
21605f226c6bSTejun Heo 		if (hpriv->cap & HOST_CAP_SNTF)
21615f226c6bSTejun Heo 			sata_async_notification(ap);
21625f226c6bSTejun Heo 		else {
21635f226c6bSTejun Heo 			/* If the 'N' bit in word 0 of the FIS is set,
21645f226c6bSTejun Heo 			 * we just received asynchronous notification.
21655f226c6bSTejun Heo 			 * Tell libata about it.
21662f294968SKristen Carlson Accardi 			 */
21672f294968SKristen Carlson Accardi 			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
21682f294968SKristen Carlson Accardi 			u32 f0 = le32_to_cpu(f[0]);
21692f294968SKristen Carlson Accardi 
21707d77b247STejun Heo 			if (f0 & (1 << 15))
21717d77b247STejun Heo 				sata_async_notification(ap);
21722f294968SKristen Carlson Accardi 		}
21735f226c6bSTejun Heo 	}
21742f294968SKristen Carlson Accardi 
21757d50b60bSTejun Heo 	/* pp->active_link is valid iff any command is in flight */
21767d50b60bSTejun Heo 	if (ap->qc_active && pp->active_link->sactive)
2177c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
2178c6fd2807SJeff Garzik 	else
2179c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
2180c6fd2807SJeff Garzik 
218179f97dadSTejun Heo 	rc = ata_qc_complete_multiple(ap, qc_active);
2182b06ce3e5STejun Heo 
2183459ad688STejun Heo 	/* while resetting, invalid completions are expected */
2184459ad688STejun Heo 	if (unlikely(rc < 0 && !resetting)) {
2185c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
2186cf480626STejun Heo 		ehi->action |= ATA_EH_RESET;
2187c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2188c6fd2807SJeff Garzik 	}
2189c6fd2807SJeff Garzik }
2190c6fd2807SJeff Garzik 
21917d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
2192c6fd2807SJeff Garzik {
2193cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
2194c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
2195c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
2196c6fd2807SJeff Garzik 	void __iomem *mmio;
2197d28f87aaSTejun Heo 	u32 irq_stat, irq_masked;
2198c6fd2807SJeff Garzik 
2199c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2200c6fd2807SJeff Garzik 
2201cca3974eSJeff Garzik 	hpriv = host->private_data;
22020d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
2203c6fd2807SJeff Garzik 
2204c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
2205c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
2206c6fd2807SJeff Garzik 	if (!irq_stat)
2207c6fd2807SJeff Garzik 		return IRQ_NONE;
2208c6fd2807SJeff Garzik 
2209d28f87aaSTejun Heo 	irq_masked = irq_stat & hpriv->port_map;
2210d28f87aaSTejun Heo 
2211cca3974eSJeff Garzik 	spin_lock(&host->lock);
2212c6fd2807SJeff Garzik 
2213cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
2214c6fd2807SJeff Garzik 		struct ata_port *ap;
2215c6fd2807SJeff Garzik 
2216d28f87aaSTejun Heo 		if (!(irq_masked & (1 << i)))
2217c6fd2807SJeff Garzik 			continue;
2218c6fd2807SJeff Garzik 
2219cca3974eSJeff Garzik 		ap = host->ports[i];
2220c6fd2807SJeff Garzik 		if (ap) {
2221df69c9c5SJeff Garzik 			ahci_port_intr(ap);
2222c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
2223c6fd2807SJeff Garzik 		} else {
2224c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
2225c6fd2807SJeff Garzik 			if (ata_ratelimit())
2226cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
2227c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
2228c6fd2807SJeff Garzik 		}
2229c6fd2807SJeff Garzik 
2230c6fd2807SJeff Garzik 		handled = 1;
2231c6fd2807SJeff Garzik 	}
2232c6fd2807SJeff Garzik 
2233d28f87aaSTejun Heo 	/* HOST_IRQ_STAT behaves as level triggered latch meaning that
2234d28f87aaSTejun Heo 	 * it should be cleared after all the port events are cleared;
2235d28f87aaSTejun Heo 	 * otherwise, it will raise a spurious interrupt after each
2236d28f87aaSTejun Heo 	 * valid one.  Please read section 10.6.2 of ahci 1.1 for more
2237d28f87aaSTejun Heo 	 * information.
2238d28f87aaSTejun Heo 	 *
2239d28f87aaSTejun Heo 	 * Also, use the unmasked value to clear interrupt as spurious
2240d28f87aaSTejun Heo 	 * pending event on a dummy port might cause screaming IRQ.
2241d28f87aaSTejun Heo 	 */
2242ea0c62f7STejun Heo 	writel(irq_stat, mmio + HOST_IRQ_STAT);
2243ea0c62f7STejun Heo 
2244cca3974eSJeff Garzik 	spin_unlock(&host->lock);
2245c6fd2807SJeff Garzik 
2246c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
2247c6fd2807SJeff Garzik 
2248c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
2249c6fd2807SJeff Garzik }
2250c6fd2807SJeff Garzik 
2251c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
2252c6fd2807SJeff Garzik {
2253c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
22544447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22557d50b60bSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22567d50b60bSTejun Heo 
22577d50b60bSTejun Heo 	/* Keep track of the currently active link.  It will be used
22587d50b60bSTejun Heo 	 * in completion path to determine whether NCQ phase is in
22597d50b60bSTejun Heo 	 * progress.
22607d50b60bSTejun Heo 	 */
22617d50b60bSTejun Heo 	pp->active_link = qc->dev->link;
2262c6fd2807SJeff Garzik 
2263c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
2264c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
2265c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
2266c6fd2807SJeff Garzik 
226718f7ba4cSKristen Carlson Accardi 	ahci_sw_activity(qc->dev->link);
226818f7ba4cSKristen Carlson Accardi 
2269c6fd2807SJeff Garzik 	return 0;
2270c6fd2807SJeff Garzik }
2271c6fd2807SJeff Garzik 
22724c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
22734c9bf4e7STejun Heo {
22744c9bf4e7STejun Heo 	struct ahci_port_priv *pp = qc->ap->private_data;
22754c9bf4e7STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
22764c9bf4e7STejun Heo 
22774c9bf4e7STejun Heo 	ata_tf_from_fis(d2h_fis, &qc->result_tf);
22784c9bf4e7STejun Heo 	return true;
22794c9bf4e7STejun Heo }
22804c9bf4e7STejun Heo 
2281c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
2282c6fd2807SJeff Garzik {
22834447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2284c6fd2807SJeff Garzik 
2285c6fd2807SJeff Garzik 	/* turn IRQ off */
2286c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
2287c6fd2807SJeff Garzik }
2288c6fd2807SJeff Garzik 
2289c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
2290c6fd2807SJeff Garzik {
22910d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
22924447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2293c6fd2807SJeff Garzik 	u32 tmp;
2294a7384925SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
2295c6fd2807SJeff Garzik 
2296c6fd2807SJeff Garzik 	/* clear IRQ */
2297c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
2298c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
2299a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
2300c6fd2807SJeff Garzik 
23011c954a4dSTejun Heo 	/* turn IRQ back on */
23021c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
2303c6fd2807SJeff Garzik }
2304c6fd2807SJeff Garzik 
2305c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
2306c6fd2807SJeff Garzik {
2307c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
2308c6fd2807SJeff Garzik 		/* restart engine */
23094447d351STejun Heo 		ahci_stop_engine(ap);
23104447d351STejun Heo 		ahci_start_engine(ap);
2311c6fd2807SJeff Garzik 	}
2312c6fd2807SJeff Garzik 
2313a1efdabaSTejun Heo 	sata_pmp_error_handler(ap);
2314edc93052STejun Heo }
2315edc93052STejun Heo 
2316c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
2317c6fd2807SJeff Garzik {
2318c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
2319c6fd2807SJeff Garzik 
2320c6fd2807SJeff Garzik 	/* make DMA engine forget about the failed command */
2321d2e75dffSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED)
2322*78d5ae39SShane Huang 		ahci_kick_engine(ap);
2323c6fd2807SJeff Garzik }
2324c6fd2807SJeff Garzik 
23257d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap)
23267d50b60bSTejun Heo {
23277d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
23281c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
23297d50b60bSTejun Heo 	u32 cmd;
23307d50b60bSTejun Heo 
23317d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
23327d50b60bSTejun Heo 	cmd |= PORT_CMD_PMP;
23337d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
23341c954a4dSTejun Heo 
23351c954a4dSTejun Heo 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
23361c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
23377d50b60bSTejun Heo }
23387d50b60bSTejun Heo 
23397d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap)
23407d50b60bSTejun Heo {
23417d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
23421c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
23437d50b60bSTejun Heo 	u32 cmd;
23447d50b60bSTejun Heo 
23457d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
23467d50b60bSTejun Heo 	cmd &= ~PORT_CMD_PMP;
23477d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
23481c954a4dSTejun Heo 
23491c954a4dSTejun Heo 	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
23501c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
23517d50b60bSTejun Heo }
23527d50b60bSTejun Heo 
2353028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap)
2354028a2596SAlexey Dobriyan {
2355028a2596SAlexey Dobriyan 	ahci_power_up(ap);
2356028a2596SAlexey Dobriyan 	ahci_start_port(ap);
2357028a2596SAlexey Dobriyan 
2358071f44b1STejun Heo 	if (sata_pmp_attached(ap))
23597d50b60bSTejun Heo 		ahci_pmp_attach(ap);
23607d50b60bSTejun Heo 	else
23617d50b60bSTejun Heo 		ahci_pmp_detach(ap);
23627d50b60bSTejun Heo 
2363028a2596SAlexey Dobriyan 	return 0;
2364028a2596SAlexey Dobriyan }
2365028a2596SAlexey Dobriyan 
2366438ac6d5STejun Heo #ifdef CONFIG_PM
2367c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
2368c6fd2807SJeff Garzik {
2369c6fd2807SJeff Garzik 	const char *emsg = NULL;
2370c6fd2807SJeff Garzik 	int rc;
2371c6fd2807SJeff Garzik 
23724447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
23738e16f941STejun Heo 	if (rc == 0)
23744447d351STejun Heo 		ahci_power_down(ap);
23758e16f941STejun Heo 	else {
2376c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
2377df69c9c5SJeff Garzik 		ahci_start_port(ap);
2378c6fd2807SJeff Garzik 	}
2379c6fd2807SJeff Garzik 
2380c6fd2807SJeff Garzik 	return rc;
2381c6fd2807SJeff Garzik }
2382c6fd2807SJeff Garzik 
2383c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
2384c6fd2807SJeff Garzik {
2385cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
23869b10ae86STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
23870d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2388c6fd2807SJeff Garzik 	u32 ctl;
2389c6fd2807SJeff Garzik 
23909b10ae86STejun Heo 	if (mesg.event & PM_EVENT_SUSPEND &&
23919b10ae86STejun Heo 	    hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
23929b10ae86STejun Heo 		dev_printk(KERN_ERR, &pdev->dev,
23939b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
23949b10ae86STejun Heo 		return -EIO;
23959b10ae86STejun Heo 	}
23969b10ae86STejun Heo 
23973a2d5b70SRafael J. Wysocki 	if (mesg.event & PM_EVENT_SLEEP) {
2398c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
2399c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
2400c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
2401c6fd2807SJeff Garzik 		 */
2402c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
2403c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
2404c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
2405c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
2406c6fd2807SJeff Garzik 	}
2407c6fd2807SJeff Garzik 
2408c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
2409c6fd2807SJeff Garzik }
2410c6fd2807SJeff Garzik 
2411c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
2412c6fd2807SJeff Garzik {
2413cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
2414c6fd2807SJeff Garzik 	int rc;
2415c6fd2807SJeff Garzik 
2416553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
2417553c4aa6STejun Heo 	if (rc)
2418553c4aa6STejun Heo 		return rc;
2419c6fd2807SJeff Garzik 
2420c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
24214447d351STejun Heo 		rc = ahci_reset_controller(host);
2422c6fd2807SJeff Garzik 		if (rc)
2423c6fd2807SJeff Garzik 			return rc;
2424c6fd2807SJeff Garzik 
24254447d351STejun Heo 		ahci_init_controller(host);
2426c6fd2807SJeff Garzik 	}
2427c6fd2807SJeff Garzik 
2428cca3974eSJeff Garzik 	ata_host_resume(host);
2429c6fd2807SJeff Garzik 
2430c6fd2807SJeff Garzik 	return 0;
2431c6fd2807SJeff Garzik }
2432438ac6d5STejun Heo #endif
2433c6fd2807SJeff Garzik 
2434c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
2435c6fd2807SJeff Garzik {
2436cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
2437c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
2438c6fd2807SJeff Garzik 	void *mem;
2439c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
2440c6fd2807SJeff Garzik 
244124dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
2442c6fd2807SJeff Garzik 	if (!pp)
2443c6fd2807SJeff Garzik 		return -ENOMEM;
2444c6fd2807SJeff Garzik 
244524dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
244624dc5f33STejun Heo 				  GFP_KERNEL);
244724dc5f33STejun Heo 	if (!mem)
2448c6fd2807SJeff Garzik 		return -ENOMEM;
2449c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
2450c6fd2807SJeff Garzik 
2451c6fd2807SJeff Garzik 	/*
2452c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
2453c6fd2807SJeff Garzik 	 * 32 bytes each in size
2454c6fd2807SJeff Garzik 	 */
2455c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
2456c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
2457c6fd2807SJeff Garzik 
2458c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
2459c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
2460c6fd2807SJeff Garzik 
2461c6fd2807SJeff Garzik 	/*
2462c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
2463c6fd2807SJeff Garzik 	 */
2464c6fd2807SJeff Garzik 	pp->rx_fis = mem;
2465c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
2466c6fd2807SJeff Garzik 
2467c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
2468c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
2469c6fd2807SJeff Garzik 
2470c6fd2807SJeff Garzik 	/*
2471c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
2472c6fd2807SJeff Garzik 	 * and its scatter-gather table
2473c6fd2807SJeff Garzik 	 */
2474c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
2475c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
2476c6fd2807SJeff Garzik 
2477a7384925SKristen Carlson Accardi 	/*
2478a7384925SKristen Carlson Accardi 	 * Save off initial list of interrupts to be enabled.
2479a7384925SKristen Carlson Accardi 	 * This could be changed later
2480a7384925SKristen Carlson Accardi 	 */
2481a7384925SKristen Carlson Accardi 	pp->intr_mask = DEF_PORT_IRQ;
2482a7384925SKristen Carlson Accardi 
2483c6fd2807SJeff Garzik 	ap->private_data = pp;
2484c6fd2807SJeff Garzik 
2485df69c9c5SJeff Garzik 	/* engage engines, captain */
2486df69c9c5SJeff Garzik 	return ahci_port_resume(ap);
2487c6fd2807SJeff Garzik }
2488c6fd2807SJeff Garzik 
2489c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
2490c6fd2807SJeff Garzik {
2491c6fd2807SJeff Garzik 	const char *emsg = NULL;
2492c6fd2807SJeff Garzik 	int rc;
2493c6fd2807SJeff Garzik 
2494c6fd2807SJeff Garzik 	/* de-initialize port */
24954447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
2496c6fd2807SJeff Garzik 	if (rc)
2497c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
2498c6fd2807SJeff Garzik }
2499c6fd2807SJeff Garzik 
25004447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
2501c6fd2807SJeff Garzik {
2502c6fd2807SJeff Garzik 	int rc;
2503c6fd2807SJeff Garzik 
2504c6fd2807SJeff Garzik 	if (using_dac &&
25056a35528aSYang Hongyang 	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
25066a35528aSYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
2507c6fd2807SJeff Garzik 		if (rc) {
2508284901a9SYang Hongyang 			rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
2509c6fd2807SJeff Garzik 			if (rc) {
2510c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
2511c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
2512c6fd2807SJeff Garzik 				return rc;
2513c6fd2807SJeff Garzik 			}
2514c6fd2807SJeff Garzik 		}
2515c6fd2807SJeff Garzik 	} else {
2516284901a9SYang Hongyang 		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
2517c6fd2807SJeff Garzik 		if (rc) {
2518c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2519c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
2520c6fd2807SJeff Garzik 			return rc;
2521c6fd2807SJeff Garzik 		}
2522284901a9SYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
2523c6fd2807SJeff Garzik 		if (rc) {
2524c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2525c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
2526c6fd2807SJeff Garzik 			return rc;
2527c6fd2807SJeff Garzik 		}
2528c6fd2807SJeff Garzik 	}
2529c6fd2807SJeff Garzik 	return 0;
2530c6fd2807SJeff Garzik }
2531c6fd2807SJeff Garzik 
25324447d351STejun Heo static void ahci_print_info(struct ata_host *host)
2533c6fd2807SJeff Garzik {
25344447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
25354447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
25364447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2537c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
2538c6fd2807SJeff Garzik 	const char *speed_s;
2539c6fd2807SJeff Garzik 	u16 cc;
2540c6fd2807SJeff Garzik 	const char *scc_s;
2541c6fd2807SJeff Garzik 
2542c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
2543c6fd2807SJeff Garzik 	cap = hpriv->cap;
2544c6fd2807SJeff Garzik 	impl = hpriv->port_map;
2545c6fd2807SJeff Garzik 
2546c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
2547c6fd2807SJeff Garzik 	if (speed == 1)
2548c6fd2807SJeff Garzik 		speed_s = "1.5";
2549c6fd2807SJeff Garzik 	else if (speed == 2)
2550c6fd2807SJeff Garzik 		speed_s = "3";
25518522ee25SShane Huang 	else if (speed == 3)
25528522ee25SShane Huang 		speed_s = "6";
2553c6fd2807SJeff Garzik 	else
2554c6fd2807SJeff Garzik 		speed_s = "?";
2555c6fd2807SJeff Garzik 
2556c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
2557c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
2558c6fd2807SJeff Garzik 		scc_s = "IDE";
2559c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
2560c6fd2807SJeff Garzik 		scc_s = "SATA";
2561c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
2562c6fd2807SJeff Garzik 		scc_s = "RAID";
2563c6fd2807SJeff Garzik 	else
2564c6fd2807SJeff Garzik 		scc_s = "unknown";
2565c6fd2807SJeff Garzik 
2566c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2567c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
2568c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
2569c6fd2807SJeff Garzik 		,
2570c6fd2807SJeff Garzik 
2571c6fd2807SJeff Garzik 		(vers >> 24) & 0xff,
2572c6fd2807SJeff Garzik 		(vers >> 16) & 0xff,
2573c6fd2807SJeff Garzik 		(vers >> 8) & 0xff,
2574c6fd2807SJeff Garzik 		vers & 0xff,
2575c6fd2807SJeff Garzik 
2576c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
2577c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
2578c6fd2807SJeff Garzik 		speed_s,
2579c6fd2807SJeff Garzik 		impl,
2580c6fd2807SJeff Garzik 		scc_s);
2581c6fd2807SJeff Garzik 
2582c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2583c6fd2807SJeff Garzik 		"flags: "
2584203ef6c4STejun Heo 		"%s%s%s%s%s%s%s"
258518f7ba4cSKristen Carlson Accardi 		"%s%s%s%s%s%s%s"
258618f7ba4cSKristen Carlson Accardi 		"%s\n"
2587c6fd2807SJeff Garzik 		,
2588c6fd2807SJeff Garzik 
2589c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
2590c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
2591203ef6c4STejun Heo 		cap & (1 << 29) ? "sntf " : "",
2592c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
2593c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
2594c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
2595c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
2596c6fd2807SJeff Garzik 
2597c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
2598c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
2599c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
2600c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
2601c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
2602c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
260318f7ba4cSKristen Carlson Accardi 		cap & (1 << 13) ? "part " : "",
260418f7ba4cSKristen Carlson Accardi 		cap & (1 << 6) ? "ems ": ""
2605c6fd2807SJeff Garzik 		);
2606c6fd2807SJeff Garzik }
2607c6fd2807SJeff Garzik 
2608edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2609edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
2610edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
2611edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
2612edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
2613edc93052STejun Heo  * other configuration).
2614edc93052STejun Heo  *
2615edc93052STejun Heo  * When there's no device attached to the first downstream port of the
2616edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
2617edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
2618edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
2619edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2620edc93052STejun Heo  *
2621edc93052STejun Heo  * The following function works around the problem by always using
2622edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
2623edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
2624edc93052STejun Heo  * assumed without follow-up softreset.
2625edc93052STejun Heo  */
2626edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
2627edc93052STejun Heo {
2628edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
2629edc93052STejun Heo 		{
2630edc93052STejun Heo 			.ident = "P5W DH Deluxe",
2631edc93052STejun Heo 			.matches = {
2632edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
2633edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
2634edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2635edc93052STejun Heo 			},
2636edc93052STejun Heo 		},
2637edc93052STejun Heo 		{ }
2638edc93052STejun Heo 	};
2639edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
2640edc93052STejun Heo 
2641edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2642edc93052STejun Heo 	    dmi_check_system(sysids)) {
2643edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
2644edc93052STejun Heo 
2645edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2646edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
2647edc93052STejun Heo 
2648edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
2649edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2650edc93052STejun Heo 	}
2651edc93052STejun Heo }
2652edc93052STejun Heo 
265358a09b38SShane Huang /*
265403d783bfSTejun Heo  * SB600 ahci controller on certain boards can't do 64bit DMA with
265503d783bfSTejun Heo  * older BIOS.
265658a09b38SShane Huang  */
265703d783bfSTejun Heo static bool ahci_sb600_32bit_only(struct pci_dev *pdev)
265858a09b38SShane Huang {
265958a09b38SShane Huang 	static const struct dmi_system_id sysids[] = {
266003d783bfSTejun Heo 		/*
266103d783bfSTejun Heo 		 * The oldest version known to be broken is 0901 and
266203d783bfSTejun Heo 		 * working is 1501 which was released on 2007-10-26.
266303d783bfSTejun Heo 		 * Force 32bit DMA on anything older than 1501.
266403d783bfSTejun Heo 		 * Please read bko#9412 for more info.
266503d783bfSTejun Heo 		 */
266658a09b38SShane Huang 		{
266758a09b38SShane Huang 			.ident = "ASUS M2A-VM",
266858a09b38SShane Huang 			.matches = {
266958a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_VENDOR,
267058a09b38SShane Huang 					  "ASUSTeK Computer INC."),
267158a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
267258a09b38SShane Huang 			},
267303d783bfSTejun Heo 			.driver_data = "20071026",	/* yyyymmdd */
267458a09b38SShane Huang 		},
26751b549dcbSTejun Heo 		/*
26761b549dcbSTejun Heo 		 * It's yet unknown whether more recent BIOS fixes the
26771b549dcbSTejun Heo 		 * problem.  Blacklist the whole board for the time
26781b549dcbSTejun Heo 		 * being.  Please read the following thread for more
26791b549dcbSTejun Heo 		 * info.
26801b549dcbSTejun Heo 		 *
26811b549dcbSTejun Heo 		 * http://thread.gmane.org/gmane.linux.ide/42326
26821b549dcbSTejun Heo 		 */
26831b549dcbSTejun Heo 		{
26841b549dcbSTejun Heo 			.ident = "Gigabyte GA-MA69VM-S2",
26851b549dcbSTejun Heo 			.matches = {
26861b549dcbSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
26871b549dcbSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
26881b549dcbSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "GA-MA69VM-S2"),
26891b549dcbSTejun Heo 			},
26901b549dcbSTejun Heo 		},
269158a09b38SShane Huang 		{ }
269258a09b38SShane Huang 	};
269303d783bfSTejun Heo 	const struct dmi_system_id *match;
269458a09b38SShane Huang 
269503d783bfSTejun Heo 	match = dmi_first_match(sysids);
269658a09b38SShane Huang 	if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
269703d783bfSTejun Heo 	    !match)
269858a09b38SShane Huang 		return false;
269958a09b38SShane Huang 
270003d783bfSTejun Heo 	if (match->driver_data) {
270103d783bfSTejun Heo 		int year, month, date;
270203d783bfSTejun Heo 		char buf[9];
270303d783bfSTejun Heo 
270403d783bfSTejun Heo 		dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
270503d783bfSTejun Heo 		snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
270603d783bfSTejun Heo 
270703d783bfSTejun Heo 		if (strcmp(buf, match->driver_data) >= 0)
270858a09b38SShane Huang 			return false;
270958a09b38SShane Huang 
271003d783bfSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, "
271103d783bfSTejun Heo 			   "forcing 32bit DMA, update BIOS\n", match->ident);
271203d783bfSTejun Heo 	} else
271303d783bfSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev, "%s: this board can't "
271403d783bfSTejun Heo 			   "do 64bit DMA, forcing 32bit\n", match->ident);
271558a09b38SShane Huang 
271658a09b38SShane Huang 	return true;
271758a09b38SShane Huang }
271858a09b38SShane Huang 
27191fd68434SRafael J. Wysocki static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
27201fd68434SRafael J. Wysocki {
27211fd68434SRafael J. Wysocki 	static const struct dmi_system_id broken_systems[] = {
27221fd68434SRafael J. Wysocki 		{
27231fd68434SRafael J. Wysocki 			.ident = "HP Compaq nx6310",
27241fd68434SRafael J. Wysocki 			.matches = {
27251fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27261fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
27271fd68434SRafael J. Wysocki 			},
27281fd68434SRafael J. Wysocki 			/* PCI slot number of the controller */
27291fd68434SRafael J. Wysocki 			.driver_data = (void *)0x1FUL,
27301fd68434SRafael J. Wysocki 		},
2731d2f9c061SMaciej Rutecki 		{
2732d2f9c061SMaciej Rutecki 			.ident = "HP Compaq 6720s",
2733d2f9c061SMaciej Rutecki 			.matches = {
2734d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2735d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
2736d2f9c061SMaciej Rutecki 			},
2737d2f9c061SMaciej Rutecki 			/* PCI slot number of the controller */
2738d2f9c061SMaciej Rutecki 			.driver_data = (void *)0x1FUL,
2739d2f9c061SMaciej Rutecki 		},
27401fd68434SRafael J. Wysocki 
27411fd68434SRafael J. Wysocki 		{ }	/* terminate list */
27421fd68434SRafael J. Wysocki 	};
27431fd68434SRafael J. Wysocki 	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
27441fd68434SRafael J. Wysocki 
27451fd68434SRafael J. Wysocki 	if (dmi) {
27461fd68434SRafael J. Wysocki 		unsigned long slot = (unsigned long)dmi->driver_data;
27471fd68434SRafael J. Wysocki 		/* apply the quirk only to on-board controllers */
27481fd68434SRafael J. Wysocki 		return slot == PCI_SLOT(pdev->devfn);
27491fd68434SRafael J. Wysocki 	}
27501fd68434SRafael J. Wysocki 
27511fd68434SRafael J. Wysocki 	return false;
27521fd68434SRafael J. Wysocki }
27531fd68434SRafael J. Wysocki 
27549b10ae86STejun Heo static bool ahci_broken_suspend(struct pci_dev *pdev)
27559b10ae86STejun Heo {
27569b10ae86STejun Heo 	static const struct dmi_system_id sysids[] = {
27579b10ae86STejun Heo 		/*
27589b10ae86STejun Heo 		 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
27599b10ae86STejun Heo 		 * to the harddisk doesn't become online after
27609b10ae86STejun Heo 		 * resuming from STR.  Warn and fail suspend.
27619b10ae86STejun Heo 		 */
27629b10ae86STejun Heo 		{
27639b10ae86STejun Heo 			.ident = "dv4",
27649b10ae86STejun Heo 			.matches = {
27659b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27669b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
27679b10ae86STejun Heo 					  "HP Pavilion dv4 Notebook PC"),
27689b10ae86STejun Heo 			},
27699b10ae86STejun Heo 			.driver_data = "F.30", /* cutoff BIOS version */
27709b10ae86STejun Heo 		},
27719b10ae86STejun Heo 		{
27729b10ae86STejun Heo 			.ident = "dv5",
27739b10ae86STejun Heo 			.matches = {
27749b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27759b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
27769b10ae86STejun Heo 					  "HP Pavilion dv5 Notebook PC"),
27779b10ae86STejun Heo 			},
27789b10ae86STejun Heo 			.driver_data = "F.16", /* cutoff BIOS version */
27799b10ae86STejun Heo 		},
27809b10ae86STejun Heo 		{
27819b10ae86STejun Heo 			.ident = "dv6",
27829b10ae86STejun Heo 			.matches = {
27839b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27849b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
27859b10ae86STejun Heo 					  "HP Pavilion dv6 Notebook PC"),
27869b10ae86STejun Heo 			},
27879b10ae86STejun Heo 			.driver_data = "F.21",	/* cutoff BIOS version */
27889b10ae86STejun Heo 		},
27899b10ae86STejun Heo 		{
27909b10ae86STejun Heo 			.ident = "HDX18",
27919b10ae86STejun Heo 			.matches = {
27929b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27939b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
27949b10ae86STejun Heo 					  "HP HDX18 Notebook PC"),
27959b10ae86STejun Heo 			},
27969b10ae86STejun Heo 			.driver_data = "F.23",	/* cutoff BIOS version */
27979b10ae86STejun Heo 		},
27989b10ae86STejun Heo 		{ }	/* terminate list */
27999b10ae86STejun Heo 	};
28009b10ae86STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
28019b10ae86STejun Heo 	const char *ver;
28029b10ae86STejun Heo 
28039b10ae86STejun Heo 	if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
28049b10ae86STejun Heo 		return false;
28059b10ae86STejun Heo 
28069b10ae86STejun Heo 	ver = dmi_get_system_info(DMI_BIOS_VERSION);
28079b10ae86STejun Heo 
28089b10ae86STejun Heo 	return !ver || strcmp(ver, dmi->driver_data) < 0;
28099b10ae86STejun Heo }
28109b10ae86STejun Heo 
28115594639aSTejun Heo static bool ahci_broken_online(struct pci_dev *pdev)
28125594639aSTejun Heo {
28135594639aSTejun Heo #define ENCODE_BUSDEVFN(bus, slot, func)			\
28145594639aSTejun Heo 	(void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
28155594639aSTejun Heo 	static const struct dmi_system_id sysids[] = {
28165594639aSTejun Heo 		/*
28175594639aSTejun Heo 		 * There are several gigabyte boards which use
28185594639aSTejun Heo 		 * SIMG5723s configured as hardware RAID.  Certain
28195594639aSTejun Heo 		 * 5723 firmware revisions shipped there keep the link
28205594639aSTejun Heo 		 * online but fail to answer properly to SRST or
28215594639aSTejun Heo 		 * IDENTIFY when no device is attached downstream
28225594639aSTejun Heo 		 * causing libata to retry quite a few times leading
28235594639aSTejun Heo 		 * to excessive detection delay.
28245594639aSTejun Heo 		 *
28255594639aSTejun Heo 		 * As these firmwares respond to the second reset try
28265594639aSTejun Heo 		 * with invalid device signature, considering unknown
28275594639aSTejun Heo 		 * sig as offline works around the problem acceptably.
28285594639aSTejun Heo 		 */
28295594639aSTejun Heo 		{
28305594639aSTejun Heo 			.ident = "EP45-DQ6",
28315594639aSTejun Heo 			.matches = {
28325594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
28335594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
28345594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
28355594639aSTejun Heo 			},
28365594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
28375594639aSTejun Heo 		},
28385594639aSTejun Heo 		{
28395594639aSTejun Heo 			.ident = "EP45-DS5",
28405594639aSTejun Heo 			.matches = {
28415594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
28425594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
28435594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
28445594639aSTejun Heo 			},
28455594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
28465594639aSTejun Heo 		},
28475594639aSTejun Heo 		{ }	/* terminate list */
28485594639aSTejun Heo 	};
28495594639aSTejun Heo #undef ENCODE_BUSDEVFN
28505594639aSTejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
28515594639aSTejun Heo 	unsigned int val;
28525594639aSTejun Heo 
28535594639aSTejun Heo 	if (!dmi)
28545594639aSTejun Heo 		return false;
28555594639aSTejun Heo 
28565594639aSTejun Heo 	val = (unsigned long)dmi->driver_data;
28575594639aSTejun Heo 
28585594639aSTejun Heo 	return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
28595594639aSTejun Heo }
28605594639aSTejun Heo 
2861c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2862c6fd2807SJeff Garzik {
2863c6fd2807SJeff Garzik 	static int printed_version;
2864e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
2865e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
28664447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
286724dc5f33STejun Heo 	struct device *dev = &pdev->dev;
2868c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
28694447d351STejun Heo 	struct ata_host *host;
2870837f5f8fSTejun Heo 	int n_ports, i, rc;
2871c6fd2807SJeff Garzik 
2872c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2873c6fd2807SJeff Garzik 
2874c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
2875c6fd2807SJeff Garzik 
2876c6fd2807SJeff Garzik 	if (!printed_version++)
2877c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
2878c6fd2807SJeff Garzik 
28795b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
28805b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
28815b66c829SAlan Cox 	   AHCI stays out of the way */
28825b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
28835b66c829SAlan Cox 		return -ENODEV;
28845b66c829SAlan Cox 
28854447d351STejun Heo 	/* acquire resources */
288624dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
2887c6fd2807SJeff Garzik 	if (rc)
2888c6fd2807SJeff Garzik 		return rc;
2889c6fd2807SJeff Garzik 
2890dea55137STejun Heo 	/* AHCI controllers often implement SFF compatible interface.
2891dea55137STejun Heo 	 * Grab all PCI BARs just in case.
2892dea55137STejun Heo 	 */
2893dea55137STejun Heo 	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
28940d5ff566STejun Heo 	if (rc == -EBUSY)
289524dc5f33STejun Heo 		pcim_pin_device(pdev);
28960d5ff566STejun Heo 	if (rc)
289724dc5f33STejun Heo 		return rc;
2898c6fd2807SJeff Garzik 
2899c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
2900c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
2901c4f7792cSTejun Heo 		u8 map;
2902c4f7792cSTejun Heo 
2903c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
2904c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
2905c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
2906c4f7792cSTejun Heo 		 */
2907c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
2908c4f7792cSTejun Heo 		if (map & 0x3) {
2909c4f7792cSTejun Heo 			dev_printk(KERN_INFO, &pdev->dev, "controller is in "
2910c4f7792cSTejun Heo 				   "combined mode, can't enable AHCI mode\n");
2911c4f7792cSTejun Heo 			return -ENODEV;
2912c4f7792cSTejun Heo 		}
2913c4f7792cSTejun Heo 	}
2914c4f7792cSTejun Heo 
291524dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
291624dc5f33STejun Heo 	if (!hpriv)
291724dc5f33STejun Heo 		return -ENOMEM;
2918417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
2919417a1a6dSTejun Heo 
2920e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
2921e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
2922e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
2923e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
2924e297d99eSTejun Heo 
2925e427fe04SShane Huang 	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
2926e427fe04SShane Huang 	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
2927e427fe04SShane Huang 		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
2928e427fe04SShane Huang 
292903d783bfSTejun Heo 	/* apply sb600 32bit only quirk */
293003d783bfSTejun Heo 	if (ahci_sb600_32bit_only(pdev))
293158a09b38SShane Huang 		hpriv->flags |= AHCI_HFLAG_32BIT_ONLY;
293258a09b38SShane Huang 
2933a5bfc471STejun Heo 	if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
2934a5bfc471STejun Heo 		pci_enable_msi(pdev);
2935c6fd2807SJeff Garzik 
29364447d351STejun Heo 	/* save initial config */
2937417a1a6dSTejun Heo 	ahci_save_initial_config(pdev, hpriv);
2938c6fd2807SJeff Garzik 
29394447d351STejun Heo 	/* prepare host */
2940274c1fdeSTejun Heo 	if (hpriv->cap & HOST_CAP_NCQ)
2941388539f3SShaohua Li 		pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA;
29424447d351STejun Heo 
29437d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
29447d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
29457d50b60bSTejun Heo 
294618f7ba4cSKristen Carlson Accardi 	if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) {
294718f7ba4cSKristen Carlson Accardi 		u8 messages;
294818f7ba4cSKristen Carlson Accardi 		void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
294918f7ba4cSKristen Carlson Accardi 		u32 em_loc = readl(mmio + HOST_EM_LOC);
295018f7ba4cSKristen Carlson Accardi 		u32 em_ctl = readl(mmio + HOST_EM_CTL);
295118f7ba4cSKristen Carlson Accardi 
295287943acfSDavid Milburn 		messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
295318f7ba4cSKristen Carlson Accardi 
295418f7ba4cSKristen Carlson Accardi 		/* we only support LED message type right now */
295518f7ba4cSKristen Carlson Accardi 		if ((messages & 0x01) && (ahci_em_messages == 1)) {
295618f7ba4cSKristen Carlson Accardi 			/* store em_loc */
295718f7ba4cSKristen Carlson Accardi 			hpriv->em_loc = ((em_loc >> 16) * 4);
295818f7ba4cSKristen Carlson Accardi 			pi.flags |= ATA_FLAG_EM;
295918f7ba4cSKristen Carlson Accardi 			if (!(em_ctl & EM_CTL_ALHD))
296018f7ba4cSKristen Carlson Accardi 				pi.flags |= ATA_FLAG_SW_ACTIVITY;
296118f7ba4cSKristen Carlson Accardi 		}
296218f7ba4cSKristen Carlson Accardi 	}
296318f7ba4cSKristen Carlson Accardi 
29641fd68434SRafael J. Wysocki 	if (ahci_broken_system_poweroff(pdev)) {
29651fd68434SRafael J. Wysocki 		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
29661fd68434SRafael J. Wysocki 		dev_info(&pdev->dev,
29671fd68434SRafael J. Wysocki 			"quirky BIOS, skipping spindown on poweroff\n");
29681fd68434SRafael J. Wysocki 	}
29691fd68434SRafael J. Wysocki 
29709b10ae86STejun Heo 	if (ahci_broken_suspend(pdev)) {
29719b10ae86STejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
29729b10ae86STejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
29739b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
29749b10ae86STejun Heo 	}
29759b10ae86STejun Heo 
29765594639aSTejun Heo 	if (ahci_broken_online(pdev)) {
29775594639aSTejun Heo 		hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
29785594639aSTejun Heo 		dev_info(&pdev->dev,
29795594639aSTejun Heo 			 "online status unreliable, applying workaround\n");
29805594639aSTejun Heo 	}
29815594639aSTejun Heo 
2982837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
2983837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
2984837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
2985837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
2986837f5f8fSTejun Heo 	 */
2987837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
2988837f5f8fSTejun Heo 
2989837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
29904447d351STejun Heo 	if (!host)
29914447d351STejun Heo 		return -ENOMEM;
29924447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
29934447d351STejun Heo 	host->private_data = hpriv;
29944447d351STejun Heo 
2995f3d7f23fSArjan van de Ven 	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
2996886ad09fSArjan van de Ven 		host->flags |= ATA_HOST_PARALLEL_SCAN;
2997f3d7f23fSArjan van de Ven 	else
2998f3d7f23fSArjan van de Ven 		printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
2999886ad09fSArjan van de Ven 
300018f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
300118f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
300218f7ba4cSKristen Carlson Accardi 
30034447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
30044447d351STejun Heo 		struct ata_port *ap = host->ports[i];
30054447d351STejun Heo 
3006cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
3007cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
3008cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
3009cbcdd875STejun Heo 
301031556594SKristen Carlson Accardi 		/* set initial link pm policy */
301131556594SKristen Carlson Accardi 		ap->pm_policy = NOT_AVAILABLE;
301231556594SKristen Carlson Accardi 
301318f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
301418f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
301518f7ba4cSKristen Carlson Accardi 			ap->em_message_type = ahci_em_messages;
301618f7ba4cSKristen Carlson Accardi 
301718f7ba4cSKristen Carlson Accardi 
3018dab632e8SJeff Garzik 		/* disabled/not-implemented port */
3019350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
3020dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
30214447d351STejun Heo 	}
3022c6fd2807SJeff Garzik 
3023edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
3024edc93052STejun Heo 	ahci_p5wdh_workaround(host);
3025edc93052STejun Heo 
3026c6fd2807SJeff Garzik 	/* initialize adapter */
30274447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
3028c6fd2807SJeff Garzik 	if (rc)
302924dc5f33STejun Heo 		return rc;
3030c6fd2807SJeff Garzik 
30314447d351STejun Heo 	rc = ahci_reset_controller(host);
30324447d351STejun Heo 	if (rc)
30334447d351STejun Heo 		return rc;
3034c6fd2807SJeff Garzik 
30354447d351STejun Heo 	ahci_init_controller(host);
30364447d351STejun Heo 	ahci_print_info(host);
3037c6fd2807SJeff Garzik 
30384447d351STejun Heo 	pci_set_master(pdev);
30394447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
30404447d351STejun Heo 				 &ahci_sht);
3041c6fd2807SJeff Garzik }
3042c6fd2807SJeff Garzik 
3043c6fd2807SJeff Garzik static int __init ahci_init(void)
3044c6fd2807SJeff Garzik {
3045c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
3046c6fd2807SJeff Garzik }
3047c6fd2807SJeff Garzik 
3048c6fd2807SJeff Garzik static void __exit ahci_exit(void)
3049c6fd2807SJeff Garzik {
3050c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
3051c6fd2807SJeff Garzik }
3052c6fd2807SJeff Garzik 
3053c6fd2807SJeff Garzik 
3054c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
3055c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
3056c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
3057c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
3058c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
3059c6fd2807SJeff Garzik 
3060c6fd2807SJeff Garzik module_init(ahci_init);
3061c6fd2807SJeff Garzik module_exit(ahci_exit);
3062