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