xref: /openbmc/linux/drivers/ata/ahci.c (revision 8e5132175bebaa26f8ea5036a1e942686c11cab4)
1c6fd2807SJeff Garzik /*
2c6fd2807SJeff Garzik  *  ahci.c - AHCI SATA support
3c6fd2807SJeff Garzik  *
4c6fd2807SJeff Garzik  *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
5c6fd2807SJeff Garzik  *    		    Please ALWAYS copy linux-ide@vger.kernel.org
6c6fd2807SJeff Garzik  *		    on emails.
7c6fd2807SJeff Garzik  *
8c6fd2807SJeff Garzik  *  Copyright 2004-2005 Red Hat, Inc.
9c6fd2807SJeff Garzik  *
10c6fd2807SJeff Garzik  *
11c6fd2807SJeff Garzik  *  This program is free software; you can redistribute it and/or modify
12c6fd2807SJeff Garzik  *  it under the terms of the GNU General Public License as published by
13c6fd2807SJeff Garzik  *  the Free Software Foundation; either version 2, or (at your option)
14c6fd2807SJeff Garzik  *  any later version.
15c6fd2807SJeff Garzik  *
16c6fd2807SJeff Garzik  *  This program is distributed in the hope that it will be useful,
17c6fd2807SJeff Garzik  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18c6fd2807SJeff Garzik  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19c6fd2807SJeff Garzik  *  GNU General Public License for more details.
20c6fd2807SJeff Garzik  *
21c6fd2807SJeff Garzik  *  You should have received a copy of the GNU General Public License
22c6fd2807SJeff Garzik  *  along with this program; see the file COPYING.  If not, write to
23c6fd2807SJeff Garzik  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24c6fd2807SJeff Garzik  *
25c6fd2807SJeff Garzik  *
26c6fd2807SJeff Garzik  * libata documentation is available via 'make {ps|pdf}docs',
27c6fd2807SJeff Garzik  * as Documentation/DocBook/libata.*
28c6fd2807SJeff Garzik  *
29c6fd2807SJeff Garzik  * AHCI hardware documentation:
30c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
31c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
32c6fd2807SJeff Garzik  *
33c6fd2807SJeff Garzik  */
34c6fd2807SJeff Garzik 
35c6fd2807SJeff Garzik #include <linux/kernel.h>
36c6fd2807SJeff Garzik #include <linux/module.h>
37c6fd2807SJeff Garzik #include <linux/pci.h>
38c6fd2807SJeff Garzik #include <linux/init.h>
39c6fd2807SJeff Garzik #include <linux/blkdev.h>
40c6fd2807SJeff Garzik #include <linux/delay.h>
41c6fd2807SJeff Garzik #include <linux/interrupt.h>
42c6fd2807SJeff Garzik #include <linux/dma-mapping.h>
43c6fd2807SJeff Garzik #include <linux/device.h>
44edc93052STejun Heo #include <linux/dmi.h>
45c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
46c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
47c6fd2807SJeff Garzik #include <linux/libata.h>
48c6fd2807SJeff Garzik 
49c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
507d50b60bSTejun Heo #define DRV_VERSION	"3.0"
51c6fd2807SJeff Garzik 
5287943acfSDavid Milburn /* Enclosure Management Control */
5387943acfSDavid Milburn #define EM_CTRL_MSG_TYPE              0x000f0000
5487943acfSDavid Milburn 
5587943acfSDavid Milburn /* Enclosure Management LED Message Type */
5687943acfSDavid Milburn #define EM_MSG_LED_HBA_PORT           0x0000000f
5787943acfSDavid Milburn #define EM_MSG_LED_PMP_SLOT           0x0000ff00
5887943acfSDavid Milburn #define EM_MSG_LED_VALUE              0xffff0000
5987943acfSDavid Milburn #define EM_MSG_LED_VALUE_ACTIVITY     0x00070000
6087943acfSDavid Milburn #define EM_MSG_LED_VALUE_OFF          0xfff80000
6187943acfSDavid Milburn #define EM_MSG_LED_VALUE_ON           0x00010000
6287943acfSDavid Milburn 
63a22e6444STejun Heo static int ahci_skip_host_reset;
64f3d7f23fSArjan van de Ven static int ahci_ignore_sss;
65f3d7f23fSArjan van de Ven 
66a22e6444STejun Heo module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
67a22e6444STejun Heo MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
68a22e6444STejun Heo 
69f3d7f23fSArjan van de Ven module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
70f3d7f23fSArjan van de Ven MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
71f3d7f23fSArjan van de Ven 
7231556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
7331556594SKristen Carlson Accardi 		enum link_pm policy);
7431556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap);
7518f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
7618f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
7718f7ba4cSKristen Carlson Accardi 			      size_t size);
7818f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
7918f7ba4cSKristen Carlson Accardi 					ssize_t size);
80c6fd2807SJeff Garzik 
81c6fd2807SJeff Garzik enum {
82c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
83648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
84c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
85c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
86c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
87c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
88c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
89c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
90c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
91c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
92c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
93c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
94c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
95c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
96c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
97c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
98c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
99c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
100c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
101c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
102c6fd2807SJeff Garzik 
103c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
1040291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
105c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
106c6fd2807SJeff Garzik 
107c6fd2807SJeff Garzik 	board_ahci		= 0,
1087a234affSTejun Heo 	board_ahci_vt8251	= 1,
1097a234affSTejun Heo 	board_ahci_ign_iferr	= 2,
1107a234affSTejun Heo 	board_ahci_sb600	= 3,
1117a234affSTejun Heo 	board_ahci_mv		= 4,
112e427fe04SShane Huang 	board_ahci_sb700	= 5, /* for SB700 and SB800 */
113e297d99eSTejun Heo 	board_ahci_mcp65	= 6,
1149a3b103cSTejun Heo 	board_ahci_nopmp	= 7,
115aa431dd3STejun Heo 	board_ahci_yesncq	= 8,
116c6fd2807SJeff Garzik 
117c6fd2807SJeff Garzik 	/* global controller registers */
118c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
119c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
120c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
121c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
122c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
12318f7ba4cSKristen Carlson Accardi 	HOST_EM_LOC		= 0x1c, /* Enclosure Management location */
12418f7ba4cSKristen Carlson Accardi 	HOST_EM_CTL		= 0x20, /* Enclosure Management Control */
1254c521c8eSRobert Hancock 	HOST_CAP2		= 0x24, /* host capabilities, extended */
126c6fd2807SJeff Garzik 
127c6fd2807SJeff Garzik 	/* HOST_CTL bits */
128c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
129c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
130c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
131c6fd2807SJeff Garzik 
132c6fd2807SJeff Garzik 	/* HOST_CAP bits */
1334c521c8eSRobert Hancock 	HOST_CAP_SXS		= (1 << 5),  /* Supports External SATA */
13418f7ba4cSKristen Carlson Accardi 	HOST_CAP_EMS		= (1 << 6),  /* Enclosure Management support */
1354c521c8eSRobert Hancock 	HOST_CAP_CCC		= (1 << 7),  /* Command Completion Coalescing */
1364c521c8eSRobert Hancock 	HOST_CAP_PART		= (1 << 13), /* Partial state capable */
1374c521c8eSRobert Hancock 	HOST_CAP_SSC		= (1 << 14), /* Slumber state capable */
1384c521c8eSRobert Hancock 	HOST_CAP_PIO_MULTI	= (1 << 15), /* PIO multiple DRQ support */
1394c521c8eSRobert Hancock 	HOST_CAP_FBS		= (1 << 16), /* FIS-based switching support */
1407d50b60bSTejun Heo 	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
1414c521c8eSRobert Hancock 	HOST_CAP_ONLY		= (1 << 18), /* Supports AHCI mode only */
142c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
1434c521c8eSRobert Hancock 	HOST_CAP_LED		= (1 << 25), /* Supports activity LED */
14431556594SKristen Carlson Accardi 	HOST_CAP_ALPM		= (1 << 26), /* Aggressive Link PM support */
145c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
1464c521c8eSRobert Hancock 	HOST_CAP_MPS		= (1 << 28), /* Mechanical presence switch */
147203ef6c4STejun Heo 	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
148c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
149c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
150c6fd2807SJeff Garzik 
1514c521c8eSRobert Hancock 	/* HOST_CAP2 bits */
1524c521c8eSRobert Hancock 	HOST_CAP2_BOH		= (1 << 0),  /* BIOS/OS handoff supported */
1534c521c8eSRobert Hancock 	HOST_CAP2_NVMHCI	= (1 << 1),  /* NVMHCI supported */
1544c521c8eSRobert Hancock 	HOST_CAP2_APST		= (1 << 2),  /* Automatic partial to slumber */
1554c521c8eSRobert Hancock 
156c6fd2807SJeff Garzik 	/* registers for each SATA port */
157c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
158c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
159c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
160c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
161c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
162c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
163c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
164c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
165c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
166c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
167c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
168c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
169c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
170c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
171203ef6c4STejun Heo 	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
172c6fd2807SJeff Garzik 
173c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
174c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
175c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
176c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
177c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
178c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
179c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
180c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
181c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
182c6fd2807SJeff Garzik 
183c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
184c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
185c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
186c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
187c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
188c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
189c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
190c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
191c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
192c6fd2807SJeff Garzik 
193c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
194c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
195c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
196c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
1977d50b60bSTejun Heo 				  PORT_IRQ_UNK_FIS |
1987d50b60bSTejun Heo 				  PORT_IRQ_BAD_PMP,
199c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
200c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
201c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
202c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
203c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
204c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
205c6fd2807SJeff Garzik 
206c6fd2807SJeff Garzik 	/* PORT_CMD bits */
20731556594SKristen Carlson Accardi 	PORT_CMD_ASP		= (1 << 27), /* Aggressive Slumber/Partial */
20831556594SKristen Carlson Accardi 	PORT_CMD_ALPE		= (1 << 26), /* Aggressive Link PM enable */
209c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
2107d50b60bSTejun Heo 	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
211c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
212c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
213c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
214c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
215c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
216c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
217c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
218c6fd2807SJeff Garzik 
219c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
220c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
221c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
222c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
223c6fd2807SJeff Garzik 
224417a1a6dSTejun Heo 	/* hpriv->flags bits */
225417a1a6dSTejun Heo 	AHCI_HFLAG_NO_NCQ		= (1 << 0),
226417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
227417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
228417a1a6dSTejun Heo 	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
229417a1a6dSTejun Heo 	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
230417a1a6dSTejun Heo 	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
2316949b914STejun Heo 	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
23231556594SKristen Carlson Accardi 	AHCI_HFLAG_NO_HOTPLUG		= (1 << 7), /* ignore PxSERR.DIAG.N */
233a878539eSJeff Garzik 	AHCI_HFLAG_SECT255		= (1 << 8), /* max 255 sectors */
234e297d99eSTejun Heo 	AHCI_HFLAG_YES_NCQ		= (1 << 9), /* force NCQ cap on */
2359b10ae86STejun Heo 	AHCI_HFLAG_NO_SUSPEND		= (1 << 10), /* don't suspend */
2365594639aSTejun Heo 	AHCI_HFLAG_SRST_TOUT_IS_OFFLINE	= (1 << 11), /* treat SRST timeout as
2375594639aSTejun Heo 							link offline */
238417a1a6dSTejun Heo 
239c6fd2807SJeff Garzik 	/* ap->flags bits */
2401188c0d8STejun Heo 
2411188c0d8STejun Heo 	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
2421188c0d8STejun Heo 					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
24331556594SKristen Carlson Accardi 					  ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
24431556594SKristen Carlson Accardi 					  ATA_FLAG_IPM,
245c4f7792cSTejun Heo 
246c4f7792cSTejun Heo 	ICH_MAP				= 0x90, /* ICH MAP register */
24718f7ba4cSKristen Carlson Accardi 
248d50ce07dSTejun Heo 	/* em constants */
249d50ce07dSTejun Heo 	EM_MAX_SLOTS			= 8,
250d50ce07dSTejun Heo 	EM_MAX_RETRY			= 5,
251d50ce07dSTejun Heo 
25218f7ba4cSKristen Carlson Accardi 	/* em_ctl bits */
25318f7ba4cSKristen Carlson Accardi 	EM_CTL_RST			= (1 << 9), /* Reset */
25418f7ba4cSKristen Carlson Accardi 	EM_CTL_TM			= (1 << 8), /* Transmit Message */
25518f7ba4cSKristen Carlson Accardi 	EM_CTL_ALHD			= (1 << 26), /* Activity LED */
256c6fd2807SJeff Garzik };
257c6fd2807SJeff Garzik 
258c6fd2807SJeff Garzik struct ahci_cmd_hdr {
2594ca4e439SAl Viro 	__le32			opts;
2604ca4e439SAl Viro 	__le32			status;
2614ca4e439SAl Viro 	__le32			tbl_addr;
2624ca4e439SAl Viro 	__le32			tbl_addr_hi;
2634ca4e439SAl Viro 	__le32			reserved[4];
264c6fd2807SJeff Garzik };
265c6fd2807SJeff Garzik 
266c6fd2807SJeff Garzik struct ahci_sg {
2674ca4e439SAl Viro 	__le32			addr;
2684ca4e439SAl Viro 	__le32			addr_hi;
2694ca4e439SAl Viro 	__le32			reserved;
2704ca4e439SAl Viro 	__le32			flags_size;
271c6fd2807SJeff Garzik };
272c6fd2807SJeff Garzik 
27318f7ba4cSKristen Carlson Accardi struct ahci_em_priv {
27418f7ba4cSKristen Carlson Accardi 	enum sw_activity blink_policy;
27518f7ba4cSKristen Carlson Accardi 	struct timer_list timer;
27618f7ba4cSKristen Carlson Accardi 	unsigned long saved_activity;
27718f7ba4cSKristen Carlson Accardi 	unsigned long activity;
27818f7ba4cSKristen Carlson Accardi 	unsigned long led_state;
27918f7ba4cSKristen Carlson Accardi };
28018f7ba4cSKristen Carlson Accardi 
281c6fd2807SJeff Garzik struct ahci_host_priv {
282417a1a6dSTejun Heo 	unsigned int		flags;		/* AHCI_HFLAG_* */
283d447df14STejun Heo 	u32			cap;		/* cap to use */
2844c521c8eSRobert Hancock 	u32			cap2;		/* cap2 to use */
285d447df14STejun Heo 	u32			port_map;	/* port map to use */
286d447df14STejun Heo 	u32			saved_cap;	/* saved initial cap */
2874c521c8eSRobert Hancock 	u32			saved_cap2;	/* saved initial cap2 */
288d447df14STejun Heo 	u32			saved_port_map;	/* saved initial port_map */
28918f7ba4cSKristen Carlson Accardi 	u32 			em_loc; /* enclosure management location */
290c6fd2807SJeff Garzik };
291c6fd2807SJeff Garzik 
292c6fd2807SJeff Garzik struct ahci_port_priv {
2937d50b60bSTejun Heo 	struct ata_link		*active_link;
294c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
295c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
296c6fd2807SJeff Garzik 	void			*cmd_tbl;
297c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
298c6fd2807SJeff Garzik 	void			*rx_fis;
299c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
3000291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
3010291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
3020291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
303afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
304a7384925SKristen Carlson Accardi 	u32 			intr_mask;	/* interrupts to enable */
305d50ce07dSTejun Heo 	/* enclosure management info per PM slot */
306d50ce07dSTejun Heo 	struct ahci_em_priv	em_priv[EM_MAX_SLOTS];
307c6fd2807SJeff Garzik };
308c6fd2807SJeff Garzik 
30982ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
31082ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
311c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
312c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
3134c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
314c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
315c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
316c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
317c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
318c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
3197d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap);
3207d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap);
321a1efdabaSTejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class,
322a1efdabaSTejun Heo 			  unsigned long deadline);
323bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
324bd17243aSShane Huang 			  unsigned long deadline);
325a1efdabaSTejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
326a1efdabaSTejun Heo 			  unsigned long deadline);
327a1efdabaSTejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
328a1efdabaSTejun Heo 				 unsigned long deadline);
329a1efdabaSTejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
330a1efdabaSTejun Heo 				unsigned long deadline);
331a1efdabaSTejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class);
332c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
333c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
334df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
335a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev);
336dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
337dab632e8SJeff Garzik 			       u32 opts);
338438ac6d5STejun Heo #ifdef CONFIG_PM
339c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
340c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
341c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
342438ac6d5STejun Heo #endif
34318f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf);
34418f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev,
34518f7ba4cSKristen Carlson Accardi 				   enum sw_activity val);
34618f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link);
347c6fd2807SJeff Garzik 
34877cdec1aSMatthew Garrett static ssize_t ahci_show_host_caps(struct device *dev,
34977cdec1aSMatthew Garrett 				   struct device_attribute *attr, char *buf);
3504c521c8eSRobert Hancock static ssize_t ahci_show_host_cap2(struct device *dev,
3514c521c8eSRobert Hancock 				   struct device_attribute *attr, char *buf);
35277cdec1aSMatthew Garrett static ssize_t ahci_show_host_version(struct device *dev,
35377cdec1aSMatthew Garrett 				      struct device_attribute *attr, char *buf);
35477cdec1aSMatthew Garrett static ssize_t ahci_show_port_cmd(struct device *dev,
35577cdec1aSMatthew Garrett 				  struct device_attribute *attr, char *buf);
35677cdec1aSMatthew Garrett 
35777cdec1aSMatthew Garrett DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
3584c521c8eSRobert Hancock DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
35977cdec1aSMatthew Garrett DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
36077cdec1aSMatthew Garrett DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
36177cdec1aSMatthew Garrett 
362ee959b00STony Jones static struct device_attribute *ahci_shost_attrs[] = {
363ee959b00STony Jones 	&dev_attr_link_power_management_policy,
36418f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message_type,
36518f7ba4cSKristen Carlson Accardi 	&dev_attr_em_message,
36677cdec1aSMatthew Garrett 	&dev_attr_ahci_host_caps,
3674c521c8eSRobert Hancock 	&dev_attr_ahci_host_cap2,
36877cdec1aSMatthew Garrett 	&dev_attr_ahci_host_version,
36977cdec1aSMatthew Garrett 	&dev_attr_ahci_port_cmd,
37018f7ba4cSKristen Carlson Accardi 	NULL
37118f7ba4cSKristen Carlson Accardi };
37218f7ba4cSKristen Carlson Accardi 
37318f7ba4cSKristen Carlson Accardi static struct device_attribute *ahci_sdev_attrs[] = {
37418f7ba4cSKristen Carlson Accardi 	&dev_attr_sw_activity,
37545fabbb7SElias Oltmanns 	&dev_attr_unload_heads,
37631556594SKristen Carlson Accardi 	NULL
37731556594SKristen Carlson Accardi };
37831556594SKristen Carlson Accardi 
379c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
38068d1d07bSTejun Heo 	ATA_NCQ_SHT(DRV_NAME),
381c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
382c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
383c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
38431556594SKristen Carlson Accardi 	.shost_attrs		= ahci_shost_attrs,
38518f7ba4cSKristen Carlson Accardi 	.sdev_attrs		= ahci_sdev_attrs,
386c6fd2807SJeff Garzik };
387c6fd2807SJeff Garzik 
388029cfd6bSTejun Heo static struct ata_port_operations ahci_ops = {
389029cfd6bSTejun Heo 	.inherits		= &sata_pmp_port_ops,
390029cfd6bSTejun Heo 
3917d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
392c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
393c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
3944c9bf4e7STejun Heo 	.qc_fill_rtf		= ahci_qc_fill_rtf,
395c6fd2807SJeff Garzik 
396c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
397c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
398a1efdabaSTejun Heo 	.softreset		= ahci_softreset,
399a1efdabaSTejun Heo 	.hardreset		= ahci_hardreset,
400a1efdabaSTejun Heo 	.postreset		= ahci_postreset,
401071f44b1STejun Heo 	.pmp_softreset		= ahci_softreset,
402c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
403c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
404029cfd6bSTejun Heo 	.dev_config		= ahci_dev_config,
405c6fd2807SJeff Garzik 
406029cfd6bSTejun Heo 	.scr_read		= ahci_scr_read,
407029cfd6bSTejun Heo 	.scr_write		= ahci_scr_write,
4087d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
4097d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
4107d50b60bSTejun Heo 
411029cfd6bSTejun Heo 	.enable_pm		= ahci_enable_alpm,
412029cfd6bSTejun Heo 	.disable_pm		= ahci_disable_alpm,
41318f7ba4cSKristen Carlson Accardi 	.em_show		= ahci_led_show,
41418f7ba4cSKristen Carlson Accardi 	.em_store		= ahci_led_store,
41518f7ba4cSKristen Carlson Accardi 	.sw_activity_show	= ahci_activity_show,
41618f7ba4cSKristen Carlson Accardi 	.sw_activity_store	= ahci_activity_store,
417438ac6d5STejun Heo #ifdef CONFIG_PM
418c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
419c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
420438ac6d5STejun Heo #endif
421c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
422c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
423c6fd2807SJeff Garzik };
424c6fd2807SJeff Garzik 
425029cfd6bSTejun Heo static struct ata_port_operations ahci_vt8251_ops = {
426029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
427a1efdabaSTejun Heo 	.hardreset		= ahci_vt8251_hardreset,
428ad616ffbSTejun Heo };
429ad616ffbSTejun Heo 
430029cfd6bSTejun Heo static struct ata_port_operations ahci_p5wdh_ops = {
431029cfd6bSTejun Heo 	.inherits		= &ahci_ops,
432a1efdabaSTejun Heo 	.hardreset		= ahci_p5wdh_hardreset,
433edc93052STejun Heo };
434edc93052STejun Heo 
435bd17243aSShane Huang static struct ata_port_operations ahci_sb600_ops = {
436bd17243aSShane Huang 	.inherits		= &ahci_ops,
437bd17243aSShane Huang 	.softreset		= ahci_sb600_softreset,
438bd17243aSShane Huang 	.pmp_softreset		= ahci_sb600_softreset,
439bd17243aSShane Huang };
440bd17243aSShane Huang 
441417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
442417a1a6dSTejun Heo 
443c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
4444da646b7SJeff Garzik 	[board_ahci] =
445c6fd2807SJeff Garzik 	{
4461188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
44714bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
448469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
449c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
450c6fd2807SJeff Garzik 	},
4514da646b7SJeff Garzik 	[board_ahci_vt8251] =
452c6fd2807SJeff Garzik 	{
4536949b914STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
454417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
45514bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
456469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
457ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
458c6fd2807SJeff Garzik 	},
4594da646b7SJeff Garzik 	[board_ahci_ign_iferr] =
46041669553STejun Heo 	{
461417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
462417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
46314bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
464469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
46541669553STejun Heo 		.port_ops	= &ahci_ops,
46641669553STejun Heo 	},
4674da646b7SJeff Garzik 	[board_ahci_sb600] =
46855a61604SConke Hu 	{
469417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
4702fcad9d2STejun Heo 				 AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
4712fcad9d2STejun Heo 				 AHCI_HFLAG_32BIT_ONLY),
472417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
47314bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
474469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
475bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
47655a61604SConke Hu 	},
4774da646b7SJeff Garzik 	[board_ahci_mv] =
478cd70c266SJeff Garzik 	{
479417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
48017248461STejun Heo 				 AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
481cd70c266SJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
482417a1a6dSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
48314bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
484cd70c266SJeff Garzik 		.udma_mask	= ATA_UDMA6,
485cd70c266SJeff Garzik 		.port_ops	= &ahci_ops,
486cd70c266SJeff Garzik 	},
4874da646b7SJeff Garzik 	[board_ahci_sb700] =	/* for SB700 and SB800 */
488e39fc8c9SShane Huang 	{
489bd17243aSShane Huang 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL),
490e39fc8c9SShane Huang 		.flags		= AHCI_FLAG_COMMON,
49114bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
492e39fc8c9SShane Huang 		.udma_mask	= ATA_UDMA6,
493bd17243aSShane Huang 		.port_ops	= &ahci_sb600_ops,
494e39fc8c9SShane Huang 	},
4954da646b7SJeff Garzik 	[board_ahci_mcp65] =
496e297d99eSTejun Heo 	{
497e297d99eSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
498e297d99eSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
49914bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
500e297d99eSTejun Heo 		.udma_mask	= ATA_UDMA6,
501e297d99eSTejun Heo 		.port_ops	= &ahci_ops,
502e297d99eSTejun Heo 	},
5034da646b7SJeff Garzik 	[board_ahci_nopmp] =
5049a3b103cSTejun Heo 	{
5059a3b103cSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP),
5069a3b103cSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
50714bdef98SErik Inge Bolsø 		.pio_mask	= ATA_PIO4,
5089a3b103cSTejun Heo 		.udma_mask	= ATA_UDMA6,
5099a3b103cSTejun Heo 		.port_ops	= &ahci_ops,
5109a3b103cSTejun Heo 	},
511aa431dd3STejun Heo 	/* board_ahci_yesncq */
512aa431dd3STejun Heo 	{
513aa431dd3STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_YES_NCQ),
514aa431dd3STejun Heo 		.flags		= AHCI_FLAG_COMMON,
515aa431dd3STejun Heo 		.pio_mask	= ATA_PIO4,
516aa431dd3STejun Heo 		.udma_mask	= ATA_UDMA6,
517aa431dd3STejun Heo 		.port_ops	= &ahci_ops,
518aa431dd3STejun Heo 	},
519c6fd2807SJeff Garzik };
520c6fd2807SJeff Garzik 
521c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
522c6fd2807SJeff Garzik 	/* Intel */
52354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
52454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
52554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
52654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
52754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
52882490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
52954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
53054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
53154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
53254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
5337a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
5347a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
5357a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
5367a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
5377a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
5387a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
5397a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
5407a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
5417a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
5427a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
5437a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
5447a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
5457a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
5467a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
5477a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
5487a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
5497a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
550d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
551d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
55216ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
553b2dde6afSMark Goodwin 	{ PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
55416ad1ad9SJason Gaston 	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
555c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
556c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
557adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
5588e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
559c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
560adcb5308SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
5618e48b6b3SSeth Heasley 	{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
562c1f57d9bSDavid Milburn 	{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
563c6fd2807SJeff Garzik 
564e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
565e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
566e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
567c6fd2807SJeff Garzik 
568c6fd2807SJeff Garzik 	/* ATI */
569c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
570e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
571e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
572e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
573e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
574e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
575e39fc8c9SShane Huang 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
576c6fd2807SJeff Garzik 
577e2dd90b1SShane Huang 	/* AMD */
578e2dd90b1SShane Huang 	{ PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD SB900 */
579e2dd90b1SShane Huang 	/* AMD is using RAID class only for ahci controllers */
580e2dd90b1SShane Huang 	{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
581e2dd90b1SShane Huang 	  PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
582e2dd90b1SShane Huang 
583c6fd2807SJeff Garzik 	/* VIA */
58454bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
585bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
586c6fd2807SJeff Garzik 
587c6fd2807SJeff Garzik 	/* NVIDIA */
588e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 },	/* MCP65 */
589e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 },	/* MCP65 */
590e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 },	/* MCP65 */
591e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 },	/* MCP65 */
592e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 },	/* MCP65 */
593e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 },	/* MCP65 */
594e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 },	/* MCP65 */
595e297d99eSTejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 },	/* MCP65 */
596aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq },	/* MCP67 */
597aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq },	/* MCP67 */
598aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq },	/* MCP67 */
599aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq },	/* MCP67 */
600aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq },	/* MCP67 */
601aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq },	/* MCP67 */
602aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq },	/* MCP67 */
603aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq },	/* MCP67 */
604aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq },	/* MCP67 */
605aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq },	/* MCP67 */
606aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq },	/* MCP67 */
607aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq },	/* MCP67 */
608aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq },	/* MCP73 */
609aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq },	/* MCP73 */
610aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq },	/* MCP73 */
611aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq },	/* MCP73 */
612aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq },	/* MCP73 */
613aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq },	/* MCP73 */
614aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq },	/* MCP73 */
615aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq },	/* MCP73 */
616aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq },	/* MCP73 */
617aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq },	/* MCP73 */
618aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq },	/* MCP73 */
619aa431dd3STejun Heo 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq },	/* MCP73 */
6200522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },		/* MCP77 */
6210522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },		/* MCP77 */
6220522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },		/* MCP77 */
6230522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },		/* MCP77 */
6240522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },		/* MCP77 */
6250522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },		/* MCP77 */
6260522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },		/* MCP77 */
6270522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },		/* MCP77 */
6280522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },		/* MCP77 */
6290522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
6300522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
6310522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
6326ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci },		/* MCP79 */
6336ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci },		/* MCP79 */
6346ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci },		/* MCP79 */
6356ba86958Speerchen 	{ PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci },		/* MCP79 */
6367100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
6377100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
6387100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
6397100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
6407100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
6417100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
6427100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
6437100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
6447adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci },		/* MCP89 */
6457adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci },		/* MCP89 */
6467adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci },		/* MCP89 */
6477adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci },		/* MCP89 */
6487adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci },		/* MCP89 */
6497adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci },		/* MCP89 */
6507adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci },		/* MCP89 */
6517adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci },		/* MCP89 */
6527adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci },		/* MCP89 */
6537adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci },		/* MCP89 */
6547adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci },		/* MCP89 */
6557adbe46bSpeerchen 	{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci },		/* MCP89 */
656c6fd2807SJeff Garzik 
657c6fd2807SJeff Garzik 	/* SiS */
65820e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1184), board_ahci },		/* SiS 966 */
65920e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
66020e2de4aSTejun Heo 	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */
661c6fd2807SJeff Garzik 
662cd70c266SJeff Garzik 	/* Marvell */
663cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
664c40e7cb8SJose Alberto Reguero 	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
665cd70c266SJeff Garzik 
666c77a036bSMark Nelson 	/* Promise */
667c77a036bSMark Nelson 	{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci },	/* PDC42819 */
668c77a036bSMark Nelson 
669415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
670415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
671c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
672415ae2b5SJeff Garzik 
673c6fd2807SJeff Garzik 	{ }	/* terminate list */
674c6fd2807SJeff Garzik };
675c6fd2807SJeff Garzik 
676c6fd2807SJeff Garzik 
677c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
678c6fd2807SJeff Garzik 	.name			= DRV_NAME,
679c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
680c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
68124dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
682438ac6d5STejun Heo #ifdef CONFIG_PM
683c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
684c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
685438ac6d5STejun Heo #endif
686c6fd2807SJeff Garzik };
687c6fd2807SJeff Garzik 
68818f7ba4cSKristen Carlson Accardi static int ahci_em_messages = 1;
68918f7ba4cSKristen Carlson Accardi module_param(ahci_em_messages, int, 0444);
69018f7ba4cSKristen Carlson Accardi /* add other LED protocol types when they become supported */
69118f7ba4cSKristen Carlson Accardi MODULE_PARM_DESC(ahci_em_messages,
69218f7ba4cSKristen Carlson Accardi 	"Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
693c6fd2807SJeff Garzik 
6945b66c829SAlan Cox #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
6955b66c829SAlan Cox static int marvell_enable;
6965b66c829SAlan Cox #else
6975b66c829SAlan Cox static int marvell_enable = 1;
6985b66c829SAlan Cox #endif
6995b66c829SAlan Cox module_param(marvell_enable, int, 0644);
7005b66c829SAlan Cox MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
7015b66c829SAlan Cox 
7025b66c829SAlan Cox 
70398fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
70498fa4b60STejun Heo {
70598fa4b60STejun Heo 	return (cap & 0x1f) + 1;
70698fa4b60STejun Heo }
70798fa4b60STejun Heo 
708dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host,
709dab632e8SJeff Garzik 					     unsigned int port_no)
710dab632e8SJeff Garzik {
711dab632e8SJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
712dab632e8SJeff Garzik 
713dab632e8SJeff Garzik 	return mmio + 0x100 + (port_no * 0x80);
714dab632e8SJeff Garzik }
715dab632e8SJeff Garzik 
7164447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
717c6fd2807SJeff Garzik {
718dab632e8SJeff Garzik 	return __ahci_port_base(ap->host, ap->port_no);
719c6fd2807SJeff Garzik }
720c6fd2807SJeff Garzik 
721b710a1f4STejun Heo static void ahci_enable_ahci(void __iomem *mmio)
722b710a1f4STejun Heo {
72315fe982eSTejun Heo 	int i;
724b710a1f4STejun Heo 	u32 tmp;
725b710a1f4STejun Heo 
726b710a1f4STejun Heo 	/* turn on AHCI_EN */
727b710a1f4STejun Heo 	tmp = readl(mmio + HOST_CTL);
72815fe982eSTejun Heo 	if (tmp & HOST_AHCI_EN)
72915fe982eSTejun Heo 		return;
73015fe982eSTejun Heo 
73115fe982eSTejun Heo 	/* Some controllers need AHCI_EN to be written multiple times.
73215fe982eSTejun Heo 	 * Try a few times before giving up.
73315fe982eSTejun Heo 	 */
73415fe982eSTejun Heo 	for (i = 0; i < 5; i++) {
735b710a1f4STejun Heo 		tmp |= HOST_AHCI_EN;
736b710a1f4STejun Heo 		writel(tmp, mmio + HOST_CTL);
737b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
73815fe982eSTejun Heo 		if (tmp & HOST_AHCI_EN)
73915fe982eSTejun Heo 			return;
74015fe982eSTejun Heo 		msleep(10);
741b710a1f4STejun Heo 	}
74215fe982eSTejun Heo 
74315fe982eSTejun Heo 	WARN_ON(1);
744b710a1f4STejun Heo }
745b710a1f4STejun Heo 
74677cdec1aSMatthew Garrett static ssize_t ahci_show_host_caps(struct device *dev,
74777cdec1aSMatthew Garrett 				   struct device_attribute *attr, char *buf)
74877cdec1aSMatthew Garrett {
74977cdec1aSMatthew Garrett 	struct Scsi_Host *shost = class_to_shost(dev);
75077cdec1aSMatthew Garrett 	struct ata_port *ap = ata_shost_to_port(shost);
75177cdec1aSMatthew Garrett 	struct ahci_host_priv *hpriv = ap->host->private_data;
75277cdec1aSMatthew Garrett 
75377cdec1aSMatthew Garrett 	return sprintf(buf, "%x\n", hpriv->cap);
75477cdec1aSMatthew Garrett }
75577cdec1aSMatthew Garrett 
7564c521c8eSRobert Hancock static ssize_t ahci_show_host_cap2(struct device *dev,
7574c521c8eSRobert Hancock 				   struct device_attribute *attr, char *buf)
7584c521c8eSRobert Hancock {
7594c521c8eSRobert Hancock 	struct Scsi_Host *shost = class_to_shost(dev);
7604c521c8eSRobert Hancock 	struct ata_port *ap = ata_shost_to_port(shost);
7614c521c8eSRobert Hancock 	struct ahci_host_priv *hpriv = ap->host->private_data;
7624c521c8eSRobert Hancock 
7634c521c8eSRobert Hancock 	return sprintf(buf, "%x\n", hpriv->cap2);
7644c521c8eSRobert Hancock }
7654c521c8eSRobert Hancock 
76677cdec1aSMatthew Garrett static ssize_t ahci_show_host_version(struct device *dev,
76777cdec1aSMatthew Garrett 				   struct device_attribute *attr, char *buf)
76877cdec1aSMatthew Garrett {
76977cdec1aSMatthew Garrett 	struct Scsi_Host *shost = class_to_shost(dev);
77077cdec1aSMatthew Garrett 	struct ata_port *ap = ata_shost_to_port(shost);
77177cdec1aSMatthew Garrett 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
77277cdec1aSMatthew Garrett 
77377cdec1aSMatthew Garrett 	return sprintf(buf, "%x\n", readl(mmio + HOST_VERSION));
77477cdec1aSMatthew Garrett }
77577cdec1aSMatthew Garrett 
77677cdec1aSMatthew Garrett static ssize_t ahci_show_port_cmd(struct device *dev,
77777cdec1aSMatthew Garrett 				  struct device_attribute *attr, char *buf)
77877cdec1aSMatthew Garrett {
77977cdec1aSMatthew Garrett 	struct Scsi_Host *shost = class_to_shost(dev);
78077cdec1aSMatthew Garrett 	struct ata_port *ap = ata_shost_to_port(shost);
78177cdec1aSMatthew Garrett 	void __iomem *port_mmio = ahci_port_base(ap);
78277cdec1aSMatthew Garrett 
78377cdec1aSMatthew Garrett 	return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD));
78477cdec1aSMatthew Garrett }
78577cdec1aSMatthew Garrett 
786d447df14STejun Heo /**
787d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
7884447d351STejun Heo  *	@pdev: target PCI device
7894447d351STejun Heo  *	@hpriv: host private area to store config values
790d447df14STejun Heo  *
791d447df14STejun Heo  *	Some registers containing configuration info might be setup by
792d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
793d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
794d447df14STejun Heo  *	can be restored after controller reset.
795d447df14STejun Heo  *
796d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
797d447df14STejun Heo  *
798d447df14STejun Heo  *	LOCKING:
799d447df14STejun Heo  *	None.
800d447df14STejun Heo  */
8014447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
8024447d351STejun Heo 				     struct ahci_host_priv *hpriv)
803d447df14STejun Heo {
8044447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
8054c521c8eSRobert Hancock 	u32 cap, cap2, vers, port_map;
80617199b18STejun Heo 	int i;
807c40e7cb8SJose Alberto Reguero 	int mv;
808d447df14STejun Heo 
809b710a1f4STejun Heo 	/* make sure AHCI mode is enabled before accessing CAP */
810b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
811b710a1f4STejun Heo 
812d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
813d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
814d447df14STejun Heo 	 */
815d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
816d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
817d447df14STejun Heo 
8184c521c8eSRobert Hancock 	/* CAP2 register is only defined for AHCI 1.2 and later */
8194c521c8eSRobert Hancock 	vers = readl(mmio + HOST_VERSION);
8204c521c8eSRobert Hancock 	if ((vers >> 16) > 1 ||
8214c521c8eSRobert Hancock 	   ((vers >> 16) == 1 && (vers & 0xFFFF) >= 0x200))
8224c521c8eSRobert Hancock 		hpriv->saved_cap2 = cap2 = readl(mmio + HOST_CAP2);
8234c521c8eSRobert Hancock 	else
8244c521c8eSRobert Hancock 		hpriv->saved_cap2 = cap2 = 0;
8254c521c8eSRobert Hancock 
826274c1fdeSTejun Heo 	/* some chips have errata preventing 64bit use */
827417a1a6dSTejun Heo 	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
828c7a42156STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
829c7a42156STejun Heo 			   "controller can't do 64bit DMA, forcing 32bit\n");
830c7a42156STejun Heo 		cap &= ~HOST_CAP_64;
831c7a42156STejun Heo 	}
832c7a42156STejun Heo 
833417a1a6dSTejun Heo 	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
834274c1fdeSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
835274c1fdeSTejun Heo 			   "controller can't do NCQ, turning off CAP_NCQ\n");
836274c1fdeSTejun Heo 		cap &= ~HOST_CAP_NCQ;
837274c1fdeSTejun Heo 	}
838274c1fdeSTejun Heo 
839e297d99eSTejun Heo 	if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
840e297d99eSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
841e297d99eSTejun Heo 			   "controller can do NCQ, turning on CAP_NCQ\n");
842e297d99eSTejun Heo 		cap |= HOST_CAP_NCQ;
843e297d99eSTejun Heo 	}
844e297d99eSTejun Heo 
845258cd846SRoel Kluin 	if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
8466949b914STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
8476949b914STejun Heo 			   "controller can't do PMP, turning off CAP_PMP\n");
8486949b914STejun Heo 		cap &= ~HOST_CAP_PMP;
8496949b914STejun Heo 	}
8506949b914STejun Heo 
851d799e083STejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
852d799e083STejun Heo 	    port_map != 1) {
853d799e083STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
854d799e083STejun Heo 			   "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
855d799e083STejun Heo 			   port_map, 1);
856d799e083STejun Heo 		port_map = 1;
857d799e083STejun Heo 	}
858d799e083STejun Heo 
859cd70c266SJeff Garzik 	/*
860cd70c266SJeff Garzik 	 * Temporary Marvell 6145 hack: PATA port presence
861cd70c266SJeff Garzik 	 * is asserted through the standard AHCI port
862cd70c266SJeff Garzik 	 * presence register, as bit 4 (counting from 0)
863cd70c266SJeff Garzik 	 */
864417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
865c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
866c40e7cb8SJose Alberto Reguero 			mv = 0x3;
867c40e7cb8SJose Alberto Reguero 		else
868c40e7cb8SJose Alberto Reguero 			mv = 0xf;
869cd70c266SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
870cd70c266SJeff Garzik 			   "MV_AHCI HACK: port_map %x -> %x\n",
871c40e7cb8SJose Alberto Reguero 			   port_map,
872c40e7cb8SJose Alberto Reguero 			   port_map & mv);
8735b66c829SAlan Cox 		dev_printk(KERN_ERR, &pdev->dev,
8745b66c829SAlan Cox 			  "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
875cd70c266SJeff Garzik 
876c40e7cb8SJose Alberto Reguero 		port_map &= mv;
877cd70c266SJeff Garzik 	}
878cd70c266SJeff Garzik 
87917199b18STejun Heo 	/* cross check port_map and cap.n_ports */
8807a234affSTejun Heo 	if (port_map) {
881837f5f8fSTejun Heo 		int map_ports = 0;
88217199b18STejun Heo 
883837f5f8fSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS; i++)
884837f5f8fSTejun Heo 			if (port_map & (1 << i))
885837f5f8fSTejun Heo 				map_ports++;
88617199b18STejun Heo 
887837f5f8fSTejun Heo 		/* If PI has more ports than n_ports, whine, clear
888837f5f8fSTejun Heo 		 * port_map and let it be generated from n_ports.
88917199b18STejun Heo 		 */
890837f5f8fSTejun Heo 		if (map_ports > ahci_nr_ports(cap)) {
8914447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
892837f5f8fSTejun Heo 				   "implemented port map (0x%x) contains more "
893837f5f8fSTejun Heo 				   "ports than nr_ports (%u), using nr_ports\n",
894837f5f8fSTejun Heo 				   port_map, ahci_nr_ports(cap));
8957a234affSTejun Heo 			port_map = 0;
8967a234affSTejun Heo 		}
8977a234affSTejun Heo 	}
8987a234affSTejun Heo 
89917199b18STejun Heo 	/* fabricate port_map from cap.nr_ports */
9007a234affSTejun Heo 	if (!port_map) {
90117199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
9027a234affSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
9037a234affSTejun Heo 			   "forcing PORTS_IMPL to 0x%x\n", port_map);
9047a234affSTejun Heo 
9057a234affSTejun Heo 		/* write the fixed up value to the PI register */
9067a234affSTejun Heo 		hpriv->saved_port_map = port_map;
90717199b18STejun Heo 	}
90817199b18STejun Heo 
909d447df14STejun Heo 	/* record values to use during operation */
910d447df14STejun Heo 	hpriv->cap = cap;
9114c521c8eSRobert Hancock 	hpriv->cap2 = cap2;
912d447df14STejun Heo 	hpriv->port_map = port_map;
913d447df14STejun Heo }
914d447df14STejun Heo 
915d447df14STejun Heo /**
916d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
9174447d351STejun Heo  *	@host: target ATA host
918d447df14STejun Heo  *
919d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
920d447df14STejun Heo  *
921d447df14STejun Heo  *	LOCKING:
922d447df14STejun Heo  *	None.
923d447df14STejun Heo  */
9244447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
925d447df14STejun Heo {
9264447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
9274447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
9284447d351STejun Heo 
929d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
9304c521c8eSRobert Hancock 	if (hpriv->saved_cap2)
9314c521c8eSRobert Hancock 		writel(hpriv->saved_cap2, mmio + HOST_CAP2);
932d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
933d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
934d447df14STejun Heo }
935d447df14STejun Heo 
936203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
937c6fd2807SJeff Garzik {
938203ef6c4STejun Heo 	static const int offset[] = {
939203ef6c4STejun Heo 		[SCR_STATUS]		= PORT_SCR_STAT,
940203ef6c4STejun Heo 		[SCR_CONTROL]		= PORT_SCR_CTL,
941203ef6c4STejun Heo 		[SCR_ERROR]		= PORT_SCR_ERR,
942203ef6c4STejun Heo 		[SCR_ACTIVE]		= PORT_SCR_ACT,
943203ef6c4STejun Heo 		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
944203ef6c4STejun Heo 	};
945203ef6c4STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
946c6fd2807SJeff Garzik 
947203ef6c4STejun Heo 	if (sc_reg < ARRAY_SIZE(offset) &&
948203ef6c4STejun Heo 	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
949203ef6c4STejun Heo 		return offset[sc_reg];
950da3dbb17STejun Heo 	return 0;
951c6fd2807SJeff Garzik }
952c6fd2807SJeff Garzik 
95382ef04fbSTejun Heo static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
954c6fd2807SJeff Garzik {
95582ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
95682ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
957c6fd2807SJeff Garzik 
958203ef6c4STejun Heo 	if (offset) {
959203ef6c4STejun Heo 		*val = readl(port_mmio + offset);
960203ef6c4STejun Heo 		return 0;
961203ef6c4STejun Heo 	}
962da3dbb17STejun Heo 	return -EINVAL;
963c6fd2807SJeff Garzik }
964c6fd2807SJeff Garzik 
96582ef04fbSTejun Heo static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
966203ef6c4STejun Heo {
96782ef04fbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(link->ap);
96882ef04fbSTejun Heo 	int offset = ahci_scr_offset(link->ap, sc_reg);
969203ef6c4STejun Heo 
970203ef6c4STejun Heo 	if (offset) {
971203ef6c4STejun Heo 		writel(val, port_mmio + offset);
972da3dbb17STejun Heo 		return 0;
973c6fd2807SJeff Garzik 	}
974203ef6c4STejun Heo 	return -EINVAL;
975203ef6c4STejun Heo }
976c6fd2807SJeff Garzik 
9774447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
978c6fd2807SJeff Garzik {
9794447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
980c6fd2807SJeff Garzik 	u32 tmp;
981c6fd2807SJeff Garzik 
982c6fd2807SJeff Garzik 	/* start DMA */
983c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
984c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
985c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
986c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
987c6fd2807SJeff Garzik }
988c6fd2807SJeff Garzik 
9894447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
990c6fd2807SJeff Garzik {
9914447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
992c6fd2807SJeff Garzik 	u32 tmp;
993c6fd2807SJeff Garzik 
994c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
995c6fd2807SJeff Garzik 
996c6fd2807SJeff Garzik 	/* check if the HBA is idle */
997c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
998c6fd2807SJeff Garzik 		return 0;
999c6fd2807SJeff Garzik 
1000c6fd2807SJeff Garzik 	/* setting HBA to idle */
1001c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
1002c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1003c6fd2807SJeff Garzik 
1004c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
1005c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1006c6fd2807SJeff Garzik 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
1007c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
1008c6fd2807SJeff Garzik 		return -EIO;
1009c6fd2807SJeff Garzik 
1010c6fd2807SJeff Garzik 	return 0;
1011c6fd2807SJeff Garzik }
1012c6fd2807SJeff Garzik 
10134447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
1014c6fd2807SJeff Garzik {
10154447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
10164447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
10174447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1018c6fd2807SJeff Garzik 	u32 tmp;
1019c6fd2807SJeff Garzik 
1020c6fd2807SJeff Garzik 	/* set FIS registers */
10214447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
10224447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
10234447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
10244447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
1025c6fd2807SJeff Garzik 
10264447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
10274447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
10284447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
10294447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
1030c6fd2807SJeff Garzik 
1031c6fd2807SJeff Garzik 	/* enable FIS reception */
1032c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1033c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
1034c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1035c6fd2807SJeff Garzik 
1036c6fd2807SJeff Garzik 	/* flush */
1037c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
1038c6fd2807SJeff Garzik }
1039c6fd2807SJeff Garzik 
10404447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
1041c6fd2807SJeff Garzik {
10424447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1043c6fd2807SJeff Garzik 	u32 tmp;
1044c6fd2807SJeff Garzik 
1045c6fd2807SJeff Garzik 	/* disable FIS reception */
1046c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1047c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
1048c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1049c6fd2807SJeff Garzik 
1050c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
1051c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
1052c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
1053c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
1054c6fd2807SJeff Garzik 		return -EBUSY;
1055c6fd2807SJeff Garzik 
1056c6fd2807SJeff Garzik 	return 0;
1057c6fd2807SJeff Garzik }
1058c6fd2807SJeff Garzik 
10594447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
1060c6fd2807SJeff Garzik {
10614447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
10624447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1063c6fd2807SJeff Garzik 	u32 cmd;
1064c6fd2807SJeff Garzik 
1065c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1066c6fd2807SJeff Garzik 
1067c6fd2807SJeff Garzik 	/* spin up device */
10684447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
1069c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
1070c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
1071c6fd2807SJeff Garzik 	}
1072c6fd2807SJeff Garzik 
1073c6fd2807SJeff Garzik 	/* wake up link */
1074c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
1075c6fd2807SJeff Garzik }
1076c6fd2807SJeff Garzik 
107731556594SKristen Carlson Accardi static void ahci_disable_alpm(struct ata_port *ap)
107831556594SKristen Carlson Accardi {
107931556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
108031556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
108131556594SKristen Carlson Accardi 	u32 cmd;
108231556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
108331556594SKristen Carlson Accardi 
108431556594SKristen Carlson Accardi 	/* IPM bits should be disabled by libata-core */
108531556594SKristen Carlson Accardi 	/* get the existing command bits */
108631556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
108731556594SKristen Carlson Accardi 
108831556594SKristen Carlson Accardi 	/* disable ALPM and ASP */
108931556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ASP;
109031556594SKristen Carlson Accardi 	cmd &= ~PORT_CMD_ALPE;
109131556594SKristen Carlson Accardi 
109231556594SKristen Carlson Accardi 	/* force the interface back to active */
109331556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ICC_ACTIVE;
109431556594SKristen Carlson Accardi 
109531556594SKristen Carlson Accardi 	/* write out new cmd value */
109631556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
109731556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
109831556594SKristen Carlson Accardi 
109931556594SKristen Carlson Accardi 	/* wait 10ms to be sure we've come out of any low power state */
110031556594SKristen Carlson Accardi 	msleep(10);
110131556594SKristen Carlson Accardi 
110231556594SKristen Carlson Accardi 	/* clear out any PhyRdy stuff from interrupt status */
110331556594SKristen Carlson Accardi 	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
110431556594SKristen Carlson Accardi 
110531556594SKristen Carlson Accardi 	/* go ahead and clean out PhyRdy Change from Serror too */
110682ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
110731556594SKristen Carlson Accardi 
110831556594SKristen Carlson Accardi 	/*
110931556594SKristen Carlson Accardi  	 * Clear flag to indicate that we should ignore all PhyRdy
111031556594SKristen Carlson Accardi  	 * state changes
111131556594SKristen Carlson Accardi  	 */
111231556594SKristen Carlson Accardi 	hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
111331556594SKristen Carlson Accardi 
111431556594SKristen Carlson Accardi 	/*
111531556594SKristen Carlson Accardi  	 * Enable interrupts on Phy Ready.
111631556594SKristen Carlson Accardi  	 */
111731556594SKristen Carlson Accardi 	pp->intr_mask |= PORT_IRQ_PHYRDY;
111831556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
111931556594SKristen Carlson Accardi 
112031556594SKristen Carlson Accardi 	/*
112131556594SKristen Carlson Accardi  	 * don't change the link pm policy - we can be called
112231556594SKristen Carlson Accardi  	 * just to turn of link pm temporarily
112331556594SKristen Carlson Accardi  	 */
112431556594SKristen Carlson Accardi }
112531556594SKristen Carlson Accardi 
112631556594SKristen Carlson Accardi static int ahci_enable_alpm(struct ata_port *ap,
112731556594SKristen Carlson Accardi 	enum link_pm policy)
112831556594SKristen Carlson Accardi {
112931556594SKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
113031556594SKristen Carlson Accardi 	void __iomem *port_mmio = ahci_port_base(ap);
113131556594SKristen Carlson Accardi 	u32 cmd;
113231556594SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
113331556594SKristen Carlson Accardi 	u32 asp;
113431556594SKristen Carlson Accardi 
113531556594SKristen Carlson Accardi 	/* Make sure the host is capable of link power management */
113631556594SKristen Carlson Accardi 	if (!(hpriv->cap & HOST_CAP_ALPM))
113731556594SKristen Carlson Accardi 		return -EINVAL;
113831556594SKristen Carlson Accardi 
113931556594SKristen Carlson Accardi 	switch (policy) {
114031556594SKristen Carlson Accardi 	case MAX_PERFORMANCE:
114131556594SKristen Carlson Accardi 	case NOT_AVAILABLE:
114231556594SKristen Carlson Accardi 		/*
114331556594SKristen Carlson Accardi  		 * if we came here with NOT_AVAILABLE,
114431556594SKristen Carlson Accardi  		 * it just means this is the first time we
114531556594SKristen Carlson Accardi  		 * have tried to enable - default to max performance,
114631556594SKristen Carlson Accardi  		 * and let the user go to lower power modes on request.
114731556594SKristen Carlson Accardi  		 */
114831556594SKristen Carlson Accardi 		ahci_disable_alpm(ap);
114931556594SKristen Carlson Accardi 		return 0;
115031556594SKristen Carlson Accardi 	case MIN_POWER:
115131556594SKristen Carlson Accardi 		/* configure HBA to enter SLUMBER */
115231556594SKristen Carlson Accardi 		asp = PORT_CMD_ASP;
115331556594SKristen Carlson Accardi 		break;
115431556594SKristen Carlson Accardi 	case MEDIUM_POWER:
115531556594SKristen Carlson Accardi 		/* configure HBA to enter PARTIAL */
115631556594SKristen Carlson Accardi 		asp = 0;
115731556594SKristen Carlson Accardi 		break;
115831556594SKristen Carlson Accardi 	default:
115931556594SKristen Carlson Accardi 		return -EINVAL;
116031556594SKristen Carlson Accardi 	}
116131556594SKristen Carlson Accardi 
116231556594SKristen Carlson Accardi 	/*
116331556594SKristen Carlson Accardi  	 * Disable interrupts on Phy Ready. This keeps us from
116431556594SKristen Carlson Accardi  	 * getting woken up due to spurious phy ready interrupts
116531556594SKristen Carlson Accardi 	 * TBD - Hot plug should be done via polling now, is
116631556594SKristen Carlson Accardi 	 * that even supported?
116731556594SKristen Carlson Accardi  	 */
116831556594SKristen Carlson Accardi 	pp->intr_mask &= ~PORT_IRQ_PHYRDY;
116931556594SKristen Carlson Accardi 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
117031556594SKristen Carlson Accardi 
117131556594SKristen Carlson Accardi 	/*
117231556594SKristen Carlson Accardi  	 * Set a flag to indicate that we should ignore all PhyRdy
117331556594SKristen Carlson Accardi  	 * state changes since these can happen now whenever we
117431556594SKristen Carlson Accardi  	 * change link state
117531556594SKristen Carlson Accardi  	 */
117631556594SKristen Carlson Accardi 	hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
117731556594SKristen Carlson Accardi 
117831556594SKristen Carlson Accardi 	/* get the existing command bits */
117931556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
118031556594SKristen Carlson Accardi 
118131556594SKristen Carlson Accardi 	/*
118231556594SKristen Carlson Accardi  	 * Set ASP based on Policy
118331556594SKristen Carlson Accardi  	 */
118431556594SKristen Carlson Accardi 	cmd |= asp;
118531556594SKristen Carlson Accardi 
118631556594SKristen Carlson Accardi 	/*
118731556594SKristen Carlson Accardi  	 * Setting this bit will instruct the HBA to aggressively
118831556594SKristen Carlson Accardi  	 * enter a lower power link state when it's appropriate and
118931556594SKristen Carlson Accardi  	 * based on the value set above for ASP
119031556594SKristen Carlson Accardi  	 */
119131556594SKristen Carlson Accardi 	cmd |= PORT_CMD_ALPE;
119231556594SKristen Carlson Accardi 
119331556594SKristen Carlson Accardi 	/* write out new cmd value */
119431556594SKristen Carlson Accardi 	writel(cmd, port_mmio + PORT_CMD);
119531556594SKristen Carlson Accardi 	cmd = readl(port_mmio + PORT_CMD);
119631556594SKristen Carlson Accardi 
119731556594SKristen Carlson Accardi 	/* IPM bits should be set by libata-core */
119831556594SKristen Carlson Accardi 	return 0;
119931556594SKristen Carlson Accardi }
120031556594SKristen Carlson Accardi 
1201438ac6d5STejun Heo #ifdef CONFIG_PM
12024447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
1203c6fd2807SJeff Garzik {
12044447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
12054447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1206c6fd2807SJeff Garzik 	u32 cmd, scontrol;
1207c6fd2807SJeff Garzik 
12084447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
120907c53dacSTejun Heo 		return;
1210c6fd2807SJeff Garzik 
121107c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
1212c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
1213c6fd2807SJeff Garzik 	scontrol &= ~0xf;
1214c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
1215c6fd2807SJeff Garzik 
1216c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
121707c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
1218c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
1219c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
1220c6fd2807SJeff Garzik }
1221438ac6d5STejun Heo #endif
1222c6fd2807SJeff Garzik 
1223df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap)
1224c6fd2807SJeff Garzik {
122518f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
122618f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
122718f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
12284c1e9aa4SDavid Milburn 	ssize_t rc;
12294c1e9aa4SDavid Milburn 	int i;
123018f7ba4cSKristen Carlson Accardi 
1231c6fd2807SJeff Garzik 	/* enable FIS reception */
12324447d351STejun Heo 	ahci_start_fis_rx(ap);
1233c6fd2807SJeff Garzik 
1234c6fd2807SJeff Garzik 	/* enable DMA */
12354447d351STejun Heo 	ahci_start_engine(ap);
123618f7ba4cSKristen Carlson Accardi 
123718f7ba4cSKristen Carlson Accardi 	/* turn on LEDs */
123818f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_EM) {
12391eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE) {
124018f7ba4cSKristen Carlson Accardi 			emp = &pp->em_priv[link->pmp];
12414c1e9aa4SDavid Milburn 
12424c1e9aa4SDavid Milburn 			/* EM Transmit bit maybe busy during init */
1243d50ce07dSTejun Heo 			for (i = 0; i < EM_MAX_RETRY; i++) {
12444c1e9aa4SDavid Milburn 				rc = ahci_transmit_led_message(ap,
12454c1e9aa4SDavid Milburn 							       emp->led_state,
12464c1e9aa4SDavid Milburn 							       4);
12474c1e9aa4SDavid Milburn 				if (rc == -EBUSY)
1248d50ce07dSTejun Heo 					msleep(1);
12494c1e9aa4SDavid Milburn 				else
12504c1e9aa4SDavid Milburn 					break;
12514c1e9aa4SDavid Milburn 			}
125218f7ba4cSKristen Carlson Accardi 		}
125318f7ba4cSKristen Carlson Accardi 	}
125418f7ba4cSKristen Carlson Accardi 
125518f7ba4cSKristen Carlson Accardi 	if (ap->flags & ATA_FLAG_SW_ACTIVITY)
12561eca4365STejun Heo 		ata_for_each_link(link, ap, EDGE)
125718f7ba4cSKristen Carlson Accardi 			ahci_init_sw_activity(link);
125818f7ba4cSKristen Carlson Accardi 
1259c6fd2807SJeff Garzik }
1260c6fd2807SJeff Garzik 
12614447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
1262c6fd2807SJeff Garzik {
1263c6fd2807SJeff Garzik 	int rc;
1264c6fd2807SJeff Garzik 
1265c6fd2807SJeff Garzik 	/* disable DMA */
12664447d351STejun Heo 	rc = ahci_stop_engine(ap);
1267c6fd2807SJeff Garzik 	if (rc) {
1268c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
1269c6fd2807SJeff Garzik 		return rc;
1270c6fd2807SJeff Garzik 	}
1271c6fd2807SJeff Garzik 
1272c6fd2807SJeff Garzik 	/* disable FIS reception */
12734447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
1274c6fd2807SJeff Garzik 	if (rc) {
1275c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
1276c6fd2807SJeff Garzik 		return rc;
1277c6fd2807SJeff Garzik 	}
1278c6fd2807SJeff Garzik 
1279c6fd2807SJeff Garzik 	return 0;
1280c6fd2807SJeff Garzik }
1281c6fd2807SJeff Garzik 
12824447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
1283c6fd2807SJeff Garzik {
12844447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
128549f29090STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
12864447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1287d447df14STejun Heo 	u32 tmp;
1288c6fd2807SJeff Garzik 
12893cc3eb11SJeff Garzik 	/* we must be in AHCI mode, before using anything
12903cc3eb11SJeff Garzik 	 * AHCI-specific, such as HOST_RESET.
12913cc3eb11SJeff Garzik 	 */
1292b710a1f4STejun Heo 	ahci_enable_ahci(mmio);
12933cc3eb11SJeff Garzik 
12943cc3eb11SJeff Garzik 	/* global controller reset */
1295a22e6444STejun Heo 	if (!ahci_skip_host_reset) {
1296b710a1f4STejun Heo 		tmp = readl(mmio + HOST_CTL);
1297c6fd2807SJeff Garzik 		if ((tmp & HOST_RESET) == 0) {
1298c6fd2807SJeff Garzik 			writel(tmp | HOST_RESET, mmio + HOST_CTL);
1299c6fd2807SJeff Garzik 			readl(mmio + HOST_CTL); /* flush */
1300c6fd2807SJeff Garzik 		}
1301c6fd2807SJeff Garzik 
130224920c8aSZhang Rui 		/*
130324920c8aSZhang Rui 		 * to perform host reset, OS should set HOST_RESET
130424920c8aSZhang Rui 		 * and poll until this bit is read to be "0".
130524920c8aSZhang Rui 		 * reset must complete within 1 second, or
1306c6fd2807SJeff Garzik 		 * the hardware should be considered fried.
1307c6fd2807SJeff Garzik 		 */
130824920c8aSZhang Rui 		tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
130924920c8aSZhang Rui 					HOST_RESET, 10, 1000);
1310c6fd2807SJeff Garzik 
1311c6fd2807SJeff Garzik 		if (tmp & HOST_RESET) {
13124447d351STejun Heo 			dev_printk(KERN_ERR, host->dev,
1313c6fd2807SJeff Garzik 				   "controller reset failed (0x%x)\n", tmp);
1314c6fd2807SJeff Garzik 			return -EIO;
1315c6fd2807SJeff Garzik 		}
1316c6fd2807SJeff Garzik 
131798fa4b60STejun Heo 		/* turn on AHCI mode */
1318b710a1f4STejun Heo 		ahci_enable_ahci(mmio);
131998fa4b60STejun Heo 
1320a22e6444STejun Heo 		/* Some registers might be cleared on reset.  Restore
1321a22e6444STejun Heo 		 * initial values.
1322a22e6444STejun Heo 		 */
13234447d351STejun Heo 		ahci_restore_initial_config(host);
1324a22e6444STejun Heo 	} else
1325a22e6444STejun Heo 		dev_printk(KERN_INFO, host->dev,
1326a22e6444STejun Heo 			   "skipping global host reset\n");
1327c6fd2807SJeff Garzik 
1328c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
1329c6fd2807SJeff Garzik 		u16 tmp16;
1330c6fd2807SJeff Garzik 
1331c6fd2807SJeff Garzik 		/* configure PCS */
1332c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
133349f29090STejun Heo 		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
133449f29090STejun Heo 			tmp16 |= hpriv->port_map;
1335c6fd2807SJeff Garzik 			pci_write_config_word(pdev, 0x92, tmp16);
1336c6fd2807SJeff Garzik 		}
133749f29090STejun Heo 	}
1338c6fd2807SJeff Garzik 
1339c6fd2807SJeff Garzik 	return 0;
1340c6fd2807SJeff Garzik }
1341c6fd2807SJeff Garzik 
134218f7ba4cSKristen Carlson Accardi static void ahci_sw_activity(struct ata_link *link)
134318f7ba4cSKristen Carlson Accardi {
134418f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
134518f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
134618f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
134718f7ba4cSKristen Carlson Accardi 
134818f7ba4cSKristen Carlson Accardi 	if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
134918f7ba4cSKristen Carlson Accardi 		return;
135018f7ba4cSKristen Carlson Accardi 
135118f7ba4cSKristen Carlson Accardi 	emp->activity++;
135218f7ba4cSKristen Carlson Accardi 	if (!timer_pending(&emp->timer))
135318f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
135418f7ba4cSKristen Carlson Accardi }
135518f7ba4cSKristen Carlson Accardi 
135618f7ba4cSKristen Carlson Accardi static void ahci_sw_activity_blink(unsigned long arg)
135718f7ba4cSKristen Carlson Accardi {
135818f7ba4cSKristen Carlson Accardi 	struct ata_link *link = (struct ata_link *)arg;
135918f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
136018f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
136118f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
136218f7ba4cSKristen Carlson Accardi 	unsigned long led_message = emp->led_state;
136318f7ba4cSKristen Carlson Accardi 	u32 activity_led_state;
1364eb40963cSDavid Milburn 	unsigned long flags;
136518f7ba4cSKristen Carlson Accardi 
136687943acfSDavid Milburn 	led_message &= EM_MSG_LED_VALUE;
136718f7ba4cSKristen Carlson Accardi 	led_message |= ap->port_no | (link->pmp << 8);
136818f7ba4cSKristen Carlson Accardi 
136918f7ba4cSKristen Carlson Accardi 	/* check to see if we've had activity.  If so,
137018f7ba4cSKristen Carlson Accardi 	 * toggle state of LED and reset timer.  If not,
137118f7ba4cSKristen Carlson Accardi 	 * turn LED to desired idle state.
137218f7ba4cSKristen Carlson Accardi 	 */
1373eb40963cSDavid Milburn 	spin_lock_irqsave(ap->lock, flags);
137418f7ba4cSKristen Carlson Accardi 	if (emp->saved_activity != emp->activity) {
137518f7ba4cSKristen Carlson Accardi 		emp->saved_activity = emp->activity;
137618f7ba4cSKristen Carlson Accardi 		/* get the current LED state */
137787943acfSDavid Milburn 		activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
137818f7ba4cSKristen Carlson Accardi 
137918f7ba4cSKristen Carlson Accardi 		if (activity_led_state)
138018f7ba4cSKristen Carlson Accardi 			activity_led_state = 0;
138118f7ba4cSKristen Carlson Accardi 		else
138218f7ba4cSKristen Carlson Accardi 			activity_led_state = 1;
138318f7ba4cSKristen Carlson Accardi 
138418f7ba4cSKristen Carlson Accardi 		/* clear old state */
138587943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
138618f7ba4cSKristen Carlson Accardi 
138718f7ba4cSKristen Carlson Accardi 		/* toggle state */
138818f7ba4cSKristen Carlson Accardi 		led_message |= (activity_led_state << 16);
138918f7ba4cSKristen Carlson Accardi 		mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
139018f7ba4cSKristen Carlson Accardi 	} else {
139118f7ba4cSKristen Carlson Accardi 		/* switch to idle */
139287943acfSDavid Milburn 		led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
139318f7ba4cSKristen Carlson Accardi 		if (emp->blink_policy == BLINK_OFF)
139418f7ba4cSKristen Carlson Accardi 			led_message |= (1 << 16);
139518f7ba4cSKristen Carlson Accardi 	}
1396eb40963cSDavid Milburn 	spin_unlock_irqrestore(ap->lock, flags);
139718f7ba4cSKristen Carlson Accardi 	ahci_transmit_led_message(ap, led_message, 4);
139818f7ba4cSKristen Carlson Accardi }
139918f7ba4cSKristen Carlson Accardi 
140018f7ba4cSKristen Carlson Accardi static void ahci_init_sw_activity(struct ata_link *link)
140118f7ba4cSKristen Carlson Accardi {
140218f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
140318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
140418f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
140518f7ba4cSKristen Carlson Accardi 
140618f7ba4cSKristen Carlson Accardi 	/* init activity stats, setup timer */
140718f7ba4cSKristen Carlson Accardi 	emp->saved_activity = emp->activity = 0;
140818f7ba4cSKristen Carlson Accardi 	setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
140918f7ba4cSKristen Carlson Accardi 
141018f7ba4cSKristen Carlson Accardi 	/* check our blink policy and set flag for link if it's enabled */
141118f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
141218f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
141318f7ba4cSKristen Carlson Accardi }
141418f7ba4cSKristen Carlson Accardi 
141518f7ba4cSKristen Carlson Accardi static int ahci_reset_em(struct ata_host *host)
141618f7ba4cSKristen Carlson Accardi {
141718f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
141818f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
141918f7ba4cSKristen Carlson Accardi 
142018f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
142118f7ba4cSKristen Carlson Accardi 	if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
142218f7ba4cSKristen Carlson Accardi 		return -EINVAL;
142318f7ba4cSKristen Carlson Accardi 
142418f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
142518f7ba4cSKristen Carlson Accardi 	return 0;
142618f7ba4cSKristen Carlson Accardi }
142718f7ba4cSKristen Carlson Accardi 
142818f7ba4cSKristen Carlson Accardi static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
142918f7ba4cSKristen Carlson Accardi 					ssize_t size)
143018f7ba4cSKristen Carlson Accardi {
143118f7ba4cSKristen Carlson Accardi 	struct ahci_host_priv *hpriv = ap->host->private_data;
143218f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
143318f7ba4cSKristen Carlson Accardi 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
143418f7ba4cSKristen Carlson Accardi 	u32 em_ctl;
143518f7ba4cSKristen Carlson Accardi 	u32 message[] = {0, 0};
143693082f0bSLinus Torvalds 	unsigned long flags;
143718f7ba4cSKristen Carlson Accardi 	int pmp;
143818f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
143918f7ba4cSKristen Carlson Accardi 
144018f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
144187943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
1442d50ce07dSTejun Heo 	if (pmp < EM_MAX_SLOTS)
144318f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
144418f7ba4cSKristen Carlson Accardi 	else
144518f7ba4cSKristen Carlson Accardi 		return -EINVAL;
144618f7ba4cSKristen Carlson Accardi 
144718f7ba4cSKristen Carlson Accardi 	spin_lock_irqsave(ap->lock, flags);
144818f7ba4cSKristen Carlson Accardi 
144918f7ba4cSKristen Carlson Accardi 	/*
145018f7ba4cSKristen Carlson Accardi 	 * if we are still busy transmitting a previous message,
145118f7ba4cSKristen Carlson Accardi 	 * do not allow
145218f7ba4cSKristen Carlson Accardi 	 */
145318f7ba4cSKristen Carlson Accardi 	em_ctl = readl(mmio + HOST_EM_CTL);
145418f7ba4cSKristen Carlson Accardi 	if (em_ctl & EM_CTL_TM) {
145518f7ba4cSKristen Carlson Accardi 		spin_unlock_irqrestore(ap->lock, flags);
14564c1e9aa4SDavid Milburn 		return -EBUSY;
145718f7ba4cSKristen Carlson Accardi 	}
145818f7ba4cSKristen Carlson Accardi 
145918f7ba4cSKristen Carlson Accardi 	/*
146018f7ba4cSKristen Carlson Accardi 	 * create message header - this is all zero except for
146118f7ba4cSKristen Carlson Accardi 	 * the message size, which is 4 bytes.
146218f7ba4cSKristen Carlson Accardi 	 */
146318f7ba4cSKristen Carlson Accardi 	message[0] |= (4 << 8);
146418f7ba4cSKristen Carlson Accardi 
146518f7ba4cSKristen Carlson Accardi 	/* ignore 0:4 of byte zero, fill in port info yourself */
146687943acfSDavid Milburn 	message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
146718f7ba4cSKristen Carlson Accardi 
146818f7ba4cSKristen Carlson Accardi 	/* write message to EM_LOC */
146918f7ba4cSKristen Carlson Accardi 	writel(message[0], mmio + hpriv->em_loc);
147018f7ba4cSKristen Carlson Accardi 	writel(message[1], mmio + hpriv->em_loc+4);
147118f7ba4cSKristen Carlson Accardi 
147218f7ba4cSKristen Carlson Accardi 	/* save off new led state for port/slot */
1473208f2a88SDavid Milburn 	emp->led_state = state;
147418f7ba4cSKristen Carlson Accardi 
147518f7ba4cSKristen Carlson Accardi 	/*
147618f7ba4cSKristen Carlson Accardi 	 * tell hardware to transmit the message
147718f7ba4cSKristen Carlson Accardi 	 */
147818f7ba4cSKristen Carlson Accardi 	writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
147918f7ba4cSKristen Carlson Accardi 
148018f7ba4cSKristen Carlson Accardi 	spin_unlock_irqrestore(ap->lock, flags);
148118f7ba4cSKristen Carlson Accardi 	return size;
148218f7ba4cSKristen Carlson Accardi }
148318f7ba4cSKristen Carlson Accardi 
148418f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
148518f7ba4cSKristen Carlson Accardi {
148618f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
148718f7ba4cSKristen Carlson Accardi 	struct ata_link *link;
148818f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
148918f7ba4cSKristen Carlson Accardi 	int rc = 0;
149018f7ba4cSKristen Carlson Accardi 
14911eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE) {
149218f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[link->pmp];
149318f7ba4cSKristen Carlson Accardi 		rc += sprintf(buf, "%lx\n", emp->led_state);
149418f7ba4cSKristen Carlson Accardi 	}
149518f7ba4cSKristen Carlson Accardi 	return rc;
149618f7ba4cSKristen Carlson Accardi }
149718f7ba4cSKristen Carlson Accardi 
149818f7ba4cSKristen Carlson Accardi static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
149918f7ba4cSKristen Carlson Accardi 				size_t size)
150018f7ba4cSKristen Carlson Accardi {
150118f7ba4cSKristen Carlson Accardi 	int state;
150218f7ba4cSKristen Carlson Accardi 	int pmp;
150318f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
150418f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp;
150518f7ba4cSKristen Carlson Accardi 
150618f7ba4cSKristen Carlson Accardi 	state = simple_strtoul(buf, NULL, 0);
150718f7ba4cSKristen Carlson Accardi 
150818f7ba4cSKristen Carlson Accardi 	/* get the slot number from the message */
150987943acfSDavid Milburn 	pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
1510d50ce07dSTejun Heo 	if (pmp < EM_MAX_SLOTS)
151118f7ba4cSKristen Carlson Accardi 		emp = &pp->em_priv[pmp];
151218f7ba4cSKristen Carlson Accardi 	else
151318f7ba4cSKristen Carlson Accardi 		return -EINVAL;
151418f7ba4cSKristen Carlson Accardi 
151518f7ba4cSKristen Carlson Accardi 	/* mask off the activity bits if we are in sw_activity
151618f7ba4cSKristen Carlson Accardi 	 * mode, user should turn off sw_activity before setting
151718f7ba4cSKristen Carlson Accardi 	 * activity led through em_message
151818f7ba4cSKristen Carlson Accardi 	 */
151918f7ba4cSKristen Carlson Accardi 	if (emp->blink_policy)
152087943acfSDavid Milburn 		state &= ~EM_MSG_LED_VALUE_ACTIVITY;
152118f7ba4cSKristen Carlson Accardi 
152218f7ba4cSKristen Carlson Accardi 	return ahci_transmit_led_message(ap, state, size);
152318f7ba4cSKristen Carlson Accardi }
152418f7ba4cSKristen Carlson Accardi 
152518f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
152618f7ba4cSKristen Carlson Accardi {
152718f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
152818f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
152918f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
153018f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
153118f7ba4cSKristen Carlson Accardi 	u32 port_led_state = emp->led_state;
153218f7ba4cSKristen Carlson Accardi 
153318f7ba4cSKristen Carlson Accardi 	/* save the desired Activity LED behavior */
153418f7ba4cSKristen Carlson Accardi 	if (val == OFF) {
153518f7ba4cSKristen Carlson Accardi 		/* clear LFLAG */
153618f7ba4cSKristen Carlson Accardi 		link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
153718f7ba4cSKristen Carlson Accardi 
153818f7ba4cSKristen Carlson Accardi 		/* set the LED to OFF */
153987943acfSDavid Milburn 		port_led_state &= EM_MSG_LED_VALUE_OFF;
154018f7ba4cSKristen Carlson Accardi 		port_led_state |= (ap->port_no | (link->pmp << 8));
154118f7ba4cSKristen Carlson Accardi 		ahci_transmit_led_message(ap, port_led_state, 4);
154218f7ba4cSKristen Carlson Accardi 	} else {
154318f7ba4cSKristen Carlson Accardi 		link->flags |= ATA_LFLAG_SW_ACTIVITY;
154418f7ba4cSKristen Carlson Accardi 		if (val == BLINK_OFF) {
154518f7ba4cSKristen Carlson Accardi 			/* set LED to ON for idle */
154687943acfSDavid Milburn 			port_led_state &= EM_MSG_LED_VALUE_OFF;
154718f7ba4cSKristen Carlson Accardi 			port_led_state |= (ap->port_no | (link->pmp << 8));
154887943acfSDavid Milburn 			port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
154918f7ba4cSKristen Carlson Accardi 			ahci_transmit_led_message(ap, port_led_state, 4);
155018f7ba4cSKristen Carlson Accardi 		}
155118f7ba4cSKristen Carlson Accardi 	}
155218f7ba4cSKristen Carlson Accardi 	emp->blink_policy = val;
155318f7ba4cSKristen Carlson Accardi 	return 0;
155418f7ba4cSKristen Carlson Accardi }
155518f7ba4cSKristen Carlson Accardi 
155618f7ba4cSKristen Carlson Accardi static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
155718f7ba4cSKristen Carlson Accardi {
155818f7ba4cSKristen Carlson Accardi 	struct ata_link *link = dev->link;
155918f7ba4cSKristen Carlson Accardi 	struct ata_port *ap = link->ap;
156018f7ba4cSKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
156118f7ba4cSKristen Carlson Accardi 	struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
156218f7ba4cSKristen Carlson Accardi 
156318f7ba4cSKristen Carlson Accardi 	/* display the saved value of activity behavior for this
156418f7ba4cSKristen Carlson Accardi 	 * disk.
156518f7ba4cSKristen Carlson Accardi 	 */
156618f7ba4cSKristen Carlson Accardi 	return sprintf(buf, "%d\n", emp->blink_policy);
156718f7ba4cSKristen Carlson Accardi }
156818f7ba4cSKristen Carlson Accardi 
15692bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
15702bcd866bSJeff Garzik 			   int port_no, void __iomem *mmio,
15712bcd866bSJeff Garzik 			   void __iomem *port_mmio)
1572c6fd2807SJeff Garzik {
1573c6fd2807SJeff Garzik 	const char *emsg = NULL;
15742bcd866bSJeff Garzik 	int rc;
15752bcd866bSJeff Garzik 	u32 tmp;
1576c6fd2807SJeff Garzik 
1577c6fd2807SJeff Garzik 	/* make sure port is not active */
15784447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1579c6fd2807SJeff Garzik 	if (rc)
1580c6fd2807SJeff Garzik 		dev_printk(KERN_WARNING, &pdev->dev,
1581c6fd2807SJeff Garzik 			   "%s (%d)\n", emsg, rc);
1582c6fd2807SJeff Garzik 
1583c6fd2807SJeff Garzik 	/* clear SError */
1584c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SCR_ERR);
1585c6fd2807SJeff Garzik 	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
1586c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_SCR_ERR);
1587c6fd2807SJeff Garzik 
1588c6fd2807SJeff Garzik 	/* clear port IRQ */
1589c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1590c6fd2807SJeff Garzik 	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1591c6fd2807SJeff Garzik 	if (tmp)
1592c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_IRQ_STAT);
1593c6fd2807SJeff Garzik 
15942bcd866bSJeff Garzik 	writel(1 << port_no, mmio + HOST_IRQ_STAT);
15952bcd866bSJeff Garzik }
15962bcd866bSJeff Garzik 
15972bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host)
15982bcd866bSJeff Garzik {
1599417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
16002bcd866bSJeff Garzik 	struct pci_dev *pdev = to_pci_dev(host->dev);
16012bcd866bSJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
16022bcd866bSJeff Garzik 	int i;
1603cd70c266SJeff Garzik 	void __iomem *port_mmio;
16042bcd866bSJeff Garzik 	u32 tmp;
1605c40e7cb8SJose Alberto Reguero 	int mv;
16062bcd866bSJeff Garzik 
1607417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
1608c40e7cb8SJose Alberto Reguero 		if (pdev->device == 0x6121)
1609c40e7cb8SJose Alberto Reguero 			mv = 2;
1610c40e7cb8SJose Alberto Reguero 		else
1611c40e7cb8SJose Alberto Reguero 			mv = 4;
1612c40e7cb8SJose Alberto Reguero 		port_mmio = __ahci_port_base(host, mv);
1613cd70c266SJeff Garzik 
1614cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
1615cd70c266SJeff Garzik 
1616cd70c266SJeff Garzik 		/* clear port IRQ */
1617cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
1618cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1619cd70c266SJeff Garzik 		if (tmp)
1620cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
1621cd70c266SJeff Garzik 	}
1622cd70c266SJeff Garzik 
16232bcd866bSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
16242bcd866bSJeff Garzik 		struct ata_port *ap = host->ports[i];
16252bcd866bSJeff Garzik 
1626cd70c266SJeff Garzik 		port_mmio = ahci_port_base(ap);
16272bcd866bSJeff Garzik 		if (ata_port_is_dummy(ap))
16282bcd866bSJeff Garzik 			continue;
16292bcd866bSJeff Garzik 
16302bcd866bSJeff Garzik 		ahci_port_init(pdev, ap, i, mmio, port_mmio);
1631c6fd2807SJeff Garzik 	}
1632c6fd2807SJeff Garzik 
1633c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1634c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1635c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
1636c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1637c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1638c6fd2807SJeff Garzik }
1639c6fd2807SJeff Garzik 
1640a878539eSJeff Garzik static void ahci_dev_config(struct ata_device *dev)
1641a878539eSJeff Garzik {
1642a878539eSJeff Garzik 	struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
1643a878539eSJeff Garzik 
16444cde32fcSJeff Garzik 	if (hpriv->flags & AHCI_HFLAG_SECT255) {
1645a878539eSJeff Garzik 		dev->max_sectors = 255;
16464cde32fcSJeff Garzik 		ata_dev_printk(dev, KERN_INFO,
16474cde32fcSJeff Garzik 			       "SB600 AHCI: limiting to 255 sectors per cmd\n");
16484cde32fcSJeff Garzik 	}
1649a878539eSJeff Garzik }
1650a878539eSJeff Garzik 
1651c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
1652c6fd2807SJeff Garzik {
16534447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1654c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1655c6fd2807SJeff Garzik 	u32 tmp;
1656c6fd2807SJeff Garzik 
1657c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
1658c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
1659c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
1660c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
1661c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
1662c6fd2807SJeff Garzik 
1663c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
1664c6fd2807SJeff Garzik }
1665c6fd2807SJeff Garzik 
1666c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
1667c6fd2807SJeff Garzik 			       u32 opts)
1668c6fd2807SJeff Garzik {
1669c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
1670c6fd2807SJeff Garzik 
1671c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
1672c6fd2807SJeff Garzik 
1673c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
1674c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
1675c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
1676c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
1677c6fd2807SJeff Garzik }
1678c6fd2807SJeff Garzik 
167978d5ae39SShane Huang static int ahci_kick_engine(struct ata_port *ap)
1680c6fd2807SJeff Garzik {
1681350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1682cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1683520d06f9STejun Heo 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1684c6fd2807SJeff Garzik 	u32 tmp;
1685d2e75dffSTejun Heo 	int busy, rc;
1686c6fd2807SJeff Garzik 
1687d2e75dffSTejun Heo 	/* stop engine */
1688d2e75dffSTejun Heo 	rc = ahci_stop_engine(ap);
1689d2e75dffSTejun Heo 	if (rc)
1690d2e75dffSTejun Heo 		goto out_restart;
1691d2e75dffSTejun Heo 
169278d5ae39SShane Huang 	/* need to do CLO?
169378d5ae39SShane Huang 	 * always do CLO if PMP is attached (AHCI-1.3 9.2)
169478d5ae39SShane Huang 	 */
169578d5ae39SShane Huang 	busy = status & (ATA_BUSY | ATA_DRQ);
169678d5ae39SShane Huang 	if (!busy && !sata_pmp_attached(ap)) {
1697d2e75dffSTejun Heo 		rc = 0;
1698d2e75dffSTejun Heo 		goto out_restart;
1699d2e75dffSTejun Heo 	}
1700d2e75dffSTejun Heo 
1701d2e75dffSTejun Heo 	if (!(hpriv->cap & HOST_CAP_CLO)) {
1702d2e75dffSTejun Heo 		rc = -EOPNOTSUPP;
1703d2e75dffSTejun Heo 		goto out_restart;
1704d2e75dffSTejun Heo 	}
1705d2e75dffSTejun Heo 
1706d2e75dffSTejun Heo 	/* perform CLO */
1707c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1708c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
1709c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1710c6fd2807SJeff Garzik 
1711d2e75dffSTejun Heo 	rc = 0;
1712c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1713c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
1714c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
1715d2e75dffSTejun Heo 		rc = -EIO;
1716c6fd2807SJeff Garzik 
1717d2e75dffSTejun Heo 	/* restart engine */
1718d2e75dffSTejun Heo  out_restart:
1719d2e75dffSTejun Heo 	ahci_start_engine(ap);
1720d2e75dffSTejun Heo 	return rc;
1721c6fd2807SJeff Garzik }
1722c6fd2807SJeff Garzik 
172391c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
172491c4a2e0STejun Heo 				struct ata_taskfile *tf, int is_cmd, u16 flags,
172591c4a2e0STejun Heo 				unsigned long timeout_msec)
172691c4a2e0STejun Heo {
172791c4a2e0STejun Heo 	const u32 cmd_fis_len = 5; /* five dwords */
172891c4a2e0STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
172991c4a2e0STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
173091c4a2e0STejun Heo 	u8 *fis = pp->cmd_tbl;
173191c4a2e0STejun Heo 	u32 tmp;
173291c4a2e0STejun Heo 
173391c4a2e0STejun Heo 	/* prep the command */
173491c4a2e0STejun Heo 	ata_tf_to_fis(tf, pmp, is_cmd, fis);
173591c4a2e0STejun Heo 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
173691c4a2e0STejun Heo 
173791c4a2e0STejun Heo 	/* issue & wait */
173891c4a2e0STejun Heo 	writel(1, port_mmio + PORT_CMD_ISSUE);
173991c4a2e0STejun Heo 
174091c4a2e0STejun Heo 	if (timeout_msec) {
174191c4a2e0STejun Heo 		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
174291c4a2e0STejun Heo 					1, timeout_msec);
174391c4a2e0STejun Heo 		if (tmp & 0x1) {
174478d5ae39SShane Huang 			ahci_kick_engine(ap);
174591c4a2e0STejun Heo 			return -EBUSY;
174691c4a2e0STejun Heo 		}
174791c4a2e0STejun Heo 	} else
174891c4a2e0STejun Heo 		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
174991c4a2e0STejun Heo 
175091c4a2e0STejun Heo 	return 0;
175191c4a2e0STejun Heo }
175291c4a2e0STejun Heo 
1753bd17243aSShane Huang static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1754bd17243aSShane Huang 			     int pmp, unsigned long deadline,
1755bd17243aSShane Huang 			     int (*check_ready)(struct ata_link *link))
1756c6fd2807SJeff Garzik {
1757cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
17585594639aSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1759c6fd2807SJeff Garzik 	const char *reason = NULL;
17602cbb79ebSTejun Heo 	unsigned long now, msecs;
1761c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1762c6fd2807SJeff Garzik 	int rc;
1763c6fd2807SJeff Garzik 
1764c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1765c6fd2807SJeff Garzik 
1766c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
176778d5ae39SShane Huang 	rc = ahci_kick_engine(ap);
1768994056d7STejun Heo 	if (rc && rc != -EOPNOTSUPP)
1769cc0680a5STejun Heo 		ata_link_printk(link, KERN_WARNING,
1770994056d7STejun Heo 				"failed to reset engine (errno=%d)\n", rc);
1771c6fd2807SJeff Garzik 
1772cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1773c6fd2807SJeff Garzik 
1774c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
17752cbb79ebSTejun Heo 	msecs = 0;
17762cbb79ebSTejun Heo 	now = jiffies;
17772cbb79ebSTejun Heo 	if (time_after(now, deadline))
17782cbb79ebSTejun Heo 		msecs = jiffies_to_msecs(deadline - now);
17792cbb79ebSTejun Heo 
1780c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
1781a9cf5e85STejun Heo 	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
178291c4a2e0STejun Heo 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
1783c6fd2807SJeff Garzik 		rc = -EIO;
1784c6fd2807SJeff Garzik 		reason = "1st FIS failed";
1785c6fd2807SJeff Garzik 		goto fail;
1786c6fd2807SJeff Garzik 	}
1787c6fd2807SJeff Garzik 
1788c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
1789c6fd2807SJeff Garzik 	msleep(1);
1790c6fd2807SJeff Garzik 
1791c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
1792c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
1793a9cf5e85STejun Heo 	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1794c6fd2807SJeff Garzik 
1795705e76beSTejun Heo 	/* wait for link to become ready */
1796bd17243aSShane Huang 	rc = ata_wait_after_reset(link, deadline, check_ready);
17975594639aSTejun Heo 	if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) {
17985594639aSTejun Heo 		/*
17995594639aSTejun Heo 		 * Workaround for cases where link online status can't
18005594639aSTejun Heo 		 * be trusted.  Treat device readiness timeout as link
18015594639aSTejun Heo 		 * offline.
18025594639aSTejun Heo 		 */
18035594639aSTejun Heo 		ata_link_printk(link, KERN_INFO,
18045594639aSTejun Heo 				"device not ready, treating as offline\n");
18055594639aSTejun Heo 		*class = ATA_DEV_NONE;
18065594639aSTejun Heo 	} else if (rc) {
18079b89391cSTejun Heo 		/* link occupied, -ENODEV too is an error */
1808c6fd2807SJeff Garzik 		reason = "device not ready";
1809c6fd2807SJeff Garzik 		goto fail;
18105594639aSTejun Heo 	} else
1811c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
1812c6fd2807SJeff Garzik 
1813c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
1814c6fd2807SJeff Garzik 	return 0;
1815c6fd2807SJeff Garzik 
1816c6fd2807SJeff Garzik  fail:
1817cc0680a5STejun Heo 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
1818c6fd2807SJeff Garzik 	return rc;
1819c6fd2807SJeff Garzik }
1820c6fd2807SJeff Garzik 
1821bd17243aSShane Huang static int ahci_check_ready(struct ata_link *link)
1822bd17243aSShane Huang {
1823bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1824bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1825bd17243aSShane Huang 
1826bd17243aSShane Huang 	return ata_check_ready(status);
1827bd17243aSShane Huang }
1828bd17243aSShane Huang 
1829bd17243aSShane Huang static int ahci_softreset(struct ata_link *link, unsigned int *class,
1830bd17243aSShane Huang 			  unsigned long deadline)
1831bd17243aSShane Huang {
1832bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1833bd17243aSShane Huang 
1834bd17243aSShane Huang 	DPRINTK("ENTER\n");
1835bd17243aSShane Huang 
1836bd17243aSShane Huang 	return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
1837bd17243aSShane Huang }
1838bd17243aSShane Huang 
1839bd17243aSShane Huang static int ahci_sb600_check_ready(struct ata_link *link)
1840bd17243aSShane Huang {
1841bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(link->ap);
1842bd17243aSShane Huang 	u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1843bd17243aSShane Huang 	u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
1844bd17243aSShane Huang 
1845bd17243aSShane Huang 	/*
1846bd17243aSShane Huang 	 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
1847bd17243aSShane Huang 	 * which can save timeout delay.
1848bd17243aSShane Huang 	 */
1849bd17243aSShane Huang 	if (irq_status & PORT_IRQ_BAD_PMP)
1850bd17243aSShane Huang 		return -EIO;
1851bd17243aSShane Huang 
1852bd17243aSShane Huang 	return ata_check_ready(status);
1853bd17243aSShane Huang }
1854bd17243aSShane Huang 
1855bd17243aSShane Huang static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
1856bd17243aSShane Huang 				unsigned long deadline)
1857bd17243aSShane Huang {
1858bd17243aSShane Huang 	struct ata_port *ap = link->ap;
1859bd17243aSShane Huang 	void __iomem *port_mmio = ahci_port_base(ap);
1860bd17243aSShane Huang 	int pmp = sata_srst_pmp(link);
1861bd17243aSShane Huang 	int rc;
1862bd17243aSShane Huang 	u32 irq_sts;
1863bd17243aSShane Huang 
1864bd17243aSShane Huang 	DPRINTK("ENTER\n");
1865bd17243aSShane Huang 
1866bd17243aSShane Huang 	rc = ahci_do_softreset(link, class, pmp, deadline,
1867bd17243aSShane Huang 			       ahci_sb600_check_ready);
1868bd17243aSShane Huang 
1869bd17243aSShane Huang 	/*
1870bd17243aSShane Huang 	 * Soft reset fails on some ATI chips with IPMS set when PMP
1871bd17243aSShane Huang 	 * is enabled but SATA HDD/ODD is connected to SATA port,
1872bd17243aSShane Huang 	 * do soft reset again to port 0.
1873bd17243aSShane Huang 	 */
1874bd17243aSShane Huang 	if (rc == -EIO) {
1875bd17243aSShane Huang 		irq_sts = readl(port_mmio + PORT_IRQ_STAT);
1876bd17243aSShane Huang 		if (irq_sts & PORT_IRQ_BAD_PMP) {
1877bd17243aSShane Huang 			ata_link_printk(link, KERN_WARNING,
1878b6931c1fSShane Huang 					"applying SB600 PMP SRST workaround "
1879b6931c1fSShane Huang 					"and retrying\n");
1880bd17243aSShane Huang 			rc = ahci_do_softreset(link, class, 0, deadline,
1881bd17243aSShane Huang 					       ahci_check_ready);
1882bd17243aSShane Huang 		}
1883bd17243aSShane Huang 	}
1884bd17243aSShane Huang 
1885bd17243aSShane Huang 	return rc;
1886bd17243aSShane Huang }
1887bd17243aSShane Huang 
1888cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1889d4b2bab4STejun Heo 			  unsigned long deadline)
1890c6fd2807SJeff Garzik {
18919dadd45bSTejun Heo 	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
1892cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1893c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1894c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1895c6fd2807SJeff Garzik 	struct ata_taskfile tf;
18969dadd45bSTejun Heo 	bool online;
1897c6fd2807SJeff Garzik 	int rc;
1898c6fd2807SJeff Garzik 
1899c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1900c6fd2807SJeff Garzik 
19014447d351STejun Heo 	ahci_stop_engine(ap);
1902c6fd2807SJeff Garzik 
1903c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1904cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1905dfd7a3dbSTejun Heo 	tf.command = 0x80;
19069977126cSTejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1907c6fd2807SJeff Garzik 
19089dadd45bSTejun Heo 	rc = sata_link_hardreset(link, timing, deadline, &online,
19099dadd45bSTejun Heo 				 ahci_check_ready);
1910c6fd2807SJeff Garzik 
19114447d351STejun Heo 	ahci_start_engine(ap);
1912c6fd2807SJeff Garzik 
19139dadd45bSTejun Heo 	if (online)
19149dadd45bSTejun Heo 		*class = ahci_dev_classify(ap);
1915c6fd2807SJeff Garzik 
1916c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1917c6fd2807SJeff Garzik 	return rc;
1918c6fd2807SJeff Garzik }
1919c6fd2807SJeff Garzik 
1920cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1921d4b2bab4STejun Heo 				 unsigned long deadline)
1922ad616ffbSTejun Heo {
1923cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
19249dadd45bSTejun Heo 	bool online;
1925ad616ffbSTejun Heo 	int rc;
1926ad616ffbSTejun Heo 
1927ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1928ad616ffbSTejun Heo 
19294447d351STejun Heo 	ahci_stop_engine(ap);
1930ad616ffbSTejun Heo 
1931cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
19329dadd45bSTejun Heo 				 deadline, &online, NULL);
1933ad616ffbSTejun Heo 
19344447d351STejun Heo 	ahci_start_engine(ap);
1935ad616ffbSTejun Heo 
1936ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1937ad616ffbSTejun Heo 
1938ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1939ad616ffbSTejun Heo 	 * request follow-up softreset.
1940ad616ffbSTejun Heo 	 */
19419dadd45bSTejun Heo 	return online ? -EAGAIN : rc;
1942ad616ffbSTejun Heo }
1943ad616ffbSTejun Heo 
1944edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1945edc93052STejun Heo 				unsigned long deadline)
1946edc93052STejun Heo {
1947edc93052STejun Heo 	struct ata_port *ap = link->ap;
1948edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1949edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1950edc93052STejun Heo 	struct ata_taskfile tf;
19519dadd45bSTejun Heo 	bool online;
1952edc93052STejun Heo 	int rc;
1953edc93052STejun Heo 
1954edc93052STejun Heo 	ahci_stop_engine(ap);
1955edc93052STejun Heo 
1956edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
1957edc93052STejun Heo 	ata_tf_init(link->device, &tf);
1958edc93052STejun Heo 	tf.command = 0x80;
1959edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1960edc93052STejun Heo 
1961edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
19629dadd45bSTejun Heo 				 deadline, &online, NULL);
1963edc93052STejun Heo 
1964edc93052STejun Heo 	ahci_start_engine(ap);
1965edc93052STejun Heo 
1966edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
1967edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1968edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
1969edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
1970edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
1971edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1972edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1973edc93052STejun Heo 	 *
1974edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
1975edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
1976edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
1977edc93052STejun Heo 	 * suffice while making probing snappish enough.
1978edc93052STejun Heo 	 */
19799dadd45bSTejun Heo 	if (online) {
19809dadd45bSTejun Heo 		rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
19819dadd45bSTejun Heo 					  ahci_check_ready);
1982edc93052STejun Heo 		if (rc)
198378d5ae39SShane Huang 			ahci_kick_engine(ap);
19849dadd45bSTejun Heo 	}
19859dadd45bSTejun Heo 	return rc;
1986edc93052STejun Heo }
1987edc93052STejun Heo 
1988cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class)
1989c6fd2807SJeff Garzik {
1990cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
19914447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1992c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1993c6fd2807SJeff Garzik 
1994203c75b8STejun Heo 	ata_std_postreset(link, class);
1995c6fd2807SJeff Garzik 
1996c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1997c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1998c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1999c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
2000c6fd2807SJeff Garzik 	else
2001c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
2002c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
2003c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
2004c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
2005c6fd2807SJeff Garzik 	}
2006c6fd2807SJeff Garzik }
2007c6fd2807SJeff Garzik 
2008c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
2009c6fd2807SJeff Garzik {
2010c6fd2807SJeff Garzik 	struct scatterlist *sg;
2011ff2aeb1eSTejun Heo 	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
2012ff2aeb1eSTejun Heo 	unsigned int si;
2013c6fd2807SJeff Garzik 
2014c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2015c6fd2807SJeff Garzik 
2016c6fd2807SJeff Garzik 	/*
2017c6fd2807SJeff Garzik 	 * Next, the S/G list.
2018c6fd2807SJeff Garzik 	 */
2019ff2aeb1eSTejun Heo 	for_each_sg(qc->sg, sg, qc->n_elem, si) {
2020c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
2021c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
2022c6fd2807SJeff Garzik 
2023ff2aeb1eSTejun Heo 		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
2024ff2aeb1eSTejun Heo 		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
2025ff2aeb1eSTejun Heo 		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
2026c6fd2807SJeff Garzik 	}
2027c6fd2807SJeff Garzik 
2028ff2aeb1eSTejun Heo 	return si;
2029c6fd2807SJeff Garzik }
2030c6fd2807SJeff Garzik 
2031c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
2032c6fd2807SJeff Garzik {
2033c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
2034c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
2035405e66b3STejun Heo 	int is_atapi = ata_is_atapi(qc->tf.protocol);
2036c6fd2807SJeff Garzik 	void *cmd_tbl;
2037c6fd2807SJeff Garzik 	u32 opts;
2038c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
2039c6fd2807SJeff Garzik 	unsigned int n_elem;
2040c6fd2807SJeff Garzik 
2041c6fd2807SJeff Garzik 	/*
2042c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
2043c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
2044c6fd2807SJeff Garzik 	 */
2045c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
2046c6fd2807SJeff Garzik 
20477d50b60bSTejun Heo 	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
2048c6fd2807SJeff Garzik 	if (is_atapi) {
2049c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
2050c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
2051c6fd2807SJeff Garzik 	}
2052c6fd2807SJeff Garzik 
2053c6fd2807SJeff Garzik 	n_elem = 0;
2054c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
2055c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
2056c6fd2807SJeff Garzik 
2057c6fd2807SJeff Garzik 	/*
2058c6fd2807SJeff Garzik 	 * Fill in command slot information.
2059c6fd2807SJeff Garzik 	 */
20607d50b60bSTejun Heo 	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
2061c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
2062c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
2063c6fd2807SJeff Garzik 	if (is_atapi)
2064c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
2065c6fd2807SJeff Garzik 
2066c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
2067c6fd2807SJeff Garzik }
2068c6fd2807SJeff Garzik 
2069c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
2070c6fd2807SJeff Garzik {
2071417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
2072c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
20737d50b60bSTejun Heo 	struct ata_eh_info *host_ehi = &ap->link.eh_info;
20747d50b60bSTejun Heo 	struct ata_link *link = NULL;
20757d50b60bSTejun Heo 	struct ata_queued_cmd *active_qc;
20767d50b60bSTejun Heo 	struct ata_eh_info *active_ehi;
2077c6fd2807SJeff Garzik 	u32 serror;
2078c6fd2807SJeff Garzik 
20797d50b60bSTejun Heo 	/* determine active link */
20801eca4365STejun Heo 	ata_for_each_link(link, ap, EDGE)
20817d50b60bSTejun Heo 		if (ata_link_active(link))
20827d50b60bSTejun Heo 			break;
20837d50b60bSTejun Heo 	if (!link)
20847d50b60bSTejun Heo 		link = &ap->link;
20857d50b60bSTejun Heo 
20867d50b60bSTejun Heo 	active_qc = ata_qc_from_tag(ap, link->active_tag);
20877d50b60bSTejun Heo 	active_ehi = &link->eh_info;
20887d50b60bSTejun Heo 
20897d50b60bSTejun Heo 	/* record irq stat */
20907d50b60bSTejun Heo 	ata_ehi_clear_desc(host_ehi);
20917d50b60bSTejun Heo 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
2092c6fd2807SJeff Garzik 
2093c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
209482ef04fbSTejun Heo 	ahci_scr_read(&ap->link, SCR_ERROR, &serror);
209582ef04fbSTejun Heo 	ahci_scr_write(&ap->link, SCR_ERROR, serror);
20967d50b60bSTejun Heo 	host_ehi->serror |= serror;
2097c6fd2807SJeff Garzik 
209841669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
2099417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
210041669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
210141669553STejun Heo 
210255a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
21037d50b60bSTejun Heo 		/* If qc is active, charge it; otherwise, the active
21047d50b60bSTejun Heo 		 * link.  There's no active qc on NCQ errors.  It will
21057d50b60bSTejun Heo 		 * be determined by EH by reading log page 10h.
21067d50b60bSTejun Heo 		 */
21077d50b60bSTejun Heo 		if (active_qc)
21087d50b60bSTejun Heo 			active_qc->err_mask |= AC_ERR_DEV;
21097d50b60bSTejun Heo 		else
21107d50b60bSTejun Heo 			active_ehi->err_mask |= AC_ERR_DEV;
21117d50b60bSTejun Heo 
2112417a1a6dSTejun Heo 		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
21137d50b60bSTejun Heo 			host_ehi->serror &= ~SERR_INTERNAL;
2114c6fd2807SJeff Garzik 	}
2115c6fd2807SJeff Garzik 
2116c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
2117c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
2118c6fd2807SJeff Garzik 
21197d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
2120cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
21217d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi,
21227d50b60bSTejun Heo 				  "unknown FIS %08x %08x %08x %08x" ,
2123c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
2124c6fd2807SJeff Garzik 	}
2125c6fd2807SJeff Garzik 
2126071f44b1STejun Heo 	if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
21277d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
2128cf480626STejun Heo 		active_ehi->action |= ATA_EH_RESET;
21297d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi, "incorrect PMP");
21307d50b60bSTejun Heo 	}
2131c6fd2807SJeff Garzik 
21327d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
21337d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_HOST_BUS;
2134cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
21357d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "host bus error");
21367d50b60bSTejun Heo 	}
21377d50b60bSTejun Heo 
21387d50b60bSTejun Heo 	if (irq_stat & PORT_IRQ_IF_ERR) {
21397d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_ATA_BUS;
2140cf480626STejun Heo 		host_ehi->action |= ATA_EH_RESET;
21417d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "interface fatal error");
21427d50b60bSTejun Heo 	}
21437d50b60bSTejun Heo 
21447d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
21457d50b60bSTejun Heo 		ata_ehi_hotplugged(host_ehi);
21467d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "%s",
21477d50b60bSTejun Heo 			irq_stat & PORT_IRQ_CONNECT ?
21487d50b60bSTejun Heo 			"connection status changed" : "PHY RDY changed");
21497d50b60bSTejun Heo 	}
21507d50b60bSTejun Heo 
21517d50b60bSTejun Heo 	/* okay, let's hand over to EH */
2152c6fd2807SJeff Garzik 
2153c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
2154c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2155c6fd2807SJeff Garzik 	else
2156c6fd2807SJeff Garzik 		ata_port_abort(ap);
2157c6fd2807SJeff Garzik }
2158c6fd2807SJeff Garzik 
2159df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap)
2160c6fd2807SJeff Garzik {
2161350756f6STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
21629af5c9c9STejun Heo 	struct ata_eh_info *ehi = &ap->link.eh_info;
21630291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
21645f226c6bSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
2165b06ce3e5STejun Heo 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
2166c6fd2807SJeff Garzik 	u32 status, qc_active;
2167459ad688STejun Heo 	int rc;
2168c6fd2807SJeff Garzik 
2169c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
2170c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
2171c6fd2807SJeff Garzik 
2172b06ce3e5STejun Heo 	/* ignore BAD_PMP while resetting */
2173b06ce3e5STejun Heo 	if (unlikely(resetting))
2174b06ce3e5STejun Heo 		status &= ~PORT_IRQ_BAD_PMP;
2175b06ce3e5STejun Heo 
217631556594SKristen Carlson Accardi 	/* If we are getting PhyRdy, this is
217731556594SKristen Carlson Accardi  	 * just a power state change, we should
217831556594SKristen Carlson Accardi  	 * clear out this, plus the PhyRdy/Comm
217931556594SKristen Carlson Accardi  	 * Wake bits from Serror
218031556594SKristen Carlson Accardi  	 */
218131556594SKristen Carlson Accardi 	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
218231556594SKristen Carlson Accardi 		(status & PORT_IRQ_PHYRDY)) {
218331556594SKristen Carlson Accardi 		status &= ~PORT_IRQ_PHYRDY;
218482ef04fbSTejun Heo 		ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
218531556594SKristen Carlson Accardi 	}
218631556594SKristen Carlson Accardi 
2187c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
2188c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
2189c6fd2807SJeff Garzik 		return;
2190c6fd2807SJeff Garzik 	}
2191c6fd2807SJeff Garzik 
21922f294968SKristen Carlson Accardi 	if (status & PORT_IRQ_SDB_FIS) {
21935f226c6bSTejun Heo 		/* If SNotification is available, leave notification
21945f226c6bSTejun Heo 		 * handling to sata_async_notification().  If not,
21955f226c6bSTejun Heo 		 * emulate it by snooping SDB FIS RX area.
21965f226c6bSTejun Heo 		 *
21975f226c6bSTejun Heo 		 * Snooping FIS RX area is probably cheaper than
21985f226c6bSTejun Heo 		 * poking SNotification but some constrollers which
21995f226c6bSTejun Heo 		 * implement SNotification, ICH9 for example, don't
22005f226c6bSTejun Heo 		 * store AN SDB FIS into receive area.
22015f226c6bSTejun Heo 		 */
22025f226c6bSTejun Heo 		if (hpriv->cap & HOST_CAP_SNTF)
22035f226c6bSTejun Heo 			sata_async_notification(ap);
22045f226c6bSTejun Heo 		else {
22055f226c6bSTejun Heo 			/* If the 'N' bit in word 0 of the FIS is set,
22065f226c6bSTejun Heo 			 * we just received asynchronous notification.
22075f226c6bSTejun Heo 			 * Tell libata about it.
22082f294968SKristen Carlson Accardi 			 */
22092f294968SKristen Carlson Accardi 			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
22102f294968SKristen Carlson Accardi 			u32 f0 = le32_to_cpu(f[0]);
22112f294968SKristen Carlson Accardi 
22127d77b247STejun Heo 			if (f0 & (1 << 15))
22137d77b247STejun Heo 				sata_async_notification(ap);
22142f294968SKristen Carlson Accardi 		}
22155f226c6bSTejun Heo 	}
22162f294968SKristen Carlson Accardi 
22177d50b60bSTejun Heo 	/* pp->active_link is valid iff any command is in flight */
22187d50b60bSTejun Heo 	if (ap->qc_active && pp->active_link->sactive)
2219c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
2220c6fd2807SJeff Garzik 	else
2221c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
2222c6fd2807SJeff Garzik 
222379f97dadSTejun Heo 	rc = ata_qc_complete_multiple(ap, qc_active);
2224b06ce3e5STejun Heo 
2225459ad688STejun Heo 	/* while resetting, invalid completions are expected */
2226459ad688STejun Heo 	if (unlikely(rc < 0 && !resetting)) {
2227c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
2228cf480626STejun Heo 		ehi->action |= ATA_EH_RESET;
2229c6fd2807SJeff Garzik 		ata_port_freeze(ap);
2230c6fd2807SJeff Garzik 	}
2231c6fd2807SJeff Garzik }
2232c6fd2807SJeff Garzik 
22337d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
2234c6fd2807SJeff Garzik {
2235cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
2236c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
2237c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
2238c6fd2807SJeff Garzik 	void __iomem *mmio;
2239d28f87aaSTejun Heo 	u32 irq_stat, irq_masked;
2240c6fd2807SJeff Garzik 
2241c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2242c6fd2807SJeff Garzik 
2243cca3974eSJeff Garzik 	hpriv = host->private_data;
22440d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
2245c6fd2807SJeff Garzik 
2246c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
2247c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
2248c6fd2807SJeff Garzik 	if (!irq_stat)
2249c6fd2807SJeff Garzik 		return IRQ_NONE;
2250c6fd2807SJeff Garzik 
2251d28f87aaSTejun Heo 	irq_masked = irq_stat & hpriv->port_map;
2252d28f87aaSTejun Heo 
2253cca3974eSJeff Garzik 	spin_lock(&host->lock);
2254c6fd2807SJeff Garzik 
2255cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
2256c6fd2807SJeff Garzik 		struct ata_port *ap;
2257c6fd2807SJeff Garzik 
2258d28f87aaSTejun Heo 		if (!(irq_masked & (1 << i)))
2259c6fd2807SJeff Garzik 			continue;
2260c6fd2807SJeff Garzik 
2261cca3974eSJeff Garzik 		ap = host->ports[i];
2262c6fd2807SJeff Garzik 		if (ap) {
2263df69c9c5SJeff Garzik 			ahci_port_intr(ap);
2264c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
2265c6fd2807SJeff Garzik 		} else {
2266c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
2267c6fd2807SJeff Garzik 			if (ata_ratelimit())
2268cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
2269c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
2270c6fd2807SJeff Garzik 		}
2271c6fd2807SJeff Garzik 
2272c6fd2807SJeff Garzik 		handled = 1;
2273c6fd2807SJeff Garzik 	}
2274c6fd2807SJeff Garzik 
2275d28f87aaSTejun Heo 	/* HOST_IRQ_STAT behaves as level triggered latch meaning that
2276d28f87aaSTejun Heo 	 * it should be cleared after all the port events are cleared;
2277d28f87aaSTejun Heo 	 * otherwise, it will raise a spurious interrupt after each
2278d28f87aaSTejun Heo 	 * valid one.  Please read section 10.6.2 of ahci 1.1 for more
2279d28f87aaSTejun Heo 	 * information.
2280d28f87aaSTejun Heo 	 *
2281d28f87aaSTejun Heo 	 * Also, use the unmasked value to clear interrupt as spurious
2282d28f87aaSTejun Heo 	 * pending event on a dummy port might cause screaming IRQ.
2283d28f87aaSTejun Heo 	 */
2284ea0c62f7STejun Heo 	writel(irq_stat, mmio + HOST_IRQ_STAT);
2285ea0c62f7STejun Heo 
2286cca3974eSJeff Garzik 	spin_unlock(&host->lock);
2287c6fd2807SJeff Garzik 
2288c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
2289c6fd2807SJeff Garzik 
2290c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
2291c6fd2807SJeff Garzik }
2292c6fd2807SJeff Garzik 
2293c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
2294c6fd2807SJeff Garzik {
2295c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
22964447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
22977d50b60bSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
22987d50b60bSTejun Heo 
22997d50b60bSTejun Heo 	/* Keep track of the currently active link.  It will be used
23007d50b60bSTejun Heo 	 * in completion path to determine whether NCQ phase is in
23017d50b60bSTejun Heo 	 * progress.
23027d50b60bSTejun Heo 	 */
23037d50b60bSTejun Heo 	pp->active_link = qc->dev->link;
2304c6fd2807SJeff Garzik 
2305c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
2306c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
2307c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
2308c6fd2807SJeff Garzik 
230918f7ba4cSKristen Carlson Accardi 	ahci_sw_activity(qc->dev->link);
231018f7ba4cSKristen Carlson Accardi 
2311c6fd2807SJeff Garzik 	return 0;
2312c6fd2807SJeff Garzik }
2313c6fd2807SJeff Garzik 
23144c9bf4e7STejun Heo static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
23154c9bf4e7STejun Heo {
23164c9bf4e7STejun Heo 	struct ahci_port_priv *pp = qc->ap->private_data;
23174c9bf4e7STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
23184c9bf4e7STejun Heo 
23194c9bf4e7STejun Heo 	ata_tf_from_fis(d2h_fis, &qc->result_tf);
23204c9bf4e7STejun Heo 	return true;
23214c9bf4e7STejun Heo }
23224c9bf4e7STejun Heo 
2323c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
2324c6fd2807SJeff Garzik {
23254447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2326c6fd2807SJeff Garzik 
2327c6fd2807SJeff Garzik 	/* turn IRQ off */
2328c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
2329c6fd2807SJeff Garzik }
2330c6fd2807SJeff Garzik 
2331c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
2332c6fd2807SJeff Garzik {
23330d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
23344447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
2335c6fd2807SJeff Garzik 	u32 tmp;
2336a7384925SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
2337c6fd2807SJeff Garzik 
2338c6fd2807SJeff Garzik 	/* clear IRQ */
2339c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
2340c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
2341a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
2342c6fd2807SJeff Garzik 
23431c954a4dSTejun Heo 	/* turn IRQ back on */
23441c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
2345c6fd2807SJeff Garzik }
2346c6fd2807SJeff Garzik 
2347c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
2348c6fd2807SJeff Garzik {
2349c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
2350c6fd2807SJeff Garzik 		/* restart engine */
23514447d351STejun Heo 		ahci_stop_engine(ap);
23524447d351STejun Heo 		ahci_start_engine(ap);
2353c6fd2807SJeff Garzik 	}
2354c6fd2807SJeff Garzik 
2355a1efdabaSTejun Heo 	sata_pmp_error_handler(ap);
2356edc93052STejun Heo }
2357edc93052STejun Heo 
2358c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
2359c6fd2807SJeff Garzik {
2360c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
2361c6fd2807SJeff Garzik 
2362c6fd2807SJeff Garzik 	/* make DMA engine forget about the failed command */
2363d2e75dffSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED)
236478d5ae39SShane Huang 		ahci_kick_engine(ap);
2365c6fd2807SJeff Garzik }
2366c6fd2807SJeff Garzik 
23677d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap)
23687d50b60bSTejun Heo {
23697d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
23701c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
23717d50b60bSTejun Heo 	u32 cmd;
23727d50b60bSTejun Heo 
23737d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
23747d50b60bSTejun Heo 	cmd |= PORT_CMD_PMP;
23757d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
23761c954a4dSTejun Heo 
23771c954a4dSTejun Heo 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
23781c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
23797d50b60bSTejun Heo }
23807d50b60bSTejun Heo 
23817d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap)
23827d50b60bSTejun Heo {
23837d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
23841c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
23857d50b60bSTejun Heo 	u32 cmd;
23867d50b60bSTejun Heo 
23877d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
23887d50b60bSTejun Heo 	cmd &= ~PORT_CMD_PMP;
23897d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
23901c954a4dSTejun Heo 
23911c954a4dSTejun Heo 	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
23921c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
23937d50b60bSTejun Heo }
23947d50b60bSTejun Heo 
2395028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap)
2396028a2596SAlexey Dobriyan {
2397028a2596SAlexey Dobriyan 	ahci_power_up(ap);
2398028a2596SAlexey Dobriyan 	ahci_start_port(ap);
2399028a2596SAlexey Dobriyan 
2400071f44b1STejun Heo 	if (sata_pmp_attached(ap))
24017d50b60bSTejun Heo 		ahci_pmp_attach(ap);
24027d50b60bSTejun Heo 	else
24037d50b60bSTejun Heo 		ahci_pmp_detach(ap);
24047d50b60bSTejun Heo 
2405028a2596SAlexey Dobriyan 	return 0;
2406028a2596SAlexey Dobriyan }
2407028a2596SAlexey Dobriyan 
2408438ac6d5STejun Heo #ifdef CONFIG_PM
2409c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
2410c6fd2807SJeff Garzik {
2411c6fd2807SJeff Garzik 	const char *emsg = NULL;
2412c6fd2807SJeff Garzik 	int rc;
2413c6fd2807SJeff Garzik 
24144447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
24158e16f941STejun Heo 	if (rc == 0)
24164447d351STejun Heo 		ahci_power_down(ap);
24178e16f941STejun Heo 	else {
2418c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
2419df69c9c5SJeff Garzik 		ahci_start_port(ap);
2420c6fd2807SJeff Garzik 	}
2421c6fd2807SJeff Garzik 
2422c6fd2807SJeff Garzik 	return rc;
2423c6fd2807SJeff Garzik }
2424c6fd2807SJeff Garzik 
2425c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
2426c6fd2807SJeff Garzik {
2427cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
24289b10ae86STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
24290d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
2430c6fd2807SJeff Garzik 	u32 ctl;
2431c6fd2807SJeff Garzik 
24329b10ae86STejun Heo 	if (mesg.event & PM_EVENT_SUSPEND &&
24339b10ae86STejun Heo 	    hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
24349b10ae86STejun Heo 		dev_printk(KERN_ERR, &pdev->dev,
24359b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
24369b10ae86STejun Heo 		return -EIO;
24379b10ae86STejun Heo 	}
24389b10ae86STejun Heo 
24393a2d5b70SRafael J. Wysocki 	if (mesg.event & PM_EVENT_SLEEP) {
2440c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
2441c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
2442c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
2443c6fd2807SJeff Garzik 		 */
2444c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
2445c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
2446c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
2447c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
2448c6fd2807SJeff Garzik 	}
2449c6fd2807SJeff Garzik 
2450c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
2451c6fd2807SJeff Garzik }
2452c6fd2807SJeff Garzik 
2453c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
2454c6fd2807SJeff Garzik {
2455cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
2456c6fd2807SJeff Garzik 	int rc;
2457c6fd2807SJeff Garzik 
2458553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
2459553c4aa6STejun Heo 	if (rc)
2460553c4aa6STejun Heo 		return rc;
2461c6fd2807SJeff Garzik 
2462c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
24634447d351STejun Heo 		rc = ahci_reset_controller(host);
2464c6fd2807SJeff Garzik 		if (rc)
2465c6fd2807SJeff Garzik 			return rc;
2466c6fd2807SJeff Garzik 
24674447d351STejun Heo 		ahci_init_controller(host);
2468c6fd2807SJeff Garzik 	}
2469c6fd2807SJeff Garzik 
2470cca3974eSJeff Garzik 	ata_host_resume(host);
2471c6fd2807SJeff Garzik 
2472c6fd2807SJeff Garzik 	return 0;
2473c6fd2807SJeff Garzik }
2474438ac6d5STejun Heo #endif
2475c6fd2807SJeff Garzik 
2476c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
2477c6fd2807SJeff Garzik {
2478cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
2479c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
2480c6fd2807SJeff Garzik 	void *mem;
2481c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
2482c6fd2807SJeff Garzik 
248324dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
2484c6fd2807SJeff Garzik 	if (!pp)
2485c6fd2807SJeff Garzik 		return -ENOMEM;
2486c6fd2807SJeff Garzik 
248724dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
248824dc5f33STejun Heo 				  GFP_KERNEL);
248924dc5f33STejun Heo 	if (!mem)
2490c6fd2807SJeff Garzik 		return -ENOMEM;
2491c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
2492c6fd2807SJeff Garzik 
2493c6fd2807SJeff Garzik 	/*
2494c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
2495c6fd2807SJeff Garzik 	 * 32 bytes each in size
2496c6fd2807SJeff Garzik 	 */
2497c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
2498c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
2499c6fd2807SJeff Garzik 
2500c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
2501c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
2502c6fd2807SJeff Garzik 
2503c6fd2807SJeff Garzik 	/*
2504c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
2505c6fd2807SJeff Garzik 	 */
2506c6fd2807SJeff Garzik 	pp->rx_fis = mem;
2507c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
2508c6fd2807SJeff Garzik 
2509c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
2510c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
2511c6fd2807SJeff Garzik 
2512c6fd2807SJeff Garzik 	/*
2513c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
2514c6fd2807SJeff Garzik 	 * and its scatter-gather table
2515c6fd2807SJeff Garzik 	 */
2516c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
2517c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
2518c6fd2807SJeff Garzik 
2519a7384925SKristen Carlson Accardi 	/*
2520a7384925SKristen Carlson Accardi 	 * Save off initial list of interrupts to be enabled.
2521a7384925SKristen Carlson Accardi 	 * This could be changed later
2522a7384925SKristen Carlson Accardi 	 */
2523a7384925SKristen Carlson Accardi 	pp->intr_mask = DEF_PORT_IRQ;
2524a7384925SKristen Carlson Accardi 
2525c6fd2807SJeff Garzik 	ap->private_data = pp;
2526c6fd2807SJeff Garzik 
2527df69c9c5SJeff Garzik 	/* engage engines, captain */
2528df69c9c5SJeff Garzik 	return ahci_port_resume(ap);
2529c6fd2807SJeff Garzik }
2530c6fd2807SJeff Garzik 
2531c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
2532c6fd2807SJeff Garzik {
2533c6fd2807SJeff Garzik 	const char *emsg = NULL;
2534c6fd2807SJeff Garzik 	int rc;
2535c6fd2807SJeff Garzik 
2536c6fd2807SJeff Garzik 	/* de-initialize port */
25374447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
2538c6fd2807SJeff Garzik 	if (rc)
2539c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
2540c6fd2807SJeff Garzik }
2541c6fd2807SJeff Garzik 
25424447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
2543c6fd2807SJeff Garzik {
2544c6fd2807SJeff Garzik 	int rc;
2545c6fd2807SJeff Garzik 
2546c6fd2807SJeff Garzik 	if (using_dac &&
25476a35528aSYang Hongyang 	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
25486a35528aSYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
2549c6fd2807SJeff Garzik 		if (rc) {
2550284901a9SYang Hongyang 			rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
2551c6fd2807SJeff Garzik 			if (rc) {
2552c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
2553c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
2554c6fd2807SJeff Garzik 				return rc;
2555c6fd2807SJeff Garzik 			}
2556c6fd2807SJeff Garzik 		}
2557c6fd2807SJeff Garzik 	} else {
2558284901a9SYang Hongyang 		rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
2559c6fd2807SJeff Garzik 		if (rc) {
2560c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2561c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
2562c6fd2807SJeff Garzik 			return rc;
2563c6fd2807SJeff Garzik 		}
2564284901a9SYang Hongyang 		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
2565c6fd2807SJeff Garzik 		if (rc) {
2566c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
2567c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
2568c6fd2807SJeff Garzik 			return rc;
2569c6fd2807SJeff Garzik 		}
2570c6fd2807SJeff Garzik 	}
2571c6fd2807SJeff Garzik 	return 0;
2572c6fd2807SJeff Garzik }
2573c6fd2807SJeff Garzik 
25744447d351STejun Heo static void ahci_print_info(struct ata_host *host)
2575c6fd2807SJeff Garzik {
25764447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
25774447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
25784447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
25794c521c8eSRobert Hancock 	u32 vers, cap, cap2, impl, speed;
2580c6fd2807SJeff Garzik 	const char *speed_s;
2581c6fd2807SJeff Garzik 	u16 cc;
2582c6fd2807SJeff Garzik 	const char *scc_s;
2583c6fd2807SJeff Garzik 
2584c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
2585c6fd2807SJeff Garzik 	cap = hpriv->cap;
25864c521c8eSRobert Hancock 	cap2 = hpriv->cap2;
2587c6fd2807SJeff Garzik 	impl = hpriv->port_map;
2588c6fd2807SJeff Garzik 
2589c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
2590c6fd2807SJeff Garzik 	if (speed == 1)
2591c6fd2807SJeff Garzik 		speed_s = "1.5";
2592c6fd2807SJeff Garzik 	else if (speed == 2)
2593c6fd2807SJeff Garzik 		speed_s = "3";
25948522ee25SShane Huang 	else if (speed == 3)
25958522ee25SShane Huang 		speed_s = "6";
2596c6fd2807SJeff Garzik 	else
2597c6fd2807SJeff Garzik 		speed_s = "?";
2598c6fd2807SJeff Garzik 
2599c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
2600c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
2601c6fd2807SJeff Garzik 		scc_s = "IDE";
2602c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
2603c6fd2807SJeff Garzik 		scc_s = "SATA";
2604c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
2605c6fd2807SJeff Garzik 		scc_s = "RAID";
2606c6fd2807SJeff Garzik 	else
2607c6fd2807SJeff Garzik 		scc_s = "unknown";
2608c6fd2807SJeff Garzik 
2609c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2610c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
2611c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
2612c6fd2807SJeff Garzik 		,
2613c6fd2807SJeff Garzik 
2614c6fd2807SJeff Garzik 		(vers >> 24) & 0xff,
2615c6fd2807SJeff Garzik 		(vers >> 16) & 0xff,
2616c6fd2807SJeff Garzik 		(vers >> 8) & 0xff,
2617c6fd2807SJeff Garzik 		vers & 0xff,
2618c6fd2807SJeff Garzik 
2619c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
2620c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
2621c6fd2807SJeff Garzik 		speed_s,
2622c6fd2807SJeff Garzik 		impl,
2623c6fd2807SJeff Garzik 		scc_s);
2624c6fd2807SJeff Garzik 
2625c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2626c6fd2807SJeff Garzik 		"flags: "
2627203ef6c4STejun Heo 		"%s%s%s%s%s%s%s"
262818f7ba4cSKristen Carlson Accardi 		"%s%s%s%s%s%s%s"
26294c521c8eSRobert Hancock 		"%s%s%s%s%s%s\n"
2630c6fd2807SJeff Garzik 		,
2631c6fd2807SJeff Garzik 
26324c521c8eSRobert Hancock 		cap & HOST_CAP_64 ? "64bit " : "",
26334c521c8eSRobert Hancock 		cap & HOST_CAP_NCQ ? "ncq " : "",
26344c521c8eSRobert Hancock 		cap & HOST_CAP_SNTF ? "sntf " : "",
26354c521c8eSRobert Hancock 		cap & HOST_CAP_MPS ? "ilck " : "",
26364c521c8eSRobert Hancock 		cap & HOST_CAP_SSS ? "stag " : "",
26374c521c8eSRobert Hancock 		cap & HOST_CAP_ALPM ? "pm " : "",
26384c521c8eSRobert Hancock 		cap & HOST_CAP_LED ? "led " : "",
26394c521c8eSRobert Hancock 		cap & HOST_CAP_CLO ? "clo " : "",
26404c521c8eSRobert Hancock 		cap & HOST_CAP_ONLY ? "only " : "",
26414c521c8eSRobert Hancock 		cap & HOST_CAP_PMP ? "pmp " : "",
26424c521c8eSRobert Hancock 		cap & HOST_CAP_FBS ? "fbs " : "",
26434c521c8eSRobert Hancock 		cap & HOST_CAP_PIO_MULTI ? "pio " : "",
26444c521c8eSRobert Hancock 		cap & HOST_CAP_SSC ? "slum " : "",
26454c521c8eSRobert Hancock 		cap & HOST_CAP_PART ? "part " : "",
26464c521c8eSRobert Hancock 		cap & HOST_CAP_CCC ? "ccc " : "",
26474c521c8eSRobert Hancock 		cap & HOST_CAP_EMS ? "ems " : "",
26484c521c8eSRobert Hancock 		cap & HOST_CAP_SXS ? "sxs " : "",
26494c521c8eSRobert Hancock 		cap2 & HOST_CAP2_APST ? "apst " : "",
26504c521c8eSRobert Hancock 		cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",
26514c521c8eSRobert Hancock 		cap2 & HOST_CAP2_BOH ? "boh " : ""
2652c6fd2807SJeff Garzik 		);
2653c6fd2807SJeff Garzik }
2654c6fd2807SJeff Garzik 
2655edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2656edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
2657edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
2658edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
2659edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
2660edc93052STejun Heo  * other configuration).
2661edc93052STejun Heo  *
2662edc93052STejun Heo  * When there's no device attached to the first downstream port of the
2663edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
2664edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
2665edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
2666edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2667edc93052STejun Heo  *
2668edc93052STejun Heo  * The following function works around the problem by always using
2669edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
2670edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
2671edc93052STejun Heo  * assumed without follow-up softreset.
2672edc93052STejun Heo  */
2673edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
2674edc93052STejun Heo {
2675edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
2676edc93052STejun Heo 		{
2677edc93052STejun Heo 			.ident = "P5W DH Deluxe",
2678edc93052STejun Heo 			.matches = {
2679edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
2680edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
2681edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2682edc93052STejun Heo 			},
2683edc93052STejun Heo 		},
2684edc93052STejun Heo 		{ }
2685edc93052STejun Heo 	};
2686edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
2687edc93052STejun Heo 
2688edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2689edc93052STejun Heo 	    dmi_check_system(sysids)) {
2690edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
2691edc93052STejun Heo 
2692edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2693edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
2694edc93052STejun Heo 
2695edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
2696edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2697edc93052STejun Heo 	}
2698edc93052STejun Heo }
2699edc93052STejun Heo 
27002fcad9d2STejun Heo /* only some SB600 ahci controllers can do 64bit DMA */
27012fcad9d2STejun Heo static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
270258a09b38SShane Huang {
270358a09b38SShane Huang 	static const struct dmi_system_id sysids[] = {
270403d783bfSTejun Heo 		/*
270503d783bfSTejun Heo 		 * The oldest version known to be broken is 0901 and
270603d783bfSTejun Heo 		 * working is 1501 which was released on 2007-10-26.
27072fcad9d2STejun Heo 		 * Enable 64bit DMA on 1501 and anything newer.
27082fcad9d2STejun Heo 		 *
270903d783bfSTejun Heo 		 * Please read bko#9412 for more info.
271003d783bfSTejun Heo 		 */
271158a09b38SShane Huang 		{
271258a09b38SShane Huang 			.ident = "ASUS M2A-VM",
271358a09b38SShane Huang 			.matches = {
271458a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_VENDOR,
271558a09b38SShane Huang 					  "ASUSTeK Computer INC."),
271658a09b38SShane Huang 				DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
271758a09b38SShane Huang 			},
271803d783bfSTejun Heo 			.driver_data = "20071026",	/* yyyymmdd */
271958a09b38SShane Huang 		},
272058a09b38SShane Huang 		{ }
272158a09b38SShane Huang 	};
272203d783bfSTejun Heo 	const struct dmi_system_id *match;
27232fcad9d2STejun Heo 	int year, month, date;
27242fcad9d2STejun Heo 	char buf[9];
272558a09b38SShane Huang 
272603d783bfSTejun Heo 	match = dmi_first_match(sysids);
272758a09b38SShane Huang 	if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
272803d783bfSTejun Heo 	    !match)
272958a09b38SShane Huang 		return false;
273058a09b38SShane Huang 
273103d783bfSTejun Heo 	dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
273203d783bfSTejun Heo 	snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
273303d783bfSTejun Heo 
27342fcad9d2STejun Heo 	if (strcmp(buf, match->driver_data) >= 0) {
27352fcad9d2STejun Heo 		dev_printk(KERN_WARNING, &pdev->dev, "%s: enabling 64bit DMA\n",
27362fcad9d2STejun Heo 			   match->ident);
27372fcad9d2STejun Heo 		return true;
27382fcad9d2STejun Heo 	} else {
273903d783bfSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, "
274003d783bfSTejun Heo 			   "forcing 32bit DMA, update BIOS\n", match->ident);
27412fcad9d2STejun Heo 		return false;
27422fcad9d2STejun Heo 	}
274358a09b38SShane Huang }
274458a09b38SShane Huang 
27451fd68434SRafael J. Wysocki static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
27461fd68434SRafael J. Wysocki {
27471fd68434SRafael J. Wysocki 	static const struct dmi_system_id broken_systems[] = {
27481fd68434SRafael J. Wysocki 		{
27491fd68434SRafael J. Wysocki 			.ident = "HP Compaq nx6310",
27501fd68434SRafael J. Wysocki 			.matches = {
27511fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27521fd68434SRafael J. Wysocki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
27531fd68434SRafael J. Wysocki 			},
27541fd68434SRafael J. Wysocki 			/* PCI slot number of the controller */
27551fd68434SRafael J. Wysocki 			.driver_data = (void *)0x1FUL,
27561fd68434SRafael J. Wysocki 		},
2757d2f9c061SMaciej Rutecki 		{
2758d2f9c061SMaciej Rutecki 			.ident = "HP Compaq 6720s",
2759d2f9c061SMaciej Rutecki 			.matches = {
2760d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
2761d2f9c061SMaciej Rutecki 				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
2762d2f9c061SMaciej Rutecki 			},
2763d2f9c061SMaciej Rutecki 			/* PCI slot number of the controller */
2764d2f9c061SMaciej Rutecki 			.driver_data = (void *)0x1FUL,
2765d2f9c061SMaciej Rutecki 		},
27661fd68434SRafael J. Wysocki 
27671fd68434SRafael J. Wysocki 		{ }	/* terminate list */
27681fd68434SRafael J. Wysocki 	};
27691fd68434SRafael J. Wysocki 	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
27701fd68434SRafael J. Wysocki 
27711fd68434SRafael J. Wysocki 	if (dmi) {
27721fd68434SRafael J. Wysocki 		unsigned long slot = (unsigned long)dmi->driver_data;
27731fd68434SRafael J. Wysocki 		/* apply the quirk only to on-board controllers */
27741fd68434SRafael J. Wysocki 		return slot == PCI_SLOT(pdev->devfn);
27751fd68434SRafael J. Wysocki 	}
27761fd68434SRafael J. Wysocki 
27771fd68434SRafael J. Wysocki 	return false;
27781fd68434SRafael J. Wysocki }
27791fd68434SRafael J. Wysocki 
27809b10ae86STejun Heo static bool ahci_broken_suspend(struct pci_dev *pdev)
27819b10ae86STejun Heo {
27829b10ae86STejun Heo 	static const struct dmi_system_id sysids[] = {
27839b10ae86STejun Heo 		/*
27849b10ae86STejun Heo 		 * On HP dv[4-6] and HDX18 with earlier BIOSen, link
27859b10ae86STejun Heo 		 * to the harddisk doesn't become online after
27869b10ae86STejun Heo 		 * resuming from STR.  Warn and fail suspend.
27879b10ae86STejun Heo 		 */
27889b10ae86STejun Heo 		{
27899b10ae86STejun Heo 			.ident = "dv4",
27909b10ae86STejun Heo 			.matches = {
27919b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
27929b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
27939b10ae86STejun Heo 					  "HP Pavilion dv4 Notebook PC"),
27949b10ae86STejun Heo 			},
27959b10ae86STejun Heo 			.driver_data = "F.30", /* cutoff BIOS version */
27969b10ae86STejun Heo 		},
27979b10ae86STejun Heo 		{
27989b10ae86STejun Heo 			.ident = "dv5",
27999b10ae86STejun Heo 			.matches = {
28009b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
28019b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
28029b10ae86STejun Heo 					  "HP Pavilion dv5 Notebook PC"),
28039b10ae86STejun Heo 			},
28049b10ae86STejun Heo 			.driver_data = "F.16", /* cutoff BIOS version */
28059b10ae86STejun Heo 		},
28069b10ae86STejun Heo 		{
28079b10ae86STejun Heo 			.ident = "dv6",
28089b10ae86STejun Heo 			.matches = {
28099b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
28109b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
28119b10ae86STejun Heo 					  "HP Pavilion dv6 Notebook PC"),
28129b10ae86STejun Heo 			},
28139b10ae86STejun Heo 			.driver_data = "F.21",	/* cutoff BIOS version */
28149b10ae86STejun Heo 		},
28159b10ae86STejun Heo 		{
28169b10ae86STejun Heo 			.ident = "HDX18",
28179b10ae86STejun Heo 			.matches = {
28189b10ae86STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
28199b10ae86STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME,
28209b10ae86STejun Heo 					  "HP HDX18 Notebook PC"),
28219b10ae86STejun Heo 			},
28229b10ae86STejun Heo 			.driver_data = "F.23",	/* cutoff BIOS version */
28239b10ae86STejun Heo 		},
28249b10ae86STejun Heo 		{ }	/* terminate list */
28259b10ae86STejun Heo 	};
28269b10ae86STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
28279b10ae86STejun Heo 	const char *ver;
28289b10ae86STejun Heo 
28299b10ae86STejun Heo 	if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
28309b10ae86STejun Heo 		return false;
28319b10ae86STejun Heo 
28329b10ae86STejun Heo 	ver = dmi_get_system_info(DMI_BIOS_VERSION);
28339b10ae86STejun Heo 
28349b10ae86STejun Heo 	return !ver || strcmp(ver, dmi->driver_data) < 0;
28359b10ae86STejun Heo }
28369b10ae86STejun Heo 
28375594639aSTejun Heo static bool ahci_broken_online(struct pci_dev *pdev)
28385594639aSTejun Heo {
28395594639aSTejun Heo #define ENCODE_BUSDEVFN(bus, slot, func)			\
28405594639aSTejun Heo 	(void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
28415594639aSTejun Heo 	static const struct dmi_system_id sysids[] = {
28425594639aSTejun Heo 		/*
28435594639aSTejun Heo 		 * There are several gigabyte boards which use
28445594639aSTejun Heo 		 * SIMG5723s configured as hardware RAID.  Certain
28455594639aSTejun Heo 		 * 5723 firmware revisions shipped there keep the link
28465594639aSTejun Heo 		 * online but fail to answer properly to SRST or
28475594639aSTejun Heo 		 * IDENTIFY when no device is attached downstream
28485594639aSTejun Heo 		 * causing libata to retry quite a few times leading
28495594639aSTejun Heo 		 * to excessive detection delay.
28505594639aSTejun Heo 		 *
28515594639aSTejun Heo 		 * As these firmwares respond to the second reset try
28525594639aSTejun Heo 		 * with invalid device signature, considering unknown
28535594639aSTejun Heo 		 * sig as offline works around the problem acceptably.
28545594639aSTejun Heo 		 */
28555594639aSTejun Heo 		{
28565594639aSTejun Heo 			.ident = "EP45-DQ6",
28575594639aSTejun Heo 			.matches = {
28585594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
28595594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
28605594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
28615594639aSTejun Heo 			},
28625594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
28635594639aSTejun Heo 		},
28645594639aSTejun Heo 		{
28655594639aSTejun Heo 			.ident = "EP45-DS5",
28665594639aSTejun Heo 			.matches = {
28675594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_VENDOR,
28685594639aSTejun Heo 					  "Gigabyte Technology Co., Ltd."),
28695594639aSTejun Heo 				DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
28705594639aSTejun Heo 			},
28715594639aSTejun Heo 			.driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
28725594639aSTejun Heo 		},
28735594639aSTejun Heo 		{ }	/* terminate list */
28745594639aSTejun Heo 	};
28755594639aSTejun Heo #undef ENCODE_BUSDEVFN
28765594639aSTejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
28775594639aSTejun Heo 	unsigned int val;
28785594639aSTejun Heo 
28795594639aSTejun Heo 	if (!dmi)
28805594639aSTejun Heo 		return false;
28815594639aSTejun Heo 
28825594639aSTejun Heo 	val = (unsigned long)dmi->driver_data;
28835594639aSTejun Heo 
28845594639aSTejun Heo 	return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
28855594639aSTejun Heo }
28865594639aSTejun Heo 
2887*8e513217SMarkus Trippelsdorf #ifdef CONFIG_ATA_ACPI
2888f80ae7e4STejun Heo static void ahci_gtf_filter_workaround(struct ata_host *host)
2889f80ae7e4STejun Heo {
2890f80ae7e4STejun Heo 	static const struct dmi_system_id sysids[] = {
2891f80ae7e4STejun Heo 		/*
2892f80ae7e4STejun Heo 		 * Aspire 3810T issues a bunch of SATA enable commands
2893f80ae7e4STejun Heo 		 * via _GTF including an invalid one and one which is
2894f80ae7e4STejun Heo 		 * rejected by the device.  Among the successful ones
2895f80ae7e4STejun Heo 		 * is FPDMA non-zero offset enable which when enabled
2896f80ae7e4STejun Heo 		 * only on the drive side leads to NCQ command
2897f80ae7e4STejun Heo 		 * failures.  Filter it out.
2898f80ae7e4STejun Heo 		 */
2899f80ae7e4STejun Heo 		{
2900f80ae7e4STejun Heo 			.ident = "Aspire 3810T",
2901f80ae7e4STejun Heo 			.matches = {
2902f80ae7e4STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
2903f80ae7e4STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
2904f80ae7e4STejun Heo 			},
2905f80ae7e4STejun Heo 			.driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
2906f80ae7e4STejun Heo 		},
2907f80ae7e4STejun Heo 		{ }
2908f80ae7e4STejun Heo 	};
2909f80ae7e4STejun Heo 	const struct dmi_system_id *dmi = dmi_first_match(sysids);
2910f80ae7e4STejun Heo 	unsigned int filter;
2911f80ae7e4STejun Heo 	int i;
2912f80ae7e4STejun Heo 
2913f80ae7e4STejun Heo 	if (!dmi)
2914f80ae7e4STejun Heo 		return;
2915f80ae7e4STejun Heo 
2916f80ae7e4STejun Heo 	filter = (unsigned long)dmi->driver_data;
2917f80ae7e4STejun Heo 	dev_printk(KERN_INFO, host->dev,
2918f80ae7e4STejun Heo 		   "applying extra ACPI _GTF filter 0x%x for %s\n",
2919f80ae7e4STejun Heo 		   filter, dmi->ident);
2920f80ae7e4STejun Heo 
2921f80ae7e4STejun Heo 	for (i = 0; i < host->n_ports; i++) {
2922f80ae7e4STejun Heo 		struct ata_port *ap = host->ports[i];
2923f80ae7e4STejun Heo 		struct ata_link *link;
2924f80ae7e4STejun Heo 		struct ata_device *dev;
2925f80ae7e4STejun Heo 
2926f80ae7e4STejun Heo 		ata_for_each_link(link, ap, EDGE)
2927f80ae7e4STejun Heo 			ata_for_each_dev(dev, link, ALL)
2928f80ae7e4STejun Heo 				dev->gtf_filter |= filter;
2929f80ae7e4STejun Heo 	}
2930f80ae7e4STejun Heo }
2931*8e513217SMarkus Trippelsdorf #else
2932*8e513217SMarkus Trippelsdorf static inline void ahci_gtf_filter_workaround(struct ata_host *host)
2933*8e513217SMarkus Trippelsdorf {}
2934*8e513217SMarkus Trippelsdorf #endif
2935f80ae7e4STejun Heo 
2936c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2937c6fd2807SJeff Garzik {
2938c6fd2807SJeff Garzik 	static int printed_version;
2939e297d99eSTejun Heo 	unsigned int board_id = ent->driver_data;
2940e297d99eSTejun Heo 	struct ata_port_info pi = ahci_port_info[board_id];
29414447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
294224dc5f33STejun Heo 	struct device *dev = &pdev->dev;
2943c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
29444447d351STejun Heo 	struct ata_host *host;
2945837f5f8fSTejun Heo 	int n_ports, i, rc;
2946c6fd2807SJeff Garzik 
2947c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2948c6fd2807SJeff Garzik 
2949c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
2950c6fd2807SJeff Garzik 
2951c6fd2807SJeff Garzik 	if (!printed_version++)
2952c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
2953c6fd2807SJeff Garzik 
29545b66c829SAlan Cox 	/* The AHCI driver can only drive the SATA ports, the PATA driver
29555b66c829SAlan Cox 	   can drive them all so if both drivers are selected make sure
29565b66c829SAlan Cox 	   AHCI stays out of the way */
29575b66c829SAlan Cox 	if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
29585b66c829SAlan Cox 		return -ENODEV;
29595b66c829SAlan Cox 
29604447d351STejun Heo 	/* acquire resources */
296124dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
2962c6fd2807SJeff Garzik 	if (rc)
2963c6fd2807SJeff Garzik 		return rc;
2964c6fd2807SJeff Garzik 
2965dea55137STejun Heo 	/* AHCI controllers often implement SFF compatible interface.
2966dea55137STejun Heo 	 * Grab all PCI BARs just in case.
2967dea55137STejun Heo 	 */
2968dea55137STejun Heo 	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
29690d5ff566STejun Heo 	if (rc == -EBUSY)
297024dc5f33STejun Heo 		pcim_pin_device(pdev);
29710d5ff566STejun Heo 	if (rc)
297224dc5f33STejun Heo 		return rc;
2973c6fd2807SJeff Garzik 
2974c4f7792cSTejun Heo 	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
2975c4f7792cSTejun Heo 	    (pdev->device == 0x2652 || pdev->device == 0x2653)) {
2976c4f7792cSTejun Heo 		u8 map;
2977c4f7792cSTejun Heo 
2978c4f7792cSTejun Heo 		/* ICH6s share the same PCI ID for both piix and ahci
2979c4f7792cSTejun Heo 		 * modes.  Enabling ahci mode while MAP indicates
2980c4f7792cSTejun Heo 		 * combined mode is a bad idea.  Yield to ata_piix.
2981c4f7792cSTejun Heo 		 */
2982c4f7792cSTejun Heo 		pci_read_config_byte(pdev, ICH_MAP, &map);
2983c4f7792cSTejun Heo 		if (map & 0x3) {
2984c4f7792cSTejun Heo 			dev_printk(KERN_INFO, &pdev->dev, "controller is in "
2985c4f7792cSTejun Heo 				   "combined mode, can't enable AHCI mode\n");
2986c4f7792cSTejun Heo 			return -ENODEV;
2987c4f7792cSTejun Heo 		}
2988c4f7792cSTejun Heo 	}
2989c4f7792cSTejun Heo 
299024dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
299124dc5f33STejun Heo 	if (!hpriv)
299224dc5f33STejun Heo 		return -ENOMEM;
2993417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
2994417a1a6dSTejun Heo 
2995e297d99eSTejun Heo 	/* MCP65 revision A1 and A2 can't do MSI */
2996e297d99eSTejun Heo 	if (board_id == board_ahci_mcp65 &&
2997e297d99eSTejun Heo 	    (pdev->revision == 0xa1 || pdev->revision == 0xa2))
2998e297d99eSTejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_MSI;
2999e297d99eSTejun Heo 
3000e427fe04SShane Huang 	/* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
3001e427fe04SShane Huang 	if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
3002e427fe04SShane Huang 		hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
3003e427fe04SShane Huang 
30042fcad9d2STejun Heo 	/* only some SB600s can do 64bit DMA */
30052fcad9d2STejun Heo 	if (ahci_sb600_enable_64bit(pdev))
30062fcad9d2STejun Heo 		hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
300758a09b38SShane Huang 
300831b239adSTejun Heo 	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
300931b239adSTejun Heo 		pci_intx(pdev, 1);
3010c6fd2807SJeff Garzik 
30114447d351STejun Heo 	/* save initial config */
3012417a1a6dSTejun Heo 	ahci_save_initial_config(pdev, hpriv);
3013c6fd2807SJeff Garzik 
30144447d351STejun Heo 	/* prepare host */
3015274c1fdeSTejun Heo 	if (hpriv->cap & HOST_CAP_NCQ)
3016388539f3SShaohua Li 		pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA;
30174447d351STejun Heo 
30187d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
30197d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
30207d50b60bSTejun Heo 
302118f7ba4cSKristen Carlson Accardi 	if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) {
302218f7ba4cSKristen Carlson Accardi 		u8 messages;
302318f7ba4cSKristen Carlson Accardi 		void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
302418f7ba4cSKristen Carlson Accardi 		u32 em_loc = readl(mmio + HOST_EM_LOC);
302518f7ba4cSKristen Carlson Accardi 		u32 em_ctl = readl(mmio + HOST_EM_CTL);
302618f7ba4cSKristen Carlson Accardi 
302787943acfSDavid Milburn 		messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
302818f7ba4cSKristen Carlson Accardi 
302918f7ba4cSKristen Carlson Accardi 		/* we only support LED message type right now */
303018f7ba4cSKristen Carlson Accardi 		if ((messages & 0x01) && (ahci_em_messages == 1)) {
303118f7ba4cSKristen Carlson Accardi 			/* store em_loc */
303218f7ba4cSKristen Carlson Accardi 			hpriv->em_loc = ((em_loc >> 16) * 4);
303318f7ba4cSKristen Carlson Accardi 			pi.flags |= ATA_FLAG_EM;
303418f7ba4cSKristen Carlson Accardi 			if (!(em_ctl & EM_CTL_ALHD))
303518f7ba4cSKristen Carlson Accardi 				pi.flags |= ATA_FLAG_SW_ACTIVITY;
303618f7ba4cSKristen Carlson Accardi 		}
303718f7ba4cSKristen Carlson Accardi 	}
303818f7ba4cSKristen Carlson Accardi 
30391fd68434SRafael J. Wysocki 	if (ahci_broken_system_poweroff(pdev)) {
30401fd68434SRafael J. Wysocki 		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
30411fd68434SRafael J. Wysocki 		dev_info(&pdev->dev,
30421fd68434SRafael J. Wysocki 			"quirky BIOS, skipping spindown on poweroff\n");
30431fd68434SRafael J. Wysocki 	}
30441fd68434SRafael J. Wysocki 
30459b10ae86STejun Heo 	if (ahci_broken_suspend(pdev)) {
30469b10ae86STejun Heo 		hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
30479b10ae86STejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
30489b10ae86STejun Heo 			   "BIOS update required for suspend/resume\n");
30499b10ae86STejun Heo 	}
30509b10ae86STejun Heo 
30515594639aSTejun Heo 	if (ahci_broken_online(pdev)) {
30525594639aSTejun Heo 		hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
30535594639aSTejun Heo 		dev_info(&pdev->dev,
30545594639aSTejun Heo 			 "online status unreliable, applying workaround\n");
30555594639aSTejun Heo 	}
30565594639aSTejun Heo 
3057837f5f8fSTejun Heo 	/* CAP.NP sometimes indicate the index of the last enabled
3058837f5f8fSTejun Heo 	 * port, at other times, that of the last possible port, so
3059837f5f8fSTejun Heo 	 * determining the maximum port number requires looking at
3060837f5f8fSTejun Heo 	 * both CAP.NP and port_map.
3061837f5f8fSTejun Heo 	 */
3062837f5f8fSTejun Heo 	n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
3063837f5f8fSTejun Heo 
3064837f5f8fSTejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
30654447d351STejun Heo 	if (!host)
30664447d351STejun Heo 		return -ENOMEM;
30674447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
30684447d351STejun Heo 	host->private_data = hpriv;
30694447d351STejun Heo 
3070f3d7f23fSArjan van de Ven 	if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
3071886ad09fSArjan van de Ven 		host->flags |= ATA_HOST_PARALLEL_SCAN;
3072f3d7f23fSArjan van de Ven 	else
3073f3d7f23fSArjan van de Ven 		printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
3074886ad09fSArjan van de Ven 
307518f7ba4cSKristen Carlson Accardi 	if (pi.flags & ATA_FLAG_EM)
307618f7ba4cSKristen Carlson Accardi 		ahci_reset_em(host);
307718f7ba4cSKristen Carlson Accardi 
30784447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
30794447d351STejun Heo 		struct ata_port *ap = host->ports[i];
30804447d351STejun Heo 
3081cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
3082cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
3083cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
3084cbcdd875STejun Heo 
308531556594SKristen Carlson Accardi 		/* set initial link pm policy */
308631556594SKristen Carlson Accardi 		ap->pm_policy = NOT_AVAILABLE;
308731556594SKristen Carlson Accardi 
308818f7ba4cSKristen Carlson Accardi 		/* set enclosure management message type */
308918f7ba4cSKristen Carlson Accardi 		if (ap->flags & ATA_FLAG_EM)
309018f7ba4cSKristen Carlson Accardi 			ap->em_message_type = ahci_em_messages;
309118f7ba4cSKristen Carlson Accardi 
309218f7ba4cSKristen Carlson Accardi 
3093dab632e8SJeff Garzik 		/* disabled/not-implemented port */
3094350756f6STejun Heo 		if (!(hpriv->port_map & (1 << i)))
3095dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
30964447d351STejun Heo 	}
3097c6fd2807SJeff Garzik 
3098edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
3099edc93052STejun Heo 	ahci_p5wdh_workaround(host);
3100edc93052STejun Heo 
3101f80ae7e4STejun Heo 	/* apply gtf filter quirk */
3102f80ae7e4STejun Heo 	ahci_gtf_filter_workaround(host);
3103f80ae7e4STejun Heo 
3104c6fd2807SJeff Garzik 	/* initialize adapter */
31054447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
3106c6fd2807SJeff Garzik 	if (rc)
310724dc5f33STejun Heo 		return rc;
3108c6fd2807SJeff Garzik 
31094447d351STejun Heo 	rc = ahci_reset_controller(host);
31104447d351STejun Heo 	if (rc)
31114447d351STejun Heo 		return rc;
3112c6fd2807SJeff Garzik 
31134447d351STejun Heo 	ahci_init_controller(host);
31144447d351STejun Heo 	ahci_print_info(host);
3115c6fd2807SJeff Garzik 
31164447d351STejun Heo 	pci_set_master(pdev);
31174447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
31184447d351STejun Heo 				 &ahci_sht);
3119c6fd2807SJeff Garzik }
3120c6fd2807SJeff Garzik 
3121c6fd2807SJeff Garzik static int __init ahci_init(void)
3122c6fd2807SJeff Garzik {
3123c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
3124c6fd2807SJeff Garzik }
3125c6fd2807SJeff Garzik 
3126c6fd2807SJeff Garzik static void __exit ahci_exit(void)
3127c6fd2807SJeff Garzik {
3128c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
3129c6fd2807SJeff Garzik }
3130c6fd2807SJeff Garzik 
3131c6fd2807SJeff Garzik 
3132c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
3133c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
3134c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
3135c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
3136c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
3137c6fd2807SJeff Garzik 
3138c6fd2807SJeff Garzik module_init(ahci_init);
3139c6fd2807SJeff Garzik module_exit(ahci_exit);
3140