xref: /openbmc/linux/drivers/ata/ahci.c (revision 438ac6d5e3f8106a6bd1a5682c508d660294a85d)
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>
44c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
45c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
46c6fd2807SJeff Garzik #include <linux/libata.h>
47c6fd2807SJeff Garzik 
48c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
49cb48cab7SJeff Garzik #define DRV_VERSION	"2.1"
50c6fd2807SJeff Garzik 
51c6fd2807SJeff Garzik 
52c6fd2807SJeff Garzik enum {
53c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
54648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
55c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
56c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
57c6fd2807SJeff Garzik 	AHCI_USE_CLUSTERING	= 0,
58c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
59c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
60c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
61c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
62c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
63c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
64c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
65c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
66c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
67c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
68c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
69c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
70c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
71c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
72c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
73c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
74c6fd2807SJeff Garzik 
75c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
760291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
77c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
78c6fd2807SJeff Garzik 
79c6fd2807SJeff Garzik 	board_ahci		= 0,
80648a88beSTejun Heo 	board_ahci_pi		= 1,
81648a88beSTejun Heo 	board_ahci_vt8251	= 2,
82648a88beSTejun Heo 	board_ahci_ign_iferr	= 3,
83c6fd2807SJeff Garzik 
84c6fd2807SJeff Garzik 	/* global controller registers */
85c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
86c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
87c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
88c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
89c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
90c6fd2807SJeff Garzik 
91c6fd2807SJeff Garzik 	/* HOST_CTL bits */
92c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
93c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
94c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
95c6fd2807SJeff Garzik 
96c6fd2807SJeff Garzik 	/* HOST_CAP bits */
97c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
98c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
99c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
100c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
101c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
102c6fd2807SJeff Garzik 
103c6fd2807SJeff Garzik 	/* registers for each SATA port */
104c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
105c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
106c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
107c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
108c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
109c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
110c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
111c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
112c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
113c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
114c6fd2807SJeff Garzik 	PORT_SCR		= 0x28, /* SATA phy register block */
115c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
116c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
117c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
118c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
119c6fd2807SJeff Garzik 
120c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
121c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
122c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
123c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
124c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
125c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
126c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
127c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
128c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
129c6fd2807SJeff Garzik 
130c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
131c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
132c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
133c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
134c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
135c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
136c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
137c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
138c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
139c6fd2807SJeff Garzik 
140c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
141c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
142c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
143c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
144c6fd2807SJeff Garzik 				  PORT_IRQ_UNK_FIS,
145c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
146c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
147c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
148c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
149c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
150c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
151c6fd2807SJeff Garzik 
152c6fd2807SJeff Garzik 	/* PORT_CMD bits */
153c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
154c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
155c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
156c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
157c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
158c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
159c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
160c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
161c6fd2807SJeff Garzik 
162c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
163c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
164c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
165c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
166c6fd2807SJeff Garzik 
167c6fd2807SJeff Garzik 	/* ap->flags bits */
1684aeb0e32STejun Heo 	AHCI_FLAG_NO_NCQ		= (1 << 24),
1694aeb0e32STejun Heo 	AHCI_FLAG_IGN_IRQ_IF_ERR	= (1 << 25), /* ignore IRQ_IF_ERR */
170648a88beSTejun Heo 	AHCI_FLAG_HONOR_PI		= (1 << 26), /* honor PORTS_IMPL */
171c6fd2807SJeff Garzik };
172c6fd2807SJeff Garzik 
173c6fd2807SJeff Garzik struct ahci_cmd_hdr {
174c6fd2807SJeff Garzik 	u32			opts;
175c6fd2807SJeff Garzik 	u32			status;
176c6fd2807SJeff Garzik 	u32			tbl_addr;
177c6fd2807SJeff Garzik 	u32			tbl_addr_hi;
178c6fd2807SJeff Garzik 	u32			reserved[4];
179c6fd2807SJeff Garzik };
180c6fd2807SJeff Garzik 
181c6fd2807SJeff Garzik struct ahci_sg {
182c6fd2807SJeff Garzik 	u32			addr;
183c6fd2807SJeff Garzik 	u32			addr_hi;
184c6fd2807SJeff Garzik 	u32			reserved;
185c6fd2807SJeff Garzik 	u32			flags_size;
186c6fd2807SJeff Garzik };
187c6fd2807SJeff Garzik 
188c6fd2807SJeff Garzik struct ahci_host_priv {
189c6fd2807SJeff Garzik 	u32			cap;	/* cache of HOST_CAP register */
190c6fd2807SJeff Garzik 	u32			port_map; /* cache of HOST_PORTS_IMPL reg */
191c6fd2807SJeff Garzik };
192c6fd2807SJeff Garzik 
193c6fd2807SJeff Garzik struct ahci_port_priv {
194c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
195c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
196c6fd2807SJeff Garzik 	void			*cmd_tbl;
197c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
198c6fd2807SJeff Garzik 	void			*rx_fis;
199c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2000291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2010291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2020291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
203afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
204c6fd2807SJeff Garzik };
205c6fd2807SJeff Garzik 
206c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
207c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
208c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
209c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
2107d12e780SDavid Howells static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
211c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap);
212c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
213c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
214c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
215c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
216c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap);
217c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
218c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
219c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
220ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap);
221c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
222*438ac6d5STejun Heo #ifdef CONFIG_PM
223c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
224c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
225c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
226c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
227*438ac6d5STejun Heo #endif
228c6fd2807SJeff Garzik 
229c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
230c6fd2807SJeff Garzik 	.module			= THIS_MODULE,
231c6fd2807SJeff Garzik 	.name			= DRV_NAME,
232c6fd2807SJeff Garzik 	.ioctl			= ata_scsi_ioctl,
233c6fd2807SJeff Garzik 	.queuecommand		= ata_scsi_queuecmd,
234c6fd2807SJeff Garzik 	.change_queue_depth	= ata_scsi_change_queue_depth,
235c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
236c6fd2807SJeff Garzik 	.this_id		= ATA_SHT_THIS_ID,
237c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
238c6fd2807SJeff Garzik 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
239c6fd2807SJeff Garzik 	.emulated		= ATA_SHT_EMULATED,
240c6fd2807SJeff Garzik 	.use_clustering		= AHCI_USE_CLUSTERING,
241c6fd2807SJeff Garzik 	.proc_name		= DRV_NAME,
242c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
243c6fd2807SJeff Garzik 	.slave_configure	= ata_scsi_slave_config,
244c6fd2807SJeff Garzik 	.slave_destroy		= ata_scsi_slave_destroy,
245c6fd2807SJeff Garzik 	.bios_param		= ata_std_bios_param,
246*438ac6d5STejun Heo #ifdef CONFIG_PM
247c6fd2807SJeff Garzik 	.suspend		= ata_scsi_device_suspend,
248c6fd2807SJeff Garzik 	.resume			= ata_scsi_device_resume,
249*438ac6d5STejun Heo #endif
250c6fd2807SJeff Garzik };
251c6fd2807SJeff Garzik 
252c6fd2807SJeff Garzik static const struct ata_port_operations ahci_ops = {
253c6fd2807SJeff Garzik 	.port_disable		= ata_port_disable,
254c6fd2807SJeff Garzik 
255c6fd2807SJeff Garzik 	.check_status		= ahci_check_status,
256c6fd2807SJeff Garzik 	.check_altstatus	= ahci_check_status,
257c6fd2807SJeff Garzik 	.dev_select		= ata_noop_dev_select,
258c6fd2807SJeff Garzik 
259c6fd2807SJeff Garzik 	.tf_read		= ahci_tf_read,
260c6fd2807SJeff Garzik 
261c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
262c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
263c6fd2807SJeff Garzik 
264c6fd2807SJeff Garzik 	.irq_handler		= ahci_interrupt,
265c6fd2807SJeff Garzik 	.irq_clear		= ahci_irq_clear,
266246ce3b6SAkira Iguchi 	.irq_on			= ata_dummy_irq_on,
267246ce3b6SAkira Iguchi 	.irq_ack		= ata_dummy_irq_ack,
268c6fd2807SJeff Garzik 
269c6fd2807SJeff Garzik 	.scr_read		= ahci_scr_read,
270c6fd2807SJeff Garzik 	.scr_write		= ahci_scr_write,
271c6fd2807SJeff Garzik 
272c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
273c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
274c6fd2807SJeff Garzik 
275c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
276c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
277c6fd2807SJeff Garzik 
278*438ac6d5STejun Heo #ifdef CONFIG_PM
279c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
280c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
281*438ac6d5STejun Heo #endif
282c6fd2807SJeff Garzik 
283c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
284c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
285c6fd2807SJeff Garzik };
286c6fd2807SJeff Garzik 
287ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = {
288ad616ffbSTejun Heo 	.port_disable		= ata_port_disable,
289ad616ffbSTejun Heo 
290ad616ffbSTejun Heo 	.check_status		= ahci_check_status,
291ad616ffbSTejun Heo 	.check_altstatus	= ahci_check_status,
292ad616ffbSTejun Heo 	.dev_select		= ata_noop_dev_select,
293ad616ffbSTejun Heo 
294ad616ffbSTejun Heo 	.tf_read		= ahci_tf_read,
295ad616ffbSTejun Heo 
296ad616ffbSTejun Heo 	.qc_prep		= ahci_qc_prep,
297ad616ffbSTejun Heo 	.qc_issue		= ahci_qc_issue,
298ad616ffbSTejun Heo 
299ad616ffbSTejun Heo 	.irq_handler		= ahci_interrupt,
300ad616ffbSTejun Heo 	.irq_clear		= ahci_irq_clear,
301246ce3b6SAkira Iguchi 	.irq_on			= ata_dummy_irq_on,
302246ce3b6SAkira Iguchi 	.irq_ack		= ata_dummy_irq_ack,
303ad616ffbSTejun Heo 
304ad616ffbSTejun Heo 	.scr_read		= ahci_scr_read,
305ad616ffbSTejun Heo 	.scr_write		= ahci_scr_write,
306ad616ffbSTejun Heo 
307ad616ffbSTejun Heo 	.freeze			= ahci_freeze,
308ad616ffbSTejun Heo 	.thaw			= ahci_thaw,
309ad616ffbSTejun Heo 
310ad616ffbSTejun Heo 	.error_handler		= ahci_vt8251_error_handler,
311ad616ffbSTejun Heo 	.post_internal_cmd	= ahci_post_internal_cmd,
312ad616ffbSTejun Heo 
313*438ac6d5STejun Heo #ifdef CONFIG_PM
314ad616ffbSTejun Heo 	.port_suspend		= ahci_port_suspend,
315ad616ffbSTejun Heo 	.port_resume		= ahci_port_resume,
316*438ac6d5STejun Heo #endif
317ad616ffbSTejun Heo 
318ad616ffbSTejun Heo 	.port_start		= ahci_port_start,
319ad616ffbSTejun Heo 	.port_stop		= ahci_port_stop,
320ad616ffbSTejun Heo };
321ad616ffbSTejun Heo 
322c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
323c6fd2807SJeff Garzik 	/* board_ahci */
324c6fd2807SJeff Garzik 	{
325c6fd2807SJeff Garzik 		.sht		= &ahci_sht,
326cca3974eSJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
327c6fd2807SJeff Garzik 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
328c6fd2807SJeff Garzik 				  ATA_FLAG_SKIP_D2H_BSY,
329c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
330c6fd2807SJeff Garzik 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
331c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
332c6fd2807SJeff Garzik 	},
333648a88beSTejun Heo 	/* board_ahci_pi */
334648a88beSTejun Heo 	{
335648a88beSTejun Heo 		.sht		= &ahci_sht,
336648a88beSTejun Heo 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
337648a88beSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
338648a88beSTejun Heo 				  ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
339648a88beSTejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
340648a88beSTejun Heo 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
341648a88beSTejun Heo 		.port_ops	= &ahci_ops,
342648a88beSTejun Heo 	},
343c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
344c6fd2807SJeff Garzik 	{
345c6fd2807SJeff Garzik 		.sht		= &ahci_sht,
346cca3974eSJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
347c6fd2807SJeff Garzik 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
348ad616ffbSTejun Heo 				  ATA_FLAG_SKIP_D2H_BSY |
349ad616ffbSTejun Heo 				  ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
350c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
351c6fd2807SJeff Garzik 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
352ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
353c6fd2807SJeff Garzik 	},
35441669553STejun Heo 	/* board_ahci_ign_iferr */
35541669553STejun Heo 	{
35641669553STejun Heo 		.sht		= &ahci_sht,
35741669553STejun Heo 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
35841669553STejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
35941669553STejun Heo 				  ATA_FLAG_SKIP_D2H_BSY |
36041669553STejun Heo 				  AHCI_FLAG_IGN_IRQ_IF_ERR,
36141669553STejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
36241669553STejun Heo 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
36341669553STejun Heo 		.port_ops	= &ahci_ops,
36441669553STejun Heo 	},
365c6fd2807SJeff Garzik };
366c6fd2807SJeff Garzik 
367c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
368c6fd2807SJeff Garzik 	/* Intel */
36954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
37054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
37154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
37254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
37354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
37482490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
37554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
37654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
37754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
37854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
379648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
380648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
381648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
382648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
383648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
384648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */
385648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */
386648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */
387648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */
388648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */
389648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
390648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
391648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
392648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
393648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
394648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
395c6fd2807SJeff Garzik 
396e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
397e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
398e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
399c6fd2807SJeff Garzik 
400c6fd2807SJeff Garzik 	/* ATI */
40154bb3a94SJeff Garzik 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
40254bb3a94SJeff Garzik 	{ PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
403c6fd2807SJeff Garzik 
404c6fd2807SJeff Garzik 	/* VIA */
40554bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
406c6fd2807SJeff Garzik 
407c6fd2807SJeff Garzik 	/* NVIDIA */
40854bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },		/* MCP65 */
40954bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci },		/* MCP65 */
41054bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci },		/* MCP65 */
41154bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci },		/* MCP65 */
4126fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci },		/* MCP65 */
4136fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci },		/* MCP65 */
4146fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci },		/* MCP65 */
4156fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci },		/* MCP65 */
4166fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci },		/* MCP67 */
4176fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci },		/* MCP67 */
4186fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci },		/* MCP67 */
4196fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci },		/* MCP67 */
420895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },		/* MCP67 */
421895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },		/* MCP67 */
422895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },		/* MCP67 */
423895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },		/* MCP67 */
424895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },		/* MCP67 */
425895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },		/* MCP67 */
426895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },		/* MCP67 */
427895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },		/* MCP67 */
428c6fd2807SJeff Garzik 
429c6fd2807SJeff Garzik 	/* SiS */
43054bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
43154bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
43254bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
433c6fd2807SJeff Garzik 
434415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
435415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
436c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
437415ae2b5SJeff Garzik 
438c6fd2807SJeff Garzik 	{ }	/* terminate list */
439c6fd2807SJeff Garzik };
440c6fd2807SJeff Garzik 
441c6fd2807SJeff Garzik 
442c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
443c6fd2807SJeff Garzik 	.name			= DRV_NAME,
444c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
445c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
44624dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
447*438ac6d5STejun Heo #ifdef CONFIG_PM
448c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
449c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
450*438ac6d5STejun Heo #endif
451c6fd2807SJeff Garzik };
452c6fd2807SJeff Garzik 
453c6fd2807SJeff Garzik 
45498fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
45598fa4b60STejun Heo {
45698fa4b60STejun Heo 	return (cap & 0x1f) + 1;
45798fa4b60STejun Heo }
45898fa4b60STejun Heo 
4590d5ff566STejun Heo static inline void __iomem *ahci_port_base(void __iomem *base,
4600d5ff566STejun Heo 					   unsigned int port)
461c6fd2807SJeff Garzik {
462c6fd2807SJeff Garzik 	return base + 0x100 + (port * 0x80);
463c6fd2807SJeff Garzik }
464c6fd2807SJeff Garzik 
465c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
466c6fd2807SJeff Garzik {
467c6fd2807SJeff Garzik 	unsigned int sc_reg;
468c6fd2807SJeff Garzik 
469c6fd2807SJeff Garzik 	switch (sc_reg_in) {
470c6fd2807SJeff Garzik 	case SCR_STATUS:	sc_reg = 0; break;
471c6fd2807SJeff Garzik 	case SCR_CONTROL:	sc_reg = 1; break;
472c6fd2807SJeff Garzik 	case SCR_ERROR:		sc_reg = 2; break;
473c6fd2807SJeff Garzik 	case SCR_ACTIVE:	sc_reg = 3; break;
474c6fd2807SJeff Garzik 	default:
475c6fd2807SJeff Garzik 		return 0xffffffffU;
476c6fd2807SJeff Garzik 	}
477c6fd2807SJeff Garzik 
4780d5ff566STejun Heo 	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
479c6fd2807SJeff Garzik }
480c6fd2807SJeff Garzik 
481c6fd2807SJeff Garzik 
482c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
483c6fd2807SJeff Garzik 			       u32 val)
484c6fd2807SJeff Garzik {
485c6fd2807SJeff Garzik 	unsigned int sc_reg;
486c6fd2807SJeff Garzik 
487c6fd2807SJeff Garzik 	switch (sc_reg_in) {
488c6fd2807SJeff Garzik 	case SCR_STATUS:	sc_reg = 0; break;
489c6fd2807SJeff Garzik 	case SCR_CONTROL:	sc_reg = 1; break;
490c6fd2807SJeff Garzik 	case SCR_ERROR:		sc_reg = 2; break;
491c6fd2807SJeff Garzik 	case SCR_ACTIVE:	sc_reg = 3; break;
492c6fd2807SJeff Garzik 	default:
493c6fd2807SJeff Garzik 		return;
494c6fd2807SJeff Garzik 	}
495c6fd2807SJeff Garzik 
4960d5ff566STejun Heo 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
497c6fd2807SJeff Garzik }
498c6fd2807SJeff Garzik 
499c6fd2807SJeff Garzik static void ahci_start_engine(void __iomem *port_mmio)
500c6fd2807SJeff Garzik {
501c6fd2807SJeff Garzik 	u32 tmp;
502c6fd2807SJeff Garzik 
503c6fd2807SJeff Garzik 	/* start DMA */
504c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
505c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
506c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
507c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
508c6fd2807SJeff Garzik }
509c6fd2807SJeff Garzik 
510c6fd2807SJeff Garzik static int ahci_stop_engine(void __iomem *port_mmio)
511c6fd2807SJeff Garzik {
512c6fd2807SJeff Garzik 	u32 tmp;
513c6fd2807SJeff Garzik 
514c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
515c6fd2807SJeff Garzik 
516c6fd2807SJeff Garzik 	/* check if the HBA is idle */
517c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
518c6fd2807SJeff Garzik 		return 0;
519c6fd2807SJeff Garzik 
520c6fd2807SJeff Garzik 	/* setting HBA to idle */
521c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
522c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
523c6fd2807SJeff Garzik 
524c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
525c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
526c6fd2807SJeff Garzik 			        PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
527c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
528c6fd2807SJeff Garzik 		return -EIO;
529c6fd2807SJeff Garzik 
530c6fd2807SJeff Garzik 	return 0;
531c6fd2807SJeff Garzik }
532c6fd2807SJeff Garzik 
533c6fd2807SJeff Garzik static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
534c6fd2807SJeff Garzik 			      dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
535c6fd2807SJeff Garzik {
536c6fd2807SJeff Garzik 	u32 tmp;
537c6fd2807SJeff Garzik 
538c6fd2807SJeff Garzik 	/* set FIS registers */
539c6fd2807SJeff Garzik 	if (cap & HOST_CAP_64)
540c6fd2807SJeff Garzik 		writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
541c6fd2807SJeff Garzik 	writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
542c6fd2807SJeff Garzik 
543c6fd2807SJeff Garzik 	if (cap & HOST_CAP_64)
544c6fd2807SJeff Garzik 		writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
545c6fd2807SJeff Garzik 	writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
546c6fd2807SJeff Garzik 
547c6fd2807SJeff Garzik 	/* enable FIS reception */
548c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
549c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
550c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
551c6fd2807SJeff Garzik 
552c6fd2807SJeff Garzik 	/* flush */
553c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
554c6fd2807SJeff Garzik }
555c6fd2807SJeff Garzik 
556c6fd2807SJeff Garzik static int ahci_stop_fis_rx(void __iomem *port_mmio)
557c6fd2807SJeff Garzik {
558c6fd2807SJeff Garzik 	u32 tmp;
559c6fd2807SJeff Garzik 
560c6fd2807SJeff Garzik 	/* disable FIS reception */
561c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
562c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
563c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
564c6fd2807SJeff Garzik 
565c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
566c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
567c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
568c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
569c6fd2807SJeff Garzik 		return -EBUSY;
570c6fd2807SJeff Garzik 
571c6fd2807SJeff Garzik 	return 0;
572c6fd2807SJeff Garzik }
573c6fd2807SJeff Garzik 
574c6fd2807SJeff Garzik static void ahci_power_up(void __iomem *port_mmio, u32 cap)
575c6fd2807SJeff Garzik {
576c6fd2807SJeff Garzik 	u32 cmd;
577c6fd2807SJeff Garzik 
578c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
579c6fd2807SJeff Garzik 
580c6fd2807SJeff Garzik 	/* spin up device */
581c6fd2807SJeff Garzik 	if (cap & HOST_CAP_SSS) {
582c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
583c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
584c6fd2807SJeff Garzik 	}
585c6fd2807SJeff Garzik 
586c6fd2807SJeff Garzik 	/* wake up link */
587c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
588c6fd2807SJeff Garzik }
589c6fd2807SJeff Garzik 
590*438ac6d5STejun Heo #ifdef CONFIG_PM
591c6fd2807SJeff Garzik static void ahci_power_down(void __iomem *port_mmio, u32 cap)
592c6fd2807SJeff Garzik {
593c6fd2807SJeff Garzik 	u32 cmd, scontrol;
594c6fd2807SJeff Garzik 
59507c53dacSTejun Heo 	if (!(cap & HOST_CAP_SSS))
59607c53dacSTejun Heo 		return;
597c6fd2807SJeff Garzik 
59807c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
599c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
600c6fd2807SJeff Garzik 	scontrol &= ~0xf;
601c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
602c6fd2807SJeff Garzik 
603c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
60407c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
605c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
606c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
607c6fd2807SJeff Garzik }
608*438ac6d5STejun Heo #endif
609c6fd2807SJeff Garzik 
610c6fd2807SJeff Garzik static void ahci_init_port(void __iomem *port_mmio, u32 cap,
611c6fd2807SJeff Garzik 			   dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
612c6fd2807SJeff Garzik {
613c6fd2807SJeff Garzik 	/* enable FIS reception */
614c6fd2807SJeff Garzik 	ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
615c6fd2807SJeff Garzik 
616c6fd2807SJeff Garzik 	/* enable DMA */
617c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
618c6fd2807SJeff Garzik }
619c6fd2807SJeff Garzik 
620c6fd2807SJeff Garzik static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
621c6fd2807SJeff Garzik {
622c6fd2807SJeff Garzik 	int rc;
623c6fd2807SJeff Garzik 
624c6fd2807SJeff Garzik 	/* disable DMA */
625c6fd2807SJeff Garzik 	rc = ahci_stop_engine(port_mmio);
626c6fd2807SJeff Garzik 	if (rc) {
627c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
628c6fd2807SJeff Garzik 		return rc;
629c6fd2807SJeff Garzik 	}
630c6fd2807SJeff Garzik 
631c6fd2807SJeff Garzik 	/* disable FIS reception */
632c6fd2807SJeff Garzik 	rc = ahci_stop_fis_rx(port_mmio);
633c6fd2807SJeff Garzik 	if (rc) {
634c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
635c6fd2807SJeff Garzik 		return rc;
636c6fd2807SJeff Garzik 	}
637c6fd2807SJeff Garzik 
638c6fd2807SJeff Garzik 	return 0;
639c6fd2807SJeff Garzik }
640c6fd2807SJeff Garzik 
641c6fd2807SJeff Garzik static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
642c6fd2807SJeff Garzik {
64398fa4b60STejun Heo 	u32 cap_save, impl_save, tmp;
644c6fd2807SJeff Garzik 
645c6fd2807SJeff Garzik 	cap_save = readl(mmio + HOST_CAP);
64698fa4b60STejun Heo 	impl_save = readl(mmio + HOST_PORTS_IMPL);
647c6fd2807SJeff Garzik 
648c6fd2807SJeff Garzik 	/* global controller reset */
649c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
650c6fd2807SJeff Garzik 	if ((tmp & HOST_RESET) == 0) {
651c6fd2807SJeff Garzik 		writel(tmp | HOST_RESET, mmio + HOST_CTL);
652c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
653c6fd2807SJeff Garzik 	}
654c6fd2807SJeff Garzik 
655c6fd2807SJeff Garzik 	/* reset must complete within 1 second, or
656c6fd2807SJeff Garzik 	 * the hardware should be considered fried.
657c6fd2807SJeff Garzik 	 */
658c6fd2807SJeff Garzik 	ssleep(1);
659c6fd2807SJeff Garzik 
660c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
661c6fd2807SJeff Garzik 	if (tmp & HOST_RESET) {
662c6fd2807SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
663c6fd2807SJeff Garzik 			   "controller reset failed (0x%x)\n", tmp);
664c6fd2807SJeff Garzik 		return -EIO;
665c6fd2807SJeff Garzik 	}
666c6fd2807SJeff Garzik 
66798fa4b60STejun Heo 	/* turn on AHCI mode */
668c6fd2807SJeff Garzik 	writel(HOST_AHCI_EN, mmio + HOST_CTL);
669c6fd2807SJeff Garzik 	(void) readl(mmio + HOST_CTL);	/* flush */
67098fa4b60STejun Heo 
67198fa4b60STejun Heo 	/* These write-once registers are normally cleared on reset.
67298fa4b60STejun Heo 	 * Restore BIOS values... which we HOPE were present before
67398fa4b60STejun Heo 	 * reset.
67498fa4b60STejun Heo 	 */
67598fa4b60STejun Heo 	if (!impl_save) {
67698fa4b60STejun Heo 		impl_save = (1 << ahci_nr_ports(cap_save)) - 1;
67798fa4b60STejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
67898fa4b60STejun Heo 			   "PORTS_IMPL is zero, forcing 0x%x\n", impl_save);
67998fa4b60STejun Heo 	}
680c6fd2807SJeff Garzik 	writel(cap_save, mmio + HOST_CAP);
68198fa4b60STejun Heo 	writel(impl_save, mmio + HOST_PORTS_IMPL);
682c6fd2807SJeff Garzik 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
683c6fd2807SJeff Garzik 
684c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
685c6fd2807SJeff Garzik 		u16 tmp16;
686c6fd2807SJeff Garzik 
687c6fd2807SJeff Garzik 		/* configure PCS */
688c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
689c6fd2807SJeff Garzik 		tmp16 |= 0xf;
690c6fd2807SJeff Garzik 		pci_write_config_word(pdev, 0x92, tmp16);
691c6fd2807SJeff Garzik 	}
692c6fd2807SJeff Garzik 
693c6fd2807SJeff Garzik 	return 0;
694c6fd2807SJeff Garzik }
695c6fd2807SJeff Garzik 
696c6fd2807SJeff Garzik static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
697648a88beSTejun Heo 				 int n_ports, unsigned int port_flags,
698648a88beSTejun Heo 				 struct ahci_host_priv *hpriv)
699c6fd2807SJeff Garzik {
700c6fd2807SJeff Garzik 	int i, rc;
701c6fd2807SJeff Garzik 	u32 tmp;
702c6fd2807SJeff Garzik 
703c6fd2807SJeff Garzik 	for (i = 0; i < n_ports; i++) {
704c6fd2807SJeff Garzik 		void __iomem *port_mmio = ahci_port_base(mmio, i);
705c6fd2807SJeff Garzik 		const char *emsg = NULL;
706c6fd2807SJeff Garzik 
707648a88beSTejun Heo 		if ((port_flags & AHCI_FLAG_HONOR_PI) &&
708648a88beSTejun Heo 		    !(hpriv->port_map & (1 << i)))
709c6fd2807SJeff Garzik 			continue;
710c6fd2807SJeff Garzik 
711c6fd2807SJeff Garzik 		/* make sure port is not active */
712648a88beSTejun Heo 		rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
713c6fd2807SJeff Garzik 		if (rc)
714c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
715c6fd2807SJeff Garzik 				   "%s (%d)\n", emsg, rc);
716c6fd2807SJeff Garzik 
717c6fd2807SJeff Garzik 		/* clear SError */
718c6fd2807SJeff Garzik 		tmp = readl(port_mmio + PORT_SCR_ERR);
719c6fd2807SJeff Garzik 		VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
720c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_SCR_ERR);
721c6fd2807SJeff Garzik 
722c6fd2807SJeff Garzik 		/* clear port IRQ */
723c6fd2807SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
724c6fd2807SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
725c6fd2807SJeff Garzik 		if (tmp)
726c6fd2807SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
727c6fd2807SJeff Garzik 
728c6fd2807SJeff Garzik 		writel(1 << i, mmio + HOST_IRQ_STAT);
729c6fd2807SJeff Garzik 	}
730c6fd2807SJeff Garzik 
731c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
732c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
733c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
734c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
735c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
736c6fd2807SJeff Garzik }
737c6fd2807SJeff Garzik 
738c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
739c6fd2807SJeff Garzik {
7400d5ff566STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
741c6fd2807SJeff Garzik 	struct ata_taskfile tf;
742c6fd2807SJeff Garzik 	u32 tmp;
743c6fd2807SJeff Garzik 
744c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
745c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
746c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
747c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
748c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
749c6fd2807SJeff Garzik 
750c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
751c6fd2807SJeff Garzik }
752c6fd2807SJeff Garzik 
753c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
754c6fd2807SJeff Garzik 			       u32 opts)
755c6fd2807SJeff Garzik {
756c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
757c6fd2807SJeff Garzik 
758c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
759c6fd2807SJeff Garzik 
760c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
761c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
762c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
763c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
764c6fd2807SJeff Garzik }
765c6fd2807SJeff Garzik 
766c6fd2807SJeff Garzik static int ahci_clo(struct ata_port *ap)
767c6fd2807SJeff Garzik {
7680d5ff566STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
769cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
770c6fd2807SJeff Garzik 	u32 tmp;
771c6fd2807SJeff Garzik 
772c6fd2807SJeff Garzik 	if (!(hpriv->cap & HOST_CAP_CLO))
773c6fd2807SJeff Garzik 		return -EOPNOTSUPP;
774c6fd2807SJeff Garzik 
775c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
776c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
777c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
778c6fd2807SJeff Garzik 
779c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
780c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
781c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
782c6fd2807SJeff Garzik 		return -EIO;
783c6fd2807SJeff Garzik 
784c6fd2807SJeff Garzik 	return 0;
785c6fd2807SJeff Garzik }
786c6fd2807SJeff Garzik 
787c6fd2807SJeff Garzik static int ahci_softreset(struct ata_port *ap, unsigned int *class)
788c6fd2807SJeff Garzik {
789c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
7900d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
791c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
792c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
793c6fd2807SJeff Garzik 	const char *reason = NULL;
794c6fd2807SJeff Garzik 	struct ata_taskfile tf;
795c6fd2807SJeff Garzik 	u32 tmp;
796c6fd2807SJeff Garzik 	u8 *fis;
797c6fd2807SJeff Garzik 	int rc;
798c6fd2807SJeff Garzik 
799c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
800c6fd2807SJeff Garzik 
801c6fd2807SJeff Garzik 	if (ata_port_offline(ap)) {
802c6fd2807SJeff Garzik 		DPRINTK("PHY reports no device\n");
803c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
804c6fd2807SJeff Garzik 		return 0;
805c6fd2807SJeff Garzik 	}
806c6fd2807SJeff Garzik 
807c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
808c6fd2807SJeff Garzik 	rc = ahci_stop_engine(port_mmio);
809c6fd2807SJeff Garzik 	if (rc) {
810c6fd2807SJeff Garzik 		reason = "failed to stop engine";
811c6fd2807SJeff Garzik 		goto fail_restart;
812c6fd2807SJeff Garzik 	}
813c6fd2807SJeff Garzik 
814c6fd2807SJeff Garzik 	/* check BUSY/DRQ, perform Command List Override if necessary */
8151244a19cSTejun Heo 	if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
816c6fd2807SJeff Garzik 		rc = ahci_clo(ap);
817c6fd2807SJeff Garzik 
818c6fd2807SJeff Garzik 		if (rc == -EOPNOTSUPP) {
819c6fd2807SJeff Garzik 			reason = "port busy but CLO unavailable";
820c6fd2807SJeff Garzik 			goto fail_restart;
821c6fd2807SJeff Garzik 		} else if (rc) {
822c6fd2807SJeff Garzik 			reason = "port busy but CLO failed";
823c6fd2807SJeff Garzik 			goto fail_restart;
824c6fd2807SJeff Garzik 		}
825c6fd2807SJeff Garzik 	}
826c6fd2807SJeff Garzik 
827c6fd2807SJeff Garzik 	/* restart engine */
828c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
829c6fd2807SJeff Garzik 
830c6fd2807SJeff Garzik 	ata_tf_init(ap->device, &tf);
831c6fd2807SJeff Garzik 	fis = pp->cmd_tbl;
832c6fd2807SJeff Garzik 
833c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
834c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, 0,
835c6fd2807SJeff Garzik 			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
836c6fd2807SJeff Garzik 
837c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
838c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, fis, 0);
839c6fd2807SJeff Garzik 	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
840c6fd2807SJeff Garzik 
841c6fd2807SJeff Garzik 	writel(1, port_mmio + PORT_CMD_ISSUE);
842c6fd2807SJeff Garzik 
843c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
844c6fd2807SJeff Garzik 	if (tmp & 0x1) {
845c6fd2807SJeff Garzik 		rc = -EIO;
846c6fd2807SJeff Garzik 		reason = "1st FIS failed";
847c6fd2807SJeff Garzik 		goto fail;
848c6fd2807SJeff Garzik 	}
849c6fd2807SJeff Garzik 
850c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
851c6fd2807SJeff Garzik 	msleep(1);
852c6fd2807SJeff Garzik 
853c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
854c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
855c6fd2807SJeff Garzik 
856c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
857c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, fis, 0);
858c6fd2807SJeff Garzik 	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
859c6fd2807SJeff Garzik 
860c6fd2807SJeff Garzik 	writel(1, port_mmio + PORT_CMD_ISSUE);
861c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
862c6fd2807SJeff Garzik 
863c6fd2807SJeff Garzik 	/* spec mandates ">= 2ms" before checking status.
864c6fd2807SJeff Garzik 	 * We wait 150ms, because that was the magic delay used for
865c6fd2807SJeff Garzik 	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time
866c6fd2807SJeff Garzik 	 * between when the ATA command register is written, and then
867c6fd2807SJeff Garzik 	 * status is checked.  Because waiting for "a while" before
868c6fd2807SJeff Garzik 	 * checking status is fine, post SRST, we perform this magic
869c6fd2807SJeff Garzik 	 * delay here as well.
870c6fd2807SJeff Garzik 	 */
871c6fd2807SJeff Garzik 	msleep(150);
872c6fd2807SJeff Garzik 
873c6fd2807SJeff Garzik 	*class = ATA_DEV_NONE;
874c6fd2807SJeff Garzik 	if (ata_port_online(ap)) {
875c6fd2807SJeff Garzik 		if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
876c6fd2807SJeff Garzik 			rc = -EIO;
877c6fd2807SJeff Garzik 			reason = "device not ready";
878c6fd2807SJeff Garzik 			goto fail;
879c6fd2807SJeff Garzik 		}
880c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
881c6fd2807SJeff Garzik 	}
882c6fd2807SJeff Garzik 
883c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
884c6fd2807SJeff Garzik 	return 0;
885c6fd2807SJeff Garzik 
886c6fd2807SJeff Garzik  fail_restart:
887c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
888c6fd2807SJeff Garzik  fail:
889c6fd2807SJeff Garzik 	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
890c6fd2807SJeff Garzik 	return rc;
891c6fd2807SJeff Garzik }
892c6fd2807SJeff Garzik 
893c6fd2807SJeff Garzik static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
894c6fd2807SJeff Garzik {
895c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
896c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
897c6fd2807SJeff Garzik 	struct ata_taskfile tf;
8980d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
899c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
900c6fd2807SJeff Garzik 	int rc;
901c6fd2807SJeff Garzik 
902c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
903c6fd2807SJeff Garzik 
904c6fd2807SJeff Garzik 	ahci_stop_engine(port_mmio);
905c6fd2807SJeff Garzik 
906c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
907c6fd2807SJeff Garzik 	ata_tf_init(ap->device, &tf);
908dfd7a3dbSTejun Heo 	tf.command = 0x80;
909c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, d2h_fis, 0);
910c6fd2807SJeff Garzik 
911c6fd2807SJeff Garzik 	rc = sata_std_hardreset(ap, class);
912c6fd2807SJeff Garzik 
913c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
914c6fd2807SJeff Garzik 
915c6fd2807SJeff Garzik 	if (rc == 0 && ata_port_online(ap))
916c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
917c6fd2807SJeff Garzik 	if (*class == ATA_DEV_UNKNOWN)
918c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
919c6fd2807SJeff Garzik 
920c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
921c6fd2807SJeff Garzik 	return rc;
922c6fd2807SJeff Garzik }
923c6fd2807SJeff Garzik 
924ad616ffbSTejun Heo static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
925ad616ffbSTejun Heo {
9260d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
927ad616ffbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
928ad616ffbSTejun Heo 	int rc;
929ad616ffbSTejun Heo 
930ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
931ad616ffbSTejun Heo 
932ad616ffbSTejun Heo 	ahci_stop_engine(port_mmio);
933ad616ffbSTejun Heo 
934ad616ffbSTejun Heo 	rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
935ad616ffbSTejun Heo 
936ad616ffbSTejun Heo 	/* vt8251 needs SError cleared for the port to operate */
937ad616ffbSTejun Heo 	ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
938ad616ffbSTejun Heo 
939ad616ffbSTejun Heo 	ahci_start_engine(port_mmio);
940ad616ffbSTejun Heo 
941ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
942ad616ffbSTejun Heo 
943ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
944ad616ffbSTejun Heo 	 * request follow-up softreset.
945ad616ffbSTejun Heo 	 */
946ad616ffbSTejun Heo 	return rc ?: -EAGAIN;
947ad616ffbSTejun Heo }
948ad616ffbSTejun Heo 
949c6fd2807SJeff Garzik static void ahci_postreset(struct ata_port *ap, unsigned int *class)
950c6fd2807SJeff Garzik {
9510d5ff566STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
952c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
953c6fd2807SJeff Garzik 
954c6fd2807SJeff Garzik 	ata_std_postreset(ap, class);
955c6fd2807SJeff Garzik 
956c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
957c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
958c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
959c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
960c6fd2807SJeff Garzik 	else
961c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
962c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
963c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
964c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
965c6fd2807SJeff Garzik 	}
966c6fd2807SJeff Garzik }
967c6fd2807SJeff Garzik 
968c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap)
969c6fd2807SJeff Garzik {
9700d5ff566STejun Heo 	void __iomem *mmio = ap->ioaddr.cmd_addr;
971c6fd2807SJeff Garzik 
972c6fd2807SJeff Garzik 	return readl(mmio + PORT_TFDATA) & 0xFF;
973c6fd2807SJeff Garzik }
974c6fd2807SJeff Garzik 
975c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
976c6fd2807SJeff Garzik {
977c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
978c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
979c6fd2807SJeff Garzik 
980c6fd2807SJeff Garzik 	ata_tf_from_fis(d2h_fis, tf);
981c6fd2807SJeff Garzik }
982c6fd2807SJeff Garzik 
983c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
984c6fd2807SJeff Garzik {
985c6fd2807SJeff Garzik 	struct scatterlist *sg;
986c6fd2807SJeff Garzik 	struct ahci_sg *ahci_sg;
987c6fd2807SJeff Garzik 	unsigned int n_sg = 0;
988c6fd2807SJeff Garzik 
989c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
990c6fd2807SJeff Garzik 
991c6fd2807SJeff Garzik 	/*
992c6fd2807SJeff Garzik 	 * Next, the S/G list.
993c6fd2807SJeff Garzik 	 */
994c6fd2807SJeff Garzik 	ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
995c6fd2807SJeff Garzik 	ata_for_each_sg(sg, qc) {
996c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
997c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
998c6fd2807SJeff Garzik 
999c6fd2807SJeff Garzik 		ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
1000c6fd2807SJeff Garzik 		ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
1001c6fd2807SJeff Garzik 		ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
1002c6fd2807SJeff Garzik 
1003c6fd2807SJeff Garzik 		ahci_sg++;
1004c6fd2807SJeff Garzik 		n_sg++;
1005c6fd2807SJeff Garzik 	}
1006c6fd2807SJeff Garzik 
1007c6fd2807SJeff Garzik 	return n_sg;
1008c6fd2807SJeff Garzik }
1009c6fd2807SJeff Garzik 
1010c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1011c6fd2807SJeff Garzik {
1012c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1013c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1014c6fd2807SJeff Garzik 	int is_atapi = is_atapi_taskfile(&qc->tf);
1015c6fd2807SJeff Garzik 	void *cmd_tbl;
1016c6fd2807SJeff Garzik 	u32 opts;
1017c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1018c6fd2807SJeff Garzik 	unsigned int n_elem;
1019c6fd2807SJeff Garzik 
1020c6fd2807SJeff Garzik 	/*
1021c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1022c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1023c6fd2807SJeff Garzik 	 */
1024c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1025c6fd2807SJeff Garzik 
1026c6fd2807SJeff Garzik 	ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
1027c6fd2807SJeff Garzik 	if (is_atapi) {
1028c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1029c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1030c6fd2807SJeff Garzik 	}
1031c6fd2807SJeff Garzik 
1032c6fd2807SJeff Garzik 	n_elem = 0;
1033c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1034c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1035c6fd2807SJeff Garzik 
1036c6fd2807SJeff Garzik 	/*
1037c6fd2807SJeff Garzik 	 * Fill in command slot information.
1038c6fd2807SJeff Garzik 	 */
1039c6fd2807SJeff Garzik 	opts = cmd_fis_len | n_elem << 16;
1040c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1041c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1042c6fd2807SJeff Garzik 	if (is_atapi)
1043c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1044c6fd2807SJeff Garzik 
1045c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1046c6fd2807SJeff Garzik }
1047c6fd2807SJeff Garzik 
1048c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1049c6fd2807SJeff Garzik {
1050c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1051c6fd2807SJeff Garzik 	struct ata_eh_info *ehi = &ap->eh_info;
1052c6fd2807SJeff Garzik 	unsigned int err_mask = 0, action = 0;
1053c6fd2807SJeff Garzik 	struct ata_queued_cmd *qc;
1054c6fd2807SJeff Garzik 	u32 serror;
1055c6fd2807SJeff Garzik 
1056c6fd2807SJeff Garzik 	ata_ehi_clear_desc(ehi);
1057c6fd2807SJeff Garzik 
1058c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
1059c6fd2807SJeff Garzik 	serror = ahci_scr_read(ap, SCR_ERROR);
1060c6fd2807SJeff Garzik 	ahci_scr_write(ap, SCR_ERROR, serror);
1061c6fd2807SJeff Garzik 
1062c6fd2807SJeff Garzik 	/* analyze @irq_stat */
1063c6fd2807SJeff Garzik 	ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
1064c6fd2807SJeff Garzik 
106541669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
106641669553STejun Heo 	if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
106741669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
106841669553STejun Heo 
1069c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_TF_ERR)
1070c6fd2807SJeff Garzik 		err_mask |= AC_ERR_DEV;
1071c6fd2807SJeff Garzik 
1072c6fd2807SJeff Garzik 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
1073c6fd2807SJeff Garzik 		err_mask |= AC_ERR_HOST_BUS;
1074c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1075c6fd2807SJeff Garzik 	}
1076c6fd2807SJeff Garzik 
1077c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_IF_ERR) {
1078c6fd2807SJeff Garzik 		err_mask |= AC_ERR_ATA_BUS;
1079c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1080c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", interface fatal error");
1081c6fd2807SJeff Garzik 	}
1082c6fd2807SJeff Garzik 
1083c6fd2807SJeff Garzik 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
1084c6fd2807SJeff Garzik 		ata_ehi_hotplugged(ehi);
1085c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
1086c6fd2807SJeff Garzik 			"connection status changed" : "PHY RDY changed");
1087c6fd2807SJeff Garzik 	}
1088c6fd2807SJeff Garzik 
1089c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
1090c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
1091c6fd2807SJeff Garzik 
1092c6fd2807SJeff Garzik 		err_mask |= AC_ERR_HSM;
1093c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1094c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
1095c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
1096c6fd2807SJeff Garzik 	}
1097c6fd2807SJeff Garzik 
1098c6fd2807SJeff Garzik 	/* okay, let's hand over to EH */
1099c6fd2807SJeff Garzik 	ehi->serror |= serror;
1100c6fd2807SJeff Garzik 	ehi->action |= action;
1101c6fd2807SJeff Garzik 
1102c6fd2807SJeff Garzik 	qc = ata_qc_from_tag(ap, ap->active_tag);
1103c6fd2807SJeff Garzik 	if (qc)
1104c6fd2807SJeff Garzik 		qc->err_mask |= err_mask;
1105c6fd2807SJeff Garzik 	else
1106c6fd2807SJeff Garzik 		ehi->err_mask |= err_mask;
1107c6fd2807SJeff Garzik 
1108c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
1109c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1110c6fd2807SJeff Garzik 	else
1111c6fd2807SJeff Garzik 		ata_port_abort(ap);
1112c6fd2807SJeff Garzik }
1113c6fd2807SJeff Garzik 
1114c6fd2807SJeff Garzik static void ahci_host_intr(struct ata_port *ap)
1115c6fd2807SJeff Garzik {
11160d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1117c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1118c6fd2807SJeff Garzik 	struct ata_eh_info *ehi = &ap->eh_info;
11190291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1120c6fd2807SJeff Garzik 	u32 status, qc_active;
11210291f95fSTejun Heo 	int rc, known_irq = 0;
1122c6fd2807SJeff Garzik 
1123c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
1124c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
1125c6fd2807SJeff Garzik 
1126c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
1127c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
1128c6fd2807SJeff Garzik 		return;
1129c6fd2807SJeff Garzik 	}
1130c6fd2807SJeff Garzik 
1131c6fd2807SJeff Garzik 	if (ap->sactive)
1132c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
1133c6fd2807SJeff Garzik 	else
1134c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
1135c6fd2807SJeff Garzik 
1136c6fd2807SJeff Garzik 	rc = ata_qc_complete_multiple(ap, qc_active, NULL);
1137c6fd2807SJeff Garzik 	if (rc > 0)
1138c6fd2807SJeff Garzik 		return;
1139c6fd2807SJeff Garzik 	if (rc < 0) {
1140c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
1141c6fd2807SJeff Garzik 		ehi->action |= ATA_EH_SOFTRESET;
1142c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1143c6fd2807SJeff Garzik 		return;
1144c6fd2807SJeff Garzik 	}
1145c6fd2807SJeff Garzik 
1146c6fd2807SJeff Garzik 	/* hmmm... a spurious interupt */
1147c6fd2807SJeff Garzik 
11480291f95fSTejun Heo 	/* if !NCQ, ignore.  No modern ATA device has broken HSM
11490291f95fSTejun Heo 	 * implementation for non-NCQ commands.
11500291f95fSTejun Heo 	 */
11510291f95fSTejun Heo 	if (!ap->sactive)
1152c6fd2807SJeff Garzik 		return;
1153c6fd2807SJeff Garzik 
11540291f95fSTejun Heo 	if (status & PORT_IRQ_D2H_REG_FIS) {
11550291f95fSTejun Heo 		if (!pp->ncq_saw_d2h)
11560291f95fSTejun Heo 			ata_port_printk(ap, KERN_INFO,
11570291f95fSTejun Heo 				"D2H reg with I during NCQ, "
11580291f95fSTejun Heo 				"this message won't be printed again\n");
11590291f95fSTejun Heo 		pp->ncq_saw_d2h = 1;
11600291f95fSTejun Heo 		known_irq = 1;
11610291f95fSTejun Heo 	}
1162c6fd2807SJeff Garzik 
11630291f95fSTejun Heo 	if (status & PORT_IRQ_DMAS_FIS) {
11640291f95fSTejun Heo 		if (!pp->ncq_saw_dmas)
11650291f95fSTejun Heo 			ata_port_printk(ap, KERN_INFO,
11660291f95fSTejun Heo 				"DMAS FIS during NCQ, "
11670291f95fSTejun Heo 				"this message won't be printed again\n");
11680291f95fSTejun Heo 		pp->ncq_saw_dmas = 1;
11690291f95fSTejun Heo 		known_irq = 1;
11700291f95fSTejun Heo 	}
11710291f95fSTejun Heo 
1172a2bbd0c9STejun Heo 	if (status & PORT_IRQ_SDB_FIS) {
117304d4f7a1SAl Viro 		const __le32 *f = pp->rx_fis + RX_FIS_SDB;
11740291f95fSTejun Heo 
1175afb2d552STejun Heo 		if (le32_to_cpu(f[1])) {
1176afb2d552STejun Heo 			/* SDB FIS containing spurious completions
1177afb2d552STejun Heo 			 * might be dangerous, whine and fail commands
1178afb2d552STejun Heo 			 * with HSM violation.  EH will turn off NCQ
1179afb2d552STejun Heo 			 * after several such failures.
1180afb2d552STejun Heo 			 */
1181afb2d552STejun Heo 			ata_ehi_push_desc(ehi,
1182afb2d552STejun Heo 				"spurious completions during NCQ "
1183a2bbd0c9STejun Heo 				"issue=0x%x SAct=0x%x FIS=%08x:%08x",
11840291f95fSTejun Heo 				readl(port_mmio + PORT_CMD_ISSUE),
11856096b63eSTejun Heo 				readl(port_mmio + PORT_SCR_ACT),
1186a2bbd0c9STejun Heo 				le32_to_cpu(f[0]), le32_to_cpu(f[1]));
1187a2bbd0c9STejun Heo 			ehi->err_mask |= AC_ERR_HSM;
1188a2bbd0c9STejun Heo 			ehi->action |= ATA_EH_SOFTRESET;
1189a2bbd0c9STejun Heo 			ata_port_freeze(ap);
1190afb2d552STejun Heo 		} else {
1191afb2d552STejun Heo 			if (!pp->ncq_saw_sdb)
1192afb2d552STejun Heo 				ata_port_printk(ap, KERN_INFO,
1193afb2d552STejun Heo 					"spurious SDB FIS %08x:%08x during NCQ, "
1194afb2d552STejun Heo 					"this message won't be printed again\n",
1195afb2d552STejun Heo 					le32_to_cpu(f[0]), le32_to_cpu(f[1]));
1196afb2d552STejun Heo 			pp->ncq_saw_sdb = 1;
1197afb2d552STejun Heo 		}
11980291f95fSTejun Heo 		known_irq = 1;
11990291f95fSTejun Heo 	}
12000291f95fSTejun Heo 
12010291f95fSTejun Heo 	if (!known_irq)
1202c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
12030291f95fSTejun Heo 				"(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
1204c6fd2807SJeff Garzik 				status, ap->active_tag, ap->sactive);
1205c6fd2807SJeff Garzik }
1206c6fd2807SJeff Garzik 
1207c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap)
1208c6fd2807SJeff Garzik {
1209c6fd2807SJeff Garzik 	/* TODO */
1210c6fd2807SJeff Garzik }
1211c6fd2807SJeff Garzik 
12127d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1213c6fd2807SJeff Garzik {
1214cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
1215c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1216c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
1217c6fd2807SJeff Garzik 	void __iomem *mmio;
1218c6fd2807SJeff Garzik 	u32 irq_stat, irq_ack = 0;
1219c6fd2807SJeff Garzik 
1220c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1221c6fd2807SJeff Garzik 
1222cca3974eSJeff Garzik 	hpriv = host->private_data;
12230d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
1224c6fd2807SJeff Garzik 
1225c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
1226c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
1227c6fd2807SJeff Garzik 	irq_stat &= hpriv->port_map;
1228c6fd2807SJeff Garzik 	if (!irq_stat)
1229c6fd2807SJeff Garzik 		return IRQ_NONE;
1230c6fd2807SJeff Garzik 
1231cca3974eSJeff Garzik         spin_lock(&host->lock);
1232c6fd2807SJeff Garzik 
1233cca3974eSJeff Garzik         for (i = 0; i < host->n_ports; i++) {
1234c6fd2807SJeff Garzik 		struct ata_port *ap;
1235c6fd2807SJeff Garzik 
1236c6fd2807SJeff Garzik 		if (!(irq_stat & (1 << i)))
1237c6fd2807SJeff Garzik 			continue;
1238c6fd2807SJeff Garzik 
1239cca3974eSJeff Garzik 		ap = host->ports[i];
1240c6fd2807SJeff Garzik 		if (ap) {
1241c6fd2807SJeff Garzik 			ahci_host_intr(ap);
1242c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
1243c6fd2807SJeff Garzik 		} else {
1244c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
1245c6fd2807SJeff Garzik 			if (ata_ratelimit())
1246cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
1247c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
1248c6fd2807SJeff Garzik 		}
1249c6fd2807SJeff Garzik 
1250c6fd2807SJeff Garzik 		irq_ack |= (1 << i);
1251c6fd2807SJeff Garzik 	}
1252c6fd2807SJeff Garzik 
1253c6fd2807SJeff Garzik 	if (irq_ack) {
1254c6fd2807SJeff Garzik 		writel(irq_ack, mmio + HOST_IRQ_STAT);
1255c6fd2807SJeff Garzik 		handled = 1;
1256c6fd2807SJeff Garzik 	}
1257c6fd2807SJeff Garzik 
1258cca3974eSJeff Garzik 	spin_unlock(&host->lock);
1259c6fd2807SJeff Garzik 
1260c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1261c6fd2807SJeff Garzik 
1262c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
1263c6fd2807SJeff Garzik }
1264c6fd2807SJeff Garzik 
1265c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
1266c6fd2807SJeff Garzik {
1267c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
12680d5ff566STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
1269c6fd2807SJeff Garzik 
1270c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
1271c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
1272c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
1273c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
1274c6fd2807SJeff Garzik 
1275c6fd2807SJeff Garzik 	return 0;
1276c6fd2807SJeff Garzik }
1277c6fd2807SJeff Garzik 
1278c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
1279c6fd2807SJeff Garzik {
12800d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1281c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1282c6fd2807SJeff Garzik 
1283c6fd2807SJeff Garzik 	/* turn IRQ off */
1284c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
1285c6fd2807SJeff Garzik }
1286c6fd2807SJeff Garzik 
1287c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
1288c6fd2807SJeff Garzik {
12890d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1290c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1291c6fd2807SJeff Garzik 	u32 tmp;
1292c6fd2807SJeff Garzik 
1293c6fd2807SJeff Garzik 	/* clear IRQ */
1294c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1295c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
1296a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
1297c6fd2807SJeff Garzik 
1298c6fd2807SJeff Garzik 	/* turn IRQ back on */
1299c6fd2807SJeff Garzik 	writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
1300c6fd2807SJeff Garzik }
1301c6fd2807SJeff Garzik 
1302c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
1303c6fd2807SJeff Garzik {
13040d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1305c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1306c6fd2807SJeff Garzik 
1307c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1308c6fd2807SJeff Garzik 		/* restart engine */
1309c6fd2807SJeff Garzik 		ahci_stop_engine(port_mmio);
1310c6fd2807SJeff Garzik 		ahci_start_engine(port_mmio);
1311c6fd2807SJeff Garzik 	}
1312c6fd2807SJeff Garzik 
1313c6fd2807SJeff Garzik 	/* perform recovery */
13144aeb0e32STejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
1315c6fd2807SJeff Garzik 		  ahci_postreset);
1316c6fd2807SJeff Garzik }
1317c6fd2807SJeff Garzik 
1318ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap)
1319ad616ffbSTejun Heo {
13200d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1321ad616ffbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1322ad616ffbSTejun Heo 
1323ad616ffbSTejun Heo 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1324ad616ffbSTejun Heo 		/* restart engine */
1325ad616ffbSTejun Heo 		ahci_stop_engine(port_mmio);
1326ad616ffbSTejun Heo 		ahci_start_engine(port_mmio);
1327ad616ffbSTejun Heo 	}
1328ad616ffbSTejun Heo 
1329ad616ffbSTejun Heo 	/* perform recovery */
1330ad616ffbSTejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset,
1331ad616ffbSTejun Heo 		  ahci_postreset);
1332ad616ffbSTejun Heo }
1333ad616ffbSTejun Heo 
1334c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
1335c6fd2807SJeff Garzik {
1336c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
13370d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1338c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1339c6fd2807SJeff Garzik 
1340c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_FAILED)
1341c6fd2807SJeff Garzik 		qc->err_mask |= AC_ERR_OTHER;
1342c6fd2807SJeff Garzik 
1343c6fd2807SJeff Garzik 	if (qc->err_mask) {
1344c6fd2807SJeff Garzik 		/* make DMA engine forget about the failed command */
1345c6fd2807SJeff Garzik 		ahci_stop_engine(port_mmio);
1346c6fd2807SJeff Garzik 		ahci_start_engine(port_mmio);
1347c6fd2807SJeff Garzik 	}
1348c6fd2807SJeff Garzik }
1349c6fd2807SJeff Garzik 
1350*438ac6d5STejun Heo #ifdef CONFIG_PM
1351c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
1352c6fd2807SJeff Garzik {
1353cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1354c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
13550d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1356c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1357c6fd2807SJeff Garzik 	const char *emsg = NULL;
1358c6fd2807SJeff Garzik 	int rc;
1359c6fd2807SJeff Garzik 
1360c6fd2807SJeff Garzik 	rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
13618e16f941STejun Heo 	if (rc == 0)
13628e16f941STejun Heo 		ahci_power_down(port_mmio, hpriv->cap);
13638e16f941STejun Heo 	else {
1364c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
1365c6fd2807SJeff Garzik 		ahci_init_port(port_mmio, hpriv->cap,
1366c6fd2807SJeff Garzik 			       pp->cmd_slot_dma, pp->rx_fis_dma);
1367c6fd2807SJeff Garzik 	}
1368c6fd2807SJeff Garzik 
1369c6fd2807SJeff Garzik 	return rc;
1370c6fd2807SJeff Garzik }
1371c6fd2807SJeff Garzik 
1372c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap)
1373c6fd2807SJeff Garzik {
1374c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1375cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
13760d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1377c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1378c6fd2807SJeff Garzik 
13798e16f941STejun Heo 	ahci_power_up(port_mmio, hpriv->cap);
1380c6fd2807SJeff Garzik 	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
1381c6fd2807SJeff Garzik 
1382c6fd2807SJeff Garzik 	return 0;
1383c6fd2807SJeff Garzik }
1384c6fd2807SJeff Garzik 
1385c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
1386c6fd2807SJeff Garzik {
1387cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
13880d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1389c6fd2807SJeff Garzik 	u32 ctl;
1390c6fd2807SJeff Garzik 
1391c6fd2807SJeff Garzik 	if (mesg.event == PM_EVENT_SUSPEND) {
1392c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
1393c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
1394c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
1395c6fd2807SJeff Garzik 		 */
1396c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
1397c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
1398c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
1399c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
1400c6fd2807SJeff Garzik 	}
1401c6fd2807SJeff Garzik 
1402c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
1403c6fd2807SJeff Garzik }
1404c6fd2807SJeff Garzik 
1405c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
1406c6fd2807SJeff Garzik {
1407cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
1408cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = host->private_data;
14090d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1410c6fd2807SJeff Garzik 	int rc;
1411c6fd2807SJeff Garzik 
1412553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
1413553c4aa6STejun Heo 	if (rc)
1414553c4aa6STejun Heo 		return rc;
1415c6fd2807SJeff Garzik 
1416c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
1417c6fd2807SJeff Garzik 		rc = ahci_reset_controller(mmio, pdev);
1418c6fd2807SJeff Garzik 		if (rc)
1419c6fd2807SJeff Garzik 			return rc;
1420c6fd2807SJeff Garzik 
1421648a88beSTejun Heo 		ahci_init_controller(mmio, pdev, host->n_ports,
1422648a88beSTejun Heo 				     host->ports[0]->flags, hpriv);
1423c6fd2807SJeff Garzik 	}
1424c6fd2807SJeff Garzik 
1425cca3974eSJeff Garzik 	ata_host_resume(host);
1426c6fd2807SJeff Garzik 
1427c6fd2807SJeff Garzik 	return 0;
1428c6fd2807SJeff Garzik }
1429*438ac6d5STejun Heo #endif
1430c6fd2807SJeff Garzik 
1431c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
1432c6fd2807SJeff Garzik {
1433cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
1434cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1435c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
14360d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1437c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1438c6fd2807SJeff Garzik 	void *mem;
1439c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
1440c6fd2807SJeff Garzik 	int rc;
1441c6fd2807SJeff Garzik 
144224dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
1443c6fd2807SJeff Garzik 	if (!pp)
1444c6fd2807SJeff Garzik 		return -ENOMEM;
1445c6fd2807SJeff Garzik 
1446c6fd2807SJeff Garzik 	rc = ata_pad_alloc(ap, dev);
144724dc5f33STejun Heo 	if (rc)
1448c6fd2807SJeff Garzik 		return rc;
1449c6fd2807SJeff Garzik 
145024dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
145124dc5f33STejun Heo 				  GFP_KERNEL);
145224dc5f33STejun Heo 	if (!mem)
1453c6fd2807SJeff Garzik 		return -ENOMEM;
1454c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
1455c6fd2807SJeff Garzik 
1456c6fd2807SJeff Garzik 	/*
1457c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
1458c6fd2807SJeff Garzik 	 * 32 bytes each in size
1459c6fd2807SJeff Garzik 	 */
1460c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
1461c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
1462c6fd2807SJeff Garzik 
1463c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
1464c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
1465c6fd2807SJeff Garzik 
1466c6fd2807SJeff Garzik 	/*
1467c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
1468c6fd2807SJeff Garzik 	 */
1469c6fd2807SJeff Garzik 	pp->rx_fis = mem;
1470c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
1471c6fd2807SJeff Garzik 
1472c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
1473c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
1474c6fd2807SJeff Garzik 
1475c6fd2807SJeff Garzik 	/*
1476c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
1477c6fd2807SJeff Garzik 	 * and its scatter-gather table
1478c6fd2807SJeff Garzik 	 */
1479c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
1480c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
1481c6fd2807SJeff Garzik 
1482c6fd2807SJeff Garzik 	ap->private_data = pp;
1483c6fd2807SJeff Garzik 
14848e16f941STejun Heo 	/* power up port */
14858e16f941STejun Heo 	ahci_power_up(port_mmio, hpriv->cap);
14868e16f941STejun Heo 
1487c6fd2807SJeff Garzik 	/* initialize port */
1488c6fd2807SJeff Garzik 	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
1489c6fd2807SJeff Garzik 
1490c6fd2807SJeff Garzik 	return 0;
1491c6fd2807SJeff Garzik }
1492c6fd2807SJeff Garzik 
1493c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
1494c6fd2807SJeff Garzik {
1495cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
14960d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1497c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1498c6fd2807SJeff Garzik 	const char *emsg = NULL;
1499c6fd2807SJeff Garzik 	int rc;
1500c6fd2807SJeff Garzik 
1501c6fd2807SJeff Garzik 	/* de-initialize port */
1502c6fd2807SJeff Garzik 	rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
1503c6fd2807SJeff Garzik 	if (rc)
1504c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
1505c6fd2807SJeff Garzik }
1506c6fd2807SJeff Garzik 
15070d5ff566STejun Heo static void ahci_setup_port(struct ata_ioports *port, void __iomem *base,
1508c6fd2807SJeff Garzik 			    unsigned int port_idx)
1509c6fd2807SJeff Garzik {
1510c6fd2807SJeff Garzik 	VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
15110d5ff566STejun Heo 	base = ahci_port_base(base, port_idx);
1512c6fd2807SJeff Garzik 	VPRINTK("base now==0x%lx\n", base);
1513c6fd2807SJeff Garzik 
1514c6fd2807SJeff Garzik 	port->cmd_addr		= base;
1515c6fd2807SJeff Garzik 	port->scr_addr		= base + PORT_SCR;
1516c6fd2807SJeff Garzik 
1517c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1518c6fd2807SJeff Garzik }
1519c6fd2807SJeff Garzik 
1520c6fd2807SJeff Garzik static int ahci_host_init(struct ata_probe_ent *probe_ent)
1521c6fd2807SJeff Garzik {
1522c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv = probe_ent->private_data;
1523c6fd2807SJeff Garzik 	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
15240d5ff566STejun Heo 	void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
1525648a88beSTejun Heo 	unsigned int i, cap_n_ports, using_dac;
1526c6fd2807SJeff Garzik 	int rc;
1527c6fd2807SJeff Garzik 
1528c6fd2807SJeff Garzik 	rc = ahci_reset_controller(mmio, pdev);
1529c6fd2807SJeff Garzik 	if (rc)
1530c6fd2807SJeff Garzik 		return rc;
1531c6fd2807SJeff Garzik 
1532c6fd2807SJeff Garzik 	hpriv->cap = readl(mmio + HOST_CAP);
1533c6fd2807SJeff Garzik 	hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
1534648a88beSTejun Heo 	cap_n_ports = ahci_nr_ports(hpriv->cap);
1535c6fd2807SJeff Garzik 
1536c6fd2807SJeff Garzik 	VPRINTK("cap 0x%x  port_map 0x%x  n_ports %d\n",
1537648a88beSTejun Heo 		hpriv->cap, hpriv->port_map, cap_n_ports);
1538648a88beSTejun Heo 
1539648a88beSTejun Heo 	if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) {
1540648a88beSTejun Heo 		unsigned int n_ports = cap_n_ports;
1541648a88beSTejun Heo 		u32 port_map = hpriv->port_map;
1542648a88beSTejun Heo 		int max_port = 0;
1543648a88beSTejun Heo 
1544648a88beSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
1545648a88beSTejun Heo 			if (port_map & (1 << i)) {
1546648a88beSTejun Heo 				n_ports--;
1547648a88beSTejun Heo 				port_map &= ~(1 << i);
1548648a88beSTejun Heo 				max_port = i;
1549648a88beSTejun Heo 			} else
1550648a88beSTejun Heo 				probe_ent->dummy_port_mask |= 1 << i;
1551648a88beSTejun Heo 		}
1552648a88beSTejun Heo 
1553648a88beSTejun Heo 		if (n_ports || port_map)
1554648a88beSTejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
1555648a88beSTejun Heo 				   "nr_ports (%u) and implemented port map "
1556648a88beSTejun Heo 				   "(0x%x) don't match\n",
1557648a88beSTejun Heo 				   cap_n_ports, hpriv->port_map);
1558648a88beSTejun Heo 
1559648a88beSTejun Heo 		probe_ent->n_ports = max_port + 1;
1560648a88beSTejun Heo 	} else
1561648a88beSTejun Heo 		probe_ent->n_ports = cap_n_ports;
1562c6fd2807SJeff Garzik 
1563c6fd2807SJeff Garzik 	using_dac = hpriv->cap & HOST_CAP_64;
1564c6fd2807SJeff Garzik 	if (using_dac &&
1565c6fd2807SJeff Garzik 	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
1566c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
1567c6fd2807SJeff Garzik 		if (rc) {
1568c6fd2807SJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1569c6fd2807SJeff Garzik 			if (rc) {
1570c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
1571c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
1572c6fd2807SJeff Garzik 				return rc;
1573c6fd2807SJeff Garzik 			}
1574c6fd2807SJeff Garzik 		}
1575c6fd2807SJeff Garzik 	} else {
1576c6fd2807SJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
1577c6fd2807SJeff Garzik 		if (rc) {
1578c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1579c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
1580c6fd2807SJeff Garzik 			return rc;
1581c6fd2807SJeff Garzik 		}
1582c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1583c6fd2807SJeff Garzik 		if (rc) {
1584c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1585c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
1586c6fd2807SJeff Garzik 			return rc;
1587c6fd2807SJeff Garzik 		}
1588c6fd2807SJeff Garzik 	}
1589c6fd2807SJeff Garzik 
1590c6fd2807SJeff Garzik 	for (i = 0; i < probe_ent->n_ports; i++)
15910d5ff566STejun Heo 		ahci_setup_port(&probe_ent->port[i], mmio, i);
1592c6fd2807SJeff Garzik 
1593648a88beSTejun Heo 	ahci_init_controller(mmio, pdev, probe_ent->n_ports,
1594648a88beSTejun Heo 			     probe_ent->port_flags, hpriv);
1595c6fd2807SJeff Garzik 
1596c6fd2807SJeff Garzik 	pci_set_master(pdev);
1597c6fd2807SJeff Garzik 
1598c6fd2807SJeff Garzik 	return 0;
1599c6fd2807SJeff Garzik }
1600c6fd2807SJeff Garzik 
1601c6fd2807SJeff Garzik static void ahci_print_info(struct ata_probe_ent *probe_ent)
1602c6fd2807SJeff Garzik {
1603c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv = probe_ent->private_data;
1604c6fd2807SJeff Garzik 	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
16050d5ff566STejun Heo 	void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
1606c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
1607c6fd2807SJeff Garzik 	const char *speed_s;
1608c6fd2807SJeff Garzik 	u16 cc;
1609c6fd2807SJeff Garzik 	const char *scc_s;
1610c6fd2807SJeff Garzik 
1611c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
1612c6fd2807SJeff Garzik 	cap = hpriv->cap;
1613c6fd2807SJeff Garzik 	impl = hpriv->port_map;
1614c6fd2807SJeff Garzik 
1615c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
1616c6fd2807SJeff Garzik 	if (speed == 1)
1617c6fd2807SJeff Garzik 		speed_s = "1.5";
1618c6fd2807SJeff Garzik 	else if (speed == 2)
1619c6fd2807SJeff Garzik 		speed_s = "3";
1620c6fd2807SJeff Garzik 	else
1621c6fd2807SJeff Garzik 		speed_s = "?";
1622c6fd2807SJeff Garzik 
1623c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
1624c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
1625c6fd2807SJeff Garzik 		scc_s = "IDE";
1626c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
1627c6fd2807SJeff Garzik 		scc_s = "SATA";
1628c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
1629c6fd2807SJeff Garzik 		scc_s = "RAID";
1630c6fd2807SJeff Garzik 	else
1631c6fd2807SJeff Garzik 		scc_s = "unknown";
1632c6fd2807SJeff Garzik 
1633c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
1634c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
1635c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
1636c6fd2807SJeff Garzik 	       	,
1637c6fd2807SJeff Garzik 
1638c6fd2807SJeff Garzik 	       	(vers >> 24) & 0xff,
1639c6fd2807SJeff Garzik 	       	(vers >> 16) & 0xff,
1640c6fd2807SJeff Garzik 	       	(vers >> 8) & 0xff,
1641c6fd2807SJeff Garzik 	       	vers & 0xff,
1642c6fd2807SJeff Garzik 
1643c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
1644c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
1645c6fd2807SJeff Garzik 		speed_s,
1646c6fd2807SJeff Garzik 		impl,
1647c6fd2807SJeff Garzik 		scc_s);
1648c6fd2807SJeff Garzik 
1649c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
1650c6fd2807SJeff Garzik 		"flags: "
1651c6fd2807SJeff Garzik 	       	"%s%s%s%s%s%s"
1652c6fd2807SJeff Garzik 	       	"%s%s%s%s%s%s%s\n"
1653c6fd2807SJeff Garzik 	       	,
1654c6fd2807SJeff Garzik 
1655c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
1656c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
1657c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
1658c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
1659c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
1660c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
1661c6fd2807SJeff Garzik 
1662c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
1663c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
1664c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
1665c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
1666c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
1667c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
1668c6fd2807SJeff Garzik 		cap & (1 << 13) ? "part " : ""
1669c6fd2807SJeff Garzik 		);
1670c6fd2807SJeff Garzik }
1671c6fd2807SJeff Garzik 
1672c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1673c6fd2807SJeff Garzik {
1674c6fd2807SJeff Garzik 	static int printed_version;
167524dc5f33STejun Heo 	unsigned int board_idx = (unsigned int) ent->driver_data;
167624dc5f33STejun Heo 	struct device *dev = &pdev->dev;
167724dc5f33STejun Heo 	struct ata_probe_ent *probe_ent;
1678c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1679c6fd2807SJeff Garzik 	int rc;
1680c6fd2807SJeff Garzik 
1681c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1682c6fd2807SJeff Garzik 
1683c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
1684c6fd2807SJeff Garzik 
1685c6fd2807SJeff Garzik 	if (!printed_version++)
1686c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
1687c6fd2807SJeff Garzik 
168824dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
1689c6fd2807SJeff Garzik 	if (rc)
1690c6fd2807SJeff Garzik 		return rc;
1691c6fd2807SJeff Garzik 
16920d5ff566STejun Heo 	rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
16930d5ff566STejun Heo 	if (rc == -EBUSY)
169424dc5f33STejun Heo 		pcim_pin_device(pdev);
16950d5ff566STejun Heo 	if (rc)
169624dc5f33STejun Heo 		return rc;
1697c6fd2807SJeff Garzik 
169824dc5f33STejun Heo 	if (pci_enable_msi(pdev))
1699c6fd2807SJeff Garzik 		pci_intx(pdev, 1);
1700c6fd2807SJeff Garzik 
170124dc5f33STejun Heo 	probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
170224dc5f33STejun Heo 	if (probe_ent == NULL)
170324dc5f33STejun Heo 		return -ENOMEM;
1704c6fd2807SJeff Garzik 
1705c6fd2807SJeff Garzik 	probe_ent->dev = pci_dev_to_dev(pdev);
1706c6fd2807SJeff Garzik 	INIT_LIST_HEAD(&probe_ent->node);
1707c6fd2807SJeff Garzik 
170824dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
170924dc5f33STejun Heo 	if (!hpriv)
171024dc5f33STejun Heo 		return -ENOMEM;
1711c6fd2807SJeff Garzik 
1712c6fd2807SJeff Garzik 	probe_ent->sht		= ahci_port_info[board_idx].sht;
1713cca3974eSJeff Garzik 	probe_ent->port_flags	= ahci_port_info[board_idx].flags;
1714c6fd2807SJeff Garzik 	probe_ent->pio_mask	= ahci_port_info[board_idx].pio_mask;
1715c6fd2807SJeff Garzik 	probe_ent->udma_mask	= ahci_port_info[board_idx].udma_mask;
1716c6fd2807SJeff Garzik 	probe_ent->port_ops	= ahci_port_info[board_idx].port_ops;
1717c6fd2807SJeff Garzik 
1718c6fd2807SJeff Garzik        	probe_ent->irq = pdev->irq;
1719c6fd2807SJeff Garzik        	probe_ent->irq_flags = IRQF_SHARED;
17200d5ff566STejun Heo 	probe_ent->iomap = pcim_iomap_table(pdev);
1721c6fd2807SJeff Garzik 	probe_ent->private_data = hpriv;
1722c6fd2807SJeff Garzik 
1723c6fd2807SJeff Garzik 	/* initialize adapter */
1724c6fd2807SJeff Garzik 	rc = ahci_host_init(probe_ent);
1725c6fd2807SJeff Garzik 	if (rc)
172624dc5f33STejun Heo 		return rc;
1727c6fd2807SJeff Garzik 
1728cca3974eSJeff Garzik 	if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
1729c6fd2807SJeff Garzik 	    (hpriv->cap & HOST_CAP_NCQ))
1730cca3974eSJeff Garzik 		probe_ent->port_flags |= ATA_FLAG_NCQ;
1731c6fd2807SJeff Garzik 
1732c6fd2807SJeff Garzik 	ahci_print_info(probe_ent);
1733c6fd2807SJeff Garzik 
173424dc5f33STejun Heo 	if (!ata_device_add(probe_ent))
173524dc5f33STejun Heo 		return -ENODEV;
1736c6fd2807SJeff Garzik 
173724dc5f33STejun Heo 	devm_kfree(dev, probe_ent);
1738c6fd2807SJeff Garzik 	return 0;
1739c6fd2807SJeff Garzik }
1740c6fd2807SJeff Garzik 
1741c6fd2807SJeff Garzik static int __init ahci_init(void)
1742c6fd2807SJeff Garzik {
1743c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
1744c6fd2807SJeff Garzik }
1745c6fd2807SJeff Garzik 
1746c6fd2807SJeff Garzik static void __exit ahci_exit(void)
1747c6fd2807SJeff Garzik {
1748c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
1749c6fd2807SJeff Garzik }
1750c6fd2807SJeff Garzik 
1751c6fd2807SJeff Garzik 
1752c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
1753c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
1754c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
1755c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
1756c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
1757c6fd2807SJeff Garzik 
1758c6fd2807SJeff Garzik module_init(ahci_init);
1759c6fd2807SJeff Garzik module_exit(ahci_exit);
1760