xref: /linux/drivers/scsi/leapraid/leapraid_transport.c (revision 35748ddd3b2c91555bd86b8cf88edc90e7317e57)
1*5597088cSDongdong Hao // SPDX-License-Identifier: GPL-2.0
2*5597088cSDongdong Hao /*
3*5597088cSDongdong Hao  * Copyright (C) 2026 LeapIO Tech Inc.
4*5597088cSDongdong Hao  *
5*5597088cSDongdong Hao  * LeapRAID storage and RAID controller driver.
6*5597088cSDongdong Hao  */
7*5597088cSDongdong Hao #include <scsi/scsi_host.h>
8*5597088cSDongdong Hao 
9*5597088cSDongdong Hao #include "leapraid_func.h"
10*5597088cSDongdong Hao 
11*5597088cSDongdong Hao static struct leapraid_topo_node *leapraid_transport_topo_node_by_sas_addr(
12*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
13*5597088cSDongdong Hao 		u64 sas_addr,
14*5597088cSDongdong Hao 		struct leapraid_card_port *card_port)
15*5597088cSDongdong Hao {
16*5597088cSDongdong Hao 	if (adapter->dev_topo.card.sas_address == sas_addr)
17*5597088cSDongdong Hao 		return &adapter->dev_topo.card;
18*5597088cSDongdong Hao 
19*5597088cSDongdong Hao 	return leapraid_exp_find_by_sas_address(adapter, sas_addr, card_port);
20*5597088cSDongdong Hao }
21*5597088cSDongdong Hao 
22*5597088cSDongdong Hao static u8 leapraid_get_port_id_by_expander(struct leapraid_adapter *adapter,
23*5597088cSDongdong Hao 					   struct sas_rphy *rphy)
24*5597088cSDongdong Hao {
25*5597088cSDongdong Hao 	struct leapraid_topo_node *topo_node_exp;
26*5597088cSDongdong Hao 	unsigned long flags;
27*5597088cSDongdong Hao 	u8 port_id = 0xFF;
28*5597088cSDongdong Hao 
29*5597088cSDongdong Hao 	spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
30*5597088cSDongdong Hao 	list_for_each_entry(topo_node_exp, &adapter->dev_topo.exp_list, list) {
31*5597088cSDongdong Hao 		if (topo_node_exp->rphy == rphy) {
32*5597088cSDongdong Hao 			port_id = topo_node_exp->card_port->port_id;
33*5597088cSDongdong Hao 			break;
34*5597088cSDongdong Hao 		}
35*5597088cSDongdong Hao 	}
36*5597088cSDongdong Hao 	spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
37*5597088cSDongdong Hao 
38*5597088cSDongdong Hao 	return port_id;
39*5597088cSDongdong Hao }
40*5597088cSDongdong Hao 
41*5597088cSDongdong Hao static u8 leapraid_get_port_id_by_end_dev(struct leapraid_adapter *adapter,
42*5597088cSDongdong Hao 					  struct sas_rphy *rphy)
43*5597088cSDongdong Hao {
44*5597088cSDongdong Hao 	struct leapraid_sas_dev *sas_dev;
45*5597088cSDongdong Hao 	unsigned long flags;
46*5597088cSDongdong Hao 	u8 port_id = 0xFF;
47*5597088cSDongdong Hao 
48*5597088cSDongdong Hao 	spin_lock_irqsave(&adapter->dev_topo.sas_dev_lock, flags);
49*5597088cSDongdong Hao 	sas_dev = leapraid_hold_lock_get_sas_dev_by_addr_and_rphy(
50*5597088cSDongdong Hao 			adapter,
51*5597088cSDongdong Hao 			rphy->identify.sas_address,
52*5597088cSDongdong Hao 			rphy);
53*5597088cSDongdong Hao 	if (sas_dev) {
54*5597088cSDongdong Hao 		port_id = sas_dev->card_port->port_id;
55*5597088cSDongdong Hao 		leapraid_sdev_put(sas_dev);
56*5597088cSDongdong Hao 	}
57*5597088cSDongdong Hao 	spin_unlock_irqrestore(&adapter->dev_topo.sas_dev_lock, flags);
58*5597088cSDongdong Hao 
59*5597088cSDongdong Hao 	return port_id;
60*5597088cSDongdong Hao }
61*5597088cSDongdong Hao 
62*5597088cSDongdong Hao static u8 leapraid_transport_get_port_id_by_rphy(
63*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
64*5597088cSDongdong Hao 		struct sas_rphy *rphy)
65*5597088cSDongdong Hao {
66*5597088cSDongdong Hao 	if (!rphy)
67*5597088cSDongdong Hao 		return 0xFF;
68*5597088cSDongdong Hao 
69*5597088cSDongdong Hao 	switch (rphy->identify.device_type) {
70*5597088cSDongdong Hao 	case SAS_EDGE_EXPANDER_DEVICE:
71*5597088cSDongdong Hao 	case SAS_FANOUT_EXPANDER_DEVICE:
72*5597088cSDongdong Hao 		return leapraid_get_port_id_by_expander(adapter, rphy);
73*5597088cSDongdong Hao 	case SAS_END_DEVICE:
74*5597088cSDongdong Hao 		return leapraid_get_port_id_by_end_dev(adapter, rphy);
75*5597088cSDongdong Hao 	default:
76*5597088cSDongdong Hao 		return 0xFF;
77*5597088cSDongdong Hao 	}
78*5597088cSDongdong Hao }
79*5597088cSDongdong Hao 
80*5597088cSDongdong Hao static enum sas_linkrate leapraid_transport_convert_phy_link_rate(u8 link_rate)
81*5597088cSDongdong Hao {
82*5597088cSDongdong Hao 	unsigned int i;
83*5597088cSDongdong Hao 
84*5597088cSDongdong Hao 	#define SAS_RATE_12G SAS_LINK_RATE_12_0_GBPS
85*5597088cSDongdong Hao 
86*5597088cSDongdong Hao 	const struct linkrate_map {
87*5597088cSDongdong Hao 		u8 in;
88*5597088cSDongdong Hao 		enum sas_linkrate out;
89*5597088cSDongdong Hao 	} linkrate_table[] = {
90*5597088cSDongdong Hao 		{
91*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_1_5,
92*5597088cSDongdong Hao 			SAS_LINK_RATE_1_5_GBPS
93*5597088cSDongdong Hao 		},
94*5597088cSDongdong Hao 		{
95*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_3_0,
96*5597088cSDongdong Hao 			SAS_LINK_RATE_3_0_GBPS
97*5597088cSDongdong Hao 		},
98*5597088cSDongdong Hao 		{
99*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_6_0,
100*5597088cSDongdong Hao 			SAS_LINK_RATE_6_0_GBPS
101*5597088cSDongdong Hao 		},
102*5597088cSDongdong Hao 		{
103*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_12_0,
104*5597088cSDongdong Hao 			SAS_RATE_12G
105*5597088cSDongdong Hao 		},
106*5597088cSDongdong Hao 		{
107*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_PHY_DISABLED,
108*5597088cSDongdong Hao 			SAS_PHY_DISABLED
109*5597088cSDongdong Hao 		},
110*5597088cSDongdong Hao 		{
111*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED,
112*5597088cSDongdong Hao 			SAS_LINK_RATE_FAILED
113*5597088cSDongdong Hao 		},
114*5597088cSDongdong Hao 		{
115*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_PORT_SELECTOR,
116*5597088cSDongdong Hao 			SAS_SATA_PORT_SELECTOR
117*5597088cSDongdong Hao 		},
118*5597088cSDongdong Hao 		{
119*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_SMP_RESETTING,
120*5597088cSDongdong Hao 			SAS_LINK_RATE_UNKNOWN
121*5597088cSDongdong Hao 		},
122*5597088cSDongdong Hao 		{
123*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE,
124*5597088cSDongdong Hao 			SAS_LINK_RATE_UNKNOWN
125*5597088cSDongdong Hao 		},
126*5597088cSDongdong Hao 		{
127*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE,
128*5597088cSDongdong Hao 			SAS_LINK_RATE_UNKNOWN
129*5597088cSDongdong Hao 		},
130*5597088cSDongdong Hao 	};
131*5597088cSDongdong Hao 
132*5597088cSDongdong Hao 	for (i = 0; i < ARRAY_SIZE(linkrate_table); i++)
133*5597088cSDongdong Hao 		if (linkrate_table[i].in == link_rate)
134*5597088cSDongdong Hao 			return linkrate_table[i].out;
135*5597088cSDongdong Hao 
136*5597088cSDongdong Hao 	return SAS_LINK_RATE_UNKNOWN;
137*5597088cSDongdong Hao }
138*5597088cSDongdong Hao 
139*5597088cSDongdong Hao static void leapraid_set_identify_protocol_flags(u32 dev_info,
140*5597088cSDongdong Hao 						 struct sas_identify *identify)
141*5597088cSDongdong Hao {
142*5597088cSDongdong Hao 	unsigned int i;
143*5597088cSDongdong Hao 
144*5597088cSDongdong Hao 	const struct protocol_mapping {
145*5597088cSDongdong Hao 		u32 mask;
146*5597088cSDongdong Hao 		u32 *target;
147*5597088cSDongdong Hao 		u32 protocol;
148*5597088cSDongdong Hao 	} mappings[] = {
149*5597088cSDongdong Hao 		{
150*5597088cSDongdong Hao 			LEAPRAID_DEVTYP_SSP_INIT,
151*5597088cSDongdong Hao 			&identify->initiator_port_protocols,
152*5597088cSDongdong Hao 			SAS_PROTOCOL_SSP
153*5597088cSDongdong Hao 		},
154*5597088cSDongdong Hao 		{
155*5597088cSDongdong Hao 			LEAPRAID_DEVTYP_STP_INIT,
156*5597088cSDongdong Hao 			&identify->initiator_port_protocols,
157*5597088cSDongdong Hao 			SAS_PROTOCOL_STP
158*5597088cSDongdong Hao 		},
159*5597088cSDongdong Hao 		{
160*5597088cSDongdong Hao 			LEAPRAID_DEVTYP_SMP_INIT,
161*5597088cSDongdong Hao 			&identify->initiator_port_protocols,
162*5597088cSDongdong Hao 			SAS_PROTOCOL_SMP
163*5597088cSDongdong Hao 		},
164*5597088cSDongdong Hao 		{
165*5597088cSDongdong Hao 			LEAPRAID_DEVTYP_SATA_HOST,
166*5597088cSDongdong Hao 			&identify->initiator_port_protocols,
167*5597088cSDongdong Hao 			SAS_PROTOCOL_SATA
168*5597088cSDongdong Hao 		},
169*5597088cSDongdong Hao 		{
170*5597088cSDongdong Hao 			LEAPRAID_DEVTYP_SSP_TGT,
171*5597088cSDongdong Hao 			&identify->target_port_protocols,
172*5597088cSDongdong Hao 			SAS_PROTOCOL_SSP
173*5597088cSDongdong Hao 		},
174*5597088cSDongdong Hao 		{
175*5597088cSDongdong Hao 			LEAPRAID_DEVTYP_STP_TGT,
176*5597088cSDongdong Hao 			&identify->target_port_protocols,
177*5597088cSDongdong Hao 			SAS_PROTOCOL_STP
178*5597088cSDongdong Hao 		},
179*5597088cSDongdong Hao 		{
180*5597088cSDongdong Hao 			LEAPRAID_DEVTYP_SMP_TGT,
181*5597088cSDongdong Hao 			&identify->target_port_protocols,
182*5597088cSDongdong Hao 			SAS_PROTOCOL_SMP
183*5597088cSDongdong Hao 		},
184*5597088cSDongdong Hao 		{
185*5597088cSDongdong Hao 			LEAPRAID_DEVTYP_SATA_DEV,
186*5597088cSDongdong Hao 			&identify->target_port_protocols,
187*5597088cSDongdong Hao 			SAS_PROTOCOL_SATA
188*5597088cSDongdong Hao 		},
189*5597088cSDongdong Hao 	};
190*5597088cSDongdong Hao 
191*5597088cSDongdong Hao 	for (i = 0; i < ARRAY_SIZE(mappings); i++)
192*5597088cSDongdong Hao 		if (dev_info & mappings[i].mask && mappings[i].target)
193*5597088cSDongdong Hao 			*mappings[i].target |= mappings[i].protocol;
194*5597088cSDongdong Hao }
195*5597088cSDongdong Hao 
196*5597088cSDongdong Hao static int leapraid_transport_set_identify(struct leapraid_adapter *adapter,
197*5597088cSDongdong Hao 					   u16 hdl,
198*5597088cSDongdong Hao 					   struct sas_identify *identify)
199*5597088cSDongdong Hao {
200*5597088cSDongdong Hao 	union cfg_param_1 cfgp1 = {0};
201*5597088cSDongdong Hao 	union cfg_param_2 cfgp2 = {0};
202*5597088cSDongdong Hao 	struct leapraid_sas_dev_p0 sas_dev_pg0;
203*5597088cSDongdong Hao 	u32 dev_info;
204*5597088cSDongdong Hao 
205*5597088cSDongdong Hao 	if ((adapter->access_ctrl.shost_recovering &&
206*5597088cSDongdong Hao 	     !adapter->scan_dev_desc.driver_loading) ||
207*5597088cSDongdong Hao 	    adapter->access_ctrl.pcie_recovering) {
208*5597088cSDongdong Hao 		dev_warn(&adapter->pdev->dev,
209*5597088cSDongdong Hao 			 "%s: Failed, shost_recovering=%d pcie_recovering=%d\n",
210*5597088cSDongdong Hao 			 __func__,
211*5597088cSDongdong Hao 			 adapter->access_ctrl.shost_recovering,
212*5597088cSDongdong Hao 			 adapter->access_ctrl.pcie_recovering);
213*5597088cSDongdong Hao 		return -EFAULT;
214*5597088cSDongdong Hao 	}
215*5597088cSDongdong Hao 
216*5597088cSDongdong Hao 	cfgp1.form = LEAPRAID_SAS_DEV_CFG_PGAD_HDL;
217*5597088cSDongdong Hao 	cfgp2.handle = hdl;
218*5597088cSDongdong Hao 	if (leapraid_op_config_page(adapter, &sas_dev_pg0, cfgp1,
219*5597088cSDongdong Hao 				    cfgp2, GET_SAS_DEVICE_PG0))
220*5597088cSDongdong Hao 		return -ENXIO;
221*5597088cSDongdong Hao 
222*5597088cSDongdong Hao 	memset(identify, 0, sizeof(struct sas_identify));
223*5597088cSDongdong Hao 	dev_info = le32_to_cpu(sas_dev_pg0.dev_info);
224*5597088cSDongdong Hao 	identify->sas_address = le64_to_cpu(sas_dev_pg0.sas_address);
225*5597088cSDongdong Hao 	identify->phy_identifier = sas_dev_pg0.phy_num;
226*5597088cSDongdong Hao 
227*5597088cSDongdong Hao 	switch (dev_info & LEAPRAID_DEVTYP_MASK_DEV_TYPE) {
228*5597088cSDongdong Hao 	case LEAPRAID_DEVTYP_NO_DEV:
229*5597088cSDongdong Hao 		identify->device_type = SAS_PHY_UNUSED;
230*5597088cSDongdong Hao 		break;
231*5597088cSDongdong Hao 	case LEAPRAID_DEVTYP_END_DEV:
232*5597088cSDongdong Hao 		identify->device_type = SAS_END_DEVICE;
233*5597088cSDongdong Hao 		break;
234*5597088cSDongdong Hao 	case LEAPRAID_DEVTYP_EDGE_EXPANDER:
235*5597088cSDongdong Hao 		identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
236*5597088cSDongdong Hao 		break;
237*5597088cSDongdong Hao 	case LEAPRAID_DEVTYP_FANOUT_EXPANDER:
238*5597088cSDongdong Hao 		identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
239*5597088cSDongdong Hao 		break;
240*5597088cSDongdong Hao 	}
241*5597088cSDongdong Hao 
242*5597088cSDongdong Hao 	leapraid_set_identify_protocol_flags(dev_info, identify);
243*5597088cSDongdong Hao 
244*5597088cSDongdong Hao 	return 0;
245*5597088cSDongdong Hao }
246*5597088cSDongdong Hao 
247*5597088cSDongdong Hao static void leapraid_transport_exp_set_edev(struct leapraid_adapter *adapter,
248*5597088cSDongdong Hao 					    void *data_out,
249*5597088cSDongdong Hao 					    struct sas_expander_device *edev)
250*5597088cSDongdong Hao {
251*5597088cSDongdong Hao 	struct leapraid_smp_passthrough_rep *smp_passthrough_rep;
252*5597088cSDongdong Hao 	struct leapraid_rep_manu_reply *rep_manu_reply;
253*5597088cSDongdong Hao 	u8 *component_id;
254*5597088cSDongdong Hao 
255*5597088cSDongdong Hao 	smp_passthrough_rep =
256*5597088cSDongdong Hao 		(void *)&adapter->driver_cmds.transport_cmd.reply;
257*5597088cSDongdong Hao 	if (le16_to_cpu(smp_passthrough_rep->resp_data_len) !=
258*5597088cSDongdong Hao 	    sizeof(struct leapraid_rep_manu_reply))
259*5597088cSDongdong Hao 		return;
260*5597088cSDongdong Hao 
261*5597088cSDongdong Hao 	rep_manu_reply = data_out + sizeof(struct leapraid_rep_manu_request);
262*5597088cSDongdong Hao 
263*5597088cSDongdong Hao 	memcpy(edev->vendor_id, rep_manu_reply->vendor_identification,
264*5597088cSDongdong Hao 	       SAS_EXPANDER_VENDOR_ID_LEN);
265*5597088cSDongdong Hao 	edev->vendor_id[SAS_EXPANDER_VENDOR_ID_LEN] = '\0';
266*5597088cSDongdong Hao 
267*5597088cSDongdong Hao 	memcpy(edev->product_id, rep_manu_reply->product_identification,
268*5597088cSDongdong Hao 	       SAS_EXPANDER_PRODUCT_ID_LEN);
269*5597088cSDongdong Hao 	edev->product_id[SAS_EXPANDER_PRODUCT_ID_LEN] = '\0';
270*5597088cSDongdong Hao 
271*5597088cSDongdong Hao 	memcpy(edev->product_rev, rep_manu_reply->product_revision_level,
272*5597088cSDongdong Hao 	       SAS_EXPANDER_PRODUCT_REV_LEN);
273*5597088cSDongdong Hao 	edev->product_rev[SAS_EXPANDER_PRODUCT_REV_LEN] = '\0';
274*5597088cSDongdong Hao 
275*5597088cSDongdong Hao 	edev->level = rep_manu_reply->sas_format & 1;
276*5597088cSDongdong Hao 	if (edev->level) {
277*5597088cSDongdong Hao 		memcpy(edev->component_vendor_id,
278*5597088cSDongdong Hao 		       rep_manu_reply->comp_vendor_identification,
279*5597088cSDongdong Hao 		       SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
280*5597088cSDongdong Hao 		edev->component_vendor_id[
281*5597088cSDongdong Hao 			SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN] = '\0';
282*5597088cSDongdong Hao 
283*5597088cSDongdong Hao 		component_id = (u8 *)&rep_manu_reply->component_id;
284*5597088cSDongdong Hao 		edev->component_id = component_id[0] << 8 | component_id[1];
285*5597088cSDongdong Hao 		edev->component_revision_id =
286*5597088cSDongdong Hao 			rep_manu_reply->component_revision_level;
287*5597088cSDongdong Hao 	}
288*5597088cSDongdong Hao }
289*5597088cSDongdong Hao 
290*5597088cSDongdong Hao static int leapraid_transport_exp_report_manu(struct leapraid_adapter *adapter,
291*5597088cSDongdong Hao 					      u64 sas_address,
292*5597088cSDongdong Hao 					      struct sas_expander_device *edev,
293*5597088cSDongdong Hao 					      u8 port_id)
294*5597088cSDongdong Hao {
295*5597088cSDongdong Hao 	struct leapraid_smp_passthrough_req *smp_passthrough_req;
296*5597088cSDongdong Hao 	struct leapraid_rep_manu_request *rep_manu_request;
297*5597088cSDongdong Hao 	dma_addr_t h2c_dma_addr;
298*5597088cSDongdong Hao 	dma_addr_t c2h_dma_addr;
299*5597088cSDongdong Hao 	bool issue_reset = false;
300*5597088cSDongdong Hao 	void *data_out = NULL;
301*5597088cSDongdong Hao 	u16 inter_taskid;
302*5597088cSDongdong Hao 	size_t c2h_size;
303*5597088cSDongdong Hao 	size_t h2c_size;
304*5597088cSDongdong Hao 	void *psge;
305*5597088cSDongdong Hao 	int rc;
306*5597088cSDongdong Hao 
307*5597088cSDongdong Hao 	if (adapter->access_ctrl.shost_recovering ||
308*5597088cSDongdong Hao 	    adapter->access_ctrl.pcie_recovering) {
309*5597088cSDongdong Hao 		dev_warn(&adapter->pdev->dev,
310*5597088cSDongdong Hao 			 "%s: Failed, shost_recovering=%d pcie_recovering=%d\n",
311*5597088cSDongdong Hao 			 __func__,
312*5597088cSDongdong Hao 			 adapter->access_ctrl.shost_recovering,
313*5597088cSDongdong Hao 			 adapter->access_ctrl.pcie_recovering);
314*5597088cSDongdong Hao 		return -EFAULT;
315*5597088cSDongdong Hao 	}
316*5597088cSDongdong Hao 
317*5597088cSDongdong Hao 	mutex_lock(&adapter->driver_cmds.transport_cmd.mutex);
318*5597088cSDongdong Hao 	adapter->driver_cmds.transport_cmd.status = LEAPRAID_CMD_PENDING;
319*5597088cSDongdong Hao 	rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_SHORT,
320*5597088cSDongdong Hao 					  __func__);
321*5597088cSDongdong Hao 	if (rc)
322*5597088cSDongdong Hao 		goto out_cleanup;
323*5597088cSDongdong Hao 
324*5597088cSDongdong Hao 	h2c_size = sizeof(struct leapraid_rep_manu_request);
325*5597088cSDongdong Hao 	c2h_size = sizeof(struct leapraid_rep_manu_reply);
326*5597088cSDongdong Hao 	data_out = dma_alloc_coherent(&adapter->pdev->dev,
327*5597088cSDongdong Hao 				      h2c_size + c2h_size,
328*5597088cSDongdong Hao 				      &h2c_dma_addr,
329*5597088cSDongdong Hao 				      GFP_ATOMIC);
330*5597088cSDongdong Hao 	if (!data_out) {
331*5597088cSDongdong Hao 		rc = -ENOMEM;
332*5597088cSDongdong Hao 		goto out_cleanup;
333*5597088cSDongdong Hao 	}
334*5597088cSDongdong Hao 
335*5597088cSDongdong Hao 	rep_manu_request = data_out;
336*5597088cSDongdong Hao 	rep_manu_request->smp_frame_type =
337*5597088cSDongdong Hao 		SMP_REPORT_MANUFACTURER_INFORMATION_FRAME_TYPE;
338*5597088cSDongdong Hao 	rep_manu_request->function = SMP_REPORT_MANUFACTURER_INFORMATION_FUNC;
339*5597088cSDongdong Hao 	rep_manu_request->allocated_response_length = 0;
340*5597088cSDongdong Hao 	rep_manu_request->request_length = 0;
341*5597088cSDongdong Hao 
342*5597088cSDongdong Hao 	inter_taskid = adapter->driver_cmds.transport_cmd.inter_taskid;
343*5597088cSDongdong Hao 	smp_passthrough_req = leapraid_get_task_desc(adapter, inter_taskid);
344*5597088cSDongdong Hao 	memset(smp_passthrough_req, 0,
345*5597088cSDongdong Hao 	       sizeof(struct leapraid_smp_passthrough_req));
346*5597088cSDongdong Hao 	smp_passthrough_req->func = LEAPRAID_FUNC_SMP_PASSTHROUGH;
347*5597088cSDongdong Hao 	smp_passthrough_req->physical_port = port_id;
348*5597088cSDongdong Hao 	smp_passthrough_req->sas_address = cpu_to_le64(sas_address);
349*5597088cSDongdong Hao 	smp_passthrough_req->req_data_len = cpu_to_le16(h2c_size);
350*5597088cSDongdong Hao 	psge = &smp_passthrough_req->sgl;
351*5597088cSDongdong Hao 	c2h_dma_addr = h2c_dma_addr + sizeof(struct leapraid_rep_manu_request);
352*5597088cSDongdong Hao 	leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, h2c_size,
353*5597088cSDongdong Hao 			       c2h_dma_addr, c2h_size);
354*5597088cSDongdong Hao 
355*5597088cSDongdong Hao 	init_completion(&adapter->driver_cmds.transport_cmd.done);
356*5597088cSDongdong Hao 	leapraid_fire_task(adapter, inter_taskid);
357*5597088cSDongdong Hao 	wait_for_completion_timeout(&adapter->driver_cmds.transport_cmd.done,
358*5597088cSDongdong Hao 				    LEAPRAID_TRANSPORT_CMD_TIMEOUT * HZ);
359*5597088cSDongdong Hao 	if (!(adapter->driver_cmds.transport_cmd.status & LEAPRAID_CMD_DONE)) {
360*5597088cSDongdong Hao 		rc = -ETIMEDOUT;
361*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
362*5597088cSDongdong Hao 			"%s: SMP passthrough timeout, st=0x%x\n",
363*5597088cSDongdong Hao 			__func__, adapter->driver_cmds.transport_cmd.status);
364*5597088cSDongdong Hao 		leapraid_log_req_context(adapter, inter_taskid,
365*5597088cSDongdong Hao 					 smp_passthrough_req);
366*5597088cSDongdong Hao 		if (!(adapter->driver_cmds.transport_cmd.status &
367*5597088cSDongdong Hao 		      LEAPRAID_CMD_RESET))
368*5597088cSDongdong Hao 			issue_reset = true;
369*5597088cSDongdong Hao 
370*5597088cSDongdong Hao 		goto hard_reset;
371*5597088cSDongdong Hao 	}
372*5597088cSDongdong Hao 
373*5597088cSDongdong Hao 	if (adapter->driver_cmds.transport_cmd.status &
374*5597088cSDongdong Hao 	    LEAPRAID_CMD_REPLY_VALID)
375*5597088cSDongdong Hao 		leapraid_transport_exp_set_edev(adapter, data_out, edev);
376*5597088cSDongdong Hao 
377*5597088cSDongdong Hao hard_reset:
378*5597088cSDongdong Hao 	if (issue_reset) {
379*5597088cSDongdong Hao 		dev_info(&adapter->pdev->dev, "%s:%d: call hard_reset\n",
380*5597088cSDongdong Hao 			 __func__, __LINE__);
381*5597088cSDongdong Hao 		rc = leapraid_hard_reset_handler(adapter, FULL_RESET);
382*5597088cSDongdong Hao 	}
383*5597088cSDongdong Hao out_cleanup:
384*5597088cSDongdong Hao 	adapter->driver_cmds.transport_cmd.status = LEAPRAID_CMD_NOT_USED;
385*5597088cSDongdong Hao 	if (data_out)
386*5597088cSDongdong Hao 		dma_free_coherent(&adapter->pdev->dev, h2c_size + c2h_size,
387*5597088cSDongdong Hao 				  data_out, h2c_dma_addr);
388*5597088cSDongdong Hao 
389*5597088cSDongdong Hao 	mutex_unlock(&adapter->driver_cmds.transport_cmd.mutex);
390*5597088cSDongdong Hao 	return rc;
391*5597088cSDongdong Hao }
392*5597088cSDongdong Hao 
393*5597088cSDongdong Hao static void leapraid_transport_del_port(struct leapraid_adapter *adapter,
394*5597088cSDongdong Hao 					struct leapraid_sas_port *sas_port)
395*5597088cSDongdong Hao {
396*5597088cSDongdong Hao 	dev_info(&sas_port->port->dev,
397*5597088cSDongdong Hao 		 "Remove port: SAS addr=0x%016llx\n",
398*5597088cSDongdong Hao 		 (unsigned long long)sas_port->remote_identify.sas_address);
399*5597088cSDongdong Hao 	switch (sas_port->remote_identify.device_type) {
400*5597088cSDongdong Hao 	case SAS_END_DEVICE:
401*5597088cSDongdong Hao 		leapraid_sas_dev_remove_by_sas_address(
402*5597088cSDongdong Hao 			adapter,
403*5597088cSDongdong Hao 			sas_port->remote_identify.sas_address,
404*5597088cSDongdong Hao 			sas_port->card_port);
405*5597088cSDongdong Hao 		break;
406*5597088cSDongdong Hao 	case SAS_EDGE_EXPANDER_DEVICE:
407*5597088cSDongdong Hao 	case SAS_FANOUT_EXPANDER_DEVICE:
408*5597088cSDongdong Hao 		leapraid_exp_rm(adapter, sas_port->remote_identify.sas_address,
409*5597088cSDongdong Hao 				sas_port->card_port);
410*5597088cSDongdong Hao 		break;
411*5597088cSDongdong Hao 	default:
412*5597088cSDongdong Hao 		break;
413*5597088cSDongdong Hao 	}
414*5597088cSDongdong Hao }
415*5597088cSDongdong Hao 
416*5597088cSDongdong Hao static void leapraid_transport_del_phy(struct leapraid_adapter *adapter,
417*5597088cSDongdong Hao 				       struct leapraid_sas_port *sas_port,
418*5597088cSDongdong Hao 				       struct leapraid_card_phy *card_phy)
419*5597088cSDongdong Hao {
420*5597088cSDongdong Hao 	dev_info(&card_phy->phy->dev,
421*5597088cSDongdong Hao 		 "Remove PHY: SAS addr=0x%016llx, phy=%d\n",
422*5597088cSDongdong Hao 		 (unsigned long long)sas_port->remote_identify.sas_address,
423*5597088cSDongdong Hao 		 card_phy->phy_id);
424*5597088cSDongdong Hao 	list_del(&card_phy->port_siblings);
425*5597088cSDongdong Hao 	sas_port->phys_num--;
426*5597088cSDongdong Hao 	sas_port_delete_phy(sas_port->port, card_phy->phy);
427*5597088cSDongdong Hao 	card_phy->phy_is_assigned = 0;
428*5597088cSDongdong Hao }
429*5597088cSDongdong Hao 
430*5597088cSDongdong Hao static void leapraid_transport_add_phy(struct leapraid_adapter *adapter,
431*5597088cSDongdong Hao 				       struct leapraid_sas_port *sas_port,
432*5597088cSDongdong Hao 				       struct leapraid_card_phy *card_phy)
433*5597088cSDongdong Hao {
434*5597088cSDongdong Hao 	dev_info(&card_phy->phy->dev,
435*5597088cSDongdong Hao 		 "Add PHY: SAS addr=0x%016llx, phy=%d\n",
436*5597088cSDongdong Hao 		 (unsigned long long)sas_port->remote_identify.sas_address,
437*5597088cSDongdong Hao 		 card_phy->phy_id);
438*5597088cSDongdong Hao 	list_add_tail(&card_phy->port_siblings, &sas_port->phy_list);
439*5597088cSDongdong Hao 	sas_port->phys_num++;
440*5597088cSDongdong Hao 	sas_port_add_phy(sas_port->port, card_phy->phy);
441*5597088cSDongdong Hao 	card_phy->phy_is_assigned = 1;
442*5597088cSDongdong Hao }
443*5597088cSDongdong Hao 
444*5597088cSDongdong Hao void leapraid_transport_attach_phy_to_port(
445*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
446*5597088cSDongdong Hao 		struct leapraid_topo_node *topo_node,
447*5597088cSDongdong Hao 		struct leapraid_card_phy *card_phy,
448*5597088cSDongdong Hao 		u64 sas_address,
449*5597088cSDongdong Hao 		struct leapraid_card_port *card_port)
450*5597088cSDongdong Hao {
451*5597088cSDongdong Hao 	struct leapraid_sas_port *sas_port;
452*5597088cSDongdong Hao 	struct leapraid_card_phy *card_phy_srch;
453*5597088cSDongdong Hao 
454*5597088cSDongdong Hao 	if (card_phy->phy_is_assigned)
455*5597088cSDongdong Hao 		return;
456*5597088cSDongdong Hao 
457*5597088cSDongdong Hao 	if (!card_port)
458*5597088cSDongdong Hao 		return;
459*5597088cSDongdong Hao 
460*5597088cSDongdong Hao 	list_for_each_entry(sas_port, &topo_node->sas_port_list, port_list) {
461*5597088cSDongdong Hao 		if (sas_port->remote_identify.sas_address != sas_address)
462*5597088cSDongdong Hao 			continue;
463*5597088cSDongdong Hao 
464*5597088cSDongdong Hao 		if (sas_port->card_port != card_port)
465*5597088cSDongdong Hao 			continue;
466*5597088cSDongdong Hao 
467*5597088cSDongdong Hao 		list_for_each_entry(card_phy_srch, &sas_port->phy_list,
468*5597088cSDongdong Hao 				    port_siblings) {
469*5597088cSDongdong Hao 			if (card_phy_srch == card_phy)
470*5597088cSDongdong Hao 				return;
471*5597088cSDongdong Hao 		}
472*5597088cSDongdong Hao 		leapraid_transport_add_phy(adapter, sas_port, card_phy);
473*5597088cSDongdong Hao 		return;
474*5597088cSDongdong Hao 	}
475*5597088cSDongdong Hao }
476*5597088cSDongdong Hao 
477*5597088cSDongdong Hao void leapraid_transport_detach_phy_to_port(
478*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
479*5597088cSDongdong Hao 		struct leapraid_topo_node *topo_node,
480*5597088cSDongdong Hao 		struct leapraid_card_phy *target_card_phy)
481*5597088cSDongdong Hao {
482*5597088cSDongdong Hao 	struct leapraid_sas_port *sas_port, *sas_port_next;
483*5597088cSDongdong Hao 	struct leapraid_card_phy *cur_card_phy;
484*5597088cSDongdong Hao 
485*5597088cSDongdong Hao 	if (!target_card_phy->phy_is_assigned)
486*5597088cSDongdong Hao 		return;
487*5597088cSDongdong Hao 
488*5597088cSDongdong Hao 	list_for_each_entry_safe(sas_port, sas_port_next,
489*5597088cSDongdong Hao 				 &topo_node->sas_port_list, port_list) {
490*5597088cSDongdong Hao 		list_for_each_entry(cur_card_phy, &sas_port->phy_list,
491*5597088cSDongdong Hao 				    port_siblings) {
492*5597088cSDongdong Hao 			if (cur_card_phy != target_card_phy)
493*5597088cSDongdong Hao 				continue;
494*5597088cSDongdong Hao 
495*5597088cSDongdong Hao 			if (sas_port->phys_num == 1 &&
496*5597088cSDongdong Hao 			    !adapter->access_ctrl.shost_recovering)
497*5597088cSDongdong Hao 				leapraid_transport_del_port(adapter, sas_port);
498*5597088cSDongdong Hao 			else
499*5597088cSDongdong Hao 				leapraid_transport_del_phy(adapter, sas_port,
500*5597088cSDongdong Hao 							   target_card_phy);
501*5597088cSDongdong Hao 			return;
502*5597088cSDongdong Hao 		}
503*5597088cSDongdong Hao 	}
504*5597088cSDongdong Hao }
505*5597088cSDongdong Hao 
506*5597088cSDongdong Hao static void leapraid_detach_phy_from_old_port(
507*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
508*5597088cSDongdong Hao 		struct leapraid_topo_node *topo_node,
509*5597088cSDongdong Hao 		u64 sas_address,
510*5597088cSDongdong Hao 		struct leapraid_card_port *card_port)
511*5597088cSDongdong Hao {
512*5597088cSDongdong Hao 	int i;
513*5597088cSDongdong Hao 
514*5597088cSDongdong Hao 	for (i = 0; i < topo_node->phys_num; i++) {
515*5597088cSDongdong Hao 		if (topo_node->card_phy[i].remote_identify.sas_address !=
516*5597088cSDongdong Hao 			sas_address ||
517*5597088cSDongdong Hao 		    topo_node->card_phy[i].card_port != card_port)
518*5597088cSDongdong Hao 			continue;
519*5597088cSDongdong Hao 		if (topo_node->card_phy[i].phy_is_assigned)
520*5597088cSDongdong Hao 			leapraid_transport_detach_phy_to_port(
521*5597088cSDongdong Hao 				adapter,
522*5597088cSDongdong Hao 				topo_node,
523*5597088cSDongdong Hao 				&topo_node->card_phy[i]);
524*5597088cSDongdong Hao 	}
525*5597088cSDongdong Hao }
526*5597088cSDongdong Hao 
527*5597088cSDongdong Hao static struct leapraid_sas_port *leapraid_prepare_sas_port(
528*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
529*5597088cSDongdong Hao 		u16 handle, u64 sas_address,
530*5597088cSDongdong Hao 		struct leapraid_card_port *card_port,
531*5597088cSDongdong Hao 		struct leapraid_topo_node **out_topo_node)
532*5597088cSDongdong Hao {
533*5597088cSDongdong Hao 	struct leapraid_topo_node *topo_node;
534*5597088cSDongdong Hao 	struct leapraid_sas_port *sas_port;
535*5597088cSDongdong Hao 	unsigned long flags;
536*5597088cSDongdong Hao 
537*5597088cSDongdong Hao 	sas_port = kzalloc_obj(*sas_port);
538*5597088cSDongdong Hao 	if (!sas_port) {
539*5597088cSDongdong Hao 		dev_warn(&adapter->pdev->dev,
540*5597088cSDongdong Hao 			 "%s: Failed alloc sas_port\n", __func__);
541*5597088cSDongdong Hao 		return NULL;
542*5597088cSDongdong Hao 	}
543*5597088cSDongdong Hao 
544*5597088cSDongdong Hao 	INIT_LIST_HEAD(&sas_port->port_list);
545*5597088cSDongdong Hao 	INIT_LIST_HEAD(&sas_port->phy_list);
546*5597088cSDongdong Hao 
547*5597088cSDongdong Hao 	spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
548*5597088cSDongdong Hao 	topo_node = leapraid_transport_topo_node_by_sas_addr(adapter,
549*5597088cSDongdong Hao 							     sas_address,
550*5597088cSDongdong Hao 							     card_port);
551*5597088cSDongdong Hao 	spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
552*5597088cSDongdong Hao 
553*5597088cSDongdong Hao 	if (!topo_node) {
554*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
555*5597088cSDongdong Hao 			"%s: Failed to locate parent for SAS 0x%016llx!\n",
556*5597088cSDongdong Hao 			__func__, sas_address);
557*5597088cSDongdong Hao 		goto out_cleanup;
558*5597088cSDongdong Hao 	}
559*5597088cSDongdong Hao 
560*5597088cSDongdong Hao 	if (leapraid_transport_set_identify(adapter, handle,
561*5597088cSDongdong Hao 					    &sas_port->remote_identify))
562*5597088cSDongdong Hao 		goto out_cleanup;
563*5597088cSDongdong Hao 
564*5597088cSDongdong Hao 	if (sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
565*5597088cSDongdong Hao 		dev_warn(&adapter->pdev->dev,
566*5597088cSDongdong Hao 			 "%s: Failed, device type is SAS_PHY_UNUSED\n",
567*5597088cSDongdong Hao 			 __func__);
568*5597088cSDongdong Hao 		goto out_cleanup;
569*5597088cSDongdong Hao 	}
570*5597088cSDongdong Hao 
571*5597088cSDongdong Hao 	sas_port->card_port = card_port;
572*5597088cSDongdong Hao 	*out_topo_node = topo_node;
573*5597088cSDongdong Hao 
574*5597088cSDongdong Hao 	return sas_port;
575*5597088cSDongdong Hao 
576*5597088cSDongdong Hao out_cleanup:
577*5597088cSDongdong Hao 	kfree(sas_port);
578*5597088cSDongdong Hao 	return NULL;
579*5597088cSDongdong Hao }
580*5597088cSDongdong Hao 
581*5597088cSDongdong Hao static int leapraid_bind_phys_and_vphy(struct leapraid_adapter *adapter,
582*5597088cSDongdong Hao 				       struct leapraid_sas_port *sas_port,
583*5597088cSDongdong Hao 				       struct leapraid_topo_node *topo_node,
584*5597088cSDongdong Hao 				       struct leapraid_card_port *card_port,
585*5597088cSDongdong Hao 				       struct leapraid_vphy **out_vphy)
586*5597088cSDongdong Hao {
587*5597088cSDongdong Hao 	struct leapraid_vphy *vphy = NULL;
588*5597088cSDongdong Hao 	int i;
589*5597088cSDongdong Hao 
590*5597088cSDongdong Hao 	for (i = 0; i < topo_node->phys_num; i++) {
591*5597088cSDongdong Hao 		if (topo_node->card_phy[i].remote_identify.sas_address !=
592*5597088cSDongdong Hao 			sas_port->remote_identify.sas_address ||
593*5597088cSDongdong Hao 		    topo_node->card_phy[i].card_port != card_port)
594*5597088cSDongdong Hao 			continue;
595*5597088cSDongdong Hao 
596*5597088cSDongdong Hao 		list_add_tail(&topo_node->card_phy[i].port_siblings,
597*5597088cSDongdong Hao 			      &sas_port->phy_list);
598*5597088cSDongdong Hao 		sas_port->phys_num++;
599*5597088cSDongdong Hao 
600*5597088cSDongdong Hao 		if (topo_node->hdl <= adapter->dev_topo.card.phys_num) {
601*5597088cSDongdong Hao 			if (!topo_node->card_phy[i].vphy) {
602*5597088cSDongdong Hao 				card_port->phy_mask |= BIT(i);
603*5597088cSDongdong Hao 				continue;
604*5597088cSDongdong Hao 			}
605*5597088cSDongdong Hao 
606*5597088cSDongdong Hao 			vphy = leapraid_get_vphy_by_phy(card_port, i);
607*5597088cSDongdong Hao 			if (!vphy)
608*5597088cSDongdong Hao 				return LEAPRAID_OPERATION_FAILED;
609*5597088cSDongdong Hao 		}
610*5597088cSDongdong Hao 	}
611*5597088cSDongdong Hao 
612*5597088cSDongdong Hao 	*out_vphy = vphy;
613*5597088cSDongdong Hao 	return sas_port->phys_num ? 0 : LEAPRAID_OPERATION_FAILED;
614*5597088cSDongdong Hao }
615*5597088cSDongdong Hao 
616*5597088cSDongdong Hao static struct sas_rphy *leapraid_create_and_register_rphy(
617*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
618*5597088cSDongdong Hao 		struct leapraid_sas_port *sas_port,
619*5597088cSDongdong Hao 		struct leapraid_topo_node *topo_node,
620*5597088cSDongdong Hao 		struct leapraid_card_port *card_port,
621*5597088cSDongdong Hao 		struct leapraid_vphy *vphy)
622*5597088cSDongdong Hao {
623*5597088cSDongdong Hao 	struct leapraid_sas_dev *sas_dev = NULL;
624*5597088cSDongdong Hao 	struct leapraid_card_phy *card_phy;
625*5597088cSDongdong Hao 	struct sas_port *port;
626*5597088cSDongdong Hao 	struct sas_rphy *rphy;
627*5597088cSDongdong Hao 
628*5597088cSDongdong Hao 	if (sas_port->remote_identify.device_type == SAS_END_DEVICE) {
629*5597088cSDongdong Hao 		sas_dev = leapraid_get_sas_dev_by_addr(
630*5597088cSDongdong Hao 				adapter,
631*5597088cSDongdong Hao 				sas_port->remote_identify.sas_address,
632*5597088cSDongdong Hao 				card_port);
633*5597088cSDongdong Hao 		if (!sas_dev)
634*5597088cSDongdong Hao 			return NULL;
635*5597088cSDongdong Hao 		sas_dev->pend_sas_rphy_add = 1;
636*5597088cSDongdong Hao 	}
637*5597088cSDongdong Hao 
638*5597088cSDongdong Hao 	if (!topo_node->parent_dev) {
639*5597088cSDongdong Hao 		dev_warn(&adapter->pdev->dev,
640*5597088cSDongdong Hao 			 "%s: topo_node parent device is NULL\n",  __func__);
641*5597088cSDongdong Hao 		goto cleanup_sas_dev;
642*5597088cSDongdong Hao 	}
643*5597088cSDongdong Hao 
644*5597088cSDongdong Hao 	port = sas_port_alloc_num(topo_node->parent_dev);
645*5597088cSDongdong Hao 	if (!port) {
646*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
647*5597088cSDongdong Hao 			"%s: Failed to allocate SAS port\n", __func__);
648*5597088cSDongdong Hao 		goto cleanup_sas_dev;
649*5597088cSDongdong Hao 	}
650*5597088cSDongdong Hao 
651*5597088cSDongdong Hao 	if (sas_port_add(port)) {
652*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
653*5597088cSDongdong Hao 			"%s: Failed to add SAS port\n", __func__);
654*5597088cSDongdong Hao 		goto out_delete_port;
655*5597088cSDongdong Hao 	}
656*5597088cSDongdong Hao 
657*5597088cSDongdong Hao 	list_for_each_entry(card_phy, &sas_port->phy_list, port_siblings) {
658*5597088cSDongdong Hao 		sas_port_add_phy(port, card_phy->phy);
659*5597088cSDongdong Hao 		card_phy->phy_is_assigned = 1;
660*5597088cSDongdong Hao 		card_phy->card_port = card_port;
661*5597088cSDongdong Hao 	}
662*5597088cSDongdong Hao 
663*5597088cSDongdong Hao 	if (sas_dev) {
664*5597088cSDongdong Hao 		rphy = sas_end_device_alloc(port);
665*5597088cSDongdong Hao 		sas_dev->rphy = rphy;
666*5597088cSDongdong Hao 
667*5597088cSDongdong Hao 		if (topo_node->hdl <= adapter->dev_topo.card.phys_num) {
668*5597088cSDongdong Hao 			if (!vphy)
669*5597088cSDongdong Hao 				card_port->sas_address = sas_dev->sas_addr;
670*5597088cSDongdong Hao 			else
671*5597088cSDongdong Hao 				vphy->sas_address = sas_dev->sas_addr;
672*5597088cSDongdong Hao 		}
673*5597088cSDongdong Hao 	} else {
674*5597088cSDongdong Hao 		rphy = sas_expander_alloc(
675*5597088cSDongdong Hao 				port,
676*5597088cSDongdong Hao 				sas_port->remote_identify.device_type);
677*5597088cSDongdong Hao 		if (topo_node->hdl <= adapter->dev_topo.card.phys_num)
678*5597088cSDongdong Hao 			card_port->sas_address =
679*5597088cSDongdong Hao 				sas_port->remote_identify.sas_address;
680*5597088cSDongdong Hao 	}
681*5597088cSDongdong Hao 
682*5597088cSDongdong Hao 	if (!rphy) {
683*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
684*5597088cSDongdong Hao 			"%s: Failed to allocate RPHY\n", __func__);
685*5597088cSDongdong Hao 		goto cleanup_card_phy;
686*5597088cSDongdong Hao 	}
687*5597088cSDongdong Hao 
688*5597088cSDongdong Hao 	rphy->identify = sas_port->remote_identify;
689*5597088cSDongdong Hao 
690*5597088cSDongdong Hao 	if (sas_rphy_add(rphy)) {
691*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
692*5597088cSDongdong Hao 			"%s: Failed to add RPHY\n", __func__);
693*5597088cSDongdong Hao 		if (sas_dev)
694*5597088cSDongdong Hao 			sas_dev->rphy = NULL;
695*5597088cSDongdong Hao 
696*5597088cSDongdong Hao 		sas_rphy_free(rphy);
697*5597088cSDongdong Hao 		goto cleanup_card_phy;
698*5597088cSDongdong Hao 	}
699*5597088cSDongdong Hao 	sas_port->port = port;
700*5597088cSDongdong Hao 
701*5597088cSDongdong Hao 	if (sas_dev) {
702*5597088cSDongdong Hao 		sas_dev->pend_sas_rphy_add = 0;
703*5597088cSDongdong Hao 		leapraid_sdev_put(sas_dev);
704*5597088cSDongdong Hao 	}
705*5597088cSDongdong Hao 
706*5597088cSDongdong Hao 	return rphy;
707*5597088cSDongdong Hao 
708*5597088cSDongdong Hao cleanup_card_phy:
709*5597088cSDongdong Hao 	if (topo_node->hdl <= adapter->dev_topo.card.phys_num) {
710*5597088cSDongdong Hao 		if (!vphy)
711*5597088cSDongdong Hao 			card_port->sas_address = 0;
712*5597088cSDongdong Hao 		else
713*5597088cSDongdong Hao 			vphy->sas_address = 0;
714*5597088cSDongdong Hao 	}
715*5597088cSDongdong Hao 
716*5597088cSDongdong Hao 	list_for_each_entry(card_phy, &sas_port->phy_list, port_siblings) {
717*5597088cSDongdong Hao 		card_phy->phy_is_assigned = 0;
718*5597088cSDongdong Hao 		card_phy->card_port = NULL;
719*5597088cSDongdong Hao 	}
720*5597088cSDongdong Hao 
721*5597088cSDongdong Hao out_delete_port:
722*5597088cSDongdong Hao 	sas_port_delete(port);
723*5597088cSDongdong Hao 
724*5597088cSDongdong Hao cleanup_sas_dev:
725*5597088cSDongdong Hao 	if (sas_dev) {
726*5597088cSDongdong Hao 		sas_dev->pend_sas_rphy_add = 0;
727*5597088cSDongdong Hao 		leapraid_sdev_put(sas_dev);
728*5597088cSDongdong Hao 	}
729*5597088cSDongdong Hao 	return NULL;
730*5597088cSDongdong Hao }
731*5597088cSDongdong Hao 
732*5597088cSDongdong Hao struct leapraid_sas_port *leapraid_transport_port_add(
733*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
734*5597088cSDongdong Hao 		u16 hdl, u64 sas_address,
735*5597088cSDongdong Hao 		struct leapraid_card_port *card_port)
736*5597088cSDongdong Hao {
737*5597088cSDongdong Hao 	struct leapraid_card_phy *card_phy, *card_phy_next;
738*5597088cSDongdong Hao 	struct leapraid_topo_node *topo_node = NULL;
739*5597088cSDongdong Hao 	struct leapraid_sas_port *sas_port;
740*5597088cSDongdong Hao 	struct leapraid_vphy *vphy = NULL;
741*5597088cSDongdong Hao 	struct sas_rphy *rphy;
742*5597088cSDongdong Hao 	unsigned long flags;
743*5597088cSDongdong Hao 
744*5597088cSDongdong Hao 	if (!card_port) {
745*5597088cSDongdong Hao 		dev_warn(&adapter->pdev->dev,
746*5597088cSDongdong Hao 			 "%s: Invalid card_port\n", __func__);
747*5597088cSDongdong Hao 		return NULL;
748*5597088cSDongdong Hao 	}
749*5597088cSDongdong Hao 
750*5597088cSDongdong Hao 	sas_port = leapraid_prepare_sas_port(adapter, hdl, sas_address,
751*5597088cSDongdong Hao 					     card_port, &topo_node);
752*5597088cSDongdong Hao 	if (!sas_port)
753*5597088cSDongdong Hao 		return NULL;
754*5597088cSDongdong Hao 
755*5597088cSDongdong Hao 	leapraid_detach_phy_from_old_port(
756*5597088cSDongdong Hao 		adapter,
757*5597088cSDongdong Hao 		topo_node,
758*5597088cSDongdong Hao 		sas_port->remote_identify.sas_address,
759*5597088cSDongdong Hao 		card_port);
760*5597088cSDongdong Hao 
761*5597088cSDongdong Hao 	if (leapraid_bind_phys_and_vphy(adapter, sas_port, topo_node,
762*5597088cSDongdong Hao 					card_port, &vphy)) {
763*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
764*5597088cSDongdong Hao 			"%s: Failed to bind phy to vphy\n", __func__);
765*5597088cSDongdong Hao 		goto out_fail;
766*5597088cSDongdong Hao 	}
767*5597088cSDongdong Hao 
768*5597088cSDongdong Hao 	rphy = leapraid_create_and_register_rphy(adapter, sas_port, topo_node,
769*5597088cSDongdong Hao 						 card_port, vphy);
770*5597088cSDongdong Hao 	if (!rphy) {
771*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
772*5597088cSDongdong Hao 			"%s: Failed to create rphy\n", __func__);
773*5597088cSDongdong Hao 		goto out_fail;
774*5597088cSDongdong Hao 	}
775*5597088cSDongdong Hao 
776*5597088cSDongdong Hao 	dev_info(&rphy->dev,
777*5597088cSDongdong Hao 		 "%s: Added dev: hdl=0x%04x, SAS addr=0x%016llx\n",
778*5597088cSDongdong Hao 		 __func__, hdl,
779*5597088cSDongdong Hao 		 (unsigned long long)sas_port->remote_identify.sas_address);
780*5597088cSDongdong Hao 
781*5597088cSDongdong Hao 	sas_port->rphy = rphy;
782*5597088cSDongdong Hao 
783*5597088cSDongdong Hao 	spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
784*5597088cSDongdong Hao 	list_add_tail(&sas_port->port_list, &topo_node->sas_port_list);
785*5597088cSDongdong Hao 	spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
786*5597088cSDongdong Hao 
787*5597088cSDongdong Hao 	if (sas_port->remote_identify.device_type ==
788*5597088cSDongdong Hao 	    SAS_EDGE_EXPANDER_DEVICE ||
789*5597088cSDongdong Hao 	    sas_port->remote_identify.device_type ==
790*5597088cSDongdong Hao 	    SAS_FANOUT_EXPANDER_DEVICE)
791*5597088cSDongdong Hao 		leapraid_transport_exp_report_manu(
792*5597088cSDongdong Hao 			adapter,
793*5597088cSDongdong Hao 			sas_port->remote_identify.sas_address,
794*5597088cSDongdong Hao 			rphy_to_expander_device(rphy),
795*5597088cSDongdong Hao 			card_port->port_id);
796*5597088cSDongdong Hao 
797*5597088cSDongdong Hao 	return sas_port;
798*5597088cSDongdong Hao 
799*5597088cSDongdong Hao out_fail:
800*5597088cSDongdong Hao 	list_for_each_entry_safe(card_phy, card_phy_next,
801*5597088cSDongdong Hao 				 &sas_port->phy_list, port_siblings) {
802*5597088cSDongdong Hao 		if (topo_node->hdl <= adapter->dev_topo.card.phys_num &&
803*5597088cSDongdong Hao 		    !card_phy->vphy)
804*5597088cSDongdong Hao 			card_port->phy_mask &= ~BIT(card_phy->phy_id);
805*5597088cSDongdong Hao 
806*5597088cSDongdong Hao 		list_del_init(&card_phy->port_siblings);
807*5597088cSDongdong Hao 	}
808*5597088cSDongdong Hao 
809*5597088cSDongdong Hao 	kfree(sas_port);
810*5597088cSDongdong Hao 	return NULL;
811*5597088cSDongdong Hao }
812*5597088cSDongdong Hao 
813*5597088cSDongdong Hao static struct leapraid_sas_port *leapraid_find_and_remove_sas_port(
814*5597088cSDongdong Hao 		struct leapraid_topo_node *topo_node,
815*5597088cSDongdong Hao 		u64 sas_address,
816*5597088cSDongdong Hao 		struct leapraid_card_port *remove_card_port,
817*5597088cSDongdong Hao 		bool *found)
818*5597088cSDongdong Hao {
819*5597088cSDongdong Hao 	struct leapraid_sas_port *sas_port, *sas_port_next;
820*5597088cSDongdong Hao 
821*5597088cSDongdong Hao 	list_for_each_entry_safe(sas_port, sas_port_next,
822*5597088cSDongdong Hao 				 &topo_node->sas_port_list, port_list) {
823*5597088cSDongdong Hao 		if (sas_port->remote_identify.sas_address != sas_address)
824*5597088cSDongdong Hao 			continue;
825*5597088cSDongdong Hao 
826*5597088cSDongdong Hao 		if (sas_port->card_port != remove_card_port)
827*5597088cSDongdong Hao 			continue;
828*5597088cSDongdong Hao 
829*5597088cSDongdong Hao 		*found = true;
830*5597088cSDongdong Hao 		list_del(&sas_port->port_list);
831*5597088cSDongdong Hao 		return sas_port;
832*5597088cSDongdong Hao 	}
833*5597088cSDongdong Hao 	return NULL;
834*5597088cSDongdong Hao }
835*5597088cSDongdong Hao 
836*5597088cSDongdong Hao static void leapraid_cleanup_card_port_and_vphys(
837*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
838*5597088cSDongdong Hao 		u64 sas_address,
839*5597088cSDongdong Hao 		struct leapraid_card_port *remove_card_port)
840*5597088cSDongdong Hao {
841*5597088cSDongdong Hao 	struct leapraid_card_port *card_port, *card_port_next;
842*5597088cSDongdong Hao 	struct leapraid_vphy *vphy, *vphy_next;
843*5597088cSDongdong Hao 
844*5597088cSDongdong Hao 	if (remove_card_port->vphys_mask) {
845*5597088cSDongdong Hao 		list_for_each_entry_safe(vphy, vphy_next,
846*5597088cSDongdong Hao 					 &remove_card_port->vphys_list, list) {
847*5597088cSDongdong Hao 			if (vphy->sas_address != sas_address)
848*5597088cSDongdong Hao 				continue;
849*5597088cSDongdong Hao 
850*5597088cSDongdong Hao 			dev_dbg(&adapter->pdev->dev,
851*5597088cSDongdong Hao 				"%s: Remove vphy=%p from port=%p port_id=%d\n",
852*5597088cSDongdong Hao 				__func__, vphy, remove_card_port,
853*5597088cSDongdong Hao 				remove_card_port->port_id);
854*5597088cSDongdong Hao 
855*5597088cSDongdong Hao 			remove_card_port->vphys_mask &= ~vphy->phy_mask;
856*5597088cSDongdong Hao 			list_del(&vphy->list);
857*5597088cSDongdong Hao 			kfree(vphy);
858*5597088cSDongdong Hao 		}
859*5597088cSDongdong Hao 
860*5597088cSDongdong Hao 		if (!remove_card_port->vphys_mask &&
861*5597088cSDongdong Hao 		    !remove_card_port->sas_address) {
862*5597088cSDongdong Hao 			dev_dbg(&adapter->pdev->dev,
863*5597088cSDongdong Hao 				"%s: Remove empty hba_port: %p, port_id=%d\n",
864*5597088cSDongdong Hao 				__func__,
865*5597088cSDongdong Hao 				remove_card_port,
866*5597088cSDongdong Hao 				remove_card_port->port_id);
867*5597088cSDongdong Hao 			list_del(&remove_card_port->list);
868*5597088cSDongdong Hao 			kfree(remove_card_port);
869*5597088cSDongdong Hao 			remove_card_port = NULL;
870*5597088cSDongdong Hao 		}
871*5597088cSDongdong Hao 	}
872*5597088cSDongdong Hao 
873*5597088cSDongdong Hao 	list_for_each_entry_safe(card_port, card_port_next,
874*5597088cSDongdong Hao 				 &adapter->dev_topo.card_port_list, list) {
875*5597088cSDongdong Hao 		if (card_port != remove_card_port)
876*5597088cSDongdong Hao 			continue;
877*5597088cSDongdong Hao 
878*5597088cSDongdong Hao 		if (card_port->sas_address != sas_address)
879*5597088cSDongdong Hao 			continue;
880*5597088cSDongdong Hao 
881*5597088cSDongdong Hao 		if (!remove_card_port->vphys_mask) {
882*5597088cSDongdong Hao 			dev_dbg(&adapter->pdev->dev,
883*5597088cSDongdong Hao 				"%s: Remove hba_port: %p, port_id=%d\n",
884*5597088cSDongdong Hao 				__func__, card_port, card_port->port_id);
885*5597088cSDongdong Hao 			list_del(&card_port->list);
886*5597088cSDongdong Hao 			kfree(card_port);
887*5597088cSDongdong Hao 		} else {
888*5597088cSDongdong Hao 			dev_dbg(&adapter->pdev->dev,
889*5597088cSDongdong Hao 				"Clear sas_address of port=%p, port_id=%d\n",
890*5597088cSDongdong Hao 				card_port, card_port->port_id);
891*5597088cSDongdong Hao 			remove_card_port->sas_address = 0;
892*5597088cSDongdong Hao 		}
893*5597088cSDongdong Hao 		break;
894*5597088cSDongdong Hao 	}
895*5597088cSDongdong Hao }
896*5597088cSDongdong Hao 
897*5597088cSDongdong Hao static void leapraid_clear_topo_node_phys(struct leapraid_topo_node *topo_node,
898*5597088cSDongdong Hao 					  u64 sas_address)
899*5597088cSDongdong Hao {
900*5597088cSDongdong Hao 	int i;
901*5597088cSDongdong Hao 
902*5597088cSDongdong Hao 	for (i = 0; i < topo_node->phys_num; i++)
903*5597088cSDongdong Hao 		if (topo_node->card_phy[i].remote_identify.sas_address ==
904*5597088cSDongdong Hao 		    sas_address) {
905*5597088cSDongdong Hao 			memset(&topo_node->card_phy[i].remote_identify, 0,
906*5597088cSDongdong Hao 			       sizeof(struct sas_identify));
907*5597088cSDongdong Hao 			topo_node->card_phy[i].vphy = 0;
908*5597088cSDongdong Hao 		}
909*5597088cSDongdong Hao }
910*5597088cSDongdong Hao 
911*5597088cSDongdong Hao void leapraid_transport_port_remove(
912*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
913*5597088cSDongdong Hao 		u64 sas_address,
914*5597088cSDongdong Hao 		u64 sas_address_parent,
915*5597088cSDongdong Hao 		struct leapraid_card_port *remove_card_port)
916*5597088cSDongdong Hao {
917*5597088cSDongdong Hao 	struct leapraid_card_phy *card_phy, *card_phy_next;
918*5597088cSDongdong Hao 	struct leapraid_sas_port *sas_port;
919*5597088cSDongdong Hao 	struct leapraid_topo_node *topo_node;
920*5597088cSDongdong Hao 	unsigned long flags;
921*5597088cSDongdong Hao 	bool found = false;
922*5597088cSDongdong Hao 
923*5597088cSDongdong Hao 	if (!remove_card_port)
924*5597088cSDongdong Hao 		return;
925*5597088cSDongdong Hao 
926*5597088cSDongdong Hao 	spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
927*5597088cSDongdong Hao 
928*5597088cSDongdong Hao 	topo_node = leapraid_transport_topo_node_by_sas_addr(adapter,
929*5597088cSDongdong Hao 							     sas_address_parent,
930*5597088cSDongdong Hao 							     remove_card_port);
931*5597088cSDongdong Hao 	if (!topo_node) {
932*5597088cSDongdong Hao 		spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock,
933*5597088cSDongdong Hao 				       flags);
934*5597088cSDongdong Hao 		return;
935*5597088cSDongdong Hao 	}
936*5597088cSDongdong Hao 
937*5597088cSDongdong Hao 	sas_port = leapraid_find_and_remove_sas_port(topo_node, sas_address,
938*5597088cSDongdong Hao 						     remove_card_port, &found);
939*5597088cSDongdong Hao 
940*5597088cSDongdong Hao 	if (!found) {
941*5597088cSDongdong Hao 		spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock,
942*5597088cSDongdong Hao 				       flags);
943*5597088cSDongdong Hao 		return;
944*5597088cSDongdong Hao 	}
945*5597088cSDongdong Hao 
946*5597088cSDongdong Hao 	if (topo_node->hdl <= adapter->dev_topo.card.phys_num &&
947*5597088cSDongdong Hao 	    adapter->adapter_attr.enable_mp)
948*5597088cSDongdong Hao 		leapraid_cleanup_card_port_and_vphys(adapter, sas_address,
949*5597088cSDongdong Hao 						     remove_card_port);
950*5597088cSDongdong Hao 
951*5597088cSDongdong Hao 	leapraid_clear_topo_node_phys(topo_node, sas_address);
952*5597088cSDongdong Hao 	spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
953*5597088cSDongdong Hao 
954*5597088cSDongdong Hao 	list_for_each_entry_safe(card_phy, card_phy_next,
955*5597088cSDongdong Hao 				 &sas_port->phy_list, port_siblings) {
956*5597088cSDongdong Hao 		card_phy->phy_is_assigned = 0;
957*5597088cSDongdong Hao 		if (!adapter->access_ctrl.host_removing)
958*5597088cSDongdong Hao 			sas_port_delete_phy(sas_port->port, card_phy->phy);
959*5597088cSDongdong Hao 
960*5597088cSDongdong Hao 		list_del(&card_phy->port_siblings);
961*5597088cSDongdong Hao 	}
962*5597088cSDongdong Hao 
963*5597088cSDongdong Hao 	if (!adapter->access_ctrl.host_removing)
964*5597088cSDongdong Hao 		sas_port_delete(sas_port->port);
965*5597088cSDongdong Hao 
966*5597088cSDongdong Hao 	dev_dbg(&adapter->pdev->dev,
967*5597088cSDongdong Hao 		"%s: Removed sas_port for SAS addr=0x%016llx\n",
968*5597088cSDongdong Hao 		__func__, (unsigned long long)sas_address);
969*5597088cSDongdong Hao 
970*5597088cSDongdong Hao 	kfree(sas_port);
971*5597088cSDongdong Hao }
972*5597088cSDongdong Hao 
973*5597088cSDongdong Hao static void leapraid_init_sas_or_exp_phy(struct leapraid_adapter *adapter,
974*5597088cSDongdong Hao 					 struct leapraid_card_phy *card_phy,
975*5597088cSDongdong Hao 					 struct sas_phy *phy,
976*5597088cSDongdong Hao 					 struct leapraid_sas_phy_p0 *phy_pg0,
977*5597088cSDongdong Hao 					 struct leapraid_exp_p1 *exp_pg1)
978*5597088cSDongdong Hao {
979*5597088cSDongdong Hao 	if (exp_pg1 && phy_pg0)
980*5597088cSDongdong Hao 		return;
981*5597088cSDongdong Hao 
982*5597088cSDongdong Hao 	if (!exp_pg1 && !phy_pg0)
983*5597088cSDongdong Hao 		return;
984*5597088cSDongdong Hao 
985*5597088cSDongdong Hao 	phy->identify = card_phy->identify;
986*5597088cSDongdong Hao 	phy->identify.phy_identifier = card_phy->phy_id;
987*5597088cSDongdong Hao 	phy->negotiated_linkrate = phy_pg0 ?
988*5597088cSDongdong Hao 		leapraid_transport_convert_phy_link_rate(
989*5597088cSDongdong Hao 			phy_pg0->neg_link_rate &
990*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_MASK_PHYSICAL) :
991*5597088cSDongdong Hao 		 leapraid_transport_convert_phy_link_rate(
992*5597088cSDongdong Hao 			exp_pg1->neg_link_rate &
993*5597088cSDongdong Hao 			LEAPRAID_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
994*5597088cSDongdong Hao 	phy->minimum_linkrate_hw = phy_pg0 ?
995*5597088cSDongdong Hao 		 leapraid_transport_convert_phy_link_rate(
996*5597088cSDongdong Hao 			phy_pg0->hw_link_rate &
997*5597088cSDongdong Hao 			LEAPRAID_SAS_HWRATE_MIN_RATE_MASK) :
998*5597088cSDongdong Hao 		 leapraid_transport_convert_phy_link_rate(
999*5597088cSDongdong Hao 			exp_pg1->hw_link_rate &
1000*5597088cSDongdong Hao 			LEAPRAID_SAS_HWRATE_MIN_RATE_MASK);
1001*5597088cSDongdong Hao 	phy->maximum_linkrate_hw = phy_pg0 ?
1002*5597088cSDongdong Hao 		 leapraid_transport_convert_phy_link_rate(
1003*5597088cSDongdong Hao 			phy_pg0->hw_link_rate >>
1004*5597088cSDongdong Hao 			 LEAPRAID_SAS_NEG_LINK_RATE_SHIFT) :
1005*5597088cSDongdong Hao 		 leapraid_transport_convert_phy_link_rate(
1006*5597088cSDongdong Hao 			exp_pg1->hw_link_rate >>
1007*5597088cSDongdong Hao 			 LEAPRAID_SAS_NEG_LINK_RATE_SHIFT);
1008*5597088cSDongdong Hao 	phy->minimum_linkrate = phy_pg0 ?
1009*5597088cSDongdong Hao 		 leapraid_transport_convert_phy_link_rate(
1010*5597088cSDongdong Hao 			phy_pg0->p_link_rate &
1011*5597088cSDongdong Hao 			LEAPRAID_SAS_PRATE_MIN_RATE_MASK) :
1012*5597088cSDongdong Hao 		 leapraid_transport_convert_phy_link_rate(
1013*5597088cSDongdong Hao 			exp_pg1->p_link_rate &
1014*5597088cSDongdong Hao 			LEAPRAID_SAS_PRATE_MIN_RATE_MASK);
1015*5597088cSDongdong Hao 	phy->maximum_linkrate = phy_pg0 ?
1016*5597088cSDongdong Hao 		 leapraid_transport_convert_phy_link_rate(
1017*5597088cSDongdong Hao 			phy_pg0->p_link_rate >>
1018*5597088cSDongdong Hao 			 LEAPRAID_SAS_NEG_LINK_RATE_SHIFT) :
1019*5597088cSDongdong Hao 		 leapraid_transport_convert_phy_link_rate(
1020*5597088cSDongdong Hao 			exp_pg1->p_link_rate >>
1021*5597088cSDongdong Hao 			 LEAPRAID_SAS_NEG_LINK_RATE_SHIFT);
1022*5597088cSDongdong Hao 	phy->hostdata = card_phy->card_port;
1023*5597088cSDongdong Hao }
1024*5597088cSDongdong Hao 
1025*5597088cSDongdong Hao void leapraid_transport_add_card_phy(struct leapraid_adapter *adapter,
1026*5597088cSDongdong Hao 				     struct leapraid_card_phy *card_phy,
1027*5597088cSDongdong Hao 				     struct leapraid_sas_phy_p0 *phy_pg0,
1028*5597088cSDongdong Hao 				     struct device *parent_dev)
1029*5597088cSDongdong Hao {
1030*5597088cSDongdong Hao 	struct sas_phy *phy;
1031*5597088cSDongdong Hao 	int ret;
1032*5597088cSDongdong Hao 
1033*5597088cSDongdong Hao 	INIT_LIST_HEAD(&card_phy->port_siblings);
1034*5597088cSDongdong Hao 	phy = sas_phy_alloc(parent_dev, card_phy->phy_id);
1035*5597088cSDongdong Hao 	if (!phy) {
1036*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1037*5597088cSDongdong Hao 			"%s: sas_phy_alloc failed!\n", __func__);
1038*5597088cSDongdong Hao 		return;
1039*5597088cSDongdong Hao 	}
1040*5597088cSDongdong Hao 
1041*5597088cSDongdong Hao 	if (leapraid_transport_set_identify(adapter, card_phy->hdl,
1042*5597088cSDongdong Hao 					    &card_phy->identify)) {
1043*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1044*5597088cSDongdong Hao 			"%s: Set PHY handle identify failed!\n", __func__);
1045*5597088cSDongdong Hao 		sas_phy_free(phy);
1046*5597088cSDongdong Hao 		return;
1047*5597088cSDongdong Hao 	}
1048*5597088cSDongdong Hao 
1049*5597088cSDongdong Hao 	card_phy->attached_hdl = le16_to_cpu(phy_pg0->attached_dev_hdl);
1050*5597088cSDongdong Hao 	if (card_phy->attached_hdl) {
1051*5597088cSDongdong Hao 		ret = leapraid_transport_set_identify(
1052*5597088cSDongdong Hao 				adapter,
1053*5597088cSDongdong Hao 				card_phy->attached_hdl,
1054*5597088cSDongdong Hao 				&card_phy->remote_identify);
1055*5597088cSDongdong Hao 		if (ret) {
1056*5597088cSDongdong Hao 			dev_err(&adapter->pdev->dev,
1057*5597088cSDongdong Hao 				"%s: Set PHY attached hdl identify failed!\n",
1058*5597088cSDongdong Hao 				__func__);
1059*5597088cSDongdong Hao 			sas_phy_free(phy);
1060*5597088cSDongdong Hao 			return;
1061*5597088cSDongdong Hao 		}
1062*5597088cSDongdong Hao 	}
1063*5597088cSDongdong Hao 
1064*5597088cSDongdong Hao 	leapraid_init_sas_or_exp_phy(adapter, card_phy, phy, phy_pg0, NULL);
1065*5597088cSDongdong Hao 
1066*5597088cSDongdong Hao 	if (sas_phy_add(phy)) {
1067*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1068*5597088cSDongdong Hao 			"%s: SAS PHY add failed!\n", __func__);
1069*5597088cSDongdong Hao 		sas_phy_free(phy);
1070*5597088cSDongdong Hao 		return;
1071*5597088cSDongdong Hao 	}
1072*5597088cSDongdong Hao 
1073*5597088cSDongdong Hao 	card_phy->phy = phy;
1074*5597088cSDongdong Hao }
1075*5597088cSDongdong Hao 
1076*5597088cSDongdong Hao int leapraid_transport_add_exp_phy(struct leapraid_adapter *adapter,
1077*5597088cSDongdong Hao 				   struct leapraid_card_phy *card_phy,
1078*5597088cSDongdong Hao 				   struct leapraid_exp_p1 *exp_pg1,
1079*5597088cSDongdong Hao 				   struct device *parent_dev)
1080*5597088cSDongdong Hao {
1081*5597088cSDongdong Hao 	struct sas_phy *phy;
1082*5597088cSDongdong Hao 	int ret;
1083*5597088cSDongdong Hao 
1084*5597088cSDongdong Hao 	INIT_LIST_HEAD(&card_phy->port_siblings);
1085*5597088cSDongdong Hao 	phy = sas_phy_alloc(parent_dev, card_phy->phy_id);
1086*5597088cSDongdong Hao 	if (!phy) {
1087*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1088*5597088cSDongdong Hao 			"%s: sas_phy_alloc failed!\n", __func__);
1089*5597088cSDongdong Hao 		return -EFAULT;
1090*5597088cSDongdong Hao 	}
1091*5597088cSDongdong Hao 
1092*5597088cSDongdong Hao 	if (leapraid_transport_set_identify(adapter, card_phy->hdl,
1093*5597088cSDongdong Hao 					    &card_phy->identify)) {
1094*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1095*5597088cSDongdong Hao 			"%s: Set PHY hdl identify failed!\n", __func__);
1096*5597088cSDongdong Hao 		sas_phy_free(phy);
1097*5597088cSDongdong Hao 		return -EFAULT;
1098*5597088cSDongdong Hao 	}
1099*5597088cSDongdong Hao 
1100*5597088cSDongdong Hao 	card_phy->attached_hdl = le16_to_cpu(exp_pg1->attached_dev_hdl);
1101*5597088cSDongdong Hao 	if (card_phy->attached_hdl) {
1102*5597088cSDongdong Hao 		ret = leapraid_transport_set_identify(
1103*5597088cSDongdong Hao 				adapter,
1104*5597088cSDongdong Hao 				card_phy->attached_hdl,
1105*5597088cSDongdong Hao 				&card_phy->remote_identify);
1106*5597088cSDongdong Hao 		if (ret)
1107*5597088cSDongdong Hao 			dev_warn(&adapter->pdev->dev,
1108*5597088cSDongdong Hao 				 "%s: Set PHY attached hdl identify failed!\n",
1109*5597088cSDongdong Hao 				 __func__);
1110*5597088cSDongdong Hao 	}
1111*5597088cSDongdong Hao 
1112*5597088cSDongdong Hao 	leapraid_init_sas_or_exp_phy(adapter, card_phy, phy, NULL, exp_pg1);
1113*5597088cSDongdong Hao 
1114*5597088cSDongdong Hao 	if (sas_phy_add(phy)) {
1115*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1116*5597088cSDongdong Hao 			"%s: SAS PHY add failed!\n", __func__);
1117*5597088cSDongdong Hao 		sas_phy_free(phy);
1118*5597088cSDongdong Hao 		return -EFAULT;
1119*5597088cSDongdong Hao 	}
1120*5597088cSDongdong Hao 
1121*5597088cSDongdong Hao 	card_phy->phy = phy;
1122*5597088cSDongdong Hao 	return 0;
1123*5597088cSDongdong Hao }
1124*5597088cSDongdong Hao 
1125*5597088cSDongdong Hao void leapraid_transport_update_links(
1126*5597088cSDongdong Hao 		struct leapraid_adapter *adapter,
1127*5597088cSDongdong Hao 		u64 sas_address, u16 hdl, u8 phy_index,
1128*5597088cSDongdong Hao 		u8 link_rate, struct leapraid_card_port *target_card_port)
1129*5597088cSDongdong Hao {
1130*5597088cSDongdong Hao 	struct leapraid_topo_node *topo_node;
1131*5597088cSDongdong Hao 	struct leapraid_card_phy *card_phy;
1132*5597088cSDongdong Hao 	struct leapraid_card_port *card_port;
1133*5597088cSDongdong Hao 	unsigned long flags;
1134*5597088cSDongdong Hao 
1135*5597088cSDongdong Hao 	if (adapter->access_ctrl.shost_recovering ||
1136*5597088cSDongdong Hao 	    adapter->access_ctrl.pcie_recovering)
1137*5597088cSDongdong Hao 		return;
1138*5597088cSDongdong Hao 
1139*5597088cSDongdong Hao 	spin_lock_irqsave(&adapter->dev_topo.topo_node_lock, flags);
1140*5597088cSDongdong Hao 	topo_node = leapraid_transport_topo_node_by_sas_addr(adapter,
1141*5597088cSDongdong Hao 							     sas_address,
1142*5597088cSDongdong Hao 							     target_card_port);
1143*5597088cSDongdong Hao 	if (!topo_node) {
1144*5597088cSDongdong Hao 		spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock,
1145*5597088cSDongdong Hao 				       flags);
1146*5597088cSDongdong Hao 		return;
1147*5597088cSDongdong Hao 	}
1148*5597088cSDongdong Hao 
1149*5597088cSDongdong Hao 	card_phy = &topo_node->card_phy[phy_index];
1150*5597088cSDongdong Hao 	card_phy->attached_hdl = hdl;
1151*5597088cSDongdong Hao 	spin_unlock_irqrestore(&adapter->dev_topo.topo_node_lock, flags);
1152*5597088cSDongdong Hao 
1153*5597088cSDongdong Hao 	if (hdl && link_rate >= LEAPRAID_SAS_NEG_LINK_RATE_1_5) {
1154*5597088cSDongdong Hao 		leapraid_transport_set_identify(adapter, hdl,
1155*5597088cSDongdong Hao 						&card_phy->remote_identify);
1156*5597088cSDongdong Hao 		if (topo_node->hdl <= adapter->dev_topo.card.phys_num &&
1157*5597088cSDongdong Hao 		    adapter->adapter_attr.enable_mp) {
1158*5597088cSDongdong Hao 			list_for_each_entry(card_port,
1159*5597088cSDongdong Hao 					    &adapter->dev_topo.card_port_list,
1160*5597088cSDongdong Hao 					    list) {
1161*5597088cSDongdong Hao 				if (card_port->sas_address == sas_address &&
1162*5597088cSDongdong Hao 				    card_port == target_card_port)
1163*5597088cSDongdong Hao 					card_port->phy_mask |=
1164*5597088cSDongdong Hao 						BIT(card_phy->phy_id);
1165*5597088cSDongdong Hao 			}
1166*5597088cSDongdong Hao 		}
1167*5597088cSDongdong Hao 		leapraid_transport_attach_phy_to_port(
1168*5597088cSDongdong Hao 			adapter,
1169*5597088cSDongdong Hao 			topo_node,
1170*5597088cSDongdong Hao 			card_phy,
1171*5597088cSDongdong Hao 			card_phy->remote_identify.sas_address,
1172*5597088cSDongdong Hao 			target_card_port);
1173*5597088cSDongdong Hao 	} else {
1174*5597088cSDongdong Hao 		memset(&card_phy->remote_identify, 0,
1175*5597088cSDongdong Hao 		       sizeof(struct sas_identify));
1176*5597088cSDongdong Hao 	}
1177*5597088cSDongdong Hao 
1178*5597088cSDongdong Hao 	if (card_phy->phy)
1179*5597088cSDongdong Hao 		card_phy->phy->negotiated_linkrate =
1180*5597088cSDongdong Hao 			leapraid_transport_convert_phy_link_rate(link_rate);
1181*5597088cSDongdong Hao }
1182*5597088cSDongdong Hao 
1183*5597088cSDongdong Hao static int leapraid_dma_map_buffer(struct device *dev, struct bsg_buffer *buf,
1184*5597088cSDongdong Hao 				   dma_addr_t *dma_addr,
1185*5597088cSDongdong Hao 				   size_t *dma_len, void **p)
1186*5597088cSDongdong Hao {
1187*5597088cSDongdong Hao 	if (buf->sg_cnt > 1) {
1188*5597088cSDongdong Hao 		*p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
1189*5597088cSDongdong Hao 					GFP_KERNEL);
1190*5597088cSDongdong Hao 		if (!*p)
1191*5597088cSDongdong Hao 			return -ENOMEM;
1192*5597088cSDongdong Hao 
1193*5597088cSDongdong Hao 		*dma_len = buf->payload_len;
1194*5597088cSDongdong Hao 	} else {
1195*5597088cSDongdong Hao 		if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL)) {
1196*5597088cSDongdong Hao 			dev_err(dev,
1197*5597088cSDongdong Hao 				"%s: Failed to map sg buffer for dma\n",
1198*5597088cSDongdong Hao 				__func__);
1199*5597088cSDongdong Hao 			return -ENOMEM;
1200*5597088cSDongdong Hao 		}
1201*5597088cSDongdong Hao 
1202*5597088cSDongdong Hao 		*dma_addr = sg_dma_address(buf->sg_list);
1203*5597088cSDongdong Hao 		*dma_len = sg_dma_len(buf->sg_list);
1204*5597088cSDongdong Hao 		*p = NULL;
1205*5597088cSDongdong Hao 	}
1206*5597088cSDongdong Hao 	return 0;
1207*5597088cSDongdong Hao }
1208*5597088cSDongdong Hao 
1209*5597088cSDongdong Hao static void leapraid_dma_unmap_buffer(struct device *dev,
1210*5597088cSDongdong Hao 				      struct bsg_buffer *buf,
1211*5597088cSDongdong Hao 				      dma_addr_t dma_addr,
1212*5597088cSDongdong Hao 				      void *p)
1213*5597088cSDongdong Hao {
1214*5597088cSDongdong Hao 	if (p)
1215*5597088cSDongdong Hao 		dma_free_coherent(dev, buf->payload_len, p, dma_addr);
1216*5597088cSDongdong Hao 	else
1217*5597088cSDongdong Hao 		dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
1218*5597088cSDongdong Hao }
1219*5597088cSDongdong Hao 
1220*5597088cSDongdong Hao static void leapraid_build_smp_task(struct leapraid_adapter *adapter,
1221*5597088cSDongdong Hao 				    struct sas_rphy *rphy,
1222*5597088cSDongdong Hao 				    dma_addr_t h2c_dma_addr, size_t h2c_size,
1223*5597088cSDongdong Hao 				    dma_addr_t c2h_dma_addr, size_t c2h_size)
1224*5597088cSDongdong Hao {
1225*5597088cSDongdong Hao 	struct leapraid_smp_passthrough_req *smp_passthrough_req;
1226*5597088cSDongdong Hao 	u16 inter_taskid;
1227*5597088cSDongdong Hao 	void *psge;
1228*5597088cSDongdong Hao 
1229*5597088cSDongdong Hao 	inter_taskid = adapter->driver_cmds.transport_cmd.inter_taskid;
1230*5597088cSDongdong Hao 	smp_passthrough_req = leapraid_get_task_desc(adapter, inter_taskid);
1231*5597088cSDongdong Hao 	memset(smp_passthrough_req, 0, sizeof(*smp_passthrough_req));
1232*5597088cSDongdong Hao 
1233*5597088cSDongdong Hao 	smp_passthrough_req->func = LEAPRAID_FUNC_SMP_PASSTHROUGH;
1234*5597088cSDongdong Hao 	smp_passthrough_req->physical_port =
1235*5597088cSDongdong Hao 		leapraid_transport_get_port_id_by_rphy(adapter, rphy);
1236*5597088cSDongdong Hao 	smp_passthrough_req->sas_address = (rphy) ?
1237*5597088cSDongdong Hao 		cpu_to_le64(rphy->identify.sas_address) :
1238*5597088cSDongdong Hao 		cpu_to_le64(adapter->dev_topo.card.sas_address);
1239*5597088cSDongdong Hao 	smp_passthrough_req->req_data_len =
1240*5597088cSDongdong Hao 		cpu_to_le16(h2c_size - LEAPRAID_SMP_FRAME_HEADER_SIZE);
1241*5597088cSDongdong Hao 	psge = &smp_passthrough_req->sgl;
1242*5597088cSDongdong Hao 	leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr,
1243*5597088cSDongdong Hao 			       h2c_size - LEAPRAID_SMP_FRAME_HEADER_SIZE,
1244*5597088cSDongdong Hao 			       c2h_dma_addr,
1245*5597088cSDongdong Hao 			       c2h_size - LEAPRAID_SMP_FRAME_HEADER_SIZE);
1246*5597088cSDongdong Hao }
1247*5597088cSDongdong Hao 
1248*5597088cSDongdong Hao static int leapraid_send_smp_req(struct leapraid_adapter *adapter)
1249*5597088cSDongdong Hao {
1250*5597088cSDongdong Hao 	const struct leapraid_smp_passthrough_req *smp_passthrough_req;
1251*5597088cSDongdong Hao 	u16 inter_taskid;
1252*5597088cSDongdong Hao 
1253*5597088cSDongdong Hao 	dev_dbg(&adapter->pdev->dev,
1254*5597088cSDongdong Hao 		"%s: Sending smp request\n", __func__);
1255*5597088cSDongdong Hao 	inter_taskid = adapter->driver_cmds.transport_cmd.inter_taskid;
1256*5597088cSDongdong Hao 	smp_passthrough_req = leapraid_get_task_desc(adapter, inter_taskid);
1257*5597088cSDongdong Hao 	init_completion(&adapter->driver_cmds.transport_cmd.done);
1258*5597088cSDongdong Hao 	leapraid_fire_task(adapter, inter_taskid);
1259*5597088cSDongdong Hao 	wait_for_completion_timeout(&adapter->driver_cmds.transport_cmd.done,
1260*5597088cSDongdong Hao 				    LEAPRAID_TRANSPORT_CMD_TIMEOUT * HZ);
1261*5597088cSDongdong Hao 	if (!(adapter->driver_cmds.transport_cmd.status & LEAPRAID_CMD_DONE)) {
1262*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev, "%s: timeout, st=0x%x\n",
1263*5597088cSDongdong Hao 			__func__, adapter->driver_cmds.transport_cmd.status);
1264*5597088cSDongdong Hao 		leapraid_log_req_context(adapter, inter_taskid,
1265*5597088cSDongdong Hao 					 smp_passthrough_req);
1266*5597088cSDongdong Hao 		if (!(adapter->driver_cmds.transport_cmd.status &
1267*5597088cSDongdong Hao 		      LEAPRAID_CMD_RESET)) {
1268*5597088cSDongdong Hao 			dev_dbg(&adapter->pdev->dev,
1269*5597088cSDongdong Hao 				"%s:%d: call hard_reset\n",
1270*5597088cSDongdong Hao 				__func__, __LINE__);
1271*5597088cSDongdong Hao 			leapraid_hard_reset_handler(adapter, FULL_RESET);
1272*5597088cSDongdong Hao 			return -ETIMEDOUT;
1273*5597088cSDongdong Hao 		}
1274*5597088cSDongdong Hao 	}
1275*5597088cSDongdong Hao 
1276*5597088cSDongdong Hao 	dev_dbg(&adapter->pdev->dev, "%s: SMP request complete\n", __func__);
1277*5597088cSDongdong Hao 	if (!(adapter->driver_cmds.transport_cmd.status &
1278*5597088cSDongdong Hao 	      LEAPRAID_CMD_REPLY_VALID)) {
1279*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1280*5597088cSDongdong Hao 			"%s: SMP request no reply\n", __func__);
1281*5597088cSDongdong Hao 		return -ENXIO;
1282*5597088cSDongdong Hao 	}
1283*5597088cSDongdong Hao 
1284*5597088cSDongdong Hao 	return 0;
1285*5597088cSDongdong Hao }
1286*5597088cSDongdong Hao 
1287*5597088cSDongdong Hao static void leapraid_handle_smp_rep(struct leapraid_adapter *adapter,
1288*5597088cSDongdong Hao 				    struct bsg_job *job, void *addr_in,
1289*5597088cSDongdong Hao 				    unsigned int *reslen)
1290*5597088cSDongdong Hao {
1291*5597088cSDongdong Hao 	struct leapraid_smp_passthrough_rep *smp_passthrough_rep;
1292*5597088cSDongdong Hao 
1293*5597088cSDongdong Hao 	smp_passthrough_rep =
1294*5597088cSDongdong Hao 		(void *)&adapter->driver_cmds.transport_cmd.reply;
1295*5597088cSDongdong Hao 
1296*5597088cSDongdong Hao 	dev_dbg(&adapter->pdev->dev, "%s: Response data len=%d\n",
1297*5597088cSDongdong Hao 		__func__, le16_to_cpu(smp_passthrough_rep->resp_data_len));
1298*5597088cSDongdong Hao 
1299*5597088cSDongdong Hao 	memcpy(job->reply, smp_passthrough_rep, sizeof(*smp_passthrough_rep));
1300*5597088cSDongdong Hao 	job->reply_len = sizeof(*smp_passthrough_rep);
1301*5597088cSDongdong Hao 	*reslen = le16_to_cpu(smp_passthrough_rep->resp_data_len);
1302*5597088cSDongdong Hao 
1303*5597088cSDongdong Hao 	if (addr_in)
1304*5597088cSDongdong Hao 		sg_copy_from_buffer(job->reply_payload.sg_list,
1305*5597088cSDongdong Hao 				    job->reply_payload.sg_cnt, addr_in,
1306*5597088cSDongdong Hao 				    job->reply_payload.payload_len);
1307*5597088cSDongdong Hao }
1308*5597088cSDongdong Hao 
1309*5597088cSDongdong Hao static void leapraid_transport_smp_handler(struct bsg_job *job,
1310*5597088cSDongdong Hao 					   struct Scsi_Host *shost,
1311*5597088cSDongdong Hao 					   struct sas_rphy *rphy)
1312*5597088cSDongdong Hao {
1313*5597088cSDongdong Hao 	struct leapraid_adapter *adapter = shost_priv(shost);
1314*5597088cSDongdong Hao 	dma_addr_t c2h_dma_addr;
1315*5597088cSDongdong Hao 	dma_addr_t h2c_dma_addr;
1316*5597088cSDongdong Hao 	void *addr_in = NULL;
1317*5597088cSDongdong Hao 	void *addr_out = NULL;
1318*5597088cSDongdong Hao 	size_t c2h_size;
1319*5597088cSDongdong Hao 	size_t h2c_size;
1320*5597088cSDongdong Hao 	int rc;
1321*5597088cSDongdong Hao 	unsigned int reslen = 0;
1322*5597088cSDongdong Hao 
1323*5597088cSDongdong Hao 	if (adapter->access_ctrl.shost_recovering ||
1324*5597088cSDongdong Hao 	    adapter->access_ctrl.pcie_recovering) {
1325*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1326*5597088cSDongdong Hao 			"%s: Failed, shost_recovering=%d pcie_recovering=%d\n",
1327*5597088cSDongdong Hao 			__func__,
1328*5597088cSDongdong Hao 			adapter->access_ctrl.shost_recovering,
1329*5597088cSDongdong Hao 			adapter->access_ctrl.pcie_recovering);
1330*5597088cSDongdong Hao 		rc = -EFAULT;
1331*5597088cSDongdong Hao 		goto exit_bsg_job;
1332*5597088cSDongdong Hao 	}
1333*5597088cSDongdong Hao 
1334*5597088cSDongdong Hao 	rc = mutex_lock_interruptible(&adapter->driver_cmds
1335*5597088cSDongdong Hao 				      .transport_cmd.mutex);
1336*5597088cSDongdong Hao 	if (rc)
1337*5597088cSDongdong Hao 		goto exit_bsg_job;
1338*5597088cSDongdong Hao 
1339*5597088cSDongdong Hao 	adapter->driver_cmds.transport_cmd.status = LEAPRAID_CMD_PENDING;
1340*5597088cSDongdong Hao 	rc = leapraid_dma_map_buffer(&adapter->pdev->dev,
1341*5597088cSDongdong Hao 				     &job->request_payload,
1342*5597088cSDongdong Hao 				     &h2c_dma_addr, &h2c_size, &addr_out);
1343*5597088cSDongdong Hao 	if (rc)
1344*5597088cSDongdong Hao 		goto release_lock;
1345*5597088cSDongdong Hao 
1346*5597088cSDongdong Hao 	if (h2c_size < LEAPRAID_SMP_FRAME_HEADER_SIZE) {
1347*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1348*5597088cSDongdong Hao 			"%s: Invalid SMP request payload size=%zu\n",
1349*5597088cSDongdong Hao 			__func__, h2c_size);
1350*5597088cSDongdong Hao 		rc = -EINVAL;
1351*5597088cSDongdong Hao 		goto free_req_buf;
1352*5597088cSDongdong Hao 	}
1353*5597088cSDongdong Hao 
1354*5597088cSDongdong Hao 	if (addr_out)
1355*5597088cSDongdong Hao 		sg_copy_to_buffer(job->request_payload.sg_list,
1356*5597088cSDongdong Hao 				  job->request_payload.sg_cnt, addr_out,
1357*5597088cSDongdong Hao 				  job->request_payload.payload_len);
1358*5597088cSDongdong Hao 
1359*5597088cSDongdong Hao 	rc = leapraid_dma_map_buffer(&adapter->pdev->dev, &job->reply_payload,
1360*5597088cSDongdong Hao 				     &c2h_dma_addr, &c2h_size, &addr_in);
1361*5597088cSDongdong Hao 	if (rc)
1362*5597088cSDongdong Hao 		goto free_req_buf;
1363*5597088cSDongdong Hao 
1364*5597088cSDongdong Hao 	if (c2h_size < LEAPRAID_SMP_FRAME_HEADER_SIZE) {
1365*5597088cSDongdong Hao 		dev_err(&adapter->pdev->dev,
1366*5597088cSDongdong Hao 			"%s: Invalid SMP reply payload size=%zu\n",
1367*5597088cSDongdong Hao 			__func__, c2h_size);
1368*5597088cSDongdong Hao 		rc = -EINVAL;
1369*5597088cSDongdong Hao 		goto free_rep_buf;
1370*5597088cSDongdong Hao 	}
1371*5597088cSDongdong Hao 
1372*5597088cSDongdong Hao 	rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_SHORT,
1373*5597088cSDongdong Hao 					  __func__);
1374*5597088cSDongdong Hao 	if (rc)
1375*5597088cSDongdong Hao 		goto free_rep_buf;
1376*5597088cSDongdong Hao 
1377*5597088cSDongdong Hao 	leapraid_build_smp_task(adapter, rphy, h2c_dma_addr,
1378*5597088cSDongdong Hao 				h2c_size, c2h_dma_addr, c2h_size);
1379*5597088cSDongdong Hao 
1380*5597088cSDongdong Hao 	rc = leapraid_send_smp_req(adapter);
1381*5597088cSDongdong Hao 	if (rc)
1382*5597088cSDongdong Hao 		goto free_rep_buf;
1383*5597088cSDongdong Hao 
1384*5597088cSDongdong Hao 	leapraid_handle_smp_rep(adapter, job, addr_in, &reslen);
1385*5597088cSDongdong Hao 
1386*5597088cSDongdong Hao free_rep_buf:
1387*5597088cSDongdong Hao 	leapraid_dma_unmap_buffer(&adapter->pdev->dev, &job->reply_payload,
1388*5597088cSDongdong Hao 				  c2h_dma_addr, addr_in);
1389*5597088cSDongdong Hao free_req_buf:
1390*5597088cSDongdong Hao 	leapraid_dma_unmap_buffer(&adapter->pdev->dev, &job->request_payload,
1391*5597088cSDongdong Hao 				  h2c_dma_addr, addr_out);
1392*5597088cSDongdong Hao release_lock:
1393*5597088cSDongdong Hao 	adapter->driver_cmds.transport_cmd.status = LEAPRAID_CMD_NOT_USED;
1394*5597088cSDongdong Hao 	mutex_unlock(&adapter->driver_cmds.transport_cmd.mutex);
1395*5597088cSDongdong Hao exit_bsg_job:
1396*5597088cSDongdong Hao 	bsg_job_done(job, rc, reslen);
1397*5597088cSDongdong Hao }
1398*5597088cSDongdong Hao 
1399*5597088cSDongdong Hao struct sas_function_template leapraid_transport_functions = {
1400*5597088cSDongdong Hao 	.smp_handler = leapraid_transport_smp_handler,
1401*5597088cSDongdong Hao };
1402*5597088cSDongdong Hao 
1403*5597088cSDongdong Hao struct scsi_transport_template *leapraid_transport_template;
1404