xref: /linux/drivers/scsi/mpi3mr/mpi3mr_transport.c (revision 8f5b5f78113e881cb8570c961b0dc42b218a1b9e)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Driver for Broadcom MPI3 Storage Controllers
4  *
5  * Copyright (C) 2017-2023 Broadcom Inc.
6  *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
7  *
8  */
9 
10 #include "mpi3mr.h"
11 
12 /**
13  * mpi3mr_post_transport_req - Issue transport requests and wait
14  * @mrioc: Adapter instance reference
15  * @request: Properly populated MPI3 request
16  * @request_sz: Size of the MPI3 request
17  * @reply: Pointer to return MPI3 reply
18  * @reply_sz: Size of the MPI3 reply buffer
19  * @timeout: Timeout in seconds
20  * @ioc_status: Pointer to return ioc status
21  *
22  * A generic function for posting MPI3 requests from the SAS
23  * transport layer that uses transport command infrastructure.
24  * This blocks for the completion of request for timeout seconds
25  * and if the request times out this function faults the
26  * controller with proper reason code.
27  *
28  * On successful completion of the request this function returns
29  * appropriate ioc status from the firmware back to the caller.
30  *
31  * Return: 0 on success, non-zero on failure.
32  */
33 static int mpi3mr_post_transport_req(struct mpi3mr_ioc *mrioc, void *request,
34 	u16 request_sz, void *reply, u16 reply_sz, int timeout,
35 	u16 *ioc_status)
36 {
37 	int retval = 0;
38 
39 	mutex_lock(&mrioc->transport_cmds.mutex);
40 	if (mrioc->transport_cmds.state & MPI3MR_CMD_PENDING) {
41 		retval = -1;
42 		ioc_err(mrioc, "sending transport request failed due to command in use\n");
43 		mutex_unlock(&mrioc->transport_cmds.mutex);
44 		goto out;
45 	}
46 	mrioc->transport_cmds.state = MPI3MR_CMD_PENDING;
47 	mrioc->transport_cmds.is_waiting = 1;
48 	mrioc->transport_cmds.callback = NULL;
49 	mrioc->transport_cmds.ioc_status = 0;
50 	mrioc->transport_cmds.ioc_loginfo = 0;
51 
52 	init_completion(&mrioc->transport_cmds.done);
53 	dprint_cfg_info(mrioc, "posting transport request\n");
54 	if (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO)
55 		dprint_dump(request, request_sz, "transport_req");
56 	retval = mpi3mr_admin_request_post(mrioc, request, request_sz, 1);
57 	if (retval) {
58 		ioc_err(mrioc, "posting transport request failed\n");
59 		goto out_unlock;
60 	}
61 	wait_for_completion_timeout(&mrioc->transport_cmds.done,
62 	    (timeout * HZ));
63 	if (!(mrioc->transport_cmds.state & MPI3MR_CMD_COMPLETE)) {
64 		mpi3mr_check_rh_fault_ioc(mrioc,
65 		    MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT);
66 		ioc_err(mrioc, "transport request timed out\n");
67 		retval = -1;
68 		goto out_unlock;
69 	}
70 	*ioc_status = mrioc->transport_cmds.ioc_status &
71 		MPI3_IOCSTATUS_STATUS_MASK;
72 	if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
73 		dprint_transport_err(mrioc,
74 		    "transport request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
75 		    *ioc_status, mrioc->transport_cmds.ioc_loginfo);
76 
77 	if ((reply) && (mrioc->transport_cmds.state & MPI3MR_CMD_REPLY_VALID))
78 		memcpy((u8 *)reply, mrioc->transport_cmds.reply, reply_sz);
79 
80 out_unlock:
81 	mrioc->transport_cmds.state = MPI3MR_CMD_NOTUSED;
82 	mutex_unlock(&mrioc->transport_cmds.mutex);
83 
84 out:
85 	return retval;
86 }
87 
88 /* report manufacture request structure */
89 struct rep_manu_request {
90 	u8 smp_frame_type;
91 	u8 function;
92 	u8 reserved;
93 	u8 request_length;
94 };
95 
96 /* report manufacture reply structure */
97 struct rep_manu_reply {
98 	u8 smp_frame_type; /* 0x41 */
99 	u8 function; /* 0x01 */
100 	u8 function_result;
101 	u8 response_length;
102 	u16 expander_change_count;
103 	u8 reserved0[2];
104 	u8 sas_format;
105 	u8 reserved2[3];
106 	u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
107 	u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
108 	u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
109 	u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
110 	u16 component_id;
111 	u8 component_revision_id;
112 	u8 reserved3;
113 	u8 vendor_specific[8];
114 };
115 
116 /**
117  * mpi3mr_report_manufacture - obtain SMP report_manufacture
118  * @mrioc: Adapter instance reference
119  * @sas_address: SAS address of the expander device
120  * @edev: SAS transport layer sas_expander_device object
121  * @port_id: ID of the HBA port
122  *
123  * Fills in the sas_expander_device with manufacturing info.
124  *
125  * Return: 0 for success, non-zero for failure.
126  */
127 static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
128 	u64 sas_address, struct sas_expander_device *edev, u8 port_id)
129 {
130 	struct mpi3_smp_passthrough_request mpi_request;
131 	struct mpi3_smp_passthrough_reply mpi_reply;
132 	struct rep_manu_reply *manufacture_reply;
133 	struct rep_manu_request *manufacture_request;
134 	int rc = 0;
135 	void *psge;
136 	void *data_out = NULL;
137 	dma_addr_t data_out_dma;
138 	dma_addr_t data_in_dma;
139 	size_t data_in_sz;
140 	size_t data_out_sz;
141 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
142 	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
143 	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
144 	u16 ioc_status;
145 	u8 *tmp;
146 
147 	if (mrioc->reset_in_progress) {
148 		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
149 		return -EFAULT;
150 	}
151 
152 	data_out_sz = sizeof(struct rep_manu_request);
153 	data_in_sz = sizeof(struct rep_manu_reply);
154 	data_out = dma_alloc_coherent(&mrioc->pdev->dev,
155 	    data_out_sz + data_in_sz, &data_out_dma, GFP_KERNEL);
156 	if (!data_out) {
157 		rc = -ENOMEM;
158 		goto out;
159 	}
160 
161 	data_in_dma = data_out_dma + data_out_sz;
162 	manufacture_reply = data_out + data_out_sz;
163 
164 	manufacture_request = data_out;
165 	manufacture_request->smp_frame_type = 0x40;
166 	manufacture_request->function = 1;
167 	manufacture_request->reserved = 0;
168 	manufacture_request->request_length = 0;
169 
170 	memset(&mpi_request, 0, request_sz);
171 	memset(&mpi_reply, 0, reply_sz);
172 	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
173 	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
174 	mpi_request.io_unit_port = (u8) port_id;
175 	mpi_request.sas_address = cpu_to_le64(sas_address);
176 
177 	psge = &mpi_request.request_sge;
178 	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
179 
180 	psge = &mpi_request.response_sge;
181 	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
182 
183 	dprint_transport_info(mrioc,
184 	    "sending report manufacturer SMP request to sas_address(0x%016llx), port(%d)\n",
185 	    (unsigned long long)sas_address, port_id);
186 
187 	rc = mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
188 				       &mpi_reply, reply_sz,
189 				       MPI3MR_INTADMCMD_TIMEOUT, &ioc_status);
190 	if (rc)
191 		goto out;
192 
193 	dprint_transport_info(mrioc,
194 	    "report manufacturer SMP request completed with ioc_status(0x%04x)\n",
195 	    ioc_status);
196 
197 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
198 		rc = -EINVAL;
199 		goto out;
200 	}
201 
202 	dprint_transport_info(mrioc,
203 	    "report manufacturer - reply data transfer size(%d)\n",
204 	    le16_to_cpu(mpi_reply.response_data_length));
205 
206 	if (le16_to_cpu(mpi_reply.response_data_length) !=
207 	    sizeof(struct rep_manu_reply)) {
208 		rc = -EINVAL;
209 		goto out;
210 	}
211 
212 	memtostr(edev->vendor_id, manufacture_reply->vendor_id);
213 	memtostr(edev->product_id, manufacture_reply->product_id);
214 	memtostr(edev->product_rev, manufacture_reply->product_rev);
215 	edev->level = manufacture_reply->sas_format & 1;
216 	if (edev->level) {
217 		memtostr(edev->component_vendor_id,
218 			 manufacture_reply->component_vendor_id);
219 		tmp = (u8 *)&manufacture_reply->component_id;
220 		edev->component_id = tmp[0] << 8 | tmp[1];
221 		edev->component_revision_id =
222 		    manufacture_reply->component_revision_id;
223 	}
224 
225 out:
226 	if (data_out)
227 		dma_free_coherent(&mrioc->pdev->dev, data_out_sz + data_in_sz,
228 		    data_out, data_out_dma);
229 
230 	return rc;
231 }
232 
233 /**
234  * __mpi3mr_expander_find_by_handle - expander search by handle
235  * @mrioc: Adapter instance reference
236  * @handle: Firmware device handle of the expander
237  *
238  * Context: The caller should acquire sas_node_lock
239  *
240  * This searches for expander device based on handle, then
241  * returns the sas_node object.
242  *
243  * Return: Expander sas_node object reference or NULL
244  */
245 struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc
246 	*mrioc, u16 handle)
247 {
248 	struct mpi3mr_sas_node *sas_expander, *r;
249 
250 	r = NULL;
251 	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
252 		if (sas_expander->handle != handle)
253 			continue;
254 		r = sas_expander;
255 		goto out;
256 	}
257  out:
258 	return r;
259 }
260 
261 /**
262  * mpi3mr_is_expander_device - if device is an expander
263  * @device_info: Bitfield providing information about the device
264  *
265  * Return: 1 if the device is expander device, else 0.
266  */
267 u8 mpi3mr_is_expander_device(u16 device_info)
268 {
269 	if ((device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) ==
270 	     MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER)
271 		return 1;
272 	else
273 		return 0;
274 }
275 
276 /**
277  * mpi3mr_get_sas_address - retrieve sas_address for handle
278  * @mrioc: Adapter instance reference
279  * @handle: Firmware device handle
280  * @sas_address: Address to hold sas address
281  *
282  * This function issues device page0 read for a given device
283  * handle and gets the SAS address and return it back
284  *
285  * Return: 0 for success, non-zero for failure
286  */
287 static int mpi3mr_get_sas_address(struct mpi3mr_ioc *mrioc, u16 handle,
288 	u64 *sas_address)
289 {
290 	struct mpi3_device_page0 dev_pg0;
291 	u16 ioc_status;
292 	struct mpi3_device0_sas_sata_format *sasinf;
293 
294 	*sas_address = 0;
295 
296 	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
297 	    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
298 	    handle))) {
299 		ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
300 		return -ENXIO;
301 	}
302 
303 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
304 		ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
305 		    handle, ioc_status, __FILE__, __LINE__, __func__);
306 		return -ENXIO;
307 	}
308 
309 	if (le16_to_cpu(dev_pg0.flags) &
310 	    MPI3_DEVICE0_FLAGS_CONTROLLER_DEV_HANDLE)
311 		*sas_address = mrioc->sas_hba.sas_address;
312 	else if (dev_pg0.device_form == MPI3_DEVICE_DEVFORM_SAS_SATA) {
313 		sasinf = &dev_pg0.device_specific.sas_sata_format;
314 		*sas_address = le64_to_cpu(sasinf->sas_address);
315 	} else {
316 		ioc_err(mrioc, "%s: device_form(%d) is not SAS_SATA\n",
317 		    __func__, dev_pg0.device_form);
318 		return -ENXIO;
319 	}
320 	return 0;
321 }
322 
323 /**
324  * __mpi3mr_get_tgtdev_by_addr - target device search
325  * @mrioc: Adapter instance reference
326  * @sas_address: SAS address of the device
327  * @hba_port: HBA port entry
328  *
329  * This searches for target device from sas address and hba port
330  * pointer then return mpi3mr_tgt_dev object.
331  *
332  * Return: Valid tget_dev or NULL
333  */
334 static struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc,
335 	u64 sas_address, struct mpi3mr_hba_port *hba_port)
336 {
337 	struct mpi3mr_tgt_dev *tgtdev;
338 
339 	assert_spin_locked(&mrioc->tgtdev_lock);
340 
341 	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
342 		if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&
343 		    (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)
344 		    && (tgtdev->dev_spec.sas_sata_inf.hba_port == hba_port))
345 			goto found_device;
346 	return NULL;
347 found_device:
348 	mpi3mr_tgtdev_get(tgtdev);
349 	return tgtdev;
350 }
351 
352 /**
353  * mpi3mr_get_tgtdev_by_addr - target device search
354  * @mrioc: Adapter instance reference
355  * @sas_address: SAS address of the device
356  * @hba_port: HBA port entry
357  *
358  * This searches for target device from sas address and hba port
359  * pointer then return mpi3mr_tgt_dev object.
360  *
361  * Context: This function will acquire tgtdev_lock and will
362  * release before returning the mpi3mr_tgt_dev object.
363  *
364  * Return: Valid tget_dev or NULL
365  */
366 static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc,
367 	u64 sas_address, struct mpi3mr_hba_port *hba_port)
368 {
369 	struct mpi3mr_tgt_dev *tgtdev = NULL;
370 	unsigned long flags;
371 
372 	if (!hba_port)
373 		goto out;
374 
375 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
376 	tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc, sas_address, hba_port);
377 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
378 
379 out:
380 	return tgtdev;
381 }
382 
383 /**
384  * mpi3mr_remove_device_by_sas_address - remove the device
385  * @mrioc: Adapter instance reference
386  * @sas_address: SAS address of the device
387  * @hba_port: HBA port entry
388  *
389  * This searches for target device using sas address and hba
390  * port pointer then removes it from the OS.
391  *
392  * Return: None
393  */
394 static void mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc,
395 	u64 sas_address, struct mpi3mr_hba_port *hba_port)
396 {
397 	struct mpi3mr_tgt_dev *tgtdev = NULL;
398 	unsigned long flags;
399 	u8 was_on_tgtdev_list = 0;
400 
401 	if (!hba_port)
402 		return;
403 
404 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
405 	tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc,
406 			 sas_address, hba_port);
407 	if (tgtdev) {
408 		if (!list_empty(&tgtdev->list)) {
409 			list_del_init(&tgtdev->list);
410 			was_on_tgtdev_list = 1;
411 			mpi3mr_tgtdev_put(tgtdev);
412 		}
413 	}
414 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
415 	if (was_on_tgtdev_list) {
416 		if (tgtdev->host_exposed)
417 			mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
418 		mpi3mr_tgtdev_put(tgtdev);
419 	}
420 }
421 
422 /**
423  * __mpi3mr_get_tgtdev_by_addr_and_rphy - target device search
424  * @mrioc: Adapter instance reference
425  * @sas_address: SAS address of the device
426  * @rphy: SAS transport layer rphy object
427  *
428  * This searches for target device from sas address and rphy
429  * pointer then return mpi3mr_tgt_dev object.
430  *
431  * Return: Valid tget_dev or NULL
432  */
433 struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
434 	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy)
435 {
436 	struct mpi3mr_tgt_dev *tgtdev;
437 
438 	assert_spin_locked(&mrioc->tgtdev_lock);
439 
440 	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
441 		if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&
442 		    (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)
443 		    && (tgtdev->dev_spec.sas_sata_inf.rphy == rphy))
444 			goto found_device;
445 	return NULL;
446 found_device:
447 	mpi3mr_tgtdev_get(tgtdev);
448 	return tgtdev;
449 }
450 
451 /**
452  * mpi3mr_expander_find_by_sas_address - sas expander search
453  * @mrioc: Adapter instance reference
454  * @sas_address: SAS address of expander
455  * @hba_port: HBA port entry
456  *
457  * Return: A valid SAS expander node or NULL.
458  *
459  */
460 static struct mpi3mr_sas_node *mpi3mr_expander_find_by_sas_address(
461 	struct mpi3mr_ioc *mrioc, u64 sas_address,
462 	struct mpi3mr_hba_port *hba_port)
463 {
464 	struct mpi3mr_sas_node *sas_expander, *r = NULL;
465 
466 	if (!hba_port)
467 		goto out;
468 
469 	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
470 		if ((sas_expander->sas_address != sas_address) ||
471 					 (sas_expander->hba_port != hba_port))
472 			continue;
473 		r = sas_expander;
474 		goto out;
475 	}
476 out:
477 	return r;
478 }
479 
480 /**
481  * __mpi3mr_sas_node_find_by_sas_address - sas node search
482  * @mrioc: Adapter instance reference
483  * @sas_address: SAS address of expander or sas host
484  * @hba_port: HBA port entry
485  * Context: Caller should acquire mrioc->sas_node_lock.
486  *
487  * If the SAS address indicates the device is direct attached to
488  * the controller (controller's SAS address) then the SAS node
489  * associated with the controller is returned back else the SAS
490  * address and hba port are used to identify the exact expander
491  * and the associated sas_node object is returned. If there is
492  * no match NULL is returned.
493  *
494  * Return: A valid SAS node or NULL.
495  *
496  */
497 static struct mpi3mr_sas_node *__mpi3mr_sas_node_find_by_sas_address(
498 	struct mpi3mr_ioc *mrioc, u64 sas_address,
499 	struct mpi3mr_hba_port *hba_port)
500 {
501 
502 	if (mrioc->sas_hba.sas_address == sas_address)
503 		return &mrioc->sas_hba;
504 	return mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
505 	    hba_port);
506 }
507 
508 /**
509  * mpi3mr_parent_present - Is parent present for a phy
510  * @mrioc: Adapter instance reference
511  * @phy: SAS transport layer phy object
512  *
513  * Return: 0 if parent is present else non-zero
514  */
515 static int mpi3mr_parent_present(struct mpi3mr_ioc *mrioc, struct sas_phy *phy)
516 {
517 	unsigned long flags;
518 	struct mpi3mr_hba_port *hba_port = phy->hostdata;
519 
520 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
521 	if (__mpi3mr_sas_node_find_by_sas_address(mrioc,
522 	    phy->identify.sas_address,
523 	    hba_port) == NULL) {
524 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
525 		return -1;
526 	}
527 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
528 	return 0;
529 }
530 
531 /**
532  * mpi3mr_convert_phy_link_rate -
533  * @link_rate: link rate as defined in the MPI header
534  *
535  * Convert link_rate from mpi format into sas_transport layer
536  * form.
537  *
538  * Return: A valid SAS transport layer defined link rate
539  */
540 static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
541 {
542 	enum sas_linkrate rc;
543 
544 	switch (link_rate) {
545 	case MPI3_SAS_NEG_LINK_RATE_1_5:
546 		rc = SAS_LINK_RATE_1_5_GBPS;
547 		break;
548 	case MPI3_SAS_NEG_LINK_RATE_3_0:
549 		rc = SAS_LINK_RATE_3_0_GBPS;
550 		break;
551 	case MPI3_SAS_NEG_LINK_RATE_6_0:
552 		rc = SAS_LINK_RATE_6_0_GBPS;
553 		break;
554 	case MPI3_SAS_NEG_LINK_RATE_12_0:
555 		rc = SAS_LINK_RATE_12_0_GBPS;
556 		break;
557 	case MPI3_SAS_NEG_LINK_RATE_22_5:
558 		rc = SAS_LINK_RATE_22_5_GBPS;
559 		break;
560 	case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:
561 		rc = SAS_PHY_DISABLED;
562 		break;
563 	case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
564 		rc = SAS_LINK_RATE_FAILED;
565 		break;
566 	case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:
567 		rc = SAS_SATA_PORT_SELECTOR;
568 		break;
569 	case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
570 		rc = SAS_PHY_RESET_IN_PROGRESS;
571 		break;
572 	case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
573 	case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
574 	default:
575 		rc = SAS_LINK_RATE_UNKNOWN;
576 		break;
577 	}
578 	return rc;
579 }
580 
581 /**
582  * mpi3mr_delete_sas_phy - Remove a single phy from port
583  * @mrioc: Adapter instance reference
584  * @mr_sas_port: Internal Port object
585  * @mr_sas_phy: Internal Phy object
586  *
587  * Return: None.
588  */
589 static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
590 	struct mpi3mr_sas_port *mr_sas_port,
591 	struct mpi3mr_sas_phy *mr_sas_phy)
592 {
593 	u64 sas_address = mr_sas_port->remote_identify.sas_address;
594 
595 	dev_info(&mr_sas_phy->phy->dev,
596 	    "remove: sas_address(0x%016llx), phy(%d)\n",
597 	    (unsigned long long) sas_address, mr_sas_phy->phy_id);
598 
599 	list_del(&mr_sas_phy->port_siblings);
600 	mr_sas_port->num_phys--;
601 	mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);
602 	if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)
603 		mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
604 	sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
605 	mr_sas_phy->phy_belongs_to_port = 0;
606 }
607 
608 /**
609  * mpi3mr_add_sas_phy - Adding a single phy to a port
610  * @mrioc: Adapter instance reference
611  * @mr_sas_port: Internal Port object
612  * @mr_sas_phy: Internal Phy object
613  *
614  * Return: None.
615  */
616 static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
617 	struct mpi3mr_sas_port *mr_sas_port,
618 	struct mpi3mr_sas_phy *mr_sas_phy)
619 {
620 	u64 sas_address = mr_sas_port->remote_identify.sas_address;
621 
622 	dev_info(&mr_sas_phy->phy->dev,
623 	    "add: sas_address(0x%016llx), phy(%d)\n", (unsigned long long)
624 	    sas_address, mr_sas_phy->phy_id);
625 
626 	list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
627 	mr_sas_port->num_phys++;
628 	mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);
629 	if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)
630 		mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
631 	sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
632 	mr_sas_phy->phy_belongs_to_port = 1;
633 }
634 
635 /**
636  * mpi3mr_add_phy_to_an_existing_port - add phy to existing port
637  * @mrioc: Adapter instance reference
638  * @mr_sas_node: Internal sas node object (expander or host)
639  * @mr_sas_phy: Internal Phy object *
640  * @sas_address: SAS address of device/expander were phy needs
641  *             to be added to
642  * @hba_port: HBA port entry
643  *
644  * Return: None.
645  */
646 static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,
647 	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy,
648 	u64 sas_address, struct mpi3mr_hba_port *hba_port)
649 {
650 	struct mpi3mr_sas_port *mr_sas_port;
651 	struct mpi3mr_sas_phy *srch_phy;
652 
653 	if (mr_sas_phy->phy_belongs_to_port == 1)
654 		return;
655 
656 	if (!hba_port)
657 		return;
658 
659 	list_for_each_entry(mr_sas_port, &mr_sas_node->sas_port_list,
660 	    port_list) {
661 		if (mr_sas_port->remote_identify.sas_address !=
662 		    sas_address)
663 			continue;
664 		if (mr_sas_port->hba_port != hba_port)
665 			continue;
666 		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
667 		    port_siblings) {
668 			if (srch_phy == mr_sas_phy)
669 				return;
670 		}
671 		mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy);
672 		return;
673 	}
674 }
675 
676 /**
677  * mpi3mr_delete_sas_port - helper function to removing a port
678  * @mrioc: Adapter instance reference
679  * @mr_sas_port: Internal Port object
680  *
681  * Return: None.
682  */
683 static void  mpi3mr_delete_sas_port(struct mpi3mr_ioc *mrioc,
684 	struct mpi3mr_sas_port *mr_sas_port)
685 {
686 	u64 sas_address = mr_sas_port->remote_identify.sas_address;
687 	struct mpi3mr_hba_port *hba_port = mr_sas_port->hba_port;
688 	enum sas_device_type device_type =
689 	    mr_sas_port->remote_identify.device_type;
690 
691 	dev_info(&mr_sas_port->port->dev,
692 	    "remove: sas_address(0x%016llx)\n",
693 	    (unsigned long long) sas_address);
694 
695 	if (device_type == SAS_END_DEVICE)
696 		mpi3mr_remove_device_by_sas_address(mrioc, sas_address,
697 		    hba_port);
698 
699 	else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
700 	    device_type == SAS_FANOUT_EXPANDER_DEVICE)
701 		mpi3mr_expander_remove(mrioc, sas_address, hba_port);
702 }
703 
704 /**
705  * mpi3mr_del_phy_from_an_existing_port - del phy from a port
706  * @mrioc: Adapter instance reference
707  * @mr_sas_node: Internal sas node object (expander or host)
708  * @mr_sas_phy: Internal Phy object
709  *
710  * Return: None.
711  */
712 static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
713 	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy)
714 {
715 	struct mpi3mr_sas_port *mr_sas_port, *next;
716 	struct mpi3mr_sas_phy *srch_phy;
717 
718 	if (mr_sas_phy->phy_belongs_to_port == 0)
719 		return;
720 
721 	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
722 	    port_list) {
723 		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
724 		    port_siblings) {
725 			if (srch_phy != mr_sas_phy)
726 				continue;
727 			if ((mr_sas_port->num_phys == 1) &&
728 			    !mrioc->reset_in_progress)
729 				mpi3mr_delete_sas_port(mrioc, mr_sas_port);
730 			else
731 				mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
732 				    mr_sas_phy);
733 			return;
734 		}
735 	}
736 }
737 
738 /**
739  * mpi3mr_sas_port_sanity_check - sanity check while adding port
740  * @mrioc: Adapter instance reference
741  * @mr_sas_node: Internal sas node object (expander or host)
742  * @sas_address: SAS address of device/expander
743  * @hba_port: HBA port entry
744  *
745  * Verifies whether the Phys attached to a device with the given
746  * SAS address already belongs to an existing sas port if so
747  * will remove those phys from the sas port
748  *
749  * Return: None.
750  */
751 static void mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc,
752 	struct mpi3mr_sas_node *mr_sas_node, u64 sas_address,
753 	struct mpi3mr_hba_port *hba_port)
754 {
755 	int i;
756 
757 	for (i = 0; i < mr_sas_node->num_phys; i++) {
758 		if ((mr_sas_node->phy[i].remote_identify.sas_address !=
759 		    sas_address) || (mr_sas_node->phy[i].hba_port != hba_port))
760 			continue;
761 		if (mr_sas_node->phy[i].phy_belongs_to_port == 1)
762 			mpi3mr_del_phy_from_an_existing_port(mrioc,
763 			    mr_sas_node, &mr_sas_node->phy[i]);
764 	}
765 }
766 
767 /**
768  * mpi3mr_set_identify - set identify for phys and end devices
769  * @mrioc: Adapter instance reference
770  * @handle: Firmware device handle
771  * @identify: SAS transport layer's identify info
772  *
773  * Populates sas identify info for a specific device.
774  *
775  * Return: 0 for success, non-zero for failure.
776  */
777 static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
778 	struct sas_identify *identify)
779 {
780 
781 	struct mpi3_device_page0 device_pg0;
782 	struct mpi3_device0_sas_sata_format *sasinf;
783 	u16 device_info;
784 	u16 ioc_status;
785 
786 	if (mrioc->reset_in_progress) {
787 		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
788 		return -EFAULT;
789 	}
790 
791 	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
792 	    sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {
793 		ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
794 		return -ENXIO;
795 	}
796 
797 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
798 		ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
799 		    handle, ioc_status, __FILE__, __LINE__, __func__);
800 		return -EIO;
801 	}
802 
803 	memset(identify, 0, sizeof(struct sas_identify));
804 	sasinf = &device_pg0.device_specific.sas_sata_format;
805 	device_info = le16_to_cpu(sasinf->device_info);
806 
807 	/* sas_address */
808 	identify->sas_address = le64_to_cpu(sasinf->sas_address);
809 
810 	/* phy number of the parent device this device is linked to */
811 	identify->phy_identifier = sasinf->phy_num;
812 
813 	/* device_type */
814 	switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) {
815 	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:
816 		identify->device_type = SAS_PHY_UNUSED;
817 		break;
818 	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:
819 		identify->device_type = SAS_END_DEVICE;
820 		break;
821 	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:
822 		identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
823 		break;
824 	}
825 
826 	/* initiator_port_protocols */
827 	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)
828 		identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
829 	/* MPI3.0 doesn't have define for SATA INIT so setting both here*/
830 	if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)
831 		identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |
832 		    SAS_PROTOCOL_SATA);
833 	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)
834 		identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
835 
836 	/* target_port_protocols */
837 	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)
838 		identify->target_port_protocols |= SAS_PROTOCOL_SSP;
839 	/* MPI3.0 doesn't have define for STP Target so setting both here*/
840 	if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)
841 		identify->target_port_protocols |= (SAS_PROTOCOL_STP |
842 		    SAS_PROTOCOL_SATA);
843 	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)
844 		identify->target_port_protocols |= SAS_PROTOCOL_SMP;
845 	return 0;
846 }
847 
848 /**
849  * mpi3mr_add_host_phy - report sas_host phy to SAS transport
850  * @mrioc: Adapter instance reference
851  * @mr_sas_phy: Internal Phy object
852  * @phy_pg0: SAS phy page 0
853  * @parent_dev: Prent device class object
854  *
855  * Return: 0 for success, non-zero for failure.
856  */
857 static int mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc,
858 	struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0,
859 	struct device *parent_dev)
860 {
861 	struct sas_phy *phy;
862 	int phy_index = mr_sas_phy->phy_id;
863 
864 
865 	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
866 	phy = sas_phy_alloc(parent_dev, phy_index);
867 	if (!phy) {
868 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
869 		    __FILE__, __LINE__, __func__);
870 		return -1;
871 	}
872 	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
873 	    &mr_sas_phy->identify))) {
874 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
875 		    __FILE__, __LINE__, __func__);
876 		sas_phy_free(phy);
877 		return -1;
878 	}
879 	phy->identify = mr_sas_phy->identify;
880 	mr_sas_phy->attached_handle = le16_to_cpu(phy_pg0.attached_dev_handle);
881 	if (mr_sas_phy->attached_handle)
882 		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
883 		    &mr_sas_phy->remote_identify);
884 	phy->identify.phy_identifier = mr_sas_phy->phy_id;
885 	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
886 	    (phy_pg0.negotiated_link_rate &
887 	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
888 	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
889 	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
890 	    phy_pg0.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
891 	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
892 	    phy_pg0.hw_link_rate >> 4);
893 	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
894 	    phy_pg0.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
895 	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
896 	    phy_pg0.programmed_link_rate >> 4);
897 	phy->hostdata = mr_sas_phy->hba_port;
898 
899 	if ((sas_phy_add(phy))) {
900 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
901 		    __FILE__, __LINE__, __func__);
902 		sas_phy_free(phy);
903 		return -1;
904 	}
905 	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
906 		dev_info(&phy->dev,
907 		    "add: handle(0x%04x), sas_address(0x%016llx)\n"
908 		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
909 		    mr_sas_phy->handle, (unsigned long long)
910 		    mr_sas_phy->identify.sas_address,
911 		    mr_sas_phy->attached_handle,
912 		    (unsigned long long)
913 		    mr_sas_phy->remote_identify.sas_address);
914 	mr_sas_phy->phy = phy;
915 	return 0;
916 }
917 
918 /**
919  * mpi3mr_add_expander_phy - report expander phy to transport
920  * @mrioc: Adapter instance reference
921  * @mr_sas_phy: Internal Phy object
922  * @expander_pg1: SAS Expander page 1
923  * @parent_dev: Parent device class object
924  *
925  * Return: 0 for success, non-zero for failure.
926  */
927 static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc,
928 	struct mpi3mr_sas_phy *mr_sas_phy,
929 	struct mpi3_sas_expander_page1 expander_pg1,
930 	struct device *parent_dev)
931 {
932 	struct sas_phy *phy;
933 	int phy_index = mr_sas_phy->phy_id;
934 
935 	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
936 	phy = sas_phy_alloc(parent_dev, phy_index);
937 	if (!phy) {
938 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
939 		    __FILE__, __LINE__, __func__);
940 		return -1;
941 	}
942 	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
943 	    &mr_sas_phy->identify))) {
944 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
945 		    __FILE__, __LINE__, __func__);
946 		sas_phy_free(phy);
947 		return -1;
948 	}
949 	phy->identify = mr_sas_phy->identify;
950 	mr_sas_phy->attached_handle =
951 	    le16_to_cpu(expander_pg1.attached_dev_handle);
952 	if (mr_sas_phy->attached_handle)
953 		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
954 		    &mr_sas_phy->remote_identify);
955 	phy->identify.phy_identifier = mr_sas_phy->phy_id;
956 	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
957 	    (expander_pg1.negotiated_link_rate &
958 	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
959 	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
960 	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
961 	    expander_pg1.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
962 	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
963 	    expander_pg1.hw_link_rate >> 4);
964 	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
965 	    expander_pg1.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
966 	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
967 	    expander_pg1.programmed_link_rate >> 4);
968 	phy->hostdata = mr_sas_phy->hba_port;
969 
970 	if ((sas_phy_add(phy))) {
971 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
972 		    __FILE__, __LINE__, __func__);
973 		sas_phy_free(phy);
974 		return -1;
975 	}
976 	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
977 		dev_info(&phy->dev,
978 		    "add: handle(0x%04x), sas_address(0x%016llx)\n"
979 		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
980 		    mr_sas_phy->handle, (unsigned long long)
981 		    mr_sas_phy->identify.sas_address,
982 		    mr_sas_phy->attached_handle,
983 		    (unsigned long long)
984 		    mr_sas_phy->remote_identify.sas_address);
985 	mr_sas_phy->phy = phy;
986 	return 0;
987 }
988 
989 /**
990  * mpi3mr_alloc_hba_port - alloc hba port object
991  * @mrioc: Adapter instance reference
992  * @port_id: Port number
993  *
994  * Alloc memory for hba port object.
995  */
996 static struct mpi3mr_hba_port *
997 mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)
998 {
999 	struct mpi3mr_hba_port *hba_port;
1000 
1001 	hba_port = kzalloc(sizeof(struct mpi3mr_hba_port),
1002 	    GFP_KERNEL);
1003 	if (!hba_port)
1004 		return NULL;
1005 	hba_port->port_id = port_id;
1006 	ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
1007 	    hba_port, hba_port->port_id);
1008 	list_add_tail(&hba_port->list, &mrioc->hba_port_table_list);
1009 	return hba_port;
1010 }
1011 
1012 /**
1013  * mpi3mr_get_hba_port_by_id - find hba port by id
1014  * @mrioc: Adapter instance reference
1015  * @port_id - Port ID to search
1016  *
1017  * Return: mpi3mr_hba_port reference for the matched port
1018  */
1019 
1020 struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,
1021 	u8 port_id)
1022 {
1023 	struct mpi3mr_hba_port *port, *port_next;
1024 
1025 	list_for_each_entry_safe(port, port_next,
1026 	    &mrioc->hba_port_table_list, list) {
1027 		if (port->port_id != port_id)
1028 			continue;
1029 		if (port->flags & MPI3MR_HBA_PORT_FLAG_DIRTY)
1030 			continue;
1031 		return port;
1032 	}
1033 
1034 	return NULL;
1035 }
1036 
1037 /**
1038  * mpi3mr_update_links - refreshing SAS phy link changes
1039  * @mrioc: Adapter instance reference
1040  * @sas_address_parent: SAS address of parent expander or host
1041  * @handle: Firmware device handle of attached device
1042  * @phy_number: Phy number
1043  * @link_rate: New link rate
1044  * @hba_port: HBA port entry
1045  *
1046  * Return: None.
1047  */
1048 void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
1049 	u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate,
1050 	struct mpi3mr_hba_port *hba_port)
1051 {
1052 	unsigned long flags;
1053 	struct mpi3mr_sas_node *mr_sas_node;
1054 	struct mpi3mr_sas_phy *mr_sas_phy;
1055 
1056 	if (mrioc->reset_in_progress)
1057 		return;
1058 
1059 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1060 	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1061 	    sas_address_parent, hba_port);
1062 	if (!mr_sas_node) {
1063 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1064 		return;
1065 	}
1066 
1067 	mr_sas_phy = &mr_sas_node->phy[phy_number];
1068 	mr_sas_phy->attached_handle = handle;
1069 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1070 	if (handle && (link_rate >= MPI3_SAS_NEG_LINK_RATE_1_5)) {
1071 		mpi3mr_set_identify(mrioc, handle,
1072 		    &mr_sas_phy->remote_identify);
1073 		mpi3mr_add_phy_to_an_existing_port(mrioc, mr_sas_node,
1074 		    mr_sas_phy, mr_sas_phy->remote_identify.sas_address,
1075 		    hba_port);
1076 	} else
1077 		memset(&mr_sas_phy->remote_identify, 0, sizeof(struct
1078 		    sas_identify));
1079 
1080 	if (mr_sas_phy->phy)
1081 		mr_sas_phy->phy->negotiated_linkrate =
1082 		    mpi3mr_convert_phy_link_rate(link_rate);
1083 
1084 	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1085 		dev_info(&mr_sas_phy->phy->dev,
1086 		    "refresh: parent sas_address(0x%016llx),\n"
1087 		    "\tlink_rate(0x%02x), phy(%d)\n"
1088 		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
1089 		    (unsigned long long)sas_address_parent,
1090 		    link_rate, phy_number, handle, (unsigned long long)
1091 		    mr_sas_phy->remote_identify.sas_address);
1092 }
1093 
1094 /**
1095  * mpi3mr_sas_host_refresh - refreshing sas host object contents
1096  * @mrioc: Adapter instance reference
1097  *
1098  * This function refreshes the controllers phy information and
1099  * updates the SAS transport layer with updated information,
1100  * this is executed for each device addition or device info
1101  * change events
1102  *
1103  * Return: None.
1104  */
1105 void mpi3mr_sas_host_refresh(struct mpi3mr_ioc *mrioc)
1106 {
1107 	int i;
1108 	u8 link_rate;
1109 	u16 sz, port_id, attached_handle;
1110 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1111 
1112 	dprint_transport_info(mrioc,
1113 	    "updating handles for sas_host(0x%016llx)\n",
1114 	    (unsigned long long)mrioc->sas_hba.sas_address);
1115 
1116 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1117 	    (mrioc->sas_hba.num_phys *
1118 	     sizeof(struct mpi3_sas_io_unit0_phy_data));
1119 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1120 	if (!sas_io_unit_pg0)
1121 		return;
1122 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1123 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1124 		    __FILE__, __LINE__, __func__);
1125 		goto out;
1126 	}
1127 
1128 	mrioc->sas_hba.handle = 0;
1129 	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1130 		if (sas_io_unit_pg0->phy_data[i].phy_flags &
1131 		    (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
1132 		     MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
1133 			continue;
1134 		link_rate =
1135 		    sas_io_unit_pg0->phy_data[i].negotiated_link_rate >> 4;
1136 		if (!mrioc->sas_hba.handle)
1137 			mrioc->sas_hba.handle = le16_to_cpu(
1138 			    sas_io_unit_pg0->phy_data[i].controller_dev_handle);
1139 		port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1140 		if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
1141 			if (!mpi3mr_alloc_hba_port(mrioc, port_id))
1142 				goto out;
1143 
1144 		mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
1145 		attached_handle = le16_to_cpu(
1146 		    sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1147 		if (attached_handle && link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)
1148 			link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;
1149 		mrioc->sas_hba.phy[i].hba_port =
1150 			mpi3mr_get_hba_port_by_id(mrioc, port_id);
1151 		mpi3mr_update_links(mrioc, mrioc->sas_hba.sas_address,
1152 		    attached_handle, i, link_rate,
1153 		    mrioc->sas_hba.phy[i].hba_port);
1154 	}
1155  out:
1156 	kfree(sas_io_unit_pg0);
1157 }
1158 
1159 /**
1160  * mpi3mr_sas_host_add - create sas host object
1161  * @mrioc: Adapter instance reference
1162  *
1163  * This function creates the controllers phy information and
1164  * updates the SAS transport layer with updated information,
1165  * this is executed for first device addition or device info
1166  * change event.
1167  *
1168  * Return: None.
1169  */
1170 void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
1171 {
1172 	int i;
1173 	u16 sz, num_phys = 1, port_id, ioc_status;
1174 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1175 	struct mpi3_sas_phy_page0 phy_pg0;
1176 	struct mpi3_device_page0 dev_pg0;
1177 	struct mpi3_enclosure_page0 encl_pg0;
1178 	struct mpi3_device0_sas_sata_format *sasinf;
1179 
1180 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1181 	    (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
1182 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1183 	if (!sas_io_unit_pg0)
1184 		return;
1185 
1186 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1187 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1188 		    __FILE__, __LINE__, __func__);
1189 		goto out;
1190 	}
1191 	num_phys = sas_io_unit_pg0->num_phys;
1192 	kfree(sas_io_unit_pg0);
1193 
1194 	mrioc->sas_hba.host_node = 1;
1195 	INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list);
1196 	mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev;
1197 	mrioc->sas_hba.phy = kcalloc(num_phys,
1198 	    sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);
1199 	if (!mrioc->sas_hba.phy)
1200 		return;
1201 
1202 	mrioc->sas_hba.num_phys = num_phys;
1203 
1204 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1205 	    (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
1206 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1207 	if (!sas_io_unit_pg0)
1208 		return;
1209 
1210 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1211 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1212 		    __FILE__, __LINE__, __func__);
1213 		goto out;
1214 	}
1215 
1216 	mrioc->sas_hba.handle = 0;
1217 	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1218 		if (sas_io_unit_pg0->phy_data[i].phy_flags &
1219 		    (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
1220 		    MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
1221 			continue;
1222 		if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
1223 		    sizeof(struct mpi3_sas_phy_page0),
1224 		    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, i)) {
1225 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1226 			    __FILE__, __LINE__, __func__);
1227 			goto out;
1228 		}
1229 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1230 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1231 			    __FILE__, __LINE__, __func__);
1232 			goto out;
1233 		}
1234 
1235 		if (!mrioc->sas_hba.handle)
1236 			mrioc->sas_hba.handle = le16_to_cpu(
1237 			    sas_io_unit_pg0->phy_data[i].controller_dev_handle);
1238 		port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1239 
1240 		if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
1241 			if (!mpi3mr_alloc_hba_port(mrioc, port_id))
1242 				goto out;
1243 
1244 		mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
1245 		mrioc->sas_hba.phy[i].phy_id = i;
1246 		mrioc->sas_hba.phy[i].hba_port =
1247 		    mpi3mr_get_hba_port_by_id(mrioc, port_id);
1248 		mpi3mr_add_host_phy(mrioc, &mrioc->sas_hba.phy[i],
1249 		    phy_pg0, mrioc->sas_hba.parent_dev);
1250 	}
1251 	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
1252 	    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
1253 	    mrioc->sas_hba.handle))) {
1254 		ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
1255 		goto out;
1256 	}
1257 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1258 		ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
1259 		    mrioc->sas_hba.handle, ioc_status, __FILE__, __LINE__,
1260 		    __func__);
1261 		goto out;
1262 	}
1263 	mrioc->sas_hba.enclosure_handle =
1264 	    le16_to_cpu(dev_pg0.enclosure_handle);
1265 	sasinf = &dev_pg0.device_specific.sas_sata_format;
1266 	mrioc->sas_hba.sas_address =
1267 	    le64_to_cpu(sasinf->sas_address);
1268 	ioc_info(mrioc,
1269 	    "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
1270 	    mrioc->sas_hba.handle,
1271 	    (unsigned long long) mrioc->sas_hba.sas_address,
1272 	    mrioc->sas_hba.num_phys);
1273 
1274 	if (mrioc->sas_hba.enclosure_handle) {
1275 		if (!(mpi3mr_cfg_get_enclosure_pg0(mrioc, &ioc_status,
1276 		    &encl_pg0, sizeof(encl_pg0),
1277 		    MPI3_ENCLOS_PGAD_FORM_HANDLE,
1278 		    mrioc->sas_hba.enclosure_handle)) &&
1279 		    (ioc_status == MPI3_IOCSTATUS_SUCCESS))
1280 			mrioc->sas_hba.enclosure_logical_id =
1281 				le64_to_cpu(encl_pg0.enclosure_logical_id);
1282 	}
1283 
1284 out:
1285 	kfree(sas_io_unit_pg0);
1286 }
1287 
1288 /**
1289  * mpi3mr_sas_port_add - Expose the SAS device to the SAS TL
1290  * @mrioc: Adapter instance reference
1291  * @handle: Firmware device handle of the attached device
1292  * @sas_address_parent: sas address of parent expander or host
1293  * @hba_port: HBA port entry
1294  *
1295  * This function creates a new sas port object for the given end
1296  * device matching sas address and hba_port and adds it to the
1297  * sas_node's sas_port_list and expose the attached sas device
1298  * to the SAS transport layer through sas_rphy_add.
1299  *
1300  * Returns a valid mpi3mr_sas_port reference or NULL.
1301  */
1302 static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
1303 	u16 handle, u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
1304 {
1305 	struct mpi3mr_sas_phy *mr_sas_phy, *next;
1306 	struct mpi3mr_sas_port *mr_sas_port;
1307 	unsigned long flags;
1308 	struct mpi3mr_sas_node *mr_sas_node;
1309 	struct sas_rphy *rphy;
1310 	struct mpi3mr_tgt_dev *tgtdev = NULL;
1311 	int i;
1312 	struct sas_port *port;
1313 
1314 	if (!hba_port) {
1315 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1316 		    __FILE__, __LINE__, __func__);
1317 		return NULL;
1318 	}
1319 
1320 	mr_sas_port = kzalloc(sizeof(struct mpi3mr_sas_port), GFP_KERNEL);
1321 	if (!mr_sas_port)
1322 		return NULL;
1323 
1324 	INIT_LIST_HEAD(&mr_sas_port->port_list);
1325 	INIT_LIST_HEAD(&mr_sas_port->phy_list);
1326 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1327 	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1328 	    sas_address_parent, hba_port);
1329 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1330 
1331 	if (!mr_sas_node) {
1332 		ioc_err(mrioc, "%s:could not find parent sas_address(0x%016llx)!\n",
1333 		    __func__, (unsigned long long)sas_address_parent);
1334 		goto out_fail;
1335 	}
1336 
1337 	if ((mpi3mr_set_identify(mrioc, handle,
1338 	    &mr_sas_port->remote_identify))) {
1339 		ioc_err(mrioc,  "failure at %s:%d/%s()!\n",
1340 		    __FILE__, __LINE__, __func__);
1341 		goto out_fail;
1342 	}
1343 
1344 	if (mr_sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
1345 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1346 		    __FILE__, __LINE__, __func__);
1347 		goto out_fail;
1348 	}
1349 
1350 	mr_sas_port->hba_port = hba_port;
1351 	mpi3mr_sas_port_sanity_check(mrioc, mr_sas_node,
1352 	    mr_sas_port->remote_identify.sas_address, hba_port);
1353 
1354 	for (i = 0; i < mr_sas_node->num_phys; i++) {
1355 		if ((mr_sas_node->phy[i].remote_identify.sas_address !=
1356 		    mr_sas_port->remote_identify.sas_address) ||
1357 		    (mr_sas_node->phy[i].hba_port != hba_port))
1358 			continue;
1359 		list_add_tail(&mr_sas_node->phy[i].port_siblings,
1360 		    &mr_sas_port->phy_list);
1361 		mr_sas_port->num_phys++;
1362 		mr_sas_port->phy_mask |= (1 << i);
1363 	}
1364 
1365 	if (!mr_sas_port->num_phys) {
1366 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1367 		    __FILE__, __LINE__, __func__);
1368 		goto out_fail;
1369 	}
1370 
1371 	mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
1372 
1373 	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1374 		tgtdev = mpi3mr_get_tgtdev_by_addr(mrioc,
1375 		    mr_sas_port->remote_identify.sas_address,
1376 		    mr_sas_port->hba_port);
1377 
1378 		if (!tgtdev) {
1379 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1380 			    __FILE__, __LINE__, __func__);
1381 			goto out_fail;
1382 		}
1383 		tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 1;
1384 	}
1385 
1386 	if (!mr_sas_node->parent_dev) {
1387 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1388 		    __FILE__, __LINE__, __func__);
1389 		goto out_fail;
1390 	}
1391 
1392 	port = sas_port_alloc_num(mr_sas_node->parent_dev);
1393 	if ((sas_port_add(port))) {
1394 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1395 		    __FILE__, __LINE__, __func__);
1396 		goto out_fail;
1397 	}
1398 
1399 	list_for_each_entry(mr_sas_phy, &mr_sas_port->phy_list,
1400 	    port_siblings) {
1401 		if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1402 			dev_info(&port->dev,
1403 			    "add: handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
1404 			    handle, (unsigned long long)
1405 			    mr_sas_port->remote_identify.sas_address,
1406 			    mr_sas_phy->phy_id);
1407 		sas_port_add_phy(port, mr_sas_phy->phy);
1408 		mr_sas_phy->phy_belongs_to_port = 1;
1409 		mr_sas_phy->hba_port = hba_port;
1410 	}
1411 
1412 	mr_sas_port->port = port;
1413 	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1414 		rphy = sas_end_device_alloc(port);
1415 		tgtdev->dev_spec.sas_sata_inf.rphy = rphy;
1416 	} else {
1417 		rphy = sas_expander_alloc(port,
1418 		    mr_sas_port->remote_identify.device_type);
1419 	}
1420 	rphy->identify = mr_sas_port->remote_identify;
1421 
1422 	if (mrioc->current_event)
1423 		mrioc->current_event->pending_at_sml = 1;
1424 
1425 	if ((sas_rphy_add(rphy))) {
1426 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1427 		    __FILE__, __LINE__, __func__);
1428 	}
1429 	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1430 		tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;
1431 		tgtdev->dev_spec.sas_sata_inf.sas_transport_attached = 1;
1432 		mpi3mr_tgtdev_put(tgtdev);
1433 	}
1434 
1435 	dev_info(&rphy->dev,
1436 	    "%s: added: handle(0x%04x), sas_address(0x%016llx)\n",
1437 	    __func__, handle, (unsigned long long)
1438 	    mr_sas_port->remote_identify.sas_address);
1439 
1440 	mr_sas_port->rphy = rphy;
1441 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1442 	list_add_tail(&mr_sas_port->port_list, &mr_sas_node->sas_port_list);
1443 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1444 
1445 	if (mrioc->current_event) {
1446 		mrioc->current_event->pending_at_sml = 0;
1447 		if (mrioc->current_event->discard)
1448 			mpi3mr_print_device_event_notice(mrioc, true);
1449 	}
1450 
1451 	/* fill in report manufacture */
1452 	if (mr_sas_port->remote_identify.device_type ==
1453 	    SAS_EDGE_EXPANDER_DEVICE ||
1454 	    mr_sas_port->remote_identify.device_type ==
1455 	    SAS_FANOUT_EXPANDER_DEVICE)
1456 		mpi3mr_report_manufacture(mrioc,
1457 		    mr_sas_port->remote_identify.sas_address,
1458 		    rphy_to_expander_device(rphy), hba_port->port_id);
1459 
1460 	return mr_sas_port;
1461 
1462  out_fail:
1463 	list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,
1464 	    port_siblings)
1465 		list_del(&mr_sas_phy->port_siblings);
1466 	kfree(mr_sas_port);
1467 	return NULL;
1468 }
1469 
1470 /**
1471  * mpi3mr_sas_port_remove - remove port from the list
1472  * @mrioc: Adapter instance reference
1473  * @sas_address: SAS address of attached device
1474  * @sas_address_parent: SAS address of parent expander or host
1475  * @hba_port: HBA port entry
1476  *
1477  * Removing object and freeing associated memory from the
1478  * sas_port_list.
1479  *
1480  * Return: None
1481  */
1482 static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
1483 	u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
1484 {
1485 	int i;
1486 	unsigned long flags;
1487 	struct mpi3mr_sas_port *mr_sas_port, *next;
1488 	struct mpi3mr_sas_node *mr_sas_node;
1489 	u8 found = 0;
1490 	struct mpi3mr_sas_phy *mr_sas_phy, *next_phy;
1491 	struct mpi3mr_hba_port *srch_port, *hba_port_next = NULL;
1492 
1493 	if (!hba_port)
1494 		return;
1495 
1496 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1497 	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1498 	    sas_address_parent, hba_port);
1499 	if (!mr_sas_node) {
1500 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1501 		return;
1502 	}
1503 	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
1504 	    port_list) {
1505 		if (mr_sas_port->remote_identify.sas_address != sas_address)
1506 			continue;
1507 		if (mr_sas_port->hba_port != hba_port)
1508 			continue;
1509 		found = 1;
1510 		list_del(&mr_sas_port->port_list);
1511 		goto out;
1512 	}
1513 
1514  out:
1515 	if (!found) {
1516 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1517 		return;
1518 	}
1519 
1520 	if (mr_sas_node->host_node) {
1521 		list_for_each_entry_safe(srch_port, hba_port_next,
1522 		    &mrioc->hba_port_table_list, list) {
1523 			if (srch_port != hba_port)
1524 				continue;
1525 			ioc_info(mrioc,
1526 			    "removing hba_port entry: %p port: %d from hba_port list\n",
1527 			    srch_port, srch_port->port_id);
1528 			list_del(&hba_port->list);
1529 			kfree(hba_port);
1530 			break;
1531 		}
1532 	}
1533 
1534 	for (i = 0; i < mr_sas_node->num_phys; i++) {
1535 		if (mr_sas_node->phy[i].remote_identify.sas_address ==
1536 		    sas_address)
1537 			memset(&mr_sas_node->phy[i].remote_identify, 0,
1538 			    sizeof(struct sas_identify));
1539 	}
1540 
1541 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1542 
1543 	if (mrioc->current_event)
1544 		mrioc->current_event->pending_at_sml = 1;
1545 
1546 	list_for_each_entry_safe(mr_sas_phy, next_phy,
1547 	    &mr_sas_port->phy_list, port_siblings) {
1548 		if ((!mrioc->stop_drv_processing) &&
1549 		    (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1550 			dev_info(&mr_sas_port->port->dev,
1551 			    "remove: sas_address(0x%016llx), phy(%d)\n",
1552 			    (unsigned long long)
1553 			    mr_sas_port->remote_identify.sas_address,
1554 			    mr_sas_phy->phy_id);
1555 		mr_sas_phy->phy_belongs_to_port = 0;
1556 		if (!mrioc->stop_drv_processing)
1557 			sas_port_delete_phy(mr_sas_port->port,
1558 			    mr_sas_phy->phy);
1559 		list_del(&mr_sas_phy->port_siblings);
1560 	}
1561 	if (!mrioc->stop_drv_processing)
1562 		sas_port_delete(mr_sas_port->port);
1563 	ioc_info(mrioc, "%s: removed sas_address(0x%016llx)\n",
1564 	    __func__, (unsigned long long)sas_address);
1565 
1566 	if (mrioc->current_event) {
1567 		mrioc->current_event->pending_at_sml = 0;
1568 		if (mrioc->current_event->discard)
1569 			mpi3mr_print_device_event_notice(mrioc, false);
1570 	}
1571 
1572 	kfree(mr_sas_port);
1573 }
1574 
1575 /**
1576  * struct host_port - host port details
1577  * @sas_address: SAS Address of the attached device
1578  * @phy_mask: phy mask of host port
1579  * @handle: Device Handle of attached device
1580  * @iounit_port_id: port ID
1581  * @used: host port is already matched with sas port from sas_port_list
1582  * @lowest_phy: lowest phy ID of host port
1583  */
1584 struct host_port {
1585 	u64	sas_address;
1586 	u64	phy_mask;
1587 	u16	handle;
1588 	u8	iounit_port_id;
1589 	u8	used;
1590 	u8	lowest_phy;
1591 };
1592 
1593 /**
1594  * mpi3mr_update_mr_sas_port - update sas port objects during reset
1595  * @mrioc: Adapter instance reference
1596  * @h_port: host_port object
1597  * @mr_sas_port: sas_port objects which needs to be updated
1598  *
1599  * Update the port ID of sas port object. Also add the phys if new phys got
1600  * added to current sas port and remove the phys if some phys are moved
1601  * out of the current sas port.
1602  *
1603  * Return: Nothing.
1604  */
1605 static void
1606 mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port,
1607 	struct mpi3mr_sas_port *mr_sas_port)
1608 {
1609 	struct mpi3mr_sas_phy *mr_sas_phy;
1610 	u64 phy_mask_xor;
1611 	u64 phys_to_be_added, phys_to_be_removed;
1612 	int i;
1613 
1614 	h_port->used = 1;
1615 	mr_sas_port->marked_responding = 1;
1616 
1617 	dev_info(&mr_sas_port->port->dev,
1618 	    "sas_address(0x%016llx), old: port_id %d phy_mask 0x%llx, new: port_id %d phy_mask:0x%llx\n",
1619 	    mr_sas_port->remote_identify.sas_address,
1620 	    mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask,
1621 	    h_port->iounit_port_id, h_port->phy_mask);
1622 
1623 	mr_sas_port->hba_port->port_id = h_port->iounit_port_id;
1624 	mr_sas_port->hba_port->flags &= ~MPI3MR_HBA_PORT_FLAG_DIRTY;
1625 
1626 	/* Get the newly added phys bit map & removed phys bit map */
1627 	phy_mask_xor = mr_sas_port->phy_mask ^ h_port->phy_mask;
1628 	phys_to_be_added = h_port->phy_mask & phy_mask_xor;
1629 	phys_to_be_removed = mr_sas_port->phy_mask & phy_mask_xor;
1630 
1631 	/*
1632 	 * Register these new phys to current mr_sas_port's port.
1633 	 * if these phys are previously registered with another port
1634 	 * then delete these phys from that port first.
1635 	 */
1636 	for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u64)) {
1637 		mr_sas_phy = &mrioc->sas_hba.phy[i];
1638 		if (mr_sas_phy->phy_belongs_to_port)
1639 			mpi3mr_del_phy_from_an_existing_port(mrioc,
1640 			    &mrioc->sas_hba, mr_sas_phy);
1641 		mpi3mr_add_phy_to_an_existing_port(mrioc,
1642 		    &mrioc->sas_hba, mr_sas_phy,
1643 		    mr_sas_port->remote_identify.sas_address,
1644 		    mr_sas_port->hba_port);
1645 	}
1646 
1647 	/* Delete the phys which are not part of current mr_sas_port's port. */
1648 	for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u64)) {
1649 		mr_sas_phy = &mrioc->sas_hba.phy[i];
1650 		if (mr_sas_phy->phy_belongs_to_port)
1651 			mpi3mr_del_phy_from_an_existing_port(mrioc,
1652 			    &mrioc->sas_hba, mr_sas_phy);
1653 	}
1654 }
1655 
1656 /**
1657  * mpi3mr_refresh_sas_ports - update host's sas ports during reset
1658  * @mrioc: Adapter instance reference
1659  *
1660  * Update the host's sas ports during reset by checking whether
1661  * sas ports are still intact or not. Add/remove phys if any hba
1662  * phys are (moved in)/(moved out) of sas port. Also update
1663  * io_unit_port if it got changed during reset.
1664  *
1665  * Return: Nothing.
1666  */
1667 void
1668 mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
1669 {
1670 	struct host_port *h_port = NULL;
1671 	int i, j, found, host_port_count = 0, port_idx;
1672 	u16 sz, attached_handle, ioc_status;
1673 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1674 	struct mpi3_device_page0 dev_pg0;
1675 	struct mpi3_device0_sas_sata_format *sasinf;
1676 	struct mpi3mr_sas_port *mr_sas_port;
1677 
1678 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1679 		(mrioc->sas_hba.num_phys *
1680 		 sizeof(struct mpi3_sas_io_unit0_phy_data));
1681 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1682 	if (!sas_io_unit_pg0)
1683 		return;
1684 	h_port = kcalloc(64, sizeof(struct host_port), GFP_KERNEL);
1685 	if (!h_port)
1686 		goto out;
1687 
1688 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1689 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1690 		    __FILE__, __LINE__, __func__);
1691 		goto out;
1692 	}
1693 
1694 	/* Create a new expander port table */
1695 	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1696 		attached_handle = le16_to_cpu(
1697 		    sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1698 		if (!attached_handle)
1699 			continue;
1700 		found = 0;
1701 		for (j = 0; j < host_port_count; j++) {
1702 			if (h_port[j].handle == attached_handle) {
1703 				h_port[j].phy_mask |= (1 << i);
1704 				found = 1;
1705 				break;
1706 			}
1707 		}
1708 		if (found)
1709 			continue;
1710 		if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
1711 		    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
1712 		    attached_handle))) {
1713 			dprint_reset(mrioc,
1714 			    "failed to read dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1715 			    attached_handle, __FILE__, __LINE__, __func__);
1716 			continue;
1717 		}
1718 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1719 			dprint_reset(mrioc,
1720 			    "ioc_status(0x%x) while reading dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1721 			    ioc_status, attached_handle,
1722 			    __FILE__, __LINE__, __func__);
1723 			continue;
1724 		}
1725 		sasinf = &dev_pg0.device_specific.sas_sata_format;
1726 
1727 		port_idx = host_port_count;
1728 		h_port[port_idx].sas_address = le64_to_cpu(sasinf->sas_address);
1729 		h_port[port_idx].handle = attached_handle;
1730 		h_port[port_idx].phy_mask = (1 << i);
1731 		h_port[port_idx].iounit_port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1732 		h_port[port_idx].lowest_phy = sasinf->phy_num;
1733 		h_port[port_idx].used = 0;
1734 		host_port_count++;
1735 	}
1736 
1737 	if (!host_port_count)
1738 		goto out;
1739 
1740 	if (mrioc->logging_level & MPI3_DEBUG_RESET) {
1741 		ioc_info(mrioc, "Host port details before reset\n");
1742 		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1743 		    port_list) {
1744 			ioc_info(mrioc,
1745 			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
1746 			    mr_sas_port->hba_port->port_id,
1747 			    mr_sas_port->remote_identify.sas_address,
1748 			    mr_sas_port->phy_mask, mr_sas_port->lowest_phy);
1749 		}
1750 		mr_sas_port = NULL;
1751 		ioc_info(mrioc, "Host port details after reset\n");
1752 		for (i = 0; i < host_port_count; i++) {
1753 			ioc_info(mrioc,
1754 			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
1755 			    h_port[i].iounit_port_id, h_port[i].sas_address,
1756 			    h_port[i].phy_mask, h_port[i].lowest_phy);
1757 		}
1758 	}
1759 
1760 	/* mark all host sas port entries as dirty */
1761 	list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1762 	    port_list) {
1763 		mr_sas_port->marked_responding = 0;
1764 		mr_sas_port->hba_port->flags |= MPI3MR_HBA_PORT_FLAG_DIRTY;
1765 	}
1766 
1767 	/* First check for matching lowest phy */
1768 	for (i = 0; i < host_port_count; i++) {
1769 		mr_sas_port = NULL;
1770 		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1771 		    port_list) {
1772 			if (mr_sas_port->marked_responding)
1773 				continue;
1774 			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1775 				continue;
1776 			if (h_port[i].lowest_phy == mr_sas_port->lowest_phy) {
1777 				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1778 				break;
1779 			}
1780 		}
1781 	}
1782 
1783 	/* In case if lowest phy is got enabled or disabled during reset */
1784 	for (i = 0; i < host_port_count; i++) {
1785 		if (h_port[i].used)
1786 			continue;
1787 		mr_sas_port = NULL;
1788 		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1789 		    port_list) {
1790 			if (mr_sas_port->marked_responding)
1791 				continue;
1792 			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1793 				continue;
1794 			if (h_port[i].phy_mask & mr_sas_port->phy_mask) {
1795 				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1796 				break;
1797 			}
1798 		}
1799 	}
1800 
1801 	/* In case if expander cable is removed & connected to another HBA port during reset */
1802 	for (i = 0; i < host_port_count; i++) {
1803 		if (h_port[i].used)
1804 			continue;
1805 		mr_sas_port = NULL;
1806 		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1807 		    port_list) {
1808 			if (mr_sas_port->marked_responding)
1809 				continue;
1810 			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1811 				continue;
1812 			mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1813 			break;
1814 		}
1815 	}
1816 out:
1817 	kfree(h_port);
1818 	kfree(sas_io_unit_pg0);
1819 }
1820 
1821 /**
1822  * mpi3mr_refresh_expanders - Refresh expander device exposure
1823  * @mrioc: Adapter instance reference
1824  *
1825  * This is executed post controller reset to identify any
1826  * missing expander devices during reset and remove from the upper layers
1827  * or expose any newly detected expander device to the upper layers.
1828  *
1829  * Return: Nothing.
1830  */
1831 void
1832 mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc)
1833 {
1834 	struct mpi3mr_sas_node *sas_expander, *sas_expander_next;
1835 	struct mpi3_sas_expander_page0 expander_pg0;
1836 	u16 ioc_status, handle;
1837 	u64 sas_address;
1838 	int i;
1839 	unsigned long flags;
1840 	struct mpi3mr_hba_port *hba_port;
1841 
1842 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1843 	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
1844 		sas_expander->non_responding = 1;
1845 	}
1846 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1847 
1848 	sas_expander = NULL;
1849 
1850 	handle = 0xffff;
1851 
1852 	/* Search for responding expander devices and add them if they are newly got added */
1853 	while (true) {
1854 		if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
1855 		    sizeof(struct mpi3_sas_expander_page0),
1856 		    MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
1857 			dprint_reset(mrioc,
1858 			    "failed to read exp pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1859 			    handle, __FILE__, __LINE__, __func__);
1860 			break;
1861 		}
1862 
1863 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1864 			dprint_reset(mrioc,
1865 			   "ioc_status(0x%x) while reading exp pg0 for handle:(0x%04x), %s:%d/%s()!\n",
1866 			   ioc_status, handle, __FILE__, __LINE__, __func__);
1867 			break;
1868 		}
1869 
1870 		handle = le16_to_cpu(expander_pg0.dev_handle);
1871 		sas_address = le64_to_cpu(expander_pg0.sas_address);
1872 		hba_port = mpi3mr_get_hba_port_by_id(mrioc, expander_pg0.io_unit_port);
1873 
1874 		if (!hba_port) {
1875 			mpi3mr_sas_host_refresh(mrioc);
1876 			mpi3mr_expander_add(mrioc, handle);
1877 			continue;
1878 		}
1879 
1880 		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1881 		sas_expander =
1882 		    mpi3mr_expander_find_by_sas_address(mrioc,
1883 		    sas_address, hba_port);
1884 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1885 
1886 		if (!sas_expander) {
1887 			mpi3mr_sas_host_refresh(mrioc);
1888 			mpi3mr_expander_add(mrioc, handle);
1889 			continue;
1890 		}
1891 
1892 		sas_expander->non_responding = 0;
1893 		if (sas_expander->handle == handle)
1894 			continue;
1895 
1896 		sas_expander->handle = handle;
1897 		for (i = 0 ; i < sas_expander->num_phys ; i++)
1898 			sas_expander->phy[i].handle = handle;
1899 	}
1900 
1901 	/*
1902 	 * Delete non responding expander devices and the corresponding
1903 	 * hba_port if the non responding expander device's parent device
1904 	 * is a host node.
1905 	 */
1906 	sas_expander = NULL;
1907 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1908 	list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
1909 	    &mrioc->sas_expander_list, list) {
1910 		if (sas_expander->non_responding) {
1911 			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1912 			mpi3mr_expander_node_remove(mrioc, sas_expander);
1913 			spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1914 		}
1915 	}
1916 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1917 }
1918 
1919 /**
1920  * mpi3mr_expander_node_add - insert an expander to the list.
1921  * @mrioc: Adapter instance reference
1922  * @sas_expander: Expander sas node
1923  * Context: This function will acquire sas_node_lock.
1924  *
1925  * Adding new object to the ioc->sas_expander_list.
1926  *
1927  * Return: None.
1928  */
1929 static void mpi3mr_expander_node_add(struct mpi3mr_ioc *mrioc,
1930 	struct mpi3mr_sas_node *sas_expander)
1931 {
1932 	unsigned long flags;
1933 
1934 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1935 	list_add_tail(&sas_expander->list, &mrioc->sas_expander_list);
1936 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1937 }
1938 
1939 /**
1940  * mpi3mr_expander_add -  Create expander object
1941  * @mrioc: Adapter instance reference
1942  * @handle: Expander firmware device handle
1943  *
1944  * This function creating expander object, stored in
1945  * sas_expander_list and expose it to the SAS transport
1946  * layer.
1947  *
1948  * Return: 0 for success, non-zero for failure.
1949  */
1950 int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)
1951 {
1952 	struct mpi3mr_sas_node *sas_expander;
1953 	struct mpi3mr_enclosure_node *enclosure_dev;
1954 	struct mpi3_sas_expander_page0 expander_pg0;
1955 	struct mpi3_sas_expander_page1 expander_pg1;
1956 	u16 ioc_status, parent_handle, temp_handle;
1957 	u64 sas_address, sas_address_parent = 0;
1958 	int i;
1959 	unsigned long flags;
1960 	u8 port_id, link_rate;
1961 	struct mpi3mr_sas_port *mr_sas_port = NULL;
1962 	struct mpi3mr_hba_port *hba_port;
1963 	u32 phynum_handle;
1964 	int rc = 0;
1965 
1966 	if (!handle)
1967 		return -1;
1968 
1969 	if (mrioc->reset_in_progress)
1970 		return -1;
1971 
1972 	if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
1973 	    sizeof(expander_pg0), MPI3_SAS_EXPAND_PGAD_FORM_HANDLE, handle))) {
1974 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1975 		    __FILE__, __LINE__, __func__);
1976 		return -1;
1977 	}
1978 
1979 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1980 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1981 		    __FILE__, __LINE__, __func__);
1982 		return -1;
1983 	}
1984 
1985 	parent_handle = le16_to_cpu(expander_pg0.parent_dev_handle);
1986 	if (mpi3mr_get_sas_address(mrioc, parent_handle, &sas_address_parent)
1987 	    != 0) {
1988 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1989 		    __FILE__, __LINE__, __func__);
1990 		return -1;
1991 	}
1992 
1993 	port_id = expander_pg0.io_unit_port;
1994 	hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
1995 	if (!hba_port) {
1996 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1997 		    __FILE__, __LINE__, __func__);
1998 		return -1;
1999 	}
2000 
2001 	if (sas_address_parent != mrioc->sas_hba.sas_address) {
2002 		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2003 		sas_expander =
2004 		   mpi3mr_expander_find_by_sas_address(mrioc,
2005 		    sas_address_parent, hba_port);
2006 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2007 		if (!sas_expander) {
2008 			rc = mpi3mr_expander_add(mrioc, parent_handle);
2009 			if (rc != 0)
2010 				return rc;
2011 		} else {
2012 			/*
2013 			 * When there is a parent expander present, update it's
2014 			 * phys where child expander is connected with the link
2015 			 * speed, attached dev handle and sas address.
2016 			 */
2017 			for (i = 0 ; i < sas_expander->num_phys ; i++) {
2018 				phynum_handle =
2019 				    (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2020 				    parent_handle;
2021 				if (mpi3mr_cfg_get_sas_exp_pg1(mrioc,
2022 				    &ioc_status, &expander_pg1,
2023 				    sizeof(expander_pg1),
2024 				    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2025 				    phynum_handle)) {
2026 					ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2027 					    __FILE__, __LINE__, __func__);
2028 					rc = -1;
2029 					return rc;
2030 				}
2031 				if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2032 					ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2033 					    __FILE__, __LINE__, __func__);
2034 					rc = -1;
2035 					return rc;
2036 				}
2037 				temp_handle = le16_to_cpu(
2038 				    expander_pg1.attached_dev_handle);
2039 				if (temp_handle != handle)
2040 					continue;
2041 				link_rate = (expander_pg1.negotiated_link_rate &
2042 				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2043 				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2044 				mpi3mr_update_links(mrioc, sas_address_parent,
2045 				    handle, i, link_rate, hba_port);
2046 			}
2047 		}
2048 	}
2049 
2050 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2051 	sas_address = le64_to_cpu(expander_pg0.sas_address);
2052 	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc,
2053 	    sas_address, hba_port);
2054 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2055 
2056 	if (sas_expander)
2057 		return 0;
2058 
2059 	sas_expander = kzalloc(sizeof(struct mpi3mr_sas_node),
2060 	    GFP_KERNEL);
2061 	if (!sas_expander)
2062 		return -ENOMEM;
2063 
2064 	sas_expander->handle = handle;
2065 	sas_expander->num_phys = expander_pg0.num_phys;
2066 	sas_expander->sas_address_parent = sas_address_parent;
2067 	sas_expander->sas_address = sas_address;
2068 	sas_expander->hba_port = hba_port;
2069 
2070 	ioc_info(mrioc,
2071 	    "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
2072 	    handle, parent_handle, (unsigned long long)
2073 	    sas_expander->sas_address, sas_expander->num_phys);
2074 
2075 	if (!sas_expander->num_phys) {
2076 		rc = -1;
2077 		goto out_fail;
2078 	}
2079 	sas_expander->phy = kcalloc(sas_expander->num_phys,
2080 	    sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);
2081 	if (!sas_expander->phy) {
2082 		rc = -1;
2083 		goto out_fail;
2084 	}
2085 
2086 	INIT_LIST_HEAD(&sas_expander->sas_port_list);
2087 	mr_sas_port = mpi3mr_sas_port_add(mrioc, handle, sas_address_parent,
2088 	    sas_expander->hba_port);
2089 	if (!mr_sas_port) {
2090 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2091 		    __FILE__, __LINE__, __func__);
2092 		rc = -1;
2093 		goto out_fail;
2094 	}
2095 	sas_expander->parent_dev = &mr_sas_port->rphy->dev;
2096 	sas_expander->rphy = mr_sas_port->rphy;
2097 
2098 	for (i = 0 ; i < sas_expander->num_phys ; i++) {
2099 		phynum_handle = (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2100 		    handle;
2101 		if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2102 		    &expander_pg1, sizeof(expander_pg1),
2103 		    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2104 		    phynum_handle)) {
2105 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2106 			    __FILE__, __LINE__, __func__);
2107 			rc = -1;
2108 			goto out_fail;
2109 		}
2110 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2111 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2112 			    __FILE__, __LINE__, __func__);
2113 			rc = -1;
2114 			goto out_fail;
2115 		}
2116 
2117 		sas_expander->phy[i].handle = handle;
2118 		sas_expander->phy[i].phy_id = i;
2119 		sas_expander->phy[i].hba_port = hba_port;
2120 
2121 		if ((mpi3mr_add_expander_phy(mrioc, &sas_expander->phy[i],
2122 		    expander_pg1, sas_expander->parent_dev))) {
2123 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2124 			    __FILE__, __LINE__, __func__);
2125 			rc = -1;
2126 			goto out_fail;
2127 		}
2128 	}
2129 
2130 	if (sas_expander->enclosure_handle) {
2131 		enclosure_dev =
2132 			mpi3mr_enclosure_find_by_handle(mrioc,
2133 						sas_expander->enclosure_handle);
2134 		if (enclosure_dev)
2135 			sas_expander->enclosure_logical_id = le64_to_cpu(
2136 			    enclosure_dev->pg0.enclosure_logical_id);
2137 	}
2138 
2139 	mpi3mr_expander_node_add(mrioc, sas_expander);
2140 	return 0;
2141 
2142 out_fail:
2143 
2144 	if (mr_sas_port)
2145 		mpi3mr_sas_port_remove(mrioc,
2146 		    sas_expander->sas_address,
2147 		    sas_address_parent, sas_expander->hba_port);
2148 	kfree(sas_expander->phy);
2149 	kfree(sas_expander);
2150 	return rc;
2151 }
2152 
2153 /**
2154  * mpi3mr_expander_node_remove - recursive removal of expander.
2155  * @mrioc: Adapter instance reference
2156  * @sas_expander: Expander device object
2157  *
2158  * Removes expander object and freeing associated memory from
2159  * the sas_expander_list and removes the same from SAS TL, if
2160  * one of the attached device is an expander then it recursively
2161  * removes the expander device too.
2162  *
2163  * Return nothing.
2164  */
2165 void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
2166 	struct mpi3mr_sas_node *sas_expander)
2167 {
2168 	struct mpi3mr_sas_port *mr_sas_port, *next;
2169 	unsigned long flags;
2170 	u8 port_id;
2171 
2172 	/* remove sibling ports attached to this expander */
2173 	list_for_each_entry_safe(mr_sas_port, next,
2174 	   &sas_expander->sas_port_list, port_list) {
2175 		if (mrioc->reset_in_progress)
2176 			return;
2177 		if (mr_sas_port->remote_identify.device_type ==
2178 		    SAS_END_DEVICE)
2179 			mpi3mr_remove_device_by_sas_address(mrioc,
2180 			    mr_sas_port->remote_identify.sas_address,
2181 			    mr_sas_port->hba_port);
2182 		else if (mr_sas_port->remote_identify.device_type ==
2183 		    SAS_EDGE_EXPANDER_DEVICE ||
2184 		    mr_sas_port->remote_identify.device_type ==
2185 		    SAS_FANOUT_EXPANDER_DEVICE)
2186 			mpi3mr_expander_remove(mrioc,
2187 			    mr_sas_port->remote_identify.sas_address,
2188 			    mr_sas_port->hba_port);
2189 	}
2190 
2191 	port_id = sas_expander->hba_port->port_id;
2192 	mpi3mr_sas_port_remove(mrioc, sas_expander->sas_address,
2193 	    sas_expander->sas_address_parent, sas_expander->hba_port);
2194 
2195 	ioc_info(mrioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n",
2196 	    sas_expander->handle, (unsigned long long)
2197 	    sas_expander->sas_address, port_id);
2198 
2199 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2200 	list_del(&sas_expander->list);
2201 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2202 
2203 	kfree(sas_expander->phy);
2204 	kfree(sas_expander);
2205 }
2206 
2207 /**
2208  * mpi3mr_expander_remove - Remove expander object
2209  * @mrioc: Adapter instance reference
2210  * @sas_address: Remove expander sas_address
2211  * @hba_port: HBA port reference
2212  *
2213  * This function remove expander object, stored in
2214  * mrioc->sas_expander_list and removes it from the SAS TL by
2215  * calling mpi3mr_expander_node_remove().
2216  *
2217  * Return: None
2218  */
2219 void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
2220 	struct mpi3mr_hba_port *hba_port)
2221 {
2222 	struct mpi3mr_sas_node *sas_expander;
2223 	unsigned long flags;
2224 
2225 	if (mrioc->reset_in_progress)
2226 		return;
2227 
2228 	if (!hba_port)
2229 		return;
2230 
2231 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2232 	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
2233 	    hba_port);
2234 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2235 	if (sas_expander)
2236 		mpi3mr_expander_node_remove(mrioc, sas_expander);
2237 
2238 }
2239 
2240 /**
2241  * mpi3mr_get_sas_negotiated_logical_linkrate - get linkrate
2242  * @mrioc: Adapter instance reference
2243  * @tgtdev: Target device
2244  *
2245  * This function identifies whether the target device is
2246  * attached directly or through expander and issues sas phy
2247  * page0 or expander phy page1 and gets the link rate, if there
2248  * is any failure in reading the pages then this returns link
2249  * rate of 1.5.
2250  *
2251  * Return: logical link rate.
2252  */
2253 static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc,
2254 	struct mpi3mr_tgt_dev *tgtdev)
2255 {
2256 	u8 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5, phy_number;
2257 	struct mpi3_sas_expander_page1 expander_pg1;
2258 	struct mpi3_sas_phy_page0 phy_pg0;
2259 	u32 phynum_handle;
2260 	u16 ioc_status;
2261 
2262 	phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2263 	if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) {
2264 		phynum_handle = ((phy_number<<MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT)
2265 				 | tgtdev->parent_handle);
2266 		if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2267 		    &expander_pg1, sizeof(expander_pg1),
2268 		    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2269 		    phynum_handle)) {
2270 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2271 			    __FILE__, __LINE__, __func__);
2272 			goto out;
2273 		}
2274 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2275 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2276 			    __FILE__, __LINE__, __func__);
2277 			goto out;
2278 		}
2279 		link_rate = (expander_pg1.negotiated_link_rate &
2280 			     MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2281 			MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2282 		goto out;
2283 	}
2284 	if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
2285 	    sizeof(struct mpi3_sas_phy_page0),
2286 	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy_number)) {
2287 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2288 		    __FILE__, __LINE__, __func__);
2289 		goto out;
2290 	}
2291 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2292 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2293 		    __FILE__, __LINE__, __func__);
2294 		goto out;
2295 	}
2296 	link_rate = (phy_pg0.negotiated_link_rate &
2297 		     MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2298 		MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2299 out:
2300 	return link_rate;
2301 }
2302 
2303 /**
2304  * mpi3mr_report_tgtdev_to_sas_transport - expose dev to SAS TL
2305  * @mrioc: Adapter instance reference
2306  * @tgtdev: Target device
2307  *
2308  * This function exposes the target device after
2309  * preparing host_phy, setting up link rate etc.
2310  *
2311  * Return: 0 on success, non-zero for failure.
2312  */
2313 int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc,
2314 	struct mpi3mr_tgt_dev *tgtdev)
2315 {
2316 	int retval = 0;
2317 	u8 link_rate, parent_phy_number;
2318 	u64 sas_address_parent, sas_address;
2319 	struct mpi3mr_hba_port *hba_port;
2320 	u8 port_id;
2321 
2322 	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2323 	    !mrioc->sas_transport_enabled)
2324 		return -1;
2325 
2326 	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2327 	if (!mrioc->sas_hba.num_phys)
2328 		mpi3mr_sas_host_add(mrioc);
2329 	else
2330 		mpi3mr_sas_host_refresh(mrioc);
2331 
2332 	if (mpi3mr_get_sas_address(mrioc, tgtdev->parent_handle,
2333 	    &sas_address_parent) != 0) {
2334 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2335 		    __FILE__, __LINE__, __func__);
2336 		return -1;
2337 	}
2338 	tgtdev->dev_spec.sas_sata_inf.sas_address_parent = sas_address_parent;
2339 
2340 	parent_phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2341 	port_id = tgtdev->io_unit_port;
2342 
2343 	hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
2344 	if (!hba_port) {
2345 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2346 		    __FILE__, __LINE__, __func__);
2347 		return -1;
2348 	}
2349 	tgtdev->dev_spec.sas_sata_inf.hba_port = hba_port;
2350 
2351 	link_rate = mpi3mr_get_sas_negotiated_logical_linkrate(mrioc, tgtdev);
2352 
2353 	mpi3mr_update_links(mrioc, sas_address_parent, tgtdev->dev_handle,
2354 	    parent_phy_number, link_rate, hba_port);
2355 
2356 	tgtdev->host_exposed = 1;
2357 	if (!mpi3mr_sas_port_add(mrioc, tgtdev->dev_handle,
2358 	    sas_address_parent, hba_port)) {
2359 		retval = -1;
2360 		} else if ((!tgtdev->starget) && (!mrioc->is_driver_loading)) {
2361 			mpi3mr_sas_port_remove(mrioc, sas_address,
2362 			    sas_address_parent, hba_port);
2363 		retval = -1;
2364 	}
2365 	if (retval) {
2366 		tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2367 		tgtdev->host_exposed = 0;
2368 	}
2369 	return retval;
2370 }
2371 
2372 /**
2373  * mpi3mr_remove_tgtdev_from_sas_transport - remove from SAS TL
2374  * @mrioc: Adapter instance reference
2375  * @tgtdev: Target device
2376  *
2377  * This function removes the target device
2378  *
2379  * Return: None.
2380  */
2381 void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
2382 	struct mpi3mr_tgt_dev *tgtdev)
2383 {
2384 	u64 sas_address_parent, sas_address;
2385 	struct mpi3mr_hba_port *hba_port;
2386 
2387 	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2388 	    !mrioc->sas_transport_enabled)
2389 		return;
2390 
2391 	hba_port = tgtdev->dev_spec.sas_sata_inf.hba_port;
2392 	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2393 	sas_address_parent = tgtdev->dev_spec.sas_sata_inf.sas_address_parent;
2394 	mpi3mr_sas_port_remove(mrioc, sas_address, sas_address_parent,
2395 	    hba_port);
2396 	tgtdev->host_exposed = 0;
2397 	tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2398 }
2399 
2400 /**
2401  * mpi3mr_get_port_id_by_sas_phy -  Get port ID of the given phy
2402  * @phy: SAS transport layer phy object
2403  *
2404  * Return: Port number for valid ID else 0xFFFF
2405  */
2406 static inline u8 mpi3mr_get_port_id_by_sas_phy(struct sas_phy *phy)
2407 {
2408 	u8 port_id = 0xFF;
2409 	struct mpi3mr_hba_port *hba_port = phy->hostdata;
2410 
2411 	if (hba_port)
2412 		port_id = hba_port->port_id;
2413 
2414 	return port_id;
2415 }
2416 
2417 /**
2418  * mpi3mr_get_port_id_by_rphy - Get Port number from SAS rphy
2419  *
2420  * @mrioc: Adapter instance reference
2421  * @rphy: SAS transport layer remote phy object
2422  *
2423  * Retrieves HBA port number in which the device pointed by the
2424  * rphy object is attached with.
2425  *
2426  * Return: Valid port number on success else OxFFFF.
2427  */
2428 static u8 mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc *mrioc, struct sas_rphy *rphy)
2429 {
2430 	struct mpi3mr_sas_node *sas_expander;
2431 	struct mpi3mr_tgt_dev *tgtdev;
2432 	unsigned long flags;
2433 	u8 port_id = 0xFF;
2434 
2435 	if (!rphy)
2436 		return port_id;
2437 
2438 	if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
2439 	    rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {
2440 		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2441 		list_for_each_entry(sas_expander, &mrioc->sas_expander_list,
2442 		    list) {
2443 			if (sas_expander->rphy == rphy) {
2444 				port_id = sas_expander->hba_port->port_id;
2445 				break;
2446 			}
2447 		}
2448 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2449 	} else if (rphy->identify.device_type == SAS_END_DEVICE) {
2450 		spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2451 
2452 		tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2453 			    rphy->identify.sas_address, rphy);
2454 		if (tgtdev && tgtdev->dev_spec.sas_sata_inf.hba_port) {
2455 			port_id =
2456 				tgtdev->dev_spec.sas_sata_inf.hba_port->port_id;
2457 			mpi3mr_tgtdev_put(tgtdev);
2458 		}
2459 		spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2460 	}
2461 	return port_id;
2462 }
2463 
2464 static inline struct mpi3mr_ioc *phy_to_mrioc(struct sas_phy *phy)
2465 {
2466 	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
2467 
2468 	return shost_priv(shost);
2469 }
2470 
2471 static inline struct mpi3mr_ioc *rphy_to_mrioc(struct sas_rphy *rphy)
2472 {
2473 	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
2474 
2475 	return shost_priv(shost);
2476 }
2477 
2478 /* report phy error log structure */
2479 struct phy_error_log_request {
2480 	u8 smp_frame_type; /* 0x40 */
2481 	u8 function; /* 0x11 */
2482 	u8 allocated_response_length;
2483 	u8 request_length; /* 02 */
2484 	u8 reserved_1[5];
2485 	u8 phy_identifier;
2486 	u8 reserved_2[2];
2487 };
2488 
2489 /* report phy error log reply structure */
2490 struct phy_error_log_reply {
2491 	u8 smp_frame_type; /* 0x41 */
2492 	u8 function; /* 0x11 */
2493 	u8 function_result;
2494 	u8 response_length;
2495 	__be16 expander_change_count;
2496 	u8 reserved_1[3];
2497 	u8 phy_identifier;
2498 	u8 reserved_2[2];
2499 	__be32 invalid_dword;
2500 	__be32 running_disparity_error;
2501 	__be32 loss_of_dword_sync;
2502 	__be32 phy_reset_problem;
2503 };
2504 
2505 
2506 /**
2507  * mpi3mr_get_expander_phy_error_log - return expander counters:
2508  * @mrioc: Adapter instance reference
2509  * @phy: The SAS transport layer phy object
2510  *
2511  * Return: 0 for success, non-zero for failure.
2512  *
2513  */
2514 static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
2515 	struct sas_phy *phy)
2516 {
2517 	struct mpi3_smp_passthrough_request mpi_request;
2518 	struct mpi3_smp_passthrough_reply mpi_reply;
2519 	struct phy_error_log_request *phy_error_log_request;
2520 	struct phy_error_log_reply *phy_error_log_reply;
2521 	int rc;
2522 	void *psge;
2523 	void *data_out = NULL;
2524 	dma_addr_t data_out_dma, data_in_dma;
2525 	u32 data_out_sz, data_in_sz, sz;
2526 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2527 	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2528 	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2529 	u16 ioc_status;
2530 
2531 	if (mrioc->reset_in_progress) {
2532 		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2533 		return -EFAULT;
2534 	}
2535 
2536 	data_out_sz = sizeof(struct phy_error_log_request);
2537 	data_in_sz = sizeof(struct phy_error_log_reply);
2538 	sz = data_out_sz + data_in_sz;
2539 	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2540 	    GFP_KERNEL);
2541 	if (!data_out) {
2542 		rc = -ENOMEM;
2543 		goto out;
2544 	}
2545 
2546 	data_in_dma = data_out_dma + data_out_sz;
2547 	phy_error_log_reply = data_out + data_out_sz;
2548 
2549 	rc = -EINVAL;
2550 	memset(data_out, 0, sz);
2551 	phy_error_log_request = data_out;
2552 	phy_error_log_request->smp_frame_type = 0x40;
2553 	phy_error_log_request->function = 0x11;
2554 	phy_error_log_request->request_length = 2;
2555 	phy_error_log_request->allocated_response_length = 0;
2556 	phy_error_log_request->phy_identifier = phy->number;
2557 
2558 	memset(&mpi_request, 0, request_sz);
2559 	memset(&mpi_reply, 0, reply_sz);
2560 	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2561 	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2562 	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2563 	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2564 
2565 	psge = &mpi_request.request_sge;
2566 	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2567 
2568 	psge = &mpi_request.response_sge;
2569 	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2570 
2571 	dprint_transport_info(mrioc,
2572 	    "sending phy error log SMP request to sas_address(0x%016llx), phy_id(%d)\n",
2573 	    (unsigned long long)phy->identify.sas_address, phy->number);
2574 
2575 	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2576 	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2577 		goto out;
2578 
2579 	dprint_transport_info(mrioc,
2580 	    "phy error log SMP request completed with ioc_status(0x%04x)\n",
2581 	    ioc_status);
2582 
2583 	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2584 		dprint_transport_info(mrioc,
2585 		    "phy error log - reply data transfer size(%d)\n",
2586 		    le16_to_cpu(mpi_reply.response_data_length));
2587 
2588 		if (le16_to_cpu(mpi_reply.response_data_length) !=
2589 		    sizeof(struct phy_error_log_reply))
2590 			goto out;
2591 
2592 		dprint_transport_info(mrioc,
2593 		    "phy error log - function_result(%d)\n",
2594 		    phy_error_log_reply->function_result);
2595 
2596 		phy->invalid_dword_count =
2597 		    be32_to_cpu(phy_error_log_reply->invalid_dword);
2598 		phy->running_disparity_error_count =
2599 		    be32_to_cpu(phy_error_log_reply->running_disparity_error);
2600 		phy->loss_of_dword_sync_count =
2601 		    be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
2602 		phy->phy_reset_problem_count =
2603 		    be32_to_cpu(phy_error_log_reply->phy_reset_problem);
2604 		rc = 0;
2605 	}
2606 
2607 out:
2608 	if (data_out)
2609 		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2610 		    data_out_dma);
2611 
2612 	return rc;
2613 }
2614 
2615 /**
2616  * mpi3mr_transport_get_linkerrors - return phy error counters
2617  * @phy: The SAS transport layer phy object
2618  *
2619  * This function retrieves the phy error log information of the
2620  * HBA or expander for which the phy belongs to
2621  *
2622  * Return: 0 for success, non-zero for failure.
2623  */
2624 static int mpi3mr_transport_get_linkerrors(struct sas_phy *phy)
2625 {
2626 	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2627 	struct mpi3_sas_phy_page1 phy_pg1;
2628 	int rc = 0;
2629 	u16 ioc_status;
2630 
2631 	rc = mpi3mr_parent_present(mrioc, phy);
2632 	if (rc)
2633 		return rc;
2634 
2635 	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2636 		return mpi3mr_get_expander_phy_error_log(mrioc, phy);
2637 
2638 	memset(&phy_pg1, 0, sizeof(struct mpi3_sas_phy_page1));
2639 	/* get hba phy error logs */
2640 	if ((mpi3mr_cfg_get_sas_phy_pg1(mrioc, &ioc_status, &phy_pg1,
2641 	    sizeof(struct mpi3_sas_phy_page1),
2642 	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number))) {
2643 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2644 		    __FILE__, __LINE__, __func__);
2645 		return -ENXIO;
2646 	}
2647 
2648 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2649 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2650 		    __FILE__, __LINE__, __func__);
2651 		return -ENXIO;
2652 	}
2653 	phy->invalid_dword_count = le32_to_cpu(phy_pg1.invalid_dword_count);
2654 	phy->running_disparity_error_count =
2655 		le32_to_cpu(phy_pg1.running_disparity_error_count);
2656 	phy->loss_of_dword_sync_count =
2657 		le32_to_cpu(phy_pg1.loss_dword_synch_count);
2658 	phy->phy_reset_problem_count =
2659 		le32_to_cpu(phy_pg1.phy_reset_problem_count);
2660 	return 0;
2661 }
2662 
2663 /**
2664  * mpi3mr_transport_get_enclosure_identifier - Get Enclosure ID
2665  * @rphy: The SAS transport layer remote phy object
2666  * @identifier: Enclosure identifier to be returned
2667  *
2668  * Returns the enclosure id for the device pointed by the remote
2669  * phy object.
2670  *
2671  * Return: 0 on success or -ENXIO
2672  */
2673 static int
2674 mpi3mr_transport_get_enclosure_identifier(struct sas_rphy *rphy,
2675 	u64 *identifier)
2676 {
2677 	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2678 	struct mpi3mr_tgt_dev *tgtdev = NULL;
2679 	unsigned long flags;
2680 	int rc;
2681 
2682 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2683 	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2684 	    rphy->identify.sas_address, rphy);
2685 	if (tgtdev) {
2686 		*identifier =
2687 			tgtdev->enclosure_logical_id;
2688 		rc = 0;
2689 		mpi3mr_tgtdev_put(tgtdev);
2690 	} else {
2691 		*identifier = 0;
2692 		rc = -ENXIO;
2693 	}
2694 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2695 
2696 	return rc;
2697 }
2698 
2699 /**
2700  * mpi3mr_transport_get_bay_identifier - Get bay ID
2701  * @rphy: The SAS transport layer remote phy object
2702  *
2703  * Returns the slot id for the device pointed by the remote phy
2704  * object.
2705  *
2706  * Return: Valid slot ID on success or -ENXIO
2707  */
2708 static int
2709 mpi3mr_transport_get_bay_identifier(struct sas_rphy *rphy)
2710 {
2711 	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2712 	struct mpi3mr_tgt_dev *tgtdev = NULL;
2713 	unsigned long flags;
2714 	int rc;
2715 
2716 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2717 	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2718 	    rphy->identify.sas_address, rphy);
2719 	if (tgtdev) {
2720 		rc = tgtdev->slot;
2721 		mpi3mr_tgtdev_put(tgtdev);
2722 	} else
2723 		rc = -ENXIO;
2724 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2725 
2726 	return rc;
2727 }
2728 
2729 /* phy control request structure */
2730 struct phy_control_request {
2731 	u8 smp_frame_type; /* 0x40 */
2732 	u8 function; /* 0x91 */
2733 	u8 allocated_response_length;
2734 	u8 request_length; /* 0x09 */
2735 	u16 expander_change_count;
2736 	u8 reserved_1[3];
2737 	u8 phy_identifier;
2738 	u8 phy_operation;
2739 	u8 reserved_2[13];
2740 	u64 attached_device_name;
2741 	u8 programmed_min_physical_link_rate;
2742 	u8 programmed_max_physical_link_rate;
2743 	u8 reserved_3[6];
2744 };
2745 
2746 /* phy control reply structure */
2747 struct phy_control_reply {
2748 	u8 smp_frame_type; /* 0x41 */
2749 	u8 function; /* 0x11 */
2750 	u8 function_result;
2751 	u8 response_length;
2752 };
2753 
2754 #define SMP_PHY_CONTROL_LINK_RESET	(0x01)
2755 #define SMP_PHY_CONTROL_HARD_RESET	(0x02)
2756 #define SMP_PHY_CONTROL_DISABLE		(0x03)
2757 
2758 /**
2759  * mpi3mr_expander_phy_control - expander phy control
2760  * @mrioc: Adapter instance reference
2761  * @phy: The SAS transport layer phy object
2762  * @phy_operation: The phy operation to be executed
2763  *
2764  * Issues SMP passthru phy control request to execute a specific
2765  * phy operation for a given expander device.
2766  *
2767  * Return: 0 for success, non-zero for failure.
2768  */
2769 static int
2770 mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
2771 	struct sas_phy *phy, u8 phy_operation)
2772 {
2773 	struct mpi3_smp_passthrough_request mpi_request;
2774 	struct mpi3_smp_passthrough_reply mpi_reply;
2775 	struct phy_control_request *phy_control_request;
2776 	struct phy_control_reply *phy_control_reply;
2777 	int rc;
2778 	void *psge;
2779 	void *data_out = NULL;
2780 	dma_addr_t data_out_dma;
2781 	dma_addr_t data_in_dma;
2782 	size_t data_in_sz;
2783 	size_t data_out_sz;
2784 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2785 	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2786 	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2787 	u16 ioc_status;
2788 	u16 sz;
2789 
2790 	if (mrioc->reset_in_progress) {
2791 		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2792 		return -EFAULT;
2793 	}
2794 
2795 	data_out_sz = sizeof(struct phy_control_request);
2796 	data_in_sz = sizeof(struct phy_control_reply);
2797 	sz = data_out_sz + data_in_sz;
2798 	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2799 	    GFP_KERNEL);
2800 	if (!data_out) {
2801 		rc = -ENOMEM;
2802 		goto out;
2803 	}
2804 
2805 	data_in_dma = data_out_dma + data_out_sz;
2806 	phy_control_reply = data_out + data_out_sz;
2807 
2808 	rc = -EINVAL;
2809 	memset(data_out, 0, sz);
2810 
2811 	phy_control_request = data_out;
2812 	phy_control_request->smp_frame_type = 0x40;
2813 	phy_control_request->function = 0x91;
2814 	phy_control_request->request_length = 9;
2815 	phy_control_request->allocated_response_length = 0;
2816 	phy_control_request->phy_identifier = phy->number;
2817 	phy_control_request->phy_operation = phy_operation;
2818 	phy_control_request->programmed_min_physical_link_rate =
2819 	    phy->minimum_linkrate << 4;
2820 	phy_control_request->programmed_max_physical_link_rate =
2821 	    phy->maximum_linkrate << 4;
2822 
2823 	memset(&mpi_request, 0, request_sz);
2824 	memset(&mpi_reply, 0, reply_sz);
2825 	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2826 	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2827 	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2828 	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2829 
2830 	psge = &mpi_request.request_sge;
2831 	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2832 
2833 	psge = &mpi_request.response_sge;
2834 	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2835 
2836 	dprint_transport_info(mrioc,
2837 	    "sending phy control SMP request to sas_address(0x%016llx), phy_id(%d) opcode(%d)\n",
2838 	    (unsigned long long)phy->identify.sas_address, phy->number,
2839 	    phy_operation);
2840 
2841 	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2842 	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2843 		goto out;
2844 
2845 	dprint_transport_info(mrioc,
2846 	    "phy control SMP request completed with ioc_status(0x%04x)\n",
2847 	    ioc_status);
2848 
2849 	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2850 		dprint_transport_info(mrioc,
2851 		    "phy control - reply data transfer size(%d)\n",
2852 		    le16_to_cpu(mpi_reply.response_data_length));
2853 
2854 		if (le16_to_cpu(mpi_reply.response_data_length) !=
2855 		    sizeof(struct phy_control_reply))
2856 			goto out;
2857 		dprint_transport_info(mrioc,
2858 		    "phy control - function_result(%d)\n",
2859 		    phy_control_reply->function_result);
2860 		rc = 0;
2861 	}
2862  out:
2863 	if (data_out)
2864 		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2865 		    data_out_dma);
2866 
2867 	return rc;
2868 }
2869 
2870 /**
2871  * mpi3mr_transport_phy_reset - Reset a given phy
2872  * @phy: The SAS transport layer phy object
2873  * @hard_reset: Flag to indicate the type of reset
2874  *
2875  * Return: 0 for success, non-zero for failure.
2876  */
2877 static int
2878 mpi3mr_transport_phy_reset(struct sas_phy *phy, int hard_reset)
2879 {
2880 	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2881 	struct mpi3_iounit_control_request mpi_request;
2882 	struct mpi3_iounit_control_reply mpi_reply;
2883 	u16 request_sz = sizeof(struct mpi3_iounit_control_request);
2884 	u16 reply_sz = sizeof(struct mpi3_iounit_control_reply);
2885 	int rc = 0;
2886 	u16 ioc_status;
2887 
2888 	rc = mpi3mr_parent_present(mrioc, phy);
2889 	if (rc)
2890 		return rc;
2891 
2892 	/* handle expander phys */
2893 	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2894 		return mpi3mr_expander_phy_control(mrioc, phy,
2895 		    (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
2896 		    SMP_PHY_CONTROL_LINK_RESET);
2897 
2898 	/* handle hba phys */
2899 	memset(&mpi_request, 0, request_sz);
2900 	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2901 	mpi_request.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
2902 	mpi_request.operation = MPI3_CTRL_OP_SAS_PHY_CONTROL;
2903 	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX] =
2904 		(hard_reset ? MPI3_CTRL_ACTION_HARD_RESET :
2905 		 MPI3_CTRL_ACTION_LINK_RESET);
2906 	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX] =
2907 		phy->number;
2908 
2909 	dprint_transport_info(mrioc,
2910 	    "sending phy reset request to sas_address(0x%016llx), phy_id(%d) hard_reset(%d)\n",
2911 	    (unsigned long long)phy->identify.sas_address, phy->number,
2912 	    hard_reset);
2913 
2914 	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2915 	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status)) {
2916 		rc = -EAGAIN;
2917 		goto out;
2918 	}
2919 
2920 	dprint_transport_info(mrioc,
2921 	    "phy reset request completed with ioc_status(0x%04x)\n",
2922 	    ioc_status);
2923 out:
2924 	return rc;
2925 }
2926 
2927 /**
2928  * mpi3mr_transport_phy_enable - enable/disable phys
2929  * @phy: The SAS transport layer phy object
2930  * @enable: flag to enable/disable, enable phy when true
2931  *
2932  * This function enables/disables a given by executing required
2933  * configuration page changes or expander phy control command
2934  *
2935  * Return: 0 for success, non-zero for failure.
2936  */
2937 static int
2938 mpi3mr_transport_phy_enable(struct sas_phy *phy, int enable)
2939 {
2940 	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2941 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
2942 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
2943 	u16 sz;
2944 	int rc = 0;
2945 	int i, discovery_active;
2946 
2947 	rc = mpi3mr_parent_present(mrioc, phy);
2948 	if (rc)
2949 		return rc;
2950 
2951 	/* handle expander phys */
2952 	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2953 		return mpi3mr_expander_phy_control(mrioc, phy,
2954 		    (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
2955 		    SMP_PHY_CONTROL_DISABLE);
2956 
2957 	/* handle hba phys */
2958 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
2959 		(mrioc->sas_hba.num_phys *
2960 		 sizeof(struct mpi3_sas_io_unit0_phy_data));
2961 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
2962 	if (!sas_io_unit_pg0) {
2963 		rc = -ENOMEM;
2964 		goto out;
2965 	}
2966 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
2967 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2968 		    __FILE__, __LINE__, __func__);
2969 		rc = -ENXIO;
2970 		goto out;
2971 	}
2972 
2973 	/* unable to enable/disable phys when discovery is active */
2974 	for (i = 0, discovery_active = 0; i < mrioc->sas_hba.num_phys ; i++) {
2975 		if (sas_io_unit_pg0->phy_data[i].port_flags &
2976 		    MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS) {
2977 			ioc_err(mrioc,
2978 			    "discovery is active on port = %d, phy = %d\n"
2979 			    "\tunable to enable/disable phys, try again later!\n",
2980 			    sas_io_unit_pg0->phy_data[i].io_unit_port, i);
2981 			discovery_active = 1;
2982 		}
2983 	}
2984 
2985 	if (discovery_active) {
2986 		rc = -EAGAIN;
2987 		goto out;
2988 	}
2989 
2990 	if ((sas_io_unit_pg0->phy_data[phy->number].phy_flags &
2991 	     (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
2992 	      MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))) {
2993 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2994 		    __FILE__, __LINE__, __func__);
2995 		rc = -ENXIO;
2996 		goto out;
2997 	}
2998 
2999 	/* read sas_iounit page 1 */
3000 	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3001 		(mrioc->sas_hba.num_phys *
3002 		 sizeof(struct mpi3_sas_io_unit1_phy_data));
3003 	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3004 	if (!sas_io_unit_pg1) {
3005 		rc = -ENOMEM;
3006 		goto out;
3007 	}
3008 
3009 	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3010 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3011 		    __FILE__, __LINE__, __func__);
3012 		rc = -ENXIO;
3013 		goto out;
3014 	}
3015 
3016 	if (enable)
3017 		sas_io_unit_pg1->phy_data[phy->number].phy_flags
3018 		    &= ~MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3019 	else
3020 		sas_io_unit_pg1->phy_data[phy->number].phy_flags
3021 		    |= MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3022 
3023 	mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz);
3024 
3025 	/* link reset */
3026 	if (enable)
3027 		mpi3mr_transport_phy_reset(phy, 0);
3028 
3029  out:
3030 	kfree(sas_io_unit_pg1);
3031 	kfree(sas_io_unit_pg0);
3032 	return rc;
3033 }
3034 
3035 /**
3036  * mpi3mr_transport_phy_speed - set phy min/max speed
3037  * @phy: The SAS transport later phy object
3038  * @rates: Rates defined as in sas_phy_linkrates
3039  *
3040  * This function sets the link rates given in the rates
3041  * argument to the given phy by executing required configuration
3042  * page changes or expander phy control command
3043  *
3044  * Return: 0 for success, non-zero for failure.
3045  */
3046 static int
3047 mpi3mr_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
3048 {
3049 	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
3050 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
3051 	struct mpi3_sas_phy_page0 phy_pg0;
3052 	u16 sz, ioc_status;
3053 	int rc = 0;
3054 
3055 	rc = mpi3mr_parent_present(mrioc, phy);
3056 	if (rc)
3057 		return rc;
3058 
3059 	if (!rates->minimum_linkrate)
3060 		rates->minimum_linkrate = phy->minimum_linkrate;
3061 	else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
3062 		rates->minimum_linkrate = phy->minimum_linkrate_hw;
3063 
3064 	if (!rates->maximum_linkrate)
3065 		rates->maximum_linkrate = phy->maximum_linkrate;
3066 	else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
3067 		rates->maximum_linkrate = phy->maximum_linkrate_hw;
3068 
3069 	/* handle expander phys */
3070 	if (phy->identify.sas_address != mrioc->sas_hba.sas_address) {
3071 		phy->minimum_linkrate = rates->minimum_linkrate;
3072 		phy->maximum_linkrate = rates->maximum_linkrate;
3073 		return mpi3mr_expander_phy_control(mrioc, phy,
3074 		    SMP_PHY_CONTROL_LINK_RESET);
3075 	}
3076 
3077 	/* handle hba phys */
3078 	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3079 		(mrioc->sas_hba.num_phys *
3080 		 sizeof(struct mpi3_sas_io_unit1_phy_data));
3081 	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3082 	if (!sas_io_unit_pg1) {
3083 		rc = -ENOMEM;
3084 		goto out;
3085 	}
3086 
3087 	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3088 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3089 		    __FILE__, __LINE__, __func__);
3090 		rc = -ENXIO;
3091 		goto out;
3092 	}
3093 
3094 	sas_io_unit_pg1->phy_data[phy->number].max_min_link_rate =
3095 		(rates->minimum_linkrate + (rates->maximum_linkrate << 4));
3096 
3097 	if (mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3098 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3099 		    __FILE__, __LINE__, __func__);
3100 		rc = -ENXIO;
3101 		goto out;
3102 	}
3103 
3104 	/* link reset */
3105 	mpi3mr_transport_phy_reset(phy, 0);
3106 
3107 	/* read phy page 0, then update the rates in the sas transport phy */
3108 	if (!mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
3109 	    sizeof(struct mpi3_sas_phy_page0),
3110 	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number) &&
3111 	    (ioc_status == MPI3_IOCSTATUS_SUCCESS)) {
3112 		phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
3113 		    phy_pg0.programmed_link_rate &
3114 		    MPI3_SAS_PRATE_MIN_RATE_MASK);
3115 		phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
3116 		    phy_pg0.programmed_link_rate >> 4);
3117 		phy->negotiated_linkrate =
3118 			mpi3mr_convert_phy_link_rate(
3119 			    (phy_pg0.negotiated_link_rate &
3120 			    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK)
3121 			    >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
3122 	}
3123 
3124 out:
3125 	kfree(sas_io_unit_pg1);
3126 	return rc;
3127 }
3128 
3129 /**
3130  * mpi3mr_map_smp_buffer - map BSG dma buffer
3131  * @dev: Generic device reference
3132  * @buf: BSG buffer pointer
3133  * @dma_addr: Physical address holder
3134  * @dma_len: Mapped DMA buffer length.
3135  * @p: Virtual address holder
3136  *
3137  * This function maps the DMAable buffer
3138  *
3139  * Return: 0 on success, non-zero on failure
3140  */
3141 static int
3142 mpi3mr_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3143 		dma_addr_t *dma_addr, size_t *dma_len, void **p)
3144 {
3145 	/* Check if the request is split across multiple segments */
3146 	if (buf->sg_cnt > 1) {
3147 		*p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
3148 				GFP_KERNEL);
3149 		if (!*p)
3150 			return -ENOMEM;
3151 		*dma_len = buf->payload_len;
3152 	} else {
3153 		if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))
3154 			return -ENOMEM;
3155 		*dma_addr = sg_dma_address(buf->sg_list);
3156 		*dma_len = sg_dma_len(buf->sg_list);
3157 		*p = NULL;
3158 	}
3159 
3160 	return 0;
3161 }
3162 
3163 /**
3164  * mpi3mr_unmap_smp_buffer - unmap BSG dma buffer
3165  * @dev: Generic device reference
3166  * @buf: BSG buffer pointer
3167  * @dma_addr: Physical address to be unmapped
3168  * @p: Virtual address
3169  *
3170  * This function unmaps the DMAable buffer
3171  */
3172 static void
3173 mpi3mr_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3174 		dma_addr_t dma_addr, void *p)
3175 {
3176 	if (p)
3177 		dma_free_coherent(dev, buf->payload_len, p, dma_addr);
3178 	else
3179 		dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
3180 }
3181 
3182 /**
3183  * mpi3mr_transport_smp_handler - handler for smp passthru
3184  * @job: BSG job reference
3185  * @shost: SCSI host object reference
3186  * @rphy: SAS transport rphy object pointing the expander
3187  *
3188  * This is used primarily by smp utils for sending the SMP
3189  * commands to the expanders attached to the controller
3190  */
3191 static void
3192 mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
3193 	struct sas_rphy *rphy)
3194 {
3195 	struct mpi3mr_ioc *mrioc = shost_priv(shost);
3196 	struct mpi3_smp_passthrough_request mpi_request;
3197 	struct mpi3_smp_passthrough_reply mpi_reply;
3198 	int rc;
3199 	void *psge;
3200 	dma_addr_t dma_addr_in;
3201 	dma_addr_t dma_addr_out;
3202 	void *addr_in = NULL;
3203 	void *addr_out = NULL;
3204 	size_t dma_len_in;
3205 	size_t dma_len_out;
3206 	unsigned int reslen = 0;
3207 	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
3208 	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
3209 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
3210 	u16 ioc_status;
3211 
3212 	if (mrioc->reset_in_progress) {
3213 		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
3214 		rc = -EFAULT;
3215 		goto out;
3216 	}
3217 
3218 	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3219 	    &dma_addr_out, &dma_len_out, &addr_out);
3220 	if (rc)
3221 		goto out;
3222 
3223 	if (addr_out)
3224 		sg_copy_to_buffer(job->request_payload.sg_list,
3225 		    job->request_payload.sg_cnt, addr_out,
3226 		    job->request_payload.payload_len);
3227 
3228 	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3229 			&dma_addr_in, &dma_len_in, &addr_in);
3230 	if (rc)
3231 		goto unmap_out;
3232 
3233 	memset(&mpi_request, 0, request_sz);
3234 	memset(&mpi_reply, 0, reply_sz);
3235 	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
3236 	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
3237 	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_rphy(mrioc, rphy);
3238 	mpi_request.sas_address = ((rphy) ?
3239 	    cpu_to_le64(rphy->identify.sas_address) :
3240 	    cpu_to_le64(mrioc->sas_hba.sas_address));
3241 	psge = &mpi_request.request_sge;
3242 	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_out - 4, dma_addr_out);
3243 
3244 	psge = &mpi_request.response_sge;
3245 	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_in - 4, dma_addr_in);
3246 
3247 	dprint_transport_info(mrioc, "sending SMP request\n");
3248 
3249 	rc = mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
3250 				       &mpi_reply, reply_sz,
3251 				       MPI3MR_INTADMCMD_TIMEOUT, &ioc_status);
3252 	if (rc)
3253 		goto unmap_in;
3254 
3255 	dprint_transport_info(mrioc,
3256 	    "SMP request completed with ioc_status(0x%04x)\n", ioc_status);
3257 
3258 	dprint_transport_info(mrioc,
3259 		    "SMP request - reply data transfer size(%d)\n",
3260 		    le16_to_cpu(mpi_reply.response_data_length));
3261 
3262 	memcpy(job->reply, &mpi_reply, reply_sz);
3263 	job->reply_len = reply_sz;
3264 	reslen = le16_to_cpu(mpi_reply.response_data_length);
3265 
3266 	if (addr_in)
3267 		sg_copy_from_buffer(job->reply_payload.sg_list,
3268 				job->reply_payload.sg_cnt, addr_in,
3269 				job->reply_payload.payload_len);
3270 
3271 	rc = 0;
3272 unmap_in:
3273 	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3274 			dma_addr_in, addr_in);
3275 unmap_out:
3276 	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3277 			dma_addr_out, addr_out);
3278 out:
3279 	bsg_job_done(job, rc, reslen);
3280 }
3281 
3282 struct sas_function_template mpi3mr_transport_functions = {
3283 	.get_linkerrors		= mpi3mr_transport_get_linkerrors,
3284 	.get_enclosure_identifier = mpi3mr_transport_get_enclosure_identifier,
3285 	.get_bay_identifier	= mpi3mr_transport_get_bay_identifier,
3286 	.phy_reset		= mpi3mr_transport_phy_reset,
3287 	.phy_enable		= mpi3mr_transport_phy_enable,
3288 	.set_phy_speed		= mpi3mr_transport_phy_speed,
3289 	.smp_handler		= mpi3mr_transport_smp_handler,
3290 };
3291 
3292 struct scsi_transport_template *mpi3mr_transport_template;
3293