mv_sas.c revision b1124cd3ec97406c767b90bf7e93ecd2d2915592
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>
60b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *
820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * This file is licensed under GPLv2.
920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *
1020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * This program is free software; you can redistribute it and/or
1120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * modify it under the terms of the GNU General Public License as
1220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * published by the Free Software Foundation; version 2 of the
1320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * License.
1420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *
1520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * This program is distributed in the hope that it will be useful,
1620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * but WITHOUT ANY WARRANTY; without even the implied warranty of
1720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * General Public License for more details.
1920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *
2020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * You should have received a copy of the GNU General Public License
2120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * along with this program; if not, write to the Free Software
2220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
2320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * USA
2420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan*/
25b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
26dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#include "mv_sas.h"
27b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
28dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
29dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
30dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (task->lldd_task) {
31dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct mvs_slot_info *slot;
32f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan		slot = task->lldd_task;
3320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		*tag = slot->slot_tag;
34dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return 1;
35dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
36dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
37dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
3920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_tag_clear(struct mvs_info *mvi, u32 tag)
40dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
41b89e8f539ff8bcf2a1464578fa91cb96cc433fc3Xiangliang Yu	void *bitmap = mvi->tags;
42dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	clear_bit(tag, bitmap);
43dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
4520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_tag_free(struct mvs_info *mvi, u32 tag)
46dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
47dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_clear(mvi, tag);
48dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
5020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
51dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
52b89e8f539ff8bcf2a1464578fa91cb96cc433fc3Xiangliang Yu	void *bitmap = mvi->tags;
53dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	set_bit(tag, bitmap);
54dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
5620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yaninline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
57dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
58dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	unsigned int index, tag;
59b89e8f539ff8bcf2a1464578fa91cb96cc433fc3Xiangliang Yu	void *bitmap = mvi->tags;
60b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	index = find_first_zero_bit(bitmap, mvi->tags_num);
62dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	tag = index;
6320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (tag >= mvi->tags_num)
64dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -SAS_QUEUE_FULL;
65dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_set(mvi, tag);
66dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	*tag_out = tag;
67dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
68dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
69b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
70dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_tag_init(struct mvs_info *mvi)
71dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
72dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int i;
7320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (i = 0; i < mvi->tags_num; ++i)
74dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_tag_clear(mvi, i);
75dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
76b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
7720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstruct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
7820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
7920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long i = 0, j = 0, hi = 0;
8020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sha = dev->port->ha;
8120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = NULL;
8220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_phy *phy;
8320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
8420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (sha->sas_port[i]) {
8520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sha->sas_port[i] == dev->port) {
8620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy =  container_of(sha->sas_port[i]->phy_list.next,
8720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				struct asd_sas_phy, port_phy_el);
8820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			j = 0;
8920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			while (sha->sas_phy[j]) {
9020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				if (sha->sas_phy[j] == phy)
9120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					break;
9220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				j++;
9320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
9420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
9520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
9620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i++;
9720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
9820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	hi = j/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
9920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
1008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return mvi;
1028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
10520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
10620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
10720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long i = 0, j = 0, n = 0, num = 0;
1089870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
1099870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_info *mvi = mvi_dev->mvi_info;
11020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sha = dev->port->ha;
11120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
11220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (sha->sas_port[i]) {
11320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sha->sas_port[i] == dev->port) {
11420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct asd_sas_phy *phy;
11520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			list_for_each_entry(phy,
11620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				&sha->sas_port[i]->phy_list, port_phy_el) {
11720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				j = 0;
11820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				while (sha->sas_phy[j]) {
11920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					if (sha->sas_phy[j] == phy)
12020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						break;
12120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					j++;
12220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				}
12320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phyno[n] = (j >= mvi->chip->n_phy) ?
12420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					(j - mvi->chip->n_phy) : j;
12520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				num++;
12620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				n++;
127dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			}
128dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
129dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
13020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i++;
13120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
13220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return num;
13320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
13420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
135534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yustruct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi,
136534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu						u8 reg_set)
137534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu{
138534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu	u32 dev_no;
139534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu	for (dev_no = 0; dev_no < MVS_MAX_DEVICES; dev_no++) {
140534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu		if (mvi->devices[dev_no].taskfileset == MVS_ID_NOT_MAPPED)
141534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu			continue;
142534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu
143534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu		if (mvi->devices[dev_no].taskfileset == reg_set)
144534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu			return &mvi->devices[dev_no];
145534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu	}
146534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu	return NULL;
147534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu}
148534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu
14920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic inline void mvs_free_reg_set(struct mvs_info *mvi,
15020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				struct mvs_device *dev)
15120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
15220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!dev) {
15320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("device has been free.\n");
15420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
15520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
15620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (dev->taskfileset == MVS_ID_NOT_MAPPED)
15720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
15820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset);
15920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
16020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
16120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic inline u8 mvs_assign_reg_set(struct mvs_info *mvi,
16220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				struct mvs_device *dev)
16320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
16420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (dev->taskfileset != MVS_ID_NOT_MAPPED)
16520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return 0;
16620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset);
16720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
16820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
16920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard)
17020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
17120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 no;
17220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for_each_phy(phy_mask, phy_mask, no) {
17320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (!(phy_mask & 1))
17420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			continue;
17520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_reset(mvi, no, hard);
17620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
17720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
17820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
17920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
18020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			void *funcdata)
18120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
18220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = 0, phy_id = sas_phy->id;
18320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tmp, i = 0, hi;
18420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sha = sas_phy->ha;
18520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = NULL;
18620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
18720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (sha->sas_phy[i]) {
18820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sha->sas_phy[i] == sas_phy)
18920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
19020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i++;
19120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
19220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
19320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
19420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
19520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	switch (func) {
19620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case PHY_FUNC_SET_LINK_RATE:
19720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata);
19820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
1998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
200dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_HARD_RESET:
20120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id);
202dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (tmp & PHY_RST_HARD)
203dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			break;
204a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_HARD_RESET);
205dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
206b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
207dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_LINK_RESET:
20820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_enable(mvi, phy_id);
209a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_SOFT_RESET);
210dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
211b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
212dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_DISABLE:
21320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->phy_disable(mvi, phy_id);
21420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
215dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case PHY_FUNC_RELEASE_SPINUP_HOLD:
216dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	default:
217ac013ed1cb7b1b36113548ce83881a1b5f757b58Dan Williams		rc = -ENOSYS;
218b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
21920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	msleep(200);
220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
22320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id,
22420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				u32 off_lo, u32 off_hi, u64 sas_addr)
22520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
22620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 lo = (u32)sas_addr;
22720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 hi = (u32)(sas_addr>>32);
22820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
22920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_lo);
23020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, lo);
23120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_hi);
23220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi);
23320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
23420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
235dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
236ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei{
237dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
23820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_phy *sas_phy = &phy->sas_phy;
23920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sas_ha;
240dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!phy->phy_attached)
241dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return;
242dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
24320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!(phy->att_dev_info & PORT_DEV_TRGT_MASK)
24420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		&& phy->phy_type & PORT_TYPE_SAS) {
24520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
24620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
24720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
24820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	sas_ha = mvi->sas;
24920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE);
25020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
251dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (sas_phy->phy) {
252dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct sas_phy *sphy = sas_phy->phy;
253dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
254dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->negotiated_linkrate = sas_phy->linkrate;
255dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->minimum_linkrate = phy->minimum_linkrate;
256dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
257dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		sphy->maximum_linkrate = phy->maximum_linkrate;
25820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		sphy->maximum_linkrate_hw = MVS_CHIP_DISP->phy_max_link_rate();
259ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei	}
260ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei
261dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->phy_type & PORT_TYPE_SAS) {
262dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		struct sas_identify_frame *id;
263b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
264dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id = (struct sas_identify_frame *)phy->frame_rcvd;
265dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id->dev_type = phy->identify.device_type;
266dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id->initiator_bits = SAS_PROTOCOL_ALL;
267dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		id->target_bits = phy->identify.target_port_protocols;
268477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu
269477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu		/* direct attached SAS device */
270477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu		if (phy->att_dev_info & PORT_SSP_TRGT_MASK) {
271477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu			MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
272477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu			MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x00);
273477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu		}
274dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	} else if (phy->phy_type & PORT_TYPE_SATA) {
27520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/*Nothing*/
276dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
27720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_dprintk("phy %d byte dmaded.\n", i + mvi->id * mvi->chip->n_phy);
27820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
27920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
28020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
28120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi->sas->notify_port_event(sas_phy,
282dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				   PORTE_BYTES_DMAED);
283ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei}
284ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei
285dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_scan_start(struct Scsi_Host *shost)
286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
28720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int i, j;
28820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned short core_nr;
28920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi;
29020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
29184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	struct mvs_prv_info *mvs_prv = sha->lldd_ha;
29220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
29320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
294dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
29520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (j = 0; j < core_nr; j++) {
29620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j];
29720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		for (i = 0; i < mvi->chip->n_phy; ++i)
29820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_bytes_dmaed(mvi, i);
299dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
30084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	mvs_prv->scan_finished = 1;
301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
302b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
303dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
304b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
30584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
30684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	struct mvs_prv_info *mvs_prv = sha->lldd_ha;
30784fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu
30884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	if (mvs_prv->scan_finished == 0)
309dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return 0;
31084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu
311b1124cd3ec97406c767b90bf7e93ecd2d2915592Dan Williams	sas_drain_work(sha);
312dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 1;
313b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
314b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
315dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_smp(struct mvs_info *mvi,
316dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     struct mvs_task_exec_info *tei)
317b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
318dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int elem, rc, i;
319dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct sas_task *task = tei->task;
320dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
32120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct domain_device *dev = task->dev;
32220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_port *sas_port = dev->port;
323dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct scatterlist *sg_req, *sg_resp;
324dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 req_len, resp_len, tag = tei->tag;
325dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	void *buf_tmp;
326dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u8 *buf_oaf;
327dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	dma_addr_t buf_tmp_dma;
32820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	void *buf_prd;
329dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_slot_info *slot = &mvi->slot_info[tag];
330dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
331b89e8f539ff8bcf2a1464578fa91cb96cc433fc3Xiangliang Yu
332dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/*
333dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * DMA-map SMP request, response buffers
334dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
335dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	sg_req = &task->smp_task.smp_req;
33620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	elem = dma_map_sg(mvi->dev, sg_req, 1, PCI_DMA_TODEVICE);
337dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!elem)
338dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return -ENOMEM;
339dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	req_len = sg_dma_len(sg_req);
340b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
341dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	sg_resp = &task->smp_task.smp_resp;
34220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	elem = dma_map_sg(mvi->dev, sg_resp, 1, PCI_DMA_FROMDEVICE);
343dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!elem) {
344dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -ENOMEM;
345dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out;
346dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
34720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	resp_len = SB_RFB_MAX;
348b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
349dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* must be in dwords */
350dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if ((req_len & 0x3) || (resp_len & 0x3)) {
351dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		rc = -EINVAL;
352dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		goto err_out_2;
353b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
354b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
355dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/*
356dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
357dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
358b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
35920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */
360dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp = slot->buf;
361dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma = slot->buf_dma;
362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
363dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
365dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
366dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_oaf = buf_tmp;
367dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
368b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
369dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp += MVS_OAF_SZ;
370dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
37220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* region 3: PRD table *********************************** */
373dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_prd = buf_tmp;
374dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (tei->n_elem)
375dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
376dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	else
377dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		hdr->prd_tbl = 0;
378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
37920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
380dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp += i;
381dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	buf_tmp_dma += i;
382b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
383dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
384dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->response = buf_tmp;
385dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
38620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->flags & MVF_FLAG_SOC)
38720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		hdr->reserved[0] = 0;
388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
389dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/*
390dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 * Fill in TX ring and command slot header
391dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	 */
392dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->tx = mvi->tx_prod;
393dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
394dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					TXQ_MODE_I | tag |
395dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik					(sas_port->phy_mask << TXQ_PHY_SHIFT));
396b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
397dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->flags |= flags;
398dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
399dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->tags = cpu_to_le32(tag);
400dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	hdr->data_len = 0;
401b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
402dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* generate open address frame hdr (first 12 bytes) */
40320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* initiator, SMP, ftype 1h */
40420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	buf_oaf[0] = (1 << 7) | (PROTOCOL_SMP << 4) | 0x01;
4056ceae7c6234f2961dc59912412e8c0706d825873Xiangliang Yu	buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf;
406dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	*(u16 *)(buf_oaf + 2) = 0xFFFF;		/* SAS SPEC */
40720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
408dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
409dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
41020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
411b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
412b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
413b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
414dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_2:
41520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1,
416dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		     PCI_DMA_FROMDEVICE);
417b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out:
41820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1,
419dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		     PCI_DMA_TODEVICE);
420b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return rc;
4218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
4228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
423dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
4248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
425dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct ata_queued_cmd *qc = task->uldd_task;
4268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
427dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (qc) {
428dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
429dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			qc->tf.command == ATA_CMD_FPDMA_READ) {
430dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			*tag = qc->tag;
431dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			return 1;
432dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
4338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
4348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
435dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
4368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
4378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
438dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_ata(struct mvs_info *mvi,
439dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     struct mvs_task_exec_info *tei)
440b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct domain_device *dev = task->dev;
443f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device *mvi_dev = dev->lldd_dev;
444b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
445b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct asd_sas_port *sas_port = dev->port;
4468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_slot_info *slot;
44720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	void *buf_prd;
44820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tag = tei->tag, hdr_tag;
44920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 flags, del_q;
450b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
451b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf;
452b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
4538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 i, req_len, resp_len;
4548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	const u32 max_resp_len = SB_RFB_MAX;
4558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
45620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvs_assign_reg_set(mvi, mvi_dev) == MVS_ID_NOT_MAPPED) {
45720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("Have not enough regiset for dev %d.\n",
45820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvi_dev->device_id);
4598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		return -EBUSY;
46020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
4618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot = &mvi->slot_info[tag];
4628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->tx = mvi->tx_prod;
46320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	del_q = TXQ_MODE_I | tag |
46420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
46520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		(sas_port->phy_mask << TXQ_PHY_SHIFT) |
46620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		(mvi_dev->taskfileset << TXQ_SRS_SHIFT);
46720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q);
46820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
46920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->data_dir == DMA_FROM_DEVICE)
47020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT);
47120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	else
47220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
4738882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu
474b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ata_task.use_ncq)
475b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FPDMA;
4768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
4778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
4788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			flags |= MCH_ATAPI;
4798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
4808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
481b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->flags = cpu_to_le32(flags);
4828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
48320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag))
48420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
4854e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei	else
48620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		hdr_tag = tag;
48720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
48820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	hdr->tags = cpu_to_le32(hdr_tag);
48920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
490b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = cpu_to_le32(task->total_xfer_len);
491b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
492b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
493b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
494b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
495b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
4968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
4978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd = buf_tmp = slot->buf;
498b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma = slot->buf_dma;
499b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
500b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
501b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
502b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_ATA_CMD_SZ;
503b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_ATA_CMD_SZ;
504b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
506b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* used for STP.  unused for SATA? */
507b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
508b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
509b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
510b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
511b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
512b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 3: PRD table ********************************************* */
514b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
51520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
5168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tei->n_elem)
5178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
5188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
5198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = 0;
52020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	i = MVS_CHIP_DISP->prd_size() * MVS_CHIP_DISP->prd_count();
521b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
522b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
523b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
527b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
52820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->flags & MVF_FLAG_SOC)
52920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		hdr->reserved[0] = 0;
530b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
5318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	req_len = sizeof(struct host_to_dev_fis);
532b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
5338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_err_info) - i;
534b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
535b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
5368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	resp_len = min(resp_len, max_resp_len);
537b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
538b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
53920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (likely(!task->ata_task.device_control_reg_update))
54020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
541b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in command FIS and ATAPI CDB */
5428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
5438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
5448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		memcpy(buf_cmd + STP_ATAPI_CMD,
5458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei			task->ata_task.atapi_packet, 16);
5468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
5478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* generate open address frame hdr (first 12 bytes) */
54820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* initiator, STP, ftype 1h */
54920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	buf_oaf[0] = (1 << 7) | (PROTOCOL_STP << 4) | 0x1;
5506ceae7c6234f2961dc59912412e8c0706d825873Xiangliang Yu	buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf;
55120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	*(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
55220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
553b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* fill in PRD (scatter/gather) table, if any */
55520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
5568882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu
55720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->data_dir == DMA_FROM_DEVICE)
5588882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu		MVS_CHIP_DISP->dma_fix(mvi, sas_port->phy_mask,
55920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				TRASH_BUCKET_SIZE, tei->n_elem, buf_prd);
5608882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu
561b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
562b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
563b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
564b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ssp(struct mvs_info *mvi,
56520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			     struct mvs_task_exec_info *tei, int is_tmf,
56620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			     struct mvs_tmf_task *tmf)
567b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
568b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct sas_task *task = tei->task;
569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_cmd_hdr *hdr = tei->hdr;
5708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct mvs_port *port = tei->port;
57120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct domain_device *dev = task->dev;
572f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device *mvi_dev = dev->lldd_dev;
57320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_port *sas_port = dev->port;
574b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_slot_info *slot;
57520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	void *buf_prd;
576b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct ssp_frame_hdr *ssp_hdr;
577b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	void *buf_tmp;
578b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u8 *buf_cmd, *buf_oaf, fburst = 0;
579b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	dma_addr_t buf_tmp_dma;
580b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	u32 flags;
5818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	u32 resp_len, req_len, i, tag = tei->tag;
5828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	const u32 max_resp_len = SB_RFB_MAX;
58320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 phy_mask;
584b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
585b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot = &mvi->slot_info[tag];
586b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
58720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy_mask = ((port->wide_port_phymap) ? port->wide_port_phymap :
58820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		sas_port->phy_mask) & TXQ_PHY_MASK;
58920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
5908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	slot->tx = mvi->tx_prod;
5918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
5928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei				(TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
5934e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei				(phy_mask << TXQ_PHY_SHIFT));
594b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
595b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	flags = MCH_RETRY;
596b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	if (task->ssp_task.enable_first_burst) {
597b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		flags |= MCH_FBURST;
598b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik		fburst = (1 << 7);
599b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
6002b288133ab6306b1761e0a2ef943b944ead6ad69Andy Yan	if (is_tmf)
6012b288133ab6306b1761e0a2ef943b944ead6ad69Andy Yan		flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
60284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	else
60384fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);
60484fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu
6052b288133ab6306b1761e0a2ef943b944ead6ad69Andy Yan	hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->tags = cpu_to_le32(tag);
607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->data_len = cpu_to_le32(task->total_xfer_len);
608b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
609b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/*
610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
611b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	 */
612b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
6148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	buf_cmd = buf_tmp = slot->buf;
615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma = slot->buf_dma;
616b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
617b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
618b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
619b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_SSP_CMD_SZ;
620b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_SSP_CMD_SZ;
621b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
623b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_oaf = buf_tmp;
624b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
625b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
626b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += MVS_OAF_SZ;
627b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += MVS_OAF_SZ;
628b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 3: PRD table ********************************************* */
630b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_prd = buf_tmp;
6318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	if (tei->n_elem)
6328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
6338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	else
6348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei		hdr->prd_tbl = 0;
635b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
63620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
637b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp += i;
638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_tmp_dma += i;
639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
641b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	slot->response = buf_tmp;
642b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
64320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->flags & MVF_FLAG_SOC)
64420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		hdr->reserved[0] = 0;
645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
6478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	    sizeof(struct mvs_err_info) - i;
6488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	resp_len = min(resp_len, max_resp_len);
6498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
6508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	req_len = sizeof(struct ssp_frame_hdr) + 28;
651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* request, response lengths */
653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	/* generate open address frame hdr (first 12 bytes) */
65620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* initiator, SSP, ftype 1h */
65720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	buf_oaf[0] = (1 << 7) | (PROTOCOL_SSP << 4) | 0x1;
6586ceae7c6234f2961dc59912412e8c0706d825873Xiangliang Yu	buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf;
65920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	*(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
66020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
6628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	/* fill in SSP frame header (Command Table.SSP frame header) */
6638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
66420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
66520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (is_tmf)
66620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		ssp_hdr->frame_type = SSP_TASK;
66720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	else
66820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		ssp_hdr->frame_type = SSP_COMMAND;
66920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
67020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr,
671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	       HASHED_SAS_ADDR_SIZE);
672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(ssp_hdr->hashed_src_addr,
67320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	       dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	ssp_hdr->tag = cpu_to_be16(tag);
675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
67620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* fill in IU for TASK and Command Frame */
677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	buf_cmd += sizeof(*ssp_hdr);
678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
68020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (ssp_hdr->frame_type != SSP_TASK) {
68120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		buf_cmd[9] = fburst | task->ssp_task.task_attr |
68220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				(task->ssp_task.task_prio << 3);
68320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
68420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else{
68520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		buf_cmd[10] = tmf->tmf;
68620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		switch (tmf->tmf) {
68720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_ABORT_TASK:
68820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_QUERY_TASK:
68920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			buf_cmd[12] =
69020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				(tmf->tag_of_task_to_be_managed >> 8) & 0xff;
69120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			buf_cmd[13] =
69220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				tmf->tag_of_task_to_be_managed & 0xff;
69320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
69420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		default:
69520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
69620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
697b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
69820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* fill in PRD (scatter/gather) table, if any */
69920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
700b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	return 0;
701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
70320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#define	DEV_IS_GONE(mvi_dev)	((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE)))
7040b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf,
7050b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				struct mvs_tmf_task *tmf, int *pass)
706b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
7078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	struct domain_device *dev = task->dev;
7080b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct mvs_device *mvi_dev = dev->lldd_dev;
709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	struct mvs_task_exec_info tei;
7104e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei	struct mvs_slot_info *slot;
7110b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	u32 tag = 0xdeadbeef, n_elem = 0;
7120b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	int rc = 0;
713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
71420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!dev->port) {
7150b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		struct task_status_struct *tsm = &task->task_status;
71620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
71720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tsm->resp = SAS_TASK_UNDELIVERED;
71820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tsm->stat = SAS_PHY_DOWN;
7190b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		/*
7200b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		 * libsas will use dev->port, should
7210b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		 * not call task_done for sata
7220b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		 */
7239dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (dev->dev_type != SATA_DEV)
7240b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			task->task_done(task);
7250b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		return rc;
72620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
72720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
7280b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (DEV_IS_GONE(mvi_dev)) {
7290b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		if (mvi_dev)
7300b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			mv_dprintk("device %d not ready.\n",
7310b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				mvi_dev->device_id);
7320b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		else
7330b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			mv_dprintk("device %016llx not ready.\n",
7340b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				SAS_ADDR(dev->sas_addr));
73520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
73620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			rc = SAS_PHY_DOWN;
7370b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			return rc;
7380b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
7390b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	tei.port = dev->port->lldd_port;
7400b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (tei.port && !tei.port->port_attached && !tmf) {
7410b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		if (sas_protocol_ata(task->task_proto)) {
7420b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			struct task_status_struct *ts = &task->task_status;
7430b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			mv_dprintk("SATA/STP port %d does not attach"
7440b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu					"device.\n", dev->port->id);
7450b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			ts->resp = SAS_TASK_COMPLETE;
7460b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			ts->stat = SAS_PHY_DOWN;
74720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
7480b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			task->task_done(task);
749dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
750dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else {
7510b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			struct task_status_struct *ts = &task->task_status;
7520b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			mv_dprintk("SAS port %d does not attach"
7530b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				"device.\n", dev->port->id);
7540b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			ts->resp = SAS_TASK_UNDELIVERED;
7550b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			ts->stat = SAS_PHY_DOWN;
7560b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			task->task_done(task);
757dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
7580b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		return rc;
7590b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
760dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
7610b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (!sas_protocol_ata(task->task_proto)) {
7620b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		if (task->num_scatter) {
7630b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			n_elem = dma_map_sg(mvi->dev,
7640b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu					    task->scatter,
7650b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu					    task->num_scatter,
7660b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu					    task->data_dir);
7670b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			if (!n_elem) {
7680b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				rc = -ENOMEM;
7690b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				goto prep_out;
7700b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			}
7710b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		}
7720b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	} else {
7730b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		n_elem = task->num_scatter;
7740b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
77520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
7760b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	rc = mvs_tag_alloc(mvi, &tag);
7770b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (rc)
7780b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		goto err_out;
77920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
7800b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	slot = &mvi->slot_info[tag];
78120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
7820b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	task->lldd_task = NULL;
7830b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	slot->n_elem = n_elem;
7840b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	slot->slot_tag = tag;
7850b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
7860b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	slot->buf = pci_pool_alloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma);
7870b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (!slot->buf)
7880b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		goto err_out_tag;
7890b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
7900b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
7910b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	tei.task = task;
7920b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	tei.hdr = &mvi->slot[tag];
7930b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	tei.tag = tag;
7940b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	tei.n_elem = n_elem;
7950b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	switch (task->task_proto) {
7960b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	case SAS_PROTOCOL_SMP:
7970b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		rc = mvs_task_prep_smp(mvi, &tei);
7980b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		break;
7990b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	case SAS_PROTOCOL_SSP:
8000b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf);
8010b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		break;
8020b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	case SAS_PROTOCOL_SATA:
8030b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	case SAS_PROTOCOL_STP:
8040b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
8050b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		rc = mvs_task_prep_ata(mvi, &tei);
8060b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		break;
8070b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	default:
8080b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		dev_printk(KERN_ERR, mvi->dev,
8090b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			"unknown sas_task proto: 0x%x\n",
8100b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			task->task_proto);
8110b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		rc = -EINVAL;
8120b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		break;
8130b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
814dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
8150b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (rc) {
8160b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		mv_dprintk("rc is %x\n", rc);
8170b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		goto err_out_slot_buf;
8180b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
8190b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	slot->task = task;
8200b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	slot->port = tei.port;
8210b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	task->lldd_task = slot;
8220b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	list_add_tail(&slot->entry, &tei.port->list);
8230b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	spin_lock(&task->task_state_lock);
8240b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	task->task_state_flags |= SAS_TASK_AT_INITIATOR;
8250b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	spin_unlock(&task->task_state_lock);
8260b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8270b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	mvi_dev->running_req++;
8280b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	++(*pass);
8290b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
8309dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
8310b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	return rc;
832dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
8330b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yuerr_out_slot_buf:
8340b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma);
835dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_tag:
836dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_free(mvi, tag);
837dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out:
83820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
8390b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc);
8400b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (!sas_protocol_ata(task->task_proto))
841dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (n_elem)
8420b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			dma_unmap_sg(mvi->dev, task->scatter, n_elem,
8430b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				     task->data_dir);
8440b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yuprep_out:
8450b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	return rc;
8460b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu}
8470b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8480b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic struct mvs_task_list *mvs_task_alloc_list(int *num, gfp_t gfp_flags)
8490b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu{
8500b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct mvs_task_list *first = NULL;
8510b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8520b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	for (; *num > 0; --*num) {
8530b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		struct mvs_task_list *mvs_list = kmem_cache_zalloc(mvs_task_list_cache, gfp_flags);
8540b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8550b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		if (!mvs_list)
8560b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			break;
8570b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8580b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		INIT_LIST_HEAD(&mvs_list->list);
8590b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		if (!first)
8600b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			first = mvs_list;
8610b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		else
8620b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			list_add_tail(&mvs_list->list, &first->list);
8630b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8640b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
8650b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8660b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	return first;
8670b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu}
8680b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8690b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic inline void mvs_task_free_list(struct mvs_task_list *mvs_list)
8700b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu{
8710b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	LIST_HEAD(list);
8720b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct list_head *pos, *a;
8730b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct mvs_task_list *mlist = NULL;
8740b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8750b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	__list_add(&list, mvs_list->list.prev, &mvs_list->list);
8760b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8770b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	list_for_each_safe(pos, a, &list) {
8780b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		list_del_init(pos);
8790b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		mlist = list_entry(pos, struct mvs_task_list, list);
8800b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		kmem_cache_free(mvs_task_list_cache, mlist);
8810b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
8820b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu}
8830b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8840b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
8850b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				struct completion *completion, int is_tmf,
8860b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				struct mvs_tmf_task *tmf)
8870b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu{
8880b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct domain_device *dev = task->dev;
8890b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct mvs_info *mvi = NULL;
8900b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	u32 rc = 0;
8910b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	u32 pass = 0;
8920b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	unsigned long flags = 0;
8930b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8940b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info;
8950b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8960b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
8970b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		spin_unlock_irq(dev->sata_dev.ap->lock);
8980b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
8990b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	spin_lock_irqsave(&mvi->lock, flags);
9000b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass);
9010b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (rc)
9020b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
9030b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9040b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (likely(pass))
9050b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) &
9060b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				(MVS_CHIP_SLOT_SZ - 1));
9070b84b7094e87769120def1e703b8b4d037281038Andy Yan	spin_unlock_irqrestore(&mvi->lock, flags);
9080b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9090b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
9100b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		spin_lock_irq(dev->sata_dev.ap->lock);
9110b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9120b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	return rc;
9130b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu}
9140b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9150b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic int mvs_collector_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
9160b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				struct completion *completion, int is_tmf,
9170b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				struct mvs_tmf_task *tmf)
9180b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu{
9190b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct domain_device *dev = task->dev;
9200b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct mvs_prv_info *mpi = dev->port->ha->lldd_ha;
9210b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct mvs_info *mvi = NULL;
9220b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct sas_task *t = task;
9230b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct mvs_task_list *mvs_list = NULL, *a;
9240b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	LIST_HEAD(q);
9250b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	int pass[2] = {0};
9260b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	u32 rc = 0;
9270b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	u32 n = num;
9280b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	unsigned long flags = 0;
9290b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9300b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	mvs_list = mvs_task_alloc_list(&n, gfp_flags);
9310b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (n) {
9320b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		printk(KERN_ERR "%s: mvs alloc list failed.\n", __func__);
9330b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		rc = -ENOMEM;
9340b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		goto free_list;
9350b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
9360b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9370b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	__list_add(&q, mvs_list->list.prev, &mvs_list->list);
9380b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9390b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	list_for_each_entry(a, &q, list) {
9400b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		a->task = t;
9410b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		t = list_entry(t->list.next, struct sas_task, list);
9420b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
9430b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9440b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	list_for_each_entry(a, &q , list) {
9450b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9460b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		t = a->task;
9470b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		mvi = ((struct mvs_device *)t->dev->lldd_dev)->mvi_info;
9480b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9490b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		spin_lock_irqsave(&mvi->lock, flags);
9500b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		rc = mvs_task_prep(t, mvi, is_tmf, tmf, &pass[mvi->id]);
9510b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		if (rc)
9520b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
9530b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		spin_unlock_irqrestore(&mvi->lock, flags);
9540b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
9550b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9560b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (likely(pass[0]))
9570b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			MVS_CHIP_DISP->start_delivery(mpi->mvi[0],
9580b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				(mpi->mvi[0]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
9590b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9600b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (likely(pass[1]))
9610b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu			MVS_CHIP_DISP->start_delivery(mpi->mvi[1],
9620b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu				(mpi->mvi[1]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
9630b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9640b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	list_del_init(&q);
9650b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9660b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yufree_list:
9670b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (mvs_list)
9680b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		mvs_task_free_list(mvs_list);
9690b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
970dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return rc;
971dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
972dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
97320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_queue_command(struct sas_task *task, const int num,
97420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			gfp_t gfp_flags)
97520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
9760b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct mvs_device *mvi_dev = task->dev->lldd_dev;
9770b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	struct sas_ha_struct *sas = mvi_dev->mvi_info->sas;
9780b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
9790b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (sas->lldd_max_execute_num < 2)
9800b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL);
9810b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	else
9820b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		return mvs_collector_task_exec(task, num, gfp_flags, NULL, 0, NULL);
98320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
98420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
985dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
986dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
987dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
988dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	mvs_tag_clear(mvi, slot_idx);
989dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
990dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
991dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
992dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			  struct mvs_slot_info *slot, u32 slot_idx)
993dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
99420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!slot->task)
99520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
996dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!sas_protocol_ata(task->task_proto))
997dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (slot->n_elem)
99820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			dma_unmap_sg(mvi->dev, task->scatter,
999dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				     slot->n_elem, task->data_dir);
1000dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1001dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	switch (task->task_proto) {
1002dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SMP:
100320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1,
1004dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     PCI_DMA_FROMDEVICE);
100520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1,
1006dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			     PCI_DMA_TODEVICE);
1007dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1008dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1009dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA:
1010dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_STP:
1011dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SSP:
1012dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	default:
1013dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		/* do nothing */
1014dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1015dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
10160b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu
10170b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	if (slot->buf) {
10180b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma);
10190b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu		slot->buf = NULL;
10200b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	}
102120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	list_del_init(&slot->entry);
1022dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	task->lldd_task = NULL;
1023dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->task = NULL;
1024dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	slot->port = NULL;
102520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	slot->slot_tag = 0xFFFFFFFF;
102620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_slot_free(mvi, slot_idx);
1027dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1028dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
102984fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yustatic void mvs_update_wideport(struct mvs_info *mvi, int phy_no)
1030dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
103184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	struct mvs_phy *phy = &mvi->phy[phy_no];
1032dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_port *port = phy->port;
1033dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	int j, no;
1034dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
103520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for_each_phy(port->wide_port_phymap, j, no) {
103620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (j & 1) {
103720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
103820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						PHYR_WIDE_PORT);
103920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
1040dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik						port->wide_port_phymap);
1041dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else {
104220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
104320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						PHYR_WIDE_PORT);
104420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
104520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						0);
1046dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
104720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
1048dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1049dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1050dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
1051dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1052dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 tmp;
1053dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
105420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_port *port = phy->port;
1055dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
105620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, i);
1057dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
1058dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (!port)
1059dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->phy_attached = 1;
1060dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return tmp;
1061dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1062dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1063dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (port) {
1064dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		if (phy->phy_type & PORT_TYPE_SAS) {
1065dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			port->wide_port_phymap &= ~(1U << i);
1066dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (!port->wide_port_phymap)
1067dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				port->port_attached = 0;
1068dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			mvs_update_wideport(mvi, i);
1069dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		} else if (phy->phy_type & PORT_TYPE_SATA)
1070dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			port->port_attached = 0;
1071dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->port = NULL;
1072dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->phy_attached = 0;
1073dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
1074dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1075dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return 0;
1076dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1077dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1078dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
1079dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1080dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	u32 *s = (u32 *) buf;
1081dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1082dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (!s)
1083dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		return NULL;
1084dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
108520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
108684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	s[3] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
1087dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
108820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
108984fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	s[2] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
1090dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
109120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
109284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	s[1] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
1093dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
109420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
109584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	s[0] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
109620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
109720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
109820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10);
1099dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1100f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	return s;
1101dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1102dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1103dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_sig_fis_received(u32 irq_status)
1104dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1105dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return irq_status & PHYEV_SIG_FIS;
1106dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1107dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
11088882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yustatic void mvs_sig_remove_timer(struct mvs_phy *phy)
11098882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu{
11108882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu	if (phy->timer.function)
11118882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu		del_timer(&phy->timer);
11128882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu	phy->timer.function = NULL;
11138882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu}
11148882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu
111520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
1116dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1117dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = &mvi->phy[i];
111820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_identify_frame *id;
1119b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
112020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	id = (struct sas_identify_frame *)phy->frame_rcvd;
1121b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1122dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (get_st) {
112320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, i);
1124dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		phy->phy_status = mvs_is_phy_ready(mvi, i);
1125dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
11268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1127dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->phy_status) {
112820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int oob_done = 0;
112920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct asd_sas_phy *sas_phy = &mvi->phy[i].sas_phy;
1130b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
113120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		oob_done = MVS_CHIP_DISP->oob_done(mvi, i);
113220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
113320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->fix_phy_info(mvi, i, id);
113420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy->phy_type & PORT_TYPE_SATA) {
113520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
113620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (mvs_is_sig_fis_received(phy->irq_status)) {
11378882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu				mvs_sig_remove_timer(phy);
113820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->phy_attached = 1;
113920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->att_dev_sas_addr =
114020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					i + mvi->id * mvi->chip->n_phy;
114120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				if (oob_done)
114220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					sas_phy->oob_mode = SATA_OOB_MODE;
114320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->frame_rcvd_size =
114420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    sizeof(struct dev_to_host_fis);
1145f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan				mvs_get_d2h_reg(mvi, i, id);
114620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			} else {
114720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				u32 tmp;
114820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				dev_printk(KERN_DEBUG, mvi->dev,
114920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					"Phy%d : No sig fis\n", i);
115020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, i);
115120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				MVS_CHIP_DISP->write_port_irq_mask(mvi, i,
115220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						tmp | PHYEV_SIG_FIS);
115320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->phy_attached = 0;
115420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->phy_type &= ~PORT_TYPE_SATA;
115520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				goto out_done;
115620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
11579dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		}	else if (phy->phy_type & PORT_TYPE_SAS
115820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			|| phy->att_dev_info & PORT_SSP_INIT_MASK) {
115920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->phy_attached = 1;
1160dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->identify.device_type =
116120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->att_dev_info & PORT_DEV_TYPE_MASK;
1162b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1163dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			if (phy->identify.device_type == SAS_END_DEV)
1164dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				phy->identify.target_port_protocols =
1165dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							SAS_PROTOCOL_SSP;
1166dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			else if (phy->identify.device_type != NO_DEVICE)
1167dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				phy->identify.target_port_protocols =
1168dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik							SAS_PROTOCOL_SMP;
116920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (oob_done)
1170dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik				sas_phy->oob_mode = SAS_OOB_MODE;
1171dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			phy->frame_rcvd_size =
1172dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			    sizeof(struct sas_identify_frame);
1173dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
117420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		memcpy(sas_phy->attached_sas_addr,
117520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			&phy->att_dev_sas_addr, SAS_ADDR_SIZE);
1176b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
117720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (MVS_CHIP_DISP->phy_work_around)
117820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->phy_work_around(mvi, i);
1179dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
118084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	mv_dprintk("phy %d attach dev info is %x\n",
118120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i + mvi->id * mvi->chip->n_phy, phy->att_dev_info);
118284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	mv_dprintk("phy %d attach sas addr is %llx\n",
118320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr);
11844e52fc0a0a2ec2158691efba3f149f6416481255Ke Weiout_done:
1185dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (get_st)
118620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->write_port_irq_stat(mvi, i, phy->irq_status);
1187b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1188b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
118920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
11908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
1191dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct sas_ha_struct *sas_ha = sas_phy->ha;
119220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = NULL; int i = 0, hi;
1193dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	struct mvs_phy *phy = sas_phy->lldd_phy;
119420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct asd_sas_port *sas_port = sas_phy->port;
119520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_port *port;
119620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags = 0;
119720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!sas_port)
119820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
11998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
120020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (sas_ha->sas_phy[i]) {
120120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sas_ha->sas_phy[i] == sas_phy)
120220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
120320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		i++;
120420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
120520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy;
120620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi];
120784fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	if (i >= mvi->chip->n_phy)
120884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		port = &mvi->port[i - mvi->chip->n_phy];
120920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	else
121084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		port = &mvi->port[i];
121120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (lock)
121220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_lock_irqsave(&mvi->lock, flags);
1213dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	port->port_attached = 1;
1214dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	phy->port = port;
12150b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu	sas_port->lldd_port = port;
1216dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	if (phy->phy_type & PORT_TYPE_SAS) {
1217dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		port->wide_port_phymap = sas_port->phy_mask;
121820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("set wide port phy map %x\n", sas_port->phy_mask);
1219dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		mvs_update_wideport(mvi, sas_phy->id);
1220477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu
1221477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu		/* direct attached SAS device */
1222477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu		if (phy->att_dev_info & PORT_SSP_TRGT_MASK) {
1223477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu			MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
1224477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu			MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x04);
1225477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu		}
12268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
122720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (lock)
122820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_unlock_irqrestore(&mvi->lock, flags);
1229dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1230dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
123120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
1232dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
12339dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct domain_device *dev;
12349dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct mvs_phy *phy = sas_phy->lldd_phy;
12359dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct mvs_info *mvi = phy->mvi;
12369dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct asd_sas_port *port = sas_phy->port;
12379dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	int phy_no = 0;
12389dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
12399dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	while (phy != &mvi->phy[phy_no]) {
12409dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		phy_no++;
12419dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (phy_no >= MVS_MAX_PHYS)
12429dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			return;
12439dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	}
12449dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	list_for_each_entry(dev, &port->dev_list, dev_list_node)
124584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		mvs_do_release_task(phy->mvi, phy_no, dev);
12469dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
1247dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1248dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
1249dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
125020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_port_formed(struct asd_sas_phy *sas_phy)
125120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
125220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_port_notify_formed(sas_phy, 1);
1253dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1254dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
125520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_port_deformed(struct asd_sas_phy *sas_phy)
1256dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
125720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_port_notify_deformed(sas_phy, 1);
125820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
12598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
126020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstruct mvs_device *mvs_alloc_dev(struct mvs_info *mvi)
126120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
126220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 dev;
126320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (dev = 0; dev < MVS_MAX_DEVICES; dev++) {
126420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (mvi->devices[dev].dev_type == NO_DEVICE) {
126520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvi->devices[dev].device_id = dev;
126620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			return &mvi->devices[dev];
126720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
12688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei	}
12698121ed420285885654af133a6ca1919590f98917Ke Wei
127020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (dev == MVS_MAX_DEVICES)
127120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("max support %d devices, ignore ..\n",
127220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_MAX_DEVICES);
127320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
127420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return NULL;
12758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
12768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
127720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_free_dev(struct mvs_device *mvi_dev)
1278b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
127920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 id = mvi_dev->device_id;
128020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memset(mvi_dev, 0, sizeof(*mvi_dev));
128120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->device_id = id;
128220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->dev_type = NO_DEVICE;
128320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->dev_status = MVS_DEV_NORMAL;
128420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->taskfileset = MVS_ID_NOT_MAPPED;
128520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
128720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_dev_found_notify(struct domain_device *dev, int lock)
128820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
128920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags = 0;
129020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int res = 0;
129120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = NULL;
129220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct domain_device *parent_dev = dev->parent;
129320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_device *mvi_device;
1294b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
129520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi = mvs_find_dev_mvi(dev);
1296b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
129720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (lock)
129820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_lock_irqsave(&mvi->lock, flags);
129920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
130020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_device = mvs_alloc_dev(mvi);
130120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!mvi_device) {
130220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		res = -1;
130320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		goto found_out;
1304b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1305f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	dev->lldd_dev = mvi_device;
13069dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvi_device->dev_status = MVS_DEV_NORMAL;
130720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_device->dev_type = dev->dev_type;
13089870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	mvi_device->mvi_info = mvi;
130984fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	mvi_device->sas_device = dev;
131020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
131120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int phy_id;
131220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		u8 phy_num = parent_dev->ex_dev.num_phys;
131320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct ex_phy *phy;
131420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		for (phy_id = 0; phy_id < phy_num; phy_id++) {
131520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy = &parent_dev->ex_dev.ex_phy[phy_id];
131620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (SAS_ADDR(phy->attached_sas_addr) ==
131720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				SAS_ADDR(dev->sas_addr)) {
131820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvi_device->attached_phy = phy_id;
131920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				break;
132020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
132120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
132320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy_id == phy_num) {
132420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_printk("Error: no attached dev:%016llx"
132520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				"at ex:%016llx.\n",
132620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				SAS_ADDR(dev->sas_addr),
132720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				SAS_ADDR(parent_dev->sas_addr));
132820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			res = -1;
132920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1330dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1331b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
133220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanfound_out:
133320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (lock)
133420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_unlock_irqrestore(&mvi->lock, flags);
133520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return res;
133620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
133820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_dev_found(struct domain_device *dev)
133920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
134020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return mvs_dev_found_notify(dev, 1);
134120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1342b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13439dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivasvoid mvs_dev_gone_notify(struct domain_device *dev)
134420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
134520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags = 0;
1346f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device *mvi_dev = dev->lldd_dev;
13479870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_info *mvi = mvi_dev->mvi_info;
1348b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13499dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	spin_lock_irqsave(&mvi->lock, flags);
1350b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
135120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi_dev) {
135220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("found dev[%d:%x] is gone.\n",
135320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvi_dev->device_id, mvi_dev->dev_type);
13549dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvs_release_task(mvi, dev);
135520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_free_reg_set(mvi, mvi_dev);
135620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_free_dev(mvi_dev);
135720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else {
135820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("found dev has gone.\n");
1359b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
136020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	dev->lldd_dev = NULL;
136184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	mvi_dev->sas_device = NULL;
1362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
13639dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	spin_unlock_irqrestore(&mvi->lock, flags);
1364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1365b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
136720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_dev_gone(struct domain_device *dev)
136820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
13699dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvs_dev_gone_notify(dev);
137020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
137220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_task_done(struct sas_task *task)
137320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
137420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!del_timer(&task->timer))
137520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
137620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	complete(&task->completion);
1377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
1378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
137920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_tmf_timedout(unsigned long data)
1380b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
138120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_task *task = (struct sas_task *)data;
13828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
138320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
138420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	complete(&task->completion);
138520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
13868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
138720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#define MVS_TASK_TIMEOUT 20
138820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_exec_internal_tmf_task(struct domain_device *dev,
138920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			void *parameter, u32 para_len, struct mvs_tmf_task *tmf)
139020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
139120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int res, retry;
139220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_task *task = NULL;
13938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
139420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (retry = 0; retry < 3; retry++) {
13954fcf812ca392303aa79dd50e96e83a29faa13bd0Dan Williams		task = sas_alloc_task(GFP_KERNEL);
139620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (!task)
139720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			return -ENOMEM;
13988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
139920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->dev = dev;
140020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->task_proto = dev->tproto;
14018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
140220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		memcpy(&task->ssp_task, parameter, para_len);
140320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->task_done = mvs_task_done;
14048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
140520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->timer.data = (unsigned long) task;
140620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->timer.function = mvs_tmf_timedout;
140720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
140820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		add_timer(&task->timer);
14098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14100b84b7094e87769120def1e703b8b4d037281038Andy Yan		res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf);
14118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
141220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (res) {
141320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			del_timer(&task->timer);
141420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_printk("executing internel task failed:%d\n", res);
141520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			goto ex_err;
141620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
14178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
141820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		wait_for_completion(&task->completion);
141984fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		res = TMF_RESP_FUNC_FAILED;
142020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* Even TMF timed out, return direct. */
142120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
142220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
142320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_printk("TMF task[%x] timeout.\n", tmf->tmf);
142420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				goto ex_err;
142520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
142620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
14278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
142820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (task->task_status.resp == SAS_TASK_COMPLETE &&
1429df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley		    task->task_status.stat == SAM_STAT_GOOD) {
143020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			res = TMF_RESP_FUNC_COMPLETE;
143120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
143220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1433b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
143420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (task->task_status.resp == SAS_TASK_COMPLETE &&
143520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		      task->task_status.stat == SAS_DATA_UNDERRUN) {
143620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			/* no error, but return the number of bytes of
143720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			 * underrun */
143820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			res = task->task_status.residual;
143920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
144020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
144220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (task->task_status.resp == SAS_TASK_COMPLETE &&
144320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		      task->task_status.stat == SAS_DATA_OVERRUN) {
144420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_dprintk("blocked task error.\n");
144520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			res = -EMSGSIZE;
144620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
144720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else {
144820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_dprintk(" task to dev %016llx response: 0x%x "
144920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    "status 0x%x\n",
145020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    SAS_ADDR(dev->sas_addr),
145120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    task->task_status.resp,
145220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				    task->task_status.stat);
14534fcf812ca392303aa79dd50e96e83a29faa13bd0Dan Williams			sas_free_task(task);
145420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			task = NULL;
1455b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1456dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		}
1457dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
145820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanex_err:
145920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	BUG_ON(retry == 3 && task != NULL);
14604fcf812ca392303aa79dd50e96e83a29faa13bd0Dan Williams	sas_free_task(task);
146120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return res;
1462dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
1463b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
146420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_debug_issue_ssp_tmf(struct domain_device *dev,
146520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				u8 *lun, struct mvs_tmf_task *tmf)
1466dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
146720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_ssp_task ssp_task;
146820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!(dev->tproto & SAS_PROTOCOL_SSP))
146920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return TMF_RESP_FUNC_ESUPP;
1470b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
147184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	memcpy(ssp_task.LUN, lun, 8);
1472b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
147320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return mvs_exec_internal_tmf_task(dev, &ssp_task,
147420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				sizeof(ssp_task), tmf);
147520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
14768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
14778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
147820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/*  Standard mandates link reset for ATA  (type 0)
147920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan    and hard reset for SSP (type 1) , only for RECOVERY */
148020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
148120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
148220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc;
148320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_phy *phy = sas_find_local_phy(dev);
148420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int reset_type = (dev->dev_type == SATA_DEV ||
148520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			(dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
148620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = sas_phy_reset(phy, reset_type);
148720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	msleep(2000);
148820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
148920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
14908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
149120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* mandatory SAM-3 */
149220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_lu_reset(struct domain_device *dev, u8 *lun)
149320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
149420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags;
149584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	int rc = TMF_RESP_FUNC_FAILED;
149620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
1497f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device * mvi_dev = dev->lldd_dev;
14989870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_info *mvi = mvi_dev->mvi_info;
149920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
150020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmf_task.tmf = TMF_LU_RESET;
150120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi_dev->dev_status = MVS_DEV_EH;
150220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
150320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (rc == TMF_RESP_FUNC_COMPLETE) {
150420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_lock_irqsave(&mvi->lock, flags);
150584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		mvs_release_task(mvi, dev);
150620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_unlock_irqrestore(&mvi->lock, flags);
1507dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
150820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* If failed, fall-through I_T_Nexus reset */
150920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_printk("%s for device[%x]:rc= %d\n", __func__,
151020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvi_dev->device_id, rc);
151120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
151220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
15138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
151420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_I_T_nexus_reset(struct domain_device *dev)
151520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
151620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags;
15179dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	int rc = TMF_RESP_FUNC_FAILED;
15189dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas    struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;
15199870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_info *mvi = mvi_dev->mvi_info;
152020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
152120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi_dev->dev_status != MVS_DEV_EH)
152220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return TMF_RESP_FUNC_COMPLETE;
152384fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	else
152484fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		mvi_dev->dev_status = MVS_DEV_NORMAL;
152520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_I_T_nexus_reset(dev);
152620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_printk("%s for device[%x]:rc= %d\n",
152720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		__func__, mvi_dev->device_id, rc);
152820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
152920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock_irqsave(&mvi->lock, flags);
15309dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvs_release_task(mvi, dev);
153120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock_irqrestore(&mvi->lock, flags);
153220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
153320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
153420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
153520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* optional SAM-3 */
153620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_query_task(struct sas_task *task)
153720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
153820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tag;
153920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct scsi_lun lun;
154020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
154120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
154220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
154320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
154420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
154520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct domain_device *dev = task->dev;
15469870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan		struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
15479870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan		struct mvs_info *mvi = mvi_dev->mvi_info;
154820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
154920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int_to_scsilun(cmnd->device->lun, &lun);
155020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = mvs_find_tag(mvi, task, &tag);
155120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rc == 0) {
155220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			rc = TMF_RESP_FUNC_FAILED;
1553dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik			return rc;
155420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
15558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
155620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmf_task.tmf = TMF_QUERY_TASK;
155720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
15588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
155920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
156020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		switch (rc) {
156120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* The task is still in Lun, release it then */
156220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_RESP_FUNC_SUCC:
156320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* The task is not in Lun or failed, reset the phy */
156420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_RESP_FUNC_FAILED:
156520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		case TMF_RESP_FUNC_COMPLETE:
156620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
156720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1568dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
156920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mv_printk("%s:rc= %d\n", __func__, rc);
157020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
15718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
15728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
157320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/*  mandatory SAM-3, still need free task/slot info */
157420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_abort_task(struct sas_task *task)
15758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
157620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct scsi_lun lun;
157720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
157820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct domain_device *dev = task->dev;
15799870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
158024ae163ed33d2b8a70d2f0b1947b401d0a8e8719Jiri Slaby	struct mvs_info *mvi;
158120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
158220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags;
158320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tag;
15849870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan
15859dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (!mvi_dev) {
158684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		mv_printk("Device has removed\n");
158784fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		return TMF_RESP_FUNC_FAILED;
15889dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	}
15899dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
159024ae163ed33d2b8a70d2f0b1947b401d0a8e8719Jiri Slaby	mvi = mvi_dev->mvi_info;
159124ae163ed33d2b8a70d2f0b1947b401d0a8e8719Jiri Slaby
159220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock_irqsave(&task->task_state_lock, flags);
159320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
159420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		spin_unlock_irqrestore(&task->task_state_lock, flags);
159520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = TMF_RESP_FUNC_COMPLETE;
159620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		goto out;
1597dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
159820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock_irqrestore(&task->task_state_lock, flags);
15999dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvi_dev->dev_status = MVS_DEV_EH;
160020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
160120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
160220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
160320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int_to_scsilun(cmnd->device->lun, &lun);
160420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = mvs_find_tag(mvi, task, &tag);
160520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rc == 0) {
160620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_printk("No such tag in %s\n", __func__);
160720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			rc = TMF_RESP_FUNC_FAILED;
160820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			return rc;
160920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
16108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
161120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmf_task.tmf = TMF_ABORT_TASK;
161220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
16138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
161420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
16158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
161620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* if successful, clear the task and callback forwards.*/
161720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rc == TMF_RESP_FUNC_COMPLETE) {
161820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			u32 slot_no;
161920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct mvs_slot_info *slot;
16208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
162120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (task->lldd_task) {
1622f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan				slot = task->lldd_task;
162320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				slot_no = (u32) (slot - mvi->slot_info);
16249dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				spin_lock_irqsave(&mvi->lock, flags);
162520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_slot_complete(mvi, slot_no, 1);
16269dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				spin_unlock_irqrestore(&mvi->lock, flags);
162720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
162820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
16299dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
163020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else if (task->task_proto & SAS_PROTOCOL_SATA ||
163120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->task_proto & SAS_PROTOCOL_STP) {
16329dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (SATA_DEV == dev->dev_type) {
16339dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			struct mvs_slot_info *slot = task->lldd_task;
16349dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			u32 slot_idx = (u32)(slot - mvi->slot_info);
163584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu			mv_dprintk("mvs_abort_task() mvi=%p task=%p "
16369dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				   "slot=%p slot_idx=x%x\n",
16379dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				   mvi, task, slot, slot_idx);
163884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu			mvs_tmf_timedout((unsigned long)task);
16399dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mvs_slot_task_free(mvi, task, slot, slot_idx);
164084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu			rc = TMF_RESP_FUNC_COMPLETE;
164184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu			goto out;
16429dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		}
16438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
164420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
164520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanout:
164620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (rc != TMF_RESP_FUNC_COMPLETE)
164720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("%s:rc= %d\n", __func__, rc);
1648dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	return rc;
16498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
16508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
165120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_abort_task_set(struct domain_device *dev, u8 *lun)
16528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
165320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
165420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
16558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
165620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmf_task.tmf = TMF_ABORT_TASK_SET;
165720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
1658dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
165920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
16608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
16618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
166220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_clear_aca(struct domain_device *dev, u8 *lun)
16638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
166420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
166520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
16668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
166720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmf_task.tmf = TMF_CLEAR_ACA;
166820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
16698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
167020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
167120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
16728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
167320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_clear_task_set(struct domain_device *dev, u8 *lun)
167420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
167520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int rc = TMF_RESP_FUNC_FAILED;
167620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_tmf_task tmf_task;
16778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
167820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tmf_task.tmf = TMF_CLEAR_TASK_SET;
167920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
16808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
168120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return rc;
1682dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik}
16838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
168420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
168520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			u32 slot_idx, int err)
1686dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{
1687f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan	struct mvs_device *mvi_dev = task->dev->lldd_dev;
168820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct task_status_struct *tstat = &task->task_status;
168920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
1690df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley	int stat = SAM_STAT_GOOD;
1691e9ff91b6927079307b5d481a93beac4134e923ebKe Wei
16928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
169320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	resp->frame_len = sizeof(struct dev_to_host_fis);
169420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memcpy(&resp->ending_fis[0],
169520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	       SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset),
169620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	       sizeof(struct dev_to_host_fis));
169720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tstat->buf_valid_size = sizeof(*resp);
16989dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (unlikely(err)) {
16999dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (unlikely(err & CMD_ISS_STPD))
17009dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			stat = SAS_OPEN_REJECT;
17019dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		else
17029dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			stat = SAS_PROTO_RESPONSE;
17039dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas       }
17049dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
170520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return stat;
17068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei}
17078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
1708a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yuvoid mvs_set_sense(u8 *buffer, int len, int d_sense,
1709a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		int key, int asc, int ascq)
1710a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu{
1711a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	memset(buffer, 0, len);
1712a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu
1713a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	if (d_sense) {
1714a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		/* Descriptor format */
1715a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (len < 4) {
1716a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			mv_printk("Length %d of sense buffer too small to "
1717a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu				"fit sense %x:%x:%x", len, key, asc, ascq);
1718a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		}
1719a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu
1720a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		buffer[0] = 0x72;		/* Response Code	*/
1721a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (len > 1)
1722a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			buffer[1] = key;	/* Sense Key */
1723a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (len > 2)
1724a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			buffer[2] = asc;	/* ASC	*/
1725a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (len > 3)
1726a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			buffer[3] = ascq;	/* ASCQ	*/
1727a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	} else {
1728a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (len < 14) {
1729a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			mv_printk("Length %d of sense buffer too small to "
1730a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu				"fit sense %x:%x:%x", len, key, asc, ascq);
1731a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		}
1732a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu
1733a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		buffer[0] = 0x70;		/* Response Code	*/
1734a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (len > 2)
1735a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			buffer[2] = key;	/* Sense Key */
1736a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (len > 7)
1737a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			buffer[7] = 0x0a;	/* Additional Sense Length */
1738a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (len > 12)
1739a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			buffer[12] = asc;	/* ASC */
1740a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (len > 13)
1741a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			buffer[13] = ascq; /* ASCQ */
1742a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	}
1743a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu
1744a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	return;
1745a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu}
1746a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu
1747a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yuvoid mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu,
1748a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu				u8 key, u8 asc, u8 asc_q)
1749a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu{
1750a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	iu->datapres = 2;
1751a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	iu->response_data_len = 0;
1752a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	iu->sense_data_len = 17;
1753a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	iu->status = 02;
1754a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	mvs_set_sense(iu->sense_data, 17, 0,
1755a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			key, asc, asc_q);
1756a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu}
1757a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu
175820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
175920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			 u32 slot_idx)
17608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{
176120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
176220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int stat;
176384fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	u32 err_dw0 = le32_to_cpu(*(u32 *)slot->response);
1764a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1));
176520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tfs = 0;
176620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	enum mvs_port_type type = PORT_TYPE_SAS;
17678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
176820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (err_dw0 & CMD_ISS_STPD)
176920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->issue_stop(mvi, type, tfs);
177020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
177120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	MVS_CHIP_DISP->command_active(mvi, slot_idx);
1772b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1773df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley	stat = SAM_STAT_CHECK_CONDITION;
1774dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	switch (task->task_proto) {
1775dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SSP:
1776a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	{
177720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		stat = SAS_ABORTED_TASK;
1778a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if ((err_dw0 & NO_DEST) || err_dw1 & bit(31)) {
1779a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			struct ssp_response_iu *iu = slot->response +
1780a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu				sizeof(struct mvs_err_info);
1781a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			mvs_fill_ssp_resp_iu(iu, NOT_READY, 0x04, 01);
1782a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			sas_ssp_task_response(mvi->dev, task, iu);
1783a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			stat = SAM_STAT_CHECK_CONDITION;
1784a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		}
1785a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		if (err_dw1 & bit(31))
1786a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			mv_printk("reuse same slot, retry command.\n");
178720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
1788a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	}
178920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SMP:
1790df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley		stat = SAM_STAT_CHECK_CONDITION;
1791dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
179220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
1793dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_SATA:
1794dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	case SAS_PROTOCOL_STP:
179520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
179620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	{
179720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->ata_task.use_ncq = 0;
179884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		stat = SAS_PROTO_RESPONSE;
17999dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvs_sata_done(mvi, task, slot_idx, err_dw0);
1800dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
180120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
1802dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	default:
1803dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik		break;
1804dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik	}
1805dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik
180620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return stat;
1807e9ff91b6927079307b5d481a93beac4134e923ebKe Wei}
1808e9ff91b6927079307b5d481a93beac4134e923ebKe Wei
180920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
1810b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
181120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
181220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
181320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct sas_task *task = slot->task;
181420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_device *mvi_dev = NULL;
181520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct task_status_struct *tstat;
18169dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	struct domain_device *dev;
18179dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	u32 aborted;
181820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
181920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	void *to;
182020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	enum exec_status sts;
182120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
18229dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (unlikely(!task || !task->lldd_task || !task->dev))
182320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return -1;
182420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
182520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tstat = &task->task_status;
18269dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	dev = task->dev;
18279dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvi_dev = dev->lldd_dev;
1828b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
182920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock(&task->task_state_lock);
183020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	task->task_state_flags &=
183120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
183220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	task->task_state_flags |= SAS_TASK_STATE_DONE;
183320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* race condition*/
183420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
183520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock(&task->task_state_lock);
183620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
183720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	memset(tstat, 0, sizeof(*tstat));
183820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	tstat->resp = SAS_TASK_COMPLETE;
183920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
184020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (unlikely(aborted)) {
184120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tstat->stat = SAS_ABORTED_TASK;
18429dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (mvi_dev && mvi_dev->running_req)
18439dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mvi_dev->running_req--;
184420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (sas_protocol_ata(task->task_proto))
184520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_free_reg_set(mvi, mvi_dev);
184620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
184720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_slot_task_free(mvi, task, slot, slot_idx);
184820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return -1;
1849b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1850b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
1851e144f7ef49ec85e9dfdf130f3a9a2372fe5fe39bXiangliang Yu	/* when no device attaching, go ahead and complete by error handling*/
18529dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (unlikely(!mvi_dev || flags)) {
18539dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (!mvi_dev)
18549dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mv_dprintk("port has not device.\n");
185520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tstat->stat = SAS_PHY_DOWN;
185620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		goto out;
185720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
1858b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
185920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* error info record present */
186020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
186184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		mv_dprintk("port %d slot %d rx_desc %X has error info"
186284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu			"%016llX.\n", slot->port->sas_port.id, slot_idx,
186384fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu			 rx_desc, (u64)(*(u64 *)slot->response));
186420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tstat->stat = mvs_slot_err(mvi, task, slot_idx);
18659dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		tstat->resp = SAS_TASK_COMPLETE;
186620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		goto out;
1867b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
1868b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
186920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	switch (task->task_proto) {
187020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SSP:
187120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* hw says status == 0, datapres == 0 */
187220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rx_desc & RXQ_GOOD) {
1873df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley			tstat->stat = SAM_STAT_GOOD;
187420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			tstat->resp = SAS_TASK_COMPLETE;
187520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
187620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* response frame present */
187720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		else if (rx_desc & RXQ_RSP) {
187820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct ssp_response_iu *iu = slot->response +
187920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						sizeof(struct mvs_err_info);
188020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			sas_ssp_task_response(mvi->dev, task, iu);
188120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else
1882df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley			tstat->stat = SAM_STAT_CHECK_CONDITION;
188320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
1884b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
188520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SMP: {
188620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct scatterlist *sg_resp = &task->smp_task.smp_resp;
1887df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley			tstat->stat = SAM_STAT_GOOD;
188820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
188920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			memcpy(to + sg_resp->offset,
189020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				slot->response + sizeof(struct mvs_err_info),
189120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				sg_dma_len(sg_resp));
189220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			kunmap_atomic(to, KM_IRQ0);
189320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
189420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
18958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
189620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SATA:
189720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_STP:
189820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
189920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
190020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			break;
190120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
1902b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
190320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	default:
1904df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley		tstat->stat = SAM_STAT_CHECK_CONDITION;
190520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		break;
190620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
19079dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (!slot->port->port_attached) {
19089dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mv_dprintk("port %d has removed.\n", slot->port->sas_port.id);
19099dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		tstat->stat = SAS_PHY_DOWN;
19109dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	}
19119dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
1912b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
191320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanout:
19149dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (mvi_dev && mvi_dev->running_req) {
19159dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvi_dev->running_req--;
19169dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		if (sas_protocol_ata(task->task_proto) && !mvi_dev->running_req)
19170f980a871678b7ec143fcb45b31bf9234e4585c8Andy Yan			mvs_free_reg_set(mvi, mvi_dev);
19180f980a871678b7ec143fcb45b31bf9234e4585c8Andy Yan	}
191920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvs_slot_task_free(mvi, task, slot, slot_idx);
192020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	sts = tstat->stat;
19218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
192220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock(&mvi->lock);
192320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (task->task_done)
192420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task->task_done(task);
192584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu
192620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock(&mvi->lock);
1927b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
192820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return sts;
192920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1930b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19319dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivasvoid mvs_do_release_task(struct mvs_info *mvi,
193220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		int phy_no, struct domain_device *dev)
193320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
19349dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	u32 slot_idx;
193520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_phy *phy;
193620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_port *port;
193720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_slot_info *slot, *slot2;
1938b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
193920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy = &mvi->phy[phy_no];
194020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	port = phy->port;
194120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (!port)
194220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return;
19439dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	/* clean cmpl queue in case request is already finished */
19449dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	mvs_int_rx(mvi, false);
19459dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
19469dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
1947b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
194820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	list_for_each_entry_safe(slot, slot2, &port->list, entry) {
194920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		struct sas_task *task;
195020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		slot_idx = (u32) (slot - mvi->slot_info);
195120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		task = slot->task;
1952b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
195320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (dev && task->dev != dev)
195420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			continue;
19558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
195620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_printk("Release slot [%x] tag[%x], task [%p]:\n",
195720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			slot_idx, slot->slot_tag, task);
19589dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		MVS_CHIP_DISP->command_active(mvi, slot_idx);
1959b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
196020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvs_slot_complete(mvi, slot_idx, 1);
1961b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
196220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
1963b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
19649dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivasvoid mvs_release_task(struct mvs_info *mvi,
19659dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		      struct domain_device *dev)
19669dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas{
19679dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	int i, phyno[WIDE_PORT_MAX_PHY], num;
19689dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	num = mvs_find_dev_phyno(dev, phyno);
19699dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	for (i = 0; i < num; i++)
19709dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		mvs_do_release_task(mvi, phyno[i], dev);
19719dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas}
19729dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
197320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_phy_disconnected(struct mvs_phy *phy)
197420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
197520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy->phy_attached = 0;
197620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy->att_dev_info = 0;
197720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy->att_dev_sas_addr = 0;
197820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
197920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
198020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_work_queue(struct work_struct *work)
198120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
198220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct delayed_work *dw = container_of(work, struct delayed_work, work);
198320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q);
198420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = mwq->mvi;
198520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	unsigned long flags;
1986a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	u32 phy_no = (unsigned long) mwq->data;
1987a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	struct sas_ha_struct *sas_ha = mvi->sas;
1988a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	struct mvs_phy *phy = &mvi->phy[phy_no];
1989a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	struct asd_sas_phy *sas_phy = &phy->sas_phy;
1990b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
199120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_lock_irqsave(&mvi->lock, flags);
199220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mwq->handler & PHY_PLUG_EVENT) {
199320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
199420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy->phy_event & PHY_PLUG_OUT) {
199520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			u32 tmp;
199620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			struct sas_identify_frame *id;
199720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			id = (struct sas_identify_frame *)phy->frame_rcvd;
199820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no);
199920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->phy_event &= ~PHY_PLUG_OUT;
200020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (!(tmp & PHY_READY_MASK)) {
200120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				sas_phy_disconnected(sas_phy);
200220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_phy_disconnected(phy);
200320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				sas_ha->notify_phy_event(sas_phy,
200420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					PHYE_LOSS_OF_SIGNAL);
200520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_dprintk("phy%d Removed Device\n", phy_no);
200620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			} else {
200720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
200820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_update_phyinfo(mvi, phy_no, 1);
200920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_bytes_dmaed(mvi, phy_no);
201020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_port_notify_formed(sas_phy, 0);
201120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mv_dprintk("phy%d Attached Device\n", phy_no);
201220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
201320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
2014a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu	} else if (mwq->handler & EXP_BRCT_CHG) {
2015a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		phy->phy_event &= ~EXP_BRCT_CHG;
2016a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		sas_ha->notify_port_event(sas_phy,
2017a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu				PORTE_BROADCAST_RCVD);
2018a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		mv_dprintk("phy%d Got Broadcast Change\n", phy_no);
201920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
202020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	list_del(&mwq->entry);
202120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	spin_unlock_irqrestore(&mvi->lock, flags);
202220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	kfree(mwq);
202320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
20248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
202520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_handle_event(struct mvs_info *mvi, void *data, int handler)
202620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
202720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_wq *mwq;
202820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	int ret = 0;
202920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
203020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC);
203120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mwq) {
203220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mwq->mvi = mvi;
203320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mwq->data = data;
203420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mwq->handler = handler;
203520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq);
203620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		list_add_tail(&mwq->entry, &mvi->wq_list);
203720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		schedule_delayed_work(&mwq->work_q, HZ * 2);
203820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else
203920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		ret = -ENOMEM;
204020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
204120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return ret;
204220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
2043b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
204420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_sig_time_out(unsigned long tphy)
204520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
204620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_phy *phy = (struct mvs_phy *)tphy;
204720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_info *mvi = phy->mvi;
204820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u8 phy_no;
204920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
205020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	for (phy_no = 0; phy_no < mvi->chip->n_phy; phy_no++) {
205120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (&mvi->phy[phy_no] == phy) {
205220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_dprintk("Get signature time out, reset phy %d\n",
205320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy_no+mvi->id*mvi->chip->n_phy);
2054a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu			MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_HARD_RESET);
205520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
2056b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik	}
205720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan}
2058b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
205920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
206020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{
206120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 tmp;
206220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	struct mvs_phy *phy = &mvi->phy[phy_no];
20638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
206420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
206584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
206684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	mv_dprintk("phy %d ctrl sts=0x%08X.\n", phy_no+mvi->id*mvi->chip->n_phy,
206720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no));
206884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu	mv_dprintk("phy %d irq sts = 0x%08X\n", phy_no+mvi->id*mvi->chip->n_phy,
206920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		phy->irq_status);
20708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei
207120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/*
207220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	* events is port event now ,
207320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	* we need check the interrupt status which belongs to per port.
207420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	*/
2075b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
20769dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	if (phy->irq_status & PHYEV_DCDR_ERR) {
207784fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		mv_dprintk("phy %d STP decoding error.\n",
20789dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas		phy_no + mvi->id*mvi->chip->n_phy);
20799dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas	}
208020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
208120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (phy->irq_status & PHYEV_POOF) {
208284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		mdelay(500);
208320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (!(phy->phy_event & PHY_PLUG_OUT)) {
208420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			int dev_sata = phy->phy_type & PORT_TYPE_SATA;
208520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			int ready;
20869dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			mvs_do_release_task(mvi, phy_no, NULL);
208720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->phy_event |= PHY_PLUG_OUT;
20889dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			MVS_CHIP_DISP->clear_srs_irq(mvi, 0, 1);
208920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_handle_event(mvi,
209020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				(void *)(unsigned long)phy_no,
209120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				PHY_PLUG_EVENT);
209220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			ready = mvs_is_phy_ready(mvi, phy_no);
209320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (ready || dev_sata) {
209420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				if (MVS_CHIP_DISP->stp_reset)
209520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					MVS_CHIP_DISP->stp_reset(mvi,
209620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan							phy_no);
209720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				else
209820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					MVS_CHIP_DISP->phy_reset(mvi,
2099a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu							phy_no, MVS_SOFT_RESET);
210020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				return;
210120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
210220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
210320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
2104b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
210520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (phy->irq_status & PHYEV_COMWAKE) {
210620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, phy_no);
210720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no,
210820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan					tmp | PHYEV_SIG_FIS);
210920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy->timer.function == NULL) {
211020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->timer.data = (unsigned long)phy;
211120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy->timer.function = mvs_sig_time_out;
211284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu			phy->timer.expires = jiffies + 5*HZ;
211320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			add_timer(&phy->timer);
211420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
211520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
211620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
211720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
211820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mv_dprintk("notify plug in on phy[%d]\n", phy_no);
211920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (phy->phy_status) {
212020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mdelay(10);
212120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
212220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (phy->phy_type & PORT_TYPE_SATA) {
212320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				tmp = MVS_CHIP_DISP->read_port_irq_mask(
212420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan						mvi, phy_no);
212520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				tmp &= ~PHYEV_SIG_FIS;
212620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				MVS_CHIP_DISP->write_port_irq_mask(mvi,
212720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan							phy_no, tmp);
212820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
212920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_update_phyinfo(mvi, phy_no, 0);
21309dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			if (phy->phy_type & PORT_TYPE_SAS) {
2131a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu				MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_PHY_TUNE);
21329dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas				mdelay(10);
21339dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas			}
21349dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas
213520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_bytes_dmaed(mvi, phy_no);
213620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			/* whether driver is going to handle hot plug */
213720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (phy->phy_event & PHY_PLUG_OUT) {
2138a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu				mvs_port_notify_formed(&phy->sas_phy, 0);
213920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy->phy_event &= ~PHY_PLUG_OUT;
214020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			}
214120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else {
214220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mv_dprintk("plugin interrupt but phy%d is gone\n",
214320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				phy_no + mvi->id*mvi->chip->n_phy);
214420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
214520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	} else if (phy->irq_status & PHYEV_BROAD_CH) {
214684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu		mv_dprintk("phy %d broadcast change.\n",
214720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			phy_no + mvi->id*mvi->chip->n_phy);
2148a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu		mvs_handle_event(mvi, (void *)(unsigned long)phy_no,
2149a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu				EXP_BRCT_CHG);
215020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
2151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2152b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
215320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_int_rx(struct mvs_info *mvi, bool self_clear)
2154b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{
215520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	u32 rx_prod_idx, rx_desc;
215620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	bool attn = false;
2157b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
215820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* the first dword in the RX ring is special: it contains
215920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	 * a mirror of the hardware's RX producer index, so that
216020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	 * we don't have to stall the CPU reading that register.
216120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	 * The actual RX ring is offset by one dword, due to this.
216220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	 */
216320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	rx_prod_idx = mvi->rx_cons;
216420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
216520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->rx_cons == 0xfff)	/* h/w hasn't touched RX ring yet */
216620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return 0;
2167b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
216820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	/* The CMPL_Q may come late, read from register and try again
216920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	* note: if coalescing is enabled,
217020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	* it will need to read from register every time for sure
217120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	*/
217220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (unlikely(mvi->rx_cons == rx_prod_idx))
217320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		mvi->rx_cons = MVS_CHIP_DISP->rx_update(mvi) & RX_RING_SZ_MASK;
217420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
217520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (mvi->rx_cons == rx_prod_idx)
217620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		return 0;
217720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
217820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	while (mvi->rx_cons != rx_prod_idx) {
217920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		/* increment our internal RX consumer pointer */
218020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
218120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
218220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
218320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (likely(rx_desc & RXQ_DONE))
218420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_slot_complete(mvi, rx_desc, 0);
218520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		if (rx_desc & RXQ_ATTN) {
218620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			attn = true;
218720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else if (rx_desc & RXQ_ERR) {
218820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			if (!(rx_desc & RXQ_DONE))
218920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan				mvs_slot_complete(mvi, rx_desc, 0);
219020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		} else if (rx_desc & RXQ_SLOT_RESET) {
219120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan			mvs_slot_free(mvi, rx_desc);
219220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		}
219320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	}
219420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan
219520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	if (attn && self_clear)
219620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan		MVS_CHIP_DISP->int_full(mvi);
219720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan	return 0;
2198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik}
2199b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik
2200