xref: /openbmc/linux/drivers/ata/ahci.c (revision 4447d35156169cf136e829eb6b5cac2d6370f2d9)
1c6fd2807SJeff Garzik /*
2c6fd2807SJeff Garzik  *  ahci.c - AHCI SATA support
3c6fd2807SJeff Garzik  *
4c6fd2807SJeff Garzik  *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
5c6fd2807SJeff Garzik  *    		    Please ALWAYS copy linux-ide@vger.kernel.org
6c6fd2807SJeff Garzik  *		    on emails.
7c6fd2807SJeff Garzik  *
8c6fd2807SJeff Garzik  *  Copyright 2004-2005 Red Hat, Inc.
9c6fd2807SJeff Garzik  *
10c6fd2807SJeff Garzik  *
11c6fd2807SJeff Garzik  *  This program is free software; you can redistribute it and/or modify
12c6fd2807SJeff Garzik  *  it under the terms of the GNU General Public License as published by
13c6fd2807SJeff Garzik  *  the Free Software Foundation; either version 2, or (at your option)
14c6fd2807SJeff Garzik  *  any later version.
15c6fd2807SJeff Garzik  *
16c6fd2807SJeff Garzik  *  This program is distributed in the hope that it will be useful,
17c6fd2807SJeff Garzik  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18c6fd2807SJeff Garzik  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19c6fd2807SJeff Garzik  *  GNU General Public License for more details.
20c6fd2807SJeff Garzik  *
21c6fd2807SJeff Garzik  *  You should have received a copy of the GNU General Public License
22c6fd2807SJeff Garzik  *  along with this program; see the file COPYING.  If not, write to
23c6fd2807SJeff Garzik  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24c6fd2807SJeff Garzik  *
25c6fd2807SJeff Garzik  *
26c6fd2807SJeff Garzik  * libata documentation is available via 'make {ps|pdf}docs',
27c6fd2807SJeff Garzik  * as Documentation/DocBook/libata.*
28c6fd2807SJeff Garzik  *
29c6fd2807SJeff Garzik  * AHCI hardware documentation:
30c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
31c6fd2807SJeff Garzik  * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
32c6fd2807SJeff Garzik  *
33c6fd2807SJeff Garzik  */
34c6fd2807SJeff Garzik 
35c6fd2807SJeff Garzik #include <linux/kernel.h>
36c6fd2807SJeff Garzik #include <linux/module.h>
37c6fd2807SJeff Garzik #include <linux/pci.h>
38c6fd2807SJeff Garzik #include <linux/init.h>
39c6fd2807SJeff Garzik #include <linux/blkdev.h>
40c6fd2807SJeff Garzik #include <linux/delay.h>
41c6fd2807SJeff Garzik #include <linux/interrupt.h>
42c6fd2807SJeff Garzik #include <linux/dma-mapping.h>
43c6fd2807SJeff Garzik #include <linux/device.h>
44c6fd2807SJeff Garzik #include <scsi/scsi_host.h>
45c6fd2807SJeff Garzik #include <scsi/scsi_cmnd.h>
46c6fd2807SJeff Garzik #include <linux/libata.h>
47c6fd2807SJeff Garzik 
48c6fd2807SJeff Garzik #define DRV_NAME	"ahci"
49cb48cab7SJeff Garzik #define DRV_VERSION	"2.1"
50c6fd2807SJeff Garzik 
51c6fd2807SJeff Garzik 
52c6fd2807SJeff Garzik enum {
53c6fd2807SJeff Garzik 	AHCI_PCI_BAR		= 5,
54648a88beSTejun Heo 	AHCI_MAX_PORTS		= 32,
55c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
56c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
57c6fd2807SJeff Garzik 	AHCI_USE_CLUSTERING	= 0,
58c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
59c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
60c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
61c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
62c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
63c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
64c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
65c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
66c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
67c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
68c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
69c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
70c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
71c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
72c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
73c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
74c6fd2807SJeff Garzik 
75c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
760291f95fSTejun Heo 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
77c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
78c6fd2807SJeff Garzik 
79c6fd2807SJeff Garzik 	board_ahci		= 0,
80648a88beSTejun Heo 	board_ahci_pi		= 1,
81648a88beSTejun Heo 	board_ahci_vt8251	= 2,
82648a88beSTejun Heo 	board_ahci_ign_iferr	= 3,
8355a61604SConke Hu 	board_ahci_sb600	= 4,
84c6fd2807SJeff Garzik 
85c6fd2807SJeff Garzik 	/* global controller registers */
86c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
87c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
88c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
89c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
90c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
91c6fd2807SJeff Garzik 
92c6fd2807SJeff Garzik 	/* HOST_CTL bits */
93c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
94c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
95c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
96c6fd2807SJeff Garzik 
97c6fd2807SJeff Garzik 	/* HOST_CAP bits */
98c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
99c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
100c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
101c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
102c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
103c6fd2807SJeff Garzik 
104c6fd2807SJeff Garzik 	/* registers for each SATA port */
105c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
106c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
107c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
108c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
109c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
110c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
111c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
112c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
113c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
114c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
115c6fd2807SJeff Garzik 	PORT_SCR		= 0x28, /* SATA phy register block */
116c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
117c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
118c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
119c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
120c6fd2807SJeff Garzik 
121c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
122c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
123c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
124c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
125c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
126c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
127c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
128c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
129c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
130c6fd2807SJeff Garzik 
131c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
132c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
133c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
134c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
135c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
136c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
137c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
138c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
139c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
140c6fd2807SJeff Garzik 
141c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
142c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
143c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
144c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
145c6fd2807SJeff Garzik 				  PORT_IRQ_UNK_FIS,
146c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
147c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
148c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
149c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
150c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
151c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
152c6fd2807SJeff Garzik 
153c6fd2807SJeff Garzik 	/* PORT_CMD bits */
154c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
155c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
156c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
157c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
158c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
159c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
160c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
161c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
162c6fd2807SJeff Garzik 
163c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
164c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
165c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
166c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
167c6fd2807SJeff Garzik 
168c6fd2807SJeff Garzik 	/* ap->flags bits */
1694aeb0e32STejun Heo 	AHCI_FLAG_NO_NCQ		= (1 << 24),
1704aeb0e32STejun Heo 	AHCI_FLAG_IGN_IRQ_IF_ERR	= (1 << 25), /* ignore IRQ_IF_ERR */
171648a88beSTejun Heo 	AHCI_FLAG_HONOR_PI		= (1 << 26), /* honor PORTS_IMPL */
17255a61604SConke Hu 	AHCI_FLAG_IGN_SERR_INTERNAL	= (1 << 27), /* ignore SERR_INTERNAL */
173c6fd2807SJeff Garzik };
174c6fd2807SJeff Garzik 
175c6fd2807SJeff Garzik struct ahci_cmd_hdr {
176c6fd2807SJeff Garzik 	u32			opts;
177c6fd2807SJeff Garzik 	u32			status;
178c6fd2807SJeff Garzik 	u32			tbl_addr;
179c6fd2807SJeff Garzik 	u32			tbl_addr_hi;
180c6fd2807SJeff Garzik 	u32			reserved[4];
181c6fd2807SJeff Garzik };
182c6fd2807SJeff Garzik 
183c6fd2807SJeff Garzik struct ahci_sg {
184c6fd2807SJeff Garzik 	u32			addr;
185c6fd2807SJeff Garzik 	u32			addr_hi;
186c6fd2807SJeff Garzik 	u32			reserved;
187c6fd2807SJeff Garzik 	u32			flags_size;
188c6fd2807SJeff Garzik };
189c6fd2807SJeff Garzik 
190c6fd2807SJeff Garzik struct ahci_host_priv {
191d447df14STejun Heo 	u32			cap;		/* cap to use */
192d447df14STejun Heo 	u32			port_map;	/* port map to use */
193d447df14STejun Heo 	u32			saved_cap;	/* saved initial cap */
194d447df14STejun Heo 	u32			saved_port_map;	/* saved initial port_map */
195c6fd2807SJeff Garzik };
196c6fd2807SJeff Garzik 
197c6fd2807SJeff Garzik struct ahci_port_priv {
198c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
199c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
200c6fd2807SJeff Garzik 	void			*cmd_tbl;
201c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
202c6fd2807SJeff Garzik 	void			*rx_fis;
203c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
2040291f95fSTejun Heo 	/* for NCQ spurious interrupt analysis */
2050291f95fSTejun Heo 	unsigned int		ncq_saw_d2h:1;
2060291f95fSTejun Heo 	unsigned int		ncq_saw_dmas:1;
207afb2d552STejun Heo 	unsigned int		ncq_saw_sdb:1;
208c6fd2807SJeff Garzik };
209c6fd2807SJeff Garzik 
210c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
211c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
212c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
213c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
214c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap);
215c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
216c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
217c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
218c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
219c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap);
220c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
221c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
222c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
223ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap);
224c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
225438ac6d5STejun Heo #ifdef CONFIG_PM
226c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
227c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
228c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
229c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
230438ac6d5STejun Heo #endif
231c6fd2807SJeff Garzik 
232c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
233c6fd2807SJeff Garzik 	.module			= THIS_MODULE,
234c6fd2807SJeff Garzik 	.name			= DRV_NAME,
235c6fd2807SJeff Garzik 	.ioctl			= ata_scsi_ioctl,
236c6fd2807SJeff Garzik 	.queuecommand		= ata_scsi_queuecmd,
237c6fd2807SJeff Garzik 	.change_queue_depth	= ata_scsi_change_queue_depth,
238c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
239c6fd2807SJeff Garzik 	.this_id		= ATA_SHT_THIS_ID,
240c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
241c6fd2807SJeff Garzik 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
242c6fd2807SJeff Garzik 	.emulated		= ATA_SHT_EMULATED,
243c6fd2807SJeff Garzik 	.use_clustering		= AHCI_USE_CLUSTERING,
244c6fd2807SJeff Garzik 	.proc_name		= DRV_NAME,
245c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
246c6fd2807SJeff Garzik 	.slave_configure	= ata_scsi_slave_config,
247c6fd2807SJeff Garzik 	.slave_destroy		= ata_scsi_slave_destroy,
248c6fd2807SJeff Garzik 	.bios_param		= ata_std_bios_param,
249438ac6d5STejun Heo #ifdef CONFIG_PM
250c6fd2807SJeff Garzik 	.suspend		= ata_scsi_device_suspend,
251c6fd2807SJeff Garzik 	.resume			= ata_scsi_device_resume,
252438ac6d5STejun Heo #endif
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_clear		= ahci_irq_clear,
268246ce3b6SAkira Iguchi 	.irq_on			= ata_dummy_irq_on,
269246ce3b6SAkira Iguchi 	.irq_ack		= ata_dummy_irq_ack,
270c6fd2807SJeff Garzik 
271c6fd2807SJeff Garzik 	.scr_read		= ahci_scr_read,
272c6fd2807SJeff Garzik 	.scr_write		= ahci_scr_write,
273c6fd2807SJeff Garzik 
274c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
275c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
276c6fd2807SJeff Garzik 
277c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
278c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
279c6fd2807SJeff Garzik 
280438ac6d5STejun Heo #ifdef CONFIG_PM
281c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
282c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
283438ac6d5STejun Heo #endif
284c6fd2807SJeff Garzik 
285c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
286c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
287c6fd2807SJeff Garzik };
288c6fd2807SJeff Garzik 
289ad616ffbSTejun Heo static const struct ata_port_operations ahci_vt8251_ops = {
290ad616ffbSTejun Heo 	.port_disable		= ata_port_disable,
291ad616ffbSTejun Heo 
292ad616ffbSTejun Heo 	.check_status		= ahci_check_status,
293ad616ffbSTejun Heo 	.check_altstatus	= ahci_check_status,
294ad616ffbSTejun Heo 	.dev_select		= ata_noop_dev_select,
295ad616ffbSTejun Heo 
296ad616ffbSTejun Heo 	.tf_read		= ahci_tf_read,
297ad616ffbSTejun Heo 
298ad616ffbSTejun Heo 	.qc_prep		= ahci_qc_prep,
299ad616ffbSTejun Heo 	.qc_issue		= ahci_qc_issue,
300ad616ffbSTejun Heo 
301ad616ffbSTejun Heo 	.irq_clear		= ahci_irq_clear,
302246ce3b6SAkira Iguchi 	.irq_on			= ata_dummy_irq_on,
303246ce3b6SAkira Iguchi 	.irq_ack		= ata_dummy_irq_ack,
304ad616ffbSTejun Heo 
305ad616ffbSTejun Heo 	.scr_read		= ahci_scr_read,
306ad616ffbSTejun Heo 	.scr_write		= ahci_scr_write,
307ad616ffbSTejun Heo 
308ad616ffbSTejun Heo 	.freeze			= ahci_freeze,
309ad616ffbSTejun Heo 	.thaw			= ahci_thaw,
310ad616ffbSTejun Heo 
311ad616ffbSTejun Heo 	.error_handler		= ahci_vt8251_error_handler,
312ad616ffbSTejun Heo 	.post_internal_cmd	= ahci_post_internal_cmd,
313ad616ffbSTejun Heo 
314438ac6d5STejun Heo #ifdef CONFIG_PM
315ad616ffbSTejun Heo 	.port_suspend		= ahci_port_suspend,
316ad616ffbSTejun Heo 	.port_resume		= ahci_port_resume,
317438ac6d5STejun Heo #endif
318ad616ffbSTejun Heo 
319ad616ffbSTejun Heo 	.port_start		= ahci_port_start,
320ad616ffbSTejun Heo 	.port_stop		= ahci_port_stop,
321ad616ffbSTejun Heo };
322ad616ffbSTejun Heo 
323c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
324c6fd2807SJeff Garzik 	/* board_ahci */
325c6fd2807SJeff Garzik 	{
326cca3974eSJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
327c6fd2807SJeff Garzik 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
328c6fd2807SJeff Garzik 				  ATA_FLAG_SKIP_D2H_BSY,
329c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
330c6fd2807SJeff Garzik 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
331c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
332c6fd2807SJeff Garzik 	},
333648a88beSTejun Heo 	/* board_ahci_pi */
334648a88beSTejun Heo 	{
335648a88beSTejun Heo 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
336648a88beSTejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
337648a88beSTejun Heo 				  ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
338648a88beSTejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
339648a88beSTejun Heo 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
340648a88beSTejun Heo 		.port_ops	= &ahci_ops,
341648a88beSTejun Heo 	},
342c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
343c6fd2807SJeff Garzik 	{
344cca3974eSJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
345c6fd2807SJeff Garzik 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
346ad616ffbSTejun Heo 				  ATA_FLAG_SKIP_D2H_BSY |
347ad616ffbSTejun Heo 				  ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
348c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
349c6fd2807SJeff Garzik 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
350ad616ffbSTejun Heo 		.port_ops	= &ahci_vt8251_ops,
351c6fd2807SJeff Garzik 	},
35241669553STejun Heo 	/* board_ahci_ign_iferr */
35341669553STejun Heo 	{
35441669553STejun Heo 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
35541669553STejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
35641669553STejun Heo 				  ATA_FLAG_SKIP_D2H_BSY |
35741669553STejun Heo 				  AHCI_FLAG_IGN_IRQ_IF_ERR,
35841669553STejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
35941669553STejun Heo 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
36041669553STejun Heo 		.port_ops	= &ahci_ops,
36141669553STejun Heo 	},
36255a61604SConke Hu 	/* board_ahci_sb600 */
36355a61604SConke Hu 	{
36455a61604SConke Hu 		.sht		= &ahci_sht,
36555a61604SConke Hu 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
36655a61604SConke Hu 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
36755a61604SConke Hu 				  ATA_FLAG_SKIP_D2H_BSY |
36855a61604SConke Hu 				  AHCI_FLAG_IGN_SERR_INTERNAL,
36955a61604SConke Hu 		.pio_mask	= 0x1f, /* pio0-4 */
37055a61604SConke Hu 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
37155a61604SConke Hu 		.port_ops	= &ahci_ops,
37255a61604SConke Hu 	},
37355a61604SConke Hu 
374c6fd2807SJeff Garzik };
375c6fd2807SJeff Garzik 
376c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
377c6fd2807SJeff Garzik 	/* Intel */
37854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
37954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
38054bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
38154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
38254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
38382490c09STejun Heo 	{ PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr }, /* ULi M5288 */
38454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
38554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
38654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
38754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
388648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
389648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
390648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
391648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
392648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
393648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */
394648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */
395648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */
396648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */
397648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */
398648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
399648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
400648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
4018af12cdbSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */
402648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
403648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
404648a88beSTejun Heo 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
405c6fd2807SJeff Garzik 
406e34bb370STejun Heo 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
407e34bb370STejun Heo 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
408e34bb370STejun Heo 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
409c6fd2807SJeff Garzik 
410c6fd2807SJeff Garzik 	/* ATI */
411c65ec1c2SConke Hu 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
412c6fd2807SJeff Garzik 
413c6fd2807SJeff Garzik 	/* VIA */
41454bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
415bf335542STejun Heo 	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
416c6fd2807SJeff Garzik 
417c6fd2807SJeff Garzik 	/* NVIDIA */
41854bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },		/* MCP65 */
41954bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci },		/* MCP65 */
42054bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci },		/* MCP65 */
42154bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci },		/* MCP65 */
4226fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045c), board_ahci },		/* MCP65 */
4236fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045d), board_ahci },		/* MCP65 */
4246fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045e), board_ahci },		/* MCP65 */
4256fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x045f), board_ahci },		/* MCP65 */
4266fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci },		/* MCP67 */
4276fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci },		/* MCP67 */
4286fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci },		/* MCP67 */
4296fbf5ba4SPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0553), board_ahci },		/* MCP67 */
430895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },		/* MCP67 */
431895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },		/* MCP67 */
432895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },		/* MCP67 */
433895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },		/* MCP67 */
434895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },		/* MCP67 */
435895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },		/* MCP67 */
436895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },		/* MCP67 */
437895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },		/* MCP67 */
438c6fd2807SJeff Garzik 
439c6fd2807SJeff Garzik 	/* SiS */
44054bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
44154bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
44254bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
443c6fd2807SJeff Garzik 
444415ae2b5SJeff Garzik 	/* Generic, PCI class code for AHCI */
445415ae2b5SJeff Garzik 	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
446c9f89475SConke Hu 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
447415ae2b5SJeff Garzik 
448c6fd2807SJeff Garzik 	{ }	/* terminate list */
449c6fd2807SJeff Garzik };
450c6fd2807SJeff Garzik 
451c6fd2807SJeff Garzik 
452c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
453c6fd2807SJeff Garzik 	.name			= DRV_NAME,
454c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
455c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
45624dc5f33STejun Heo 	.remove			= ata_pci_remove_one,
457438ac6d5STejun Heo #ifdef CONFIG_PM
458c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
459c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
460438ac6d5STejun Heo #endif
461c6fd2807SJeff Garzik };
462c6fd2807SJeff Garzik 
463c6fd2807SJeff Garzik 
46498fa4b60STejun Heo static inline int ahci_nr_ports(u32 cap)
46598fa4b60STejun Heo {
46698fa4b60STejun Heo 	return (cap & 0x1f) + 1;
46798fa4b60STejun Heo }
46898fa4b60STejun Heo 
469*4447d351STejun Heo static inline void __iomem *ahci_port_base(struct ata_port *ap)
470c6fd2807SJeff Garzik {
471*4447d351STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
472*4447d351STejun Heo 
473*4447d351STejun Heo 	return mmio + 0x100 + (ap->port_no * 0x80);
474c6fd2807SJeff Garzik }
475c6fd2807SJeff Garzik 
476d447df14STejun Heo /**
477d447df14STejun Heo  *	ahci_save_initial_config - Save and fixup initial config values
478*4447d351STejun Heo  *	@pdev: target PCI device
479*4447d351STejun Heo  *	@pi: associated ATA port info
480*4447d351STejun Heo  *	@hpriv: host private area to store config values
481d447df14STejun Heo  *
482d447df14STejun Heo  *	Some registers containing configuration info might be setup by
483d447df14STejun Heo  *	BIOS and might be cleared on reset.  This function saves the
484d447df14STejun Heo  *	initial values of those registers into @hpriv such that they
485d447df14STejun Heo  *	can be restored after controller reset.
486d447df14STejun Heo  *
487d447df14STejun Heo  *	If inconsistent, config values are fixed up by this function.
488d447df14STejun Heo  *
489d447df14STejun Heo  *	LOCKING:
490d447df14STejun Heo  *	None.
491d447df14STejun Heo  */
492*4447d351STejun Heo static void ahci_save_initial_config(struct pci_dev *pdev,
493*4447d351STejun Heo 				     const struct ata_port_info *pi,
494*4447d351STejun Heo 				     struct ahci_host_priv *hpriv)
495d447df14STejun Heo {
496*4447d351STejun Heo 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
497d447df14STejun Heo 	u32 cap, port_map;
49817199b18STejun Heo 	int i;
499d447df14STejun Heo 
500d447df14STejun Heo 	/* Values prefixed with saved_ are written back to host after
501d447df14STejun Heo 	 * reset.  Values without are used for driver operation.
502d447df14STejun Heo 	 */
503d447df14STejun Heo 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
504d447df14STejun Heo 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
505d447df14STejun Heo 
506d447df14STejun Heo 	/* fixup zero port_map */
507d447df14STejun Heo 	if (!port_map) {
508d447df14STejun Heo 		port_map = (1 << ahci_nr_ports(hpriv->cap)) - 1;
509*4447d351STejun Heo 		dev_printk(KERN_WARNING, &pdev->dev,
510d447df14STejun Heo 			   "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
511d447df14STejun Heo 
512d447df14STejun Heo 		/* write the fixed up value to the PI register */
513d447df14STejun Heo 		hpriv->saved_port_map = port_map;
514d447df14STejun Heo 	}
515d447df14STejun Heo 
51617199b18STejun Heo 	/* cross check port_map and cap.n_ports */
517*4447d351STejun Heo 	if (pi->flags & AHCI_FLAG_HONOR_PI) {
51817199b18STejun Heo 		u32 tmp_port_map = port_map;
51917199b18STejun Heo 		int n_ports = ahci_nr_ports(cap);
52017199b18STejun Heo 
52117199b18STejun Heo 		for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
52217199b18STejun Heo 			if (tmp_port_map & (1 << i)) {
52317199b18STejun Heo 				n_ports--;
52417199b18STejun Heo 				tmp_port_map &= ~(1 << i);
52517199b18STejun Heo 			}
52617199b18STejun Heo 		}
52717199b18STejun Heo 
52817199b18STejun Heo 		/* Whine if inconsistent.  No need to update cap.
52917199b18STejun Heo 		 * port_map is used to determine number of ports.
53017199b18STejun Heo 		 */
53117199b18STejun Heo 		if (n_ports || tmp_port_map)
532*4447d351STejun Heo 			dev_printk(KERN_WARNING, &pdev->dev,
53317199b18STejun Heo 				   "nr_ports (%u) and implemented port map "
53417199b18STejun Heo 				   "(0x%x) don't match\n",
53517199b18STejun Heo 				   ahci_nr_ports(cap), port_map);
53617199b18STejun Heo 	} else {
53717199b18STejun Heo 		/* fabricate port_map from cap.nr_ports */
53817199b18STejun Heo 		port_map = (1 << ahci_nr_ports(cap)) - 1;
53917199b18STejun Heo 	}
54017199b18STejun Heo 
541d447df14STejun Heo 	/* record values to use during operation */
542d447df14STejun Heo 	hpriv->cap = cap;
543d447df14STejun Heo 	hpriv->port_map = port_map;
544d447df14STejun Heo }
545d447df14STejun Heo 
546d447df14STejun Heo /**
547d447df14STejun Heo  *	ahci_restore_initial_config - Restore initial config
548*4447d351STejun Heo  *	@host: target ATA host
549d447df14STejun Heo  *
550d447df14STejun Heo  *	Restore initial config stored by ahci_save_initial_config().
551d447df14STejun Heo  *
552d447df14STejun Heo  *	LOCKING:
553d447df14STejun Heo  *	None.
554d447df14STejun Heo  */
555*4447d351STejun Heo static void ahci_restore_initial_config(struct ata_host *host)
556d447df14STejun Heo {
557*4447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
558*4447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
559*4447d351STejun Heo 
560d447df14STejun Heo 	writel(hpriv->saved_cap, mmio + HOST_CAP);
561d447df14STejun Heo 	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
562d447df14STejun Heo 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
563d447df14STejun Heo }
564d447df14STejun Heo 
565c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
566c6fd2807SJeff Garzik {
567c6fd2807SJeff Garzik 	unsigned int sc_reg;
568c6fd2807SJeff Garzik 
569c6fd2807SJeff Garzik 	switch (sc_reg_in) {
570c6fd2807SJeff Garzik 	case SCR_STATUS:	sc_reg = 0; break;
571c6fd2807SJeff Garzik 	case SCR_CONTROL:	sc_reg = 1; break;
572c6fd2807SJeff Garzik 	case SCR_ERROR:		sc_reg = 2; break;
573c6fd2807SJeff Garzik 	case SCR_ACTIVE:	sc_reg = 3; break;
574c6fd2807SJeff Garzik 	default:
575c6fd2807SJeff Garzik 		return 0xffffffffU;
576c6fd2807SJeff Garzik 	}
577c6fd2807SJeff Garzik 
5780d5ff566STejun Heo 	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
579c6fd2807SJeff Garzik }
580c6fd2807SJeff Garzik 
581c6fd2807SJeff Garzik 
582c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
583c6fd2807SJeff Garzik 			       u32 val)
584c6fd2807SJeff Garzik {
585c6fd2807SJeff Garzik 	unsigned int sc_reg;
586c6fd2807SJeff Garzik 
587c6fd2807SJeff Garzik 	switch (sc_reg_in) {
588c6fd2807SJeff Garzik 	case SCR_STATUS:	sc_reg = 0; break;
589c6fd2807SJeff Garzik 	case SCR_CONTROL:	sc_reg = 1; break;
590c6fd2807SJeff Garzik 	case SCR_ERROR:		sc_reg = 2; break;
591c6fd2807SJeff Garzik 	case SCR_ACTIVE:	sc_reg = 3; break;
592c6fd2807SJeff Garzik 	default:
593c6fd2807SJeff Garzik 		return;
594c6fd2807SJeff Garzik 	}
595c6fd2807SJeff Garzik 
5960d5ff566STejun Heo 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
597c6fd2807SJeff Garzik }
598c6fd2807SJeff Garzik 
599*4447d351STejun Heo static void ahci_start_engine(struct ata_port *ap)
600c6fd2807SJeff Garzik {
601*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
602c6fd2807SJeff Garzik 	u32 tmp;
603c6fd2807SJeff Garzik 
604c6fd2807SJeff Garzik 	/* start DMA */
605c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
606c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
607c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
608c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
609c6fd2807SJeff Garzik }
610c6fd2807SJeff Garzik 
611*4447d351STejun Heo static int ahci_stop_engine(struct ata_port *ap)
612c6fd2807SJeff Garzik {
613*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
614c6fd2807SJeff Garzik 	u32 tmp;
615c6fd2807SJeff Garzik 
616c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
617c6fd2807SJeff Garzik 
618c6fd2807SJeff Garzik 	/* check if the HBA is idle */
619c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
620c6fd2807SJeff Garzik 		return 0;
621c6fd2807SJeff Garzik 
622c6fd2807SJeff Garzik 	/* setting HBA to idle */
623c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
624c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
625c6fd2807SJeff Garzik 
626c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
627c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
628c6fd2807SJeff Garzik 			        PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
629c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
630c6fd2807SJeff Garzik 		return -EIO;
631c6fd2807SJeff Garzik 
632c6fd2807SJeff Garzik 	return 0;
633c6fd2807SJeff Garzik }
634c6fd2807SJeff Garzik 
635*4447d351STejun Heo static void ahci_start_fis_rx(struct ata_port *ap)
636c6fd2807SJeff Garzik {
637*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
638*4447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
639*4447d351STejun Heo 	struct ahci_port_priv *pp = ap->private_data;
640c6fd2807SJeff Garzik 	u32 tmp;
641c6fd2807SJeff Garzik 
642c6fd2807SJeff Garzik 	/* set FIS registers */
643*4447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
644*4447d351STejun Heo 		writel((pp->cmd_slot_dma >> 16) >> 16,
645*4447d351STejun Heo 		       port_mmio + PORT_LST_ADDR_HI);
646*4447d351STejun Heo 	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
647c6fd2807SJeff Garzik 
648*4447d351STejun Heo 	if (hpriv->cap & HOST_CAP_64)
649*4447d351STejun Heo 		writel((pp->rx_fis_dma >> 16) >> 16,
650*4447d351STejun Heo 		       port_mmio + PORT_FIS_ADDR_HI);
651*4447d351STejun Heo 	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
652c6fd2807SJeff Garzik 
653c6fd2807SJeff Garzik 	/* enable FIS reception */
654c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
655c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
656c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
657c6fd2807SJeff Garzik 
658c6fd2807SJeff Garzik 	/* flush */
659c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
660c6fd2807SJeff Garzik }
661c6fd2807SJeff Garzik 
662*4447d351STejun Heo static int ahci_stop_fis_rx(struct ata_port *ap)
663c6fd2807SJeff Garzik {
664*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
665c6fd2807SJeff Garzik 	u32 tmp;
666c6fd2807SJeff Garzik 
667c6fd2807SJeff Garzik 	/* disable FIS reception */
668c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
669c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
670c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
671c6fd2807SJeff Garzik 
672c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
673c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
674c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
675c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
676c6fd2807SJeff Garzik 		return -EBUSY;
677c6fd2807SJeff Garzik 
678c6fd2807SJeff Garzik 	return 0;
679c6fd2807SJeff Garzik }
680c6fd2807SJeff Garzik 
681*4447d351STejun Heo static void ahci_power_up(struct ata_port *ap)
682c6fd2807SJeff Garzik {
683*4447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
684*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
685c6fd2807SJeff Garzik 	u32 cmd;
686c6fd2807SJeff Garzik 
687c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
688c6fd2807SJeff Garzik 
689c6fd2807SJeff Garzik 	/* spin up device */
690*4447d351STejun Heo 	if (hpriv->cap & HOST_CAP_SSS) {
691c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
692c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
693c6fd2807SJeff Garzik 	}
694c6fd2807SJeff Garzik 
695c6fd2807SJeff Garzik 	/* wake up link */
696c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
697c6fd2807SJeff Garzik }
698c6fd2807SJeff Garzik 
699438ac6d5STejun Heo #ifdef CONFIG_PM
700*4447d351STejun Heo static void ahci_power_down(struct ata_port *ap)
701c6fd2807SJeff Garzik {
702*4447d351STejun Heo 	struct ahci_host_priv *hpriv = ap->host->private_data;
703*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
704c6fd2807SJeff Garzik 	u32 cmd, scontrol;
705c6fd2807SJeff Garzik 
706*4447d351STejun Heo 	if (!(hpriv->cap & HOST_CAP_SSS))
70707c53dacSTejun Heo 		return;
708c6fd2807SJeff Garzik 
70907c53dacSTejun Heo 	/* put device into listen mode, first set PxSCTL.DET to 0 */
710c6fd2807SJeff Garzik 	scontrol = readl(port_mmio + PORT_SCR_CTL);
711c6fd2807SJeff Garzik 	scontrol &= ~0xf;
712c6fd2807SJeff Garzik 	writel(scontrol, port_mmio + PORT_SCR_CTL);
713c6fd2807SJeff Garzik 
714c6fd2807SJeff Garzik 	/* then set PxCMD.SUD to 0 */
71507c53dacSTejun Heo 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
716c6fd2807SJeff Garzik 	cmd &= ~PORT_CMD_SPIN_UP;
717c6fd2807SJeff Garzik 	writel(cmd, port_mmio + PORT_CMD);
718c6fd2807SJeff Garzik }
719438ac6d5STejun Heo #endif
720c6fd2807SJeff Garzik 
721*4447d351STejun Heo static void ahci_init_port(struct ata_port *ap)
722c6fd2807SJeff Garzik {
723c6fd2807SJeff Garzik 	/* enable FIS reception */
724*4447d351STejun Heo 	ahci_start_fis_rx(ap);
725c6fd2807SJeff Garzik 
726c6fd2807SJeff Garzik 	/* enable DMA */
727*4447d351STejun Heo 	ahci_start_engine(ap);
728c6fd2807SJeff Garzik }
729c6fd2807SJeff Garzik 
730*4447d351STejun Heo static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
731c6fd2807SJeff Garzik {
732c6fd2807SJeff Garzik 	int rc;
733c6fd2807SJeff Garzik 
734c6fd2807SJeff Garzik 	/* disable DMA */
735*4447d351STejun Heo 	rc = ahci_stop_engine(ap);
736c6fd2807SJeff Garzik 	if (rc) {
737c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
738c6fd2807SJeff Garzik 		return rc;
739c6fd2807SJeff Garzik 	}
740c6fd2807SJeff Garzik 
741c6fd2807SJeff Garzik 	/* disable FIS reception */
742*4447d351STejun Heo 	rc = ahci_stop_fis_rx(ap);
743c6fd2807SJeff Garzik 	if (rc) {
744c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
745c6fd2807SJeff Garzik 		return rc;
746c6fd2807SJeff Garzik 	}
747c6fd2807SJeff Garzik 
748c6fd2807SJeff Garzik 	return 0;
749c6fd2807SJeff Garzik }
750c6fd2807SJeff Garzik 
751*4447d351STejun Heo static int ahci_reset_controller(struct ata_host *host)
752c6fd2807SJeff Garzik {
753*4447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
754*4447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
755d447df14STejun Heo 	u32 tmp;
756c6fd2807SJeff Garzik 
757c6fd2807SJeff Garzik 	/* global controller reset */
758c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
759c6fd2807SJeff Garzik 	if ((tmp & HOST_RESET) == 0) {
760c6fd2807SJeff Garzik 		writel(tmp | HOST_RESET, mmio + HOST_CTL);
761c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
762c6fd2807SJeff Garzik 	}
763c6fd2807SJeff Garzik 
764c6fd2807SJeff Garzik 	/* reset must complete within 1 second, or
765c6fd2807SJeff Garzik 	 * the hardware should be considered fried.
766c6fd2807SJeff Garzik 	 */
767c6fd2807SJeff Garzik 	ssleep(1);
768c6fd2807SJeff Garzik 
769c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
770c6fd2807SJeff Garzik 	if (tmp & HOST_RESET) {
771*4447d351STejun Heo 		dev_printk(KERN_ERR, host->dev,
772c6fd2807SJeff Garzik 			   "controller reset failed (0x%x)\n", tmp);
773c6fd2807SJeff Garzik 		return -EIO;
774c6fd2807SJeff Garzik 	}
775c6fd2807SJeff Garzik 
77698fa4b60STejun Heo 	/* turn on AHCI mode */
777c6fd2807SJeff Garzik 	writel(HOST_AHCI_EN, mmio + HOST_CTL);
778c6fd2807SJeff Garzik 	(void) readl(mmio + HOST_CTL);	/* flush */
77998fa4b60STejun Heo 
780d447df14STejun Heo 	/* some registers might be cleared on reset.  restore initial values */
781*4447d351STejun Heo 	ahci_restore_initial_config(host);
782c6fd2807SJeff Garzik 
783c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
784c6fd2807SJeff Garzik 		u16 tmp16;
785c6fd2807SJeff Garzik 
786c6fd2807SJeff Garzik 		/* configure PCS */
787c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
788c6fd2807SJeff Garzik 		tmp16 |= 0xf;
789c6fd2807SJeff Garzik 		pci_write_config_word(pdev, 0x92, tmp16);
790c6fd2807SJeff Garzik 	}
791c6fd2807SJeff Garzik 
792c6fd2807SJeff Garzik 	return 0;
793c6fd2807SJeff Garzik }
794c6fd2807SJeff Garzik 
795*4447d351STejun Heo static void ahci_init_controller(struct ata_host *host)
796c6fd2807SJeff Garzik {
797*4447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
798*4447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
799c6fd2807SJeff Garzik 	int i, rc;
800c6fd2807SJeff Garzik 	u32 tmp;
801c6fd2807SJeff Garzik 
802*4447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
803*4447d351STejun Heo 		struct ata_port *ap = host->ports[i];
804*4447d351STejun Heo 		void __iomem *port_mmio = ahci_port_base(ap);
805c6fd2807SJeff Garzik 		const char *emsg = NULL;
806c6fd2807SJeff Garzik 
807*4447d351STejun Heo 		if (ata_port_is_dummy(ap))
808c6fd2807SJeff Garzik 			continue;
809c6fd2807SJeff Garzik 
810c6fd2807SJeff Garzik 		/* make sure port is not active */
811*4447d351STejun Heo 		rc = ahci_deinit_port(ap, &emsg);
812c6fd2807SJeff Garzik 		if (rc)
813c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
814c6fd2807SJeff Garzik 				   "%s (%d)\n", emsg, rc);
815c6fd2807SJeff Garzik 
816c6fd2807SJeff Garzik 		/* clear SError */
817c6fd2807SJeff Garzik 		tmp = readl(port_mmio + PORT_SCR_ERR);
818c6fd2807SJeff Garzik 		VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
819c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_SCR_ERR);
820c6fd2807SJeff Garzik 
821c6fd2807SJeff Garzik 		/* clear port IRQ */
822c6fd2807SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
823c6fd2807SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
824c6fd2807SJeff Garzik 		if (tmp)
825c6fd2807SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
826c6fd2807SJeff Garzik 
827c6fd2807SJeff Garzik 		writel(1 << i, mmio + HOST_IRQ_STAT);
828c6fd2807SJeff Garzik 	}
829c6fd2807SJeff Garzik 
830c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
831c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
832c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
833c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
834c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
835c6fd2807SJeff Garzik }
836c6fd2807SJeff Garzik 
837c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
838c6fd2807SJeff Garzik {
839*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
840c6fd2807SJeff Garzik 	struct ata_taskfile tf;
841c6fd2807SJeff Garzik 	u32 tmp;
842c6fd2807SJeff Garzik 
843c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
844c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
845c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
846c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
847c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
848c6fd2807SJeff Garzik 
849c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
850c6fd2807SJeff Garzik }
851c6fd2807SJeff Garzik 
852c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
853c6fd2807SJeff Garzik 			       u32 opts)
854c6fd2807SJeff Garzik {
855c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
856c6fd2807SJeff Garzik 
857c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
858c6fd2807SJeff Garzik 
859c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
860c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
861c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
862c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
863c6fd2807SJeff Garzik }
864c6fd2807SJeff Garzik 
865c6fd2807SJeff Garzik static int ahci_clo(struct ata_port *ap)
866c6fd2807SJeff Garzik {
8670d5ff566STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
868cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
869c6fd2807SJeff Garzik 	u32 tmp;
870c6fd2807SJeff Garzik 
871c6fd2807SJeff Garzik 	if (!(hpriv->cap & HOST_CAP_CLO))
872c6fd2807SJeff Garzik 		return -EOPNOTSUPP;
873c6fd2807SJeff Garzik 
874c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
875c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
876c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
877c6fd2807SJeff Garzik 
878c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
879c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
880c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
881c6fd2807SJeff Garzik 		return -EIO;
882c6fd2807SJeff Garzik 
883c6fd2807SJeff Garzik 	return 0;
884c6fd2807SJeff Garzik }
885c6fd2807SJeff Garzik 
886c6fd2807SJeff Garzik static int ahci_softreset(struct ata_port *ap, unsigned int *class)
887c6fd2807SJeff Garzik {
888c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
889*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
890c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
891c6fd2807SJeff Garzik 	const char *reason = NULL;
892c6fd2807SJeff Garzik 	struct ata_taskfile tf;
893c6fd2807SJeff Garzik 	u32 tmp;
894c6fd2807SJeff Garzik 	u8 *fis;
895c6fd2807SJeff Garzik 	int rc;
896c6fd2807SJeff Garzik 
897c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
898c6fd2807SJeff Garzik 
899c6fd2807SJeff Garzik 	if (ata_port_offline(ap)) {
900c6fd2807SJeff Garzik 		DPRINTK("PHY reports no device\n");
901c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
902c6fd2807SJeff Garzik 		return 0;
903c6fd2807SJeff Garzik 	}
904c6fd2807SJeff Garzik 
905c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
906*4447d351STejun Heo 	rc = ahci_stop_engine(ap);
907c6fd2807SJeff Garzik 	if (rc) {
908c6fd2807SJeff Garzik 		reason = "failed to stop engine";
909c6fd2807SJeff Garzik 		goto fail_restart;
910c6fd2807SJeff Garzik 	}
911c6fd2807SJeff Garzik 
912c6fd2807SJeff Garzik 	/* check BUSY/DRQ, perform Command List Override if necessary */
9131244a19cSTejun Heo 	if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
914c6fd2807SJeff Garzik 		rc = ahci_clo(ap);
915c6fd2807SJeff Garzik 
916c6fd2807SJeff Garzik 		if (rc == -EOPNOTSUPP) {
917c6fd2807SJeff Garzik 			reason = "port busy but CLO unavailable";
918c6fd2807SJeff Garzik 			goto fail_restart;
919c6fd2807SJeff Garzik 		} else if (rc) {
920c6fd2807SJeff Garzik 			reason = "port busy but CLO failed";
921c6fd2807SJeff Garzik 			goto fail_restart;
922c6fd2807SJeff Garzik 		}
923c6fd2807SJeff Garzik 	}
924c6fd2807SJeff Garzik 
925c6fd2807SJeff Garzik 	/* restart engine */
926*4447d351STejun Heo 	ahci_start_engine(ap);
927c6fd2807SJeff Garzik 
928c6fd2807SJeff Garzik 	ata_tf_init(ap->device, &tf);
929c6fd2807SJeff Garzik 	fis = pp->cmd_tbl;
930c6fd2807SJeff Garzik 
931c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
932c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, 0,
933c6fd2807SJeff Garzik 			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
934c6fd2807SJeff Garzik 
935c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
936c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, fis, 0);
937c6fd2807SJeff Garzik 	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
938c6fd2807SJeff Garzik 
939c6fd2807SJeff Garzik 	writel(1, port_mmio + PORT_CMD_ISSUE);
940c6fd2807SJeff Garzik 
941c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
942c6fd2807SJeff Garzik 	if (tmp & 0x1) {
943c6fd2807SJeff Garzik 		rc = -EIO;
944c6fd2807SJeff Garzik 		reason = "1st FIS failed";
945c6fd2807SJeff Garzik 		goto fail;
946c6fd2807SJeff Garzik 	}
947c6fd2807SJeff Garzik 
948c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
949c6fd2807SJeff Garzik 	msleep(1);
950c6fd2807SJeff Garzik 
951c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
952c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
953c6fd2807SJeff Garzik 
954c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
955c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, fis, 0);
956c6fd2807SJeff Garzik 	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
957c6fd2807SJeff Garzik 
958c6fd2807SJeff Garzik 	writel(1, port_mmio + PORT_CMD_ISSUE);
959c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
960c6fd2807SJeff Garzik 
961c6fd2807SJeff Garzik 	/* spec mandates ">= 2ms" before checking status.
962c6fd2807SJeff Garzik 	 * We wait 150ms, because that was the magic delay used for
963c6fd2807SJeff Garzik 	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time
964c6fd2807SJeff Garzik 	 * between when the ATA command register is written, and then
965c6fd2807SJeff Garzik 	 * status is checked.  Because waiting for "a while" before
966c6fd2807SJeff Garzik 	 * checking status is fine, post SRST, we perform this magic
967c6fd2807SJeff Garzik 	 * delay here as well.
968c6fd2807SJeff Garzik 	 */
969c6fd2807SJeff Garzik 	msleep(150);
970c6fd2807SJeff Garzik 
971c6fd2807SJeff Garzik 	*class = ATA_DEV_NONE;
972c6fd2807SJeff Garzik 	if (ata_port_online(ap)) {
973c6fd2807SJeff Garzik 		if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
974c6fd2807SJeff Garzik 			rc = -EIO;
975c6fd2807SJeff Garzik 			reason = "device not ready";
976c6fd2807SJeff Garzik 			goto fail;
977c6fd2807SJeff Garzik 		}
978c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
979c6fd2807SJeff Garzik 	}
980c6fd2807SJeff Garzik 
981c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
982c6fd2807SJeff Garzik 	return 0;
983c6fd2807SJeff Garzik 
984c6fd2807SJeff Garzik  fail_restart:
985*4447d351STejun Heo 	ahci_start_engine(ap);
986c6fd2807SJeff Garzik  fail:
987c6fd2807SJeff Garzik 	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
988c6fd2807SJeff Garzik 	return rc;
989c6fd2807SJeff Garzik }
990c6fd2807SJeff Garzik 
991c6fd2807SJeff Garzik static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
992c6fd2807SJeff Garzik {
993c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
994c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
995c6fd2807SJeff Garzik 	struct ata_taskfile tf;
996c6fd2807SJeff Garzik 	int rc;
997c6fd2807SJeff Garzik 
998c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
999c6fd2807SJeff Garzik 
1000*4447d351STejun Heo 	ahci_stop_engine(ap);
1001c6fd2807SJeff Garzik 
1002c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
1003c6fd2807SJeff Garzik 	ata_tf_init(ap->device, &tf);
1004dfd7a3dbSTejun Heo 	tf.command = 0x80;
1005c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, d2h_fis, 0);
1006c6fd2807SJeff Garzik 
1007c6fd2807SJeff Garzik 	rc = sata_std_hardreset(ap, class);
1008c6fd2807SJeff Garzik 
1009*4447d351STejun Heo 	ahci_start_engine(ap);
1010c6fd2807SJeff Garzik 
1011c6fd2807SJeff Garzik 	if (rc == 0 && ata_port_online(ap))
1012c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
1013c6fd2807SJeff Garzik 	if (*class == ATA_DEV_UNKNOWN)
1014c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
1015c6fd2807SJeff Garzik 
1016c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1017c6fd2807SJeff Garzik 	return rc;
1018c6fd2807SJeff Garzik }
1019c6fd2807SJeff Garzik 
1020ad616ffbSTejun Heo static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
1021ad616ffbSTejun Heo {
1022ad616ffbSTejun Heo 	int rc;
1023ad616ffbSTejun Heo 
1024ad616ffbSTejun Heo 	DPRINTK("ENTER\n");
1025ad616ffbSTejun Heo 
1026*4447d351STejun Heo 	ahci_stop_engine(ap);
1027ad616ffbSTejun Heo 
1028ad616ffbSTejun Heo 	rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
1029ad616ffbSTejun Heo 
1030ad616ffbSTejun Heo 	/* vt8251 needs SError cleared for the port to operate */
1031ad616ffbSTejun Heo 	ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
1032ad616ffbSTejun Heo 
1033*4447d351STejun Heo 	ahci_start_engine(ap);
1034ad616ffbSTejun Heo 
1035ad616ffbSTejun Heo 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
1036ad616ffbSTejun Heo 
1037ad616ffbSTejun Heo 	/* vt8251 doesn't clear BSY on signature FIS reception,
1038ad616ffbSTejun Heo 	 * request follow-up softreset.
1039ad616ffbSTejun Heo 	 */
1040ad616ffbSTejun Heo 	return rc ?: -EAGAIN;
1041ad616ffbSTejun Heo }
1042ad616ffbSTejun Heo 
1043c6fd2807SJeff Garzik static void ahci_postreset(struct ata_port *ap, unsigned int *class)
1044c6fd2807SJeff Garzik {
1045*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1046c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
1047c6fd2807SJeff Garzik 
1048c6fd2807SJeff Garzik 	ata_std_postreset(ap, class);
1049c6fd2807SJeff Garzik 
1050c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
1051c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
1052c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
1053c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
1054c6fd2807SJeff Garzik 	else
1055c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
1056c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
1057c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
1058c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
1059c6fd2807SJeff Garzik 	}
1060c6fd2807SJeff Garzik }
1061c6fd2807SJeff Garzik 
1062c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap)
1063c6fd2807SJeff Garzik {
10640d5ff566STejun Heo 	void __iomem *mmio = ap->ioaddr.cmd_addr;
1065c6fd2807SJeff Garzik 
1066c6fd2807SJeff Garzik 	return readl(mmio + PORT_TFDATA) & 0xFF;
1067c6fd2807SJeff Garzik }
1068c6fd2807SJeff Garzik 
1069c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
1070c6fd2807SJeff Garzik {
1071c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1072c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1073c6fd2807SJeff Garzik 
1074c6fd2807SJeff Garzik 	ata_tf_from_fis(d2h_fis, tf);
1075c6fd2807SJeff Garzik }
1076c6fd2807SJeff Garzik 
1077c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
1078c6fd2807SJeff Garzik {
1079c6fd2807SJeff Garzik 	struct scatterlist *sg;
1080c6fd2807SJeff Garzik 	struct ahci_sg *ahci_sg;
1081c6fd2807SJeff Garzik 	unsigned int n_sg = 0;
1082c6fd2807SJeff Garzik 
1083c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1084c6fd2807SJeff Garzik 
1085c6fd2807SJeff Garzik 	/*
1086c6fd2807SJeff Garzik 	 * Next, the S/G list.
1087c6fd2807SJeff Garzik 	 */
1088c6fd2807SJeff Garzik 	ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
1089c6fd2807SJeff Garzik 	ata_for_each_sg(sg, qc) {
1090c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
1091c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
1092c6fd2807SJeff Garzik 
1093c6fd2807SJeff Garzik 		ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
1094c6fd2807SJeff Garzik 		ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
1095c6fd2807SJeff Garzik 		ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
1096c6fd2807SJeff Garzik 
1097c6fd2807SJeff Garzik 		ahci_sg++;
1098c6fd2807SJeff Garzik 		n_sg++;
1099c6fd2807SJeff Garzik 	}
1100c6fd2807SJeff Garzik 
1101c6fd2807SJeff Garzik 	return n_sg;
1102c6fd2807SJeff Garzik }
1103c6fd2807SJeff Garzik 
1104c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
1105c6fd2807SJeff Garzik {
1106c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1107c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1108c6fd2807SJeff Garzik 	int is_atapi = is_atapi_taskfile(&qc->tf);
1109c6fd2807SJeff Garzik 	void *cmd_tbl;
1110c6fd2807SJeff Garzik 	u32 opts;
1111c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
1112c6fd2807SJeff Garzik 	unsigned int n_elem;
1113c6fd2807SJeff Garzik 
1114c6fd2807SJeff Garzik 	/*
1115c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
1116c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
1117c6fd2807SJeff Garzik 	 */
1118c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
1119c6fd2807SJeff Garzik 
1120c6fd2807SJeff Garzik 	ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
1121c6fd2807SJeff Garzik 	if (is_atapi) {
1122c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
1123c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
1124c6fd2807SJeff Garzik 	}
1125c6fd2807SJeff Garzik 
1126c6fd2807SJeff Garzik 	n_elem = 0;
1127c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
1128c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
1129c6fd2807SJeff Garzik 
1130c6fd2807SJeff Garzik 	/*
1131c6fd2807SJeff Garzik 	 * Fill in command slot information.
1132c6fd2807SJeff Garzik 	 */
1133c6fd2807SJeff Garzik 	opts = cmd_fis_len | n_elem << 16;
1134c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
1135c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
1136c6fd2807SJeff Garzik 	if (is_atapi)
1137c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
1138c6fd2807SJeff Garzik 
1139c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
1140c6fd2807SJeff Garzik }
1141c6fd2807SJeff Garzik 
1142c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
1143c6fd2807SJeff Garzik {
1144c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1145c6fd2807SJeff Garzik 	struct ata_eh_info *ehi = &ap->eh_info;
1146c6fd2807SJeff Garzik 	unsigned int err_mask = 0, action = 0;
1147c6fd2807SJeff Garzik 	struct ata_queued_cmd *qc;
1148c6fd2807SJeff Garzik 	u32 serror;
1149c6fd2807SJeff Garzik 
1150c6fd2807SJeff Garzik 	ata_ehi_clear_desc(ehi);
1151c6fd2807SJeff Garzik 
1152c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
1153c6fd2807SJeff Garzik 	serror = ahci_scr_read(ap, SCR_ERROR);
1154c6fd2807SJeff Garzik 	ahci_scr_write(ap, SCR_ERROR, serror);
1155c6fd2807SJeff Garzik 
1156c6fd2807SJeff Garzik 	/* analyze @irq_stat */
1157c6fd2807SJeff Garzik 	ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
1158c6fd2807SJeff Garzik 
115941669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
116041669553STejun Heo 	if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
116141669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
116241669553STejun Heo 
116355a61604SConke Hu 	if (irq_stat & PORT_IRQ_TF_ERR) {
1164c6fd2807SJeff Garzik 		err_mask |= AC_ERR_DEV;
116555a61604SConke Hu 		if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL)
116655a61604SConke Hu 			serror &= ~SERR_INTERNAL;
116755a61604SConke Hu 	}
1168c6fd2807SJeff Garzik 
1169c6fd2807SJeff Garzik 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
1170c6fd2807SJeff Garzik 		err_mask |= AC_ERR_HOST_BUS;
1171c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1172c6fd2807SJeff Garzik 	}
1173c6fd2807SJeff Garzik 
1174c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_IF_ERR) {
1175c6fd2807SJeff Garzik 		err_mask |= AC_ERR_ATA_BUS;
1176c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1177c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", interface fatal error");
1178c6fd2807SJeff Garzik 	}
1179c6fd2807SJeff Garzik 
1180c6fd2807SJeff Garzik 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
1181c6fd2807SJeff Garzik 		ata_ehi_hotplugged(ehi);
1182c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
1183c6fd2807SJeff Garzik 			"connection status changed" : "PHY RDY changed");
1184c6fd2807SJeff Garzik 	}
1185c6fd2807SJeff Garzik 
1186c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
1187c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
1188c6fd2807SJeff Garzik 
1189c6fd2807SJeff Garzik 		err_mask |= AC_ERR_HSM;
1190c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1191c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
1192c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
1193c6fd2807SJeff Garzik 	}
1194c6fd2807SJeff Garzik 
1195c6fd2807SJeff Garzik 	/* okay, let's hand over to EH */
1196c6fd2807SJeff Garzik 	ehi->serror |= serror;
1197c6fd2807SJeff Garzik 	ehi->action |= action;
1198c6fd2807SJeff Garzik 
1199c6fd2807SJeff Garzik 	qc = ata_qc_from_tag(ap, ap->active_tag);
1200c6fd2807SJeff Garzik 	if (qc)
1201c6fd2807SJeff Garzik 		qc->err_mask |= err_mask;
1202c6fd2807SJeff Garzik 	else
1203c6fd2807SJeff Garzik 		ehi->err_mask |= err_mask;
1204c6fd2807SJeff Garzik 
1205c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
1206c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1207c6fd2807SJeff Garzik 	else
1208c6fd2807SJeff Garzik 		ata_port_abort(ap);
1209c6fd2807SJeff Garzik }
1210c6fd2807SJeff Garzik 
1211c6fd2807SJeff Garzik static void ahci_host_intr(struct ata_port *ap)
1212c6fd2807SJeff Garzik {
1213*4447d351STejun Heo 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
1214c6fd2807SJeff Garzik 	struct ata_eh_info *ehi = &ap->eh_info;
12150291f95fSTejun Heo 	struct ahci_port_priv *pp = ap->private_data;
1216c6fd2807SJeff Garzik 	u32 status, qc_active;
12170291f95fSTejun Heo 	int rc, known_irq = 0;
1218c6fd2807SJeff Garzik 
1219c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
1220c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
1221c6fd2807SJeff Garzik 
1222c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
1223c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
1224c6fd2807SJeff Garzik 		return;
1225c6fd2807SJeff Garzik 	}
1226c6fd2807SJeff Garzik 
1227c6fd2807SJeff Garzik 	if (ap->sactive)
1228c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
1229c6fd2807SJeff Garzik 	else
1230c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
1231c6fd2807SJeff Garzik 
1232c6fd2807SJeff Garzik 	rc = ata_qc_complete_multiple(ap, qc_active, NULL);
1233c6fd2807SJeff Garzik 	if (rc > 0)
1234c6fd2807SJeff Garzik 		return;
1235c6fd2807SJeff Garzik 	if (rc < 0) {
1236c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
1237c6fd2807SJeff Garzik 		ehi->action |= ATA_EH_SOFTRESET;
1238c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1239c6fd2807SJeff Garzik 		return;
1240c6fd2807SJeff Garzik 	}
1241c6fd2807SJeff Garzik 
1242c6fd2807SJeff Garzik 	/* hmmm... a spurious interupt */
1243c6fd2807SJeff Garzik 
12440291f95fSTejun Heo 	/* if !NCQ, ignore.  No modern ATA device has broken HSM
12450291f95fSTejun Heo 	 * implementation for non-NCQ commands.
12460291f95fSTejun Heo 	 */
12470291f95fSTejun Heo 	if (!ap->sactive)
1248c6fd2807SJeff Garzik 		return;
1249c6fd2807SJeff Garzik 
12500291f95fSTejun Heo 	if (status & PORT_IRQ_D2H_REG_FIS) {
12510291f95fSTejun Heo 		if (!pp->ncq_saw_d2h)
12520291f95fSTejun Heo 			ata_port_printk(ap, KERN_INFO,
12530291f95fSTejun Heo 				"D2H reg with I during NCQ, "
12540291f95fSTejun Heo 				"this message won't be printed again\n");
12550291f95fSTejun Heo 		pp->ncq_saw_d2h = 1;
12560291f95fSTejun Heo 		known_irq = 1;
12570291f95fSTejun Heo 	}
1258c6fd2807SJeff Garzik 
12590291f95fSTejun Heo 	if (status & PORT_IRQ_DMAS_FIS) {
12600291f95fSTejun Heo 		if (!pp->ncq_saw_dmas)
12610291f95fSTejun Heo 			ata_port_printk(ap, KERN_INFO,
12620291f95fSTejun Heo 				"DMAS FIS during NCQ, "
12630291f95fSTejun Heo 				"this message won't be printed again\n");
12640291f95fSTejun Heo 		pp->ncq_saw_dmas = 1;
12650291f95fSTejun Heo 		known_irq = 1;
12660291f95fSTejun Heo 	}
12670291f95fSTejun Heo 
1268a2bbd0c9STejun Heo 	if (status & PORT_IRQ_SDB_FIS) {
126904d4f7a1SAl Viro 		const __le32 *f = pp->rx_fis + RX_FIS_SDB;
12700291f95fSTejun Heo 
1271afb2d552STejun Heo 		if (le32_to_cpu(f[1])) {
1272afb2d552STejun Heo 			/* SDB FIS containing spurious completions
1273afb2d552STejun Heo 			 * might be dangerous, whine and fail commands
1274afb2d552STejun Heo 			 * with HSM violation.  EH will turn off NCQ
1275afb2d552STejun Heo 			 * after several such failures.
1276afb2d552STejun Heo 			 */
1277afb2d552STejun Heo 			ata_ehi_push_desc(ehi,
1278afb2d552STejun Heo 				"spurious completions during NCQ "
1279a2bbd0c9STejun Heo 				"issue=0x%x SAct=0x%x FIS=%08x:%08x",
12800291f95fSTejun Heo 				readl(port_mmio + PORT_CMD_ISSUE),
12816096b63eSTejun Heo 				readl(port_mmio + PORT_SCR_ACT),
1282a2bbd0c9STejun Heo 				le32_to_cpu(f[0]), le32_to_cpu(f[1]));
1283a2bbd0c9STejun Heo 			ehi->err_mask |= AC_ERR_HSM;
1284a2bbd0c9STejun Heo 			ehi->action |= ATA_EH_SOFTRESET;
1285a2bbd0c9STejun Heo 			ata_port_freeze(ap);
1286afb2d552STejun Heo 		} else {
1287afb2d552STejun Heo 			if (!pp->ncq_saw_sdb)
1288afb2d552STejun Heo 				ata_port_printk(ap, KERN_INFO,
1289afb2d552STejun Heo 					"spurious SDB FIS %08x:%08x during NCQ, "
1290afb2d552STejun Heo 					"this message won't be printed again\n",
1291afb2d552STejun Heo 					le32_to_cpu(f[0]), le32_to_cpu(f[1]));
1292afb2d552STejun Heo 			pp->ncq_saw_sdb = 1;
1293afb2d552STejun Heo 		}
12940291f95fSTejun Heo 		known_irq = 1;
12950291f95fSTejun Heo 	}
12960291f95fSTejun Heo 
12970291f95fSTejun Heo 	if (!known_irq)
1298c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
12990291f95fSTejun Heo 				"(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
1300c6fd2807SJeff Garzik 				status, ap->active_tag, ap->sactive);
1301c6fd2807SJeff Garzik }
1302c6fd2807SJeff Garzik 
1303c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap)
1304c6fd2807SJeff Garzik {
1305c6fd2807SJeff Garzik 	/* TODO */
1306c6fd2807SJeff Garzik }
1307c6fd2807SJeff Garzik 
13087d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1309c6fd2807SJeff Garzik {
1310cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
1311c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1312c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
1313c6fd2807SJeff Garzik 	void __iomem *mmio;
1314c6fd2807SJeff Garzik 	u32 irq_stat, irq_ack = 0;
1315c6fd2807SJeff Garzik 
1316c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1317c6fd2807SJeff Garzik 
1318cca3974eSJeff Garzik 	hpriv = host->private_data;
13190d5ff566STejun Heo 	mmio = host->iomap[AHCI_PCI_BAR];
1320c6fd2807SJeff Garzik 
1321c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
1322c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
1323c6fd2807SJeff Garzik 	irq_stat &= hpriv->port_map;
1324c6fd2807SJeff Garzik 	if (!irq_stat)
1325c6fd2807SJeff Garzik 		return IRQ_NONE;
1326c6fd2807SJeff Garzik 
1327cca3974eSJeff Garzik         spin_lock(&host->lock);
1328c6fd2807SJeff Garzik 
1329cca3974eSJeff Garzik         for (i = 0; i < host->n_ports; i++) {
1330c6fd2807SJeff Garzik 		struct ata_port *ap;
1331c6fd2807SJeff Garzik 
1332c6fd2807SJeff Garzik 		if (!(irq_stat & (1 << i)))
1333c6fd2807SJeff Garzik 			continue;
1334c6fd2807SJeff Garzik 
1335cca3974eSJeff Garzik 		ap = host->ports[i];
1336c6fd2807SJeff Garzik 		if (ap) {
1337c6fd2807SJeff Garzik 			ahci_host_intr(ap);
1338c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
1339c6fd2807SJeff Garzik 		} else {
1340c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
1341c6fd2807SJeff Garzik 			if (ata_ratelimit())
1342cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
1343c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
1344c6fd2807SJeff Garzik 		}
1345c6fd2807SJeff Garzik 
1346c6fd2807SJeff Garzik 		irq_ack |= (1 << i);
1347c6fd2807SJeff Garzik 	}
1348c6fd2807SJeff Garzik 
1349c6fd2807SJeff Garzik 	if (irq_ack) {
1350c6fd2807SJeff Garzik 		writel(irq_ack, mmio + HOST_IRQ_STAT);
1351c6fd2807SJeff Garzik 		handled = 1;
1352c6fd2807SJeff Garzik 	}
1353c6fd2807SJeff Garzik 
1354cca3974eSJeff Garzik 	spin_unlock(&host->lock);
1355c6fd2807SJeff Garzik 
1356c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1357c6fd2807SJeff Garzik 
1358c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
1359c6fd2807SJeff Garzik }
1360c6fd2807SJeff Garzik 
1361c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
1362c6fd2807SJeff Garzik {
1363c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1364*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1365c6fd2807SJeff Garzik 
1366c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
1367c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
1368c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
1369c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
1370c6fd2807SJeff Garzik 
1371c6fd2807SJeff Garzik 	return 0;
1372c6fd2807SJeff Garzik }
1373c6fd2807SJeff Garzik 
1374c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
1375c6fd2807SJeff Garzik {
1376*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1377c6fd2807SJeff Garzik 
1378c6fd2807SJeff Garzik 	/* turn IRQ off */
1379c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
1380c6fd2807SJeff Garzik }
1381c6fd2807SJeff Garzik 
1382c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
1383c6fd2807SJeff Garzik {
13840d5ff566STejun Heo 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
1385*4447d351STejun Heo 	void __iomem *port_mmio = ahci_port_base(ap);
1386c6fd2807SJeff Garzik 	u32 tmp;
1387c6fd2807SJeff Garzik 
1388c6fd2807SJeff Garzik 	/* clear IRQ */
1389c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1390c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
1391a718728fSTejun Heo 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
1392c6fd2807SJeff Garzik 
1393c6fd2807SJeff Garzik 	/* turn IRQ back on */
1394c6fd2807SJeff Garzik 	writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
1395c6fd2807SJeff Garzik }
1396c6fd2807SJeff Garzik 
1397c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
1398c6fd2807SJeff Garzik {
1399c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1400c6fd2807SJeff Garzik 		/* restart engine */
1401*4447d351STejun Heo 		ahci_stop_engine(ap);
1402*4447d351STejun Heo 		ahci_start_engine(ap);
1403c6fd2807SJeff Garzik 	}
1404c6fd2807SJeff Garzik 
1405c6fd2807SJeff Garzik 	/* perform recovery */
14064aeb0e32STejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
1407c6fd2807SJeff Garzik 		  ahci_postreset);
1408c6fd2807SJeff Garzik }
1409c6fd2807SJeff Garzik 
1410ad616ffbSTejun Heo static void ahci_vt8251_error_handler(struct ata_port *ap)
1411ad616ffbSTejun Heo {
1412ad616ffbSTejun Heo 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1413ad616ffbSTejun Heo 		/* restart engine */
1414*4447d351STejun Heo 		ahci_stop_engine(ap);
1415*4447d351STejun Heo 		ahci_start_engine(ap);
1416ad616ffbSTejun Heo 	}
1417ad616ffbSTejun Heo 
1418ad616ffbSTejun Heo 	/* perform recovery */
1419ad616ffbSTejun Heo 	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset,
1420ad616ffbSTejun Heo 		  ahci_postreset);
1421ad616ffbSTejun Heo }
1422ad616ffbSTejun Heo 
1423c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
1424c6fd2807SJeff Garzik {
1425c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1426c6fd2807SJeff Garzik 
1427a51d644aSTejun Heo 	if (qc->flags & ATA_QCFLAG_FAILED) {
1428c6fd2807SJeff Garzik 		/* make DMA engine forget about the failed command */
1429*4447d351STejun Heo 		ahci_stop_engine(ap);
1430*4447d351STejun Heo 		ahci_start_engine(ap);
1431c6fd2807SJeff Garzik 	}
1432c6fd2807SJeff Garzik }
1433c6fd2807SJeff Garzik 
1434438ac6d5STejun Heo #ifdef CONFIG_PM
1435c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
1436c6fd2807SJeff Garzik {
1437c6fd2807SJeff Garzik 	const char *emsg = NULL;
1438c6fd2807SJeff Garzik 	int rc;
1439c6fd2807SJeff Garzik 
1440*4447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
14418e16f941STejun Heo 	if (rc == 0)
1442*4447d351STejun Heo 		ahci_power_down(ap);
14438e16f941STejun Heo 	else {
1444c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
1445*4447d351STejun Heo 		ahci_init_port(ap);
1446c6fd2807SJeff Garzik 	}
1447c6fd2807SJeff Garzik 
1448c6fd2807SJeff Garzik 	return rc;
1449c6fd2807SJeff Garzik }
1450c6fd2807SJeff Garzik 
1451c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap)
1452c6fd2807SJeff Garzik {
1453*4447d351STejun Heo 	ahci_power_up(ap);
1454*4447d351STejun Heo 	ahci_init_port(ap);
1455c6fd2807SJeff Garzik 
1456c6fd2807SJeff Garzik 	return 0;
1457c6fd2807SJeff Garzik }
1458c6fd2807SJeff Garzik 
1459c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
1460c6fd2807SJeff Garzik {
1461cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
14620d5ff566STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1463c6fd2807SJeff Garzik 	u32 ctl;
1464c6fd2807SJeff Garzik 
1465c6fd2807SJeff Garzik 	if (mesg.event == PM_EVENT_SUSPEND) {
1466c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
1467c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
1468c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
1469c6fd2807SJeff Garzik 		 */
1470c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
1471c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
1472c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
1473c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
1474c6fd2807SJeff Garzik 	}
1475c6fd2807SJeff Garzik 
1476c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
1477c6fd2807SJeff Garzik }
1478c6fd2807SJeff Garzik 
1479c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
1480c6fd2807SJeff Garzik {
1481cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
1482c6fd2807SJeff Garzik 	int rc;
1483c6fd2807SJeff Garzik 
1484553c4aa6STejun Heo 	rc = ata_pci_device_do_resume(pdev);
1485553c4aa6STejun Heo 	if (rc)
1486553c4aa6STejun Heo 		return rc;
1487c6fd2807SJeff Garzik 
1488c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
1489*4447d351STejun Heo 		rc = ahci_reset_controller(host);
1490c6fd2807SJeff Garzik 		if (rc)
1491c6fd2807SJeff Garzik 			return rc;
1492c6fd2807SJeff Garzik 
1493*4447d351STejun Heo 		ahci_init_controller(host);
1494c6fd2807SJeff Garzik 	}
1495c6fd2807SJeff Garzik 
1496cca3974eSJeff Garzik 	ata_host_resume(host);
1497c6fd2807SJeff Garzik 
1498c6fd2807SJeff Garzik 	return 0;
1499c6fd2807SJeff Garzik }
1500438ac6d5STejun Heo #endif
1501c6fd2807SJeff Garzik 
1502c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
1503c6fd2807SJeff Garzik {
1504cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
1505c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
1506c6fd2807SJeff Garzik 	void *mem;
1507c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
1508c6fd2807SJeff Garzik 	int rc;
1509c6fd2807SJeff Garzik 
151024dc5f33STejun Heo 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
1511c6fd2807SJeff Garzik 	if (!pp)
1512c6fd2807SJeff Garzik 		return -ENOMEM;
1513c6fd2807SJeff Garzik 
1514c6fd2807SJeff Garzik 	rc = ata_pad_alloc(ap, dev);
151524dc5f33STejun Heo 	if (rc)
1516c6fd2807SJeff Garzik 		return rc;
1517c6fd2807SJeff Garzik 
151824dc5f33STejun Heo 	mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
151924dc5f33STejun Heo 				  GFP_KERNEL);
152024dc5f33STejun Heo 	if (!mem)
1521c6fd2807SJeff Garzik 		return -ENOMEM;
1522c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
1523c6fd2807SJeff Garzik 
1524c6fd2807SJeff Garzik 	/*
1525c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
1526c6fd2807SJeff Garzik 	 * 32 bytes each in size
1527c6fd2807SJeff Garzik 	 */
1528c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
1529c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
1530c6fd2807SJeff Garzik 
1531c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
1532c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
1533c6fd2807SJeff Garzik 
1534c6fd2807SJeff Garzik 	/*
1535c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
1536c6fd2807SJeff Garzik 	 */
1537c6fd2807SJeff Garzik 	pp->rx_fis = mem;
1538c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
1539c6fd2807SJeff Garzik 
1540c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
1541c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
1542c6fd2807SJeff Garzik 
1543c6fd2807SJeff Garzik 	/*
1544c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
1545c6fd2807SJeff Garzik 	 * and its scatter-gather table
1546c6fd2807SJeff Garzik 	 */
1547c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
1548c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
1549c6fd2807SJeff Garzik 
1550c6fd2807SJeff Garzik 	ap->private_data = pp;
1551c6fd2807SJeff Garzik 
15528e16f941STejun Heo 	/* power up port */
1553*4447d351STejun Heo 	ahci_power_up(ap);
15548e16f941STejun Heo 
1555c6fd2807SJeff Garzik 	/* initialize port */
1556*4447d351STejun Heo 	ahci_init_port(ap);
1557c6fd2807SJeff Garzik 
1558c6fd2807SJeff Garzik 	return 0;
1559c6fd2807SJeff Garzik }
1560c6fd2807SJeff Garzik 
1561c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
1562c6fd2807SJeff Garzik {
1563c6fd2807SJeff Garzik 	const char *emsg = NULL;
1564c6fd2807SJeff Garzik 	int rc;
1565c6fd2807SJeff Garzik 
1566c6fd2807SJeff Garzik 	/* de-initialize port */
1567*4447d351STejun Heo 	rc = ahci_deinit_port(ap, &emsg);
1568c6fd2807SJeff Garzik 	if (rc)
1569c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
1570c6fd2807SJeff Garzik }
1571c6fd2807SJeff Garzik 
1572*4447d351STejun Heo static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
1573c6fd2807SJeff Garzik {
1574c6fd2807SJeff Garzik 	int rc;
1575c6fd2807SJeff Garzik 
1576c6fd2807SJeff Garzik 	if (using_dac &&
1577c6fd2807SJeff Garzik 	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
1578c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
1579c6fd2807SJeff Garzik 		if (rc) {
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 					   "64-bit DMA enable failed\n");
1584c6fd2807SJeff Garzik 				return rc;
1585c6fd2807SJeff Garzik 			}
1586c6fd2807SJeff Garzik 		}
1587c6fd2807SJeff Garzik 	} else {
1588c6fd2807SJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
1589c6fd2807SJeff Garzik 		if (rc) {
1590c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1591c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
1592c6fd2807SJeff Garzik 			return rc;
1593c6fd2807SJeff Garzik 		}
1594c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1595c6fd2807SJeff Garzik 		if (rc) {
1596c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1597c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
1598c6fd2807SJeff Garzik 			return rc;
1599c6fd2807SJeff Garzik 		}
1600c6fd2807SJeff Garzik 	}
1601c6fd2807SJeff Garzik 	return 0;
1602c6fd2807SJeff Garzik }
1603c6fd2807SJeff Garzik 
1604*4447d351STejun Heo static void ahci_print_info(struct ata_host *host)
1605c6fd2807SJeff Garzik {
1606*4447d351STejun Heo 	struct ahci_host_priv *hpriv = host->private_data;
1607*4447d351STejun Heo 	struct pci_dev *pdev = to_pci_dev(host->dev);
1608*4447d351STejun Heo 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
1609c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
1610c6fd2807SJeff Garzik 	const char *speed_s;
1611c6fd2807SJeff Garzik 	u16 cc;
1612c6fd2807SJeff Garzik 	const char *scc_s;
1613c6fd2807SJeff Garzik 
1614c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
1615c6fd2807SJeff Garzik 	cap = hpriv->cap;
1616c6fd2807SJeff Garzik 	impl = hpriv->port_map;
1617c6fd2807SJeff Garzik 
1618c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
1619c6fd2807SJeff Garzik 	if (speed == 1)
1620c6fd2807SJeff Garzik 		speed_s = "1.5";
1621c6fd2807SJeff Garzik 	else if (speed == 2)
1622c6fd2807SJeff Garzik 		speed_s = "3";
1623c6fd2807SJeff Garzik 	else
1624c6fd2807SJeff Garzik 		speed_s = "?";
1625c6fd2807SJeff Garzik 
1626c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
1627c9f89475SConke Hu 	if (cc == PCI_CLASS_STORAGE_IDE)
1628c6fd2807SJeff Garzik 		scc_s = "IDE";
1629c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_SATA)
1630c6fd2807SJeff Garzik 		scc_s = "SATA";
1631c9f89475SConke Hu 	else if (cc == PCI_CLASS_STORAGE_RAID)
1632c6fd2807SJeff Garzik 		scc_s = "RAID";
1633c6fd2807SJeff Garzik 	else
1634c6fd2807SJeff Garzik 		scc_s = "unknown";
1635c6fd2807SJeff Garzik 
1636c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
1637c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
1638c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
1639c6fd2807SJeff Garzik 	       	,
1640c6fd2807SJeff Garzik 
1641c6fd2807SJeff Garzik 	       	(vers >> 24) & 0xff,
1642c6fd2807SJeff Garzik 	       	(vers >> 16) & 0xff,
1643c6fd2807SJeff Garzik 	       	(vers >> 8) & 0xff,
1644c6fd2807SJeff Garzik 	       	vers & 0xff,
1645c6fd2807SJeff Garzik 
1646c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
1647c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
1648c6fd2807SJeff Garzik 		speed_s,
1649c6fd2807SJeff Garzik 		impl,
1650c6fd2807SJeff Garzik 		scc_s);
1651c6fd2807SJeff Garzik 
1652c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
1653c6fd2807SJeff Garzik 		"flags: "
1654c6fd2807SJeff Garzik 	       	"%s%s%s%s%s%s"
1655c6fd2807SJeff Garzik 	       	"%s%s%s%s%s%s%s\n"
1656c6fd2807SJeff Garzik 	       	,
1657c6fd2807SJeff Garzik 
1658c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
1659c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
1660c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
1661c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
1662c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
1663c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
1664c6fd2807SJeff Garzik 
1665c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
1666c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
1667c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
1668c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
1669c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
1670c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
1671c6fd2807SJeff Garzik 		cap & (1 << 13) ? "part " : ""
1672c6fd2807SJeff Garzik 		);
1673c6fd2807SJeff Garzik }
1674c6fd2807SJeff Garzik 
1675c6fd2807SJeff Garzik static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1676c6fd2807SJeff Garzik {
1677c6fd2807SJeff Garzik 	static int printed_version;
1678*4447d351STejun Heo 	struct ata_port_info pi = ahci_port_info[ent->driver_data];
1679*4447d351STejun Heo 	const struct ata_port_info *ppi[] = { &pi, NULL };
168024dc5f33STejun Heo 	struct device *dev = &pdev->dev;
1681c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1682*4447d351STejun Heo 	struct ata_host *host;
1683*4447d351STejun Heo 	int i, rc;
1684c6fd2807SJeff Garzik 
1685c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1686c6fd2807SJeff Garzik 
1687c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
1688c6fd2807SJeff Garzik 
1689c6fd2807SJeff Garzik 	if (!printed_version++)
1690c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
1691c6fd2807SJeff Garzik 
1692*4447d351STejun Heo 	/* acquire resources */
169324dc5f33STejun Heo 	rc = pcim_enable_device(pdev);
1694c6fd2807SJeff Garzik 	if (rc)
1695c6fd2807SJeff Garzik 		return rc;
1696c6fd2807SJeff Garzik 
16970d5ff566STejun Heo 	rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
16980d5ff566STejun Heo 	if (rc == -EBUSY)
169924dc5f33STejun Heo 		pcim_pin_device(pdev);
17000d5ff566STejun Heo 	if (rc)
170124dc5f33STejun Heo 		return rc;
1702c6fd2807SJeff Garzik 
170324dc5f33STejun Heo 	if (pci_enable_msi(pdev))
1704c6fd2807SJeff Garzik 		pci_intx(pdev, 1);
1705c6fd2807SJeff Garzik 
170624dc5f33STejun Heo 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
170724dc5f33STejun Heo 	if (!hpriv)
170824dc5f33STejun Heo 		return -ENOMEM;
1709c6fd2807SJeff Garzik 
1710*4447d351STejun Heo 	/* save initial config */
1711*4447d351STejun Heo 	ahci_save_initial_config(pdev, &pi, hpriv);
1712c6fd2807SJeff Garzik 
1713*4447d351STejun Heo 	/* prepare host */
1714*4447d351STejun Heo 	if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
1715*4447d351STejun Heo 		pi.flags |= ATA_FLAG_NCQ;
1716*4447d351STejun Heo 
1717*4447d351STejun Heo 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
1718*4447d351STejun Heo 	if (!host)
1719*4447d351STejun Heo 		return -ENOMEM;
1720*4447d351STejun Heo 	host->iomap = pcim_iomap_table(pdev);
1721*4447d351STejun Heo 	host->private_data = hpriv;
1722*4447d351STejun Heo 
1723*4447d351STejun Heo 	for (i = 0; i < host->n_ports; i++) {
1724*4447d351STejun Heo 		if (hpriv->port_map & (1 << i)) {
1725*4447d351STejun Heo 			struct ata_port *ap = host->ports[i];
1726*4447d351STejun Heo 			void __iomem *port_mmio = ahci_port_base(ap);
1727*4447d351STejun Heo 
1728*4447d351STejun Heo 			ap->ioaddr.cmd_addr = port_mmio;
1729*4447d351STejun Heo 			ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
1730*4447d351STejun Heo 		} else
1731*4447d351STejun Heo 			host->ports[i]->ops = &ata_dummy_port_ops;
1732*4447d351STejun Heo 	}
1733c6fd2807SJeff Garzik 
1734c6fd2807SJeff Garzik 	/* initialize adapter */
1735*4447d351STejun Heo 	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
1736c6fd2807SJeff Garzik 	if (rc)
173724dc5f33STejun Heo 		return rc;
1738c6fd2807SJeff Garzik 
1739*4447d351STejun Heo 	rc = ahci_reset_controller(host);
1740*4447d351STejun Heo 	if (rc)
1741*4447d351STejun Heo 		return rc;
1742c6fd2807SJeff Garzik 
1743*4447d351STejun Heo 	ahci_init_controller(host);
1744*4447d351STejun Heo 	ahci_print_info(host);
1745c6fd2807SJeff Garzik 
1746*4447d351STejun Heo 	pci_set_master(pdev);
1747*4447d351STejun Heo 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
1748*4447d351STejun Heo 				 &ahci_sht);
1749c6fd2807SJeff Garzik }
1750c6fd2807SJeff Garzik 
1751c6fd2807SJeff Garzik static int __init ahci_init(void)
1752c6fd2807SJeff Garzik {
1753c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
1754c6fd2807SJeff Garzik }
1755c6fd2807SJeff Garzik 
1756c6fd2807SJeff Garzik static void __exit ahci_exit(void)
1757c6fd2807SJeff Garzik {
1758c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
1759c6fd2807SJeff Garzik }
1760c6fd2807SJeff Garzik 
1761c6fd2807SJeff Garzik 
1762c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
1763c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
1764c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
1765c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
1766c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
1767c6fd2807SJeff Garzik 
1768c6fd2807SJeff Garzik module_init(ahci_init);
1769c6fd2807SJeff Garzik module_exit(ahci_exit);
1770