xref: /openbmc/linux/drivers/ata/ahci.c (revision 41669553353554211310cdb23079d58af1fda41e)
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,
56c6fd2807SJeff Garzik 	AHCI_MAX_SG		= 168, /* hardware max is 64K */
57c6fd2807SJeff Garzik 	AHCI_DMA_BOUNDARY	= 0xffffffff,
58c6fd2807SJeff Garzik 	AHCI_USE_CLUSTERING	= 0,
59c6fd2807SJeff Garzik 	AHCI_MAX_CMDS		= 32,
60c6fd2807SJeff Garzik 	AHCI_CMD_SZ		= 32,
61c6fd2807SJeff Garzik 	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
62c6fd2807SJeff Garzik 	AHCI_RX_FIS_SZ		= 256,
63c6fd2807SJeff Garzik 	AHCI_CMD_TBL_CDB	= 0x40,
64c6fd2807SJeff Garzik 	AHCI_CMD_TBL_HDR_SZ	= 0x80,
65c6fd2807SJeff Garzik 	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
66c6fd2807SJeff Garzik 	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
67c6fd2807SJeff Garzik 	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
68c6fd2807SJeff Garzik 				  AHCI_RX_FIS_SZ,
69c6fd2807SJeff Garzik 	AHCI_IRQ_ON_SG		= (1 << 31),
70c6fd2807SJeff Garzik 	AHCI_CMD_ATAPI		= (1 << 5),
71c6fd2807SJeff Garzik 	AHCI_CMD_WRITE		= (1 << 6),
72c6fd2807SJeff Garzik 	AHCI_CMD_PREFETCH	= (1 << 7),
73c6fd2807SJeff Garzik 	AHCI_CMD_RESET		= (1 << 8),
74c6fd2807SJeff Garzik 	AHCI_CMD_CLR_BUSY	= (1 << 10),
75c6fd2807SJeff Garzik 
76c6fd2807SJeff Garzik 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
77c6fd2807SJeff Garzik 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
78c6fd2807SJeff Garzik 
79c6fd2807SJeff Garzik 	board_ahci		= 0,
80c6fd2807SJeff Garzik 	board_ahci_vt8251	= 1,
81*41669553STejun Heo 	board_ahci_ign_iferr	= 2,
82c6fd2807SJeff Garzik 
83c6fd2807SJeff Garzik 	/* global controller registers */
84c6fd2807SJeff Garzik 	HOST_CAP		= 0x00, /* host capabilities */
85c6fd2807SJeff Garzik 	HOST_CTL		= 0x04, /* global host control */
86c6fd2807SJeff Garzik 	HOST_IRQ_STAT		= 0x08, /* interrupt status */
87c6fd2807SJeff Garzik 	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
88c6fd2807SJeff Garzik 	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
89c6fd2807SJeff Garzik 
90c6fd2807SJeff Garzik 	/* HOST_CTL bits */
91c6fd2807SJeff Garzik 	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
92c6fd2807SJeff Garzik 	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
93c6fd2807SJeff Garzik 	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
94c6fd2807SJeff Garzik 
95c6fd2807SJeff Garzik 	/* HOST_CAP bits */
96c6fd2807SJeff Garzik 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
97c6fd2807SJeff Garzik 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
98c6fd2807SJeff Garzik 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
99c6fd2807SJeff Garzik 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
100c6fd2807SJeff Garzik 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
101c6fd2807SJeff Garzik 
102c6fd2807SJeff Garzik 	/* registers for each SATA port */
103c6fd2807SJeff Garzik 	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
104c6fd2807SJeff Garzik 	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
105c6fd2807SJeff Garzik 	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
106c6fd2807SJeff Garzik 	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
107c6fd2807SJeff Garzik 	PORT_IRQ_STAT		= 0x10, /* interrupt status */
108c6fd2807SJeff Garzik 	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
109c6fd2807SJeff Garzik 	PORT_CMD		= 0x18, /* port command */
110c6fd2807SJeff Garzik 	PORT_TFDATA		= 0x20,	/* taskfile data */
111c6fd2807SJeff Garzik 	PORT_SIG		= 0x24,	/* device TF signature */
112c6fd2807SJeff Garzik 	PORT_CMD_ISSUE		= 0x38, /* command issue */
113c6fd2807SJeff Garzik 	PORT_SCR		= 0x28, /* SATA phy register block */
114c6fd2807SJeff Garzik 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
115c6fd2807SJeff Garzik 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
116c6fd2807SJeff Garzik 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
117c6fd2807SJeff Garzik 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
118c6fd2807SJeff Garzik 
119c6fd2807SJeff Garzik 	/* PORT_IRQ_{STAT,MASK} bits */
120c6fd2807SJeff Garzik 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
121c6fd2807SJeff Garzik 	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
122c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
123c6fd2807SJeff Garzik 	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
124c6fd2807SJeff Garzik 	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
125c6fd2807SJeff Garzik 	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
126c6fd2807SJeff Garzik 	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
127c6fd2807SJeff Garzik 	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
128c6fd2807SJeff Garzik 
129c6fd2807SJeff Garzik 	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
130c6fd2807SJeff Garzik 	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
131c6fd2807SJeff Garzik 	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
132c6fd2807SJeff Garzik 	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
133c6fd2807SJeff Garzik 	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
134c6fd2807SJeff Garzik 	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
135c6fd2807SJeff Garzik 	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
136c6fd2807SJeff Garzik 	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
137c6fd2807SJeff Garzik 	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
138c6fd2807SJeff Garzik 
139c6fd2807SJeff Garzik 	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
140c6fd2807SJeff Garzik 				  PORT_IRQ_IF_ERR |
141c6fd2807SJeff Garzik 				  PORT_IRQ_CONNECT |
142c6fd2807SJeff Garzik 				  PORT_IRQ_PHYRDY |
143c6fd2807SJeff Garzik 				  PORT_IRQ_UNK_FIS,
144c6fd2807SJeff Garzik 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
145c6fd2807SJeff Garzik 				  PORT_IRQ_TF_ERR |
146c6fd2807SJeff Garzik 				  PORT_IRQ_HBUS_DATA_ERR,
147c6fd2807SJeff Garzik 	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
148c6fd2807SJeff Garzik 				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
149c6fd2807SJeff Garzik 				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
150c6fd2807SJeff Garzik 
151c6fd2807SJeff Garzik 	/* PORT_CMD bits */
152c6fd2807SJeff Garzik 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
153c6fd2807SJeff Garzik 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
154c6fd2807SJeff Garzik 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
155c6fd2807SJeff Garzik 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
156c6fd2807SJeff Garzik 	PORT_CMD_CLO		= (1 << 3), /* Command list override */
157c6fd2807SJeff Garzik 	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
158c6fd2807SJeff Garzik 	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
159c6fd2807SJeff Garzik 	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
160c6fd2807SJeff Garzik 
161c6fd2807SJeff Garzik 	PORT_CMD_ICC_MASK	= (0xf << 28), /* i/f ICC state mask */
162c6fd2807SJeff Garzik 	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
163c6fd2807SJeff Garzik 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
164c6fd2807SJeff Garzik 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
165c6fd2807SJeff Garzik 
166c6fd2807SJeff Garzik 	/* hpriv->flags bits */
167c6fd2807SJeff Garzik 	AHCI_FLAG_MSI		= (1 << 0),
168c6fd2807SJeff Garzik 
169c6fd2807SJeff Garzik 	/* ap->flags bits */
170c6fd2807SJeff Garzik 	AHCI_FLAG_RESET_NEEDS_CLO	= (1 << 24),
171c6fd2807SJeff Garzik 	AHCI_FLAG_NO_NCQ		= (1 << 25),
172*41669553STejun Heo 	AHCI_FLAG_IGN_IRQ_IF_ERR	= (1 << 26), /* ignore IRQ_IF_ERR */
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 {
191c6fd2807SJeff Garzik 	unsigned long		flags;
192c6fd2807SJeff Garzik 	u32			cap;	/* cache of HOST_CAP register */
193c6fd2807SJeff Garzik 	u32			port_map; /* cache of HOST_PORTS_IMPL reg */
194c6fd2807SJeff Garzik };
195c6fd2807SJeff Garzik 
196c6fd2807SJeff Garzik struct ahci_port_priv {
197c6fd2807SJeff Garzik 	struct ahci_cmd_hdr	*cmd_slot;
198c6fd2807SJeff Garzik 	dma_addr_t		cmd_slot_dma;
199c6fd2807SJeff Garzik 	void			*cmd_tbl;
200c6fd2807SJeff Garzik 	dma_addr_t		cmd_tbl_dma;
201c6fd2807SJeff Garzik 	void			*rx_fis;
202c6fd2807SJeff Garzik 	dma_addr_t		rx_fis_dma;
203c6fd2807SJeff Garzik };
204c6fd2807SJeff Garzik 
205c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
206c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
207c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
208c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
2097d12e780SDavid Howells static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
210c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap);
211c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap);
212c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap);
213c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
214c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc);
215c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap);
216c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap);
217c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap);
218c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap);
219c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
220c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
221c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap);
222c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
223c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev);
224c6fd2807SJeff Garzik static void ahci_remove_one (struct pci_dev *pdev);
225c6fd2807SJeff Garzik 
226c6fd2807SJeff Garzik static struct scsi_host_template ahci_sht = {
227c6fd2807SJeff Garzik 	.module			= THIS_MODULE,
228c6fd2807SJeff Garzik 	.name			= DRV_NAME,
229c6fd2807SJeff Garzik 	.ioctl			= ata_scsi_ioctl,
230c6fd2807SJeff Garzik 	.queuecommand		= ata_scsi_queuecmd,
231c6fd2807SJeff Garzik 	.change_queue_depth	= ata_scsi_change_queue_depth,
232c6fd2807SJeff Garzik 	.can_queue		= AHCI_MAX_CMDS - 1,
233c6fd2807SJeff Garzik 	.this_id		= ATA_SHT_THIS_ID,
234c6fd2807SJeff Garzik 	.sg_tablesize		= AHCI_MAX_SG,
235c6fd2807SJeff Garzik 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
236c6fd2807SJeff Garzik 	.emulated		= ATA_SHT_EMULATED,
237c6fd2807SJeff Garzik 	.use_clustering		= AHCI_USE_CLUSTERING,
238c6fd2807SJeff Garzik 	.proc_name		= DRV_NAME,
239c6fd2807SJeff Garzik 	.dma_boundary		= AHCI_DMA_BOUNDARY,
240c6fd2807SJeff Garzik 	.slave_configure	= ata_scsi_slave_config,
241c6fd2807SJeff Garzik 	.slave_destroy		= ata_scsi_slave_destroy,
242c6fd2807SJeff Garzik 	.bios_param		= ata_std_bios_param,
243c6fd2807SJeff Garzik 	.suspend		= ata_scsi_device_suspend,
244c6fd2807SJeff Garzik 	.resume			= ata_scsi_device_resume,
245c6fd2807SJeff Garzik };
246c6fd2807SJeff Garzik 
247c6fd2807SJeff Garzik static const struct ata_port_operations ahci_ops = {
248c6fd2807SJeff Garzik 	.port_disable		= ata_port_disable,
249c6fd2807SJeff Garzik 
250c6fd2807SJeff Garzik 	.check_status		= ahci_check_status,
251c6fd2807SJeff Garzik 	.check_altstatus	= ahci_check_status,
252c6fd2807SJeff Garzik 	.dev_select		= ata_noop_dev_select,
253c6fd2807SJeff Garzik 
254c6fd2807SJeff Garzik 	.tf_read		= ahci_tf_read,
255c6fd2807SJeff Garzik 
256c6fd2807SJeff Garzik 	.qc_prep		= ahci_qc_prep,
257c6fd2807SJeff Garzik 	.qc_issue		= ahci_qc_issue,
258c6fd2807SJeff Garzik 
259c6fd2807SJeff Garzik 	.irq_handler		= ahci_interrupt,
260c6fd2807SJeff Garzik 	.irq_clear		= ahci_irq_clear,
261c6fd2807SJeff Garzik 
262c6fd2807SJeff Garzik 	.scr_read		= ahci_scr_read,
263c6fd2807SJeff Garzik 	.scr_write		= ahci_scr_write,
264c6fd2807SJeff Garzik 
265c6fd2807SJeff Garzik 	.freeze			= ahci_freeze,
266c6fd2807SJeff Garzik 	.thaw			= ahci_thaw,
267c6fd2807SJeff Garzik 
268c6fd2807SJeff Garzik 	.error_handler		= ahci_error_handler,
269c6fd2807SJeff Garzik 	.post_internal_cmd	= ahci_post_internal_cmd,
270c6fd2807SJeff Garzik 
271c6fd2807SJeff Garzik 	.port_suspend		= ahci_port_suspend,
272c6fd2807SJeff Garzik 	.port_resume		= ahci_port_resume,
273c6fd2807SJeff Garzik 
274c6fd2807SJeff Garzik 	.port_start		= ahci_port_start,
275c6fd2807SJeff Garzik 	.port_stop		= ahci_port_stop,
276c6fd2807SJeff Garzik };
277c6fd2807SJeff Garzik 
278c6fd2807SJeff Garzik static const struct ata_port_info ahci_port_info[] = {
279c6fd2807SJeff Garzik 	/* board_ahci */
280c6fd2807SJeff Garzik 	{
281c6fd2807SJeff Garzik 		.sht		= &ahci_sht,
282cca3974eSJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
283c6fd2807SJeff Garzik 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
284c6fd2807SJeff Garzik 				  ATA_FLAG_SKIP_D2H_BSY,
285c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
286c6fd2807SJeff Garzik 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
287c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
288c6fd2807SJeff Garzik 	},
289c6fd2807SJeff Garzik 	/* board_ahci_vt8251 */
290c6fd2807SJeff Garzik 	{
291c6fd2807SJeff Garzik 		.sht		= &ahci_sht,
292cca3974eSJeff Garzik 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
293c6fd2807SJeff Garzik 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
294c6fd2807SJeff Garzik 				  ATA_FLAG_SKIP_D2H_BSY |
295c6fd2807SJeff Garzik 				  AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ,
296c6fd2807SJeff Garzik 		.pio_mask	= 0x1f, /* pio0-4 */
297c6fd2807SJeff Garzik 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
298c6fd2807SJeff Garzik 		.port_ops	= &ahci_ops,
299c6fd2807SJeff Garzik 	},
300*41669553STejun Heo 	/* board_ahci_ign_iferr */
301*41669553STejun Heo 	{
302*41669553STejun Heo 		.sht		= &ahci_sht,
303*41669553STejun Heo 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
304*41669553STejun Heo 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
305*41669553STejun Heo 				  ATA_FLAG_SKIP_D2H_BSY |
306*41669553STejun Heo 				  AHCI_FLAG_IGN_IRQ_IF_ERR,
307*41669553STejun Heo 		.pio_mask	= 0x1f, /* pio0-4 */
308*41669553STejun Heo 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
309*41669553STejun Heo 		.port_ops	= &ahci_ops,
310*41669553STejun Heo 	},
311c6fd2807SJeff Garzik };
312c6fd2807SJeff Garzik 
313c6fd2807SJeff Garzik static const struct pci_device_id ahci_pci_tbl[] = {
314c6fd2807SJeff Garzik 	/* Intel */
31554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
31654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
31754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
31854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
31954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
32054bb3a94SJeff Garzik 	{ PCI_VDEVICE(AL, 0x5288), board_ahci }, /* ULi M5288 */
32154bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
32254bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
32354bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
32454bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
32554bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
32654bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
32754bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
32854bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
32954bb3a94SJeff Garzik 	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
330f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
331f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
332f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
333f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
334f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
335f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
336f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
337f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
338f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
339f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
340f33d625fSJason Gaston 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
341c6fd2807SJeff Garzik 
342c6fd2807SJeff Garzik 	/* JMicron */
343*41669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2360), board_ahci_ign_iferr }, /* JMB360 */
344*41669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2361), board_ahci_ign_iferr }, /* JMB361 */
345*41669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2363), board_ahci_ign_iferr }, /* JMB363 */
346*41669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2365), board_ahci_ign_iferr }, /* JMB365 */
347*41669553STejun Heo 	{ PCI_VDEVICE(JMICRON, 0x2366), board_ahci_ign_iferr }, /* JMB366 */
348c6fd2807SJeff Garzik 
349c6fd2807SJeff Garzik 	/* ATI */
35054bb3a94SJeff Garzik 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
35154bb3a94SJeff Garzik 	{ PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
352c6fd2807SJeff Garzik 
353c6fd2807SJeff Garzik 	/* VIA */
35454bb3a94SJeff Garzik 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
355c6fd2807SJeff Garzik 
356c6fd2807SJeff Garzik 	/* NVIDIA */
35754bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },		/* MCP65 */
35854bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci },		/* MCP65 */
35954bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci },		/* MCP65 */
36054bb3a94SJeff Garzik 	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci },		/* MCP65 */
361895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0554), board_ahci },		/* MCP67 */
362895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0555), board_ahci },		/* MCP67 */
363895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0556), board_ahci },		/* MCP67 */
364895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0557), board_ahci },		/* MCP67 */
365895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0558), board_ahci },		/* MCP67 */
366895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci },		/* MCP67 */
367895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci },		/* MCP67 */
368895663cdSPeer Chen 	{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci },		/* MCP67 */
369c6fd2807SJeff Garzik 
370c6fd2807SJeff Garzik 	/* SiS */
37154bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
37254bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
37354bb3a94SJeff Garzik 	{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
374c6fd2807SJeff Garzik 
375c6fd2807SJeff Garzik 	{ }	/* terminate list */
376c6fd2807SJeff Garzik };
377c6fd2807SJeff Garzik 
378c6fd2807SJeff Garzik 
379c6fd2807SJeff Garzik static struct pci_driver ahci_pci_driver = {
380c6fd2807SJeff Garzik 	.name			= DRV_NAME,
381c6fd2807SJeff Garzik 	.id_table		= ahci_pci_tbl,
382c6fd2807SJeff Garzik 	.probe			= ahci_init_one,
383c6fd2807SJeff Garzik 	.suspend		= ahci_pci_device_suspend,
384c6fd2807SJeff Garzik 	.resume			= ahci_pci_device_resume,
385c6fd2807SJeff Garzik 	.remove			= ahci_remove_one,
386c6fd2807SJeff Garzik };
387c6fd2807SJeff Garzik 
388c6fd2807SJeff Garzik 
389c6fd2807SJeff Garzik static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
390c6fd2807SJeff Garzik {
391c6fd2807SJeff Garzik 	return base + 0x100 + (port * 0x80);
392c6fd2807SJeff Garzik }
393c6fd2807SJeff Garzik 
394c6fd2807SJeff Garzik static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
395c6fd2807SJeff Garzik {
396c6fd2807SJeff Garzik 	return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
397c6fd2807SJeff Garzik }
398c6fd2807SJeff Garzik 
399c6fd2807SJeff Garzik static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
400c6fd2807SJeff Garzik {
401c6fd2807SJeff Garzik 	unsigned int sc_reg;
402c6fd2807SJeff Garzik 
403c6fd2807SJeff Garzik 	switch (sc_reg_in) {
404c6fd2807SJeff Garzik 	case SCR_STATUS:	sc_reg = 0; break;
405c6fd2807SJeff Garzik 	case SCR_CONTROL:	sc_reg = 1; break;
406c6fd2807SJeff Garzik 	case SCR_ERROR:		sc_reg = 2; break;
407c6fd2807SJeff Garzik 	case SCR_ACTIVE:	sc_reg = 3; break;
408c6fd2807SJeff Garzik 	default:
409c6fd2807SJeff Garzik 		return 0xffffffffU;
410c6fd2807SJeff Garzik 	}
411c6fd2807SJeff Garzik 
412c6fd2807SJeff Garzik 	return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
413c6fd2807SJeff Garzik }
414c6fd2807SJeff Garzik 
415c6fd2807SJeff Garzik 
416c6fd2807SJeff Garzik static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
417c6fd2807SJeff Garzik 			       u32 val)
418c6fd2807SJeff Garzik {
419c6fd2807SJeff Garzik 	unsigned int sc_reg;
420c6fd2807SJeff Garzik 
421c6fd2807SJeff Garzik 	switch (sc_reg_in) {
422c6fd2807SJeff Garzik 	case SCR_STATUS:	sc_reg = 0; break;
423c6fd2807SJeff Garzik 	case SCR_CONTROL:	sc_reg = 1; break;
424c6fd2807SJeff Garzik 	case SCR_ERROR:		sc_reg = 2; break;
425c6fd2807SJeff Garzik 	case SCR_ACTIVE:	sc_reg = 3; break;
426c6fd2807SJeff Garzik 	default:
427c6fd2807SJeff Garzik 		return;
428c6fd2807SJeff Garzik 	}
429c6fd2807SJeff Garzik 
430c6fd2807SJeff Garzik 	writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
431c6fd2807SJeff Garzik }
432c6fd2807SJeff Garzik 
433c6fd2807SJeff Garzik static void ahci_start_engine(void __iomem *port_mmio)
434c6fd2807SJeff Garzik {
435c6fd2807SJeff Garzik 	u32 tmp;
436c6fd2807SJeff Garzik 
437c6fd2807SJeff Garzik 	/* start DMA */
438c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
439c6fd2807SJeff Garzik 	tmp |= PORT_CMD_START;
440c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
441c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD); /* flush */
442c6fd2807SJeff Garzik }
443c6fd2807SJeff Garzik 
444c6fd2807SJeff Garzik static int ahci_stop_engine(void __iomem *port_mmio)
445c6fd2807SJeff Garzik {
446c6fd2807SJeff Garzik 	u32 tmp;
447c6fd2807SJeff Garzik 
448c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
449c6fd2807SJeff Garzik 
450c6fd2807SJeff Garzik 	/* check if the HBA is idle */
451c6fd2807SJeff Garzik 	if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
452c6fd2807SJeff Garzik 		return 0;
453c6fd2807SJeff Garzik 
454c6fd2807SJeff Garzik 	/* setting HBA to idle */
455c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_START;
456c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
457c6fd2807SJeff Garzik 
458c6fd2807SJeff Garzik 	/* wait for engine to stop. This could be as long as 500 msec */
459c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
460c6fd2807SJeff Garzik 			        PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
461c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_LIST_ON)
462c6fd2807SJeff Garzik 		return -EIO;
463c6fd2807SJeff Garzik 
464c6fd2807SJeff Garzik 	return 0;
465c6fd2807SJeff Garzik }
466c6fd2807SJeff Garzik 
467c6fd2807SJeff Garzik static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
468c6fd2807SJeff Garzik 			      dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
469c6fd2807SJeff Garzik {
470c6fd2807SJeff Garzik 	u32 tmp;
471c6fd2807SJeff Garzik 
472c6fd2807SJeff Garzik 	/* set FIS registers */
473c6fd2807SJeff Garzik 	if (cap & HOST_CAP_64)
474c6fd2807SJeff Garzik 		writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
475c6fd2807SJeff Garzik 	writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
476c6fd2807SJeff Garzik 
477c6fd2807SJeff Garzik 	if (cap & HOST_CAP_64)
478c6fd2807SJeff Garzik 		writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
479c6fd2807SJeff Garzik 	writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
480c6fd2807SJeff Garzik 
481c6fd2807SJeff Garzik 	/* enable FIS reception */
482c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
483c6fd2807SJeff Garzik 	tmp |= PORT_CMD_FIS_RX;
484c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
485c6fd2807SJeff Garzik 
486c6fd2807SJeff Garzik 	/* flush */
487c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD);
488c6fd2807SJeff Garzik }
489c6fd2807SJeff Garzik 
490c6fd2807SJeff Garzik static int ahci_stop_fis_rx(void __iomem *port_mmio)
491c6fd2807SJeff Garzik {
492c6fd2807SJeff Garzik 	u32 tmp;
493c6fd2807SJeff Garzik 
494c6fd2807SJeff Garzik 	/* disable FIS reception */
495c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
496c6fd2807SJeff Garzik 	tmp &= ~PORT_CMD_FIS_RX;
497c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
498c6fd2807SJeff Garzik 
499c6fd2807SJeff Garzik 	/* wait for completion, spec says 500ms, give it 1000 */
500c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
501c6fd2807SJeff Garzik 				PORT_CMD_FIS_ON, 10, 1000);
502c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_FIS_ON)
503c6fd2807SJeff Garzik 		return -EBUSY;
504c6fd2807SJeff Garzik 
505c6fd2807SJeff Garzik 	return 0;
506c6fd2807SJeff Garzik }
507c6fd2807SJeff Garzik 
508c6fd2807SJeff Garzik static void ahci_power_up(void __iomem *port_mmio, u32 cap)
509c6fd2807SJeff Garzik {
510c6fd2807SJeff Garzik 	u32 cmd;
511c6fd2807SJeff Garzik 
512c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
513c6fd2807SJeff Garzik 
514c6fd2807SJeff Garzik 	/* spin up device */
515c6fd2807SJeff Garzik 	if (cap & HOST_CAP_SSS) {
516c6fd2807SJeff Garzik 		cmd |= PORT_CMD_SPIN_UP;
517c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
518c6fd2807SJeff Garzik 	}
519c6fd2807SJeff Garzik 
520c6fd2807SJeff Garzik 	/* wake up link */
521c6fd2807SJeff Garzik 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
522c6fd2807SJeff Garzik }
523c6fd2807SJeff Garzik 
524c6fd2807SJeff Garzik static void ahci_power_down(void __iomem *port_mmio, u32 cap)
525c6fd2807SJeff Garzik {
526c6fd2807SJeff Garzik 	u32 cmd, scontrol;
527c6fd2807SJeff Garzik 
528c6fd2807SJeff Garzik 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
529c6fd2807SJeff Garzik 
530c6fd2807SJeff Garzik 	if (cap & HOST_CAP_SSC) {
531c6fd2807SJeff Garzik 		/* enable transitions to slumber mode */
532c6fd2807SJeff Garzik 		scontrol = readl(port_mmio + PORT_SCR_CTL);
533c6fd2807SJeff Garzik 		if ((scontrol & 0x0f00) > 0x100) {
534c6fd2807SJeff Garzik 			scontrol &= ~0xf00;
535c6fd2807SJeff Garzik 			writel(scontrol, port_mmio + PORT_SCR_CTL);
536c6fd2807SJeff Garzik 		}
537c6fd2807SJeff Garzik 
538c6fd2807SJeff Garzik 		/* put device into slumber mode */
539c6fd2807SJeff Garzik 		writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
540c6fd2807SJeff Garzik 
541c6fd2807SJeff Garzik 		/* wait for the transition to complete */
542c6fd2807SJeff Garzik 		ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
543c6fd2807SJeff Garzik 				  PORT_CMD_ICC_SLUMBER, 1, 50);
544c6fd2807SJeff Garzik 	}
545c6fd2807SJeff Garzik 
546c6fd2807SJeff Garzik 	/* put device into listen mode */
547c6fd2807SJeff Garzik 	if (cap & HOST_CAP_SSS) {
548c6fd2807SJeff Garzik 		/* first set PxSCTL.DET to 0 */
549c6fd2807SJeff Garzik 		scontrol = readl(port_mmio + PORT_SCR_CTL);
550c6fd2807SJeff Garzik 		scontrol &= ~0xf;
551c6fd2807SJeff Garzik 		writel(scontrol, port_mmio + PORT_SCR_CTL);
552c6fd2807SJeff Garzik 
553c6fd2807SJeff Garzik 		/* then set PxCMD.SUD to 0 */
554c6fd2807SJeff Garzik 		cmd &= ~PORT_CMD_SPIN_UP;
555c6fd2807SJeff Garzik 		writel(cmd, port_mmio + PORT_CMD);
556c6fd2807SJeff Garzik 	}
557c6fd2807SJeff Garzik }
558c6fd2807SJeff Garzik 
559c6fd2807SJeff Garzik static void ahci_init_port(void __iomem *port_mmio, u32 cap,
560c6fd2807SJeff Garzik 			   dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
561c6fd2807SJeff Garzik {
562c6fd2807SJeff Garzik 	/* power up */
563c6fd2807SJeff Garzik 	ahci_power_up(port_mmio, cap);
564c6fd2807SJeff Garzik 
565c6fd2807SJeff Garzik 	/* enable FIS reception */
566c6fd2807SJeff Garzik 	ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
567c6fd2807SJeff Garzik 
568c6fd2807SJeff Garzik 	/* enable DMA */
569c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
570c6fd2807SJeff Garzik }
571c6fd2807SJeff Garzik 
572c6fd2807SJeff Garzik static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
573c6fd2807SJeff Garzik {
574c6fd2807SJeff Garzik 	int rc;
575c6fd2807SJeff Garzik 
576c6fd2807SJeff Garzik 	/* disable DMA */
577c6fd2807SJeff Garzik 	rc = ahci_stop_engine(port_mmio);
578c6fd2807SJeff Garzik 	if (rc) {
579c6fd2807SJeff Garzik 		*emsg = "failed to stop engine";
580c6fd2807SJeff Garzik 		return rc;
581c6fd2807SJeff Garzik 	}
582c6fd2807SJeff Garzik 
583c6fd2807SJeff Garzik 	/* disable FIS reception */
584c6fd2807SJeff Garzik 	rc = ahci_stop_fis_rx(port_mmio);
585c6fd2807SJeff Garzik 	if (rc) {
586c6fd2807SJeff Garzik 		*emsg = "failed stop FIS RX";
587c6fd2807SJeff Garzik 		return rc;
588c6fd2807SJeff Garzik 	}
589c6fd2807SJeff Garzik 
590c6fd2807SJeff Garzik 	/* put device into slumber mode */
591c6fd2807SJeff Garzik 	ahci_power_down(port_mmio, cap);
592c6fd2807SJeff Garzik 
593c6fd2807SJeff Garzik 	return 0;
594c6fd2807SJeff Garzik }
595c6fd2807SJeff Garzik 
596c6fd2807SJeff Garzik static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
597c6fd2807SJeff Garzik {
598c6fd2807SJeff Garzik 	u32 cap_save, tmp;
599c6fd2807SJeff Garzik 
600c6fd2807SJeff Garzik 	cap_save = readl(mmio + HOST_CAP);
601c6fd2807SJeff Garzik 	cap_save &= ( (1<<28) | (1<<17) );
602c6fd2807SJeff Garzik 	cap_save |= (1 << 27);
603c6fd2807SJeff Garzik 
604c6fd2807SJeff Garzik 	/* global controller reset */
605c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
606c6fd2807SJeff Garzik 	if ((tmp & HOST_RESET) == 0) {
607c6fd2807SJeff Garzik 		writel(tmp | HOST_RESET, mmio + HOST_CTL);
608c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
609c6fd2807SJeff Garzik 	}
610c6fd2807SJeff Garzik 
611c6fd2807SJeff Garzik 	/* reset must complete within 1 second, or
612c6fd2807SJeff Garzik 	 * the hardware should be considered fried.
613c6fd2807SJeff Garzik 	 */
614c6fd2807SJeff Garzik 	ssleep(1);
615c6fd2807SJeff Garzik 
616c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
617c6fd2807SJeff Garzik 	if (tmp & HOST_RESET) {
618c6fd2807SJeff Garzik 		dev_printk(KERN_ERR, &pdev->dev,
619c6fd2807SJeff Garzik 			   "controller reset failed (0x%x)\n", tmp);
620c6fd2807SJeff Garzik 		return -EIO;
621c6fd2807SJeff Garzik 	}
622c6fd2807SJeff Garzik 
623c6fd2807SJeff Garzik 	writel(HOST_AHCI_EN, mmio + HOST_CTL);
624c6fd2807SJeff Garzik 	(void) readl(mmio + HOST_CTL);	/* flush */
625c6fd2807SJeff Garzik 	writel(cap_save, mmio + HOST_CAP);
626c6fd2807SJeff Garzik 	writel(0xf, mmio + HOST_PORTS_IMPL);
627c6fd2807SJeff Garzik 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
628c6fd2807SJeff Garzik 
629c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
630c6fd2807SJeff Garzik 		u16 tmp16;
631c6fd2807SJeff Garzik 
632c6fd2807SJeff Garzik 		/* configure PCS */
633c6fd2807SJeff Garzik 		pci_read_config_word(pdev, 0x92, &tmp16);
634c6fd2807SJeff Garzik 		tmp16 |= 0xf;
635c6fd2807SJeff Garzik 		pci_write_config_word(pdev, 0x92, tmp16);
636c6fd2807SJeff Garzik 	}
637c6fd2807SJeff Garzik 
638c6fd2807SJeff Garzik 	return 0;
639c6fd2807SJeff Garzik }
640c6fd2807SJeff Garzik 
641c6fd2807SJeff Garzik static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
642c6fd2807SJeff Garzik 				 int n_ports, u32 cap)
643c6fd2807SJeff Garzik {
644c6fd2807SJeff Garzik 	int i, rc;
645c6fd2807SJeff Garzik 	u32 tmp;
646c6fd2807SJeff Garzik 
647c6fd2807SJeff Garzik 	for (i = 0; i < n_ports; i++) {
648c6fd2807SJeff Garzik 		void __iomem *port_mmio = ahci_port_base(mmio, i);
649c6fd2807SJeff Garzik 		const char *emsg = NULL;
650c6fd2807SJeff Garzik 
651c6fd2807SJeff Garzik #if 0 /* BIOSen initialize this incorrectly */
652c6fd2807SJeff Garzik 		if (!(hpriv->port_map & (1 << i)))
653c6fd2807SJeff Garzik 			continue;
654c6fd2807SJeff Garzik #endif
655c6fd2807SJeff Garzik 
656c6fd2807SJeff Garzik 		/* make sure port is not active */
657c6fd2807SJeff Garzik 		rc = ahci_deinit_port(port_mmio, cap, &emsg);
658c6fd2807SJeff Garzik 		if (rc)
659c6fd2807SJeff Garzik 			dev_printk(KERN_WARNING, &pdev->dev,
660c6fd2807SJeff Garzik 				   "%s (%d)\n", emsg, rc);
661c6fd2807SJeff Garzik 
662c6fd2807SJeff Garzik 		/* clear SError */
663c6fd2807SJeff Garzik 		tmp = readl(port_mmio + PORT_SCR_ERR);
664c6fd2807SJeff Garzik 		VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
665c6fd2807SJeff Garzik 		writel(tmp, port_mmio + PORT_SCR_ERR);
666c6fd2807SJeff Garzik 
667c6fd2807SJeff Garzik 		/* clear port IRQ */
668c6fd2807SJeff Garzik 		tmp = readl(port_mmio + PORT_IRQ_STAT);
669c6fd2807SJeff Garzik 		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
670c6fd2807SJeff Garzik 		if (tmp)
671c6fd2807SJeff Garzik 			writel(tmp, port_mmio + PORT_IRQ_STAT);
672c6fd2807SJeff Garzik 
673c6fd2807SJeff Garzik 		writel(1 << i, mmio + HOST_IRQ_STAT);
674c6fd2807SJeff Garzik 	}
675c6fd2807SJeff Garzik 
676c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
677c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
678c6fd2807SJeff Garzik 	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
679c6fd2807SJeff Garzik 	tmp = readl(mmio + HOST_CTL);
680c6fd2807SJeff Garzik 	VPRINTK("HOST_CTL 0x%x\n", tmp);
681c6fd2807SJeff Garzik }
682c6fd2807SJeff Garzik 
683c6fd2807SJeff Garzik static unsigned int ahci_dev_classify(struct ata_port *ap)
684c6fd2807SJeff Garzik {
685c6fd2807SJeff Garzik 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
686c6fd2807SJeff Garzik 	struct ata_taskfile tf;
687c6fd2807SJeff Garzik 	u32 tmp;
688c6fd2807SJeff Garzik 
689c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_SIG);
690c6fd2807SJeff Garzik 	tf.lbah		= (tmp >> 24)	& 0xff;
691c6fd2807SJeff Garzik 	tf.lbam		= (tmp >> 16)	& 0xff;
692c6fd2807SJeff Garzik 	tf.lbal		= (tmp >> 8)	& 0xff;
693c6fd2807SJeff Garzik 	tf.nsect	= (tmp)		& 0xff;
694c6fd2807SJeff Garzik 
695c6fd2807SJeff Garzik 	return ata_dev_classify(&tf);
696c6fd2807SJeff Garzik }
697c6fd2807SJeff Garzik 
698c6fd2807SJeff Garzik static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
699c6fd2807SJeff Garzik 			       u32 opts)
700c6fd2807SJeff Garzik {
701c6fd2807SJeff Garzik 	dma_addr_t cmd_tbl_dma;
702c6fd2807SJeff Garzik 
703c6fd2807SJeff Garzik 	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
704c6fd2807SJeff Garzik 
705c6fd2807SJeff Garzik 	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
706c6fd2807SJeff Garzik 	pp->cmd_slot[tag].status = 0;
707c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
708c6fd2807SJeff Garzik 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
709c6fd2807SJeff Garzik }
710c6fd2807SJeff Garzik 
711c6fd2807SJeff Garzik static int ahci_clo(struct ata_port *ap)
712c6fd2807SJeff Garzik {
713c6fd2807SJeff Garzik 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
714cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
715c6fd2807SJeff Garzik 	u32 tmp;
716c6fd2807SJeff Garzik 
717c6fd2807SJeff Garzik 	if (!(hpriv->cap & HOST_CAP_CLO))
718c6fd2807SJeff Garzik 		return -EOPNOTSUPP;
719c6fd2807SJeff Garzik 
720c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_CMD);
721c6fd2807SJeff Garzik 	tmp |= PORT_CMD_CLO;
722c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_CMD);
723c6fd2807SJeff Garzik 
724c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD,
725c6fd2807SJeff Garzik 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
726c6fd2807SJeff Garzik 	if (tmp & PORT_CMD_CLO)
727c6fd2807SJeff Garzik 		return -EIO;
728c6fd2807SJeff Garzik 
729c6fd2807SJeff Garzik 	return 0;
730c6fd2807SJeff Garzik }
731c6fd2807SJeff Garzik 
732c6fd2807SJeff Garzik static int ahci_prereset(struct ata_port *ap)
733c6fd2807SJeff Garzik {
734c6fd2807SJeff Garzik 	if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
735c6fd2807SJeff Garzik 	    (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
736c6fd2807SJeff Garzik 		/* ATA_BUSY hasn't cleared, so send a CLO */
737c6fd2807SJeff Garzik 		ahci_clo(ap);
738c6fd2807SJeff Garzik 	}
739c6fd2807SJeff Garzik 
740c6fd2807SJeff Garzik 	return ata_std_prereset(ap);
741c6fd2807SJeff Garzik }
742c6fd2807SJeff Garzik 
743c6fd2807SJeff Garzik static int ahci_softreset(struct ata_port *ap, unsigned int *class)
744c6fd2807SJeff Garzik {
745c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
746cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
747c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
748c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
749c6fd2807SJeff Garzik 	const char *reason = NULL;
750c6fd2807SJeff Garzik 	struct ata_taskfile tf;
751c6fd2807SJeff Garzik 	u32 tmp;
752c6fd2807SJeff Garzik 	u8 *fis;
753c6fd2807SJeff Garzik 	int rc;
754c6fd2807SJeff Garzik 
755c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
756c6fd2807SJeff Garzik 
757c6fd2807SJeff Garzik 	if (ata_port_offline(ap)) {
758c6fd2807SJeff Garzik 		DPRINTK("PHY reports no device\n");
759c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
760c6fd2807SJeff Garzik 		return 0;
761c6fd2807SJeff Garzik 	}
762c6fd2807SJeff Garzik 
763c6fd2807SJeff Garzik 	/* prepare for SRST (AHCI-1.1 10.4.1) */
764c6fd2807SJeff Garzik 	rc = ahci_stop_engine(port_mmio);
765c6fd2807SJeff Garzik 	if (rc) {
766c6fd2807SJeff Garzik 		reason = "failed to stop engine";
767c6fd2807SJeff Garzik 		goto fail_restart;
768c6fd2807SJeff Garzik 	}
769c6fd2807SJeff Garzik 
770c6fd2807SJeff Garzik 	/* check BUSY/DRQ, perform Command List Override if necessary */
7711244a19cSTejun Heo 	if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
772c6fd2807SJeff Garzik 		rc = ahci_clo(ap);
773c6fd2807SJeff Garzik 
774c6fd2807SJeff Garzik 		if (rc == -EOPNOTSUPP) {
775c6fd2807SJeff Garzik 			reason = "port busy but CLO unavailable";
776c6fd2807SJeff Garzik 			goto fail_restart;
777c6fd2807SJeff Garzik 		} else if (rc) {
778c6fd2807SJeff Garzik 			reason = "port busy but CLO failed";
779c6fd2807SJeff Garzik 			goto fail_restart;
780c6fd2807SJeff Garzik 		}
781c6fd2807SJeff Garzik 	}
782c6fd2807SJeff Garzik 
783c6fd2807SJeff Garzik 	/* restart engine */
784c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
785c6fd2807SJeff Garzik 
786c6fd2807SJeff Garzik 	ata_tf_init(ap->device, &tf);
787c6fd2807SJeff Garzik 	fis = pp->cmd_tbl;
788c6fd2807SJeff Garzik 
789c6fd2807SJeff Garzik 	/* issue the first D2H Register FIS */
790c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, 0,
791c6fd2807SJeff Garzik 			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
792c6fd2807SJeff Garzik 
793c6fd2807SJeff Garzik 	tf.ctl |= ATA_SRST;
794c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, fis, 0);
795c6fd2807SJeff Garzik 	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
796c6fd2807SJeff Garzik 
797c6fd2807SJeff Garzik 	writel(1, port_mmio + PORT_CMD_ISSUE);
798c6fd2807SJeff Garzik 
799c6fd2807SJeff Garzik 	tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
800c6fd2807SJeff Garzik 	if (tmp & 0x1) {
801c6fd2807SJeff Garzik 		rc = -EIO;
802c6fd2807SJeff Garzik 		reason = "1st FIS failed";
803c6fd2807SJeff Garzik 		goto fail;
804c6fd2807SJeff Garzik 	}
805c6fd2807SJeff Garzik 
806c6fd2807SJeff Garzik 	/* spec says at least 5us, but be generous and sleep for 1ms */
807c6fd2807SJeff Garzik 	msleep(1);
808c6fd2807SJeff Garzik 
809c6fd2807SJeff Garzik 	/* issue the second D2H Register FIS */
810c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
811c6fd2807SJeff Garzik 
812c6fd2807SJeff Garzik 	tf.ctl &= ~ATA_SRST;
813c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, fis, 0);
814c6fd2807SJeff Garzik 	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
815c6fd2807SJeff Garzik 
816c6fd2807SJeff Garzik 	writel(1, port_mmio + PORT_CMD_ISSUE);
817c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
818c6fd2807SJeff Garzik 
819c6fd2807SJeff Garzik 	/* spec mandates ">= 2ms" before checking status.
820c6fd2807SJeff Garzik 	 * We wait 150ms, because that was the magic delay used for
821c6fd2807SJeff Garzik 	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time
822c6fd2807SJeff Garzik 	 * between when the ATA command register is written, and then
823c6fd2807SJeff Garzik 	 * status is checked.  Because waiting for "a while" before
824c6fd2807SJeff Garzik 	 * checking status is fine, post SRST, we perform this magic
825c6fd2807SJeff Garzik 	 * delay here as well.
826c6fd2807SJeff Garzik 	 */
827c6fd2807SJeff Garzik 	msleep(150);
828c6fd2807SJeff Garzik 
829c6fd2807SJeff Garzik 	*class = ATA_DEV_NONE;
830c6fd2807SJeff Garzik 	if (ata_port_online(ap)) {
831c6fd2807SJeff Garzik 		if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
832c6fd2807SJeff Garzik 			rc = -EIO;
833c6fd2807SJeff Garzik 			reason = "device not ready";
834c6fd2807SJeff Garzik 			goto fail;
835c6fd2807SJeff Garzik 		}
836c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
837c6fd2807SJeff Garzik 	}
838c6fd2807SJeff Garzik 
839c6fd2807SJeff Garzik 	DPRINTK("EXIT, class=%u\n", *class);
840c6fd2807SJeff Garzik 	return 0;
841c6fd2807SJeff Garzik 
842c6fd2807SJeff Garzik  fail_restart:
843c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
844c6fd2807SJeff Garzik  fail:
845c6fd2807SJeff Garzik 	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
846c6fd2807SJeff Garzik 	return rc;
847c6fd2807SJeff Garzik }
848c6fd2807SJeff Garzik 
849c6fd2807SJeff Garzik static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
850c6fd2807SJeff Garzik {
851c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
852c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
853c6fd2807SJeff Garzik 	struct ata_taskfile tf;
854cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
855c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
856c6fd2807SJeff Garzik 	int rc;
857c6fd2807SJeff Garzik 
858c6fd2807SJeff Garzik 	DPRINTK("ENTER\n");
859c6fd2807SJeff Garzik 
860c6fd2807SJeff Garzik 	ahci_stop_engine(port_mmio);
861c6fd2807SJeff Garzik 
862c6fd2807SJeff Garzik 	/* clear D2H reception area to properly wait for D2H FIS */
863c6fd2807SJeff Garzik 	ata_tf_init(ap->device, &tf);
864c6fd2807SJeff Garzik 	tf.command = 0xff;
865c6fd2807SJeff Garzik 	ata_tf_to_fis(&tf, d2h_fis, 0);
866c6fd2807SJeff Garzik 
867c6fd2807SJeff Garzik 	rc = sata_std_hardreset(ap, class);
868c6fd2807SJeff Garzik 
869c6fd2807SJeff Garzik 	ahci_start_engine(port_mmio);
870c6fd2807SJeff Garzik 
871c6fd2807SJeff Garzik 	if (rc == 0 && ata_port_online(ap))
872c6fd2807SJeff Garzik 		*class = ahci_dev_classify(ap);
873c6fd2807SJeff Garzik 	if (*class == ATA_DEV_UNKNOWN)
874c6fd2807SJeff Garzik 		*class = ATA_DEV_NONE;
875c6fd2807SJeff Garzik 
876c6fd2807SJeff Garzik 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
877c6fd2807SJeff Garzik 	return rc;
878c6fd2807SJeff Garzik }
879c6fd2807SJeff Garzik 
880c6fd2807SJeff Garzik static void ahci_postreset(struct ata_port *ap, unsigned int *class)
881c6fd2807SJeff Garzik {
882c6fd2807SJeff Garzik 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
883c6fd2807SJeff Garzik 	u32 new_tmp, tmp;
884c6fd2807SJeff Garzik 
885c6fd2807SJeff Garzik 	ata_std_postreset(ap, class);
886c6fd2807SJeff Garzik 
887c6fd2807SJeff Garzik 	/* Make sure port's ATAPI bit is set appropriately */
888c6fd2807SJeff Garzik 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
889c6fd2807SJeff Garzik 	if (*class == ATA_DEV_ATAPI)
890c6fd2807SJeff Garzik 		new_tmp |= PORT_CMD_ATAPI;
891c6fd2807SJeff Garzik 	else
892c6fd2807SJeff Garzik 		new_tmp &= ~PORT_CMD_ATAPI;
893c6fd2807SJeff Garzik 	if (new_tmp != tmp) {
894c6fd2807SJeff Garzik 		writel(new_tmp, port_mmio + PORT_CMD);
895c6fd2807SJeff Garzik 		readl(port_mmio + PORT_CMD); /* flush */
896c6fd2807SJeff Garzik 	}
897c6fd2807SJeff Garzik }
898c6fd2807SJeff Garzik 
899c6fd2807SJeff Garzik static u8 ahci_check_status(struct ata_port *ap)
900c6fd2807SJeff Garzik {
901c6fd2807SJeff Garzik 	void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
902c6fd2807SJeff Garzik 
903c6fd2807SJeff Garzik 	return readl(mmio + PORT_TFDATA) & 0xFF;
904c6fd2807SJeff Garzik }
905c6fd2807SJeff Garzik 
906c6fd2807SJeff Garzik static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
907c6fd2807SJeff Garzik {
908c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
909c6fd2807SJeff Garzik 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
910c6fd2807SJeff Garzik 
911c6fd2807SJeff Garzik 	ata_tf_from_fis(d2h_fis, tf);
912c6fd2807SJeff Garzik }
913c6fd2807SJeff Garzik 
914c6fd2807SJeff Garzik static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
915c6fd2807SJeff Garzik {
916c6fd2807SJeff Garzik 	struct scatterlist *sg;
917c6fd2807SJeff Garzik 	struct ahci_sg *ahci_sg;
918c6fd2807SJeff Garzik 	unsigned int n_sg = 0;
919c6fd2807SJeff Garzik 
920c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
921c6fd2807SJeff Garzik 
922c6fd2807SJeff Garzik 	/*
923c6fd2807SJeff Garzik 	 * Next, the S/G list.
924c6fd2807SJeff Garzik 	 */
925c6fd2807SJeff Garzik 	ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
926c6fd2807SJeff Garzik 	ata_for_each_sg(sg, qc) {
927c6fd2807SJeff Garzik 		dma_addr_t addr = sg_dma_address(sg);
928c6fd2807SJeff Garzik 		u32 sg_len = sg_dma_len(sg);
929c6fd2807SJeff Garzik 
930c6fd2807SJeff Garzik 		ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
931c6fd2807SJeff Garzik 		ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
932c6fd2807SJeff Garzik 		ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
933c6fd2807SJeff Garzik 
934c6fd2807SJeff Garzik 		ahci_sg++;
935c6fd2807SJeff Garzik 		n_sg++;
936c6fd2807SJeff Garzik 	}
937c6fd2807SJeff Garzik 
938c6fd2807SJeff Garzik 	return n_sg;
939c6fd2807SJeff Garzik }
940c6fd2807SJeff Garzik 
941c6fd2807SJeff Garzik static void ahci_qc_prep(struct ata_queued_cmd *qc)
942c6fd2807SJeff Garzik {
943c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
944c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
945c6fd2807SJeff Garzik 	int is_atapi = is_atapi_taskfile(&qc->tf);
946c6fd2807SJeff Garzik 	void *cmd_tbl;
947c6fd2807SJeff Garzik 	u32 opts;
948c6fd2807SJeff Garzik 	const u32 cmd_fis_len = 5; /* five dwords */
949c6fd2807SJeff Garzik 	unsigned int n_elem;
950c6fd2807SJeff Garzik 
951c6fd2807SJeff Garzik 	/*
952c6fd2807SJeff Garzik 	 * Fill in command table information.  First, the header,
953c6fd2807SJeff Garzik 	 * a SATA Register - Host to Device command FIS.
954c6fd2807SJeff Garzik 	 */
955c6fd2807SJeff Garzik 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
956c6fd2807SJeff Garzik 
957c6fd2807SJeff Garzik 	ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
958c6fd2807SJeff Garzik 	if (is_atapi) {
959c6fd2807SJeff Garzik 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
960c6fd2807SJeff Garzik 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
961c6fd2807SJeff Garzik 	}
962c6fd2807SJeff Garzik 
963c6fd2807SJeff Garzik 	n_elem = 0;
964c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_DMAMAP)
965c6fd2807SJeff Garzik 		n_elem = ahci_fill_sg(qc, cmd_tbl);
966c6fd2807SJeff Garzik 
967c6fd2807SJeff Garzik 	/*
968c6fd2807SJeff Garzik 	 * Fill in command slot information.
969c6fd2807SJeff Garzik 	 */
970c6fd2807SJeff Garzik 	opts = cmd_fis_len | n_elem << 16;
971c6fd2807SJeff Garzik 	if (qc->tf.flags & ATA_TFLAG_WRITE)
972c6fd2807SJeff Garzik 		opts |= AHCI_CMD_WRITE;
973c6fd2807SJeff Garzik 	if (is_atapi)
974c6fd2807SJeff Garzik 		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
975c6fd2807SJeff Garzik 
976c6fd2807SJeff Garzik 	ahci_fill_cmd_slot(pp, qc->tag, opts);
977c6fd2807SJeff Garzik }
978c6fd2807SJeff Garzik 
979c6fd2807SJeff Garzik static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
980c6fd2807SJeff Garzik {
981c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
982c6fd2807SJeff Garzik 	struct ata_eh_info *ehi = &ap->eh_info;
983c6fd2807SJeff Garzik 	unsigned int err_mask = 0, action = 0;
984c6fd2807SJeff Garzik 	struct ata_queued_cmd *qc;
985c6fd2807SJeff Garzik 	u32 serror;
986c6fd2807SJeff Garzik 
987c6fd2807SJeff Garzik 	ata_ehi_clear_desc(ehi);
988c6fd2807SJeff Garzik 
989c6fd2807SJeff Garzik 	/* AHCI needs SError cleared; otherwise, it might lock up */
990c6fd2807SJeff Garzik 	serror = ahci_scr_read(ap, SCR_ERROR);
991c6fd2807SJeff Garzik 	ahci_scr_write(ap, SCR_ERROR, serror);
992c6fd2807SJeff Garzik 
993c6fd2807SJeff Garzik 	/* analyze @irq_stat */
994c6fd2807SJeff Garzik 	ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
995c6fd2807SJeff Garzik 
996*41669553STejun Heo 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
997*41669553STejun Heo 	if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
998*41669553STejun Heo 		irq_stat &= ~PORT_IRQ_IF_ERR;
999*41669553STejun Heo 
1000c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_TF_ERR)
1001c6fd2807SJeff Garzik 		err_mask |= AC_ERR_DEV;
1002c6fd2807SJeff Garzik 
1003c6fd2807SJeff Garzik 	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
1004c6fd2807SJeff Garzik 		err_mask |= AC_ERR_HOST_BUS;
1005c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1006c6fd2807SJeff Garzik 	}
1007c6fd2807SJeff Garzik 
1008c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_IF_ERR) {
1009c6fd2807SJeff Garzik 		err_mask |= AC_ERR_ATA_BUS;
1010c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1011c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", interface fatal error");
1012c6fd2807SJeff Garzik 	}
1013c6fd2807SJeff Garzik 
1014c6fd2807SJeff Garzik 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
1015c6fd2807SJeff Garzik 		ata_ehi_hotplugged(ehi);
1016c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
1017c6fd2807SJeff Garzik 			"connection status changed" : "PHY RDY changed");
1018c6fd2807SJeff Garzik 	}
1019c6fd2807SJeff Garzik 
1020c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_UNK_FIS) {
1021c6fd2807SJeff Garzik 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
1022c6fd2807SJeff Garzik 
1023c6fd2807SJeff Garzik 		err_mask |= AC_ERR_HSM;
1024c6fd2807SJeff Garzik 		action |= ATA_EH_SOFTRESET;
1025c6fd2807SJeff Garzik 		ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
1026c6fd2807SJeff Garzik 				  unk[0], unk[1], unk[2], unk[3]);
1027c6fd2807SJeff Garzik 	}
1028c6fd2807SJeff Garzik 
1029c6fd2807SJeff Garzik 	/* okay, let's hand over to EH */
1030c6fd2807SJeff Garzik 	ehi->serror |= serror;
1031c6fd2807SJeff Garzik 	ehi->action |= action;
1032c6fd2807SJeff Garzik 
1033c6fd2807SJeff Garzik 	qc = ata_qc_from_tag(ap, ap->active_tag);
1034c6fd2807SJeff Garzik 	if (qc)
1035c6fd2807SJeff Garzik 		qc->err_mask |= err_mask;
1036c6fd2807SJeff Garzik 	else
1037c6fd2807SJeff Garzik 		ehi->err_mask |= err_mask;
1038c6fd2807SJeff Garzik 
1039c6fd2807SJeff Garzik 	if (irq_stat & PORT_IRQ_FREEZE)
1040c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1041c6fd2807SJeff Garzik 	else
1042c6fd2807SJeff Garzik 		ata_port_abort(ap);
1043c6fd2807SJeff Garzik }
1044c6fd2807SJeff Garzik 
1045c6fd2807SJeff Garzik static void ahci_host_intr(struct ata_port *ap)
1046c6fd2807SJeff Garzik {
1047cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1048c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1049c6fd2807SJeff Garzik 	struct ata_eh_info *ehi = &ap->eh_info;
1050c6fd2807SJeff Garzik 	u32 status, qc_active;
1051c6fd2807SJeff Garzik 	int rc;
1052c6fd2807SJeff Garzik 
1053c6fd2807SJeff Garzik 	status = readl(port_mmio + PORT_IRQ_STAT);
1054c6fd2807SJeff Garzik 	writel(status, port_mmio + PORT_IRQ_STAT);
1055c6fd2807SJeff Garzik 
1056c6fd2807SJeff Garzik 	if (unlikely(status & PORT_IRQ_ERROR)) {
1057c6fd2807SJeff Garzik 		ahci_error_intr(ap, status);
1058c6fd2807SJeff Garzik 		return;
1059c6fd2807SJeff Garzik 	}
1060c6fd2807SJeff Garzik 
1061c6fd2807SJeff Garzik 	if (ap->sactive)
1062c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_SCR_ACT);
1063c6fd2807SJeff Garzik 	else
1064c6fd2807SJeff Garzik 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
1065c6fd2807SJeff Garzik 
1066c6fd2807SJeff Garzik 	rc = ata_qc_complete_multiple(ap, qc_active, NULL);
1067c6fd2807SJeff Garzik 	if (rc > 0)
1068c6fd2807SJeff Garzik 		return;
1069c6fd2807SJeff Garzik 	if (rc < 0) {
1070c6fd2807SJeff Garzik 		ehi->err_mask |= AC_ERR_HSM;
1071c6fd2807SJeff Garzik 		ehi->action |= ATA_EH_SOFTRESET;
1072c6fd2807SJeff Garzik 		ata_port_freeze(ap);
1073c6fd2807SJeff Garzik 		return;
1074c6fd2807SJeff Garzik 	}
1075c6fd2807SJeff Garzik 
1076c6fd2807SJeff Garzik 	/* hmmm... a spurious interupt */
1077c6fd2807SJeff Garzik 
1078c6fd2807SJeff Garzik 	/* some devices send D2H reg with I bit set during NCQ command phase */
107912a87d36SAlan Cox 	if (ap->sactive && (status & PORT_IRQ_D2H_REG_FIS))
1080c6fd2807SJeff Garzik 		return;
1081c6fd2807SJeff Garzik 
1082c6fd2807SJeff Garzik 	/* ignore interim PIO setup fis interrupts */
1083c6fd2807SJeff Garzik 	if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS))
1084c6fd2807SJeff Garzik 		return;
1085c6fd2807SJeff Garzik 
1086c6fd2807SJeff Garzik 	if (ata_ratelimit())
1087c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
1088c6fd2807SJeff Garzik 				"(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
1089c6fd2807SJeff Garzik 				status, ap->active_tag, ap->sactive);
1090c6fd2807SJeff Garzik }
1091c6fd2807SJeff Garzik 
1092c6fd2807SJeff Garzik static void ahci_irq_clear(struct ata_port *ap)
1093c6fd2807SJeff Garzik {
1094c6fd2807SJeff Garzik 	/* TODO */
1095c6fd2807SJeff Garzik }
1096c6fd2807SJeff Garzik 
10977d12e780SDavid Howells static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1098c6fd2807SJeff Garzik {
1099cca3974eSJeff Garzik 	struct ata_host *host = dev_instance;
1100c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1101c6fd2807SJeff Garzik 	unsigned int i, handled = 0;
1102c6fd2807SJeff Garzik 	void __iomem *mmio;
1103c6fd2807SJeff Garzik 	u32 irq_stat, irq_ack = 0;
1104c6fd2807SJeff Garzik 
1105c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1106c6fd2807SJeff Garzik 
1107cca3974eSJeff Garzik 	hpriv = host->private_data;
1108cca3974eSJeff Garzik 	mmio = host->mmio_base;
1109c6fd2807SJeff Garzik 
1110c6fd2807SJeff Garzik 	/* sigh.  0xffffffff is a valid return from h/w */
1111c6fd2807SJeff Garzik 	irq_stat = readl(mmio + HOST_IRQ_STAT);
1112c6fd2807SJeff Garzik 	irq_stat &= hpriv->port_map;
1113c6fd2807SJeff Garzik 	if (!irq_stat)
1114c6fd2807SJeff Garzik 		return IRQ_NONE;
1115c6fd2807SJeff Garzik 
1116cca3974eSJeff Garzik         spin_lock(&host->lock);
1117c6fd2807SJeff Garzik 
1118cca3974eSJeff Garzik         for (i = 0; i < host->n_ports; i++) {
1119c6fd2807SJeff Garzik 		struct ata_port *ap;
1120c6fd2807SJeff Garzik 
1121c6fd2807SJeff Garzik 		if (!(irq_stat & (1 << i)))
1122c6fd2807SJeff Garzik 			continue;
1123c6fd2807SJeff Garzik 
1124cca3974eSJeff Garzik 		ap = host->ports[i];
1125c6fd2807SJeff Garzik 		if (ap) {
1126c6fd2807SJeff Garzik 			ahci_host_intr(ap);
1127c6fd2807SJeff Garzik 			VPRINTK("port %u\n", i);
1128c6fd2807SJeff Garzik 		} else {
1129c6fd2807SJeff Garzik 			VPRINTK("port %u (no irq)\n", i);
1130c6fd2807SJeff Garzik 			if (ata_ratelimit())
1131cca3974eSJeff Garzik 				dev_printk(KERN_WARNING, host->dev,
1132c6fd2807SJeff Garzik 					"interrupt on disabled port %u\n", i);
1133c6fd2807SJeff Garzik 		}
1134c6fd2807SJeff Garzik 
1135c6fd2807SJeff Garzik 		irq_ack |= (1 << i);
1136c6fd2807SJeff Garzik 	}
1137c6fd2807SJeff Garzik 
1138c6fd2807SJeff Garzik 	if (irq_ack) {
1139c6fd2807SJeff Garzik 		writel(irq_ack, mmio + HOST_IRQ_STAT);
1140c6fd2807SJeff Garzik 		handled = 1;
1141c6fd2807SJeff Garzik 	}
1142c6fd2807SJeff Garzik 
1143cca3974eSJeff Garzik 	spin_unlock(&host->lock);
1144c6fd2807SJeff Garzik 
1145c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1146c6fd2807SJeff Garzik 
1147c6fd2807SJeff Garzik 	return IRQ_RETVAL(handled);
1148c6fd2807SJeff Garzik }
1149c6fd2807SJeff Garzik 
1150c6fd2807SJeff Garzik static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
1151c6fd2807SJeff Garzik {
1152c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1153c6fd2807SJeff Garzik 	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
1154c6fd2807SJeff Garzik 
1155c6fd2807SJeff Garzik 	if (qc->tf.protocol == ATA_PROT_NCQ)
1156c6fd2807SJeff Garzik 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
1157c6fd2807SJeff Garzik 	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
1158c6fd2807SJeff Garzik 	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
1159c6fd2807SJeff Garzik 
1160c6fd2807SJeff Garzik 	return 0;
1161c6fd2807SJeff Garzik }
1162c6fd2807SJeff Garzik 
1163c6fd2807SJeff Garzik static void ahci_freeze(struct ata_port *ap)
1164c6fd2807SJeff Garzik {
1165cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1166c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1167c6fd2807SJeff Garzik 
1168c6fd2807SJeff Garzik 	/* turn IRQ off */
1169c6fd2807SJeff Garzik 	writel(0, port_mmio + PORT_IRQ_MASK);
1170c6fd2807SJeff Garzik }
1171c6fd2807SJeff Garzik 
1172c6fd2807SJeff Garzik static void ahci_thaw(struct ata_port *ap)
1173c6fd2807SJeff Garzik {
1174cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1175c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1176c6fd2807SJeff Garzik 	u32 tmp;
1177c6fd2807SJeff Garzik 
1178c6fd2807SJeff Garzik 	/* clear IRQ */
1179c6fd2807SJeff Garzik 	tmp = readl(port_mmio + PORT_IRQ_STAT);
1180c6fd2807SJeff Garzik 	writel(tmp, port_mmio + PORT_IRQ_STAT);
1181c6fd2807SJeff Garzik 	writel(1 << ap->id, mmio + HOST_IRQ_STAT);
1182c6fd2807SJeff Garzik 
1183c6fd2807SJeff Garzik 	/* turn IRQ back on */
1184c6fd2807SJeff Garzik 	writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
1185c6fd2807SJeff Garzik }
1186c6fd2807SJeff Garzik 
1187c6fd2807SJeff Garzik static void ahci_error_handler(struct ata_port *ap)
1188c6fd2807SJeff Garzik {
1189cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1190c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1191c6fd2807SJeff Garzik 
1192c6fd2807SJeff Garzik 	if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1193c6fd2807SJeff Garzik 		/* restart engine */
1194c6fd2807SJeff Garzik 		ahci_stop_engine(port_mmio);
1195c6fd2807SJeff Garzik 		ahci_start_engine(port_mmio);
1196c6fd2807SJeff Garzik 	}
1197c6fd2807SJeff Garzik 
1198c6fd2807SJeff Garzik 	/* perform recovery */
1199c6fd2807SJeff Garzik 	ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
1200c6fd2807SJeff Garzik 		  ahci_postreset);
1201c6fd2807SJeff Garzik }
1202c6fd2807SJeff Garzik 
1203c6fd2807SJeff Garzik static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
1204c6fd2807SJeff Garzik {
1205c6fd2807SJeff Garzik 	struct ata_port *ap = qc->ap;
1206cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1207c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1208c6fd2807SJeff Garzik 
1209c6fd2807SJeff Garzik 	if (qc->flags & ATA_QCFLAG_FAILED)
1210c6fd2807SJeff Garzik 		qc->err_mask |= AC_ERR_OTHER;
1211c6fd2807SJeff Garzik 
1212c6fd2807SJeff Garzik 	if (qc->err_mask) {
1213c6fd2807SJeff Garzik 		/* make DMA engine forget about the failed command */
1214c6fd2807SJeff Garzik 		ahci_stop_engine(port_mmio);
1215c6fd2807SJeff Garzik 		ahci_start_engine(port_mmio);
1216c6fd2807SJeff Garzik 	}
1217c6fd2807SJeff Garzik }
1218c6fd2807SJeff Garzik 
1219c6fd2807SJeff Garzik static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
1220c6fd2807SJeff Garzik {
1221cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1222c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1223cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1224c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1225c6fd2807SJeff Garzik 	const char *emsg = NULL;
1226c6fd2807SJeff Garzik 	int rc;
1227c6fd2807SJeff Garzik 
1228c6fd2807SJeff Garzik 	rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
1229c6fd2807SJeff Garzik 	if (rc) {
1230c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
1231c6fd2807SJeff Garzik 		ahci_init_port(port_mmio, hpriv->cap,
1232c6fd2807SJeff Garzik 			       pp->cmd_slot_dma, pp->rx_fis_dma);
1233c6fd2807SJeff Garzik 	}
1234c6fd2807SJeff Garzik 
1235c6fd2807SJeff Garzik 	return rc;
1236c6fd2807SJeff Garzik }
1237c6fd2807SJeff Garzik 
1238c6fd2807SJeff Garzik static int ahci_port_resume(struct ata_port *ap)
1239c6fd2807SJeff Garzik {
1240c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1241cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1242cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1243c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1244c6fd2807SJeff Garzik 
1245c6fd2807SJeff Garzik 	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
1246c6fd2807SJeff Garzik 
1247c6fd2807SJeff Garzik 	return 0;
1248c6fd2807SJeff Garzik }
1249c6fd2807SJeff Garzik 
1250c6fd2807SJeff Garzik static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
1251c6fd2807SJeff Garzik {
1252cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
1253cca3974eSJeff Garzik 	void __iomem *mmio = host->mmio_base;
1254c6fd2807SJeff Garzik 	u32 ctl;
1255c6fd2807SJeff Garzik 
1256c6fd2807SJeff Garzik 	if (mesg.event == PM_EVENT_SUSPEND) {
1257c6fd2807SJeff Garzik 		/* AHCI spec rev1.1 section 8.3.3:
1258c6fd2807SJeff Garzik 		 * Software must disable interrupts prior to requesting a
1259c6fd2807SJeff Garzik 		 * transition of the HBA to D3 state.
1260c6fd2807SJeff Garzik 		 */
1261c6fd2807SJeff Garzik 		ctl = readl(mmio + HOST_CTL);
1262c6fd2807SJeff Garzik 		ctl &= ~HOST_IRQ_EN;
1263c6fd2807SJeff Garzik 		writel(ctl, mmio + HOST_CTL);
1264c6fd2807SJeff Garzik 		readl(mmio + HOST_CTL); /* flush */
1265c6fd2807SJeff Garzik 	}
1266c6fd2807SJeff Garzik 
1267c6fd2807SJeff Garzik 	return ata_pci_device_suspend(pdev, mesg);
1268c6fd2807SJeff Garzik }
1269c6fd2807SJeff Garzik 
1270c6fd2807SJeff Garzik static int ahci_pci_device_resume(struct pci_dev *pdev)
1271c6fd2807SJeff Garzik {
1272cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
1273cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = host->private_data;
1274cca3974eSJeff Garzik 	void __iomem *mmio = host->mmio_base;
1275c6fd2807SJeff Garzik 	int rc;
1276c6fd2807SJeff Garzik 
1277c6fd2807SJeff Garzik 	ata_pci_device_do_resume(pdev);
1278c6fd2807SJeff Garzik 
1279c6fd2807SJeff Garzik 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
1280c6fd2807SJeff Garzik 		rc = ahci_reset_controller(mmio, pdev);
1281c6fd2807SJeff Garzik 		if (rc)
1282c6fd2807SJeff Garzik 			return rc;
1283c6fd2807SJeff Garzik 
1284cca3974eSJeff Garzik 		ahci_init_controller(mmio, pdev, host->n_ports, hpriv->cap);
1285c6fd2807SJeff Garzik 	}
1286c6fd2807SJeff Garzik 
1287cca3974eSJeff Garzik 	ata_host_resume(host);
1288c6fd2807SJeff Garzik 
1289c6fd2807SJeff Garzik 	return 0;
1290c6fd2807SJeff Garzik }
1291c6fd2807SJeff Garzik 
1292c6fd2807SJeff Garzik static int ahci_port_start(struct ata_port *ap)
1293c6fd2807SJeff Garzik {
1294cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
1295cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1296c6fd2807SJeff Garzik 	struct ahci_port_priv *pp;
1297cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1298c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1299c6fd2807SJeff Garzik 	void *mem;
1300c6fd2807SJeff Garzik 	dma_addr_t mem_dma;
1301c6fd2807SJeff Garzik 	int rc;
1302c6fd2807SJeff Garzik 
1303c6fd2807SJeff Garzik 	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
1304c6fd2807SJeff Garzik 	if (!pp)
1305c6fd2807SJeff Garzik 		return -ENOMEM;
1306c6fd2807SJeff Garzik 	memset(pp, 0, sizeof(*pp));
1307c6fd2807SJeff Garzik 
1308c6fd2807SJeff Garzik 	rc = ata_pad_alloc(ap, dev);
1309c6fd2807SJeff Garzik 	if (rc) {
1310c6fd2807SJeff Garzik 		kfree(pp);
1311c6fd2807SJeff Garzik 		return rc;
1312c6fd2807SJeff Garzik 	}
1313c6fd2807SJeff Garzik 
1314c6fd2807SJeff Garzik 	mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
1315c6fd2807SJeff Garzik 	if (!mem) {
1316c6fd2807SJeff Garzik 		ata_pad_free(ap, dev);
1317c6fd2807SJeff Garzik 		kfree(pp);
1318c6fd2807SJeff Garzik 		return -ENOMEM;
1319c6fd2807SJeff Garzik 	}
1320c6fd2807SJeff Garzik 	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
1321c6fd2807SJeff Garzik 
1322c6fd2807SJeff Garzik 	/*
1323c6fd2807SJeff Garzik 	 * First item in chunk of DMA memory: 32-slot command table,
1324c6fd2807SJeff Garzik 	 * 32 bytes each in size
1325c6fd2807SJeff Garzik 	 */
1326c6fd2807SJeff Garzik 	pp->cmd_slot = mem;
1327c6fd2807SJeff Garzik 	pp->cmd_slot_dma = mem_dma;
1328c6fd2807SJeff Garzik 
1329c6fd2807SJeff Garzik 	mem += AHCI_CMD_SLOT_SZ;
1330c6fd2807SJeff Garzik 	mem_dma += AHCI_CMD_SLOT_SZ;
1331c6fd2807SJeff Garzik 
1332c6fd2807SJeff Garzik 	/*
1333c6fd2807SJeff Garzik 	 * Second item: Received-FIS area
1334c6fd2807SJeff Garzik 	 */
1335c6fd2807SJeff Garzik 	pp->rx_fis = mem;
1336c6fd2807SJeff Garzik 	pp->rx_fis_dma = mem_dma;
1337c6fd2807SJeff Garzik 
1338c6fd2807SJeff Garzik 	mem += AHCI_RX_FIS_SZ;
1339c6fd2807SJeff Garzik 	mem_dma += AHCI_RX_FIS_SZ;
1340c6fd2807SJeff Garzik 
1341c6fd2807SJeff Garzik 	/*
1342c6fd2807SJeff Garzik 	 * Third item: data area for storing a single command
1343c6fd2807SJeff Garzik 	 * and its scatter-gather table
1344c6fd2807SJeff Garzik 	 */
1345c6fd2807SJeff Garzik 	pp->cmd_tbl = mem;
1346c6fd2807SJeff Garzik 	pp->cmd_tbl_dma = mem_dma;
1347c6fd2807SJeff Garzik 
1348c6fd2807SJeff Garzik 	ap->private_data = pp;
1349c6fd2807SJeff Garzik 
1350c6fd2807SJeff Garzik 	/* initialize port */
1351c6fd2807SJeff Garzik 	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
1352c6fd2807SJeff Garzik 
1353c6fd2807SJeff Garzik 	return 0;
1354c6fd2807SJeff Garzik }
1355c6fd2807SJeff Garzik 
1356c6fd2807SJeff Garzik static void ahci_port_stop(struct ata_port *ap)
1357c6fd2807SJeff Garzik {
1358cca3974eSJeff Garzik 	struct device *dev = ap->host->dev;
1359cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = ap->host->private_data;
1360c6fd2807SJeff Garzik 	struct ahci_port_priv *pp = ap->private_data;
1361cca3974eSJeff Garzik 	void __iomem *mmio = ap->host->mmio_base;
1362c6fd2807SJeff Garzik 	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1363c6fd2807SJeff Garzik 	const char *emsg = NULL;
1364c6fd2807SJeff Garzik 	int rc;
1365c6fd2807SJeff Garzik 
1366c6fd2807SJeff Garzik 	/* de-initialize port */
1367c6fd2807SJeff Garzik 	rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
1368c6fd2807SJeff Garzik 	if (rc)
1369c6fd2807SJeff Garzik 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
1370c6fd2807SJeff Garzik 
1371c6fd2807SJeff Garzik 	ap->private_data = NULL;
1372c6fd2807SJeff Garzik 	dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
1373c6fd2807SJeff Garzik 			  pp->cmd_slot, pp->cmd_slot_dma);
1374c6fd2807SJeff Garzik 	ata_pad_free(ap, dev);
1375c6fd2807SJeff Garzik 	kfree(pp);
1376c6fd2807SJeff Garzik }
1377c6fd2807SJeff Garzik 
1378c6fd2807SJeff Garzik static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
1379c6fd2807SJeff Garzik 			    unsigned int port_idx)
1380c6fd2807SJeff Garzik {
1381c6fd2807SJeff Garzik 	VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
1382c6fd2807SJeff Garzik 	base = ahci_port_base_ul(base, port_idx);
1383c6fd2807SJeff Garzik 	VPRINTK("base now==0x%lx\n", base);
1384c6fd2807SJeff Garzik 
1385c6fd2807SJeff Garzik 	port->cmd_addr		= base;
1386c6fd2807SJeff Garzik 	port->scr_addr		= base + PORT_SCR;
1387c6fd2807SJeff Garzik 
1388c6fd2807SJeff Garzik 	VPRINTK("EXIT\n");
1389c6fd2807SJeff Garzik }
1390c6fd2807SJeff Garzik 
1391c6fd2807SJeff Garzik static int ahci_host_init(struct ata_probe_ent *probe_ent)
1392c6fd2807SJeff Garzik {
1393c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv = probe_ent->private_data;
1394c6fd2807SJeff Garzik 	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
1395c6fd2807SJeff Garzik 	void __iomem *mmio = probe_ent->mmio_base;
1396c6fd2807SJeff Garzik 	unsigned int i, using_dac;
1397c6fd2807SJeff Garzik 	int rc;
1398c6fd2807SJeff Garzik 
1399c6fd2807SJeff Garzik 	rc = ahci_reset_controller(mmio, pdev);
1400c6fd2807SJeff Garzik 	if (rc)
1401c6fd2807SJeff Garzik 		return rc;
1402c6fd2807SJeff Garzik 
1403c6fd2807SJeff Garzik 	hpriv->cap = readl(mmio + HOST_CAP);
1404c6fd2807SJeff Garzik 	hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
1405c6fd2807SJeff Garzik 	probe_ent->n_ports = (hpriv->cap & 0x1f) + 1;
1406c6fd2807SJeff Garzik 
1407c6fd2807SJeff Garzik 	VPRINTK("cap 0x%x  port_map 0x%x  n_ports %d\n",
1408c6fd2807SJeff Garzik 		hpriv->cap, hpriv->port_map, probe_ent->n_ports);
1409c6fd2807SJeff Garzik 
1410c6fd2807SJeff Garzik 	using_dac = hpriv->cap & HOST_CAP_64;
1411c6fd2807SJeff Garzik 	if (using_dac &&
1412c6fd2807SJeff Garzik 	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
1413c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
1414c6fd2807SJeff Garzik 		if (rc) {
1415c6fd2807SJeff Garzik 			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1416c6fd2807SJeff Garzik 			if (rc) {
1417c6fd2807SJeff Garzik 				dev_printk(KERN_ERR, &pdev->dev,
1418c6fd2807SJeff Garzik 					   "64-bit DMA enable failed\n");
1419c6fd2807SJeff Garzik 				return rc;
1420c6fd2807SJeff Garzik 			}
1421c6fd2807SJeff Garzik 		}
1422c6fd2807SJeff Garzik 	} else {
1423c6fd2807SJeff Garzik 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
1424c6fd2807SJeff Garzik 		if (rc) {
1425c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1426c6fd2807SJeff Garzik 				   "32-bit DMA enable failed\n");
1427c6fd2807SJeff Garzik 			return rc;
1428c6fd2807SJeff Garzik 		}
1429c6fd2807SJeff Garzik 		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
1430c6fd2807SJeff Garzik 		if (rc) {
1431c6fd2807SJeff Garzik 			dev_printk(KERN_ERR, &pdev->dev,
1432c6fd2807SJeff Garzik 				   "32-bit consistent DMA enable failed\n");
1433c6fd2807SJeff Garzik 			return rc;
1434c6fd2807SJeff Garzik 		}
1435c6fd2807SJeff Garzik 	}
1436c6fd2807SJeff Garzik 
1437c6fd2807SJeff Garzik 	for (i = 0; i < probe_ent->n_ports; i++)
1438c6fd2807SJeff Garzik 		ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
1439c6fd2807SJeff Garzik 
1440c6fd2807SJeff Garzik 	ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap);
1441c6fd2807SJeff Garzik 
1442c6fd2807SJeff Garzik 	pci_set_master(pdev);
1443c6fd2807SJeff Garzik 
1444c6fd2807SJeff Garzik 	return 0;
1445c6fd2807SJeff Garzik }
1446c6fd2807SJeff Garzik 
1447c6fd2807SJeff Garzik static void ahci_print_info(struct ata_probe_ent *probe_ent)
1448c6fd2807SJeff Garzik {
1449c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv = probe_ent->private_data;
1450c6fd2807SJeff Garzik 	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
1451c6fd2807SJeff Garzik 	void __iomem *mmio = probe_ent->mmio_base;
1452c6fd2807SJeff Garzik 	u32 vers, cap, impl, speed;
1453c6fd2807SJeff Garzik 	const char *speed_s;
1454c6fd2807SJeff Garzik 	u16 cc;
1455c6fd2807SJeff Garzik 	const char *scc_s;
1456c6fd2807SJeff Garzik 
1457c6fd2807SJeff Garzik 	vers = readl(mmio + HOST_VERSION);
1458c6fd2807SJeff Garzik 	cap = hpriv->cap;
1459c6fd2807SJeff Garzik 	impl = hpriv->port_map;
1460c6fd2807SJeff Garzik 
1461c6fd2807SJeff Garzik 	speed = (cap >> 20) & 0xf;
1462c6fd2807SJeff Garzik 	if (speed == 1)
1463c6fd2807SJeff Garzik 		speed_s = "1.5";
1464c6fd2807SJeff Garzik 	else if (speed == 2)
1465c6fd2807SJeff Garzik 		speed_s = "3";
1466c6fd2807SJeff Garzik 	else
1467c6fd2807SJeff Garzik 		speed_s = "?";
1468c6fd2807SJeff Garzik 
1469c6fd2807SJeff Garzik 	pci_read_config_word(pdev, 0x0a, &cc);
1470c6fd2807SJeff Garzik 	if (cc == 0x0101)
1471c6fd2807SJeff Garzik 		scc_s = "IDE";
1472c6fd2807SJeff Garzik 	else if (cc == 0x0106)
1473c6fd2807SJeff Garzik 		scc_s = "SATA";
1474c6fd2807SJeff Garzik 	else if (cc == 0x0104)
1475c6fd2807SJeff Garzik 		scc_s = "RAID";
1476c6fd2807SJeff Garzik 	else
1477c6fd2807SJeff Garzik 		scc_s = "unknown";
1478c6fd2807SJeff Garzik 
1479c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
1480c6fd2807SJeff Garzik 		"AHCI %02x%02x.%02x%02x "
1481c6fd2807SJeff Garzik 		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
1482c6fd2807SJeff Garzik 	       	,
1483c6fd2807SJeff Garzik 
1484c6fd2807SJeff Garzik 	       	(vers >> 24) & 0xff,
1485c6fd2807SJeff Garzik 	       	(vers >> 16) & 0xff,
1486c6fd2807SJeff Garzik 	       	(vers >> 8) & 0xff,
1487c6fd2807SJeff Garzik 	       	vers & 0xff,
1488c6fd2807SJeff Garzik 
1489c6fd2807SJeff Garzik 		((cap >> 8) & 0x1f) + 1,
1490c6fd2807SJeff Garzik 		(cap & 0x1f) + 1,
1491c6fd2807SJeff Garzik 		speed_s,
1492c6fd2807SJeff Garzik 		impl,
1493c6fd2807SJeff Garzik 		scc_s);
1494c6fd2807SJeff Garzik 
1495c6fd2807SJeff Garzik 	dev_printk(KERN_INFO, &pdev->dev,
1496c6fd2807SJeff Garzik 		"flags: "
1497c6fd2807SJeff Garzik 	       	"%s%s%s%s%s%s"
1498c6fd2807SJeff Garzik 	       	"%s%s%s%s%s%s%s\n"
1499c6fd2807SJeff Garzik 	       	,
1500c6fd2807SJeff Garzik 
1501c6fd2807SJeff Garzik 		cap & (1 << 31) ? "64bit " : "",
1502c6fd2807SJeff Garzik 		cap & (1 << 30) ? "ncq " : "",
1503c6fd2807SJeff Garzik 		cap & (1 << 28) ? "ilck " : "",
1504c6fd2807SJeff Garzik 		cap & (1 << 27) ? "stag " : "",
1505c6fd2807SJeff Garzik 		cap & (1 << 26) ? "pm " : "",
1506c6fd2807SJeff Garzik 		cap & (1 << 25) ? "led " : "",
1507c6fd2807SJeff Garzik 
1508c6fd2807SJeff Garzik 		cap & (1 << 24) ? "clo " : "",
1509c6fd2807SJeff Garzik 		cap & (1 << 19) ? "nz " : "",
1510c6fd2807SJeff Garzik 		cap & (1 << 18) ? "only " : "",
1511c6fd2807SJeff Garzik 		cap & (1 << 17) ? "pmp " : "",
1512c6fd2807SJeff Garzik 		cap & (1 << 15) ? "pio " : "",
1513c6fd2807SJeff Garzik 		cap & (1 << 14) ? "slum " : "",
1514c6fd2807SJeff Garzik 		cap & (1 << 13) ? "part " : ""
1515c6fd2807SJeff Garzik 		);
1516c6fd2807SJeff Garzik }
1517c6fd2807SJeff Garzik 
1518c6fd2807SJeff Garzik static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
1519c6fd2807SJeff Garzik {
1520c6fd2807SJeff Garzik 	static int printed_version;
1521c6fd2807SJeff Garzik 	struct ata_probe_ent *probe_ent = NULL;
1522c6fd2807SJeff Garzik 	struct ahci_host_priv *hpriv;
1523c6fd2807SJeff Garzik 	unsigned long base;
1524c6fd2807SJeff Garzik 	void __iomem *mmio_base;
1525c6fd2807SJeff Garzik 	unsigned int board_idx = (unsigned int) ent->driver_data;
1526c6fd2807SJeff Garzik 	int have_msi, pci_dev_busy = 0;
1527c6fd2807SJeff Garzik 	int rc;
1528c6fd2807SJeff Garzik 
1529c6fd2807SJeff Garzik 	VPRINTK("ENTER\n");
1530c6fd2807SJeff Garzik 
1531c6fd2807SJeff Garzik 	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
1532c6fd2807SJeff Garzik 
1533c6fd2807SJeff Garzik 	if (!printed_version++)
1534c6fd2807SJeff Garzik 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
1535c6fd2807SJeff Garzik 
1536c6fd2807SJeff Garzik 	/* JMicron-specific fixup: make sure we're in AHCI mode */
1537c6fd2807SJeff Garzik 	/* This is protected from races with ata_jmicron by the pci probe
1538c6fd2807SJeff Garzik 	   locking */
1539c6fd2807SJeff Garzik 	if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
1540c6fd2807SJeff Garzik 		/* AHCI enable, AHCI on function 0 */
1541c6fd2807SJeff Garzik 		pci_write_config_byte(pdev, 0x41, 0xa1);
1542c6fd2807SJeff Garzik 		/* Function 1 is the PATA controller */
1543c6fd2807SJeff Garzik 		if (PCI_FUNC(pdev->devfn))
1544c6fd2807SJeff Garzik 			return -ENODEV;
1545c6fd2807SJeff Garzik 	}
1546c6fd2807SJeff Garzik 
1547c6fd2807SJeff Garzik 	rc = pci_enable_device(pdev);
1548c6fd2807SJeff Garzik 	if (rc)
1549c6fd2807SJeff Garzik 		return rc;
1550c6fd2807SJeff Garzik 
1551c6fd2807SJeff Garzik 	rc = pci_request_regions(pdev, DRV_NAME);
1552c6fd2807SJeff Garzik 	if (rc) {
1553c6fd2807SJeff Garzik 		pci_dev_busy = 1;
1554c6fd2807SJeff Garzik 		goto err_out;
1555c6fd2807SJeff Garzik 	}
1556c6fd2807SJeff Garzik 
1557c6fd2807SJeff Garzik 	if (pci_enable_msi(pdev) == 0)
1558c6fd2807SJeff Garzik 		have_msi = 1;
1559c6fd2807SJeff Garzik 	else {
1560c6fd2807SJeff Garzik 		pci_intx(pdev, 1);
1561c6fd2807SJeff Garzik 		have_msi = 0;
1562c6fd2807SJeff Garzik 	}
1563c6fd2807SJeff Garzik 
1564c6fd2807SJeff Garzik 	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
1565c6fd2807SJeff Garzik 	if (probe_ent == NULL) {
1566c6fd2807SJeff Garzik 		rc = -ENOMEM;
1567c6fd2807SJeff Garzik 		goto err_out_msi;
1568c6fd2807SJeff Garzik 	}
1569c6fd2807SJeff Garzik 
1570c6fd2807SJeff Garzik 	memset(probe_ent, 0, sizeof(*probe_ent));
1571c6fd2807SJeff Garzik 	probe_ent->dev = pci_dev_to_dev(pdev);
1572c6fd2807SJeff Garzik 	INIT_LIST_HEAD(&probe_ent->node);
1573c6fd2807SJeff Garzik 
1574c6fd2807SJeff Garzik 	mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
1575c6fd2807SJeff Garzik 	if (mmio_base == NULL) {
1576c6fd2807SJeff Garzik 		rc = -ENOMEM;
1577c6fd2807SJeff Garzik 		goto err_out_free_ent;
1578c6fd2807SJeff Garzik 	}
1579c6fd2807SJeff Garzik 	base = (unsigned long) mmio_base;
1580c6fd2807SJeff Garzik 
1581c6fd2807SJeff Garzik 	hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
1582c6fd2807SJeff Garzik 	if (!hpriv) {
1583c6fd2807SJeff Garzik 		rc = -ENOMEM;
1584c6fd2807SJeff Garzik 		goto err_out_iounmap;
1585c6fd2807SJeff Garzik 	}
1586c6fd2807SJeff Garzik 	memset(hpriv, 0, sizeof(*hpriv));
1587c6fd2807SJeff Garzik 
1588c6fd2807SJeff Garzik 	probe_ent->sht		= ahci_port_info[board_idx].sht;
1589cca3974eSJeff Garzik 	probe_ent->port_flags	= ahci_port_info[board_idx].flags;
1590c6fd2807SJeff Garzik 	probe_ent->pio_mask	= ahci_port_info[board_idx].pio_mask;
1591c6fd2807SJeff Garzik 	probe_ent->udma_mask	= ahci_port_info[board_idx].udma_mask;
1592c6fd2807SJeff Garzik 	probe_ent->port_ops	= ahci_port_info[board_idx].port_ops;
1593c6fd2807SJeff Garzik 
1594c6fd2807SJeff Garzik        	probe_ent->irq = pdev->irq;
1595c6fd2807SJeff Garzik        	probe_ent->irq_flags = IRQF_SHARED;
1596c6fd2807SJeff Garzik 	probe_ent->mmio_base = mmio_base;
1597c6fd2807SJeff Garzik 	probe_ent->private_data = hpriv;
1598c6fd2807SJeff Garzik 
1599c6fd2807SJeff Garzik 	if (have_msi)
1600c6fd2807SJeff Garzik 		hpriv->flags |= AHCI_FLAG_MSI;
1601c6fd2807SJeff Garzik 
1602c6fd2807SJeff Garzik 	/* initialize adapter */
1603c6fd2807SJeff Garzik 	rc = ahci_host_init(probe_ent);
1604c6fd2807SJeff Garzik 	if (rc)
1605c6fd2807SJeff Garzik 		goto err_out_hpriv;
1606c6fd2807SJeff Garzik 
1607cca3974eSJeff Garzik 	if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
1608c6fd2807SJeff Garzik 	    (hpriv->cap & HOST_CAP_NCQ))
1609cca3974eSJeff Garzik 		probe_ent->port_flags |= ATA_FLAG_NCQ;
1610c6fd2807SJeff Garzik 
1611c6fd2807SJeff Garzik 	ahci_print_info(probe_ent);
1612c6fd2807SJeff Garzik 
1613c6fd2807SJeff Garzik 	/* FIXME: check ata_device_add return value */
1614c6fd2807SJeff Garzik 	ata_device_add(probe_ent);
1615c6fd2807SJeff Garzik 	kfree(probe_ent);
1616c6fd2807SJeff Garzik 
1617c6fd2807SJeff Garzik 	return 0;
1618c6fd2807SJeff Garzik 
1619c6fd2807SJeff Garzik err_out_hpriv:
1620c6fd2807SJeff Garzik 	kfree(hpriv);
1621c6fd2807SJeff Garzik err_out_iounmap:
1622c6fd2807SJeff Garzik 	pci_iounmap(pdev, mmio_base);
1623c6fd2807SJeff Garzik err_out_free_ent:
1624c6fd2807SJeff Garzik 	kfree(probe_ent);
1625c6fd2807SJeff Garzik err_out_msi:
1626c6fd2807SJeff Garzik 	if (have_msi)
1627c6fd2807SJeff Garzik 		pci_disable_msi(pdev);
1628c6fd2807SJeff Garzik 	else
1629c6fd2807SJeff Garzik 		pci_intx(pdev, 0);
1630c6fd2807SJeff Garzik 	pci_release_regions(pdev);
1631c6fd2807SJeff Garzik err_out:
1632c6fd2807SJeff Garzik 	if (!pci_dev_busy)
1633c6fd2807SJeff Garzik 		pci_disable_device(pdev);
1634c6fd2807SJeff Garzik 	return rc;
1635c6fd2807SJeff Garzik }
1636c6fd2807SJeff Garzik 
1637c6fd2807SJeff Garzik static void ahci_remove_one (struct pci_dev *pdev)
1638c6fd2807SJeff Garzik {
1639c6fd2807SJeff Garzik 	struct device *dev = pci_dev_to_dev(pdev);
1640cca3974eSJeff Garzik 	struct ata_host *host = dev_get_drvdata(dev);
1641cca3974eSJeff Garzik 	struct ahci_host_priv *hpriv = host->private_data;
1642c6fd2807SJeff Garzik 	unsigned int i;
1643c6fd2807SJeff Garzik 	int have_msi;
1644c6fd2807SJeff Garzik 
1645cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++)
1646cca3974eSJeff Garzik 		ata_port_detach(host->ports[i]);
1647c6fd2807SJeff Garzik 
1648c6fd2807SJeff Garzik 	have_msi = hpriv->flags & AHCI_FLAG_MSI;
1649cca3974eSJeff Garzik 	free_irq(host->irq, host);
1650c6fd2807SJeff Garzik 
1651cca3974eSJeff Garzik 	for (i = 0; i < host->n_ports; i++) {
1652cca3974eSJeff Garzik 		struct ata_port *ap = host->ports[i];
1653c6fd2807SJeff Garzik 
1654cca3974eSJeff Garzik 		ata_scsi_release(ap->scsi_host);
1655cca3974eSJeff Garzik 		scsi_host_put(ap->scsi_host);
1656c6fd2807SJeff Garzik 	}
1657c6fd2807SJeff Garzik 
1658c6fd2807SJeff Garzik 	kfree(hpriv);
1659cca3974eSJeff Garzik 	pci_iounmap(pdev, host->mmio_base);
1660cca3974eSJeff Garzik 	kfree(host);
1661c6fd2807SJeff Garzik 
1662c6fd2807SJeff Garzik 	if (have_msi)
1663c6fd2807SJeff Garzik 		pci_disable_msi(pdev);
1664c6fd2807SJeff Garzik 	else
1665c6fd2807SJeff Garzik 		pci_intx(pdev, 0);
1666c6fd2807SJeff Garzik 	pci_release_regions(pdev);
1667c6fd2807SJeff Garzik 	pci_disable_device(pdev);
1668c6fd2807SJeff Garzik 	dev_set_drvdata(dev, NULL);
1669c6fd2807SJeff Garzik }
1670c6fd2807SJeff Garzik 
1671c6fd2807SJeff Garzik static int __init ahci_init(void)
1672c6fd2807SJeff Garzik {
1673c6fd2807SJeff Garzik 	return pci_register_driver(&ahci_pci_driver);
1674c6fd2807SJeff Garzik }
1675c6fd2807SJeff Garzik 
1676c6fd2807SJeff Garzik static void __exit ahci_exit(void)
1677c6fd2807SJeff Garzik {
1678c6fd2807SJeff Garzik 	pci_unregister_driver(&ahci_pci_driver);
1679c6fd2807SJeff Garzik }
1680c6fd2807SJeff Garzik 
1681c6fd2807SJeff Garzik 
1682c6fd2807SJeff Garzik MODULE_AUTHOR("Jeff Garzik");
1683c6fd2807SJeff Garzik MODULE_DESCRIPTION("AHCI SATA low-level driver");
1684c6fd2807SJeff Garzik MODULE_LICENSE("GPL");
1685c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
1686c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION);
1687c6fd2807SJeff Garzik 
1688c6fd2807SJeff Garzik module_init(ahci_init);
1689c6fd2807SJeff Garzik module_exit(ahci_exit);
1690