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