xref: /openbmc/linux/drivers/ata/ahci.c (revision 9b10ae86d1616f46dabb67c663fe6a9c3a502663)
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);
8018f7ba4cSKristen Carlson Accardi #define MAX_SLOTS 8
814c1e9aa4SDavid Milburn #define MAX_RETRY 15
82c6fd2807SJeff Garzik 
83c6fd2807SJeff Garzik enum {
84c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
85648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
86c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
87c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
88c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
89c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
90c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
91c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
92c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
93c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
94c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
95c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
96c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
97c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
98c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
99c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
100c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
101c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
102c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
103c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
104c6fd2807SJeff Garzik 
105c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
1060291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
107c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
108c6fd2807SJeff Garzik 
109c6fd2807SJeff Garzik 	board_ahci		= 0,
1107a234affSTejun Heo 	board_ahci_vt8251	= 1,
1117a234affSTejun Heo 	board_ahci_ign_iferr	= 2,
1127a234affSTejun Heo 	board_ahci_sb600	= 3,
1137a234affSTejun Heo 	board_ahci_mv		= 4,
114e427fe04SShane Huang 	board_ahci_sb700	= 5, /* for SB700 and SB800 */
115e297d99eSTejun Heo 	board_ahci_mcp65	= 6,
1169a3b103cSTejun Heo 	board_ahci_nopmp	= 7,
117aa431dd3STejun Heo 	board_ahci_yesncq	= 8,
118c6fd2807SJeff Garzik 
119c6fd2807SJeff Garzik 	/* global controller registers */
120c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
121c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
122c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
123c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
124c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
12518f7ba4cSKristen Carlson Accardi 	HOST_EM_LOC		= 0x1c, /* Enclosure Management location */
12618f7ba4cSKristen Carlson Accardi 	HOST_EM_CTL		= 0x20, /* Enclosure Management Control */
127c6fd2807SJeff Garzik 
128c6fd2807SJeff Garzik 	/* HOST_CTL bits */
129c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
130c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
131c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
132c6fd2807SJeff Garzik 
133c6fd2807SJeff Garzik 	/* HOST_CAP bits */
13418f7ba4cSKristen Carlson Accardi 	HOST_CAP_EMS		= (1 << 6),  /* Enclosure Management support */
135c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
1367d50b60bSTejun Heo 	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
137c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
13831556594SKristen Carlson Accardi 	HOST_CAP_ALPM		= (1 << 26), /* Aggressive Link PM support */
139c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
140203ef6c4STejun Heo 	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
141c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
142c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
143c6fd2807SJeff Garzik 
144c6fd2807SJeff Garzik 	/* registers for each SATA port */
145c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
146c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
147c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
148c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
149c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
150c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
151c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
152c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
153c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
154c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
155c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
156c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
157c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
158c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
159203ef6c4STejun Heo 	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
160c6fd2807SJeff Garzik 
161c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
162c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
163c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
164c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
165c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
166c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
167c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
168c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
169c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
170c6fd2807SJeff Garzik 
171c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
172c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
173c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
174c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
175c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
176c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
177c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
178c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
179c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
180c6fd2807SJeff Garzik 
181c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
182c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
183c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
184c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
1857d50b60bSTejun Heo 				  PORT_IRQ_UNK_FIS |
1867d50b60bSTejun Heo 				  PORT_IRQ_BAD_PMP,
187c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
188c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
189c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
190c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
191c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
192c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
193c6fd2807SJeff Garzik 
194c6fd2807SJeff Garzik 	/* PORT_CMD bits */
19531556594SKristen Carlson Accardi 	PORT_CMD_ASP		= (1 << 27), /* Aggressive Slumber/Partial */
19631556594SKristen Carlson Accardi 	PORT_CMD_ALPE		= (1 << 26), /* Aggressive Link PM enable */
197c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
1987d50b60bSTejun Heo 	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
199c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
200c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
201c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
202c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
203c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
204c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
205c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
206c6fd2807SJeff Garzik 
207c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
208c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
209c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
210c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
211c6fd2807SJeff Garzik 
212417a1a6dSTejun Heo 	/* hpriv->flags bits */
213417a1a6dSTejun Heo 	AHCI_HFLAG_NO_NCQ		= (1 << 0),
214417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
215417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
216417a1a6dSTejun Heo 	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
217417a1a6dSTejun Heo 	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
218417a1a6dSTejun Heo 	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
2196949b914STejun Heo 	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
22031556594SKristen Carlson Accardi 	AHCI_HFLAG_NO_HOTPLUG		= (1 << 7), /* ignore PxSERR.DIAG.N */
221a878539eSJeff Garzik 	AHCI_HFLAG_SECT255		= (1 << 8), /* max 255 sectors */
222e297d99eSTejun Heo 	AHCI_HFLAG_YES_NCQ		= (1 << 9), /* force NCQ cap on */
223*9b10ae86STejun Heo 	AHCI_HFLAG_NO_SUSPEND		= (1 << 10), /* don't suspend */
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 
23418f7ba4cSKristen Carlson Accardi 	/* em_ctl bits */
23518f7ba4cSKristen Carlson Accardi 	EM_CTL_RST			= (1 << 9), /* Reset */
23618f7ba4cSKristen Carlson Accardi 	EM_CTL_TM			= (1 << 8), /* Transmit Message */
23718f7ba4cSKristen Carlson Accardi 	EM_CTL_ALHD			= (1 << 26), /* Activity LED */
238c6fd2807SJeff Garzik };
239c6fd2807SJeff Garzik 
240c6fd2807SJeff Garzik struct ahci_cmd_hdr {
2414ca4e439SAl Viro 	__le32			opts;
2424ca4e439SAl Viro 	__le32			status;
2434ca4e439SAl Viro 	__le32			tbl_addr;
2444ca4e439SAl Viro 	__le32			tbl_addr_hi;
2454ca4e439SAl Viro 	__le32			reserved[4];
246c6fd2807SJeff Garzik };
247c6fd2807SJeff Garzik 
248c6fd2807SJeff Garzik struct ahci_sg {
2494ca4e439SAl Viro 	__le32			addr;
2504ca4e439SAl Viro 	__le32			addr_hi;
2514ca4e439SAl Viro 	__le32			reserved;
2524ca4e439SAl Viro 	__le32			flags_size;
253c6fd2807SJeff Garzik };
254c6fd2807SJeff Garzik 
25518f7ba4cSKristen Carlson Accardi struct ahci_em_priv {
25618f7ba4cSKristen Carlson Accardi 	enum sw_activity blink_policy;
25718f7ba4cSKristen Carlson Accardi 	struct timer_list timer;
25818f7ba4cSKristen Carlson Accardi 	unsigned long saved_activity;
25918f7ba4cSKristen Carlson Accardi 	unsigned long activity;
26018f7ba4cSKristen Carlson Accardi 	unsigned long led_state;
26118f7ba4cSKristen Carlson Accardi };
26218f7ba4cSKristen Carlson Accardi 
263c6fd2807SJeff Garzik struct ahci_host_priv {
264417a1a6dSTejun Heo 	unsigned int		flags;		/* AHCI_HFLAG_* */
265d447df14STejun Heo 	u32			cap;		/* cap to use */
266d447df14STejun Heo 	u32			port_map;	/* port map to use */
267d447df14STejun Heo 	u32			saved_cap;	/* saved initial cap */
268d447df14STejun Heo 	u32			saved_port_map;	/* saved initial port_map */
26918f7ba4cSKristen Carlson Accardi 	u32 			em_loc; /* enclosure management location */
270c6fd2807SJeff Garzik };
271c6fd2807SJeff Garzik 
272c6fd2807SJeff Garzik struct ahci_port_priv {
2737d50b60bSTejun Heo 	struct ata_link		*active_link;
274c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
275c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
276c6fd2807SJeff Garzik 	void			*cmd_tbl;
277c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
278c6fd2807SJeff Garzik 	void			*rx_fis;
279c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2800291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2810291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2820291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
283afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
284a7384925SKristen Carlson Accardi 	u32 			intr_mask;	/* interrupts to enable */
28518f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv	em_priv[MAX_SLOTS];/* enclosure management info
28618f7ba4cSKristen Carlson Accardi 					 	 * per PM slot */
287c6fd2807SJeff Garzik };
288c6fd2807SJeff Garzik 
28982ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
29082ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
291c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
292c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
2934c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
294c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
295c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
296c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
297c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
298c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
2997d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap);
3007d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap);
301a1efdabaSTejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class,
302a1efdabaSTejun Heo 			  unsigned long deadline);
303bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
304bd17243aSShane Huang 			  unsigned long deadline);
305a1efdabaSTejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
306a1efdabaSTejun Heo 			  unsigned long deadline);
307a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
308a1efdabaSTejun Heo 				 unsigned long deadline);
309a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
310a1efdabaSTejun Heo 				unsigned long deadline);
311a1efdabaSTejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class);
312c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
313c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
314df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
315a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev);
316dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
317dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
318dab632e8SJeff Garzik 			       u32 opts);
319438ac6d5STejun Heo #ifdef CONFIG_PM
320c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
321c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
322c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
323438ac6d5STejun Heo #endif
32418f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf);
32518f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev,
32618f7ba4cSKristen Carlson Accardi 				   enum sw_activity val);
32718f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link);
328c6fd2807SJeff Garzik 
329ee959b00STony Jones static struct device_attribute *ahci_shost_attrs[] = {
330ee959b00STony Jones 	&dev_attr_link_power_management_policy,
33118f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message_type,
33218f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message,
33318f7ba4cSKristen Carlson Accardi 	NULL
33418f7ba4cSKristen Carlson Accardi };
33518f7ba4cSKristen Carlson Accardi 
33618f7ba4cSKristen Carlson Accardi static struct device_attribute *ahci_sdev_attrs[] = {
33718f7ba4cSKristen Carlson Accardi 	&dev_attr_sw_activity,
33845fabbb7SElias Oltmanns 	&dev_attr_unload_heads,
33931556594SKristen Carlson Accardi 	NULL
34031556594SKristen Carlson Accardi };
34131556594SKristen Carlson Accardi 
342c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
34368d1d07bSTejun Heo 	ATA_NCQ_SHT(DRV_NAME),
344c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
345c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
346c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
34731556594SKristen Carlson Accardi 	.shost_attrs		= ahci_shost_attrs,
34818f7ba4cSKristen Carlson Accardi 	.sdev_attrs		= ahci_sdev_attrs,
349c6fd2807SJeff Garzik };
350c6fd2807SJeff Garzik 
351029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = {
352029cfd6bSTejun Heo 	.inherits		= &sata_pmp_port_ops,
353029cfd6bSTejun Heo 
3547d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
355c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
356c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
3574c9bf4e7STejun Heo 	.qc_fill_rtf		= ahci_qc_fill_rtf,
358c6fd2807SJeff Garzik 
359c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
360c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
361a1efdabaSTejun Heo 	.softreset		= ahci_softreset,
362a1efdabaSTejun Heo 	.hardreset		= ahci_hardreset,
363a1efdabaSTejun Heo 	.postreset		= ahci_postreset,
364071f44b1STejun Heo 	.pmp_softreset		= ahci_softreset,
365c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
366c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
367029cfd6bSTejun Heo 	.dev_config		= ahci_dev_config,
368c6fd2807SJeff Garzik 
369029cfd6bSTejun Heo 	.scr_read		= ahci_scr_read,
370029cfd6bSTejun Heo 	.scr_write		= ahci_scr_write,
3717d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
3727d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3737d50b60bSTejun Heo 
374029cfd6bSTejun Heo 	.enable_pm		= ahci_enable_alpm,
375029cfd6bSTejun Heo 	.disable_pm		= ahci_disable_alpm,
37618f7ba4cSKristen Carlson Accardi 	.em_show		= ahci_led_show,
37718f7ba4cSKristen Carlson Accardi 	.em_store		= ahci_led_store,
37818f7ba4cSKristen Carlson Accardi 	.sw_activity_show	= ahci_activity_show,
37918f7ba4cSKristen Carlson Accardi 	.sw_activity_store	= ahci_activity_store,
380438ac6d5STejun Heo #ifdef CONFIG_PM
381c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
382c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
383438ac6d5STejun Heo #endif
384c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
385c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
386c6fd2807SJeff Garzik };
387c6fd2807SJeff Garzik 
388029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
389029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
390a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
391ad616ffbSTejun Heo };
392ad616ffbSTejun Heo 
393029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
394029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
395a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
396edc93052STejun Heo };
397edc93052STejun Heo 
398bd17243aSShane Huang static struct ata_port_operations ahci_sb600_ops = {
399bd17243aSShane Huang 	.inherits		= &ahci_ops,
400bd17243aSShane Huang 	.softreset		= ahci_sb600_softreset,
401bd17243aSShane Huang 	.pmp_softreset		= ahci_sb600_softreset,
402bd17243aSShane Huang };
403bd17243aSShane Huang 
404417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
405417a1a6dSTejun Heo 
406c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
407c6fd2807SJeff Garzik 	/* board_ahci */
408c6fd2807SJeff Garzik 	{
4091188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
41014bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
411469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
412c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
413c6fd2807SJeff Garzik 	},
414c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
415c6fd2807SJeff Garzik 	{
4166949b914STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
417417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
41814bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
419469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
420ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
421c6fd2807SJeff Garzik 	},
42241669553STejun Heo 	/* board_ahci_ign_iferr */
42341669553STejun Heo 	{
424417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
425417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
42614bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
427469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
42841669553STejun Heo 		.port_ops	= &ahci_ops,
42941669553STejun Heo 	},
43055a61604SConke Hu 	/* board_ahci_sb600 */
43155a61604SConke Hu 	{
432417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
43322b5e7a7STejun Heo 				 AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
434bd17243aSShane Huang 				 AHCI_HFLAG_SECT255),
435417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
43614bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
437469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
438bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
43955a61604SConke Hu 	},
440cd70c266SJeff Garzik 	/* board_ahci_mv */
441cd70c266SJeff Garzik 	{
442417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
44317248461STejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
444cd70c266SJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
445417a1a6dSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
44614bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
447cd70c266SJeff Garzik 		.udma_mask	= ATA_UDMA6,
448cd70c266SJeff Garzik 		.port_ops	= &ahci_ops,
449cd70c266SJeff Garzik 	},
450e427fe04SShane Huang 	/* board_ahci_sb700, for SB700 and SB800 */
451e39fc8c9SShane Huang 	{
452bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
453e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
45414bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
455e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
456bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
457e39fc8c9SShane Huang 	},
458e297d99eSTejun Heo 	/* board_ahci_mcp65 */
459e297d99eSTejun Heo 	{
460e297d99eSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
461e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
46214bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
463e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
464e297d99eSTejun Heo 		.port_ops	= &ahci_ops,
465e297d99eSTejun Heo 	},
4669a3b103cSTejun Heo 	/* board_ahci_nopmp */
4679a3b103cSTejun Heo 	{
4689a3b103cSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP),
4699a3b103cSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
47014bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
4719a3b103cSTejun Heo 		.udma_mask	= ATA_UDMA6,
4729a3b103cSTejun Heo 		.port_ops	= &ahci_ops,
4739a3b103cSTejun Heo 	},
474aa431dd3STejun Heo 	/* board_ahci_yesncq */
475aa431dd3STejun Heo 	{
476aa431dd3STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
477aa431dd3STejun Heo 		.flags		= AHCI_FLAG_COMMON,
478aa431dd3STejun Heo 		.pio_mask	= ATA_PIO4,
479aa431dd3STejun Heo 		.udma_mask	= ATA_UDMA6,
480aa431dd3STejun Heo 		.port_ops	= &ahci_ops,
481aa431dd3STejun Heo 	},
482c6fd2807SJeff Garzik };
483c6fd2807SJeff Garzik 
484c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
485c6fd2807SJeff Garzik 	/* Intel */
48654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
48754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
48854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
48954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
49054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
49182490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
49254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
49354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
49454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
49554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
4967a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
4977a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
4987a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
4997a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
5007a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
5017a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
5027a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
5037a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
5047a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
5057a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
5067a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
5077a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
5087a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
5097a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
5107a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
5117a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
5127a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
513d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
514d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
51516ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
51616ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
517adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
5188e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
519adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
5208e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
521c6fd2807SJeff Garzik 
522e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
523e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
524e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
525c6fd2807SJeff Garzik 
526c6fd2807SJeff Garzik 	/* ATI */
527c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
528e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
529e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
530e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
531e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
532e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
533e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
534c6fd2807SJeff Garzik 
535c6fd2807SJeff Garzik 	/* VIA */
53654bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
537bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
538c6fd2807SJeff Garzik 
539c6fd2807SJeff Garzik 	/* NVIDIA */
540e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
541e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
542e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
543e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
544e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
545e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
546e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
547e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
548aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq },	/* MCP67 */
549aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq },	/* MCP67 */
550aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq },	/* MCP67 */
551aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq },	/* MCP67 */
552aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq },	/* MCP67 */
553aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq },	/* MCP67 */
554aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq },	/* MCP67 */
555aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq },	/* MCP67 */
556aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq },	/* MCP67 */
557aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq },	/* MCP67 */
558aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq },	/* MCP67 */
559aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq },	/* MCP67 */
560aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq },	/* MCP73 */
561aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq },	/* MCP73 */
562aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq },	/* MCP73 */
563aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq },	/* MCP73 */
564aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq },	/* MCP73 */
565aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq },	/* MCP73 */
566aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq },	/* MCP73 */
567aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq },	/* MCP73 */
568aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq },	/* MCP73 */
569aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq },	/* MCP73 */
570aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq },	/* MCP73 */
571aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq },	/* MCP73 */
5720522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },		/* MCP77 */
5730522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },		/* MCP77 */
5740522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },		/* MCP77 */
5750522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },		/* MCP77 */
5760522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },		/* MCP77 */
5770522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },		/* MCP77 */
5780522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },		/* MCP77 */
5790522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },		/* MCP77 */
5800522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },		/* MCP77 */
5810522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
5820522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
5830522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
5846ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci },		/* MCP79 */
5856ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci },		/* MCP79 */
5866ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci },		/* MCP79 */
5876ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci },		/* MCP79 */
5887100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
5897100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
5907100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
5917100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
5927100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
5937100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
5947100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
5957100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
5967adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci },		/* MCP89 */
5977adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci },		/* MCP89 */
5987adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci },		/* MCP89 */
5997adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci },		/* MCP89 */
6007adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci },		/* MCP89 */
6017adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci },		/* MCP89 */
6027adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci },		/* MCP89 */
6037adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci },		/* MCP89 */
6047adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci },		/* MCP89 */
6057adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci },		/* MCP89 */
6067adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci },		/* MCP89 */
6077adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci },		/* MCP89 */
608c6fd2807SJeff Garzik 
609c6fd2807SJeff Garzik 	/* SiS */
61020e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
61120e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
61220e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
613c6fd2807SJeff Garzik 
614cd70c266SJeff Garzik 	/* Marvell */
615cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
616c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
617cd70c266SJeff Garzik 
618c77a036bSMark Nelson 	/* Promise */
619c77a036bSMark Nelson 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
620c77a036bSMark Nelson 
621415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
622415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
623c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
624415ae2b5SJeff Garzik 
625c6fd2807SJeff Garzik 	{ }	/* terminate list */
626c6fd2807SJeff Garzik };
627c6fd2807SJeff Garzik 
628c6fd2807SJeff Garzik 
629c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
630c6fd2807SJeff Garzik 	.name			= DRV_NAME,
631c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
632c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
63324dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
634438ac6d5STejun Heo #ifdef CONFIG_PM
635c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
636c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
637438ac6d5STejun Heo #endif
638c6fd2807SJeff Garzik };
639c6fd2807SJeff Garzik 
64018f7ba4cSKristen Carlson Accardi static int ahci_em_messages = 1;
64118f7ba4cSKristen Carlson Accardi module_param(ahci_em_messages, int, 0444);
64218f7ba4cSKristen Carlson Accardi /* add other LED protocol types when they become supported */
64318f7ba4cSKristen Carlson Accardi MODULE_PARM_DESC(ahci_em_messages,
64418f7ba4cSKristen Carlson Accardi 	"Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
645c6fd2807SJeff Garzik 
6465b66c829SAlan Cox #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
6475b66c829SAlan Cox static int marvell_enable;
6485b66c829SAlan Cox #else
6495b66c829SAlan Cox static int marvell_enable = 1;
6505b66c829SAlan Cox #endif
6515b66c829SAlan Cox module_param(marvell_enable, int, 0644);
6525b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
6535b66c829SAlan Cox 
6545b66c829SAlan Cox 
65598fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
65698fa4b60STejun Heo {
65798fa4b60STejun Heo 	return (cap & 0x1f) + 1;
65898fa4b60STejun Heo }
65998fa4b60STejun Heo 
660dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host,
661dab632e8SJeff Garzik 					     unsigned int port_no)
662dab632e8SJeff Garzik {
663dab632e8SJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
664dab632e8SJeff Garzik 
665dab632e8SJeff Garzik 	return mmio + 0x100 + (port_no * 0x80);
666dab632e8SJeff Garzik }
667dab632e8SJeff Garzik 
6684447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
669c6fd2807SJeff Garzik {
670dab632e8SJeff Garzik 	return __ahci_port_base(ap->host, ap->port_no);
671c6fd2807SJeff Garzik }
672c6fd2807SJeff Garzik 
673b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio)
674b710a1f4STejun Heo {
67515fe982eSTejun Heo 	int i;
676b710a1f4STejun Heo 	u32 tmp;
677b710a1f4STejun Heo 
678b710a1f4STejun Heo 	/* turn on AHCI_EN */
679b710a1f4STejun Heo 	tmp = readl(mmio + HOST_CTL);
68015fe982eSTejun Heo 	if (tmp & HOST_AHCI_EN)
68115fe982eSTejun Heo 		return;
68215fe982eSTejun Heo 
68315fe982eSTejun Heo 	/* Some controllers need AHCI_EN to be written multiple times.
68415fe982eSTejun Heo 	 * Try a few times before giving up.
68515fe982eSTejun Heo 	 */
68615fe982eSTejun Heo 	for (i = 0; i < 5; i++) {
687b710a1f4STejun Heo 		tmp |= HOST_AHCI_EN;
688b710a1f4STejun Heo 		writel(tmp, mmio + HOST_CTL);
689b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
69015fe982eSTejun Heo 		if (tmp & HOST_AHCI_EN)
69115fe982eSTejun Heo 			return;
69215fe982eSTejun Heo 		msleep(10);
693b710a1f4STejun Heo 	}
69415fe982eSTejun Heo 
69515fe982eSTejun Heo 	WARN_ON(1);
696b710a1f4STejun Heo }
697b710a1f4STejun Heo 
698d447df14STejun Heo /**
699d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
7004447d351STejun Heo  *	@pdev: target PCI device
7014447d351STejun Heo  *	@hpriv: host private area to store config values
702d447df14STejun Heo  *
703d447df14STejun Heo  *	Some registers containing configuration info might be setup by
704d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
705d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
706d447df14STejun Heo  *	can be restored after controller reset.
707d447df14STejun Heo  *
708d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
709d447df14STejun Heo  *
710d447df14STejun Heo  *	LOCKING:
711d447df14STejun Heo  *	None.
712d447df14STejun Heo  */
7134447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
7144447d351STejun Heo 				     struct ahci_host_priv *hpriv)
715d447df14STejun Heo {
7164447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
717d447df14STejun Heo 	u32 cap, port_map;
71817199b18STejun Heo 	int i;
719c40e7cb8SJose Alberto Reguero 	int mv;
720d447df14STejun Heo 
721b710a1f4STejun Heo 	/* make sure AHCI mode is enabled before accessing CAP */
722b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
723b710a1f4STejun Heo 
724d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
725d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
726d447df14STejun Heo 	 */
727d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
728d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
729d447df14STejun Heo 
730274c1fdeSTejun Heo 	/* some chips have errata preventing 64bit use */
731417a1a6dSTejun Heo 	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
732c7a42156STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
733c7a42156STejun Heo 			   "controller can't do 64bit DMA, forcing 32bit\n");
734c7a42156STejun Heo 		cap &= ~HOST_CAP_64;
735c7a42156STejun Heo 	}
736c7a42156STejun Heo 
737417a1a6dSTejun Heo 	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
738274c1fdeSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
739274c1fdeSTejun Heo 			   "controller can't do NCQ, turning off CAP_NCQ\n");
740274c1fdeSTejun Heo 		cap &= ~HOST_CAP_NCQ;
741274c1fdeSTejun Heo 	}
742274c1fdeSTejun Heo 
743e297d99eSTejun Heo 	if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
744e297d99eSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
745e297d99eSTejun Heo 			   "controller can do NCQ, turning on CAP_NCQ\n");
746e297d99eSTejun Heo 		cap |= HOST_CAP_NCQ;
747e297d99eSTejun Heo 	}
748e297d99eSTejun Heo 
749258cd846SRoel Kluin 	if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
7506949b914STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
7516949b914STejun Heo 			   "controller can't do PMP, turning off CAP_PMP\n");
7526949b914STejun Heo 		cap &= ~HOST_CAP_PMP;
7536949b914STejun Heo 	}
7546949b914STejun Heo 
755d799e083STejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
756d799e083STejun Heo 	    port_map != 1) {
757d799e083STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
758d799e083STejun Heo 			   "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
759d799e083STejun Heo 			   port_map, 1);
760d799e083STejun Heo 		port_map = 1;
761d799e083STejun Heo 	}
762d799e083STejun Heo 
763cd70c266SJeff Garzik 	/*
764cd70c266SJeff Garzik 	 * Temporary Marvell 6145 hack: PATA port presence
765cd70c266SJeff Garzik 	 * is asserted through the standard AHCI port
766cd70c266SJeff Garzik 	 * presence register, as bit 4 (counting from 0)
767cd70c266SJeff Garzik 	 */
768417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
769c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
770c40e7cb8SJose Alberto Reguero 			mv = 0x3;
771c40e7cb8SJose Alberto Reguero 		else
772c40e7cb8SJose Alberto Reguero 			mv = 0xf;
773cd70c266SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
774cd70c266SJeff Garzik 			   "MV_AHCI HACK: port_map %x -> %x\n",
775c40e7cb8SJose Alberto Reguero 			   port_map,
776c40e7cb8SJose Alberto Reguero 			   port_map & mv);
7775b66c829SAlan Cox 		dev_printk(KERN_ERR, &pdev->dev,
7785b66c829SAlan Cox 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
779cd70c266SJeff Garzik 
780c40e7cb8SJose Alberto Reguero 		port_map &= mv;
781cd70c266SJeff Garzik 	}
782cd70c266SJeff Garzik 
78317199b18STejun Heo 	/* cross check port_map and cap.n_ports */
7847a234affSTejun Heo 	if (port_map) {
785837f5f8fSTejun Heo 		int map_ports = 0;
78617199b18STejun Heo 
787837f5f8fSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS; i++)
788837f5f8fSTejun Heo 			if (port_map & (1 << i))
789837f5f8fSTejun Heo 				map_ports++;
79017199b18STejun Heo 
791837f5f8fSTejun Heo 		/* If PI has more ports than n_ports, whine, clear
792837f5f8fSTejun Heo 		 * port_map and let it be generated from n_ports.
79317199b18STejun Heo 		 */
794837f5f8fSTejun Heo 		if (map_ports > ahci_nr_ports(cap)) {
7954447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
796837f5f8fSTejun Heo 				   "implemented port map (0x%x) contains more "
797837f5f8fSTejun Heo 				   "ports than nr_ports (%u), using nr_ports\n",
798837f5f8fSTejun Heo 				   port_map, ahci_nr_ports(cap));
7997a234affSTejun Heo 			port_map = 0;
8007a234affSTejun Heo 		}
8017a234affSTejun Heo 	}
8027a234affSTejun Heo 
80317199b18STejun Heo 	/* fabricate port_map from cap.nr_ports */
8047a234affSTejun Heo 	if (!port_map) {
80517199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
8067a234affSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
8077a234affSTejun Heo 			   "forcing PORTS_IMPL to 0x%x\n", port_map);
8087a234affSTejun Heo 
8097a234affSTejun Heo 		/* write the fixed up value to the PI register */
8107a234affSTejun Heo 		hpriv->saved_port_map = port_map;
81117199b18STejun Heo 	}
81217199b18STejun Heo 
813d447df14STejun Heo 	/* record values to use during operation */
814d447df14STejun Heo 	hpriv->cap = cap;
815d447df14STejun Heo 	hpriv->port_map = port_map;
816d447df14STejun Heo }
817d447df14STejun Heo 
818d447df14STejun Heo /**
819d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
8204447d351STejun Heo  *	@host: target ATA host
821d447df14STejun Heo  *
822d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
823d447df14STejun Heo  *
824d447df14STejun Heo  *	LOCKING:
825d447df14STejun Heo  *	None.
826d447df14STejun Heo  */
8274447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
828d447df14STejun Heo {
8294447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
8304447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
8314447d351STejun Heo 
832d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
833d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
834d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
835d447df14STejun Heo }
836d447df14STejun Heo 
837203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
838c6fd2807SJeff Garzik {
839203ef6c4STejun Heo 	static const int offset[] = {
840203ef6c4STejun Heo 		[SCR_STATUS]		= PORT_SCR_STAT,
841203ef6c4STejun Heo 		[SCR_CONTROL]		= PORT_SCR_CTL,
842203ef6c4STejun Heo 		[SCR_ERROR]		= PORT_SCR_ERR,
843203ef6c4STejun Heo 		[SCR_ACTIVE]		= PORT_SCR_ACT,
844203ef6c4STejun Heo 		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
845203ef6c4STejun Heo 	};
846203ef6c4STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
847c6fd2807SJeff Garzik 
848203ef6c4STejun Heo 	if (sc_reg < ARRAY_SIZE(offset) &&
849203ef6c4STejun Heo 	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
850203ef6c4STejun Heo 		return offset[sc_reg];
851da3dbb17STejun Heo 	return 0;
852c6fd2807SJeff Garzik }
853c6fd2807SJeff Garzik 
85482ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
855c6fd2807SJeff Garzik {
85682ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
85782ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
858c6fd2807SJeff Garzik 
859203ef6c4STejun Heo 	if (offset) {
860203ef6c4STejun Heo 		*val = readl(port_mmio + offset);
861203ef6c4STejun Heo 		return 0;
862203ef6c4STejun Heo 	}
863da3dbb17STejun Heo 	return -EINVAL;
864c6fd2807SJeff Garzik }
865c6fd2807SJeff Garzik 
86682ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
867203ef6c4STejun Heo {
86882ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
86982ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
870203ef6c4STejun Heo 
871203ef6c4STejun Heo 	if (offset) {
872203ef6c4STejun Heo 		writel(val, port_mmio + offset);
873da3dbb17STejun Heo 		return 0;
874c6fd2807SJeff Garzik 	}
875203ef6c4STejun Heo 	return -EINVAL;
876203ef6c4STejun Heo }
877c6fd2807SJeff Garzik 
8784447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
879c6fd2807SJeff Garzik {
8804447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
881c6fd2807SJeff Garzik 	u32 tmp;
882c6fd2807SJeff Garzik 
883c6fd2807SJeff Garzik 	/* start DMA */
884c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
885c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
886c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
887c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
888c6fd2807SJeff Garzik }
889c6fd2807SJeff Garzik 
8904447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
891c6fd2807SJeff Garzik {
8924447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
893c6fd2807SJeff Garzik 	u32 tmp;
894c6fd2807SJeff Garzik 
895c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
896c6fd2807SJeff Garzik 
897c6fd2807SJeff Garzik 	/* check if the HBA is idle */
898c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
899c6fd2807SJeff Garzik 		return 0;
900c6fd2807SJeff Garzik 
901c6fd2807SJeff Garzik 	/* setting HBA to idle */
902c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
903c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
904c6fd2807SJeff Garzik 
905c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
906c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
907c6fd2807SJeff Garzik 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
908c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
909c6fd2807SJeff Garzik 		return -EIO;
910c6fd2807SJeff Garzik 
911c6fd2807SJeff Garzik 	return 0;
912c6fd2807SJeff Garzik }
913c6fd2807SJeff Garzik 
9144447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
915c6fd2807SJeff Garzik {
9164447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
9174447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
9184447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
919c6fd2807SJeff Garzik 	u32 tmp;
920c6fd2807SJeff Garzik 
921c6fd2807SJeff Garzik 	/* set FIS registers */
9224447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
9234447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
9244447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
9254447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
926c6fd2807SJeff Garzik 
9274447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
9284447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
9294447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
9304447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
931c6fd2807SJeff Garzik 
932c6fd2807SJeff Garzik 	/* enable FIS reception */
933c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
934c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
935c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
936c6fd2807SJeff Garzik 
937c6fd2807SJeff Garzik 	/* flush */
938c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
939c6fd2807SJeff Garzik }
940c6fd2807SJeff Garzik 
9414447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
942c6fd2807SJeff Garzik {
9434447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
944c6fd2807SJeff Garzik 	u32 tmp;
945c6fd2807SJeff Garzik 
946c6fd2807SJeff Garzik 	/* disable FIS reception */
947c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
948c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
949c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
950c6fd2807SJeff Garzik 
951c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
952c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
953c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
954c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
955c6fd2807SJeff Garzik 		return -EBUSY;
956c6fd2807SJeff Garzik 
957c6fd2807SJeff Garzik 	return 0;
958c6fd2807SJeff Garzik }
959c6fd2807SJeff Garzik 
9604447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
961c6fd2807SJeff Garzik {
9624447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
9634447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
964c6fd2807SJeff Garzik 	u32 cmd;
965c6fd2807SJeff Garzik 
966c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
967c6fd2807SJeff Garzik 
968c6fd2807SJeff Garzik 	/* spin up device */
9694447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
970c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
971c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
972c6fd2807SJeff Garzik 	}
973c6fd2807SJeff Garzik 
974c6fd2807SJeff Garzik 	/* wake up link */
975c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
976c6fd2807SJeff Garzik }
977c6fd2807SJeff Garzik 
97831556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap)
97931556594SKristen Carlson Accardi {
98031556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
98131556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
98231556594SKristen Carlson Accardi 	u32 cmd;
98331556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
98431556594SKristen Carlson Accardi 
98531556594SKristen Carlson Accardi 	/* IPM bits should be disabled by libata-core */
98631556594SKristen Carlson Accardi 	/* get the existing command bits */
98731556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
98831556594SKristen Carlson Accardi 
98931556594SKristen Carlson Accardi 	/* disable ALPM and ASP */
99031556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ASP;
99131556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ALPE;
99231556594SKristen Carlson Accardi 
99331556594SKristen Carlson Accardi 	/* force the interface back to active */
99431556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ICC_ACTIVE;
99531556594SKristen Carlson Accardi 
99631556594SKristen Carlson Accardi 	/* write out new cmd value */
99731556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
99831556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
99931556594SKristen Carlson Accardi 
100031556594SKristen Carlson Accardi 	/* wait 10ms to be sure we've come out of any low power state */
100131556594SKristen Carlson Accardi 	msleep(10);
100231556594SKristen Carlson Accardi 
100331556594SKristen Carlson Accardi 	/* clear out any PhyRdy stuff from interrupt status */
100431556594SKristen Carlson Accardi 	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
100531556594SKristen Carlson Accardi 
100631556594SKristen Carlson Accardi 	/* go ahead and clean out PhyRdy Change from Serror too */
100782ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
100831556594SKristen Carlson Accardi 
100931556594SKristen Carlson Accardi 	/*
101031556594SKristen Carlson Accardi  	 * Clear flag to indicate that we should ignore all PhyRdy
101131556594SKristen Carlson Accardi  	 * state changes
101231556594SKristen Carlson Accardi  	 */
101331556594SKristen Carlson Accardi 	hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
101431556594SKristen Carlson Accardi 
101531556594SKristen Carlson Accardi 	/*
101631556594SKristen Carlson Accardi  	 * Enable interrupts on Phy Ready.
101731556594SKristen Carlson Accardi  	 */
101831556594SKristen Carlson Accardi 	pp->intr_mask |= PORT_IRQ_PHYRDY;
101931556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
102031556594SKristen Carlson Accardi 
102131556594SKristen Carlson Accardi 	/*
102231556594SKristen Carlson Accardi  	 * don't change the link pm policy - we can be called
102331556594SKristen Carlson Accardi  	 * just to turn of link pm temporarily
102431556594SKristen Carlson Accardi  	 */
102531556594SKristen Carlson Accardi }
102631556594SKristen Carlson Accardi 
102731556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
102831556594SKristen Carlson Accardi 	enum link_pm policy)
102931556594SKristen Carlson Accardi {
103031556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
103131556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
103231556594SKristen Carlson Accardi 	u32 cmd;
103331556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
103431556594SKristen Carlson Accardi 	u32 asp;
103531556594SKristen Carlson Accardi 
103631556594SKristen Carlson Accardi 	/* Make sure the host is capable of link power management */
103731556594SKristen Carlson Accardi 	if (!(hpriv->cap & HOST_CAP_ALPM))
103831556594SKristen Carlson Accardi 		return -EINVAL;
103931556594SKristen Carlson Accardi 
104031556594SKristen Carlson Accardi 	switch (policy) {
104131556594SKristen Carlson Accardi 	case MAX_PERFORMANCE:
104231556594SKristen Carlson Accardi 	case NOT_AVAILABLE:
104331556594SKristen Carlson Accardi 		/*
104431556594SKristen Carlson Accardi  		 * if we came here with NOT_AVAILABLE,
104531556594SKristen Carlson Accardi  		 * it just means this is the first time we
104631556594SKristen Carlson Accardi  		 * have tried to enable - default to max performance,
104731556594SKristen Carlson Accardi  		 * and let the user go to lower power modes on request.
104831556594SKristen Carlson Accardi  		 */
104931556594SKristen Carlson Accardi 		ahci_disable_alpm(ap);
105031556594SKristen Carlson Accardi 		return 0;
105131556594SKristen Carlson Accardi 	case MIN_POWER:
105231556594SKristen Carlson Accardi 		/* configure HBA to enter SLUMBER */
105331556594SKristen Carlson Accardi 		asp = PORT_CMD_ASP;
105431556594SKristen Carlson Accardi 		break;
105531556594SKristen Carlson Accardi 	case MEDIUM_POWER:
105631556594SKristen Carlson Accardi 		/* configure HBA to enter PARTIAL */
105731556594SKristen Carlson Accardi 		asp = 0;
105831556594SKristen Carlson Accardi 		break;
105931556594SKristen Carlson Accardi 	default:
106031556594SKristen Carlson Accardi 		return -EINVAL;
106131556594SKristen Carlson Accardi 	}
106231556594SKristen Carlson Accardi 
106331556594SKristen Carlson Accardi 	/*
106431556594SKristen Carlson Accardi  	 * Disable interrupts on Phy Ready. This keeps us from
106531556594SKristen Carlson Accardi  	 * getting woken up due to spurious phy ready interrupts
106631556594SKristen Carlson Accardi 	 * TBD - Hot plug should be done via polling now, is
106731556594SKristen Carlson Accardi 	 * that even supported?
106831556594SKristen Carlson Accardi  	 */
106931556594SKristen Carlson Accardi 	pp->intr_mask &= ~PORT_IRQ_PHYRDY;
107031556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
107131556594SKristen Carlson Accardi 
107231556594SKristen Carlson Accardi 	/*
107331556594SKristen Carlson Accardi  	 * Set a flag to indicate that we should ignore all PhyRdy
107431556594SKristen Carlson Accardi  	 * state changes since these can happen now whenever we
107531556594SKristen Carlson Accardi  	 * change link state
107631556594SKristen Carlson Accardi  	 */
107731556594SKristen Carlson Accardi 	hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
107831556594SKristen Carlson Accardi 
107931556594SKristen Carlson Accardi 	/* get the existing command bits */
108031556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
108131556594SKristen Carlson Accardi 
108231556594SKristen Carlson Accardi 	/*
108331556594SKristen Carlson Accardi  	 * Set ASP based on Policy
108431556594SKristen Carlson Accardi  	 */
108531556594SKristen Carlson Accardi 	cmd |= asp;
108631556594SKristen Carlson Accardi 
108731556594SKristen Carlson Accardi 	/*
108831556594SKristen Carlson Accardi  	 * Setting this bit will instruct the HBA to aggressively
108931556594SKristen Carlson Accardi  	 * enter a lower power link state when it's appropriate and
109031556594SKristen Carlson Accardi  	 * based on the value set above for ASP
109131556594SKristen Carlson Accardi  	 */
109231556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ALPE;
109331556594SKristen Carlson Accardi 
109431556594SKristen Carlson Accardi 	/* write out new cmd value */
109531556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
109631556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
109731556594SKristen Carlson Accardi 
109831556594SKristen Carlson Accardi 	/* IPM bits should be set by libata-core */
109931556594SKristen Carlson Accardi 	return 0;
110031556594SKristen Carlson Accardi }
110131556594SKristen Carlson Accardi 
1102438ac6d5STejun Heo #ifdef CONFIG_PM
11034447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
1104c6fd2807SJeff Garzik {
11054447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
11064447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1107c6fd2807SJeff Garzik 	u32 cmd, scontrol;
1108c6fd2807SJeff Garzik 
11094447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
111007c53dacSTejun Heo 		return;
1111c6fd2807SJeff Garzik 
111207c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
1113c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
1114c6fd2807SJeff Garzik 	scontrol &= ~0xf;
1115c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
1116c6fd2807SJeff Garzik 
1117c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
111807c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1119c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
1120c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
1121c6fd2807SJeff Garzik }
1122438ac6d5STejun Heo #endif
1123c6fd2807SJeff Garzik 
1124df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap)
1125c6fd2807SJeff Garzik {
112618f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
112718f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
112818f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
11294c1e9aa4SDavid Milburn 	ssize_t rc;
11304c1e9aa4SDavid Milburn 	int i;
113118f7ba4cSKristen Carlson Accardi 
1132c6fd2807SJeff Garzik 	/* enable FIS reception */
11334447d351STejun Heo 	ahci_start_fis_rx(ap);
1134c6fd2807SJeff Garzik 
1135c6fd2807SJeff Garzik 	/* enable DMA */
11364447d351STejun Heo 	ahci_start_engine(ap);
113718f7ba4cSKristen Carlson Accardi 
113818f7ba4cSKristen Carlson Accardi 	/* turn on LEDs */
113918f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_EM) {
11401eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE) {
114118f7ba4cSKristen Carlson Accardi 			emp = &pp->em_priv[link->pmp];
11424c1e9aa4SDavid Milburn 
11434c1e9aa4SDavid Milburn 			/* EM Transmit bit maybe busy during init */
11444c1e9aa4SDavid Milburn 			for (i = 0; i < MAX_RETRY; i++) {
11454c1e9aa4SDavid Milburn 				rc = ahci_transmit_led_message(ap,
11464c1e9aa4SDavid Milburn 							       emp->led_state,
11474c1e9aa4SDavid Milburn 							       4);
11484c1e9aa4SDavid Milburn 				if (rc == -EBUSY)
11494c1e9aa4SDavid Milburn 					udelay(100);
11504c1e9aa4SDavid Milburn 				else
11514c1e9aa4SDavid Milburn 					break;
11524c1e9aa4SDavid Milburn 			}
115318f7ba4cSKristen Carlson Accardi 		}
115418f7ba4cSKristen Carlson Accardi 	}
115518f7ba4cSKristen Carlson Accardi 
115618f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_SW_ACTIVITY)
11571eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE)
115818f7ba4cSKristen Carlson Accardi 			ahci_init_sw_activity(link);
115918f7ba4cSKristen Carlson Accardi 
1160c6fd2807SJeff Garzik }
1161c6fd2807SJeff Garzik 
11624447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
1163c6fd2807SJeff Garzik {
1164c6fd2807SJeff Garzik 	int rc;
1165c6fd2807SJeff Garzik 
1166c6fd2807SJeff Garzik 	/* disable DMA */
11674447d351STejun Heo 	rc = ahci_stop_engine(ap);
1168c6fd2807SJeff Garzik 	if (rc) {
1169c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
1170c6fd2807SJeff Garzik 		return rc;
1171c6fd2807SJeff Garzik 	}
1172c6fd2807SJeff Garzik 
1173c6fd2807SJeff Garzik 	/* disable FIS reception */
11744447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
1175c6fd2807SJeff Garzik 	if (rc) {
1176c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
1177c6fd2807SJeff Garzik 		return rc;
1178c6fd2807SJeff Garzik 	}
1179c6fd2807SJeff Garzik 
1180c6fd2807SJeff Garzik 	return 0;
1181c6fd2807SJeff Garzik }
1182c6fd2807SJeff Garzik 
11834447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
1184c6fd2807SJeff Garzik {
11854447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
118649f29090STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
11874447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1188d447df14STejun Heo 	u32 tmp;
1189c6fd2807SJeff Garzik 
11903cc3eb11SJeff Garzik 	/* we must be in AHCI mode, before using anything
11913cc3eb11SJeff Garzik 	 * AHCI-specific, such as HOST_RESET.
11923cc3eb11SJeff Garzik 	 */
1193b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
11943cc3eb11SJeff Garzik 
11953cc3eb11SJeff Garzik 	/* global controller reset */
1196a22e6444STejun Heo 	if (!ahci_skip_host_reset) {
1197b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);
1198c6fd2807SJeff Garzik 		if ((tmp & HOST_RESET) == 0) {
1199c6fd2807SJeff Garzik 			writel(tmp | HOST_RESET, mmio + HOST_CTL);
1200c6fd2807SJeff Garzik 			readl(mmio + HOST_CTL); /* flush */
1201c6fd2807SJeff Garzik 		}
1202c6fd2807SJeff Garzik 
120324920c8aSZhang Rui 		/*
120424920c8aSZhang Rui 		 * to perform host reset, OS should set HOST_RESET
120524920c8aSZhang Rui 		 * and poll until this bit is read to be "0".
120624920c8aSZhang Rui 		 * reset must complete within 1 second, or
1207c6fd2807SJeff Garzik 		 * the hardware should be considered fried.
1208c6fd2807SJeff Garzik 		 */
120924920c8aSZhang Rui 		tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
121024920c8aSZhang Rui 					HOST_RESET, 10, 1000);
1211c6fd2807SJeff Garzik 
1212c6fd2807SJeff Garzik 		if (tmp & HOST_RESET) {
12134447d351STejun Heo 			dev_printk(KERN_ERR, host->dev,
1214c6fd2807SJeff Garzik 				   "controller reset failed (0x%x)\n", tmp);
1215c6fd2807SJeff Garzik 			return -EIO;
1216c6fd2807SJeff Garzik 		}
1217c6fd2807SJeff Garzik 
121898fa4b60STejun Heo 		/* turn on AHCI mode */
1219b710a1f4STejun Heo 		ahci_enable_ahci(mmio);
122098fa4b60STejun Heo 
1221a22e6444STejun Heo 		/* Some registers might be cleared on reset.  Restore
1222a22e6444STejun Heo 		 * initial values.
1223a22e6444STejun Heo 		 */
12244447d351STejun Heo 		ahci_restore_initial_config(host);
1225a22e6444STejun Heo 	} else
1226a22e6444STejun Heo 		dev_printk(KERN_INFO, host->dev,
1227a22e6444STejun Heo 			   "skipping global host reset\n");
1228c6fd2807SJeff Garzik 
1229c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
1230c6fd2807SJeff Garzik 		u16 tmp16;
1231c6fd2807SJeff Garzik 
1232c6fd2807SJeff Garzik 		/* configure PCS */
1233c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
123449f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
123549f29090STejun Heo 			tmp16 |= hpriv->port_map;
1236c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
1237c6fd2807SJeff Garzik 		}
123849f29090STejun Heo 	}
1239c6fd2807SJeff Garzik 
1240c6fd2807SJeff Garzik 	return 0;
1241c6fd2807SJeff Garzik }
1242c6fd2807SJeff Garzik 
124318f7ba4cSKristen Carlson Accardi static void ahci_sw_activity(struct ata_link *link)
124418f7ba4cSKristen Carlson Accardi {
124518f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
124618f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
124718f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
124818f7ba4cSKristen Carlson Accardi 
124918f7ba4cSKristen Carlson Accardi 	if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
125018f7ba4cSKristen Carlson Accardi 		return;
125118f7ba4cSKristen Carlson Accardi 
125218f7ba4cSKristen Carlson Accardi 	emp->activity++;
125318f7ba4cSKristen Carlson Accardi 	if (!timer_pending(&emp->timer))
125418f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
125518f7ba4cSKristen Carlson Accardi }
125618f7ba4cSKristen Carlson Accardi 
125718f7ba4cSKristen Carlson Accardi static void ahci_sw_activity_blink(unsigned long arg)
125818f7ba4cSKristen Carlson Accardi {
125918f7ba4cSKristen Carlson Accardi 	struct ata_link *link = (struct ata_link *)arg;
126018f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
126118f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
126218f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
126318f7ba4cSKristen Carlson Accardi 	unsigned long led_message = emp->led_state;
126418f7ba4cSKristen Carlson Accardi 	u32 activity_led_state;
1265eb40963cSDavid Milburn 	unsigned long flags;
126618f7ba4cSKristen Carlson Accardi 
126787943acfSDavid Milburn 	led_message &= EM_MSG_LED_VALUE;
126818f7ba4cSKristen Carlson Accardi 	led_message |= ap->port_no | (link->pmp << 8);
126918f7ba4cSKristen Carlson Accardi 
127018f7ba4cSKristen Carlson Accardi 	/* check to see if we've had activity.  If so,
127118f7ba4cSKristen Carlson Accardi 	 * toggle state of LED and reset timer.  If not,
127218f7ba4cSKristen Carlson Accardi 	 * turn LED to desired idle state.
127318f7ba4cSKristen Carlson Accardi 	 */
1274eb40963cSDavid Milburn 	spin_lock_irqsave(ap->lock, flags);
127518f7ba4cSKristen Carlson Accardi 	if (emp->saved_activity != emp->activity) {
127618f7ba4cSKristen Carlson Accardi 		emp->saved_activity = emp->activity;
127718f7ba4cSKristen Carlson Accardi 		/* get the current LED state */
127887943acfSDavid Milburn 		activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
127918f7ba4cSKristen Carlson Accardi 
128018f7ba4cSKristen Carlson Accardi 		if (activity_led_state)
128118f7ba4cSKristen Carlson Accardi 			activity_led_state = 0;
128218f7ba4cSKristen Carlson Accardi 		else
128318f7ba4cSKristen Carlson Accardi 			activity_led_state = 1;
128418f7ba4cSKristen Carlson Accardi 
128518f7ba4cSKristen Carlson Accardi 		/* clear old state */
128687943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
128718f7ba4cSKristen Carlson Accardi 
128818f7ba4cSKristen Carlson Accardi 		/* toggle state */
128918f7ba4cSKristen Carlson Accardi 		led_message |= (activity_led_state << 16);
129018f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
129118f7ba4cSKristen Carlson Accardi 	} else {
129218f7ba4cSKristen Carlson Accardi 		/* switch to idle */
129387943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
129418f7ba4cSKristen Carlson Accardi 		if (emp->blink_policy == BLINK_OFF)
129518f7ba4cSKristen Carlson Accardi 			led_message |= (1 << 16);
129618f7ba4cSKristen Carlson Accardi 	}
1297eb40963cSDavid Milburn 	spin_unlock_irqrestore(ap->lock, flags);
129818f7ba4cSKristen Carlson Accardi 	ahci_transmit_led_message(ap, led_message, 4);
129918f7ba4cSKristen Carlson Accardi }
130018f7ba4cSKristen Carlson Accardi 
130118f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link)
130218f7ba4cSKristen Carlson Accardi {
130318f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
130418f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
130518f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
130618f7ba4cSKristen Carlson Accardi 
130718f7ba4cSKristen Carlson Accardi 	/* init activity stats, setup timer */
130818f7ba4cSKristen Carlson Accardi 	emp->saved_activity = emp->activity = 0;
130918f7ba4cSKristen Carlson Accardi 	setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
131018f7ba4cSKristen Carlson Accardi 
131118f7ba4cSKristen Carlson Accardi 	/* check our blink policy and set flag for link if it's enabled */
131218f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
131318f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
131418f7ba4cSKristen Carlson Accardi }
131518f7ba4cSKristen Carlson Accardi 
131618f7ba4cSKristen Carlson Accardi static int ahci_reset_em(struct ata_host *host)
131718f7ba4cSKristen Carlson Accardi {
131818f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
131918f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
132018f7ba4cSKristen Carlson Accardi 
132118f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
132218f7ba4cSKristen Carlson Accardi 	if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
132318f7ba4cSKristen Carlson Accardi 		return -EINVAL;
132418f7ba4cSKristen Carlson Accardi 
132518f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
132618f7ba4cSKristen Carlson Accardi 	return 0;
132718f7ba4cSKristen Carlson Accardi }
132818f7ba4cSKristen Carlson Accardi 
132918f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
133018f7ba4cSKristen Carlson Accardi 					ssize_t size)
133118f7ba4cSKristen Carlson Accardi {
133218f7ba4cSKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
133318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
133418f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
133518f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
133618f7ba4cSKristen Carlson Accardi 	u32 message[] = {0, 0};
133793082f0bSLinus Torvalds 	unsigned long flags;
133818f7ba4cSKristen Carlson Accardi 	int pmp;
133918f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
134018f7ba4cSKristen Carlson Accardi 
134118f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
134287943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
134318f7ba4cSKristen Carlson Accardi 	if (pmp < MAX_SLOTS)
134418f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
134518f7ba4cSKristen Carlson Accardi 	else
134618f7ba4cSKristen Carlson Accardi 		return -EINVAL;
134718f7ba4cSKristen Carlson Accardi 
134818f7ba4cSKristen Carlson Accardi 	spin_lock_irqsave(ap->lock, flags);
134918f7ba4cSKristen Carlson Accardi 
135018f7ba4cSKristen Carlson Accardi 	/*
135118f7ba4cSKristen Carlson Accardi 	 * if we are still busy transmitting a previous message,
135218f7ba4cSKristen Carlson Accardi 	 * do not allow
135318f7ba4cSKristen Carlson Accardi 	 */
135418f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
135518f7ba4cSKristen Carlson Accardi 	if (em_ctl & EM_CTL_TM) {
135618f7ba4cSKristen Carlson Accardi 		spin_unlock_irqrestore(ap->lock, flags);
13574c1e9aa4SDavid Milburn 		return -EBUSY;
135818f7ba4cSKristen Carlson Accardi 	}
135918f7ba4cSKristen Carlson Accardi 
136018f7ba4cSKristen Carlson Accardi 	/*
136118f7ba4cSKristen Carlson Accardi 	 * create message header - this is all zero except for
136218f7ba4cSKristen Carlson Accardi 	 * the message size, which is 4 bytes.
136318f7ba4cSKristen Carlson Accardi 	 */
136418f7ba4cSKristen Carlson Accardi 	message[0] |= (4 << 8);
136518f7ba4cSKristen Carlson Accardi 
136618f7ba4cSKristen Carlson Accardi 	/* ignore 0:4 of byte zero, fill in port info yourself */
136787943acfSDavid Milburn 	message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
136818f7ba4cSKristen Carlson Accardi 
136918f7ba4cSKristen Carlson Accardi 	/* write message to EM_LOC */
137018f7ba4cSKristen Carlson Accardi 	writel(message[0], mmio + hpriv->em_loc);
137118f7ba4cSKristen Carlson Accardi 	writel(message[1], mmio + hpriv->em_loc+4);
137218f7ba4cSKristen Carlson Accardi 
137318f7ba4cSKristen Carlson Accardi 	/* save off new led state for port/slot */
1374208f2a88SDavid Milburn 	emp->led_state = state;
137518f7ba4cSKristen Carlson Accardi 
137618f7ba4cSKristen Carlson Accardi 	/*
137718f7ba4cSKristen Carlson Accardi 	 * tell hardware to transmit the message
137818f7ba4cSKristen Carlson Accardi 	 */
137918f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
138018f7ba4cSKristen Carlson Accardi 
138118f7ba4cSKristen Carlson Accardi 	spin_unlock_irqrestore(ap->lock, flags);
138218f7ba4cSKristen Carlson Accardi 	return size;
138318f7ba4cSKristen Carlson Accardi }
138418f7ba4cSKristen Carlson Accardi 
138518f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
138618f7ba4cSKristen Carlson Accardi {
138718f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
138818f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
138918f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
139018f7ba4cSKristen Carlson Accardi 	int rc = 0;
139118f7ba4cSKristen Carlson Accardi 
13921eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE) {
139318f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[link->pmp];
139418f7ba4cSKristen Carlson Accardi 		rc += sprintf(buf, "%lx\n", emp->led_state);
139518f7ba4cSKristen Carlson Accardi 	}
139618f7ba4cSKristen Carlson Accardi 	return rc;
139718f7ba4cSKristen Carlson Accardi }
139818f7ba4cSKristen Carlson Accardi 
139918f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
140018f7ba4cSKristen Carlson Accardi 				size_t size)
140118f7ba4cSKristen Carlson Accardi {
140218f7ba4cSKristen Carlson Accardi 	int state;
140318f7ba4cSKristen Carlson Accardi 	int pmp;
140418f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
140518f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
140618f7ba4cSKristen Carlson Accardi 
140718f7ba4cSKristen Carlson Accardi 	state = simple_strtoul(buf, NULL, 0);
140818f7ba4cSKristen Carlson Accardi 
140918f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
141087943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
141118f7ba4cSKristen Carlson Accardi 	if (pmp < MAX_SLOTS)
141218f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
141318f7ba4cSKristen Carlson Accardi 	else
141418f7ba4cSKristen Carlson Accardi 		return -EINVAL;
141518f7ba4cSKristen Carlson Accardi 
141618f7ba4cSKristen Carlson Accardi 	/* mask off the activity bits if we are in sw_activity
141718f7ba4cSKristen Carlson Accardi 	 * mode, user should turn off sw_activity before setting
141818f7ba4cSKristen Carlson Accardi 	 * activity led through em_message
141918f7ba4cSKristen Carlson Accardi 	 */
142018f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
142187943acfSDavid Milburn 		state &= ~EM_MSG_LED_VALUE_ACTIVITY;
142218f7ba4cSKristen Carlson Accardi 
142318f7ba4cSKristen Carlson Accardi 	return ahci_transmit_led_message(ap, state, size);
142418f7ba4cSKristen Carlson Accardi }
142518f7ba4cSKristen Carlson Accardi 
142618f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
142718f7ba4cSKristen Carlson Accardi {
142818f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
142918f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
143018f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
143118f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
143218f7ba4cSKristen Carlson Accardi 	u32 port_led_state = emp->led_state;
143318f7ba4cSKristen Carlson Accardi 
143418f7ba4cSKristen Carlson Accardi 	/* save the desired Activity LED behavior */
143518f7ba4cSKristen Carlson Accardi 	if (val == OFF) {
143618f7ba4cSKristen Carlson Accardi 		/* clear LFLAG */
143718f7ba4cSKristen Carlson Accardi 		link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
143818f7ba4cSKristen Carlson Accardi 
143918f7ba4cSKristen Carlson Accardi 		/* set the LED to OFF */
144087943acfSDavid Milburn 		port_led_state &= EM_MSG_LED_VALUE_OFF;
144118f7ba4cSKristen Carlson Accardi 		port_led_state |= (ap->port_no | (link->pmp << 8));
144218f7ba4cSKristen Carlson Accardi 		ahci_transmit_led_message(ap, port_led_state, 4);
144318f7ba4cSKristen Carlson Accardi 	} else {
144418f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
144518f7ba4cSKristen Carlson Accardi 		if (val == BLINK_OFF) {
144618f7ba4cSKristen Carlson Accardi 			/* set LED to ON for idle */
144787943acfSDavid Milburn 			port_led_state &= EM_MSG_LED_VALUE_OFF;
144818f7ba4cSKristen Carlson Accardi 			port_led_state |= (ap->port_no | (link->pmp << 8));
144987943acfSDavid Milburn 			port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
145018f7ba4cSKristen Carlson Accardi 			ahci_transmit_led_message(ap, port_led_state, 4);
145118f7ba4cSKristen Carlson Accardi 		}
145218f7ba4cSKristen Carlson Accardi 	}
145318f7ba4cSKristen Carlson Accardi 	emp->blink_policy = val;
145418f7ba4cSKristen Carlson Accardi 	return 0;
145518f7ba4cSKristen Carlson Accardi }
145618f7ba4cSKristen Carlson Accardi 
145718f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
145818f7ba4cSKristen Carlson Accardi {
145918f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
146018f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
146118f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
146218f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
146318f7ba4cSKristen Carlson Accardi 
146418f7ba4cSKristen Carlson Accardi 	/* display the saved value of activity behavior for this
146518f7ba4cSKristen Carlson Accardi 	 * disk.
146618f7ba4cSKristen Carlson Accardi 	 */
146718f7ba4cSKristen Carlson Accardi 	return sprintf(buf, "%d\n", emp->blink_policy);
146818f7ba4cSKristen Carlson Accardi }
146918f7ba4cSKristen Carlson Accardi 
14702bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
14712bcd866bSJeff Garzik 			   int port_no, void __iomem *mmio,
14722bcd866bSJeff Garzik 			   void __iomem *port_mmio)
1473c6fd2807SJeff Garzik {
1474c6fd2807SJeff Garzik 	const char *emsg = NULL;
14752bcd866bSJeff Garzik 	int rc;
14762bcd866bSJeff Garzik 	u32 tmp;
1477c6fd2807SJeff Garzik 
1478c6fd2807SJeff Garzik 	/* make sure port is not active */
14794447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1480c6fd2807SJeff Garzik 	if (rc)
1481c6fd2807SJeff Garzik 		dev_printk(KERN_WARNING, &pdev->dev,
1482c6fd2807SJeff Garzik 			   "%s (%d)\n", emsg, rc);
1483c6fd2807SJeff Garzik 
1484c6fd2807SJeff Garzik 	/* clear SError */
1485c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SCR_ERR);
1486c6fd2807SJeff Garzik 	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
1487c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_SCR_ERR);
1488c6fd2807SJeff Garzik 
1489c6fd2807SJeff Garzik 	/* clear port IRQ */
1490c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1491c6fd2807SJeff Garzik 	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1492c6fd2807SJeff Garzik 	if (tmp)
1493c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_IRQ_STAT);
1494c6fd2807SJeff Garzik 
14952bcd866bSJeff Garzik 	writel(1 << port_no, mmio + HOST_IRQ_STAT);
14962bcd866bSJeff Garzik }
14972bcd866bSJeff Garzik 
14982bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host)
14992bcd866bSJeff Garzik {
1500417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
15012bcd866bSJeff Garzik 	struct pci_dev *pdev = to_pci_dev(host->dev);
15022bcd866bSJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
15032bcd866bSJeff Garzik 	int i;
1504cd70c266SJeff Garzik 	void __iomem *port_mmio;
15052bcd866bSJeff Garzik 	u32 tmp;
1506c40e7cb8SJose Alberto Reguero 	int mv;
15072bcd866bSJeff Garzik 
1508417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
1509c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
1510c40e7cb8SJose Alberto Reguero 			mv = 2;
1511c40e7cb8SJose Alberto Reguero 		else
1512c40e7cb8SJose Alberto Reguero 			mv = 4;
1513c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
1514cd70c266SJeff Garzik 
1515cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
1516cd70c266SJeff Garzik 
1517cd70c266SJeff Garzik 		/* clear port IRQ */
1518cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
1519cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1520cd70c266SJeff Garzik 		if (tmp)
1521cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
1522cd70c266SJeff Garzik 	}
1523cd70c266SJeff Garzik 
15242bcd866bSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
15252bcd866bSJeff Garzik 		struct ata_port *ap = host->ports[i];
15262bcd866bSJeff Garzik 
1527cd70c266SJeff Garzik 		port_mmio = ahci_port_base(ap);
15282bcd866bSJeff Garzik 		if (ata_port_is_dummy(ap))
15292bcd866bSJeff Garzik 			continue;
15302bcd866bSJeff Garzik 
15312bcd866bSJeff Garzik 		ahci_port_init(pdev, ap, i, mmio, port_mmio);
1532c6fd2807SJeff Garzik 	}
1533c6fd2807SJeff Garzik 
1534c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1535c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1536c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
1537c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1538c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1539c6fd2807SJeff Garzik }
1540c6fd2807SJeff Garzik 
1541a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev)
1542a878539eSJeff Garzik {
1543a878539eSJeff Garzik 	struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
1544a878539eSJeff Garzik 
15454cde32fcSJeff Garzik 	if (hpriv->flags & AHCI_HFLAG_SECT255) {
1546a878539eSJeff Garzik 		dev->max_sectors = 255;
15474cde32fcSJeff Garzik 		ata_dev_printk(dev, KERN_INFO,
15484cde32fcSJeff Garzik 			       "SB600 AHCI: limiting to 255 sectors per cmd\n");
15494cde32fcSJeff Garzik 	}
1550a878539eSJeff Garzik }
1551a878539eSJeff Garzik 
1552c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
1553c6fd2807SJeff Garzik {
15544447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1555c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1556c6fd2807SJeff Garzik 	u32 tmp;
1557c6fd2807SJeff Garzik 
1558c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
1559c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
1560c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
1561c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
1562c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
1563c6fd2807SJeff Garzik 
1564c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
1565c6fd2807SJeff Garzik }
1566c6fd2807SJeff Garzik 
1567c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
1568c6fd2807SJeff Garzik 			       u32 opts)
1569c6fd2807SJeff Garzik {
1570c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
1571c6fd2807SJeff Garzik 
1572c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
1573c6fd2807SJeff Garzik 
1574c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
1575c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
1576c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
1577c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
1578c6fd2807SJeff Garzik }
1579c6fd2807SJeff Garzik 
1580d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart)
1581c6fd2807SJeff Garzik {
1582350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1583cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1584520d06f9STejun Heo 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1585c6fd2807SJeff Garzik 	u32 tmp;
1586d2e75dffSTejun Heo 	int busy, rc;
1587c6fd2807SJeff Garzik 
1588d2e75dffSTejun Heo 	/* do we need to kick the port? */
1589520d06f9STejun Heo 	busy = status & (ATA_BUSY | ATA_DRQ);
1590d2e75dffSTejun Heo 	if (!busy && !force_restart)
1591d2e75dffSTejun Heo 		return 0;
1592c6fd2807SJeff Garzik 
1593d2e75dffSTejun Heo 	/* stop engine */
1594d2e75dffSTejun Heo 	rc = ahci_stop_engine(ap);
1595d2e75dffSTejun Heo 	if (rc)
1596d2e75dffSTejun Heo 		goto out_restart;
1597d2e75dffSTejun Heo 
1598d2e75dffSTejun Heo 	/* need to do CLO? */
1599d2e75dffSTejun Heo 	if (!busy) {
1600d2e75dffSTejun Heo 		rc = 0;
1601d2e75dffSTejun Heo 		goto out_restart;
1602d2e75dffSTejun Heo 	}
1603d2e75dffSTejun Heo 
1604d2e75dffSTejun Heo 	if (!(hpriv->cap & HOST_CAP_CLO)) {
1605d2e75dffSTejun Heo 		rc = -EOPNOTSUPP;
1606d2e75dffSTejun Heo 		goto out_restart;
1607d2e75dffSTejun Heo 	}
1608d2e75dffSTejun Heo 
1609d2e75dffSTejun Heo 	/* perform CLO */
1610c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1611c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
1612c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1613c6fd2807SJeff Garzik 
1614d2e75dffSTejun Heo 	rc = 0;
1615c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1616c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
1617c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
1618d2e75dffSTejun Heo 		rc = -EIO;
1619c6fd2807SJeff Garzik 
1620d2e75dffSTejun Heo 	/* restart engine */
1621d2e75dffSTejun Heo  out_restart:
1622d2e75dffSTejun Heo 	ahci_start_engine(ap);
1623d2e75dffSTejun Heo 	return rc;
1624c6fd2807SJeff Garzik }
1625c6fd2807SJeff Garzik 
162691c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
162791c4a2e0STejun Heo 				struct ata_taskfile *tf, int is_cmd, u16 flags,
162891c4a2e0STejun Heo 				unsigned long timeout_msec)
162991c4a2e0STejun Heo {
163091c4a2e0STejun Heo 	const u32 cmd_fis_len = 5; /* five dwords */
163191c4a2e0STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
163291c4a2e0STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
163391c4a2e0STejun Heo 	u8 *fis = pp->cmd_tbl;
163491c4a2e0STejun Heo 	u32 tmp;
163591c4a2e0STejun Heo 
163691c4a2e0STejun Heo 	/* prep the command */
163791c4a2e0STejun Heo 	ata_tf_to_fis(tf, pmp, is_cmd, fis);
163891c4a2e0STejun Heo 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
163991c4a2e0STejun Heo 
164091c4a2e0STejun Heo 	/* issue & wait */
164191c4a2e0STejun Heo 	writel(1, port_mmio + PORT_CMD_ISSUE);
164291c4a2e0STejun Heo 
164391c4a2e0STejun Heo 	if (timeout_msec) {
164491c4a2e0STejun Heo 		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
164591c4a2e0STejun Heo 					1, timeout_msec);
164691c4a2e0STejun Heo 		if (tmp & 0x1) {
164791c4a2e0STejun Heo 			ahci_kick_engine(ap, 1);
164891c4a2e0STejun Heo 			return -EBUSY;
164991c4a2e0STejun Heo 		}
165091c4a2e0STejun Heo 	} else
165191c4a2e0STejun Heo 		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
165291c4a2e0STejun Heo 
165391c4a2e0STejun Heo 	return 0;
165491c4a2e0STejun Heo }
165591c4a2e0STejun Heo 
1656bd17243aSShane Huang static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1657bd17243aSShane Huang 			     int pmp, unsigned long deadline,
1658bd17243aSShane Huang 			     int (*check_ready)(struct ata_link *link))
1659c6fd2807SJeff Garzik {
1660cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1661c6fd2807SJeff Garzik 	const char *reason = NULL;
16622cbb79ebSTejun Heo 	unsigned long now, msecs;
1663c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1664c6fd2807SJeff Garzik 	int rc;
1665c6fd2807SJeff Garzik 
1666c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1667c6fd2807SJeff Garzik 
1668c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
1669d2e75dffSTejun Heo 	rc = ahci_kick_engine(ap, 1);
1670994056d7STejun Heo 	if (rc && rc != -EOPNOTSUPP)
1671cc0680a5STejun Heo 		ata_link_printk(link, KERN_WARNING,
1672994056d7STejun Heo 				"failed to reset engine (errno=%d)\n", rc);
1673c6fd2807SJeff Garzik 
1674cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1675c6fd2807SJeff Garzik 
1676c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
16772cbb79ebSTejun Heo 	msecs = 0;
16782cbb79ebSTejun Heo 	now = jiffies;
16792cbb79ebSTejun Heo 	if (time_after(now, deadline))
16802cbb79ebSTejun Heo 		msecs = jiffies_to_msecs(deadline - now);
16812cbb79ebSTejun Heo 
1682c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
1683a9cf5e85STejun Heo 	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
168491c4a2e0STejun Heo 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
1685c6fd2807SJeff Garzik 		rc = -EIO;
1686c6fd2807SJeff Garzik 		reason = "1st FIS failed";
1687c6fd2807SJeff Garzik 		goto fail;
1688c6fd2807SJeff Garzik 	}
1689c6fd2807SJeff Garzik 
1690c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
1691c6fd2807SJeff Garzik 	msleep(1);
1692c6fd2807SJeff Garzik 
1693c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
1694c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
1695a9cf5e85STejun Heo 	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1696c6fd2807SJeff Garzik 
1697705e76beSTejun Heo 	/* wait for link to become ready */
1698bd17243aSShane Huang 	rc = ata_wait_after_reset(link, deadline, check_ready);
16999b89391cSTejun Heo 	/* link occupied, -ENODEV too is an error */
17009b89391cSTejun Heo 	if (rc) {
1701c6fd2807SJeff Garzik 		reason = "device not ready";
1702c6fd2807SJeff Garzik 		goto fail;
1703c6fd2807SJeff Garzik 	}
1704c6fd2807SJeff Garzik 	*class = ahci_dev_classify(ap);
1705c6fd2807SJeff Garzik 
1706c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
1707c6fd2807SJeff Garzik 	return 0;
1708c6fd2807SJeff Garzik 
1709c6fd2807SJeff Garzik  fail:
1710cc0680a5STejun Heo 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
1711c6fd2807SJeff Garzik 	return rc;
1712c6fd2807SJeff Garzik }
1713c6fd2807SJeff Garzik 
1714bd17243aSShane Huang static int ahci_check_ready(struct ata_link *link)
1715bd17243aSShane Huang {
1716bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1717bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1718bd17243aSShane Huang 
1719bd17243aSShane Huang 	return ata_check_ready(status);
1720bd17243aSShane Huang }
1721bd17243aSShane Huang 
1722bd17243aSShane Huang static int ahci_softreset(struct ata_link *link, unsigned int *class,
1723bd17243aSShane Huang 			  unsigned long deadline)
1724bd17243aSShane Huang {
1725bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1726bd17243aSShane Huang 
1727bd17243aSShane Huang 	DPRINTK("ENTER\n");
1728bd17243aSShane Huang 
1729bd17243aSShane Huang 	return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
1730bd17243aSShane Huang }
1731bd17243aSShane Huang 
1732bd17243aSShane Huang static int ahci_sb600_check_ready(struct ata_link *link)
1733bd17243aSShane Huang {
1734bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1735bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1736bd17243aSShane Huang 	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
1737bd17243aSShane Huang 
1738bd17243aSShane Huang 	/*
1739bd17243aSShane Huang 	 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
1740bd17243aSShane Huang 	 * which can save timeout delay.
1741bd17243aSShane Huang 	 */
1742bd17243aSShane Huang 	if (irq_status & PORT_IRQ_BAD_PMP)
1743bd17243aSShane Huang 		return -EIO;
1744bd17243aSShane Huang 
1745bd17243aSShane Huang 	return ata_check_ready(status);
1746bd17243aSShane Huang }
1747bd17243aSShane Huang 
1748bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
1749bd17243aSShane Huang 				unsigned long deadline)
1750bd17243aSShane Huang {
1751bd17243aSShane Huang 	struct ata_port *ap = link->ap;
1752bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(ap);
1753bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1754bd17243aSShane Huang 	int rc;
1755bd17243aSShane Huang 	u32 irq_sts;
1756bd17243aSShane Huang 
1757bd17243aSShane Huang 	DPRINTK("ENTER\n");
1758bd17243aSShane Huang 
1759bd17243aSShane Huang 	rc = ahci_do_softreset(link, class, pmp, deadline,
1760bd17243aSShane Huang 			       ahci_sb600_check_ready);
1761bd17243aSShane Huang 
1762bd17243aSShane Huang 	/*
1763bd17243aSShane Huang 	 * Soft reset fails on some ATI chips with IPMS set when PMP
1764bd17243aSShane Huang 	 * is enabled but SATA HDD/ODD is connected to SATA port,
1765bd17243aSShane Huang 	 * do soft reset again to port 0.
1766bd17243aSShane Huang 	 */
1767bd17243aSShane Huang 	if (rc == -EIO) {
1768bd17243aSShane Huang 		irq_sts = readl(port_mmio + PORT_IRQ_STAT);
1769bd17243aSShane Huang 		if (irq_sts & PORT_IRQ_BAD_PMP) {
1770bd17243aSShane Huang 			ata_link_printk(link, KERN_WARNING,
1771bd17243aSShane Huang 					"failed due to HW bug, retry pmp=0\n");
1772bd17243aSShane Huang 			rc = ahci_do_softreset(link, class, 0, deadline,
1773bd17243aSShane Huang 					       ahci_check_ready);
1774bd17243aSShane Huang 		}
1775bd17243aSShane Huang 	}
1776bd17243aSShane Huang 
1777bd17243aSShane Huang 	return rc;
1778bd17243aSShane Huang }
1779bd17243aSShane Huang 
1780cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1781d4b2bab4STejun Heo 			  unsigned long deadline)
1782c6fd2807SJeff Garzik {
17839dadd45bSTejun Heo 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
1784cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1785c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1786c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1787c6fd2807SJeff Garzik 	struct ata_taskfile tf;
17889dadd45bSTejun Heo 	bool online;
1789c6fd2807SJeff Garzik 	int rc;
1790c6fd2807SJeff Garzik 
1791c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1792c6fd2807SJeff Garzik 
17934447d351STejun Heo 	ahci_stop_engine(ap);
1794c6fd2807SJeff Garzik 
1795c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1796cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1797dfd7a3dbSTejun Heo 	tf.command = 0x80;
17989977126cSTejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1799c6fd2807SJeff Garzik 
18009dadd45bSTejun Heo 	rc = sata_link_hardreset(link, timing, deadline, &online,
18019dadd45bSTejun Heo 				 ahci_check_ready);
1802c6fd2807SJeff Garzik 
18034447d351STejun Heo 	ahci_start_engine(ap);
1804c6fd2807SJeff Garzik 
18059dadd45bSTejun Heo 	if (online)
18069dadd45bSTejun Heo 		*class = ahci_dev_classify(ap);
1807c6fd2807SJeff Garzik 
1808c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1809c6fd2807SJeff Garzik 	return rc;
1810c6fd2807SJeff Garzik }
1811c6fd2807SJeff Garzik 
1812cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1813d4b2bab4STejun Heo 				 unsigned long deadline)
1814ad616ffbSTejun Heo {
1815cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
18169dadd45bSTejun Heo 	bool online;
1817ad616ffbSTejun Heo 	int rc;
1818ad616ffbSTejun Heo 
1819ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1820ad616ffbSTejun Heo 
18214447d351STejun Heo 	ahci_stop_engine(ap);
1822ad616ffbSTejun Heo 
1823cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
18249dadd45bSTejun Heo 				 deadline, &online, NULL);
1825ad616ffbSTejun Heo 
18264447d351STejun Heo 	ahci_start_engine(ap);
1827ad616ffbSTejun Heo 
1828ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1829ad616ffbSTejun Heo 
1830ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1831ad616ffbSTejun Heo 	 * request follow-up softreset.
1832ad616ffbSTejun Heo 	 */
18339dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
1834ad616ffbSTejun Heo }
1835ad616ffbSTejun Heo 
1836edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1837edc93052STejun Heo 				unsigned long deadline)
1838edc93052STejun Heo {
1839edc93052STejun Heo 	struct ata_port *ap = link->ap;
1840edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1841edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1842edc93052STejun Heo 	struct ata_taskfile tf;
18439dadd45bSTejun Heo 	bool online;
1844edc93052STejun Heo 	int rc;
1845edc93052STejun Heo 
1846edc93052STejun Heo 	ahci_stop_engine(ap);
1847edc93052STejun Heo 
1848edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
1849edc93052STejun Heo 	ata_tf_init(link->device, &tf);
1850edc93052STejun Heo 	tf.command = 0x80;
1851edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1852edc93052STejun Heo 
1853edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
18549dadd45bSTejun Heo 				 deadline, &online, NULL);
1855edc93052STejun Heo 
1856edc93052STejun Heo 	ahci_start_engine(ap);
1857edc93052STejun Heo 
1858edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
1859edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1860edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
1861edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
1862edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
1863edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1864edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1865edc93052STejun Heo 	 *
1866edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
1867edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
1868edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
1869edc93052STejun Heo 	 * suffice while making probing snappish enough.
1870edc93052STejun Heo 	 */
18719dadd45bSTejun Heo 	if (online) {
18729dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
18739dadd45bSTejun Heo 					  ahci_check_ready);
1874edc93052STejun Heo 		if (rc)
1875edc93052STejun Heo 			ahci_kick_engine(ap, 0);
18769dadd45bSTejun Heo 	}
18779dadd45bSTejun Heo 	return rc;
1878edc93052STejun Heo }
1879edc93052STejun Heo 
1880cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class)
1881c6fd2807SJeff Garzik {
1882cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
18834447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1884c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1885c6fd2807SJeff Garzik 
1886203c75b8STejun Heo 	ata_std_postreset(link, class);
1887c6fd2807SJeff Garzik 
1888c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1889c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1890c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1891c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
1892c6fd2807SJeff Garzik 	else
1893c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
1894c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
1895c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
1896c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
1897c6fd2807SJeff Garzik 	}
1898c6fd2807SJeff Garzik }
1899c6fd2807SJeff Garzik 
1900c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
1901c6fd2807SJeff Garzik {
1902c6fd2807SJeff Garzik 	struct scatterlist *sg;
1903ff2aeb1eSTejun Heo 	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
1904ff2aeb1eSTejun Heo 	unsigned int si;
1905c6fd2807SJeff Garzik 
1906c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1907c6fd2807SJeff Garzik 
1908c6fd2807SJeff Garzik 	/*
1909c6fd2807SJeff Garzik 	 * Next, the S/G list.
1910c6fd2807SJeff Garzik 	 */
1911ff2aeb1eSTejun Heo 	for_each_sg(qc->sg, sg, qc->n_elem, si) {
1912c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1913c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1914c6fd2807SJeff Garzik 
1915ff2aeb1eSTejun Heo 		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
1916ff2aeb1eSTejun Heo 		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
1917ff2aeb1eSTejun Heo 		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
1918c6fd2807SJeff Garzik 	}
1919c6fd2807SJeff Garzik 
1920ff2aeb1eSTejun Heo 	return si;
1921c6fd2807SJeff Garzik }
1922c6fd2807SJeff Garzik 
1923c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1924c6fd2807SJeff Garzik {
1925c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1926c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1927405e66b3STejun Heo 	int is_atapi = ata_is_atapi(qc->tf.protocol);
1928c6fd2807SJeff Garzik 	void *cmd_tbl;
1929c6fd2807SJeff Garzik 	u32 opts;
1930c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1931c6fd2807SJeff Garzik 	unsigned int n_elem;
1932c6fd2807SJeff Garzik 
1933c6fd2807SJeff Garzik 	/*
1934c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1935c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1936c6fd2807SJeff Garzik 	 */
1937c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1938c6fd2807SJeff Garzik 
19397d50b60bSTejun Heo 	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
1940c6fd2807SJeff Garzik 	if (is_atapi) {
1941c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1942c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1943c6fd2807SJeff Garzik 	}
1944c6fd2807SJeff Garzik 
1945c6fd2807SJeff Garzik 	n_elem = 0;
1946c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1947c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1948c6fd2807SJeff Garzik 
1949c6fd2807SJeff Garzik 	/*
1950c6fd2807SJeff Garzik 	 * Fill in command slot information.
1951c6fd2807SJeff Garzik 	 */
19527d50b60bSTejun Heo 	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
1953c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1954c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1955c6fd2807SJeff Garzik 	if (is_atapi)
1956c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1957c6fd2807SJeff Garzik 
1958c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1959c6fd2807SJeff Garzik }
1960c6fd2807SJeff Garzik 
1961c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1962c6fd2807SJeff Garzik {
1963417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1964c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
19657d50b60bSTejun Heo 	struct ata_eh_info *host_ehi = &ap->link.eh_info;
19667d50b60bSTejun Heo 	struct ata_link *link = NULL;
19677d50b60bSTejun Heo 	struct ata_queued_cmd *active_qc;
19687d50b60bSTejun Heo 	struct ata_eh_info *active_ehi;
1969c6fd2807SJeff Garzik 	u32 serror;
1970c6fd2807SJeff Garzik 
19717d50b60bSTejun Heo 	/* determine active link */
19721eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE)
19737d50b60bSTejun Heo 		if (ata_link_active(link))
19747d50b60bSTejun Heo 			break;
19757d50b60bSTejun Heo 	if (!link)
19767d50b60bSTejun Heo 		link = &ap->link;
19777d50b60bSTejun Heo 
19787d50b60bSTejun Heo 	active_qc = ata_qc_from_tag(ap, link->active_tag);
19797d50b60bSTejun Heo 	active_ehi = &link->eh_info;
19807d50b60bSTejun Heo 
19817d50b60bSTejun Heo 	/* record irq stat */
19827d50b60bSTejun Heo 	ata_ehi_clear_desc(host_ehi);
19837d50b60bSTejun Heo 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
1984c6fd2807SJeff Garzik 
1985c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
198682ef04fbSTejun Heo 	ahci_scr_read(&ap->link, SCR_ERROR, &serror);
198782ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, serror);
19887d50b60bSTejun Heo 	host_ehi->serror |= serror;
1989c6fd2807SJeff Garzik 
199041669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
1991417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
199241669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
199341669553STejun Heo 
199455a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
19957d50b60bSTejun Heo 		/* If qc is active, charge it; otherwise, the active
19967d50b60bSTejun Heo 		 * link.  There's no active qc on NCQ errors.  It will
19977d50b60bSTejun Heo 		 * be determined by EH by reading log page 10h.
19987d50b60bSTejun Heo 		 */
19997d50b60bSTejun Heo 		if (active_qc)
20007d50b60bSTejun Heo 			active_qc->err_mask |= AC_ERR_DEV;
20017d50b60bSTejun Heo 		else
20027d50b60bSTejun Heo 			active_ehi->err_mask |= AC_ERR_DEV;
20037d50b60bSTejun Heo 
2004417a1a6dSTejun Heo 		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
20057d50b60bSTejun Heo 			host_ehi->serror &= ~SERR_INTERNAL;
2006c6fd2807SJeff Garzik 	}
2007c6fd2807SJeff Garzik 
2008c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
2009c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
2010c6fd2807SJeff Garzik 
20117d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
2012cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
20137d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi,
20147d50b60bSTejun Heo 				  "unknown FIS %08x %08x %08x %08x" ,
2015c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
2016c6fd2807SJeff Garzik 	}
2017c6fd2807SJeff Garzik 
2018071f44b1STejun Heo 	if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
20197d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
2020cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
20217d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi, "incorrect PMP");
20227d50b60bSTejun Heo 	}
2023c6fd2807SJeff Garzik 
20247d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
20257d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_HOST_BUS;
2026cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
20277d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "host bus error");
20287d50b60bSTejun Heo 	}
20297d50b60bSTejun Heo 
20307d50b60bSTejun Heo 	if (irq_stat & PORT_IRQ_IF_ERR) {
20317d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_ATA_BUS;
2032cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
20337d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "interface fatal error");
20347d50b60bSTejun Heo 	}
20357d50b60bSTejun Heo 
20367d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
20377d50b60bSTejun Heo 		ata_ehi_hotplugged(host_ehi);
20387d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "%s",
20397d50b60bSTejun Heo 			irq_stat & PORT_IRQ_CONNECT ?
20407d50b60bSTejun Heo 			"connection status changed" : "PHY RDY changed");
20417d50b60bSTejun Heo 	}
20427d50b60bSTejun Heo 
20437d50b60bSTejun Heo 	/* okay, let's hand over to EH */
2044c6fd2807SJeff Garzik 
2045c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
2046c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2047c6fd2807SJeff Garzik 	else
2048c6fd2807SJeff Garzik 		ata_port_abort(ap);
2049c6fd2807SJeff Garzik }
2050c6fd2807SJeff Garzik 
2051df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap)
2052c6fd2807SJeff Garzik {
2053350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
20549af5c9c9STejun Heo 	struct ata_eh_info *ehi = &ap->link.eh_info;
20550291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
20565f226c6bSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
2057b06ce3e5STejun Heo 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
2058c6fd2807SJeff Garzik 	u32 status, qc_active;
2059459ad688STejun Heo 	int rc;
2060c6fd2807SJeff Garzik 
2061c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
2062c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
2063c6fd2807SJeff Garzik 
2064b06ce3e5STejun Heo 	/* ignore BAD_PMP while resetting */
2065b06ce3e5STejun Heo 	if (unlikely(resetting))
2066b06ce3e5STejun Heo 		status &= ~PORT_IRQ_BAD_PMP;
2067b06ce3e5STejun Heo 
206831556594SKristen Carlson Accardi 	/* If we are getting PhyRdy, this is
206931556594SKristen Carlson Accardi  	 * just a power state change, we should
207031556594SKristen Carlson Accardi  	 * clear out this, plus the PhyRdy/Comm
207131556594SKristen Carlson Accardi  	 * Wake bits from Serror
207231556594SKristen Carlson Accardi  	 */
207331556594SKristen Carlson Accardi 	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
207431556594SKristen Carlson Accardi 		(status & PORT_IRQ_PHYRDY)) {
207531556594SKristen Carlson Accardi 		status &= ~PORT_IRQ_PHYRDY;
207682ef04fbSTejun Heo 		ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
207731556594SKristen Carlson Accardi 	}
207831556594SKristen Carlson Accardi 
2079c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
2080c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
2081c6fd2807SJeff Garzik 		return;
2082c6fd2807SJeff Garzik 	}
2083c6fd2807SJeff Garzik 
20842f294968SKristen Carlson Accardi 	if (status & PORT_IRQ_SDB_FIS) {
20855f226c6bSTejun Heo 		/* If SNotification is available, leave notification
20865f226c6bSTejun Heo 		 * handling to sata_async_notification().  If not,
20875f226c6bSTejun Heo 		 * emulate it by snooping SDB FIS RX area.
20885f226c6bSTejun Heo 		 *
20895f226c6bSTejun Heo 		 * Snooping FIS RX area is probably cheaper than
20905f226c6bSTejun Heo 		 * poking SNotification but some constrollers which
20915f226c6bSTejun Heo 		 * implement SNotification, ICH9 for example, don't
20925f226c6bSTejun Heo 		 * store AN SDB FIS into receive area.
20935f226c6bSTejun Heo 		 */
20945f226c6bSTejun Heo 		if (hpriv->cap & HOST_CAP_SNTF)
20955f226c6bSTejun Heo 			sata_async_notification(ap);
20965f226c6bSTejun Heo 		else {
20975f226c6bSTejun Heo 			/* If the 'N' bit in word 0 of the FIS is set,
20985f226c6bSTejun Heo 			 * we just received asynchronous notification.
20995f226c6bSTejun Heo 			 * Tell libata about it.
21002f294968SKristen Carlson Accardi 			 */
21012f294968SKristen Carlson Accardi 			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
21022f294968SKristen Carlson Accardi 			u32 f0 = le32_to_cpu(f[0]);
21032f294968SKristen Carlson Accardi 
21047d77b247STejun Heo 			if (f0 & (1 << 15))
21057d77b247STejun Heo 				sata_async_notification(ap);
21062f294968SKristen Carlson Accardi 		}
21075f226c6bSTejun Heo 	}
21082f294968SKristen Carlson Accardi 
21097d50b60bSTejun Heo 	/* pp->active_link is valid iff any command is in flight */
21107d50b60bSTejun Heo 	if (ap->qc_active && pp->active_link->sactive)
2111c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
2112c6fd2807SJeff Garzik 	else
2113c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
2114c6fd2807SJeff Garzik 
211579f97dadSTejun Heo 	rc = ata_qc_complete_multiple(ap, qc_active);
2116b06ce3e5STejun Heo 
2117459ad688STejun Heo 	/* while resetting, invalid completions are expected */
2118459ad688STejun Heo 	if (unlikely(rc < 0 && !resetting)) {
2119c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
2120cf480626STejun Heo 		ehi->action |= ATA_EH_RESET;
2121c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2122c6fd2807SJeff Garzik 	}
2123c6fd2807SJeff Garzik }
2124c6fd2807SJeff Garzik 
21257d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
2126c6fd2807SJeff Garzik {
2127cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
2128c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
2129c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
2130c6fd2807SJeff Garzik 	void __iomem *mmio;
2131d28f87aaSTejun Heo 	u32 irq_stat, irq_masked;
2132c6fd2807SJeff Garzik 
2133c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2134c6fd2807SJeff Garzik 
2135cca3974eSJeff Garzik 	hpriv = host->private_data;
21360d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
2137c6fd2807SJeff Garzik 
2138c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
2139c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
2140c6fd2807SJeff Garzik 	if (!irq_stat)
2141c6fd2807SJeff Garzik 		return IRQ_NONE;
2142c6fd2807SJeff Garzik 
2143d28f87aaSTejun Heo 	irq_masked = irq_stat & hpriv->port_map;
2144d28f87aaSTejun Heo 
2145cca3974eSJeff Garzik 	spin_lock(&host->lock);
2146c6fd2807SJeff Garzik 
2147cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
2148c6fd2807SJeff Garzik 		struct ata_port *ap;
2149c6fd2807SJeff Garzik 
2150d28f87aaSTejun Heo 		if (!(irq_masked & (1 << i)))
2151c6fd2807SJeff Garzik 			continue;
2152c6fd2807SJeff Garzik 
2153cca3974eSJeff Garzik 		ap = host->ports[i];
2154c6fd2807SJeff Garzik 		if (ap) {
2155df69c9c5SJeff Garzik 			ahci_port_intr(ap);
2156c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
2157c6fd2807SJeff Garzik 		} else {
2158c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
2159c6fd2807SJeff Garzik 			if (ata_ratelimit())
2160cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
2161c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
2162c6fd2807SJeff Garzik 		}
2163c6fd2807SJeff Garzik 
2164c6fd2807SJeff Garzik 		handled = 1;
2165c6fd2807SJeff Garzik 	}
2166c6fd2807SJeff Garzik 
2167d28f87aaSTejun Heo 	/* HOST_IRQ_STAT behaves as level triggered latch meaning that
2168d28f87aaSTejun Heo 	 * it should be cleared after all the port events are cleared;
2169d28f87aaSTejun Heo 	 * otherwise, it will raise a spurious interrupt after each
2170d28f87aaSTejun Heo 	 * valid one.  Please read section 10.6.2 of ahci 1.1 for more
2171d28f87aaSTejun Heo 	 * information.
2172d28f87aaSTejun Heo 	 *
2173d28f87aaSTejun Heo 	 * Also, use the unmasked value to clear interrupt as spurious
2174d28f87aaSTejun Heo 	 * pending event on a dummy port might cause screaming IRQ.
2175d28f87aaSTejun Heo 	 */
2176ea0c62f7STejun Heo 	writel(irq_stat, mmio + HOST_IRQ_STAT);
2177ea0c62f7STejun Heo 
2178cca3974eSJeff Garzik 	spin_unlock(&host->lock);
2179c6fd2807SJeff Garzik 
2180c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
2181c6fd2807SJeff Garzik 
2182c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
2183c6fd2807SJeff Garzik }
2184c6fd2807SJeff Garzik 
2185c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
2186c6fd2807SJeff Garzik {
2187c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
21884447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
21897d50b60bSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
21907d50b60bSTejun Heo 
21917d50b60bSTejun Heo 	/* Keep track of the currently active link.  It will be used
21927d50b60bSTejun Heo 	 * in completion path to determine whether NCQ phase is in
21937d50b60bSTejun Heo 	 * progress.
21947d50b60bSTejun Heo 	 */
21957d50b60bSTejun Heo 	pp->active_link = qc->dev->link;
2196c6fd2807SJeff Garzik 
2197c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
2198c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
2199c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
2200c6fd2807SJeff Garzik 
220118f7ba4cSKristen Carlson Accardi 	ahci_sw_activity(qc->dev->link);
220218f7ba4cSKristen Carlson Accardi 
2203c6fd2807SJeff Garzik 	return 0;
2204c6fd2807SJeff Garzik }
2205c6fd2807SJeff Garzik 
22064c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
22074c9bf4e7STejun Heo {
22084c9bf4e7STejun Heo 	struct ahci_port_priv *pp = qc->ap->private_data;
22094c9bf4e7STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
22104c9bf4e7STejun Heo 
22114c9bf4e7STejun Heo 	ata_tf_from_fis(d2h_fis, &qc->result_tf);
22124c9bf4e7STejun Heo 	return true;
22134c9bf4e7STejun Heo }
22144c9bf4e7STejun Heo 
2215c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
2216c6fd2807SJeff Garzik {
22174447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2218c6fd2807SJeff Garzik 
2219c6fd2807SJeff Garzik 	/* turn IRQ off */
2220c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
2221c6fd2807SJeff Garzik }
2222c6fd2807SJeff Garzik 
2223c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
2224c6fd2807SJeff Garzik {
22250d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
22264447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2227c6fd2807SJeff Garzik 	u32 tmp;
2228a7384925SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
2229c6fd2807SJeff Garzik 
2230c6fd2807SJeff Garzik 	/* clear IRQ */
2231c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
2232c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
2233a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
2234c6fd2807SJeff Garzik 
22351c954a4dSTejun Heo 	/* turn IRQ back on */
22361c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
2237c6fd2807SJeff Garzik }
2238c6fd2807SJeff Garzik 
2239c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
2240c6fd2807SJeff Garzik {
2241c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
2242c6fd2807SJeff Garzik 		/* restart engine */
22434447d351STejun Heo 		ahci_stop_engine(ap);
22444447d351STejun Heo 		ahci_start_engine(ap);
2245c6fd2807SJeff Garzik 	}
2246c6fd2807SJeff Garzik 
2247a1efdabaSTejun Heo 	sata_pmp_error_handler(ap);
2248edc93052STejun Heo }
2249edc93052STejun Heo 
2250c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
2251c6fd2807SJeff Garzik {
2252c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
2253c6fd2807SJeff Garzik 
2254c6fd2807SJeff Garzik 	/* make DMA engine forget about the failed command */
2255d2e75dffSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED)
2256d2e75dffSTejun Heo 		ahci_kick_engine(ap, 1);
2257c6fd2807SJeff Garzik }
2258c6fd2807SJeff Garzik 
22597d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap)
22607d50b60bSTejun Heo {
22617d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22621c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22637d50b60bSTejun Heo 	u32 cmd;
22647d50b60bSTejun Heo 
22657d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
22667d50b60bSTejun Heo 	cmd |= PORT_CMD_PMP;
22677d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
22681c954a4dSTejun Heo 
22691c954a4dSTejun Heo 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
22701c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
22717d50b60bSTejun Heo }
22727d50b60bSTejun Heo 
22737d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap)
22747d50b60bSTejun Heo {
22757d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22761c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22777d50b60bSTejun Heo 	u32 cmd;
22787d50b60bSTejun Heo 
22797d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
22807d50b60bSTejun Heo 	cmd &= ~PORT_CMD_PMP;
22817d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
22821c954a4dSTejun Heo 
22831c954a4dSTejun Heo 	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
22841c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
22857d50b60bSTejun Heo }
22867d50b60bSTejun Heo 
2287028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap)
2288028a2596SAlexey Dobriyan {
2289028a2596SAlexey Dobriyan 	ahci_power_up(ap);
2290028a2596SAlexey Dobriyan 	ahci_start_port(ap);
2291028a2596SAlexey Dobriyan 
2292071f44b1STejun Heo 	if (sata_pmp_attached(ap))
22937d50b60bSTejun Heo 		ahci_pmp_attach(ap);
22947d50b60bSTejun Heo 	else
22957d50b60bSTejun Heo 		ahci_pmp_detach(ap);
22967d50b60bSTejun Heo 
2297028a2596SAlexey Dobriyan 	return 0;
2298028a2596SAlexey Dobriyan }
2299028a2596SAlexey Dobriyan 
2300438ac6d5STejun Heo #ifdef CONFIG_PM
2301c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
2302c6fd2807SJeff Garzik {
2303c6fd2807SJeff Garzik 	const char *emsg = NULL;
2304c6fd2807SJeff Garzik 	int rc;
2305c6fd2807SJeff Garzik 
23064447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
23078e16f941STejun Heo 	if (rc == 0)
23084447d351STejun Heo 		ahci_power_down(ap);
23098e16f941STejun Heo 	else {
2310c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
2311df69c9c5SJeff Garzik 		ahci_start_port(ap);
2312c6fd2807SJeff Garzik 	}
2313c6fd2807SJeff Garzik 
2314c6fd2807SJeff Garzik 	return rc;
2315c6fd2807SJeff Garzik }
2316c6fd2807SJeff Garzik 
2317c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
2318c6fd2807SJeff Garzik {
2319cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
2320*9b10ae86STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
23210d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2322c6fd2807SJeff Garzik 	u32 ctl;
2323c6fd2807SJeff Garzik 
2324*9b10ae86STejun Heo 	if (mesg.event & PM_EVENT_SUSPEND &&
2325*9b10ae86STejun Heo 	    hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
2326*9b10ae86STejun Heo 		dev_printk(KERN_ERR, &pdev->dev,
2327*9b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
2328*9b10ae86STejun Heo 		return -EIO;
2329*9b10ae86STejun Heo 	}
2330*9b10ae86STejun Heo 
23313a2d5b70SRafael J. Wysocki 	if (mesg.event & PM_EVENT_SLEEP) {
2332c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
2333c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
2334c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
2335c6fd2807SJeff Garzik 		 */
2336c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
2337c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
2338c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
2339c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
2340c6fd2807SJeff Garzik 	}
2341c6fd2807SJeff Garzik 
2342c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
2343c6fd2807SJeff Garzik }
2344c6fd2807SJeff Garzik 
2345c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
2346c6fd2807SJeff Garzik {
2347cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
2348c6fd2807SJeff Garzik 	int rc;
2349c6fd2807SJeff Garzik 
2350553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
2351553c4aa6STejun Heo 	if (rc)
2352553c4aa6STejun Heo 		return rc;
2353c6fd2807SJeff Garzik 
2354c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
23554447d351STejun Heo 		rc = ahci_reset_controller(host);
2356c6fd2807SJeff Garzik 		if (rc)
2357c6fd2807SJeff Garzik 			return rc;
2358c6fd2807SJeff Garzik 
23594447d351STejun Heo 		ahci_init_controller(host);
2360c6fd2807SJeff Garzik 	}
2361c6fd2807SJeff Garzik 
2362cca3974eSJeff Garzik 	ata_host_resume(host);
2363c6fd2807SJeff Garzik 
2364c6fd2807SJeff Garzik 	return 0;
2365c6fd2807SJeff Garzik }
2366438ac6d5STejun Heo #endif
2367c6fd2807SJeff Garzik 
2368c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
2369c6fd2807SJeff Garzik {
2370cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
2371c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
2372c6fd2807SJeff Garzik 	void *mem;
2373c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
2374c6fd2807SJeff Garzik 
237524dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
2376c6fd2807SJeff Garzik 	if (!pp)
2377c6fd2807SJeff Garzik 		return -ENOMEM;
2378c6fd2807SJeff Garzik 
237924dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
238024dc5f33STejun Heo 				  GFP_KERNEL);
238124dc5f33STejun Heo 	if (!mem)
2382c6fd2807SJeff Garzik 		return -ENOMEM;
2383c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
2384c6fd2807SJeff Garzik 
2385c6fd2807SJeff Garzik 	/*
2386c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
2387c6fd2807SJeff Garzik 	 * 32 bytes each in size
2388c6fd2807SJeff Garzik 	 */
2389c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
2390c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
2391c6fd2807SJeff Garzik 
2392c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
2393c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
2394c6fd2807SJeff Garzik 
2395c6fd2807SJeff Garzik 	/*
2396c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
2397c6fd2807SJeff Garzik 	 */
2398c6fd2807SJeff Garzik 	pp->rx_fis = mem;
2399c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
2400c6fd2807SJeff Garzik 
2401c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
2402c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
2403c6fd2807SJeff Garzik 
2404c6fd2807SJeff Garzik 	/*
2405c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
2406c6fd2807SJeff Garzik 	 * and its scatter-gather table
2407c6fd2807SJeff Garzik 	 */
2408c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
2409c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
2410c6fd2807SJeff Garzik 
2411a7384925SKristen Carlson Accardi 	/*
2412a7384925SKristen Carlson Accardi 	 * Save off initial list of interrupts to be enabled.
2413a7384925SKristen Carlson Accardi 	 * This could be changed later
2414a7384925SKristen Carlson Accardi 	 */
2415a7384925SKristen Carlson Accardi 	pp->intr_mask = DEF_PORT_IRQ;
2416a7384925SKristen Carlson Accardi 
2417c6fd2807SJeff Garzik 	ap->private_data = pp;
2418c6fd2807SJeff Garzik 
2419df69c9c5SJeff Garzik 	/* engage engines, captain */
2420df69c9c5SJeff Garzik 	return ahci_port_resume(ap);
2421c6fd2807SJeff Garzik }
2422c6fd2807SJeff Garzik 
2423c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
2424c6fd2807SJeff Garzik {
2425c6fd2807SJeff Garzik 	const char *emsg = NULL;
2426c6fd2807SJeff Garzik 	int rc;
2427c6fd2807SJeff Garzik 
2428c6fd2807SJeff Garzik 	/* de-initialize port */
24294447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
2430c6fd2807SJeff Garzik 	if (rc)
2431c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
2432c6fd2807SJeff Garzik }
2433c6fd2807SJeff Garzik 
24344447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
2435c6fd2807SJeff Garzik {
2436c6fd2807SJeff Garzik 	int rc;
2437c6fd2807SJeff Garzik 
2438c6fd2807SJeff Garzik 	if (using_dac &&
24396a35528aSYang Hongyang 	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
24406a35528aSYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
2441c6fd2807SJeff Garzik 		if (rc) {
2442284901a9SYang Hongyang 			rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
2443c6fd2807SJeff Garzik 			if (rc) {
2444c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
2445c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
2446c6fd2807SJeff Garzik 				return rc;
2447c6fd2807SJeff Garzik 			}
2448c6fd2807SJeff Garzik 		}
2449c6fd2807SJeff Garzik 	} else {
2450284901a9SYang Hongyang 		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
2451c6fd2807SJeff Garzik 		if (rc) {
2452c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2453c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
2454c6fd2807SJeff Garzik 			return rc;
2455c6fd2807SJeff Garzik 		}
2456284901a9SYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
2457c6fd2807SJeff Garzik 		if (rc) {
2458c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2459c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
2460c6fd2807SJeff Garzik 			return rc;
2461c6fd2807SJeff Garzik 		}
2462c6fd2807SJeff Garzik 	}
2463c6fd2807SJeff Garzik 	return 0;
2464c6fd2807SJeff Garzik }
2465c6fd2807SJeff Garzik 
24664447d351STejun Heo static void ahci_print_info(struct ata_host *host)
2467c6fd2807SJeff Garzik {
24684447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
24694447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
24704447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2471c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
2472c6fd2807SJeff Garzik 	const char *speed_s;
2473c6fd2807SJeff Garzik 	u16 cc;
2474c6fd2807SJeff Garzik 	const char *scc_s;
2475c6fd2807SJeff Garzik 
2476c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
2477c6fd2807SJeff Garzik 	cap = hpriv->cap;
2478c6fd2807SJeff Garzik 	impl = hpriv->port_map;
2479c6fd2807SJeff Garzik 
2480c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
2481c6fd2807SJeff Garzik 	if (speed == 1)
2482c6fd2807SJeff Garzik 		speed_s = "1.5";
2483c6fd2807SJeff Garzik 	else if (speed == 2)
2484c6fd2807SJeff Garzik 		speed_s = "3";
24858522ee25SShane Huang 	else if (speed == 3)
24868522ee25SShane Huang 		speed_s = "6";
2487c6fd2807SJeff Garzik 	else
2488c6fd2807SJeff Garzik 		speed_s = "?";
2489c6fd2807SJeff Garzik 
2490c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
2491c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
2492c6fd2807SJeff Garzik 		scc_s = "IDE";
2493c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
2494c6fd2807SJeff Garzik 		scc_s = "SATA";
2495c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
2496c6fd2807SJeff Garzik 		scc_s = "RAID";
2497c6fd2807SJeff Garzik 	else
2498c6fd2807SJeff Garzik 		scc_s = "unknown";
2499c6fd2807SJeff Garzik 
2500c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2501c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
2502c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
2503c6fd2807SJeff Garzik 		,
2504c6fd2807SJeff Garzik 
2505c6fd2807SJeff Garzik 		(vers >> 24) & 0xff,
2506c6fd2807SJeff Garzik 		(vers >> 16) & 0xff,
2507c6fd2807SJeff Garzik 		(vers >> 8) & 0xff,
2508c6fd2807SJeff Garzik 		vers & 0xff,
2509c6fd2807SJeff Garzik 
2510c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
2511c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
2512c6fd2807SJeff Garzik 		speed_s,
2513c6fd2807SJeff Garzik 		impl,
2514c6fd2807SJeff Garzik 		scc_s);
2515c6fd2807SJeff Garzik 
2516c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2517c6fd2807SJeff Garzik 		"flags: "
2518203ef6c4STejun Heo 		"%s%s%s%s%s%s%s"
251918f7ba4cSKristen Carlson Accardi 		"%s%s%s%s%s%s%s"
252018f7ba4cSKristen Carlson Accardi 		"%s\n"
2521c6fd2807SJeff Garzik 		,
2522c6fd2807SJeff Garzik 
2523c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
2524c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
2525203ef6c4STejun Heo 		cap & (1 << 29) ? "sntf " : "",
2526c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
2527c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
2528c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
2529c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
2530c6fd2807SJeff Garzik 
2531c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
2532c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
2533c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
2534c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
2535c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
2536c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
253718f7ba4cSKristen Carlson Accardi 		cap & (1 << 13) ? "part " : "",
253818f7ba4cSKristen Carlson Accardi 		cap & (1 << 6) ? "ems ": ""
2539c6fd2807SJeff Garzik 		);
2540c6fd2807SJeff Garzik }
2541c6fd2807SJeff Garzik 
2542edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2543edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
2544edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
2545edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
2546edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
2547edc93052STejun Heo  * other configuration).
2548edc93052STejun Heo  *
2549edc93052STejun Heo  * When there's no device attached to the first downstream port of the
2550edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
2551edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
2552edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
2553edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2554edc93052STejun Heo  *
2555edc93052STejun Heo  * The following function works around the problem by always using
2556edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
2557edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
2558edc93052STejun Heo  * assumed without follow-up softreset.
2559edc93052STejun Heo  */
2560edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
2561edc93052STejun Heo {
2562edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
2563edc93052STejun Heo 		{
2564edc93052STejun Heo 			.ident = "P5W DH Deluxe",
2565edc93052STejun Heo 			.matches = {
2566edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
2567edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
2568edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2569edc93052STejun Heo 			},
2570edc93052STejun Heo 		},
2571edc93052STejun Heo 		{ }
2572edc93052STejun Heo 	};
2573edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
2574edc93052STejun Heo 
2575edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2576edc93052STejun Heo 	    dmi_check_system(sysids)) {
2577edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
2578edc93052STejun Heo 
2579edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2580edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
2581edc93052STejun Heo 
2582edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
2583edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2584edc93052STejun Heo 	}
2585edc93052STejun Heo }
2586edc93052STejun Heo 
25871fd68434SRafael J. Wysocki static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
25881fd68434SRafael J. Wysocki {
25891fd68434SRafael J. Wysocki 	static const struct dmi_system_id broken_systems[] = {
25901fd68434SRafael J. Wysocki 		{
25911fd68434SRafael J. Wysocki 			.ident = "HP Compaq nx6310",
25921fd68434SRafael J. Wysocki 			.matches = {
25931fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
25941fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
25951fd68434SRafael J. Wysocki 			},
25961fd68434SRafael J. Wysocki 			/* PCI slot number of the controller */
25971fd68434SRafael J. Wysocki 			.driver_data = (void *)0x1FUL,
25981fd68434SRafael J. Wysocki 		},
2599d2f9c061SMaciej Rutecki 		{
2600d2f9c061SMaciej Rutecki 			.ident = "HP Compaq 6720s",
2601d2f9c061SMaciej Rutecki 			.matches = {
2602d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2603d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
2604d2f9c061SMaciej Rutecki 			},
2605d2f9c061SMaciej Rutecki 			/* PCI slot number of the controller */
2606d2f9c061SMaciej Rutecki 			.driver_data = (void *)0x1FUL,
2607d2f9c061SMaciej Rutecki 		},
26081fd68434SRafael J. Wysocki 
26091fd68434SRafael J. Wysocki 		{ }	/* terminate list */
26101fd68434SRafael J. Wysocki 	};
26111fd68434SRafael J. Wysocki 	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
26121fd68434SRafael J. Wysocki 
26131fd68434SRafael J. Wysocki 	if (dmi) {
26141fd68434SRafael J. Wysocki 		unsigned long slot = (unsigned long)dmi->driver_data;
26151fd68434SRafael J. Wysocki 		/* apply the quirk only to on-board controllers */
26161fd68434SRafael J. Wysocki 		return slot == PCI_SLOT(pdev->devfn);
26171fd68434SRafael J. Wysocki 	}
26181fd68434SRafael J. Wysocki 
26191fd68434SRafael J. Wysocki 	return false;
26201fd68434SRafael J. Wysocki }
26211fd68434SRafael J. Wysocki 
2622*9b10ae86STejun Heo static bool ahci_broken_suspend(struct pci_dev *pdev)
2623*9b10ae86STejun Heo {
2624*9b10ae86STejun Heo 	static const struct dmi_system_id sysids[] = {
2625*9b10ae86STejun Heo 		/*
2626*9b10ae86STejun Heo 		 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
2627*9b10ae86STejun Heo 		 * to the harddisk doesn't become online after
2628*9b10ae86STejun Heo 		 * resuming from STR.  Warn and fail suspend.
2629*9b10ae86STejun Heo 		 */
2630*9b10ae86STejun Heo 		{
2631*9b10ae86STejun Heo 			.ident = "dv4",
2632*9b10ae86STejun Heo 			.matches = {
2633*9b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2634*9b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
2635*9b10ae86STejun Heo 					  "HP Pavilion dv4 Notebook PC"),
2636*9b10ae86STejun Heo 			},
2637*9b10ae86STejun Heo 			.driver_data = "F.30", /* cutoff BIOS version */
2638*9b10ae86STejun Heo 		},
2639*9b10ae86STejun Heo 		{
2640*9b10ae86STejun Heo 			.ident = "dv5",
2641*9b10ae86STejun Heo 			.matches = {
2642*9b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2643*9b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
2644*9b10ae86STejun Heo 					  "HP Pavilion dv5 Notebook PC"),
2645*9b10ae86STejun Heo 			},
2646*9b10ae86STejun Heo 			.driver_data = "F.16", /* cutoff BIOS version */
2647*9b10ae86STejun Heo 		},
2648*9b10ae86STejun Heo 		{
2649*9b10ae86STejun Heo 			.ident = "dv6",
2650*9b10ae86STejun Heo 			.matches = {
2651*9b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2652*9b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
2653*9b10ae86STejun Heo 					  "HP Pavilion dv6 Notebook PC"),
2654*9b10ae86STejun Heo 			},
2655*9b10ae86STejun Heo 			.driver_data = "F.21",	/* cutoff BIOS version */
2656*9b10ae86STejun Heo 		},
2657*9b10ae86STejun Heo 		{
2658*9b10ae86STejun Heo 			.ident = "HDX18",
2659*9b10ae86STejun Heo 			.matches = {
2660*9b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2661*9b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
2662*9b10ae86STejun Heo 					  "HP HDX18 Notebook PC"),
2663*9b10ae86STejun Heo 			},
2664*9b10ae86STejun Heo 			.driver_data = "F.23",	/* cutoff BIOS version */
2665*9b10ae86STejun Heo 		},
2666*9b10ae86STejun Heo 		{ }	/* terminate list */
2667*9b10ae86STejun Heo 	};
2668*9b10ae86STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
2669*9b10ae86STejun Heo 	const char *ver;
2670*9b10ae86STejun Heo 
2671*9b10ae86STejun Heo 	if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
2672*9b10ae86STejun Heo 		return false;
2673*9b10ae86STejun Heo 
2674*9b10ae86STejun Heo 	ver = dmi_get_system_info(DMI_BIOS_VERSION);
2675*9b10ae86STejun Heo 
2676*9b10ae86STejun Heo 	return !ver || strcmp(ver, dmi->driver_data) < 0;
2677*9b10ae86STejun Heo }
2678*9b10ae86STejun Heo 
2679c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2680c6fd2807SJeff Garzik {
2681c6fd2807SJeff Garzik 	static int printed_version;
2682e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
2683e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
26844447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
268524dc5f33STejun Heo 	struct device *dev = &pdev->dev;
2686c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
26874447d351STejun Heo 	struct ata_host *host;
2688837f5f8fSTejun Heo 	int n_ports, i, rc;
2689c6fd2807SJeff Garzik 
2690c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2691c6fd2807SJeff Garzik 
2692c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
2693c6fd2807SJeff Garzik 
2694c6fd2807SJeff Garzik 	if (!printed_version++)
2695c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
2696c6fd2807SJeff Garzik 
26975b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
26985b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
26995b66c829SAlan Cox 	   AHCI stays out of the way */
27005b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
27015b66c829SAlan Cox 		return -ENODEV;
27025b66c829SAlan Cox 
27034447d351STejun Heo 	/* acquire resources */
270424dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
2705c6fd2807SJeff Garzik 	if (rc)
2706c6fd2807SJeff Garzik 		return rc;
2707c6fd2807SJeff Garzik 
2708dea55137STejun Heo 	/* AHCI controllers often implement SFF compatible interface.
2709dea55137STejun Heo 	 * Grab all PCI BARs just in case.
2710dea55137STejun Heo 	 */
2711dea55137STejun Heo 	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
27120d5ff566STejun Heo 	if (rc == -EBUSY)
271324dc5f33STejun Heo 		pcim_pin_device(pdev);
27140d5ff566STejun Heo 	if (rc)
271524dc5f33STejun Heo 		return rc;
2716c6fd2807SJeff Garzik 
2717c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
2718c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
2719c4f7792cSTejun Heo 		u8 map;
2720c4f7792cSTejun Heo 
2721c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
2722c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
2723c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
2724c4f7792cSTejun Heo 		 */
2725c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
2726c4f7792cSTejun Heo 		if (map & 0x3) {
2727c4f7792cSTejun Heo 			dev_printk(KERN_INFO, &pdev->dev, "controller is in "
2728c4f7792cSTejun Heo 				   "combined mode, can't enable AHCI mode\n");
2729c4f7792cSTejun Heo 			return -ENODEV;
2730c4f7792cSTejun Heo 		}
2731c4f7792cSTejun Heo 	}
2732c4f7792cSTejun Heo 
273324dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
273424dc5f33STejun Heo 	if (!hpriv)
273524dc5f33STejun Heo 		return -ENOMEM;
2736417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
2737417a1a6dSTejun Heo 
2738e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
2739e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
2740e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
2741e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
2742e297d99eSTejun Heo 
2743e427fe04SShane Huang 	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
2744e427fe04SShane Huang 	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
2745e427fe04SShane Huang 		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
2746e427fe04SShane Huang 
2747a5bfc471STejun Heo 	if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
2748a5bfc471STejun Heo 		pci_enable_msi(pdev);
2749c6fd2807SJeff Garzik 
27504447d351STejun Heo 	/* save initial config */
2751417a1a6dSTejun Heo 	ahci_save_initial_config(pdev, hpriv);
2752c6fd2807SJeff Garzik 
27534447d351STejun Heo 	/* prepare host */
2754274c1fdeSTejun Heo 	if (hpriv->cap & HOST_CAP_NCQ)
27554447d351STejun Heo 		pi.flags |= ATA_FLAG_NCQ;
27564447d351STejun Heo 
27577d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
27587d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
27597d50b60bSTejun Heo 
276018f7ba4cSKristen Carlson Accardi 	if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) {
276118f7ba4cSKristen Carlson Accardi 		u8 messages;
276218f7ba4cSKristen Carlson Accardi 		void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
276318f7ba4cSKristen Carlson Accardi 		u32 em_loc = readl(mmio + HOST_EM_LOC);
276418f7ba4cSKristen Carlson Accardi 		u32 em_ctl = readl(mmio + HOST_EM_CTL);
276518f7ba4cSKristen Carlson Accardi 
276687943acfSDavid Milburn 		messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
276718f7ba4cSKristen Carlson Accardi 
276818f7ba4cSKristen Carlson Accardi 		/* we only support LED message type right now */
276918f7ba4cSKristen Carlson Accardi 		if ((messages & 0x01) && (ahci_em_messages == 1)) {
277018f7ba4cSKristen Carlson Accardi 			/* store em_loc */
277118f7ba4cSKristen Carlson Accardi 			hpriv->em_loc = ((em_loc >> 16) * 4);
277218f7ba4cSKristen Carlson Accardi 			pi.flags |= ATA_FLAG_EM;
277318f7ba4cSKristen Carlson Accardi 			if (!(em_ctl & EM_CTL_ALHD))
277418f7ba4cSKristen Carlson Accardi 				pi.flags |= ATA_FLAG_SW_ACTIVITY;
277518f7ba4cSKristen Carlson Accardi 		}
277618f7ba4cSKristen Carlson Accardi 	}
277718f7ba4cSKristen Carlson Accardi 
27781fd68434SRafael J. Wysocki 	if (ahci_broken_system_poweroff(pdev)) {
27791fd68434SRafael J. Wysocki 		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
27801fd68434SRafael J. Wysocki 		dev_info(&pdev->dev,
27811fd68434SRafael J. Wysocki 			"quirky BIOS, skipping spindown on poweroff\n");
27821fd68434SRafael J. Wysocki 	}
27831fd68434SRafael J. Wysocki 
2784*9b10ae86STejun Heo 	if (ahci_broken_suspend(pdev)) {
2785*9b10ae86STejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
2786*9b10ae86STejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
2787*9b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
2788*9b10ae86STejun Heo 	}
2789*9b10ae86STejun Heo 
2790837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
2791837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
2792837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
2793837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
2794837f5f8fSTejun Heo 	 */
2795837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
2796837f5f8fSTejun Heo 
2797837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
27984447d351STejun Heo 	if (!host)
27994447d351STejun Heo 		return -ENOMEM;
28004447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
28014447d351STejun Heo 	host->private_data = hpriv;
28024447d351STejun Heo 
2803f3d7f23fSArjan van de Ven 	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
2804886ad09fSArjan van de Ven 		host->flags |= ATA_HOST_PARALLEL_SCAN;
2805f3d7f23fSArjan van de Ven 	else
2806f3d7f23fSArjan van de Ven 		printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
2807886ad09fSArjan van de Ven 
280818f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
280918f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
281018f7ba4cSKristen Carlson Accardi 
28114447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
28124447d351STejun Heo 		struct ata_port *ap = host->ports[i];
28134447d351STejun Heo 
2814cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
2815cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
2816cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
2817cbcdd875STejun Heo 
281831556594SKristen Carlson Accardi 		/* set initial link pm policy */
281931556594SKristen Carlson Accardi 		ap->pm_policy = NOT_AVAILABLE;
282031556594SKristen Carlson Accardi 
282118f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
282218f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
282318f7ba4cSKristen Carlson Accardi 			ap->em_message_type = ahci_em_messages;
282418f7ba4cSKristen Carlson Accardi 
282518f7ba4cSKristen Carlson Accardi 
2826dab632e8SJeff Garzik 		/* disabled/not-implemented port */
2827350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
2828dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
28294447d351STejun Heo 	}
2830c6fd2807SJeff Garzik 
2831edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
2832edc93052STejun Heo 	ahci_p5wdh_workaround(host);
2833edc93052STejun Heo 
2834c6fd2807SJeff Garzik 	/* initialize adapter */
28354447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
2836c6fd2807SJeff Garzik 	if (rc)
283724dc5f33STejun Heo 		return rc;
2838c6fd2807SJeff Garzik 
28394447d351STejun Heo 	rc = ahci_reset_controller(host);
28404447d351STejun Heo 	if (rc)
28414447d351STejun Heo 		return rc;
2842c6fd2807SJeff Garzik 
28434447d351STejun Heo 	ahci_init_controller(host);
28444447d351STejun Heo 	ahci_print_info(host);
2845c6fd2807SJeff Garzik 
28464447d351STejun Heo 	pci_set_master(pdev);
28474447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
28484447d351STejun Heo 				 &ahci_sht);
2849c6fd2807SJeff Garzik }
2850c6fd2807SJeff Garzik 
2851c6fd2807SJeff Garzik static int __init ahci_init(void)
2852c6fd2807SJeff Garzik {
2853c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
2854c6fd2807SJeff Garzik }
2855c6fd2807SJeff Garzik 
2856c6fd2807SJeff Garzik static void __exit ahci_exit(void)
2857c6fd2807SJeff Garzik {
2858c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
2859c6fd2807SJeff Garzik }
2860c6fd2807SJeff Garzik 
2861c6fd2807SJeff Garzik 
2862c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
2863c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
2864c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
2865c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
2866c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
2867c6fd2807SJeff Garzik 
2868c6fd2807SJeff Garzik module_init(ahci_init);
2869c6fd2807SJeff Garzik module_exit(ahci_exit);
2870