mv_sas.c revision dd4969a892ea522ecf9d7d826ba1531ce044d46f
1b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/*
2dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mv_sas.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
31dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#include "mv_sas.h"
32dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#include "mv_64xx.h"
33dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#include "mv_chips.h"
348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei/* offset for D2H FIS in the Received FIS List Structure */
368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define SATA_RECEIVED_D2H_FIS(reg_set)	\
378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define SATA_RECEIVED_PIO_FIS(reg_set)	\
398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#define UNASSOC_D2H_FIS(id)		\
418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	((void *) mvi->rx_fis + 0x100 * id)
428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
43dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstruct mvs_task_exec_info {
44dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct sas_task *task;
45dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_cmd_hdr *hdr;
46dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port;
47dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 tag;
48dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int n_elem;
49b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik};
50b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
51dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_release_task(struct mvs_info *mvi, int phy_no);
52dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i);
53dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_update_phyinfo(struct mvs_info *mvi, int i,
54dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					int get_st);
55dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
56dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task,
57dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				u32 slot_idx);
58b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
59dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
60dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
61dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (task->lldd_task) {
62dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct mvs_slot_info *slot;
63dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot = (struct mvs_slot_info *) task->lldd_task;
64dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		*tag = slot - mvi->slot_info;
65dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return 1;
66dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
67dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
68dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
70dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
71dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
72dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void *bitmap = (void *) &mvi->tags;
73dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	clear_bit(tag, bitmap);
74dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
76dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_tag_free(struct mvs_info *mvi, u32 tag)
77dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
78dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_clear(mvi, tag);
79dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
81dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
82dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
83dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void *bitmap = (void *) &mvi->tags;
84dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	set_bit(tag, bitmap);
85dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
87dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
88dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
89dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	unsigned int index, tag;
90dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void *bitmap = (void *) &mvi->tags;
91b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
92dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	index = find_first_zero_bit(bitmap, MVS_SLOTS);
93dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tag = index;
94dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (tag >= MVS_SLOTS)
95dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -SAS_QUEUE_FULL;
96dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_set(mvi, tag);
97dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	*tag_out = tag;
98dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
99dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
100b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
101dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_tag_init(struct mvs_info *mvi)
102dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
103dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int i;
104dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	for (i = 0; i < MVS_SLOTS; ++i)
105dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_tag_clear(mvi, i);
106dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
107b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
1098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 i;
1118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 run;
1128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 offset;
1138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	offset = 0;
1158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	while (size) {
1168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		printk("%08X : ", baseaddr + offset);
1178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (size >= 16)
1188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			run = 16;
1198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		else
1208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			run = size;
1218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		size -= run;
1228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		for (i = 0; i < 16; i++) {
1238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (i < run)
1248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				printk("%02X ", (u32)data[i]);
1258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			else
1268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				printk("   ");
1278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
1288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		printk(": ");
1298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		for (i = 0; i < run; i++)
1308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			printk("%c", isalnum(data[i]) ? data[i] : '.');
1318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		printk("\n");
1328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		data = &data[16];
1338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		offset += run;
1348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
1358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	printk("\n");
1368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
1378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
138ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei#if _MV_DUMP
1398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
1408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				   enum sas_protocol proto)
1418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 offset;
1438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
1448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot = &mvi->slot_info[tag];
1458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	offset = slot->cmd_size + MVS_OAF_SZ +
1478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_prd) * slot->n_elem;
1488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer[%d] :\n",
1498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tag);
1508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(32, (u8 *) slot->response,
1518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		    (u32) slot->buf_dma + offset);
1528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
153ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei#endif
1548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
1568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				enum sas_protocol proto)
1578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
159ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	u32 sz, w_ptr;
1608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64 addr;
1618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
1628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
1638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot = &mvi->slot_info[tag];
1648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*Delivery Queue */
1668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	sz = mr32(TX_CFG) & TX_RING_SZ_MASK;
167ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	w_ptr = slot->tx;
1688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO);
1698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev,
170ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei		"Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr);
1718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev,
1728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Delivery Queue Base Address=0x%llX (PA)"
1738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"(tx_dma=0x%llX), Entry=%04d\n",
1748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		addr, mvi->tx_dma, w_ptr);
1758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
1768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			(u32) mvi->tx_dma + sizeof(u32) * w_ptr);
1778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*Command List */
178ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	addr = mvi->slot_dma;
1798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev,
1808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Command List Base Address=0x%llX (PA)"
1818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"(slot_dma=0x%llX), Header=%03d\n",
182ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei		addr, slot->buf_dma, tag);
1838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "Command Header[%03d]:\n", tag);
1848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*mvs_cmd_hdr */
1858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
1868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		(u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
1878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*1.command table area */
1888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "+---->Command Table :\n");
1898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
1908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*2.open address frame area */
1918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "+---->Open Address Frame :\n");
1928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
1938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(u32) slot->buf_dma + slot->cmd_size);
1948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*3.status buffer */
1958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hba_sb_dump(mvi, tag, proto);
1968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*4.PRD table */
1978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev, "+---->PRD table :\n");
1988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(struct mvs_prd) * slot->n_elem,
1998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		(u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
2008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		(u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
2018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
2028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
2038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
2048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_cq_dump(struct mvs_info *mvi)
2058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
206ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei#if (_MV_DUMP > 2)
2078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64 addr;
2088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
2098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
2108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 entry = mvi->rx_cons + 1;
2118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
2128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
2138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*Completion Queue */
2148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
215ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	dev_printk(KERN_DEBUG, &pdev->dev, "Completion Task = 0x%p\n",
216ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei		   mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
2178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	dev_printk(KERN_DEBUG, &pdev->dev,
2188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Completion List Base Address=0x%llX (PA), "
2198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"CQ_Entry=%04d, CQ_WP=0x%08X\n",
2208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		addr, entry - 1, mvi->rx[0]);
2218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
2228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		    mvi->rx_dma + sizeof(u32) * entry);
2238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
2248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
2258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
226dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik/* FIXME: locking? */
227dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata)
2288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
229dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_info *mvi = sas_phy->ha->lldd_ha;
230dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int rc = 0, phy_id = sas_phy->id;
2318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tmp;
2328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
233dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tmp = mvs_read_phy_ctl(mvi, phy_id);
2348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
235dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	switch (func) {
236dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_SET_LINK_RATE:{
237dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			struct sas_phy_linkrates *rates = funcdata;
238dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			u32 lrmin = 0, lrmax = 0;
2398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
240dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			lrmin = (rates->minimum_linkrate << 8);
241dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			lrmax = (rates->maximum_linkrate << 12);
2428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
243dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (lrmin) {
244dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				tmp &= ~(0xf << 8);
245dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				tmp |= lrmin;
246dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
247dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (lrmax) {
248dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				tmp &= ~(0xf << 12);
249dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				tmp |= lrmax;
250dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
251dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_write_phy_ctl(mvi, phy_id, tmp);
252dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
253dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
2548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
255dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_HARD_RESET:
256dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (tmp & PHY_RST_HARD)
257dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
258dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD);
259dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
260b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
261dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_LINK_RESET:
262dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST);
263dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
265dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_DISABLE:
266dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_RELEASE_SPINUP_HOLD:
267dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	default:
268dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -EOPNOTSUPP;
269b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
270b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
272b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
273b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
274dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
275ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei{
276dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
277dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
278dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
279dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!phy->phy_attached)
280dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return;
281dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
282dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (sas_phy->phy) {
283dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct sas_phy *sphy = sas_phy->phy;
284dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
285dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->negotiated_linkrate = sas_phy->linkrate;
286dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->minimum_linkrate = phy->minimum_linkrate;
287dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
288dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->maximum_linkrate = phy->maximum_linkrate;
289dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
290ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	}
291ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei
292dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->phy_type & PORT_TYPE_SAS) {
293dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct sas_identify_frame *id;
294b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
295dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id = (struct sas_identify_frame *)phy->frame_rcvd;
296dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id->dev_type = phy->identify.device_type;
297dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id->initiator_bits = SAS_PROTOCOL_ALL;
298dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id->target_bits = phy->identify.target_port_protocols;
299dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	} else if (phy->phy_type & PORT_TYPE_SATA) {
300dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* TODO */
301dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
302dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
303dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
304dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				   PORTE_BYTES_DMAED);
305ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei}
306ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei
307dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_slave_configure(struct scsi_device *sdev)
308ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei{
309dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct domain_device *dev = sdev_to_domain_dev(sdev);
310dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int ret = sas_slave_configure(sdev);
311b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
312dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (ret)
313dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return ret;
314ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei
315dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (dev_is_sata(dev)) {
316dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* struct ata_port *ap = dev->sata_dev.ap; */
317dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* struct ata_device *adev = ap->link.device; */
318dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
319dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* clamp at no NCQ for the time being */
320dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* adev->flags |= ATA_DFLAG_NCQ_OFF; */
321dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
322dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
323ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	return 0;
324b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
325b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
326dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_scan_start(struct Scsi_Host *shost)
327b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
3288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	int i;
329dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
330dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
331dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	for (i = 0; i < mvi->chip->n_phy; ++i) {
332dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_bytes_dmaed(mvi, i);
333dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
334b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
335b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
336dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
338dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* give the phy enabling interrupt event time to come in (1s
339dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * is empirically about all it takes) */
340dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (time < HZ)
341dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return 0;
342dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* Wait for discovery to finish */
343dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	scsi_flush_work(shost);
344dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 1;
345b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
346b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
347dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_smp(struct mvs_info *mvi,
348dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     struct mvs_task_exec_info *tei)
349b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
350dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int elem, rc, i;
351dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct sas_task *task = tei->task;
352dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
353dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct scatterlist *sg_req, *sg_resp;
354dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 req_len, resp_len, tag = tei->tag;
355dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void *buf_tmp;
356dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u8 *buf_oaf;
357dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	dma_addr_t buf_tmp_dma;
358dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_prd *buf_prd;
359dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct scatterlist *sg;
360dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_slot_info *slot = &mvi->slot_info[tag];
361dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct asd_sas_port *sas_port = task->dev->port;
362dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
363dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP
364dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u8 *buf_cmd;
365dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void *from;
366dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
367dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/*
368dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * DMA-map SMP request, response buffers
369dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
370dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	sg_req = &task->smp_task.smp_req;
371dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE);
372dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!elem)
373dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -ENOMEM;
374dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	req_len = sg_dma_len(sg_req);
375b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
376dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	sg_resp = &task->smp_task.smp_resp;
377dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE);
378dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!elem) {
379dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -ENOMEM;
380dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out;
381dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
382dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	resp_len = sg_dma_len(sg_resp);
383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
384dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* must be in dwords */
385dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if ((req_len & 0x3) || (resp_len & 0x3)) {
386dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -EINVAL;
387dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out_2;
388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
390dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/*
391dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
392dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
393b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
394dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
395dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp = slot->buf;
396dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma = slot->buf_dma;
397b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
398dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP
399dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_cmd = buf_tmp;
400dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
401dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp += req_len;
402dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma += req_len;
403dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->cmd_size = req_len;
404dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#else
405dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
406dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
407b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
408dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
409dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_oaf = buf_tmp;
410dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
411b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
412dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp += MVS_OAF_SZ;
413dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
415dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* region 3: PRD table ********************************************* */
416dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_prd = buf_tmp;
417dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (tei->n_elem)
418dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
419dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	else
420dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		hdr->prd_tbl = 0;
421b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
422dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	i = sizeof(struct mvs_prd) * tei->n_elem;
423dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp += i;
424dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma += i;
425b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
426dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
427dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->response = buf_tmp;
428dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
429b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
430dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/*
431dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * Fill in TX ring and command slot header
432dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
433dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->tx = mvi->tx_prod;
434dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
435dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					TXQ_MODE_I | tag |
436dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					(sas_port->phy_mask << TXQ_PHY_SHIFT));
437b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
438dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->flags |= flags;
439dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
440dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->tags = cpu_to_le32(tag);
441dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->data_len = 0;
442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
443dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* generate open address frame hdr (first 12 bytes) */
444dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_oaf[0] = (1 << 7) | (0 << 4) | 0x01; /* initiator, SMP, ftype 1h */
445dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_oaf[1] = task->dev->linkrate & 0xf;
446dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	*(u16 *)(buf_oaf + 2) = 0xFFFF;		/* SAS SPEC */
447dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
448dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
449dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
450dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	for_each_sg(task->scatter, sg, tei->n_elem, i) {
451dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
452dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
453dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		buf_prd++;
454b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
455b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
456dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP
457dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* copy cmd table */
458dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
459dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	memcpy(buf_cmd, from + sg_req->offset, req_len);
460dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	kunmap_atomic(from, KM_IRQ0);
461dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
462b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
463b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
464dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_2:
465dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1,
466dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		     PCI_DMA_FROMDEVICE);
467b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
468dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1,
469dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		     PCI_DMA_TODEVICE);
470b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
4718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
4728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
473dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
4748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
475dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct ata_queued_cmd *qc = task->uldd_task;
4768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
477dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (qc) {
478dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
479dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			qc->tf.command == ATA_CMD_FPDMA_READ) {
480dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			*tag = qc->tag;
481dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			return 1;
482dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
4838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
4848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
485dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
4868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
4878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
488dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_ata(struct mvs_info *mvi,
489dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     struct mvs_task_exec_info *tei)
490b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
491b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
492b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct domain_device *dev = task->dev;
493b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
494b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port *sas_port = dev->port;
4958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot;
496b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct scatterlist *sg;
497b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_prd *buf_prd;
4988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port = tei->port;
4998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tag = tei->tag;
5008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
501b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
502b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf;
503b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
5048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 i, req_len, resp_len;
5058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	const u32 max_resp_len = SB_RFB_MAX;
5068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
5078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED)
5088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return -EBUSY;
509b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot = &mvi->slot_info[tag];
5118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->tx = mvi->tx_prod;
5128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
5138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
5148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(sas_port->phy_mask << TXQ_PHY_SHIFT) |
5158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei					(port->taskfileset << TXQ_SRS_SHIFT));
516b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
517b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ata_task.use_ncq)
518b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FPDMA;
5198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
5208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
5218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			flags |= MCH_ATAPI;
5228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
5238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: fill in port multiplier number */
525b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->flags = cpu_to_le32(flags);
5278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
5288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* FIXME: the low order order 5 bits for the TAG if enable NCQ */
5294e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei	if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr->tags))
5304e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei		task->ata_task.fis.sector_count |= hdr->tags << 3;
5314e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei	else
5328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->tags = cpu_to_le32(tag);
533b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = cpu_to_le32(task->total_xfer_len);
534b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
535b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
536b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
537b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
538b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
5408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd = buf_tmp = slot->buf;
541b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma = slot->buf_dma;
542b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
543b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
544b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
545b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_ATA_CMD_SZ;
546b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_ATA_CMD_SZ;
5478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
5488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->cmd_size = MVS_ATA_CMD_SZ;
5498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
550b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
552b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* used for STP.  unused for SATA? */
553b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
555b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
556b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
557b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
558b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 3: PRD table ********************************************* */
560b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
5618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tei->n_elem)
5628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
5638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
5648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = 0;
565b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
566b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	i = sizeof(struct mvs_prd) * tei->n_elem;
567b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
568b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
571b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: probably unused, for SATA.  kept here just in case
572b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * we get a STP/SATA error information record
573b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
574b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
575b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
576b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	req_len = sizeof(struct host_to_dev_fis);
578b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
5798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_err_info) - i;
580b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
581b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
5828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	resp_len = min(resp_len, max_resp_len);
583b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
584b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
586b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in command FIS and ATAPI CDB */
5878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
5888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
5898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		memcpy(buf_cmd + STP_ATAPI_CMD,
5908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			task->ata_task.atapi_packet, 16);
5918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
5928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* generate open address frame hdr (first 12 bytes) */
5938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_oaf[0] = (1 << 7) | (2 << 4) | 0x1;	/* initiator, STP, ftype 1h */
5948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_oaf[1] = task->dev->linkrate & 0xf;
5958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	*(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
5968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
597b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
598b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
5998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for_each_sg(task->scatter, sg, tei->n_elem, i) {
600b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
601b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
602b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd++;
603b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
604b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
605b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
608b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ssp(struct mvs_info *mvi,
609b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			     struct mvs_task_exec_info *tei)
610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
611b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
612b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
6138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port = tei->port;
614b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info *slot;
615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct scatterlist *sg;
616b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_prd *buf_prd;
617b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct ssp_frame_hdr *ssp_hdr;
618b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
619b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf, fburst = 0;
620b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
621b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 flags;
6228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 resp_len, req_len, i, tag = tei->tag;
6238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	const u32 max_resp_len = SB_RFB_MAX;
6244e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei	u8 phy_mask;
625b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
626b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot = &mvi->slot_info[tag];
627b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6284e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei	phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
6294e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei		task->dev->port->phy_mask;
6308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->tx = mvi->tx_prod;
6318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
6328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
6334e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei				(phy_mask << TXQ_PHY_SHIFT));
634b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
635b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	flags = MCH_RETRY;
636b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ssp_task.enable_first_burst) {
637b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FBURST;
638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		fburst = (1 << 7);
639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
640b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->flags = cpu_to_le32(flags |
6418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				 (tei->n_elem << MCH_PRD_LEN_SHIFT) |
6428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				 (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
643b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
644b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->tags = cpu_to_le32(tag);
645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = cpu_to_le32(task->total_xfer_len);
646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
647b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
6528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd = buf_tmp = slot->buf;
653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma = slot->buf_dma;
654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_SSP_CMD_SZ;
658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_SSP_CMD_SZ;
6598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
6608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->cmd_size = MVS_SSP_CMD_SZ;
6618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 3: PRD table ********************************************* */
671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
6728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tei->n_elem)
6738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
6748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
6758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = 0;
676b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	i = sizeof(struct mvs_prd) * tei->n_elem;
678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
6868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_err_info) - i;
6878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	resp_len = min(resp_len, max_resp_len);
6888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
6898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	req_len = sizeof(struct ssp_frame_hdr) + 28;
690b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
692b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
694b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* generate open address frame hdr (first 12 bytes) */
695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf[0] = (1 << 7) | (1 << 4) | 0x1;	/* initiator, SSP, ftype 1h */
696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf[1] = task->dev->linkrate & 0xf;
6978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	*(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
7008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* fill in SSP frame header (Command Table.SSP frame header) */
7018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	ssp_hdr->frame_type = SSP_COMMAND;
703b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr,
704b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	       HASHED_SAS_ADDR_SIZE);
705b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(ssp_hdr->hashed_src_addr,
706b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	       task->dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
707b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	ssp_hdr->tag = cpu_to_be16(tag);
708b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in command frame IU */
710b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_cmd += sizeof(*ssp_hdr);
711b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
7128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd[9] = fburst | task->ssp_task.task_attr |
7138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			(task->ssp_task.task_prio << 3);
714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
715b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
7178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	for_each_sg(task->scatter, sg, tei->n_elem, i) {
718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd->len = cpu_to_le32(sg_dma_len(sg));
720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		buf_prd++;
721b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
723b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
724b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
725b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
726dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
7288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct domain_device *dev = task->dev;
7298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_info *mvi = dev->port->ha->lldd_ha;
7308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct pci_dev *pdev = mvi->pdev;
731b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_task_exec_info tei;
7338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct sas_task *t = task;
7344e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei	struct mvs_slot_info *slot;
7358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tag = 0xdeadbeef, rc, n_elem = 0;
7368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	unsigned long flags;
7378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 n = num, pass = 0;
738b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
7398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	spin_lock_irqsave(&mvi->lock, flags);
7408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	do {
7414e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei		dev = t->dev;
7428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tei.port = &mvi->port[dev->port->id];
743b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
744dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (!tei.port->port_attached) {
745dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (sas_protocol_ata(t->task_proto)) {
746dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				rc = SAS_PHY_DOWN;
747dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				goto out_done;
748dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			} else {
749dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				struct task_status_struct *ts = &t->task_status;
750dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				ts->resp = SAS_TASK_UNDELIVERED;
751dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				ts->stat = SAS_PHY_DOWN;
752dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				t->task_done(t);
753dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				if (n > 1)
754dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					t = list_entry(t->list.next,
755dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							struct sas_task, list);
756dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				continue;
757dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
758dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
759dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
760dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (!sas_protocol_ata(t->task_proto)) {
761dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (t->num_scatter) {
762dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				n_elem = pci_map_sg(mvi->pdev, t->scatter,
763dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						    t->num_scatter,
764dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						    t->data_dir);
765dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				if (!n_elem) {
766dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					rc = -ENOMEM;
767dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					goto err_out;
768dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				}
769dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
770dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else {
771dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			n_elem = t->num_scatter;
772dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
773dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
774dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = mvs_tag_alloc(mvi, &tag);
775dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (rc)
776dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			goto err_out;
777dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
778dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot = &mvi->slot_info[tag];
779dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		t->lldd_task = NULL;
780dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot->n_elem = n_elem;
781dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
782dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tei.task = t;
783dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tei.hdr = &mvi->slot[tag];
784dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tei.tag = tag;
785dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tei.n_elem = n_elem;
786dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
787dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		switch (t->task_proto) {
788dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_SMP:
789dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			rc = mvs_task_prep_smp(mvi, &tei);
790dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
791dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_SSP:
792dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			rc = mvs_task_prep_ssp(mvi, &tei);
793dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
794dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_SATA:
795dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_STP:
796dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
797dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			rc = mvs_task_prep_ata(mvi, &tei);
798dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
799dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		default:
800dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			dev_printk(KERN_ERR, &pdev->dev,
801dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				"unknown sas_task proto: 0x%x\n",
802dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				t->task_proto);
803dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			rc = -EINVAL;
804dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
805dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
806dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
807dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (rc)
808dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			goto err_out_tag;
809dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
810dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot->task = t;
811dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot->port = tei.port;
812dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		t->lldd_task = (void *) slot;
813dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		list_add_tail(&slot->list, &slot->port->list);
814dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* TODO: select normal or high priority */
815dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
816dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		spin_lock(&t->task_state_lock);
817dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		t->task_state_flags |= SAS_TASK_AT_INITIATOR;
818dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		spin_unlock(&t->task_state_lock);
819dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
820dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_hba_memory_dump(mvi, tag, t->task_proto);
821dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
822dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		++pass;
823dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
824dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (n > 1)
825dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			t = list_entry(t->list.next, struct sas_task, list);
826dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	} while (--n);
827dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
828dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	rc = 0;
829dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	goto out_done;
830dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
831dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_tag:
832dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_free(mvi, tag);
833dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out:
834dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc);
835dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!sas_protocol_ata(t->task_proto))
836dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (n_elem)
837dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
838dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				     t->data_dir);
839dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikout_done:
840dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (pass)
841dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
842dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_unlock_irqrestore(&mvi->lock, flags);
843dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return rc;
844dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
845dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
846dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
847dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
848dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
849dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_clear(mvi, slot_idx);
850dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
851dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
852dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
853dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			  struct mvs_slot_info *slot, u32 slot_idx)
854dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
855dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!sas_protocol_ata(task->task_proto))
856dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (slot->n_elem)
857dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			pci_unmap_sg(mvi->pdev, task->scatter,
858dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				     slot->n_elem, task->data_dir);
859dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
860dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	switch (task->task_proto) {
861dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SMP:
862dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1,
863dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     PCI_DMA_FROMDEVICE);
864dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1,
865dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     PCI_DMA_TODEVICE);
866dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
867dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
868dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA:
869dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_STP:
870dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SSP:
871dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	default:
872dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* do nothing */
873dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
874dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
875dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	list_del(&slot->list);
876dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	task->lldd_task = NULL;
877dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->task = NULL;
878dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->port = NULL;
879dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
880dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
881dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_update_wideport(struct mvs_info *mvi, int i)
882dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
883dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
884dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port = phy->port;
885dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int j, no;
886dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
887dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy)
888dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (no & 1) {
889dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
890dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_write_port_cfg_data(mvi, no,
891dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						port->wide_port_phymap);
892dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else {
893dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
894dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_write_port_cfg_data(mvi, no, 0);
895dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
896dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
897dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
898dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
899dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
900dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 tmp;
901dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
902dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port = phy->port;;
903dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
904dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tmp = mvs_read_phy_ctl(mvi, i);
905dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
906dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
907dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (!port)
908dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->phy_attached = 1;
909dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return tmp;
910dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
911dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
912dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (port) {
913dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (phy->phy_type & PORT_TYPE_SAS) {
914dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			port->wide_port_phymap &= ~(1U << i);
915dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (!port->wide_port_phymap)
916dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				port->port_attached = 0;
917dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_update_wideport(mvi, i);
918dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else if (phy->phy_type & PORT_TYPE_SATA)
919dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			port->port_attached = 0;
920dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_free_reg_set(mvi, phy->port);
921dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->port = NULL;
922dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->phy_attached = 0;
923dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
924dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
925dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
926dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
927dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
928dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
929dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
930dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 *s = (u32 *) buf;
931dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
932dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!s)
933dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return NULL;
934dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
935dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
936dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	s[3] = mvs_read_port_cfg_data(mvi, i);
937dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
938dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
939dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	s[2] = mvs_read_port_cfg_data(mvi, i);
940dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
941dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
942dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	s[1] = mvs_read_port_cfg_data(mvi, i);
943dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
944dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
945dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	s[0] = mvs_read_port_cfg_data(mvi, i);
946dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
947dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return (void *)s;
948dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
949dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
950dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_sig_fis_received(u32 irq_status)
951dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
952dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return irq_status & PHYEV_SIG_FIS;
953dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
954dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
955dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_update_phyinfo(struct mvs_info *mvi, int i,
956dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					int get_st)
957dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
958dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
959dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct pci_dev *pdev = mvi->pdev;
960dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 tmp;
961dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u64 tmp64;
962dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
963dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
964dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	phy->dev_info = mvs_read_port_cfg_data(mvi, i);
9654e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei
966dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
967dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32;
968b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
969dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
970dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
971b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
972dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (get_st) {
973dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->irq_status = mvs_read_port_irq_stat(mvi, i);
974dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->phy_status = mvs_is_phy_ready(mvi, i);
975dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
9768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
977dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->phy_status) {
978dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		u32 phy_st;
979dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
980b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
981dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
982dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy_st = mvs_read_port_cfg_data(mvi, i);
983b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
984dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sas_phy->linkrate =
985dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			(phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
986dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
987dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->minimum_linkrate =
988dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			(phy->phy_status &
989dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8;
990dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->maximum_linkrate =
991dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			(phy->phy_status &
992dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12;
993b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
994dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (phy->phy_type & PORT_TYPE_SAS) {
995dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			/* Updated attached_sas_addr */
996dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
997dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->att_dev_sas_addr =
998dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				(u64) mvs_read_port_cfg_data(mvi, i) << 32;
999dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
1000dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
1001dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
1002dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
1003dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->identify.device_type =
1004dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			    phy->att_dev_info & PORT_DEV_TYPE_MASK;
1005b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1006dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (phy->identify.device_type == SAS_END_DEV)
1007dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				phy->identify.target_port_protocols =
1008dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							SAS_PROTOCOL_SSP;
1009dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			else if (phy->identify.device_type != NO_DEVICE)
1010dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				phy->identify.target_port_protocols =
1011dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							SAS_PROTOCOL_SMP;
1012dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (phy_st & PHY_OOB_DTCTD)
1013dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				sas_phy->oob_mode = SAS_OOB_MODE;
1014dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->frame_rcvd_size =
1015dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			    sizeof(struct sas_identify_frame);
1016dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else if (phy->phy_type & PORT_TYPE_SATA) {
1017dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
1018dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (mvs_is_sig_fis_received(phy->irq_status)) {
1019dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				phy->att_dev_sas_addr = i;	/* temp */
1020dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				if (phy_st & PHY_OOB_DTCTD)
1021dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					sas_phy->oob_mode = SATA_OOB_MODE;
1022dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				phy->frame_rcvd_size =
1023dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				    sizeof(struct dev_to_host_fis);
1024dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				mvs_get_d2h_reg(mvi, i,
1025dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						(void *)sas_phy->frame_rcvd);
1026dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			} else {
1027dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				dev_printk(KERN_DEBUG, &pdev->dev,
1028dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					"No sig fis\n");
1029dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				phy->phy_type &= ~(PORT_TYPE_SATA);
1030dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				goto out_done;
1031dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
1032dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1033dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
1034dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
1035b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1036dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		dev_printk(KERN_DEBUG, &pdev->dev,
1037dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			"phy[%d] Get Attached Address 0x%llX ,"
1038dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			" SAS Address 0x%llX\n",
1039dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			i,
1040dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			(unsigned long long)phy->att_dev_sas_addr,
1041dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			(unsigned long long)phy->dev_sas_addr);
1042dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		dev_printk(KERN_DEBUG, &pdev->dev,
1043dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			"Rate = %x , type = %d\n",
1044dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			sas_phy->linkrate, phy->phy_type);
1045b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1046dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* workaround for HW phy decoding error on 1.5g disk drive */
1047dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
1048dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tmp = mvs_read_port_vsr_data(mvi, i);
1049dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
1050dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		     PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
1051dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			SAS_LINK_RATE_1_5_GBPS)
1052dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			tmp &= ~PHY_MODE6_LATECLK;
1053dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		else
1054dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			tmp |= PHY_MODE6_LATECLK;
1055dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_write_port_vsr_data(mvi, i, tmp);
1056b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1057dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
10584e52fc0a0a2ec2158691efba3f149f6416481255Ke Weiout_done:
1059dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (get_st)
1060dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_write_port_irq_stat(mvi, i, phy->irq_status);
1061b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1062b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1063dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_port_formed(struct asd_sas_phy *sas_phy)
10648f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1065dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct sas_ha_struct *sas_ha = sas_phy->ha;
1066dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_info *mvi = sas_ha->lldd_ha;
1067dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct asd_sas_port *sas_port = sas_phy->port;
1068dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = sas_phy->lldd_phy;
1069dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port = &mvi->port[sas_port->id];
10708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	unsigned long flags;
10718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1072dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_lock_irqsave(&mvi->lock, flags);
1073dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	port->port_attached = 1;
1074dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	phy->port = port;
1075dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	port->taskfileset = MVS_ID_NOT_MAPPED;
1076dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->phy_type & PORT_TYPE_SAS) {
1077dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		port->wide_port_phymap = sas_port->phy_mask;
1078dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_update_wideport(mvi, sas_phy->id);
10798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
1080dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_unlock_irqrestore(&mvi->lock, flags);
1081dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1082dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1083dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_I_T_nexus_reset(struct domain_device *dev)
1084dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1085dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return TMF_RESP_FUNC_FAILED;
1086dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1087dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1088dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
1089dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			u32 slot_idx, int err)
1090dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1091dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port = mvi->slot_info[slot_idx].port;
1092dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct task_status_struct *tstat = &task->task_status;
1093dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
1094dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int stat = SAM_GOOD;
1095dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1096dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	resp->frame_len = sizeof(struct dev_to_host_fis);
1097dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	memcpy(&resp->ending_fis[0],
1098dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	       SATA_RECEIVED_D2H_FIS(port->taskfileset),
1099dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	       sizeof(struct dev_to_host_fis));
1100dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tstat->buf_valid_size = sizeof(*resp);
1101dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (unlikely(err))
1102dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		stat = SAS_PROTO_RESPONSE;
1103dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return stat;
1104dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1105dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1106dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
1107dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			 u32 slot_idx)
1108dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1109dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
1110dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
1111dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4));
1112dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int stat = SAM_CHECK_COND;
11138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1114dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (err_dw1 & SLOT_BSY_ERR) {
1115dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		stat = SAS_QUEUE_FULL;
1116dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_slot_reset(mvi, task, slot_idx);
1117dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
11188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	switch (task->task_proto) {
11198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_SSP:
1120dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1121dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SMP:
11228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		break;
11238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_SATA:
11248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	case SAS_PROTOCOL_STP:
1125dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
1126dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (err_dw0 & TFILE_ERR)
1127dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			stat = mvs_sata_done(mvi, task, slot_idx, 1);
11288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		break;
11298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	default:
11308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		break;
11318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
11328121ed420285885654af133a6ca1919590f98917Ke Wei
1133dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_hexdump(16, (u8 *) slot->response, 0);
1134dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return stat;
11358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
11368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1137dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
1138b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1139dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
1140dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
1141dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct sas_task *task = slot->task;
1142dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct task_status_struct *tstat;
1143dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port;
1144dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	bool aborted;
1145dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void *to;
1146b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1147dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (unlikely(!task || !task->lldd_task))
1148dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -1;
1149b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1150dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_hba_cq_dump(mvi);
1151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1152dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_lock(&task->task_state_lock);
1153dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
1154dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!aborted) {
1155dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		task->task_state_flags &=
1156dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		    ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
1157dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		task->task_state_flags |= SAS_TASK_STATE_DONE;
1158b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1159dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_unlock(&task->task_state_lock);
1160b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1161dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (aborted) {
1162dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_slot_task_free(mvi, task, slot, slot_idx);
1163dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_slot_free(mvi, rx_desc);
1164dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -1;
1165dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1166b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1167dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	port = slot->port;
1168dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tstat = &task->task_status;
1169dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	memset(tstat, 0, sizeof(*tstat));
1170dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tstat->resp = SAS_TASK_COMPLETE;
1171b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1172dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (unlikely(!port->port_attached || flags)) {
1173dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_slot_err(mvi, task, slot_idx);
1174dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (!sas_protocol_ata(task->task_proto))
1175dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			tstat->stat = SAS_PHY_DOWN;
1176dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto out;
1177dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1178b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1179dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* error info record present */
1180dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
1181dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tstat->stat = mvs_slot_err(mvi, task, slot_idx);
1182dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto out;
1183dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1184b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1185dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	switch (task->task_proto) {
1186dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SSP:
1187dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* hw says status == 0, datapres == 0 */
1188dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (rx_desc & RXQ_GOOD) {
1189dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			tstat->stat = SAM_GOOD;
1190dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			tstat->resp = SAS_TASK_COMPLETE;
1191dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1192dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* response frame present */
1193dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		else if (rx_desc & RXQ_RSP) {
1194dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			struct ssp_response_iu *iu =
1195dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			    slot->response + sizeof(struct mvs_err_info);
1196dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			sas_ssp_task_response(&mvi->pdev->dev, task, iu);
1197dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1199dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* should never happen? */
1200dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		else
1201dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			tstat->stat = SAM_CHECK_COND;
1202dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1203dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1204dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SMP: {
1205dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			struct scatterlist *sg_resp = &task->smp_task.smp_resp;
1206dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			tstat->stat = SAM_GOOD;
1207dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
1208dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			memcpy(to + sg_resp->offset,
1209dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				slot->response + sizeof(struct mvs_err_info),
1210dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				sg_dma_len(sg_resp));
1211dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			kunmap_atomic(to, KM_IRQ0);
12128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			break;
1213b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
1214b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1215dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA:
1216dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_STP:
1217dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
1218dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
1219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			break;
1220dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	default:
1223dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tstat->stat = SAM_CHECK_COND;
1224dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1225b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1226b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1227dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikout:
1228dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_slot_task_free(mvi, task, slot, slot_idx);
1229dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (unlikely(tstat->stat != SAS_QUEUE_FULL))
1230dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_slot_free(mvi, rx_desc);
1231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1232dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_unlock(&mvi->lock);
1233dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	task->task_done(task);
1234dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_lock(&mvi->lock);
1235dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return tstat->stat;
1236b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1237b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1238dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_release_task(struct mvs_info *mvi, int phy_no)
1239b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1240dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct list_head *pos, *n;
1241dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_slot_info *slot;
1242dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[phy_no];
1243dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port = phy->port;
1244dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 rx_desc;
1245b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1246dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!port)
1247dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return;
1248b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1249dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	list_for_each_safe(pos, n, &port->list) {
1250dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot = container_of(pos, struct mvs_slot_info, list);
1251dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rx_desc = (u32) (slot - mvi->slot_info);
1252dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_slot_complete(mvi, rx_desc, 1);
1253b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1254dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1255b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1256dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
1257dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1258dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct pci_dev *pdev = mvi->pdev;
1259dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct sas_ha_struct *sas_ha = &mvi->sas;
1260dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[phy_no];
1261dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct asd_sas_phy *sas_phy = &phy->sas_phy;
1262b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1263dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	phy->irq_status = mvs_read_port_irq_stat(mvi, phy_no);
1264b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
1265dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	* events is port event now ,
1266dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	* we need check the interrupt status which belongs to per port.
1267dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	*/
1268dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	dev_printk(KERN_DEBUG, &pdev->dev,
1269dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		"Port %d Event = %X\n",
1270dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy_no, phy->irq_status);
1271b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1272dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) {
1273dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_release_task(mvi, phy_no);
1274dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (!mvs_is_phy_ready(mvi, phy_no)) {
1275dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			sas_phy_disconnected(sas_phy);
1276dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
1277dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			dev_printk(KERN_INFO, &pdev->dev,
1278dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				"Port %d Unplug Notice\n", phy_no);
1279b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1280dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else
1281dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL);
1282b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1283dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!(phy->irq_status & PHYEV_DEC_ERR)) {
1284dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (phy->irq_status & PHYEV_COMWAKE) {
1285dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			u32 tmp = mvs_read_port_irq_mask(mvi, phy_no);
1286dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_write_port_irq_mask(mvi, phy_no,
1287dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						tmp | PHYEV_SIG_FIS);
1288dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1289dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
1290dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
1291dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (phy->phy_status) {
1292dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				mvs_detect_porttype(mvi, phy_no);
1293b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1294dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				if (phy->phy_type & PORT_TYPE_SATA) {
1295dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					u32 tmp = mvs_read_port_irq_mask(mvi,
1296dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik								phy_no);
1297dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					tmp &= ~PHYEV_SIG_FIS;
1298dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					mvs_write_port_irq_mask(mvi,
1299dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik								phy_no, tmp);
1300dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				}
1301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1302dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				mvs_update_phyinfo(mvi, phy_no, 0);
1303dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				sas_ha->notify_phy_event(sas_phy,
1304dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							PHYE_OOB_DONE);
1305dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				mvs_bytes_dmaed(mvi, phy_no);
1306dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			} else {
1307dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				dev_printk(KERN_DEBUG, &pdev->dev,
1308dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					"plugin interrupt but phy is gone\n");
1309dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET,
1310dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							NULL);
1311dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
1312dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else if (phy->irq_status & PHYEV_BROAD_CH) {
1313dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_release_task(mvi, phy_no);
1314dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			sas_ha->notify_port_event(sas_phy,
1315dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						PORTE_BROADCAST_RCVD);
1316dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1317dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1318dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_write_port_irq_stat(mvi, phy_no, phy->irq_status);
1319b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1320b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1321dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
1322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1323b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1324dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 rx_prod_idx, rx_desc;
1325dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	bool attn = false;
1326dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct pci_dev *pdev = mvi->pdev;
13278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1328dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* the first dword in the RX ring is special: it contains
1329dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * a mirror of the hardware's RX producer index, so that
1330dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * we don't have to stall the CPU reading that register.
1331dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * The actual RX ring is offset by one dword, due to this.
1332dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
1333dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	rx_prod_idx = mvi->rx_cons;
1334dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
1335dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (mvi->rx_cons == 0xfff)	/* h/w hasn't touched RX ring yet */
1336dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return 0;
13378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1338dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* The CMPL_Q may come late, read from register and try again
1339dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	* note: if coalescing is enabled,
1340dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	* it will need to read from register every time for sure
1341dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	*/
1342dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (mvi->rx_cons == rx_prod_idx)
1343dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
13448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1345dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (mvi->rx_cons == rx_prod_idx)
1346dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return 0;
13478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1348dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	while (mvi->rx_cons != rx_prod_idx) {
13498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1350dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* increment our internal RX consumer pointer */
1351dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
13528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1353dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
13548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1355dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (likely(rx_desc & RXQ_DONE))
1356dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_slot_complete(mvi, rx_desc, 0);
1357dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (rx_desc & RXQ_ATTN) {
1358dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			attn = true;
1359dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n",
1360dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				rx_desc);
1361dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else if (rx_desc & RXQ_ERR) {
1362dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (!(rx_desc & RXQ_DONE))
1363dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				mvs_slot_complete(mvi, rx_desc, 0);
1364dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n",
1365dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				rx_desc);
1366dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else if (rx_desc & RXQ_SLOT_RESET) {
1367dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n",
1368dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				rx_desc);
1369dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_slot_free(mvi, rx_desc);
1370dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1371dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
13728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1373dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (attn && self_clear)
1374dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_int_full(mvi);
13758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1376dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
13778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
13788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1379dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#ifndef MVS_DISABLE_NVRAM
1380dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data)
13818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1382dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int timeout = 1000;
1383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1384dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (addr & ~SPI_ADDR_MASK)
1385dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -EINVAL;
1386b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1387dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	writel(addr, regs + SPI_CMD);
1388dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	writel(TWSI_RD, regs + SPI_CTL);
1389b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1390dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	while (timeout-- > 0) {
1391dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (readl(regs + SPI_CTL) & TWSI_RDY) {
1392dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			*data = readl(regs + SPI_DATA);
1393dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			return 0;
1394dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1395b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1396dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		udelay(10);
1397dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1398b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1399dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return -EBUSY;
1400dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1401b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1402dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_eep_read_buf(void __iomem *regs, u32 addr,
1403dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			    void *buf, u32 buflen)
1404dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1405dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 addr_end, tmp_addr, i, j;
1406dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 tmp = 0;
1407dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int rc;
1408dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u8 *tmp8, *buf8 = buf;
1409b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1410dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	addr_end = addr + buflen;
1411dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tmp_addr = ALIGN(addr, 4);
1412dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (addr > 0xff)
1413dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -EINVAL;
1414b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1415dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	j = addr & 0x3;
1416dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (j) {
1417dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = mvs_eep_read(regs, tmp_addr, &tmp);
1418dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (rc)
1419dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			return rc;
1420b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1421dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tmp8 = (u8 *)&tmp;
1422dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		for (i = j; i < 4; i++)
1423dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			*buf8++ = tmp8[i];
14248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1425dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tmp_addr += 4;
1426dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
14278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1428dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) {
1429dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = mvs_eep_read(regs, tmp_addr, &tmp);
1430dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (rc)
1431dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			return rc;
14328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1433dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		memcpy(buf8, &tmp, 4);
1434dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		buf8 += 4;
1435dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
14368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1437dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (tmp_addr < addr_end) {
1438dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = mvs_eep_read(regs, tmp_addr, &tmp);
1439dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (rc)
1440dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			return rc;
14418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1442dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tmp8 = (u8 *)&tmp;
1443dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		j = addr_end - tmp_addr;
1444dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		for (i = 0; i < j; i++)
1445dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			*buf8++ = tmp8[i];
14468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1447dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tmp_addr += 4;
1448dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
14498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1450dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
14518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
1452dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
14538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1454dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_nvram_read(struct mvs_info *mvi, u32 addr, void *buf, u32 buflen)
14558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1456dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#ifndef MVS_DISABLE_NVRAM
14578f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
1458dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int rc, i;
1459dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 sum;
1460dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u8 hdr[2], *tmp;
1461dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	const char *msg;
14628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1463dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	rc = mvs_eep_read_buf(regs, addr, &hdr, 2);
1464dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (rc) {
1465dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		msg = "nvram hdr read failed";
1466dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out;
1467dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1468dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen);
1469dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (rc) {
1470dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		msg = "nvram read failed";
1471dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out;
1472dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
14738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1474dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (hdr[0] != 0x5A) {
1475dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* entry id */
1476dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		msg = "invalid nvram entry id";
1477dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -ENOENT;
1478dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out;
1479dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
14808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1481dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tmp = buf;
1482dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	sum = ((u32)hdr[0]) + ((u32)hdr[1]);
1483dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	for (i = 0; i < buflen; i++)
1484dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sum += ((u32)tmp[i]);
14858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1486dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (sum) {
1487dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		msg = "nvram checksum failure";
1488dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -EILSEQ;
1489dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out;
1490dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
14918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1492dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
14938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1494dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out:
1495dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
1496dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return rc;
1497dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#else
1498dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* FIXME , For SAS target mode */
1499dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
1500dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
1501dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
15028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
15038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1504dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_int_sata(struct mvs_info *mvi)
15058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1506dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 tmp;
1507dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void __iomem *regs = mvi->regs;
1508dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tmp = mr32(INT_STAT_SRS);
1509dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mw32(INT_STAT_SRS, tmp & 0xFFFF);
15108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
15118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1512dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task,
1513dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				u32 slot_idx)
15148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1515dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void __iomem *regs = mvi->regs;
1516dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct domain_device *dev = task->dev;
1517dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct asd_sas_port *sas_port = dev->port;
1518dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port = mvi->slot_info[slot_idx].port;
1519dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 reg_set, phy_mask;
15208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1521dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!sas_protocol_ata(task->task_proto)) {
1522dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		reg_set = 0;
1523dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
1524dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				sas_port->phy_mask;
1525dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	} else {
1526dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		reg_set = port->taskfileset;
1527dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy_mask = sas_port->phy_mask;
15288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
1529dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx |
1530dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					(TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) |
1531dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					(phy_mask << TXQ_PHY_SHIFT) |
1532dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					(reg_set << TXQ_SRS_SHIFT));
1533dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1534dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mw32(TX_PROD_IDX, mvi->tx_prod);
1535dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
15368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
15378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1538dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_int_full(struct mvs_info *mvi)
15398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1540dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void __iomem *regs = mvi->regs;
1541dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 tmp, stat;
1542dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int i;
15438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1544dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	stat = mr32(INT_STAT);
15458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1546dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_int_rx(mvi, false);
15478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1548dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	for (i = 0; i < MVS_MAX_PORTS; i++) {
1549dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
1550dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (tmp)
1551dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_int_port(mvi, i, tmp);
15528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
15538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1554dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (stat & CINT_SRS)
1555dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_int_sata(mvi);
15568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1557dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mw32(INT_STAT, stat);
1558dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
15598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1560dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#ifndef MVS_DISABLE_MSI
1561dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
1562dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1563dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_info *mvi = opaque;
1564e9ff91b6927079307b5d481a93beac4134e923ebKe Wei
1565dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#ifndef MVS_USE_TASKLET
1566dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_lock(&mvi->lock);
1567e9ff91b6927079307b5d481a93beac4134e923ebKe Wei
1568dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_int_rx(mvi, true);
15698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1570dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_unlock(&mvi->lock);
1571dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#else
1572dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tasklet_schedule(&mvi->tasklet);
1573dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
1574dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return IRQ_HANDLED;
15758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
1576dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
15778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1578dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_task_abort(struct sas_task *task)
15798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1580dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int rc;
15818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	unsigned long flags;
1582dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
1583dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct pci_dev *pdev = mvi->pdev;
1584dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int tag;
15858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1586dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_lock_irqsave(&task->task_state_lock, flags);
1587dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
1588dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = TMF_RESP_FUNC_COMPLETE;
1589dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		spin_unlock_irqrestore(&task->task_state_lock, flags);
1590dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto out_done;
15918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
1592dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	spin_unlock_irqrestore(&task->task_state_lock, flags);
1593b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1594dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	switch (task->task_proto) {
1595dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SMP:
1596dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n");
1597dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1598dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SSP:
1599dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n");
1600dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1601dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA:
1602dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_STP:
1603dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{
1604dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n");
1605dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP
1606dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n");
1607dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_hexdump(sizeof(struct host_to_dev_fis),
1608dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				(void *)&task->ata_task.fis, 0);
1609dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
1610dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_hexdump(16, task->ata_task.atapi_packet, 0);
1611dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
1612dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		spin_lock_irqsave(&task->task_state_lock, flags);
1613dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) {
1614dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			/* TODO */
1615dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			;
1616dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1617dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		spin_unlock_irqrestore(&task->task_state_lock, flags);
1618dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1619dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1620dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	default:
1621dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1622dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1623dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1624dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (mvs_find_tag(mvi, task, &tag)) {
1625dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		spin_lock_irqsave(&mvi->lock, flags);
1626dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag);
1627dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		spin_unlock_irqrestore(&mvi->lock, flags);
1628dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1629dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!mvs_task_exec(task, 1, GFP_ATOMIC))
1630dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = TMF_RESP_FUNC_COMPLETE;
1631dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	else
1632dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = TMF_RESP_FUNC_FAILED;
1633dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikout_done:
1634dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return rc;
1635e9ff91b6927079307b5d481a93beac4134e923ebKe Wei}
1636e9ff91b6927079307b5d481a93beac4134e923ebKe Wei
1637dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint __devinit mvs_hw_init(struct mvs_info *mvi)
1638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void __iomem *regs = mvi->regs;
1640b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	int i;
1641b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 tmp, cctl;
1642b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1643b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* make sure interrupts are masked immediately (paranoia) */
1644b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(GBL_CTL, 0);
1645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp = mr32(GBL_CTL);
1646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* Reset Controller */
1648b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!(tmp & HBA_RST)) {
1649b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (mvi->flags & MVF_PHY_PWR_FIX) {
1650b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
1651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp &= ~PCTL_PWR_ON;
1652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp |= PCTL_OFF;
1653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
1654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
1656b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp &= ~PCTL_PWR_ON;
1657b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			tmp |= PCTL_OFF;
1658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
1659b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		}
1660b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* global reset, incl. COMRESET/H_RESET_N (self-clearing) */
1662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mw32_f(GBL_CTL, HBA_RST);
1663b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* wait for reset to finish; timeout is just a guess */
1666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	i = 1000;
1667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	while (i-- > 0) {
1668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		msleep(10);
1669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		if (!(mr32(GBL_CTL) & HBA_RST))
1671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik			break;
1672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1673b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (mr32(GBL_CTL) & HBA_RST) {
1674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dev_printk(KERN_ERR, &mvi->pdev->dev, "HBA reset failed\n");
1675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		return -EBUSY;
1676b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* Init Chip */
1679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* make sure RST is set; HBA_RST /should/ have done that for us */
1680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	cctl = mr32(CTL);
1681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (cctl & CCTL_RST)
1682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		cctl &= ~CCTL_RST;
1683b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	else
1684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		mw32_f(CTL, cctl | CCTL_RST);
1685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
16868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* write to device control _AND_ device status register? - A.C. */
16878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
16888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp &= ~PRD_REQ_MASK;
16898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp |= PRD_REQ_SIZE;
16908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
16918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1692b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
1693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= PCTL_PWR_ON;
1694b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~PCTL_OFF;
1695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
1696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1697b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
1698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp |= PCTL_PWR_ON;
1699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	tmp &= ~PCTL_OFF;
1700b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
1701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32_f(CTL, cctl);
1703b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* reset control */
17058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(PCS, 0);		/*MVS_PCS */
17068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1707b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mvs_phy_hacks(mvi);
1708b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_LIST_LO, mvi->slot_dma);
1710b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
1711b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1712b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_FIS_LO, mvi->rx_fis_dma);
1713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
1714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(TX_CFG, MVS_CHIP_SLOT_SZ);
1716b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(TX_LO, mvi->tx_dma);
1717b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(TX_HI, (mvi->tx_dma >> 16) >> 16);
1718b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1719b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_CFG, MVS_RX_RING_SZ);
1720b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_LO, mvi->rx_dma);
1721b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_HI, (mvi->rx_dma >> 16) >> 16);
1722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* enable auto port detection */
17248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
1725ddccf307a3599e452804e228d8ed30fba578923eReinhard Nissl	msleep(1100);
1726b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* init and reset phys */
1727b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < mvi->chip->n_phy; i++) {
172800da714b31b944400ee789e477f58247cff30b1bKe Wei		u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]);
172900da714b31b944400ee789e477f58247cff30b1bKe Wei		u32 hi = be32_to_cpu(*(u32 *)&mvi->sas_addr[0]);
17308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
17318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_detect_porttype(mvi, i);
1732b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1733b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* set phy local SAS address */
17348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
17358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_data(mvi, i, lo);
17368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
17378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_cfg_data(mvi, i, hi);
1738b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1739b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* reset phy */
17408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = mvs_read_phy_ctl(mvi, i);
1741b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		tmp |= PHY_RST;
17428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_phy_ctl(mvi, i, tmp);
1743b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1744b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1745b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	msleep(100);
1746b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1747b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	for (i = 0; i < mvi->chip->n_phy; i++) {
17488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		/* clear phy int status */
17498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = mvs_read_port_irq_stat(mvi, i);
17508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp &= ~PHYEV_SIG_FIS;
17518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_irq_stat(mvi, i, tmp);
17528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1753b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		/* set phy int mask */
17548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS |
17558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			PHYEV_ID_DONE | PHYEV_DEC_ERR;
17568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_write_port_irq_mask(mvi, i, tmp);
1757b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		msleep(100);
17598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_update_phyinfo(mvi, i, 1);
17608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		mvs_enable_xmt(mvi, i);
1761b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1762b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1763b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: update wide port bitmaps */
1764b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* little endian for open address and command table, etc. */
17668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* A.C.
17678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * it seems that ( from the spec ) turning on big-endian won't
17688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * do us any good on big-endian machines, need further confirmation
17698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 */
17708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl = mr32(CTL);
17718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl |= CCTL_ENDIAN_CMD;
17728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl |= CCTL_ENDIAN_DATA;
17738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl &= ~CCTL_ENDIAN_OPEN;
17748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	cctl |= CCTL_ENDIAN_RSP;
17758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32_f(CTL, cctl);
17768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
17778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* reset CMD queue */
17788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = mr32(PCS);
17798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp |= PCS_CMD_RST;
17808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(PCS, tmp);
17818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* interrupt coalescing may cause missing HW interrput in some case,
17828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * and the max count is 0x1ff, while our max slot is 0x200,
17838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 * it will make count 0.
17848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	 */
17858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = 0;
17868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(INT_COAL, tmp);
17878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
17888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	tmp = 0x100;
17898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(INT_COAL_TMOUT, tmp);
17908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1791b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* ladies and gentlemen, start your engines */
17928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(TX_CFG, 0);
17938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
1794b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
17958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* enable CMD/CMPL_Q/RESP mode */
17968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN);
1797b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
17988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* enable completion queue interrupt */
1799e9ff91b6927079307b5d481a93beac4134e923ebKe Wei	tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS);
18008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mw32(INT_MASK, tmp);
1801b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1802e9ff91b6927079307b5d481a93beac4134e923ebKe Wei	/* Enable SRS interrupt */
1803e9ff91b6927079307b5d481a93beac4134e923ebKe Wei	mw32(INT_MASK_SRS, 0xFF);
1804b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
1805b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1806b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1807dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid __devinit mvs_print_info(struct mvs_info *mvi)
1808b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
1809b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct pci_dev *pdev = mvi->pdev;
1810b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	static int printed_version;
1811b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1812b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (!printed_version++)
1813b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
1814b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1815b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dev_printk(KERN_INFO, &pdev->dev, "%u phys, addr %llx\n",
1816b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		   mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr));
1817b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1818b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1819