xref: /openbmc/linux/drivers/scsi/mvsas/mv_sas.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1873e65bcSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22ad52f47SJeff Garzik /*
320b09c29SAndy Yan  * Marvell 88SE64xx/88SE94xx main function
420b09c29SAndy Yan  *
520b09c29SAndy Yan  * Copyright 2007 Red Hat, Inc.
620b09c29SAndy Yan  * Copyright 2008 Marvell. <kewei@marvell.com>
70b15fb1fSXiangliang Yu  * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
82ad52f47SJeff Garzik */
92ad52f47SJeff Garzik 
10dd4969a8SJeff Garzik #include "mv_sas.h"
112ad52f47SJeff Garzik 
mvs_find_tag(struct mvs_info * mvi,struct sas_task * task,u32 * tag)12dd4969a8SJeff Garzik static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
13dd4969a8SJeff Garzik {
14dd4969a8SJeff Garzik 	if (task->lldd_task) {
15dd4969a8SJeff Garzik 		struct mvs_slot_info *slot;
16f9da3be5SAndy Yan 		slot = task->lldd_task;
1720b09c29SAndy Yan 		*tag = slot->slot_tag;
18dd4969a8SJeff Garzik 		return 1;
19dd4969a8SJeff Garzik 	}
20dd4969a8SJeff Garzik 	return 0;
21dd4969a8SJeff Garzik }
222ad52f47SJeff Garzik 
mvs_tag_clear(struct mvs_info * mvi,u32 tag)232acf97f1SJohn Garry static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
24dd4969a8SJeff Garzik {
252acf97f1SJohn Garry 	void *bitmap = mvi->rsvd_tags;
26dd4969a8SJeff Garzik 	clear_bit(tag, bitmap);
27dd4969a8SJeff Garzik }
282ad52f47SJeff Garzik 
mvs_tag_free(struct mvs_info * mvi,u32 tag)292acf97f1SJohn Garry static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
30dd4969a8SJeff Garzik {
312acf97f1SJohn Garry 	if (tag >= MVS_RSVD_SLOTS)
322acf97f1SJohn Garry 		return;
332acf97f1SJohn Garry 
34dd4969a8SJeff Garzik 	mvs_tag_clear(mvi, tag);
35dd4969a8SJeff Garzik }
362ad52f47SJeff Garzik 
mvs_tag_set(struct mvs_info * mvi,unsigned int tag)372acf97f1SJohn Garry static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
38dd4969a8SJeff Garzik {
392acf97f1SJohn Garry 	void *bitmap = mvi->rsvd_tags;
40dd4969a8SJeff Garzik 	set_bit(tag, bitmap);
41dd4969a8SJeff Garzik }
42dd4969a8SJeff Garzik 
mvs_tag_alloc(struct mvs_info * mvi,u32 * tag_out)432acf97f1SJohn Garry static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
44dd4969a8SJeff Garzik {
45dd4969a8SJeff Garzik 	unsigned int index, tag;
462acf97f1SJohn Garry 	void *bitmap = mvi->rsvd_tags;
47dd4969a8SJeff Garzik 
482acf97f1SJohn Garry 	index = find_first_zero_bit(bitmap, MVS_RSVD_SLOTS);
49dd4969a8SJeff Garzik 	tag = index;
502acf97f1SJohn Garry 	if (tag >= MVS_RSVD_SLOTS)
51dd4969a8SJeff Garzik 		return -SAS_QUEUE_FULL;
52dd4969a8SJeff Garzik 	mvs_tag_set(mvi, tag);
53dd4969a8SJeff Garzik 	*tag_out = tag;
54dd4969a8SJeff Garzik 	return 0;
55dd4969a8SJeff Garzik }
56dd4969a8SJeff Garzik 
mvs_find_dev_mvi(struct domain_device * dev)5714bf41dcSBaoyou Xie static struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
5820b09c29SAndy Yan {
5920b09c29SAndy Yan 	unsigned long i = 0, j = 0, hi = 0;
6020b09c29SAndy Yan 	struct sas_ha_struct *sha = dev->port->ha;
6120b09c29SAndy Yan 	struct mvs_info *mvi = NULL;
6220b09c29SAndy Yan 	struct asd_sas_phy *phy;
6320b09c29SAndy Yan 
6420b09c29SAndy Yan 	while (sha->sas_port[i]) {
6520b09c29SAndy Yan 		if (sha->sas_port[i] == dev->port) {
66133b688bSXiang Chen 			spin_lock(&sha->sas_port[i]->phy_list_lock);
6720b09c29SAndy Yan 			phy =  container_of(sha->sas_port[i]->phy_list.next,
6820b09c29SAndy Yan 				struct asd_sas_phy, port_phy_el);
69133b688bSXiang Chen 			spin_unlock(&sha->sas_port[i]->phy_list_lock);
7020b09c29SAndy Yan 			j = 0;
7120b09c29SAndy Yan 			while (sha->sas_phy[j]) {
7220b09c29SAndy Yan 				if (sha->sas_phy[j] == phy)
7320b09c29SAndy Yan 					break;
7420b09c29SAndy Yan 				j++;
7520b09c29SAndy Yan 			}
7620b09c29SAndy Yan 			break;
7720b09c29SAndy Yan 		}
7820b09c29SAndy Yan 		i++;
7920b09c29SAndy Yan 	}
8020b09c29SAndy Yan 	hi = j/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
8120b09c29SAndy Yan 	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
8220b09c29SAndy Yan 
8320b09c29SAndy Yan 	return mvi;
8420b09c29SAndy Yan 
8520b09c29SAndy Yan }
8620b09c29SAndy Yan 
mvs_find_dev_phyno(struct domain_device * dev,int * phyno)8714bf41dcSBaoyou Xie static int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
8820b09c29SAndy Yan {
8920b09c29SAndy Yan 	unsigned long i = 0, j = 0, n = 0, num = 0;
909870d9a2SAndy Yan 	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
919870d9a2SAndy Yan 	struct mvs_info *mvi = mvi_dev->mvi_info;
9220b09c29SAndy Yan 	struct sas_ha_struct *sha = dev->port->ha;
9320b09c29SAndy Yan 
9420b09c29SAndy Yan 	while (sha->sas_port[i]) {
9520b09c29SAndy Yan 		if (sha->sas_port[i] == dev->port) {
9620b09c29SAndy Yan 			struct asd_sas_phy *phy;
97133b688bSXiang Chen 
98133b688bSXiang Chen 			spin_lock(&sha->sas_port[i]->phy_list_lock);
9920b09c29SAndy Yan 			list_for_each_entry(phy,
10020b09c29SAndy Yan 				&sha->sas_port[i]->phy_list, port_phy_el) {
10120b09c29SAndy Yan 				j = 0;
10220b09c29SAndy Yan 				while (sha->sas_phy[j]) {
10320b09c29SAndy Yan 					if (sha->sas_phy[j] == phy)
10420b09c29SAndy Yan 						break;
10520b09c29SAndy Yan 					j++;
10620b09c29SAndy Yan 				}
10720b09c29SAndy Yan 				phyno[n] = (j >= mvi->chip->n_phy) ?
10820b09c29SAndy Yan 					(j - mvi->chip->n_phy) : j;
10920b09c29SAndy Yan 				num++;
11020b09c29SAndy Yan 				n++;
11120b09c29SAndy Yan 			}
112133b688bSXiang Chen 			spin_unlock(&sha->sas_port[i]->phy_list_lock);
11320b09c29SAndy Yan 			break;
11420b09c29SAndy Yan 		}
11520b09c29SAndy Yan 		i++;
11620b09c29SAndy Yan 	}
11720b09c29SAndy Yan 	return num;
11820b09c29SAndy Yan }
11920b09c29SAndy Yan 
mvs_find_dev_by_reg_set(struct mvs_info * mvi,u8 reg_set)120534ff101SXiangliang Yu struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi,
121534ff101SXiangliang Yu 						u8 reg_set)
122534ff101SXiangliang Yu {
123534ff101SXiangliang Yu 	u32 dev_no;
124534ff101SXiangliang Yu 	for (dev_no = 0; dev_no < MVS_MAX_DEVICES; dev_no++) {
125534ff101SXiangliang Yu 		if (mvi->devices[dev_no].taskfileset == MVS_ID_NOT_MAPPED)
126534ff101SXiangliang Yu 			continue;
127534ff101SXiangliang Yu 
128534ff101SXiangliang Yu 		if (mvi->devices[dev_no].taskfileset == reg_set)
129534ff101SXiangliang Yu 			return &mvi->devices[dev_no];
130534ff101SXiangliang Yu 	}
131534ff101SXiangliang Yu 	return NULL;
132534ff101SXiangliang Yu }
133534ff101SXiangliang Yu 
mvs_free_reg_set(struct mvs_info * mvi,struct mvs_device * dev)13420b09c29SAndy Yan static inline void mvs_free_reg_set(struct mvs_info *mvi,
13520b09c29SAndy Yan 				struct mvs_device *dev)
13620b09c29SAndy Yan {
13720b09c29SAndy Yan 	if (!dev) {
13820b09c29SAndy Yan 		mv_printk("device has been free.\n");
13920b09c29SAndy Yan 		return;
14020b09c29SAndy Yan 	}
14120b09c29SAndy Yan 	if (dev->taskfileset == MVS_ID_NOT_MAPPED)
14220b09c29SAndy Yan 		return;
14320b09c29SAndy Yan 	MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset);
14420b09c29SAndy Yan }
14520b09c29SAndy Yan 
mvs_assign_reg_set(struct mvs_info * mvi,struct mvs_device * dev)14620b09c29SAndy Yan static inline u8 mvs_assign_reg_set(struct mvs_info *mvi,
14720b09c29SAndy Yan 				struct mvs_device *dev)
14820b09c29SAndy Yan {
14920b09c29SAndy Yan 	if (dev->taskfileset != MVS_ID_NOT_MAPPED)
15020b09c29SAndy Yan 		return 0;
15120b09c29SAndy Yan 	return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset);
15220b09c29SAndy Yan }
15320b09c29SAndy Yan 
mvs_phys_reset(struct mvs_info * mvi,u32 phy_mask,int hard)15420b09c29SAndy Yan void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard)
15520b09c29SAndy Yan {
15620b09c29SAndy Yan 	u32 no;
15720b09c29SAndy Yan 	for_each_phy(phy_mask, phy_mask, no) {
15820b09c29SAndy Yan 		if (!(phy_mask & 1))
15920b09c29SAndy Yan 			continue;
16020b09c29SAndy Yan 		MVS_CHIP_DISP->phy_reset(mvi, no, hard);
16120b09c29SAndy Yan 	}
16220b09c29SAndy Yan }
16320b09c29SAndy Yan 
mvs_phy_control(struct asd_sas_phy * sas_phy,enum phy_func func,void * funcdata)16420b09c29SAndy Yan int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
16520b09c29SAndy Yan 			void *funcdata)
16620b09c29SAndy Yan {
16720b09c29SAndy Yan 	int rc = 0, phy_id = sas_phy->id;
16820b09c29SAndy Yan 	u32 tmp, i = 0, hi;
16920b09c29SAndy Yan 	struct sas_ha_struct *sha = sas_phy->ha;
17020b09c29SAndy Yan 	struct mvs_info *mvi = NULL;
17120b09c29SAndy Yan 
17220b09c29SAndy Yan 	while (sha->sas_phy[i]) {
17320b09c29SAndy Yan 		if (sha->sas_phy[i] == sas_phy)
17420b09c29SAndy Yan 			break;
17520b09c29SAndy Yan 		i++;
17620b09c29SAndy Yan 	}
17720b09c29SAndy Yan 	hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy;
17820b09c29SAndy Yan 	mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi];
1792ad52f47SJeff Garzik 
180dd4969a8SJeff Garzik 	switch (func) {
18120b09c29SAndy Yan 	case PHY_FUNC_SET_LINK_RATE:
18220b09c29SAndy Yan 		MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata);
183dd4969a8SJeff Garzik 		break;
1842ad52f47SJeff Garzik 
185dd4969a8SJeff Garzik 	case PHY_FUNC_HARD_RESET:
18620b09c29SAndy Yan 		tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id);
187dd4969a8SJeff Garzik 		if (tmp & PHY_RST_HARD)
188dd4969a8SJeff Garzik 			break;
189a4632aaeSXiangliang Yu 		MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_HARD_RESET);
190dd4969a8SJeff Garzik 		break;
1912ad52f47SJeff Garzik 
192dd4969a8SJeff Garzik 	case PHY_FUNC_LINK_RESET:
19320b09c29SAndy Yan 		MVS_CHIP_DISP->phy_enable(mvi, phy_id);
194a4632aaeSXiangliang Yu 		MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_SOFT_RESET);
195dd4969a8SJeff Garzik 		break;
1962ad52f47SJeff Garzik 
197dd4969a8SJeff Garzik 	case PHY_FUNC_DISABLE:
19820b09c29SAndy Yan 		MVS_CHIP_DISP->phy_disable(mvi, phy_id);
19920b09c29SAndy Yan 		break;
200dd4969a8SJeff Garzik 	case PHY_FUNC_RELEASE_SPINUP_HOLD:
201dd4969a8SJeff Garzik 	default:
202ac013ed1SDan Williams 		rc = -ENOSYS;
2032ad52f47SJeff Garzik 	}
20420b09c29SAndy Yan 	msleep(200);
2052ad52f47SJeff Garzik 	return rc;
2062ad52f47SJeff Garzik }
2072ad52f47SJeff Garzik 
mvs_set_sas_addr(struct mvs_info * mvi,int port_id,u32 off_lo,u32 off_hi,u64 sas_addr)2086f039790SGreg Kroah-Hartman void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo,
2096f039790SGreg Kroah-Hartman 		      u32 off_hi, u64 sas_addr)
21020b09c29SAndy Yan {
21120b09c29SAndy Yan 	u32 lo = (u32)sas_addr;
21220b09c29SAndy Yan 	u32 hi = (u32)(sas_addr>>32);
21320b09c29SAndy Yan 
21420b09c29SAndy Yan 	MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_lo);
21520b09c29SAndy Yan 	MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, lo);
21620b09c29SAndy Yan 	MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_hi);
21720b09c29SAndy Yan 	MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi);
21820b09c29SAndy Yan }
21920b09c29SAndy Yan 
mvs_bytes_dmaed(struct mvs_info * mvi,int i,gfp_t gfp_flags)220feb18e90SAhmed S. Darwish static void mvs_bytes_dmaed(struct mvs_info *mvi, int i, gfp_t gfp_flags)
2212ad52f47SJeff Garzik {
2222ad52f47SJeff Garzik 	struct mvs_phy *phy = &mvi->phy[i];
22320b09c29SAndy Yan 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
224121181f3SJohn Garry 
2252ad52f47SJeff Garzik 	if (!phy->phy_attached)
2262ad52f47SJeff Garzik 		return;
2272ad52f47SJeff Garzik 
22820b09c29SAndy Yan 	if (!(phy->att_dev_info & PORT_DEV_TRGT_MASK)
22920b09c29SAndy Yan 		&& phy->phy_type & PORT_TYPE_SAS) {
23020b09c29SAndy Yan 		return;
23120b09c29SAndy Yan 	}
23220b09c29SAndy Yan 
23336cdfd0fSAhmed S. Darwish 	sas_notify_phy_event(sas_phy, PHYE_OOB_DONE, gfp_flags);
23420b09c29SAndy Yan 
2352ad52f47SJeff Garzik 	if (sas_phy->phy) {
2362ad52f47SJeff Garzik 		struct sas_phy *sphy = sas_phy->phy;
2372ad52f47SJeff Garzik 
2382ad52f47SJeff Garzik 		sphy->negotiated_linkrate = sas_phy->linkrate;
2392ad52f47SJeff Garzik 		sphy->minimum_linkrate = phy->minimum_linkrate;
2402ad52f47SJeff Garzik 		sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
2412ad52f47SJeff Garzik 		sphy->maximum_linkrate = phy->maximum_linkrate;
24220b09c29SAndy Yan 		sphy->maximum_linkrate_hw = MVS_CHIP_DISP->phy_max_link_rate();
2432ad52f47SJeff Garzik 	}
2442ad52f47SJeff Garzik 
2452ad52f47SJeff Garzik 	if (phy->phy_type & PORT_TYPE_SAS) {
2462ad52f47SJeff Garzik 		struct sas_identify_frame *id;
2472ad52f47SJeff Garzik 
2482ad52f47SJeff Garzik 		id = (struct sas_identify_frame *)phy->frame_rcvd;
2492ad52f47SJeff Garzik 		id->dev_type = phy->identify.device_type;
2502ad52f47SJeff Garzik 		id->initiator_bits = SAS_PROTOCOL_ALL;
2512ad52f47SJeff Garzik 		id->target_bits = phy->identify.target_port_protocols;
252477f6d19SXiangliang Yu 
253477f6d19SXiangliang Yu 		/* direct attached SAS device */
254477f6d19SXiangliang Yu 		if (phy->att_dev_info & PORT_SSP_TRGT_MASK) {
255477f6d19SXiangliang Yu 			MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
256477f6d19SXiangliang Yu 			MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x00);
257477f6d19SXiangliang Yu 		}
2582ad52f47SJeff Garzik 	} else if (phy->phy_type & PORT_TYPE_SATA) {
25920b09c29SAndy Yan 		/*Nothing*/
2602ad52f47SJeff Garzik 	}
26120b09c29SAndy Yan 	mv_dprintk("phy %d byte dmaded.\n", i + mvi->id * mvi->chip->n_phy);
26220b09c29SAndy Yan 
26320b09c29SAndy Yan 	sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
26420b09c29SAndy Yan 
26536cdfd0fSAhmed S. Darwish 	sas_notify_port_event(sas_phy, PORTE_BYTES_DMAED, gfp_flags);
2662ad52f47SJeff Garzik }
2672ad52f47SJeff Garzik 
mvs_scan_start(struct Scsi_Host * shost)268dd4969a8SJeff Garzik void mvs_scan_start(struct Scsi_Host *shost)
2692ad52f47SJeff Garzik {
27020b09c29SAndy Yan 	int i, j;
27120b09c29SAndy Yan 	unsigned short core_nr;
27220b09c29SAndy Yan 	struct mvs_info *mvi;
27320b09c29SAndy Yan 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
27484fbd0ceSXiangliang Yu 	struct mvs_prv_info *mvs_prv = sha->lldd_ha;
2752ad52f47SJeff Garzik 
27620b09c29SAndy Yan 	core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
27720b09c29SAndy Yan 
27820b09c29SAndy Yan 	for (j = 0; j < core_nr; j++) {
27920b09c29SAndy Yan 		mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j];
28020b09c29SAndy Yan 		for (i = 0; i < mvi->chip->n_phy; ++i)
281feb18e90SAhmed S. Darwish 			mvs_bytes_dmaed(mvi, i, GFP_KERNEL);
282dd4969a8SJeff Garzik 	}
28384fbd0ceSXiangliang Yu 	mvs_prv->scan_finished = 1;
2842ad52f47SJeff Garzik }
2852ad52f47SJeff Garzik 
mvs_scan_finished(struct Scsi_Host * shost,unsigned long time)286dd4969a8SJeff Garzik int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
2872ad52f47SJeff Garzik {
28884fbd0ceSXiangliang Yu 	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
28984fbd0ceSXiangliang Yu 	struct mvs_prv_info *mvs_prv = sha->lldd_ha;
29084fbd0ceSXiangliang Yu 
29184fbd0ceSXiangliang Yu 	if (mvs_prv->scan_finished == 0)
2922ad52f47SJeff Garzik 		return 0;
29384fbd0ceSXiangliang Yu 
294b1124cd3SDan Williams 	sas_drain_work(sha);
295dd4969a8SJeff Garzik 	return 1;
2962ad52f47SJeff Garzik }
2972ad52f47SJeff Garzik 
mvs_task_prep_smp(struct mvs_info * mvi,struct mvs_task_exec_info * tei)2982ad52f47SJeff Garzik static int mvs_task_prep_smp(struct mvs_info *mvi,
2992ad52f47SJeff Garzik 			     struct mvs_task_exec_info *tei)
3002ad52f47SJeff Garzik {
3012ad52f47SJeff Garzik 	int elem, rc, i;
3027c237c5fSXiangliang Yu 	struct sas_ha_struct *sha = mvi->sas;
3032ad52f47SJeff Garzik 	struct sas_task *task = tei->task;
3042ad52f47SJeff Garzik 	struct mvs_cmd_hdr *hdr = tei->hdr;
30520b09c29SAndy Yan 	struct domain_device *dev = task->dev;
30620b09c29SAndy Yan 	struct asd_sas_port *sas_port = dev->port;
3077c237c5fSXiangliang Yu 	struct sas_phy *sphy = dev->phy;
3087c237c5fSXiangliang Yu 	struct asd_sas_phy *sas_phy = sha->sas_phy[sphy->number];
3092ad52f47SJeff Garzik 	struct scatterlist *sg_req, *sg_resp;
3102ad52f47SJeff Garzik 	u32 req_len, resp_len, tag = tei->tag;
3112ad52f47SJeff Garzik 	void *buf_tmp;
3122ad52f47SJeff Garzik 	u8 *buf_oaf;
3132ad52f47SJeff Garzik 	dma_addr_t buf_tmp_dma;
31420b09c29SAndy Yan 	void *buf_prd;
3152ad52f47SJeff Garzik 	struct mvs_slot_info *slot = &mvi->slot_info[tag];
3162ad52f47SJeff Garzik 	u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
317b89e8f53SXiangliang Yu 
3182ad52f47SJeff Garzik 	/*
3192ad52f47SJeff Garzik 	 * DMA-map SMP request, response buffers
3202ad52f47SJeff Garzik 	 */
3212ad52f47SJeff Garzik 	sg_req = &task->smp_task.smp_req;
3224179a061SChristoph Hellwig 	elem = dma_map_sg(mvi->dev, sg_req, 1, DMA_TO_DEVICE);
3232ad52f47SJeff Garzik 	if (!elem)
3242ad52f47SJeff Garzik 		return -ENOMEM;
3252ad52f47SJeff Garzik 	req_len = sg_dma_len(sg_req);
3262ad52f47SJeff Garzik 
3272ad52f47SJeff Garzik 	sg_resp = &task->smp_task.smp_resp;
3284179a061SChristoph Hellwig 	elem = dma_map_sg(mvi->dev, sg_resp, 1, DMA_FROM_DEVICE);
3292ad52f47SJeff Garzik 	if (!elem) {
3302ad52f47SJeff Garzik 		rc = -ENOMEM;
3312ad52f47SJeff Garzik 		goto err_out;
3322ad52f47SJeff Garzik 	}
33320b09c29SAndy Yan 	resp_len = SB_RFB_MAX;
3342ad52f47SJeff Garzik 
3352ad52f47SJeff Garzik 	/* must be in dwords */
3362ad52f47SJeff Garzik 	if ((req_len & 0x3) || (resp_len & 0x3)) {
3372ad52f47SJeff Garzik 		rc = -EINVAL;
3382ad52f47SJeff Garzik 		goto err_out_2;
3392ad52f47SJeff Garzik 	}
3402ad52f47SJeff Garzik 
3412ad52f47SJeff Garzik 	/*
3422ad52f47SJeff Garzik 	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
3432ad52f47SJeff Garzik 	 */
3442ad52f47SJeff Garzik 
34520b09c29SAndy Yan 	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */
3462ad52f47SJeff Garzik 	buf_tmp = slot->buf;
3472ad52f47SJeff Garzik 	buf_tmp_dma = slot->buf_dma;
3482ad52f47SJeff Garzik 
3492ad52f47SJeff Garzik 	hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
3502ad52f47SJeff Garzik 
3512ad52f47SJeff Garzik 	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
3522ad52f47SJeff Garzik 	buf_oaf = buf_tmp;
3532ad52f47SJeff Garzik 	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
3542ad52f47SJeff Garzik 
3552ad52f47SJeff Garzik 	buf_tmp += MVS_OAF_SZ;
3562ad52f47SJeff Garzik 	buf_tmp_dma += MVS_OAF_SZ;
3572ad52f47SJeff Garzik 
35820b09c29SAndy Yan 	/* region 3: PRD table *********************************** */
3592ad52f47SJeff Garzik 	buf_prd = buf_tmp;
3602ad52f47SJeff Garzik 	if (tei->n_elem)
3612ad52f47SJeff Garzik 		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
3622ad52f47SJeff Garzik 	else
3632ad52f47SJeff Garzik 		hdr->prd_tbl = 0;
3642ad52f47SJeff Garzik 
36520b09c29SAndy Yan 	i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
3662ad52f47SJeff Garzik 	buf_tmp += i;
3672ad52f47SJeff Garzik 	buf_tmp_dma += i;
3682ad52f47SJeff Garzik 
3692ad52f47SJeff Garzik 	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
3702ad52f47SJeff Garzik 	slot->response = buf_tmp;
3712ad52f47SJeff Garzik 	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
37220b09c29SAndy Yan 	if (mvi->flags & MVF_FLAG_SOC)
37320b09c29SAndy Yan 		hdr->reserved[0] = 0;
3742ad52f47SJeff Garzik 
3752ad52f47SJeff Garzik 	/*
3762ad52f47SJeff Garzik 	 * Fill in TX ring and command slot header
3772ad52f47SJeff Garzik 	 */
3782ad52f47SJeff Garzik 	slot->tx = mvi->tx_prod;
3792ad52f47SJeff Garzik 	mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
3802ad52f47SJeff Garzik 					TXQ_MODE_I | tag |
3817c237c5fSXiangliang Yu 					(MVS_PHY_ID << TXQ_PHY_SHIFT));
3822ad52f47SJeff Garzik 
3832ad52f47SJeff Garzik 	hdr->flags |= flags;
3842ad52f47SJeff Garzik 	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
3852ad52f47SJeff Garzik 	hdr->tags = cpu_to_le32(tag);
3862ad52f47SJeff Garzik 	hdr->data_len = 0;
3872ad52f47SJeff Garzik 
3882ad52f47SJeff Garzik 	/* generate open address frame hdr (first 12 bytes) */
38920b09c29SAndy Yan 	/* initiator, SMP, ftype 1h */
39020b09c29SAndy Yan 	buf_oaf[0] = (1 << 7) | (PROTOCOL_SMP << 4) | 0x01;
3916ceae7c6SXiangliang Yu 	buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf;
3922ad52f47SJeff Garzik 	*(u16 *)(buf_oaf + 2) = 0xFFFF;		/* SAS SPEC */
39320b09c29SAndy Yan 	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
3942ad52f47SJeff Garzik 
3952ad52f47SJeff Garzik 	/* fill in PRD (scatter/gather) table, if any */
39620b09c29SAndy Yan 	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
3972ad52f47SJeff Garzik 
3982ad52f47SJeff Garzik 	return 0;
3992ad52f47SJeff Garzik 
4002ad52f47SJeff Garzik err_out_2:
40120b09c29SAndy Yan 	dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1,
4024179a061SChristoph Hellwig 		     DMA_FROM_DEVICE);
4032ad52f47SJeff Garzik err_out:
40420b09c29SAndy Yan 	dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1,
4054179a061SChristoph Hellwig 		     DMA_TO_DEVICE);
4062ad52f47SJeff Garzik 	return rc;
4072ad52f47SJeff Garzik }
4082ad52f47SJeff Garzik 
mvs_get_ncq_tag(struct sas_task * task,u32 * tag)4092ad52f47SJeff Garzik static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
4102ad52f47SJeff Garzik {
4112ad52f47SJeff Garzik 	struct ata_queued_cmd *qc = task->uldd_task;
4122ad52f47SJeff Garzik 
4132ad52f47SJeff Garzik 	if (qc) {
4142ad52f47SJeff Garzik 		if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
415ef026b18SHannes Reinecke 		    qc->tf.command == ATA_CMD_FPDMA_READ ||
416ef026b18SHannes Reinecke 		    qc->tf.command == ATA_CMD_FPDMA_RECV ||
417661ce1f0SHannes Reinecke 		    qc->tf.command == ATA_CMD_FPDMA_SEND ||
418661ce1f0SHannes Reinecke 		    qc->tf.command == ATA_CMD_NCQ_NON_DATA) {
4192ad52f47SJeff Garzik 			*tag = qc->tag;
4202ad52f47SJeff Garzik 			return 1;
4212ad52f47SJeff Garzik 		}
4222ad52f47SJeff Garzik 	}
4232ad52f47SJeff Garzik 
4242ad52f47SJeff Garzik 	return 0;
4252ad52f47SJeff Garzik }
4262ad52f47SJeff Garzik 
mvs_task_prep_ata(struct mvs_info * mvi,struct mvs_task_exec_info * tei)4272ad52f47SJeff Garzik static int mvs_task_prep_ata(struct mvs_info *mvi,
4282ad52f47SJeff Garzik 			     struct mvs_task_exec_info *tei)
4292ad52f47SJeff Garzik {
4302ad52f47SJeff Garzik 	struct sas_task *task = tei->task;
4312ad52f47SJeff Garzik 	struct domain_device *dev = task->dev;
432f9da3be5SAndy Yan 	struct mvs_device *mvi_dev = dev->lldd_dev;
4332ad52f47SJeff Garzik 	struct mvs_cmd_hdr *hdr = tei->hdr;
4342ad52f47SJeff Garzik 	struct asd_sas_port *sas_port = dev->port;
4352ad52f47SJeff Garzik 	struct mvs_slot_info *slot;
43620b09c29SAndy Yan 	void *buf_prd;
43720b09c29SAndy Yan 	u32 tag = tei->tag, hdr_tag;
43820b09c29SAndy Yan 	u32 flags, del_q;
4392ad52f47SJeff Garzik 	void *buf_tmp;
4402ad52f47SJeff Garzik 	u8 *buf_cmd, *buf_oaf;
4412ad52f47SJeff Garzik 	dma_addr_t buf_tmp_dma;
4422ad52f47SJeff Garzik 	u32 i, req_len, resp_len;
4432ad52f47SJeff Garzik 	const u32 max_resp_len = SB_RFB_MAX;
4442ad52f47SJeff Garzik 
44520b09c29SAndy Yan 	if (mvs_assign_reg_set(mvi, mvi_dev) == MVS_ID_NOT_MAPPED) {
44620b09c29SAndy Yan 		mv_dprintk("Have not enough regiset for dev %d.\n",
44720b09c29SAndy Yan 			mvi_dev->device_id);
4482ad52f47SJeff Garzik 		return -EBUSY;
44920b09c29SAndy Yan 	}
4502ad52f47SJeff Garzik 	slot = &mvi->slot_info[tag];
4512ad52f47SJeff Garzik 	slot->tx = mvi->tx_prod;
45220b09c29SAndy Yan 	del_q = TXQ_MODE_I | tag |
4532ad52f47SJeff Garzik 		(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
45456cbd0ccSJames Bottomley 		((sas_port->phy_mask & TXQ_PHY_MASK) << TXQ_PHY_SHIFT) |
45520b09c29SAndy Yan 		(mvi_dev->taskfileset << TXQ_SRS_SHIFT);
45620b09c29SAndy Yan 	mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q);
4572ad52f47SJeff Garzik 
45820b09c29SAndy Yan 	if (task->data_dir == DMA_FROM_DEVICE)
45920b09c29SAndy Yan 		flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT);
46020b09c29SAndy Yan 	else
46120b09c29SAndy Yan 		flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
4628882f081SXiangliang Yu 
4632ad52f47SJeff Garzik 	if (task->ata_task.use_ncq)
4642ad52f47SJeff Garzik 		flags |= MCH_FPDMA;
4651cbd772dSHannes Reinecke 	if (dev->sata_dev.class == ATA_DEV_ATAPI) {
4662ad52f47SJeff Garzik 		if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
4672ad52f47SJeff Garzik 			flags |= MCH_ATAPI;
4682ad52f47SJeff Garzik 	}
4692ad52f47SJeff Garzik 
4702ad52f47SJeff Garzik 	hdr->flags = cpu_to_le32(flags);
4712ad52f47SJeff Garzik 
47220b09c29SAndy Yan 	if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag))
47320b09c29SAndy Yan 		task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
4742ad52f47SJeff Garzik 	else
47520b09c29SAndy Yan 		hdr_tag = tag;
47620b09c29SAndy Yan 
47720b09c29SAndy Yan 	hdr->tags = cpu_to_le32(hdr_tag);
47820b09c29SAndy Yan 
4792ad52f47SJeff Garzik 	hdr->data_len = cpu_to_le32(task->total_xfer_len);
4802ad52f47SJeff Garzik 
4812ad52f47SJeff Garzik 	/*
4822ad52f47SJeff Garzik 	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
4832ad52f47SJeff Garzik 	 */
4842ad52f47SJeff Garzik 
4852ad52f47SJeff Garzik 	/* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
4862ad52f47SJeff Garzik 	buf_cmd = buf_tmp = slot->buf;
4872ad52f47SJeff Garzik 	buf_tmp_dma = slot->buf_dma;
4882ad52f47SJeff Garzik 
4892ad52f47SJeff Garzik 	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
4902ad52f47SJeff Garzik 
4912ad52f47SJeff Garzik 	buf_tmp += MVS_ATA_CMD_SZ;
4922ad52f47SJeff Garzik 	buf_tmp_dma += MVS_ATA_CMD_SZ;
4932ad52f47SJeff Garzik 
4942ad52f47SJeff Garzik 	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
4952ad52f47SJeff Garzik 	/* used for STP.  unused for SATA? */
4962ad52f47SJeff Garzik 	buf_oaf = buf_tmp;
4972ad52f47SJeff Garzik 	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
4982ad52f47SJeff Garzik 
4992ad52f47SJeff Garzik 	buf_tmp += MVS_OAF_SZ;
5002ad52f47SJeff Garzik 	buf_tmp_dma += MVS_OAF_SZ;
5012ad52f47SJeff Garzik 
5022ad52f47SJeff Garzik 	/* region 3: PRD table ********************************************* */
5032ad52f47SJeff Garzik 	buf_prd = buf_tmp;
50420b09c29SAndy Yan 
5052ad52f47SJeff Garzik 	if (tei->n_elem)
5062ad52f47SJeff Garzik 		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
5072ad52f47SJeff Garzik 	else
5082ad52f47SJeff Garzik 		hdr->prd_tbl = 0;
50920b09c29SAndy Yan 	i = MVS_CHIP_DISP->prd_size() * MVS_CHIP_DISP->prd_count();
5102ad52f47SJeff Garzik 
5112ad52f47SJeff Garzik 	buf_tmp += i;
5122ad52f47SJeff Garzik 	buf_tmp_dma += i;
5132ad52f47SJeff Garzik 
5142ad52f47SJeff Garzik 	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
5152ad52f47SJeff Garzik 	slot->response = buf_tmp;
5162ad52f47SJeff Garzik 	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
51720b09c29SAndy Yan 	if (mvi->flags & MVF_FLAG_SOC)
51820b09c29SAndy Yan 		hdr->reserved[0] = 0;
5192ad52f47SJeff Garzik 
5202ad52f47SJeff Garzik 	req_len = sizeof(struct host_to_dev_fis);
5212ad52f47SJeff Garzik 	resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
5222ad52f47SJeff Garzik 	    sizeof(struct mvs_err_info) - i;
5232ad52f47SJeff Garzik 
5242ad52f47SJeff Garzik 	/* request, response lengths */
5252ad52f47SJeff Garzik 	resp_len = min(resp_len, max_resp_len);
5262ad52f47SJeff Garzik 	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
5272ad52f47SJeff Garzik 
52820b09c29SAndy Yan 	if (likely(!task->ata_task.device_control_reg_update))
5292ad52f47SJeff Garzik 		task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
5302ad52f47SJeff Garzik 	/* fill in command FIS and ATAPI CDB */
5312ad52f47SJeff Garzik 	memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
5321cbd772dSHannes Reinecke 	if (dev->sata_dev.class == ATA_DEV_ATAPI)
5332ad52f47SJeff Garzik 		memcpy(buf_cmd + STP_ATAPI_CMD,
5342ad52f47SJeff Garzik 			task->ata_task.atapi_packet, 16);
5352ad52f47SJeff Garzik 
5362ad52f47SJeff Garzik 	/* generate open address frame hdr (first 12 bytes) */
53720b09c29SAndy Yan 	/* initiator, STP, ftype 1h */
53820b09c29SAndy Yan 	buf_oaf[0] = (1 << 7) | (PROTOCOL_STP << 4) | 0x1;
5396ceae7c6SXiangliang Yu 	buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf;
54020b09c29SAndy Yan 	*(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
54120b09c29SAndy Yan 	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
5422ad52f47SJeff Garzik 
5432ad52f47SJeff Garzik 	/* fill in PRD (scatter/gather) table, if any */
54420b09c29SAndy Yan 	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
5458882f081SXiangliang Yu 
54620b09c29SAndy Yan 	if (task->data_dir == DMA_FROM_DEVICE)
5478882f081SXiangliang Yu 		MVS_CHIP_DISP->dma_fix(mvi, sas_port->phy_mask,
54820b09c29SAndy Yan 				TRASH_BUCKET_SIZE, tei->n_elem, buf_prd);
5498882f081SXiangliang Yu 
5502ad52f47SJeff Garzik 	return 0;
5512ad52f47SJeff Garzik }
5522ad52f47SJeff Garzik 
mvs_task_prep_ssp(struct mvs_info * mvi,struct mvs_task_exec_info * tei,int is_tmf,struct sas_tmf_task * tmf)5532ad52f47SJeff Garzik static int mvs_task_prep_ssp(struct mvs_info *mvi,
55420b09c29SAndy Yan 			     struct mvs_task_exec_info *tei, int is_tmf,
555bbfe82cdSJohn Garry 			     struct sas_tmf_task *tmf)
5562ad52f47SJeff Garzik {
5572ad52f47SJeff Garzik 	struct sas_task *task = tei->task;
5582ad52f47SJeff Garzik 	struct mvs_cmd_hdr *hdr = tei->hdr;
5592ad52f47SJeff Garzik 	struct mvs_port *port = tei->port;
56020b09c29SAndy Yan 	struct domain_device *dev = task->dev;
561f9da3be5SAndy Yan 	struct mvs_device *mvi_dev = dev->lldd_dev;
56220b09c29SAndy Yan 	struct asd_sas_port *sas_port = dev->port;
5632ad52f47SJeff Garzik 	struct mvs_slot_info *slot;
56420b09c29SAndy Yan 	void *buf_prd;
5652ad52f47SJeff Garzik 	struct ssp_frame_hdr *ssp_hdr;
5662ad52f47SJeff Garzik 	void *buf_tmp;
567ebf26e93SJohn Garry 	u8 *buf_cmd, *buf_oaf;
5682ad52f47SJeff Garzik 	dma_addr_t buf_tmp_dma;
5692ad52f47SJeff Garzik 	u32 flags;
5702ad52f47SJeff Garzik 	u32 resp_len, req_len, i, tag = tei->tag;
5712ad52f47SJeff Garzik 	const u32 max_resp_len = SB_RFB_MAX;
57220b09c29SAndy Yan 	u32 phy_mask;
5732ad52f47SJeff Garzik 
5742ad52f47SJeff Garzik 	slot = &mvi->slot_info[tag];
5752ad52f47SJeff Garzik 
57620b09c29SAndy Yan 	phy_mask = ((port->wide_port_phymap) ? port->wide_port_phymap :
57720b09c29SAndy Yan 		sas_port->phy_mask) & TXQ_PHY_MASK;
57820b09c29SAndy Yan 
5792ad52f47SJeff Garzik 	slot->tx = mvi->tx_prod;
5802ad52f47SJeff Garzik 	mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
5812ad52f47SJeff Garzik 				(TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
5822ad52f47SJeff Garzik 				(phy_mask << TXQ_PHY_SHIFT));
5832ad52f47SJeff Garzik 
5842ad52f47SJeff Garzik 	flags = MCH_RETRY;
5852b288133SAndy Yan 	if (is_tmf)
5862b288133SAndy Yan 		flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
58784fbd0ceSXiangliang Yu 	else
58884fbd0ceSXiangliang Yu 		flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);
58984fbd0ceSXiangliang Yu 
5902b288133SAndy Yan 	hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
5912ad52f47SJeff Garzik 	hdr->tags = cpu_to_le32(tag);
5922ad52f47SJeff Garzik 	hdr->data_len = cpu_to_le32(task->total_xfer_len);
5932ad52f47SJeff Garzik 
5942ad52f47SJeff Garzik 	/*
5952ad52f47SJeff Garzik 	 * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
5962ad52f47SJeff Garzik 	 */
5972ad52f47SJeff Garzik 
5982ad52f47SJeff Garzik 	/* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
5992ad52f47SJeff Garzik 	buf_cmd = buf_tmp = slot->buf;
6002ad52f47SJeff Garzik 	buf_tmp_dma = slot->buf_dma;
6012ad52f47SJeff Garzik 
6022ad52f47SJeff Garzik 	hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
6032ad52f47SJeff Garzik 
6042ad52f47SJeff Garzik 	buf_tmp += MVS_SSP_CMD_SZ;
6052ad52f47SJeff Garzik 	buf_tmp_dma += MVS_SSP_CMD_SZ;
6062ad52f47SJeff Garzik 
6072ad52f47SJeff Garzik 	/* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
6082ad52f47SJeff Garzik 	buf_oaf = buf_tmp;
6092ad52f47SJeff Garzik 	hdr->open_frame = cpu_to_le64(buf_tmp_dma);
6102ad52f47SJeff Garzik 
6112ad52f47SJeff Garzik 	buf_tmp += MVS_OAF_SZ;
6122ad52f47SJeff Garzik 	buf_tmp_dma += MVS_OAF_SZ;
6132ad52f47SJeff Garzik 
6142ad52f47SJeff Garzik 	/* region 3: PRD table ********************************************* */
6152ad52f47SJeff Garzik 	buf_prd = buf_tmp;
6162ad52f47SJeff Garzik 	if (tei->n_elem)
6172ad52f47SJeff Garzik 		hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
6182ad52f47SJeff Garzik 	else
6192ad52f47SJeff Garzik 		hdr->prd_tbl = 0;
6202ad52f47SJeff Garzik 
62120b09c29SAndy Yan 	i = MVS_CHIP_DISP->prd_size() * tei->n_elem;
6222ad52f47SJeff Garzik 	buf_tmp += i;
6232ad52f47SJeff Garzik 	buf_tmp_dma += i;
6242ad52f47SJeff Garzik 
6252ad52f47SJeff Garzik 	/* region 4: status buffer (larger the PRD, smaller this buf) ****** */
6262ad52f47SJeff Garzik 	slot->response = buf_tmp;
6272ad52f47SJeff Garzik 	hdr->status_buf = cpu_to_le64(buf_tmp_dma);
62820b09c29SAndy Yan 	if (mvi->flags & MVF_FLAG_SOC)
62920b09c29SAndy Yan 		hdr->reserved[0] = 0;
6302ad52f47SJeff Garzik 
6312ad52f47SJeff Garzik 	resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
6322ad52f47SJeff Garzik 	    sizeof(struct mvs_err_info) - i;
6332ad52f47SJeff Garzik 	resp_len = min(resp_len, max_resp_len);
6342ad52f47SJeff Garzik 
6352ad52f47SJeff Garzik 	req_len = sizeof(struct ssp_frame_hdr) + 28;
6362ad52f47SJeff Garzik 
6372ad52f47SJeff Garzik 	/* request, response lengths */
6382ad52f47SJeff Garzik 	hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
6392ad52f47SJeff Garzik 
6402ad52f47SJeff Garzik 	/* generate open address frame hdr (first 12 bytes) */
64120b09c29SAndy Yan 	/* initiator, SSP, ftype 1h */
64220b09c29SAndy Yan 	buf_oaf[0] = (1 << 7) | (PROTOCOL_SSP << 4) | 0x1;
6436ceae7c6SXiangliang Yu 	buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf;
64420b09c29SAndy Yan 	*(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1);
64520b09c29SAndy Yan 	memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE);
6462ad52f47SJeff Garzik 
6472ad52f47SJeff Garzik 	/* fill in SSP frame header (Command Table.SSP frame header) */
6482ad52f47SJeff Garzik 	ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
64920b09c29SAndy Yan 
65020b09c29SAndy Yan 	if (is_tmf)
65120b09c29SAndy Yan 		ssp_hdr->frame_type = SSP_TASK;
65220b09c29SAndy Yan 	else
6532ad52f47SJeff Garzik 		ssp_hdr->frame_type = SSP_COMMAND;
65420b09c29SAndy Yan 
65520b09c29SAndy Yan 	memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr,
6562ad52f47SJeff Garzik 	       HASHED_SAS_ADDR_SIZE);
6572ad52f47SJeff Garzik 	memcpy(ssp_hdr->hashed_src_addr,
65820b09c29SAndy Yan 	       dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
6592ad52f47SJeff Garzik 	ssp_hdr->tag = cpu_to_be16(tag);
6602ad52f47SJeff Garzik 
66120b09c29SAndy Yan 	/* fill in IU for TASK and Command Frame */
6622ad52f47SJeff Garzik 	buf_cmd += sizeof(*ssp_hdr);
6632ad52f47SJeff Garzik 	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
66420b09c29SAndy Yan 
66520b09c29SAndy Yan 	if (ssp_hdr->frame_type != SSP_TASK) {
666*4dc051ebSJohn Garry 		buf_cmd[9] = task->ssp_task.task_attr;
667e73823f7SJames Bottomley 		memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
668e73823f7SJames Bottomley 		       task->ssp_task.cmd->cmd_len);
66920b09c29SAndy Yan 	} else{
67020b09c29SAndy Yan 		buf_cmd[10] = tmf->tmf;
67120b09c29SAndy Yan 		switch (tmf->tmf) {
67220b09c29SAndy Yan 		case TMF_ABORT_TASK:
67320b09c29SAndy Yan 		case TMF_QUERY_TASK:
67420b09c29SAndy Yan 			buf_cmd[12] =
67520b09c29SAndy Yan 				(tmf->tag_of_task_to_be_managed >> 8) & 0xff;
67620b09c29SAndy Yan 			buf_cmd[13] =
67720b09c29SAndy Yan 				tmf->tag_of_task_to_be_managed & 0xff;
67820b09c29SAndy Yan 			break;
67920b09c29SAndy Yan 		default:
68020b09c29SAndy Yan 			break;
6812ad52f47SJeff Garzik 		}
68220b09c29SAndy Yan 	}
68320b09c29SAndy Yan 	/* fill in PRD (scatter/gather) table, if any */
68420b09c29SAndy Yan 	MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
6852ad52f47SJeff Garzik 	return 0;
6862ad52f47SJeff Garzik }
6872ad52f47SJeff Garzik 
688aa9f8328SJames Bottomley #define	DEV_IS_GONE(mvi_dev)	((!mvi_dev || (mvi_dev->dev_type == SAS_PHY_UNUSED)))
mvs_task_prep(struct sas_task * task,struct mvs_info * mvi,int is_tmf,struct sas_tmf_task * tmf,int * pass)6890b15fb1fSXiangliang Yu static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf,
690bbfe82cdSJohn Garry 				struct sas_tmf_task *tmf, int *pass)
6912ad52f47SJeff Garzik {
6922ad52f47SJeff Garzik 	struct domain_device *dev = task->dev;
6930b15fb1fSXiangliang Yu 	struct mvs_device *mvi_dev = dev->lldd_dev;
6942ad52f47SJeff Garzik 	struct mvs_task_exec_info tei;
6952ad52f47SJeff Garzik 	struct mvs_slot_info *slot;
6960b15fb1fSXiangliang Yu 	u32 tag = 0xdeadbeef, n_elem = 0;
6972acf97f1SJohn Garry 	struct request *rq;
6980b15fb1fSXiangliang Yu 	int rc = 0;
6992ad52f47SJeff Garzik 
70020b09c29SAndy Yan 	if (!dev->port) {
7010b15fb1fSXiangliang Yu 		struct task_status_struct *tsm = &task->task_status;
70220b09c29SAndy Yan 
70320b09c29SAndy Yan 		tsm->resp = SAS_TASK_UNDELIVERED;
70420b09c29SAndy Yan 		tsm->stat = SAS_PHY_DOWN;
7050b15fb1fSXiangliang Yu 		/*
7060b15fb1fSXiangliang Yu 		 * libsas will use dev->port, should
7070b15fb1fSXiangliang Yu 		 * not call task_done for sata
7080b15fb1fSXiangliang Yu 		 */
709aa9f8328SJames Bottomley 		if (dev->dev_type != SAS_SATA_DEV)
7100b15fb1fSXiangliang Yu 			task->task_done(task);
7110b15fb1fSXiangliang Yu 		return rc;
71220b09c29SAndy Yan 	}
71320b09c29SAndy Yan 
71420b09c29SAndy Yan 	if (DEV_IS_GONE(mvi_dev)) {
71520b09c29SAndy Yan 		if (mvi_dev)
71620b09c29SAndy Yan 			mv_dprintk("device %d not ready.\n",
71720b09c29SAndy Yan 				mvi_dev->device_id);
71820b09c29SAndy Yan 		else
71920b09c29SAndy Yan 			mv_dprintk("device %016llx not ready.\n",
72020b09c29SAndy Yan 				SAS_ADDR(dev->sas_addr));
72120b09c29SAndy Yan 
72220b09c29SAndy Yan 		rc = SAS_PHY_DOWN;
7230b15fb1fSXiangliang Yu 		return rc;
72420b09c29SAndy Yan 	}
7250b15fb1fSXiangliang Yu 	tei.port = dev->port->lldd_port;
7260b15fb1fSXiangliang Yu 	if (tei.port && !tei.port->port_attached && !tmf) {
7270b15fb1fSXiangliang Yu 		if (sas_protocol_ata(task->task_proto)) {
7280b15fb1fSXiangliang Yu 			struct task_status_struct *ts = &task->task_status;
7290b15fb1fSXiangliang Yu 			mv_dprintk("SATA/STP port %d does not attach"
7300b15fb1fSXiangliang Yu 					"device.\n", dev->port->id);
7310b15fb1fSXiangliang Yu 			ts->resp = SAS_TASK_COMPLETE;
7329dc9fd94SSrinivas 			ts->stat = SAS_PHY_DOWN;
7330b15fb1fSXiangliang Yu 
7340b15fb1fSXiangliang Yu 			task->task_done(task);
7350b15fb1fSXiangliang Yu 
7362ad52f47SJeff Garzik 		} else {
7370b15fb1fSXiangliang Yu 			struct task_status_struct *ts = &task->task_status;
7380b15fb1fSXiangliang Yu 			mv_dprintk("SAS port %d does not attach"
7390b15fb1fSXiangliang Yu 				"device.\n", dev->port->id);
7402ad52f47SJeff Garzik 			ts->resp = SAS_TASK_UNDELIVERED;
7412ad52f47SJeff Garzik 			ts->stat = SAS_PHY_DOWN;
7420b15fb1fSXiangliang Yu 			task->task_done(task);
7432ad52f47SJeff Garzik 		}
7440b15fb1fSXiangliang Yu 		return rc;
7452ad52f47SJeff Garzik 	}
7462ad52f47SJeff Garzik 
7470b15fb1fSXiangliang Yu 	if (!sas_protocol_ata(task->task_proto)) {
7480b15fb1fSXiangliang Yu 		if (task->num_scatter) {
74920b09c29SAndy Yan 			n_elem = dma_map_sg(mvi->dev,
7500b15fb1fSXiangliang Yu 					    task->scatter,
7510b15fb1fSXiangliang Yu 					    task->num_scatter,
7520b15fb1fSXiangliang Yu 					    task->data_dir);
7532ad52f47SJeff Garzik 			if (!n_elem) {
7542ad52f47SJeff Garzik 				rc = -ENOMEM;
7550b15fb1fSXiangliang Yu 				goto prep_out;
7562ad52f47SJeff Garzik 			}
7572ad52f47SJeff Garzik 		}
7582ad52f47SJeff Garzik 	} else {
7590b15fb1fSXiangliang Yu 		n_elem = task->num_scatter;
7602ad52f47SJeff Garzik 	}
7612ad52f47SJeff Garzik 
7622acf97f1SJohn Garry 	rq = sas_task_find_rq(task);
7632acf97f1SJohn Garry 	if (rq) {
7642acf97f1SJohn Garry 		tag = rq->tag + MVS_RSVD_SLOTS;
7652acf97f1SJohn Garry 	} else {
7662ad52f47SJeff Garzik 		rc = mvs_tag_alloc(mvi, &tag);
7672ad52f47SJeff Garzik 		if (rc)
7682ad52f47SJeff Garzik 			goto err_out;
7692acf97f1SJohn Garry 	}
7702ad52f47SJeff Garzik 
7712ad52f47SJeff Garzik 	slot = &mvi->slot_info[tag];
77220b09c29SAndy Yan 
7730b15fb1fSXiangliang Yu 	task->lldd_task = NULL;
7742ad52f47SJeff Garzik 	slot->n_elem = n_elem;
77520b09c29SAndy Yan 	slot->slot_tag = tag;
7760b15fb1fSXiangliang Yu 
7771b171b1aSSabyasachi Gupta 	slot->buf = dma_pool_zalloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma);
77818eddaedSWei Yongjun 	if (!slot->buf) {
77918eddaedSWei Yongjun 		rc = -ENOMEM;
7800b15fb1fSXiangliang Yu 		goto err_out_tag;
78118eddaedSWei Yongjun 	}
78220b09c29SAndy Yan 
7830b15fb1fSXiangliang Yu 	tei.task = task;
7842ad52f47SJeff Garzik 	tei.hdr = &mvi->slot[tag];
7852ad52f47SJeff Garzik 	tei.tag = tag;
7862ad52f47SJeff Garzik 	tei.n_elem = n_elem;
7870b15fb1fSXiangliang Yu 	switch (task->task_proto) {
7882ad52f47SJeff Garzik 	case SAS_PROTOCOL_SMP:
7892ad52f47SJeff Garzik 		rc = mvs_task_prep_smp(mvi, &tei);
7902ad52f47SJeff Garzik 		break;
7912ad52f47SJeff Garzik 	case SAS_PROTOCOL_SSP:
79220b09c29SAndy Yan 		rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf);
7932ad52f47SJeff Garzik 		break;
7942ad52f47SJeff Garzik 	case SAS_PROTOCOL_SATA:
7952ad52f47SJeff Garzik 	case SAS_PROTOCOL_STP:
7962ad52f47SJeff Garzik 	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
7972ad52f47SJeff Garzik 		rc = mvs_task_prep_ata(mvi, &tei);
7982ad52f47SJeff Garzik 		break;
7992ad52f47SJeff Garzik 	default:
80020b09c29SAndy Yan 		dev_printk(KERN_ERR, mvi->dev,
8012ad52f47SJeff Garzik 			"unknown sas_task proto: 0x%x\n",
8020b15fb1fSXiangliang Yu 			task->task_proto);
8032ad52f47SJeff Garzik 		rc = -EINVAL;
8042ad52f47SJeff Garzik 		break;
8052ad52f47SJeff Garzik 	}
8062ad52f47SJeff Garzik 
80720b09c29SAndy Yan 	if (rc) {
80820b09c29SAndy Yan 		mv_dprintk("rc is %x\n", rc);
8090b15fb1fSXiangliang Yu 		goto err_out_slot_buf;
81020b09c29SAndy Yan 	}
8110b15fb1fSXiangliang Yu 	slot->task = task;
8122ad52f47SJeff Garzik 	slot->port = tei.port;
8130b15fb1fSXiangliang Yu 	task->lldd_task = slot;
81420b09c29SAndy Yan 	list_add_tail(&slot->entry, &tei.port->list);
8152ad52f47SJeff Garzik 
8169dc9fd94SSrinivas 	mvi_dev->running_req++;
8170b15fb1fSXiangliang Yu 	++(*pass);
8182ad52f47SJeff Garzik 	mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
8199dc9fd94SSrinivas 
8200b15fb1fSXiangliang Yu 	return rc;
8212ad52f47SJeff Garzik 
8220b15fb1fSXiangliang Yu err_out_slot_buf:
8234dbd6712SRomain Perier 	dma_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma);
8242ad52f47SJeff Garzik err_out_tag:
8252ad52f47SJeff Garzik 	mvs_tag_free(mvi, tag);
8262ad52f47SJeff Garzik err_out:
82720b09c29SAndy Yan 
8280b15fb1fSXiangliang Yu 	dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc);
8290b15fb1fSXiangliang Yu 	if (!sas_protocol_ata(task->task_proto))
8302ad52f47SJeff Garzik 		if (n_elem)
8310b15fb1fSXiangliang Yu 			dma_unmap_sg(mvi->dev, task->scatter, n_elem,
8320b15fb1fSXiangliang Yu 				     task->data_dir);
8330b15fb1fSXiangliang Yu prep_out:
8340b15fb1fSXiangliang Yu 	return rc;
8350b15fb1fSXiangliang Yu }
8360b15fb1fSXiangliang Yu 
mvs_queue_command(struct sas_task * task,gfp_t gfp_flags)83796e54376SJohn Garry int mvs_queue_command(struct sas_task *task, gfp_t gfp_flags)
8380b15fb1fSXiangliang Yu {
8390b15fb1fSXiangliang Yu 	struct mvs_info *mvi = NULL;
8400b15fb1fSXiangliang Yu 	u32 rc = 0;
8410b15fb1fSXiangliang Yu 	u32 pass = 0;
8420b15fb1fSXiangliang Yu 	unsigned long flags = 0;
84396e54376SJohn Garry 	struct sas_tmf_task *tmf = task->tmf;
84496e54376SJohn Garry 	int is_tmf = !!task->tmf;
8450b15fb1fSXiangliang Yu 
8460b15fb1fSXiangliang Yu 	mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info;
8470b15fb1fSXiangliang Yu 
8480b15fb1fSXiangliang Yu 	spin_lock_irqsave(&mvi->lock, flags);
8490b15fb1fSXiangliang Yu 	rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass);
8500b15fb1fSXiangliang Yu 	if (rc)
8510b15fb1fSXiangliang Yu 		dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
8520b15fb1fSXiangliang Yu 
8530b15fb1fSXiangliang Yu 	if (likely(pass))
8540b15fb1fSXiangliang Yu 			MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) &
8550b15fb1fSXiangliang Yu 				(MVS_CHIP_SLOT_SZ - 1));
8562ad52f47SJeff Garzik 	spin_unlock_irqrestore(&mvi->lock, flags);
8570b15fb1fSXiangliang Yu 
8580b15fb1fSXiangliang Yu 	return rc;
8590b15fb1fSXiangliang Yu }
8600b15fb1fSXiangliang Yu 
mvs_slot_free(struct mvs_info * mvi,u32 rx_desc)861dd4969a8SJeff Garzik static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
8622ad52f47SJeff Garzik {
863dd4969a8SJeff Garzik 	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
8642acf97f1SJohn Garry 	mvs_tag_free(mvi, slot_idx);
8652ad52f47SJeff Garzik }
866dd4969a8SJeff Garzik 
mvs_slot_task_free(struct mvs_info * mvi,struct sas_task * task,struct mvs_slot_info * slot,u32 slot_idx)867dd4969a8SJeff Garzik static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
868dd4969a8SJeff Garzik 			  struct mvs_slot_info *slot, u32 slot_idx)
869dd4969a8SJeff Garzik {
87022805217SDāvis Mosāns 	if (!slot)
87122805217SDāvis Mosāns 		return;
87220b09c29SAndy Yan 	if (!slot->task)
87320b09c29SAndy Yan 		return;
874dd4969a8SJeff Garzik 	if (!sas_protocol_ata(task->task_proto))
875dd4969a8SJeff Garzik 		if (slot->n_elem)
87620b09c29SAndy Yan 			dma_unmap_sg(mvi->dev, task->scatter,
877dd4969a8SJeff Garzik 				     slot->n_elem, task->data_dir);
8782ad52f47SJeff Garzik 
8792ad52f47SJeff Garzik 	switch (task->task_proto) {
8802ad52f47SJeff Garzik 	case SAS_PROTOCOL_SMP:
88120b09c29SAndy Yan 		dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1,
8824179a061SChristoph Hellwig 			     DMA_FROM_DEVICE);
88320b09c29SAndy Yan 		dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1,
8844179a061SChristoph Hellwig 			     DMA_TO_DEVICE);
8852ad52f47SJeff Garzik 		break;
886dd4969a8SJeff Garzik 
8872ad52f47SJeff Garzik 	case SAS_PROTOCOL_SATA:
8882ad52f47SJeff Garzik 	case SAS_PROTOCOL_STP:
889dd4969a8SJeff Garzik 	case SAS_PROTOCOL_SSP:
8902ad52f47SJeff Garzik 	default:
891dd4969a8SJeff Garzik 		/* do nothing */
8922ad52f47SJeff Garzik 		break;
8932ad52f47SJeff Garzik 	}
8940b15fb1fSXiangliang Yu 
8950b15fb1fSXiangliang Yu 	if (slot->buf) {
8964dbd6712SRomain Perier 		dma_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma);
8970b15fb1fSXiangliang Yu 		slot->buf = NULL;
8980b15fb1fSXiangliang Yu 	}
89920b09c29SAndy Yan 	list_del_init(&slot->entry);
900dd4969a8SJeff Garzik 	task->lldd_task = NULL;
901dd4969a8SJeff Garzik 	slot->task = NULL;
902dd4969a8SJeff Garzik 	slot->port = NULL;
90320b09c29SAndy Yan 	slot->slot_tag = 0xFFFFFFFF;
90420b09c29SAndy Yan 	mvs_slot_free(mvi, slot_idx);
9052ad52f47SJeff Garzik }
9062ad52f47SJeff Garzik 
mvs_update_wideport(struct mvs_info * mvi,int phy_no)90784fbd0ceSXiangliang Yu static void mvs_update_wideport(struct mvs_info *mvi, int phy_no)
9082ad52f47SJeff Garzik {
90984fbd0ceSXiangliang Yu 	struct mvs_phy *phy = &mvi->phy[phy_no];
9102ad52f47SJeff Garzik 	struct mvs_port *port = phy->port;
9112ad52f47SJeff Garzik 	int j, no;
9122ad52f47SJeff Garzik 
91320b09c29SAndy Yan 	for_each_phy(port->wide_port_phymap, j, no) {
91420b09c29SAndy Yan 		if (j & 1) {
91520b09c29SAndy Yan 			MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
91620b09c29SAndy Yan 						PHYR_WIDE_PORT);
91720b09c29SAndy Yan 			MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
9182ad52f47SJeff Garzik 						port->wide_port_phymap);
9192ad52f47SJeff Garzik 		} else {
92020b09c29SAndy Yan 			MVS_CHIP_DISP->write_port_cfg_addr(mvi, no,
92120b09c29SAndy Yan 						PHYR_WIDE_PORT);
92220b09c29SAndy Yan 			MVS_CHIP_DISP->write_port_cfg_data(mvi, no,
92320b09c29SAndy Yan 						0);
92420b09c29SAndy Yan 		}
9252ad52f47SJeff Garzik 	}
9262ad52f47SJeff Garzik }
9272ad52f47SJeff Garzik 
mvs_is_phy_ready(struct mvs_info * mvi,int i)9282ad52f47SJeff Garzik static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
9292ad52f47SJeff Garzik {
9302ad52f47SJeff Garzik 	u32 tmp;
9312ad52f47SJeff Garzik 	struct mvs_phy *phy = &mvi->phy[i];
93220b09c29SAndy Yan 	struct mvs_port *port = phy->port;
9332ad52f47SJeff Garzik 
93420b09c29SAndy Yan 	tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, i);
9352ad52f47SJeff Garzik 	if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
9362ad52f47SJeff Garzik 		if (!port)
9372ad52f47SJeff Garzik 			phy->phy_attached = 1;
9382ad52f47SJeff Garzik 		return tmp;
9392ad52f47SJeff Garzik 	}
9402ad52f47SJeff Garzik 
9412ad52f47SJeff Garzik 	if (port) {
9422ad52f47SJeff Garzik 		if (phy->phy_type & PORT_TYPE_SAS) {
9432ad52f47SJeff Garzik 			port->wide_port_phymap &= ~(1U << i);
9442ad52f47SJeff Garzik 			if (!port->wide_port_phymap)
9452ad52f47SJeff Garzik 				port->port_attached = 0;
9462ad52f47SJeff Garzik 			mvs_update_wideport(mvi, i);
9472ad52f47SJeff Garzik 		} else if (phy->phy_type & PORT_TYPE_SATA)
9482ad52f47SJeff Garzik 			port->port_attached = 0;
9492ad52f47SJeff Garzik 		phy->port = NULL;
9502ad52f47SJeff Garzik 		phy->phy_attached = 0;
9512ad52f47SJeff Garzik 		phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
9522ad52f47SJeff Garzik 	}
9532ad52f47SJeff Garzik 	return 0;
9542ad52f47SJeff Garzik }
9552ad52f47SJeff Garzik 
mvs_get_d2h_reg(struct mvs_info * mvi,int i,void * buf)956dd4969a8SJeff Garzik static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
957dd4969a8SJeff Garzik {
958dd4969a8SJeff Garzik 	u32 *s = (u32 *) buf;
959dd4969a8SJeff Garzik 
960dd4969a8SJeff Garzik 	if (!s)
961dd4969a8SJeff Garzik 		return NULL;
962dd4969a8SJeff Garzik 
96320b09c29SAndy Yan 	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
96484fbd0ceSXiangliang Yu 	s[3] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
965dd4969a8SJeff Garzik 
96620b09c29SAndy Yan 	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
96784fbd0ceSXiangliang Yu 	s[2] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
968dd4969a8SJeff Garzik 
96920b09c29SAndy Yan 	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
97084fbd0ceSXiangliang Yu 	s[1] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
971dd4969a8SJeff Garzik 
97220b09c29SAndy Yan 	MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
97384fbd0ceSXiangliang Yu 	s[0] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
97420b09c29SAndy Yan 
97520b09c29SAndy Yan 	if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
97620b09c29SAndy Yan 		s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10);
977dd4969a8SJeff Garzik 
978f9da3be5SAndy Yan 	return s;
979dd4969a8SJeff Garzik }
980dd4969a8SJeff Garzik 
mvs_is_sig_fis_received(u32 irq_status)981dd4969a8SJeff Garzik static u32 mvs_is_sig_fis_received(u32 irq_status)
982dd4969a8SJeff Garzik {
983dd4969a8SJeff Garzik 	return irq_status & PHYEV_SIG_FIS;
984dd4969a8SJeff Garzik }
985dd4969a8SJeff Garzik 
mvs_sig_remove_timer(struct mvs_phy * phy)9868882f081SXiangliang Yu static void mvs_sig_remove_timer(struct mvs_phy *phy)
9878882f081SXiangliang Yu {
9888882f081SXiangliang Yu 	if (phy->timer.function)
9898882f081SXiangliang Yu 		del_timer(&phy->timer);
9908882f081SXiangliang Yu 	phy->timer.function = NULL;
9918882f081SXiangliang Yu }
9928882f081SXiangliang Yu 
mvs_update_phyinfo(struct mvs_info * mvi,int i,int get_st)99320b09c29SAndy Yan void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
9942ad52f47SJeff Garzik {
9952ad52f47SJeff Garzik 	struct mvs_phy *phy = &mvi->phy[i];
99620b09c29SAndy Yan 	struct sas_identify_frame *id;
9972ad52f47SJeff Garzik 
99820b09c29SAndy Yan 	id = (struct sas_identify_frame *)phy->frame_rcvd;
9992ad52f47SJeff Garzik 
10002ad52f47SJeff Garzik 	if (get_st) {
100120b09c29SAndy Yan 		phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, i);
10022ad52f47SJeff Garzik 		phy->phy_status = mvs_is_phy_ready(mvi, i);
10032ad52f47SJeff Garzik 	}
10042ad52f47SJeff Garzik 
10052ad52f47SJeff Garzik 	if (phy->phy_status) {
100620b09c29SAndy Yan 		int oob_done = 0;
100720b09c29SAndy Yan 		struct asd_sas_phy *sas_phy = &mvi->phy[i].sas_phy;
10082ad52f47SJeff Garzik 
100920b09c29SAndy Yan 		oob_done = MVS_CHIP_DISP->oob_done(mvi, i);
10102ad52f47SJeff Garzik 
101120b09c29SAndy Yan 		MVS_CHIP_DISP->fix_phy_info(mvi, i, id);
101220b09c29SAndy Yan 		if (phy->phy_type & PORT_TYPE_SATA) {
101320b09c29SAndy Yan 			phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
101420b09c29SAndy Yan 			if (mvs_is_sig_fis_received(phy->irq_status)) {
10158882f081SXiangliang Yu 				mvs_sig_remove_timer(phy);
101620b09c29SAndy Yan 				phy->phy_attached = 1;
10172ad52f47SJeff Garzik 				phy->att_dev_sas_addr =
101820b09c29SAndy Yan 					i + mvi->id * mvi->chip->n_phy;
101920b09c29SAndy Yan 				if (oob_done)
102020b09c29SAndy Yan 					sas_phy->oob_mode = SATA_OOB_MODE;
102120b09c29SAndy Yan 				phy->frame_rcvd_size =
102220b09c29SAndy Yan 				    sizeof(struct dev_to_host_fis);
1023f9da3be5SAndy Yan 				mvs_get_d2h_reg(mvi, i, id);
102420b09c29SAndy Yan 			} else {
102520b09c29SAndy Yan 				u32 tmp;
102620b09c29SAndy Yan 				dev_printk(KERN_DEBUG, mvi->dev,
102720b09c29SAndy Yan 					"Phy%d : No sig fis\n", i);
102820b09c29SAndy Yan 				tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, i);
102920b09c29SAndy Yan 				MVS_CHIP_DISP->write_port_irq_mask(mvi, i,
103020b09c29SAndy Yan 						tmp | PHYEV_SIG_FIS);
103120b09c29SAndy Yan 				phy->phy_attached = 0;
103220b09c29SAndy Yan 				phy->phy_type &= ~PORT_TYPE_SATA;
103320b09c29SAndy Yan 				goto out_done;
103420b09c29SAndy Yan 			}
103520b09c29SAndy Yan 		}	else if (phy->phy_type & PORT_TYPE_SAS
103620b09c29SAndy Yan 			|| phy->att_dev_info & PORT_SSP_INIT_MASK) {
103720b09c29SAndy Yan 			phy->phy_attached = 1;
10382ad52f47SJeff Garzik 			phy->identify.device_type =
10392ad52f47SJeff Garzik 				phy->att_dev_info & PORT_DEV_TYPE_MASK;
10402ad52f47SJeff Garzik 
1041aa9f8328SJames Bottomley 			if (phy->identify.device_type == SAS_END_DEVICE)
10422ad52f47SJeff Garzik 				phy->identify.target_port_protocols =
10432ad52f47SJeff Garzik 							SAS_PROTOCOL_SSP;
1044aa9f8328SJames Bottomley 			else if (phy->identify.device_type != SAS_PHY_UNUSED)
10452ad52f47SJeff Garzik 				phy->identify.target_port_protocols =
10462ad52f47SJeff Garzik 							SAS_PROTOCOL_SMP;
104720b09c29SAndy Yan 			if (oob_done)
10482ad52f47SJeff Garzik 				sas_phy->oob_mode = SAS_OOB_MODE;
10492ad52f47SJeff Garzik 			phy->frame_rcvd_size =
10502ad52f47SJeff Garzik 			    sizeof(struct sas_identify_frame);
10512ad52f47SJeff Garzik 		}
105220b09c29SAndy Yan 		memcpy(sas_phy->attached_sas_addr,
105320b09c29SAndy Yan 			&phy->att_dev_sas_addr, SAS_ADDR_SIZE);
105420b09c29SAndy Yan 
105520b09c29SAndy Yan 		if (MVS_CHIP_DISP->phy_work_around)
105620b09c29SAndy Yan 			MVS_CHIP_DISP->phy_work_around(mvi, i);
10572ad52f47SJeff Garzik 	}
105884fbd0ceSXiangliang Yu 	mv_dprintk("phy %d attach dev info is %x\n",
105920b09c29SAndy Yan 		i + mvi->id * mvi->chip->n_phy, phy->att_dev_info);
106084fbd0ceSXiangliang Yu 	mv_dprintk("phy %d attach sas addr is %llx\n",
106120b09c29SAndy Yan 		i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr);
10622ad52f47SJeff Garzik out_done:
10632ad52f47SJeff Garzik 	if (get_st)
106420b09c29SAndy Yan 		MVS_CHIP_DISP->write_port_irq_stat(mvi, i, phy->irq_status);
10652ad52f47SJeff Garzik }
10662ad52f47SJeff Garzik 
mvs_port_notify_formed(struct asd_sas_phy * sas_phy,int lock)106720b09c29SAndy Yan static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
10682ad52f47SJeff Garzik {
10692ad52f47SJeff Garzik 	struct sas_ha_struct *sas_ha = sas_phy->ha;
107020b09c29SAndy Yan 	struct mvs_info *mvi = NULL; int i = 0, hi;
10712ad52f47SJeff Garzik 	struct mvs_phy *phy = sas_phy->lldd_phy;
107220b09c29SAndy Yan 	struct asd_sas_port *sas_port = sas_phy->port;
107320b09c29SAndy Yan 	struct mvs_port *port;
107420b09c29SAndy Yan 	unsigned long flags = 0;
107520b09c29SAndy Yan 	if (!sas_port)
107620b09c29SAndy Yan 		return;
10772ad52f47SJeff Garzik 
107820b09c29SAndy Yan 	while (sas_ha->sas_phy[i]) {
107920b09c29SAndy Yan 		if (sas_ha->sas_phy[i] == sas_phy)
108020b09c29SAndy Yan 			break;
108120b09c29SAndy Yan 		i++;
108220b09c29SAndy Yan 	}
108320b09c29SAndy Yan 	hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy;
108420b09c29SAndy Yan 	mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi];
108584fbd0ceSXiangliang Yu 	if (i >= mvi->chip->n_phy)
108684fbd0ceSXiangliang Yu 		port = &mvi->port[i - mvi->chip->n_phy];
108720b09c29SAndy Yan 	else
108884fbd0ceSXiangliang Yu 		port = &mvi->port[i];
108920b09c29SAndy Yan 	if (lock)
10902ad52f47SJeff Garzik 		spin_lock_irqsave(&mvi->lock, flags);
10912ad52f47SJeff Garzik 	port->port_attached = 1;
10922ad52f47SJeff Garzik 	phy->port = port;
10930b15fb1fSXiangliang Yu 	sas_port->lldd_port = port;
10942ad52f47SJeff Garzik 	if (phy->phy_type & PORT_TYPE_SAS) {
10952ad52f47SJeff Garzik 		port->wide_port_phymap = sas_port->phy_mask;
109620b09c29SAndy Yan 		mv_printk("set wide port phy map %x\n", sas_port->phy_mask);
10972ad52f47SJeff Garzik 		mvs_update_wideport(mvi, sas_phy->id);
1098477f6d19SXiangliang Yu 
1099477f6d19SXiangliang Yu 		/* direct attached SAS device */
1100477f6d19SXiangliang Yu 		if (phy->att_dev_info & PORT_SSP_TRGT_MASK) {
1101477f6d19SXiangliang Yu 			MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
1102477f6d19SXiangliang Yu 			MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x04);
1103477f6d19SXiangliang Yu 		}
11042ad52f47SJeff Garzik 	}
110520b09c29SAndy Yan 	if (lock)
11062ad52f47SJeff Garzik 		spin_unlock_irqrestore(&mvi->lock, flags);
11072ad52f47SJeff Garzik }
11082ad52f47SJeff Garzik 
mvs_port_notify_deformed(struct asd_sas_phy * sas_phy,int lock)110920b09c29SAndy Yan static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
111020b09c29SAndy Yan {
11119dc9fd94SSrinivas 	struct domain_device *dev;
11129dc9fd94SSrinivas 	struct mvs_phy *phy = sas_phy->lldd_phy;
11139dc9fd94SSrinivas 	struct mvs_info *mvi = phy->mvi;
11149dc9fd94SSrinivas 	struct asd_sas_port *port = sas_phy->port;
11159dc9fd94SSrinivas 	int phy_no = 0;
11169dc9fd94SSrinivas 
11179dc9fd94SSrinivas 	while (phy != &mvi->phy[phy_no]) {
11189dc9fd94SSrinivas 		phy_no++;
11199dc9fd94SSrinivas 		if (phy_no >= MVS_MAX_PHYS)
11209dc9fd94SSrinivas 			return;
11219dc9fd94SSrinivas 	}
11229dc9fd94SSrinivas 	list_for_each_entry(dev, &port->dev_list, dev_list_node)
112384fbd0ceSXiangliang Yu 		mvs_do_release_task(phy->mvi, phy_no, dev);
11249dc9fd94SSrinivas 
112520b09c29SAndy Yan }
112620b09c29SAndy Yan 
112720b09c29SAndy Yan 
mvs_port_formed(struct asd_sas_phy * sas_phy)112820b09c29SAndy Yan void mvs_port_formed(struct asd_sas_phy *sas_phy)
112920b09c29SAndy Yan {
113020b09c29SAndy Yan 	mvs_port_notify_formed(sas_phy, 1);
113120b09c29SAndy Yan }
113220b09c29SAndy Yan 
mvs_port_deformed(struct asd_sas_phy * sas_phy)113320b09c29SAndy Yan void mvs_port_deformed(struct asd_sas_phy *sas_phy)
113420b09c29SAndy Yan {
113520b09c29SAndy Yan 	mvs_port_notify_deformed(sas_phy, 1);
113620b09c29SAndy Yan }
113720b09c29SAndy Yan 
mvs_alloc_dev(struct mvs_info * mvi)113814bf41dcSBaoyou Xie static struct mvs_device *mvs_alloc_dev(struct mvs_info *mvi)
113920b09c29SAndy Yan {
114020b09c29SAndy Yan 	u32 dev;
114120b09c29SAndy Yan 	for (dev = 0; dev < MVS_MAX_DEVICES; dev++) {
1142aa9f8328SJames Bottomley 		if (mvi->devices[dev].dev_type == SAS_PHY_UNUSED) {
114320b09c29SAndy Yan 			mvi->devices[dev].device_id = dev;
114420b09c29SAndy Yan 			return &mvi->devices[dev];
114520b09c29SAndy Yan 		}
114620b09c29SAndy Yan 	}
114720b09c29SAndy Yan 
114820b09c29SAndy Yan 	if (dev == MVS_MAX_DEVICES)
114920b09c29SAndy Yan 		mv_printk("max support %d devices, ignore ..\n",
115020b09c29SAndy Yan 			MVS_MAX_DEVICES);
115120b09c29SAndy Yan 
115220b09c29SAndy Yan 	return NULL;
115320b09c29SAndy Yan }
115420b09c29SAndy Yan 
mvs_free_dev(struct mvs_device * mvi_dev)115514bf41dcSBaoyou Xie static void mvs_free_dev(struct mvs_device *mvi_dev)
115620b09c29SAndy Yan {
115720b09c29SAndy Yan 	u32 id = mvi_dev->device_id;
115820b09c29SAndy Yan 	memset(mvi_dev, 0, sizeof(*mvi_dev));
115920b09c29SAndy Yan 	mvi_dev->device_id = id;
1160aa9f8328SJames Bottomley 	mvi_dev->dev_type = SAS_PHY_UNUSED;
116120b09c29SAndy Yan 	mvi_dev->dev_status = MVS_DEV_NORMAL;
116220b09c29SAndy Yan 	mvi_dev->taskfileset = MVS_ID_NOT_MAPPED;
116320b09c29SAndy Yan }
116420b09c29SAndy Yan 
mvs_dev_found_notify(struct domain_device * dev,int lock)116514bf41dcSBaoyou Xie static int mvs_dev_found_notify(struct domain_device *dev, int lock)
116620b09c29SAndy Yan {
116720b09c29SAndy Yan 	unsigned long flags = 0;
116820b09c29SAndy Yan 	int res = 0;
116920b09c29SAndy Yan 	struct mvs_info *mvi = NULL;
117020b09c29SAndy Yan 	struct domain_device *parent_dev = dev->parent;
117120b09c29SAndy Yan 	struct mvs_device *mvi_device;
117220b09c29SAndy Yan 
117320b09c29SAndy Yan 	mvi = mvs_find_dev_mvi(dev);
117420b09c29SAndy Yan 
117520b09c29SAndy Yan 	if (lock)
117620b09c29SAndy Yan 		spin_lock_irqsave(&mvi->lock, flags);
117720b09c29SAndy Yan 
117820b09c29SAndy Yan 	mvi_device = mvs_alloc_dev(mvi);
117920b09c29SAndy Yan 	if (!mvi_device) {
118020b09c29SAndy Yan 		res = -1;
118120b09c29SAndy Yan 		goto found_out;
118220b09c29SAndy Yan 	}
1183f9da3be5SAndy Yan 	dev->lldd_dev = mvi_device;
11849dc9fd94SSrinivas 	mvi_device->dev_status = MVS_DEV_NORMAL;
118520b09c29SAndy Yan 	mvi_device->dev_type = dev->dev_type;
11869870d9a2SAndy Yan 	mvi_device->mvi_info = mvi;
118784fbd0ceSXiangliang Yu 	mvi_device->sas_device = dev;
1188924a3541SJohn Garry 	if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
118920b09c29SAndy Yan 		int phy_id;
119020b09c29SAndy Yan 
1191178c39d9SJason Yan 		phy_id = sas_find_attached_phy_id(&parent_dev->ex_dev, dev);
1192178c39d9SJason Yan 		if (phy_id < 0) {
119320b09c29SAndy Yan 			mv_printk("Error: no attached dev:%016llx"
119420b09c29SAndy Yan 				"at ex:%016llx.\n",
119520b09c29SAndy Yan 				SAS_ADDR(dev->sas_addr),
119620b09c29SAndy Yan 				SAS_ADDR(parent_dev->sas_addr));
1197178c39d9SJason Yan 			res = phy_id;
1198178c39d9SJason Yan 		} else {
1199178c39d9SJason Yan 			mvi_device->attached_phy = phy_id;
120020b09c29SAndy Yan 		}
120120b09c29SAndy Yan 	}
120220b09c29SAndy Yan 
120320b09c29SAndy Yan found_out:
120420b09c29SAndy Yan 	if (lock)
120520b09c29SAndy Yan 		spin_unlock_irqrestore(&mvi->lock, flags);
120620b09c29SAndy Yan 	return res;
120720b09c29SAndy Yan }
120820b09c29SAndy Yan 
mvs_dev_found(struct domain_device * dev)120920b09c29SAndy Yan int mvs_dev_found(struct domain_device *dev)
121020b09c29SAndy Yan {
121120b09c29SAndy Yan 	return mvs_dev_found_notify(dev, 1);
121220b09c29SAndy Yan }
121320b09c29SAndy Yan 
mvs_dev_gone_notify(struct domain_device * dev)121414bf41dcSBaoyou Xie static void mvs_dev_gone_notify(struct domain_device *dev)
121520b09c29SAndy Yan {
121620b09c29SAndy Yan 	unsigned long flags = 0;
1217f9da3be5SAndy Yan 	struct mvs_device *mvi_dev = dev->lldd_dev;
1218eaa015d2SRickard Strandqvist 	struct mvs_info *mvi;
1219eaa015d2SRickard Strandqvist 
1220eaa015d2SRickard Strandqvist 	if (!mvi_dev) {
1221eaa015d2SRickard Strandqvist 		mv_dprintk("found dev has gone.\n");
1222eaa015d2SRickard Strandqvist 		return;
1223eaa015d2SRickard Strandqvist 	}
1224eaa015d2SRickard Strandqvist 
1225eaa015d2SRickard Strandqvist 	mvi = mvi_dev->mvi_info;
122620b09c29SAndy Yan 
122720b09c29SAndy Yan 	spin_lock_irqsave(&mvi->lock, flags);
122820b09c29SAndy Yan 
122920b09c29SAndy Yan 	mv_dprintk("found dev[%d:%x] is gone.\n",
123020b09c29SAndy Yan 		mvi_dev->device_id, mvi_dev->dev_type);
12319dc9fd94SSrinivas 	mvs_release_task(mvi, dev);
123220b09c29SAndy Yan 	mvs_free_reg_set(mvi, mvi_dev);
123320b09c29SAndy Yan 	mvs_free_dev(mvi_dev);
1234eaa015d2SRickard Strandqvist 
123520b09c29SAndy Yan 	dev->lldd_dev = NULL;
123684fbd0ceSXiangliang Yu 	mvi_dev->sas_device = NULL;
123720b09c29SAndy Yan 
123820b09c29SAndy Yan 	spin_unlock_irqrestore(&mvi->lock, flags);
123920b09c29SAndy Yan }
124020b09c29SAndy Yan 
124120b09c29SAndy Yan 
mvs_dev_gone(struct domain_device * dev)124220b09c29SAndy Yan void mvs_dev_gone(struct domain_device *dev)
124320b09c29SAndy Yan {
12449dc9fd94SSrinivas 	mvs_dev_gone_notify(dev);
124520b09c29SAndy Yan }
124620b09c29SAndy Yan 
124720b09c29SAndy Yan /*  Standard mandates link reset for ATA  (type 0)
124820b09c29SAndy Yan     and hard reset for SSP (type 1) , only for RECOVERY */
mvs_debug_I_T_nexus_reset(struct domain_device * dev)124920b09c29SAndy Yan static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
125020b09c29SAndy Yan {
125120b09c29SAndy Yan 	int rc;
1252f41a0c44SDan Williams 	struct sas_phy *phy = sas_get_local_phy(dev);
1253aa9f8328SJames Bottomley 	int reset_type = (dev->dev_type == SAS_SATA_DEV ||
125420b09c29SAndy Yan 			(dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
125520b09c29SAndy Yan 	rc = sas_phy_reset(phy, reset_type);
1256f41a0c44SDan Williams 	sas_put_local_phy(phy);
125720b09c29SAndy Yan 	msleep(2000);
125820b09c29SAndy Yan 	return rc;
125920b09c29SAndy Yan }
126020b09c29SAndy Yan 
126120b09c29SAndy Yan /* mandatory SAM-3 */
mvs_lu_reset(struct domain_device * dev,u8 * lun)126220b09c29SAndy Yan int mvs_lu_reset(struct domain_device *dev, u8 *lun)
126320b09c29SAndy Yan {
126420b09c29SAndy Yan 	unsigned long flags;
126584fbd0ceSXiangliang Yu 	int rc = TMF_RESP_FUNC_FAILED;
1266f9da3be5SAndy Yan 	struct mvs_device * mvi_dev = dev->lldd_dev;
12679870d9a2SAndy Yan 	struct mvs_info *mvi = mvi_dev->mvi_info;
126820b09c29SAndy Yan 
126920b09c29SAndy Yan 	mvi_dev->dev_status = MVS_DEV_EH;
127029d77690SJohn Garry 	rc = sas_lu_reset(dev, lun);
127120b09c29SAndy Yan 	if (rc == TMF_RESP_FUNC_COMPLETE) {
127220b09c29SAndy Yan 		spin_lock_irqsave(&mvi->lock, flags);
12739dc9fd94SSrinivas 		mvs_release_task(mvi, dev);
127420b09c29SAndy Yan 		spin_unlock_irqrestore(&mvi->lock, flags);
127520b09c29SAndy Yan 	}
127620b09c29SAndy Yan 	/* If failed, fall-through I_T_Nexus reset */
127720b09c29SAndy Yan 	mv_printk("%s for device[%x]:rc= %d\n", __func__,
127820b09c29SAndy Yan 			mvi_dev->device_id, rc);
127920b09c29SAndy Yan 	return rc;
128020b09c29SAndy Yan }
128120b09c29SAndy Yan 
mvs_I_T_nexus_reset(struct domain_device * dev)1282dd4969a8SJeff Garzik int mvs_I_T_nexus_reset(struct domain_device *dev)
12832ad52f47SJeff Garzik {
128420b09c29SAndy Yan 	unsigned long flags;
12859dc9fd94SSrinivas 	int rc = TMF_RESP_FUNC_FAILED;
128620b09c29SAndy Yan 	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
12879870d9a2SAndy Yan 	struct mvs_info *mvi = mvi_dev->mvi_info;
128820b09c29SAndy Yan 
128920b09c29SAndy Yan 	if (mvi_dev->dev_status != MVS_DEV_EH)
129020b09c29SAndy Yan 		return TMF_RESP_FUNC_COMPLETE;
129184fbd0ceSXiangliang Yu 	else
129284fbd0ceSXiangliang Yu 		mvi_dev->dev_status = MVS_DEV_NORMAL;
129320b09c29SAndy Yan 	rc = mvs_debug_I_T_nexus_reset(dev);
129420b09c29SAndy Yan 	mv_printk("%s for device[%x]:rc= %d\n",
129520b09c29SAndy Yan 		__func__, mvi_dev->device_id, rc);
129620b09c29SAndy Yan 
129720b09c29SAndy Yan 	spin_lock_irqsave(&mvi->lock, flags);
12989dc9fd94SSrinivas 	mvs_release_task(mvi, dev);
129920b09c29SAndy Yan 	spin_unlock_irqrestore(&mvi->lock, flags);
130020b09c29SAndy Yan 
130120b09c29SAndy Yan 	return rc;
130220b09c29SAndy Yan }
130320b09c29SAndy Yan /* optional SAM-3 */
mvs_query_task(struct sas_task * task)130420b09c29SAndy Yan int mvs_query_task(struct sas_task *task)
130520b09c29SAndy Yan {
130620b09c29SAndy Yan 	u32 tag;
130720b09c29SAndy Yan 	int rc = TMF_RESP_FUNC_FAILED;
130820b09c29SAndy Yan 
130920b09c29SAndy Yan 	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
131020b09c29SAndy Yan 		struct domain_device *dev = task->dev;
13119870d9a2SAndy Yan 		struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
13129870d9a2SAndy Yan 		struct mvs_info *mvi = mvi_dev->mvi_info;
131320b09c29SAndy Yan 
131420b09c29SAndy Yan 		rc = mvs_find_tag(mvi, task, &tag);
131520b09c29SAndy Yan 		if (rc == 0) {
131620b09c29SAndy Yan 			rc = TMF_RESP_FUNC_FAILED;
131720b09c29SAndy Yan 			return rc;
131820b09c29SAndy Yan 		}
131920b09c29SAndy Yan 
132072f8810eSJohn Garry 		rc = sas_query_task(task, tag);
132120b09c29SAndy Yan 		switch (rc) {
132220b09c29SAndy Yan 		/* The task is still in Lun, release it then */
132320b09c29SAndy Yan 		case TMF_RESP_FUNC_SUCC:
132420b09c29SAndy Yan 		/* The task is not in Lun or failed, reset the phy */
132520b09c29SAndy Yan 		case TMF_RESP_FUNC_FAILED:
132620b09c29SAndy Yan 		case TMF_RESP_FUNC_COMPLETE:
132720b09c29SAndy Yan 			break;
132820b09c29SAndy Yan 		}
132920b09c29SAndy Yan 	}
133020b09c29SAndy Yan 	mv_printk("%s:rc= %d\n", __func__, rc);
133120b09c29SAndy Yan 	return rc;
133220b09c29SAndy Yan }
133320b09c29SAndy Yan 
133420b09c29SAndy Yan /*  mandatory SAM-3, still need free task/slot info */
mvs_abort_task(struct sas_task * task)133520b09c29SAndy Yan int mvs_abort_task(struct sas_task *task)
133620b09c29SAndy Yan {
133720b09c29SAndy Yan 	struct domain_device *dev = task->dev;
13389870d9a2SAndy Yan 	struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
133924ae163eSJiri Slaby 	struct mvs_info *mvi;
134020b09c29SAndy Yan 	int rc = TMF_RESP_FUNC_FAILED;
134120b09c29SAndy Yan 	unsigned long flags;
134220b09c29SAndy Yan 	u32 tag;
13439870d9a2SAndy Yan 
13449dc9fd94SSrinivas 	if (!mvi_dev) {
134584fbd0ceSXiangliang Yu 		mv_printk("Device has removed\n");
134684fbd0ceSXiangliang Yu 		return TMF_RESP_FUNC_FAILED;
13479dc9fd94SSrinivas 	}
13489dc9fd94SSrinivas 
134924ae163eSJiri Slaby 	mvi = mvi_dev->mvi_info;
135024ae163eSJiri Slaby 
135120b09c29SAndy Yan 	spin_lock_irqsave(&task->task_state_lock, flags);
135220b09c29SAndy Yan 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
135320b09c29SAndy Yan 		spin_unlock_irqrestore(&task->task_state_lock, flags);
135420b09c29SAndy Yan 		rc = TMF_RESP_FUNC_COMPLETE;
135520b09c29SAndy Yan 		goto out;
135620b09c29SAndy Yan 	}
135720b09c29SAndy Yan 	spin_unlock_irqrestore(&task->task_state_lock, flags);
13589dc9fd94SSrinivas 	mvi_dev->dev_status = MVS_DEV_EH;
135920b09c29SAndy Yan 	if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
136020b09c29SAndy Yan 		rc = mvs_find_tag(mvi, task, &tag);
136120b09c29SAndy Yan 		if (rc == 0) {
136220b09c29SAndy Yan 			mv_printk("No such tag in %s\n", __func__);
136320b09c29SAndy Yan 			rc = TMF_RESP_FUNC_FAILED;
136420b09c29SAndy Yan 			return rc;
136520b09c29SAndy Yan 		}
136620b09c29SAndy Yan 
13674fea759eSJohn Garry 		rc = sas_abort_task(task, tag);
136820b09c29SAndy Yan 
136920b09c29SAndy Yan 		/* if successful, clear the task and callback forwards.*/
137020b09c29SAndy Yan 		if (rc == TMF_RESP_FUNC_COMPLETE) {
137120b09c29SAndy Yan 			u32 slot_no;
137220b09c29SAndy Yan 			struct mvs_slot_info *slot;
137320b09c29SAndy Yan 
137420b09c29SAndy Yan 			if (task->lldd_task) {
1375f9da3be5SAndy Yan 				slot = task->lldd_task;
137620b09c29SAndy Yan 				slot_no = (u32) (slot - mvi->slot_info);
13779dc9fd94SSrinivas 				spin_lock_irqsave(&mvi->lock, flags);
137820b09c29SAndy Yan 				mvs_slot_complete(mvi, slot_no, 1);
13799dc9fd94SSrinivas 				spin_unlock_irqrestore(&mvi->lock, flags);
138020b09c29SAndy Yan 			}
138120b09c29SAndy Yan 		}
13829dc9fd94SSrinivas 
138320b09c29SAndy Yan 	} else if (task->task_proto & SAS_PROTOCOL_SATA ||
138420b09c29SAndy Yan 		task->task_proto & SAS_PROTOCOL_STP) {
1385aa9f8328SJames Bottomley 		if (SAS_SATA_DEV == dev->dev_type) {
13869dc9fd94SSrinivas 			struct mvs_slot_info *slot = task->lldd_task;
13879dc9fd94SSrinivas 			u32 slot_idx = (u32)(slot - mvi->slot_info);
138884fbd0ceSXiangliang Yu 			mv_dprintk("mvs_abort_task() mvi=%p task=%p "
13899dc9fd94SSrinivas 				   "slot=%p slot_idx=x%x\n",
13909dc9fd94SSrinivas 				   mvi, task, slot, slot_idx);
139195ab0003SJianpeng Ma 			task->task_state_flags |= SAS_TASK_STATE_ABORTED;
13929dc9fd94SSrinivas 			mvs_slot_task_free(mvi, task, slot, slot_idx);
139384fbd0ceSXiangliang Yu 			rc = TMF_RESP_FUNC_COMPLETE;
139484fbd0ceSXiangliang Yu 			goto out;
13959dc9fd94SSrinivas 		}
139620b09c29SAndy Yan 
139720b09c29SAndy Yan 	}
139820b09c29SAndy Yan out:
139920b09c29SAndy Yan 	if (rc != TMF_RESP_FUNC_COMPLETE)
140020b09c29SAndy Yan 		mv_printk("%s:rc= %d\n", __func__, rc);
140120b09c29SAndy Yan 	return rc;
140220b09c29SAndy Yan }
140320b09c29SAndy Yan 
mvs_sata_done(struct mvs_info * mvi,struct sas_task * task,u32 slot_idx,int err)1404dd4969a8SJeff Garzik static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
1405dd4969a8SJeff Garzik 			u32 slot_idx, int err)
1406dd4969a8SJeff Garzik {
1407f9da3be5SAndy Yan 	struct mvs_device *mvi_dev = task->dev->lldd_dev;
1408dd4969a8SJeff Garzik 	struct task_status_struct *tstat = &task->task_status;
1409dd4969a8SJeff Garzik 	struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
1410df64d3caSJames Bottomley 	int stat = SAM_STAT_GOOD;
1411dd4969a8SJeff Garzik 
141220b09c29SAndy Yan 
1413dd4969a8SJeff Garzik 	resp->frame_len = sizeof(struct dev_to_host_fis);
1414dd4969a8SJeff Garzik 	memcpy(&resp->ending_fis[0],
141520b09c29SAndy Yan 	       SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset),
1416dd4969a8SJeff Garzik 	       sizeof(struct dev_to_host_fis));
1417dd4969a8SJeff Garzik 	tstat->buf_valid_size = sizeof(*resp);
14189dc9fd94SSrinivas 	if (unlikely(err)) {
14199dc9fd94SSrinivas 		if (unlikely(err & CMD_ISS_STPD))
14209dc9fd94SSrinivas 			stat = SAS_OPEN_REJECT;
14219dc9fd94SSrinivas 		else
1422dd4969a8SJeff Garzik 			stat = SAS_PROTO_RESPONSE;
14239dc9fd94SSrinivas        }
14249dc9fd94SSrinivas 
1425dd4969a8SJeff Garzik 	return stat;
1426dd4969a8SJeff Garzik }
1427dd4969a8SJeff Garzik 
mvs_set_sense(u8 * buffer,int len,int d_sense,int key,int asc,int ascq)142814bf41dcSBaoyou Xie static void mvs_set_sense(u8 *buffer, int len, int d_sense,
1429a4632aaeSXiangliang Yu 		int key, int asc, int ascq)
1430a4632aaeSXiangliang Yu {
1431a4632aaeSXiangliang Yu 	memset(buffer, 0, len);
1432a4632aaeSXiangliang Yu 
1433a4632aaeSXiangliang Yu 	if (d_sense) {
1434a4632aaeSXiangliang Yu 		/* Descriptor format */
1435a4632aaeSXiangliang Yu 		if (len < 4) {
1436a4632aaeSXiangliang Yu 			mv_printk("Length %d of sense buffer too small to "
1437a4632aaeSXiangliang Yu 				"fit sense %x:%x:%x", len, key, asc, ascq);
1438a4632aaeSXiangliang Yu 		}
1439a4632aaeSXiangliang Yu 
1440a4632aaeSXiangliang Yu 		buffer[0] = 0x72;		/* Response Code	*/
1441a4632aaeSXiangliang Yu 		if (len > 1)
1442a4632aaeSXiangliang Yu 			buffer[1] = key;	/* Sense Key */
1443a4632aaeSXiangliang Yu 		if (len > 2)
1444a4632aaeSXiangliang Yu 			buffer[2] = asc;	/* ASC	*/
1445a4632aaeSXiangliang Yu 		if (len > 3)
1446a4632aaeSXiangliang Yu 			buffer[3] = ascq;	/* ASCQ	*/
1447a4632aaeSXiangliang Yu 	} else {
1448a4632aaeSXiangliang Yu 		if (len < 14) {
1449a4632aaeSXiangliang Yu 			mv_printk("Length %d of sense buffer too small to "
1450a4632aaeSXiangliang Yu 				"fit sense %x:%x:%x", len, key, asc, ascq);
1451a4632aaeSXiangliang Yu 		}
1452a4632aaeSXiangliang Yu 
1453a4632aaeSXiangliang Yu 		buffer[0] = 0x70;		/* Response Code	*/
1454a4632aaeSXiangliang Yu 		if (len > 2)
1455a4632aaeSXiangliang Yu 			buffer[2] = key;	/* Sense Key */
1456a4632aaeSXiangliang Yu 		if (len > 7)
1457a4632aaeSXiangliang Yu 			buffer[7] = 0x0a;	/* Additional Sense Length */
1458a4632aaeSXiangliang Yu 		if (len > 12)
1459a4632aaeSXiangliang Yu 			buffer[12] = asc;	/* ASC */
1460a4632aaeSXiangliang Yu 		if (len > 13)
1461a4632aaeSXiangliang Yu 			buffer[13] = ascq; /* ASCQ */
1462a4632aaeSXiangliang Yu 	}
1463a4632aaeSXiangliang Yu 
1464a4632aaeSXiangliang Yu 	return;
1465a4632aaeSXiangliang Yu }
1466a4632aaeSXiangliang Yu 
mvs_fill_ssp_resp_iu(struct ssp_response_iu * iu,u8 key,u8 asc,u8 asc_q)146714bf41dcSBaoyou Xie static void mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu,
1468a4632aaeSXiangliang Yu 				u8 key, u8 asc, u8 asc_q)
1469a4632aaeSXiangliang Yu {
14701d6049a3SJohn Garry 	iu->datapres = SAS_DATAPRES_SENSE_DATA;
1471a4632aaeSXiangliang Yu 	iu->response_data_len = 0;
1472a4632aaeSXiangliang Yu 	iu->sense_data_len = 17;
1473a4632aaeSXiangliang Yu 	iu->status = 02;
1474a4632aaeSXiangliang Yu 	mvs_set_sense(iu->sense_data, 17, 0,
1475a4632aaeSXiangliang Yu 			key, asc, asc_q);
1476a4632aaeSXiangliang Yu }
1477a4632aaeSXiangliang Yu 
mvs_slot_err(struct mvs_info * mvi,struct sas_task * task,u32 slot_idx)1478dd4969a8SJeff Garzik static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
1479dd4969a8SJeff Garzik 			 u32 slot_idx)
1480dd4969a8SJeff Garzik {
1481dd4969a8SJeff Garzik 	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
148220b09c29SAndy Yan 	int stat;
148384fbd0ceSXiangliang Yu 	u32 err_dw0 = le32_to_cpu(*(u32 *)slot->response);
1484a4632aaeSXiangliang Yu 	u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1));
148520b09c29SAndy Yan 	u32 tfs = 0;
148620b09c29SAndy Yan 	enum mvs_port_type type = PORT_TYPE_SAS;
1487dd4969a8SJeff Garzik 
148820b09c29SAndy Yan 	if (err_dw0 & CMD_ISS_STPD)
148920b09c29SAndy Yan 		MVS_CHIP_DISP->issue_stop(mvi, type, tfs);
149020b09c29SAndy Yan 
149120b09c29SAndy Yan 	MVS_CHIP_DISP->command_active(mvi, slot_idx);
149220b09c29SAndy Yan 
1493df64d3caSJames Bottomley 	stat = SAM_STAT_CHECK_CONDITION;
1494dd4969a8SJeff Garzik 	switch (task->task_proto) {
1495dd4969a8SJeff Garzik 	case SAS_PROTOCOL_SSP:
1496a4632aaeSXiangliang Yu 	{
149720b09c29SAndy Yan 		stat = SAS_ABORTED_TASK;
1498a4632aaeSXiangliang Yu 		if ((err_dw0 & NO_DEST) || err_dw1 & bit(31)) {
1499a4632aaeSXiangliang Yu 			struct ssp_response_iu *iu = slot->response +
1500a4632aaeSXiangliang Yu 				sizeof(struct mvs_err_info);
1501a4632aaeSXiangliang Yu 			mvs_fill_ssp_resp_iu(iu, NOT_READY, 0x04, 01);
1502a4632aaeSXiangliang Yu 			sas_ssp_task_response(mvi->dev, task, iu);
1503a4632aaeSXiangliang Yu 			stat = SAM_STAT_CHECK_CONDITION;
1504a4632aaeSXiangliang Yu 		}
1505a4632aaeSXiangliang Yu 		if (err_dw1 & bit(31))
1506a4632aaeSXiangliang Yu 			mv_printk("reuse same slot, retry command.\n");
1507dd4969a8SJeff Garzik 		break;
1508a4632aaeSXiangliang Yu 	}
1509dd4969a8SJeff Garzik 	case SAS_PROTOCOL_SMP:
1510df64d3caSJames Bottomley 		stat = SAM_STAT_CHECK_CONDITION;
1511dd4969a8SJeff Garzik 		break;
151220b09c29SAndy Yan 
1513dd4969a8SJeff Garzik 	case SAS_PROTOCOL_SATA:
1514dd4969a8SJeff Garzik 	case SAS_PROTOCOL_STP:
1515dd4969a8SJeff Garzik 	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
151620b09c29SAndy Yan 	{
151720b09c29SAndy Yan 		task->ata_task.use_ncq = 0;
151884fbd0ceSXiangliang Yu 		stat = SAS_PROTO_RESPONSE;
15199dc9fd94SSrinivas 		mvs_sata_done(mvi, task, slot_idx, err_dw0);
152020b09c29SAndy Yan 	}
1521dd4969a8SJeff Garzik 		break;
1522dd4969a8SJeff Garzik 	default:
1523dd4969a8SJeff Garzik 		break;
1524dd4969a8SJeff Garzik 	}
1525dd4969a8SJeff Garzik 
1526dd4969a8SJeff Garzik 	return stat;
1527dd4969a8SJeff Garzik }
1528dd4969a8SJeff Garzik 
mvs_slot_complete(struct mvs_info * mvi,u32 rx_desc,u32 flags)152920b09c29SAndy Yan int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
1530dd4969a8SJeff Garzik {
1531dd4969a8SJeff Garzik 	u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
1532dd4969a8SJeff Garzik 	struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
1533dd4969a8SJeff Garzik 	struct sas_task *task = slot->task;
153420b09c29SAndy Yan 	struct mvs_device *mvi_dev = NULL;
1535dd4969a8SJeff Garzik 	struct task_status_struct *tstat;
15369dc9fd94SSrinivas 	struct domain_device *dev;
15379dc9fd94SSrinivas 	u32 aborted;
153820b09c29SAndy Yan 
1539dd4969a8SJeff Garzik 	void *to;
154020b09c29SAndy Yan 	enum exec_status sts;
1541dd4969a8SJeff Garzik 
15429dc9fd94SSrinivas 	if (unlikely(!task || !task->lldd_task || !task->dev))
1543dd4969a8SJeff Garzik 		return -1;
1544dd4969a8SJeff Garzik 
154520b09c29SAndy Yan 	tstat = &task->task_status;
15469dc9fd94SSrinivas 	dev = task->dev;
15479dc9fd94SSrinivas 	mvi_dev = dev->lldd_dev;
154820b09c29SAndy Yan 
1549dd4969a8SJeff Garzik 	spin_lock(&task->task_state_lock);
155026fc0ea7SJohn Garry 	task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
1551dd4969a8SJeff Garzik 	task->task_state_flags |= SAS_TASK_STATE_DONE;
155220b09c29SAndy Yan 	/* race condition*/
155320b09c29SAndy Yan 	aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
1554dd4969a8SJeff Garzik 	spin_unlock(&task->task_state_lock);
1555dd4969a8SJeff Garzik 
1556dd4969a8SJeff Garzik 	memset(tstat, 0, sizeof(*tstat));
1557dd4969a8SJeff Garzik 	tstat->resp = SAS_TASK_COMPLETE;
1558dd4969a8SJeff Garzik 
155920b09c29SAndy Yan 	if (unlikely(aborted)) {
156020b09c29SAndy Yan 		tstat->stat = SAS_ABORTED_TASK;
15619dc9fd94SSrinivas 		if (mvi_dev && mvi_dev->running_req)
15629dc9fd94SSrinivas 			mvi_dev->running_req--;
156320b09c29SAndy Yan 		if (sas_protocol_ata(task->task_proto))
156420b09c29SAndy Yan 			mvs_free_reg_set(mvi, mvi_dev);
156520b09c29SAndy Yan 
156620b09c29SAndy Yan 		mvs_slot_task_free(mvi, task, slot, slot_idx);
156720b09c29SAndy Yan 		return -1;
156820b09c29SAndy Yan 	}
156920b09c29SAndy Yan 
1570e144f7efSXiangliang Yu 	/* when no device attaching, go ahead and complete by error handling*/
15719dc9fd94SSrinivas 	if (unlikely(!mvi_dev || flags)) {
15729dc9fd94SSrinivas 		if (!mvi_dev)
157320b09c29SAndy Yan 			mv_dprintk("port has not device.\n");
1574dd4969a8SJeff Garzik 		tstat->stat = SAS_PHY_DOWN;
1575dd4969a8SJeff Garzik 		goto out;
1576dd4969a8SJeff Garzik 	}
1577dd4969a8SJeff Garzik 
157853a983c4SJames Bottomley 	/*
157953a983c4SJames Bottomley 	 * error info record present; slot->response is 32 bit aligned but may
158053a983c4SJames Bottomley 	 * not be 64 bit aligned, so check for zero in two 32 bit reads
158153a983c4SJames Bottomley 	 */
158253a983c4SJames Bottomley 	if (unlikely((rx_desc & RXQ_ERR)
158353a983c4SJames Bottomley 		     && (*((u32 *)slot->response)
158453a983c4SJames Bottomley 			 || *(((u32 *)slot->response) + 1)))) {
158584fbd0ceSXiangliang Yu 		mv_dprintk("port %d slot %d rx_desc %X has error info"
158684fbd0ceSXiangliang Yu 			"%016llX.\n", slot->port->sas_port.id, slot_idx,
158753a983c4SJames Bottomley 			 rx_desc, get_unaligned_le64(slot->response));
1588dd4969a8SJeff Garzik 		tstat->stat = mvs_slot_err(mvi, task, slot_idx);
15899dc9fd94SSrinivas 		tstat->resp = SAS_TASK_COMPLETE;
1590dd4969a8SJeff Garzik 		goto out;
1591dd4969a8SJeff Garzik 	}
1592dd4969a8SJeff Garzik 
1593dd4969a8SJeff Garzik 	switch (task->task_proto) {
1594dd4969a8SJeff Garzik 	case SAS_PROTOCOL_SSP:
1595dd4969a8SJeff Garzik 		/* hw says status == 0, datapres == 0 */
1596dd4969a8SJeff Garzik 		if (rx_desc & RXQ_GOOD) {
1597d377f415SBart Van Assche 			tstat->stat = SAS_SAM_STAT_GOOD;
1598dd4969a8SJeff Garzik 			tstat->resp = SAS_TASK_COMPLETE;
1599dd4969a8SJeff Garzik 		}
1600dd4969a8SJeff Garzik 		/* response frame present */
1601dd4969a8SJeff Garzik 		else if (rx_desc & RXQ_RSP) {
160220b09c29SAndy Yan 			struct ssp_response_iu *iu = slot->response +
160320b09c29SAndy Yan 						sizeof(struct mvs_err_info);
160420b09c29SAndy Yan 			sas_ssp_task_response(mvi->dev, task, iu);
160520b09c29SAndy Yan 		} else
1606d377f415SBart Van Assche 			tstat->stat = SAS_SAM_STAT_CHECK_CONDITION;
1607dd4969a8SJeff Garzik 		break;
1608dd4969a8SJeff Garzik 
1609dd4969a8SJeff Garzik 	case SAS_PROTOCOL_SMP: {
1610dd4969a8SJeff Garzik 			struct scatterlist *sg_resp = &task->smp_task.smp_resp;
1611d377f415SBart Van Assche 			tstat->stat = SAS_SAM_STAT_GOOD;
161277dfce07SCong Wang 			to = kmap_atomic(sg_page(sg_resp));
1613dd4969a8SJeff Garzik 			memcpy(to + sg_resp->offset,
1614dd4969a8SJeff Garzik 				slot->response + sizeof(struct mvs_err_info),
1615dd4969a8SJeff Garzik 				sg_dma_len(sg_resp));
161677dfce07SCong Wang 			kunmap_atomic(to);
1617dd4969a8SJeff Garzik 			break;
1618dd4969a8SJeff Garzik 		}
1619dd4969a8SJeff Garzik 
1620dd4969a8SJeff Garzik 	case SAS_PROTOCOL_SATA:
1621dd4969a8SJeff Garzik 	case SAS_PROTOCOL_STP:
1622dd4969a8SJeff Garzik 	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
1623dd4969a8SJeff Garzik 			tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
1624dd4969a8SJeff Garzik 			break;
1625dd4969a8SJeff Garzik 		}
1626dd4969a8SJeff Garzik 
1627dd4969a8SJeff Garzik 	default:
1628d377f415SBart Van Assche 		tstat->stat = SAS_SAM_STAT_CHECK_CONDITION;
1629dd4969a8SJeff Garzik 		break;
1630dd4969a8SJeff Garzik 	}
16319dc9fd94SSrinivas 	if (!slot->port->port_attached) {
16329dc9fd94SSrinivas 		mv_dprintk("port %d has removed.\n", slot->port->sas_port.id);
16339dc9fd94SSrinivas 		tstat->stat = SAS_PHY_DOWN;
16349dc9fd94SSrinivas 	}
16359dc9fd94SSrinivas 
1636dd4969a8SJeff Garzik 
1637dd4969a8SJeff Garzik out:
16389dc9fd94SSrinivas 	if (mvi_dev && mvi_dev->running_req) {
16399dc9fd94SSrinivas 		mvi_dev->running_req--;
16409dc9fd94SSrinivas 		if (sas_protocol_ata(task->task_proto) && !mvi_dev->running_req)
164120b09c29SAndy Yan 			mvs_free_reg_set(mvi, mvi_dev);
16420f980a87SAndy Yan 	}
1643dd4969a8SJeff Garzik 	mvs_slot_task_free(mvi, task, slot, slot_idx);
164420b09c29SAndy Yan 	sts = tstat->stat;
1645dd4969a8SJeff Garzik 
1646dd4969a8SJeff Garzik 	spin_unlock(&mvi->lock);
164720b09c29SAndy Yan 	if (task->task_done)
1648dd4969a8SJeff Garzik 		task->task_done(task);
164984fbd0ceSXiangliang Yu 
1650dd4969a8SJeff Garzik 	spin_lock(&mvi->lock);
165120b09c29SAndy Yan 
165220b09c29SAndy Yan 	return sts;
1653dd4969a8SJeff Garzik }
1654dd4969a8SJeff Garzik 
mvs_do_release_task(struct mvs_info * mvi,int phy_no,struct domain_device * dev)16559dc9fd94SSrinivas void mvs_do_release_task(struct mvs_info *mvi,
165620b09c29SAndy Yan 		int phy_no, struct domain_device *dev)
1657dd4969a8SJeff Garzik {
16589dc9fd94SSrinivas 	u32 slot_idx;
165920b09c29SAndy Yan 	struct mvs_phy *phy;
166020b09c29SAndy Yan 	struct mvs_port *port;
166120b09c29SAndy Yan 	struct mvs_slot_info *slot, *slot2;
1662dd4969a8SJeff Garzik 
166320b09c29SAndy Yan 	phy = &mvi->phy[phy_no];
166420b09c29SAndy Yan 	port = phy->port;
1665dd4969a8SJeff Garzik 	if (!port)
1666dd4969a8SJeff Garzik 		return;
16679dc9fd94SSrinivas 	/* clean cmpl queue in case request is already finished */
16689dc9fd94SSrinivas 	mvs_int_rx(mvi, false);
16699dc9fd94SSrinivas 
16709dc9fd94SSrinivas 
1671dd4969a8SJeff Garzik 
167220b09c29SAndy Yan 	list_for_each_entry_safe(slot, slot2, &port->list, entry) {
167320b09c29SAndy Yan 		struct sas_task *task;
167420b09c29SAndy Yan 		slot_idx = (u32) (slot - mvi->slot_info);
167520b09c29SAndy Yan 		task = slot->task;
167620b09c29SAndy Yan 
167720b09c29SAndy Yan 		if (dev && task->dev != dev)
167820b09c29SAndy Yan 			continue;
167920b09c29SAndy Yan 
168020b09c29SAndy Yan 		mv_printk("Release slot [%x] tag[%x], task [%p]:\n",
168120b09c29SAndy Yan 			slot_idx, slot->slot_tag, task);
16829dc9fd94SSrinivas 		MVS_CHIP_DISP->command_active(mvi, slot_idx);
168320b09c29SAndy Yan 
168420b09c29SAndy Yan 		mvs_slot_complete(mvi, slot_idx, 1);
1685dd4969a8SJeff Garzik 	}
1686dd4969a8SJeff Garzik }
1687dd4969a8SJeff Garzik 
mvs_release_task(struct mvs_info * mvi,struct domain_device * dev)16889dc9fd94SSrinivas void mvs_release_task(struct mvs_info *mvi,
16899dc9fd94SSrinivas 		      struct domain_device *dev)
16909dc9fd94SSrinivas {
16919dc9fd94SSrinivas 	int i, phyno[WIDE_PORT_MAX_PHY], num;
16929dc9fd94SSrinivas 	num = mvs_find_dev_phyno(dev, phyno);
16939dc9fd94SSrinivas 	for (i = 0; i < num; i++)
16949dc9fd94SSrinivas 		mvs_do_release_task(mvi, phyno[i], dev);
16959dc9fd94SSrinivas }
16969dc9fd94SSrinivas 
mvs_phy_disconnected(struct mvs_phy * phy)169720b09c29SAndy Yan static void mvs_phy_disconnected(struct mvs_phy *phy)
1698dd4969a8SJeff Garzik {
169920b09c29SAndy Yan 	phy->phy_attached = 0;
170020b09c29SAndy Yan 	phy->att_dev_info = 0;
170120b09c29SAndy Yan 	phy->att_dev_sas_addr = 0;
170220b09c29SAndy Yan }
170320b09c29SAndy Yan 
mvs_work_queue(struct work_struct * work)170420b09c29SAndy Yan static void mvs_work_queue(struct work_struct *work)
170520b09c29SAndy Yan {
170620b09c29SAndy Yan 	struct delayed_work *dw = container_of(work, struct delayed_work, work);
170720b09c29SAndy Yan 	struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q);
170820b09c29SAndy Yan 	struct mvs_info *mvi = mwq->mvi;
170920b09c29SAndy Yan 	unsigned long flags;
171020b09c29SAndy Yan 	u32 phy_no = (unsigned long) mwq->data;
1711dd4969a8SJeff Garzik 	struct mvs_phy *phy = &mvi->phy[phy_no];
1712dd4969a8SJeff Garzik 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
1713dd4969a8SJeff Garzik 
1714a4632aaeSXiangliang Yu 	spin_lock_irqsave(&mvi->lock, flags);
1715a4632aaeSXiangliang Yu 	if (mwq->handler & PHY_PLUG_EVENT) {
1716a4632aaeSXiangliang Yu 
171720b09c29SAndy Yan 		if (phy->phy_event & PHY_PLUG_OUT) {
171820b09c29SAndy Yan 			u32 tmp;
171933279c30SYueHaibing 
172020b09c29SAndy Yan 			tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no);
172120b09c29SAndy Yan 			phy->phy_event &= ~PHY_PLUG_OUT;
172220b09c29SAndy Yan 			if (!(tmp & PHY_READY_MASK)) {
172320b09c29SAndy Yan 				sas_phy_disconnected(sas_phy);
172420b09c29SAndy Yan 				mvs_phy_disconnected(phy);
172536cdfd0fSAhmed S. Darwish 				sas_notify_phy_event(sas_phy,
1726feb18e90SAhmed S. Darwish 					PHYE_LOSS_OF_SIGNAL, GFP_ATOMIC);
172720b09c29SAndy Yan 				mv_dprintk("phy%d Removed Device\n", phy_no);
172820b09c29SAndy Yan 			} else {
172920b09c29SAndy Yan 				MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
173020b09c29SAndy Yan 				mvs_update_phyinfo(mvi, phy_no, 1);
1731feb18e90SAhmed S. Darwish 				mvs_bytes_dmaed(mvi, phy_no, GFP_ATOMIC);
173220b09c29SAndy Yan 				mvs_port_notify_formed(sas_phy, 0);
173320b09c29SAndy Yan 				mv_dprintk("phy%d Attached Device\n", phy_no);
173420b09c29SAndy Yan 			}
173520b09c29SAndy Yan 		}
1736a4632aaeSXiangliang Yu 	} else if (mwq->handler & EXP_BRCT_CHG) {
1737a4632aaeSXiangliang Yu 		phy->phy_event &= ~EXP_BRCT_CHG;
173836cdfd0fSAhmed S. Darwish 		sas_notify_port_event(sas_phy,
1739feb18e90SAhmed S. Darwish 				PORTE_BROADCAST_RCVD, GFP_ATOMIC);
1740a4632aaeSXiangliang Yu 		mv_dprintk("phy%d Got Broadcast Change\n", phy_no);
174120b09c29SAndy Yan 	}
174220b09c29SAndy Yan 	list_del(&mwq->entry);
174320b09c29SAndy Yan 	spin_unlock_irqrestore(&mvi->lock, flags);
174420b09c29SAndy Yan 	kfree(mwq);
174520b09c29SAndy Yan }
174620b09c29SAndy Yan 
mvs_handle_event(struct mvs_info * mvi,void * data,int handler)174720b09c29SAndy Yan static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler)
174820b09c29SAndy Yan {
174920b09c29SAndy Yan 	struct mvs_wq *mwq;
175020b09c29SAndy Yan 	int ret = 0;
175120b09c29SAndy Yan 
175220b09c29SAndy Yan 	mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC);
175320b09c29SAndy Yan 	if (mwq) {
175420b09c29SAndy Yan 		mwq->mvi = mvi;
175520b09c29SAndy Yan 		mwq->data = data;
175620b09c29SAndy Yan 		mwq->handler = handler;
175720b09c29SAndy Yan 		MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq);
175820b09c29SAndy Yan 		list_add_tail(&mwq->entry, &mvi->wq_list);
175920b09c29SAndy Yan 		schedule_delayed_work(&mwq->work_q, HZ * 2);
176020b09c29SAndy Yan 	} else
176120b09c29SAndy Yan 		ret = -ENOMEM;
176220b09c29SAndy Yan 
176320b09c29SAndy Yan 	return ret;
176420b09c29SAndy Yan }
176520b09c29SAndy Yan 
mvs_sig_time_out(struct timer_list * t)176677570eedSKees Cook static void mvs_sig_time_out(struct timer_list *t)
176720b09c29SAndy Yan {
176877570eedSKees Cook 	struct mvs_phy *phy = from_timer(phy, t, timer);
176920b09c29SAndy Yan 	struct mvs_info *mvi = phy->mvi;
177020b09c29SAndy Yan 	u8 phy_no;
177120b09c29SAndy Yan 
177220b09c29SAndy Yan 	for (phy_no = 0; phy_no < mvi->chip->n_phy; phy_no++) {
177320b09c29SAndy Yan 		if (&mvi->phy[phy_no] == phy) {
177420b09c29SAndy Yan 			mv_dprintk("Get signature time out, reset phy %d\n",
177520b09c29SAndy Yan 				phy_no+mvi->id*mvi->chip->n_phy);
1776a4632aaeSXiangliang Yu 			MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_HARD_RESET);
177720b09c29SAndy Yan 		}
177820b09c29SAndy Yan 	}
177920b09c29SAndy Yan }
178020b09c29SAndy Yan 
mvs_int_port(struct mvs_info * mvi,int phy_no,u32 events)178120b09c29SAndy Yan void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
178220b09c29SAndy Yan {
178320b09c29SAndy Yan 	u32 tmp;
178420b09c29SAndy Yan 	struct mvs_phy *phy = &mvi->phy[phy_no];
178520b09c29SAndy Yan 
178620b09c29SAndy Yan 	phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
178784fbd0ceSXiangliang Yu 	MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
178884fbd0ceSXiangliang Yu 	mv_dprintk("phy %d ctrl sts=0x%08X.\n", phy_no+mvi->id*mvi->chip->n_phy,
178920b09c29SAndy Yan 		MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no));
179084fbd0ceSXiangliang Yu 	mv_dprintk("phy %d irq sts = 0x%08X\n", phy_no+mvi->id*mvi->chip->n_phy,
179120b09c29SAndy Yan 		phy->irq_status);
179220b09c29SAndy Yan 
1793dd4969a8SJeff Garzik 	/*
1794dd4969a8SJeff Garzik 	* events is port event now ,
1795dd4969a8SJeff Garzik 	* we need check the interrupt status which belongs to per port.
1796dd4969a8SJeff Garzik 	*/
1797dd4969a8SJeff Garzik 
17989dc9fd94SSrinivas 	if (phy->irq_status & PHYEV_DCDR_ERR) {
179984fbd0ceSXiangliang Yu 		mv_dprintk("phy %d STP decoding error.\n",
180020b09c29SAndy Yan 		phy_no + mvi->id*mvi->chip->n_phy);
18019dc9fd94SSrinivas 	}
1802dd4969a8SJeff Garzik 
180320b09c29SAndy Yan 	if (phy->irq_status & PHYEV_POOF) {
180484fbd0ceSXiangliang Yu 		mdelay(500);
180520b09c29SAndy Yan 		if (!(phy->phy_event & PHY_PLUG_OUT)) {
180620b09c29SAndy Yan 			int dev_sata = phy->phy_type & PORT_TYPE_SATA;
180720b09c29SAndy Yan 			int ready;
18089dc9fd94SSrinivas 			mvs_do_release_task(mvi, phy_no, NULL);
180920b09c29SAndy Yan 			phy->phy_event |= PHY_PLUG_OUT;
18109dc9fd94SSrinivas 			MVS_CHIP_DISP->clear_srs_irq(mvi, 0, 1);
181120b09c29SAndy Yan 			mvs_handle_event(mvi,
181220b09c29SAndy Yan 				(void *)(unsigned long)phy_no,
181320b09c29SAndy Yan 				PHY_PLUG_EVENT);
181420b09c29SAndy Yan 			ready = mvs_is_phy_ready(mvi, phy_no);
181520b09c29SAndy Yan 			if (ready || dev_sata) {
181620b09c29SAndy Yan 				if (MVS_CHIP_DISP->stp_reset)
181720b09c29SAndy Yan 					MVS_CHIP_DISP->stp_reset(mvi,
181820b09c29SAndy Yan 							phy_no);
181920b09c29SAndy Yan 				else
182020b09c29SAndy Yan 					MVS_CHIP_DISP->phy_reset(mvi,
1821a4632aaeSXiangliang Yu 							phy_no, MVS_SOFT_RESET);
182220b09c29SAndy Yan 				return;
1823dd4969a8SJeff Garzik 			}
182420b09c29SAndy Yan 		}
182520b09c29SAndy Yan 	}
182620b09c29SAndy Yan 
1827dd4969a8SJeff Garzik 	if (phy->irq_status & PHYEV_COMWAKE) {
182820b09c29SAndy Yan 		tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, phy_no);
182920b09c29SAndy Yan 		MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no,
1830dd4969a8SJeff Garzik 					tmp | PHYEV_SIG_FIS);
183120b09c29SAndy Yan 		if (phy->timer.function == NULL) {
1832841b86f3SKees Cook 			phy->timer.function = mvs_sig_time_out;
183384fbd0ceSXiangliang Yu 			phy->timer.expires = jiffies + 5*HZ;
183420b09c29SAndy Yan 			add_timer(&phy->timer);
183520b09c29SAndy Yan 		}
1836dd4969a8SJeff Garzik 	}
1837dd4969a8SJeff Garzik 	if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
1838dd4969a8SJeff Garzik 		phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
183920b09c29SAndy Yan 		mv_dprintk("notify plug in on phy[%d]\n", phy_no);
1840dd4969a8SJeff Garzik 		if (phy->phy_status) {
184120b09c29SAndy Yan 			mdelay(10);
184220b09c29SAndy Yan 			MVS_CHIP_DISP->detect_porttype(mvi, phy_no);
1843dd4969a8SJeff Garzik 			if (phy->phy_type & PORT_TYPE_SATA) {
184420b09c29SAndy Yan 				tmp = MVS_CHIP_DISP->read_port_irq_mask(
184520b09c29SAndy Yan 						mvi, phy_no);
1846dd4969a8SJeff Garzik 				tmp &= ~PHYEV_SIG_FIS;
184720b09c29SAndy Yan 				MVS_CHIP_DISP->write_port_irq_mask(mvi,
1848dd4969a8SJeff Garzik 							phy_no, tmp);
1849dd4969a8SJeff Garzik 			}
1850dd4969a8SJeff Garzik 			mvs_update_phyinfo(mvi, phy_no, 0);
18519dc9fd94SSrinivas 			if (phy->phy_type & PORT_TYPE_SAS) {
1852a4632aaeSXiangliang Yu 				MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_PHY_TUNE);
18539dc9fd94SSrinivas 				mdelay(10);
18549dc9fd94SSrinivas 			}
18559dc9fd94SSrinivas 
1856feb18e90SAhmed S. Darwish 			mvs_bytes_dmaed(mvi, phy_no, GFP_ATOMIC);
185720b09c29SAndy Yan 			/* whether driver is going to handle hot plug */
185820b09c29SAndy Yan 			if (phy->phy_event & PHY_PLUG_OUT) {
1859a4632aaeSXiangliang Yu 				mvs_port_notify_formed(&phy->sas_phy, 0);
186020b09c29SAndy Yan 				phy->phy_event &= ~PHY_PLUG_OUT;
186120b09c29SAndy Yan 			}
1862dd4969a8SJeff Garzik 		} else {
186320b09c29SAndy Yan 			mv_dprintk("plugin interrupt but phy%d is gone\n",
186420b09c29SAndy Yan 				phy_no + mvi->id*mvi->chip->n_phy);
1865dd4969a8SJeff Garzik 		}
1866dd4969a8SJeff Garzik 	} else if (phy->irq_status & PHYEV_BROAD_CH) {
186784fbd0ceSXiangliang Yu 		mv_dprintk("phy %d broadcast change.\n",
186820b09c29SAndy Yan 			phy_no + mvi->id*mvi->chip->n_phy);
1869a4632aaeSXiangliang Yu 		mvs_handle_event(mvi, (void *)(unsigned long)phy_no,
1870a4632aaeSXiangliang Yu 				EXP_BRCT_CHG);
1871dd4969a8SJeff Garzik 	}
1872dd4969a8SJeff Garzik }
1873dd4969a8SJeff Garzik 
mvs_int_rx(struct mvs_info * mvi,bool self_clear)187420b09c29SAndy Yan int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
1875dd4969a8SJeff Garzik {
1876dd4969a8SJeff Garzik 	u32 rx_prod_idx, rx_desc;
1877dd4969a8SJeff Garzik 	bool attn = false;
1878dd4969a8SJeff Garzik 
1879dd4969a8SJeff Garzik 	/* the first dword in the RX ring is special: it contains
1880dd4969a8SJeff Garzik 	 * a mirror of the hardware's RX producer index, so that
1881dd4969a8SJeff Garzik 	 * we don't have to stall the CPU reading that register.
1882dd4969a8SJeff Garzik 	 * The actual RX ring is offset by one dword, due to this.
1883dd4969a8SJeff Garzik 	 */
1884dd4969a8SJeff Garzik 	rx_prod_idx = mvi->rx_cons;
1885dd4969a8SJeff Garzik 	mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
1886dd4969a8SJeff Garzik 	if (mvi->rx_cons == 0xfff)	/* h/w hasn't touched RX ring yet */
1887dd4969a8SJeff Garzik 		return 0;
1888dd4969a8SJeff Garzik 
1889dd4969a8SJeff Garzik 	/* The CMPL_Q may come late, read from register and try again
1890dd4969a8SJeff Garzik 	* note: if coalescing is enabled,
1891dd4969a8SJeff Garzik 	* it will need to read from register every time for sure
1892dd4969a8SJeff Garzik 	*/
189320b09c29SAndy Yan 	if (unlikely(mvi->rx_cons == rx_prod_idx))
189420b09c29SAndy Yan 		mvi->rx_cons = MVS_CHIP_DISP->rx_update(mvi) & RX_RING_SZ_MASK;
1895dd4969a8SJeff Garzik 
1896dd4969a8SJeff Garzik 	if (mvi->rx_cons == rx_prod_idx)
1897dd4969a8SJeff Garzik 		return 0;
1898dd4969a8SJeff Garzik 
1899dd4969a8SJeff Garzik 	while (mvi->rx_cons != rx_prod_idx) {
1900dd4969a8SJeff Garzik 		/* increment our internal RX consumer pointer */
1901dd4969a8SJeff Garzik 		rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
1902dd4969a8SJeff Garzik 		rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
1903dd4969a8SJeff Garzik 
1904dd4969a8SJeff Garzik 		if (likely(rx_desc & RXQ_DONE))
1905dd4969a8SJeff Garzik 			mvs_slot_complete(mvi, rx_desc, 0);
1906dd4969a8SJeff Garzik 		if (rx_desc & RXQ_ATTN) {
1907dd4969a8SJeff Garzik 			attn = true;
1908dd4969a8SJeff Garzik 		} else if (rx_desc & RXQ_ERR) {
1909dd4969a8SJeff Garzik 			if (!(rx_desc & RXQ_DONE))
1910dd4969a8SJeff Garzik 				mvs_slot_complete(mvi, rx_desc, 0);
1911dd4969a8SJeff Garzik 		} else if (rx_desc & RXQ_SLOT_RESET) {
1912dd4969a8SJeff Garzik 			mvs_slot_free(mvi, rx_desc);
1913dd4969a8SJeff Garzik 		}
1914dd4969a8SJeff Garzik 	}
1915dd4969a8SJeff Garzik 
1916dd4969a8SJeff Garzik 	if (attn && self_clear)
191720b09c29SAndy Yan 		MVS_CHIP_DISP->int_full(mvi);
1918dd4969a8SJeff Garzik 	return 0;
1919dd4969a8SJeff Garzik }
1920dd4969a8SJeff Garzik 
mvs_gpio_write(struct sas_ha_struct * sha,u8 reg_type,u8 reg_index,u8 reg_count,u8 * write_data)1921c56f5f1dSWilfried Weissmann int mvs_gpio_write(struct sas_ha_struct *sha, u8 reg_type, u8 reg_index,
1922c56f5f1dSWilfried Weissmann 			u8 reg_count, u8 *write_data)
1923c56f5f1dSWilfried Weissmann {
1924c56f5f1dSWilfried Weissmann 	struct mvs_prv_info *mvs_prv = sha->lldd_ha;
1925c56f5f1dSWilfried Weissmann 	struct mvs_info *mvi = mvs_prv->mvi[0];
1926c56f5f1dSWilfried Weissmann 
1927c56f5f1dSWilfried Weissmann 	if (MVS_CHIP_DISP->gpio_write) {
1928c56f5f1dSWilfried Weissmann 		return MVS_CHIP_DISP->gpio_write(mvs_prv, reg_type,
1929c56f5f1dSWilfried Weissmann 			reg_index, reg_count, write_data);
1930c56f5f1dSWilfried Weissmann 	}
1931c56f5f1dSWilfried Weissmann 
1932c56f5f1dSWilfried Weissmann 	return -ENOSYS;
1933c56f5f1dSWilfried Weissmann }
1934