mv_sas.c revision df64d3caab8db6ae17dacd229a03d7689a10c432
1b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/*
220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * Marvell 88SE64xx/88SE94xx main function
320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *
420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * Copyright 2007 Red Hat, Inc.
520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * Copyright 2008 Marvell. <kewei@marvell.com>
620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *
720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * This file is licensed under GPLv2.
820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *
920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * This program is free software; you can redistribute it and/or
1020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * modify it under the terms of the GNU General Public License as
1120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * published by the Free Software Foundation; version 2 of the
1220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * License.
1320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *
1420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * This program is distributed in the hope that it will be useful,
1520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * but WITHOUT ANY WARRANTY; without even the implied warranty of
1620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * General Public License for more details.
1820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *
1920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * You should have received a copy of the GNU General Public License
2020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * along with this program; if not, write to the Free Software
2120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
2220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * USA
2320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan*/
24b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
25dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#include "mv_sas.h"
26b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
27dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
28dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
29dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (task->lldd_task) {
30dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct mvs_slot_info *slot;
31f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan		slot = task->lldd_task;
3220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		*tag = slot->slot_tag;
33dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return 1;
34dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
35dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
36dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
3820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_tag_clear(struct mvs_info *mvi, u32 tag)
39dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
40f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	void *bitmap = &mvi->tags;
41dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	clear_bit(tag, bitmap);
42dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
4420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_tag_free(struct mvs_info *mvi, u32 tag)
45dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
46dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_clear(mvi, tag);
47dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
4920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
50dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
51f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	void *bitmap = &mvi->tags;
52dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	set_bit(tag, bitmap);
53dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
5520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yaninline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
56dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
57dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	unsigned int index, tag;
58f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	void *bitmap = &mvi->tags;
59b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	index = find_first_zero_bit(bitmap, mvi->tags_num);
61dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tag = index;
6220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (tag >= mvi->tags_num)
63dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -SAS_QUEUE_FULL;
64dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_set(mvi, tag);
65dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	*tag_out = tag;
66dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
67dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
68b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
69dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_tag_init(struct mvs_info *mvi)
70dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
71dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int i;
7220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (i = 0; i < mvi->tags_num; ++i)
73dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_tag_clear(mvi, i);
74dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
75b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
7620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 i;
798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 run;
808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 offset;
818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	offset = 0;
838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	while (size) {
8420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		printk(KERN_DEBUG"%08X : ", baseaddr + offset);
858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (size >= 16)
868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			run = 16;
878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		else
888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			run = size;
898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		size -= run;
908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		for (i = 0; i < 16; i++) {
918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			if (i < run)
9220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				printk(KERN_DEBUG"%02X ", (u32)data[i]);
938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			else
9420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				printk(KERN_DEBUG"   ");
958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		}
9620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		printk(KERN_DEBUG": ");
978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		for (i = 0; i < run; i++)
9820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			printk(KERN_DEBUG"%c",
9920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				isalnum(data[i]) ? data[i] : '.');
10020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		printk(KERN_DEBUG"\n");
1018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		data = &data[16];
1028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		offset += run;
1038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
10420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	printk(KERN_DEBUG"\n");
1058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
1068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#if (_MV_DUMP > 1)
1088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
1098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				   enum sas_protocol proto)
1108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 offset;
1128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot = &mvi->slot_info[tag];
1138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	offset = slot->cmd_size + MVS_OAF_SZ +
11520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	    MVS_CHIP_DISP->prd_size() * slot->n_elem;
11620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev, "+---->Status buffer[%d] :\n",
1178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			tag);
1188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(32, (u8 *) slot->response,
1198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		    (u32) slot->buf_dma + offset);
1208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
121ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei#endif
1228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
1248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				enum sas_protocol proto)
1258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
12620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#if (_MV_DUMP > 1)
127ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	u32 sz, w_ptr;
1288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64 addr;
1298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot = &mvi->slot_info[tag];
1308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*Delivery Queue */
13220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	sz = MVS_CHIP_SLOT_SZ;
133ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	w_ptr = slot->tx;
13420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	addr = mvi->tx_dma;
13520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev,
136ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei		"Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr);
13720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev,
1388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Delivery Queue Base Address=0x%llX (PA)"
1398f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"(tx_dma=0x%llX), Entry=%04d\n",
14020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		addr, (unsigned long long)mvi->tx_dma, w_ptr);
1418f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
1428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			(u32) mvi->tx_dma + sizeof(u32) * w_ptr);
1438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*Command List */
144ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	addr = mvi->slot_dma;
14520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev,
1468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Command List Base Address=0x%llX (PA)"
1478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"(slot_dma=0x%llX), Header=%03d\n",
14820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		addr, (unsigned long long)slot->buf_dma, tag);
14920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev, "Command Header[%03d]:\n", tag);
1508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*mvs_cmd_hdr */
1518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
1528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		(u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
1538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*1.command table area */
15420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev, "+---->Command Table :\n");
1558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
1568f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*2.open address frame area */
15720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev, "+---->Open Address Frame :\n");
1588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
1598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(u32) slot->buf_dma + slot->cmd_size);
1608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*3.status buffer */
1618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hba_sb_dump(mvi, tag, proto);
1628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*4.PRD table */
16320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev, "+---->PRD table :\n");
16420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_hexdump(MVS_CHIP_DISP->prd_size() * slot->n_elem,
1658f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		(u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
1668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		(u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
1678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
1688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
1698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Weistatic void mvs_hba_cq_dump(struct mvs_info *mvi)
1718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
172ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei#if (_MV_DUMP > 2)
1738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u64 addr;
1748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	void __iomem *regs = mvi->regs;
1758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 entry = mvi->rx_cons + 1;
1768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
1778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/*Completion Queue */
1798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
18020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev, "Completion Task = 0x%p\n",
181ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei		   mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
18220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_DEBUG, mvi->dev,
1838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"Completion List Base Address=0x%llX (PA), "
1848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		"CQ_Entry=%04d, CQ_WP=0x%08X\n",
1858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		addr, entry - 1, mvi->rx[0]);
1868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
1878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		    mvi->rx_dma + sizeof(u32) * entry);
1888f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
1898f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
1908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
19120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_get_sas_addr(void *buf, u32 buflen)
1928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
19320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/*memcpy(buf, "\x50\x05\x04\x30\x11\xab\x64\x40", 8);*/
19420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
19620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstruct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
19720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
19820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long i = 0, j = 0, hi = 0;
19920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sha = dev->port->ha;
20020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = NULL;
20120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_phy *phy;
20220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
20320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (sha->sas_port[i]) {
20420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sha->sas_port[i] == dev->port) {
20520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy =  container_of(sha->sas_port[i]->phy_list.next,
20620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				struct asd_sas_phy, port_phy_el);
20720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			j = 0;
20820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			while (sha->sas_phy[j]) {
20920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				if (sha->sas_phy[j] == phy)
21020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					break;
21120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				j++;
21220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
21320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
21420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
21520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i++;
21620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
21720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	hi = j/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
21820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
2198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
22020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return mvi;
2218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
22220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
2238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
22420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* FIXME */
22520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
22620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
22720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long i = 0, j = 0, n = 0, num = 0;
2289870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
2299870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_info *mvi = mvi_dev->mvi_info;
23020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sha = dev->port->ha;
23120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
23220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (sha->sas_port[i]) {
23320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sha->sas_port[i] == dev->port) {
23420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct asd_sas_phy *phy;
23520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			list_for_each_entry(phy,
23620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				&sha->sas_port[i]->phy_list, port_phy_el) {
23720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				j = 0;
23820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				while (sha->sas_phy[j]) {
23920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					if (sha->sas_phy[j] == phy)
24020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						break;
24120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					j++;
24220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				}
24320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phyno[n] = (j >= mvi->chip->n_phy) ?
24420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					(j - mvi->chip->n_phy) : j;
24520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				num++;
24620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				n++;
247dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
248dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
249dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
25020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i++;
25120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
25220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return num;
25320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
25420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
25520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic inline void mvs_free_reg_set(struct mvs_info *mvi,
25620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				struct mvs_device *dev)
25720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
25820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!dev) {
25920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("device has been free.\n");
26020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
26120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
26220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (dev->taskfileset == MVS_ID_NOT_MAPPED)
26320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
26420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset);
26520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
26620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
26720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic inline u8 mvs_assign_reg_set(struct mvs_info *mvi,
26820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				struct mvs_device *dev)
26920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
27020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (dev->taskfileset != MVS_ID_NOT_MAPPED)
27120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return 0;
27220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset);
27320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
27420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
27520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard)
27620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
27720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 no;
27820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for_each_phy(phy_mask, phy_mask, no) {
27920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (!(phy_mask & 1))
28020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			continue;
28120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_reset(mvi, no, hard);
28220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
28320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
28420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
28520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* FIXME: locking? */
28620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
28720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			void *funcdata)
28820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
28920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = 0, phy_id = sas_phy->id;
29020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tmp, i = 0, hi;
29120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sha = sas_phy->ha;
29220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = NULL;
29320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
29420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (sha->sas_phy[i]) {
29520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sha->sas_phy[i] == sas_phy)
29620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
29720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i++;
29820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
29920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
30020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
30120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
30220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	switch (func) {
30320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case PHY_FUNC_SET_LINK_RATE:
30420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata);
30520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
3068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
307dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_HARD_RESET:
30820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id);
309dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (tmp & PHY_RST_HARD)
310dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
31120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_reset(mvi, phy_id, 1);
312dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
313b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
314dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_LINK_RESET:
31520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_enable(mvi, phy_id);
31620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_reset(mvi, phy_id, 0);
317dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
318b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
319dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_DISABLE:
32020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_disable(mvi, phy_id);
32120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
322dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_RELEASE_SPINUP_HOLD:
323dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	default:
324dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -EOPNOTSUPP;
325b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
32620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	msleep(200);
327b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
328b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
329b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
33020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id,
33120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				u32 off_lo, u32 off_hi, u64 sas_addr)
33220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
33320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 lo = (u32)sas_addr;
33420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 hi = (u32)(sas_addr>>32);
33520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
33620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_lo);
33720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, lo);
33820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_hi);
33920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi);
34020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
34120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
342dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
343ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei{
344dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
34520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_phy *sas_phy = &phy->sas_phy;
34620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sas_ha;
347dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!phy->phy_attached)
348dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return;
349dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
35020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!(phy->att_dev_info & PORT_DEV_TRGT_MASK)
35120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		&& phy->phy_type & PORT_TYPE_SAS) {
35220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
35320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
35420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
35520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	sas_ha = mvi->sas;
35620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE);
35720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
358dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (sas_phy->phy) {
359dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct sas_phy *sphy = sas_phy->phy;
360dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
361dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->negotiated_linkrate = sas_phy->linkrate;
362dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->minimum_linkrate = phy->minimum_linkrate;
363dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
364dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->maximum_linkrate = phy->maximum_linkrate;
36520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		sphy->maximum_linkrate_hw = MVS_CHIP_DISP->phy_max_link_rate();
366ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	}
367ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei
368dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->phy_type & PORT_TYPE_SAS) {
369dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct sas_identify_frame *id;
370b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
371dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id = (struct sas_identify_frame *)phy->frame_rcvd;
372dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id->dev_type = phy->identify.device_type;
373dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id->initiator_bits = SAS_PROTOCOL_ALL;
374dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id->target_bits = phy->identify.target_port_protocols;
375dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	} else if (phy->phy_type & PORT_TYPE_SATA) {
37620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/*Nothing*/
377dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
37820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_dprintk("phy %d byte dmaded.\n", i + mvi->id * mvi->chip->n_phy);
37920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
38020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
38120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
38220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi->sas->notify_port_event(sas_phy,
383dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				   PORTE_BYTES_DMAED);
384ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei}
385ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei
38620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_slave_alloc(struct scsi_device *scsi_dev)
38720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
38820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
38920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (dev_is_sata(dev)) {
39020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* We don't need to rescan targets
39120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		 * if REPORT_LUNS request is failed
39220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		 */
39320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (scsi_dev->lun > 0)
39420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			return -ENXIO;
39520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		scsi_dev->tagged_supported = 1;
39620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
39720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
39820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return sas_slave_alloc(scsi_dev);
39920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
40020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
401dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_slave_configure(struct scsi_device *sdev)
402ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei{
403dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct domain_device *dev = sdev_to_domain_dev(sdev);
404dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int ret = sas_slave_configure(sdev);
405b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
406dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (ret)
407dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return ret;
408dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (dev_is_sata(dev)) {
40920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* may set PIO mode */
41020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	#if MV_DISABLE_NCQ
41120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct ata_port *ap = dev->sata_dev.ap;
41220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct ata_device *adev = ap->link.device;
41320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		adev->flags |= ATA_DFLAG_NCQ_OFF;
414dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
41520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	#endif
416dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
417ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	return 0;
418b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
419b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
420dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_scan_start(struct Scsi_Host *shost)
421b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
42220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int i, j;
42320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned short core_nr;
42420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi;
42520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
42620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
42720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
428dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
42920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (j = 0; j < core_nr; j++) {
43020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j];
43120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		for (i = 0; i < mvi->chip->n_phy; ++i)
43220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_bytes_dmaed(mvi, i);
433dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
434b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
435b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
436dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
437b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
438dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* give the phy enabling interrupt event time to come in (1s
439dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * is empirically about all it takes) */
440dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (time < HZ)
441dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return 0;
442dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* Wait for discovery to finish */
443dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	scsi_flush_work(shost);
444dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 1;
445b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
446b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
447dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_smp(struct mvs_info *mvi,
448dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     struct mvs_task_exec_info *tei)
449b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
450dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int elem, rc, i;
451dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct sas_task *task = tei->task;
452dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
45320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct domain_device *dev = task->dev;
45420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_port *sas_port = dev->port;
455dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct scatterlist *sg_req, *sg_resp;
456dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 req_len, resp_len, tag = tei->tag;
457dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void *buf_tmp;
458dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u8 *buf_oaf;
459dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	dma_addr_t buf_tmp_dma;
46020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	void *buf_prd;
461dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_slot_info *slot = &mvi->slot_info[tag];
462dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
463dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP
464dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u8 *buf_cmd;
465dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void *from;
466dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
467dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/*
468dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * DMA-map SMP request, response buffers
469dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
470dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	sg_req = &task->smp_task.smp_req;
47120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	elem = dma_map_sg(mvi->dev, sg_req, 1, PCI_DMA_TODEVICE);
472dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!elem)
473dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -ENOMEM;
474dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	req_len = sg_dma_len(sg_req);
475b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
476dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	sg_resp = &task->smp_task.smp_resp;
47720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	elem = dma_map_sg(mvi->dev, sg_resp, 1, PCI_DMA_FROMDEVICE);
478dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!elem) {
479dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -ENOMEM;
480dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out;
481dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
48220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	resp_len = SB_RFB_MAX;
483b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
484dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* must be in dwords */
485dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if ((req_len & 0x3) || (resp_len & 0x3)) {
486dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -EINVAL;
487dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out_2;
488b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
489b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
490dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/*
491dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
492dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
493b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
49420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */
495dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp = slot->buf;
496dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma = slot->buf_dma;
497b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
498dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP
499dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_cmd = buf_tmp;
500dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
501dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp += req_len;
502dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma += req_len;
503dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->cmd_size = req_len;
504dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#else
505dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
506dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
507b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
508dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
509dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_oaf = buf_tmp;
510dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
511b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
512dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp += MVS_OAF_SZ;
513dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
514b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
51520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* region 3: PRD table *********************************** */
516dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_prd = buf_tmp;
517dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (tei->n_elem)
518dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
519dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	else
520dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		hdr->prd_tbl = 0;
521b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
52220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
523dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp += i;
524dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma += i;
525b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
526dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
527dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->response = buf_tmp;
528dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
52920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->flags & MVF_FLAG_SOC)
53020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		hdr->reserved[0] = 0;
531b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
532dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/*
533dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * Fill in TX ring and command slot header
534dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
535dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->tx = mvi->tx_prod;
536dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
537dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					TXQ_MODE_I | tag |
538dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					(sas_port->phy_mask << TXQ_PHY_SHIFT));
539b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
540dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->flags |= flags;
541dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
542dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->tags = cpu_to_le32(tag);
543dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->data_len = 0;
544b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
545dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* generate open address frame hdr (first 12 bytes) */
54620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* initiator, SMP, ftype 1h */
54720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	buf_oaf[0] = (1 << 7) | (PROTOCOL_SMP << 4) | 0x01;
54820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	buf_oaf[1] = dev->linkrate & 0xf;
549dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	*(u16 *)(buf_oaf + 2) = 0xFFFF;		/* SAS SPEC */
55020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
551dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
552dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
55320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
555dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#if _MV_DUMP
556dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* copy cmd table */
557dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
558dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	memcpy(buf_cmd, from + sg_req->offset, req_len);
559dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	kunmap_atomic(from, KM_IRQ0);
560dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#endif
561b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
562b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
563dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_2:
56420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1,
565dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		     PCI_DMA_FROMDEVICE);
566b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
56720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1,
568dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		     PCI_DMA_TODEVICE);
569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
5708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
5718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
572dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
5738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
574dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct ata_queued_cmd *qc = task->uldd_task;
5758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
576dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (qc) {
577dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
578dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			qc->tf.command == ATA_CMD_FPDMA_READ) {
579dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			*tag = qc->tag;
580dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			return 1;
581dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
5828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
5838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
584dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
5858f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
5868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
587dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_ata(struct mvs_info *mvi,
588dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     struct mvs_task_exec_info *tei)
589b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
590b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
591b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct domain_device *dev = task->dev;
592f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device *mvi_dev = dev->lldd_dev;
593b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
594b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port *sas_port = dev->port;
5958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot;
59620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	void *buf_prd;
59720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tag = tei->tag, hdr_tag;
59820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 flags, del_q;
599b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
600b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf;
601b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
6028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 i, req_len, resp_len;
6038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	const u32 max_resp_len = SB_RFB_MAX;
6048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
60520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvs_assign_reg_set(mvi, mvi_dev) == MVS_ID_NOT_MAPPED) {
60620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("Have not enough regiset for dev %d.\n",
60720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvi_dev->device_id);
6088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return -EBUSY;
60920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
6108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot = &mvi->slot_info[tag];
6118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->tx = mvi->tx_prod;
61220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	del_q = TXQ_MODE_I | tag |
61320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
61420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		(sas_port->phy_mask << TXQ_PHY_SHIFT) |
61520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		(mvi_dev->taskfileset << TXQ_SRS_SHIFT);
61620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q);
61720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
61820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#ifndef DISABLE_HOTPLUG_DMA_FIX
61920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->data_dir == DMA_FROM_DEVICE)
62020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT);
62120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	else
62220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
62320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#else
62420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
62520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#endif
626b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ata_task.use_ncq)
627b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FPDMA;
6288f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
6298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
6308f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			flags |= MCH_ATAPI;
6318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
6328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
633b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: fill in port multiplier number */
634b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
635b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->flags = cpu_to_le32(flags);
6368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
6378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* FIXME: the low order order 5 bits for the TAG if enable NCQ */
63820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag))
63920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
6404e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei	else
64120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		hdr_tag = tag;
64220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
64320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	hdr->tags = cpu_to_le32(hdr_tag);
64420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
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_ATA_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_ATA_CMD_SZ;
658b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_ATA_CMD_SZ;
6598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
6608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->cmd_size = MVS_ATA_CMD_SZ;
6618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
662b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
664b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* used for STP.  unused for SATA? */
665b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
666b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
667b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
668b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
669b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
670b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 3: PRD table ********************************************* */
672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
67320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
6748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tei->n_elem)
6758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
6768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
6778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = 0;
67820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	i = MVS_CHIP_DISP->prd_size() * MVS_CHIP_DISP->prd_count();
679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
680b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
681b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
682b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
684b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* FIXME: probably unused, for SATA.  kept here just in case
685b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * we get a STP/SATA error information record
686b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
687b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
688b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
68920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->flags & MVF_FLAG_SOC)
69020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		hdr->reserved[0] = 0;
691b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	req_len = sizeof(struct host_to_dev_fis);
693b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
6948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_err_info) - i;
695b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
696b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
6978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	resp_len = min(resp_len, max_resp_len);
698b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
699b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
70020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (likely(!task->ata_task.device_control_reg_update))
70120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in command FIS and ATAPI CDB */
7038f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
7048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
7058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		memcpy(buf_cmd + STP_ATAPI_CMD,
7068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			task->ata_task.atapi_packet, 16);
7078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
7088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* generate open address frame hdr (first 12 bytes) */
70920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* initiator, STP, ftype 1h */
71020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	buf_oaf[0] = (1 << 7) | (PROTOCOL_STP << 4) | 0x1;
71120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	buf_oaf[1] = dev->linkrate & 0xf;
71220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	*(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
71320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
714b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
715b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
71620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
71720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#ifndef DISABLE_HOTPLUG_DMA_FIX
71820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->data_dir == DMA_FROM_DEVICE)
71920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->dma_fix(mvi->bulk_buffer_dma,
72020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				TRASH_BUCKET_SIZE, tei->n_elem, buf_prd);
72120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#endif
722b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
723b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
724b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
725b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ssp(struct mvs_info *mvi,
72620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			     struct mvs_task_exec_info *tei, int is_tmf,
72720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			     struct mvs_tmf_task *tmf)
728b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
729b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
730b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
7318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port = tei->port;
73220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct domain_device *dev = task->dev;
733f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device *mvi_dev = dev->lldd_dev;
73420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_port *sas_port = dev->port;
735b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info *slot;
73620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	void *buf_prd;
737b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct ssp_frame_hdr *ssp_hdr;
738b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
739b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf, fburst = 0;
740b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
741b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 flags;
7428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 resp_len, req_len, i, tag = tei->tag;
7438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	const u32 max_resp_len = SB_RFB_MAX;
74420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 phy_mask;
745b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
746b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot = &mvi->slot_info[tag];
747b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
74820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy_mask = ((port->wide_port_phymap) ? port->wide_port_phymap :
74920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		sas_port->phy_mask) & TXQ_PHY_MASK;
75020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
7518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->tx = mvi->tx_prod;
7528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
7538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
7544e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei				(phy_mask << TXQ_PHY_SHIFT));
755b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
756b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	flags = MCH_RETRY;
757b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ssp_task.enable_first_burst) {
758b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FBURST;
759b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		fburst = (1 << 7);
760b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
7612b288133ab6306b1761e0a2ef943b944ead6ad69Andy Yan	if (is_tmf)
7622b288133ab6306b1761e0a2ef943b944ead6ad69Andy Yan		flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
7632b288133ab6306b1761e0a2ef943b944ead6ad69Andy Yan	hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
764b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->tags = cpu_to_le32(tag);
765b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = cpu_to_le32(task->total_xfer_len);
766b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
767b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
768b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
769b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
770b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
7718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
7728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd = buf_tmp = slot->buf;
773b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma = slot->buf_dma;
774b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
775b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
776b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
777b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_SSP_CMD_SZ;
778b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_SSP_CMD_SZ;
7798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#if _MV_DUMP
7808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->cmd_size = MVS_SSP_CMD_SZ;
7818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei#endif
782b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
7838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
784b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
785b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
786b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
787b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
788b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
789b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
7908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 3: PRD table ********************************************* */
791b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
7928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tei->n_elem)
7938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
7948f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
7958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = 0;
796b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
79720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
798b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
799b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
800b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
8018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
802b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
803b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
80420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->flags & MVF_FLAG_SOC)
80520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		hdr->reserved[0] = 0;
806b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
807b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
8088f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_err_info) - i;
8098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	resp_len = min(resp_len, max_resp_len);
8108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
8118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	req_len = sizeof(struct ssp_frame_hdr) + 28;
812b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
813b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
814b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
815b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
816b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* generate open address frame hdr (first 12 bytes) */
81720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* initiator, SSP, ftype 1h */
81820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	buf_oaf[0] = (1 << 7) | (PROTOCOL_SSP << 4) | 0x1;
81920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	buf_oaf[1] = dev->linkrate & 0xf;
82020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	*(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
82120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
822b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
8238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* fill in SSP frame header (Command Table.SSP frame header) */
8248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
82520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
82620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (is_tmf)
82720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		ssp_hdr->frame_type = SSP_TASK;
82820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	else
82920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		ssp_hdr->frame_type = SSP_COMMAND;
83020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
83120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr,
832b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	       HASHED_SAS_ADDR_SIZE);
833b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(ssp_hdr->hashed_src_addr,
83420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	       dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
835b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	ssp_hdr->tag = cpu_to_be16(tag);
836b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
83720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* fill in IU for TASK and Command Frame */
838b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_cmd += sizeof(*ssp_hdr);
839b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
840b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
84120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (ssp_hdr->frame_type != SSP_TASK) {
84220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		buf_cmd[9] = fburst | task->ssp_task.task_attr |
84320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				(task->ssp_task.task_prio << 3);
84420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
84520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else{
84620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		buf_cmd[10] = tmf->tmf;
84720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		switch (tmf->tmf) {
84820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_ABORT_TASK:
84920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_QUERY_TASK:
85020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			buf_cmd[12] =
85120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				(tmf->tag_of_task_to_be_managed >> 8) & 0xff;
85220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			buf_cmd[13] =
85320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				tmf->tag_of_task_to_be_managed & 0xff;
85420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
85520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		default:
85620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
85720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
858b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
85920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* fill in PRD (scatter/gather) table, if any */
86020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
861b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
862b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
863b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
86420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#define	DEV_IS_GONE(mvi_dev)	((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE)))
86520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
8660b84b7094e87769120def1e703b8b4d037281038Andy Yan				struct completion *completion,int is_tmf,
8670b84b7094e87769120def1e703b8b4d037281038Andy Yan				struct mvs_tmf_task *tmf)
868b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
8698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct domain_device *dev = task->dev;
8709870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
8719870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_info *mvi = mvi_dev->mvi_info;
872b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_task_exec_info tei;
8738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct sas_task *t = task;
8744e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei	struct mvs_slot_info *slot;
8758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 tag = 0xdeadbeef, rc, n_elem = 0;
8768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 n = num, pass = 0;
8779dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	unsigned long flags = 0,  flags_libsas = 0;
878b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
87920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!dev->port) {
88020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct task_status_struct *tsm = &t->task_status;
88120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
88220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tsm->resp = SAS_TASK_UNDELIVERED;
88320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tsm->stat = SAS_PHY_DOWN;
8849dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (dev->dev_type != SATA_DEV)
8859dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			t->task_done(t);
88620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return 0;
88720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
88820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
8890b84b7094e87769120def1e703b8b4d037281038Andy Yan	spin_lock_irqsave(&mvi->lock, flags);
8908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	do {
8914e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei		dev = t->dev;
892f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan		mvi_dev = dev->lldd_dev;
89320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (DEV_IS_GONE(mvi_dev)) {
89420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (mvi_dev)
89520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_dprintk("device %d not ready.\n",
89620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					mvi_dev->device_id);
89720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			else
89820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_dprintk("device %016llx not ready.\n",
89920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					SAS_ADDR(dev->sas_addr));
90020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
90120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			rc = SAS_PHY_DOWN;
90220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			goto out_done;
90320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
90420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
90520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (dev->port->id >= mvi->chip->n_phy)
90620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			tei.port = &mvi->port[dev->port->id - mvi->chip->n_phy];
90720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		else
90820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			tei.port = &mvi->port[dev->port->id];
909b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
9109dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (tei.port && !tei.port->port_attached) {
911dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (sas_protocol_ata(t->task_proto)) {
9129dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				struct task_status_struct *ts = &t->task_status;
9139dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
91420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_dprintk("port %d does not"
91520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					"attached device.\n", dev->port->id);
9169dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				ts->stat = SAS_PROTO_RESPONSE;
9179dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				ts->stat = SAS_PHY_DOWN;
9189dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				spin_unlock_irqrestore(dev->sata_dev.ap->lock,
9199dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas						       flags_libsas);
9209dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				spin_unlock_irqrestore(&mvi->lock, flags);
9219dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				t->task_done(t);
9229dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				spin_lock_irqsave(&mvi->lock, flags);
9239dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				spin_lock_irqsave(dev->sata_dev.ap->lock,
9249dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas						  flags_libsas);
9259dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				if (n > 1)
9269dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas					t = list_entry(t->list.next,
9279dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas						       struct sas_task, list);
9289dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				continue;
929dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			} else {
930dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				struct task_status_struct *ts = &t->task_status;
931dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				ts->resp = SAS_TASK_UNDELIVERED;
932dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				ts->stat = SAS_PHY_DOWN;
933dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				t->task_done(t);
934dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				if (n > 1)
935dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					t = list_entry(t->list.next,
936dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							struct sas_task, list);
937dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				continue;
938dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
939dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
940dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
941dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (!sas_protocol_ata(t->task_proto)) {
942dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (t->num_scatter) {
94320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				n_elem = dma_map_sg(mvi->dev,
94420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						    t->scatter,
945dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						    t->num_scatter,
946dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						    t->data_dir);
947dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				if (!n_elem) {
948dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					rc = -ENOMEM;
949dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					goto err_out;
950dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				}
951dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
952dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else {
953dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			n_elem = t->num_scatter;
954dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
955dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
956dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = mvs_tag_alloc(mvi, &tag);
957dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (rc)
958dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			goto err_out;
959dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
960dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot = &mvi->slot_info[tag];
96120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
96220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
963dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		t->lldd_task = NULL;
964dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot->n_elem = n_elem;
96520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		slot->slot_tag = tag;
966dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
96720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
968dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tei.task = t;
969dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tei.hdr = &mvi->slot[tag];
970dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tei.tag = tag;
971dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		tei.n_elem = n_elem;
972dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		switch (t->task_proto) {
973dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_SMP:
974dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			rc = mvs_task_prep_smp(mvi, &tei);
975dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
976dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_SSP:
97720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf);
978dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
979dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_SATA:
980dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_STP:
981dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
982dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			rc = mvs_task_prep_ata(mvi, &tei);
983dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
984dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		default:
98520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			dev_printk(KERN_ERR, mvi->dev,
9869dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				   "unknown sas_task proto: 0x%x\n",
9879dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				   t->task_proto);
988dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			rc = -EINVAL;
989dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
990dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
991dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
99220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rc) {
99320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_dprintk("rc is %x\n", rc);
994dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			goto err_out_tag;
99520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
996dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot->task = t;
997dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		slot->port = tei.port;
998f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan		t->lldd_task = slot;
99920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		list_add_tail(&slot->entry, &tei.port->list);
1000dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* TODO: select normal or high priority */
1001dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		spin_lock(&t->task_state_lock);
1002dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		t->task_state_flags |= SAS_TASK_AT_INITIATOR;
1003dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		spin_unlock(&t->task_state_lock);
1004dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1005dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_hba_memory_dump(mvi, tag, t->task_proto);
10069dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvi_dev->running_req++;
1007dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		++pass;
1008dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
1009dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (n > 1)
1010dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			t = list_entry(t->list.next, struct sas_task, list);
10119dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (likely(pass))
10129dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) &
10139dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas						      (MVS_CHIP_SLOT_SZ - 1));
10149dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
1015dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	} while (--n);
1016dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	rc = 0;
1017dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	goto out_done;
1018dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1019dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_tag:
1020dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_free(mvi, tag);
1021dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out:
102220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
102320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
1024dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!sas_protocol_ata(t->task_proto))
1025dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (n_elem)
102620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			dma_unmap_sg(mvi->dev, t->scatter, n_elem,
1027dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				     t->data_dir);
1028dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikout_done:
10290b84b7094e87769120def1e703b8b4d037281038Andy Yan	spin_unlock_irqrestore(&mvi->lock, flags);
1030dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return rc;
1031dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1032dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
103320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_queue_command(struct sas_task *task, const int num,
103420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			gfp_t gfp_flags)
103520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
10360b84b7094e87769120def1e703b8b4d037281038Andy Yan	return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL);
103720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
103820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
1039dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
1040dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1041dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
1042dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_clear(mvi, slot_idx);
1043dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1044dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1045dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
1046dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			  struct mvs_slot_info *slot, u32 slot_idx)
1047dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
104820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!slot->task)
104920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
1050dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!sas_protocol_ata(task->task_proto))
1051dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (slot->n_elem)
105220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			dma_unmap_sg(mvi->dev, task->scatter,
1053dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				     slot->n_elem, task->data_dir);
1054dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1055dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	switch (task->task_proto) {
1056dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SMP:
105720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1,
1058dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     PCI_DMA_FROMDEVICE);
105920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1,
1060dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     PCI_DMA_TODEVICE);
1061dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1062dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1063dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA:
1064dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_STP:
1065dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SSP:
1066dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	default:
1067dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* do nothing */
1068dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1069dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
107020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	list_del_init(&slot->entry);
1071dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	task->lldd_task = NULL;
1072dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->task = NULL;
1073dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->port = NULL;
107420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	slot->slot_tag = 0xFFFFFFFF;
107520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_slot_free(mvi, slot_idx);
1076dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1077dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1078dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_update_wideport(struct mvs_info *mvi, int i)
1079dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1080dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
1081dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port = phy->port;
1082dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int j, no;
1083dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
108420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for_each_phy(port->wide_port_phymap, j, no) {
108520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (j & 1) {
108620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
108720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						PHYR_WIDE_PORT);
108820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
1089dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						port->wide_port_phymap);
1090dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else {
109120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
109220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						PHYR_WIDE_PORT);
109320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
109420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						0);
1095dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
109620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
1097dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1098dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1099dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
1100dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1101dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 tmp;
1102dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
110320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_port *port = phy->port;
1104dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
110520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, i);
1106dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
1107dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (!port)
1108dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->phy_attached = 1;
1109dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return tmp;
1110dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1111dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1112dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (port) {
1113dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (phy->phy_type & PORT_TYPE_SAS) {
1114dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			port->wide_port_phymap &= ~(1U << i);
1115dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (!port->wide_port_phymap)
1116dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				port->port_attached = 0;
1117dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_update_wideport(mvi, i);
1118dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else if (phy->phy_type & PORT_TYPE_SATA)
1119dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			port->port_attached = 0;
1120dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->port = NULL;
1121dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->phy_attached = 0;
1122dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
1123dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1124dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
1125dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1126dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1127dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
1128dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1129dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 *s = (u32 *) buf;
1130dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1131dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!s)
1132dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return NULL;
1133dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
113420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
113520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	s[3] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
1136dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
113720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
113820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	s[2] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
1139dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
114020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
114120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	s[1] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
1142dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
114320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
114420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	s[0] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
114520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
114620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* Workaround: take some ATAPI devices for ATA */
114720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
114820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10);
1149dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1150f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	return s;
1151dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1152dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1153dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_sig_fis_received(u32 irq_status)
1154dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1155dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return irq_status & PHYEV_SIG_FIS;
1156dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1157dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
115820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
1159dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1160dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
116120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_identify_frame *id;
1162b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
116320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	id = (struct sas_identify_frame *)phy->frame_rcvd;
1164b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1165dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (get_st) {
116620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, i);
1167dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->phy_status = mvs_is_phy_ready(mvi, i);
1168dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
11698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1170dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->phy_status) {
117120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int oob_done = 0;
117220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct asd_sas_phy *sas_phy = &mvi->phy[i].sas_phy;
1173b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
117420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		oob_done = MVS_CHIP_DISP->oob_done(mvi, i);
117520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
117620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->fix_phy_info(mvi, i, id);
117720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy->phy_type & PORT_TYPE_SATA) {
117820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
117920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (mvs_is_sig_fis_received(phy->irq_status)) {
118020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->phy_attached = 1;
118120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->att_dev_sas_addr =
118220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					i + mvi->id * mvi->chip->n_phy;
118320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				if (oob_done)
118420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					sas_phy->oob_mode = SATA_OOB_MODE;
118520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->frame_rcvd_size =
118620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    sizeof(struct dev_to_host_fis);
1187f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan				mvs_get_d2h_reg(mvi, i, id);
118820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			} else {
118920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				u32 tmp;
119020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				dev_printk(KERN_DEBUG, mvi->dev,
119120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					"Phy%d : No sig fis\n", i);
119220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, i);
119320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				MVS_CHIP_DISP->write_port_irq_mask(mvi, i,
119420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						tmp | PHYEV_SIG_FIS);
119520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->phy_attached = 0;
119620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->phy_type &= ~PORT_TYPE_SATA;
119720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				MVS_CHIP_DISP->phy_reset(mvi, i, 0);
119820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				goto out_done;
119920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
12009dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		}	else if (phy->phy_type & PORT_TYPE_SAS
120120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			|| phy->att_dev_info & PORT_SSP_INIT_MASK) {
120220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->phy_attached = 1;
1203dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->identify.device_type =
120420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->att_dev_info & PORT_DEV_TYPE_MASK;
1205b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1206dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (phy->identify.device_type == SAS_END_DEV)
1207dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				phy->identify.target_port_protocols =
1208dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							SAS_PROTOCOL_SSP;
1209dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			else if (phy->identify.device_type != NO_DEVICE)
1210dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				phy->identify.target_port_protocols =
1211dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							SAS_PROTOCOL_SMP;
121220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (oob_done)
1213dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				sas_phy->oob_mode = SAS_OOB_MODE;
1214dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->frame_rcvd_size =
1215dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			    sizeof(struct sas_identify_frame);
1216dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
121720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		memcpy(sas_phy->attached_sas_addr,
121820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			&phy->att_dev_sas_addr, SAS_ADDR_SIZE);
1219b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
122020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (MVS_CHIP_DISP->phy_work_around)
122120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->phy_work_around(mvi, i);
1222dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
122320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_dprintk("port %d attach dev info is %x\n",
122420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i + mvi->id * mvi->chip->n_phy, phy->att_dev_info);
122520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_dprintk("port %d attach sas addr is %llx\n",
122620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr);
12274e52fc0a0a2ec2158691efba3f149f6416481255Ke Weiout_done:
1228dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (get_st)
122920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->write_port_irq_stat(mvi, i, phy->irq_status);
1230b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1231b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
123220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
12338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1234dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct sas_ha_struct *sas_ha = sas_phy->ha;
123520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = NULL; int i = 0, hi;
1236dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = sas_phy->lldd_phy;
123720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_port *sas_port = sas_phy->port;
123820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_port *port;
123920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags = 0;
124020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!sas_port)
124120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
12428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
124320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (sas_ha->sas_phy[i]) {
124420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sas_ha->sas_phy[i] == sas_phy)
124520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
124620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i++;
124720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
124820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy;
124920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi];
125020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (sas_port->id >= mvi->chip->n_phy)
125120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		port = &mvi->port[sas_port->id - mvi->chip->n_phy];
125220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	else
125320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		port = &mvi->port[sas_port->id];
125420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (lock)
125520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_lock_irqsave(&mvi->lock, flags);
1256dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	port->port_attached = 1;
1257dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	phy->port = port;
1258dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->phy_type & PORT_TYPE_SAS) {
1259dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		port->wide_port_phymap = sas_port->phy_mask;
126020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("set wide port phy map %x\n", sas_port->phy_mask);
1261dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_update_wideport(mvi, sas_phy->id);
12628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
126320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (lock)
126420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_unlock_irqrestore(&mvi->lock, flags);
1265dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1266dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
126720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
1268dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
12699dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct domain_device *dev;
12709dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct mvs_phy *phy = sas_phy->lldd_phy;
12719dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct mvs_info *mvi = phy->mvi;
12729dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct asd_sas_port *port = sas_phy->port;
12739dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	int phy_no = 0;
12749dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
12759dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	while (phy != &mvi->phy[phy_no]) {
12769dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		phy_no++;
12779dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (phy_no >= MVS_MAX_PHYS)
12789dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			return;
12799dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	}
12809dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	list_for_each_entry(dev, &port->dev_list, dev_list_node)
12819dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvs_do_release_task(phy->mvi, phy_no, NULL);
12829dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
1283dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1284dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1285dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
128620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_port_formed(struct asd_sas_phy *sas_phy)
128720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
128820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_port_notify_formed(sas_phy, 1);
1289dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1290dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
129120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_port_deformed(struct asd_sas_phy *sas_phy)
1292dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
129320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_port_notify_deformed(sas_phy, 1);
129420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
12958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
129620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstruct mvs_device *mvs_alloc_dev(struct mvs_info *mvi)
129720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
129820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 dev;
129920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (dev = 0; dev < MVS_MAX_DEVICES; dev++) {
130020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (mvi->devices[dev].dev_type == NO_DEVICE) {
130120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvi->devices[dev].device_id = dev;
130220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			return &mvi->devices[dev];
130320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
13048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
13058121ed420285885654af133a6ca1919590f98917Ke Wei
130620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (dev == MVS_MAX_DEVICES)
130720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("max support %d devices, ignore ..\n",
130820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_MAX_DEVICES);
130920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
131020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return NULL;
13118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
13128f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
131320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_free_dev(struct mvs_device *mvi_dev)
1314b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
131520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 id = mvi_dev->device_id;
131620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memset(mvi_dev, 0, sizeof(*mvi_dev));
131720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->device_id = id;
131820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->dev_type = NO_DEVICE;
131920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->dev_status = MVS_DEV_NORMAL;
132020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->taskfileset = MVS_ID_NOT_MAPPED;
132120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
132320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_dev_found_notify(struct domain_device *dev, int lock)
132420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
132520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags = 0;
132620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int res = 0;
132720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = NULL;
132820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct domain_device *parent_dev = dev->parent;
132920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_device *mvi_device;
1330b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
133120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi = mvs_find_dev_mvi(dev);
1332b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
133320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (lock)
133420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_lock_irqsave(&mvi->lock, flags);
133520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
133620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_device = mvs_alloc_dev(mvi);
133720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!mvi_device) {
133820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		res = -1;
133920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		goto found_out;
1340b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1341f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	dev->lldd_dev = mvi_device;
13429dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvi_device->dev_status = MVS_DEV_NORMAL;
134320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_device->dev_type = dev->dev_type;
13449870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	mvi_device->mvi_info = mvi;
134520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
134620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int phy_id;
134720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		u8 phy_num = parent_dev->ex_dev.num_phys;
134820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct ex_phy *phy;
134920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		for (phy_id = 0; phy_id < phy_num; phy_id++) {
135020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy = &parent_dev->ex_dev.ex_phy[phy_id];
135120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (SAS_ADDR(phy->attached_sas_addr) ==
135220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				SAS_ADDR(dev->sas_addr)) {
135320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvi_device->attached_phy = phy_id;
135420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				break;
135520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
135620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1357b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
135820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy_id == phy_num) {
135920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_printk("Error: no attached dev:%016llx"
136020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				"at ex:%016llx.\n",
136120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				SAS_ADDR(dev->sas_addr),
136220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				SAS_ADDR(parent_dev->sas_addr));
136320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			res = -1;
136420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1365dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
136720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanfound_out:
136820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (lock)
136920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_unlock_irqrestore(&mvi->lock, flags);
137020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return res;
137120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1372b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
137320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_dev_found(struct domain_device *dev)
137420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
137520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return mvs_dev_found_notify(dev, 1);
137620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13789dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivasvoid mvs_dev_gone_notify(struct domain_device *dev)
137920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
138020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags = 0;
1381f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device *mvi_dev = dev->lldd_dev;
13829870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_info *mvi = mvi_dev->mvi_info;
1383b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13849dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	spin_lock_irqsave(&mvi->lock, flags);
1385b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
138620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi_dev) {
138720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("found dev[%d:%x] is gone.\n",
138820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvi_dev->device_id, mvi_dev->dev_type);
13899dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvs_release_task(mvi, dev);
139020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_free_reg_set(mvi, mvi_dev);
139120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_free_dev(mvi_dev);
139220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else {
139320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("found dev has gone.\n");
1394b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
139520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev->lldd_dev = NULL;
1396b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13979dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	spin_unlock_irqrestore(&mvi->lock, flags);
1398b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1399b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1400b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
140120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_dev_gone(struct domain_device *dev)
140220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
14039dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvs_dev_gone_notify(dev);
140420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1405b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
140620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic  struct sas_task *mvs_alloc_task(void)
140720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
140820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_task *task = kzalloc(sizeof(struct sas_task), GFP_KERNEL);
140920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
141020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task) {
141120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		INIT_LIST_HEAD(&task->list);
141220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_lock_init(&task->task_state_lock);
141320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->task_state_flags = SAS_TASK_STATE_PENDING;
141420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		init_timer(&task->timer);
141520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		init_completion(&task->completion);
1416b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
141720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return task;
1418dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1419b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
142020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic  void mvs_free_task(struct sas_task *task)
1421dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
142220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task) {
142320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		BUG_ON(!list_empty(&task->list));
142420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		kfree(task);
1425b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
142620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1427b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
142820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_task_done(struct sas_task *task)
142920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
143020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!del_timer(&task->timer))
143120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
143220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	complete(&task->completion);
1433b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1434b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
143520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_tmf_timedout(unsigned long data)
1436b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
143720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_task *task = (struct sas_task *)data;
14388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
143920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
144020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	complete(&task->completion);
144120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
14428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
144320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* XXX */
144420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#define MVS_TASK_TIMEOUT 20
144520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_exec_internal_tmf_task(struct domain_device *dev,
144620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			void *parameter, u32 para_len, struct mvs_tmf_task *tmf)
144720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
144820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int res, retry;
144920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_task *task = NULL;
14508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
145120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (retry = 0; retry < 3; retry++) {
145220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task = mvs_alloc_task();
145320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (!task)
145420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			return -ENOMEM;
14558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
145620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->dev = dev;
145720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->task_proto = dev->tproto;
14588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
145920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		memcpy(&task->ssp_task, parameter, para_len);
146020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->task_done = mvs_task_done;
14618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
146220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->timer.data = (unsigned long) task;
146320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->timer.function = mvs_tmf_timedout;
146420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
146520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		add_timer(&task->timer);
14668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14670b84b7094e87769120def1e703b8b4d037281038Andy Yan		res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf);
14688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
146920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (res) {
147020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			del_timer(&task->timer);
147120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_printk("executing internel task failed:%d\n", res);
147220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			goto ex_err;
147320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
14748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
147520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		wait_for_completion(&task->completion);
147620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		res = -TMF_RESP_FUNC_FAILED;
147720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* Even TMF timed out, return direct. */
147820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
147920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
148020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_printk("TMF task[%x] timeout.\n", tmf->tmf);
148120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				goto ex_err;
148220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
148320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
14848f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
148520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (task->task_status.resp == SAS_TASK_COMPLETE &&
1486df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley		    task->task_status.stat == SAM_STAT_GOOD) {
148720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			res = TMF_RESP_FUNC_COMPLETE;
148820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
148920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1490b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
149120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (task->task_status.resp == SAS_TASK_COMPLETE &&
149220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		      task->task_status.stat == SAS_DATA_UNDERRUN) {
149320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			/* no error, but return the number of bytes of
149420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			 * underrun */
149520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			res = task->task_status.residual;
149620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
149720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1498b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
149920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (task->task_status.resp == SAS_TASK_COMPLETE &&
150020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		      task->task_status.stat == SAS_DATA_OVERRUN) {
150120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_dprintk("blocked task error.\n");
150220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			res = -EMSGSIZE;
150320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
150420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else {
150520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_dprintk(" task to dev %016llx response: 0x%x "
150620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    "status 0x%x\n",
150720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    SAS_ADDR(dev->sas_addr),
150820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    task->task_status.resp,
150920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    task->task_status.stat);
151020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_free_task(task);
151120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			task = NULL;
1512b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1513dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1514dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
151520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanex_err:
151620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	BUG_ON(retry == 3 && task != NULL);
151720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task != NULL)
151820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_free_task(task);
151920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return res;
1520dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1521b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
152220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_debug_issue_ssp_tmf(struct domain_device *dev,
152320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				u8 *lun, struct mvs_tmf_task *tmf)
1524dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
152520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ssp_task ssp_task;
152620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	DECLARE_COMPLETION_ONSTACK(completion);
152720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!(dev->tproto & SAS_PROTOCOL_SSP))
152820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return TMF_RESP_FUNC_ESUPP;
1529b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
153020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	strncpy((u8 *)&ssp_task.LUN, lun, 8);
1531b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
153220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return mvs_exec_internal_tmf_task(dev, &ssp_task,
153320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				sizeof(ssp_task), tmf);
153420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
15358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
15368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
153720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/*  Standard mandates link reset for ATA  (type 0)
153820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan    and hard reset for SSP (type 1) , only for RECOVERY */
153920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
154020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
154120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc;
154220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_phy *phy = sas_find_local_phy(dev);
154320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int reset_type = (dev->dev_type == SATA_DEV ||
154420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			(dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
154520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = sas_phy_reset(phy, reset_type);
154620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	msleep(2000);
154720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
154820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
15498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
155020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* mandatory SAM-3 */
155120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_lu_reset(struct domain_device *dev, u8 *lun)
155220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
155320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags;
155420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
155520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
1556f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device * mvi_dev = dev->lldd_dev;
15579870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_info *mvi = mvi_dev->mvi_info;
155820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
155920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmf_task.tmf = TMF_LU_RESET;
156020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->dev_status = MVS_DEV_EH;
156120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
156220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (rc == TMF_RESP_FUNC_COMPLETE) {
156320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		num = mvs_find_dev_phyno(dev, phyno);
156420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_lock_irqsave(&mvi->lock, flags);
156520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		for (i = 0; i < num; i++)
15669dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mvs_release_task(mvi, dev);
156720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_unlock_irqrestore(&mvi->lock, flags);
1568dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
156920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* If failed, fall-through I_T_Nexus reset */
157020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_printk("%s for device[%x]:rc= %d\n", __func__,
157120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvi_dev->device_id, rc);
157220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
157320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
15748f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
157520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_I_T_nexus_reset(struct domain_device *dev)
157620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
157720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags;
15789dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	int rc = TMF_RESP_FUNC_FAILED;
15799dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas    struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;
15809870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_info *mvi = mvi_dev->mvi_info;
158120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
158220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi_dev->dev_status != MVS_DEV_EH)
158320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return TMF_RESP_FUNC_COMPLETE;
158420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_I_T_nexus_reset(dev);
158520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_printk("%s for device[%x]:rc= %d\n",
158620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		__func__, mvi_dev->device_id, rc);
158720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
158820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* housekeeper */
158920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock_irqsave(&mvi->lock, flags);
15909dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvs_release_task(mvi, dev);
159120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock_irqrestore(&mvi->lock, flags);
159220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
159320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
159420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
159520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* optional SAM-3 */
159620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_query_task(struct sas_task *task)
159720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
159820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tag;
159920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct scsi_lun lun;
160020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
160120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
160220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
160320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
160420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
160520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct domain_device *dev = task->dev;
16069870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan		struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
16079870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan		struct mvs_info *mvi = mvi_dev->mvi_info;
160820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
160920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int_to_scsilun(cmnd->device->lun, &lun);
161020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = mvs_find_tag(mvi, task, &tag);
161120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rc == 0) {
161220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			rc = TMF_RESP_FUNC_FAILED;
1613dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			return rc;
161420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
16158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
161620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmf_task.tmf = TMF_QUERY_TASK;
161720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
16188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
161920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
162020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		switch (rc) {
162120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* The task is still in Lun, release it then */
162220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_RESP_FUNC_SUCC:
162320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* The task is not in Lun or failed, reset the phy */
162420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_RESP_FUNC_FAILED:
162520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_RESP_FUNC_COMPLETE:
162620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
16279dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		default:
16289dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			rc = TMF_RESP_FUNC_COMPLETE;
16299dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			break;
163020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1631dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
163220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_printk("%s:rc= %d\n", __func__, rc);
163320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
16348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
16358f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
163620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/*  mandatory SAM-3, still need free task/slot info */
163720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_abort_task(struct sas_task *task)
16388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
163920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct scsi_lun lun;
164020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
164120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct domain_device *dev = task->dev;
16429870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
164324ae163ed33d2b8a70d2f0b1947b401d0a8e8719Jiri Slaby	struct mvs_info *mvi;
164420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
164520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags;
164620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tag;
16479870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan
16489dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (!mvi_dev) {
16499dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mv_printk("%s:%d TMF_RESP_FUNC_FAILED\n", __func__, __LINE__);
16509dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		rc = TMF_RESP_FUNC_FAILED;
16519dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	}
16529dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
165324ae163ed33d2b8a70d2f0b1947b401d0a8e8719Jiri Slaby	mvi = mvi_dev->mvi_info;
165424ae163ed33d2b8a70d2f0b1947b401d0a8e8719Jiri Slaby
165520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock_irqsave(&task->task_state_lock, flags);
165620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
165720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_unlock_irqrestore(&task->task_state_lock, flags);
165820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = TMF_RESP_FUNC_COMPLETE;
165920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		goto out;
1660dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
166120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock_irqrestore(&task->task_state_lock, flags);
16629dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvi_dev->dev_status = MVS_DEV_EH;
166320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
166420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
166520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
166620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int_to_scsilun(cmnd->device->lun, &lun);
166720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = mvs_find_tag(mvi, task, &tag);
166820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rc == 0) {
166920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_printk("No such tag in %s\n", __func__);
167020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			rc = TMF_RESP_FUNC_FAILED;
167120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			return rc;
167220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
16738f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
167420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmf_task.tmf = TMF_ABORT_TASK;
167520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
16768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
167720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
16788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
167920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* if successful, clear the task and callback forwards.*/
168020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rc == TMF_RESP_FUNC_COMPLETE) {
168120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			u32 slot_no;
168220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct mvs_slot_info *slot;
16838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
168420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (task->lldd_task) {
1685f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan				slot = task->lldd_task;
168620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				slot_no = (u32) (slot - mvi->slot_info);
16879dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				spin_lock_irqsave(&mvi->lock, flags);
168820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_slot_complete(mvi, slot_no, 1);
16899dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				spin_unlock_irqrestore(&mvi->lock, flags);
169020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
169120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
16929dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
169320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else if (task->task_proto & SAS_PROTOCOL_SATA ||
169420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->task_proto & SAS_PROTOCOL_STP) {
169520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* to do free register_set */
16969dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (SATA_DEV == dev->dev_type) {
16979dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			struct mvs_slot_info *slot = task->lldd_task;
16989dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			struct task_status_struct *tstat;
16999dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			u32 slot_idx = (u32)(slot - mvi->slot_info);
17009dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			tstat = &task->task_status;
17019dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mv_dprintk(KERN_DEBUG "mv_abort_task() mvi=%p task=%p "
17029dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				   "slot=%p slot_idx=x%x\n",
17039dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				   mvi, task, slot, slot_idx);
17049dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			tstat->stat = SAS_ABORTED_TASK;
17059dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			if (mvi_dev && mvi_dev->running_req)
17069dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				mvi_dev->running_req--;
17079dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			if (sas_protocol_ata(task->task_proto))
17089dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				mvs_free_reg_set(mvi, mvi_dev);
17099dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mvs_slot_task_free(mvi, task, slot, slot_idx);
17109dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			return -1;
17119dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		}
171220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else {
171320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* SMP */
17148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
171520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
171620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanout:
171720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (rc != TMF_RESP_FUNC_COMPLETE)
171820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("%s:rc= %d\n", __func__, rc);
1719dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return rc;
17208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
17218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
172220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_abort_task_set(struct domain_device *dev, u8 *lun)
17238f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
172420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
172520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
17268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
172720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmf_task.tmf = TMF_ABORT_TASK_SET;
172820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
1729dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
173020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
17318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
17328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
173320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_clear_aca(struct domain_device *dev, u8 *lun)
17348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
173520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
173620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
17378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
173820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmf_task.tmf = TMF_CLEAR_ACA;
173920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
17408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
174120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
174220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
17438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
174420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_clear_task_set(struct domain_device *dev, u8 *lun)
174520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
174620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
174720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
17488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
174920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmf_task.tmf = TMF_CLEAR_TASK_SET;
175020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
17518f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
175220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
1753dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
17548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
175520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
175620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			u32 slot_idx, int err)
1757dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1758f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device *mvi_dev = task->dev->lldd_dev;
175920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct task_status_struct *tstat = &task->task_status;
176020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
1761df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley	int stat = SAM_STAT_GOOD;
1762e9ff91b6927079307b5d481a93beac4134e923ebKe Wei
17638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
176420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	resp->frame_len = sizeof(struct dev_to_host_fis);
176520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(&resp->ending_fis[0],
176620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	       SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset),
176720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	       sizeof(struct dev_to_host_fis));
176820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tstat->buf_valid_size = sizeof(*resp);
17699dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (unlikely(err)) {
17709dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (unlikely(err & CMD_ISS_STPD))
17719dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			stat = SAS_OPEN_REJECT;
17729dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		else
17739dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			stat = SAS_PROTO_RESPONSE;
17749dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas       }
17759dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
177620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return stat;
17778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
17788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
177920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
178020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			 u32 slot_idx)
17818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
178220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
178320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int stat;
178420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
178520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tfs = 0;
178620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	enum mvs_port_type type = PORT_TYPE_SAS;
17878f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
178820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (err_dw0 & CMD_ISS_STPD)
178920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->issue_stop(mvi, type, tfs);
179020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
179120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->command_active(mvi, slot_idx);
1792b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1793df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley	stat = SAM_STAT_CHECK_CONDITION;
1794dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	switch (task->task_proto) {
1795dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SSP:
179620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		stat = SAS_ABORTED_TASK;
179720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
179820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SMP:
1799df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley		stat = SAM_STAT_CHECK_CONDITION;
1800dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
180120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
1802dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA:
1803dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_STP:
180420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
180520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	{
180620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (err_dw0 == 0x80400002)
180720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_printk("find reserved error, why?\n");
180820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
180920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->ata_task.use_ncq = 0;
18109dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvs_sata_done(mvi, task, slot_idx, err_dw0);
1811dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
181220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
1813dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	default:
1814dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1815dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1816dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
181720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return stat;
1818e9ff91b6927079307b5d481a93beac4134e923ebKe Wei}
1819e9ff91b6927079307b5d481a93beac4134e923ebKe Wei
182020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
1821b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
182220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
182320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
182420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_task *task = slot->task;
182520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_device *mvi_dev = NULL;
182620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct task_status_struct *tstat;
18279dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct domain_device *dev;
18289dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	u32 aborted;
182920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
183020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	void *to;
183120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	enum exec_status sts;
183220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
183320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->exp_req)
183420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvi->exp_req--;
18359dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (unlikely(!task || !task->lldd_task || !task->dev))
183620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return -1;
183720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
183820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tstat = &task->task_status;
18399dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	dev = task->dev;
18409dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvi_dev = dev->lldd_dev;
1841b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
184220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_hba_cq_dump(mvi);
184320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
184420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock(&task->task_state_lock);
184520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	task->task_state_flags &=
184620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
184720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	task->task_state_flags |= SAS_TASK_STATE_DONE;
184820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* race condition*/
184920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
185020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock(&task->task_state_lock);
185120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
185220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memset(tstat, 0, sizeof(*tstat));
185320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tstat->resp = SAS_TASK_COMPLETE;
185420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
185520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (unlikely(aborted)) {
185620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tstat->stat = SAS_ABORTED_TASK;
18579dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (mvi_dev && mvi_dev->running_req)
18589dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mvi_dev->running_req--;
185920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sas_protocol_ata(task->task_proto))
186020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_free_reg_set(mvi, mvi_dev);
186120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
186220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_slot_task_free(mvi, task, slot, slot_idx);
186320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return -1;
1864b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1865b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
18669dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (unlikely(!mvi_dev || flags)) {
18679dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (!mvi_dev)
18689dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mv_dprintk("port has not device.\n");
186920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tstat->stat = SAS_PHY_DOWN;
187020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		goto out;
187120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
1872b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
187320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* error info record present */
187420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
187520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tstat->stat = mvs_slot_err(mvi, task, slot_idx);
18769dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		tstat->resp = SAS_TASK_COMPLETE;
187720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		goto out;
1878b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1879b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
188020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	switch (task->task_proto) {
188120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SSP:
188220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* hw says status == 0, datapres == 0 */
188320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rx_desc & RXQ_GOOD) {
1884df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley			tstat->stat = SAM_STAT_GOOD;
188520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			tstat->resp = SAS_TASK_COMPLETE;
188620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
188720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* response frame present */
188820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		else if (rx_desc & RXQ_RSP) {
188920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct ssp_response_iu *iu = slot->response +
189020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						sizeof(struct mvs_err_info);
189120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			sas_ssp_task_response(mvi->dev, task, iu);
189220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else
1893df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley			tstat->stat = SAM_STAT_CHECK_CONDITION;
189420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
1895b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
189620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SMP: {
189720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct scatterlist *sg_resp = &task->smp_task.smp_resp;
1898df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley			tstat->stat = SAM_STAT_GOOD;
189920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
190020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			memcpy(to + sg_resp->offset,
190120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				slot->response + sizeof(struct mvs_err_info),
190220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				sg_dma_len(sg_resp));
190320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			kunmap_atomic(to, KM_IRQ0);
190420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
190520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
19068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
190720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SATA:
190820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_STP:
190920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
191020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
191120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
191220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1913b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
191420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	default:
1915df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley		tstat->stat = SAM_STAT_CHECK_CONDITION;
191620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
191720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
19189dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (!slot->port->port_attached) {
19199dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mv_dprintk("port %d has removed.\n", slot->port->sas_port.id);
19209dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		tstat->stat = SAS_PHY_DOWN;
19219dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	}
19229dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
1923b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
192420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanout:
19259dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (mvi_dev && mvi_dev->running_req) {
19269dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvi_dev->running_req--;
19279dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (sas_protocol_ata(task->task_proto) && !mvi_dev->running_req)
19280f980a871678b7ec143fcb45b31bf9234e4585c8Andy Yan			mvs_free_reg_set(mvi, mvi_dev);
19290f980a871678b7ec143fcb45b31bf9234e4585c8Andy Yan	}
193020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_slot_task_free(mvi, task, slot, slot_idx);
193120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	sts = tstat->stat;
19328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
193320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock(&mvi->lock);
193420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->task_done)
193520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->task_done(task);
193620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	else
193720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("why has not task_done.\n");
193820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock(&mvi->lock);
1939b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
194020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return sts;
194120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1942b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19439dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivasvoid mvs_do_release_task(struct mvs_info *mvi,
194420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int phy_no, struct domain_device *dev)
194520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
19469dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	u32 slot_idx;
194720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_phy *phy;
194820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_port *port;
194920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_slot_info *slot, *slot2;
1950b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
195120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy = &mvi->phy[phy_no];
195220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	port = phy->port;
195320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!port)
195420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
19559dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	/* clean cmpl queue in case request is already finished */
19569dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvs_int_rx(mvi, false);
19579dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
19589dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
1959b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
196020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	list_for_each_entry_safe(slot, slot2, &port->list, entry) {
196120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct sas_task *task;
196220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		slot_idx = (u32) (slot - mvi->slot_info);
196320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task = slot->task;
1964b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
196520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (dev && task->dev != dev)
196620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			continue;
19678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
196820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("Release slot [%x] tag[%x], task [%p]:\n",
196920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			slot_idx, slot->slot_tag, task);
19709dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		MVS_CHIP_DISP->command_active(mvi, slot_idx);
1971b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
197220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_slot_complete(mvi, slot_idx, 1);
1973b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
197420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1975b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19769dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivasvoid mvs_release_task(struct mvs_info *mvi,
19779dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		      struct domain_device *dev)
19789dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas{
19799dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	int i, phyno[WIDE_PORT_MAX_PHY], num;
19809dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	/* housekeeper */
19819dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	num = mvs_find_dev_phyno(dev, phyno);
19829dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	for (i = 0; i < num; i++)
19839dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvs_do_release_task(mvi, phyno[i], dev);
19849dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas}
19859dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
198620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_phy_disconnected(struct mvs_phy *phy)
198720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
198820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy->phy_attached = 0;
198920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy->att_dev_info = 0;
199020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy->att_dev_sas_addr = 0;
199120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
199220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
199320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_work_queue(struct work_struct *work)
199420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
199520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct delayed_work *dw = container_of(work, struct delayed_work, work);
199620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q);
199720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = mwq->mvi;
199820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags;
1999b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
200020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock_irqsave(&mvi->lock, flags);
200120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mwq->handler & PHY_PLUG_EVENT) {
200220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		u32 phy_no = (unsigned long) mwq->data;
200320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct sas_ha_struct *sas_ha = mvi->sas;
200420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct mvs_phy *phy = &mvi->phy[phy_no];
200520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct asd_sas_phy *sas_phy = &phy->sas_phy;
200620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
200720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy->phy_event & PHY_PLUG_OUT) {
200820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			u32 tmp;
200920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct sas_identify_frame *id;
201020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			id = (struct sas_identify_frame *)phy->frame_rcvd;
201120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no);
201220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->phy_event &= ~PHY_PLUG_OUT;
201320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (!(tmp & PHY_READY_MASK)) {
201420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				sas_phy_disconnected(sas_phy);
201520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_phy_disconnected(phy);
201620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				sas_ha->notify_phy_event(sas_phy,
201720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					PHYE_LOSS_OF_SIGNAL);
201820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_dprintk("phy%d Removed Device\n", phy_no);
201920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			} else {
202020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
202120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_update_phyinfo(mvi, phy_no, 1);
202220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_bytes_dmaed(mvi, phy_no);
202320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_port_notify_formed(sas_phy, 0);
202420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_dprintk("phy%d Attached Device\n", phy_no);
202520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
202620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
202720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
202820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	list_del(&mwq->entry);
202920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock_irqrestore(&mvi->lock, flags);
203020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	kfree(mwq);
203120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
20328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
203320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_handle_event(struct mvs_info *mvi, void *data, int handler)
203420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
203520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_wq *mwq;
203620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int ret = 0;
203720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
203820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC);
203920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mwq) {
204020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mwq->mvi = mvi;
204120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mwq->data = data;
204220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mwq->handler = handler;
204320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq);
204420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		list_add_tail(&mwq->entry, &mvi->wq_list);
204520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		schedule_delayed_work(&mwq->work_q, HZ * 2);
204620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else
204720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		ret = -ENOMEM;
204820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
204920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return ret;
205020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
2051b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
205220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_sig_time_out(unsigned long tphy)
205320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
205420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_phy *phy = (struct mvs_phy *)tphy;
205520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = phy->mvi;
205620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u8 phy_no;
205720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
205820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (phy_no = 0; phy_no < mvi->chip->n_phy; phy_no++) {
205920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (&mvi->phy[phy_no] == phy) {
206020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_dprintk("Get signature time out, reset phy %d\n",
206120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy_no+mvi->id*mvi->chip->n_phy);
206220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->phy_reset(mvi, phy_no, 1);
206320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
2064b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
206520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
2066b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
206720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_sig_remove_timer(struct mvs_phy *phy)
206820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
206920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (phy->timer.function)
207020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		del_timer(&phy->timer);
207120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy->timer.function = NULL;
207220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
2073b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
207420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
207520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
207620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tmp;
207720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sas_ha = mvi->sas;
207820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_phy *phy = &mvi->phy[phy_no];
207920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_phy *sas_phy = &phy->sas_phy;
20808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
208120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
208220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy,
208320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no));
208420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_dprintk("Port %d irq sts = 0x%X\n", phy_no+mvi->id*mvi->chip->n_phy,
208520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		phy->irq_status);
20868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
208720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/*
208820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	* events is port event now ,
208920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	* we need check the interrupt status which belongs to per port.
209020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	*/
2091b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
20929dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (phy->irq_status & PHYEV_DCDR_ERR) {
209320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("port %d STP decoding error.\n",
20949dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		phy_no + mvi->id*mvi->chip->n_phy);
20959dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	}
209620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
209720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (phy->irq_status & PHYEV_POOF) {
209820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (!(phy->phy_event & PHY_PLUG_OUT)) {
209920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			int dev_sata = phy->phy_type & PORT_TYPE_SATA;
210020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			int ready;
21019dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mvs_do_release_task(mvi, phy_no, NULL);
210220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->phy_event |= PHY_PLUG_OUT;
21039dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			MVS_CHIP_DISP->clear_srs_irq(mvi, 0, 1);
210420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_handle_event(mvi,
210520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				(void *)(unsigned long)phy_no,
210620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				PHY_PLUG_EVENT);
210720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			ready = mvs_is_phy_ready(mvi, phy_no);
210820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (!ready)
210920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_dprintk("phy%d Unplug Notice\n",
211020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					phy_no +
211120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					mvi->id * mvi->chip->n_phy);
211220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (ready || dev_sata) {
211320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				if (MVS_CHIP_DISP->stp_reset)
211420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					MVS_CHIP_DISP->stp_reset(mvi,
211520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan							phy_no);
211620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				else
211720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					MVS_CHIP_DISP->phy_reset(mvi,
211820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan							phy_no, 0);
211920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				return;
212020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
212120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
212220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
2123b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
212420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (phy->irq_status & PHYEV_COMWAKE) {
212520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, phy_no);
212620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no,
212720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					tmp | PHYEV_SIG_FIS);
212820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy->timer.function == NULL) {
212920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->timer.data = (unsigned long)phy;
213020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->timer.function = mvs_sig_time_out;
213120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->timer.expires = jiffies + 10*HZ;
213220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			add_timer(&phy->timer);
213320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
213420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
213520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
213620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
213720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_sig_remove_timer(phy);
213820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("notify plug in on phy[%d]\n", phy_no);
213920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy->phy_status) {
214020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mdelay(10);
214120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
214220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (phy->phy_type & PORT_TYPE_SATA) {
214320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				tmp = MVS_CHIP_DISP->read_port_irq_mask(
214420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						mvi, phy_no);
214520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				tmp &= ~PHYEV_SIG_FIS;
214620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				MVS_CHIP_DISP->write_port_irq_mask(mvi,
214720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan							phy_no, tmp);
214820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
214920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_update_phyinfo(mvi, phy_no, 0);
21509dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			if (phy->phy_type & PORT_TYPE_SAS) {
21519dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				MVS_CHIP_DISP->phy_reset(mvi, phy_no, 2);
21529dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				mdelay(10);
21539dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			}
21549dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
215520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_bytes_dmaed(mvi, phy_no);
215620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			/* whether driver is going to handle hot plug */
215720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (phy->phy_event & PHY_PLUG_OUT) {
215820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_port_notify_formed(sas_phy, 0);
215920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->phy_event &= ~PHY_PLUG_OUT;
216020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
216120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else {
216220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_dprintk("plugin interrupt but phy%d is gone\n",
216320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy_no + mvi->id*mvi->chip->n_phy);
216420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
216520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else if (phy->irq_status & PHYEV_BROAD_CH) {
216620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("port %d broadcast change.\n",
216720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy_no + mvi->id*mvi->chip->n_phy);
216820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* exception for Samsung disk drive*/
216920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mdelay(1000);
217020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
217120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
217220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
2173b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2174b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
217520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_int_rx(struct mvs_info *mvi, bool self_clear)
2176b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
217720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 rx_prod_idx, rx_desc;
217820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	bool attn = false;
2179b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
218020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* the first dword in the RX ring is special: it contains
218120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	 * a mirror of the hardware's RX producer index, so that
218220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	 * we don't have to stall the CPU reading that register.
218320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	 * The actual RX ring is offset by one dword, due to this.
218420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	 */
218520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rx_prod_idx = mvi->rx_cons;
218620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
218720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->rx_cons == 0xfff)	/* h/w hasn't touched RX ring yet */
218820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return 0;
2189b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
219020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* The CMPL_Q may come late, read from register and try again
219120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	* note: if coalescing is enabled,
219220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	* it will need to read from register every time for sure
219320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	*/
219420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (unlikely(mvi->rx_cons == rx_prod_idx))
219520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvi->rx_cons = MVS_CHIP_DISP->rx_update(mvi) & RX_RING_SZ_MASK;
219620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
219720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->rx_cons == rx_prod_idx)
219820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return 0;
219920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
220020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (mvi->rx_cons != rx_prod_idx) {
220120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* increment our internal RX consumer pointer */
220220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
220320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
220420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
220520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (likely(rx_desc & RXQ_DONE))
220620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_slot_complete(mvi, rx_desc, 0);
220720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rx_desc & RXQ_ATTN) {
220820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			attn = true;
220920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else if (rx_desc & RXQ_ERR) {
221020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (!(rx_desc & RXQ_DONE))
221120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_slot_complete(mvi, rx_desc, 0);
221220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else if (rx_desc & RXQ_SLOT_RESET) {
221320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_slot_free(mvi, rx_desc);
221420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
221520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
221620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
221720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (attn && self_clear)
221820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->int_full(mvi);
221920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return 0;
2220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2222