xref: /openbmc/linux/drivers/ata/ahci.c (revision c9f89475a5b184e9a6077b995ce340e6804c1b1a)
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/sched.h>
43c6fd2807SJeff Garzik #include <linux/dma-mapping.h>
44c6fd2807SJeff Garzik #include <linux/device.h>
45c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
46c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
47c6fd2807SJeff Garzik #include <linux/libata.h>
48c6fd2807SJeff Garzik #include <asm/io.h>
49c6fd2807SJeff Garzik 
50c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
51c6fd2807SJeff Garzik #define DRV_VERSION	"2.0"
52c6fd2807SJeff Garzik 
53c6fd2807SJeff Garzik 
54c6fd2807SJeff Garzik enum {
55c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
56648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
57c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
58c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
59c6fd2807SJeff Garzik 	AHCI_USE_CLUSTERING	= 0,
60c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
61c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
62c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
63c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
64c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
65c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
66c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
67c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
68c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
69c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
70c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
71c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
72c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
73c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
74c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
75c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
76c6fd2807SJeff Garzik 
77c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
780291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
79c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
80c6fd2807SJeff Garzik 
81c6fd2807SJeff Garzik 	board_ahci		= 0,
82648a88beSTejun Heo 	board_ahci_pi		= 1,
83648a88beSTejun Heo 	board_ahci_vt8251	= 2,
84648a88beSTejun Heo 	board_ahci_ign_iferr	= 3,
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 */
100c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
101c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
102c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
103c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
104c6fd2807SJeff Garzik 
105c6fd2807SJeff Garzik 	/* registers for each SATA port */
106c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
107c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
108c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
109c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
110c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
111c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
112c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
113c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
114c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
115c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
116c6fd2807SJeff Garzik 	PORT_SCR		= 0x28, /* SATA phy register block */
117c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
118c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
119c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
120c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
121c6fd2807SJeff Garzik 
122c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
123c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
124c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
125c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
126c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
127c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
128c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
129c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
130c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
131c6fd2807SJeff Garzik 
132c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
133c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
134c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
135c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
136c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
137c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
138c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
139c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
140c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
141c6fd2807SJeff Garzik 
142c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
143c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
144c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
145c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
146c6fd2807SJeff Garzik 				  PORT_IRQ_UNK_FIS,
147c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
148c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
149c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
150c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
151c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
152c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
153c6fd2807SJeff Garzik 
154c6fd2807SJeff Garzik 	/* PORT_CMD bits */
155c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
156c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
157c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
158c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
159c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
160c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
161c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
162c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
163c6fd2807SJeff Garzik 
164c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
165c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
166c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
167c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
168c6fd2807SJeff Garzik 
169c6fd2807SJeff Garzik 	/* hpriv->flags bits */
170c6fd2807SJeff Garzik 	AHCI_FLAG_MSI		= (1 << 0),
171c6fd2807SJeff Garzik 
172c6fd2807SJeff Garzik 	/* ap->flags bits */
1734aeb0e32STejun Heo 	AHCI_FLAG_NO_NCQ		= (1 << 24),
1744aeb0e32STejun Heo 	AHCI_FLAG_IGN_IRQ_IF_ERR	= (1 << 25), /* ignore IRQ_IF_ERR */
175648a88beSTejun Heo 	AHCI_FLAG_HONOR_PI		= (1 << 26), /* honor PORTS_IMPL */
176c6fd2807SJeff Garzik };
177c6fd2807SJeff Garzik 
178c6fd2807SJeff Garzik struct ahci_cmd_hdr {
179c6fd2807SJeff Garzik 	u32			opts;
180c6fd2807SJeff Garzik 	u32			status;
181c6fd2807SJeff Garzik 	u32			tbl_addr;
182c6fd2807SJeff Garzik 	u32			tbl_addr_hi;
183c6fd2807SJeff Garzik 	u32			reserved[4];
184c6fd2807SJeff Garzik };
185c6fd2807SJeff Garzik 
186c6fd2807SJeff Garzik struct ahci_sg {
187c6fd2807SJeff Garzik 	u32			addr;
188c6fd2807SJeff Garzik 	u32			addr_hi;
189c6fd2807SJeff Garzik 	u32			reserved;
190c6fd2807SJeff Garzik 	u32			flags_size;
191c6fd2807SJeff Garzik };
192c6fd2807SJeff Garzik 
193c6fd2807SJeff Garzik struct ahci_host_priv {
194c6fd2807SJeff Garzik 	unsigned long		flags;
195c6fd2807SJeff Garzik 	u32			cap;	/* cache of HOST_CAP register */
196c6fd2807SJeff Garzik 	u32			port_map; /* cache of HOST_PORTS_IMPL reg */
197c6fd2807SJeff Garzik };
198c6fd2807SJeff Garzik 
199c6fd2807SJeff Garzik struct ahci_port_priv {
200c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
201c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
202c6fd2807SJeff Garzik 	void			*cmd_tbl;
203c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
204c6fd2807SJeff Garzik 	void			*rx_fis;
205c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2060291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2070291f95fSTejun Heo 	int			ncq_saw_spurious_sdb_cnt;
2080291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2090291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
210c6fd2807SJeff Garzik };
211c6fd2807SJeff Garzik 
212c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
213c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
214c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
215c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
2167d12e780SDavid Howells static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
217c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap);
218c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
219c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
220c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
221c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
222c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap);
223c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
224c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
225c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
226ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap);
227c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
228c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
229c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
230c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
231c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
232c6fd2807SJeff Garzik static void ahci_remove_one (struct pci_dev *pdev);
233c6fd2807SJeff Garzik 
234c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
235c6fd2807SJeff Garzik 	.module			= THIS_MODULE,
236c6fd2807SJeff Garzik 	.name			= DRV_NAME,
237c6fd2807SJeff Garzik 	.ioctl			= ata_scsi_ioctl,
238c6fd2807SJeff Garzik 	.queuecommand		= ata_scsi_queuecmd,
239c6fd2807SJeff Garzik 	.change_queue_depth	= ata_scsi_change_queue_depth,
240c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
241c6fd2807SJeff Garzik 	.this_id		= ATA_SHT_THIS_ID,
242c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
243c6fd2807SJeff Garzik 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
244c6fd2807SJeff Garzik 	.emulated		= ATA_SHT_EMULATED,
245c6fd2807SJeff Garzik 	.use_clustering		= AHCI_USE_CLUSTERING,
246c6fd2807SJeff Garzik 	.proc_name		= DRV_NAME,
247c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
248c6fd2807SJeff Garzik 	.slave_configure	= ata_scsi_slave_config,
249c6fd2807SJeff Garzik 	.slave_destroy		= ata_scsi_slave_destroy,
250c6fd2807SJeff Garzik 	.bios_param		= ata_std_bios_param,
251c6fd2807SJeff Garzik 	.suspend		= ata_scsi_device_suspend,
252c6fd2807SJeff Garzik 	.resume			= ata_scsi_device_resume,
253c6fd2807SJeff Garzik };
254c6fd2807SJeff Garzik 
255c6fd2807SJeff Garzik static const struct ata_port_operations ahci_ops = {
256c6fd2807SJeff Garzik 	.port_disable		= ata_port_disable,
257c6fd2807SJeff Garzik 
258c6fd2807SJeff Garzik 	.check_status		= ahci_check_status,
259c6fd2807SJeff Garzik 	.check_altstatus	= ahci_check_status,
260c6fd2807SJeff Garzik 	.dev_select		= ata_noop_dev_select,
261c6fd2807SJeff Garzik 
262c6fd2807SJeff Garzik 	.tf_read		= ahci_tf_read,
263c6fd2807SJeff Garzik 
264c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
265c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
266c6fd2807SJeff Garzik 
267c6fd2807SJeff Garzik 	.irq_handler		= ahci_interrupt,
268c6fd2807SJeff Garzik 	.irq_clear		= ahci_irq_clear,
269c6fd2807SJeff Garzik 
270c6fd2807SJeff Garzik 	.scr_read		= ahci_scr_read,
271c6fd2807SJeff Garzik 	.scr_write		= ahci_scr_write,
272c6fd2807SJeff Garzik 
273c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
274c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
275c6fd2807SJeff Garzik 
276c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
277c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
278c6fd2807SJeff Garzik 
279c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
280c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
281c6fd2807SJeff Garzik 
282c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
283c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
284c6fd2807SJeff Garzik };
285c6fd2807SJeff Garzik 
286ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = {
287ad616ffbSTejun Heo 	.port_disable		= ata_port_disable,
288ad616ffbSTejun Heo 
289ad616ffbSTejun Heo 	.check_status		= ahci_check_status,
290ad616ffbSTejun Heo 	.check_altstatus	= ahci_check_status,
291ad616ffbSTejun Heo 	.dev_select		= ata_noop_dev_select,
292ad616ffbSTejun Heo 
293ad616ffbSTejun Heo 	.tf_read		= ahci_tf_read,
294ad616ffbSTejun Heo 
295ad616ffbSTejun Heo 	.qc_prep		= ahci_qc_prep,
296ad616ffbSTejun Heo 	.qc_issue		= ahci_qc_issue,
297ad616ffbSTejun Heo 
298ad616ffbSTejun Heo 	.irq_handler		= ahci_interrupt,
299ad616ffbSTejun Heo 	.irq_clear		= ahci_irq_clear,
300ad616ffbSTejun Heo 
301ad616ffbSTejun Heo 	.scr_read		= ahci_scr_read,
302ad616ffbSTejun Heo 	.scr_write		= ahci_scr_write,
303ad616ffbSTejun Heo 
304ad616ffbSTejun Heo 	.freeze			= ahci_freeze,
305ad616ffbSTejun Heo 	.thaw			= ahci_thaw,
306ad616ffbSTejun Heo 
307ad616ffbSTejun Heo 	.error_handler		= ahci_vt8251_error_handler,
308ad616ffbSTejun Heo 	.post_internal_cmd	= ahci_post_internal_cmd,
309ad616ffbSTejun Heo 
310ad616ffbSTejun Heo 	.port_suspend		= ahci_port_suspend,
311ad616ffbSTejun Heo 	.port_resume		= ahci_port_resume,
312ad616ffbSTejun Heo 
313ad616ffbSTejun Heo 	.port_start		= ahci_port_start,
314ad616ffbSTejun Heo 	.port_stop		= ahci_port_stop,
315ad616ffbSTejun Heo };
316ad616ffbSTejun Heo 
317c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
318c6fd2807SJeff Garzik 	/* board_ahci */
319c6fd2807SJeff Garzik 	{
320c6fd2807SJeff Garzik 		.sht		= &ahci_sht,
321cca3974eSJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
322c6fd2807SJeff Garzik 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
323c6fd2807SJeff Garzik 				  ATA_FLAG_SKIP_D2H_BSY,
324c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
325c6fd2807SJeff Garzik 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
326c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
327c6fd2807SJeff Garzik 	},
328648a88beSTejun Heo 	/* board_ahci_pi */
329648a88beSTejun Heo 	{
330648a88beSTejun Heo 		.sht		= &ahci_sht,
331648a88beSTejun Heo 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
332648a88beSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
333648a88beSTejun Heo 				  ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
334648a88beSTejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
335648a88beSTejun Heo 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
336648a88beSTejun Heo 		.port_ops	= &ahci_ops,
337648a88beSTejun Heo 	},
338c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
339c6fd2807SJeff Garzik 	{
340c6fd2807SJeff Garzik 		.sht		= &ahci_sht,
341cca3974eSJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
342c6fd2807SJeff Garzik 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
343ad616ffbSTejun Heo 				  ATA_FLAG_SKIP_D2H_BSY |
344ad616ffbSTejun Heo 				  ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
345c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
346c6fd2807SJeff Garzik 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
347ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
348c6fd2807SJeff Garzik 	},
34941669553STejun Heo 	/* board_ahci_ign_iferr */
35041669553STejun Heo 	{
35141669553STejun Heo 		.sht		= &ahci_sht,
35241669553STejun Heo 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
35341669553STejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
35441669553STejun Heo 				  ATA_FLAG_SKIP_D2H_BSY |
35541669553STejun Heo 				  AHCI_FLAG_IGN_IRQ_IF_ERR,
35641669553STejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
35741669553STejun Heo 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
35841669553STejun Heo 		.port_ops	= &ahci_ops,
35941669553STejun Heo 	},
360c6fd2807SJeff Garzik };
361c6fd2807SJeff Garzik 
362c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
363c6fd2807SJeff Garzik 	/* Intel */
36454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
36554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
36654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
36754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
36854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
36982490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
37054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
37154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
37254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
37354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
374648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
375648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
376648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
377648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
378648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
379648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */
380648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */
381648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */
382648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */
383648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */
384648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
385648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
386648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
387648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
388648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
389648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
390c6fd2807SJeff Garzik 
391c6fd2807SJeff Garzik 	/* JMicron */
39241669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2360), board_ahci_ign_iferr }, /* JMB360 */
39341669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2361), board_ahci_ign_iferr }, /* JMB361 */
39441669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2363), board_ahci_ign_iferr }, /* JMB363 */
39541669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2365), board_ahci_ign_iferr }, /* JMB365 */
39641669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2366), board_ahci_ign_iferr }, /* JMB366 */
397c6fd2807SJeff Garzik 
398c6fd2807SJeff Garzik 	/* ATI */
39954bb3a94SJeff Garzik 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
40054bb3a94SJeff Garzik 	{ PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
401c6fd2807SJeff Garzik 
402c6fd2807SJeff Garzik 	/* VIA */
40354bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
404c6fd2807SJeff Garzik 
405c6fd2807SJeff Garzik 	/* NVIDIA */
40654bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },		/* MCP65 */
40754bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci },		/* MCP65 */
40854bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci },		/* MCP65 */
40954bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci },		/* MCP65 */
4106fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci },		/* MCP65 */
4116fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci },		/* MCP65 */
4126fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci },		/* MCP65 */
4136fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci },		/* MCP65 */
4146fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci },		/* MCP67 */
4156fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci },		/* MCP67 */
4166fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci },		/* MCP67 */
4176fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci },		/* MCP67 */
418895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },		/* MCP67 */
419895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },		/* MCP67 */
420895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },		/* MCP67 */
421895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },		/* MCP67 */
422895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },		/* MCP67 */
423895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },		/* MCP67 */
424895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },		/* MCP67 */
425895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },		/* MCP67 */
426c6fd2807SJeff Garzik 
427c6fd2807SJeff Garzik 	/* SiS */
42854bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
42954bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
43054bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
431c6fd2807SJeff Garzik 
432415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
433415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
434*c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
435415ae2b5SJeff Garzik 
436c6fd2807SJeff Garzik 	{ }	/* terminate list */
437c6fd2807SJeff Garzik };
438c6fd2807SJeff Garzik 
439c6fd2807SJeff Garzik 
440c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
441c6fd2807SJeff Garzik 	.name			= DRV_NAME,
442c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
443c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
444c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
445c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
446c6fd2807SJeff Garzik 	.remove			= ahci_remove_one,
447c6fd2807SJeff Garzik };
448c6fd2807SJeff Garzik 
449c6fd2807SJeff Garzik 
45098fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
45198fa4b60STejun Heo {
45298fa4b60STejun Heo 	return (cap & 0x1f) + 1;
45398fa4b60STejun Heo }
45498fa4b60STejun Heo 
455c6fd2807SJeff Garzik static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
456c6fd2807SJeff Garzik {
457c6fd2807SJeff Garzik 	return base + 0x100 + (port * 0x80);
458c6fd2807SJeff Garzik }
459c6fd2807SJeff Garzik 
460c6fd2807SJeff Garzik static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
461c6fd2807SJeff Garzik {
462c6fd2807SJeff Garzik 	return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
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 
478c6fd2807SJeff Garzik 	return readl((void __iomem *) 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 
496c6fd2807SJeff Garzik 	writel(val, (void __iomem *) 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 
590c6fd2807SJeff Garzik static void ahci_power_down(void __iomem *port_mmio, u32 cap)
591c6fd2807SJeff Garzik {
592c6fd2807SJeff Garzik 	u32 cmd, scontrol;
593c6fd2807SJeff Garzik 
59407c53dacSTejun Heo 	if (!(cap & HOST_CAP_SSS))
59507c53dacSTejun Heo 		return;
596c6fd2807SJeff Garzik 
59707c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
598c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
599c6fd2807SJeff Garzik 	scontrol &= ~0xf;
600c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
601c6fd2807SJeff Garzik 
602c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
60307c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
604c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
605c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
606c6fd2807SJeff Garzik }
607c6fd2807SJeff Garzik 
608c6fd2807SJeff Garzik static void ahci_init_port(void __iomem *port_mmio, u32 cap,
609c6fd2807SJeff Garzik 			   dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
610c6fd2807SJeff Garzik {
611c6fd2807SJeff Garzik 	/* enable FIS reception */
612c6fd2807SJeff Garzik 	ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
613c6fd2807SJeff Garzik 
614c6fd2807SJeff Garzik 	/* enable DMA */
615c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
616c6fd2807SJeff Garzik }
617c6fd2807SJeff Garzik 
618c6fd2807SJeff Garzik static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
619c6fd2807SJeff Garzik {
620c6fd2807SJeff Garzik 	int rc;
621c6fd2807SJeff Garzik 
622c6fd2807SJeff Garzik 	/* disable DMA */
623c6fd2807SJeff Garzik 	rc = ahci_stop_engine(port_mmio);
624c6fd2807SJeff Garzik 	if (rc) {
625c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
626c6fd2807SJeff Garzik 		return rc;
627c6fd2807SJeff Garzik 	}
628c6fd2807SJeff Garzik 
629c6fd2807SJeff Garzik 	/* disable FIS reception */
630c6fd2807SJeff Garzik 	rc = ahci_stop_fis_rx(port_mmio);
631c6fd2807SJeff Garzik 	if (rc) {
632c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
633c6fd2807SJeff Garzik 		return rc;
634c6fd2807SJeff Garzik 	}
635c6fd2807SJeff Garzik 
636c6fd2807SJeff Garzik 	return 0;
637c6fd2807SJeff Garzik }
638c6fd2807SJeff Garzik 
639c6fd2807SJeff Garzik static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
640c6fd2807SJeff Garzik {
64198fa4b60STejun Heo 	u32 cap_save, impl_save, tmp;
642c6fd2807SJeff Garzik 
643c6fd2807SJeff Garzik 	cap_save = readl(mmio + HOST_CAP);
64498fa4b60STejun Heo 	impl_save = readl(mmio + HOST_PORTS_IMPL);
645c6fd2807SJeff Garzik 
646c6fd2807SJeff Garzik 	/* global controller reset */
647c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
648c6fd2807SJeff Garzik 	if ((tmp & HOST_RESET) == 0) {
649c6fd2807SJeff Garzik 		writel(tmp | HOST_RESET, mmio + HOST_CTL);
650c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
651c6fd2807SJeff Garzik 	}
652c6fd2807SJeff Garzik 
653c6fd2807SJeff Garzik 	/* reset must complete within 1 second, or
654c6fd2807SJeff Garzik 	 * the hardware should be considered fried.
655c6fd2807SJeff Garzik 	 */
656c6fd2807SJeff Garzik 	ssleep(1);
657c6fd2807SJeff Garzik 
658c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
659c6fd2807SJeff Garzik 	if (tmp & HOST_RESET) {
660c6fd2807SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
661c6fd2807SJeff Garzik 			   "controller reset failed (0x%x)\n", tmp);
662c6fd2807SJeff Garzik 		return -EIO;
663c6fd2807SJeff Garzik 	}
664c6fd2807SJeff Garzik 
66598fa4b60STejun Heo 	/* turn on AHCI mode */
666c6fd2807SJeff Garzik 	writel(HOST_AHCI_EN, mmio + HOST_CTL);
667c6fd2807SJeff Garzik 	(void) readl(mmio + HOST_CTL);	/* flush */
66898fa4b60STejun Heo 
66998fa4b60STejun Heo 	/* These write-once registers are normally cleared on reset.
67098fa4b60STejun Heo 	 * Restore BIOS values... which we HOPE were present before
67198fa4b60STejun Heo 	 * reset.
67298fa4b60STejun Heo 	 */
67398fa4b60STejun Heo 	if (!impl_save) {
67498fa4b60STejun Heo 		impl_save = (1 << ahci_nr_ports(cap_save)) - 1;
67598fa4b60STejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
67698fa4b60STejun Heo 			   "PORTS_IMPL is zero, forcing 0x%x\n", impl_save);
67798fa4b60STejun Heo 	}
678c6fd2807SJeff Garzik 	writel(cap_save, mmio + HOST_CAP);
67998fa4b60STejun Heo 	writel(impl_save, mmio + HOST_PORTS_IMPL);
680c6fd2807SJeff Garzik 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
681c6fd2807SJeff Garzik 
682c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
683c6fd2807SJeff Garzik 		u16 tmp16;
684c6fd2807SJeff Garzik 
685c6fd2807SJeff Garzik 		/* configure PCS */
686c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
687c6fd2807SJeff Garzik 		tmp16 |= 0xf;
688c6fd2807SJeff Garzik 		pci_write_config_word(pdev, 0x92, tmp16);
689c6fd2807SJeff Garzik 	}
690c6fd2807SJeff Garzik 
691c6fd2807SJeff Garzik 	return 0;
692c6fd2807SJeff Garzik }
693c6fd2807SJeff Garzik 
694c6fd2807SJeff Garzik static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
695648a88beSTejun Heo 				 int n_ports, unsigned int port_flags,
696648a88beSTejun Heo 				 struct ahci_host_priv *hpriv)
697c6fd2807SJeff Garzik {
698c6fd2807SJeff Garzik 	int i, rc;
699c6fd2807SJeff Garzik 	u32 tmp;
700c6fd2807SJeff Garzik 
701c6fd2807SJeff Garzik 	for (i = 0; i < n_ports; i++) {
702c6fd2807SJeff Garzik 		void __iomem *port_mmio = ahci_port_base(mmio, i);
703c6fd2807SJeff Garzik 		const char *emsg = NULL;
704c6fd2807SJeff Garzik 
705648a88beSTejun Heo 		if ((port_flags & AHCI_FLAG_HONOR_PI) &&
706648a88beSTejun Heo 		    !(hpriv->port_map & (1 << i)))
707c6fd2807SJeff Garzik 			continue;
708c6fd2807SJeff Garzik 
709c6fd2807SJeff Garzik 		/* make sure port is not active */
710648a88beSTejun Heo 		rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
711c6fd2807SJeff Garzik 		if (rc)
712c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
713c6fd2807SJeff Garzik 				   "%s (%d)\n", emsg, rc);
714c6fd2807SJeff Garzik 
715c6fd2807SJeff Garzik 		/* clear SError */
716c6fd2807SJeff Garzik 		tmp = readl(port_mmio + PORT_SCR_ERR);
717c6fd2807SJeff Garzik 		VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
718c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_SCR_ERR);
719c6fd2807SJeff Garzik 
720c6fd2807SJeff Garzik 		/* clear port IRQ */
721c6fd2807SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
722c6fd2807SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
723c6fd2807SJeff Garzik 		if (tmp)
724c6fd2807SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
725c6fd2807SJeff Garzik 
726c6fd2807SJeff Garzik 		writel(1 << i, mmio + HOST_IRQ_STAT);
727c6fd2807SJeff Garzik 	}
728c6fd2807SJeff Garzik 
729c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
730c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
731c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
732c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
733c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
734c6fd2807SJeff Garzik }
735c6fd2807SJeff Garzik 
736c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
737c6fd2807SJeff Garzik {
738c6fd2807SJeff Garzik 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
739c6fd2807SJeff Garzik 	struct ata_taskfile tf;
740c6fd2807SJeff Garzik 	u32 tmp;
741c6fd2807SJeff Garzik 
742c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
743c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
744c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
745c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
746c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
747c6fd2807SJeff Garzik 
748c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
749c6fd2807SJeff Garzik }
750c6fd2807SJeff Garzik 
751c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
752c6fd2807SJeff Garzik 			       u32 opts)
753c6fd2807SJeff Garzik {
754c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
755c6fd2807SJeff Garzik 
756c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
757c6fd2807SJeff Garzik 
758c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
759c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
760c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
761c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
762c6fd2807SJeff Garzik }
763c6fd2807SJeff Garzik 
764c6fd2807SJeff Garzik static int ahci_clo(struct ata_port *ap)
765c6fd2807SJeff Garzik {
766c6fd2807SJeff Garzik 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
767cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
768c6fd2807SJeff Garzik 	u32 tmp;
769c6fd2807SJeff Garzik 
770c6fd2807SJeff Garzik 	if (!(hpriv->cap & HOST_CAP_CLO))
771c6fd2807SJeff Garzik 		return -EOPNOTSUPP;
772c6fd2807SJeff Garzik 
773c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
774c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
775c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
776c6fd2807SJeff Garzik 
777c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
778c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
779c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
780c6fd2807SJeff Garzik 		return -EIO;
781c6fd2807SJeff Garzik 
782c6fd2807SJeff Garzik 	return 0;
783c6fd2807SJeff Garzik }
784c6fd2807SJeff Garzik 
785c6fd2807SJeff Garzik static int ahci_softreset(struct ata_port *ap, unsigned int *class)
786c6fd2807SJeff Garzik {
787c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
788cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
789c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
790c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
791c6fd2807SJeff Garzik 	const char *reason = NULL;
792c6fd2807SJeff Garzik 	struct ata_taskfile tf;
793c6fd2807SJeff Garzik 	u32 tmp;
794c6fd2807SJeff Garzik 	u8 *fis;
795c6fd2807SJeff Garzik 	int rc;
796c6fd2807SJeff Garzik 
797c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
798c6fd2807SJeff Garzik 
799c6fd2807SJeff Garzik 	if (ata_port_offline(ap)) {
800c6fd2807SJeff Garzik 		DPRINTK("PHY reports no device\n");
801c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
802c6fd2807SJeff Garzik 		return 0;
803c6fd2807SJeff Garzik 	}
804c6fd2807SJeff Garzik 
805c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
806c6fd2807SJeff Garzik 	rc = ahci_stop_engine(port_mmio);
807c6fd2807SJeff Garzik 	if (rc) {
808c6fd2807SJeff Garzik 		reason = "failed to stop engine";
809c6fd2807SJeff Garzik 		goto fail_restart;
810c6fd2807SJeff Garzik 	}
811c6fd2807SJeff Garzik 
812c6fd2807SJeff Garzik 	/* check BUSY/DRQ, perform Command List Override if necessary */
8131244a19cSTejun Heo 	if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
814c6fd2807SJeff Garzik 		rc = ahci_clo(ap);
815c6fd2807SJeff Garzik 
816c6fd2807SJeff Garzik 		if (rc == -EOPNOTSUPP) {
817c6fd2807SJeff Garzik 			reason = "port busy but CLO unavailable";
818c6fd2807SJeff Garzik 			goto fail_restart;
819c6fd2807SJeff Garzik 		} else if (rc) {
820c6fd2807SJeff Garzik 			reason = "port busy but CLO failed";
821c6fd2807SJeff Garzik 			goto fail_restart;
822c6fd2807SJeff Garzik 		}
823c6fd2807SJeff Garzik 	}
824c6fd2807SJeff Garzik 
825c6fd2807SJeff Garzik 	/* restart engine */
826c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
827c6fd2807SJeff Garzik 
828c6fd2807SJeff Garzik 	ata_tf_init(ap->device, &tf);
829c6fd2807SJeff Garzik 	fis = pp->cmd_tbl;
830c6fd2807SJeff Garzik 
831c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
832c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, 0,
833c6fd2807SJeff Garzik 			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
834c6fd2807SJeff Garzik 
835c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
836c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, fis, 0);
837c6fd2807SJeff Garzik 	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
838c6fd2807SJeff Garzik 
839c6fd2807SJeff Garzik 	writel(1, port_mmio + PORT_CMD_ISSUE);
840c6fd2807SJeff Garzik 
841c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
842c6fd2807SJeff Garzik 	if (tmp & 0x1) {
843c6fd2807SJeff Garzik 		rc = -EIO;
844c6fd2807SJeff Garzik 		reason = "1st FIS failed";
845c6fd2807SJeff Garzik 		goto fail;
846c6fd2807SJeff Garzik 	}
847c6fd2807SJeff Garzik 
848c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
849c6fd2807SJeff Garzik 	msleep(1);
850c6fd2807SJeff Garzik 
851c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
852c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
853c6fd2807SJeff Garzik 
854c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
855c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, fis, 0);
856c6fd2807SJeff Garzik 	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
857c6fd2807SJeff Garzik 
858c6fd2807SJeff Garzik 	writel(1, port_mmio + PORT_CMD_ISSUE);
859c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
860c6fd2807SJeff Garzik 
861c6fd2807SJeff Garzik 	/* spec mandates ">= 2ms" before checking status.
862c6fd2807SJeff Garzik 	 * We wait 150ms, because that was the magic delay used for
863c6fd2807SJeff Garzik 	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time
864c6fd2807SJeff Garzik 	 * between when the ATA command register is written, and then
865c6fd2807SJeff Garzik 	 * status is checked.  Because waiting for "a while" before
866c6fd2807SJeff Garzik 	 * checking status is fine, post SRST, we perform this magic
867c6fd2807SJeff Garzik 	 * delay here as well.
868c6fd2807SJeff Garzik 	 */
869c6fd2807SJeff Garzik 	msleep(150);
870c6fd2807SJeff Garzik 
871c6fd2807SJeff Garzik 	*class = ATA_DEV_NONE;
872c6fd2807SJeff Garzik 	if (ata_port_online(ap)) {
873c6fd2807SJeff Garzik 		if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
874c6fd2807SJeff Garzik 			rc = -EIO;
875c6fd2807SJeff Garzik 			reason = "device not ready";
876c6fd2807SJeff Garzik 			goto fail;
877c6fd2807SJeff Garzik 		}
878c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
879c6fd2807SJeff Garzik 	}
880c6fd2807SJeff Garzik 
881c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
882c6fd2807SJeff Garzik 	return 0;
883c6fd2807SJeff Garzik 
884c6fd2807SJeff Garzik  fail_restart:
885c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
886c6fd2807SJeff Garzik  fail:
887c6fd2807SJeff Garzik 	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
888c6fd2807SJeff Garzik 	return rc;
889c6fd2807SJeff Garzik }
890c6fd2807SJeff Garzik 
891c6fd2807SJeff Garzik static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
892c6fd2807SJeff Garzik {
893c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
894c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
895c6fd2807SJeff Garzik 	struct ata_taskfile tf;
896cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
897c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
898c6fd2807SJeff Garzik 	int rc;
899c6fd2807SJeff Garzik 
900c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
901c6fd2807SJeff Garzik 
902c6fd2807SJeff Garzik 	ahci_stop_engine(port_mmio);
903c6fd2807SJeff Garzik 
904c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
905c6fd2807SJeff Garzik 	ata_tf_init(ap->device, &tf);
906dfd7a3dbSTejun Heo 	tf.command = 0x80;
907c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, d2h_fis, 0);
908c6fd2807SJeff Garzik 
909c6fd2807SJeff Garzik 	rc = sata_std_hardreset(ap, class);
910c6fd2807SJeff Garzik 
911c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
912c6fd2807SJeff Garzik 
913c6fd2807SJeff Garzik 	if (rc == 0 && ata_port_online(ap))
914c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
915c6fd2807SJeff Garzik 	if (*class == ATA_DEV_UNKNOWN)
916c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
917c6fd2807SJeff Garzik 
918c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
919c6fd2807SJeff Garzik 	return rc;
920c6fd2807SJeff Garzik }
921c6fd2807SJeff Garzik 
922ad616ffbSTejun Heo static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
923ad616ffbSTejun Heo {
924ad616ffbSTejun Heo 	void __iomem *mmio = ap->host->mmio_base;
925ad616ffbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
926ad616ffbSTejun Heo 	int rc;
927ad616ffbSTejun Heo 
928ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
929ad616ffbSTejun Heo 
930ad616ffbSTejun Heo 	ahci_stop_engine(port_mmio);
931ad616ffbSTejun Heo 
932ad616ffbSTejun Heo 	rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
933ad616ffbSTejun Heo 
934ad616ffbSTejun Heo 	/* vt8251 needs SError cleared for the port to operate */
935ad616ffbSTejun Heo 	ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
936ad616ffbSTejun Heo 
937ad616ffbSTejun Heo 	ahci_start_engine(port_mmio);
938ad616ffbSTejun Heo 
939ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
940ad616ffbSTejun Heo 
941ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
942ad616ffbSTejun Heo 	 * request follow-up softreset.
943ad616ffbSTejun Heo 	 */
944ad616ffbSTejun Heo 	return rc ?: -EAGAIN;
945ad616ffbSTejun Heo }
946ad616ffbSTejun Heo 
947c6fd2807SJeff Garzik static void ahci_postreset(struct ata_port *ap, unsigned int *class)
948c6fd2807SJeff Garzik {
949c6fd2807SJeff Garzik 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
950c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
951c6fd2807SJeff Garzik 
952c6fd2807SJeff Garzik 	ata_std_postreset(ap, class);
953c6fd2807SJeff Garzik 
954c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
955c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
956c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
957c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
958c6fd2807SJeff Garzik 	else
959c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
960c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
961c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
962c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
963c6fd2807SJeff Garzik 	}
964c6fd2807SJeff Garzik }
965c6fd2807SJeff Garzik 
966c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap)
967c6fd2807SJeff Garzik {
968c6fd2807SJeff Garzik 	void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
969c6fd2807SJeff Garzik 
970c6fd2807SJeff Garzik 	return readl(mmio + PORT_TFDATA) & 0xFF;
971c6fd2807SJeff Garzik }
972c6fd2807SJeff Garzik 
973c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
974c6fd2807SJeff Garzik {
975c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
976c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
977c6fd2807SJeff Garzik 
978c6fd2807SJeff Garzik 	ata_tf_from_fis(d2h_fis, tf);
979c6fd2807SJeff Garzik }
980c6fd2807SJeff Garzik 
981c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
982c6fd2807SJeff Garzik {
983c6fd2807SJeff Garzik 	struct scatterlist *sg;
984c6fd2807SJeff Garzik 	struct ahci_sg *ahci_sg;
985c6fd2807SJeff Garzik 	unsigned int n_sg = 0;
986c6fd2807SJeff Garzik 
987c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
988c6fd2807SJeff Garzik 
989c6fd2807SJeff Garzik 	/*
990c6fd2807SJeff Garzik 	 * Next, the S/G list.
991c6fd2807SJeff Garzik 	 */
992c6fd2807SJeff Garzik 	ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
993c6fd2807SJeff Garzik 	ata_for_each_sg(sg, qc) {
994c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
995c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
996c6fd2807SJeff Garzik 
997c6fd2807SJeff Garzik 		ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
998c6fd2807SJeff Garzik 		ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
999c6fd2807SJeff Garzik 		ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
1000c6fd2807SJeff Garzik 
1001c6fd2807SJeff Garzik 		ahci_sg++;
1002c6fd2807SJeff Garzik 		n_sg++;
1003c6fd2807SJeff Garzik 	}
1004c6fd2807SJeff Garzik 
1005c6fd2807SJeff Garzik 	return n_sg;
1006c6fd2807SJeff Garzik }
1007c6fd2807SJeff Garzik 
1008c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1009c6fd2807SJeff Garzik {
1010c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1011c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1012c6fd2807SJeff Garzik 	int is_atapi = is_atapi_taskfile(&qc->tf);
1013c6fd2807SJeff Garzik 	void *cmd_tbl;
1014c6fd2807SJeff Garzik 	u32 opts;
1015c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1016c6fd2807SJeff Garzik 	unsigned int n_elem;
1017c6fd2807SJeff Garzik 
1018c6fd2807SJeff Garzik 	/*
1019c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1020c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1021c6fd2807SJeff Garzik 	 */
1022c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1023c6fd2807SJeff Garzik 
1024c6fd2807SJeff Garzik 	ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
1025c6fd2807SJeff Garzik 	if (is_atapi) {
1026c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1027c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1028c6fd2807SJeff Garzik 	}
1029c6fd2807SJeff Garzik 
1030c6fd2807SJeff Garzik 	n_elem = 0;
1031c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1032c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1033c6fd2807SJeff Garzik 
1034c6fd2807SJeff Garzik 	/*
1035c6fd2807SJeff Garzik 	 * Fill in command slot information.
1036c6fd2807SJeff Garzik 	 */
1037c6fd2807SJeff Garzik 	opts = cmd_fis_len | n_elem << 16;
1038c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1039c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1040c6fd2807SJeff Garzik 	if (is_atapi)
1041c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1042c6fd2807SJeff Garzik 
1043c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1044c6fd2807SJeff Garzik }
1045c6fd2807SJeff Garzik 
1046c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1047c6fd2807SJeff Garzik {
1048c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1049c6fd2807SJeff Garzik 	struct ata_eh_info *ehi = &ap->eh_info;
1050c6fd2807SJeff Garzik 	unsigned int err_mask = 0, action = 0;
1051c6fd2807SJeff Garzik 	struct ata_queued_cmd *qc;
1052c6fd2807SJeff Garzik 	u32 serror;
1053c6fd2807SJeff Garzik 
1054c6fd2807SJeff Garzik 	ata_ehi_clear_desc(ehi);
1055c6fd2807SJeff Garzik 
1056c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
1057c6fd2807SJeff Garzik 	serror = ahci_scr_read(ap, SCR_ERROR);
1058c6fd2807SJeff Garzik 	ahci_scr_write(ap, SCR_ERROR, serror);
1059c6fd2807SJeff Garzik 
1060c6fd2807SJeff Garzik 	/* analyze @irq_stat */
1061c6fd2807SJeff Garzik 	ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
1062c6fd2807SJeff Garzik 
106341669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
106441669553STejun Heo 	if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
106541669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
106641669553STejun Heo 
1067c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_TF_ERR)
1068c6fd2807SJeff Garzik 		err_mask |= AC_ERR_DEV;
1069c6fd2807SJeff Garzik 
1070c6fd2807SJeff Garzik 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
1071c6fd2807SJeff Garzik 		err_mask |= AC_ERR_HOST_BUS;
1072c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1073c6fd2807SJeff Garzik 	}
1074c6fd2807SJeff Garzik 
1075c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_IF_ERR) {
1076c6fd2807SJeff Garzik 		err_mask |= AC_ERR_ATA_BUS;
1077c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1078c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", interface fatal error");
1079c6fd2807SJeff Garzik 	}
1080c6fd2807SJeff Garzik 
1081c6fd2807SJeff Garzik 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
1082c6fd2807SJeff Garzik 		ata_ehi_hotplugged(ehi);
1083c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
1084c6fd2807SJeff Garzik 			"connection status changed" : "PHY RDY changed");
1085c6fd2807SJeff Garzik 	}
1086c6fd2807SJeff Garzik 
1087c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
1088c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
1089c6fd2807SJeff Garzik 
1090c6fd2807SJeff Garzik 		err_mask |= AC_ERR_HSM;
1091c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1092c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
1093c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
1094c6fd2807SJeff Garzik 	}
1095c6fd2807SJeff Garzik 
1096c6fd2807SJeff Garzik 	/* okay, let's hand over to EH */
1097c6fd2807SJeff Garzik 	ehi->serror |= serror;
1098c6fd2807SJeff Garzik 	ehi->action |= action;
1099c6fd2807SJeff Garzik 
1100c6fd2807SJeff Garzik 	qc = ata_qc_from_tag(ap, ap->active_tag);
1101c6fd2807SJeff Garzik 	if (qc)
1102c6fd2807SJeff Garzik 		qc->err_mask |= err_mask;
1103c6fd2807SJeff Garzik 	else
1104c6fd2807SJeff Garzik 		ehi->err_mask |= err_mask;
1105c6fd2807SJeff Garzik 
1106c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
1107c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1108c6fd2807SJeff Garzik 	else
1109c6fd2807SJeff Garzik 		ata_port_abort(ap);
1110c6fd2807SJeff Garzik }
1111c6fd2807SJeff Garzik 
1112c6fd2807SJeff Garzik static void ahci_host_intr(struct ata_port *ap)
1113c6fd2807SJeff Garzik {
1114cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1115c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1116c6fd2807SJeff Garzik 	struct ata_eh_info *ehi = &ap->eh_info;
11170291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1118c6fd2807SJeff Garzik 	u32 status, qc_active;
11190291f95fSTejun Heo 	int rc, known_irq = 0;
1120c6fd2807SJeff Garzik 
1121c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
1122c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
1123c6fd2807SJeff Garzik 
1124c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
1125c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
1126c6fd2807SJeff Garzik 		return;
1127c6fd2807SJeff Garzik 	}
1128c6fd2807SJeff Garzik 
1129c6fd2807SJeff Garzik 	if (ap->sactive)
1130c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
1131c6fd2807SJeff Garzik 	else
1132c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
1133c6fd2807SJeff Garzik 
1134c6fd2807SJeff Garzik 	rc = ata_qc_complete_multiple(ap, qc_active, NULL);
1135c6fd2807SJeff Garzik 	if (rc > 0)
1136c6fd2807SJeff Garzik 		return;
1137c6fd2807SJeff Garzik 	if (rc < 0) {
1138c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
1139c6fd2807SJeff Garzik 		ehi->action |= ATA_EH_SOFTRESET;
1140c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1141c6fd2807SJeff Garzik 		return;
1142c6fd2807SJeff Garzik 	}
1143c6fd2807SJeff Garzik 
1144c6fd2807SJeff Garzik 	/* hmmm... a spurious interupt */
1145c6fd2807SJeff Garzik 
11460291f95fSTejun Heo 	/* if !NCQ, ignore.  No modern ATA device has broken HSM
11470291f95fSTejun Heo 	 * implementation for non-NCQ commands.
11480291f95fSTejun Heo 	 */
11490291f95fSTejun Heo 	if (!ap->sactive)
1150c6fd2807SJeff Garzik 		return;
1151c6fd2807SJeff Garzik 
11520291f95fSTejun Heo 	if (status & PORT_IRQ_D2H_REG_FIS) {
11530291f95fSTejun Heo 		if (!pp->ncq_saw_d2h)
11540291f95fSTejun Heo 			ata_port_printk(ap, KERN_INFO,
11550291f95fSTejun Heo 				"D2H reg with I during NCQ, "
11560291f95fSTejun Heo 				"this message won't be printed again\n");
11570291f95fSTejun Heo 		pp->ncq_saw_d2h = 1;
11580291f95fSTejun Heo 		known_irq = 1;
11590291f95fSTejun Heo 	}
1160c6fd2807SJeff Garzik 
11610291f95fSTejun Heo 	if (status & PORT_IRQ_DMAS_FIS) {
11620291f95fSTejun Heo 		if (!pp->ncq_saw_dmas)
11630291f95fSTejun Heo 			ata_port_printk(ap, KERN_INFO,
11640291f95fSTejun Heo 				"DMAS FIS during NCQ, "
11650291f95fSTejun Heo 				"this message won't be printed again\n");
11660291f95fSTejun Heo 		pp->ncq_saw_dmas = 1;
11670291f95fSTejun Heo 		known_irq = 1;
11680291f95fSTejun Heo 	}
11690291f95fSTejun Heo 
11700291f95fSTejun Heo 	if (status & PORT_IRQ_SDB_FIS &&
11710291f95fSTejun Heo 		   pp->ncq_saw_spurious_sdb_cnt < 10) {
11720291f95fSTejun Heo 		/* SDB FIS containing spurious completions might be
11730291f95fSTejun Heo 		 * dangerous, we need to know more about them.  Print
11740291f95fSTejun Heo 		 * more of it.
11750291f95fSTejun Heo 		 */
117604d4f7a1SAl Viro 		const __le32 *f = pp->rx_fis + RX_FIS_SDB;
11770291f95fSTejun Heo 
11780291f95fSTejun Heo 		ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ "
11790291f95fSTejun Heo 				"issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n",
11800291f95fSTejun Heo 				readl(port_mmio + PORT_CMD_ISSUE),
11816096b63eSTejun Heo 				readl(port_mmio + PORT_SCR_ACT),
11826096b63eSTejun Heo 				le32_to_cpu(f[0]), le32_to_cpu(f[1]),
11830291f95fSTejun Heo 				pp->ncq_saw_spurious_sdb_cnt < 10 ?
11840291f95fSTejun Heo 				"" : ", shutting up");
11850291f95fSTejun Heo 
11860291f95fSTejun Heo 		pp->ncq_saw_spurious_sdb_cnt++;
11870291f95fSTejun Heo 		known_irq = 1;
11880291f95fSTejun Heo 	}
11890291f95fSTejun Heo 
11900291f95fSTejun Heo 	if (!known_irq)
1191c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
11920291f95fSTejun Heo 				"(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
1193c6fd2807SJeff Garzik 				status, ap->active_tag, ap->sactive);
1194c6fd2807SJeff Garzik }
1195c6fd2807SJeff Garzik 
1196c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap)
1197c6fd2807SJeff Garzik {
1198c6fd2807SJeff Garzik 	/* TODO */
1199c6fd2807SJeff Garzik }
1200c6fd2807SJeff Garzik 
12017d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1202c6fd2807SJeff Garzik {
1203cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
1204c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1205c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
1206c6fd2807SJeff Garzik 	void __iomem *mmio;
1207c6fd2807SJeff Garzik 	u32 irq_stat, irq_ack = 0;
1208c6fd2807SJeff Garzik 
1209c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1210c6fd2807SJeff Garzik 
1211cca3974eSJeff Garzik 	hpriv = host->private_data;
1212cca3974eSJeff Garzik 	mmio = host->mmio_base;
1213c6fd2807SJeff Garzik 
1214c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
1215c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
1216c6fd2807SJeff Garzik 	irq_stat &= hpriv->port_map;
1217c6fd2807SJeff Garzik 	if (!irq_stat)
1218c6fd2807SJeff Garzik 		return IRQ_NONE;
1219c6fd2807SJeff Garzik 
1220cca3974eSJeff Garzik         spin_lock(&host->lock);
1221c6fd2807SJeff Garzik 
1222cca3974eSJeff Garzik         for (i = 0; i < host->n_ports; i++) {
1223c6fd2807SJeff Garzik 		struct ata_port *ap;
1224c6fd2807SJeff Garzik 
1225c6fd2807SJeff Garzik 		if (!(irq_stat & (1 << i)))
1226c6fd2807SJeff Garzik 			continue;
1227c6fd2807SJeff Garzik 
1228cca3974eSJeff Garzik 		ap = host->ports[i];
1229c6fd2807SJeff Garzik 		if (ap) {
1230c6fd2807SJeff Garzik 			ahci_host_intr(ap);
1231c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
1232c6fd2807SJeff Garzik 		} else {
1233c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
1234c6fd2807SJeff Garzik 			if (ata_ratelimit())
1235cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
1236c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
1237c6fd2807SJeff Garzik 		}
1238c6fd2807SJeff Garzik 
1239c6fd2807SJeff Garzik 		irq_ack |= (1 << i);
1240c6fd2807SJeff Garzik 	}
1241c6fd2807SJeff Garzik 
1242c6fd2807SJeff Garzik 	if (irq_ack) {
1243c6fd2807SJeff Garzik 		writel(irq_ack, mmio + HOST_IRQ_STAT);
1244c6fd2807SJeff Garzik 		handled = 1;
1245c6fd2807SJeff Garzik 	}
1246c6fd2807SJeff Garzik 
1247cca3974eSJeff Garzik 	spin_unlock(&host->lock);
1248c6fd2807SJeff Garzik 
1249c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1250c6fd2807SJeff Garzik 
1251c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
1252c6fd2807SJeff Garzik }
1253c6fd2807SJeff Garzik 
1254c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
1255c6fd2807SJeff Garzik {
1256c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1257c6fd2807SJeff Garzik 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
1258c6fd2807SJeff Garzik 
1259c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
1260c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
1261c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
1262c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
1263c6fd2807SJeff Garzik 
1264c6fd2807SJeff Garzik 	return 0;
1265c6fd2807SJeff Garzik }
1266c6fd2807SJeff Garzik 
1267c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
1268c6fd2807SJeff Garzik {
1269cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1270c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1271c6fd2807SJeff Garzik 
1272c6fd2807SJeff Garzik 	/* turn IRQ off */
1273c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
1274c6fd2807SJeff Garzik }
1275c6fd2807SJeff Garzik 
1276c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
1277c6fd2807SJeff Garzik {
1278cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1279c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1280c6fd2807SJeff Garzik 	u32 tmp;
1281c6fd2807SJeff Garzik 
1282c6fd2807SJeff Garzik 	/* clear IRQ */
1283c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1284c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
1285a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
1286c6fd2807SJeff Garzik 
1287c6fd2807SJeff Garzik 	/* turn IRQ back on */
1288c6fd2807SJeff Garzik 	writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
1289c6fd2807SJeff Garzik }
1290c6fd2807SJeff Garzik 
1291c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
1292c6fd2807SJeff Garzik {
1293cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1294c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1295c6fd2807SJeff Garzik 
1296c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1297c6fd2807SJeff Garzik 		/* restart engine */
1298c6fd2807SJeff Garzik 		ahci_stop_engine(port_mmio);
1299c6fd2807SJeff Garzik 		ahci_start_engine(port_mmio);
1300c6fd2807SJeff Garzik 	}
1301c6fd2807SJeff Garzik 
1302c6fd2807SJeff Garzik 	/* perform recovery */
13034aeb0e32STejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
1304c6fd2807SJeff Garzik 		  ahci_postreset);
1305c6fd2807SJeff Garzik }
1306c6fd2807SJeff Garzik 
1307ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap)
1308ad616ffbSTejun Heo {
1309ad616ffbSTejun Heo 	void __iomem *mmio = ap->host->mmio_base;
1310ad616ffbSTejun Heo 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1311ad616ffbSTejun Heo 
1312ad616ffbSTejun Heo 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1313ad616ffbSTejun Heo 		/* restart engine */
1314ad616ffbSTejun Heo 		ahci_stop_engine(port_mmio);
1315ad616ffbSTejun Heo 		ahci_start_engine(port_mmio);
1316ad616ffbSTejun Heo 	}
1317ad616ffbSTejun Heo 
1318ad616ffbSTejun Heo 	/* perform recovery */
1319ad616ffbSTejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset,
1320ad616ffbSTejun Heo 		  ahci_postreset);
1321ad616ffbSTejun Heo }
1322ad616ffbSTejun Heo 
1323c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
1324c6fd2807SJeff Garzik {
1325c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1326cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1327c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1328c6fd2807SJeff Garzik 
1329c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_FAILED)
1330c6fd2807SJeff Garzik 		qc->err_mask |= AC_ERR_OTHER;
1331c6fd2807SJeff Garzik 
1332c6fd2807SJeff Garzik 	if (qc->err_mask) {
1333c6fd2807SJeff Garzik 		/* make DMA engine forget about the failed command */
1334c6fd2807SJeff Garzik 		ahci_stop_engine(port_mmio);
1335c6fd2807SJeff Garzik 		ahci_start_engine(port_mmio);
1336c6fd2807SJeff Garzik 	}
1337c6fd2807SJeff Garzik }
1338c6fd2807SJeff Garzik 
1339c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
1340c6fd2807SJeff Garzik {
1341cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1342c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1343cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1344c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1345c6fd2807SJeff Garzik 	const char *emsg = NULL;
1346c6fd2807SJeff Garzik 	int rc;
1347c6fd2807SJeff Garzik 
1348c6fd2807SJeff Garzik 	rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
13498e16f941STejun Heo 	if (rc == 0)
13508e16f941STejun Heo 		ahci_power_down(port_mmio, hpriv->cap);
13518e16f941STejun Heo 	else {
1352c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
1353c6fd2807SJeff Garzik 		ahci_init_port(port_mmio, hpriv->cap,
1354c6fd2807SJeff Garzik 			       pp->cmd_slot_dma, pp->rx_fis_dma);
1355c6fd2807SJeff Garzik 	}
1356c6fd2807SJeff Garzik 
1357c6fd2807SJeff Garzik 	return rc;
1358c6fd2807SJeff Garzik }
1359c6fd2807SJeff Garzik 
1360c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap)
1361c6fd2807SJeff Garzik {
1362c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1363cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1364cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1365c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1366c6fd2807SJeff Garzik 
13678e16f941STejun Heo 	ahci_power_up(port_mmio, hpriv->cap);
1368c6fd2807SJeff Garzik 	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
1369c6fd2807SJeff Garzik 
1370c6fd2807SJeff Garzik 	return 0;
1371c6fd2807SJeff Garzik }
1372c6fd2807SJeff Garzik 
1373c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
1374c6fd2807SJeff Garzik {
1375cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
1376cca3974eSJeff Garzik 	void __iomem *mmio = host->mmio_base;
1377c6fd2807SJeff Garzik 	u32 ctl;
1378c6fd2807SJeff Garzik 
1379c6fd2807SJeff Garzik 	if (mesg.event == PM_EVENT_SUSPEND) {
1380c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
1381c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
1382c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
1383c6fd2807SJeff Garzik 		 */
1384c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
1385c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
1386c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
1387c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
1388c6fd2807SJeff Garzik 	}
1389c6fd2807SJeff Garzik 
1390c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
1391c6fd2807SJeff Garzik }
1392c6fd2807SJeff Garzik 
1393c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
1394c6fd2807SJeff Garzik {
1395cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
1396cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = host->private_data;
1397cca3974eSJeff Garzik 	void __iomem *mmio = host->mmio_base;
1398c6fd2807SJeff Garzik 	int rc;
1399c6fd2807SJeff Garzik 
1400c6fd2807SJeff Garzik 	ata_pci_device_do_resume(pdev);
1401c6fd2807SJeff Garzik 
1402c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
1403c6fd2807SJeff Garzik 		rc = ahci_reset_controller(mmio, pdev);
1404c6fd2807SJeff Garzik 		if (rc)
1405c6fd2807SJeff Garzik 			return rc;
1406c6fd2807SJeff Garzik 
1407648a88beSTejun Heo 		ahci_init_controller(mmio, pdev, host->n_ports,
1408648a88beSTejun Heo 				     host->ports[0]->flags, hpriv);
1409c6fd2807SJeff Garzik 	}
1410c6fd2807SJeff Garzik 
1411cca3974eSJeff Garzik 	ata_host_resume(host);
1412c6fd2807SJeff Garzik 
1413c6fd2807SJeff Garzik 	return 0;
1414c6fd2807SJeff Garzik }
1415c6fd2807SJeff Garzik 
1416c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
1417c6fd2807SJeff Garzik {
1418cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
1419cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1420c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
1421cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1422c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1423c6fd2807SJeff Garzik 	void *mem;
1424c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
1425c6fd2807SJeff Garzik 	int rc;
1426c6fd2807SJeff Garzik 
1427c6fd2807SJeff Garzik 	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
1428c6fd2807SJeff Garzik 	if (!pp)
1429c6fd2807SJeff Garzik 		return -ENOMEM;
1430c6fd2807SJeff Garzik 	memset(pp, 0, sizeof(*pp));
1431c6fd2807SJeff Garzik 
1432c6fd2807SJeff Garzik 	rc = ata_pad_alloc(ap, dev);
1433c6fd2807SJeff Garzik 	if (rc) {
1434c6fd2807SJeff Garzik 		kfree(pp);
1435c6fd2807SJeff Garzik 		return rc;
1436c6fd2807SJeff Garzik 	}
1437c6fd2807SJeff Garzik 
1438c6fd2807SJeff Garzik 	mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
1439c6fd2807SJeff Garzik 	if (!mem) {
1440c6fd2807SJeff Garzik 		ata_pad_free(ap, dev);
1441c6fd2807SJeff Garzik 		kfree(pp);
1442c6fd2807SJeff Garzik 		return -ENOMEM;
1443c6fd2807SJeff Garzik 	}
1444c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
1445c6fd2807SJeff Garzik 
1446c6fd2807SJeff Garzik 	/*
1447c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
1448c6fd2807SJeff Garzik 	 * 32 bytes each in size
1449c6fd2807SJeff Garzik 	 */
1450c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
1451c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
1452c6fd2807SJeff Garzik 
1453c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
1454c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
1455c6fd2807SJeff Garzik 
1456c6fd2807SJeff Garzik 	/*
1457c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
1458c6fd2807SJeff Garzik 	 */
1459c6fd2807SJeff Garzik 	pp->rx_fis = mem;
1460c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
1461c6fd2807SJeff Garzik 
1462c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
1463c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
1464c6fd2807SJeff Garzik 
1465c6fd2807SJeff Garzik 	/*
1466c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
1467c6fd2807SJeff Garzik 	 * and its scatter-gather table
1468c6fd2807SJeff Garzik 	 */
1469c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
1470c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
1471c6fd2807SJeff Garzik 
1472c6fd2807SJeff Garzik 	ap->private_data = pp;
1473c6fd2807SJeff Garzik 
14748e16f941STejun Heo 	/* power up port */
14758e16f941STejun Heo 	ahci_power_up(port_mmio, hpriv->cap);
14768e16f941STejun Heo 
1477c6fd2807SJeff Garzik 	/* initialize port */
1478c6fd2807SJeff Garzik 	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
1479c6fd2807SJeff Garzik 
1480c6fd2807SJeff Garzik 	return 0;
1481c6fd2807SJeff Garzik }
1482c6fd2807SJeff Garzik 
1483c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
1484c6fd2807SJeff Garzik {
1485cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
1486cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1487c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1488cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1489c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1490c6fd2807SJeff Garzik 	const char *emsg = NULL;
1491c6fd2807SJeff Garzik 	int rc;
1492c6fd2807SJeff Garzik 
1493c6fd2807SJeff Garzik 	/* de-initialize port */
1494c6fd2807SJeff Garzik 	rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
1495c6fd2807SJeff Garzik 	if (rc)
1496c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
1497c6fd2807SJeff Garzik 
1498c6fd2807SJeff Garzik 	ap->private_data = NULL;
1499c6fd2807SJeff Garzik 	dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
1500c6fd2807SJeff Garzik 			  pp->cmd_slot, pp->cmd_slot_dma);
1501c6fd2807SJeff Garzik 	ata_pad_free(ap, dev);
1502c6fd2807SJeff Garzik 	kfree(pp);
1503c6fd2807SJeff Garzik }
1504c6fd2807SJeff Garzik 
1505c6fd2807SJeff Garzik static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
1506c6fd2807SJeff Garzik 			    unsigned int port_idx)
1507c6fd2807SJeff Garzik {
1508c6fd2807SJeff Garzik 	VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
1509c6fd2807SJeff Garzik 	base = ahci_port_base_ul(base, port_idx);
1510c6fd2807SJeff Garzik 	VPRINTK("base now==0x%lx\n", base);
1511c6fd2807SJeff Garzik 
1512c6fd2807SJeff Garzik 	port->cmd_addr		= base;
1513c6fd2807SJeff Garzik 	port->scr_addr		= base + PORT_SCR;
1514c6fd2807SJeff Garzik 
1515c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1516c6fd2807SJeff Garzik }
1517c6fd2807SJeff Garzik 
1518c6fd2807SJeff Garzik static int ahci_host_init(struct ata_probe_ent *probe_ent)
1519c6fd2807SJeff Garzik {
1520c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv = probe_ent->private_data;
1521c6fd2807SJeff Garzik 	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
1522c6fd2807SJeff Garzik 	void __iomem *mmio = probe_ent->mmio_base;
1523648a88beSTejun Heo 	unsigned int i, cap_n_ports, using_dac;
1524c6fd2807SJeff Garzik 	int rc;
1525c6fd2807SJeff Garzik 
1526c6fd2807SJeff Garzik 	rc = ahci_reset_controller(mmio, pdev);
1527c6fd2807SJeff Garzik 	if (rc)
1528c6fd2807SJeff Garzik 		return rc;
1529c6fd2807SJeff Garzik 
1530c6fd2807SJeff Garzik 	hpriv->cap = readl(mmio + HOST_CAP);
1531c6fd2807SJeff Garzik 	hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
1532648a88beSTejun Heo 	cap_n_ports = ahci_nr_ports(hpriv->cap);
1533c6fd2807SJeff Garzik 
1534c6fd2807SJeff Garzik 	VPRINTK("cap 0x%x  port_map 0x%x  n_ports %d\n",
1535648a88beSTejun Heo 		hpriv->cap, hpriv->port_map, cap_n_ports);
1536648a88beSTejun Heo 
1537648a88beSTejun Heo 	if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) {
1538648a88beSTejun Heo 		unsigned int n_ports = cap_n_ports;
1539648a88beSTejun Heo 		u32 port_map = hpriv->port_map;
1540648a88beSTejun Heo 		int max_port = 0;
1541648a88beSTejun Heo 
1542648a88beSTejun Heo 		for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
1543648a88beSTejun Heo 			if (port_map & (1 << i)) {
1544648a88beSTejun Heo 				n_ports--;
1545648a88beSTejun Heo 				port_map &= ~(1 << i);
1546648a88beSTejun Heo 				max_port = i;
1547648a88beSTejun Heo 			} else
1548648a88beSTejun Heo 				probe_ent->dummy_port_mask |= 1 << i;
1549648a88beSTejun Heo 		}
1550648a88beSTejun Heo 
1551648a88beSTejun Heo 		if (n_ports || port_map)
1552648a88beSTejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
1553648a88beSTejun Heo 				   "nr_ports (%u) and implemented port map "
1554648a88beSTejun Heo 				   "(0x%x) don't match\n",
1555648a88beSTejun Heo 				   cap_n_ports, hpriv->port_map);
1556648a88beSTejun Heo 
1557648a88beSTejun Heo 		probe_ent->n_ports = max_port + 1;
1558648a88beSTejun Heo 	} else
1559648a88beSTejun Heo 		probe_ent->n_ports = cap_n_ports;
1560c6fd2807SJeff Garzik 
1561c6fd2807SJeff Garzik 	using_dac = hpriv->cap & HOST_CAP_64;
1562c6fd2807SJeff Garzik 	if (using_dac &&
1563c6fd2807SJeff Garzik 	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
1564c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
1565c6fd2807SJeff Garzik 		if (rc) {
1566c6fd2807SJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1567c6fd2807SJeff Garzik 			if (rc) {
1568c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
1569c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
1570c6fd2807SJeff Garzik 				return rc;
1571c6fd2807SJeff Garzik 			}
1572c6fd2807SJeff Garzik 		}
1573c6fd2807SJeff Garzik 	} else {
1574c6fd2807SJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
1575c6fd2807SJeff Garzik 		if (rc) {
1576c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1577c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
1578c6fd2807SJeff Garzik 			return rc;
1579c6fd2807SJeff Garzik 		}
1580c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1581c6fd2807SJeff Garzik 		if (rc) {
1582c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1583c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
1584c6fd2807SJeff Garzik 			return rc;
1585c6fd2807SJeff Garzik 		}
1586c6fd2807SJeff Garzik 	}
1587c6fd2807SJeff Garzik 
1588c6fd2807SJeff Garzik 	for (i = 0; i < probe_ent->n_ports; i++)
1589c6fd2807SJeff Garzik 		ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
1590c6fd2807SJeff Garzik 
1591648a88beSTejun Heo 	ahci_init_controller(mmio, pdev, probe_ent->n_ports,
1592648a88beSTejun Heo 			     probe_ent->port_flags, hpriv);
1593c6fd2807SJeff Garzik 
1594c6fd2807SJeff Garzik 	pci_set_master(pdev);
1595c6fd2807SJeff Garzik 
1596c6fd2807SJeff Garzik 	return 0;
1597c6fd2807SJeff Garzik }
1598c6fd2807SJeff Garzik 
1599c6fd2807SJeff Garzik static void ahci_print_info(struct ata_probe_ent *probe_ent)
1600c6fd2807SJeff Garzik {
1601c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv = probe_ent->private_data;
1602c6fd2807SJeff Garzik 	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
1603c6fd2807SJeff Garzik 	void __iomem *mmio = probe_ent->mmio_base;
1604c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
1605c6fd2807SJeff Garzik 	const char *speed_s;
1606c6fd2807SJeff Garzik 	u16 cc;
1607c6fd2807SJeff Garzik 	const char *scc_s;
1608c6fd2807SJeff Garzik 
1609c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
1610c6fd2807SJeff Garzik 	cap = hpriv->cap;
1611c6fd2807SJeff Garzik 	impl = hpriv->port_map;
1612c6fd2807SJeff Garzik 
1613c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
1614c6fd2807SJeff Garzik 	if (speed == 1)
1615c6fd2807SJeff Garzik 		speed_s = "1.5";
1616c6fd2807SJeff Garzik 	else if (speed == 2)
1617c6fd2807SJeff Garzik 		speed_s = "3";
1618c6fd2807SJeff Garzik 	else
1619c6fd2807SJeff Garzik 		speed_s = "?";
1620c6fd2807SJeff Garzik 
1621c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
1622*c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
1623c6fd2807SJeff Garzik 		scc_s = "IDE";
1624*c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
1625c6fd2807SJeff Garzik 		scc_s = "SATA";
1626*c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
1627c6fd2807SJeff Garzik 		scc_s = "RAID";
1628c6fd2807SJeff Garzik 	else
1629c6fd2807SJeff Garzik 		scc_s = "unknown";
1630c6fd2807SJeff Garzik 
1631c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
1632c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
1633c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
1634c6fd2807SJeff Garzik 	       	,
1635c6fd2807SJeff Garzik 
1636c6fd2807SJeff Garzik 	       	(vers >> 24) & 0xff,
1637c6fd2807SJeff Garzik 	       	(vers >> 16) & 0xff,
1638c6fd2807SJeff Garzik 	       	(vers >> 8) & 0xff,
1639c6fd2807SJeff Garzik 	       	vers & 0xff,
1640c6fd2807SJeff Garzik 
1641c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
1642c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
1643c6fd2807SJeff Garzik 		speed_s,
1644c6fd2807SJeff Garzik 		impl,
1645c6fd2807SJeff Garzik 		scc_s);
1646c6fd2807SJeff Garzik 
1647c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
1648c6fd2807SJeff Garzik 		"flags: "
1649c6fd2807SJeff Garzik 	       	"%s%s%s%s%s%s"
1650c6fd2807SJeff Garzik 	       	"%s%s%s%s%s%s%s\n"
1651c6fd2807SJeff Garzik 	       	,
1652c6fd2807SJeff Garzik 
1653c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
1654c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
1655c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
1656c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
1657c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
1658c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
1659c6fd2807SJeff Garzik 
1660c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
1661c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
1662c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
1663c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
1664c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
1665c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
1666c6fd2807SJeff Garzik 		cap & (1 << 13) ? "part " : ""
1667c6fd2807SJeff Garzik 		);
1668c6fd2807SJeff Garzik }
1669c6fd2807SJeff Garzik 
1670c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
1671c6fd2807SJeff Garzik {
1672c6fd2807SJeff Garzik 	static int printed_version;
1673c6fd2807SJeff Garzik 	struct ata_probe_ent *probe_ent = NULL;
1674c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1675c6fd2807SJeff Garzik 	unsigned long base;
1676c6fd2807SJeff Garzik 	void __iomem *mmio_base;
1677c6fd2807SJeff Garzik 	unsigned int board_idx = (unsigned int) ent->driver_data;
1678c6fd2807SJeff Garzik 	int have_msi, pci_dev_busy = 0;
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 
1688c6fd2807SJeff Garzik 	/* JMicron-specific fixup: make sure we're in AHCI mode */
1689c6fd2807SJeff Garzik 	/* This is protected from races with ata_jmicron by the pci probe
1690c6fd2807SJeff Garzik 	   locking */
1691c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
1692c6fd2807SJeff Garzik 		/* AHCI enable, AHCI on function 0 */
1693c6fd2807SJeff Garzik 		pci_write_config_byte(pdev, 0x41, 0xa1);
1694c6fd2807SJeff Garzik 		/* Function 1 is the PATA controller */
1695c6fd2807SJeff Garzik 		if (PCI_FUNC(pdev->devfn))
1696c6fd2807SJeff Garzik 			return -ENODEV;
1697c6fd2807SJeff Garzik 	}
1698c6fd2807SJeff Garzik 
1699c6fd2807SJeff Garzik 	rc = pci_enable_device(pdev);
1700c6fd2807SJeff Garzik 	if (rc)
1701c6fd2807SJeff Garzik 		return rc;
1702c6fd2807SJeff Garzik 
1703c6fd2807SJeff Garzik 	rc = pci_request_regions(pdev, DRV_NAME);
1704c6fd2807SJeff Garzik 	if (rc) {
1705c6fd2807SJeff Garzik 		pci_dev_busy = 1;
1706c6fd2807SJeff Garzik 		goto err_out;
1707c6fd2807SJeff Garzik 	}
1708c6fd2807SJeff Garzik 
1709c6fd2807SJeff Garzik 	if (pci_enable_msi(pdev) == 0)
1710c6fd2807SJeff Garzik 		have_msi = 1;
1711c6fd2807SJeff Garzik 	else {
1712c6fd2807SJeff Garzik 		pci_intx(pdev, 1);
1713c6fd2807SJeff Garzik 		have_msi = 0;
1714c6fd2807SJeff Garzik 	}
1715c6fd2807SJeff Garzik 
1716c6fd2807SJeff Garzik 	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
1717c6fd2807SJeff Garzik 	if (probe_ent == NULL) {
1718c6fd2807SJeff Garzik 		rc = -ENOMEM;
1719c6fd2807SJeff Garzik 		goto err_out_msi;
1720c6fd2807SJeff Garzik 	}
1721c6fd2807SJeff Garzik 
1722c6fd2807SJeff Garzik 	memset(probe_ent, 0, sizeof(*probe_ent));
1723c6fd2807SJeff Garzik 	probe_ent->dev = pci_dev_to_dev(pdev);
1724c6fd2807SJeff Garzik 	INIT_LIST_HEAD(&probe_ent->node);
1725c6fd2807SJeff Garzik 
1726c6fd2807SJeff Garzik 	mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
1727c6fd2807SJeff Garzik 	if (mmio_base == NULL) {
1728c6fd2807SJeff Garzik 		rc = -ENOMEM;
1729c6fd2807SJeff Garzik 		goto err_out_free_ent;
1730c6fd2807SJeff Garzik 	}
1731c6fd2807SJeff Garzik 	base = (unsigned long) mmio_base;
1732c6fd2807SJeff Garzik 
1733c6fd2807SJeff Garzik 	hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
1734c6fd2807SJeff Garzik 	if (!hpriv) {
1735c6fd2807SJeff Garzik 		rc = -ENOMEM;
1736c6fd2807SJeff Garzik 		goto err_out_iounmap;
1737c6fd2807SJeff Garzik 	}
1738c6fd2807SJeff Garzik 	memset(hpriv, 0, sizeof(*hpriv));
1739c6fd2807SJeff Garzik 
1740c6fd2807SJeff Garzik 	probe_ent->sht		= ahci_port_info[board_idx].sht;
1741cca3974eSJeff Garzik 	probe_ent->port_flags	= ahci_port_info[board_idx].flags;
1742c6fd2807SJeff Garzik 	probe_ent->pio_mask	= ahci_port_info[board_idx].pio_mask;
1743c6fd2807SJeff Garzik 	probe_ent->udma_mask	= ahci_port_info[board_idx].udma_mask;
1744c6fd2807SJeff Garzik 	probe_ent->port_ops	= ahci_port_info[board_idx].port_ops;
1745c6fd2807SJeff Garzik 
1746c6fd2807SJeff Garzik        	probe_ent->irq = pdev->irq;
1747c6fd2807SJeff Garzik        	probe_ent->irq_flags = IRQF_SHARED;
1748c6fd2807SJeff Garzik 	probe_ent->mmio_base = mmio_base;
1749c6fd2807SJeff Garzik 	probe_ent->private_data = hpriv;
1750c6fd2807SJeff Garzik 
1751c6fd2807SJeff Garzik 	if (have_msi)
1752c6fd2807SJeff Garzik 		hpriv->flags |= AHCI_FLAG_MSI;
1753c6fd2807SJeff Garzik 
1754c6fd2807SJeff Garzik 	/* initialize adapter */
1755c6fd2807SJeff Garzik 	rc = ahci_host_init(probe_ent);
1756c6fd2807SJeff Garzik 	if (rc)
1757c6fd2807SJeff Garzik 		goto err_out_hpriv;
1758c6fd2807SJeff Garzik 
1759cca3974eSJeff Garzik 	if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
1760c6fd2807SJeff Garzik 	    (hpriv->cap & HOST_CAP_NCQ))
1761cca3974eSJeff Garzik 		probe_ent->port_flags |= ATA_FLAG_NCQ;
1762c6fd2807SJeff Garzik 
1763c6fd2807SJeff Garzik 	ahci_print_info(probe_ent);
1764c6fd2807SJeff Garzik 
1765c6fd2807SJeff Garzik 	/* FIXME: check ata_device_add return value */
1766c6fd2807SJeff Garzik 	ata_device_add(probe_ent);
1767c6fd2807SJeff Garzik 	kfree(probe_ent);
1768c6fd2807SJeff Garzik 
1769c6fd2807SJeff Garzik 	return 0;
1770c6fd2807SJeff Garzik 
1771c6fd2807SJeff Garzik err_out_hpriv:
1772c6fd2807SJeff Garzik 	kfree(hpriv);
1773c6fd2807SJeff Garzik err_out_iounmap:
1774c6fd2807SJeff Garzik 	pci_iounmap(pdev, mmio_base);
1775c6fd2807SJeff Garzik err_out_free_ent:
1776c6fd2807SJeff Garzik 	kfree(probe_ent);
1777c6fd2807SJeff Garzik err_out_msi:
1778c6fd2807SJeff Garzik 	if (have_msi)
1779c6fd2807SJeff Garzik 		pci_disable_msi(pdev);
1780c6fd2807SJeff Garzik 	else
1781c6fd2807SJeff Garzik 		pci_intx(pdev, 0);
1782c6fd2807SJeff Garzik 	pci_release_regions(pdev);
1783c6fd2807SJeff Garzik err_out:
1784c6fd2807SJeff Garzik 	if (!pci_dev_busy)
1785c6fd2807SJeff Garzik 		pci_disable_device(pdev);
1786c6fd2807SJeff Garzik 	return rc;
1787c6fd2807SJeff Garzik }
1788c6fd2807SJeff Garzik 
1789c6fd2807SJeff Garzik static void ahci_remove_one (struct pci_dev *pdev)
1790c6fd2807SJeff Garzik {
1791c6fd2807SJeff Garzik 	struct device *dev = pci_dev_to_dev(pdev);
1792cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(dev);
1793cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = host->private_data;
1794c6fd2807SJeff Garzik 	unsigned int i;
1795c6fd2807SJeff Garzik 	int have_msi;
1796c6fd2807SJeff Garzik 
1797cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++)
1798cca3974eSJeff Garzik 		ata_port_detach(host->ports[i]);
1799c6fd2807SJeff Garzik 
1800c6fd2807SJeff Garzik 	have_msi = hpriv->flags & AHCI_FLAG_MSI;
1801cca3974eSJeff Garzik 	free_irq(host->irq, host);
1802c6fd2807SJeff Garzik 
1803cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
1804cca3974eSJeff Garzik 		struct ata_port *ap = host->ports[i];
1805c6fd2807SJeff Garzik 
1806cca3974eSJeff Garzik 		ata_scsi_release(ap->scsi_host);
1807cca3974eSJeff Garzik 		scsi_host_put(ap->scsi_host);
1808c6fd2807SJeff Garzik 	}
1809c6fd2807SJeff Garzik 
1810c6fd2807SJeff Garzik 	kfree(hpriv);
1811cca3974eSJeff Garzik 	pci_iounmap(pdev, host->mmio_base);
1812cca3974eSJeff Garzik 	kfree(host);
1813c6fd2807SJeff Garzik 
1814c6fd2807SJeff Garzik 	if (have_msi)
1815c6fd2807SJeff Garzik 		pci_disable_msi(pdev);
1816c6fd2807SJeff Garzik 	else
1817c6fd2807SJeff Garzik 		pci_intx(pdev, 0);
1818c6fd2807SJeff Garzik 	pci_release_regions(pdev);
1819c6fd2807SJeff Garzik 	pci_disable_device(pdev);
1820c6fd2807SJeff Garzik 	dev_set_drvdata(dev, NULL);
1821c6fd2807SJeff Garzik }
1822c6fd2807SJeff Garzik 
1823c6fd2807SJeff Garzik static int __init ahci_init(void)
1824c6fd2807SJeff Garzik {
1825c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
1826c6fd2807SJeff Garzik }
1827c6fd2807SJeff Garzik 
1828c6fd2807SJeff Garzik static void __exit ahci_exit(void)
1829c6fd2807SJeff Garzik {
1830c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
1831c6fd2807SJeff Garzik }
1832c6fd2807SJeff Garzik 
1833c6fd2807SJeff Garzik 
1834c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
1835c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
1836c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
1837c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
1838c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
1839c6fd2807SJeff Garzik 
1840c6fd2807SJeff Garzik module_init(ahci_init);
1841c6fd2807SJeff Garzik module_exit(ahci_exit);
1842