mv_sas.c revision 8f261aaf9be5c1246013cf6a65b98586d24832a5
1b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/*
2b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvsas.c - Marvell 88SE6440 SAS/SATA support
3b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
4b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	Copyright 2007 Red Hat, Inc.
58f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	Copyright 2008 Marvell. <kewei@marvell.com>
6b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
7b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	This program is free software; you can redistribute it and/or
8b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	modify it under the terms of the GNU General Public License as
9b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	published by the Free Software Foundation; either version 2,
10b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	or (at your option) any later version.
11b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
12b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	This program is distributed in the hope that it will be useful,
13b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	but WITHOUT ANY WARRANTY; without even the implied warranty
14b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	See the GNU General Public License for more details.
16b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	You should have received a copy of the GNU General Public
18b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	License along with this program; see the file COPYING.	If not,
19b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	write to the Free Software Foundation, 675 Mass Ave, Cambridge,
20b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MA 02139, USA.
21b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
22b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	---------------------------------------------------------------
23b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
24b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	Random notes:
25b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	* hardware supports controlling the endian-ness of data
26b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	  structures.  this permits elimination of all the le32_to_cpu()
27b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	  and cpu_to_le32() conversions.
28b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
29b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */
30b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
31b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/kernel.h>
32b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/module.h>
33b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/pci.h>
34b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/interrupt.h>
35b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/spinlock.h>
36b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/delay.h>
37b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <linux/dma-mapping.h>
38b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <scsi/libsas.h>
39b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#include <asm/io.h>
40b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define DRV_NAME	"mvsas"
428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define DRV_VERSION	"0.5"
438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define _MV_DUMP 0
448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define MVS_DISABLE_NVRAM
458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define MVS_DISABLE_MSI
46b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
47b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define mr32(reg)	readl(regs + MVS_##reg)
48b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik#define mw32(reg,val)	writel((val), regs + MVS_##reg)
498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define mw32_f(reg,val)	do {			\
50b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	writel((val), regs + MVS_##reg);	\
51b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	readl(regs + MVS_##reg);		\
52b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	} while (0)
53b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define MVS_ID_NOT_MAPPED	0xff
558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define MVS_CHIP_SLOT_SZ	(1U << mvi->chip->slot_width)
568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei/* offset for D2H FIS in the Received FIS List Structure */
588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define SATA_RECEIVED_D2H_FIS(reg_set)	\
598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define SATA_RECEIVED_PIO_FIS(reg_set)	\
618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define UNASSOC_D2H_FIS(id)		\
638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	((void *) mvi->rx_fis + 0x100 * id)
648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define for_each_phy(__lseq_mask, __mc, __lseq, __rest)			\
668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for ((__mc) = (__lseq_mask), (__lseq) = 0;			\
678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(__mc) != 0 && __rest;		\
688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(++__lseq), (__mc) >>= 1)
698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
70b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* driver compile-time configuration */
71b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum driver_configuration {
72b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_TX_RING_SZ		= 1024,	/* TX ring size (12-bit) */
73b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_RING_SZ		= 1024, /* RX ring size (12-bit) */
74b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					/* software requires power-of-2
75b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					   ring size */
76b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
77b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_SLOTS		= 512,	/* command slots */
78b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_SLOT_BUF_SZ		= 8192, /* cmd tbl + IU + status + PRD */
79b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_SSP_CMD_SZ		= 64,	/* SSP command table buffer size */
808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_ATA_CMD_SZ		= 96,	/* SATA command table buffer size */
81b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_OAF_SZ		= 64,	/* Open address frame buffer size */
82b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
83b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_FIS_COUNT	= 17,	/* Optional rx'd FISs (max 17) */
848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_QUEUE_SIZE		= 30,	/* Support Queue depth */
86b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
87b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
88b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* unchangeable hardware details */
89b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum hardware_details {
90b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_MAX_PHYS		= 8,	/* max. possible phys */
91b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_MAX_PORTS		= 8,	/* max. possible ports */
92b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_FISL_SZ		= 0x400 + (MVS_RX_FIS_COUNT * 0x100),
93b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
94b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
95b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* peripheral registers (BAR2) */
96b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum peripheral_registers {
97b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SPI_CTL			= 0x10,	/* EEPROM control */
98b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SPI_CMD			= 0x14,	/* EEPROM command */
99b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SPI_DATA		= 0x18, /* EEPROM data */
100b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
101b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
102b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum peripheral_register_bits {
103b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TWSI_RDY		= (1U << 7),	/* EEPROM interface ready */
104b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TWSI_RD			= (1U << 4),	/* EEPROM read access */
105b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
106b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SPI_ADDR_MASK		= 0x3ffff,	/* bits 17:0 */
107b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
108b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
109b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* enhanced mode registers (BAR4) */
110b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum hw_registers {
111b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_GBL_CTL		= 0x04,  /* global control */
112b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_GBL_INT_STAT	= 0x08,  /* global irq status */
113b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_GBL_PI		= 0x0C,  /* ports implemented bitmask */
1148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_GBL_PORT_TYPE	= 0xa0,  /* port type */
115b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
116b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CTL			= 0x100, /* SAS/SATA port configuration */
117b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_PCS			= 0x104, /* SAS/SATA port control/status */
118b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CMD_LIST_LO		= 0x108, /* cmd list addr */
119b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CMD_LIST_HI		= 0x10C,
120b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_FIS_LO		= 0x110, /* RX FIS list addr */
121b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_FIS_HI		= 0x114,
122b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
123b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_TX_CFG		= 0x120, /* TX configuration */
124b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_TX_LO		= 0x124, /* TX (delivery) ring addr */
125b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_TX_HI		= 0x128,
126b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_TX_PROD_IDX		= 0x12C, /* TX producer pointer */
1288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_TX_CONS_IDX		= 0x130, /* TX consumer pointer (RO) */
129b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_CFG		= 0x134, /* RX configuration */
130b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_LO		= 0x138, /* RX (completion) ring addr */
131b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_RX_HI		= 0x13C,
1328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_RX_CONS_IDX		= 0x140, /* RX consumer pointer (RO) */
133b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
134b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_COAL		= 0x148, /* Int coalescing config */
135b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_COAL_TMOUT	= 0x14C, /* Int coalescing timeout */
136b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_STAT		= 0x150, /* Central int status */
137b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_MASK		= 0x154, /* Central int enable */
138b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_INT_STAT_SRS	= 0x158, /* SATA register set status */
1398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_INT_MASK_SRS	= 0x15C,
140b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
141b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					 /* ports 1-3 follow after this */
142b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_INT_STAT		= 0x160, /* port0 interrupt status */
143b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_INT_MASK		= 0x164, /* port0 interrupt mask */
1448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_P4_INT_STAT		= 0x200, /* Port 4 interrupt status */
1458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_P4_INT_MASK		= 0x204, /* Port 4 interrupt enable mask */
146b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
147b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					 /* ports 1-3 follow after this */
148b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_SER_CTLSTAT	= 0x180, /* port0 serial control/status */
1498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_P4_SER_CTLSTAT	= 0x220, /* port4 serial control/status */
150b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CMD_ADDR		= 0x1B8, /* Command register port (addr) */
152b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_CMD_DATA		= 0x1BC, /* Command register port (data) */
153b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
154b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					 /* ports 1-3 follow after this */
155b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_CFG_ADDR		= 0x1C0, /* port0 phy register address */
156b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVS_P0_CFG_DATA		= 0x1C4, /* port0 phy register data */
1578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_P4_CFG_ADDR		= 0x230, /* Port 4 config address */
1588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_P4_CFG_DATA		= 0x234, /* Port 4 config data */
1598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					 /* ports 1-3 follow after this */
1618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_P0_VSR_ADDR		= 0x1E0, /* port0 VSR address */
1628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_P0_VSR_DATA		= 0x1E4, /* port0 VSR data */
1638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_P4_VSR_ADDR		= 0x250, /* port 4 VSR addr */
1648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MVS_P4_VSR_DATA		= 0x254, /* port 4 VSR data */
165b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
166b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
167b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum hw_register_bits {
168b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_GBL_CTL */
169b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	INT_EN			= (1U << 1),	/* Global int enable */
170b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	HBA_RST			= (1U << 0),	/* HBA reset */
171b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
172b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_GBL_INT_STAT */
173b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	INT_XOR			= (1U << 4),	/* XOR engine event */
174b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	INT_SAS_SATA		= (1U << 0),	/* SAS/SATA event */
175b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
176b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_GBL_PORT_TYPE */			/* shl for ports 1-3 */
177b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SATA_TARGET		= (1U << 16),	/* port0 SATA target enable */
1788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_AUTO_DET_PORT7 = (1U << 15),	/* port0 SAS/SATA autodetect */
1798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_AUTO_DET_PORT6 = (1U << 14),
1808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_AUTO_DET_PORT5 = (1U << 13),
1818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_AUTO_DET_PORT4 = (1U << 12),
1828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_AUTO_DET_PORT3 = (1U << 11),
1838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_AUTO_DET_PORT2 = (1U << 10),
1848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_AUTO_DET_PORT1 = (1U << 9),
1858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_AUTO_DET_PORT0 = (1U << 8),
1868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_AUTO_DET_EN    =	MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
1878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
1888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
1898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
1908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_SAS_PORT7_MASK = (1U << 7),  /* port0 SAS(1), SATA(0) mode */
1918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_SAS_PORT6_MASK = (1U << 6),
1928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_SAS_PORT5_MASK = (1U << 5),
1938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_SAS_PORT4_MASK = (1U << 4),
1948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_SAS_PORT3_MASK = (1U << 3),
1958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_SAS_PORT2_MASK = (1U << 2),
1968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_SAS_PORT1_MASK = (1U << 1),
1978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_SAS_PORT0_MASK = (1U << 0),
1988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	MODE_SAS_SATA	=	MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
1998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
2008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
2018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
2028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
2038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				/* SAS_MODE value may be
2048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				 * dictated (in hw) by values
2058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				 * of SATA_TARGET & AUTO_DET
2068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				 */
207b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
208b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_TX_CFG */
209b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TX_EN			= (1U << 16),	/* Enable TX */
210b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TX_RING_SZ_MASK		= 0xfff,	/* TX ring size, bits 11:0 */
211b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
212b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_RX_CFG */
213b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RX_EN			= (1U << 16),	/* Enable RX */
214b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RX_RING_SZ_MASK		= 0xfff,	/* RX ring size, bits 11:0 */
215b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
216b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_INT_COAL */
217b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	COAL_EN			= (1U << 16),	/* Enable int coalescing */
218b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_INT_STAT, MVS_INT_MASK */
220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_I2C		= (1U << 31),	/* I2C event */
221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_SW0		= (1U << 30),	/* software event 0 */
222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_SW1		= (1U << 29),	/* software event 1 */
223b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_PRD_BC		= (1U << 28),	/* PRD BC err for read cmd */
224b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_DMA_PCIE		= (1U << 27),	/* DMA to PCIE timeout */
225b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_MEM		= (1U << 26),	/* int mem parity err */
226b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_I2C_SLAVE		= (1U << 25),	/* slave I2C event */
227b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_SRS		= (1U << 3),	/* SRS event */
2288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	CINT_CI_STOP		= (1U << 1),	/* cmd issue stopped */
229b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_DONE		= (1U << 0),	/* cmd completion */
230b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* shl for ports 1-3 */
232b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_PORT_STOPPED	= (1U << 16),	/* port0 stopped */
233b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CINT_PORT		= (1U << 8),	/* port0 event */
2348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	CINT_PORT_MASK_OFFSET	= 8,
2358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	CINT_PORT_MASK		= (0xFF << CINT_PORT_MASK_OFFSET),
236b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
237b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* TX (delivery) ring bits */
238b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SHIFT		= 29,
239b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SSP		= 1,		/* SSP protocol */
240b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SMP		= 2,		/* SMP protocol */
241b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_STP		= 3,		/* STP/SATA protocol */
242b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SSP_FREE_LIST	= 4,		/* add to SSP targ free list */
243b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_CMD_SLOT_RESET	= 7,		/* reset command slot */
244b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_MODE_I		= (1U << 28),	/* mode: 0=target,1=initiator */
245b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_PRIO_HI		= (1U << 27),	/* priority: 0=normal, 1=high */
246b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_SRS_SHIFT		= 20,		/* SATA register set */
247b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_SRS_MASK		= 0x7f,
248b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_PHY_SHIFT		= 12,		/* PHY bitmap */
249b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_PHY_MASK		= 0xff,
250b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	TXQ_SLOT_MASK		= 0xfff,	/* slot number */
251b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
252b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* RX (completion) ring bits */
253b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_GOOD		= (1U << 23),	/* Response good */
254b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_SLOT_RESET		= (1U << 21),	/* Slot reset complete */
255b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_CMD_RX		= (1U << 20),	/* target cmd received */
256b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_ATTN		= (1U << 19),	/* attention */
257b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_RSP			= (1U << 18),	/* response frame xfer'd */
258b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_ERR			= (1U << 17),	/* err info rec xfer'd */
259b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_DONE		= (1U << 16),	/* cmd complete */
260b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	RXQ_SLOT_MASK		= 0xfff,	/* slot number */
261b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
262b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* mvs_cmd_hdr bits */
263b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_PRD_LEN_SHIFT	= 16,		/* 16-bit PRD table len */
264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_TYPE_SHIFT	= 13,		/* SSP frame type */
265b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
266b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* SSP initiator only */
267b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_CMD		= 0x0,		/* COMMAND frame */
268b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
269b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* SSP initiator or target */
270b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_TASK		= 0x1,		/* TASK frame */
271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
272b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* SSP target only */
273b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_XFER_RDY	= 0x4,		/* XFER_RDY frame */
274b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_RESP		= 0x5,		/* RESPONSE frame */
275b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_READ		= 0x6,		/* Read DATA frame(s) */
276b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_SSP_FR_READ_RESP	= 0x7,		/* ditto, plus RESPONSE */
277b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
278b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_PASSTHRU		= (1U << 12),	/* pass-through (SSP) */
279b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_FBURST		= (1U << 11),	/* first burst (SSP) */
280b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_CHK_LEN		= (1U << 10),	/* chk xfer len (SSP) */
281b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_RETRY		= (1U << 9),	/* tport layer retry (SSP) */
282b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_PROTECTION		= (1U << 8),	/* protection info rec (SSP) */
283b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_RESET		= (1U << 7),	/* Reset (STP/SATA) */
284b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_FPDMA		= (1U << 6),	/* First party DMA (STP/SATA) */
285b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_ATAPI		= (1U << 5),	/* ATAPI (STP/SATA) */
286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_BIST		= (1U << 4),	/* BIST activate (STP/SATA) */
287b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MCH_PMP_MASK		= 0xf,		/* PMP from cmd FIS (STP/SATA)*/
288b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
289b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_RST		= (1U << 5),	/* port logic reset */
290b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
291b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik						/* 0(LSB first), 1(MSB first) */
292b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_ENDIAN_DATA	= (1U << 3),	/* PRD data */
293b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_ENDIAN_RSP		= (1U << 2),	/* response frame */
294b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_ENDIAN_OPEN	= (1U << 1),	/* open address frame */
295b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CCTL_ENDIAN_CMD		= (1U << 0),	/* command table */
296b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
297b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_Px_SER_CTLSTAT (per-phy control) */
298b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHY_SSP_RST		= (1U << 3),	/* reset SSP link layer */
299b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHY_BCAST_CHG		= (1U << 2),	/* broadcast(change) notif */
300b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHY_RST_HARD		= (1U << 1),	/* hard reset + phy reset */
301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHY_RST			= (1U << 0),	/* phy reset */
3028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
3038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
3048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
3058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
3068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			(0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
3078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHY_READY_MASK		= (1U << 20),
308b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
309b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
3108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYEV_DEC_ERR		= (1U << 24),	/* Phy Decoding Error */
311b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_UNASSOC_FIS	= (1U << 19),	/* unassociated FIS rx'd */
312b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_AN		= (1U << 18),	/* SATA async notification */
313b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_BIST_ACT		= (1U << 17),	/* BIST activate FIS */
314b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_SIG_FIS		= (1U << 16),	/* signature FIS */
315b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_POOF		= (1U << 12),	/* phy ready from 1 -> 0 */
316b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_IU_BIG		= (1U << 11),	/* IU too long err */
317b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_IU_SMALL		= (1U << 10),	/* IU too short err */
318b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_UNK_TAG		= (1U << 9),	/* unknown tag */
319b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_BROAD_CH		= (1U << 8),	/* broadcast(CHANGE) */
320b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_COMWAKE		= (1U << 7),	/* COMWAKE rx'd */
321b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_PORT_SEL		= (1U << 6),	/* port selector present */
322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_HARD_RST		= (1U << 5),	/* hard reset rx'd */
323b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_ID_TMOUT		= (1U << 4),	/* identify timeout */
324b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_ID_FAIL		= (1U << 3),	/* identify failed */
325b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_ID_DONE		= (1U << 2),	/* identify done */
326b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_HARD_RST_DONE	= (1U << 1),	/* hard reset done */
327b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYEV_RDY_CH		= (1U << 0),	/* phy ready changed state */
328b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
329b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* MVS_PCS */
3308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PCS_EN_SATA_REG_SHIFT	= (16),		/* Enable SATA Register Set */
3318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PCS_EN_PORT_XMT_SHIFT	= (12),		/* Enable Port Transmit */
3328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PCS_EN_PORT_XMT_SHIFT2	= (8),		/* For 6480 */
333b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_SATA_RETRY		= (1U << 8),	/* retry ctl FIS on R_ERR */
334b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_RSP_RX_EN		= (1U << 7),	/* raw response rx */
335b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_SELF_CLEAR		= (1U << 5),	/* self-clearing int mode */
336b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_FIS_RX_EN		= (1U << 4),	/* FIS rx enable */
337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_CMD_STOP_ERR	= (1U << 3),	/* cmd stop-on-err enable */
3388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PCS_CMD_RST		= (1U << 1),	/* reset cmd issue */
339b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PCS_CMD_EN		= (1U << 0),	/* enable cmd issue */
3408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
3418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* Port n Attached Device Info */
3428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_DEV_SSP_TRGT	= (1U << 19),
3438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_DEV_SMP_TRGT	= (1U << 18),
3448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_DEV_STP_TRGT	= (1U << 17),
3458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_DEV_SSP_INIT	= (1U << 11),
3468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_DEV_SMP_INIT	= (1U << 10),
3478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_DEV_STP_INIT	= (1U << 9),
3488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_PHY_ID_MASK	= (0xFFU << 24),
3498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_DEV_TRGT_MASK	= (0x7U << 17),
3508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_DEV_INIT_MASK	= (0x7U << 9),
3518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_DEV_TYPE_MASK	= (0x7U << 0),
3528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
3538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* Port n PHY Status */
3548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHY_RDY			= (1U << 2),
3558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHY_DW_SYNC		= (1U << 1),
3568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHY_OOB_DTCTD		= (1U << 0),
3578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
3588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* VSR */
3598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* PHYMODE 6 (CDB) */
3608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHY_MODE6_DTL_SPEED	= (1U << 27),
361b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
363b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum mvs_info_flags {
364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVF_MSI			= (1U << 0),	/* MSI is enabled */
365b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	MVF_PHY_PWR_FIX		= (1U << 1),	/* bug workaround */
366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
367b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
368b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum sas_cmd_port_registers {
369b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_CMRST_OOB_DET	= 0x100, /* COMRESET OOB detect register */
370b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_CMWK_OOB_DET	= 0x104, /* COMWAKE OOB detect register */
371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_CMSAS_OOB_DET	= 0x108, /* COMSAS OOB detect register */
372b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_BRST_OOB_DET	= 0x10c, /* burst OOB detect register */
373b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_OOB_SPACE		= 0x110, /* OOB space control register */
374b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_OOB_BURST		= 0x114, /* OOB burst control register */
375b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_TIMER		= 0x118, /* PHY timer control register */
376b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_CONFIG0		= 0x11c, /* PHY config register 0 */
377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_CONFIG1		= 0x120, /* PHY config register 1 */
378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SAS_CTL0		= 0x124, /* SAS control register 0 */
379b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SAS_CTL1		= 0x128, /* SAS control register 1 */
380b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SAS_CTL2		= 0x12c, /* SAS control register 2 */
381b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SAS_CTL3		= 0x130, /* SAS control register 3 */
382b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_ID_TEST		= 0x134, /* ID test register */
383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PL_TIMER		= 0x138, /* PL timer register */
384b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_WD_TIMER		= 0x13c, /* WD timer register */
385b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_SEL_COUNT	= 0x140, /* port selector count register */
386b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_APP_MEM_CTL		= 0x144, /* Application Memory Control */
387b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_XOR_MEM_CTL		= 0x148, /* XOR Block Memory Control */
388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_DMA_MEM_CTL		= 0x14c, /* DMA Block Memory Control */
389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_CTL0	= 0x150, /* Port Memory Control 0 */
390b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_CTL1	= 0x154, /* Port Memory Control 1 */
391b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SATA_PORT_MEM_CTL0	= 0x158, /* SATA Port Memory Control 0 */
392b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SATA_PORT_MEM_CTL1	= 0x15c, /* SATA Port Memory Control 1 */
393b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_XOR_MEM_BIST_CTL	= 0x160, /* XOR Memory BIST Control */
394b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_XOR_MEM_BIST_STAT	= 0x164, /* XOR Memroy BIST Status */
395b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_DMA_MEM_BIST_CTL	= 0x168, /* DMA Memory BIST Control */
396b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_DMA_MEM_BIST_STAT	= 0x16c, /* DMA Memory BIST Status */
397b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_BIST_CTL	= 0x170, /* Port Memory BIST Control */
398b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */
399b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */
400b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_STP_MEM_BIST_CTL	= 0x17c, /* STP Memory BIST Control */
401b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_STP_MEM_BIST_STAT0	= 0x180, /* STP Memory BIST Status 0 */
402b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_STP_MEM_BIST_STAT1	= 0x184, /* STP Memory BIST Status 1 */
403b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_RESET_COUNT		= 0x188, /* Reset Count */
404b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_MONTR_DATA_SEL	= 0x18C, /* Monitor Data/Select */
405b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PLL_PHY_CONFIG	= 0x190, /* PLL/PHY Configuration */
406b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_CTL		= 0x194, /* PHY Control and Status */
407b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_TEST_COUNT0	= 0x198, /* Phy Test Count 0 */
408b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_TEST_COUNT1	= 0x19C, /* Phy Test Count 1 */
409b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_TEST_COUNT2	= 0x1A0, /* Phy Test Count 2 */
410b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_APP_ERR_CONFIG	= 0x1A4, /* Application Error Configuration */
411b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PND_FIFO_CTL0	= 0x1A8, /* Pending FIFO Control 0 */
412b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_HOST_CTL		= 0x1AC, /* Host Control Status */
413b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_HOST_WR_DATA	= 0x1B0, /* Host Write Data */
414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_HOST_RD_DATA	= 0x1B4, /* Host Read Data */
415b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PHY_MODE_21		= 0x1B8, /* Phy Mode 21 */
416b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SL_MODE0		= 0x1BC, /* SL Mode 0 */
417b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_SL_MODE1		= 0x1C0, /* SL Mode 1 */
418b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	CMD_PND_FIFO_CTL1	= 0x1C4, /* Pending FIFO Control 1 */
419b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
420b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
421b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* SAS/SATA configuration port registers, aka phy registers */
422b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum sas_sata_config_port_regs {
4238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_IDENTIFY		= 0x00,	/* info for IDENTIFY frame */
4248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_ADDR_LO		= 0x04,	/* my SAS address (low) */
4258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_ADDR_HI		= 0x08,	/* my SAS address (high) */
4268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_ATT_DEV_INFO	= 0x0C,	/* attached device info */
427b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_ATT_ADDR_LO	= 0x10,	/* attached dev SAS addr (low) */
428b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_ATT_ADDR_HI	= 0x14,	/* attached dev SAS addr (high) */
429b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_SATA_CTL		= 0x18,	/* SATA control */
430b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_PHY_STAT		= 0x1C,	/* PHY status */
4318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_SATA_SIG0		= 0x20,	/*port SATA signature FIS(Byte 0-3) */
4328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_SATA_SIG1		= 0x24,	/*port SATA signature FIS(Byte 4-7) */
4338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_SATA_SIG2		= 0x28,	/*port SATA signature FIS(Byte 8-11) */
4348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_SATA_SIG3		= 0x2c,	/*port SATA signature FIS(Byte 12-15) */
4358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_R_ERR_COUNT	= 0x30, /* port R_ERR count register */
4368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PHYR_CRC_ERR_COUNT	= 0x34, /* port CRC error count register */
437b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_WIDE_PORT		= 0x38,	/* wide port participating */
438b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_CURRENT0		= 0x80,	/* current connection info 0 */
439b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_CURRENT1		= 0x84,	/* current connection info 1 */
440b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	PHYR_CURRENT2		= 0x88,	/* current connection info 2 */
441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
4438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei/*  SAS/SATA Vendor Specific Port Registers */
4448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weienum sas_sata_vsp_regs {
4458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_STAT		= 0x00, /* Phy Status */
4468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE1		= 0x01, /* phy tx */
4478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE2		= 0x02, /* tx scc */
4488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE3		= 0x03, /* pll */
4498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE4		= 0x04, /* VCO */
4508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE5		= 0x05, /* Rx */
4518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE6		= 0x06, /* CDR */
4528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE7		= 0x07, /* Impedance */
4538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE8		= 0x08, /* Voltage */
4548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE9		= 0x09, /* Test */
4558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE10		= 0x0A, /* Power */
4568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_MODE11		= 0x0B, /* Phy Mode */
4578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_VS0		= 0x0C, /* Vednor Specific 0 */
4588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	VSR_PHY_VS1		= 0x0D, /* Vednor Specific 1 */
4598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei};
4608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
461b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum pci_cfg_registers {
4628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PCR_PHY_CTL	= 0x40,
4638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PCR_PHY_CTL2	= 0x90,
4648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PCR_DEV_CTRL	= 0xE8,
465b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
466b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
467b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum pci_cfg_register_bits {
4688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PCTL_PWR_ON	= (0xFU << 24),
4698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PCTL_OFF	= (0xFU << 12),
4708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PRD_REQ_SIZE	= (0x4000),
4718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PRD_REQ_MASK	= (0x00007000),
472b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
473b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
474b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum nvram_layout_offsets {
4758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	NVR_SIG		= 0x00,		/* 0xAA, 0x55 */
4768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	NVR_SAS_ADDR	= 0x02,		/* 8-byte SAS address */
477b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
478b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
479b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikenum chip_flavors {
480b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	chip_6320,
481b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	chip_6440,
482b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	chip_6480,
483b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
484b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
4858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weienum port_type {
4868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_TYPE_SAS	=  (1L << 1),
4878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	PORT_TYPE_SATA	=  (1L << 0),
4888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei};
4898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
4908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei/* Command Table Format */
4918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weienum ct_format {
4928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* SSP */
4938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	SSP_F_H		=  0x00,
4948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	SSP_F_IU	=  0x18,
4958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	SSP_F_MAX	=  0x4D,
4968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* STP */
4978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	STP_CMD_FIS	=  0x00,
4988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	STP_ATAPI_CMD	=  0x40,
4998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	STP_F_MAX	=  0x10,
5008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* SMP */
5018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	SMP_F_T		=  0x00,
5028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	SMP_F_DEP	=  0x01,
5038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	SMP_F_MAX	=  0x101,
5048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei};
5058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
5068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weienum status_buffer {
5078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	SB_EIR_OFF	=  0x00,	/* Error Information Record */
5088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	SB_RFB_OFF	=  0x08,	/* Response Frame Buffer */
5098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	SB_RFB_MAX	=  0x400,	/* RFB size*/
5108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei};
5118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
5128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weienum error_info_rec {
5138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	CMD_ISS_STPD	=  (1U << 31),	/* Cmd Issue Stopped */
5148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei};
5158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
516b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_chip_info {
5178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32		n_phy;
5188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32		srs_sz;
5198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32		slot_width;
520b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
521b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
522b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_err_info {
523b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			flags;
524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			flags2;
525b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
527b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_prd {
528b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			addr;		/* 64-bit buffer address */
529b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			reserved;
530b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			len;		/* 16-bit length */
531b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
532b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
533b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_cmd_hdr {
534b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			flags;		/* PRD tbl len; SAS, SATA ctl */
535b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			lens;		/* cmd, max resp frame len */
536b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			tags;		/* targ port xfer tag; tag */
537b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			data_len;	/* data xfer len */
538b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			cmd_tbl;	/* command table address */
539b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			open_frame;	/* open addr frame address */
540b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			status_buf;	/* status buffer address */
541b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le64			prd_tbl;	/* PRD tbl address */
542b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			reserved[4];
543b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
544b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
545b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_slot_info {
546b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task		*task;
5478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32			n_elem;
5488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32			tx;
549b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
550b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* DMA buffer for storing cmd tbl, open addr frame, status buffer,
551b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * and PRD table
552b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
553b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void			*buf;
554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		buf_dma;
5558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
5568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32			cmd_size;
5578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
558b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
559b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void			*response;
560b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
561b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
562b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_port {
563b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port	sas_port;
5648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u8			port_attached;
5658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u8			taskfileset;
5668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u8			wide_port_phymap;
567b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
568b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_phy {
570b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_port		*port;
571b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_phy	sas_phy;
5728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct sas_identify	identify;
5738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct scsi_device	*sdev;
5748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64		dev_sas_addr;
5758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64		att_dev_sas_addr;
5768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32		att_dev_info;
5778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32		dev_info;
5788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32		phy_type;
5798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32		phy_status;
5808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32		irq_status;
5818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32		frame_rcvd_size;
5828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u8		frame_rcvd[32];
5838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u8		phy_attached;
584b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
585b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
586b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_info {
587b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	unsigned long		flags;
588b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
589b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spinlock_t		lock;		/* host-wide lock */
590b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct pci_dev		*pdev;		/* our device */
591b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem		*regs;		/* enhanced mode registers */
592b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem		*peri_regs;	/* peripheral registers */
593b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
594b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8			sas_addr[SAS_ADDR_SIZE];
595b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_ha_struct	sas;		/* SCSI/SAS glue */
596b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct Scsi_Host	*shost;
597b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
598b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			*tx;		/* TX (delivery) DMA ring */
599b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		tx_dma;
600b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32			tx_prod;	/* cached next-producer idx */
601b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
602b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			*rx;		/* RX (completion) DMA ring */
603b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		rx_dma;
604b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32			rx_cons;	/* RX consumer idx */
605b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	__le32			*rx_fis;	/* RX'd FIS area */
607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		rx_fis_dma;
608b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_cmd_hdr	*slot;	/* DMA command header slots */
610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t		slot_dma;
611b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
612b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	const struct mvs_chip_info *chip;
613b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	unsigned long		tags[MVS_SLOTS];
615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info	slot_info[MVS_SLOTS];
6168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				/* further per-slot information */
617b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_phy		phy[MVS_MAX_PHYS];
618b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_port		port[MVS_MAX_PHYS];
6198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
6208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32			can_queue;	/* per adapter */
6218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32			tag_out;	/*Get*/
6228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32			tag_in;		/*Give*/
623b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
624b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistruct mvs_queue_task {
6268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct list_head list;
6278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
6288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void   *uldd_task;
6298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei};
6308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
6318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
6328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			   void *funcdata);
6338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port);
6348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val);
6358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port);
6368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
6378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				u32 port, u32 val);
6388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port);
6398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val);
6408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr);
6418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port);
6428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val);
6438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr);
6448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port);
6458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val);
6468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val);
6478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port);
6488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
6498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i);
6508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_detect_porttype(struct mvs_info *mvi, int i);
6518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
6528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port);
6538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port);
6548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_is_sig_fis_received(u32 irq_status);
6558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
6568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_scan_finished(struct Scsi_Host *, unsigned long);
6578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_scan_start(struct Scsi_Host *);
6588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_sas_slave_alloc(struct scsi_device *scsi_dev);
6598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
660b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct scsi_transport_template *mvs_stt;
661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic const struct mvs_chip_info mvs_chips[] = {
6638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	[chip_6320] =		{ 2, 16, 9  },
6648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	[chip_6440] =		{ 4, 16, 9  },
665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	[chip_6480] =		{ 8, 32, 10 },
666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct scsi_host_template mvs_sht = {
669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.module			= THIS_MODULE,
670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.name			= DRV_NAME,
671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.queuecommand		= sas_queuecommand,
672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.target_alloc		= sas_target_alloc,
673b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.slave_configure	= sas_slave_configure,
674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.slave_destroy		= sas_slave_destroy,
6758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	.scan_finished		= mvs_scan_finished,
6768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	.scan_start		= mvs_scan_start,
677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.change_queue_depth	= sas_change_queue_depth,
678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.change_queue_type	= sas_change_queue_type,
679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.bios_param		= sas_bios_param,
680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.can_queue		= 1,
681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.cmd_per_lun		= 1,
682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.this_id		= -1,
683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.sg_tablesize		= SG_ALL,
684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,
685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.use_clustering		= ENABLE_CLUSTERING,
6868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	.eh_device_reset_handler	= sas_eh_device_reset_handler,
687b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.eh_bus_reset_handler	= sas_eh_bus_reset_handler,
6888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	.slave_alloc		= mvs_sas_slave_alloc,
689b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.target_destroy		= sas_target_destroy,
690b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.ioctl			= sas_ioctl,
691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
692b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
6948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
6958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 i;
6968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 run;
6978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 offset;
6988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
6998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	offset = 0;
7008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	while (size) {
7018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		printk("%08X : ", baseaddr + offset);
7028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (size >= 16)
7038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			run = 16;
7048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		else
7058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			run = size;
7068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		size -= run;
7078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		for (i = 0; i < 16; i++) {
7088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (i < run)
7098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				printk("%02X ", (u32)data[i]);
7108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			else
7118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				printk("   ");
7128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
7138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		printk(": ");
7148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		for (i = 0; i < run; i++)
7158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			printk("%c", isalnum(data[i]) ? data[i] : '.');
7168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		printk("\n");
7178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		data = &data[16];
7188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		offset += run;
7198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
7208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	printk("\n");
7218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
7228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
7238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
7248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				   enum sas_protocol proto)
7258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
7268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
7278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 offset;
7288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
7298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot = &mvi->slot_info[tag];
7308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
7318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	offset = slot->cmd_size + MVS_OAF_SZ +
7328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_prd) * slot->n_elem;
7338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer[%d] :\n",
7348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tag);
7358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(32, (u8 *) slot->response,
7368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		    (u32) slot->buf_dma + offset);
7378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
7388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
7398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
7408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
7418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				enum sas_protocol proto)
7428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
7438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
7448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 sz, w_ptr, r_ptr;
7458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64 addr;
7468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
7478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
7488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot = &mvi->slot_info[tag];
7498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
7508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*Delivery Queue */
7518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	sz = mr32(TX_CFG) & TX_RING_SZ_MASK;
7528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	w_ptr = mr32(TX_PROD_IDX) & TX_RING_SZ_MASK;
7538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	r_ptr = mr32(TX_CONS_IDX) & TX_RING_SZ_MASK;
7548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO);
7558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev,
7568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Delivery Queue Size=%04d , WRT_PTR=%04X , RD_PTR=%04X\n",
7578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		sz, w_ptr, r_ptr);
7588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev,
7598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Delivery Queue Base Address=0x%llX (PA)"
7608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"(tx_dma=0x%llX), Entry=%04d\n",
7618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		addr, mvi->tx_dma, w_ptr);
7628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
7638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			(u32) mvi->tx_dma + sizeof(u32) * w_ptr);
7648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*Command List */
7658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	addr = mr32(CMD_LIST_HI) << 16 << 16 | mr32(CMD_LIST_LO);
7668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev,
7678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Command List Base Address=0x%llX (PA)"
7688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"(slot_dma=0x%llX), Header=%03d\n",
7698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		addr, mvi->slot_dma, tag);
7708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "Command Header[%03d]:\n", tag);
7718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*mvs_cmd_hdr */
7728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
7738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		(u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
7748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*1.command table area */
7758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "+---->Command Table :\n");
7768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
7778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*2.open address frame area */
7788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "+---->Open Address Frame :\n");
7798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
7808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(u32) slot->buf_dma + slot->cmd_size);
7818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*3.status buffer */
7828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hba_sb_dump(mvi, tag, proto);
7838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*4.PRD table */
7848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "+---->PRD table :\n");
7858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(struct mvs_prd) * slot->n_elem,
7868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		(u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
7878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		(u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
7888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
7898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
7908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
7918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_cq_dump(struct mvs_info *mvi)
7928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
7938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
7948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64 addr;
7958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
7968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
7978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 entry = mvi->rx_cons + 1;
7988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
7998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
8008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*Completion Queue */
8018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
8028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "Completion Task = 0x%08X\n",
8038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		   (u32) mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
8048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev,
8058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Completion List Base Address=0x%llX (PA), "
8068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"CQ_Entry=%04d, CQ_WP=0x%08X\n",
8078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		addr, entry - 1, mvi->rx[0]);
8088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
8098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		    mvi->rx_dma + sizeof(u32) * entry);
8108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
8118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
8128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
8138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_interrupt_enable(struct mvs_info *mvi)
8148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
8158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
8168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tmp;
8178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
8188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = mr32(GBL_CTL);
8198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
8208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(GBL_CTL, tmp | INT_EN);
8218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
8228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
8238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_interrupt_disable(struct mvs_info *mvi)
8248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
8258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
8268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tmp;
8278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
8288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = mr32(GBL_CTL);
8298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
8308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(GBL_CTL, tmp & ~INT_EN);
8318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
8328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
8338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
834b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
835b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* move to PCI layer or libata core? */
836b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int pci_go_64(struct pci_dev *pdev)
837b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
838b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc;
839b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
840b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
841b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
842b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc) {
843b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
844b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			if (rc) {
845b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				dev_printk(KERN_ERR, &pdev->dev,
846b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					   "64-bit DMA enable failed\n");
847b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				return rc;
848b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			}
849b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
850b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	} else {
851b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
852b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc) {
853b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
854b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				   "32-bit DMA enable failed\n");
855b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
856b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
857b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
858b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc) {
859b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
860b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				   "32-bit consistent DMA enable failed\n");
861b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
862b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
863b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
864b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
865b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
866b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
867b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
8688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
869b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
8708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tag_in = (mvi->tag_in + 1) & (MVS_SLOTS - 1);
8718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tags[mvi->tag_in] = tag;
872b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
873b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
8748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_tag_free(struct mvs_info *mvi, u32 tag)
875b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
8768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tag_out = (mvi->tag_out - 1) & (MVS_SLOTS - 1);
877b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
878b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
8798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
880b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
8818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (mvi->tag_out != mvi->tag_in) {
8828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		*tag_out = mvi->tags[mvi->tag_out];
8838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvi->tag_out = (mvi->tag_out + 1) & (MVS_SLOTS - 1);
8848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return 0;
8858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
8868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return -EBUSY;
887b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
888b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
8898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_tag_init(struct mvs_info *mvi)
890b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
8918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	int i;
8928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for (i = 0; i < MVS_SLOTS; ++i)
8938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvi->tags[i] = i;
8948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tag_out = 0;
8958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tag_in = MVS_SLOTS - 1;
896b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
897b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
8988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#ifndef MVS_DISABLE_NVRAM
8998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data)
900b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
901b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int timeout = 1000;
902b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
903b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (addr & ~SPI_ADDR_MASK)
904b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -EINVAL;
905b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
906b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	writel(addr, regs + SPI_CMD);
907b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	writel(TWSI_RD, regs + SPI_CTL);
908b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
909b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	while (timeout-- > 0) {
910b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (readl(regs + SPI_CTL) & TWSI_RDY) {
911b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			*data = readl(regs + SPI_DATA);
912b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return 0;
913b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
914b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
915b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		udelay(10);
916b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
917b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
918b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return -EBUSY;
919b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
920b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
9218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_eep_read_buf(void __iomem *regs, u32 addr,
9228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			    void *buf, u32 buflen)
923b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
9248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 addr_end, tmp_addr, i, j;
925b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp = 0;
926b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc;
927b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *tmp8, *buf8 = buf;
928b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
929b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	addr_end = addr + buflen;
930b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp_addr = ALIGN(addr, 4);
931b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (addr > 0xff)
932b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -EINVAL;
933b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
934b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	j = addr & 0x3;
935b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (j) {
936b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = mvs_eep_read(regs, tmp_addr, &tmp);
937b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc)
938b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
939b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
9408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp8 = (u8 *)&tmp;
941b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		for (i = j; i < 4; i++)
942b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			*buf8++ = tmp8[i];
943b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
944b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp_addr += 4;
945b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
946b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
947b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) {
948b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = mvs_eep_read(regs, tmp_addr, &tmp);
949b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc)
950b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
951b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
952b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		memcpy(buf8, &tmp, 4);
953b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf8 += 4;
954b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
955b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
956b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (tmp_addr < addr_end) {
957b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = mvs_eep_read(regs, tmp_addr, &tmp);
958b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (rc)
959b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			return rc;
960b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
9618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp8 = (u8 *)&tmp;
962b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		j = addr_end - tmp_addr;
963b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		for (i = 0; i < j; i++)
964b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			*buf8++ = tmp8[i];
965b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
966b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp_addr += 4;
967b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
968b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
969b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
970b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
9718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
972b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
9738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_nvram_read(struct mvs_info *mvi, u32 addr,
9748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			  void *buf, u32 buflen)
975b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
9768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#ifndef MVS_DISABLE_NVRAM
977b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
978b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc, i;
9798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 sum;
980b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 hdr[2], *tmp;
981b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	const char *msg;
982b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
983b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = mvs_eep_read_buf(regs, addr, &hdr, 2);
984b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc) {
985b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msg = "nvram hdr read failed";
986b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
987b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
988b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen);
989b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc) {
990b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msg = "nvram read failed";
991b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
992b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
993b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
9948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (hdr[0] != 0x5A) {
9958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		/* entry id */
996b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msg = "invalid nvram entry id";
997b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -ENOENT;
998b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
999b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1000b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1001b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = buf;
10028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	sum = ((u32)hdr[0]) + ((u32)hdr[1]);
1003b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < buflen; i++)
10048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		sum += ((u32)tmp[i]);
1005b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1006b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (sum) {
1007b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msg = "nvram checksum failure";
1008b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -EILSEQ;
1009b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1010b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1011b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1012b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1013b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1014b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
1015b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
1016b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
10178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#else
10188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* FIXME , For SAS target mode */
10198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memcpy(buf, "\x00\x00\xab\x11\x30\x04\x05\x50", 8);
10208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return 0;
10218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
10228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
10238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
10258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
10268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_phy *phy = &mvi->phy[i];
10278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (!phy->phy_attached)
10298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return;
10308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (phy->phy_type & PORT_TYPE_SAS) {
10328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		struct sas_identify_frame *id;
10338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		id = (struct sas_identify_frame *)phy->frame_rcvd;
10358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		id->dev_type = phy->identify.device_type;
10368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		id->initiator_bits = SAS_PROTOCOL_ALL;
10378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		id->target_bits = phy->identify.target_port_protocols;
10388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	} else if (phy->phy_type & PORT_TYPE_SATA) {
10398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		/* TODO */
10408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
10418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
10428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
10438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				   PORTE_BYTES_DMAED);
10448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
10458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
10478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
10488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* give the phy enabling interrupt event time to come in (1s
10498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * is empirically about all it takes) */
10508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (time < HZ)
10518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return 0;
10528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* Wait for discovery to finish */
10538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	scsi_flush_work(shost);
10548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return 1;
10558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
10568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_scan_start(struct Scsi_Host *shost)
10588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
10598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	int i;
10608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
10618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for (i = 0; i < mvi->chip->n_phy; ++i) {
10638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_bytes_dmaed(mvi, i);
10648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
10658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
10668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_sas_slave_alloc(struct scsi_device *scsi_dev)
10688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
10698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	int rc;
10708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	rc = sas_slave_alloc(scsi_dev);
10728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return rc;
1074b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1075b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1076b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events)
1077b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
10788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
10798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct sas_ha_struct *sas_ha = &mvi->sas;
10808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_phy *phy = &mvi->phy[port_no];
10818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct asd_sas_phy *sas_phy = &phy->sas_phy;
10828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	phy->irq_status = mvs_read_port_irq_stat(mvi, port_no);
10848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*
10858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	* events is port event now ,
10868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	* we need check the interrupt status which belongs to per port.
10878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	*/
10888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev,
10898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Port %d Event = %X\n",
10908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		port_no, phy->irq_status);
10918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) {
10938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (!mvs_is_phy_ready(mvi, port_no)) {
10948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			sas_phy_disconnected(sas_phy);
10958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
10968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		} else
10978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL);
10988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
10998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (!(phy->irq_status & PHYEV_DEC_ERR)) {
11008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (phy->irq_status & PHYEV_COMWAKE) {
11018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			u32 tmp = mvs_read_port_irq_mask(mvi, port_no);
11028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_write_port_irq_mask(mvi, port_no,
11038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei						tmp | PHYEV_SIG_FIS);
11048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
11058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
11068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			phy->phy_status = mvs_is_phy_ready(mvi, port_no);
11078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (phy->phy_status) {
11088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				mvs_detect_porttype(mvi, port_no);
11098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
11108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				if (phy->phy_type & PORT_TYPE_SATA) {
11118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					u32 tmp = mvs_read_port_irq_mask(mvi,
11128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei								port_no);
11138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					tmp &= ~PHYEV_SIG_FIS;
11148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					mvs_write_port_irq_mask(mvi,
11158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei								port_no, tmp);
11168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				}
11178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
11188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				mvs_update_phyinfo(mvi, port_no, 0);
11198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				sas_ha->notify_phy_event(sas_phy,
11208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei							PHYE_OOB_DONE);
11218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				mvs_bytes_dmaed(mvi, port_no);
11228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			} else {
11238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				dev_printk(KERN_DEBUG, &pdev->dev,
11248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					"plugin interrupt but phy is gone\n");
11258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET,
11268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei							NULL);
11278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			}
11288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		} else if (phy->irq_status & PHYEV_BROAD_CH)
11298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			sas_ha->notify_port_event(sas_phy,
11308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei						PORTE_BROADCAST_RCVD);
11318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
11328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port_irq_stat(mvi, port_no, phy->irq_status);
1133b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1134b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1135b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_sata(struct mvs_info *mvi)
1136b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1137b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME */
1138b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1139b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1140b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
11418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			  struct mvs_slot_info *slot, u32 slot_idx)
1142b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
11438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (!sas_protocol_ata(task->task_proto))
11448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (slot->n_elem)
11458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			pci_unmap_sg(mvi->pdev, task->scatter,
11468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				     slot->n_elem, task->data_dir);
1147b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1148b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	switch (task->task_proto) {
1149b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SMP:
1150b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1,
1151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     PCI_DMA_FROMDEVICE);
1152b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1,
1153b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     PCI_DMA_TODEVICE);
1154b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1155b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1156b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SATA:
1157b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_STP:
1158b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SSP:
1159b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	default:
1160b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* do nothing */
1161b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1162b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1163b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
11648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->task = NULL;
1165b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_tag_clear(mvi, slot_idx);
1166b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1167b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1168b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
11698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			 u32 slot_idx)
1170b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
11718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
11728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64 err_dw0 = *(u32 *) slot->response;
11738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
11748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tmp;
11758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
11768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (err_dw0 & CMD_ISS_STPD)
11778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (sas_protocol_ata(task->task_proto)) {
11788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tmp = mr32(INT_STAT_SRS);
11798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mw32(INT_STAT_SRS, tmp & 0xFFFF);
11808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
11818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
11828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
1183b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1184b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
11858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
1186b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
11878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
1188b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
1189b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = slot->task;
1190b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct task_status_struct *tstat = &task->task_status;
11918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port = &mvi->port[task->dev->port->id];
1192b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	bool aborted;
11938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void *to;
1194b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1195b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock(&task->task_state_lock);
1196b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
1197b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!aborted) {
1198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		task->task_state_flags &=
11998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		    ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
1200b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		task->task_state_flags |= SAS_TASK_STATE_DONE;
1201b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1202b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock(&task->task_state_lock);
1203b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1204b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (aborted)
12058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return -1;
1206b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1207b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(tstat, 0, sizeof(*tstat));
1208b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tstat->resp = SAS_TASK_COMPLETE;
1209b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
12108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
12118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (unlikely(!port->port_attached)) {
12128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tstat->stat = SAS_PHY_DOWN;
12138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		goto out;
12148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
12158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1216b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* error info record present */
12178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if ((rx_desc & RXQ_ERR) && (*(u64 *) slot->response)) {
1218b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tstat->stat = SAM_CHECK_COND;
1219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_slot_err(mvi, task, slot_idx);
1220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto out;
1221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1223b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	switch (task->task_proto) {
1224b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SSP:
1225b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* hw says status == 0, datapres == 0 */
12268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (rx_desc & RXQ_GOOD) {
1227b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tstat->stat = SAM_GOOD;
12288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tstat->resp = SAS_TASK_COMPLETE;
12298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
1230b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* response frame present */
1231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		else if (rx_desc & RXQ_RSP) {
1232b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			struct ssp_response_iu *iu =
12338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			    slot->response + sizeof(struct mvs_err_info);
1234b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			sas_ssp_task_response(&mvi->pdev->dev, task, iu);
1235b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
1236b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1237b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* should never happen? */
1238b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		else
1239b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tstat->stat = SAM_CHECK_COND;
1240b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1241b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
12428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_SMP: {
12438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			struct scatterlist *sg_resp = &task->smp_task.smp_resp;
12448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tstat->stat = SAM_GOOD;
12458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
12468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			memcpy(to + sg_resp->offset,
12478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				slot->response + sizeof(struct mvs_err_info),
12488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				sg_dma_len(sg_resp));
12498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			kunmap_atomic(to, KM_IRQ0);
12508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			break;
12518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
1252b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1253b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_SATA:
1254b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case SAS_PROTOCOL_STP:
12558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
12568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			struct ata_task_resp *resp =
12578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			    (struct ata_task_resp *)tstat->buf;
12588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
12598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) ==
12608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			    RXQ_DONE)
12618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				tstat->stat = SAM_GOOD;
12628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			else
12638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				tstat->stat = SAM_CHECK_COND;
12648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
12658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			resp->frame_len = sizeof(struct dev_to_host_fis);
12668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			memcpy(&resp->ending_fis[0],
12678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			       SATA_RECEIVED_D2H_FIS(port->taskfileset),
12688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			       sizeof(struct dev_to_host_fis));
12698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (resp->ending_fis[2] & ATA_ERR)
12708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				mvs_hexdump(16, resp->ending_fis, 0);
12718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			break;
12728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
1273b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1274b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	default:
1275b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tstat->stat = SAM_CHECK_COND;
1276b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
1277b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1278b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1279b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikout:
1280b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_slot_free(mvi, task, slot, slot_idx);
1281b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	task->task_done(task);
12828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return tstat->stat;
1283b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1284b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1285b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_int_full(struct mvs_info *mvi)
1286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1287b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1288b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp, stat;
1289b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int i;
1290b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1291b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	stat = mr32(INT_STAT);
1292b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
12938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_int_rx(mvi, false);
12948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1295b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < MVS_MAX_PORTS; i++) {
1296b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
1297b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (tmp)
1298b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			mvs_int_port(mvi, i, tmp);
1299b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1300b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (stat & CINT_SRS)
1302b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_int_sata(mvi);
1303b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1304b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(INT_STAT, stat);
1305b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1306b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
1308b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
13098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
1310b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 rx_prod_idx, rx_desc;
1311b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	bool attn = false;
13128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
1313b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1314b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* the first dword in the RX ring is special: it contains
1315b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * a mirror of the hardware's RX producer index, so that
1316b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * we don't have to stall the CPU reading that register.
1317b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * The actual RX ring is offset by one dword, due to this.
1318b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
13198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	rx_prod_idx = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
1320b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rx_prod_idx == 0xfff) {	/* h/w hasn't touched RX ring yet */
1321b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->rx_cons = 0xfff;
13228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return 0;
1323b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
13248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
13258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* The CMPL_Q may come late, read from register and try again
13268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	* note: if coalescing is enabled,
13278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	* it will need to read from register every time for sure
13288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	*/
13298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (mvi->rx_cons == rx_prod_idx)
13308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return 0;
13318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1332b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->rx_cons == 0xfff)
1333b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->rx_cons = MVS_RX_RING_SZ - 1;
1334b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1335b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	while (mvi->rx_cons != rx_prod_idx) {
13368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* increment our internal RX consumer pointer */
1338b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->rx_cons = (mvi->rx_cons + 1) & (MVS_RX_RING_SZ - 1);
1339b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1340b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rx_desc = le32_to_cpu(mvi->rx[mvi->rx_cons + 1]);
1341b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_hba_cq_dump(mvi);
1343b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (unlikely(rx_desc & RXQ_DONE))
13458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_slot_complete(mvi, rx_desc);
13468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (rx_desc & RXQ_ATTN) {
1347b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			attn = true;
13488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n",
13498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				rx_desc);
13508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		} else if (rx_desc & RXQ_ERR) {
13518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n",
13528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				rx_desc);
13538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
1354b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1355b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1356b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (attn && self_clear)
1357b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_int_full(mvi);
1358b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return 0;
1360b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1361b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic irqreturn_t mvs_interrupt(int irq, void *opaque)
1363b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi = opaque;
1365b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 stat;
1367b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1368b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	stat = mr32(GBL_INT_STAT);
13698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
13708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* clear CMD_CMPLT ASAP */
13718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32_f(INT_STAT, CINT_DONE);
13728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1373b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (stat == 0 || stat == 0xffffffff)
1374b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return IRQ_NONE;
1375b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1376b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock(&mvi->lock);
1377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_int_full(mvi);
1379b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1380b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock(&mvi->lock);
1381b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1382b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return IRQ_HANDLED;
1383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1384b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#ifndef MVS_DISABLE_MSI
1386b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
1387b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi = opaque;
1389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1390b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock(&mvi->lock);
1391b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1392b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_int_rx(mvi, true);
1393b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1394b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock(&mvi->lock);
1395b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1396b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return IRQ_HANDLED;
1397b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
13988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
1399b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1400b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstruct mvs_task_exec_info {
14018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct sas_task *task;
14028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_cmd_hdr *hdr;
14038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port;
14048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tag;
14058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	int n_elem;
1406b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
1407b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
14088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_task_prep_smp(struct mvs_info *mvi,
14098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			     struct mvs_task_exec_info *tei)
1410b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
14118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	int elem, rc, i;
14128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct sas_task *task = tei->task;
1413b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
1414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct scatterlist *sg_req, *sg_resp;
14158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 req_len, resp_len, tag = tei->tag;
14168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void *buf_tmp;
14178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u8 *buf_oaf;
14188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dma_addr_t buf_tmp_dma;
14198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_prd *buf_prd;
14208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct scatterlist *sg;
14218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot = &mvi->slot_info[tag];
14228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct asd_sas_port *sas_port = task->dev->port;
14238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
14248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
14258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u8 *buf_cmd;
14268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void *from;
14278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
1428b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
1429b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * DMA-map SMP request, response buffers
1430b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
14318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	sg_req = &task->smp_task.smp_req;
1432b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE);
1433b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!elem)
1434b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -ENOMEM;
1435b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	req_len = sg_dma_len(sg_req);
1436b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
14378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	sg_resp = &task->smp_task.smp_resp;
1438b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE);
1439b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!elem) {
1440b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -ENOMEM;
1441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
1442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1443b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = sg_dma_len(sg_resp);
1444b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1445b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* must be in dwords */
1446b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if ((req_len & 0x3) || (resp_len & 0x3)) {
1447b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -EINVAL;
1448b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_2;
1449b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1450b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1451b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
14528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
1453b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1454b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
14558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
14568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_tmp = slot->buf;
14578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_tmp_dma = slot->buf_dma;
1458b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
14598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
14608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd = buf_tmp;
14618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
14628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_tmp += req_len;
14638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_tmp_dma += req_len;
14648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->cmd_size = req_len;
14658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#else
14668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
14678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
14688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
14708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_oaf = buf_tmp;
14718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
14728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_tmp += MVS_OAF_SZ;
14748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_tmp_dma += MVS_OAF_SZ;
14758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 3: PRD table ********************************************* */
14778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_prd = buf_tmp;
14788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tei->n_elem)
14798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
14808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
14818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = 0;
14828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	i = sizeof(struct mvs_prd) * tei->n_elem;
14848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_tmp += i;
14858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_tmp_dma += i;
14868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
14888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->response = buf_tmp;
14898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
14908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*
14928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * Fill in TX ring and command slot header
14938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 */
14948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->tx = mvi->tx_prod;
14958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
14968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					TXQ_MODE_I | tag |
14978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(sas_port->phy_mask << TXQ_PHY_SHIFT));
14988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	hdr->flags |= flags;
15008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
1501b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->tags = cpu_to_le32(tag);
1502b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = 0;
1503b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
15048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* generate open address frame hdr (first 12 bytes) */
15058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_oaf[0] = (1 << 7) | (0 << 4) | 0x01; /* initiator, SMP, ftype 1h */
15068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_oaf[1] = task->dev->linkrate & 0xf;
15078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	*(u16 *)(buf_oaf + 2) = 0xFFFF;		/* SAS SPEC */
15088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
15098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* fill in PRD (scatter/gather) table, if any */
15118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for_each_sg(task->scatter, sg, tei->n_elem, i) {
15128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
15138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
15148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		buf_prd++;
15158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
15168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
15188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* copy cmd table */
15198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
15208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memcpy(buf_cmd, from + sg_req->offset, req_len);
15218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	kunmap_atomic(from, KM_IRQ0);
15228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
1523b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1525b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_2:
1526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1,
1527b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		     PCI_DMA_FROMDEVICE);
1528b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
1529b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1,
1530b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		     PCI_DMA_TODEVICE);
1531b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
1532b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1533b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
15348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
15358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
15368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
15378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tmp, offs;
15388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u8 *tfs = &port->taskfileset;
15398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (*tfs == MVS_ID_NOT_MAPPED)
15418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return;
15428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
15448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (*tfs < 16) {
15458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = mr32(PCS);
15468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mw32(PCS, tmp & ~offs);
15478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	} else {
15488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = mr32(CTL);
15498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mw32(CTL, tmp & ~offs);
15508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
15518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
15538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tmp)
15548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mw32(INT_STAT_SRS, tmp);
15558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	*tfs = MVS_ID_NOT_MAPPED;
15578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
15588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
15608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
15618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	int i;
15628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tmp, offs;
15638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
15648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (port->taskfileset != MVS_ID_NOT_MAPPED)
15668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return 0;
15678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = mr32(PCS);
15698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for (i = 0; i < mvi->chip->srs_sz; i++) {
15718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (i == 16)
15728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tmp = mr32(CTL);
15738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
15748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (!(tmp & offs)) {
15758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			port->taskfileset = i;
15768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (i < 16)
15788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				mw32(PCS, tmp | offs);
15798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			else
15808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				mw32(CTL, tmp | offs);
15818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tmp = mr32(INT_STAT_SRS) & (1U << i);
15828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (tmp)
15838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				mw32(INT_STAT_SRS, tmp);
15848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			return 0;
15858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
15868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
15878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return MVS_ID_NOT_MAPPED;
15888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
15898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_get_ncq_tag(struct sas_task *task)
15918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
15928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tag = 0;
15938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct ata_queued_cmd *qc = task->uldd_task;
15948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (qc)
15968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tag = qc->tag;
15978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return tag;
15998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
16008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1601b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ata(struct mvs_info *mvi,
1602b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     struct mvs_task_exec_info *tei)
1603b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1604b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
1605b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct domain_device *dev = task->dev;
1606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
1607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port *sas_port = dev->port;
16088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot;
1609b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct scatterlist *sg;
1610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_prd *buf_prd;
16118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port = tei->port;
16128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tag = tei->tag;
16138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
1614b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
1615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf;
1616b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
16178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 i, req_len, resp_len;
16188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	const u32 max_resp_len = SB_RFB_MAX;
16198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
16208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED)
16218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return -EBUSY;
1622b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot = &mvi->slot_info[tag];
16248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->tx = mvi->tx_prod;
16258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
16268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
16278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(sas_port->phy_mask << TXQ_PHY_SHIFT) |
16288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(port->taskfileset << TXQ_SRS_SHIFT));
1629b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1630b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ata_task.use_ncq)
1631b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FPDMA;
16328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
16338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
16348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			flags |= MCH_ATAPI;
16358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
16368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1637b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: fill in port multiplier number */
1638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->flags = cpu_to_le32(flags);
16408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
16418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* FIXME: the low order order 5 bits for the TAG if enable NCQ */
16428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (task->ata_task.use_ncq) {
16438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->tags = cpu_to_le32(mvs_get_ncq_tag(task));
16448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		/*Fill in task file */
16458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		task->ata_task.fis.sector_count = hdr->tags << 3;
16468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	} else
16478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->tags = cpu_to_le32(tag);
1648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = cpu_to_le32(task->total_xfer_len);
1649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
1651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
1652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
16558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd = buf_tmp = slot->buf;
1656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma = slot->buf_dma;
1657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
1659b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1660b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_ATA_CMD_SZ;
1661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_ATA_CMD_SZ;
16628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
16638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->cmd_size = MVS_ATA_CMD_SZ;
16648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
1665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
1667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* used for STP.  unused for SATA? */
1668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
1669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
1670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
1672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
1673b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 3: PRD table ********************************************* */
1675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
16768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tei->n_elem)
16778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
16788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
16798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = 0;
1680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	i = sizeof(struct mvs_prd) * tei->n_elem;
1682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
1683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
1684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
1686b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: probably unused, for SATA.  kept here just in case
1687b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * we get a STP/SATA error information record
1688b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1689b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
1690b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
1691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	req_len = sizeof(struct host_to_dev_fis);
1693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
16948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_err_info) - i;
1695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
16978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	resp_len = min(resp_len, max_resp_len);
1698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
1699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
1701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in command FIS and ATAPI CDB */
17028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
17038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
17048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		memcpy(buf_cmd + STP_ATAPI_CMD,
17058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			task->ata_task.atapi_packet, 16);
17068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
17078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* generate open address frame hdr (first 12 bytes) */
17088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_oaf[0] = (1 << 7) | (2 << 4) | 0x1;	/* initiator, STP, ftype 1h */
17098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_oaf[1] = task->dev->linkrate & 0xf;
17108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	*(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
17118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
1712b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
17148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for_each_sg(task->scatter, sg, tei->n_elem, i) {
1715b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
1716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
1717b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd++;
1718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1721b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1723b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ssp(struct mvs_info *mvi,
1724b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     struct mvs_task_exec_info *tei)
1725b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1726b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
1727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
17288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port = tei->port;
1729b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info *slot;
1730b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct scatterlist *sg;
1731b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_prd *buf_prd;
1732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct ssp_frame_hdr *ssp_hdr;
1733b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
1734b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf, fburst = 0;
1735b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
1736b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 flags;
17378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 resp_len, req_len, i, tag = tei->tag;
17388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	const u32 max_resp_len = SB_RFB_MAX;
1739b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1740b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot = &mvi->slot_info[tag];
1741b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->tx = mvi->tx_prod;
17438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
17448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
17458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(port->wide_port_phymap << TXQ_PHY_SHIFT));
1746b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1747b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	flags = MCH_RETRY;
1748b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ssp_task.enable_first_burst) {
1749b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FBURST;
1750b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		fburst = (1 << 7);
1751b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1752b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->flags = cpu_to_le32(flags |
17538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				 (tei->n_elem << MCH_PRD_LEN_SHIFT) |
17548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				 (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
1755b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1756b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->tags = cpu_to_le32(tag);
1757b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = cpu_to_le32(task->total_xfer_len);
1758b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1759b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
1760b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
1761b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
1762b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
17648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd = buf_tmp = slot->buf;
1765b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma = slot->buf_dma;
1766b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1767b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
1768b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1769b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_SSP_CMD_SZ;
1770b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_SSP_CMD_SZ;
17718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
17728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->cmd_size = MVS_SSP_CMD_SZ;
17738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
1774b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
1776b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
1777b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
1778b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1779b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
1780b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
1781b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 3: PRD table ********************************************* */
1783b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
17848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tei->n_elem)
17858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
17868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
17878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = 0;
1788b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1789b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	i = sizeof(struct mvs_prd) * tei->n_elem;
1790b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
1791b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
1792b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
1794b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
1795b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
1796b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1797b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
17988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_err_info) - i;
17998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	resp_len = min(resp_len, max_resp_len);
18008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
18018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	req_len = sizeof(struct ssp_frame_hdr) + 28;
1802b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1803b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
1804b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
1805b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1806b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* generate open address frame hdr (first 12 bytes) */
1807b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf[0] = (1 << 7) | (1 << 4) | 0x1;	/* initiator, SSP, ftype 1h */
1808b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf[1] = task->dev->linkrate & 0xf;
18098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	*(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
1810b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
1811b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
18128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* fill in SSP frame header (Command Table.SSP frame header) */
18138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
1814b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	ssp_hdr->frame_type = SSP_COMMAND;
1815b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr,
1816b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	       HASHED_SAS_ADDR_SIZE);
1817b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(ssp_hdr->hashed_src_addr,
1818b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	       task->dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
1819b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	ssp_hdr->tag = cpu_to_be16(tag);
1820b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1821b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in command frame IU */
1822b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_cmd += sizeof(*ssp_hdr);
1823b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
18248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd[9] = fburst | task->ssp_task.task_attr |
18258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			(task->ssp_task.task_prio << 3);
1826b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
1827b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1828b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
18298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for_each_sg(task->scatter, sg, tei->n_elem, i) {
1830b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
1831b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
1832b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd++;
1833b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1834b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1835b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1836b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1837b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1838b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
1839b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
18408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct domain_device *dev = task->dev;
18418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_info *mvi = dev->port->ha->lldd_ha;
18428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
1843b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1844b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_task_exec_info tei;
18458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct sas_task *t = task;
18468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tag = 0xdeadbeef, rc, n_elem = 0;
18478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	unsigned long flags;
18488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 n = num, pass = 0;
1849b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
18508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	spin_lock_irqsave(&mvi->lock, flags);
1851b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
18528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	do {
18538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tei.port = &mvi->port[dev->port->id];
1854b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
18558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (!tei.port->port_attached) {
18568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			struct task_status_struct *ts = &t->task_status;
18578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			ts->stat = SAS_PHY_DOWN;
18588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			t->task_done(t);
18598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			rc = 0;
18608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			goto exec_exit;
18618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
18628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (!sas_protocol_ata(t->task_proto)) {
18638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (t->num_scatter) {
18648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				n_elem = pci_map_sg(mvi->pdev, t->scatter,
18658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei						    t->num_scatter,
18668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei						    t->data_dir);
18678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				if (!n_elem) {
18688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					rc = -ENOMEM;
18698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					goto err_out;
18708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				}
18718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			}
18728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		} else {
18738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			n_elem = t->num_scatter;
18748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
1875b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
18768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		rc = mvs_tag_alloc(mvi, &tag);
18778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (rc)
18788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			goto err_out;
1879b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
18808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvi->slot_info[tag].task = t;
18818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvi->slot_info[tag].n_elem = n_elem;
18828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		memset(mvi->slot_info[tag].buf, 0, MVS_SLOT_BUF_SZ);
18838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tei.task = t;
18848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tei.hdr = &mvi->slot[tag];
18858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tei.tag = tag;
18868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tei.n_elem = n_elem;
18878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
18888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		switch (t->task_proto) {
18898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		case SAS_PROTOCOL_SMP:
18908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			rc = mvs_task_prep_smp(mvi, &tei);
18918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			break;
18928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		case SAS_PROTOCOL_SSP:
18938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			rc = mvs_task_prep_ssp(mvi, &tei);
18948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			break;
18958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		case SAS_PROTOCOL_SATA:
18968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		case SAS_PROTOCOL_STP:
18978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
18988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			rc = mvs_task_prep_ata(mvi, &tei);
18998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			break;
19008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		default:
19018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			dev_printk(KERN_ERR, &pdev->dev,
19028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				"unknown sas_task proto: 0x%x\n",
19038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				t->task_proto);
19048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			rc = -EINVAL;
19058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			break;
19068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
1907b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (rc)
19098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			goto err_out_tag;
1910b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		/* TODO: select normal or high priority */
1912b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		spin_lock(&t->task_state_lock);
19148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		t->task_state_flags |= SAS_TASK_AT_INITIATOR;
19158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		spin_unlock(&t->task_state_lock);
1916b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (n == 1) {
19188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			spin_unlock_irqrestore(&mvi->lock, flags);
19198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mw32(TX_PROD_IDX, mvi->tx_prod);
19208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
19218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_hba_memory_dump(mvi, tag, t->task_proto);
1922b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		++pass;
19248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
1925b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (n == 1)
19278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			break;
19288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
19298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		t = list_entry(t->list.next, struct sas_task, list);
19308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	} while (--n);
1931b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1932b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1933b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1934b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_tag:
19358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_tag_free(mvi, tag);
1936b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
19378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc);
19388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (!sas_protocol_ata(t->task_proto))
19398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (n_elem)
19408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
19418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				     t->data_dir);
19428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weiexec_exit:
19438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (pass)
19448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
1945b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_unlock_irqrestore(&mvi->lock, flags);
1946b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
1947b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1948b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic int mvs_task_abort(struct sas_task *task)
19508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
19518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	int rc = 1;
19528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	unsigned long flags;
19538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
19548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
19558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
19568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	spin_lock_irqsave(&task->task_state_lock, flags);
19578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
19588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		rc = TMF_RESP_FUNC_COMPLETE;
19598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		goto out_done;
19608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
19618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	spin_unlock_irqrestore(&task->task_state_lock, flags);
19628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
19638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*FIXME*/
19648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	rc = TMF_RESP_FUNC_COMPLETE;
19658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
19668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	switch (task->task_proto) {
19678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_SMP:
19688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! ");
19698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		break;
19708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_SSP:
19718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! ");
19728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		break;
19738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_SATA:
19748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_STP:
19758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{
19768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! "
19778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			"Dump D2H FIS: \n");
19788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_hexdump(sizeof(struct host_to_dev_fis),
19798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(void *)&task->ata_task.fis, 0);
19808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
19818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_hexdump(16, task->ata_task.atapi_packet, 0);
19828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		break;
19838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
19848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	default:
19858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		break;
19868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
19878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weiout_done:
19888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return rc;
19898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
19908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1991b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_free(struct mvs_info *mvi)
1992b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1993b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int i;
1994b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1995b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi)
1996b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return;
1997b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1998b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < MVS_SLOTS; i++) {
1999b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		struct mvs_slot_info *slot = &mvi->slot_info[i];
2000b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2001b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (slot->buf)
2002b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ,
2003b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik					  slot->buf, slot->buf_dma);
2004b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2005b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2006b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->tx)
2007b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dma_free_coherent(&mvi->pdev->dev,
20088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				  sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
2009b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  mvi->tx, mvi->tx_dma);
2010b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->rx_fis)
2011b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
2012b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  mvi->rx_fis, mvi->rx_fis_dma);
2013b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->rx)
2014b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dma_free_coherent(&mvi->pdev->dev,
2015b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  sizeof(*mvi->rx) * MVS_RX_RING_SZ,
2016b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  mvi->rx, mvi->rx_dma);
2017b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->slot)
2018b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dma_free_coherent(&mvi->pdev->dev,
20198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				  sizeof(*mvi->slot) * MVS_SLOTS,
2020b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				  mvi->slot, mvi->slot_dma);
20218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#ifdef MVS_ENABLE_PERI
2022b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->peri_regs)
2023b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		iounmap(mvi->peri_regs);
20248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
2025b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->regs)
2026b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		iounmap(mvi->regs);
2027b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->shost)
2028b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		scsi_host_put(mvi->shost);
2029b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	kfree(mvi->sas.sas_port);
2030b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	kfree(mvi->sas.sas_phy);
2031b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	kfree(mvi);
2032b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2033b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2034b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* FIXME: locking? */
2035b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
2036b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			   void *funcdata)
2037b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2038b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi = sas_phy->ha->lldd_ha;
2039b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc = 0, phy_id = sas_phy->id;
2040b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp;
2041b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
20428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = mvs_read_phy_ctl(mvi, phy_id);
2043b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2044b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	switch (func) {
20458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case PHY_FUNC_SET_LINK_RATE:{
20468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			struct sas_phy_linkrates *rates = funcdata;
20478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			u32 lrmin = 0, lrmax = 0;
2048b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
20498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			lrmin = (rates->minimum_linkrate << 8);
20508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			lrmax = (rates->maximum_linkrate << 12);
2051b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
20528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (lrmin) {
20538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				tmp &= ~(0xf << 8);
20548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				tmp |= lrmin;
20558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			}
20568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (lrmax) {
20578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				tmp &= ~(0xf << 12);
20588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				tmp |= lrmax;
20598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			}
20608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_write_phy_ctl(mvi, phy_id, tmp);
20618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			break;
2062b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
2063b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2064b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case PHY_FUNC_HARD_RESET:
2065b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (tmp & PHY_RST_HARD)
2066b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			break;
20678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD);
2068b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
2069b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2070b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case PHY_FUNC_LINK_RESET:
20718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST);
2072b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		break;
2073b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2074b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case PHY_FUNC_DISABLE:
2075b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	case PHY_FUNC_RELEASE_SPINUP_HOLD:
2076b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	default:
2077b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -EOPNOTSUPP;
2078b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2079b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2080b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
2081b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2082b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2083b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
2084b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2085b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_phy *phy = &mvi->phy[phy_id];
2086b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_phy *sas_phy = &phy->sas_phy;
2087b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2088b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
2089b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->class = SAS;
2090b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->iproto = SAS_PROTOCOL_ALL;
2091b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->tproto = 0;
2092b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->type = PHY_TYPE_PHYSICAL;
2093b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->role = PHY_ROLE_INITIATOR;
2094b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->oob_mode = OOB_NOT_CONNECTED;
2095b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
2096b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2097b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->id = phy_id;
2098b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->sas_addr = &mvi->sas_addr[0];
2099b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->frame_rcvd = &phy->frame_rcvd[0];
2100b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->ha = &mvi->sas;
2101b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_phy->lldd_phy = phy;
2102b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2103b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
21048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
21058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					    const struct pci_device_id *ent)
2106b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2107b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi;
21088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	unsigned long res_start, res_len, res_flag;
2109b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_phy **arr_phy;
2110b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port **arr_port;
2111b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
2112b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int i;
2113b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2114b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
2115b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * alloc and init our per-HBA mvs_info struct
2116b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
2117b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2118b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi = kzalloc(sizeof(*mvi), GFP_KERNEL);
2119b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi)
2120b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return NULL;
2121b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2122b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	spin_lock_init(&mvi->lock);
2123b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->pdev = pdev;
2124b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->chip = chip;
2125b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2126b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (pdev->device == 0x6440 && pdev->revision == 0)
2127b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->flags |= MVF_PHY_PWR_FIX;
2128b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2129b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
2130b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * alloc and init SCSI, SAS glue
2131b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
2132b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2133b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *));
2134b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->shost)
2135b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2136b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2137b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
2138b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
2139b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!arr_phy || !arr_port)
2140b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2141b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2142b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < MVS_MAX_PHYS; i++) {
2143b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvs_phy_init(mvi, i);
2144b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		arr_phy[i] = &mvi->phy[i].sas_phy;
2145b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		arr_port[i] = &mvi->port[i].sas_port;
2146b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2147b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2148b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
2149b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->shost->transportt = mvs_stt;
21508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->shost->max_id = 21;
2151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->shost->max_lun = ~0;
21528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->shost->max_channel = 0;
21538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->shost->max_cmd_len = 16;
2154b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2155b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.sas_ha_name = DRV_NAME;
2156b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.dev = &pdev->dev;
2157b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.lldd_module = THIS_MODULE;
2158b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.sas_addr = &mvi->sas_addr[0];
2159b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.sas_phy = arr_phy;
2160b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.sas_port = arr_port;
2161b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.num_phys = chip->n_phy;
21628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->sas.lldd_max_execute_num = MVS_CHIP_SLOT_SZ - 1;
21638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
21648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->can_queue = (MVS_CHIP_SLOT_SZ >> 1) - 1;
2165b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.lldd_ha = mvi;
2166b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->sas.core.shost = mvi->shost;
2167b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
21688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_tag_init(mvi);
2169b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2170b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
2171b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * ioremap main and peripheral registers
2172b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
2173b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
21748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#ifdef MVS_ENABLE_PERI
2175b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	res_start = pci_resource_start(pdev, 2);
2176b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	res_len = pci_resource_len(pdev, 2);
2177b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!res_start || !res_len)
2178b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2179b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2180b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->peri_regs = ioremap_nocache(res_start, res_len);
21818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (!mvi->peri_regs)
2182b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
21838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
2184b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2185b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	res_start = pci_resource_start(pdev, 4);
2186b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	res_len = pci_resource_len(pdev, 4);
2187b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!res_start || !res_len)
2188b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2189b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
21908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	res_flag = pci_resource_flags(pdev, 4);
21918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (res_flag & IORESOURCE_CACHEABLE)
21928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvi->regs = ioremap(res_start, res_len);
21938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
21948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvi->regs = ioremap_nocache(res_start, res_len);
21958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
2196b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->regs)
2197b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2199b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
2200b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * alloc and init our DMA areas
2201b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
2202b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2203b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->tx = dma_alloc_coherent(&pdev->dev,
22048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				     sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
2205b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				     &mvi->tx_dma, GFP_KERNEL);
2206b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->tx)
2207b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
22088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
2209b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2210b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
22118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					 &mvi->rx_fis_dma, GFP_KERNEL);
2212b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->rx_fis)
2213b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2214b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
2215b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2216b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->rx = dma_alloc_coherent(&pdev->dev,
2217b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				     sizeof(*mvi->rx) * MVS_RX_RING_SZ,
2218b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				     &mvi->rx_dma, GFP_KERNEL);
2219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->rx)
2220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(mvi->rx, 0, sizeof(*mvi->rx) * MVS_RX_RING_SZ);
2222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2223b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->rx[0] = cpu_to_le32(0xfff);
2224b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->rx_cons = 0xfff;
2225b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2226b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi->slot = dma_alloc_coherent(&pdev->dev,
2227b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				       sizeof(*mvi->slot) * MVS_SLOTS,
2228b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik				       &mvi->slot_dma, GFP_KERNEL);
2229b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi->slot)
2230b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS);
2232b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2233b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < MVS_SLOTS; i++) {
2234b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		struct mvs_slot_info *slot = &mvi->slot_info[i];
2235b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2236b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
22378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					       &slot->buf_dma, GFP_KERNEL);
2238b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (!slot->buf)
2239b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			goto err_out;
2240b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
2241b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2242b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2243b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* finally, read NVRAM to get our SAS address */
2244b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
2245b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2246b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return mvi;
2247b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2248b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
2249b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_free(mvi);
2250b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return NULL;
2251b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2252b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2253b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic u32 mvs_cr32(void __iomem *regs, u32 addr)
2254b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2255b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_ADDR, addr);
2256b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return mr32(CMD_DATA);
2257b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2258b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2259b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
2260b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2261b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_ADDR, addr);
2262b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_DATA, val);
2263b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
22658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
2266b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2267b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
22688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4):
22698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mr32(P4_SER_CTLSTAT + (port - 4) * 4);
2270b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
22728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
2273b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2274b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
22758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (port < 4)
22768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mw32(P0_SER_CTLSTAT + port * 4, val);
22778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
22788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mw32(P4_SER_CTLSTAT + (port - 4) * 4, val);
22798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
22808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
22818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port)
22828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
22838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs + off;
22848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs2 = mvi->regs + off2;
22858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return (port < 4)?readl(regs + port * 8):
22868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		readl(regs2 + (port - 4) * 8);
22878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
22888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
22898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
22908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				u32 port, u32 val)
22918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
22928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs + off;
22938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs2 = mvi->regs + off2;
22948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (port < 4)
22958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		writel(val, regs + port * 8);
22968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
22978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		writel(val, regs2 + (port - 4) * 8);
22988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
22998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
23018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return mvs_read_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port);
23038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
23048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val)
23068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port, val);
23088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
23098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr)
23118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port(mvi, MVS_P0_CFG_ADDR, MVS_P4_CFG_ADDR, port, addr);
23138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
23148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
23168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return mvs_read_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port);
23188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
23198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val)
23218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port, val);
23238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
23248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr)
23268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port(mvi, MVS_P0_VSR_ADDR, MVS_P4_VSR_ADDR, port, addr);
23288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
23298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
23318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return mvs_read_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port);
23338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
23348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
23368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val);
23388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
23398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
23418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port);
23438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
2344b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
23458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
23468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
23478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port, val);
2348b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2349b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2350b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devinit mvs_phy_hacks(struct mvs_info *mvi)
2351b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2352b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
2353b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp;
2354b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2355b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* workaround for SATA R-ERR, to ignore phy glitch */
2356b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mvs_cr32(regs, CMD_PHY_TIMER);
2357b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~(1 << 9);
2358b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= (1 << 10);
2359b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_PHY_TIMER, tmp);
2360b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2361b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* enable retry 127 times */
2362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
2363b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* extend open frame timeout to max */
2365b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mvs_cr32(regs, CMD_SAS_CTL0);
2366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~0xffff;
2367b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= 0x3fff;
2368b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_SAS_CTL0, tmp);
2369b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2370b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* workaround for WDTIMEOUT , set to 550 ms */
2371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_WD_TIMER, 0xffffff);
2372b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2373b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* not to halt for different port op during wideport link change */
2374b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
2375b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2376b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* workaround for Seagate disk not-found OOB sequence, recv
2377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * COMINIT before sending out COMWAKE */
2378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
2379b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= 0x0000ffff;
2380b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= 0x00fa0000;
2381b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
2382b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mvs_cr32(regs, CMD_PHY_TIMER);
2384b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= 0x1fffffff;
2385b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= (2U << 29);	/* 8 ms retry */
2386b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_cw32(regs, CMD_PHY_TIMER, tmp);
23878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* TEST - for phy decoding error, adjust voltage levels */
23898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(P0_VSR_ADDR + 0, 0x8);
23908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(P0_VSR_DATA + 0, 0x2F0);
23918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(P0_VSR_ADDR + 8, 0x8);
23938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(P0_VSR_DATA + 8, 0x2F0);
23948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(P0_VSR_ADDR + 16, 0x8);
23968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(P0_VSR_DATA + 16, 0x2F0);
23978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
23988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(P0_VSR_ADDR + 24, 0x8);
23998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(P0_VSR_DATA + 24, 0x2F0);
24008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
24028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
24048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
24058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
24068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tmp;
24078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = mr32(PCS);
24098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (mvi->chip->n_phy <= 4)
24108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
24118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
24128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
24138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(PCS, tmp);
24148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
24158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_detect_porttype(struct mvs_info *mvi, int i)
24178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
24188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
24198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 reg;
24208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_phy *phy = &mvi->phy[i];
24218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* TODO check & save device type */
24238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	reg = mr32(GBL_PORT_TYPE);
24248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (reg & MODE_SAS_SATA & (1 << i))
24268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy->phy_type |= PORT_TYPE_SAS;
24278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
24288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy->phy_type |= PORT_TYPE_SATA;
24298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
24308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
24328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
24338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 *s = (u32 *) buf;
24348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (!s)
24368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return NULL;
24378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
24398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	s[3] = mvs_read_port_cfg_data(mvi, i);
24408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
24428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	s[2] = mvs_read_port_cfg_data(mvi, i);
24438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
24458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	s[1] = mvs_read_port_cfg_data(mvi, i);
24468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
24488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	s[0] = mvs_read_port_cfg_data(mvi, i);
24498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return (void *)s;
24518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
24528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_is_sig_fis_received(u32 irq_status)
24548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
24558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return irq_status & PHYEV_SIG_FIS;
24568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
24578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_update_wideport(struct mvs_info *mvi, int i)
24598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
24608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_phy *phy = &mvi->phy[i];
24618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port = phy->port;
24628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	int j, no;
24638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy)
24658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (no & 1) {
24668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
24678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_write_port_cfg_data(mvi, no,
24688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei						port->wide_port_phymap);
24698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		} else {
24708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
24718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_write_port_cfg_data(mvi, no, 0);
24728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
24738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
24748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
24768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
24778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tmp;
24788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_phy *phy = &mvi->phy[i];
24798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port;
24808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = mvs_read_phy_ctl(mvi, i);
24828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
24848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (!phy->port)
24858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			phy->phy_attached = 1;
24868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return tmp;
24878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
24888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
24898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	port = phy->port;
24908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (port) {
24918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (phy->phy_type & PORT_TYPE_SAS) {
24928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			port->wide_port_phymap &= ~(1U << i);
24938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (!port->wide_port_phymap)
24948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				port->port_attached = 0;
24958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_update_wideport(mvi, i);
24968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		} else if (phy->phy_type & PORT_TYPE_SATA)
24978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			port->port_attached = 0;
24988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_free_reg_set(mvi, phy->port);
24998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy->port = NULL;
25008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy->phy_attached = 0;
25018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
25028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
25038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	return 0;
25048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
25058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_update_phyinfo(struct mvs_info *mvi, int i,
25078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					int get_st)
25088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
25098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_phy *phy = &mvi->phy[i];
25108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
25118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tmp, j;
25128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64 tmp64;
25138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
25158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	phy->dev_info = mvs_read_port_cfg_data(mvi, i);
25168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
25188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32;
25198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
25218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
25228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (get_st) {
25248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy->irq_status = mvs_read_port_irq_stat(mvi, i);
25258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy->phy_status = mvs_is_phy_ready(mvi, i);
25268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
25278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (phy->phy_status) {
25298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		u32 phy_st;
25308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
25318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
25338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy_st = mvs_read_port_cfg_data(mvi, i);
25348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		sas_phy->linkrate =
25368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			(phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
25378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
25388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		/* Updated attached_sas_addr */
25408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
25418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy->att_dev_sas_addr =
25428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(u64) mvs_read_port_cfg_data(mvi, i) << 32;
25438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
25458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
25468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		dev_printk(KERN_DEBUG, &pdev->dev,
25488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			"phy[%d] Get Attached Address 0x%llX ,"
25498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			" SAS Address 0x%llX\n",
25508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			i, phy->att_dev_sas_addr, phy->dev_sas_addr);
25518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		dev_printk(KERN_DEBUG, &pdev->dev,
25528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			"Rate = %x , type = %d\n",
25538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			sas_phy->linkrate, phy->phy_type);
25548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if 1
25568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		/*
25578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		* If the device is capable of supporting a wide port
25588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		* on its phys, it may configure the phys as a wide port.
25598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		*/
25608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (phy->phy_type & PORT_TYPE_SAS)
25618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			for (j = 0; j < mvi->chip->n_phy && j != i; ++j) {
25628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				if ((mvi->phy[j].phy_attached) &&
25638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(mvi->phy[j].phy_type & PORT_TYPE_SAS))
25648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					if (phy->att_dev_sas_addr ==
25658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					mvi->phy[j].att_dev_sas_addr - 1) {
25668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei						phy->att_dev_sas_addr =
25678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei						mvi->phy[j].att_dev_sas_addr;
25688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei						break;
25698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					}
25708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			}
25718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
25738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
25758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
25768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (phy->phy_type & PORT_TYPE_SAS) {
25788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
25798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
25808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			phy->identify.device_type =
25818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			    phy->att_dev_info & PORT_DEV_TYPE_MASK;
25828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
25838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (phy->identify.device_type == SAS_END_DEV)
25848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				phy->identify.target_port_protocols =
25858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei							SAS_PROTOCOL_SSP;
25868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			else if (phy->identify.device_type != NO_DEVICE)
25878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				phy->identify.target_port_protocols =
25888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei							SAS_PROTOCOL_SMP;
25898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (phy_st & PHY_OOB_DTCTD)
25908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				sas_phy->oob_mode = SAS_OOB_MODE;
25918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			phy->frame_rcvd_size =
25928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			    sizeof(struct sas_identify_frame);
25938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		} else if (phy->phy_type & PORT_TYPE_SATA) {
25948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
25958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (mvs_is_sig_fis_received(phy->irq_status)) {
25968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				if (phy_st & PHY_OOB_DTCTD)
25978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					sas_phy->oob_mode = SATA_OOB_MODE;
25988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				phy->frame_rcvd_size =
25998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				    sizeof(struct dev_to_host_fis);
26008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				mvs_get_d2h_reg(mvi, i,
26018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei						(void *)sas_phy->frame_rcvd);
26028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			} else {
26038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				dev_printk(KERN_DEBUG, &pdev->dev,
26048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					"No sig fis\n");
26058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			}
26068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
26078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		/* workaround for HW phy decoding error on 1.5g disk drive */
26088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
26098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = mvs_read_port_vsr_data(mvi, i);
26108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
26118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		     PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
26128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			SAS_LINK_RATE_1_5_GBPS)
26138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tmp &= ~PHY_MODE6_DTL_SPEED;
26148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		else
26158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tmp |= PHY_MODE6_DTL_SPEED;
26168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_vsr_data(mvi, i, tmp);
26178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
26188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
26198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (get_st)
26208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_irq_stat(mvi, i, phy->irq_status);
26218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
26228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
26238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_port_formed(struct asd_sas_phy *sas_phy)
26248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
26258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct sas_ha_struct *sas_ha = sas_phy->ha;
26268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_info *mvi = sas_ha->lldd_ha;
26278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct asd_sas_port *sas_port = sas_phy->port;
26288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_phy *phy = sas_phy->lldd_phy;
26298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port = &mvi->port[sas_port->id];
26308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	unsigned long flags;
26318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
26328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	spin_lock_irqsave(&mvi->lock, flags);
26338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	port->port_attached = 1;
26348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	phy->port = port;
26358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	port->taskfileset = MVS_ID_NOT_MAPPED;
26368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (phy->phy_type & PORT_TYPE_SAS) {
26378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		port->wide_port_phymap = sas_port->phy_mask;
26388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_update_wideport(mvi, sas_phy->id);
26398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
26408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	spin_unlock_irqrestore(&mvi->lock, flags);
2641b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2642b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2643b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int __devinit mvs_hw_init(struct mvs_info *mvi)
2644b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
2646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int i;
2647b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp, cctl;
2648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* make sure interrupts are masked immediately (paranoia) */
2650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(GBL_CTL, 0);
2651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mr32(GBL_CTL);
2652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
26538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* Reset Controller */
2654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!(tmp & HBA_RST)) {
2655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (mvi->flags & MVF_PHY_PWR_FIX) {
2656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
2657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp &= ~PCTL_PWR_ON;
2658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp |= PCTL_OFF;
2659b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
2660b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
2662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp &= ~PCTL_PWR_ON;
2663b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp |= PCTL_OFF;
2664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
2665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
2666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* global reset, incl. COMRESET/H_RESET_N (self-clearing) */
2668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mw32_f(GBL_CTL, HBA_RST);
2669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* wait for reset to finish; timeout is just a guess */
2672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	i = 1000;
2673b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	while (i-- > 0) {
2674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msleep(10);
2675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2676b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (!(mr32(GBL_CTL) & HBA_RST))
2677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			break;
2678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mr32(GBL_CTL) & HBA_RST) {
2680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dev_printk(KERN_ERR, &mvi->pdev->dev, "HBA reset failed\n");
2681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -EBUSY;
2682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
26848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* Init Chip */
2685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* make sure RST is set; HBA_RST /should/ have done that for us */
2686b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	cctl = mr32(CTL);
2687b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (cctl & CCTL_RST)
2688b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		cctl &= ~CCTL_RST;
2689b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	else
2690b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mw32_f(CTL, cctl | CCTL_RST);
2691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
26928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* write to device control _AND_ device status register? - A.C. */
26938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
26948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp &= ~PRD_REQ_MASK;
26958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp |= PRD_REQ_SIZE;
26968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
26978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
2698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
2699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= PCTL_PWR_ON;
2700b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~PCTL_OFF;
2701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
2702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2703b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
2704b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= PCTL_PWR_ON;
2705b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~PCTL_OFF;
2706b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
2707b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2708b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32_f(CTL, cctl);
2709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
27108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* reset control */
27118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(PCS, 0);		/*MVS_PCS */
27128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
2713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_phy_hacks(mvi);
2714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2715b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_LIST_LO, mvi->slot_dma);
2716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
2717b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_FIS_LO, mvi->rx_fis_dma);
2719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
2720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
27218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(TX_CFG, MVS_CHIP_SLOT_SZ);
2722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(TX_LO, mvi->tx_dma);
2723b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(TX_HI, (mvi->tx_dma >> 16) >> 16);
2724b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2725b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_CFG, MVS_RX_RING_SZ);
2726b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_LO, mvi->rx_dma);
2727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_HI, (mvi->rx_dma >> 16) >> 16);
2728b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
27298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* enable auto port detection */
27308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
27318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	msleep(100);
2732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* init and reset phys */
2733b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < mvi->chip->n_phy; i++) {
2734b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* FIXME: is this the correct dword order? */
27358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		u32 lo = *((u32 *)&mvi->sas_addr[0]);
27368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		u32 hi = *((u32 *)&mvi->sas_addr[4]);
27378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
27388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_detect_porttype(mvi, i);
2739b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2740b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* set phy local SAS address */
27418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
27428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_data(mvi, i, lo);
27438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
27448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_data(mvi, i, hi);
2745b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2746b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* reset phy */
27478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = mvs_read_phy_ctl(mvi, i);
2748b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp |= PHY_RST;
27498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_phy_ctl(mvi, i, tmp);
2750b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2751b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2752b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	msleep(100);
2753b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2754b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < mvi->chip->n_phy; i++) {
27558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		/* clear phy int status */
27568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = mvs_read_port_irq_stat(mvi, i);
27578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp &= ~PHYEV_SIG_FIS;
27588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_irq_stat(mvi, i, tmp);
27598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
2760b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* set phy int mask */
27618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS |
27628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			PHYEV_ID_DONE | PHYEV_DEC_ERR;
27638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_irq_mask(mvi, i, tmp);
2764b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
27658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		msleep(100);
27668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_update_phyinfo(mvi, i, 1);
27678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_enable_xmt(mvi, i);
2768b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2769b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2770b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: update wide port bitmaps */
2771b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
27728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* little endian for open address and command table, etc. */
27738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* A.C.
27748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * it seems that ( from the spec ) turning on big-endian won't
27758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * do us any good on big-endian machines, need further confirmation
27768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 */
27778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl = mr32(CTL);
27788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl |= CCTL_ENDIAN_CMD;
27798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl |= CCTL_ENDIAN_DATA;
27808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl &= ~CCTL_ENDIAN_OPEN;
27818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl |= CCTL_ENDIAN_RSP;
27828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32_f(CTL, cctl);
27838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
27848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* reset CMD queue */
27858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = mr32(PCS);
27868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp |= PCS_CMD_RST;
27878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(PCS, tmp);
27888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* interrupt coalescing may cause missing HW interrput in some case,
27898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * and the max count is 0x1ff, while our max slot is 0x200,
27908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * it will make count 0.
27918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 */
27928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = 0;
27938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(INT_COAL, tmp);
27948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
27958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = 0x100;
27968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(INT_COAL_TMOUT, tmp);
27978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
2798b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* ladies and gentlemen, start your engines */
27998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(TX_CFG, 0);
28008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
2801b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
28028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* enable CMD/CMPL_Q/RESP mode */
28038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN);
2804b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2805b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* re-enable interrupts globally */
28068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hba_interrupt_enable(mvi);
28078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
28088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* enable completion queue interrupt */
28098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM);
28108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(INT_MASK, tmp);
2811b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2812b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
2813b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2814b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2815b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devinit mvs_print_info(struct mvs_info *mvi)
2816b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2817b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct pci_dev *pdev = mvi->pdev;
2818b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	static int printed_version;
2819b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2820b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!printed_version++)
2821b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
2822b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2823b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dev_printk(KERN_INFO, &pdev->dev, "%u phys, addr %llx\n",
2824b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		   mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr));
2825b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2826b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2827b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int __devinit mvs_pci_init(struct pci_dev *pdev,
28288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				  const struct pci_device_id *ent)
2829b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2830b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc;
2831b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi;
2832b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	irq_handler_t irq_handler = mvs_interrupt;
2833b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2834b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = pci_enable_device(pdev);
2835b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
2836b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return rc;
2837b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2838b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_set_master(pdev);
2839b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2840b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = pci_request_regions(pdev, DRV_NAME);
2841b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
2842b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_disable;
2843b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2844b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = pci_go_64(pdev);
2845b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
2846b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_regions;
2847b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2848b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvi = mvs_alloc(pdev, ent);
2849b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvi) {
2850b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		rc = -ENOMEM;
2851b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_regions;
2852b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
2853b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2854b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = mvs_hw_init(mvi);
2855b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
2856b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_mvi;
2857b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
28588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#ifndef MVS_DISABLE_MSI
2859b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!pci_enable_msi(pdev)) {
28608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		u32 tmp;
28618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		void __iomem *regs = mvi->regs;
2862b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mvi->flags |= MVF_MSI;
2863b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		irq_handler = mvs_msi_interrupt;
28648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = mr32(PCS);
28658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mw32(PCS, tmp | PCS_SELF_CLEAR);
2866b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
28678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
2868b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2869b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi);
2870b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
2871b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_msi;
2872b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2873b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = scsi_add_host(mvi->shost, &pdev->dev);
2874b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
2875b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_irq;
2876b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2877b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = sas_register_ha(&mvi->sas);
2878b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
2879b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out_shost;
2880b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2881b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_set_drvdata(pdev, mvi);
2882b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2883b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_print_info(mvi);
2884b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2885b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	scsi_scan_host(mvi->shost);
28868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
2887b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
2888b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2889b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_shost:
2890b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	scsi_remove_host(mvi->shost);
2891b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_irq:
2892b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	free_irq(pdev->irq, mvi);
2893b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_msi:
2894b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mvi->flags |= MVF_MSI)
2895b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		pci_disable_msi(pdev);
2896b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_mvi:
2897b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_free(mvi);
2898b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_regions:
2899b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_release_regions(pdev);
2900b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out_disable:
2901b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_disable_device(pdev);
2902b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
2903b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2904b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2905b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __devexit mvs_pci_remove(struct pci_dev *pdev)
2906b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2907b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_info *mvi = pci_get_drvdata(pdev);
2908b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2909b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_set_drvdata(pdev, NULL);
2910b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
29118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (mvi) {
29128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		sas_unregister_ha(&mvi->sas);
29138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_hba_interrupt_disable(mvi);
29148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		sas_remove_host(mvi->shost);
29158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		scsi_remove_host(mvi->shost);
29168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
29178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		free_irq(pdev->irq, mvi);
29188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (mvi->flags & MVF_MSI)
29198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			pci_disable_msi(pdev);
29208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_free(mvi);
29218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		pci_release_regions(pdev);
29228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
2923b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_disable_device(pdev);
2924b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2925b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2926b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct sas_domain_function_template mvs_transport_ops = {
2927b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.lldd_execute_task	= mvs_task_exec,
2928b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.lldd_control_phy	= mvs_phy_control,
29298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	.lldd_abort_task	= mvs_task_abort,
29308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	.lldd_port_formed	= mvs_port_formed
2931b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
2932b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2933b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct pci_device_id __devinitdata mvs_pci_table[] = {
2934b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
2935b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
2936b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
2937b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ PCI_VDEVICE(MARVELL, 0x6480), chip_6480 },
2938b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2939b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	{ }	/* terminate list */
2940b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
2941b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2942b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic struct pci_driver mvs_pci_driver = {
2943b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.name		= DRV_NAME,
2944b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.id_table	= mvs_pci_table,
2945b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.probe		= mvs_pci_init,
2946b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	.remove		= __devexit_p(mvs_pci_remove),
2947b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
2948b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2949b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int __init mvs_init(void)
2950b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2951b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int rc;
2952b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2953b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);
2954b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!mvs_stt)
2955b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -ENOMEM;
2956b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2957b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	rc = pci_register_driver(&mvs_pci_driver);
2958b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (rc)
2959b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		goto err_out;
2960b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2961b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
2962b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2963b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
2964b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_release_transport(mvs_stt);
2965b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
2966b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2967b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2968b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic void __exit mvs_exit(void)
2969b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
2970b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_unregister_driver(&mvs_pci_driver);
2971b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	sas_release_transport(mvs_stt);
2972b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2973b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2974b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikmodule_init(mvs_init);
2975b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikmodule_exit(mvs_exit);
2976b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2977b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
2978b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
2979b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_VERSION(DRV_VERSION);
2980b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_LICENSE("GPL");
2981b5762948263dd5e9725a380e7a9626f99e40ae9dJeff GarzikMODULE_DEVICE_TABLE(pci, mvs_pci_table);
2982