mv_sas.c revision b5762948263dd5e9725a380e7a9626f99e40ae9d
1b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/*
2b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvsas.c - Marvell 88SE6440 SAS/SATA support
3b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
4b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	Copyright 2007 Red Hat, Inc.
5b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	This program is free software; you can redistribute it and/or
7b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	modify it under the terms of the GNU General Public License as
8b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	published by the Free Software Foundation; either version 2,
9b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	or (at your option) any later version.
10b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
11b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	This program is distributed in the hope that it will be useful,
12b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	but WITHOUT ANY WARRANTY; without even the implied warranty
13b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	See the GNU General Public License for more details.
15b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	You should have received a copy of the GNU General Public
17b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	License along with this program; see the file COPYING.	If not,
18b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	write to the Free Software Foundation, 675 Mass Ave, Cambridge,
19b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MA 02139, USA.
20b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
21b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	---------------------------------------------------------------
22b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
23b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	Random notes:
24b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	* hardware supports controlling the endian-ness of data
25b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	  structures.  this permits elimination of all the le32_to_cpu()
26b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	  and cpu_to_le32() conversions.
27b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
28b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */
29b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
30b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/kernel.h>
31b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/module.h>
32b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/pci.h>
33b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/interrupt.h>
34b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/spinlock.h>
35b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/delay.h>
36b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/dma-mapping.h>
37b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <scsi/libsas.h>
38b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <asm/io.h>
39b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
40b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define DRV_NAME "mvsas"
41b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define DRV_VERSION "0.1"
42b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
43b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define mr32(reg)	readl(regs + MVS_##reg)
44b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define mw32(reg,val)	writel((val), regs + MVS_##reg)
45b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define mw32_f(reg,val)	do {		\
46b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	writel((val), regs + MVS_##reg);	\
47b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	readl(regs + MVS_##reg);		\
48b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	} while (0)
49b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
50b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* driver compile-time configuration */
51b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum driver_configuration {
52b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_TX_RING_SZ		= 1024,	/* TX ring size (12-bit) */
53b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_RING_SZ		= 1024, /* RX ring size (12-bit) */
54b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					/* software requires power-of-2
55b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					   ring size */
56b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
57b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_SLOTS		= 512,	/* command slots */
58b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_SLOT_BUF_SZ		= 8192, /* cmd tbl + IU + status + PRD */
59b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_SSP_CMD_SZ		= 64,	/* SSP command table buffer size */
60b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_ATA_CMD_SZ		= 128,	/* SATA command table buffer size */
61b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_OAF_SZ		= 64,	/* Open address frame buffer size */
62b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
63b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_FIS_COUNT	= 17,	/* Optional rx'd FISs (max 17) */
64b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
65b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
66b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* unchangeable hardware details */
67b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum hardware_details {
68b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_MAX_PHYS		= 8,	/* max. possible phys */
69b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_MAX_PORTS		= 8,	/* max. possible ports */
70b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_FISL_SZ		= 0x400 + (MVS_RX_FIS_COUNT * 0x100),
71b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
72b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
73b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* peripheral registers (BAR2) */
74b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum peripheral_registers {
75b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SPI_CTL			= 0x10,	/* EEPROM control */
76b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SPI_CMD			= 0x14,	/* EEPROM command */
77b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SPI_DATA		= 0x18, /* EEPROM data */
78b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
79b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
80b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum peripheral_register_bits {
81b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TWSI_RDY		= (1U << 7),	/* EEPROM interface ready */
82b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TWSI_RD			= (1U << 4),	/* EEPROM read access */
83b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
84b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SPI_ADDR_MASK		= 0x3ffff,	/* bits 17:0 */
85b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
86b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
87b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* enhanced mode registers (BAR4) */
88b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum hw_registers {
89b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_GBL_CTL		= 0x04,  /* global control */
90b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_GBL_INT_STAT	= 0x08,  /* global irq status */
91b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_GBL_PI		= 0x0C,  /* ports implemented bitmask */
92b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_GBL_PORT_TYPE	= 0x00,  /* port type */
93b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
94b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CTL			= 0x100, /* SAS/SATA port configuration */
95b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_PCS			= 0x104, /* SAS/SATA port control/status */
96b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CMD_LIST_LO		= 0x108, /* cmd list addr */
97b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CMD_LIST_HI		= 0x10C,
98b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_FIS_LO		= 0x110, /* RX FIS list addr */
99b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_FIS_HI		= 0x114,
100b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
101b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_TX_CFG		= 0x120, /* TX configuration */
102b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_TX_LO		= 0x124, /* TX (delivery) ring addr */
103b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_TX_HI		= 0x128,
104b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
105b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_PROD_IDX		= 0x12C, /* RX producer pointer */
106b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_CONS_IDX		= 0x130, /* RX consumer pointer (RO) */
107b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_CFG		= 0x134, /* RX configuration */
108b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_LO		= 0x138, /* RX (completion) ring addr */
109b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_HI		= 0x13C,
110b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
111b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_COAL		= 0x148, /* Int coalescing config */
112b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_COAL_TMOUT	= 0x14C, /* Int coalescing timeout */
113b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_STAT		= 0x150, /* Central int status */
114b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_MASK		= 0x154, /* Central int enable */
115b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_STAT_SRS	= 0x158, /* SATA register set status */
116b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
117b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					 /* ports 1-3 follow after this */
118b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_INT_STAT		= 0x160, /* port0 interrupt status */
119b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_INT_MASK		= 0x164, /* port0 interrupt mask */
120b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
121b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					 /* ports 1-3 follow after this */
122b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_SER_CTLSTAT	= 0x180, /* port0 serial control/status */
123b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
124b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CMD_ADDR		= 0x1B8, /* Command register port (addr) */
125b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CMD_DATA		= 0x1BC, /* Command register port (data) */
126b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
127b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					 /* ports 1-3 follow after this */
128b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_CFG_ADDR		= 0x1C0, /* port0 phy register address */
129b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_CFG_DATA		= 0x1C4, /* port0 phy register data */
130b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
131b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
132b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum hw_register_bits {
133b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_GBL_CTL */
134b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	INT_EN			= (1U << 1),	/* Global int enable */
135b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	HBA_RST			= (1U << 0),	/* HBA reset */
136b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
137b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_GBL_INT_STAT */
138b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	INT_XOR			= (1U << 4),	/* XOR engine event */
139b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	INT_SAS_SATA		= (1U << 0),	/* SAS/SATA event */
140b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
141b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_GBL_PORT_TYPE */			/* shl for ports 1-3 */
142b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SATA_TARGET		= (1U << 16),	/* port0 SATA target enable */
143b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	AUTO_DET		= (1U << 8),	/* port0 SAS/SATA autodetect */
144b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SAS_MODE		= (1U << 0),	/* port0 SAS(1), SATA(0) mode */
145b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* SAS_MODE value may be
146b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						 * dictated (in hw) by values
147b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						 * of SATA_TARGET & AUTO_DET
148b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						 */
149b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
150b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_TX_CFG */
151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TX_EN			= (1U << 16),	/* Enable TX */
152b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TX_RING_SZ_MASK		= 0xfff,	/* TX ring size, bits 11:0 */
153b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
154b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_RX_CFG */
155b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RX_EN			= (1U << 16),	/* Enable RX */
156b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RX_RING_SZ_MASK		= 0xfff,	/* RX ring size, bits 11:0 */
157b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
158b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_INT_COAL */
159b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	COAL_EN			= (1U << 16),	/* Enable int coalescing */
160b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
161b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_INT_STAT, MVS_INT_MASK */
162b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_I2C		= (1U << 31),	/* I2C event */
163b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_SW0		= (1U << 30),	/* software event 0 */
164b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_SW1		= (1U << 29),	/* software event 1 */
165b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_PRD_BC		= (1U << 28),	/* PRD BC err for read cmd */
166b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_DMA_PCIE		= (1U << 27),	/* DMA to PCIE timeout */
167b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_MEM		= (1U << 26),	/* int mem parity err */
168b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_I2C_SLAVE		= (1U << 25),	/* slave I2C event */
169b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_SRS		= (1U << 3),	/* SRS event */
170b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_CI_STOP		= (1U << 10),	/* cmd issue stopped */
171b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_DONE		= (1U << 0),	/* cmd completion */
172b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
173b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* shl for ports 1-3 */
174b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_PORT_STOPPED	= (1U << 16),	/* port0 stopped */
175b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_PORT		= (1U << 8),	/* port0 event */
176b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
177b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* TX (delivery) ring bits */
178b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SHIFT		= 29,
179b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SSP		= 1,		/* SSP protocol */
180b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SMP		= 2,		/* SMP protocol */
181b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_STP		= 3,		/* STP/SATA protocol */
182b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SSP_FREE_LIST	= 4,		/* add to SSP targ free list */
183b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SLOT_RESET	= 7,		/* reset command slot */
184b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_MODE_I		= (1U << 28),	/* mode: 0=target,1=initiator */
185b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_PRIO_HI		= (1U << 27),	/* priority: 0=normal, 1=high */
186b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_SRS_SHIFT		= 20,		/* SATA register set */
187b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_SRS_MASK		= 0x7f,
188b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_PHY_SHIFT		= 12,		/* PHY bitmap */
189b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_PHY_MASK		= 0xff,
190b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_SLOT_MASK		= 0xfff,	/* slot number */
191b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
192b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* RX (completion) ring bits */
193b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_GOOD		= (1U << 23),	/* Response good */
194b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_SLOT_RESET		= (1U << 21),	/* Slot reset complete */
195b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_CMD_RX		= (1U << 20),	/* target cmd received */
196b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_ATTN		= (1U << 19),	/* attention */
197b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_RSP			= (1U << 18),	/* response frame xfer'd */
198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_ERR			= (1U << 17),	/* err info rec xfer'd */
199b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_DONE		= (1U << 16),	/* cmd complete */
200b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_SLOT_MASK		= 0xfff,	/* slot number */
201b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
202b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* mvs_cmd_hdr bits */
203b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_PRD_LEN_SHIFT	= 16,		/* 16-bit PRD table len */
204b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_TYPE_SHIFT	= 13,		/* SSP frame type */
205b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
206b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* SSP initiator only */
207b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_CMD		= 0x0,		/* COMMAND frame */
208b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
209b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* SSP initiator or target */
210b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_TASK		= 0x1,		/* TASK frame */
211b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
212b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* SSP target only */
213b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_XFER_RDY	= 0x4,		/* XFER_RDY frame */
214b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_RESP		= 0x5,		/* RESPONSE frame */
215b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_READ		= 0x6,		/* Read DATA frame(s) */
216b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_READ_RESP	= 0x7,		/* ditto, plus RESPONSE */
217b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
218b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_PASSTHRU		= (1U << 12),	/* pass-through (SSP) */
219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_FBURST		= (1U << 11),	/* first burst (SSP) */
220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_CHK_LEN		= (1U << 10),	/* chk xfer len (SSP) */
221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_RETRY		= (1U << 9),	/* tport layer retry (SSP) */
222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_PROTECTION		= (1U << 8),	/* protection info rec (SSP) */
223b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_RESET		= (1U << 7),	/* Reset (STP/SATA) */
224b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_FPDMA		= (1U << 6),	/* First party DMA (STP/SATA) */
225b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_ATAPI		= (1U << 5),	/* ATAPI (STP/SATA) */
226b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_BIST		= (1U << 4),	/* BIST activate (STP/SATA) */
227b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_PMP_MASK		= 0xf,		/* PMP from cmd FIS (STP/SATA)*/
228b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
229b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_RST		= (1U << 5),	/* port logic reset */
230b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* 0(LSB first), 1(MSB first) */
232b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_ENDIAN_DATA	= (1U << 3),	/* PRD data */
233b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_ENDIAN_RSP		= (1U << 2),	/* response frame */
234b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_ENDIAN_OPEN	= (1U << 1),	/* open address frame */
235b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_ENDIAN_CMD		= (1U << 0),	/* command table */
236b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
237b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_Px_SER_CTLSTAT (per-phy control) */
238b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHY_SSP_RST		= (1U << 3),	/* reset SSP link layer */
239b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHY_BCAST_CHG		= (1U << 2),	/* broadcast(change) notif */
240b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHY_RST_HARD		= (1U << 1),	/* hard reset + phy reset */
241b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHY_RST			= (1U << 0),	/* phy reset */
242b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
243b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
244b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_UNASSOC_FIS	= (1U << 19),	/* unassociated FIS rx'd */
245b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_AN		= (1U << 18),	/* SATA async notification */
246b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_BIST_ACT		= (1U << 17),	/* BIST activate FIS */
247b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_SIG_FIS		= (1U << 16),	/* signature FIS */
248b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_POOF		= (1U << 12),	/* phy ready from 1 -> 0 */
249b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_IU_BIG		= (1U << 11),	/* IU too long err */
250b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_IU_SMALL		= (1U << 10),	/* IU too short err */
251b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_UNK_TAG		= (1U << 9),	/* unknown tag */
252b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_BROAD_CH		= (1U << 8),	/* broadcast(CHANGE) */
253b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_COMWAKE		= (1U << 7),	/* COMWAKE rx'd */
254b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_PORT_SEL		= (1U << 6),	/* port selector present */
255b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_HARD_RST		= (1U << 5),	/* hard reset rx'd */
256b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_ID_TMOUT		= (1U << 4),	/* identify timeout */
257b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_ID_FAIL		= (1U << 3),	/* identify failed */
258b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_ID_DONE		= (1U << 2),	/* identify done */
259b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_HARD_RST_DONE	= (1U << 1),	/* hard reset done */
260b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_RDY_CH		= (1U << 0),	/* phy ready changed state */
261b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
262b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_PCS */
263b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_SATA_RETRY		= (1U << 8),	/* retry ctl FIS on R_ERR */
264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_RSP_RX_EN		= (1U << 7),	/* raw response rx */
265b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_SELF_CLEAR		= (1U << 5),	/* self-clearing int mode */
266b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_FIS_RX_EN		= (1U << 4),	/* FIS rx enable */
267b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_CMD_STOP_ERR	= (1U << 3),	/* cmd stop-on-err enable */
268b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_CMD_RST		= (1U << 2),	/* reset cmd issue */
269b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_CMD_EN		= (1U << 0),	/* enable cmd issue */
270b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
272b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum mvs_info_flags {
273b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVF_MSI			= (1U << 0),	/* MSI is enabled */
274b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVF_PHY_PWR_FIX		= (1U << 1),	/* bug workaround */
275b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
276b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
277b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum sas_cmd_port_registers {
278b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_CMRST_OOB_DET	= 0x100, /* COMRESET OOB detect register */
279b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_CMWK_OOB_DET	= 0x104, /* COMWAKE OOB detect register */
280b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_CMSAS_OOB_DET	= 0x108, /* COMSAS OOB detect register */
281b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_BRST_OOB_DET	= 0x10c, /* burst OOB detect register */
282b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_OOB_SPACE		= 0x110, /* OOB space control register */
283b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_OOB_BURST		= 0x114, /* OOB burst control register */
284b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_TIMER		= 0x118, /* PHY timer control register */
285b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_CONFIG0		= 0x11c, /* PHY config register 0 */
286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_CONFIG1		= 0x120, /* PHY config register 1 */
287b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SAS_CTL0		= 0x124, /* SAS control register 0 */
288b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SAS_CTL1		= 0x128, /* SAS control register 1 */
289b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SAS_CTL2		= 0x12c, /* SAS control register 2 */
290b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SAS_CTL3		= 0x130, /* SAS control register 3 */
291b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_ID_TEST		= 0x134, /* ID test register */
292b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PL_TIMER		= 0x138, /* PL timer register */
293b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_WD_TIMER		= 0x13c, /* WD timer register */
294b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_SEL_COUNT	= 0x140, /* port selector count register */
295b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_APP_MEM_CTL		= 0x144, /* Application Memory Control */
296b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_XOR_MEM_CTL		= 0x148, /* XOR Block Memory Control */
297b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_DMA_MEM_CTL		= 0x14c, /* DMA Block Memory Control */
298b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_CTL0	= 0x150, /* Port Memory Control 0 */
299b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_CTL1	= 0x154, /* Port Memory Control 1 */
300b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SATA_PORT_MEM_CTL0	= 0x158, /* SATA Port Memory Control 0 */
301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SATA_PORT_MEM_CTL1	= 0x15c, /* SATA Port Memory Control 1 */
302b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_XOR_MEM_BIST_CTL	= 0x160, /* XOR Memory BIST Control */
303b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_XOR_MEM_BIST_STAT	= 0x164, /* XOR Memroy BIST Status */
304b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_DMA_MEM_BIST_CTL	= 0x168, /* DMA Memory BIST Control */
305b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_DMA_MEM_BIST_STAT	= 0x16c, /* DMA Memory BIST Status */
306b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_BIST_CTL	= 0x170, /* Port Memory BIST Control */
307b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */
308b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */
309b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_STP_MEM_BIST_CTL	= 0x17c, /* STP Memory BIST Control */
310b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_STP_MEM_BIST_STAT0	= 0x180, /* STP Memory BIST Status 0 */
311b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_STP_MEM_BIST_STAT1	= 0x184, /* STP Memory BIST Status 1 */
312b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_RESET_COUNT		= 0x188, /* Reset Count */
313b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_MONTR_DATA_SEL	= 0x18C, /* Monitor Data/Select */
314b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PLL_PHY_CONFIG	= 0x190, /* PLL/PHY Configuration */
315b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_CTL		= 0x194, /* PHY Control and Status */
316b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_TEST_COUNT0	= 0x198, /* Phy Test Count 0 */
317b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_TEST_COUNT1	= 0x19C, /* Phy Test Count 1 */
318b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_TEST_COUNT2	= 0x1A0, /* Phy Test Count 2 */
319b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_APP_ERR_CONFIG	= 0x1A4, /* Application Error Configuration */
320b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PND_FIFO_CTL0	= 0x1A8, /* Pending FIFO Control 0 */
321b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_HOST_CTL		= 0x1AC, /* Host Control Status */
322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_HOST_WR_DATA	= 0x1B0, /* Host Write Data */
323b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_HOST_RD_DATA	= 0x1B4, /* Host Read Data */
324b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_MODE_21		= 0x1B8, /* Phy Mode 21 */
325b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SL_MODE0		= 0x1BC, /* SL Mode 0 */
326b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SL_MODE1		= 0x1C0, /* SL Mode 1 */
327b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PND_FIFO_CTL1	= 0x1C4, /* Pending FIFO Control 1 */
328b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
329b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
330b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* SAS/SATA configuration port registers, aka phy registers */
331b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum sas_sata_config_port_regs {
332b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_IDENTIFY		= 0x0,	/* info for IDENTIFY frame */
333b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_ADDR_LO		= 0x4,	/* my SAS address (low) */
334b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_ADDR_HI		= 0x8,	/* my SAS address (high) */
335b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_ATT_DEV_INFO	= 0xC,	/* attached device info */
336b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_ATT_ADDR_LO	= 0x10,	/* attached dev SAS addr (low) */
337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_ATT_ADDR_HI	= 0x14,	/* attached dev SAS addr (high) */
338b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_SATA_CTL		= 0x18,	/* SATA control */
339b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_PHY_STAT		= 0x1C,	/* PHY status */
340b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_WIDE_PORT		= 0x38,	/* wide port participating */
341b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_CURRENT0		= 0x80,	/* current connection info 0 */
342b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_CURRENT1		= 0x84,	/* current connection info 1 */
343b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_CURRENT2		= 0x88,	/* current connection info 2 */
344b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
345b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
346b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum pci_cfg_registers {
347b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCR_PHY_CTL		= 0x40,
348b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCR_PHY_CTL2		= 0x90,
349b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
350b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
351b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum pci_cfg_register_bits {
352b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCTL_PWR_ON		= (0xFU << 24),
353b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCTL_OFF		= (0xFU << 12),
354b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
355b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
356b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum nvram_layout_offsets {
357b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	NVR_SIG			= 0x00,		/* 0xAA, 0x55 */
358b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	NVR_SAS_ADDR		= 0x02,		/* 8-byte SAS address */
359b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
360b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
361b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum chip_flavors {
362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	chip_6320,
363b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	chip_6440,
364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	chip_6480,
365b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
367b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_chip_info {
368b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int		n_phy;
369b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int		srs_sz;
370b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int		slot_width;
371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
372b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
373b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_err_info {
374b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			flags;
375b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			flags2;
376b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_prd {
379b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			addr;		/* 64-bit buffer address */
380b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			reserved;
381b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			len;		/* 16-bit length */
382b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
384b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_cmd_hdr {
385b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			flags;		/* PRD tbl len; SAS, SATA ctl */
386b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			lens;		/* cmd, max resp frame len */
387b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			tags;		/* targ port xfer tag; tag */
388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			data_len;	/* data xfer len */
389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			cmd_tbl;	/* command table address */
390b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			open_frame;	/* open addr frame address */
391b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			status_buf;	/* status buffer address */
392b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			prd_tbl;	/* PRD tbl address */
393b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			reserved[4];
394b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
395b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
396b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_slot_info {
397b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task		*task;
398b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int		n_elem;
399b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
400b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* DMA buffer for storing cmd tbl, open addr frame, status buffer,
401b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * and PRD table
402b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
403b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void			*buf;
404b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		buf_dma;
405b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
406b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void			*response;
407b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
408b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
409b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_port {
410b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port	sas_port;
411b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
412b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
413b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_phy {
414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_port		*port;
415b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_phy	sas_phy;
416b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
417b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8			frame_rcvd[24 + 1024];
418b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
419b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
420b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_info {
421b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned long		flags;
422b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
423b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spinlock_t		lock;		/* host-wide lock */
424b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct pci_dev		*pdev;		/* our device */
425b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem		*regs;		/* enhanced mode registers */
426b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem		*peri_regs;	/* peripheral registers */
427b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
428b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8			sas_addr[SAS_ADDR_SIZE];
429b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_ha_struct	sas;		/* SCSI/SAS glue */
430b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct Scsi_Host	*shost;
431b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
432b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			*tx;		/* TX (delivery) DMA ring */
433b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		tx_dma;
434b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32			tx_prod;	/* cached next-producer idx */
435b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
436b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			*rx;		/* RX (completion) DMA ring */
437b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		rx_dma;
438b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32			rx_cons;	/* RX consumer idx */
439b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
440b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			*rx_fis;	/* RX'd FIS area */
441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		rx_fis_dma;
442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
443b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr	*slot;		/* DMA command header slots */
444b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		slot_dma;
445b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
446b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	const struct mvs_chip_info *chip;
447b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
448b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					/* further per-slot information */
449b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info	slot_info[MVS_SLOTS];
450b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned long		tags[(MVS_SLOTS / sizeof(unsigned long)) + 1];
451b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
452b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_phy		phy[MVS_MAX_PHYS];
453b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_port		port[MVS_MAX_PHYS];
454b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
455b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
456b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct scsi_transport_template *mvs_stt;
457b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
458b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic const struct mvs_chip_info mvs_chips[] = {
459b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	[chip_6320] =		{ 2, 16, 9 },
460b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	[chip_6440] =		{ 4, 16, 9 },
461b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	[chip_6480] =		{ 8, 32, 10 },
462b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
463b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
464b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct scsi_host_template mvs_sht = {
465b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.module			= THIS_MODULE,
466b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.name			= DRV_NAME,
467b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.queuecommand		= sas_queuecommand,
468b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.target_alloc		= sas_target_alloc,
469b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.slave_configure	= sas_slave_configure,
470b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.slave_destroy		= sas_slave_destroy,
471b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.change_queue_depth	= sas_change_queue_depth,
472b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.change_queue_type	= sas_change_queue_type,
473b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.bios_param		= sas_bios_param,
474b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.can_queue		= 1,
475b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.cmd_per_lun		= 1,
476b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.this_id		= -1,
477b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.sg_tablesize		= SG_ALL,
478b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,
479b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.use_clustering		= ENABLE_CLUSTERING,
480b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.eh_device_reset_handler= sas_eh_device_reset_handler,
481b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.eh_bus_reset_handler	= sas_eh_bus_reset_handler,
482b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.slave_alloc		= sas_slave_alloc,
483b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.target_destroy		= sas_target_destroy,
484b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.ioctl			= sas_ioctl,
485b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
486b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
487b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_rx(struct mvs_info *mvi, bool self_clear);
488b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
489b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* move to PCI layer or libata core? */
490b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int pci_go_64(struct pci_dev *pdev)
491b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
492b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc;
493b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
494b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
495b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
496b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc) {
497b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
498b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			if (rc) {
499b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				dev_printk(KERN_ERR, &pdev->dev,
500b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					   "64-bit DMA enable failed\n");
501b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				return rc;
502b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			}
503b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
504b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	} else {
505b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
506b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc) {
507b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
508b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				   "32-bit DMA enable failed\n");
509b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
510b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
511b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
512b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc) {
513b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
514b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				   "32-bit consistent DMA enable failed\n");
515b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
516b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
517b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
518b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
519b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
520b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
521b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
522b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_tag_clear(struct mvs_info *mvi, unsigned int tag)
523b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->tags[tag / sizeof(unsigned long)] &=
525b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		~(1UL << (tag % sizeof(unsigned long)));
526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
527b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
528b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
529b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
530b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->tags[tag / sizeof(unsigned long)] |=
531b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(1UL << (tag % sizeof(unsigned long)));
532b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
533b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
534b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic bool mvs_tag_test(struct mvs_info *mvi, unsigned int tag)
535b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
536b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return mvi->tags[tag / sizeof(unsigned long)] &
537b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(1UL << (tag % sizeof(unsigned long)));
538b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
539b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
540b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_tag_alloc(struct mvs_info *mvi, unsigned int *tag_out)
541b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
542b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int i;
543b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
544b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < MVS_SLOTS; i++)
545b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (!mvs_tag_test(mvi, i)) {
546b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			mvs_tag_set(mvi, i);
547b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			*tag_out = i;
548b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return 0;
549b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
550b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
551b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return -EBUSY;
552b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
553b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_eep_read(void __iomem *regs, unsigned int addr, u32 *data)
555b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
556b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int timeout = 1000;
557b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
558b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (addr & ~SPI_ADDR_MASK)
559b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -EINVAL;
560b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
561b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	writel(addr, regs + SPI_CMD);
562b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	writel(TWSI_RD, regs + SPI_CTL);
563b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
564b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	while (timeout-- > 0) {
565b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (readl(regs + SPI_CTL) & TWSI_RDY) {
566b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			*data = readl(regs + SPI_DATA);
567b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return 0;
568b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
570b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		udelay(10);
571b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
572b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
573b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return -EBUSY;
574b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
575b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
576b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_eep_read_buf(void __iomem *regs, unsigned int addr,
577b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			    void *buf, unsigned int buflen)
578b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
579b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int addr_end, tmp_addr, i, j;
580b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp = 0;
581b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc;
582b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *tmp8, *buf8 = buf;
583b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
584b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	addr_end = addr + buflen;
585b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp_addr = ALIGN(addr, 4);
586b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (addr > 0xff)
587b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -EINVAL;
588b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
589b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	j = addr & 0x3;
590b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (j) {
591b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = mvs_eep_read(regs, tmp_addr, &tmp);
592b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc)
593b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
594b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
595b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp8 = (u8 *) &tmp;
596b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		for (i = j; i < 4; i++)
597b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			*buf8++ = tmp8[i];
598b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
599b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp_addr += 4;
600b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
601b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
602b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) {
603b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = mvs_eep_read(regs, tmp_addr, &tmp);
604b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc)
605b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		memcpy(buf8, &tmp, 4);
608b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf8 += 4;
609b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
611b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (tmp_addr < addr_end) {
612b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = mvs_eep_read(regs, tmp_addr, &tmp);
613b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc)
614b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
616b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp8 = (u8 *) &tmp;
617b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		j = addr_end - tmp_addr;
618b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		for (i = 0; i < j; i++)
619b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			*buf8++ = tmp8[i];
620b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
621b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp_addr += 4;
622b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
623b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
624b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
625b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
626b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
627b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_nvram_read(struct mvs_info *mvi, unsigned int addr,
628b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			  void *buf, unsigned int buflen)
629b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
630b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
631b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc, i;
632b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int sum;
633b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 hdr[2], *tmp;
634b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	const char *msg;
635b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
636b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = mvs_eep_read_buf(regs, addr, &hdr, 2);
637b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc) {
638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msg = "nvram hdr read failed";
639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
640b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
641b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen);
642b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc) {
643b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msg = "nvram read failed";
644b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
647b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (hdr[0] != 0x5A) {		/* entry id */
648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msg = "invalid nvram entry id";
649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -ENOENT;
650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = buf;
654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sum = ((unsigned int)hdr[0]) + ((unsigned int)hdr[1]);
655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < buflen; i++)
656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		sum += ((unsigned int)tmp[i]);
657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (sum) {
659b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msg = "nvram checksum failure";
660b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -EILSEQ;
661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
663b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events)
672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
673b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME */
674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
676b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_sata(struct mvs_info *mvi)
677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME */
679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			  struct mvs_slot_info *slot, unsigned int slot_idx)
683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (slot->n_elem)
685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		pci_unmap_sg(mvi->pdev, task->scatter,
686b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     slot->n_elem, task->data_dir);
687b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
688b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	switch (task->task_proto) {
689b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SMP:
690b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1,
691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     PCI_DMA_FROMDEVICE);
692b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1,
693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     PCI_DMA_TODEVICE);
694b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SATA:
697b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_STP:
698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SSP:
699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	default:
700b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* do nothing */
701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
703b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
704b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_tag_clear(mvi, slot_idx);
705b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
706b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
707b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
708b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			 unsigned int slot_idx)
709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
710b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME */
711b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
712b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
715b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int slot_idx = rx_desc & RXQ_SLOT_MASK;
716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
717b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = slot->task;
718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct task_status_struct *tstat = &task->task_status;
719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	bool aborted;
720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
721b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock(&task->task_state_lock);
722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
723b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!aborted) {
724b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		task->task_state_flags &=
725b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
726b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		task->task_state_flags |= SAS_TASK_STATE_DONE;
727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
728b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock(&task->task_state_lock);
729b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
730b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (aborted)
731b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return;
732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
733b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(tstat, 0, sizeof(*tstat));
734b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tstat->resp = SAS_TASK_COMPLETE;
735b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
736b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* error info record present */
737b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rx_desc & RXQ_ERR) {
738b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tstat->stat = SAM_CHECK_COND;
739b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_slot_err(mvi, task, slot_idx);
740b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto out;
741b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
742b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
743b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	switch (task->task_proto) {
744b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SSP:
745b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* hw says status == 0, datapres == 0 */
746b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rx_desc & RXQ_GOOD)
747b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tstat->stat = SAM_GOOD;
748b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
749b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* response frame present */
750b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		else if (rx_desc & RXQ_RSP) {
751b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			struct ssp_response_iu *iu =
752b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				slot->response + sizeof(struct mvs_err_info);
753b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			sas_ssp_task_response(&mvi->pdev->dev, task, iu);
754b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
755b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
756b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* should never happen? */
757b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		else
758b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tstat->stat = SAM_CHECK_COND;
759b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
760b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
761b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SMP:
762b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tstat->stat = SAM_GOOD;
763b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
764b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
765b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SATA:
766b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_STP:
767b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) == RXQ_DONE)
768b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tstat->stat = SAM_GOOD;
769b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		else
770b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tstat->stat = SAM_CHECK_COND;
771b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* FIXME: read taskfile data from SATA register set
772b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		 * associated with SATA target
773b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		 */
774b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
775b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
776b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	default:
777b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tstat->stat = SAM_CHECK_COND;
778b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
779b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
780b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
781b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikout:
782b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_slot_free(mvi, task, slot, slot_idx);
783b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	task->task_done(task);
784b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
785b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
786b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_full(struct mvs_info *mvi)
787b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
788b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
789b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp, stat;
790b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int i;
791b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
792b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	stat = mr32(INT_STAT);
793b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
794b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < MVS_MAX_PORTS; i++) {
795b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
796b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (tmp)
797b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			mvs_int_port(mvi, i, tmp);
798b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
799b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
800b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (stat & CINT_SRS)
801b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_int_sata(mvi);
802b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
803b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (stat & (CINT_CI_STOP | CINT_DONE))
804b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_int_rx(mvi, false);
805b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
806b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(INT_STAT, stat);
807b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
808b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
809b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_rx(struct mvs_info *mvi, bool self_clear)
810b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
811b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 rx_prod_idx, rx_desc;
812b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	bool attn = false;
813b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
814b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* the first dword in the RX ring is special: it contains
815b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * a mirror of the hardware's RX producer index, so that
816b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * we don't have to stall the CPU reading that register.
817b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * The actual RX ring is offset by one dword, due to this.
818b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
819b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rx_prod_idx = le32_to_cpu(mvi->rx[0]) & 0xfff;
820b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rx_prod_idx == 0xfff) {	/* h/w hasn't touched RX ring yet */
821b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->rx_cons = 0xfff;
822b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return;
823b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
824b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->rx_cons == 0xfff)
825b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->rx_cons = MVS_RX_RING_SZ - 1;
826b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
827b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	while (mvi->rx_cons != rx_prod_idx) {
828b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* increment our internal RX consumer pointer */
829b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->rx_cons = (mvi->rx_cons + 1) & (MVS_RX_RING_SZ - 1);
830b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
831b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* Read RX descriptor at offset+1, due to above */
832b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rx_desc = le32_to_cpu(mvi->rx[mvi->rx_cons + 1]);
833b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
834b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rx_desc & RXQ_DONE)
835b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			/* we had a completion, error or no */
836b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			mvs_slot_complete(mvi, rx_desc);
837b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
838b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rx_desc & RXQ_ATTN)
839b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			attn = true;
840b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
841b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
842b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (attn && self_clear)
843b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_int_full(mvi);
844b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
845b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
846b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
847b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic irqreturn_t mvs_interrupt(int irq, void *opaque)
848b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
849b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi = opaque;
850b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
851b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 stat;
852b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
853b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	stat = mr32(GBL_INT_STAT);
854b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (stat == 0 || stat == 0xffffffff)
855b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return IRQ_NONE;
856b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
857b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock(&mvi->lock);
858b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
859b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_int_full(mvi);
860b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
861b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock(&mvi->lock);
862b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
863b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return IRQ_HANDLED;
864b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
865b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
866b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
867b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
868b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi = opaque;
869b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
870b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock(&mvi->lock);
871b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
872b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_int_rx(mvi, true);
873b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
874b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock(&mvi->lock);
875b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
876b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return IRQ_HANDLED;
877b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
878b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
879b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_task_exec_info {
880b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task		*task;
881b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr	*hdr;
882b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int		tag;
883b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int			n_elem;
884b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
885b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
886b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_smp(struct mvs_info *mvi, struct mvs_task_exec_info *tei)
887b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
888b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int elem, rc;
889b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
890b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct scatterlist *sg_req, *sg_resp;
891b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int req_len, resp_len, tag = tei->tag;
892b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
893b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
894b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * DMA-map SMP request, response buffers
895b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
896b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
897b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sg_req = &tei->task->smp_task.smp_req;
898b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE);
899b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!elem)
900b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -ENOMEM;
901b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	req_len = sg_dma_len(sg_req);
902b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
903b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sg_resp = &tei->task->smp_task.smp_resp;
904b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE);
905b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!elem) {
906b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -ENOMEM;
907b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
908b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
909b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = sg_dma_len(sg_resp);
910b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
911b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* must be in dwords */
912b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if ((req_len & 0x3) || (resp_len & 0x3)) {
913b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -EINVAL;
914b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_2;
915b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
916b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
917b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
918b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * Fill in TX ring and command slot header
919b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
920b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
921b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->tx[tag] = cpu_to_le32(
922b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(TXQ_CMD_SMP << TXQ_CMD_SHIFT) | TXQ_MODE_I | tag);
923b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
924b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->flags = 0;
925b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
926b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->tags = cpu_to_le32(tag);
927b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = 0;
928b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
929b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = 0;
930b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(sg_dma_address(sg_resp));
931b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->prd_tbl = 0;
932b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
933b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
934b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
935b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_2:
936b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1,
937b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		     PCI_DMA_FROMDEVICE);
938b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
939b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1,
940b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		     PCI_DMA_TODEVICE);
941b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
942b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
943b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
944b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ata(struct mvs_info *mvi,
945b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     struct mvs_task_exec_info *tei)
946b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
947b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
948b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct domain_device *dev = task->dev;
949b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
950b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port *sas_port = dev->port;
951b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int tag = tei->tag;
952b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info *slot = &mvi->slot_info[tag];
953b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
954b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct scatterlist *sg;
955b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_prd *buf_prd;
956b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
957b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf;
958b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
959b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int i, req_len, resp_len;
960b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
961b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: fill in SATA register set */
962b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag |
963b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
964b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(sas_port->phy_mask << TXQ_PHY_SHIFT));
965b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
966b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ata_task.use_ncq)
967b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FPDMA;
968b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
969b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_ATAPI;
970b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: fill in port multiplier number */
971b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
972b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->flags = cpu_to_le32(flags);
973b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->tags = cpu_to_le32(tag);
974b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = cpu_to_le32(task->total_xfer_len);
975b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
976b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
977b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
978b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
979b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
980b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
981b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* region 1: command table area (MVS_ATA_CMD_SZ bytes) ***************/
982b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_cmd =
983b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp = slot->buf;
984b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma = slot->buf_dma;
985b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
986b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
987b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
988b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_ATA_CMD_SZ;
989b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_ATA_CMD_SZ;
990b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
991b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
992b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* used for STP.  unused for SATA? */
993b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
994b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
995b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
996b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
997b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
998b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
999b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* region 3: PRD table ***********************************************/
1000b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
1001b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
1002b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1003b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	i = sizeof(struct mvs_prd) * tei->n_elem;
1004b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
1005b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
1006b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1007b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* region 4: status buffer (larger the PRD, smaller this buf) ********/
1008b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: probably unused, for SATA.  kept here just in case
1009b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * we get a STP/SATA error information record
1010b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1011b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
1012b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
1013b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1014b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	req_len = sizeof(struct ssp_frame_hdr) + 28;
1015b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
1016b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		   sizeof(struct mvs_err_info) - i;
1017b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1018b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
1019b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
1020b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1021b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in command FIS and ATAPI CDB */
1022b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd, &task->ata_task.fis,
1023b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	       sizeof(struct host_to_dev_fis));
1024b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
1025b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1026b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
1027b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sg = task->scatter;
1028b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < tei->n_elem; i++) {
1029b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
1030b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
1031b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1032b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		sg++;
1033b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd++;
1034b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1035b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1036b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1037b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1038b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1039b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ssp(struct mvs_info *mvi,
1040b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     struct mvs_task_exec_info *tei)
1041b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1042b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
1043b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port *sas_port = task->dev->port;
1044b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
1045b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info *slot;
1046b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct scatterlist *sg;
1047b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int resp_len, req_len, i, tag = tei->tag;
1048b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_prd *buf_prd;
1049b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct ssp_frame_hdr *ssp_hdr;
1050b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
1051b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf, fburst = 0;
1052b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
1053b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 flags;
1054b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1055b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot = &mvi->slot_info[tag];
1056b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1057b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag |
1058b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
1059b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(sas_port->phy_mask << TXQ_PHY_SHIFT));
1060b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1061b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	flags = MCH_RETRY;
1062b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ssp_task.enable_first_burst) {
1063b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FBURST;
1064b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		fburst = (1 << 7);
1065b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1066b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->flags = cpu_to_le32(flags |
1067b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(tei->n_elem << MCH_PRD_LEN_SHIFT) |
1068b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
1069b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1070b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->tags = cpu_to_le32(tag);
1071b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = cpu_to_le32(task->total_xfer_len);
1072b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1073b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
1074b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
1075b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1076b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
1077b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1078b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***************/
1079b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_cmd =
1080b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp = slot->buf;
1081b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma = slot->buf_dma;
1082b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1083b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
1084b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1085b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_SSP_CMD_SZ;
1086b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_SSP_CMD_SZ;
1087b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1088b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
1089b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
1090b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
1091b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1092b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
1093b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
1094b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1095b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* region 3: PRD table ***********************************************/
1096b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
1097b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
1098b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1099b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	i = sizeof(struct mvs_prd) * tei->n_elem;
1100b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
1101b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
1102b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1103b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* region 4: status buffer (larger the PRD, smaller this buf) ********/
1104b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
1105b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
1106b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1107b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	req_len = sizeof(struct ssp_frame_hdr) + 28;
1108b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
1109b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		   sizeof(struct mvs_err_info) - i;
1110b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1111b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
1112b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
1113b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1114b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* generate open address frame hdr (first 12 bytes) */
1115b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf[0] = (1 << 7) | (1 << 4) | 0x1;	/* initiator, SSP, ftype 1h */
1116b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf[1] = task->dev->linkrate & 0xf;
1117b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf[2] = tag >> 8;
1118b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf[3] = tag;
1119b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
1120b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1121b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in SSP frame header */
1122b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	ssp_hdr = (struct ssp_frame_hdr *) buf_cmd;
1123b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	ssp_hdr->frame_type = SSP_COMMAND;
1124b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr,
1125b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	       HASHED_SAS_ADDR_SIZE);
1126b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(ssp_hdr->hashed_src_addr,
1127b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	       task->dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
1128b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	ssp_hdr->tag = cpu_to_be16(tag);
1129b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1130b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in command frame IU */
1131b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_cmd += sizeof(*ssp_hdr);
1132b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
1133b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_cmd[9] = fburst |
1134b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		task->ssp_task.task_attr |
1135b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		(task->ssp_task.task_prio << 3);
1136b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
1137b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1138b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
1139b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sg = task->scatter;
1140b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < tei->n_elem; i++) {
1141b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
1142b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
1143b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1144b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		sg++;
1145b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd++;
1146b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1147b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1148b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1149b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1150b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
1152b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1153b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
1154b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned int tag = 0xdeadbeef, rc, n_elem = 0;
1155b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1156b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned long flags;
1157b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_task_exec_info tei;
1158b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1159b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: STP/SATA support not complete yet */
1160b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->task_proto == SAS_PROTOCOL_SATA || task->task_proto == SAS_PROTOCOL_STP)
1161b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -SAS_DEV_NO_RESPONSE;
1162b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1163b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->num_scatter) {
1164b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		n_elem = pci_map_sg(mvi->pdev, task->scatter,
1165b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				    task->num_scatter, task->data_dir);
1166b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (!n_elem)
1167b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return -ENOMEM;
1168b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1169b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1170b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock_irqsave(&mvi->lock, flags);
1171b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1172b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = mvs_tag_alloc(mvi, &tag);
1173b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1174b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1175b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1176b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->slot_info[tag].task = task;
1177b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->slot_info[tag].n_elem = n_elem;
1178b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tei.task = task;
1179b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tei.hdr = &mvi->slot[tag];
1180b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tei.tag = tag;
1181b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tei.n_elem = n_elem;
1182b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1183b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	switch (task->task_proto) {
1184b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SMP:
1185b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = mvs_task_prep_smp(mvi, &tei);
1186b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1187b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SSP:
1188b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = mvs_task_prep_ssp(mvi, &tei);
1189b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1190b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SATA:
1191b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_STP:
1192b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = mvs_task_prep_ata(mvi, &tei);
1193b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1194b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	default:
1195b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -EINVAL;
1196b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1197b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1199b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1200b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_tag;
1201b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1202b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* TODO: select normal or high priority */
1203b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1204b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_PROD_IDX, mvi->tx_prod);
1205b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1206b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_TX_RING_SZ - 1);
1207b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1208b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock(&task->task_state_lock);
1209b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	task->task_state_flags |= SAS_TASK_AT_INITIATOR;
1210b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock(&task->task_state_lock);
1211b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1212b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock_irqrestore(&mvi->lock, flags);
1213b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1214b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1215b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_tag:
1216b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_tag_clear(mvi, tag);
1217b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
1218b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (n_elem)
1219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		pci_unmap_sg(mvi->pdev, task->scatter, n_elem, task->data_dir);
1220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock_irqrestore(&mvi->lock, flags);
1221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
1222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1223b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1224b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_free(struct mvs_info *mvi)
1225b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1226b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int i;
1227b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1228b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi)
1229b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return;
1230b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < MVS_SLOTS; i++) {
1232b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		struct mvs_slot_info *slot = &mvi->slot_info[i];
1233b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1234b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (slot->buf)
1235b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ,
1236b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					  slot->buf, slot->buf_dma);
1237b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1238b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1239b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->tx)
1240b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dma_free_coherent(&mvi->pdev->dev,
1241b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  sizeof(*mvi->tx) * MVS_TX_RING_SZ,
1242b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  mvi->tx, mvi->tx_dma);
1243b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->rx_fis)
1244b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
1245b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  mvi->rx_fis, mvi->rx_fis_dma);
1246b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->rx)
1247b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dma_free_coherent(&mvi->pdev->dev,
1248b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  sizeof(*mvi->rx) * MVS_RX_RING_SZ,
1249b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  mvi->rx, mvi->rx_dma);
1250b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->slot)
1251b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dma_free_coherent(&mvi->pdev->dev,
1252b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  sizeof(*mvi->slot) * MVS_RX_RING_SZ,
1253b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  mvi->slot, mvi->slot_dma);
1254b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->peri_regs)
1255b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		iounmap(mvi->peri_regs);
1256b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->regs)
1257b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		iounmap(mvi->regs);
1258b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->shost)
1259b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		scsi_host_put(mvi->shost);
1260b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	kfree(mvi->sas.sas_port);
1261b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	kfree(mvi->sas.sas_phy);
1262b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	kfree(mvi);
1263b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1265b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* FIXME: locking? */
1266b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
1267b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			   void *funcdata)
1268b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1269b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi = sas_phy->ha->lldd_ha;
1270b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *reg;
1271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc = 0, phy_id = sas_phy->id;
1272b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp;
1273b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1274b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	reg = mvi->regs + MVS_P0_SER_CTLSTAT + (phy_id * 4);
1275b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1276b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	switch (func) {
1277b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case PHY_FUNC_SET_LINK_RATE: {
1278b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		struct sas_phy_linkrates *rates = funcdata;
1279b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		u32 lrmin = 0, lrmax = 0;
1280b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1281b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		lrmin = (rates->minimum_linkrate << 8);
1282b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		lrmax = (rates->maximum_linkrate << 12);
1283b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1284b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp = readl(reg);
1285b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (lrmin) {
1286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp &= ~(0xf << 8);
1287b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp |= lrmin;
1288b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
1289b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (lrmax) {
1290b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp &= ~(0xf << 12);
1291b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp |= lrmax;
1292b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
1293b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		writel(tmp, reg);
1294b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1295b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1296b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1297b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case PHY_FUNC_HARD_RESET:
1298b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp = readl(reg);
1299b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (tmp & PHY_RST_HARD)
1300b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			break;
1301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		writel(tmp | PHY_RST_HARD, reg);
1302b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1303b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1304b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case PHY_FUNC_LINK_RESET:
1305b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		writel(readl(reg) | PHY_RST, reg);
1306b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1307b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1308b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case PHY_FUNC_DISABLE:
1309b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case PHY_FUNC_RELEASE_SPINUP_HOLD:
1310b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	default:
1311b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -EOPNOTSUPP;
1312b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1313b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1314b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
1315b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1316b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1317b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
1318b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1319b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_phy *phy = &mvi->phy[phy_id];
1320b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_phy *sas_phy = &phy->sas_phy;
1321b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
1323b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->class = SAS;
1324b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->iproto = SAS_PROTOCOL_ALL;
1325b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->tproto = 0;
1326b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->type = PHY_TYPE_PHYSICAL;
1327b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->role = PHY_ROLE_INITIATOR;
1328b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->oob_mode = OOB_NOT_CONNECTED;
1329b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
1330b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1331b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->id = phy_id;
1332b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->sas_addr = &mvi->sas_addr[0];
1333b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->frame_rcvd = &phy->frame_rcvd[0];
1334b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->ha = &mvi->sas;
1335b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->lldd_phy = phy;
1336b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1338b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
1339b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				const struct pci_device_id *ent)
1340b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1341b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi;
1342b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned long res_start, res_len;
1343b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_phy **arr_phy;
1344b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port **arr_port;
1345b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
1346b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int i;
1347b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1348b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
1349b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * alloc and init our per-HBA mvs_info struct
1350b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1351b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1352b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi = kzalloc(sizeof(*mvi), GFP_KERNEL);
1353b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi)
1354b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return NULL;
1355b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1356b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock_init(&mvi->lock);
1357b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->pdev = pdev;
1358b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->chip = chip;
1359b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1360b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (pdev->device == 0x6440 && pdev->revision == 0)
1361b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->flags |= MVF_PHY_PWR_FIX;
1362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1363b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
1364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * alloc and init SCSI, SAS glue
1365b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1367b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *));
1368b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->shost)
1369b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1370b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
1372b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
1373b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!arr_phy || !arr_port)
1374b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1375b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1376b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < MVS_MAX_PHYS; i++) {
1377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_phy_init(mvi, i);
1378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		arr_phy[i] = &mvi->phy[i].sas_phy;
1379b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		arr_port[i] = &mvi->port[i].sas_port;
1380b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1381b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1382b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
1383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->shost->transportt = mvs_stt;
1384b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->shost->max_id = ~0;
1385b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->shost->max_lun = ~0;
1386b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->shost->max_cmd_len = ~0;
1387b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.sas_ha_name = DRV_NAME;
1389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.dev = &pdev->dev;
1390b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.lldd_module = THIS_MODULE;
1391b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.sas_addr = &mvi->sas_addr[0];
1392b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.sas_phy = arr_phy;
1393b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.sas_port = arr_port;
1394b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.num_phys = chip->n_phy;
1395b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.lldd_max_execute_num = MVS_TX_RING_SZ - 1;/* FIXME: correct? */
1396b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.lldd_queue_size = MVS_TX_RING_SZ - 1;	   /* FIXME: correct? */
1397b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.lldd_ha = mvi;
1398b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.core.shost = mvi->shost;
1399b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1400b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_tag_set(mvi, MVS_TX_RING_SZ - 1);
1401b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1402b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
1403b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * ioremap main and peripheral registers
1404b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1405b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1406b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	res_start = pci_resource_start(pdev, 2);
1407b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	res_len = pci_resource_len(pdev, 2);
1408b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!res_start || !res_len)
1409b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1410b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1411b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->peri_regs = ioremap_nocache(res_start, res_len);
1412b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->regs)
1413b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1415b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	res_start = pci_resource_start(pdev, 4);
1416b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	res_len = pci_resource_len(pdev, 4);
1417b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!res_start || !res_len)
1418b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1419b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1420b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->regs = ioremap_nocache(res_start, res_len);
1421b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->regs)
1422b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1423b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1424b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
1425b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * alloc and init our DMA areas
1426b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1427b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1428b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->tx = dma_alloc_coherent(&pdev->dev,
1429b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				     sizeof(*mvi->tx) * MVS_TX_RING_SZ,
1430b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				     &mvi->tx_dma, GFP_KERNEL);
1431b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->tx)
1432b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1433b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_TX_RING_SZ);
1434b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1435b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
1436b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				     &mvi->rx_fis_dma, GFP_KERNEL);
1437b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->rx_fis)
1438b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1439b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
1440b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->rx = dma_alloc_coherent(&pdev->dev,
1442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				     sizeof(*mvi->rx) * MVS_RX_RING_SZ,
1443b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				     &mvi->rx_dma, GFP_KERNEL);
1444b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->rx)
1445b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1446b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(mvi->rx, 0, sizeof(*mvi->rx) * MVS_RX_RING_SZ);
1447b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1448b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->rx[0] = cpu_to_le32(0xfff);
1449b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->rx_cons = 0xfff;
1450b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1451b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->slot = dma_alloc_coherent(&pdev->dev,
1452b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				       sizeof(*mvi->slot) * MVS_SLOTS,
1453b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				       &mvi->slot_dma, GFP_KERNEL);
1454b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->slot)
1455b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1456b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS);
1457b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1458b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < MVS_SLOTS; i++) {
1459b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		struct mvs_slot_info *slot = &mvi->slot_info[i];
1460b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1461b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
1462b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				       &slot->buf_dma, GFP_KERNEL);
1463b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (!slot->buf)
1464b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			goto err_out;
1465b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
1466b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1467b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1468b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* finally, read NVRAM to get our SAS address */
1469b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
1470b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1471b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1472b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return mvi;
1473b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1474b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
1475b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_free(mvi);
1476b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return NULL;
1477b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1478b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1479b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic u32 mvs_cr32(void __iomem *regs, u32 addr)
1480b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1481b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_ADDR, addr);
1482b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return mr32(CMD_DATA);
1483b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1484b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1485b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
1486b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1487b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_ADDR, addr);
1488b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_DATA, val);
1489b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1490b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1491b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#if 0
1492b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic u32 mvs_phy_read(struct mvs_info *mvi, unsigned int phy_id, u32 addr)
1493b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1494b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1495b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8);
1496b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1497b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	writel(addr, phy_regs);
1498b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return readl(phy_regs + 4);
1499b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1500b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#endif
1501b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1502b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_phy_write(struct mvs_info *mvi, unsigned int phy_id,
1503b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			  u32 addr, u32 val)
1504b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1505b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1506b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8);
1507b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1508b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	writel(addr, phy_regs);
1509b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	writel(val, phy_regs + 4);
1510b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	readl(phy_regs);	/* flush */
1511b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1512b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1513b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devinit mvs_phy_hacks(struct mvs_info *mvi)
1514b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1515b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1516b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp;
1517b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1518b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* workaround for SATA R-ERR, to ignore phy glitch */
1519b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mvs_cr32(regs, CMD_PHY_TIMER);
1520b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~(1 << 9);
1521b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= (1 << 10);
1522b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_PHY_TIMER, tmp);
1523b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* enable retry 127 times */
1525b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
1526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1527b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* extend open frame timeout to max */
1528b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mvs_cr32(regs, CMD_SAS_CTL0);
1529b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~0xffff;
1530b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= 0x3fff;
1531b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_SAS_CTL0, tmp);
1532b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1533b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* workaround for WDTIMEOUT , set to 550 ms */
1534b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_WD_TIMER, 0xffffff);
1535b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1536b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* not to halt for different port op during wideport link change */
1537b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
1538b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1539b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* workaround for Seagate disk not-found OOB sequence, recv
1540b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * COMINIT before sending out COMWAKE */
1541b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
1542b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= 0x0000ffff;
1543b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= 0x00fa0000;
1544b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
1545b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1546b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mvs_cr32(regs, CMD_PHY_TIMER);
1547b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= 0x1fffffff;
1548b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= (2U << 29);	/* 8 ms retry */
1549b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_PHY_TIMER, tmp);
1550b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1551b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1552b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int __devinit mvs_hw_init(struct mvs_info *mvi)
1553b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1555b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int i;
1556b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp, cctl;
1557b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1558b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* make sure interrupts are masked immediately (paranoia) */
1559b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(GBL_CTL, 0);
1560b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mr32(GBL_CTL);
1561b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1562b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!(tmp & HBA_RST)) {
1563b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (mvi->flags & MVF_PHY_PWR_FIX) {
1564b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
1565b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp &= ~PCTL_PWR_ON;
1566b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp |= PCTL_OFF;
1567b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
1568b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
1570b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp &= ~PCTL_PWR_ON;
1571b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp |= PCTL_OFF;
1572b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
1573b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
1574b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1575b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* global reset, incl. COMRESET/H_RESET_N (self-clearing) */
1576b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mw32_f(GBL_CTL, HBA_RST);
1577b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1578b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1579b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1580b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* wait for reset to finish; timeout is just a guess */
1581b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	i = 1000;
1582b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	while (i-- > 0) {
1583b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msleep(10);
1584b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1585b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (!(mr32(GBL_CTL) & HBA_RST))
1586b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			break;
1587b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1588b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mr32(GBL_CTL) & HBA_RST) {
1589b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dev_printk(KERN_ERR, &mvi->pdev->dev, "HBA reset failed\n");
1590b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -EBUSY;
1591b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1592b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1593b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* make sure RST is set; HBA_RST /should/ have done that for us */
1594b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	cctl = mr32(CTL);
1595b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (cctl & CCTL_RST)
1596b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		cctl &= ~CCTL_RST;
1597b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	else
1598b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mw32_f(CTL, cctl | CCTL_RST);
1599b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1600b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
1601b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= PCTL_PWR_ON;
1602b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~PCTL_OFF;
1603b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
1604b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1605b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
1606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= PCTL_PWR_ON;
1607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~PCTL_OFF;
1608b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
1609b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32_f(CTL, cctl);
1611b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1612b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_phy_hacks(mvi);
1613b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1614b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_LIST_LO, mvi->slot_dma);
1615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
1616b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1617b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_FIS_LO, mvi->rx_fis_dma);
1618b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
1619b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1620b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(TX_CFG, MVS_TX_RING_SZ);
1621b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(TX_LO, mvi->tx_dma);
1622b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(TX_HI, (mvi->tx_dma >> 16) >> 16);
1623b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1624b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_CFG, MVS_RX_RING_SZ);
1625b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_LO, mvi->rx_dma);
1626b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_HI, (mvi->rx_dma >> 16) >> 16);
1627b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1628b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* init and reset phys */
1629b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < mvi->chip->n_phy; i++) {
1630b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* FIXME: is this the correct dword order? */
1631b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		u32 lo = *((u32 *) &mvi->sas_addr[0]);
1632b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		u32 hi = *((u32 *) &mvi->sas_addr[4]);
1633b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1634b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* set phy local SAS address */
1635b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_phy_write(mvi, i, PHYR_ADDR_LO, lo);
1636b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_phy_write(mvi, i, PHYR_ADDR_HI, hi);
1637b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* reset phy */
1639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp = readl(regs + MVS_P0_SER_CTLSTAT + (i * 4));
1640b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp |= PHY_RST;
1641b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		writel(tmp, regs + MVS_P0_SER_CTLSTAT + (i * 4));
1642b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1643b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1644b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	msleep(100);
1645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < mvi->chip->n_phy; i++) {
1647b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* set phy int mask */
1648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		writel(PHYEV_BROAD_CH | PHYEV_RDY_CH,
1649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		       regs + MVS_P0_INT_MASK + (i * 8));
1650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* clear phy int status */
1652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp = readl(regs + MVS_P0_INT_STAT + (i * 8));
1653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		writel(tmp, regs + MVS_P0_INT_STAT + (i * 8));
1654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: update wide port bitmaps */
1657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* ladies and gentlemen, start your engines */
1659b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(TX_CFG, MVS_TX_RING_SZ | TX_EN);
1660b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
1661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN |
1662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	     ((mvi->flags & MVF_MSI) ? PCS_SELF_CLEAR : 0));
1663b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* re-enable interrupts globally */
1665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(GBL_CTL, INT_EN);
1666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devinit mvs_print_info(struct mvs_info *mvi)
1671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct pci_dev *pdev = mvi->pdev;
1673b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	static int printed_version;
1674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!printed_version++)
1676b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
1677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dev_printk(KERN_INFO, &pdev->dev, "%u phys, addr %llx\n",
1679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		   mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr));
1680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int __devinit mvs_pci_init(struct pci_dev *pdev,
1683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				 const struct pci_device_id *ent)
1684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc;
1686b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi;
1687b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	irq_handler_t irq_handler = mvs_interrupt;
1688b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1689b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = pci_enable_device(pdev);
1690b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return rc;
1692b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_set_master(pdev);
1694b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = pci_request_regions(pdev, DRV_NAME);
1696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1697b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_disable;
1698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = pci_go_64(pdev);
1700b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_regions;
1702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1703b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi = mvs_alloc(pdev, ent);
1704b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi) {
1705b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -ENOMEM;
1706b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_regions;
1707b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1708b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = mvs_hw_init(mvi);
1710b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1711b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_mvi;
1712b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!pci_enable_msi(pdev)) {
1714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->flags |= MVF_MSI;
1715b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		irq_handler = mvs_msi_interrupt;
1716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1717b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi);
1719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_msi;
1721b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = scsi_add_host(mvi->shost, &pdev->dev);
1723b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1724b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_irq;
1725b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1726b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = sas_register_ha(&mvi->sas);
1727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1728b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_shost;
1729b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1730b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_set_drvdata(pdev, mvi);
1731b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_print_info(mvi);
1733b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1734b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	scsi_scan_host(mvi->shost);
1735b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1736b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1737b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_shost:
1738b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	scsi_remove_host(mvi->shost);
1739b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_irq:
1740b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	free_irq(pdev->irq, mvi);
1741b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_msi:
1742b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->flags |= MVF_MSI)
1743b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		pci_disable_msi(pdev);
1744b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_mvi:
1745b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_free(mvi);
1746b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_regions:
1747b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_release_regions(pdev);
1748b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_disable:
1749b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_disable_device(pdev);
1750b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
1751b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1752b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1753b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devexit mvs_pci_remove(struct pci_dev *pdev)
1754b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1755b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi = pci_get_drvdata(pdev);
1756b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1757b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_set_drvdata(pdev, NULL);
1758b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1759b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_unregister_ha(&mvi->sas);
1760b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_remove_host(mvi->shost);
1761b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	scsi_remove_host(mvi->shost);
1762b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1763b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	free_irq(pdev->irq, mvi);
1764b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->flags & MVF_MSI)
1765b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		pci_disable_msi(pdev);
1766b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_free(mvi);
1767b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_release_regions(pdev);
1768b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_disable_device(pdev);
1769b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1770b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1771b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct sas_domain_function_template mvs_transport_ops = {
1772b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.lldd_execute_task	= mvs_task_exec,
1773b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.lldd_control_phy	= mvs_phy_control,
1774b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
1775b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1776b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct pci_device_id __devinitdata mvs_pci_table[] = {
1777b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
1778b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
1779b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
1780b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6480), chip_6480 },
1781b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1782b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ }	/* terminate list */
1783b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
1784b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1785b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct pci_driver mvs_pci_driver = {
1786b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.name		= DRV_NAME,
1787b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.id_table	= mvs_pci_table,
1788b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.probe		= mvs_pci_init,
1789b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.remove		= __devexit_p(mvs_pci_remove),
1790b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
1791b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1792b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int __init mvs_init(void)
1793b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1794b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc;
1795b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1796b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);
1797b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvs_stt)
1798b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -ENOMEM;
1799b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1800b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = pci_register_driver(&mvs_pci_driver);
1801b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
1802b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1803b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1804b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1805b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1806b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
1807b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_release_transport(mvs_stt);
1808b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
1809b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1810b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1811b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __exit mvs_exit(void)
1812b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1813b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_unregister_driver(&mvs_pci_driver);
1814b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_release_transport(mvs_stt);
1815b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1816b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1817b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikmodule_init(mvs_init);
1818b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikmodule_exit(mvs_exit);
1819b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1820b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
1821b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
1822b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_VERSION(DRV_VERSION);
1823b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_LICENSE("GPL");
1824b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_DEVICE_TABLE(pci, mvs_pci_table);
1825b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1826