xref: /openbmc/linux/drivers/ata/ahci.c (revision edc93052844c2032b2ec5910ace516da9078714d)
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>
44*edc93052STejun 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 
52c6fd2807SJeff Garzik 
53c6fd2807SJeff Garzik enum {
54c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
55648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
56c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
57c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
58be5d8218SJens Axboe 	AHCI_USE_CLUSTERING	= 1,
59c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
60c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
61c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
62c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
63c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
64c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
65c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
66c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
67c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
68c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
69c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
70c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
71c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
72c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
73c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
74c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
75c6fd2807SJeff Garzik 
76c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
770291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
78c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
79c6fd2807SJeff Garzik 
80c6fd2807SJeff Garzik 	board_ahci		= 0,
817a234affSTejun Heo 	board_ahci_vt8251	= 1,
827a234affSTejun Heo 	board_ahci_ign_iferr	= 2,
837a234affSTejun Heo 	board_ahci_sb600	= 3,
847a234affSTejun Heo 	board_ahci_mv		= 4,
85c6fd2807SJeff Garzik 
86c6fd2807SJeff Garzik 	/* global controller registers */
87c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
88c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
89c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
90c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
91c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
92c6fd2807SJeff Garzik 
93c6fd2807SJeff Garzik 	/* HOST_CTL bits */
94c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
95c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
96c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
97c6fd2807SJeff Garzik 
98c6fd2807SJeff Garzik 	/* HOST_CAP bits */
99c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
1007d50b60bSTejun Heo 	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
101c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
102c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
103203ef6c4STejun Heo 	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
104c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
105c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
106c6fd2807SJeff Garzik 
107c6fd2807SJeff Garzik 	/* registers for each SATA port */
108c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
109c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
110c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
111c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
112c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
113c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
114c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
115c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
116c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
117c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
118c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
119c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
120c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
121c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
122203ef6c4STejun Heo 	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
123c6fd2807SJeff Garzik 
124c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
125c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
126c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
127c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
128c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
129c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
130c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
131c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
132c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
133c6fd2807SJeff Garzik 
134c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
135c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
136c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
137c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
138c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
139c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
140c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
141c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
142c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
143c6fd2807SJeff Garzik 
144c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
145c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
146c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
147c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
1487d50b60bSTejun Heo 				  PORT_IRQ_UNK_FIS |
1497d50b60bSTejun Heo 				  PORT_IRQ_BAD_PMP,
150c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
151c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
152c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
153c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
154c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
155c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
156c6fd2807SJeff Garzik 
157c6fd2807SJeff Garzik 	/* PORT_CMD bits */
158c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
1597d50b60bSTejun Heo 	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
160c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
161c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
162c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
163c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
164c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
165c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
166c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
167c6fd2807SJeff Garzik 
168c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
169c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
170c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
171c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
172c6fd2807SJeff Garzik 
173417a1a6dSTejun Heo 	/* hpriv->flags bits */
174417a1a6dSTejun Heo 	AHCI_HFLAG_NO_NCQ		= (1 << 0),
175417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
176417a1a6dSTejun Heo 	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
177417a1a6dSTejun Heo 	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
178417a1a6dSTejun Heo 	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
179417a1a6dSTejun Heo 	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
1806949b914STejun Heo 	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
181417a1a6dSTejun Heo 
182c6fd2807SJeff Garzik 	/* ap->flags bits */
183417a1a6dSTejun Heo 	AHCI_FLAG_NO_HOTPLUG		= (1 << 24), /* ignore PxSERR.DIAG.N */
1841188c0d8STejun Heo 
1851188c0d8STejun Heo 	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
1861188c0d8STejun Heo 					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
187854c73a2STejun Heo 					  ATA_FLAG_ACPI_SATA | ATA_FLAG_AN,
1880c88758bSTejun Heo 	AHCI_LFLAG_COMMON		= ATA_LFLAG_SKIP_D2H_BSY,
189c6fd2807SJeff Garzik };
190c6fd2807SJeff Garzik 
191c6fd2807SJeff Garzik struct ahci_cmd_hdr {
192c6fd2807SJeff Garzik 	u32			opts;
193c6fd2807SJeff Garzik 	u32			status;
194c6fd2807SJeff Garzik 	u32			tbl_addr;
195c6fd2807SJeff Garzik 	u32			tbl_addr_hi;
196c6fd2807SJeff Garzik 	u32			reserved[4];
197c6fd2807SJeff Garzik };
198c6fd2807SJeff Garzik 
199c6fd2807SJeff Garzik struct ahci_sg {
200c6fd2807SJeff Garzik 	u32			addr;
201c6fd2807SJeff Garzik 	u32			addr_hi;
202c6fd2807SJeff Garzik 	u32			reserved;
203c6fd2807SJeff Garzik 	u32			flags_size;
204c6fd2807SJeff Garzik };
205c6fd2807SJeff Garzik 
206c6fd2807SJeff Garzik struct ahci_host_priv {
207417a1a6dSTejun Heo 	unsigned int		flags;		/* AHCI_HFLAG_* */
208d447df14STejun Heo 	u32			cap;		/* cap to use */
209d447df14STejun Heo 	u32			port_map;	/* port map to use */
210d447df14STejun Heo 	u32			saved_cap;	/* saved initial cap */
211d447df14STejun Heo 	u32			saved_port_map;	/* saved initial port_map */
212c6fd2807SJeff Garzik };
213c6fd2807SJeff Garzik 
214c6fd2807SJeff Garzik struct ahci_port_priv {
2157d50b60bSTejun Heo 	struct ata_link		*active_link;
216c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
217c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
218c6fd2807SJeff Garzik 	void			*cmd_tbl;
219c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
220c6fd2807SJeff Garzik 	void			*rx_fis;
221c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2220291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2230291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2240291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
225afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
226a7384925SKristen Carlson Accardi 	u32 			intr_mask;	/* interrupts to enable */
227c6fd2807SJeff Garzik };
228c6fd2807SJeff Garzik 
229da3dbb17STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
230da3dbb17STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
231c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
232c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
233c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap);
234c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
235c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
236c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
237c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
238c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap);
239c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
240c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
2417d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap);
2427d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap);
243c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
244ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap);
245*edc93052STejun Heo static void ahci_p5wdh_error_handler(struct ata_port *ap);
246c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
247df69c9c5SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
248dab632e8SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
249dab632e8SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
250dab632e8SJeff Garzik 			       u32 opts);
251438ac6d5STejun Heo #ifdef CONFIG_PM
252c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
253c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
254c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
255438ac6d5STejun Heo #endif
256c6fd2807SJeff Garzik 
257c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
258c6fd2807SJeff Garzik 	.module			= THIS_MODULE,
259c6fd2807SJeff Garzik 	.name			= DRV_NAME,
260c6fd2807SJeff Garzik 	.ioctl			= ata_scsi_ioctl,
261c6fd2807SJeff Garzik 	.queuecommand		= ata_scsi_queuecmd,
262c6fd2807SJeff Garzik 	.change_queue_depth	= ata_scsi_change_queue_depth,
263c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
264c6fd2807SJeff Garzik 	.this_id		= ATA_SHT_THIS_ID,
265c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
266c6fd2807SJeff Garzik 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
267c6fd2807SJeff Garzik 	.emulated		= ATA_SHT_EMULATED,
268c6fd2807SJeff Garzik 	.use_clustering		= AHCI_USE_CLUSTERING,
269c6fd2807SJeff Garzik 	.proc_name		= DRV_NAME,
270c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
271c6fd2807SJeff Garzik 	.slave_configure	= ata_scsi_slave_config,
272c6fd2807SJeff Garzik 	.slave_destroy		= ata_scsi_slave_destroy,
273c6fd2807SJeff Garzik 	.bios_param		= ata_std_bios_param,
274c6fd2807SJeff Garzik };
275c6fd2807SJeff Garzik 
276c6fd2807SJeff Garzik static const struct ata_port_operations ahci_ops = {
277c6fd2807SJeff Garzik 	.check_status		= ahci_check_status,
278c6fd2807SJeff Garzik 	.check_altstatus	= ahci_check_status,
279c6fd2807SJeff Garzik 	.dev_select		= ata_noop_dev_select,
280c6fd2807SJeff Garzik 
281c6fd2807SJeff Garzik 	.tf_read		= ahci_tf_read,
282c6fd2807SJeff Garzik 
2837d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
284c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
285c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
286c6fd2807SJeff Garzik 
287c6fd2807SJeff Garzik 	.irq_clear		= ahci_irq_clear,
288c6fd2807SJeff Garzik 
289c6fd2807SJeff Garzik 	.scr_read		= ahci_scr_read,
290c6fd2807SJeff Garzik 	.scr_write		= ahci_scr_write,
291c6fd2807SJeff Garzik 
292c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
293c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
294c6fd2807SJeff Garzik 
295c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
296c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
297c6fd2807SJeff Garzik 
2987d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
2997d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3007d50b60bSTejun Heo 
301438ac6d5STejun Heo #ifdef CONFIG_PM
302c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
303c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
304438ac6d5STejun Heo #endif
305c6fd2807SJeff Garzik 
306c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
307c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
308c6fd2807SJeff Garzik };
309c6fd2807SJeff Garzik 
310ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = {
311ad616ffbSTejun Heo 	.check_status		= ahci_check_status,
312ad616ffbSTejun Heo 	.check_altstatus	= ahci_check_status,
313ad616ffbSTejun Heo 	.dev_select		= ata_noop_dev_select,
314ad616ffbSTejun Heo 
315ad616ffbSTejun Heo 	.tf_read		= ahci_tf_read,
316ad616ffbSTejun Heo 
3177d50b60bSTejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
318ad616ffbSTejun Heo 	.qc_prep		= ahci_qc_prep,
319ad616ffbSTejun Heo 	.qc_issue		= ahci_qc_issue,
320ad616ffbSTejun Heo 
321ad616ffbSTejun Heo 	.irq_clear		= ahci_irq_clear,
322ad616ffbSTejun Heo 
323ad616ffbSTejun Heo 	.scr_read		= ahci_scr_read,
324ad616ffbSTejun Heo 	.scr_write		= ahci_scr_write,
325ad616ffbSTejun Heo 
326ad616ffbSTejun Heo 	.freeze			= ahci_freeze,
327ad616ffbSTejun Heo 	.thaw			= ahci_thaw,
328ad616ffbSTejun Heo 
329ad616ffbSTejun Heo 	.error_handler		= ahci_vt8251_error_handler,
330ad616ffbSTejun Heo 	.post_internal_cmd	= ahci_post_internal_cmd,
331ad616ffbSTejun Heo 
3327d50b60bSTejun Heo 	.pmp_attach		= ahci_pmp_attach,
3337d50b60bSTejun Heo 	.pmp_detach		= ahci_pmp_detach,
3347d50b60bSTejun Heo 
335438ac6d5STejun Heo #ifdef CONFIG_PM
336ad616ffbSTejun Heo 	.port_suspend		= ahci_port_suspend,
337ad616ffbSTejun Heo 	.port_resume		= ahci_port_resume,
338438ac6d5STejun Heo #endif
339ad616ffbSTejun Heo 
340ad616ffbSTejun Heo 	.port_start		= ahci_port_start,
341ad616ffbSTejun Heo 	.port_stop		= ahci_port_stop,
342ad616ffbSTejun Heo };
343ad616ffbSTejun Heo 
344*edc93052STejun Heo static const struct ata_port_operations ahci_p5wdh_ops = {
345*edc93052STejun Heo 	.check_status		= ahci_check_status,
346*edc93052STejun Heo 	.check_altstatus	= ahci_check_status,
347*edc93052STejun Heo 	.dev_select		= ata_noop_dev_select,
348*edc93052STejun Heo 
349*edc93052STejun Heo 	.tf_read		= ahci_tf_read,
350*edc93052STejun Heo 
351*edc93052STejun Heo 	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
352*edc93052STejun Heo 	.qc_prep		= ahci_qc_prep,
353*edc93052STejun Heo 	.qc_issue		= ahci_qc_issue,
354*edc93052STejun Heo 
355*edc93052STejun Heo 	.irq_clear		= ahci_irq_clear,
356*edc93052STejun Heo 
357*edc93052STejun Heo 	.scr_read		= ahci_scr_read,
358*edc93052STejun Heo 	.scr_write		= ahci_scr_write,
359*edc93052STejun Heo 
360*edc93052STejun Heo 	.freeze			= ahci_freeze,
361*edc93052STejun Heo 	.thaw			= ahci_thaw,
362*edc93052STejun Heo 
363*edc93052STejun Heo 	.error_handler		= ahci_p5wdh_error_handler,
364*edc93052STejun Heo 	.post_internal_cmd	= ahci_post_internal_cmd,
365*edc93052STejun Heo 
366*edc93052STejun Heo 	.pmp_attach		= ahci_pmp_attach,
367*edc93052STejun Heo 	.pmp_detach		= ahci_pmp_detach,
368*edc93052STejun Heo 
369*edc93052STejun Heo #ifdef CONFIG_PM
370*edc93052STejun Heo 	.port_suspend		= ahci_port_suspend,
371*edc93052STejun Heo 	.port_resume		= ahci_port_resume,
372*edc93052STejun Heo #endif
373*edc93052STejun Heo 
374*edc93052STejun Heo 	.port_start		= ahci_port_start,
375*edc93052STejun Heo 	.port_stop		= ahci_port_stop,
376*edc93052STejun Heo };
377*edc93052STejun Heo 
378417a1a6dSTejun Heo #define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
379417a1a6dSTejun Heo 
380c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
381c6fd2807SJeff Garzik 	/* board_ahci */
382c6fd2807SJeff Garzik 	{
3831188c0d8STejun Heo 		.flags		= AHCI_FLAG_COMMON,
3840c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON,
385c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
386469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
387c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
388c6fd2807SJeff Garzik 	},
389c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
390c6fd2807SJeff Garzik 	{
3916949b914STejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
392417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
3930c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME,
394c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
395469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
396ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
397c6fd2807SJeff Garzik 	},
39841669553STejun Heo 	/* board_ahci_ign_iferr */
39941669553STejun Heo 	{
400417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
401417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
4020c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON,
40341669553STejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
404469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
40541669553STejun Heo 		.port_ops	= &ahci_ops,
40641669553STejun Heo 	},
40755a61604SConke Hu 	/* board_ahci_sb600 */
40855a61604SConke Hu 	{
409417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
4106949b914STejun Heo 				 AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP),
411417a1a6dSTejun Heo 		.flags		= AHCI_FLAG_COMMON,
4120c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON,
41355a61604SConke Hu 		.pio_mask	= 0x1f, /* pio0-4 */
414469248abSJeff Garzik 		.udma_mask	= ATA_UDMA6,
41555a61604SConke Hu 		.port_ops	= &ahci_ops,
41655a61604SConke Hu 	},
417cd70c266SJeff Garzik 	/* board_ahci_mv */
418cd70c266SJeff Garzik 	{
419417a1a6dSTejun Heo 		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
420417a1a6dSTejun Heo 				 AHCI_HFLAG_MV_PATA),
421cd70c266SJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
422417a1a6dSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
4230c88758bSTejun Heo 		.link_flags	= AHCI_LFLAG_COMMON,
424cd70c266SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
425cd70c266SJeff Garzik 		.udma_mask	= ATA_UDMA6,
426cd70c266SJeff Garzik 		.port_ops	= &ahci_ops,
427cd70c266SJeff Garzik 	},
428c6fd2807SJeff Garzik };
429c6fd2807SJeff Garzik 
430c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
431c6fd2807SJeff Garzik 	/* Intel */
43254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
43354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
43454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
43554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
43654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
43782490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
43854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
43954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
44054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
44154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
4427a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
4437a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
4447a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
4457a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
4467a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
4477a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
4487a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
4497a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
4507a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
4517a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
4527a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
4537a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
4547a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
4557a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
4567a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
4577a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
4587a234affSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
459d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
460d4155e6fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
461c6fd2807SJeff Garzik 
462e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
463e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
464e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
465c6fd2807SJeff Garzik 
466c6fd2807SJeff Garzik 	/* ATI */
467c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
468c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */
469c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */
470c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */
471c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */
472c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */
473c69c0892Shenry su 	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */
474c6fd2807SJeff Garzik 
475c6fd2807SJeff Garzik 	/* VIA */
47654bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
477bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
478c6fd2807SJeff Garzik 
479c6fd2807SJeff Garzik 	/* NVIDIA */
48054bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },		/* MCP65 */
48154bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci },		/* MCP65 */
48254bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci },		/* MCP65 */
48354bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci },		/* MCP65 */
4846fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci },		/* MCP65 */
4856fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci },		/* MCP65 */
4866fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci },		/* MCP65 */
4876fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci },		/* MCP65 */
4886fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci },		/* MCP67 */
4896fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci },		/* MCP67 */
4906fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci },		/* MCP67 */
4916fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci },		/* MCP67 */
492895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },		/* MCP67 */
493895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },		/* MCP67 */
494895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },		/* MCP67 */
495895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },		/* MCP67 */
496895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },		/* MCP67 */
497895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },		/* MCP67 */
498895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },		/* MCP67 */
499895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },		/* MCP67 */
5000522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci },		/* MCP73 */
5010522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci },		/* MCP73 */
5020522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci },		/* MCP73 */
5030522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci },		/* MCP73 */
5040522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci },		/* MCP73 */
5050522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci },		/* MCP73 */
5060522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci },		/* MCP73 */
5070522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci },		/* MCP73 */
5080522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci },		/* MCP73 */
5090522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci },		/* MCP73 */
5100522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci },		/* MCP73 */
5110522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci },		/* MCP73 */
5120522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci },		/* MCP77 */
5130522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci },		/* MCP77 */
5140522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci },		/* MCP77 */
5150522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci },		/* MCP77 */
5160522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci },		/* MCP77 */
5170522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci },		/* MCP77 */
5180522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci },		/* MCP77 */
5190522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci },		/* MCP77 */
5200522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci },		/* MCP77 */
5210522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
5220522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
5230522b286SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
5247100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
5257100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
5267100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
5277100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
5287100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
5297100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
5307100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
5317100819fSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
532c6fd2807SJeff Garzik 
533c6fd2807SJeff Garzik 	/* SiS */
53454bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
53554bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
53654bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
537c6fd2807SJeff Garzik 
538cd70c266SJeff Garzik 	/* Marvell */
539cd70c266SJeff Garzik 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
540cd70c266SJeff Garzik 
541415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
542415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
543c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
544415ae2b5SJeff Garzik 
545c6fd2807SJeff Garzik 	{ }	/* terminate list */
546c6fd2807SJeff Garzik };
547c6fd2807SJeff Garzik 
548c6fd2807SJeff Garzik 
549c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
550c6fd2807SJeff Garzik 	.name			= DRV_NAME,
551c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
552c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
55324dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
554438ac6d5STejun Heo #ifdef CONFIG_PM
555c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
556c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
557438ac6d5STejun Heo #endif
558c6fd2807SJeff Garzik };
559c6fd2807SJeff Garzik 
560c6fd2807SJeff Garzik 
56198fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
56298fa4b60STejun Heo {
56398fa4b60STejun Heo 	return (cap & 0x1f) + 1;
56498fa4b60STejun Heo }
56598fa4b60STejun Heo 
566dab632e8SJeff Garzik static inline void __iomem *__ahci_port_base(struct ata_host *host,
567dab632e8SJeff Garzik 					     unsigned int port_no)
568dab632e8SJeff Garzik {
569dab632e8SJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
570dab632e8SJeff Garzik 
571dab632e8SJeff Garzik 	return mmio + 0x100 + (port_no * 0x80);
572dab632e8SJeff Garzik }
573dab632e8SJeff Garzik 
5744447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
575c6fd2807SJeff Garzik {
576dab632e8SJeff Garzik 	return __ahci_port_base(ap->host, ap->port_no);
577c6fd2807SJeff Garzik }
578c6fd2807SJeff Garzik 
579d447df14STejun Heo /**
580d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
5814447d351STejun Heo  *	@pdev: target PCI device
5824447d351STejun Heo  *	@hpriv: host private area to store config values
583d447df14STejun Heo  *
584d447df14STejun Heo  *	Some registers containing configuration info might be setup by
585d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
586d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
587d447df14STejun Heo  *	can be restored after controller reset.
588d447df14STejun Heo  *
589d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
590d447df14STejun Heo  *
591d447df14STejun Heo  *	LOCKING:
592d447df14STejun Heo  *	None.
593d447df14STejun Heo  */
5944447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
5954447d351STejun Heo 				     struct ahci_host_priv *hpriv)
596d447df14STejun Heo {
5974447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
598d447df14STejun Heo 	u32 cap, port_map;
59917199b18STejun Heo 	int i;
600d447df14STejun Heo 
601d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
602d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
603d447df14STejun Heo 	 */
604d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
605d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
606d447df14STejun Heo 
607274c1fdeSTejun Heo 	/* some chips have errata preventing 64bit use */
608417a1a6dSTejun Heo 	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
609c7a42156STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
610c7a42156STejun Heo 			   "controller can't do 64bit DMA, forcing 32bit\n");
611c7a42156STejun Heo 		cap &= ~HOST_CAP_64;
612c7a42156STejun Heo 	}
613c7a42156STejun Heo 
614417a1a6dSTejun Heo 	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
615274c1fdeSTejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
616274c1fdeSTejun Heo 			   "controller can't do NCQ, turning off CAP_NCQ\n");
617274c1fdeSTejun Heo 		cap &= ~HOST_CAP_NCQ;
618274c1fdeSTejun Heo 	}
619274c1fdeSTejun Heo 
6206949b914STejun Heo 	if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
6216949b914STejun Heo 		dev_printk(KERN_INFO, &pdev->dev,
6226949b914STejun Heo 			   "controller can't do PMP, turning off CAP_PMP\n");
6236949b914STejun Heo 		cap &= ~HOST_CAP_PMP;
6246949b914STejun Heo 	}
6256949b914STejun Heo 
626cd70c266SJeff Garzik 	/*
627cd70c266SJeff Garzik 	 * Temporary Marvell 6145 hack: PATA port presence
628cd70c266SJeff Garzik 	 * is asserted through the standard AHCI port
629cd70c266SJeff Garzik 	 * presence register, as bit 4 (counting from 0)
630cd70c266SJeff Garzik 	 */
631417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
632cd70c266SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
633cd70c266SJeff Garzik 			   "MV_AHCI HACK: port_map %x -> %x\n",
634cd70c266SJeff Garzik 			   hpriv->port_map,
635cd70c266SJeff Garzik 			   hpriv->port_map & 0xf);
636cd70c266SJeff Garzik 
637cd70c266SJeff Garzik 		port_map &= 0xf;
638cd70c266SJeff Garzik 	}
639cd70c266SJeff Garzik 
64017199b18STejun Heo 	/* cross check port_map and cap.n_ports */
6417a234affSTejun Heo 	if (port_map) {
64217199b18STejun Heo 		u32 tmp_port_map = port_map;
64317199b18STejun Heo 		int n_ports = ahci_nr_ports(cap);
64417199b18STejun Heo 
64517199b18STejun Heo 		for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
64617199b18STejun Heo 			if (tmp_port_map & (1 << i)) {
64717199b18STejun Heo 				n_ports--;
64817199b18STejun Heo 				tmp_port_map &= ~(1 << i);
64917199b18STejun Heo 			}
65017199b18STejun Heo 		}
65117199b18STejun Heo 
6527a234affSTejun Heo 		/* If n_ports and port_map are inconsistent, whine and
6537a234affSTejun Heo 		 * clear port_map and let it be generated from n_ports.
65417199b18STejun Heo 		 */
6557a234affSTejun Heo 		if (n_ports || tmp_port_map) {
6564447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
65717199b18STejun Heo 				   "nr_ports (%u) and implemented port map "
6587a234affSTejun Heo 				   "(0x%x) don't match, using nr_ports\n",
65917199b18STejun Heo 				   ahci_nr_ports(cap), port_map);
6607a234affSTejun Heo 			port_map = 0;
6617a234affSTejun Heo 		}
6627a234affSTejun Heo 	}
6637a234affSTejun Heo 
66417199b18STejun Heo 	/* fabricate port_map from cap.nr_ports */
6657a234affSTejun Heo 	if (!port_map) {
66617199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
6677a234affSTejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
6687a234affSTejun Heo 			   "forcing PORTS_IMPL to 0x%x\n", port_map);
6697a234affSTejun Heo 
6707a234affSTejun Heo 		/* write the fixed up value to the PI register */
6717a234affSTejun Heo 		hpriv->saved_port_map = port_map;
67217199b18STejun Heo 	}
67317199b18STejun Heo 
674d447df14STejun Heo 	/* record values to use during operation */
675d447df14STejun Heo 	hpriv->cap = cap;
676d447df14STejun Heo 	hpriv->port_map = port_map;
677d447df14STejun Heo }
678d447df14STejun Heo 
679d447df14STejun Heo /**
680d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
6814447d351STejun Heo  *	@host: target ATA host
682d447df14STejun Heo  *
683d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
684d447df14STejun Heo  *
685d447df14STejun Heo  *	LOCKING:
686d447df14STejun Heo  *	None.
687d447df14STejun Heo  */
6884447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
689d447df14STejun Heo {
6904447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
6914447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
6924447d351STejun Heo 
693d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
694d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
695d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
696d447df14STejun Heo }
697d447df14STejun Heo 
698203ef6c4STejun Heo static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
699c6fd2807SJeff Garzik {
700203ef6c4STejun Heo 	static const int offset[] = {
701203ef6c4STejun Heo 		[SCR_STATUS]		= PORT_SCR_STAT,
702203ef6c4STejun Heo 		[SCR_CONTROL]		= PORT_SCR_CTL,
703203ef6c4STejun Heo 		[SCR_ERROR]		= PORT_SCR_ERR,
704203ef6c4STejun Heo 		[SCR_ACTIVE]		= PORT_SCR_ACT,
705203ef6c4STejun Heo 		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
706203ef6c4STejun Heo 	};
707203ef6c4STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
708c6fd2807SJeff Garzik 
709203ef6c4STejun Heo 	if (sc_reg < ARRAY_SIZE(offset) &&
710203ef6c4STejun Heo 	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
711203ef6c4STejun Heo 		return offset[sc_reg];
712da3dbb17STejun Heo 	return 0;
713c6fd2807SJeff Garzik }
714c6fd2807SJeff Garzik 
715203ef6c4STejun Heo static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
716c6fd2807SJeff Garzik {
717203ef6c4STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
718203ef6c4STejun Heo 	int offset = ahci_scr_offset(ap, sc_reg);
719c6fd2807SJeff Garzik 
720203ef6c4STejun Heo 	if (offset) {
721203ef6c4STejun Heo 		*val = readl(port_mmio + offset);
722203ef6c4STejun Heo 		return 0;
723203ef6c4STejun Heo 	}
724da3dbb17STejun Heo 	return -EINVAL;
725c6fd2807SJeff Garzik }
726c6fd2807SJeff Garzik 
727203ef6c4STejun Heo static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
728203ef6c4STejun Heo {
729203ef6c4STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
730203ef6c4STejun Heo 	int offset = ahci_scr_offset(ap, sc_reg);
731203ef6c4STejun Heo 
732203ef6c4STejun Heo 	if (offset) {
733203ef6c4STejun Heo 		writel(val, port_mmio + offset);
734da3dbb17STejun Heo 		return 0;
735c6fd2807SJeff Garzik 	}
736203ef6c4STejun Heo 	return -EINVAL;
737203ef6c4STejun Heo }
738c6fd2807SJeff Garzik 
7394447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
740c6fd2807SJeff Garzik {
7414447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
742c6fd2807SJeff Garzik 	u32 tmp;
743c6fd2807SJeff Garzik 
744c6fd2807SJeff Garzik 	/* start DMA */
745c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
746c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
747c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
748c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
749c6fd2807SJeff Garzik }
750c6fd2807SJeff Garzik 
7514447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
752c6fd2807SJeff Garzik {
7534447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
754c6fd2807SJeff Garzik 	u32 tmp;
755c6fd2807SJeff Garzik 
756c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
757c6fd2807SJeff Garzik 
758c6fd2807SJeff Garzik 	/* check if the HBA is idle */
759c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
760c6fd2807SJeff Garzik 		return 0;
761c6fd2807SJeff Garzik 
762c6fd2807SJeff Garzik 	/* setting HBA to idle */
763c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
764c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
765c6fd2807SJeff Garzik 
766c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
767c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
768c6fd2807SJeff Garzik 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
769c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
770c6fd2807SJeff Garzik 		return -EIO;
771c6fd2807SJeff Garzik 
772c6fd2807SJeff Garzik 	return 0;
773c6fd2807SJeff Garzik }
774c6fd2807SJeff Garzik 
7754447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
776c6fd2807SJeff Garzik {
7774447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
7784447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
7794447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
780c6fd2807SJeff Garzik 	u32 tmp;
781c6fd2807SJeff Garzik 
782c6fd2807SJeff Garzik 	/* set FIS registers */
7834447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
7844447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
7854447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
7864447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
787c6fd2807SJeff Garzik 
7884447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
7894447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
7904447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
7914447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
792c6fd2807SJeff Garzik 
793c6fd2807SJeff Garzik 	/* enable FIS reception */
794c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
795c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
796c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
797c6fd2807SJeff Garzik 
798c6fd2807SJeff Garzik 	/* flush */
799c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
800c6fd2807SJeff Garzik }
801c6fd2807SJeff Garzik 
8024447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
803c6fd2807SJeff Garzik {
8044447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
805c6fd2807SJeff Garzik 	u32 tmp;
806c6fd2807SJeff Garzik 
807c6fd2807SJeff Garzik 	/* disable FIS reception */
808c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
809c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
810c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
811c6fd2807SJeff Garzik 
812c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
813c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
814c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
815c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
816c6fd2807SJeff Garzik 		return -EBUSY;
817c6fd2807SJeff Garzik 
818c6fd2807SJeff Garzik 	return 0;
819c6fd2807SJeff Garzik }
820c6fd2807SJeff Garzik 
8214447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
822c6fd2807SJeff Garzik {
8234447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
8244447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
825c6fd2807SJeff Garzik 	u32 cmd;
826c6fd2807SJeff Garzik 
827c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
828c6fd2807SJeff Garzik 
829c6fd2807SJeff Garzik 	/* spin up device */
8304447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
831c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
832c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
833c6fd2807SJeff Garzik 	}
834c6fd2807SJeff Garzik 
835c6fd2807SJeff Garzik 	/* wake up link */
836c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
837c6fd2807SJeff Garzik }
838c6fd2807SJeff Garzik 
839438ac6d5STejun Heo #ifdef CONFIG_PM
8404447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
841c6fd2807SJeff Garzik {
8424447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
8434447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
844c6fd2807SJeff Garzik 	u32 cmd, scontrol;
845c6fd2807SJeff Garzik 
8464447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
84707c53dacSTejun Heo 		return;
848c6fd2807SJeff Garzik 
84907c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
850c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
851c6fd2807SJeff Garzik 	scontrol &= ~0xf;
852c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
853c6fd2807SJeff Garzik 
854c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
85507c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
856c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
857c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
858c6fd2807SJeff Garzik }
859438ac6d5STejun Heo #endif
860c6fd2807SJeff Garzik 
861df69c9c5SJeff Garzik static void ahci_start_port(struct ata_port *ap)
862c6fd2807SJeff Garzik {
863c6fd2807SJeff Garzik 	/* enable FIS reception */
8644447d351STejun Heo 	ahci_start_fis_rx(ap);
865c6fd2807SJeff Garzik 
866c6fd2807SJeff Garzik 	/* enable DMA */
8674447d351STejun Heo 	ahci_start_engine(ap);
868c6fd2807SJeff Garzik }
869c6fd2807SJeff Garzik 
8704447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
871c6fd2807SJeff Garzik {
872c6fd2807SJeff Garzik 	int rc;
873c6fd2807SJeff Garzik 
874c6fd2807SJeff Garzik 	/* disable DMA */
8754447d351STejun Heo 	rc = ahci_stop_engine(ap);
876c6fd2807SJeff Garzik 	if (rc) {
877c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
878c6fd2807SJeff Garzik 		return rc;
879c6fd2807SJeff Garzik 	}
880c6fd2807SJeff Garzik 
881c6fd2807SJeff Garzik 	/* disable FIS reception */
8824447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
883c6fd2807SJeff Garzik 	if (rc) {
884c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
885c6fd2807SJeff Garzik 		return rc;
886c6fd2807SJeff Garzik 	}
887c6fd2807SJeff Garzik 
888c6fd2807SJeff Garzik 	return 0;
889c6fd2807SJeff Garzik }
890c6fd2807SJeff Garzik 
8914447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
892c6fd2807SJeff Garzik {
8934447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
8944447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
895d447df14STejun Heo 	u32 tmp;
896c6fd2807SJeff Garzik 
8973cc3eb11SJeff Garzik 	/* we must be in AHCI mode, before using anything
8983cc3eb11SJeff Garzik 	 * AHCI-specific, such as HOST_RESET.
8993cc3eb11SJeff Garzik 	 */
900c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
9013cc3eb11SJeff Garzik 	if (!(tmp & HOST_AHCI_EN))
9023cc3eb11SJeff Garzik 		writel(tmp | HOST_AHCI_EN, mmio + HOST_CTL);
9033cc3eb11SJeff Garzik 
9043cc3eb11SJeff Garzik 	/* global controller reset */
905c6fd2807SJeff Garzik 	if ((tmp & HOST_RESET) == 0) {
906c6fd2807SJeff Garzik 		writel(tmp | HOST_RESET, mmio + HOST_CTL);
907c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
908c6fd2807SJeff Garzik 	}
909c6fd2807SJeff Garzik 
910c6fd2807SJeff Garzik 	/* reset must complete within 1 second, or
911c6fd2807SJeff Garzik 	 * the hardware should be considered fried.
912c6fd2807SJeff Garzik 	 */
913c6fd2807SJeff Garzik 	ssleep(1);
914c6fd2807SJeff Garzik 
915c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
916c6fd2807SJeff Garzik 	if (tmp & HOST_RESET) {
9174447d351STejun Heo 		dev_printk(KERN_ERR, host->dev,
918c6fd2807SJeff Garzik 			   "controller reset failed (0x%x)\n", tmp);
919c6fd2807SJeff Garzik 		return -EIO;
920c6fd2807SJeff Garzik 	}
921c6fd2807SJeff Garzik 
92298fa4b60STejun Heo 	/* turn on AHCI mode */
923c6fd2807SJeff Garzik 	writel(HOST_AHCI_EN, mmio + HOST_CTL);
924c6fd2807SJeff Garzik 	(void) readl(mmio + HOST_CTL);	/* flush */
92598fa4b60STejun Heo 
926d447df14STejun Heo 	/* some registers might be cleared on reset.  restore initial values */
9274447d351STejun Heo 	ahci_restore_initial_config(host);
928c6fd2807SJeff Garzik 
929c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
930c6fd2807SJeff Garzik 		u16 tmp16;
931c6fd2807SJeff Garzik 
932c6fd2807SJeff Garzik 		/* configure PCS */
933c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
934c6fd2807SJeff Garzik 		tmp16 |= 0xf;
935c6fd2807SJeff Garzik 		pci_write_config_word(pdev, 0x92, tmp16);
936c6fd2807SJeff Garzik 	}
937c6fd2807SJeff Garzik 
938c6fd2807SJeff Garzik 	return 0;
939c6fd2807SJeff Garzik }
940c6fd2807SJeff Garzik 
9412bcd866bSJeff Garzik static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
9422bcd866bSJeff Garzik 			   int port_no, void __iomem *mmio,
9432bcd866bSJeff Garzik 			   void __iomem *port_mmio)
944c6fd2807SJeff Garzik {
945c6fd2807SJeff Garzik 	const char *emsg = NULL;
9462bcd866bSJeff Garzik 	int rc;
9472bcd866bSJeff Garzik 	u32 tmp;
948c6fd2807SJeff Garzik 
949c6fd2807SJeff Garzik 	/* make sure port is not active */
9504447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
951c6fd2807SJeff Garzik 	if (rc)
952c6fd2807SJeff Garzik 		dev_printk(KERN_WARNING, &pdev->dev,
953c6fd2807SJeff Garzik 			   "%s (%d)\n", emsg, rc);
954c6fd2807SJeff Garzik 
955c6fd2807SJeff Garzik 	/* clear SError */
956c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SCR_ERR);
957c6fd2807SJeff Garzik 	VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
958c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_SCR_ERR);
959c6fd2807SJeff Garzik 
960c6fd2807SJeff Garzik 	/* clear port IRQ */
961c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
962c6fd2807SJeff Garzik 	VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
963c6fd2807SJeff Garzik 	if (tmp)
964c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_IRQ_STAT);
965c6fd2807SJeff Garzik 
9662bcd866bSJeff Garzik 	writel(1 << port_no, mmio + HOST_IRQ_STAT);
9672bcd866bSJeff Garzik }
9682bcd866bSJeff Garzik 
9692bcd866bSJeff Garzik static void ahci_init_controller(struct ata_host *host)
9702bcd866bSJeff Garzik {
971417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
9722bcd866bSJeff Garzik 	struct pci_dev *pdev = to_pci_dev(host->dev);
9732bcd866bSJeff Garzik 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
9742bcd866bSJeff Garzik 	int i;
975cd70c266SJeff Garzik 	void __iomem *port_mmio;
9762bcd866bSJeff Garzik 	u32 tmp;
9772bcd866bSJeff Garzik 
978417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
979cd70c266SJeff Garzik 		port_mmio = __ahci_port_base(host, 4);
980cd70c266SJeff Garzik 
981cd70c266SJeff Garzik 		writel(0, port_mmio + PORT_IRQ_MASK);
982cd70c266SJeff Garzik 
983cd70c266SJeff Garzik 		/* clear port IRQ */
984cd70c266SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
985cd70c266SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
986cd70c266SJeff Garzik 		if (tmp)
987cd70c266SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
988cd70c266SJeff Garzik 	}
989cd70c266SJeff Garzik 
9902bcd866bSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
9912bcd866bSJeff Garzik 		struct ata_port *ap = host->ports[i];
9922bcd866bSJeff Garzik 
993cd70c266SJeff Garzik 		port_mmio = ahci_port_base(ap);
9942bcd866bSJeff Garzik 		if (ata_port_is_dummy(ap))
9952bcd866bSJeff Garzik 			continue;
9962bcd866bSJeff Garzik 
9972bcd866bSJeff Garzik 		ahci_port_init(pdev, ap, i, mmio, port_mmio);
998c6fd2807SJeff Garzik 	}
999c6fd2807SJeff Garzik 
1000c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1001c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1002c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
1003c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
1004c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
1005c6fd2807SJeff Garzik }
1006c6fd2807SJeff Garzik 
1007c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
1008c6fd2807SJeff Garzik {
10094447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1010c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1011c6fd2807SJeff Garzik 	u32 tmp;
1012c6fd2807SJeff Garzik 
1013c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
1014c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
1015c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
1016c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
1017c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
1018c6fd2807SJeff Garzik 
1019c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
1020c6fd2807SJeff Garzik }
1021c6fd2807SJeff Garzik 
1022c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
1023c6fd2807SJeff Garzik 			       u32 opts)
1024c6fd2807SJeff Garzik {
1025c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
1026c6fd2807SJeff Garzik 
1027c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
1028c6fd2807SJeff Garzik 
1029c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
1030c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
1031c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
1032c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
1033c6fd2807SJeff Garzik }
1034c6fd2807SJeff Garzik 
1035d2e75dffSTejun Heo static int ahci_kick_engine(struct ata_port *ap, int force_restart)
1036c6fd2807SJeff Garzik {
10370d5ff566STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
1038cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1039c6fd2807SJeff Garzik 	u32 tmp;
1040d2e75dffSTejun Heo 	int busy, rc;
1041c6fd2807SJeff Garzik 
1042d2e75dffSTejun Heo 	/* do we need to kick the port? */
1043d2e75dffSTejun Heo 	busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
1044d2e75dffSTejun Heo 	if (!busy && !force_restart)
1045d2e75dffSTejun Heo 		return 0;
1046c6fd2807SJeff Garzik 
1047d2e75dffSTejun Heo 	/* stop engine */
1048d2e75dffSTejun Heo 	rc = ahci_stop_engine(ap);
1049d2e75dffSTejun Heo 	if (rc)
1050d2e75dffSTejun Heo 		goto out_restart;
1051d2e75dffSTejun Heo 
1052d2e75dffSTejun Heo 	/* need to do CLO? */
1053d2e75dffSTejun Heo 	if (!busy) {
1054d2e75dffSTejun Heo 		rc = 0;
1055d2e75dffSTejun Heo 		goto out_restart;
1056d2e75dffSTejun Heo 	}
1057d2e75dffSTejun Heo 
1058d2e75dffSTejun Heo 	if (!(hpriv->cap & HOST_CAP_CLO)) {
1059d2e75dffSTejun Heo 		rc = -EOPNOTSUPP;
1060d2e75dffSTejun Heo 		goto out_restart;
1061d2e75dffSTejun Heo 	}
1062d2e75dffSTejun Heo 
1063d2e75dffSTejun Heo 	/* perform CLO */
1064c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
1065c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
1066c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
1067c6fd2807SJeff Garzik 
1068d2e75dffSTejun Heo 	rc = 0;
1069c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
1070c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
1071c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
1072d2e75dffSTejun Heo 		rc = -EIO;
1073c6fd2807SJeff Garzik 
1074d2e75dffSTejun Heo 	/* restart engine */
1075d2e75dffSTejun Heo  out_restart:
1076d2e75dffSTejun Heo 	ahci_start_engine(ap);
1077d2e75dffSTejun Heo 	return rc;
1078c6fd2807SJeff Garzik }
1079c6fd2807SJeff Garzik 
108091c4a2e0STejun Heo static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
108191c4a2e0STejun Heo 				struct ata_taskfile *tf, int is_cmd, u16 flags,
108291c4a2e0STejun Heo 				unsigned long timeout_msec)
108391c4a2e0STejun Heo {
108491c4a2e0STejun Heo 	const u32 cmd_fis_len = 5; /* five dwords */
108591c4a2e0STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
108691c4a2e0STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
108791c4a2e0STejun Heo 	u8 *fis = pp->cmd_tbl;
108891c4a2e0STejun Heo 	u32 tmp;
108991c4a2e0STejun Heo 
109091c4a2e0STejun Heo 	/* prep the command */
109191c4a2e0STejun Heo 	ata_tf_to_fis(tf, pmp, is_cmd, fis);
109291c4a2e0STejun Heo 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
109391c4a2e0STejun Heo 
109491c4a2e0STejun Heo 	/* issue & wait */
109591c4a2e0STejun Heo 	writel(1, port_mmio + PORT_CMD_ISSUE);
109691c4a2e0STejun Heo 
109791c4a2e0STejun Heo 	if (timeout_msec) {
109891c4a2e0STejun Heo 		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
109991c4a2e0STejun Heo 					1, timeout_msec);
110091c4a2e0STejun Heo 		if (tmp & 0x1) {
110191c4a2e0STejun Heo 			ahci_kick_engine(ap, 1);
110291c4a2e0STejun Heo 			return -EBUSY;
110391c4a2e0STejun Heo 		}
110491c4a2e0STejun Heo 	} else
110591c4a2e0STejun Heo 		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
110691c4a2e0STejun Heo 
110791c4a2e0STejun Heo 	return 0;
110891c4a2e0STejun Heo }
110991c4a2e0STejun Heo 
1110cc0680a5STejun Heo static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1111a9cf5e85STejun Heo 			     int pmp, unsigned long deadline)
1112c6fd2807SJeff Garzik {
1113cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1114c6fd2807SJeff Garzik 	const char *reason = NULL;
11152cbb79ebSTejun Heo 	unsigned long now, msecs;
1116c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1117c6fd2807SJeff Garzik 	int rc;
1118c6fd2807SJeff Garzik 
1119c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1120c6fd2807SJeff Garzik 
1121cc0680a5STejun Heo 	if (ata_link_offline(link)) {
1122c6fd2807SJeff Garzik 		DPRINTK("PHY reports no device\n");
1123c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
1124c6fd2807SJeff Garzik 		return 0;
1125c6fd2807SJeff Garzik 	}
1126c6fd2807SJeff Garzik 
1127c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
1128d2e75dffSTejun Heo 	rc = ahci_kick_engine(ap, 1);
1129d2e75dffSTejun Heo 	if (rc)
1130cc0680a5STejun Heo 		ata_link_printk(link, KERN_WARNING,
1131d2e75dffSTejun Heo 				"failed to reset engine (errno=%d)", rc);
1132c6fd2807SJeff Garzik 
1133cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1134c6fd2807SJeff Garzik 
1135c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
11362cbb79ebSTejun Heo 	msecs = 0;
11372cbb79ebSTejun Heo 	now = jiffies;
11382cbb79ebSTejun Heo 	if (time_after(now, deadline))
11392cbb79ebSTejun Heo 		msecs = jiffies_to_msecs(deadline - now);
11402cbb79ebSTejun Heo 
1141c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
1142a9cf5e85STejun Heo 	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
114391c4a2e0STejun Heo 				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
1144c6fd2807SJeff Garzik 		rc = -EIO;
1145c6fd2807SJeff Garzik 		reason = "1st FIS failed";
1146c6fd2807SJeff Garzik 		goto fail;
1147c6fd2807SJeff Garzik 	}
1148c6fd2807SJeff Garzik 
1149c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
1150c6fd2807SJeff Garzik 	msleep(1);
1151c6fd2807SJeff Garzik 
1152c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
1153c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
1154a9cf5e85STejun Heo 	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1155c6fd2807SJeff Garzik 
1156c6fd2807SJeff Garzik 	/* spec mandates ">= 2ms" before checking status.
1157c6fd2807SJeff Garzik 	 * We wait 150ms, because that was the magic delay used for
1158c6fd2807SJeff Garzik 	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time
1159c6fd2807SJeff Garzik 	 * between when the ATA command register is written, and then
1160c6fd2807SJeff Garzik 	 * status is checked.  Because waiting for "a while" before
1161c6fd2807SJeff Garzik 	 * checking status is fine, post SRST, we perform this magic
1162c6fd2807SJeff Garzik 	 * delay here as well.
1163c6fd2807SJeff Garzik 	 */
1164c6fd2807SJeff Garzik 	msleep(150);
1165c6fd2807SJeff Garzik 
1166d4b2bab4STejun Heo 	rc = ata_wait_ready(ap, deadline);
11679b89391cSTejun Heo 	/* link occupied, -ENODEV too is an error */
11689b89391cSTejun Heo 	if (rc) {
1169c6fd2807SJeff Garzik 		reason = "device not ready";
1170c6fd2807SJeff Garzik 		goto fail;
1171c6fd2807SJeff Garzik 	}
1172c6fd2807SJeff Garzik 	*class = ahci_dev_classify(ap);
1173c6fd2807SJeff Garzik 
1174c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
1175c6fd2807SJeff Garzik 	return 0;
1176c6fd2807SJeff Garzik 
1177c6fd2807SJeff Garzik  fail:
1178cc0680a5STejun Heo 	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
1179c6fd2807SJeff Garzik 	return rc;
1180c6fd2807SJeff Garzik }
1181c6fd2807SJeff Garzik 
1182cc0680a5STejun Heo static int ahci_softreset(struct ata_link *link, unsigned int *class,
1183a9cf5e85STejun Heo 			  unsigned long deadline)
1184a9cf5e85STejun Heo {
11857d50b60bSTejun Heo 	int pmp = 0;
11867d50b60bSTejun Heo 
11877d50b60bSTejun Heo 	if (link->ap->flags & ATA_FLAG_PMP)
11887d50b60bSTejun Heo 		pmp = SATA_PMP_CTRL_PORT;
11897d50b60bSTejun Heo 
11907d50b60bSTejun Heo 	return ahci_do_softreset(link, class, pmp, deadline);
1191a9cf5e85STejun Heo }
1192a9cf5e85STejun Heo 
1193cc0680a5STejun Heo static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1194d4b2bab4STejun Heo 			  unsigned long deadline)
1195c6fd2807SJeff Garzik {
1196cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1197c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1198c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1199c6fd2807SJeff Garzik 	struct ata_taskfile tf;
1200c6fd2807SJeff Garzik 	int rc;
1201c6fd2807SJeff Garzik 
1202c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
1203c6fd2807SJeff Garzik 
12044447d351STejun Heo 	ahci_stop_engine(ap);
1205c6fd2807SJeff Garzik 
1206c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1207cc0680a5STejun Heo 	ata_tf_init(link->device, &tf);
1208dfd7a3dbSTejun Heo 	tf.command = 0x80;
12099977126cSTejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1210c6fd2807SJeff Garzik 
1211cc0680a5STejun Heo 	rc = sata_std_hardreset(link, class, deadline);
1212c6fd2807SJeff Garzik 
12134447d351STejun Heo 	ahci_start_engine(ap);
1214c6fd2807SJeff Garzik 
1215cc0680a5STejun Heo 	if (rc == 0 && ata_link_online(link))
1216c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
12177d50b60bSTejun Heo 	if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN)
1218c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
1219c6fd2807SJeff Garzik 
1220c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1221c6fd2807SJeff Garzik 	return rc;
1222c6fd2807SJeff Garzik }
1223c6fd2807SJeff Garzik 
1224cc0680a5STejun Heo static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1225d4b2bab4STejun Heo 				 unsigned long deadline)
1226ad616ffbSTejun Heo {
1227cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
1228da3dbb17STejun Heo 	u32 serror;
1229ad616ffbSTejun Heo 	int rc;
1230ad616ffbSTejun Heo 
1231ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1232ad616ffbSTejun Heo 
12334447d351STejun Heo 	ahci_stop_engine(ap);
1234ad616ffbSTejun Heo 
1235cc0680a5STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
1236d4b2bab4STejun Heo 				 deadline);
1237ad616ffbSTejun Heo 
1238ad616ffbSTejun Heo 	/* vt8251 needs SError cleared for the port to operate */
1239da3dbb17STejun Heo 	ahci_scr_read(ap, SCR_ERROR, &serror);
1240da3dbb17STejun Heo 	ahci_scr_write(ap, SCR_ERROR, serror);
1241ad616ffbSTejun Heo 
12424447d351STejun Heo 	ahci_start_engine(ap);
1243ad616ffbSTejun Heo 
1244ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1245ad616ffbSTejun Heo 
1246ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1247ad616ffbSTejun Heo 	 * request follow-up softreset.
1248ad616ffbSTejun Heo 	 */
1249ad616ffbSTejun Heo 	return rc ?: -EAGAIN;
1250ad616ffbSTejun Heo }
1251ad616ffbSTejun Heo 
1252*edc93052STejun Heo static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1253*edc93052STejun Heo 				unsigned long deadline)
1254*edc93052STejun Heo {
1255*edc93052STejun Heo 	struct ata_port *ap = link->ap;
1256*edc93052STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1257*edc93052STejun Heo 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1258*edc93052STejun Heo 	struct ata_taskfile tf;
1259*edc93052STejun Heo 	int rc;
1260*edc93052STejun Heo 
1261*edc93052STejun Heo 	ahci_stop_engine(ap);
1262*edc93052STejun Heo 
1263*edc93052STejun Heo 	/* clear D2H reception area to properly wait for D2H FIS */
1264*edc93052STejun Heo 	ata_tf_init(link->device, &tf);
1265*edc93052STejun Heo 	tf.command = 0x80;
1266*edc93052STejun Heo 	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1267*edc93052STejun Heo 
1268*edc93052STejun Heo 	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
1269*edc93052STejun Heo 				 deadline);
1270*edc93052STejun Heo 
1271*edc93052STejun Heo 	ahci_start_engine(ap);
1272*edc93052STejun Heo 
1273*edc93052STejun Heo 	if (rc || ata_link_offline(link))
1274*edc93052STejun Heo 		return rc;
1275*edc93052STejun Heo 
1276*edc93052STejun Heo 	/* spec mandates ">= 2ms" before checking status */
1277*edc93052STejun Heo 	msleep(150);
1278*edc93052STejun Heo 
1279*edc93052STejun Heo 	/* The pseudo configuration device on SIMG4726 attached to
1280*edc93052STejun Heo 	 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1281*edc93052STejun Heo 	 * hardreset if no device is attached to the first downstream
1282*edc93052STejun Heo 	 * port && the pseudo device locks up on SRST w/ PMP==0.  To
1283*edc93052STejun Heo 	 * work around this, wait for !BSY only briefly.  If BSY isn't
1284*edc93052STejun Heo 	 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1285*edc93052STejun Heo 	 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1286*edc93052STejun Heo 	 *
1287*edc93052STejun Heo 	 * Wait for two seconds.  Devices attached to downstream port
1288*edc93052STejun Heo 	 * which can't process the following IDENTIFY after this will
1289*edc93052STejun Heo 	 * have to be reset again.  For most cases, this should
1290*edc93052STejun Heo 	 * suffice while making probing snappish enough.
1291*edc93052STejun Heo 	 */
1292*edc93052STejun Heo 	rc = ata_wait_ready(ap, jiffies + 2 * HZ);
1293*edc93052STejun Heo 	if (rc)
1294*edc93052STejun Heo 		ahci_kick_engine(ap, 0);
1295*edc93052STejun Heo 
1296*edc93052STejun Heo 	return 0;
1297*edc93052STejun Heo }
1298*edc93052STejun Heo 
1299cc0680a5STejun Heo static void ahci_postreset(struct ata_link *link, unsigned int *class)
1300c6fd2807SJeff Garzik {
1301cc0680a5STejun Heo 	struct ata_port *ap = link->ap;
13024447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1303c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1304c6fd2807SJeff Garzik 
1305cc0680a5STejun Heo 	ata_std_postreset(link, class);
1306c6fd2807SJeff Garzik 
1307c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1308c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1309c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1310c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
1311c6fd2807SJeff Garzik 	else
1312c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
1313c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
1314c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
1315c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
1316c6fd2807SJeff Garzik 	}
1317c6fd2807SJeff Garzik }
1318c6fd2807SJeff Garzik 
13197d50b60bSTejun Heo static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
13207d50b60bSTejun Heo 			      unsigned long deadline)
13217d50b60bSTejun Heo {
13227d50b60bSTejun Heo 	return ahci_do_softreset(link, class, link->pmp, deadline);
13237d50b60bSTejun Heo }
13247d50b60bSTejun Heo 
1325c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap)
1326c6fd2807SJeff Garzik {
13270d5ff566STejun Heo 	void __iomem *mmio = ap->ioaddr.cmd_addr;
1328c6fd2807SJeff Garzik 
1329c6fd2807SJeff Garzik 	return readl(mmio + PORT_TFDATA) & 0xFF;
1330c6fd2807SJeff Garzik }
1331c6fd2807SJeff Garzik 
1332c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
1333c6fd2807SJeff Garzik {
1334c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1335c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1336c6fd2807SJeff Garzik 
1337c6fd2807SJeff Garzik 	ata_tf_from_fis(d2h_fis, tf);
1338c6fd2807SJeff Garzik }
1339c6fd2807SJeff Garzik 
1340c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
1341c6fd2807SJeff Garzik {
1342c6fd2807SJeff Garzik 	struct scatterlist *sg;
1343c6fd2807SJeff Garzik 	struct ahci_sg *ahci_sg;
1344c6fd2807SJeff Garzik 	unsigned int n_sg = 0;
1345c6fd2807SJeff Garzik 
1346c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1347c6fd2807SJeff Garzik 
1348c6fd2807SJeff Garzik 	/*
1349c6fd2807SJeff Garzik 	 * Next, the S/G list.
1350c6fd2807SJeff Garzik 	 */
1351c6fd2807SJeff Garzik 	ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
1352c6fd2807SJeff Garzik 	ata_for_each_sg(sg, qc) {
1353c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1354c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1355c6fd2807SJeff Garzik 
1356c6fd2807SJeff Garzik 		ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
1357c6fd2807SJeff Garzik 		ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
1358c6fd2807SJeff Garzik 		ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
1359c6fd2807SJeff Garzik 
1360c6fd2807SJeff Garzik 		ahci_sg++;
1361c6fd2807SJeff Garzik 		n_sg++;
1362c6fd2807SJeff Garzik 	}
1363c6fd2807SJeff Garzik 
1364c6fd2807SJeff Garzik 	return n_sg;
1365c6fd2807SJeff Garzik }
1366c6fd2807SJeff Garzik 
1367c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1368c6fd2807SJeff Garzik {
1369c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1370c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1371c6fd2807SJeff Garzik 	int is_atapi = is_atapi_taskfile(&qc->tf);
1372c6fd2807SJeff Garzik 	void *cmd_tbl;
1373c6fd2807SJeff Garzik 	u32 opts;
1374c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1375c6fd2807SJeff Garzik 	unsigned int n_elem;
1376c6fd2807SJeff Garzik 
1377c6fd2807SJeff Garzik 	/*
1378c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1379c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1380c6fd2807SJeff Garzik 	 */
1381c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1382c6fd2807SJeff Garzik 
13837d50b60bSTejun Heo 	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
1384c6fd2807SJeff Garzik 	if (is_atapi) {
1385c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1386c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1387c6fd2807SJeff Garzik 	}
1388c6fd2807SJeff Garzik 
1389c6fd2807SJeff Garzik 	n_elem = 0;
1390c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1391c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1392c6fd2807SJeff Garzik 
1393c6fd2807SJeff Garzik 	/*
1394c6fd2807SJeff Garzik 	 * Fill in command slot information.
1395c6fd2807SJeff Garzik 	 */
13967d50b60bSTejun Heo 	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
1397c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1398c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1399c6fd2807SJeff Garzik 	if (is_atapi)
1400c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1401c6fd2807SJeff Garzik 
1402c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1403c6fd2807SJeff Garzik }
1404c6fd2807SJeff Garzik 
1405c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1406c6fd2807SJeff Garzik {
1407417a1a6dSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1408c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
14097d50b60bSTejun Heo 	struct ata_eh_info *host_ehi = &ap->link.eh_info;
14107d50b60bSTejun Heo 	struct ata_link *link = NULL;
14117d50b60bSTejun Heo 	struct ata_queued_cmd *active_qc;
14127d50b60bSTejun Heo 	struct ata_eh_info *active_ehi;
1413c6fd2807SJeff Garzik 	u32 serror;
1414c6fd2807SJeff Garzik 
14157d50b60bSTejun Heo 	/* determine active link */
14167d50b60bSTejun Heo 	ata_port_for_each_link(link, ap)
14177d50b60bSTejun Heo 		if (ata_link_active(link))
14187d50b60bSTejun Heo 			break;
14197d50b60bSTejun Heo 	if (!link)
14207d50b60bSTejun Heo 		link = &ap->link;
14217d50b60bSTejun Heo 
14227d50b60bSTejun Heo 	active_qc = ata_qc_from_tag(ap, link->active_tag);
14237d50b60bSTejun Heo 	active_ehi = &link->eh_info;
14247d50b60bSTejun Heo 
14257d50b60bSTejun Heo 	/* record irq stat */
14267d50b60bSTejun Heo 	ata_ehi_clear_desc(host_ehi);
14277d50b60bSTejun Heo 	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
1428c6fd2807SJeff Garzik 
1429c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
1430da3dbb17STejun Heo 	ahci_scr_read(ap, SCR_ERROR, &serror);
1431c6fd2807SJeff Garzik 	ahci_scr_write(ap, SCR_ERROR, serror);
14327d50b60bSTejun Heo 	host_ehi->serror |= serror;
1433c6fd2807SJeff Garzik 
143441669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
1435417a1a6dSTejun Heo 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
143641669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
143741669553STejun Heo 
143855a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
14397d50b60bSTejun Heo 		/* If qc is active, charge it; otherwise, the active
14407d50b60bSTejun Heo 		 * link.  There's no active qc on NCQ errors.  It will
14417d50b60bSTejun Heo 		 * be determined by EH by reading log page 10h.
14427d50b60bSTejun Heo 		 */
14437d50b60bSTejun Heo 		if (active_qc)
14447d50b60bSTejun Heo 			active_qc->err_mask |= AC_ERR_DEV;
14457d50b60bSTejun Heo 		else
14467d50b60bSTejun Heo 			active_ehi->err_mask |= AC_ERR_DEV;
14477d50b60bSTejun Heo 
1448417a1a6dSTejun Heo 		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
14497d50b60bSTejun Heo 			host_ehi->serror &= ~SERR_INTERNAL;
1450c6fd2807SJeff Garzik 	}
1451c6fd2807SJeff Garzik 
1452c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
1453c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
1454c6fd2807SJeff Garzik 
14557d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
14567d50b60bSTejun Heo 		active_ehi->action |= ATA_EH_SOFTRESET;
14577d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi,
14587d50b60bSTejun Heo 				  "unknown FIS %08x %08x %08x %08x" ,
1459c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
1460c6fd2807SJeff Garzik 	}
1461c6fd2807SJeff Garzik 
14627d50b60bSTejun Heo 	if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) {
14637d50b60bSTejun Heo 		active_ehi->err_mask |= AC_ERR_HSM;
14647d50b60bSTejun Heo 		active_ehi->action |= ATA_EH_SOFTRESET;
14657d50b60bSTejun Heo 		ata_ehi_push_desc(active_ehi, "incorrect PMP");
14667d50b60bSTejun Heo 	}
1467c6fd2807SJeff Garzik 
14687d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
14697d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_HOST_BUS;
14707d50b60bSTejun Heo 		host_ehi->action |= ATA_EH_SOFTRESET;
14717d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "host bus error");
14727d50b60bSTejun Heo 	}
14737d50b60bSTejun Heo 
14747d50b60bSTejun Heo 	if (irq_stat & PORT_IRQ_IF_ERR) {
14757d50b60bSTejun Heo 		host_ehi->err_mask |= AC_ERR_ATA_BUS;
14767d50b60bSTejun Heo 		host_ehi->action |= ATA_EH_SOFTRESET;
14777d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "interface fatal error");
14787d50b60bSTejun Heo 	}
14797d50b60bSTejun Heo 
14807d50b60bSTejun Heo 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
14817d50b60bSTejun Heo 		ata_ehi_hotplugged(host_ehi);
14827d50b60bSTejun Heo 		ata_ehi_push_desc(host_ehi, "%s",
14837d50b60bSTejun Heo 			irq_stat & PORT_IRQ_CONNECT ?
14847d50b60bSTejun Heo 			"connection status changed" : "PHY RDY changed");
14857d50b60bSTejun Heo 	}
14867d50b60bSTejun Heo 
14877d50b60bSTejun Heo 	/* okay, let's hand over to EH */
1488c6fd2807SJeff Garzik 
1489c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
1490c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1491c6fd2807SJeff Garzik 	else
1492c6fd2807SJeff Garzik 		ata_port_abort(ap);
1493c6fd2807SJeff Garzik }
1494c6fd2807SJeff Garzik 
1495df69c9c5SJeff Garzik static void ahci_port_intr(struct ata_port *ap)
1496c6fd2807SJeff Garzik {
14974447d351STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
14989af5c9c9STejun Heo 	struct ata_eh_info *ehi = &ap->link.eh_info;
14990291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
15005f226c6bSTejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
1501b06ce3e5STejun Heo 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
1502c6fd2807SJeff Garzik 	u32 status, qc_active;
15030291f95fSTejun Heo 	int rc, known_irq = 0;
1504c6fd2807SJeff Garzik 
1505c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
1506c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
1507c6fd2807SJeff Garzik 
1508b06ce3e5STejun Heo 	/* ignore BAD_PMP while resetting */
1509b06ce3e5STejun Heo 	if (unlikely(resetting))
1510b06ce3e5STejun Heo 		status &= ~PORT_IRQ_BAD_PMP;
1511b06ce3e5STejun Heo 
1512c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
1513c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
1514c6fd2807SJeff Garzik 		return;
1515c6fd2807SJeff Garzik 	}
1516c6fd2807SJeff Garzik 
15172f294968SKristen Carlson Accardi 	if (status & PORT_IRQ_SDB_FIS) {
15185f226c6bSTejun Heo 		/* If SNotification is available, leave notification
15195f226c6bSTejun Heo 		 * handling to sata_async_notification().  If not,
15205f226c6bSTejun Heo 		 * emulate it by snooping SDB FIS RX area.
15215f226c6bSTejun Heo 		 *
15225f226c6bSTejun Heo 		 * Snooping FIS RX area is probably cheaper than
15235f226c6bSTejun Heo 		 * poking SNotification but some constrollers which
15245f226c6bSTejun Heo 		 * implement SNotification, ICH9 for example, don't
15255f226c6bSTejun Heo 		 * store AN SDB FIS into receive area.
15265f226c6bSTejun Heo 		 */
15275f226c6bSTejun Heo 		if (hpriv->cap & HOST_CAP_SNTF)
15285f226c6bSTejun Heo 			sata_async_notification(ap);
15295f226c6bSTejun Heo 		else {
15305f226c6bSTejun Heo 			/* If the 'N' bit in word 0 of the FIS is set,
15315f226c6bSTejun Heo 			 * we just received asynchronous notification.
15325f226c6bSTejun Heo 			 * Tell libata about it.
15332f294968SKristen Carlson Accardi 			 */
15342f294968SKristen Carlson Accardi 			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
15352f294968SKristen Carlson Accardi 			u32 f0 = le32_to_cpu(f[0]);
15362f294968SKristen Carlson Accardi 
15377d77b247STejun Heo 			if (f0 & (1 << 15))
15387d77b247STejun Heo 				sata_async_notification(ap);
15392f294968SKristen Carlson Accardi 		}
15405f226c6bSTejun Heo 	}
15412f294968SKristen Carlson Accardi 
15427d50b60bSTejun Heo 	/* pp->active_link is valid iff any command is in flight */
15437d50b60bSTejun Heo 	if (ap->qc_active && pp->active_link->sactive)
1544c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
1545c6fd2807SJeff Garzik 	else
1546c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
1547c6fd2807SJeff Garzik 
1548c6fd2807SJeff Garzik 	rc = ata_qc_complete_multiple(ap, qc_active, NULL);
1549b06ce3e5STejun Heo 
1550b06ce3e5STejun Heo 	/* If resetting, spurious or invalid completions are expected,
1551b06ce3e5STejun Heo 	 * return unconditionally.
1552b06ce3e5STejun Heo 	 */
1553b06ce3e5STejun Heo 	if (resetting)
1554b06ce3e5STejun Heo 		return;
1555b06ce3e5STejun Heo 
1556c6fd2807SJeff Garzik 	if (rc > 0)
1557c6fd2807SJeff Garzik 		return;
1558c6fd2807SJeff Garzik 	if (rc < 0) {
1559c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
1560c6fd2807SJeff Garzik 		ehi->action |= ATA_EH_SOFTRESET;
1561c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1562c6fd2807SJeff Garzik 		return;
1563c6fd2807SJeff Garzik 	}
1564c6fd2807SJeff Garzik 
15653a4fa0a2SRobert P. J. Day 	/* hmmm... a spurious interrupt */
1566c6fd2807SJeff Garzik 
15670291f95fSTejun Heo 	/* if !NCQ, ignore.  No modern ATA device has broken HSM
15680291f95fSTejun Heo 	 * implementation for non-NCQ commands.
15690291f95fSTejun Heo 	 */
15709af5c9c9STejun Heo 	if (!ap->link.sactive)
1571c6fd2807SJeff Garzik 		return;
1572c6fd2807SJeff Garzik 
15730291f95fSTejun Heo 	if (status & PORT_IRQ_D2H_REG_FIS) {
15740291f95fSTejun Heo 		if (!pp->ncq_saw_d2h)
15750291f95fSTejun Heo 			ata_port_printk(ap, KERN_INFO,
15760291f95fSTejun Heo 				"D2H reg with I during NCQ, "
15770291f95fSTejun Heo 				"this message won't be printed again\n");
15780291f95fSTejun Heo 		pp->ncq_saw_d2h = 1;
15790291f95fSTejun Heo 		known_irq = 1;
15800291f95fSTejun Heo 	}
1581c6fd2807SJeff Garzik 
15820291f95fSTejun Heo 	if (status & PORT_IRQ_DMAS_FIS) {
15830291f95fSTejun Heo 		if (!pp->ncq_saw_dmas)
15840291f95fSTejun Heo 			ata_port_printk(ap, KERN_INFO,
15850291f95fSTejun Heo 				"DMAS FIS during NCQ, "
15860291f95fSTejun Heo 				"this message won't be printed again\n");
15870291f95fSTejun Heo 		pp->ncq_saw_dmas = 1;
15880291f95fSTejun Heo 		known_irq = 1;
15890291f95fSTejun Heo 	}
15900291f95fSTejun Heo 
1591a2bbd0c9STejun Heo 	if (status & PORT_IRQ_SDB_FIS) {
159204d4f7a1SAl Viro 		const __le32 *f = pp->rx_fis + RX_FIS_SDB;
15930291f95fSTejun Heo 
1594afb2d552STejun Heo 		if (le32_to_cpu(f[1])) {
1595afb2d552STejun Heo 			/* SDB FIS containing spurious completions
1596afb2d552STejun Heo 			 * might be dangerous, whine and fail commands
1597afb2d552STejun Heo 			 * with HSM violation.  EH will turn off NCQ
1598afb2d552STejun Heo 			 * after several such failures.
1599afb2d552STejun Heo 			 */
1600afb2d552STejun Heo 			ata_ehi_push_desc(ehi,
1601afb2d552STejun Heo 				"spurious completions during NCQ "
1602a2bbd0c9STejun Heo 				"issue=0x%x SAct=0x%x FIS=%08x:%08x",
16030291f95fSTejun Heo 				readl(port_mmio + PORT_CMD_ISSUE),
16046096b63eSTejun Heo 				readl(port_mmio + PORT_SCR_ACT),
1605a2bbd0c9STejun Heo 				le32_to_cpu(f[0]), le32_to_cpu(f[1]));
1606a2bbd0c9STejun Heo 			ehi->err_mask |= AC_ERR_HSM;
1607a2bbd0c9STejun Heo 			ehi->action |= ATA_EH_SOFTRESET;
1608a2bbd0c9STejun Heo 			ata_port_freeze(ap);
1609afb2d552STejun Heo 		} else {
1610afb2d552STejun Heo 			if (!pp->ncq_saw_sdb)
1611afb2d552STejun Heo 				ata_port_printk(ap, KERN_INFO,
1612afb2d552STejun Heo 					"spurious SDB FIS %08x:%08x during NCQ, "
1613afb2d552STejun Heo 					"this message won't be printed again\n",
1614afb2d552STejun Heo 					le32_to_cpu(f[0]), le32_to_cpu(f[1]));
1615afb2d552STejun Heo 			pp->ncq_saw_sdb = 1;
1616afb2d552STejun Heo 		}
16170291f95fSTejun Heo 		known_irq = 1;
16180291f95fSTejun Heo 	}
16190291f95fSTejun Heo 
16200291f95fSTejun Heo 	if (!known_irq)
1621c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
16220291f95fSTejun Heo 				"(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
16239af5c9c9STejun Heo 				status, ap->link.active_tag, ap->link.sactive);
1624c6fd2807SJeff Garzik }
1625c6fd2807SJeff Garzik 
1626c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap)
1627c6fd2807SJeff Garzik {
1628c6fd2807SJeff Garzik 	/* TODO */
1629c6fd2807SJeff Garzik }
1630c6fd2807SJeff Garzik 
16317d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1632c6fd2807SJeff Garzik {
1633cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
1634c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1635c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
1636c6fd2807SJeff Garzik 	void __iomem *mmio;
1637c6fd2807SJeff Garzik 	u32 irq_stat, irq_ack = 0;
1638c6fd2807SJeff Garzik 
1639c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1640c6fd2807SJeff Garzik 
1641cca3974eSJeff Garzik 	hpriv = host->private_data;
16420d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
1643c6fd2807SJeff Garzik 
1644c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
1645c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
1646c6fd2807SJeff Garzik 	irq_stat &= hpriv->port_map;
1647c6fd2807SJeff Garzik 	if (!irq_stat)
1648c6fd2807SJeff Garzik 		return IRQ_NONE;
1649c6fd2807SJeff Garzik 
1650cca3974eSJeff Garzik 	spin_lock(&host->lock);
1651c6fd2807SJeff Garzik 
1652cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
1653c6fd2807SJeff Garzik 		struct ata_port *ap;
1654c6fd2807SJeff Garzik 
1655c6fd2807SJeff Garzik 		if (!(irq_stat & (1 << i)))
1656c6fd2807SJeff Garzik 			continue;
1657c6fd2807SJeff Garzik 
1658cca3974eSJeff Garzik 		ap = host->ports[i];
1659c6fd2807SJeff Garzik 		if (ap) {
1660df69c9c5SJeff Garzik 			ahci_port_intr(ap);
1661c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
1662c6fd2807SJeff Garzik 		} else {
1663c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
1664c6fd2807SJeff Garzik 			if (ata_ratelimit())
1665cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
1666c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
1667c6fd2807SJeff Garzik 		}
1668c6fd2807SJeff Garzik 
1669c6fd2807SJeff Garzik 		irq_ack |= (1 << i);
1670c6fd2807SJeff Garzik 	}
1671c6fd2807SJeff Garzik 
1672c6fd2807SJeff Garzik 	if (irq_ack) {
1673c6fd2807SJeff Garzik 		writel(irq_ack, mmio + HOST_IRQ_STAT);
1674c6fd2807SJeff Garzik 		handled = 1;
1675c6fd2807SJeff Garzik 	}
1676c6fd2807SJeff Garzik 
1677cca3974eSJeff Garzik 	spin_unlock(&host->lock);
1678c6fd2807SJeff Garzik 
1679c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1680c6fd2807SJeff Garzik 
1681c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
1682c6fd2807SJeff Garzik }
1683c6fd2807SJeff Garzik 
1684c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
1685c6fd2807SJeff Garzik {
1686c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
16874447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
16887d50b60bSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
16897d50b60bSTejun Heo 
16907d50b60bSTejun Heo 	/* Keep track of the currently active link.  It will be used
16917d50b60bSTejun Heo 	 * in completion path to determine whether NCQ phase is in
16927d50b60bSTejun Heo 	 * progress.
16937d50b60bSTejun Heo 	 */
16947d50b60bSTejun Heo 	pp->active_link = qc->dev->link;
1695c6fd2807SJeff Garzik 
1696c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
1697c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
1698c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
1699c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
1700c6fd2807SJeff Garzik 
1701c6fd2807SJeff Garzik 	return 0;
1702c6fd2807SJeff Garzik }
1703c6fd2807SJeff Garzik 
1704c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
1705c6fd2807SJeff Garzik {
17064447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1707c6fd2807SJeff Garzik 
1708c6fd2807SJeff Garzik 	/* turn IRQ off */
1709c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
1710c6fd2807SJeff Garzik }
1711c6fd2807SJeff Garzik 
1712c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
1713c6fd2807SJeff Garzik {
17140d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
17154447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1716c6fd2807SJeff Garzik 	u32 tmp;
1717a7384925SKristen Carlson Accardi 	struct ahci_port_priv *pp = ap->private_data;
1718c6fd2807SJeff Garzik 
1719c6fd2807SJeff Garzik 	/* clear IRQ */
1720c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1721c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
1722a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
1723c6fd2807SJeff Garzik 
17241c954a4dSTejun Heo 	/* turn IRQ back on */
17251c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
1726c6fd2807SJeff Garzik }
1727c6fd2807SJeff Garzik 
1728c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
1729c6fd2807SJeff Garzik {
1730c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1731c6fd2807SJeff Garzik 		/* restart engine */
17324447d351STejun Heo 		ahci_stop_engine(ap);
17334447d351STejun Heo 		ahci_start_engine(ap);
1734c6fd2807SJeff Garzik 	}
1735c6fd2807SJeff Garzik 
1736c6fd2807SJeff Garzik 	/* perform recovery */
17377d50b60bSTejun Heo 	sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset,
17387d50b60bSTejun Heo 		       ahci_hardreset, ahci_postreset,
17397d50b60bSTejun Heo 		       sata_pmp_std_prereset, ahci_pmp_softreset,
17407d50b60bSTejun Heo 		       sata_pmp_std_hardreset, sata_pmp_std_postreset);
1741c6fd2807SJeff Garzik }
1742c6fd2807SJeff Garzik 
1743ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap)
1744ad616ffbSTejun Heo {
1745ad616ffbSTejun Heo 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1746ad616ffbSTejun Heo 		/* restart engine */
17474447d351STejun Heo 		ahci_stop_engine(ap);
17484447d351STejun Heo 		ahci_start_engine(ap);
1749ad616ffbSTejun Heo 	}
1750ad616ffbSTejun Heo 
1751ad616ffbSTejun Heo 	/* perform recovery */
1752ad616ffbSTejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset,
1753ad616ffbSTejun Heo 		  ahci_postreset);
1754ad616ffbSTejun Heo }
1755ad616ffbSTejun Heo 
1756*edc93052STejun Heo static void ahci_p5wdh_error_handler(struct ata_port *ap)
1757*edc93052STejun Heo {
1758*edc93052STejun Heo 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1759*edc93052STejun Heo 		/* restart engine */
1760*edc93052STejun Heo 		ahci_stop_engine(ap);
1761*edc93052STejun Heo 		ahci_start_engine(ap);
1762*edc93052STejun Heo 	}
1763*edc93052STejun Heo 
1764*edc93052STejun Heo 	/* perform recovery */
1765*edc93052STejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_p5wdh_hardreset,
1766*edc93052STejun Heo 		  ahci_postreset);
1767*edc93052STejun Heo }
1768*edc93052STejun Heo 
1769c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
1770c6fd2807SJeff Garzik {
1771c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1772c6fd2807SJeff Garzik 
1773c6fd2807SJeff Garzik 	/* make DMA engine forget about the failed command */
1774d2e75dffSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED)
1775d2e75dffSTejun Heo 		ahci_kick_engine(ap, 1);
1776c6fd2807SJeff Garzik }
1777c6fd2807SJeff Garzik 
17787d50b60bSTejun Heo static void ahci_pmp_attach(struct ata_port *ap)
17797d50b60bSTejun Heo {
17807d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
17811c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
17827d50b60bSTejun Heo 	u32 cmd;
17837d50b60bSTejun Heo 
17847d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
17857d50b60bSTejun Heo 	cmd |= PORT_CMD_PMP;
17867d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
17871c954a4dSTejun Heo 
17881c954a4dSTejun Heo 	pp->intr_mask |= PORT_IRQ_BAD_PMP;
17891c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
17907d50b60bSTejun Heo }
17917d50b60bSTejun Heo 
17927d50b60bSTejun Heo static void ahci_pmp_detach(struct ata_port *ap)
17937d50b60bSTejun Heo {
17947d50b60bSTejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
17951c954a4dSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
17967d50b60bSTejun Heo 	u32 cmd;
17977d50b60bSTejun Heo 
17987d50b60bSTejun Heo 	cmd = readl(port_mmio + PORT_CMD);
17997d50b60bSTejun Heo 	cmd &= ~PORT_CMD_PMP;
18007d50b60bSTejun Heo 	writel(cmd, port_mmio + PORT_CMD);
18011c954a4dSTejun Heo 
18021c954a4dSTejun Heo 	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
18031c954a4dSTejun Heo 	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
18047d50b60bSTejun Heo }
18057d50b60bSTejun Heo 
1806028a2596SAlexey Dobriyan static int ahci_port_resume(struct ata_port *ap)
1807028a2596SAlexey Dobriyan {
1808028a2596SAlexey Dobriyan 	ahci_power_up(ap);
1809028a2596SAlexey Dobriyan 	ahci_start_port(ap);
1810028a2596SAlexey Dobriyan 
18117d50b60bSTejun Heo 	if (ap->nr_pmp_links)
18127d50b60bSTejun Heo 		ahci_pmp_attach(ap);
18137d50b60bSTejun Heo 	else
18147d50b60bSTejun Heo 		ahci_pmp_detach(ap);
18157d50b60bSTejun Heo 
1816028a2596SAlexey Dobriyan 	return 0;
1817028a2596SAlexey Dobriyan }
1818028a2596SAlexey Dobriyan 
1819438ac6d5STejun Heo #ifdef CONFIG_PM
1820c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
1821c6fd2807SJeff Garzik {
1822c6fd2807SJeff Garzik 	const char *emsg = NULL;
1823c6fd2807SJeff Garzik 	int rc;
1824c6fd2807SJeff Garzik 
18254447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
18268e16f941STejun Heo 	if (rc == 0)
18274447d351STejun Heo 		ahci_power_down(ap);
18288e16f941STejun Heo 	else {
1829c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
1830df69c9c5SJeff Garzik 		ahci_start_port(ap);
1831c6fd2807SJeff Garzik 	}
1832c6fd2807SJeff Garzik 
1833c6fd2807SJeff Garzik 	return rc;
1834c6fd2807SJeff Garzik }
1835c6fd2807SJeff Garzik 
1836c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
1837c6fd2807SJeff Garzik {
1838cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
18390d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1840c6fd2807SJeff Garzik 	u32 ctl;
1841c6fd2807SJeff Garzik 
1842c6fd2807SJeff Garzik 	if (mesg.event == PM_EVENT_SUSPEND) {
1843c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
1844c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
1845c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
1846c6fd2807SJeff Garzik 		 */
1847c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
1848c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
1849c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
1850c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
1851c6fd2807SJeff Garzik 	}
1852c6fd2807SJeff Garzik 
1853c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
1854c6fd2807SJeff Garzik }
1855c6fd2807SJeff Garzik 
1856c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
1857c6fd2807SJeff Garzik {
1858cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
1859c6fd2807SJeff Garzik 	int rc;
1860c6fd2807SJeff Garzik 
1861553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
1862553c4aa6STejun Heo 	if (rc)
1863553c4aa6STejun Heo 		return rc;
1864c6fd2807SJeff Garzik 
1865c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
18664447d351STejun Heo 		rc = ahci_reset_controller(host);
1867c6fd2807SJeff Garzik 		if (rc)
1868c6fd2807SJeff Garzik 			return rc;
1869c6fd2807SJeff Garzik 
18704447d351STejun Heo 		ahci_init_controller(host);
1871c6fd2807SJeff Garzik 	}
1872c6fd2807SJeff Garzik 
1873cca3974eSJeff Garzik 	ata_host_resume(host);
1874c6fd2807SJeff Garzik 
1875c6fd2807SJeff Garzik 	return 0;
1876c6fd2807SJeff Garzik }
1877438ac6d5STejun Heo #endif
1878c6fd2807SJeff Garzik 
1879c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
1880c6fd2807SJeff Garzik {
1881cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
1882c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
1883c6fd2807SJeff Garzik 	void *mem;
1884c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
1885c6fd2807SJeff Garzik 	int rc;
1886c6fd2807SJeff Garzik 
188724dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
1888c6fd2807SJeff Garzik 	if (!pp)
1889c6fd2807SJeff Garzik 		return -ENOMEM;
1890c6fd2807SJeff Garzik 
1891c6fd2807SJeff Garzik 	rc = ata_pad_alloc(ap, dev);
189224dc5f33STejun Heo 	if (rc)
1893c6fd2807SJeff Garzik 		return rc;
1894c6fd2807SJeff Garzik 
189524dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
189624dc5f33STejun Heo 				  GFP_KERNEL);
189724dc5f33STejun Heo 	if (!mem)
1898c6fd2807SJeff Garzik 		return -ENOMEM;
1899c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
1900c6fd2807SJeff Garzik 
1901c6fd2807SJeff Garzik 	/*
1902c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
1903c6fd2807SJeff Garzik 	 * 32 bytes each in size
1904c6fd2807SJeff Garzik 	 */
1905c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
1906c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
1907c6fd2807SJeff Garzik 
1908c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
1909c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
1910c6fd2807SJeff Garzik 
1911c6fd2807SJeff Garzik 	/*
1912c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
1913c6fd2807SJeff Garzik 	 */
1914c6fd2807SJeff Garzik 	pp->rx_fis = mem;
1915c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
1916c6fd2807SJeff Garzik 
1917c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
1918c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
1919c6fd2807SJeff Garzik 
1920c6fd2807SJeff Garzik 	/*
1921c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
1922c6fd2807SJeff Garzik 	 * and its scatter-gather table
1923c6fd2807SJeff Garzik 	 */
1924c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
1925c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
1926c6fd2807SJeff Garzik 
1927a7384925SKristen Carlson Accardi 	/*
1928a7384925SKristen Carlson Accardi 	 * Save off initial list of interrupts to be enabled.
1929a7384925SKristen Carlson Accardi 	 * This could be changed later
1930a7384925SKristen Carlson Accardi 	 */
1931a7384925SKristen Carlson Accardi 	pp->intr_mask = DEF_PORT_IRQ;
1932a7384925SKristen Carlson Accardi 
1933c6fd2807SJeff Garzik 	ap->private_data = pp;
1934c6fd2807SJeff Garzik 
1935df69c9c5SJeff Garzik 	/* engage engines, captain */
1936df69c9c5SJeff Garzik 	return ahci_port_resume(ap);
1937c6fd2807SJeff Garzik }
1938c6fd2807SJeff Garzik 
1939c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
1940c6fd2807SJeff Garzik {
1941c6fd2807SJeff Garzik 	const char *emsg = NULL;
1942c6fd2807SJeff Garzik 	int rc;
1943c6fd2807SJeff Garzik 
1944c6fd2807SJeff Garzik 	/* de-initialize port */
19454447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1946c6fd2807SJeff Garzik 	if (rc)
1947c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
1948c6fd2807SJeff Garzik }
1949c6fd2807SJeff Garzik 
19504447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
1951c6fd2807SJeff Garzik {
1952c6fd2807SJeff Garzik 	int rc;
1953c6fd2807SJeff Garzik 
1954c6fd2807SJeff Garzik 	if (using_dac &&
1955c6fd2807SJeff Garzik 	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
1956c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
1957c6fd2807SJeff Garzik 		if (rc) {
1958c6fd2807SJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1959c6fd2807SJeff Garzik 			if (rc) {
1960c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
1961c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
1962c6fd2807SJeff Garzik 				return rc;
1963c6fd2807SJeff Garzik 			}
1964c6fd2807SJeff Garzik 		}
1965c6fd2807SJeff Garzik 	} else {
1966c6fd2807SJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
1967c6fd2807SJeff Garzik 		if (rc) {
1968c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1969c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
1970c6fd2807SJeff Garzik 			return rc;
1971c6fd2807SJeff Garzik 		}
1972c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1973c6fd2807SJeff Garzik 		if (rc) {
1974c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1975c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
1976c6fd2807SJeff Garzik 			return rc;
1977c6fd2807SJeff Garzik 		}
1978c6fd2807SJeff Garzik 	}
1979c6fd2807SJeff Garzik 	return 0;
1980c6fd2807SJeff Garzik }
1981c6fd2807SJeff Garzik 
19824447d351STejun Heo static void ahci_print_info(struct ata_host *host)
1983c6fd2807SJeff Garzik {
19844447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
19854447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
19864447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1987c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
1988c6fd2807SJeff Garzik 	const char *speed_s;
1989c6fd2807SJeff Garzik 	u16 cc;
1990c6fd2807SJeff Garzik 	const char *scc_s;
1991c6fd2807SJeff Garzik 
1992c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
1993c6fd2807SJeff Garzik 	cap = hpriv->cap;
1994c6fd2807SJeff Garzik 	impl = hpriv->port_map;
1995c6fd2807SJeff Garzik 
1996c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
1997c6fd2807SJeff Garzik 	if (speed == 1)
1998c6fd2807SJeff Garzik 		speed_s = "1.5";
1999c6fd2807SJeff Garzik 	else if (speed == 2)
2000c6fd2807SJeff Garzik 		speed_s = "3";
2001c6fd2807SJeff Garzik 	else
2002c6fd2807SJeff Garzik 		speed_s = "?";
2003c6fd2807SJeff Garzik 
2004c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
2005c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
2006c6fd2807SJeff Garzik 		scc_s = "IDE";
2007c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
2008c6fd2807SJeff Garzik 		scc_s = "SATA";
2009c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
2010c6fd2807SJeff Garzik 		scc_s = "RAID";
2011c6fd2807SJeff Garzik 	else
2012c6fd2807SJeff Garzik 		scc_s = "unknown";
2013c6fd2807SJeff Garzik 
2014c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2015c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
2016c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
2017c6fd2807SJeff Garzik 		,
2018c6fd2807SJeff Garzik 
2019c6fd2807SJeff Garzik 		(vers >> 24) & 0xff,
2020c6fd2807SJeff Garzik 		(vers >> 16) & 0xff,
2021c6fd2807SJeff Garzik 		(vers >> 8) & 0xff,
2022c6fd2807SJeff Garzik 		vers & 0xff,
2023c6fd2807SJeff Garzik 
2024c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
2025c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
2026c6fd2807SJeff Garzik 		speed_s,
2027c6fd2807SJeff Garzik 		impl,
2028c6fd2807SJeff Garzik 		scc_s);
2029c6fd2807SJeff Garzik 
2030c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
2031c6fd2807SJeff Garzik 		"flags: "
2032203ef6c4STejun Heo 		"%s%s%s%s%s%s%s"
2033c6fd2807SJeff Garzik 		"%s%s%s%s%s%s%s\n"
2034c6fd2807SJeff Garzik 		,
2035c6fd2807SJeff Garzik 
2036c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
2037c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
2038203ef6c4STejun Heo 		cap & (1 << 29) ? "sntf " : "",
2039c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
2040c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
2041c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
2042c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
2043c6fd2807SJeff Garzik 
2044c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
2045c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
2046c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
2047c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
2048c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
2049c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
2050c6fd2807SJeff Garzik 		cap & (1 << 13) ? "part " : ""
2051c6fd2807SJeff Garzik 		);
2052c6fd2807SJeff Garzik }
2053c6fd2807SJeff Garzik 
2054*edc93052STejun Heo /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2055*edc93052STejun Heo  * hardwired to on-board SIMG 4726.  The chipset is ICH8 and doesn't
2056*edc93052STejun Heo  * support PMP and the 4726 either directly exports the device
2057*edc93052STejun Heo  * attached to the first downstream port or acts as a hardware storage
2058*edc93052STejun Heo  * controller and emulate a single ATA device (can be RAID 0/1 or some
2059*edc93052STejun Heo  * other configuration).
2060*edc93052STejun Heo  *
2061*edc93052STejun Heo  * When there's no device attached to the first downstream port of the
2062*edc93052STejun Heo  * 4726, "Config Disk" appears, which is a pseudo ATA device to
2063*edc93052STejun Heo  * configure the 4726.  However, ATA emulation of the device is very
2064*edc93052STejun Heo  * lame.  It doesn't send signature D2H Reg FIS after the initial
2065*edc93052STejun Heo  * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2066*edc93052STejun Heo  *
2067*edc93052STejun Heo  * The following function works around the problem by always using
2068*edc93052STejun Heo  * hardreset on the port and not depending on receiving signature FIS
2069*edc93052STejun Heo  * afterward.  If signature FIS isn't received soon, ATA class is
2070*edc93052STejun Heo  * assumed without follow-up softreset.
2071*edc93052STejun Heo  */
2072*edc93052STejun Heo static void ahci_p5wdh_workaround(struct ata_host *host)
2073*edc93052STejun Heo {
2074*edc93052STejun Heo 	static struct dmi_system_id sysids[] = {
2075*edc93052STejun Heo 		{
2076*edc93052STejun Heo 			.ident = "P5W DH Deluxe",
2077*edc93052STejun Heo 			.matches = {
2078*edc93052STejun Heo 				DMI_MATCH(DMI_SYS_VENDOR,
2079*edc93052STejun Heo 					  "ASUSTEK COMPUTER INC"),
2080*edc93052STejun Heo 				DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2081*edc93052STejun Heo 			},
2082*edc93052STejun Heo 		},
2083*edc93052STejun Heo 		{ }
2084*edc93052STejun Heo 	};
2085*edc93052STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
2086*edc93052STejun Heo 
2087*edc93052STejun Heo 	if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2088*edc93052STejun Heo 	    dmi_check_system(sysids)) {
2089*edc93052STejun Heo 		struct ata_port *ap = host->ports[1];
2090*edc93052STejun Heo 
2091*edc93052STejun Heo 		dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2092*edc93052STejun Heo 			   "Deluxe on-board SIMG4726 workaround\n");
2093*edc93052STejun Heo 
2094*edc93052STejun Heo 		ap->ops = &ahci_p5wdh_ops;
2095*edc93052STejun Heo 		ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2096*edc93052STejun Heo 	}
2097*edc93052STejun Heo }
2098*edc93052STejun Heo 
2099c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2100c6fd2807SJeff Garzik {
2101c6fd2807SJeff Garzik 	static int printed_version;
21024447d351STejun Heo 	struct ata_port_info pi = ahci_port_info[ent->driver_data];
21034447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
210424dc5f33STejun Heo 	struct device *dev = &pdev->dev;
2105c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
21064447d351STejun Heo 	struct ata_host *host;
21074447d351STejun Heo 	int i, rc;
2108c6fd2807SJeff Garzik 
2109c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
2110c6fd2807SJeff Garzik 
2111c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
2112c6fd2807SJeff Garzik 
2113c6fd2807SJeff Garzik 	if (!printed_version++)
2114c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
2115c6fd2807SJeff Garzik 
21164447d351STejun Heo 	/* acquire resources */
211724dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
2118c6fd2807SJeff Garzik 	if (rc)
2119c6fd2807SJeff Garzik 		return rc;
2120c6fd2807SJeff Garzik 
21210d5ff566STejun Heo 	rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
21220d5ff566STejun Heo 	if (rc == -EBUSY)
212324dc5f33STejun Heo 		pcim_pin_device(pdev);
21240d5ff566STejun Heo 	if (rc)
212524dc5f33STejun Heo 		return rc;
2126c6fd2807SJeff Garzik 
212724dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
212824dc5f33STejun Heo 	if (!hpriv)
212924dc5f33STejun Heo 		return -ENOMEM;
2130417a1a6dSTejun Heo 	hpriv->flags |= (unsigned long)pi.private_data;
2131417a1a6dSTejun Heo 
2132417a1a6dSTejun Heo 	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
2133417a1a6dSTejun Heo 		pci_intx(pdev, 1);
2134c6fd2807SJeff Garzik 
21354447d351STejun Heo 	/* save initial config */
2136417a1a6dSTejun Heo 	ahci_save_initial_config(pdev, hpriv);
2137c6fd2807SJeff Garzik 
21384447d351STejun Heo 	/* prepare host */
2139274c1fdeSTejun Heo 	if (hpriv->cap & HOST_CAP_NCQ)
21404447d351STejun Heo 		pi.flags |= ATA_FLAG_NCQ;
21414447d351STejun Heo 
21427d50b60bSTejun Heo 	if (hpriv->cap & HOST_CAP_PMP)
21437d50b60bSTejun Heo 		pi.flags |= ATA_FLAG_PMP;
21447d50b60bSTejun Heo 
21454447d351STejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
21464447d351STejun Heo 	if (!host)
21474447d351STejun Heo 		return -ENOMEM;
21484447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
21494447d351STejun Heo 	host->private_data = hpriv;
21504447d351STejun Heo 
21514447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
21524447d351STejun Heo 		struct ata_port *ap = host->ports[i];
21534447d351STejun Heo 		void __iomem *port_mmio = ahci_port_base(ap);
21544447d351STejun Heo 
2155cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
2156cbcdd875STejun Heo 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
2157cbcdd875STejun Heo 				   0x100 + ap->port_no * 0x80, "port");
2158cbcdd875STejun Heo 
2159dab632e8SJeff Garzik 		/* standard SATA port setup */
2160203ef6c4STejun Heo 		if (hpriv->port_map & (1 << i))
21614447d351STejun Heo 			ap->ioaddr.cmd_addr = port_mmio;
2162dab632e8SJeff Garzik 
2163dab632e8SJeff Garzik 		/* disabled/not-implemented port */
2164dab632e8SJeff Garzik 		else
2165dab632e8SJeff Garzik 			ap->ops = &ata_dummy_port_ops;
21664447d351STejun Heo 	}
2167c6fd2807SJeff Garzik 
2168*edc93052STejun Heo 	/* apply workaround for ASUS P5W DH Deluxe mainboard */
2169*edc93052STejun Heo 	ahci_p5wdh_workaround(host);
2170*edc93052STejun Heo 
2171c6fd2807SJeff Garzik 	/* initialize adapter */
21724447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
2173c6fd2807SJeff Garzik 	if (rc)
217424dc5f33STejun Heo 		return rc;
2175c6fd2807SJeff Garzik 
21764447d351STejun Heo 	rc = ahci_reset_controller(host);
21774447d351STejun Heo 	if (rc)
21784447d351STejun Heo 		return rc;
2179c6fd2807SJeff Garzik 
21804447d351STejun Heo 	ahci_init_controller(host);
21814447d351STejun Heo 	ahci_print_info(host);
2182c6fd2807SJeff Garzik 
21834447d351STejun Heo 	pci_set_master(pdev);
21844447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
21854447d351STejun Heo 				 &ahci_sht);
2186c6fd2807SJeff Garzik }
2187c6fd2807SJeff Garzik 
2188c6fd2807SJeff Garzik static int __init ahci_init(void)
2189c6fd2807SJeff Garzik {
2190c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
2191c6fd2807SJeff Garzik }
2192c6fd2807SJeff Garzik 
2193c6fd2807SJeff Garzik static void __exit ahci_exit(void)
2194c6fd2807SJeff Garzik {
2195c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
2196c6fd2807SJeff Garzik }
2197c6fd2807SJeff Garzik 
2198c6fd2807SJeff Garzik 
2199c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
2200c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
2201c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
2202c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
2203c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
2204c6fd2807SJeff Garzik 
2205c6fd2807SJeff Garzik module_init(ahci_init);
2206c6fd2807SJeff Garzik module_exit(ahci_exit);
2207