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