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