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