xref: /openbmc/linux/drivers/ata/ahci.c (revision 5594639aab8b5614cb27a3e5b2b627505cbcd137)
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 */
222*5594639aSTejun Heo 	AHCI_HFLAG_SRST_TOUT_IS_OFFLINE	= (1 << 11), /* treat SRST timeout as
223*5594639aSTejun 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 
332ee959b00STony Jones static struct device_attribute *ahci_shost_attrs[] = {
333ee959b00STony Jones 	&dev_attr_link_power_management_policy,
33418f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message_type,
33518f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message,
33618f7ba4cSKristen Carlson Accardi 	NULL
33718f7ba4cSKristen Carlson Accardi };
33818f7ba4cSKristen Carlson Accardi 
33918f7ba4cSKristen Carlson Accardi static struct device_attribute *ahci_sdev_attrs[] = {
34018f7ba4cSKristen Carlson Accardi 	&dev_attr_sw_activity,
34145fabbb7SElias Oltmanns 	&dev_attr_unload_heads,
34231556594SKristen Carlson Accardi 	NULL
34331556594SKristen Carlson Accardi };
34431556594SKristen Carlson Accardi 
345c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
34668d1d07bSTejun Heo 	ATA_NCQ_SHT(DRV_NAME),
347c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
348c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
349c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
35031556594SKristen Carlson Accardi 	.shost_attrs		= ahci_shost_attrs,
35118f7ba4cSKristen Carlson Accardi 	.sdev_attrs		= ahci_sdev_attrs,
352c6fd2807SJeff Garzik };
353c6fd2807SJeff Garzik 
354029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = {
355029cfd6bSTejun Heo 	.inherits		= &sata_pmp_port_ops,
356029cfd6bSTejun Heo 
3577d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
358c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
359c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
3604c9bf4e7STejun Heo 	.qc_fill_rtf		= ahci_qc_fill_rtf,
361c6fd2807SJeff Garzik 
362c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
363c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
364a1efdabaSTejun Heo 	.softreset		= ahci_softreset,
365a1efdabaSTejun Heo 	.hardreset		= ahci_hardreset,
366a1efdabaSTejun Heo 	.postreset		= ahci_postreset,
367071f44b1STejun Heo 	.pmp_softreset		= ahci_softreset,
368c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
369c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
370029cfd6bSTejun Heo 	.dev_config		= ahci_dev_config,
371c6fd2807SJeff Garzik 
372029cfd6bSTejun Heo 	.scr_read		= ahci_scr_read,
373029cfd6bSTejun Heo 	.scr_write		= ahci_scr_write,
3747d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
3757d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3767d50b60bSTejun Heo 
377029cfd6bSTejun Heo 	.enable_pm		= ahci_enable_alpm,
378029cfd6bSTejun Heo 	.disable_pm		= ahci_disable_alpm,
37918f7ba4cSKristen Carlson Accardi 	.em_show		= ahci_led_show,
38018f7ba4cSKristen Carlson Accardi 	.em_store		= ahci_led_store,
38118f7ba4cSKristen Carlson Accardi 	.sw_activity_show	= ahci_activity_show,
38218f7ba4cSKristen Carlson Accardi 	.sw_activity_store	= ahci_activity_store,
383438ac6d5STejun Heo #ifdef CONFIG_PM
384c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
385c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
386438ac6d5STejun Heo #endif
387c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
388c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
389c6fd2807SJeff Garzik };
390c6fd2807SJeff Garzik 
391029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
392029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
393a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
394ad616ffbSTejun Heo };
395ad616ffbSTejun Heo 
396029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
397029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
398a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
399edc93052STejun Heo };
400edc93052STejun Heo 
401bd17243aSShane Huang static struct ata_port_operations ahci_sb600_ops = {
402bd17243aSShane Huang 	.inherits		= &ahci_ops,
403bd17243aSShane Huang 	.softreset		= ahci_sb600_softreset,
404bd17243aSShane Huang 	.pmp_softreset		= ahci_sb600_softreset,
405bd17243aSShane Huang };
406bd17243aSShane Huang 
407417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
408417a1a6dSTejun Heo 
409c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
4104da646b7SJeff Garzik 	[board_ahci] =
411c6fd2807SJeff Garzik 	{
4121188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
41314bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
414469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
415c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
416c6fd2807SJeff Garzik 	},
4174da646b7SJeff Garzik 	[board_ahci_vt8251] =
418c6fd2807SJeff Garzik 	{
4196949b914STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
420417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
42114bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
422469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
423ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
424c6fd2807SJeff Garzik 	},
4254da646b7SJeff Garzik 	[board_ahci_ign_iferr] =
42641669553STejun Heo 	{
427417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
428417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
42914bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
430469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
43141669553STejun Heo 		.port_ops	= &ahci_ops,
43241669553STejun Heo 	},
4334da646b7SJeff Garzik 	[board_ahci_sb600] =
43455a61604SConke Hu 	{
435417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
43658a09b38SShane Huang 				 AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255),
437417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
43814bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
439469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
440bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
44155a61604SConke Hu 	},
4424da646b7SJeff Garzik 	[board_ahci_mv] =
443cd70c266SJeff Garzik 	{
444417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
44517248461STejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
446cd70c266SJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
447417a1a6dSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
44814bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
449cd70c266SJeff Garzik 		.udma_mask	= ATA_UDMA6,
450cd70c266SJeff Garzik 		.port_ops	= &ahci_ops,
451cd70c266SJeff Garzik 	},
4524da646b7SJeff Garzik 	[board_ahci_sb700] =	/* for SB700 and SB800 */
453e39fc8c9SShane Huang 	{
454bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
455e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
45614bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
457e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
458bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
459e39fc8c9SShane Huang 	},
4604da646b7SJeff Garzik 	[board_ahci_mcp65] =
461e297d99eSTejun Heo 	{
462e297d99eSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
463e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
46414bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
465e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
466e297d99eSTejun Heo 		.port_ops	= &ahci_ops,
467e297d99eSTejun Heo 	},
4684da646b7SJeff Garzik 	[board_ahci_nopmp] =
4699a3b103cSTejun Heo 	{
4709a3b103cSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP),
4719a3b103cSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
47214bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
4739a3b103cSTejun Heo 		.udma_mask	= ATA_UDMA6,
4749a3b103cSTejun Heo 		.port_ops	= &ahci_ops,
4759a3b103cSTejun Heo 	},
476aa431dd3STejun Heo 	/* board_ahci_yesncq */
477aa431dd3STejun Heo 	{
478aa431dd3STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
479aa431dd3STejun Heo 		.flags		= AHCI_FLAG_COMMON,
480aa431dd3STejun Heo 		.pio_mask	= ATA_PIO4,
481aa431dd3STejun Heo 		.udma_mask	= ATA_UDMA6,
482aa431dd3STejun Heo 		.port_ops	= &ahci_ops,
483aa431dd3STejun Heo 	},
484c6fd2807SJeff Garzik };
485c6fd2807SJeff Garzik 
486c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
487c6fd2807SJeff Garzik 	/* Intel */
48854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
48954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
49054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
49154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
49254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
49382490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
49454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
49554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
49654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
49754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
4987a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
4997a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
5007a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
5017a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
5027a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
5037a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
5047a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
5057a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
5067a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
5077a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
5087a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
5097a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
5107a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
5117a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
5127a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
5137a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
5147a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
515d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
516d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
51716ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
518b2dde6afSMark Goodwin 	{ PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
51916ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
520c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
521c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
522adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
5238e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
524c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
525adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
5268e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
527c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
528c6fd2807SJeff Garzik 
529e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
530e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
531e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
532c6fd2807SJeff Garzik 
533c6fd2807SJeff Garzik 	/* ATI */
534c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
535e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
536e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
537e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
538e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
539e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
540e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
541c6fd2807SJeff Garzik 
542c6fd2807SJeff Garzik 	/* VIA */
54354bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
544bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
545c6fd2807SJeff Garzik 
546c6fd2807SJeff Garzik 	/* NVIDIA */
547e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
548e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
549e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
550e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
551e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
552e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
553e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
554e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
555aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq },	/* MCP67 */
556aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq },	/* MCP67 */
557aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq },	/* MCP67 */
558aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq },	/* MCP67 */
559aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq },	/* MCP67 */
560aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq },	/* MCP67 */
561aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq },	/* MCP67 */
562aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq },	/* MCP67 */
563aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq },	/* MCP67 */
564aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq },	/* MCP67 */
565aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq },	/* MCP67 */
566aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq },	/* MCP67 */
567aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq },	/* MCP73 */
568aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq },	/* MCP73 */
569aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq },	/* MCP73 */
570aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq },	/* MCP73 */
571aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq },	/* MCP73 */
572aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq },	/* MCP73 */
573aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq },	/* MCP73 */
574aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq },	/* MCP73 */
575aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq },	/* MCP73 */
576aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq },	/* MCP73 */
577aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq },	/* MCP73 */
578aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq },	/* MCP73 */
5790522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },		/* MCP77 */
5800522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },		/* MCP77 */
5810522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },		/* MCP77 */
5820522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },		/* MCP77 */
5830522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },		/* MCP77 */
5840522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },		/* MCP77 */
5850522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },		/* MCP77 */
5860522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },		/* MCP77 */
5870522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },		/* MCP77 */
5880522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
5890522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
5900522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
5916ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci },		/* MCP79 */
5926ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci },		/* MCP79 */
5936ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci },		/* MCP79 */
5946ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci },		/* MCP79 */
5957100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
5967100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
5977100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
5987100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
5997100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
6007100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
6017100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
6027100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
6037adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci },		/* MCP89 */
6047adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci },		/* MCP89 */
6057adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci },		/* MCP89 */
6067adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci },		/* MCP89 */
6077adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci },		/* MCP89 */
6087adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci },		/* MCP89 */
6097adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci },		/* MCP89 */
6107adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci },		/* MCP89 */
6117adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci },		/* MCP89 */
6127adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci },		/* MCP89 */
6137adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci },		/* MCP89 */
6147adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci },		/* MCP89 */
615c6fd2807SJeff Garzik 
616c6fd2807SJeff Garzik 	/* SiS */
61720e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
61820e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
61920e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
620c6fd2807SJeff Garzik 
621cd70c266SJeff Garzik 	/* Marvell */
622cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
623c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
624cd70c266SJeff Garzik 
625c77a036bSMark Nelson 	/* Promise */
626c77a036bSMark Nelson 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
627c77a036bSMark Nelson 
628415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
629415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
630c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
631415ae2b5SJeff Garzik 
632c6fd2807SJeff Garzik 	{ }	/* terminate list */
633c6fd2807SJeff Garzik };
634c6fd2807SJeff Garzik 
635c6fd2807SJeff Garzik 
636c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
637c6fd2807SJeff Garzik 	.name			= DRV_NAME,
638c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
639c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
64024dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
641438ac6d5STejun Heo #ifdef CONFIG_PM
642c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
643c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
644438ac6d5STejun Heo #endif
645c6fd2807SJeff Garzik };
646c6fd2807SJeff Garzik 
64718f7ba4cSKristen Carlson Accardi static int ahci_em_messages = 1;
64818f7ba4cSKristen Carlson Accardi module_param(ahci_em_messages, int, 0444);
64918f7ba4cSKristen Carlson Accardi /* add other LED protocol types when they become supported */
65018f7ba4cSKristen Carlson Accardi MODULE_PARM_DESC(ahci_em_messages,
65118f7ba4cSKristen Carlson Accardi 	"Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
652c6fd2807SJeff Garzik 
6535b66c829SAlan Cox #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
6545b66c829SAlan Cox static int marvell_enable;
6555b66c829SAlan Cox #else
6565b66c829SAlan Cox static int marvell_enable = 1;
6575b66c829SAlan Cox #endif
6585b66c829SAlan Cox module_param(marvell_enable, int, 0644);
6595b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
6605b66c829SAlan Cox 
6615b66c829SAlan Cox 
66298fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
66398fa4b60STejun Heo {
66498fa4b60STejun Heo 	return (cap & 0x1f) + 1;
66598fa4b60STejun Heo }
66698fa4b60STejun Heo 
667dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host,
668dab632e8SJeff Garzik 					     unsigned int port_no)
669dab632e8SJeff Garzik {
670dab632e8SJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
671dab632e8SJeff Garzik 
672dab632e8SJeff Garzik 	return mmio + 0x100 + (port_no * 0x80);
673dab632e8SJeff Garzik }
674dab632e8SJeff Garzik 
6754447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
676c6fd2807SJeff Garzik {
677dab632e8SJeff Garzik 	return __ahci_port_base(ap->host, ap->port_no);
678c6fd2807SJeff Garzik }
679c6fd2807SJeff Garzik 
680b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio)
681b710a1f4STejun Heo {
68215fe982eSTejun Heo 	int i;
683b710a1f4STejun Heo 	u32 tmp;
684b710a1f4STejun Heo 
685b710a1f4STejun Heo 	/* turn on AHCI_EN */
686b710a1f4STejun Heo 	tmp = readl(mmio + HOST_CTL);
68715fe982eSTejun Heo 	if (tmp & HOST_AHCI_EN)
68815fe982eSTejun Heo 		return;
68915fe982eSTejun Heo 
69015fe982eSTejun Heo 	/* Some controllers need AHCI_EN to be written multiple times.
69115fe982eSTejun Heo 	 * Try a few times before giving up.
69215fe982eSTejun Heo 	 */
69315fe982eSTejun Heo 	for (i = 0; i < 5; i++) {
694b710a1f4STejun Heo 		tmp |= HOST_AHCI_EN;
695b710a1f4STejun Heo 		writel(tmp, mmio + HOST_CTL);
696b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
69715fe982eSTejun Heo 		if (tmp & HOST_AHCI_EN)
69815fe982eSTejun Heo 			return;
69915fe982eSTejun Heo 		msleep(10);
700b710a1f4STejun Heo 	}
70115fe982eSTejun Heo 
70215fe982eSTejun Heo 	WARN_ON(1);
703b710a1f4STejun Heo }
704b710a1f4STejun Heo 
705d447df14STejun Heo /**
706d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
7074447d351STejun Heo  *	@pdev: target PCI device
7084447d351STejun Heo  *	@hpriv: host private area to store config values
709d447df14STejun Heo  *
710d447df14STejun Heo  *	Some registers containing configuration info might be setup by
711d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
712d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
713d447df14STejun Heo  *	can be restored after controller reset.
714d447df14STejun Heo  *
715d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
716d447df14STejun Heo  *
717d447df14STejun Heo  *	LOCKING:
718d447df14STejun Heo  *	None.
719d447df14STejun Heo  */
7204447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
7214447d351STejun Heo 				     struct ahci_host_priv *hpriv)
722d447df14STejun Heo {
7234447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
724d447df14STejun Heo 	u32 cap, port_map;
72517199b18STejun Heo 	int i;
726c40e7cb8SJose Alberto Reguero 	int mv;
727d447df14STejun Heo 
728b710a1f4STejun Heo 	/* make sure AHCI mode is enabled before accessing CAP */
729b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
730b710a1f4STejun Heo 
731d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
732d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
733d447df14STejun Heo 	 */
734d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
735d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
736d447df14STejun Heo 
737274c1fdeSTejun Heo 	/* some chips have errata preventing 64bit use */
738417a1a6dSTejun Heo 	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
739c7a42156STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
740c7a42156STejun Heo 			   "controller can't do 64bit DMA, forcing 32bit\n");
741c7a42156STejun Heo 		cap &= ~HOST_CAP_64;
742c7a42156STejun Heo 	}
743c7a42156STejun Heo 
744417a1a6dSTejun Heo 	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
745274c1fdeSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
746274c1fdeSTejun Heo 			   "controller can't do NCQ, turning off CAP_NCQ\n");
747274c1fdeSTejun Heo 		cap &= ~HOST_CAP_NCQ;
748274c1fdeSTejun Heo 	}
749274c1fdeSTejun Heo 
750e297d99eSTejun Heo 	if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
751e297d99eSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
752e297d99eSTejun Heo 			   "controller can do NCQ, turning on CAP_NCQ\n");
753e297d99eSTejun Heo 		cap |= HOST_CAP_NCQ;
754e297d99eSTejun Heo 	}
755e297d99eSTejun Heo 
756258cd846SRoel Kluin 	if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
7576949b914STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
7586949b914STejun Heo 			   "controller can't do PMP, turning off CAP_PMP\n");
7596949b914STejun Heo 		cap &= ~HOST_CAP_PMP;
7606949b914STejun Heo 	}
7616949b914STejun Heo 
762d799e083STejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
763d799e083STejun Heo 	    port_map != 1) {
764d799e083STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
765d799e083STejun Heo 			   "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
766d799e083STejun Heo 			   port_map, 1);
767d799e083STejun Heo 		port_map = 1;
768d799e083STejun Heo 	}
769d799e083STejun Heo 
770cd70c266SJeff Garzik 	/*
771cd70c266SJeff Garzik 	 * Temporary Marvell 6145 hack: PATA port presence
772cd70c266SJeff Garzik 	 * is asserted through the standard AHCI port
773cd70c266SJeff Garzik 	 * presence register, as bit 4 (counting from 0)
774cd70c266SJeff Garzik 	 */
775417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
776c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
777c40e7cb8SJose Alberto Reguero 			mv = 0x3;
778c40e7cb8SJose Alberto Reguero 		else
779c40e7cb8SJose Alberto Reguero 			mv = 0xf;
780cd70c266SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
781cd70c266SJeff Garzik 			   "MV_AHCI HACK: port_map %x -> %x\n",
782c40e7cb8SJose Alberto Reguero 			   port_map,
783c40e7cb8SJose Alberto Reguero 			   port_map & mv);
7845b66c829SAlan Cox 		dev_printk(KERN_ERR, &pdev->dev,
7855b66c829SAlan Cox 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
786cd70c266SJeff Garzik 
787c40e7cb8SJose Alberto Reguero 		port_map &= mv;
788cd70c266SJeff Garzik 	}
789cd70c266SJeff Garzik 
79017199b18STejun Heo 	/* cross check port_map and cap.n_ports */
7917a234affSTejun Heo 	if (port_map) {
792837f5f8fSTejun Heo 		int map_ports = 0;
79317199b18STejun Heo 
794837f5f8fSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS; i++)
795837f5f8fSTejun Heo 			if (port_map & (1 << i))
796837f5f8fSTejun Heo 				map_ports++;
79717199b18STejun Heo 
798837f5f8fSTejun Heo 		/* If PI has more ports than n_ports, whine, clear
799837f5f8fSTejun Heo 		 * port_map and let it be generated from n_ports.
80017199b18STejun Heo 		 */
801837f5f8fSTejun Heo 		if (map_ports > ahci_nr_ports(cap)) {
8024447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
803837f5f8fSTejun Heo 				   "implemented port map (0x%x) contains more "
804837f5f8fSTejun Heo 				   "ports than nr_ports (%u), using nr_ports\n",
805837f5f8fSTejun Heo 				   port_map, ahci_nr_ports(cap));
8067a234affSTejun Heo 			port_map = 0;
8077a234affSTejun Heo 		}
8087a234affSTejun Heo 	}
8097a234affSTejun Heo 
81017199b18STejun Heo 	/* fabricate port_map from cap.nr_ports */
8117a234affSTejun Heo 	if (!port_map) {
81217199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
8137a234affSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
8147a234affSTejun Heo 			   "forcing PORTS_IMPL to 0x%x\n", port_map);
8157a234affSTejun Heo 
8167a234affSTejun Heo 		/* write the fixed up value to the PI register */
8177a234affSTejun Heo 		hpriv->saved_port_map = port_map;
81817199b18STejun Heo 	}
81917199b18STejun Heo 
820d447df14STejun Heo 	/* record values to use during operation */
821d447df14STejun Heo 	hpriv->cap = cap;
822d447df14STejun Heo 	hpriv->port_map = port_map;
823d447df14STejun Heo }
824d447df14STejun Heo 
825d447df14STejun Heo /**
826d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
8274447d351STejun Heo  *	@host: target ATA host
828d447df14STejun Heo  *
829d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
830d447df14STejun Heo  *
831d447df14STejun Heo  *	LOCKING:
832d447df14STejun Heo  *	None.
833d447df14STejun Heo  */
8344447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
835d447df14STejun Heo {
8364447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
8374447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
8384447d351STejun Heo 
839d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
840d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
841d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
842d447df14STejun Heo }
843d447df14STejun Heo 
844203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
845c6fd2807SJeff Garzik {
846203ef6c4STejun Heo 	static const int offset[] = {
847203ef6c4STejun Heo 		[SCR_STATUS]		= PORT_SCR_STAT,
848203ef6c4STejun Heo 		[SCR_CONTROL]		= PORT_SCR_CTL,
849203ef6c4STejun Heo 		[SCR_ERROR]		= PORT_SCR_ERR,
850203ef6c4STejun Heo 		[SCR_ACTIVE]		= PORT_SCR_ACT,
851203ef6c4STejun Heo 		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
852203ef6c4STejun Heo 	};
853203ef6c4STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
854c6fd2807SJeff Garzik 
855203ef6c4STejun Heo 	if (sc_reg < ARRAY_SIZE(offset) &&
856203ef6c4STejun Heo 	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
857203ef6c4STejun Heo 		return offset[sc_reg];
858da3dbb17STejun Heo 	return 0;
859c6fd2807SJeff Garzik }
860c6fd2807SJeff Garzik 
86182ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
862c6fd2807SJeff Garzik {
86382ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
86482ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
865c6fd2807SJeff Garzik 
866203ef6c4STejun Heo 	if (offset) {
867203ef6c4STejun Heo 		*val = readl(port_mmio + offset);
868203ef6c4STejun Heo 		return 0;
869203ef6c4STejun Heo 	}
870da3dbb17STejun Heo 	return -EINVAL;
871c6fd2807SJeff Garzik }
872c6fd2807SJeff Garzik 
87382ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
874203ef6c4STejun Heo {
87582ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
87682ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
877203ef6c4STejun Heo 
878203ef6c4STejun Heo 	if (offset) {
879203ef6c4STejun Heo 		writel(val, port_mmio + offset);
880da3dbb17STejun Heo 		return 0;
881c6fd2807SJeff Garzik 	}
882203ef6c4STejun Heo 	return -EINVAL;
883203ef6c4STejun Heo }
884c6fd2807SJeff Garzik 
8854447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
886c6fd2807SJeff Garzik {
8874447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
888c6fd2807SJeff Garzik 	u32 tmp;
889c6fd2807SJeff Garzik 
890c6fd2807SJeff Garzik 	/* start DMA */
891c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
892c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
893c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
894c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
895c6fd2807SJeff Garzik }
896c6fd2807SJeff Garzik 
8974447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
898c6fd2807SJeff Garzik {
8994447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
900c6fd2807SJeff Garzik 	u32 tmp;
901c6fd2807SJeff Garzik 
902c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
903c6fd2807SJeff Garzik 
904c6fd2807SJeff Garzik 	/* check if the HBA is idle */
905c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
906c6fd2807SJeff Garzik 		return 0;
907c6fd2807SJeff Garzik 
908c6fd2807SJeff Garzik 	/* setting HBA to idle */
909c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
910c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
911c6fd2807SJeff Garzik 
912c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
913c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
914c6fd2807SJeff Garzik 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
915c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
916c6fd2807SJeff Garzik 		return -EIO;
917c6fd2807SJeff Garzik 
918c6fd2807SJeff Garzik 	return 0;
919c6fd2807SJeff Garzik }
920c6fd2807SJeff Garzik 
9214447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
922c6fd2807SJeff Garzik {
9234447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
9244447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
9254447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
926c6fd2807SJeff Garzik 	u32 tmp;
927c6fd2807SJeff Garzik 
928c6fd2807SJeff Garzik 	/* set FIS registers */
9294447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
9304447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
9314447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
9324447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
933c6fd2807SJeff Garzik 
9344447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
9354447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
9364447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
9374447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
938c6fd2807SJeff Garzik 
939c6fd2807SJeff Garzik 	/* enable FIS reception */
940c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
941c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
942c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
943c6fd2807SJeff Garzik 
944c6fd2807SJeff Garzik 	/* flush */
945c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
946c6fd2807SJeff Garzik }
947c6fd2807SJeff Garzik 
9484447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
949c6fd2807SJeff Garzik {
9504447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
951c6fd2807SJeff Garzik 	u32 tmp;
952c6fd2807SJeff Garzik 
953c6fd2807SJeff Garzik 	/* disable FIS reception */
954c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
955c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
956c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
957c6fd2807SJeff Garzik 
958c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
959c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
960c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
961c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
962c6fd2807SJeff Garzik 		return -EBUSY;
963c6fd2807SJeff Garzik 
964c6fd2807SJeff Garzik 	return 0;
965c6fd2807SJeff Garzik }
966c6fd2807SJeff Garzik 
9674447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
968c6fd2807SJeff Garzik {
9694447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
9704447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
971c6fd2807SJeff Garzik 	u32 cmd;
972c6fd2807SJeff Garzik 
973c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
974c6fd2807SJeff Garzik 
975c6fd2807SJeff Garzik 	/* spin up device */
9764447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
977c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
978c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
979c6fd2807SJeff Garzik 	}
980c6fd2807SJeff Garzik 
981c6fd2807SJeff Garzik 	/* wake up link */
982c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
983c6fd2807SJeff Garzik }
984c6fd2807SJeff Garzik 
98531556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap)
98631556594SKristen Carlson Accardi {
98731556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
98831556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
98931556594SKristen Carlson Accardi 	u32 cmd;
99031556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
99131556594SKristen Carlson Accardi 
99231556594SKristen Carlson Accardi 	/* IPM bits should be disabled by libata-core */
99331556594SKristen Carlson Accardi 	/* get the existing command bits */
99431556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
99531556594SKristen Carlson Accardi 
99631556594SKristen Carlson Accardi 	/* disable ALPM and ASP */
99731556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ASP;
99831556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ALPE;
99931556594SKristen Carlson Accardi 
100031556594SKristen Carlson Accardi 	/* force the interface back to active */
100131556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ICC_ACTIVE;
100231556594SKristen Carlson Accardi 
100331556594SKristen Carlson Accardi 	/* write out new cmd value */
100431556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
100531556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
100631556594SKristen Carlson Accardi 
100731556594SKristen Carlson Accardi 	/* wait 10ms to be sure we've come out of any low power state */
100831556594SKristen Carlson Accardi 	msleep(10);
100931556594SKristen Carlson Accardi 
101031556594SKristen Carlson Accardi 	/* clear out any PhyRdy stuff from interrupt status */
101131556594SKristen Carlson Accardi 	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
101231556594SKristen Carlson Accardi 
101331556594SKristen Carlson Accardi 	/* go ahead and clean out PhyRdy Change from Serror too */
101482ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
101531556594SKristen Carlson Accardi 
101631556594SKristen Carlson Accardi 	/*
101731556594SKristen Carlson Accardi  	 * Clear flag to indicate that we should ignore all PhyRdy
101831556594SKristen Carlson Accardi  	 * state changes
101931556594SKristen Carlson Accardi  	 */
102031556594SKristen Carlson Accardi 	hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
102131556594SKristen Carlson Accardi 
102231556594SKristen Carlson Accardi 	/*
102331556594SKristen Carlson Accardi  	 * Enable interrupts on Phy Ready.
102431556594SKristen Carlson Accardi  	 */
102531556594SKristen Carlson Accardi 	pp->intr_mask |= PORT_IRQ_PHYRDY;
102631556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
102731556594SKristen Carlson Accardi 
102831556594SKristen Carlson Accardi 	/*
102931556594SKristen Carlson Accardi  	 * don't change the link pm policy - we can be called
103031556594SKristen Carlson Accardi  	 * just to turn of link pm temporarily
103131556594SKristen Carlson Accardi  	 */
103231556594SKristen Carlson Accardi }
103331556594SKristen Carlson Accardi 
103431556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
103531556594SKristen Carlson Accardi 	enum link_pm policy)
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 	u32 asp;
104231556594SKristen Carlson Accardi 
104331556594SKristen Carlson Accardi 	/* Make sure the host is capable of link power management */
104431556594SKristen Carlson Accardi 	if (!(hpriv->cap & HOST_CAP_ALPM))
104531556594SKristen Carlson Accardi 		return -EINVAL;
104631556594SKristen Carlson Accardi 
104731556594SKristen Carlson Accardi 	switch (policy) {
104831556594SKristen Carlson Accardi 	case MAX_PERFORMANCE:
104931556594SKristen Carlson Accardi 	case NOT_AVAILABLE:
105031556594SKristen Carlson Accardi 		/*
105131556594SKristen Carlson Accardi  		 * if we came here with NOT_AVAILABLE,
105231556594SKristen Carlson Accardi  		 * it just means this is the first time we
105331556594SKristen Carlson Accardi  		 * have tried to enable - default to max performance,
105431556594SKristen Carlson Accardi  		 * and let the user go to lower power modes on request.
105531556594SKristen Carlson Accardi  		 */
105631556594SKristen Carlson Accardi 		ahci_disable_alpm(ap);
105731556594SKristen Carlson Accardi 		return 0;
105831556594SKristen Carlson Accardi 	case MIN_POWER:
105931556594SKristen Carlson Accardi 		/* configure HBA to enter SLUMBER */
106031556594SKristen Carlson Accardi 		asp = PORT_CMD_ASP;
106131556594SKristen Carlson Accardi 		break;
106231556594SKristen Carlson Accardi 	case MEDIUM_POWER:
106331556594SKristen Carlson Accardi 		/* configure HBA to enter PARTIAL */
106431556594SKristen Carlson Accardi 		asp = 0;
106531556594SKristen Carlson Accardi 		break;
106631556594SKristen Carlson Accardi 	default:
106731556594SKristen Carlson Accardi 		return -EINVAL;
106831556594SKristen Carlson Accardi 	}
106931556594SKristen Carlson Accardi 
107031556594SKristen Carlson Accardi 	/*
107131556594SKristen Carlson Accardi  	 * Disable interrupts on Phy Ready. This keeps us from
107231556594SKristen Carlson Accardi  	 * getting woken up due to spurious phy ready interrupts
107331556594SKristen Carlson Accardi 	 * TBD - Hot plug should be done via polling now, is
107431556594SKristen Carlson Accardi 	 * that even supported?
107531556594SKristen Carlson Accardi  	 */
107631556594SKristen Carlson Accardi 	pp->intr_mask &= ~PORT_IRQ_PHYRDY;
107731556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
107831556594SKristen Carlson Accardi 
107931556594SKristen Carlson Accardi 	/*
108031556594SKristen Carlson Accardi  	 * Set a flag to indicate that we should ignore all PhyRdy
108131556594SKristen Carlson Accardi  	 * state changes since these can happen now whenever we
108231556594SKristen Carlson Accardi  	 * change link state
108331556594SKristen Carlson Accardi  	 */
108431556594SKristen Carlson Accardi 	hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
108531556594SKristen Carlson Accardi 
108631556594SKristen Carlson Accardi 	/* get the existing command bits */
108731556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
108831556594SKristen Carlson Accardi 
108931556594SKristen Carlson Accardi 	/*
109031556594SKristen Carlson Accardi  	 * Set ASP based on Policy
109131556594SKristen Carlson Accardi  	 */
109231556594SKristen Carlson Accardi 	cmd |= asp;
109331556594SKristen Carlson Accardi 
109431556594SKristen Carlson Accardi 	/*
109531556594SKristen Carlson Accardi  	 * Setting this bit will instruct the HBA to aggressively
109631556594SKristen Carlson Accardi  	 * enter a lower power link state when it's appropriate and
109731556594SKristen Carlson Accardi  	 * based on the value set above for ASP
109831556594SKristen Carlson Accardi  	 */
109931556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ALPE;
110031556594SKristen Carlson Accardi 
110131556594SKristen Carlson Accardi 	/* write out new cmd value */
110231556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
110331556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
110431556594SKristen Carlson Accardi 
110531556594SKristen Carlson Accardi 	/* IPM bits should be set by libata-core */
110631556594SKristen Carlson Accardi 	return 0;
110731556594SKristen Carlson Accardi }
110831556594SKristen Carlson Accardi 
1109438ac6d5STejun Heo #ifdef CONFIG_PM
11104447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
1111c6fd2807SJeff Garzik {
11124447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
11134447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1114c6fd2807SJeff Garzik 	u32 cmd, scontrol;
1115c6fd2807SJeff Garzik 
11164447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
111707c53dacSTejun Heo 		return;
1118c6fd2807SJeff Garzik 
111907c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
1120c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
1121c6fd2807SJeff Garzik 	scontrol &= ~0xf;
1122c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
1123c6fd2807SJeff Garzik 
1124c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
112507c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1126c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
1127c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
1128c6fd2807SJeff Garzik }
1129438ac6d5STejun Heo #endif
1130c6fd2807SJeff Garzik 
1131df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap)
1132c6fd2807SJeff Garzik {
113318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
113418f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
113518f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
11364c1e9aa4SDavid Milburn 	ssize_t rc;
11374c1e9aa4SDavid Milburn 	int i;
113818f7ba4cSKristen Carlson Accardi 
1139c6fd2807SJeff Garzik 	/* enable FIS reception */
11404447d351STejun Heo 	ahci_start_fis_rx(ap);
1141c6fd2807SJeff Garzik 
1142c6fd2807SJeff Garzik 	/* enable DMA */
11434447d351STejun Heo 	ahci_start_engine(ap);
114418f7ba4cSKristen Carlson Accardi 
114518f7ba4cSKristen Carlson Accardi 	/* turn on LEDs */
114618f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_EM) {
11471eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE) {
114818f7ba4cSKristen Carlson Accardi 			emp = &pp->em_priv[link->pmp];
11494c1e9aa4SDavid Milburn 
11504c1e9aa4SDavid Milburn 			/* EM Transmit bit maybe busy during init */
1151d50ce07dSTejun Heo 			for (i = 0; i < EM_MAX_RETRY; i++) {
11524c1e9aa4SDavid Milburn 				rc = ahci_transmit_led_message(ap,
11534c1e9aa4SDavid Milburn 							       emp->led_state,
11544c1e9aa4SDavid Milburn 							       4);
11554c1e9aa4SDavid Milburn 				if (rc == -EBUSY)
1156d50ce07dSTejun Heo 					msleep(1);
11574c1e9aa4SDavid Milburn 				else
11584c1e9aa4SDavid Milburn 					break;
11594c1e9aa4SDavid Milburn 			}
116018f7ba4cSKristen Carlson Accardi 		}
116118f7ba4cSKristen Carlson Accardi 	}
116218f7ba4cSKristen Carlson Accardi 
116318f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_SW_ACTIVITY)
11641eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE)
116518f7ba4cSKristen Carlson Accardi 			ahci_init_sw_activity(link);
116618f7ba4cSKristen Carlson Accardi 
1167c6fd2807SJeff Garzik }
1168c6fd2807SJeff Garzik 
11694447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
1170c6fd2807SJeff Garzik {
1171c6fd2807SJeff Garzik 	int rc;
1172c6fd2807SJeff Garzik 
1173c6fd2807SJeff Garzik 	/* disable DMA */
11744447d351STejun Heo 	rc = ahci_stop_engine(ap);
1175c6fd2807SJeff Garzik 	if (rc) {
1176c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
1177c6fd2807SJeff Garzik 		return rc;
1178c6fd2807SJeff Garzik 	}
1179c6fd2807SJeff Garzik 
1180c6fd2807SJeff Garzik 	/* disable FIS reception */
11814447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
1182c6fd2807SJeff Garzik 	if (rc) {
1183c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
1184c6fd2807SJeff Garzik 		return rc;
1185c6fd2807SJeff Garzik 	}
1186c6fd2807SJeff Garzik 
1187c6fd2807SJeff Garzik 	return 0;
1188c6fd2807SJeff Garzik }
1189c6fd2807SJeff Garzik 
11904447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
1191c6fd2807SJeff Garzik {
11924447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
119349f29090STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
11944447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1195d447df14STejun Heo 	u32 tmp;
1196c6fd2807SJeff Garzik 
11973cc3eb11SJeff Garzik 	/* we must be in AHCI mode, before using anything
11983cc3eb11SJeff Garzik 	 * AHCI-specific, such as HOST_RESET.
11993cc3eb11SJeff Garzik 	 */
1200b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
12013cc3eb11SJeff Garzik 
12023cc3eb11SJeff Garzik 	/* global controller reset */
1203a22e6444STejun Heo 	if (!ahci_skip_host_reset) {
1204b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);
1205c6fd2807SJeff Garzik 		if ((tmp & HOST_RESET) == 0) {
1206c6fd2807SJeff Garzik 			writel(tmp | HOST_RESET, mmio + HOST_CTL);
1207c6fd2807SJeff Garzik 			readl(mmio + HOST_CTL); /* flush */
1208c6fd2807SJeff Garzik 		}
1209c6fd2807SJeff Garzik 
121024920c8aSZhang Rui 		/*
121124920c8aSZhang Rui 		 * to perform host reset, OS should set HOST_RESET
121224920c8aSZhang Rui 		 * and poll until this bit is read to be "0".
121324920c8aSZhang Rui 		 * reset must complete within 1 second, or
1214c6fd2807SJeff Garzik 		 * the hardware should be considered fried.
1215c6fd2807SJeff Garzik 		 */
121624920c8aSZhang Rui 		tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
121724920c8aSZhang Rui 					HOST_RESET, 10, 1000);
1218c6fd2807SJeff Garzik 
1219c6fd2807SJeff Garzik 		if (tmp & HOST_RESET) {
12204447d351STejun Heo 			dev_printk(KERN_ERR, host->dev,
1221c6fd2807SJeff Garzik 				   "controller reset failed (0x%x)\n", tmp);
1222c6fd2807SJeff Garzik 			return -EIO;
1223c6fd2807SJeff Garzik 		}
1224c6fd2807SJeff Garzik 
122598fa4b60STejun Heo 		/* turn on AHCI mode */
1226b710a1f4STejun Heo 		ahci_enable_ahci(mmio);
122798fa4b60STejun Heo 
1228a22e6444STejun Heo 		/* Some registers might be cleared on reset.  Restore
1229a22e6444STejun Heo 		 * initial values.
1230a22e6444STejun Heo 		 */
12314447d351STejun Heo 		ahci_restore_initial_config(host);
1232a22e6444STejun Heo 	} else
1233a22e6444STejun Heo 		dev_printk(KERN_INFO, host->dev,
1234a22e6444STejun Heo 			   "skipping global host reset\n");
1235c6fd2807SJeff Garzik 
1236c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
1237c6fd2807SJeff Garzik 		u16 tmp16;
1238c6fd2807SJeff Garzik 
1239c6fd2807SJeff Garzik 		/* configure PCS */
1240c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
124149f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
124249f29090STejun Heo 			tmp16 |= hpriv->port_map;
1243c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
1244c6fd2807SJeff Garzik 		}
124549f29090STejun Heo 	}
1246c6fd2807SJeff Garzik 
1247c6fd2807SJeff Garzik 	return 0;
1248c6fd2807SJeff Garzik }
1249c6fd2807SJeff Garzik 
125018f7ba4cSKristen Carlson Accardi static void ahci_sw_activity(struct ata_link *link)
125118f7ba4cSKristen Carlson Accardi {
125218f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
125318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
125418f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
125518f7ba4cSKristen Carlson Accardi 
125618f7ba4cSKristen Carlson Accardi 	if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
125718f7ba4cSKristen Carlson Accardi 		return;
125818f7ba4cSKristen Carlson Accardi 
125918f7ba4cSKristen Carlson Accardi 	emp->activity++;
126018f7ba4cSKristen Carlson Accardi 	if (!timer_pending(&emp->timer))
126118f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
126218f7ba4cSKristen Carlson Accardi }
126318f7ba4cSKristen Carlson Accardi 
126418f7ba4cSKristen Carlson Accardi static void ahci_sw_activity_blink(unsigned long arg)
126518f7ba4cSKristen Carlson Accardi {
126618f7ba4cSKristen Carlson Accardi 	struct ata_link *link = (struct ata_link *)arg;
126718f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
126818f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
126918f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
127018f7ba4cSKristen Carlson Accardi 	unsigned long led_message = emp->led_state;
127118f7ba4cSKristen Carlson Accardi 	u32 activity_led_state;
1272eb40963cSDavid Milburn 	unsigned long flags;
127318f7ba4cSKristen Carlson Accardi 
127487943acfSDavid Milburn 	led_message &= EM_MSG_LED_VALUE;
127518f7ba4cSKristen Carlson Accardi 	led_message |= ap->port_no | (link->pmp << 8);
127618f7ba4cSKristen Carlson Accardi 
127718f7ba4cSKristen Carlson Accardi 	/* check to see if we've had activity.  If so,
127818f7ba4cSKristen Carlson Accardi 	 * toggle state of LED and reset timer.  If not,
127918f7ba4cSKristen Carlson Accardi 	 * turn LED to desired idle state.
128018f7ba4cSKristen Carlson Accardi 	 */
1281eb40963cSDavid Milburn 	spin_lock_irqsave(ap->lock, flags);
128218f7ba4cSKristen Carlson Accardi 	if (emp->saved_activity != emp->activity) {
128318f7ba4cSKristen Carlson Accardi 		emp->saved_activity = emp->activity;
128418f7ba4cSKristen Carlson Accardi 		/* get the current LED state */
128587943acfSDavid Milburn 		activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
128618f7ba4cSKristen Carlson Accardi 
128718f7ba4cSKristen Carlson Accardi 		if (activity_led_state)
128818f7ba4cSKristen Carlson Accardi 			activity_led_state = 0;
128918f7ba4cSKristen Carlson Accardi 		else
129018f7ba4cSKristen Carlson Accardi 			activity_led_state = 1;
129118f7ba4cSKristen Carlson Accardi 
129218f7ba4cSKristen Carlson Accardi 		/* clear old state */
129387943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
129418f7ba4cSKristen Carlson Accardi 
129518f7ba4cSKristen Carlson Accardi 		/* toggle state */
129618f7ba4cSKristen Carlson Accardi 		led_message |= (activity_led_state << 16);
129718f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
129818f7ba4cSKristen Carlson Accardi 	} else {
129918f7ba4cSKristen Carlson Accardi 		/* switch to idle */
130087943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
130118f7ba4cSKristen Carlson Accardi 		if (emp->blink_policy == BLINK_OFF)
130218f7ba4cSKristen Carlson Accardi 			led_message |= (1 << 16);
130318f7ba4cSKristen Carlson Accardi 	}
1304eb40963cSDavid Milburn 	spin_unlock_irqrestore(ap->lock, flags);
130518f7ba4cSKristen Carlson Accardi 	ahci_transmit_led_message(ap, led_message, 4);
130618f7ba4cSKristen Carlson Accardi }
130718f7ba4cSKristen Carlson Accardi 
130818f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link)
130918f7ba4cSKristen Carlson Accardi {
131018f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
131118f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
131218f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
131318f7ba4cSKristen Carlson Accardi 
131418f7ba4cSKristen Carlson Accardi 	/* init activity stats, setup timer */
131518f7ba4cSKristen Carlson Accardi 	emp->saved_activity = emp->activity = 0;
131618f7ba4cSKristen Carlson Accardi 	setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
131718f7ba4cSKristen Carlson Accardi 
131818f7ba4cSKristen Carlson Accardi 	/* check our blink policy and set flag for link if it's enabled */
131918f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
132018f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
132118f7ba4cSKristen Carlson Accardi }
132218f7ba4cSKristen Carlson Accardi 
132318f7ba4cSKristen Carlson Accardi static int ahci_reset_em(struct ata_host *host)
132418f7ba4cSKristen Carlson Accardi {
132518f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
132618f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
132718f7ba4cSKristen Carlson Accardi 
132818f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
132918f7ba4cSKristen Carlson Accardi 	if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
133018f7ba4cSKristen Carlson Accardi 		return -EINVAL;
133118f7ba4cSKristen Carlson Accardi 
133218f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
133318f7ba4cSKristen Carlson Accardi 	return 0;
133418f7ba4cSKristen Carlson Accardi }
133518f7ba4cSKristen Carlson Accardi 
133618f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
133718f7ba4cSKristen Carlson Accardi 					ssize_t size)
133818f7ba4cSKristen Carlson Accardi {
133918f7ba4cSKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
134018f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
134118f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
134218f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
134318f7ba4cSKristen Carlson Accardi 	u32 message[] = {0, 0};
134493082f0bSLinus Torvalds 	unsigned long flags;
134518f7ba4cSKristen Carlson Accardi 	int pmp;
134618f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
134718f7ba4cSKristen Carlson Accardi 
134818f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
134987943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
1350d50ce07dSTejun Heo 	if (pmp < EM_MAX_SLOTS)
135118f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
135218f7ba4cSKristen Carlson Accardi 	else
135318f7ba4cSKristen Carlson Accardi 		return -EINVAL;
135418f7ba4cSKristen Carlson Accardi 
135518f7ba4cSKristen Carlson Accardi 	spin_lock_irqsave(ap->lock, flags);
135618f7ba4cSKristen Carlson Accardi 
135718f7ba4cSKristen Carlson Accardi 	/*
135818f7ba4cSKristen Carlson Accardi 	 * if we are still busy transmitting a previous message,
135918f7ba4cSKristen Carlson Accardi 	 * do not allow
136018f7ba4cSKristen Carlson Accardi 	 */
136118f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
136218f7ba4cSKristen Carlson Accardi 	if (em_ctl & EM_CTL_TM) {
136318f7ba4cSKristen Carlson Accardi 		spin_unlock_irqrestore(ap->lock, flags);
13644c1e9aa4SDavid Milburn 		return -EBUSY;
136518f7ba4cSKristen Carlson Accardi 	}
136618f7ba4cSKristen Carlson Accardi 
136718f7ba4cSKristen Carlson Accardi 	/*
136818f7ba4cSKristen Carlson Accardi 	 * create message header - this is all zero except for
136918f7ba4cSKristen Carlson Accardi 	 * the message size, which is 4 bytes.
137018f7ba4cSKristen Carlson Accardi 	 */
137118f7ba4cSKristen Carlson Accardi 	message[0] |= (4 << 8);
137218f7ba4cSKristen Carlson Accardi 
137318f7ba4cSKristen Carlson Accardi 	/* ignore 0:4 of byte zero, fill in port info yourself */
137487943acfSDavid Milburn 	message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
137518f7ba4cSKristen Carlson Accardi 
137618f7ba4cSKristen Carlson Accardi 	/* write message to EM_LOC */
137718f7ba4cSKristen Carlson Accardi 	writel(message[0], mmio + hpriv->em_loc);
137818f7ba4cSKristen Carlson Accardi 	writel(message[1], mmio + hpriv->em_loc+4);
137918f7ba4cSKristen Carlson Accardi 
138018f7ba4cSKristen Carlson Accardi 	/* save off new led state for port/slot */
1381208f2a88SDavid Milburn 	emp->led_state = state;
138218f7ba4cSKristen Carlson Accardi 
138318f7ba4cSKristen Carlson Accardi 	/*
138418f7ba4cSKristen Carlson Accardi 	 * tell hardware to transmit the message
138518f7ba4cSKristen Carlson Accardi 	 */
138618f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
138718f7ba4cSKristen Carlson Accardi 
138818f7ba4cSKristen Carlson Accardi 	spin_unlock_irqrestore(ap->lock, flags);
138918f7ba4cSKristen Carlson Accardi 	return size;
139018f7ba4cSKristen Carlson Accardi }
139118f7ba4cSKristen Carlson Accardi 
139218f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
139318f7ba4cSKristen Carlson Accardi {
139418f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
139518f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
139618f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
139718f7ba4cSKristen Carlson Accardi 	int rc = 0;
139818f7ba4cSKristen Carlson Accardi 
13991eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE) {
140018f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[link->pmp];
140118f7ba4cSKristen Carlson Accardi 		rc += sprintf(buf, "%lx\n", emp->led_state);
140218f7ba4cSKristen Carlson Accardi 	}
140318f7ba4cSKristen Carlson Accardi 	return rc;
140418f7ba4cSKristen Carlson Accardi }
140518f7ba4cSKristen Carlson Accardi 
140618f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
140718f7ba4cSKristen Carlson Accardi 				size_t size)
140818f7ba4cSKristen Carlson Accardi {
140918f7ba4cSKristen Carlson Accardi 	int state;
141018f7ba4cSKristen Carlson Accardi 	int pmp;
141118f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
141218f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
141318f7ba4cSKristen Carlson Accardi 
141418f7ba4cSKristen Carlson Accardi 	state = simple_strtoul(buf, NULL, 0);
141518f7ba4cSKristen Carlson Accardi 
141618f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
141787943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
1418d50ce07dSTejun Heo 	if (pmp < EM_MAX_SLOTS)
141918f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
142018f7ba4cSKristen Carlson Accardi 	else
142118f7ba4cSKristen Carlson Accardi 		return -EINVAL;
142218f7ba4cSKristen Carlson Accardi 
142318f7ba4cSKristen Carlson Accardi 	/* mask off the activity bits if we are in sw_activity
142418f7ba4cSKristen Carlson Accardi 	 * mode, user should turn off sw_activity before setting
142518f7ba4cSKristen Carlson Accardi 	 * activity led through em_message
142618f7ba4cSKristen Carlson Accardi 	 */
142718f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
142887943acfSDavid Milburn 		state &= ~EM_MSG_LED_VALUE_ACTIVITY;
142918f7ba4cSKristen Carlson Accardi 
143018f7ba4cSKristen Carlson Accardi 	return ahci_transmit_led_message(ap, state, size);
143118f7ba4cSKristen Carlson Accardi }
143218f7ba4cSKristen Carlson Accardi 
143318f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
143418f7ba4cSKristen Carlson Accardi {
143518f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
143618f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
143718f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
143818f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
143918f7ba4cSKristen Carlson Accardi 	u32 port_led_state = emp->led_state;
144018f7ba4cSKristen Carlson Accardi 
144118f7ba4cSKristen Carlson Accardi 	/* save the desired Activity LED behavior */
144218f7ba4cSKristen Carlson Accardi 	if (val == OFF) {
144318f7ba4cSKristen Carlson Accardi 		/* clear LFLAG */
144418f7ba4cSKristen Carlson Accardi 		link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
144518f7ba4cSKristen Carlson Accardi 
144618f7ba4cSKristen Carlson Accardi 		/* set the LED to OFF */
144787943acfSDavid Milburn 		port_led_state &= EM_MSG_LED_VALUE_OFF;
144818f7ba4cSKristen Carlson Accardi 		port_led_state |= (ap->port_no | (link->pmp << 8));
144918f7ba4cSKristen Carlson Accardi 		ahci_transmit_led_message(ap, port_led_state, 4);
145018f7ba4cSKristen Carlson Accardi 	} else {
145118f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
145218f7ba4cSKristen Carlson Accardi 		if (val == BLINK_OFF) {
145318f7ba4cSKristen Carlson Accardi 			/* set LED to ON for idle */
145487943acfSDavid Milburn 			port_led_state &= EM_MSG_LED_VALUE_OFF;
145518f7ba4cSKristen Carlson Accardi 			port_led_state |= (ap->port_no | (link->pmp << 8));
145687943acfSDavid Milburn 			port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
145718f7ba4cSKristen Carlson Accardi 			ahci_transmit_led_message(ap, port_led_state, 4);
145818f7ba4cSKristen Carlson Accardi 		}
145918f7ba4cSKristen Carlson Accardi 	}
146018f7ba4cSKristen Carlson Accardi 	emp->blink_policy = val;
146118f7ba4cSKristen Carlson Accardi 	return 0;
146218f7ba4cSKristen Carlson Accardi }
146318f7ba4cSKristen Carlson Accardi 
146418f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
146518f7ba4cSKristen Carlson Accardi {
146618f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
146718f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
146818f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
146918f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
147018f7ba4cSKristen Carlson Accardi 
147118f7ba4cSKristen Carlson Accardi 	/* display the saved value of activity behavior for this
147218f7ba4cSKristen Carlson Accardi 	 * disk.
147318f7ba4cSKristen Carlson Accardi 	 */
147418f7ba4cSKristen Carlson Accardi 	return sprintf(buf, "%d\n", emp->blink_policy);
147518f7ba4cSKristen Carlson Accardi }
147618f7ba4cSKristen Carlson Accardi 
14772bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
14782bcd866bSJeff Garzik 			   int port_no, void __iomem *mmio,
14792bcd866bSJeff Garzik 			   void __iomem *port_mmio)
1480c6fd2807SJeff Garzik {
1481c6fd2807SJeff Garzik 	const char *emsg = NULL;
14822bcd866bSJeff Garzik 	int rc;
14832bcd866bSJeff Garzik 	u32 tmp;
1484c6fd2807SJeff Garzik 
1485c6fd2807SJeff Garzik 	/* make sure port is not active */
14864447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1487c6fd2807SJeff Garzik 	if (rc)
1488c6fd2807SJeff Garzik 		dev_printk(KERN_WARNING, &pdev->dev,
1489c6fd2807SJeff Garzik 			   "%s (%d)\n", emsg, rc);
1490c6fd2807SJeff Garzik 
1491c6fd2807SJeff Garzik 	/* clear SError */
1492c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SCR_ERR);
1493c6fd2807SJeff Garzik 	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
1494c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_SCR_ERR);
1495c6fd2807SJeff Garzik 
1496c6fd2807SJeff Garzik 	/* clear port IRQ */
1497c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1498c6fd2807SJeff Garzik 	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1499c6fd2807SJeff Garzik 	if (tmp)
1500c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_IRQ_STAT);
1501c6fd2807SJeff Garzik 
15022bcd866bSJeff Garzik 	writel(1 << port_no, mmio + HOST_IRQ_STAT);
15032bcd866bSJeff Garzik }
15042bcd866bSJeff Garzik 
15052bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host)
15062bcd866bSJeff Garzik {
1507417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
15082bcd866bSJeff Garzik 	struct pci_dev *pdev = to_pci_dev(host->dev);
15092bcd866bSJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
15102bcd866bSJeff Garzik 	int i;
1511cd70c266SJeff Garzik 	void __iomem *port_mmio;
15122bcd866bSJeff Garzik 	u32 tmp;
1513c40e7cb8SJose Alberto Reguero 	int mv;
15142bcd866bSJeff Garzik 
1515417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
1516c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
1517c40e7cb8SJose Alberto Reguero 			mv = 2;
1518c40e7cb8SJose Alberto Reguero 		else
1519c40e7cb8SJose Alberto Reguero 			mv = 4;
1520c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
1521cd70c266SJeff Garzik 
1522cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
1523cd70c266SJeff Garzik 
1524cd70c266SJeff Garzik 		/* clear port IRQ */
1525cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
1526cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1527cd70c266SJeff Garzik 		if (tmp)
1528cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
1529cd70c266SJeff Garzik 	}
1530cd70c266SJeff Garzik 
15312bcd866bSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
15322bcd866bSJeff Garzik 		struct ata_port *ap = host->ports[i];
15332bcd866bSJeff Garzik 
1534cd70c266SJeff Garzik 		port_mmio = ahci_port_base(ap);
15352bcd866bSJeff Garzik 		if (ata_port_is_dummy(ap))
15362bcd866bSJeff Garzik 			continue;
15372bcd866bSJeff Garzik 
15382bcd866bSJeff Garzik 		ahci_port_init(pdev, ap, i, mmio, port_mmio);
1539c6fd2807SJeff Garzik 	}
1540c6fd2807SJeff Garzik 
1541c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1542c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1543c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
1544c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1545c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1546c6fd2807SJeff Garzik }
1547c6fd2807SJeff Garzik 
1548a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev)
1549a878539eSJeff Garzik {
1550a878539eSJeff Garzik 	struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
1551a878539eSJeff Garzik 
15524cde32fcSJeff Garzik 	if (hpriv->flags & AHCI_HFLAG_SECT255) {
1553a878539eSJeff Garzik 		dev->max_sectors = 255;
15544cde32fcSJeff Garzik 		ata_dev_printk(dev, KERN_INFO,
15554cde32fcSJeff Garzik 			       "SB600 AHCI: limiting to 255 sectors per cmd\n");
15564cde32fcSJeff Garzik 	}
1557a878539eSJeff Garzik }
1558a878539eSJeff Garzik 
1559c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
1560c6fd2807SJeff Garzik {
15614447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1562c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1563c6fd2807SJeff Garzik 	u32 tmp;
1564c6fd2807SJeff Garzik 
1565c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
1566c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
1567c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
1568c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
1569c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
1570c6fd2807SJeff Garzik 
1571c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
1572c6fd2807SJeff Garzik }
1573c6fd2807SJeff Garzik 
1574c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
1575c6fd2807SJeff Garzik 			       u32 opts)
1576c6fd2807SJeff Garzik {
1577c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
1578c6fd2807SJeff Garzik 
1579c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
1580c6fd2807SJeff Garzik 
1581c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
1582c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
1583c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
1584c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
1585c6fd2807SJeff Garzik }
1586c6fd2807SJeff Garzik 
1587d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart)
1588c6fd2807SJeff Garzik {
1589350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1590cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1591520d06f9STejun Heo 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1592c6fd2807SJeff Garzik 	u32 tmp;
1593d2e75dffSTejun Heo 	int busy, rc;
1594c6fd2807SJeff Garzik 
1595d2e75dffSTejun Heo 	/* do we need to kick the port? */
1596520d06f9STejun Heo 	busy = status & (ATA_BUSY | ATA_DRQ);
1597d2e75dffSTejun Heo 	if (!busy && !force_restart)
1598d2e75dffSTejun Heo 		return 0;
1599c6fd2807SJeff Garzik 
1600d2e75dffSTejun Heo 	/* stop engine */
1601d2e75dffSTejun Heo 	rc = ahci_stop_engine(ap);
1602d2e75dffSTejun Heo 	if (rc)
1603d2e75dffSTejun Heo 		goto out_restart;
1604d2e75dffSTejun Heo 
1605d2e75dffSTejun Heo 	/* need to do CLO? */
1606d2e75dffSTejun Heo 	if (!busy) {
1607d2e75dffSTejun Heo 		rc = 0;
1608d2e75dffSTejun Heo 		goto out_restart;
1609d2e75dffSTejun Heo 	}
1610d2e75dffSTejun Heo 
1611d2e75dffSTejun Heo 	if (!(hpriv->cap & HOST_CAP_CLO)) {
1612d2e75dffSTejun Heo 		rc = -EOPNOTSUPP;
1613d2e75dffSTejun Heo 		goto out_restart;
1614d2e75dffSTejun Heo 	}
1615d2e75dffSTejun Heo 
1616d2e75dffSTejun Heo 	/* perform CLO */
1617c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1618c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
1619c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1620c6fd2807SJeff Garzik 
1621d2e75dffSTejun Heo 	rc = 0;
1622c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1623c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
1624c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
1625d2e75dffSTejun Heo 		rc = -EIO;
1626c6fd2807SJeff Garzik 
1627d2e75dffSTejun Heo 	/* restart engine */
1628d2e75dffSTejun Heo  out_restart:
1629d2e75dffSTejun Heo 	ahci_start_engine(ap);
1630d2e75dffSTejun Heo 	return rc;
1631c6fd2807SJeff Garzik }
1632c6fd2807SJeff Garzik 
163391c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
163491c4a2e0STejun Heo 				struct ata_taskfile *tf, int is_cmd, u16 flags,
163591c4a2e0STejun Heo 				unsigned long timeout_msec)
163691c4a2e0STejun Heo {
163791c4a2e0STejun Heo 	const u32 cmd_fis_len = 5; /* five dwords */
163891c4a2e0STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
163991c4a2e0STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
164091c4a2e0STejun Heo 	u8 *fis = pp->cmd_tbl;
164191c4a2e0STejun Heo 	u32 tmp;
164291c4a2e0STejun Heo 
164391c4a2e0STejun Heo 	/* prep the command */
164491c4a2e0STejun Heo 	ata_tf_to_fis(tf, pmp, is_cmd, fis);
164591c4a2e0STejun Heo 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
164691c4a2e0STejun Heo 
164791c4a2e0STejun Heo 	/* issue & wait */
164891c4a2e0STejun Heo 	writel(1, port_mmio + PORT_CMD_ISSUE);
164991c4a2e0STejun Heo 
165091c4a2e0STejun Heo 	if (timeout_msec) {
165191c4a2e0STejun Heo 		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
165291c4a2e0STejun Heo 					1, timeout_msec);
165391c4a2e0STejun Heo 		if (tmp & 0x1) {
165491c4a2e0STejun Heo 			ahci_kick_engine(ap, 1);
165591c4a2e0STejun Heo 			return -EBUSY;
165691c4a2e0STejun Heo 		}
165791c4a2e0STejun Heo 	} else
165891c4a2e0STejun Heo 		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
165991c4a2e0STejun Heo 
166091c4a2e0STejun Heo 	return 0;
166191c4a2e0STejun Heo }
166291c4a2e0STejun Heo 
1663bd17243aSShane Huang static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1664bd17243aSShane Huang 			     int pmp, unsigned long deadline,
1665bd17243aSShane Huang 			     int (*check_ready)(struct ata_link *link))
1666c6fd2807SJeff Garzik {
1667cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1668*5594639aSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1669c6fd2807SJeff Garzik 	const char *reason = NULL;
16702cbb79ebSTejun Heo 	unsigned long now, msecs;
1671c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1672c6fd2807SJeff Garzik 	int rc;
1673c6fd2807SJeff Garzik 
1674c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1675c6fd2807SJeff Garzik 
1676c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
1677d2e75dffSTejun Heo 	rc = ahci_kick_engine(ap, 1);
1678994056d7STejun Heo 	if (rc && rc != -EOPNOTSUPP)
1679cc0680a5STejun Heo 		ata_link_printk(link, KERN_WARNING,
1680994056d7STejun Heo 				"failed to reset engine (errno=%d)\n", rc);
1681c6fd2807SJeff Garzik 
1682cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1683c6fd2807SJeff Garzik 
1684c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
16852cbb79ebSTejun Heo 	msecs = 0;
16862cbb79ebSTejun Heo 	now = jiffies;
16872cbb79ebSTejun Heo 	if (time_after(now, deadline))
16882cbb79ebSTejun Heo 		msecs = jiffies_to_msecs(deadline - now);
16892cbb79ebSTejun Heo 
1690c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
1691a9cf5e85STejun Heo 	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
169291c4a2e0STejun Heo 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
1693c6fd2807SJeff Garzik 		rc = -EIO;
1694c6fd2807SJeff Garzik 		reason = "1st FIS failed";
1695c6fd2807SJeff Garzik 		goto fail;
1696c6fd2807SJeff Garzik 	}
1697c6fd2807SJeff Garzik 
1698c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
1699c6fd2807SJeff Garzik 	msleep(1);
1700c6fd2807SJeff Garzik 
1701c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
1702c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
1703a9cf5e85STejun Heo 	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1704c6fd2807SJeff Garzik 
1705705e76beSTejun Heo 	/* wait for link to become ready */
1706bd17243aSShane Huang 	rc = ata_wait_after_reset(link, deadline, check_ready);
1707*5594639aSTejun Heo 	if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) {
1708*5594639aSTejun Heo 		/*
1709*5594639aSTejun Heo 		 * Workaround for cases where link online status can't
1710*5594639aSTejun Heo 		 * be trusted.  Treat device readiness timeout as link
1711*5594639aSTejun Heo 		 * offline.
1712*5594639aSTejun Heo 		 */
1713*5594639aSTejun Heo 		ata_link_printk(link, KERN_INFO,
1714*5594639aSTejun Heo 				"device not ready, treating as offline\n");
1715*5594639aSTejun Heo 		*class = ATA_DEV_NONE;
1716*5594639aSTejun Heo 	} else if (rc) {
17179b89391cSTejun Heo 		/* link occupied, -ENODEV too is an error */
1718c6fd2807SJeff Garzik 		reason = "device not ready";
1719c6fd2807SJeff Garzik 		goto fail;
1720*5594639aSTejun Heo 	} else
1721c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
1722c6fd2807SJeff Garzik 
1723c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
1724c6fd2807SJeff Garzik 	return 0;
1725c6fd2807SJeff Garzik 
1726c6fd2807SJeff Garzik  fail:
1727cc0680a5STejun Heo 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
1728c6fd2807SJeff Garzik 	return rc;
1729c6fd2807SJeff Garzik }
1730c6fd2807SJeff Garzik 
1731bd17243aSShane Huang static int ahci_check_ready(struct ata_link *link)
1732bd17243aSShane Huang {
1733bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1734bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1735bd17243aSShane Huang 
1736bd17243aSShane Huang 	return ata_check_ready(status);
1737bd17243aSShane Huang }
1738bd17243aSShane Huang 
1739bd17243aSShane Huang static int ahci_softreset(struct ata_link *link, unsigned int *class,
1740bd17243aSShane Huang 			  unsigned long deadline)
1741bd17243aSShane Huang {
1742bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1743bd17243aSShane Huang 
1744bd17243aSShane Huang 	DPRINTK("ENTER\n");
1745bd17243aSShane Huang 
1746bd17243aSShane Huang 	return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
1747bd17243aSShane Huang }
1748bd17243aSShane Huang 
1749bd17243aSShane Huang static int ahci_sb600_check_ready(struct ata_link *link)
1750bd17243aSShane Huang {
1751bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1752bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1753bd17243aSShane Huang 	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
1754bd17243aSShane Huang 
1755bd17243aSShane Huang 	/*
1756bd17243aSShane Huang 	 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
1757bd17243aSShane Huang 	 * which can save timeout delay.
1758bd17243aSShane Huang 	 */
1759bd17243aSShane Huang 	if (irq_status & PORT_IRQ_BAD_PMP)
1760bd17243aSShane Huang 		return -EIO;
1761bd17243aSShane Huang 
1762bd17243aSShane Huang 	return ata_check_ready(status);
1763bd17243aSShane Huang }
1764bd17243aSShane Huang 
1765bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
1766bd17243aSShane Huang 				unsigned long deadline)
1767bd17243aSShane Huang {
1768bd17243aSShane Huang 	struct ata_port *ap = link->ap;
1769bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(ap);
1770bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1771bd17243aSShane Huang 	int rc;
1772bd17243aSShane Huang 	u32 irq_sts;
1773bd17243aSShane Huang 
1774bd17243aSShane Huang 	DPRINTK("ENTER\n");
1775bd17243aSShane Huang 
1776bd17243aSShane Huang 	rc = ahci_do_softreset(link, class, pmp, deadline,
1777bd17243aSShane Huang 			       ahci_sb600_check_ready);
1778bd17243aSShane Huang 
1779bd17243aSShane Huang 	/*
1780bd17243aSShane Huang 	 * Soft reset fails on some ATI chips with IPMS set when PMP
1781bd17243aSShane Huang 	 * is enabled but SATA HDD/ODD is connected to SATA port,
1782bd17243aSShane Huang 	 * do soft reset again to port 0.
1783bd17243aSShane Huang 	 */
1784bd17243aSShane Huang 	if (rc == -EIO) {
1785bd17243aSShane Huang 		irq_sts = readl(port_mmio + PORT_IRQ_STAT);
1786bd17243aSShane Huang 		if (irq_sts & PORT_IRQ_BAD_PMP) {
1787bd17243aSShane Huang 			ata_link_printk(link, KERN_WARNING,
1788b6931c1fSShane Huang 					"applying SB600 PMP SRST workaround "
1789b6931c1fSShane Huang 					"and retrying\n");
1790bd17243aSShane Huang 			rc = ahci_do_softreset(link, class, 0, deadline,
1791bd17243aSShane Huang 					       ahci_check_ready);
1792bd17243aSShane Huang 		}
1793bd17243aSShane Huang 	}
1794bd17243aSShane Huang 
1795bd17243aSShane Huang 	return rc;
1796bd17243aSShane Huang }
1797bd17243aSShane Huang 
1798cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1799d4b2bab4STejun Heo 			  unsigned long deadline)
1800c6fd2807SJeff Garzik {
18019dadd45bSTejun Heo 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
1802cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1803c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1804c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1805c6fd2807SJeff Garzik 	struct ata_taskfile tf;
18069dadd45bSTejun Heo 	bool online;
1807c6fd2807SJeff Garzik 	int rc;
1808c6fd2807SJeff Garzik 
1809c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1810c6fd2807SJeff Garzik 
18114447d351STejun Heo 	ahci_stop_engine(ap);
1812c6fd2807SJeff Garzik 
1813c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1814cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1815dfd7a3dbSTejun Heo 	tf.command = 0x80;
18169977126cSTejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1817c6fd2807SJeff Garzik 
18189dadd45bSTejun Heo 	rc = sata_link_hardreset(link, timing, deadline, &online,
18199dadd45bSTejun Heo 				 ahci_check_ready);
1820c6fd2807SJeff Garzik 
18214447d351STejun Heo 	ahci_start_engine(ap);
1822c6fd2807SJeff Garzik 
18239dadd45bSTejun Heo 	if (online)
18249dadd45bSTejun Heo 		*class = ahci_dev_classify(ap);
1825c6fd2807SJeff Garzik 
1826c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1827c6fd2807SJeff Garzik 	return rc;
1828c6fd2807SJeff Garzik }
1829c6fd2807SJeff Garzik 
1830cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1831d4b2bab4STejun Heo 				 unsigned long deadline)
1832ad616ffbSTejun Heo {
1833cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
18349dadd45bSTejun Heo 	bool online;
1835ad616ffbSTejun Heo 	int rc;
1836ad616ffbSTejun Heo 
1837ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1838ad616ffbSTejun Heo 
18394447d351STejun Heo 	ahci_stop_engine(ap);
1840ad616ffbSTejun Heo 
1841cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
18429dadd45bSTejun Heo 				 deadline, &online, NULL);
1843ad616ffbSTejun Heo 
18444447d351STejun Heo 	ahci_start_engine(ap);
1845ad616ffbSTejun Heo 
1846ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1847ad616ffbSTejun Heo 
1848ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1849ad616ffbSTejun Heo 	 * request follow-up softreset.
1850ad616ffbSTejun Heo 	 */
18519dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
1852ad616ffbSTejun Heo }
1853ad616ffbSTejun Heo 
1854edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1855edc93052STejun Heo 				unsigned long deadline)
1856edc93052STejun Heo {
1857edc93052STejun Heo 	struct ata_port *ap = link->ap;
1858edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1859edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1860edc93052STejun Heo 	struct ata_taskfile tf;
18619dadd45bSTejun Heo 	bool online;
1862edc93052STejun Heo 	int rc;
1863edc93052STejun Heo 
1864edc93052STejun Heo 	ahci_stop_engine(ap);
1865edc93052STejun Heo 
1866edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
1867edc93052STejun Heo 	ata_tf_init(link->device, &tf);
1868edc93052STejun Heo 	tf.command = 0x80;
1869edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1870edc93052STejun Heo 
1871edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
18729dadd45bSTejun Heo 				 deadline, &online, NULL);
1873edc93052STejun Heo 
1874edc93052STejun Heo 	ahci_start_engine(ap);
1875edc93052STejun Heo 
1876edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
1877edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1878edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
1879edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
1880edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
1881edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1882edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1883edc93052STejun Heo 	 *
1884edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
1885edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
1886edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
1887edc93052STejun Heo 	 * suffice while making probing snappish enough.
1888edc93052STejun Heo 	 */
18899dadd45bSTejun Heo 	if (online) {
18909dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
18919dadd45bSTejun Heo 					  ahci_check_ready);
1892edc93052STejun Heo 		if (rc)
1893edc93052STejun Heo 			ahci_kick_engine(ap, 0);
18949dadd45bSTejun Heo 	}
18959dadd45bSTejun Heo 	return rc;
1896edc93052STejun Heo }
1897edc93052STejun Heo 
1898cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class)
1899c6fd2807SJeff Garzik {
1900cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
19014447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1902c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1903c6fd2807SJeff Garzik 
1904203c75b8STejun Heo 	ata_std_postreset(link, class);
1905c6fd2807SJeff Garzik 
1906c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1907c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1908c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1909c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
1910c6fd2807SJeff Garzik 	else
1911c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
1912c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
1913c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
1914c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
1915c6fd2807SJeff Garzik 	}
1916c6fd2807SJeff Garzik }
1917c6fd2807SJeff Garzik 
1918c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
1919c6fd2807SJeff Garzik {
1920c6fd2807SJeff Garzik 	struct scatterlist *sg;
1921ff2aeb1eSTejun Heo 	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
1922ff2aeb1eSTejun Heo 	unsigned int si;
1923c6fd2807SJeff Garzik 
1924c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1925c6fd2807SJeff Garzik 
1926c6fd2807SJeff Garzik 	/*
1927c6fd2807SJeff Garzik 	 * Next, the S/G list.
1928c6fd2807SJeff Garzik 	 */
1929ff2aeb1eSTejun Heo 	for_each_sg(qc->sg, sg, qc->n_elem, si) {
1930c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1931c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1932c6fd2807SJeff Garzik 
1933ff2aeb1eSTejun Heo 		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
1934ff2aeb1eSTejun Heo 		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
1935ff2aeb1eSTejun Heo 		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
1936c6fd2807SJeff Garzik 	}
1937c6fd2807SJeff Garzik 
1938ff2aeb1eSTejun Heo 	return si;
1939c6fd2807SJeff Garzik }
1940c6fd2807SJeff Garzik 
1941c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1942c6fd2807SJeff Garzik {
1943c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1944c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1945405e66b3STejun Heo 	int is_atapi = ata_is_atapi(qc->tf.protocol);
1946c6fd2807SJeff Garzik 	void *cmd_tbl;
1947c6fd2807SJeff Garzik 	u32 opts;
1948c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1949c6fd2807SJeff Garzik 	unsigned int n_elem;
1950c6fd2807SJeff Garzik 
1951c6fd2807SJeff Garzik 	/*
1952c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1953c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1954c6fd2807SJeff Garzik 	 */
1955c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1956c6fd2807SJeff Garzik 
19577d50b60bSTejun Heo 	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
1958c6fd2807SJeff Garzik 	if (is_atapi) {
1959c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1960c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1961c6fd2807SJeff Garzik 	}
1962c6fd2807SJeff Garzik 
1963c6fd2807SJeff Garzik 	n_elem = 0;
1964c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1965c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1966c6fd2807SJeff Garzik 
1967c6fd2807SJeff Garzik 	/*
1968c6fd2807SJeff Garzik 	 * Fill in command slot information.
1969c6fd2807SJeff Garzik 	 */
19707d50b60bSTejun Heo 	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
1971c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1972c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1973c6fd2807SJeff Garzik 	if (is_atapi)
1974c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1975c6fd2807SJeff Garzik 
1976c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1977c6fd2807SJeff Garzik }
1978c6fd2807SJeff Garzik 
1979c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1980c6fd2807SJeff Garzik {
1981417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1982c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
19837d50b60bSTejun Heo 	struct ata_eh_info *host_ehi = &ap->link.eh_info;
19847d50b60bSTejun Heo 	struct ata_link *link = NULL;
19857d50b60bSTejun Heo 	struct ata_queued_cmd *active_qc;
19867d50b60bSTejun Heo 	struct ata_eh_info *active_ehi;
1987c6fd2807SJeff Garzik 	u32 serror;
1988c6fd2807SJeff Garzik 
19897d50b60bSTejun Heo 	/* determine active link */
19901eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE)
19917d50b60bSTejun Heo 		if (ata_link_active(link))
19927d50b60bSTejun Heo 			break;
19937d50b60bSTejun Heo 	if (!link)
19947d50b60bSTejun Heo 		link = &ap->link;
19957d50b60bSTejun Heo 
19967d50b60bSTejun Heo 	active_qc = ata_qc_from_tag(ap, link->active_tag);
19977d50b60bSTejun Heo 	active_ehi = &link->eh_info;
19987d50b60bSTejun Heo 
19997d50b60bSTejun Heo 	/* record irq stat */
20007d50b60bSTejun Heo 	ata_ehi_clear_desc(host_ehi);
20017d50b60bSTejun Heo 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
2002c6fd2807SJeff Garzik 
2003c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
200482ef04fbSTejun Heo 	ahci_scr_read(&ap->link, SCR_ERROR, &serror);
200582ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, serror);
20067d50b60bSTejun Heo 	host_ehi->serror |= serror;
2007c6fd2807SJeff Garzik 
200841669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
2009417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
201041669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
201141669553STejun Heo 
201255a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
20137d50b60bSTejun Heo 		/* If qc is active, charge it; otherwise, the active
20147d50b60bSTejun Heo 		 * link.  There's no active qc on NCQ errors.  It will
20157d50b60bSTejun Heo 		 * be determined by EH by reading log page 10h.
20167d50b60bSTejun Heo 		 */
20177d50b60bSTejun Heo 		if (active_qc)
20187d50b60bSTejun Heo 			active_qc->err_mask |= AC_ERR_DEV;
20197d50b60bSTejun Heo 		else
20207d50b60bSTejun Heo 			active_ehi->err_mask |= AC_ERR_DEV;
20217d50b60bSTejun Heo 
2022417a1a6dSTejun Heo 		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
20237d50b60bSTejun Heo 			host_ehi->serror &= ~SERR_INTERNAL;
2024c6fd2807SJeff Garzik 	}
2025c6fd2807SJeff Garzik 
2026c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
2027c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
2028c6fd2807SJeff Garzik 
20297d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
2030cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
20317d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi,
20327d50b60bSTejun Heo 				  "unknown FIS %08x %08x %08x %08x" ,
2033c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
2034c6fd2807SJeff Garzik 	}
2035c6fd2807SJeff Garzik 
2036071f44b1STejun Heo 	if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
20377d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
2038cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
20397d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi, "incorrect PMP");
20407d50b60bSTejun Heo 	}
2041c6fd2807SJeff Garzik 
20427d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
20437d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_HOST_BUS;
2044cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
20457d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "host bus error");
20467d50b60bSTejun Heo 	}
20477d50b60bSTejun Heo 
20487d50b60bSTejun Heo 	if (irq_stat & PORT_IRQ_IF_ERR) {
20497d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_ATA_BUS;
2050cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
20517d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "interface fatal error");
20527d50b60bSTejun Heo 	}
20537d50b60bSTejun Heo 
20547d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
20557d50b60bSTejun Heo 		ata_ehi_hotplugged(host_ehi);
20567d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "%s",
20577d50b60bSTejun Heo 			irq_stat & PORT_IRQ_CONNECT ?
20587d50b60bSTejun Heo 			"connection status changed" : "PHY RDY changed");
20597d50b60bSTejun Heo 	}
20607d50b60bSTejun Heo 
20617d50b60bSTejun Heo 	/* okay, let's hand over to EH */
2062c6fd2807SJeff Garzik 
2063c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
2064c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2065c6fd2807SJeff Garzik 	else
2066c6fd2807SJeff Garzik 		ata_port_abort(ap);
2067c6fd2807SJeff Garzik }
2068c6fd2807SJeff Garzik 
2069df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap)
2070c6fd2807SJeff Garzik {
2071350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
20729af5c9c9STejun Heo 	struct ata_eh_info *ehi = &ap->link.eh_info;
20730291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
20745f226c6bSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
2075b06ce3e5STejun Heo 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
2076c6fd2807SJeff Garzik 	u32 status, qc_active;
2077459ad688STejun Heo 	int rc;
2078c6fd2807SJeff Garzik 
2079c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
2080c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
2081c6fd2807SJeff Garzik 
2082b06ce3e5STejun Heo 	/* ignore BAD_PMP while resetting */
2083b06ce3e5STejun Heo 	if (unlikely(resetting))
2084b06ce3e5STejun Heo 		status &= ~PORT_IRQ_BAD_PMP;
2085b06ce3e5STejun Heo 
208631556594SKristen Carlson Accardi 	/* If we are getting PhyRdy, this is
208731556594SKristen Carlson Accardi  	 * just a power state change, we should
208831556594SKristen Carlson Accardi  	 * clear out this, plus the PhyRdy/Comm
208931556594SKristen Carlson Accardi  	 * Wake bits from Serror
209031556594SKristen Carlson Accardi  	 */
209131556594SKristen Carlson Accardi 	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
209231556594SKristen Carlson Accardi 		(status & PORT_IRQ_PHYRDY)) {
209331556594SKristen Carlson Accardi 		status &= ~PORT_IRQ_PHYRDY;
209482ef04fbSTejun Heo 		ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
209531556594SKristen Carlson Accardi 	}
209631556594SKristen Carlson Accardi 
2097c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
2098c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
2099c6fd2807SJeff Garzik 		return;
2100c6fd2807SJeff Garzik 	}
2101c6fd2807SJeff Garzik 
21022f294968SKristen Carlson Accardi 	if (status & PORT_IRQ_SDB_FIS) {
21035f226c6bSTejun Heo 		/* If SNotification is available, leave notification
21045f226c6bSTejun Heo 		 * handling to sata_async_notification().  If not,
21055f226c6bSTejun Heo 		 * emulate it by snooping SDB FIS RX area.
21065f226c6bSTejun Heo 		 *
21075f226c6bSTejun Heo 		 * Snooping FIS RX area is probably cheaper than
21085f226c6bSTejun Heo 		 * poking SNotification but some constrollers which
21095f226c6bSTejun Heo 		 * implement SNotification, ICH9 for example, don't
21105f226c6bSTejun Heo 		 * store AN SDB FIS into receive area.
21115f226c6bSTejun Heo 		 */
21125f226c6bSTejun Heo 		if (hpriv->cap & HOST_CAP_SNTF)
21135f226c6bSTejun Heo 			sata_async_notification(ap);
21145f226c6bSTejun Heo 		else {
21155f226c6bSTejun Heo 			/* If the 'N' bit in word 0 of the FIS is set,
21165f226c6bSTejun Heo 			 * we just received asynchronous notification.
21175f226c6bSTejun Heo 			 * Tell libata about it.
21182f294968SKristen Carlson Accardi 			 */
21192f294968SKristen Carlson Accardi 			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
21202f294968SKristen Carlson Accardi 			u32 f0 = le32_to_cpu(f[0]);
21212f294968SKristen Carlson Accardi 
21227d77b247STejun Heo 			if (f0 & (1 << 15))
21237d77b247STejun Heo 				sata_async_notification(ap);
21242f294968SKristen Carlson Accardi 		}
21255f226c6bSTejun Heo 	}
21262f294968SKristen Carlson Accardi 
21277d50b60bSTejun Heo 	/* pp->active_link is valid iff any command is in flight */
21287d50b60bSTejun Heo 	if (ap->qc_active && pp->active_link->sactive)
2129c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
2130c6fd2807SJeff Garzik 	else
2131c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
2132c6fd2807SJeff Garzik 
213379f97dadSTejun Heo 	rc = ata_qc_complete_multiple(ap, qc_active);
2134b06ce3e5STejun Heo 
2135459ad688STejun Heo 	/* while resetting, invalid completions are expected */
2136459ad688STejun Heo 	if (unlikely(rc < 0 && !resetting)) {
2137c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
2138cf480626STejun Heo 		ehi->action |= ATA_EH_RESET;
2139c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2140c6fd2807SJeff Garzik 	}
2141c6fd2807SJeff Garzik }
2142c6fd2807SJeff Garzik 
21437d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
2144c6fd2807SJeff Garzik {
2145cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
2146c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
2147c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
2148c6fd2807SJeff Garzik 	void __iomem *mmio;
2149d28f87aaSTejun Heo 	u32 irq_stat, irq_masked;
2150c6fd2807SJeff Garzik 
2151c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2152c6fd2807SJeff Garzik 
2153cca3974eSJeff Garzik 	hpriv = host->private_data;
21540d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
2155c6fd2807SJeff Garzik 
2156c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
2157c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
2158c6fd2807SJeff Garzik 	if (!irq_stat)
2159c6fd2807SJeff Garzik 		return IRQ_NONE;
2160c6fd2807SJeff Garzik 
2161d28f87aaSTejun Heo 	irq_masked = irq_stat & hpriv->port_map;
2162d28f87aaSTejun Heo 
2163cca3974eSJeff Garzik 	spin_lock(&host->lock);
2164c6fd2807SJeff Garzik 
2165cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
2166c6fd2807SJeff Garzik 		struct ata_port *ap;
2167c6fd2807SJeff Garzik 
2168d28f87aaSTejun Heo 		if (!(irq_masked & (1 << i)))
2169c6fd2807SJeff Garzik 			continue;
2170c6fd2807SJeff Garzik 
2171cca3974eSJeff Garzik 		ap = host->ports[i];
2172c6fd2807SJeff Garzik 		if (ap) {
2173df69c9c5SJeff Garzik 			ahci_port_intr(ap);
2174c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
2175c6fd2807SJeff Garzik 		} else {
2176c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
2177c6fd2807SJeff Garzik 			if (ata_ratelimit())
2178cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
2179c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
2180c6fd2807SJeff Garzik 		}
2181c6fd2807SJeff Garzik 
2182c6fd2807SJeff Garzik 		handled = 1;
2183c6fd2807SJeff Garzik 	}
2184c6fd2807SJeff Garzik 
2185d28f87aaSTejun Heo 	/* HOST_IRQ_STAT behaves as level triggered latch meaning that
2186d28f87aaSTejun Heo 	 * it should be cleared after all the port events are cleared;
2187d28f87aaSTejun Heo 	 * otherwise, it will raise a spurious interrupt after each
2188d28f87aaSTejun Heo 	 * valid one.  Please read section 10.6.2 of ahci 1.1 for more
2189d28f87aaSTejun Heo 	 * information.
2190d28f87aaSTejun Heo 	 *
2191d28f87aaSTejun Heo 	 * Also, use the unmasked value to clear interrupt as spurious
2192d28f87aaSTejun Heo 	 * pending event on a dummy port might cause screaming IRQ.
2193d28f87aaSTejun Heo 	 */
2194ea0c62f7STejun Heo 	writel(irq_stat, mmio + HOST_IRQ_STAT);
2195ea0c62f7STejun Heo 
2196cca3974eSJeff Garzik 	spin_unlock(&host->lock);
2197c6fd2807SJeff Garzik 
2198c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
2199c6fd2807SJeff Garzik 
2200c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
2201c6fd2807SJeff Garzik }
2202c6fd2807SJeff Garzik 
2203c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
2204c6fd2807SJeff Garzik {
2205c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
22064447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22077d50b60bSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22087d50b60bSTejun Heo 
22097d50b60bSTejun Heo 	/* Keep track of the currently active link.  It will be used
22107d50b60bSTejun Heo 	 * in completion path to determine whether NCQ phase is in
22117d50b60bSTejun Heo 	 * progress.
22127d50b60bSTejun Heo 	 */
22137d50b60bSTejun Heo 	pp->active_link = qc->dev->link;
2214c6fd2807SJeff Garzik 
2215c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
2216c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
2217c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
2218c6fd2807SJeff Garzik 
221918f7ba4cSKristen Carlson Accardi 	ahci_sw_activity(qc->dev->link);
222018f7ba4cSKristen Carlson Accardi 
2221c6fd2807SJeff Garzik 	return 0;
2222c6fd2807SJeff Garzik }
2223c6fd2807SJeff Garzik 
22244c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
22254c9bf4e7STejun Heo {
22264c9bf4e7STejun Heo 	struct ahci_port_priv *pp = qc->ap->private_data;
22274c9bf4e7STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
22284c9bf4e7STejun Heo 
22294c9bf4e7STejun Heo 	ata_tf_from_fis(d2h_fis, &qc->result_tf);
22304c9bf4e7STejun Heo 	return true;
22314c9bf4e7STejun Heo }
22324c9bf4e7STejun Heo 
2233c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
2234c6fd2807SJeff Garzik {
22354447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2236c6fd2807SJeff Garzik 
2237c6fd2807SJeff Garzik 	/* turn IRQ off */
2238c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
2239c6fd2807SJeff Garzik }
2240c6fd2807SJeff Garzik 
2241c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
2242c6fd2807SJeff Garzik {
22430d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
22444447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2245c6fd2807SJeff Garzik 	u32 tmp;
2246a7384925SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
2247c6fd2807SJeff Garzik 
2248c6fd2807SJeff Garzik 	/* clear IRQ */
2249c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
2250c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
2251a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
2252c6fd2807SJeff Garzik 
22531c954a4dSTejun Heo 	/* turn IRQ back on */
22541c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
2255c6fd2807SJeff Garzik }
2256c6fd2807SJeff Garzik 
2257c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
2258c6fd2807SJeff Garzik {
2259c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
2260c6fd2807SJeff Garzik 		/* restart engine */
22614447d351STejun Heo 		ahci_stop_engine(ap);
22624447d351STejun Heo 		ahci_start_engine(ap);
2263c6fd2807SJeff Garzik 	}
2264c6fd2807SJeff Garzik 
2265a1efdabaSTejun Heo 	sata_pmp_error_handler(ap);
2266edc93052STejun Heo }
2267edc93052STejun Heo 
2268c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
2269c6fd2807SJeff Garzik {
2270c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
2271c6fd2807SJeff Garzik 
2272c6fd2807SJeff Garzik 	/* make DMA engine forget about the failed command */
2273d2e75dffSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED)
2274d2e75dffSTejun Heo 		ahci_kick_engine(ap, 1);
2275c6fd2807SJeff Garzik }
2276c6fd2807SJeff Garzik 
22777d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap)
22787d50b60bSTejun Heo {
22797d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22801c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22817d50b60bSTejun Heo 	u32 cmd;
22827d50b60bSTejun Heo 
22837d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
22847d50b60bSTejun Heo 	cmd |= PORT_CMD_PMP;
22857d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
22861c954a4dSTejun Heo 
22871c954a4dSTejun Heo 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
22881c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
22897d50b60bSTejun Heo }
22907d50b60bSTejun Heo 
22917d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap)
22927d50b60bSTejun Heo {
22937d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22941c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22957d50b60bSTejun Heo 	u32 cmd;
22967d50b60bSTejun Heo 
22977d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
22987d50b60bSTejun Heo 	cmd &= ~PORT_CMD_PMP;
22997d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
23001c954a4dSTejun Heo 
23011c954a4dSTejun Heo 	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
23021c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
23037d50b60bSTejun Heo }
23047d50b60bSTejun Heo 
2305028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap)
2306028a2596SAlexey Dobriyan {
2307028a2596SAlexey Dobriyan 	ahci_power_up(ap);
2308028a2596SAlexey Dobriyan 	ahci_start_port(ap);
2309028a2596SAlexey Dobriyan 
2310071f44b1STejun Heo 	if (sata_pmp_attached(ap))
23117d50b60bSTejun Heo 		ahci_pmp_attach(ap);
23127d50b60bSTejun Heo 	else
23137d50b60bSTejun Heo 		ahci_pmp_detach(ap);
23147d50b60bSTejun Heo 
2315028a2596SAlexey Dobriyan 	return 0;
2316028a2596SAlexey Dobriyan }
2317028a2596SAlexey Dobriyan 
2318438ac6d5STejun Heo #ifdef CONFIG_PM
2319c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
2320c6fd2807SJeff Garzik {
2321c6fd2807SJeff Garzik 	const char *emsg = NULL;
2322c6fd2807SJeff Garzik 	int rc;
2323c6fd2807SJeff Garzik 
23244447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
23258e16f941STejun Heo 	if (rc == 0)
23264447d351STejun Heo 		ahci_power_down(ap);
23278e16f941STejun Heo 	else {
2328c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
2329df69c9c5SJeff Garzik 		ahci_start_port(ap);
2330c6fd2807SJeff Garzik 	}
2331c6fd2807SJeff Garzik 
2332c6fd2807SJeff Garzik 	return rc;
2333c6fd2807SJeff Garzik }
2334c6fd2807SJeff Garzik 
2335c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
2336c6fd2807SJeff Garzik {
2337cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
23389b10ae86STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
23390d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2340c6fd2807SJeff Garzik 	u32 ctl;
2341c6fd2807SJeff Garzik 
23429b10ae86STejun Heo 	if (mesg.event & PM_EVENT_SUSPEND &&
23439b10ae86STejun Heo 	    hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
23449b10ae86STejun Heo 		dev_printk(KERN_ERR, &pdev->dev,
23459b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
23469b10ae86STejun Heo 		return -EIO;
23479b10ae86STejun Heo 	}
23489b10ae86STejun Heo 
23493a2d5b70SRafael J. Wysocki 	if (mesg.event & PM_EVENT_SLEEP) {
2350c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
2351c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
2352c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
2353c6fd2807SJeff Garzik 		 */
2354c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
2355c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
2356c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
2357c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
2358c6fd2807SJeff Garzik 	}
2359c6fd2807SJeff Garzik 
2360c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
2361c6fd2807SJeff Garzik }
2362c6fd2807SJeff Garzik 
2363c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
2364c6fd2807SJeff Garzik {
2365cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
2366c6fd2807SJeff Garzik 	int rc;
2367c6fd2807SJeff Garzik 
2368553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
2369553c4aa6STejun Heo 	if (rc)
2370553c4aa6STejun Heo 		return rc;
2371c6fd2807SJeff Garzik 
2372c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
23734447d351STejun Heo 		rc = ahci_reset_controller(host);
2374c6fd2807SJeff Garzik 		if (rc)
2375c6fd2807SJeff Garzik 			return rc;
2376c6fd2807SJeff Garzik 
23774447d351STejun Heo 		ahci_init_controller(host);
2378c6fd2807SJeff Garzik 	}
2379c6fd2807SJeff Garzik 
2380cca3974eSJeff Garzik 	ata_host_resume(host);
2381c6fd2807SJeff Garzik 
2382c6fd2807SJeff Garzik 	return 0;
2383c6fd2807SJeff Garzik }
2384438ac6d5STejun Heo #endif
2385c6fd2807SJeff Garzik 
2386c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
2387c6fd2807SJeff Garzik {
2388cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
2389c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
2390c6fd2807SJeff Garzik 	void *mem;
2391c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
2392c6fd2807SJeff Garzik 
239324dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
2394c6fd2807SJeff Garzik 	if (!pp)
2395c6fd2807SJeff Garzik 		return -ENOMEM;
2396c6fd2807SJeff Garzik 
239724dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
239824dc5f33STejun Heo 				  GFP_KERNEL);
239924dc5f33STejun Heo 	if (!mem)
2400c6fd2807SJeff Garzik 		return -ENOMEM;
2401c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
2402c6fd2807SJeff Garzik 
2403c6fd2807SJeff Garzik 	/*
2404c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
2405c6fd2807SJeff Garzik 	 * 32 bytes each in size
2406c6fd2807SJeff Garzik 	 */
2407c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
2408c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
2409c6fd2807SJeff Garzik 
2410c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
2411c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
2412c6fd2807SJeff Garzik 
2413c6fd2807SJeff Garzik 	/*
2414c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
2415c6fd2807SJeff Garzik 	 */
2416c6fd2807SJeff Garzik 	pp->rx_fis = mem;
2417c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
2418c6fd2807SJeff Garzik 
2419c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
2420c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
2421c6fd2807SJeff Garzik 
2422c6fd2807SJeff Garzik 	/*
2423c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
2424c6fd2807SJeff Garzik 	 * and its scatter-gather table
2425c6fd2807SJeff Garzik 	 */
2426c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
2427c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
2428c6fd2807SJeff Garzik 
2429a7384925SKristen Carlson Accardi 	/*
2430a7384925SKristen Carlson Accardi 	 * Save off initial list of interrupts to be enabled.
2431a7384925SKristen Carlson Accardi 	 * This could be changed later
2432a7384925SKristen Carlson Accardi 	 */
2433a7384925SKristen Carlson Accardi 	pp->intr_mask = DEF_PORT_IRQ;
2434a7384925SKristen Carlson Accardi 
2435c6fd2807SJeff Garzik 	ap->private_data = pp;
2436c6fd2807SJeff Garzik 
2437df69c9c5SJeff Garzik 	/* engage engines, captain */
2438df69c9c5SJeff Garzik 	return ahci_port_resume(ap);
2439c6fd2807SJeff Garzik }
2440c6fd2807SJeff Garzik 
2441c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
2442c6fd2807SJeff Garzik {
2443c6fd2807SJeff Garzik 	const char *emsg = NULL;
2444c6fd2807SJeff Garzik 	int rc;
2445c6fd2807SJeff Garzik 
2446c6fd2807SJeff Garzik 	/* de-initialize port */
24474447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
2448c6fd2807SJeff Garzik 	if (rc)
2449c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
2450c6fd2807SJeff Garzik }
2451c6fd2807SJeff Garzik 
24524447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
2453c6fd2807SJeff Garzik {
2454c6fd2807SJeff Garzik 	int rc;
2455c6fd2807SJeff Garzik 
2456c6fd2807SJeff Garzik 	if (using_dac &&
24576a35528aSYang Hongyang 	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
24586a35528aSYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
2459c6fd2807SJeff Garzik 		if (rc) {
2460284901a9SYang Hongyang 			rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
2461c6fd2807SJeff Garzik 			if (rc) {
2462c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
2463c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
2464c6fd2807SJeff Garzik 				return rc;
2465c6fd2807SJeff Garzik 			}
2466c6fd2807SJeff Garzik 		}
2467c6fd2807SJeff Garzik 	} else {
2468284901a9SYang Hongyang 		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
2469c6fd2807SJeff Garzik 		if (rc) {
2470c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2471c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
2472c6fd2807SJeff Garzik 			return rc;
2473c6fd2807SJeff Garzik 		}
2474284901a9SYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
2475c6fd2807SJeff Garzik 		if (rc) {
2476c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2477c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
2478c6fd2807SJeff Garzik 			return rc;
2479c6fd2807SJeff Garzik 		}
2480c6fd2807SJeff Garzik 	}
2481c6fd2807SJeff Garzik 	return 0;
2482c6fd2807SJeff Garzik }
2483c6fd2807SJeff Garzik 
24844447d351STejun Heo static void ahci_print_info(struct ata_host *host)
2485c6fd2807SJeff Garzik {
24864447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
24874447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
24884447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2489c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
2490c6fd2807SJeff Garzik 	const char *speed_s;
2491c6fd2807SJeff Garzik 	u16 cc;
2492c6fd2807SJeff Garzik 	const char *scc_s;
2493c6fd2807SJeff Garzik 
2494c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
2495c6fd2807SJeff Garzik 	cap = hpriv->cap;
2496c6fd2807SJeff Garzik 	impl = hpriv->port_map;
2497c6fd2807SJeff Garzik 
2498c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
2499c6fd2807SJeff Garzik 	if (speed == 1)
2500c6fd2807SJeff Garzik 		speed_s = "1.5";
2501c6fd2807SJeff Garzik 	else if (speed == 2)
2502c6fd2807SJeff Garzik 		speed_s = "3";
25038522ee25SShane Huang 	else if (speed == 3)
25048522ee25SShane Huang 		speed_s = "6";
2505c6fd2807SJeff Garzik 	else
2506c6fd2807SJeff Garzik 		speed_s = "?";
2507c6fd2807SJeff Garzik 
2508c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
2509c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
2510c6fd2807SJeff Garzik 		scc_s = "IDE";
2511c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
2512c6fd2807SJeff Garzik 		scc_s = "SATA";
2513c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
2514c6fd2807SJeff Garzik 		scc_s = "RAID";
2515c6fd2807SJeff Garzik 	else
2516c6fd2807SJeff Garzik 		scc_s = "unknown";
2517c6fd2807SJeff Garzik 
2518c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2519c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
2520c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
2521c6fd2807SJeff Garzik 		,
2522c6fd2807SJeff Garzik 
2523c6fd2807SJeff Garzik 		(vers >> 24) & 0xff,
2524c6fd2807SJeff Garzik 		(vers >> 16) & 0xff,
2525c6fd2807SJeff Garzik 		(vers >> 8) & 0xff,
2526c6fd2807SJeff Garzik 		vers & 0xff,
2527c6fd2807SJeff Garzik 
2528c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
2529c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
2530c6fd2807SJeff Garzik 		speed_s,
2531c6fd2807SJeff Garzik 		impl,
2532c6fd2807SJeff Garzik 		scc_s);
2533c6fd2807SJeff Garzik 
2534c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2535c6fd2807SJeff Garzik 		"flags: "
2536203ef6c4STejun Heo 		"%s%s%s%s%s%s%s"
253718f7ba4cSKristen Carlson Accardi 		"%s%s%s%s%s%s%s"
253818f7ba4cSKristen Carlson Accardi 		"%s\n"
2539c6fd2807SJeff Garzik 		,
2540c6fd2807SJeff Garzik 
2541c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
2542c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
2543203ef6c4STejun Heo 		cap & (1 << 29) ? "sntf " : "",
2544c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
2545c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
2546c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
2547c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
2548c6fd2807SJeff Garzik 
2549c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
2550c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
2551c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
2552c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
2553c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
2554c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
255518f7ba4cSKristen Carlson Accardi 		cap & (1 << 13) ? "part " : "",
255618f7ba4cSKristen Carlson Accardi 		cap & (1 << 6) ? "ems ": ""
2557c6fd2807SJeff Garzik 		);
2558c6fd2807SJeff Garzik }
2559c6fd2807SJeff Garzik 
2560edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2561edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
2562edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
2563edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
2564edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
2565edc93052STejun Heo  * other configuration).
2566edc93052STejun Heo  *
2567edc93052STejun Heo  * When there's no device attached to the first downstream port of the
2568edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
2569edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
2570edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
2571edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2572edc93052STejun Heo  *
2573edc93052STejun Heo  * The following function works around the problem by always using
2574edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
2575edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
2576edc93052STejun Heo  * assumed without follow-up softreset.
2577edc93052STejun Heo  */
2578edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
2579edc93052STejun Heo {
2580edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
2581edc93052STejun Heo 		{
2582edc93052STejun Heo 			.ident = "P5W DH Deluxe",
2583edc93052STejun Heo 			.matches = {
2584edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
2585edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
2586edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2587edc93052STejun Heo 			},
2588edc93052STejun Heo 		},
2589edc93052STejun Heo 		{ }
2590edc93052STejun Heo 	};
2591edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
2592edc93052STejun Heo 
2593edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2594edc93052STejun Heo 	    dmi_check_system(sysids)) {
2595edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
2596edc93052STejun Heo 
2597edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2598edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
2599edc93052STejun Heo 
2600edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
2601edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2602edc93052STejun Heo 	}
2603edc93052STejun Heo }
2604edc93052STejun Heo 
260558a09b38SShane Huang /*
260658a09b38SShane Huang  * SB600 ahci controller on ASUS M2A-VM can't do 64bit DMA with older
260758a09b38SShane Huang  * BIOS.  The oldest version known to be broken is 0901 and working is
260858a09b38SShane Huang  * 1501 which was released on 2007-10-26.  Force 32bit DMA on anything
260958a09b38SShane Huang  * older than 1501.  Please read bko#9412 for more info.
261058a09b38SShane Huang  */
261158a09b38SShane Huang static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev)
261258a09b38SShane Huang {
261358a09b38SShane Huang 	static const struct dmi_system_id sysids[] = {
261458a09b38SShane Huang 		{
261558a09b38SShane Huang 			.ident = "ASUS M2A-VM",
261658a09b38SShane Huang 			.matches = {
261758a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_VENDOR,
261858a09b38SShane Huang 					  "ASUSTeK Computer INC."),
261958a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
262058a09b38SShane Huang 			},
262158a09b38SShane Huang 		},
262258a09b38SShane Huang 		{ }
262358a09b38SShane Huang 	};
262458a09b38SShane Huang 	const char *cutoff_mmdd = "10/26";
262558a09b38SShane Huang 	const char *date;
262658a09b38SShane Huang 	int year;
262758a09b38SShane Huang 
262858a09b38SShane Huang 	if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
262958a09b38SShane Huang 	    !dmi_check_system(sysids))
263058a09b38SShane Huang 		return false;
263158a09b38SShane Huang 
263258a09b38SShane Huang 	/*
263358a09b38SShane Huang 	 * Argh.... both version and date are free form strings.
263458a09b38SShane Huang 	 * Let's hope they're using the same date format across
263558a09b38SShane Huang 	 * different versions.
263658a09b38SShane Huang 	 */
263758a09b38SShane Huang 	date = dmi_get_system_info(DMI_BIOS_DATE);
263858a09b38SShane Huang 	year = dmi_get_year(DMI_BIOS_DATE);
263958a09b38SShane Huang 	if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' &&
264058a09b38SShane Huang 	    (year > 2007 ||
264158a09b38SShane Huang 	     (year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0)))
264258a09b38SShane Huang 		return false;
264358a09b38SShane Huang 
264458a09b38SShane Huang 	dev_printk(KERN_WARNING, &pdev->dev, "ASUS M2A-VM: BIOS too old, "
264558a09b38SShane Huang 		   "forcing 32bit DMA, update BIOS\n");
264658a09b38SShane Huang 
264758a09b38SShane Huang 	return true;
264858a09b38SShane Huang }
264958a09b38SShane Huang 
26501fd68434SRafael J. Wysocki static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
26511fd68434SRafael J. Wysocki {
26521fd68434SRafael J. Wysocki 	static const struct dmi_system_id broken_systems[] = {
26531fd68434SRafael J. Wysocki 		{
26541fd68434SRafael J. Wysocki 			.ident = "HP Compaq nx6310",
26551fd68434SRafael J. Wysocki 			.matches = {
26561fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
26571fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
26581fd68434SRafael J. Wysocki 			},
26591fd68434SRafael J. Wysocki 			/* PCI slot number of the controller */
26601fd68434SRafael J. Wysocki 			.driver_data = (void *)0x1FUL,
26611fd68434SRafael J. Wysocki 		},
2662d2f9c061SMaciej Rutecki 		{
2663d2f9c061SMaciej Rutecki 			.ident = "HP Compaq 6720s",
2664d2f9c061SMaciej Rutecki 			.matches = {
2665d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2666d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
2667d2f9c061SMaciej Rutecki 			},
2668d2f9c061SMaciej Rutecki 			/* PCI slot number of the controller */
2669d2f9c061SMaciej Rutecki 			.driver_data = (void *)0x1FUL,
2670d2f9c061SMaciej Rutecki 		},
26711fd68434SRafael J. Wysocki 
26721fd68434SRafael J. Wysocki 		{ }	/* terminate list */
26731fd68434SRafael J. Wysocki 	};
26741fd68434SRafael J. Wysocki 	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
26751fd68434SRafael J. Wysocki 
26761fd68434SRafael J. Wysocki 	if (dmi) {
26771fd68434SRafael J. Wysocki 		unsigned long slot = (unsigned long)dmi->driver_data;
26781fd68434SRafael J. Wysocki 		/* apply the quirk only to on-board controllers */
26791fd68434SRafael J. Wysocki 		return slot == PCI_SLOT(pdev->devfn);
26801fd68434SRafael J. Wysocki 	}
26811fd68434SRafael J. Wysocki 
26821fd68434SRafael J. Wysocki 	return false;
26831fd68434SRafael J. Wysocki }
26841fd68434SRafael J. Wysocki 
26859b10ae86STejun Heo static bool ahci_broken_suspend(struct pci_dev *pdev)
26869b10ae86STejun Heo {
26879b10ae86STejun Heo 	static const struct dmi_system_id sysids[] = {
26889b10ae86STejun Heo 		/*
26899b10ae86STejun Heo 		 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
26909b10ae86STejun Heo 		 * to the harddisk doesn't become online after
26919b10ae86STejun Heo 		 * resuming from STR.  Warn and fail suspend.
26929b10ae86STejun Heo 		 */
26939b10ae86STejun Heo 		{
26949b10ae86STejun Heo 			.ident = "dv4",
26959b10ae86STejun Heo 			.matches = {
26969b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
26979b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
26989b10ae86STejun Heo 					  "HP Pavilion dv4 Notebook PC"),
26999b10ae86STejun Heo 			},
27009b10ae86STejun Heo 			.driver_data = "F.30", /* cutoff BIOS version */
27019b10ae86STejun Heo 		},
27029b10ae86STejun Heo 		{
27039b10ae86STejun Heo 			.ident = "dv5",
27049b10ae86STejun Heo 			.matches = {
27059b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27069b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
27079b10ae86STejun Heo 					  "HP Pavilion dv5 Notebook PC"),
27089b10ae86STejun Heo 			},
27099b10ae86STejun Heo 			.driver_data = "F.16", /* cutoff BIOS version */
27109b10ae86STejun Heo 		},
27119b10ae86STejun Heo 		{
27129b10ae86STejun Heo 			.ident = "dv6",
27139b10ae86STejun Heo 			.matches = {
27149b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27159b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
27169b10ae86STejun Heo 					  "HP Pavilion dv6 Notebook PC"),
27179b10ae86STejun Heo 			},
27189b10ae86STejun Heo 			.driver_data = "F.21",	/* cutoff BIOS version */
27199b10ae86STejun Heo 		},
27209b10ae86STejun Heo 		{
27219b10ae86STejun Heo 			.ident = "HDX18",
27229b10ae86STejun Heo 			.matches = {
27239b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27249b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
27259b10ae86STejun Heo 					  "HP HDX18 Notebook PC"),
27269b10ae86STejun Heo 			},
27279b10ae86STejun Heo 			.driver_data = "F.23",	/* cutoff BIOS version */
27289b10ae86STejun Heo 		},
27299b10ae86STejun Heo 		{ }	/* terminate list */
27309b10ae86STejun Heo 	};
27319b10ae86STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
27329b10ae86STejun Heo 	const char *ver;
27339b10ae86STejun Heo 
27349b10ae86STejun Heo 	if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
27359b10ae86STejun Heo 		return false;
27369b10ae86STejun Heo 
27379b10ae86STejun Heo 	ver = dmi_get_system_info(DMI_BIOS_VERSION);
27389b10ae86STejun Heo 
27399b10ae86STejun Heo 	return !ver || strcmp(ver, dmi->driver_data) < 0;
27409b10ae86STejun Heo }
27419b10ae86STejun Heo 
2742*5594639aSTejun Heo static bool ahci_broken_online(struct pci_dev *pdev)
2743*5594639aSTejun Heo {
2744*5594639aSTejun Heo #define ENCODE_BUSDEVFN(bus, slot, func)			\
2745*5594639aSTejun Heo 	(void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
2746*5594639aSTejun Heo 	static const struct dmi_system_id sysids[] = {
2747*5594639aSTejun Heo 		/*
2748*5594639aSTejun Heo 		 * There are several gigabyte boards which use
2749*5594639aSTejun Heo 		 * SIMG5723s configured as hardware RAID.  Certain
2750*5594639aSTejun Heo 		 * 5723 firmware revisions shipped there keep the link
2751*5594639aSTejun Heo 		 * online but fail to answer properly to SRST or
2752*5594639aSTejun Heo 		 * IDENTIFY when no device is attached downstream
2753*5594639aSTejun Heo 		 * causing libata to retry quite a few times leading
2754*5594639aSTejun Heo 		 * to excessive detection delay.
2755*5594639aSTejun Heo 		 *
2756*5594639aSTejun Heo 		 * As these firmwares respond to the second reset try
2757*5594639aSTejun Heo 		 * with invalid device signature, considering unknown
2758*5594639aSTejun Heo 		 * sig as offline works around the problem acceptably.
2759*5594639aSTejun Heo 		 */
2760*5594639aSTejun Heo 		{
2761*5594639aSTejun Heo 			.ident = "EP45-DQ6",
2762*5594639aSTejun Heo 			.matches = {
2763*5594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
2764*5594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
2765*5594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
2766*5594639aSTejun Heo 			},
2767*5594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
2768*5594639aSTejun Heo 		},
2769*5594639aSTejun Heo 		{
2770*5594639aSTejun Heo 			.ident = "EP45-DS5",
2771*5594639aSTejun Heo 			.matches = {
2772*5594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
2773*5594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
2774*5594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
2775*5594639aSTejun Heo 			},
2776*5594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
2777*5594639aSTejun Heo 		},
2778*5594639aSTejun Heo 		{ }	/* terminate list */
2779*5594639aSTejun Heo 	};
2780*5594639aSTejun Heo #undef ENCODE_BUSDEVFN
2781*5594639aSTejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
2782*5594639aSTejun Heo 	unsigned int val;
2783*5594639aSTejun Heo 
2784*5594639aSTejun Heo 	if (!dmi)
2785*5594639aSTejun Heo 		return false;
2786*5594639aSTejun Heo 
2787*5594639aSTejun Heo 	val = (unsigned long)dmi->driver_data;
2788*5594639aSTejun Heo 
2789*5594639aSTejun Heo 	return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
2790*5594639aSTejun Heo }
2791*5594639aSTejun Heo 
2792c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2793c6fd2807SJeff Garzik {
2794c6fd2807SJeff Garzik 	static int printed_version;
2795e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
2796e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
27974447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
279824dc5f33STejun Heo 	struct device *dev = &pdev->dev;
2799c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
28004447d351STejun Heo 	struct ata_host *host;
2801837f5f8fSTejun Heo 	int n_ports, i, rc;
2802c6fd2807SJeff Garzik 
2803c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2804c6fd2807SJeff Garzik 
2805c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
2806c6fd2807SJeff Garzik 
2807c6fd2807SJeff Garzik 	if (!printed_version++)
2808c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
2809c6fd2807SJeff Garzik 
28105b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
28115b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
28125b66c829SAlan Cox 	   AHCI stays out of the way */
28135b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
28145b66c829SAlan Cox 		return -ENODEV;
28155b66c829SAlan Cox 
28164447d351STejun Heo 	/* acquire resources */
281724dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
2818c6fd2807SJeff Garzik 	if (rc)
2819c6fd2807SJeff Garzik 		return rc;
2820c6fd2807SJeff Garzik 
2821dea55137STejun Heo 	/* AHCI controllers often implement SFF compatible interface.
2822dea55137STejun Heo 	 * Grab all PCI BARs just in case.
2823dea55137STejun Heo 	 */
2824dea55137STejun Heo 	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
28250d5ff566STejun Heo 	if (rc == -EBUSY)
282624dc5f33STejun Heo 		pcim_pin_device(pdev);
28270d5ff566STejun Heo 	if (rc)
282824dc5f33STejun Heo 		return rc;
2829c6fd2807SJeff Garzik 
2830c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
2831c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
2832c4f7792cSTejun Heo 		u8 map;
2833c4f7792cSTejun Heo 
2834c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
2835c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
2836c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
2837c4f7792cSTejun Heo 		 */
2838c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
2839c4f7792cSTejun Heo 		if (map & 0x3) {
2840c4f7792cSTejun Heo 			dev_printk(KERN_INFO, &pdev->dev, "controller is in "
2841c4f7792cSTejun Heo 				   "combined mode, can't enable AHCI mode\n");
2842c4f7792cSTejun Heo 			return -ENODEV;
2843c4f7792cSTejun Heo 		}
2844c4f7792cSTejun Heo 	}
2845c4f7792cSTejun Heo 
284624dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
284724dc5f33STejun Heo 	if (!hpriv)
284824dc5f33STejun Heo 		return -ENOMEM;
2849417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
2850417a1a6dSTejun Heo 
2851e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
2852e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
2853e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
2854e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
2855e297d99eSTejun Heo 
2856e427fe04SShane Huang 	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
2857e427fe04SShane Huang 	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
2858e427fe04SShane Huang 		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
2859e427fe04SShane Huang 
286058a09b38SShane Huang 	/* apply ASUS M2A_VM quirk */
286158a09b38SShane Huang 	if (ahci_asus_m2a_vm_32bit_only(pdev))
286258a09b38SShane Huang 		hpriv->flags |= AHCI_HFLAG_32BIT_ONLY;
286358a09b38SShane Huang 
2864a5bfc471STejun Heo 	if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
2865a5bfc471STejun Heo 		pci_enable_msi(pdev);
2866c6fd2807SJeff Garzik 
28674447d351STejun Heo 	/* save initial config */
2868417a1a6dSTejun Heo 	ahci_save_initial_config(pdev, hpriv);
2869c6fd2807SJeff Garzik 
28704447d351STejun Heo 	/* prepare host */
2871274c1fdeSTejun Heo 	if (hpriv->cap & HOST_CAP_NCQ)
28724447d351STejun Heo 		pi.flags |= ATA_FLAG_NCQ;
28734447d351STejun Heo 
28747d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
28757d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
28767d50b60bSTejun Heo 
287718f7ba4cSKristen Carlson Accardi 	if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) {
287818f7ba4cSKristen Carlson Accardi 		u8 messages;
287918f7ba4cSKristen Carlson Accardi 		void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
288018f7ba4cSKristen Carlson Accardi 		u32 em_loc = readl(mmio + HOST_EM_LOC);
288118f7ba4cSKristen Carlson Accardi 		u32 em_ctl = readl(mmio + HOST_EM_CTL);
288218f7ba4cSKristen Carlson Accardi 
288387943acfSDavid Milburn 		messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
288418f7ba4cSKristen Carlson Accardi 
288518f7ba4cSKristen Carlson Accardi 		/* we only support LED message type right now */
288618f7ba4cSKristen Carlson Accardi 		if ((messages & 0x01) && (ahci_em_messages == 1)) {
288718f7ba4cSKristen Carlson Accardi 			/* store em_loc */
288818f7ba4cSKristen Carlson Accardi 			hpriv->em_loc = ((em_loc >> 16) * 4);
288918f7ba4cSKristen Carlson Accardi 			pi.flags |= ATA_FLAG_EM;
289018f7ba4cSKristen Carlson Accardi 			if (!(em_ctl & EM_CTL_ALHD))
289118f7ba4cSKristen Carlson Accardi 				pi.flags |= ATA_FLAG_SW_ACTIVITY;
289218f7ba4cSKristen Carlson Accardi 		}
289318f7ba4cSKristen Carlson Accardi 	}
289418f7ba4cSKristen Carlson Accardi 
28951fd68434SRafael J. Wysocki 	if (ahci_broken_system_poweroff(pdev)) {
28961fd68434SRafael J. Wysocki 		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
28971fd68434SRafael J. Wysocki 		dev_info(&pdev->dev,
28981fd68434SRafael J. Wysocki 			"quirky BIOS, skipping spindown on poweroff\n");
28991fd68434SRafael J. Wysocki 	}
29001fd68434SRafael J. Wysocki 
29019b10ae86STejun Heo 	if (ahci_broken_suspend(pdev)) {
29029b10ae86STejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
29039b10ae86STejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
29049b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
29059b10ae86STejun Heo 	}
29069b10ae86STejun Heo 
2907*5594639aSTejun Heo 	if (ahci_broken_online(pdev)) {
2908*5594639aSTejun Heo 		hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
2909*5594639aSTejun Heo 		dev_info(&pdev->dev,
2910*5594639aSTejun Heo 			 "online status unreliable, applying workaround\n");
2911*5594639aSTejun Heo 	}
2912*5594639aSTejun Heo 
2913837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
2914837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
2915837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
2916837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
2917837f5f8fSTejun Heo 	 */
2918837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
2919837f5f8fSTejun Heo 
2920837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
29214447d351STejun Heo 	if (!host)
29224447d351STejun Heo 		return -ENOMEM;
29234447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
29244447d351STejun Heo 	host->private_data = hpriv;
29254447d351STejun Heo 
2926f3d7f23fSArjan van de Ven 	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
2927886ad09fSArjan van de Ven 		host->flags |= ATA_HOST_PARALLEL_SCAN;
2928f3d7f23fSArjan van de Ven 	else
2929f3d7f23fSArjan van de Ven 		printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
2930886ad09fSArjan van de Ven 
293118f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
293218f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
293318f7ba4cSKristen Carlson Accardi 
29344447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
29354447d351STejun Heo 		struct ata_port *ap = host->ports[i];
29364447d351STejun Heo 
2937cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
2938cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
2939cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
2940cbcdd875STejun Heo 
294131556594SKristen Carlson Accardi 		/* set initial link pm policy */
294231556594SKristen Carlson Accardi 		ap->pm_policy = NOT_AVAILABLE;
294331556594SKristen Carlson Accardi 
294418f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
294518f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
294618f7ba4cSKristen Carlson Accardi 			ap->em_message_type = ahci_em_messages;
294718f7ba4cSKristen Carlson Accardi 
294818f7ba4cSKristen Carlson Accardi 
2949dab632e8SJeff Garzik 		/* disabled/not-implemented port */
2950350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
2951dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
29524447d351STejun Heo 	}
2953c6fd2807SJeff Garzik 
2954edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
2955edc93052STejun Heo 	ahci_p5wdh_workaround(host);
2956edc93052STejun Heo 
2957c6fd2807SJeff Garzik 	/* initialize adapter */
29584447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
2959c6fd2807SJeff Garzik 	if (rc)
296024dc5f33STejun Heo 		return rc;
2961c6fd2807SJeff Garzik 
29624447d351STejun Heo 	rc = ahci_reset_controller(host);
29634447d351STejun Heo 	if (rc)
29644447d351STejun Heo 		return rc;
2965c6fd2807SJeff Garzik 
29664447d351STejun Heo 	ahci_init_controller(host);
29674447d351STejun Heo 	ahci_print_info(host);
2968c6fd2807SJeff Garzik 
29694447d351STejun Heo 	pci_set_master(pdev);
29704447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
29714447d351STejun Heo 				 &ahci_sht);
2972c6fd2807SJeff Garzik }
2973c6fd2807SJeff Garzik 
2974c6fd2807SJeff Garzik static int __init ahci_init(void)
2975c6fd2807SJeff Garzik {
2976c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
2977c6fd2807SJeff Garzik }
2978c6fd2807SJeff Garzik 
2979c6fd2807SJeff Garzik static void __exit ahci_exit(void)
2980c6fd2807SJeff Garzik {
2981c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
2982c6fd2807SJeff Garzik }
2983c6fd2807SJeff Garzik 
2984c6fd2807SJeff Garzik 
2985c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
2986c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
2987c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
2988c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
2989c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
2990c6fd2807SJeff Garzik 
2991c6fd2807SJeff Garzik module_init(ahci_init);
2992c6fd2807SJeff Garzik module_exit(ahci_exit);
2993