xref: /linux/drivers/scsi/mpi3mr/mpi3mr_transport.c (revision 189f164e573e18d9f8876dbd3ad8fcbe11f93037)
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 ((sas_port_add(port))) {
1432 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1433 		    __FILE__, __LINE__, __func__);
1434 		goto out_fail;
1435 	}
1436 
1437 	list_for_each_entry(mr_sas_phy, &mr_sas_port->phy_list,
1438 	    port_siblings) {
1439 		if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1440 			dev_info(&port->dev,
1441 			    "add: handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
1442 			    handle, (unsigned long long)
1443 			    mr_sas_port->remote_identify.sas_address,
1444 			    mr_sas_phy->phy_id);
1445 		sas_port_add_phy(port, mr_sas_phy->phy);
1446 		mr_sas_phy->phy_belongs_to_port = 1;
1447 		mr_sas_phy->hba_port = hba_port;
1448 	}
1449 
1450 	mr_sas_port->port = port;
1451 	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1452 		rphy = sas_end_device_alloc(port);
1453 		tgtdev->dev_spec.sas_sata_inf.rphy = rphy;
1454 	} else {
1455 		rphy = sas_expander_alloc(port,
1456 		    mr_sas_port->remote_identify.device_type);
1457 	}
1458 	rphy->identify = mr_sas_port->remote_identify;
1459 
1460 	if (mrioc->current_event)
1461 		mrioc->current_event->pending_at_sml = 1;
1462 
1463 	if ((sas_rphy_add(rphy))) {
1464 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1465 		    __FILE__, __LINE__, __func__);
1466 	}
1467 	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1468 		tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;
1469 		tgtdev->dev_spec.sas_sata_inf.sas_transport_attached = 1;
1470 		mpi3mr_tgtdev_put(tgtdev);
1471 	}
1472 
1473 	dev_info(&rphy->dev,
1474 	    "%s: added: handle(0x%04x), sas_address(0x%016llx)\n",
1475 	    __func__, handle, (unsigned long long)
1476 	    mr_sas_port->remote_identify.sas_address);
1477 
1478 	mr_sas_port->rphy = rphy;
1479 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1480 	list_add_tail(&mr_sas_port->port_list, &mr_sas_node->sas_port_list);
1481 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1482 
1483 	if (mrioc->current_event) {
1484 		mrioc->current_event->pending_at_sml = 0;
1485 		if (mrioc->current_event->discard)
1486 			mpi3mr_print_device_event_notice(mrioc, true);
1487 	}
1488 
1489 	/* fill in report manufacture */
1490 	if (mr_sas_port->remote_identify.device_type ==
1491 	    SAS_EDGE_EXPANDER_DEVICE ||
1492 	    mr_sas_port->remote_identify.device_type ==
1493 	    SAS_FANOUT_EXPANDER_DEVICE)
1494 		mpi3mr_report_manufacture(mrioc,
1495 		    mr_sas_port->remote_identify.sas_address,
1496 		    rphy_to_expander_device(rphy), hba_port->port_id);
1497 
1498 	return mr_sas_port;
1499 
1500  out_fail:
1501 	list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,
1502 	    port_siblings)
1503 		list_del(&mr_sas_phy->port_siblings);
1504 	kfree(mr_sas_port);
1505 	return NULL;
1506 }
1507 
1508 /**
1509  * mpi3mr_sas_port_remove - remove port from the list
1510  * @mrioc: Adapter instance reference
1511  * @sas_address: SAS address of attached device
1512  * @sas_address_parent: SAS address of parent expander or host
1513  * @hba_port: HBA port entry
1514  *
1515  * Removing object and freeing associated memory from the
1516  * sas_port_list.
1517  *
1518  * Return: None
1519  */
mpi3mr_sas_port_remove(struct mpi3mr_ioc * mrioc,u64 sas_address,u64 sas_address_parent,struct mpi3mr_hba_port * hba_port)1520 static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
1521 	u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
1522 {
1523 	int i;
1524 	unsigned long flags;
1525 	struct mpi3mr_sas_port *mr_sas_port, *next;
1526 	struct mpi3mr_sas_node *mr_sas_node;
1527 	u8 found = 0;
1528 	struct mpi3mr_sas_phy *mr_sas_phy, *next_phy;
1529 	struct mpi3mr_hba_port *srch_port, *hba_port_next = NULL;
1530 
1531 	if (!hba_port)
1532 		return;
1533 
1534 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1535 	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1536 	    sas_address_parent, hba_port);
1537 	if (!mr_sas_node) {
1538 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1539 		return;
1540 	}
1541 	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
1542 	    port_list) {
1543 		if (mr_sas_port->remote_identify.sas_address != sas_address)
1544 			continue;
1545 		if (mr_sas_port->hba_port != hba_port)
1546 			continue;
1547 		found = 1;
1548 		list_del(&mr_sas_port->port_list);
1549 		goto out;
1550 	}
1551 
1552  out:
1553 	if (!found) {
1554 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1555 		return;
1556 	}
1557 
1558 	if (mr_sas_node->host_node) {
1559 		list_for_each_entry_safe(srch_port, hba_port_next,
1560 		    &mrioc->hba_port_table_list, list) {
1561 			if (srch_port != hba_port)
1562 				continue;
1563 			ioc_info(mrioc,
1564 			    "removing hba_port entry: %p port: %d from hba_port list\n",
1565 			    srch_port, srch_port->port_id);
1566 			list_del(&hba_port->list);
1567 			kfree(hba_port);
1568 			break;
1569 		}
1570 	}
1571 
1572 	for (i = 0; i < mr_sas_node->num_phys; i++) {
1573 		if (mr_sas_node->phy[i].remote_identify.sas_address ==
1574 		    sas_address)
1575 			memset(&mr_sas_node->phy[i].remote_identify, 0,
1576 			    sizeof(struct sas_identify));
1577 	}
1578 
1579 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1580 
1581 	if (mrioc->current_event)
1582 		mrioc->current_event->pending_at_sml = 1;
1583 
1584 	list_for_each_entry_safe(mr_sas_phy, next_phy,
1585 	    &mr_sas_port->phy_list, port_siblings) {
1586 		if ((!mrioc->stop_drv_processing) &&
1587 		    (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1588 			dev_info(&mr_sas_port->port->dev,
1589 			    "remove: sas_address(0x%016llx), phy(%d)\n",
1590 			    (unsigned long long)
1591 			    mr_sas_port->remote_identify.sas_address,
1592 			    mr_sas_phy->phy_id);
1593 		mr_sas_phy->phy_belongs_to_port = 0;
1594 		if (!mrioc->stop_drv_processing)
1595 			sas_port_delete_phy(mr_sas_port->port,
1596 			    mr_sas_phy->phy);
1597 		list_del(&mr_sas_phy->port_siblings);
1598 	}
1599 	if (!mrioc->stop_drv_processing)
1600 		sas_port_delete(mr_sas_port->port);
1601 	ioc_info(mrioc, "%s: removed sas_address(0x%016llx)\n",
1602 	    __func__, (unsigned long long)sas_address);
1603 
1604 	if (mrioc->current_event) {
1605 		mrioc->current_event->pending_at_sml = 0;
1606 		if (mrioc->current_event->discard)
1607 			mpi3mr_print_device_event_notice(mrioc, false);
1608 	}
1609 
1610 	kfree(mr_sas_port);
1611 }
1612 
1613 /**
1614  * struct host_port - host port details
1615  * @sas_address: SAS Address of the attached device
1616  * @phy_mask: phy mask of host port
1617  * @handle: Device Handle of attached device
1618  * @iounit_port_id: port ID
1619  * @used: host port is already matched with sas port from sas_port_list
1620  * @lowest_phy: lowest phy ID of host port
1621  */
1622 struct host_port {
1623 	u64	sas_address;
1624 	u64	phy_mask;
1625 	u16	handle;
1626 	u8	iounit_port_id;
1627 	u8	used;
1628 	u8	lowest_phy;
1629 };
1630 
1631 /**
1632  * mpi3mr_update_mr_sas_port - update sas port objects during reset
1633  * @mrioc: Adapter instance reference
1634  * @h_port: host_port object
1635  * @mr_sas_port: sas_port objects which needs to be updated
1636  *
1637  * Update the port ID of sas port object. Also add the phys if new phys got
1638  * added to current sas port and remove the phys if some phys are moved
1639  * out of the current sas port.
1640  *
1641  * Return: Nothing.
1642  */
1643 static void
mpi3mr_update_mr_sas_port(struct mpi3mr_ioc * mrioc,struct host_port * h_port,struct mpi3mr_sas_port * mr_sas_port)1644 mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port,
1645 	struct mpi3mr_sas_port *mr_sas_port)
1646 {
1647 	struct mpi3mr_sas_phy *mr_sas_phy;
1648 	u64 phy_mask_xor;
1649 	u64 phys_to_be_added, phys_to_be_removed;
1650 	int i;
1651 
1652 	h_port->used = 1;
1653 	mr_sas_port->marked_responding = 1;
1654 
1655 	dev_info(&mr_sas_port->port->dev,
1656 	    "sas_address(0x%016llx), old: port_id %d phy_mask 0x%llx, new: port_id %d phy_mask:0x%llx\n",
1657 	    mr_sas_port->remote_identify.sas_address,
1658 	    mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask,
1659 	    h_port->iounit_port_id, h_port->phy_mask);
1660 
1661 	mr_sas_port->hba_port->port_id = h_port->iounit_port_id;
1662 	mr_sas_port->hba_port->flags &= ~MPI3MR_HBA_PORT_FLAG_DIRTY;
1663 
1664 	/* Get the newly added phys bit map & removed phys bit map */
1665 	phy_mask_xor = mr_sas_port->phy_mask ^ h_port->phy_mask;
1666 	phys_to_be_added = h_port->phy_mask & phy_mask_xor;
1667 	phys_to_be_removed = mr_sas_port->phy_mask & phy_mask_xor;
1668 
1669 	/*
1670 	 * Register these new phys to current mr_sas_port's port.
1671 	 * if these phys are previously registered with another port
1672 	 * then delete these phys from that port first.
1673 	 */
1674 	for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u64)) {
1675 		mr_sas_phy = &mrioc->sas_hba.phy[i];
1676 		if (mr_sas_phy->phy_belongs_to_port)
1677 			mpi3mr_del_phy_from_an_existing_port(mrioc,
1678 			    &mrioc->sas_hba, mr_sas_phy);
1679 		mpi3mr_add_phy_to_an_existing_port(mrioc,
1680 		    &mrioc->sas_hba, mr_sas_phy,
1681 		    mr_sas_port->remote_identify.sas_address,
1682 		    mr_sas_port->hba_port);
1683 	}
1684 
1685 	/* Delete the phys which are not part of current mr_sas_port's port. */
1686 	for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u64)) {
1687 		mr_sas_phy = &mrioc->sas_hba.phy[i];
1688 		if (mr_sas_phy->phy_belongs_to_port)
1689 			mpi3mr_del_phy_from_an_existing_port(mrioc,
1690 			    &mrioc->sas_hba, mr_sas_phy);
1691 	}
1692 }
1693 
1694 /**
1695  * mpi3mr_refresh_sas_ports - update host's sas ports during reset
1696  * @mrioc: Adapter instance reference
1697  *
1698  * Update the host's sas ports during reset by checking whether
1699  * sas ports are still intact or not. Add/remove phys if any hba
1700  * phys are (moved in)/(moved out) of sas port. Also update
1701  * io_unit_port if it got changed during reset.
1702  *
1703  * Return: Nothing.
1704  */
1705 void
mpi3mr_refresh_sas_ports(struct mpi3mr_ioc * mrioc)1706 mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
1707 {
1708 	struct host_port *h_port = NULL;
1709 	int i, j, found, host_port_count = 0, port_idx;
1710 	u16 sz, attached_handle, ioc_status;
1711 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1712 	struct mpi3_device_page0 dev_pg0;
1713 	struct mpi3_device0_sas_sata_format *sasinf;
1714 	struct mpi3mr_sas_port *mr_sas_port;
1715 
1716 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1717 		(mrioc->sas_hba.num_phys *
1718 		 sizeof(struct mpi3_sas_io_unit0_phy_data));
1719 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1720 	if (!sas_io_unit_pg0)
1721 		return;
1722 	h_port = kzalloc_objs(struct host_port, 64);
1723 	if (!h_port)
1724 		goto out;
1725 
1726 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1727 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1728 		    __FILE__, __LINE__, __func__);
1729 		goto out;
1730 	}
1731 
1732 	/* Create a new expander port table */
1733 	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1734 		attached_handle = le16_to_cpu(
1735 		    sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1736 		if (!attached_handle)
1737 			continue;
1738 		found = 0;
1739 		for (j = 0; j < host_port_count; j++) {
1740 			if (h_port[j].handle == attached_handle) {
1741 				h_port[j].phy_mask |= (1 << i);
1742 				found = 1;
1743 				break;
1744 			}
1745 		}
1746 		if (found)
1747 			continue;
1748 		if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
1749 		    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
1750 		    attached_handle))) {
1751 			dprint_reset(mrioc,
1752 			    "failed to read dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1753 			    attached_handle, __FILE__, __LINE__, __func__);
1754 			continue;
1755 		}
1756 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1757 			dprint_reset(mrioc,
1758 			    "ioc_status(0x%x) while reading dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1759 			    ioc_status, attached_handle,
1760 			    __FILE__, __LINE__, __func__);
1761 			continue;
1762 		}
1763 		sasinf = &dev_pg0.device_specific.sas_sata_format;
1764 
1765 		port_idx = host_port_count;
1766 		h_port[port_idx].sas_address = le64_to_cpu(sasinf->sas_address);
1767 		h_port[port_idx].handle = attached_handle;
1768 		h_port[port_idx].phy_mask = (1 << i);
1769 		h_port[port_idx].iounit_port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1770 		h_port[port_idx].lowest_phy = sasinf->phy_num;
1771 		h_port[port_idx].used = 0;
1772 		host_port_count++;
1773 	}
1774 
1775 	if (!host_port_count)
1776 		goto out;
1777 
1778 	if (mrioc->logging_level & MPI3_DEBUG_RESET) {
1779 		ioc_info(mrioc, "Host port details before reset\n");
1780 		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1781 		    port_list) {
1782 			ioc_info(mrioc,
1783 			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
1784 			    mr_sas_port->hba_port->port_id,
1785 			    mr_sas_port->remote_identify.sas_address,
1786 			    mr_sas_port->phy_mask, mr_sas_port->lowest_phy);
1787 		}
1788 		mr_sas_port = NULL;
1789 		ioc_info(mrioc, "Host port details after reset\n");
1790 		for (i = 0; i < host_port_count; i++) {
1791 			ioc_info(mrioc,
1792 			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
1793 			    h_port[i].iounit_port_id, h_port[i].sas_address,
1794 			    h_port[i].phy_mask, h_port[i].lowest_phy);
1795 		}
1796 	}
1797 
1798 	/* mark all host sas port entries as dirty */
1799 	list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1800 	    port_list) {
1801 		mr_sas_port->marked_responding = 0;
1802 		mr_sas_port->hba_port->flags |= MPI3MR_HBA_PORT_FLAG_DIRTY;
1803 	}
1804 
1805 	/* First check for matching lowest phy */
1806 	for (i = 0; i < host_port_count; i++) {
1807 		mr_sas_port = NULL;
1808 		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1809 		    port_list) {
1810 			if (mr_sas_port->marked_responding)
1811 				continue;
1812 			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1813 				continue;
1814 			if (h_port[i].lowest_phy == mr_sas_port->lowest_phy) {
1815 				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1816 				break;
1817 			}
1818 		}
1819 	}
1820 
1821 	/* In case if lowest phy is got enabled or disabled during reset */
1822 	for (i = 0; i < host_port_count; i++) {
1823 		if (h_port[i].used)
1824 			continue;
1825 		mr_sas_port = NULL;
1826 		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1827 		    port_list) {
1828 			if (mr_sas_port->marked_responding)
1829 				continue;
1830 			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1831 				continue;
1832 			if (h_port[i].phy_mask & mr_sas_port->phy_mask) {
1833 				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1834 				break;
1835 			}
1836 		}
1837 	}
1838 
1839 	/* In case if expander cable is removed & connected to another HBA port during reset */
1840 	for (i = 0; i < host_port_count; i++) {
1841 		if (h_port[i].used)
1842 			continue;
1843 		mr_sas_port = NULL;
1844 		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1845 		    port_list) {
1846 			if (mr_sas_port->marked_responding)
1847 				continue;
1848 			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1849 				continue;
1850 			mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1851 			break;
1852 		}
1853 	}
1854 out:
1855 	kfree(h_port);
1856 	kfree(sas_io_unit_pg0);
1857 }
1858 
1859 /**
1860  * mpi3mr_refresh_expanders - Refresh expander device exposure
1861  * @mrioc: Adapter instance reference
1862  *
1863  * This is executed post controller reset to identify any
1864  * missing expander devices during reset and remove from the upper layers
1865  * or expose any newly detected expander device to the upper layers.
1866  *
1867  * Return: Nothing.
1868  */
1869 void
mpi3mr_refresh_expanders(struct mpi3mr_ioc * mrioc)1870 mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc)
1871 {
1872 	struct mpi3mr_sas_node *sas_expander, *sas_expander_next;
1873 	struct mpi3_sas_expander_page0 expander_pg0;
1874 	u16 ioc_status, handle;
1875 	u64 sas_address;
1876 	int i;
1877 	unsigned long flags;
1878 	struct mpi3mr_hba_port *hba_port;
1879 
1880 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1881 	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
1882 		sas_expander->non_responding = 1;
1883 	}
1884 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1885 
1886 	sas_expander = NULL;
1887 
1888 	handle = 0xffff;
1889 
1890 	/* Search for responding expander devices and add them if they are newly got added */
1891 	while (true) {
1892 		if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
1893 		    sizeof(struct mpi3_sas_expander_page0),
1894 		    MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
1895 			dprint_reset(mrioc,
1896 			    "failed to read exp pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1897 			    handle, __FILE__, __LINE__, __func__);
1898 			break;
1899 		}
1900 
1901 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1902 			dprint_reset(mrioc,
1903 			   "ioc_status(0x%x) while reading exp pg0 for handle:(0x%04x), %s:%d/%s()!\n",
1904 			   ioc_status, handle, __FILE__, __LINE__, __func__);
1905 			break;
1906 		}
1907 
1908 		handle = le16_to_cpu(expander_pg0.dev_handle);
1909 		sas_address = le64_to_cpu(expander_pg0.sas_address);
1910 		hba_port = mpi3mr_get_hba_port_by_id(mrioc, expander_pg0.io_unit_port);
1911 
1912 		if (!hba_port) {
1913 			mpi3mr_sas_host_refresh(mrioc);
1914 			mpi3mr_expander_add(mrioc, handle);
1915 			continue;
1916 		}
1917 
1918 		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1919 		sas_expander =
1920 		    mpi3mr_expander_find_by_sas_address(mrioc,
1921 		    sas_address, hba_port);
1922 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1923 
1924 		if (!sas_expander) {
1925 			mpi3mr_sas_host_refresh(mrioc);
1926 			mpi3mr_expander_add(mrioc, handle);
1927 			continue;
1928 		}
1929 
1930 		sas_expander->non_responding = 0;
1931 		if (sas_expander->handle == handle)
1932 			continue;
1933 
1934 		sas_expander->handle = handle;
1935 		for (i = 0 ; i < sas_expander->num_phys ; i++)
1936 			sas_expander->phy[i].handle = handle;
1937 	}
1938 
1939 	/*
1940 	 * Delete non responding expander devices and the corresponding
1941 	 * hba_port if the non responding expander device's parent device
1942 	 * is a host node.
1943 	 */
1944 	sas_expander = NULL;
1945 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1946 	list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
1947 	    &mrioc->sas_expander_list, list) {
1948 		if (sas_expander->non_responding) {
1949 			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1950 			mpi3mr_expander_node_remove(mrioc, sas_expander);
1951 			spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1952 		}
1953 	}
1954 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1955 }
1956 
1957 /**
1958  * mpi3mr_expander_node_add - insert an expander to the list.
1959  * @mrioc: Adapter instance reference
1960  * @sas_expander: Expander sas node
1961  * Context: This function will acquire sas_node_lock.
1962  *
1963  * Adding new object to the ioc->sas_expander_list.
1964  *
1965  * Return: None.
1966  */
mpi3mr_expander_node_add(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_node * sas_expander)1967 static void mpi3mr_expander_node_add(struct mpi3mr_ioc *mrioc,
1968 	struct mpi3mr_sas_node *sas_expander)
1969 {
1970 	unsigned long flags;
1971 
1972 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1973 	list_add_tail(&sas_expander->list, &mrioc->sas_expander_list);
1974 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1975 }
1976 
1977 /**
1978  * mpi3mr_expander_add -  Create expander object
1979  * @mrioc: Adapter instance reference
1980  * @handle: Expander firmware device handle
1981  *
1982  * This function creating expander object, stored in
1983  * sas_expander_list and expose it to the SAS transport
1984  * layer.
1985  *
1986  * Return: 0 for success, non-zero for failure.
1987  */
mpi3mr_expander_add(struct mpi3mr_ioc * mrioc,u16 handle)1988 int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)
1989 {
1990 	struct mpi3mr_sas_node *sas_expander;
1991 	struct mpi3mr_enclosure_node *enclosure_dev;
1992 	struct mpi3_sas_expander_page0 expander_pg0;
1993 	struct mpi3_sas_expander_page1 expander_pg1;
1994 	u16 ioc_status, parent_handle, temp_handle;
1995 	u64 sas_address, sas_address_parent = 0;
1996 	int i;
1997 	unsigned long flags;
1998 	u8 port_id, link_rate;
1999 	struct mpi3mr_sas_port *mr_sas_port = NULL;
2000 	struct mpi3mr_hba_port *hba_port;
2001 	u32 phynum_handle;
2002 	int rc = 0;
2003 
2004 	if (!handle)
2005 		return -1;
2006 
2007 	if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
2008 		return -1;
2009 
2010 	if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
2011 	    sizeof(expander_pg0), MPI3_SAS_EXPAND_PGAD_FORM_HANDLE, handle))) {
2012 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2013 		    __FILE__, __LINE__, __func__);
2014 		return -1;
2015 	}
2016 
2017 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2018 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2019 		    __FILE__, __LINE__, __func__);
2020 		return -1;
2021 	}
2022 
2023 	parent_handle = le16_to_cpu(expander_pg0.parent_dev_handle);
2024 	if (mpi3mr_get_sas_address(mrioc, parent_handle, &sas_address_parent)
2025 	    != 0) {
2026 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2027 		    __FILE__, __LINE__, __func__);
2028 		return -1;
2029 	}
2030 
2031 	port_id = expander_pg0.io_unit_port;
2032 	hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
2033 	if (!hba_port) {
2034 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2035 		    __FILE__, __LINE__, __func__);
2036 		return -1;
2037 	}
2038 
2039 	if (sas_address_parent != mrioc->sas_hba.sas_address) {
2040 		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2041 		sas_expander =
2042 		   mpi3mr_expander_find_by_sas_address(mrioc,
2043 		    sas_address_parent, hba_port);
2044 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2045 		if (!sas_expander) {
2046 			rc = mpi3mr_expander_add(mrioc, parent_handle);
2047 			if (rc != 0)
2048 				return rc;
2049 		} else {
2050 			/*
2051 			 * When there is a parent expander present, update it's
2052 			 * phys where child expander is connected with the link
2053 			 * speed, attached dev handle and sas address.
2054 			 */
2055 			for (i = 0 ; i < sas_expander->num_phys ; i++) {
2056 				phynum_handle =
2057 				    (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2058 				    parent_handle;
2059 				if (mpi3mr_cfg_get_sas_exp_pg1(mrioc,
2060 				    &ioc_status, &expander_pg1,
2061 				    sizeof(expander_pg1),
2062 				    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2063 				    phynum_handle)) {
2064 					ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2065 					    __FILE__, __LINE__, __func__);
2066 					rc = -1;
2067 					return rc;
2068 				}
2069 				if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2070 					ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2071 					    __FILE__, __LINE__, __func__);
2072 					rc = -1;
2073 					return rc;
2074 				}
2075 				temp_handle = le16_to_cpu(
2076 				    expander_pg1.attached_dev_handle);
2077 				if (temp_handle != handle)
2078 					continue;
2079 				link_rate = (expander_pg1.negotiated_link_rate &
2080 				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2081 				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2082 				if (link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)
2083 					link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;
2084 				mpi3mr_update_links(mrioc, sas_address_parent,
2085 				    handle, i, link_rate, hba_port);
2086 			}
2087 		}
2088 	}
2089 
2090 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2091 	sas_address = le64_to_cpu(expander_pg0.sas_address);
2092 	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc,
2093 	    sas_address, hba_port);
2094 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2095 
2096 	if (sas_expander)
2097 		return 0;
2098 
2099 	sas_expander = kzalloc_obj(struct mpi3mr_sas_node);
2100 	if (!sas_expander)
2101 		return -ENOMEM;
2102 
2103 	sas_expander->handle = handle;
2104 	sas_expander->num_phys = expander_pg0.num_phys;
2105 	sas_expander->sas_address_parent = sas_address_parent;
2106 	sas_expander->sas_address = sas_address;
2107 	sas_expander->hba_port = hba_port;
2108 
2109 	ioc_info(mrioc,
2110 	    "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
2111 	    handle, parent_handle, (unsigned long long)
2112 	    sas_expander->sas_address, sas_expander->num_phys);
2113 
2114 	if (!sas_expander->num_phys) {
2115 		rc = -1;
2116 		goto out_fail;
2117 	}
2118 	sas_expander->phy = kzalloc_objs(struct mpi3mr_sas_phy,
2119 					 sas_expander->num_phys);
2120 	if (!sas_expander->phy) {
2121 		rc = -1;
2122 		goto out_fail;
2123 	}
2124 
2125 	INIT_LIST_HEAD(&sas_expander->sas_port_list);
2126 	mr_sas_port = mpi3mr_sas_port_add(mrioc, handle, sas_address_parent,
2127 	    sas_expander->hba_port);
2128 	if (!mr_sas_port) {
2129 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2130 		    __FILE__, __LINE__, __func__);
2131 		rc = -1;
2132 		goto out_fail;
2133 	}
2134 	sas_expander->parent_dev = &mr_sas_port->rphy->dev;
2135 	sas_expander->rphy = mr_sas_port->rphy;
2136 
2137 	for (i = 0 ; i < sas_expander->num_phys ; i++) {
2138 		phynum_handle = (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2139 		    handle;
2140 		if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2141 		    &expander_pg1, sizeof(expander_pg1),
2142 		    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2143 		    phynum_handle)) {
2144 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2145 			    __FILE__, __LINE__, __func__);
2146 			rc = -1;
2147 			goto out_fail;
2148 		}
2149 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2150 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2151 			    __FILE__, __LINE__, __func__);
2152 			rc = -1;
2153 			goto out_fail;
2154 		}
2155 
2156 		sas_expander->phy[i].handle = handle;
2157 		sas_expander->phy[i].phy_id = i;
2158 		sas_expander->phy[i].hba_port = hba_port;
2159 
2160 		if ((mpi3mr_add_expander_phy(mrioc, &sas_expander->phy[i],
2161 		    expander_pg1, sas_expander->parent_dev))) {
2162 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2163 			    __FILE__, __LINE__, __func__);
2164 			rc = -1;
2165 			goto out_fail;
2166 		}
2167 	}
2168 
2169 	if (sas_expander->enclosure_handle) {
2170 		enclosure_dev =
2171 			mpi3mr_enclosure_find_by_handle(mrioc,
2172 						sas_expander->enclosure_handle);
2173 		if (enclosure_dev)
2174 			sas_expander->enclosure_logical_id = le64_to_cpu(
2175 			    enclosure_dev->pg0.enclosure_logical_id);
2176 	}
2177 
2178 	mpi3mr_expander_node_add(mrioc, sas_expander);
2179 	return 0;
2180 
2181 out_fail:
2182 
2183 	if (mr_sas_port)
2184 		mpi3mr_sas_port_remove(mrioc,
2185 		    sas_expander->sas_address,
2186 		    sas_address_parent, sas_expander->hba_port);
2187 	kfree(sas_expander->phy);
2188 	kfree(sas_expander);
2189 	return rc;
2190 }
2191 
2192 /**
2193  * mpi3mr_expander_node_remove - recursive removal of expander.
2194  * @mrioc: Adapter instance reference
2195  * @sas_expander: Expander device object
2196  *
2197  * Removes expander object and freeing associated memory from
2198  * the sas_expander_list and removes the same from SAS TL, if
2199  * one of the attached device is an expander then it recursively
2200  * removes the expander device too.
2201  *
2202  * Return nothing.
2203  */
mpi3mr_expander_node_remove(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_node * sas_expander)2204 void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
2205 	struct mpi3mr_sas_node *sas_expander)
2206 {
2207 	struct mpi3mr_sas_port *mr_sas_port, *next;
2208 	unsigned long flags;
2209 	u8 port_id;
2210 
2211 	/* remove sibling ports attached to this expander */
2212 	list_for_each_entry_safe(mr_sas_port, next,
2213 	   &sas_expander->sas_port_list, port_list) {
2214 		if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
2215 			return;
2216 		if (mr_sas_port->remote_identify.device_type ==
2217 		    SAS_END_DEVICE)
2218 			mpi3mr_remove_device_by_sas_address(mrioc,
2219 			    mr_sas_port->remote_identify.sas_address,
2220 			    mr_sas_port->hba_port);
2221 		else if (mr_sas_port->remote_identify.device_type ==
2222 		    SAS_EDGE_EXPANDER_DEVICE ||
2223 		    mr_sas_port->remote_identify.device_type ==
2224 		    SAS_FANOUT_EXPANDER_DEVICE)
2225 			mpi3mr_expander_remove(mrioc,
2226 			    mr_sas_port->remote_identify.sas_address,
2227 			    mr_sas_port->hba_port);
2228 	}
2229 
2230 	port_id = sas_expander->hba_port->port_id;
2231 	mpi3mr_sas_port_remove(mrioc, sas_expander->sas_address,
2232 	    sas_expander->sas_address_parent, sas_expander->hba_port);
2233 
2234 	ioc_info(mrioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n",
2235 	    sas_expander->handle, (unsigned long long)
2236 	    sas_expander->sas_address, port_id);
2237 
2238 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2239 	list_del(&sas_expander->list);
2240 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2241 
2242 	kfree(sas_expander->phy);
2243 	kfree(sas_expander);
2244 }
2245 
2246 /**
2247  * mpi3mr_expander_remove - Remove expander object
2248  * @mrioc: Adapter instance reference
2249  * @sas_address: Remove expander sas_address
2250  * @hba_port: HBA port reference
2251  *
2252  * This function remove expander object, stored in
2253  * mrioc->sas_expander_list and removes it from the SAS TL by
2254  * calling mpi3mr_expander_node_remove().
2255  *
2256  * Return: None
2257  */
mpi3mr_expander_remove(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)2258 void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
2259 	struct mpi3mr_hba_port *hba_port)
2260 {
2261 	struct mpi3mr_sas_node *sas_expander;
2262 	unsigned long flags;
2263 
2264 	if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
2265 		return;
2266 
2267 	if (!hba_port)
2268 		return;
2269 
2270 	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2271 	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
2272 	    hba_port);
2273 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2274 	if (sas_expander)
2275 		mpi3mr_expander_node_remove(mrioc, sas_expander);
2276 
2277 }
2278 
2279 /**
2280  * mpi3mr_get_sas_negotiated_logical_linkrate - get linkrate
2281  * @mrioc: Adapter instance reference
2282  * @tgtdev: Target device
2283  *
2284  * This function first tries to use the link rate from DevicePage0
2285  * (populated by firmware during device discovery). If the cached
2286  * value is not available or invalid, it falls back to reading from
2287  * sas phy page0 or expander phy page1.
2288  *
2289  *
2290  * Return: logical link rate.
2291  */
mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)2292 static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc,
2293 	struct mpi3mr_tgt_dev *tgtdev)
2294 {
2295 	u8 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5, phy_number;
2296 	struct mpi3_sas_expander_page1 expander_pg1;
2297 	struct mpi3_sas_phy_page0 phy_pg0;
2298 	u32 phynum_handle;
2299 	u16 ioc_status;
2300 
2301 	/* First, try to use link rate from DevicePage0 (populated by firmware) */
2302 	if (tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate >=
2303 	    MPI3_SAS_NEG_LINK_RATE_1_5) {
2304 		link_rate = tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate;
2305 		goto out;
2306 	}
2307 
2308 	/* Fallback to reading from phy pages if DevicePage0 value not available */
2309 	phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2310 	if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) {
2311 		phynum_handle = ((phy_number<<MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT)
2312 				 | tgtdev->parent_handle);
2313 		if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2314 		    &expander_pg1, sizeof(expander_pg1),
2315 		    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2316 		    phynum_handle)) {
2317 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2318 			    __FILE__, __LINE__, __func__);
2319 			goto out;
2320 		}
2321 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2322 			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2323 			    __FILE__, __LINE__, __func__);
2324 			goto out;
2325 		}
2326 		link_rate = expander_pg1.negotiated_link_rate;
2327 		goto out;
2328 	}
2329 	if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
2330 	    sizeof(struct mpi3_sas_phy_page0),
2331 	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy_number)) {
2332 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2333 		    __FILE__, __LINE__, __func__);
2334 		goto out;
2335 	}
2336 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2337 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2338 		    __FILE__, __LINE__, __func__);
2339 		goto out;
2340 	}
2341 	link_rate = phy_pg0.negotiated_link_rate;
2342 
2343 out:
2344 	return ((link_rate & MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2345 		MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
2346 }
2347 
2348 /**
2349  * mpi3mr_report_tgtdev_to_sas_transport - expose dev to SAS TL
2350  * @mrioc: Adapter instance reference
2351  * @tgtdev: Target device
2352  *
2353  * This function exposes the target device after
2354  * preparing host_phy, setting up link rate etc.
2355  *
2356  * Return: 0 on success, non-zero for failure.
2357  */
mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)2358 int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc,
2359 	struct mpi3mr_tgt_dev *tgtdev)
2360 {
2361 	int retval = 0;
2362 	u8 link_rate, parent_phy_number;
2363 	u64 sas_address_parent, sas_address;
2364 	struct mpi3mr_hba_port *hba_port;
2365 	u8 port_id;
2366 
2367 	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2368 	    !mrioc->sas_transport_enabled)
2369 		return -1;
2370 
2371 	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2372 	if (!mrioc->sas_hba.num_phys)
2373 		mpi3mr_sas_host_add(mrioc);
2374 	else
2375 		mpi3mr_sas_host_refresh(mrioc);
2376 
2377 	if (mpi3mr_get_sas_address(mrioc, tgtdev->parent_handle,
2378 	    &sas_address_parent) != 0) {
2379 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2380 		    __FILE__, __LINE__, __func__);
2381 		return -1;
2382 	}
2383 	tgtdev->dev_spec.sas_sata_inf.sas_address_parent = sas_address_parent;
2384 
2385 	parent_phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2386 	port_id = tgtdev->io_unit_port;
2387 
2388 	hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
2389 	if (!hba_port) {
2390 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2391 		    __FILE__, __LINE__, __func__);
2392 		return -1;
2393 	}
2394 	tgtdev->dev_spec.sas_sata_inf.hba_port = hba_port;
2395 
2396 	link_rate = mpi3mr_get_sas_negotiated_logical_linkrate(mrioc, tgtdev);
2397 
2398 	if (link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)
2399 		link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;
2400 
2401 	mpi3mr_update_links(mrioc, sas_address_parent, tgtdev->dev_handle,
2402 	    parent_phy_number, link_rate, hba_port);
2403 
2404 	tgtdev->host_exposed = 1;
2405 	if (!mpi3mr_sas_port_add(mrioc, tgtdev->dev_handle,
2406 	    sas_address_parent, hba_port)) {
2407 		retval = -1;
2408 		} else if ((!tgtdev->starget) && (!mrioc->is_driver_loading)) {
2409 			mpi3mr_sas_port_remove(mrioc, sas_address,
2410 			    sas_address_parent, hba_port);
2411 		retval = -1;
2412 	}
2413 	if (retval) {
2414 		tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2415 		tgtdev->host_exposed = 0;
2416 	}
2417 	return retval;
2418 }
2419 
2420 /**
2421  * mpi3mr_remove_tgtdev_from_sas_transport - remove from SAS TL
2422  * @mrioc: Adapter instance reference
2423  * @tgtdev: Target device
2424  *
2425  * This function removes the target device
2426  *
2427  * Return: None.
2428  */
mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)2429 void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
2430 	struct mpi3mr_tgt_dev *tgtdev)
2431 {
2432 	u64 sas_address_parent, sas_address;
2433 	struct mpi3mr_hba_port *hba_port;
2434 
2435 	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2436 	    !mrioc->sas_transport_enabled)
2437 		return;
2438 
2439 	hba_port = tgtdev->dev_spec.sas_sata_inf.hba_port;
2440 	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2441 	sas_address_parent = tgtdev->dev_spec.sas_sata_inf.sas_address_parent;
2442 	mpi3mr_sas_port_remove(mrioc, sas_address, sas_address_parent,
2443 	    hba_port);
2444 	tgtdev->host_exposed = 0;
2445 	tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2446 }
2447 
2448 /**
2449  * mpi3mr_get_port_id_by_sas_phy -  Get port ID of the given phy
2450  * @phy: SAS transport layer phy object
2451  *
2452  * Return: Port number for valid ID else 0xFFFF
2453  */
mpi3mr_get_port_id_by_sas_phy(struct sas_phy * phy)2454 static inline u8 mpi3mr_get_port_id_by_sas_phy(struct sas_phy *phy)
2455 {
2456 	u8 port_id = 0xFF;
2457 	struct mpi3mr_hba_port *hba_port = phy->hostdata;
2458 
2459 	if (hba_port)
2460 		port_id = hba_port->port_id;
2461 
2462 	return port_id;
2463 }
2464 
2465 /**
2466  * mpi3mr_get_port_id_by_rphy - Get Port number from SAS rphy
2467  *
2468  * @mrioc: Adapter instance reference
2469  * @rphy: SAS transport layer remote phy object
2470  *
2471  * Retrieves HBA port number in which the device pointed by the
2472  * rphy object is attached with.
2473  *
2474  * Return: Valid port number on success else OxFFFF.
2475  */
mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc * mrioc,struct sas_rphy * rphy)2476 static u8 mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc *mrioc, struct sas_rphy *rphy)
2477 {
2478 	struct mpi3mr_sas_node *sas_expander;
2479 	struct mpi3mr_tgt_dev *tgtdev;
2480 	unsigned long flags;
2481 	u8 port_id = 0xFF;
2482 
2483 	if (!rphy)
2484 		return port_id;
2485 
2486 	if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
2487 	    rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {
2488 		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2489 		list_for_each_entry(sas_expander, &mrioc->sas_expander_list,
2490 		    list) {
2491 			if (sas_expander->rphy == rphy) {
2492 				port_id = sas_expander->hba_port->port_id;
2493 				break;
2494 			}
2495 		}
2496 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2497 	} else if (rphy->identify.device_type == SAS_END_DEVICE) {
2498 		spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2499 
2500 		tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2501 			    rphy->identify.sas_address, rphy);
2502 		if (tgtdev && tgtdev->dev_spec.sas_sata_inf.hba_port) {
2503 			port_id =
2504 				tgtdev->dev_spec.sas_sata_inf.hba_port->port_id;
2505 			mpi3mr_tgtdev_put(tgtdev);
2506 		}
2507 		spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2508 	}
2509 	return port_id;
2510 }
2511 
phy_to_mrioc(struct sas_phy * phy)2512 static inline struct mpi3mr_ioc *phy_to_mrioc(struct sas_phy *phy)
2513 {
2514 	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
2515 
2516 	return shost_priv(shost);
2517 }
2518 
rphy_to_mrioc(struct sas_rphy * rphy)2519 static inline struct mpi3mr_ioc *rphy_to_mrioc(struct sas_rphy *rphy)
2520 {
2521 	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
2522 
2523 	return shost_priv(shost);
2524 }
2525 
2526 /* report phy error log structure */
2527 struct phy_error_log_request {
2528 	u8 smp_frame_type; /* 0x40 */
2529 	u8 function; /* 0x11 */
2530 	u8 allocated_response_length;
2531 	u8 request_length; /* 02 */
2532 	u8 reserved_1[5];
2533 	u8 phy_identifier;
2534 	u8 reserved_2[2];
2535 };
2536 
2537 /* report phy error log reply structure */
2538 struct phy_error_log_reply {
2539 	u8 smp_frame_type; /* 0x41 */
2540 	u8 function; /* 0x11 */
2541 	u8 function_result;
2542 	u8 response_length;
2543 	__be16 expander_change_count;
2544 	u8 reserved_1[3];
2545 	u8 phy_identifier;
2546 	u8 reserved_2[2];
2547 	__be32 invalid_dword;
2548 	__be32 running_disparity_error;
2549 	__be32 loss_of_dword_sync;
2550 	__be32 phy_reset_problem;
2551 };
2552 
2553 
2554 /**
2555  * mpi3mr_get_expander_phy_error_log - return expander counters:
2556  * @mrioc: Adapter instance reference
2557  * @phy: The SAS transport layer phy object
2558  *
2559  * Return: 0 for success, non-zero for failure.
2560  *
2561  */
mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc * mrioc,struct sas_phy * phy)2562 static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
2563 	struct sas_phy *phy)
2564 {
2565 	struct mpi3_smp_passthrough_request mpi_request;
2566 	struct mpi3_smp_passthrough_reply mpi_reply;
2567 	struct phy_error_log_request *phy_error_log_request;
2568 	struct phy_error_log_reply *phy_error_log_reply;
2569 	int rc;
2570 	void *psge;
2571 	void *data_out = NULL;
2572 	dma_addr_t data_out_dma, data_in_dma;
2573 	u32 data_out_sz, data_in_sz, sz;
2574 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2575 	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2576 	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2577 	u16 ioc_status;
2578 
2579 	if (mrioc->reset_in_progress) {
2580 		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2581 		return -EFAULT;
2582 	}
2583 
2584 	if (mrioc->pci_err_recovery) {
2585 		ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
2586 		return -EFAULT;
2587 	}
2588 
2589 	data_out_sz = sizeof(struct phy_error_log_request);
2590 	data_in_sz = sizeof(struct phy_error_log_reply);
2591 	sz = data_out_sz + data_in_sz;
2592 	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2593 	    GFP_KERNEL);
2594 	if (!data_out) {
2595 		rc = -ENOMEM;
2596 		goto out;
2597 	}
2598 
2599 	data_in_dma = data_out_dma + data_out_sz;
2600 	phy_error_log_reply = data_out + data_out_sz;
2601 
2602 	rc = -EINVAL;
2603 	memset(data_out, 0, sz);
2604 	phy_error_log_request = data_out;
2605 	phy_error_log_request->smp_frame_type = 0x40;
2606 	phy_error_log_request->function = 0x11;
2607 	phy_error_log_request->request_length = 2;
2608 	phy_error_log_request->allocated_response_length = 0;
2609 	phy_error_log_request->phy_identifier = phy->number;
2610 
2611 	memset(&mpi_request, 0, request_sz);
2612 	memset(&mpi_reply, 0, reply_sz);
2613 	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2614 	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2615 	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2616 	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2617 
2618 	psge = &mpi_request.request_sge;
2619 	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2620 
2621 	psge = &mpi_request.response_sge;
2622 	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2623 
2624 	dprint_transport_info(mrioc,
2625 	    "sending phy error log SMP request to sas_address(0x%016llx), phy_id(%d)\n",
2626 	    (unsigned long long)phy->identify.sas_address, phy->number);
2627 
2628 	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2629 	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2630 		goto out;
2631 
2632 	dprint_transport_info(mrioc,
2633 	    "phy error log SMP request completed with ioc_status(0x%04x)\n",
2634 	    ioc_status);
2635 
2636 	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2637 		dprint_transport_info(mrioc,
2638 		    "phy error log - reply data transfer size(%d)\n",
2639 		    le16_to_cpu(mpi_reply.response_data_length));
2640 
2641 		if (le16_to_cpu(mpi_reply.response_data_length) !=
2642 		    sizeof(struct phy_error_log_reply))
2643 			goto out;
2644 
2645 		dprint_transport_info(mrioc,
2646 		    "phy error log - function_result(%d)\n",
2647 		    phy_error_log_reply->function_result);
2648 
2649 		phy->invalid_dword_count =
2650 		    be32_to_cpu(phy_error_log_reply->invalid_dword);
2651 		phy->running_disparity_error_count =
2652 		    be32_to_cpu(phy_error_log_reply->running_disparity_error);
2653 		phy->loss_of_dword_sync_count =
2654 		    be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
2655 		phy->phy_reset_problem_count =
2656 		    be32_to_cpu(phy_error_log_reply->phy_reset_problem);
2657 		rc = 0;
2658 	}
2659 
2660 out:
2661 	if (data_out)
2662 		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2663 		    data_out_dma);
2664 
2665 	return rc;
2666 }
2667 
2668 /**
2669  * mpi3mr_transport_get_linkerrors - return phy error counters
2670  * @phy: The SAS transport layer phy object
2671  *
2672  * This function retrieves the phy error log information of the
2673  * HBA or expander for which the phy belongs to
2674  *
2675  * Return: 0 for success, non-zero for failure.
2676  */
mpi3mr_transport_get_linkerrors(struct sas_phy * phy)2677 static int mpi3mr_transport_get_linkerrors(struct sas_phy *phy)
2678 {
2679 	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2680 	struct mpi3_sas_phy_page1 phy_pg1;
2681 	int rc = 0;
2682 	u16 ioc_status;
2683 
2684 	rc = mpi3mr_parent_present(mrioc, phy);
2685 	if (rc)
2686 		return rc;
2687 
2688 	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2689 		return mpi3mr_get_expander_phy_error_log(mrioc, phy);
2690 
2691 	memset(&phy_pg1, 0, sizeof(struct mpi3_sas_phy_page1));
2692 	/* get hba phy error logs */
2693 	if ((mpi3mr_cfg_get_sas_phy_pg1(mrioc, &ioc_status, &phy_pg1,
2694 	    sizeof(struct mpi3_sas_phy_page1),
2695 	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number))) {
2696 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2697 		    __FILE__, __LINE__, __func__);
2698 		return -ENXIO;
2699 	}
2700 
2701 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2702 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2703 		    __FILE__, __LINE__, __func__);
2704 		return -ENXIO;
2705 	}
2706 	phy->invalid_dword_count = le32_to_cpu(phy_pg1.invalid_dword_count);
2707 	phy->running_disparity_error_count =
2708 		le32_to_cpu(phy_pg1.running_disparity_error_count);
2709 	phy->loss_of_dword_sync_count =
2710 		le32_to_cpu(phy_pg1.loss_dword_synch_count);
2711 	phy->phy_reset_problem_count =
2712 		le32_to_cpu(phy_pg1.phy_reset_problem_count);
2713 	return 0;
2714 }
2715 
2716 /**
2717  * mpi3mr_transport_get_enclosure_identifier - Get Enclosure ID
2718  * @rphy: The SAS transport layer remote phy object
2719  * @identifier: Enclosure identifier to be returned
2720  *
2721  * Returns the enclosure id for the device pointed by the remote
2722  * phy object.
2723  *
2724  * Return: 0 on success or -ENXIO
2725  */
2726 static int
mpi3mr_transport_get_enclosure_identifier(struct sas_rphy * rphy,u64 * identifier)2727 mpi3mr_transport_get_enclosure_identifier(struct sas_rphy *rphy,
2728 	u64 *identifier)
2729 {
2730 	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2731 	struct mpi3mr_tgt_dev *tgtdev = NULL;
2732 	unsigned long flags;
2733 	int rc;
2734 
2735 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2736 	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2737 	    rphy->identify.sas_address, rphy);
2738 	if (tgtdev) {
2739 		*identifier =
2740 			tgtdev->enclosure_logical_id;
2741 		rc = 0;
2742 		mpi3mr_tgtdev_put(tgtdev);
2743 	} else {
2744 		*identifier = 0;
2745 		rc = -ENXIO;
2746 	}
2747 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2748 
2749 	return rc;
2750 }
2751 
2752 /**
2753  * mpi3mr_transport_get_bay_identifier - Get bay ID
2754  * @rphy: The SAS transport layer remote phy object
2755  *
2756  * Returns the slot id for the device pointed by the remote phy
2757  * object.
2758  *
2759  * Return: Valid slot ID on success or -ENXIO
2760  */
2761 static int
mpi3mr_transport_get_bay_identifier(struct sas_rphy * rphy)2762 mpi3mr_transport_get_bay_identifier(struct sas_rphy *rphy)
2763 {
2764 	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2765 	struct mpi3mr_tgt_dev *tgtdev = NULL;
2766 	unsigned long flags;
2767 	int rc;
2768 
2769 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2770 	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2771 	    rphy->identify.sas_address, rphy);
2772 	if (tgtdev) {
2773 		rc = tgtdev->slot;
2774 		mpi3mr_tgtdev_put(tgtdev);
2775 	} else
2776 		rc = -ENXIO;
2777 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2778 
2779 	return rc;
2780 }
2781 
2782 /* phy control request structure */
2783 struct phy_control_request {
2784 	u8 smp_frame_type; /* 0x40 */
2785 	u8 function; /* 0x91 */
2786 	u8 allocated_response_length;
2787 	u8 request_length; /* 0x09 */
2788 	u16 expander_change_count;
2789 	u8 reserved_1[3];
2790 	u8 phy_identifier;
2791 	u8 phy_operation;
2792 	u8 reserved_2[13];
2793 	u64 attached_device_name;
2794 	u8 programmed_min_physical_link_rate;
2795 	u8 programmed_max_physical_link_rate;
2796 	u8 reserved_3[6];
2797 };
2798 
2799 /* phy control reply structure */
2800 struct phy_control_reply {
2801 	u8 smp_frame_type; /* 0x41 */
2802 	u8 function; /* 0x11 */
2803 	u8 function_result;
2804 	u8 response_length;
2805 };
2806 
2807 #define SMP_PHY_CONTROL_LINK_RESET	(0x01)
2808 #define SMP_PHY_CONTROL_HARD_RESET	(0x02)
2809 #define SMP_PHY_CONTROL_DISABLE		(0x03)
2810 
2811 /**
2812  * mpi3mr_expander_phy_control - expander phy control
2813  * @mrioc: Adapter instance reference
2814  * @phy: The SAS transport layer phy object
2815  * @phy_operation: The phy operation to be executed
2816  *
2817  * Issues SMP passthru phy control request to execute a specific
2818  * phy operation for a given expander device.
2819  *
2820  * Return: 0 for success, non-zero for failure.
2821  */
2822 static int
mpi3mr_expander_phy_control(struct mpi3mr_ioc * mrioc,struct sas_phy * phy,u8 phy_operation)2823 mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
2824 	struct sas_phy *phy, u8 phy_operation)
2825 {
2826 	struct mpi3_smp_passthrough_request mpi_request;
2827 	struct mpi3_smp_passthrough_reply mpi_reply;
2828 	struct phy_control_request *phy_control_request;
2829 	struct phy_control_reply *phy_control_reply;
2830 	int rc;
2831 	void *psge;
2832 	void *data_out = NULL;
2833 	dma_addr_t data_out_dma;
2834 	dma_addr_t data_in_dma;
2835 	size_t data_in_sz;
2836 	size_t data_out_sz;
2837 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2838 	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2839 	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2840 	u16 ioc_status;
2841 	u16 sz;
2842 
2843 	if (mrioc->reset_in_progress) {
2844 		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2845 		return -EFAULT;
2846 	}
2847 
2848 	if (mrioc->pci_err_recovery) {
2849 		ioc_err(mrioc, "%s: pci error recovery in progress!\n",
2850 		    __func__);
2851 		return -EFAULT;
2852 	}
2853 
2854 	data_out_sz = sizeof(struct phy_control_request);
2855 	data_in_sz = sizeof(struct phy_control_reply);
2856 	sz = data_out_sz + data_in_sz;
2857 	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2858 	    GFP_KERNEL);
2859 	if (!data_out) {
2860 		rc = -ENOMEM;
2861 		goto out;
2862 	}
2863 
2864 	data_in_dma = data_out_dma + data_out_sz;
2865 	phy_control_reply = data_out + data_out_sz;
2866 
2867 	rc = -EINVAL;
2868 	memset(data_out, 0, sz);
2869 
2870 	phy_control_request = data_out;
2871 	phy_control_request->smp_frame_type = 0x40;
2872 	phy_control_request->function = 0x91;
2873 	phy_control_request->request_length = 9;
2874 	phy_control_request->allocated_response_length = 0;
2875 	phy_control_request->phy_identifier = phy->number;
2876 	phy_control_request->phy_operation = phy_operation;
2877 	phy_control_request->programmed_min_physical_link_rate =
2878 	    phy->minimum_linkrate << 4;
2879 	phy_control_request->programmed_max_physical_link_rate =
2880 	    phy->maximum_linkrate << 4;
2881 
2882 	memset(&mpi_request, 0, request_sz);
2883 	memset(&mpi_reply, 0, reply_sz);
2884 	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2885 	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2886 	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2887 	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2888 
2889 	psge = &mpi_request.request_sge;
2890 	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2891 
2892 	psge = &mpi_request.response_sge;
2893 	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2894 
2895 	dprint_transport_info(mrioc,
2896 	    "sending phy control SMP request to sas_address(0x%016llx), phy_id(%d) opcode(%d)\n",
2897 	    (unsigned long long)phy->identify.sas_address, phy->number,
2898 	    phy_operation);
2899 
2900 	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2901 	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2902 		goto out;
2903 
2904 	dprint_transport_info(mrioc,
2905 	    "phy control SMP request completed with ioc_status(0x%04x)\n",
2906 	    ioc_status);
2907 
2908 	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2909 		dprint_transport_info(mrioc,
2910 		    "phy control - reply data transfer size(%d)\n",
2911 		    le16_to_cpu(mpi_reply.response_data_length));
2912 
2913 		if (le16_to_cpu(mpi_reply.response_data_length) !=
2914 		    sizeof(struct phy_control_reply))
2915 			goto out;
2916 		dprint_transport_info(mrioc,
2917 		    "phy control - function_result(%d)\n",
2918 		    phy_control_reply->function_result);
2919 		rc = 0;
2920 	}
2921  out:
2922 	if (data_out)
2923 		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2924 		    data_out_dma);
2925 
2926 	return rc;
2927 }
2928 
2929 /**
2930  * mpi3mr_transport_phy_reset - Reset a given phy
2931  * @phy: The SAS transport layer phy object
2932  * @hard_reset: Flag to indicate the type of reset
2933  *
2934  * Return: 0 for success, non-zero for failure.
2935  */
2936 static int
mpi3mr_transport_phy_reset(struct sas_phy * phy,int hard_reset)2937 mpi3mr_transport_phy_reset(struct sas_phy *phy, int hard_reset)
2938 {
2939 	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2940 	struct mpi3_iounit_control_request mpi_request;
2941 	struct mpi3_iounit_control_reply mpi_reply;
2942 	u16 request_sz = sizeof(struct mpi3_iounit_control_request);
2943 	u16 reply_sz = sizeof(struct mpi3_iounit_control_reply);
2944 	int rc = 0;
2945 	u16 ioc_status;
2946 
2947 	rc = mpi3mr_parent_present(mrioc, phy);
2948 	if (rc)
2949 		return rc;
2950 
2951 	/* handle expander phys */
2952 	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2953 		return mpi3mr_expander_phy_control(mrioc, phy,
2954 		    (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
2955 		    SMP_PHY_CONTROL_LINK_RESET);
2956 
2957 	/* handle hba phys */
2958 	memset(&mpi_request, 0, request_sz);
2959 	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2960 	mpi_request.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
2961 	mpi_request.operation = MPI3_CTRL_OP_SAS_PHY_CONTROL;
2962 	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX] =
2963 		(hard_reset ? MPI3_CTRL_ACTION_HARD_RESET :
2964 		 MPI3_CTRL_ACTION_LINK_RESET);
2965 	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX] =
2966 		phy->number;
2967 
2968 	dprint_transport_info(mrioc,
2969 	    "sending phy reset request to sas_address(0x%016llx), phy_id(%d) hard_reset(%d)\n",
2970 	    (unsigned long long)phy->identify.sas_address, phy->number,
2971 	    hard_reset);
2972 
2973 	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2974 	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status)) {
2975 		rc = -EAGAIN;
2976 		goto out;
2977 	}
2978 
2979 	dprint_transport_info(mrioc,
2980 	    "phy reset request completed with ioc_status(0x%04x)\n",
2981 	    ioc_status);
2982 out:
2983 	return rc;
2984 }
2985 
2986 /**
2987  * mpi3mr_transport_phy_enable - enable/disable phys
2988  * @phy: The SAS transport layer phy object
2989  * @enable: flag to enable/disable, enable phy when true
2990  *
2991  * This function enables/disables a given by executing required
2992  * configuration page changes or expander phy control command
2993  *
2994  * Return: 0 for success, non-zero for failure.
2995  */
2996 static int
mpi3mr_transport_phy_enable(struct sas_phy * phy,int enable)2997 mpi3mr_transport_phy_enable(struct sas_phy *phy, int enable)
2998 {
2999 	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
3000 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
3001 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
3002 	u16 sz;
3003 	int rc = 0;
3004 	int i, discovery_active;
3005 
3006 	rc = mpi3mr_parent_present(mrioc, phy);
3007 	if (rc)
3008 		return rc;
3009 
3010 	/* handle expander phys */
3011 	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
3012 		return mpi3mr_expander_phy_control(mrioc, phy,
3013 		    (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
3014 		    SMP_PHY_CONTROL_DISABLE);
3015 
3016 	/* handle hba phys */
3017 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
3018 		(mrioc->sas_hba.num_phys *
3019 		 sizeof(struct mpi3_sas_io_unit0_phy_data));
3020 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
3021 	if (!sas_io_unit_pg0) {
3022 		rc = -ENOMEM;
3023 		goto out;
3024 	}
3025 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
3026 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3027 		    __FILE__, __LINE__, __func__);
3028 		rc = -ENXIO;
3029 		goto out;
3030 	}
3031 
3032 	/* unable to enable/disable phys when discovery is active */
3033 	for (i = 0, discovery_active = 0; i < mrioc->sas_hba.num_phys ; i++) {
3034 		if (sas_io_unit_pg0->phy_data[i].port_flags &
3035 		    MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS) {
3036 			ioc_err(mrioc,
3037 			    "discovery is active on port = %d, phy = %d\n"
3038 			    "\tunable to enable/disable phys, try again later!\n",
3039 			    sas_io_unit_pg0->phy_data[i].io_unit_port, i);
3040 			discovery_active = 1;
3041 		}
3042 	}
3043 
3044 	if (discovery_active) {
3045 		rc = -EAGAIN;
3046 		goto out;
3047 	}
3048 
3049 	if ((sas_io_unit_pg0->phy_data[phy->number].phy_flags &
3050 	     (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
3051 	      MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))) {
3052 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3053 		    __FILE__, __LINE__, __func__);
3054 		rc = -ENXIO;
3055 		goto out;
3056 	}
3057 
3058 	/* read sas_iounit page 1 */
3059 	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3060 		(mrioc->sas_hba.num_phys *
3061 		 sizeof(struct mpi3_sas_io_unit1_phy_data));
3062 	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3063 	if (!sas_io_unit_pg1) {
3064 		rc = -ENOMEM;
3065 		goto out;
3066 	}
3067 
3068 	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3069 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3070 		    __FILE__, __LINE__, __func__);
3071 		rc = -ENXIO;
3072 		goto out;
3073 	}
3074 
3075 	if (enable)
3076 		sas_io_unit_pg1->phy_data[phy->number].phy_flags
3077 		    &= ~MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3078 	else
3079 		sas_io_unit_pg1->phy_data[phy->number].phy_flags
3080 		    |= MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3081 
3082 	mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz);
3083 
3084 	/* link reset */
3085 	if (enable)
3086 		mpi3mr_transport_phy_reset(phy, 0);
3087 
3088  out:
3089 	kfree(sas_io_unit_pg1);
3090 	kfree(sas_io_unit_pg0);
3091 	return rc;
3092 }
3093 
3094 /**
3095  * mpi3mr_transport_phy_speed - set phy min/max speed
3096  * @phy: The SAS transport later phy object
3097  * @rates: Rates defined as in sas_phy_linkrates
3098  *
3099  * This function sets the link rates given in the rates
3100  * argument to the given phy by executing required configuration
3101  * page changes or expander phy control command
3102  *
3103  * Return: 0 for success, non-zero for failure.
3104  */
3105 static int
mpi3mr_transport_phy_speed(struct sas_phy * phy,struct sas_phy_linkrates * rates)3106 mpi3mr_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
3107 {
3108 	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
3109 	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
3110 	struct mpi3_sas_phy_page0 phy_pg0;
3111 	u16 sz, ioc_status;
3112 	int rc = 0;
3113 
3114 	rc = mpi3mr_parent_present(mrioc, phy);
3115 	if (rc)
3116 		return rc;
3117 
3118 	if (!rates->minimum_linkrate)
3119 		rates->minimum_linkrate = phy->minimum_linkrate;
3120 	else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
3121 		rates->minimum_linkrate = phy->minimum_linkrate_hw;
3122 
3123 	if (!rates->maximum_linkrate)
3124 		rates->maximum_linkrate = phy->maximum_linkrate;
3125 	else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
3126 		rates->maximum_linkrate = phy->maximum_linkrate_hw;
3127 
3128 	/* handle expander phys */
3129 	if (phy->identify.sas_address != mrioc->sas_hba.sas_address) {
3130 		phy->minimum_linkrate = rates->minimum_linkrate;
3131 		phy->maximum_linkrate = rates->maximum_linkrate;
3132 		return mpi3mr_expander_phy_control(mrioc, phy,
3133 		    SMP_PHY_CONTROL_LINK_RESET);
3134 	}
3135 
3136 	/* handle hba phys */
3137 	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3138 		(mrioc->sas_hba.num_phys *
3139 		 sizeof(struct mpi3_sas_io_unit1_phy_data));
3140 	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3141 	if (!sas_io_unit_pg1) {
3142 		rc = -ENOMEM;
3143 		goto out;
3144 	}
3145 
3146 	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3147 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3148 		    __FILE__, __LINE__, __func__);
3149 		rc = -ENXIO;
3150 		goto out;
3151 	}
3152 
3153 	sas_io_unit_pg1->phy_data[phy->number].max_min_link_rate =
3154 		(rates->minimum_linkrate + (rates->maximum_linkrate << 4));
3155 
3156 	if (mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3157 		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3158 		    __FILE__, __LINE__, __func__);
3159 		rc = -ENXIO;
3160 		goto out;
3161 	}
3162 
3163 	/* link reset */
3164 	mpi3mr_transport_phy_reset(phy, 0);
3165 
3166 	/* read phy page 0, then update the rates in the sas transport phy */
3167 	if (!mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
3168 	    sizeof(struct mpi3_sas_phy_page0),
3169 	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number) &&
3170 	    (ioc_status == MPI3_IOCSTATUS_SUCCESS)) {
3171 		phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
3172 		    phy_pg0.programmed_link_rate &
3173 		    MPI3_SAS_PRATE_MIN_RATE_MASK);
3174 		phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
3175 		    phy_pg0.programmed_link_rate >> 4);
3176 		phy->negotiated_linkrate =
3177 			mpi3mr_convert_phy_link_rate(
3178 			    (phy_pg0.negotiated_link_rate &
3179 			    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK)
3180 			    >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
3181 	}
3182 
3183 out:
3184 	kfree(sas_io_unit_pg1);
3185 	return rc;
3186 }
3187 
3188 /**
3189  * mpi3mr_map_smp_buffer - map BSG dma buffer
3190  * @dev: Generic device reference
3191  * @buf: BSG buffer pointer
3192  * @dma_addr: Physical address holder
3193  * @dma_len: Mapped DMA buffer length.
3194  * @p: Virtual address holder
3195  *
3196  * This function maps the DMAable buffer
3197  *
3198  * Return: 0 on success, non-zero on failure
3199  */
3200 static int
mpi3mr_map_smp_buffer(struct device * dev,struct bsg_buffer * buf,dma_addr_t * dma_addr,size_t * dma_len,void ** p)3201 mpi3mr_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3202 		dma_addr_t *dma_addr, size_t *dma_len, void **p)
3203 {
3204 	/* Check if the request is split across multiple segments */
3205 	if (buf->sg_cnt > 1) {
3206 		*p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
3207 				GFP_KERNEL);
3208 		if (!*p)
3209 			return -ENOMEM;
3210 		*dma_len = buf->payload_len;
3211 	} else {
3212 		if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))
3213 			return -ENOMEM;
3214 		*dma_addr = sg_dma_address(buf->sg_list);
3215 		*dma_len = sg_dma_len(buf->sg_list);
3216 		*p = NULL;
3217 	}
3218 
3219 	return 0;
3220 }
3221 
3222 /**
3223  * mpi3mr_unmap_smp_buffer - unmap BSG dma buffer
3224  * @dev: Generic device reference
3225  * @buf: BSG buffer pointer
3226  * @dma_addr: Physical address to be unmapped
3227  * @p: Virtual address
3228  *
3229  * This function unmaps the DMAable buffer
3230  */
3231 static void
mpi3mr_unmap_smp_buffer(struct device * dev,struct bsg_buffer * buf,dma_addr_t dma_addr,void * p)3232 mpi3mr_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3233 		dma_addr_t dma_addr, void *p)
3234 {
3235 	if (p)
3236 		dma_free_coherent(dev, buf->payload_len, p, dma_addr);
3237 	else
3238 		dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
3239 }
3240 
3241 /**
3242  * mpi3mr_transport_smp_handler - handler for smp passthru
3243  * @job: BSG job reference
3244  * @shost: SCSI host object reference
3245  * @rphy: SAS transport rphy object pointing the expander
3246  *
3247  * This is used primarily by smp utils for sending the SMP
3248  * commands to the expanders attached to the controller
3249  */
3250 static void
mpi3mr_transport_smp_handler(struct bsg_job * job,struct Scsi_Host * shost,struct sas_rphy * rphy)3251 mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
3252 	struct sas_rphy *rphy)
3253 {
3254 	struct mpi3mr_ioc *mrioc = shost_priv(shost);
3255 	struct mpi3_smp_passthrough_request mpi_request;
3256 	struct mpi3_smp_passthrough_reply mpi_reply;
3257 	int rc;
3258 	void *psge;
3259 	dma_addr_t dma_addr_in;
3260 	dma_addr_t dma_addr_out;
3261 	void *addr_in = NULL;
3262 	void *addr_out = NULL;
3263 	size_t dma_len_in;
3264 	size_t dma_len_out;
3265 	unsigned int reslen = 0;
3266 	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
3267 	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
3268 	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
3269 	u16 ioc_status;
3270 
3271 	if (mrioc->reset_in_progress) {
3272 		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
3273 		rc = -EFAULT;
3274 		goto out;
3275 	}
3276 
3277 	if (mrioc->pci_err_recovery) {
3278 		ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
3279 		rc = -EFAULT;
3280 		goto out;
3281 	}
3282 
3283 	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3284 	    &dma_addr_out, &dma_len_out, &addr_out);
3285 	if (rc)
3286 		goto out;
3287 
3288 	if (addr_out)
3289 		sg_copy_to_buffer(job->request_payload.sg_list,
3290 		    job->request_payload.sg_cnt, addr_out,
3291 		    job->request_payload.payload_len);
3292 
3293 	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3294 			&dma_addr_in, &dma_len_in, &addr_in);
3295 	if (rc)
3296 		goto unmap_out;
3297 
3298 	memset(&mpi_request, 0, request_sz);
3299 	memset(&mpi_reply, 0, reply_sz);
3300 	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
3301 	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
3302 	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_rphy(mrioc, rphy);
3303 	mpi_request.sas_address = ((rphy) ?
3304 	    cpu_to_le64(rphy->identify.sas_address) :
3305 	    cpu_to_le64(mrioc->sas_hba.sas_address));
3306 	psge = &mpi_request.request_sge;
3307 	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_out - 4, dma_addr_out);
3308 
3309 	psge = &mpi_request.response_sge;
3310 	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_in - 4, dma_addr_in);
3311 
3312 	dprint_transport_info(mrioc, "sending SMP request\n");
3313 
3314 	rc = mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
3315 				       &mpi_reply, reply_sz,
3316 				       MPI3MR_INTADMCMD_TIMEOUT, &ioc_status);
3317 	if (rc)
3318 		goto unmap_in;
3319 
3320 	dprint_transport_info(mrioc,
3321 	    "SMP request completed with ioc_status(0x%04x)\n", ioc_status);
3322 
3323 	dprint_transport_info(mrioc,
3324 		    "SMP request - reply data transfer size(%d)\n",
3325 		    le16_to_cpu(mpi_reply.response_data_length));
3326 
3327 	memcpy(job->reply, &mpi_reply, reply_sz);
3328 	job->reply_len = reply_sz;
3329 	reslen = le16_to_cpu(mpi_reply.response_data_length);
3330 
3331 	if (addr_in)
3332 		sg_copy_from_buffer(job->reply_payload.sg_list,
3333 				job->reply_payload.sg_cnt, addr_in,
3334 				job->reply_payload.payload_len);
3335 
3336 	rc = 0;
3337 unmap_in:
3338 	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3339 			dma_addr_in, addr_in);
3340 unmap_out:
3341 	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3342 			dma_addr_out, addr_out);
3343 out:
3344 	bsg_job_done(job, rc, reslen);
3345 }
3346 
3347 struct sas_function_template mpi3mr_transport_functions = {
3348 	.get_linkerrors		= mpi3mr_transport_get_linkerrors,
3349 	.get_enclosure_identifier = mpi3mr_transport_get_enclosure_identifier,
3350 	.get_bay_identifier	= mpi3mr_transport_get_bay_identifier,
3351 	.phy_reset		= mpi3mr_transport_phy_reset,
3352 	.phy_enable		= mpi3mr_transport_phy_enable,
3353 	.set_phy_speed		= mpi3mr_transport_phy_speed,
3354 	.smp_handler		= mpi3mr_transport_smp_handler,
3355 };
3356 
3357 struct scsi_transport_template *mpi3mr_transport_template;
3358