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];
109 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
110 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
111 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
112 u16 component_id;
113 u8 component_revision_id;
114 u8 reserved3;
115 u8 vendor_specific[8];
116 };
117
118 /**
119 * mpi3mr_report_manufacture - obtain SMP report_manufacture
120 * @mrioc: Adapter instance reference
121 * @sas_address: SAS address of the expander device
122 * @edev: SAS transport layer sas_expander_device object
123 * @port_id: ID of the HBA port
124 *
125 * Fills in the sas_expander_device with manufacturing info.
126 *
127 * Return: 0 for success, non-zero for failure.
128 */
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 list_del_init(&tgtdev->list);
417 was_on_tgtdev_list = 1;
418 mpi3mr_tgtdev_put(tgtdev);
419 }
420 }
421 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
422 if (was_on_tgtdev_list) {
423 if (tgtdev->host_exposed)
424 mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
425 mpi3mr_tgtdev_put(tgtdev);
426 }
427 }
428
429 /**
430 * __mpi3mr_get_tgtdev_by_addr_and_rphy - target device search
431 * @mrioc: Adapter instance reference
432 * @sas_address: SAS address of the device
433 * @rphy: SAS transport layer rphy object
434 *
435 * This searches for target device from sas address and rphy
436 * pointer then return mpi3mr_tgt_dev object.
437 *
438 * Return: Valid tget_dev or NULL
439 */
__mpi3mr_get_tgtdev_by_addr_and_rphy(struct mpi3mr_ioc * mrioc,u64 sas_address,struct sas_rphy * rphy)440 struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
441 struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy)
442 {
443 struct mpi3mr_tgt_dev *tgtdev;
444
445 assert_spin_locked(&mrioc->tgtdev_lock);
446
447 list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
448 if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&
449 (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)
450 && (tgtdev->dev_spec.sas_sata_inf.rphy == rphy))
451 goto found_device;
452 return NULL;
453 found_device:
454 mpi3mr_tgtdev_get(tgtdev);
455 return tgtdev;
456 }
457
458 /**
459 * mpi3mr_expander_find_by_sas_address - sas expander search
460 * @mrioc: Adapter instance reference
461 * @sas_address: SAS address of expander
462 * @hba_port: HBA port entry
463 *
464 * Return: A valid SAS expander node or NULL.
465 *
466 */
mpi3mr_expander_find_by_sas_address(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)467 static struct mpi3mr_sas_node *mpi3mr_expander_find_by_sas_address(
468 struct mpi3mr_ioc *mrioc, u64 sas_address,
469 struct mpi3mr_hba_port *hba_port)
470 {
471 struct mpi3mr_sas_node *sas_expander, *r = NULL;
472
473 if (!hba_port)
474 goto out;
475
476 list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
477 if ((sas_expander->sas_address != sas_address) ||
478 (sas_expander->hba_port != hba_port))
479 continue;
480 r = sas_expander;
481 goto out;
482 }
483 out:
484 return r;
485 }
486
487 /**
488 * __mpi3mr_sas_node_find_by_sas_address - sas node search
489 * @mrioc: Adapter instance reference
490 * @sas_address: SAS address of expander or sas host
491 * @hba_port: HBA port entry
492 * Context: Caller should acquire mrioc->sas_node_lock.
493 *
494 * If the SAS address indicates the device is direct attached to
495 * the controller (controller's SAS address) then the SAS node
496 * associated with the controller is returned back else the SAS
497 * address and hba port are used to identify the exact expander
498 * and the associated sas_node object is returned. If there is
499 * no match NULL is returned.
500 *
501 * Return: A valid SAS node or NULL.
502 *
503 */
__mpi3mr_sas_node_find_by_sas_address(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)504 static struct mpi3mr_sas_node *__mpi3mr_sas_node_find_by_sas_address(
505 struct mpi3mr_ioc *mrioc, u64 sas_address,
506 struct mpi3mr_hba_port *hba_port)
507 {
508
509 if (mrioc->sas_hba.sas_address == sas_address)
510 return &mrioc->sas_hba;
511 return mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
512 hba_port);
513 }
514
515 /**
516 * mpi3mr_parent_present - Is parent present for a phy
517 * @mrioc: Adapter instance reference
518 * @phy: SAS transport layer phy object
519 *
520 * Return: 0 if parent is present else non-zero
521 */
mpi3mr_parent_present(struct mpi3mr_ioc * mrioc,struct sas_phy * phy)522 static int mpi3mr_parent_present(struct mpi3mr_ioc *mrioc, struct sas_phy *phy)
523 {
524 unsigned long flags;
525 struct mpi3mr_hba_port *hba_port = phy->hostdata;
526
527 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
528 if (__mpi3mr_sas_node_find_by_sas_address(mrioc,
529 phy->identify.sas_address,
530 hba_port) == NULL) {
531 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
532 return -1;
533 }
534 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
535 return 0;
536 }
537
538 /**
539 * mpi3mr_convert_phy_link_rate -
540 * @link_rate: link rate as defined in the MPI header
541 *
542 * Convert link_rate from mpi format into sas_transport layer
543 * form.
544 *
545 * Return: A valid SAS transport layer defined link rate
546 */
mpi3mr_convert_phy_link_rate(u8 link_rate)547 static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
548 {
549 enum sas_linkrate rc;
550
551 switch (link_rate) {
552 case MPI3_SAS_NEG_LINK_RATE_1_5:
553 rc = SAS_LINK_RATE_1_5_GBPS;
554 break;
555 case MPI3_SAS_NEG_LINK_RATE_3_0:
556 rc = SAS_LINK_RATE_3_0_GBPS;
557 break;
558 case MPI3_SAS_NEG_LINK_RATE_6_0:
559 rc = SAS_LINK_RATE_6_0_GBPS;
560 break;
561 case MPI3_SAS_NEG_LINK_RATE_12_0:
562 rc = SAS_LINK_RATE_12_0_GBPS;
563 break;
564 case MPI3_SAS_NEG_LINK_RATE_22_5:
565 rc = SAS_LINK_RATE_22_5_GBPS;
566 break;
567 case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:
568 rc = SAS_PHY_DISABLED;
569 break;
570 case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
571 rc = SAS_LINK_RATE_FAILED;
572 break;
573 case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:
574 rc = SAS_SATA_PORT_SELECTOR;
575 break;
576 case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
577 rc = SAS_PHY_RESET_IN_PROGRESS;
578 break;
579 case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
580 case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
581 default:
582 rc = SAS_LINK_RATE_UNKNOWN;
583 break;
584 }
585 return rc;
586 }
587
588 /**
589 * mpi3mr_delete_sas_phy - Remove a single phy from port
590 * @mrioc: Adapter instance reference
591 * @mr_sas_port: Internal Port object
592 * @mr_sas_phy: Internal Phy object
593 * @host_node: Flag to indicate this is a host_node
594 *
595 * Return: None.
596 */
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)597 static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
598 struct mpi3mr_sas_port *mr_sas_port,
599 struct mpi3mr_sas_phy *mr_sas_phy, u8 host_node)
600 {
601 u64 sas_address = mr_sas_port->remote_identify.sas_address;
602
603 dev_info(&mr_sas_phy->phy->dev,
604 "remove: sas_address(0x%016llx), phy(%d)\n",
605 (unsigned long long) sas_address, mr_sas_phy->phy_id);
606
607 list_del(&mr_sas_phy->port_siblings);
608 mr_sas_port->num_phys--;
609
610 if (host_node) {
611 mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);
612
613 if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)
614 mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
615 }
616 sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
617 mr_sas_phy->phy_belongs_to_port = 0;
618 }
619
620 /**
621 * mpi3mr_add_sas_phy - Adding a single phy to a port
622 * @mrioc: Adapter instance reference
623 * @mr_sas_port: Internal Port object
624 * @mr_sas_phy: Internal Phy object
625 * @host_node: Flag to indicate this is a host_node
626 *
627 * Return: None.
628 */
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)629 static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
630 struct mpi3mr_sas_port *mr_sas_port,
631 struct mpi3mr_sas_phy *mr_sas_phy, u8 host_node)
632 {
633 u64 sas_address = mr_sas_port->remote_identify.sas_address;
634
635 dev_info(&mr_sas_phy->phy->dev,
636 "add: sas_address(0x%016llx), phy(%d)\n", (unsigned long long)
637 sas_address, mr_sas_phy->phy_id);
638
639 list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
640 mr_sas_port->num_phys++;
641 if (host_node) {
642 mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);
643
644 if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)
645 mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
646 }
647 sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
648 mr_sas_phy->phy_belongs_to_port = 1;
649 }
650
651 /**
652 * mpi3mr_add_phy_to_an_existing_port - add phy to existing port
653 * @mrioc: Adapter instance reference
654 * @mr_sas_node: Internal sas node object (expander or host)
655 * @mr_sas_phy: Internal Phy object *
656 * @sas_address: SAS address of device/expander were phy needs
657 * to be added to
658 * @hba_port: HBA port entry
659 *
660 * Return: None.
661 */
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)662 static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,
663 struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy,
664 u64 sas_address, struct mpi3mr_hba_port *hba_port)
665 {
666 struct mpi3mr_sas_port *mr_sas_port;
667 struct mpi3mr_sas_phy *srch_phy;
668
669 if (mr_sas_phy->phy_belongs_to_port == 1)
670 return;
671
672 if (!hba_port)
673 return;
674
675 list_for_each_entry(mr_sas_port, &mr_sas_node->sas_port_list,
676 port_list) {
677 if (mr_sas_port->remote_identify.sas_address !=
678 sas_address)
679 continue;
680 if (mr_sas_port->hba_port != hba_port)
681 continue;
682 list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
683 port_siblings) {
684 if (srch_phy == mr_sas_phy)
685 return;
686 }
687 mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy, mr_sas_node->host_node);
688 return;
689 }
690 }
691
692 /**
693 * mpi3mr_delete_sas_port - helper function to removing a port
694 * @mrioc: Adapter instance reference
695 * @mr_sas_port: Internal Port object
696 *
697 * Return: None.
698 */
mpi3mr_delete_sas_port(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_port * mr_sas_port)699 static void mpi3mr_delete_sas_port(struct mpi3mr_ioc *mrioc,
700 struct mpi3mr_sas_port *mr_sas_port)
701 {
702 u64 sas_address = mr_sas_port->remote_identify.sas_address;
703 struct mpi3mr_hba_port *hba_port = mr_sas_port->hba_port;
704 enum sas_device_type device_type =
705 mr_sas_port->remote_identify.device_type;
706
707 dev_info(&mr_sas_port->port->dev,
708 "remove: sas_address(0x%016llx)\n",
709 (unsigned long long) sas_address);
710
711 if (device_type == SAS_END_DEVICE)
712 mpi3mr_remove_device_by_sas_address(mrioc, sas_address,
713 hba_port);
714
715 else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
716 device_type == SAS_FANOUT_EXPANDER_DEVICE)
717 mpi3mr_expander_remove(mrioc, sas_address, hba_port);
718 }
719
720 /**
721 * mpi3mr_del_phy_from_an_existing_port - del phy from a port
722 * @mrioc: Adapter instance reference
723 * @mr_sas_node: Internal sas node object (expander or host)
724 * @mr_sas_phy: Internal Phy object
725 *
726 * Return: None.
727 */
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)728 static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
729 struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy)
730 {
731 struct mpi3mr_sas_port *mr_sas_port, *next;
732 struct mpi3mr_sas_phy *srch_phy;
733
734 if (mr_sas_phy->phy_belongs_to_port == 0)
735 return;
736
737 list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
738 port_list) {
739 list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
740 port_siblings) {
741 if (srch_phy != mr_sas_phy)
742 continue;
743 if ((mr_sas_port->num_phys == 1) &&
744 !mrioc->reset_in_progress)
745 mpi3mr_delete_sas_port(mrioc, mr_sas_port);
746 else
747 mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
748 mr_sas_phy, mr_sas_node->host_node);
749 return;
750 }
751 }
752 }
753
754 /**
755 * mpi3mr_sas_port_sanity_check - sanity check while adding port
756 * @mrioc: Adapter instance reference
757 * @mr_sas_node: Internal sas node object (expander or host)
758 * @sas_address: SAS address of device/expander
759 * @hba_port: HBA port entry
760 *
761 * Verifies whether the Phys attached to a device with the given
762 * SAS address already belongs to an existing sas port if so
763 * will remove those phys from the sas port
764 *
765 * Return: None.
766 */
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)767 static void mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc,
768 struct mpi3mr_sas_node *mr_sas_node, u64 sas_address,
769 struct mpi3mr_hba_port *hba_port)
770 {
771 int i;
772
773 for (i = 0; i < mr_sas_node->num_phys; i++) {
774 if ((mr_sas_node->phy[i].remote_identify.sas_address !=
775 sas_address) || (mr_sas_node->phy[i].hba_port != hba_port))
776 continue;
777 if (mr_sas_node->phy[i].phy_belongs_to_port == 1)
778 mpi3mr_del_phy_from_an_existing_port(mrioc,
779 mr_sas_node, &mr_sas_node->phy[i]);
780 }
781 }
782
783 /**
784 * mpi3mr_set_identify - set identify for phys and end devices
785 * @mrioc: Adapter instance reference
786 * @handle: Firmware device handle
787 * @identify: SAS transport layer's identify info
788 *
789 * Populates sas identify info for a specific device.
790 *
791 * Return: 0 for success, non-zero for failure.
792 */
mpi3mr_set_identify(struct mpi3mr_ioc * mrioc,u16 handle,struct sas_identify * identify)793 static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
794 struct sas_identify *identify)
795 {
796
797 struct mpi3_device_page0 device_pg0;
798 struct mpi3_device0_sas_sata_format *sasinf;
799 u16 device_info;
800 u16 ioc_status;
801
802 if (mrioc->reset_in_progress) {
803 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
804 return -EFAULT;
805 }
806
807 if (mrioc->pci_err_recovery) {
808 ioc_err(mrioc, "%s: pci error recovery in progress!\n",
809 __func__);
810 return -EFAULT;
811 }
812
813 if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
814 sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {
815 ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
816 return -ENXIO;
817 }
818
819 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
820 ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
821 handle, ioc_status, __FILE__, __LINE__, __func__);
822 return -EIO;
823 }
824
825 memset(identify, 0, sizeof(struct sas_identify));
826 sasinf = &device_pg0.device_specific.sas_sata_format;
827 device_info = le16_to_cpu(sasinf->device_info);
828
829 /* sas_address */
830 identify->sas_address = le64_to_cpu(sasinf->sas_address);
831
832 /* phy number of the parent device this device is linked to */
833 identify->phy_identifier = sasinf->phy_num;
834
835 /* device_type */
836 switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) {
837 case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:
838 identify->device_type = SAS_PHY_UNUSED;
839 break;
840 case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:
841 identify->device_type = SAS_END_DEVICE;
842 break;
843 case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:
844 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
845 break;
846 }
847
848 /* initiator_port_protocols */
849 if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)
850 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
851 /* MPI3.0 doesn't have define for SATA INIT so setting both here*/
852 if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)
853 identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |
854 SAS_PROTOCOL_SATA);
855 if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)
856 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
857
858 /* target_port_protocols */
859 if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)
860 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
861 /* MPI3.0 doesn't have define for STP Target so setting both here*/
862 if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)
863 identify->target_port_protocols |= (SAS_PROTOCOL_STP |
864 SAS_PROTOCOL_SATA);
865 if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)
866 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
867 return 0;
868 }
869
870 /**
871 * mpi3mr_add_host_phy - report sas_host phy to SAS transport
872 * @mrioc: Adapter instance reference
873 * @mr_sas_phy: Internal Phy object
874 * @phy_pg0: SAS phy page 0
875 * @parent_dev: Prent device class object
876 *
877 * Return: 0 for success, non-zero for failure.
878 */
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)879 static int mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc,
880 struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0,
881 struct device *parent_dev)
882 {
883 struct sas_phy *phy;
884 int phy_index = mr_sas_phy->phy_id;
885
886
887 INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
888 phy = sas_phy_alloc(parent_dev, phy_index);
889 if (!phy) {
890 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
891 __FILE__, __LINE__, __func__);
892 return -1;
893 }
894 if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
895 &mr_sas_phy->identify))) {
896 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
897 __FILE__, __LINE__, __func__);
898 sas_phy_free(phy);
899 return -1;
900 }
901 phy->identify = mr_sas_phy->identify;
902 mr_sas_phy->attached_handle = le16_to_cpu(phy_pg0.attached_dev_handle);
903 if (mr_sas_phy->attached_handle)
904 mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
905 &mr_sas_phy->remote_identify);
906 phy->identify.phy_identifier = mr_sas_phy->phy_id;
907 phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
908 (phy_pg0.negotiated_link_rate &
909 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
910 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
911 phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
912 phy_pg0.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
913 phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
914 phy_pg0.hw_link_rate >> 4);
915 phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
916 phy_pg0.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
917 phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
918 phy_pg0.programmed_link_rate >> 4);
919 phy->hostdata = mr_sas_phy->hba_port;
920
921 if ((sas_phy_add(phy))) {
922 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
923 __FILE__, __LINE__, __func__);
924 sas_phy_free(phy);
925 return -1;
926 }
927 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
928 dev_info(&phy->dev,
929 "add: handle(0x%04x), sas_address(0x%016llx)\n"
930 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
931 mr_sas_phy->handle, (unsigned long long)
932 mr_sas_phy->identify.sas_address,
933 mr_sas_phy->attached_handle,
934 (unsigned long long)
935 mr_sas_phy->remote_identify.sas_address);
936 mr_sas_phy->phy = phy;
937 return 0;
938 }
939
940 /**
941 * mpi3mr_add_expander_phy - report expander phy to transport
942 * @mrioc: Adapter instance reference
943 * @mr_sas_phy: Internal Phy object
944 * @expander_pg1: SAS Expander page 1
945 * @parent_dev: Parent device class object
946 *
947 * Return: 0 for success, non-zero for failure.
948 */
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)949 static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc,
950 struct mpi3mr_sas_phy *mr_sas_phy,
951 struct mpi3_sas_expander_page1 expander_pg1,
952 struct device *parent_dev)
953 {
954 struct sas_phy *phy;
955 int phy_index = mr_sas_phy->phy_id;
956
957 INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
958 phy = sas_phy_alloc(parent_dev, phy_index);
959 if (!phy) {
960 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
961 __FILE__, __LINE__, __func__);
962 return -1;
963 }
964 if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
965 &mr_sas_phy->identify))) {
966 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
967 __FILE__, __LINE__, __func__);
968 sas_phy_free(phy);
969 return -1;
970 }
971 phy->identify = mr_sas_phy->identify;
972 mr_sas_phy->attached_handle =
973 le16_to_cpu(expander_pg1.attached_dev_handle);
974 if (mr_sas_phy->attached_handle)
975 mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
976 &mr_sas_phy->remote_identify);
977 phy->identify.phy_identifier = mr_sas_phy->phy_id;
978 phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
979 (expander_pg1.negotiated_link_rate &
980 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
981 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
982 phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
983 expander_pg1.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
984 phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
985 expander_pg1.hw_link_rate >> 4);
986 phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
987 expander_pg1.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
988 phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
989 expander_pg1.programmed_link_rate >> 4);
990 phy->hostdata = mr_sas_phy->hba_port;
991
992 if ((sas_phy_add(phy))) {
993 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
994 __FILE__, __LINE__, __func__);
995 sas_phy_free(phy);
996 return -1;
997 }
998 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
999 dev_info(&phy->dev,
1000 "add: handle(0x%04x), sas_address(0x%016llx)\n"
1001 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
1002 mr_sas_phy->handle, (unsigned long long)
1003 mr_sas_phy->identify.sas_address,
1004 mr_sas_phy->attached_handle,
1005 (unsigned long long)
1006 mr_sas_phy->remote_identify.sas_address);
1007 mr_sas_phy->phy = phy;
1008 return 0;
1009 }
1010
1011 /**
1012 * mpi3mr_alloc_hba_port - alloc hba port object
1013 * @mrioc: Adapter instance reference
1014 * @port_id: Port number
1015 *
1016 * Alloc memory for hba port object.
1017 */
1018 static struct mpi3mr_hba_port *
mpi3mr_alloc_hba_port(struct mpi3mr_ioc * mrioc,u16 port_id)1019 mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)
1020 {
1021 struct mpi3mr_hba_port *hba_port;
1022
1023 hba_port = kzalloc(sizeof(struct mpi3mr_hba_port),
1024 GFP_KERNEL);
1025 if (!hba_port)
1026 return NULL;
1027 hba_port->port_id = port_id;
1028 ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
1029 hba_port, hba_port->port_id);
1030 if (mrioc->reset_in_progress ||
1031 mrioc->pci_err_recovery)
1032 hba_port->flags = MPI3MR_HBA_PORT_FLAG_NEW;
1033 list_add_tail(&hba_port->list, &mrioc->hba_port_table_list);
1034 return hba_port;
1035 }
1036
1037 /**
1038 * mpi3mr_get_hba_port_by_id - find hba port by id
1039 * @mrioc: Adapter instance reference
1040 * @port_id: Port ID to search
1041 *
1042 * Return: mpi3mr_hba_port reference for the matched port
1043 */
1044
mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc * mrioc,u8 port_id)1045 struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,
1046 u8 port_id)
1047 {
1048 struct mpi3mr_hba_port *port, *port_next;
1049
1050 list_for_each_entry_safe(port, port_next,
1051 &mrioc->hba_port_table_list, list) {
1052 if (port->port_id != port_id)
1053 continue;
1054 if (port->flags & MPI3MR_HBA_PORT_FLAG_DIRTY)
1055 continue;
1056 return port;
1057 }
1058
1059 return NULL;
1060 }
1061
1062 /**
1063 * mpi3mr_update_links - refreshing SAS phy link changes
1064 * @mrioc: Adapter instance reference
1065 * @sas_address_parent: SAS address of parent expander or host
1066 * @handle: Firmware device handle of attached device
1067 * @phy_number: Phy number
1068 * @link_rate: New link rate
1069 * @hba_port: HBA port entry
1070 *
1071 * Return: None.
1072 */
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)1073 void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
1074 u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate,
1075 struct mpi3mr_hba_port *hba_port)
1076 {
1077 unsigned long flags;
1078 struct mpi3mr_sas_node *mr_sas_node;
1079 struct mpi3mr_sas_phy *mr_sas_phy;
1080
1081 if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
1082 return;
1083
1084 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1085 mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1086 sas_address_parent, hba_port);
1087 if (!mr_sas_node) {
1088 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1089 return;
1090 }
1091
1092 mr_sas_phy = &mr_sas_node->phy[phy_number];
1093 mr_sas_phy->attached_handle = handle;
1094 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1095 if (handle && (link_rate >= MPI3_SAS_NEG_LINK_RATE_1_5)) {
1096 mpi3mr_set_identify(mrioc, handle,
1097 &mr_sas_phy->remote_identify);
1098 mpi3mr_add_phy_to_an_existing_port(mrioc, mr_sas_node,
1099 mr_sas_phy, mr_sas_phy->remote_identify.sas_address,
1100 hba_port);
1101 } else
1102 memset(&mr_sas_phy->remote_identify, 0, sizeof(struct
1103 sas_identify));
1104
1105 if (mr_sas_phy->phy)
1106 mr_sas_phy->phy->negotiated_linkrate =
1107 mpi3mr_convert_phy_link_rate(link_rate);
1108
1109 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1110 dev_info(&mr_sas_phy->phy->dev,
1111 "refresh: parent sas_address(0x%016llx),\n"
1112 "\tlink_rate(0x%02x), phy(%d)\n"
1113 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
1114 (unsigned long long)sas_address_parent,
1115 link_rate, phy_number, handle, (unsigned long long)
1116 mr_sas_phy->remote_identify.sas_address);
1117 }
1118
1119 /**
1120 * mpi3mr_sas_host_refresh - refreshing sas host object contents
1121 * @mrioc: Adapter instance reference
1122 *
1123 * This function refreshes the controllers phy information and
1124 * updates the SAS transport layer with updated information,
1125 * this is executed for each device addition or device info
1126 * change events
1127 *
1128 * Return: None.
1129 */
mpi3mr_sas_host_refresh(struct mpi3mr_ioc * mrioc)1130 void mpi3mr_sas_host_refresh(struct mpi3mr_ioc *mrioc)
1131 {
1132 int i;
1133 u8 link_rate;
1134 u16 sz, port_id, attached_handle;
1135 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1136
1137 dprint_transport_info(mrioc,
1138 "updating handles for sas_host(0x%016llx)\n",
1139 (unsigned long long)mrioc->sas_hba.sas_address);
1140
1141 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1142 (mrioc->sas_hba.num_phys *
1143 sizeof(struct mpi3_sas_io_unit0_phy_data));
1144 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1145 if (!sas_io_unit_pg0)
1146 return;
1147 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1148 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1149 __FILE__, __LINE__, __func__);
1150 goto out;
1151 }
1152
1153 mrioc->sas_hba.handle = 0;
1154 for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1155 if (sas_io_unit_pg0->phy_data[i].phy_flags &
1156 (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
1157 MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
1158 continue;
1159 link_rate =
1160 sas_io_unit_pg0->phy_data[i].negotiated_link_rate >> 4;
1161 if (!mrioc->sas_hba.handle)
1162 mrioc->sas_hba.handle = le16_to_cpu(
1163 sas_io_unit_pg0->phy_data[i].controller_dev_handle);
1164 port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1165 if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
1166 if (!mpi3mr_alloc_hba_port(mrioc, port_id))
1167 goto out;
1168
1169 mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
1170 attached_handle = le16_to_cpu(
1171 sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1172 if (attached_handle && link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)
1173 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;
1174 mrioc->sas_hba.phy[i].hba_port =
1175 mpi3mr_get_hba_port_by_id(mrioc, port_id);
1176 mpi3mr_update_links(mrioc, mrioc->sas_hba.sas_address,
1177 attached_handle, i, link_rate,
1178 mrioc->sas_hba.phy[i].hba_port);
1179 }
1180 out:
1181 kfree(sas_io_unit_pg0);
1182 }
1183
1184 /**
1185 * mpi3mr_sas_host_add - create sas host object
1186 * @mrioc: Adapter instance reference
1187 *
1188 * This function creates the controllers phy information and
1189 * updates the SAS transport layer with updated information,
1190 * this is executed for first device addition or device info
1191 * change event.
1192 *
1193 * Return: None.
1194 */
mpi3mr_sas_host_add(struct mpi3mr_ioc * mrioc)1195 void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
1196 {
1197 int i;
1198 u16 sz, num_phys = 1, port_id, ioc_status;
1199 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1200 struct mpi3_sas_phy_page0 phy_pg0;
1201 struct mpi3_device_page0 dev_pg0;
1202 struct mpi3_enclosure_page0 encl_pg0;
1203 struct mpi3_device0_sas_sata_format *sasinf;
1204
1205 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1206 (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
1207 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1208 if (!sas_io_unit_pg0)
1209 return;
1210
1211 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1212 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1213 __FILE__, __LINE__, __func__);
1214 goto out;
1215 }
1216 num_phys = sas_io_unit_pg0->num_phys;
1217 kfree(sas_io_unit_pg0);
1218
1219 mrioc->sas_hba.host_node = 1;
1220 INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list);
1221 mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev;
1222 mrioc->sas_hba.phy = kcalloc(num_phys,
1223 sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);
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(sizeof(struct mpi3mr_sas_port), GFP_KERNEL);
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 = kcalloc(64, sizeof(struct host_port), GFP_KERNEL);
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 mpi3mr_update_links(mrioc, sas_address_parent,
2083 handle, i, link_rate, hba_port);
2084 }
2085 }
2086 }
2087
2088 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2089 sas_address = le64_to_cpu(expander_pg0.sas_address);
2090 sas_expander = mpi3mr_expander_find_by_sas_address(mrioc,
2091 sas_address, hba_port);
2092 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2093
2094 if (sas_expander)
2095 return 0;
2096
2097 sas_expander = kzalloc(sizeof(struct mpi3mr_sas_node),
2098 GFP_KERNEL);
2099 if (!sas_expander)
2100 return -ENOMEM;
2101
2102 sas_expander->handle = handle;
2103 sas_expander->num_phys = expander_pg0.num_phys;
2104 sas_expander->sas_address_parent = sas_address_parent;
2105 sas_expander->sas_address = sas_address;
2106 sas_expander->hba_port = hba_port;
2107
2108 ioc_info(mrioc,
2109 "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
2110 handle, parent_handle, (unsigned long long)
2111 sas_expander->sas_address, sas_expander->num_phys);
2112
2113 if (!sas_expander->num_phys) {
2114 rc = -1;
2115 goto out_fail;
2116 }
2117 sas_expander->phy = kcalloc(sas_expander->num_phys,
2118 sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);
2119 if (!sas_expander->phy) {
2120 rc = -1;
2121 goto out_fail;
2122 }
2123
2124 INIT_LIST_HEAD(&sas_expander->sas_port_list);
2125 mr_sas_port = mpi3mr_sas_port_add(mrioc, handle, sas_address_parent,
2126 sas_expander->hba_port);
2127 if (!mr_sas_port) {
2128 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2129 __FILE__, __LINE__, __func__);
2130 rc = -1;
2131 goto out_fail;
2132 }
2133 sas_expander->parent_dev = &mr_sas_port->rphy->dev;
2134 sas_expander->rphy = mr_sas_port->rphy;
2135
2136 for (i = 0 ; i < sas_expander->num_phys ; i++) {
2137 phynum_handle = (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2138 handle;
2139 if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2140 &expander_pg1, sizeof(expander_pg1),
2141 MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2142 phynum_handle)) {
2143 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2144 __FILE__, __LINE__, __func__);
2145 rc = -1;
2146 goto out_fail;
2147 }
2148 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2149 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2150 __FILE__, __LINE__, __func__);
2151 rc = -1;
2152 goto out_fail;
2153 }
2154
2155 sas_expander->phy[i].handle = handle;
2156 sas_expander->phy[i].phy_id = i;
2157 sas_expander->phy[i].hba_port = hba_port;
2158
2159 if ((mpi3mr_add_expander_phy(mrioc, &sas_expander->phy[i],
2160 expander_pg1, sas_expander->parent_dev))) {
2161 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2162 __FILE__, __LINE__, __func__);
2163 rc = -1;
2164 goto out_fail;
2165 }
2166 }
2167
2168 if (sas_expander->enclosure_handle) {
2169 enclosure_dev =
2170 mpi3mr_enclosure_find_by_handle(mrioc,
2171 sas_expander->enclosure_handle);
2172 if (enclosure_dev)
2173 sas_expander->enclosure_logical_id = le64_to_cpu(
2174 enclosure_dev->pg0.enclosure_logical_id);
2175 }
2176
2177 mpi3mr_expander_node_add(mrioc, sas_expander);
2178 return 0;
2179
2180 out_fail:
2181
2182 if (mr_sas_port)
2183 mpi3mr_sas_port_remove(mrioc,
2184 sas_expander->sas_address,
2185 sas_address_parent, sas_expander->hba_port);
2186 kfree(sas_expander->phy);
2187 kfree(sas_expander);
2188 return rc;
2189 }
2190
2191 /**
2192 * mpi3mr_expander_node_remove - recursive removal of expander.
2193 * @mrioc: Adapter instance reference
2194 * @sas_expander: Expander device object
2195 *
2196 * Removes expander object and freeing associated memory from
2197 * the sas_expander_list and removes the same from SAS TL, if
2198 * one of the attached device is an expander then it recursively
2199 * removes the expander device too.
2200 *
2201 * Return nothing.
2202 */
mpi3mr_expander_node_remove(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_node * sas_expander)2203 void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
2204 struct mpi3mr_sas_node *sas_expander)
2205 {
2206 struct mpi3mr_sas_port *mr_sas_port, *next;
2207 unsigned long flags;
2208 u8 port_id;
2209
2210 /* remove sibling ports attached to this expander */
2211 list_for_each_entry_safe(mr_sas_port, next,
2212 &sas_expander->sas_port_list, port_list) {
2213 if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
2214 return;
2215 if (mr_sas_port->remote_identify.device_type ==
2216 SAS_END_DEVICE)
2217 mpi3mr_remove_device_by_sas_address(mrioc,
2218 mr_sas_port->remote_identify.sas_address,
2219 mr_sas_port->hba_port);
2220 else if (mr_sas_port->remote_identify.device_type ==
2221 SAS_EDGE_EXPANDER_DEVICE ||
2222 mr_sas_port->remote_identify.device_type ==
2223 SAS_FANOUT_EXPANDER_DEVICE)
2224 mpi3mr_expander_remove(mrioc,
2225 mr_sas_port->remote_identify.sas_address,
2226 mr_sas_port->hba_port);
2227 }
2228
2229 port_id = sas_expander->hba_port->port_id;
2230 mpi3mr_sas_port_remove(mrioc, sas_expander->sas_address,
2231 sas_expander->sas_address_parent, sas_expander->hba_port);
2232
2233 ioc_info(mrioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n",
2234 sas_expander->handle, (unsigned long long)
2235 sas_expander->sas_address, port_id);
2236
2237 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2238 list_del(&sas_expander->list);
2239 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2240
2241 kfree(sas_expander->phy);
2242 kfree(sas_expander);
2243 }
2244
2245 /**
2246 * mpi3mr_expander_remove - Remove expander object
2247 * @mrioc: Adapter instance reference
2248 * @sas_address: Remove expander sas_address
2249 * @hba_port: HBA port reference
2250 *
2251 * This function remove expander object, stored in
2252 * mrioc->sas_expander_list and removes it from the SAS TL by
2253 * calling mpi3mr_expander_node_remove().
2254 *
2255 * Return: None
2256 */
mpi3mr_expander_remove(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)2257 void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
2258 struct mpi3mr_hba_port *hba_port)
2259 {
2260 struct mpi3mr_sas_node *sas_expander;
2261 unsigned long flags;
2262
2263 if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
2264 return;
2265
2266 if (!hba_port)
2267 return;
2268
2269 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2270 sas_expander = mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
2271 hba_port);
2272 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2273 if (sas_expander)
2274 mpi3mr_expander_node_remove(mrioc, sas_expander);
2275
2276 }
2277
2278 /**
2279 * mpi3mr_get_sas_negotiated_logical_linkrate - get linkrate
2280 * @mrioc: Adapter instance reference
2281 * @tgtdev: Target device
2282 *
2283 * This function identifies whether the target device is
2284 * attached directly or through expander and issues sas phy
2285 * page0 or expander phy page1 and gets the link rate, if there
2286 * is any failure in reading the pages then this returns link
2287 * rate of 1.5.
2288 *
2289 * Return: logical link rate.
2290 */
mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)2291 static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc,
2292 struct mpi3mr_tgt_dev *tgtdev)
2293 {
2294 u8 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5, phy_number;
2295 struct mpi3_sas_expander_page1 expander_pg1;
2296 struct mpi3_sas_phy_page0 phy_pg0;
2297 u32 phynum_handle;
2298 u16 ioc_status;
2299
2300 phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2301 if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) {
2302 phynum_handle = ((phy_number<<MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT)
2303 | tgtdev->parent_handle);
2304 if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2305 &expander_pg1, sizeof(expander_pg1),
2306 MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2307 phynum_handle)) {
2308 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2309 __FILE__, __LINE__, __func__);
2310 goto out;
2311 }
2312 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2313 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2314 __FILE__, __LINE__, __func__);
2315 goto out;
2316 }
2317 link_rate = (expander_pg1.negotiated_link_rate &
2318 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2319 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2320 goto out;
2321 }
2322 if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
2323 sizeof(struct mpi3_sas_phy_page0),
2324 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy_number)) {
2325 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2326 __FILE__, __LINE__, __func__);
2327 goto out;
2328 }
2329 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2330 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2331 __FILE__, __LINE__, __func__);
2332 goto out;
2333 }
2334 link_rate = (phy_pg0.negotiated_link_rate &
2335 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2336 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2337 out:
2338 return link_rate;
2339 }
2340
2341 /**
2342 * mpi3mr_report_tgtdev_to_sas_transport - expose dev to SAS TL
2343 * @mrioc: Adapter instance reference
2344 * @tgtdev: Target device
2345 *
2346 * This function exposes the target device after
2347 * preparing host_phy, setting up link rate etc.
2348 *
2349 * Return: 0 on success, non-zero for failure.
2350 */
mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)2351 int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc,
2352 struct mpi3mr_tgt_dev *tgtdev)
2353 {
2354 int retval = 0;
2355 u8 link_rate, parent_phy_number;
2356 u64 sas_address_parent, sas_address;
2357 struct mpi3mr_hba_port *hba_port;
2358 u8 port_id;
2359
2360 if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2361 !mrioc->sas_transport_enabled)
2362 return -1;
2363
2364 sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2365 if (!mrioc->sas_hba.num_phys)
2366 mpi3mr_sas_host_add(mrioc);
2367 else
2368 mpi3mr_sas_host_refresh(mrioc);
2369
2370 if (mpi3mr_get_sas_address(mrioc, tgtdev->parent_handle,
2371 &sas_address_parent) != 0) {
2372 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2373 __FILE__, __LINE__, __func__);
2374 return -1;
2375 }
2376 tgtdev->dev_spec.sas_sata_inf.sas_address_parent = sas_address_parent;
2377
2378 parent_phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2379 port_id = tgtdev->io_unit_port;
2380
2381 hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
2382 if (!hba_port) {
2383 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2384 __FILE__, __LINE__, __func__);
2385 return -1;
2386 }
2387 tgtdev->dev_spec.sas_sata_inf.hba_port = hba_port;
2388
2389 link_rate = mpi3mr_get_sas_negotiated_logical_linkrate(mrioc, tgtdev);
2390
2391 mpi3mr_update_links(mrioc, sas_address_parent, tgtdev->dev_handle,
2392 parent_phy_number, link_rate, hba_port);
2393
2394 tgtdev->host_exposed = 1;
2395 if (!mpi3mr_sas_port_add(mrioc, tgtdev->dev_handle,
2396 sas_address_parent, hba_port)) {
2397 retval = -1;
2398 } else if ((!tgtdev->starget) && (!mrioc->is_driver_loading)) {
2399 mpi3mr_sas_port_remove(mrioc, sas_address,
2400 sas_address_parent, hba_port);
2401 retval = -1;
2402 }
2403 if (retval) {
2404 tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2405 tgtdev->host_exposed = 0;
2406 }
2407 return retval;
2408 }
2409
2410 /**
2411 * mpi3mr_remove_tgtdev_from_sas_transport - remove from SAS TL
2412 * @mrioc: Adapter instance reference
2413 * @tgtdev: Target device
2414 *
2415 * This function removes the target device
2416 *
2417 * Return: None.
2418 */
mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)2419 void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
2420 struct mpi3mr_tgt_dev *tgtdev)
2421 {
2422 u64 sas_address_parent, sas_address;
2423 struct mpi3mr_hba_port *hba_port;
2424
2425 if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2426 !mrioc->sas_transport_enabled)
2427 return;
2428
2429 hba_port = tgtdev->dev_spec.sas_sata_inf.hba_port;
2430 sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2431 sas_address_parent = tgtdev->dev_spec.sas_sata_inf.sas_address_parent;
2432 mpi3mr_sas_port_remove(mrioc, sas_address, sas_address_parent,
2433 hba_port);
2434 tgtdev->host_exposed = 0;
2435 tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2436 }
2437
2438 /**
2439 * mpi3mr_get_port_id_by_sas_phy - Get port ID of the given phy
2440 * @phy: SAS transport layer phy object
2441 *
2442 * Return: Port number for valid ID else 0xFFFF
2443 */
mpi3mr_get_port_id_by_sas_phy(struct sas_phy * phy)2444 static inline u8 mpi3mr_get_port_id_by_sas_phy(struct sas_phy *phy)
2445 {
2446 u8 port_id = 0xFF;
2447 struct mpi3mr_hba_port *hba_port = phy->hostdata;
2448
2449 if (hba_port)
2450 port_id = hba_port->port_id;
2451
2452 return port_id;
2453 }
2454
2455 /**
2456 * mpi3mr_get_port_id_by_rphy - Get Port number from SAS rphy
2457 *
2458 * @mrioc: Adapter instance reference
2459 * @rphy: SAS transport layer remote phy object
2460 *
2461 * Retrieves HBA port number in which the device pointed by the
2462 * rphy object is attached with.
2463 *
2464 * Return: Valid port number on success else OxFFFF.
2465 */
mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc * mrioc,struct sas_rphy * rphy)2466 static u8 mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc *mrioc, struct sas_rphy *rphy)
2467 {
2468 struct mpi3mr_sas_node *sas_expander;
2469 struct mpi3mr_tgt_dev *tgtdev;
2470 unsigned long flags;
2471 u8 port_id = 0xFF;
2472
2473 if (!rphy)
2474 return port_id;
2475
2476 if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
2477 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {
2478 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2479 list_for_each_entry(sas_expander, &mrioc->sas_expander_list,
2480 list) {
2481 if (sas_expander->rphy == rphy) {
2482 port_id = sas_expander->hba_port->port_id;
2483 break;
2484 }
2485 }
2486 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2487 } else if (rphy->identify.device_type == SAS_END_DEVICE) {
2488 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2489
2490 tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2491 rphy->identify.sas_address, rphy);
2492 if (tgtdev && tgtdev->dev_spec.sas_sata_inf.hba_port) {
2493 port_id =
2494 tgtdev->dev_spec.sas_sata_inf.hba_port->port_id;
2495 mpi3mr_tgtdev_put(tgtdev);
2496 }
2497 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2498 }
2499 return port_id;
2500 }
2501
phy_to_mrioc(struct sas_phy * phy)2502 static inline struct mpi3mr_ioc *phy_to_mrioc(struct sas_phy *phy)
2503 {
2504 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
2505
2506 return shost_priv(shost);
2507 }
2508
rphy_to_mrioc(struct sas_rphy * rphy)2509 static inline struct mpi3mr_ioc *rphy_to_mrioc(struct sas_rphy *rphy)
2510 {
2511 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
2512
2513 return shost_priv(shost);
2514 }
2515
2516 /* report phy error log structure */
2517 struct phy_error_log_request {
2518 u8 smp_frame_type; /* 0x40 */
2519 u8 function; /* 0x11 */
2520 u8 allocated_response_length;
2521 u8 request_length; /* 02 */
2522 u8 reserved_1[5];
2523 u8 phy_identifier;
2524 u8 reserved_2[2];
2525 };
2526
2527 /* report phy error log reply structure */
2528 struct phy_error_log_reply {
2529 u8 smp_frame_type; /* 0x41 */
2530 u8 function; /* 0x11 */
2531 u8 function_result;
2532 u8 response_length;
2533 __be16 expander_change_count;
2534 u8 reserved_1[3];
2535 u8 phy_identifier;
2536 u8 reserved_2[2];
2537 __be32 invalid_dword;
2538 __be32 running_disparity_error;
2539 __be32 loss_of_dword_sync;
2540 __be32 phy_reset_problem;
2541 };
2542
2543
2544 /**
2545 * mpi3mr_get_expander_phy_error_log - return expander counters:
2546 * @mrioc: Adapter instance reference
2547 * @phy: The SAS transport layer phy object
2548 *
2549 * Return: 0 for success, non-zero for failure.
2550 *
2551 */
mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc * mrioc,struct sas_phy * phy)2552 static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
2553 struct sas_phy *phy)
2554 {
2555 struct mpi3_smp_passthrough_request mpi_request;
2556 struct mpi3_smp_passthrough_reply mpi_reply;
2557 struct phy_error_log_request *phy_error_log_request;
2558 struct phy_error_log_reply *phy_error_log_reply;
2559 int rc;
2560 void *psge;
2561 void *data_out = NULL;
2562 dma_addr_t data_out_dma, data_in_dma;
2563 u32 data_out_sz, data_in_sz, sz;
2564 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2565 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2566 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2567 u16 ioc_status;
2568
2569 if (mrioc->reset_in_progress) {
2570 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2571 return -EFAULT;
2572 }
2573
2574 if (mrioc->pci_err_recovery) {
2575 ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
2576 return -EFAULT;
2577 }
2578
2579 data_out_sz = sizeof(struct phy_error_log_request);
2580 data_in_sz = sizeof(struct phy_error_log_reply);
2581 sz = data_out_sz + data_in_sz;
2582 data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2583 GFP_KERNEL);
2584 if (!data_out) {
2585 rc = -ENOMEM;
2586 goto out;
2587 }
2588
2589 data_in_dma = data_out_dma + data_out_sz;
2590 phy_error_log_reply = data_out + data_out_sz;
2591
2592 rc = -EINVAL;
2593 memset(data_out, 0, sz);
2594 phy_error_log_request = data_out;
2595 phy_error_log_request->smp_frame_type = 0x40;
2596 phy_error_log_request->function = 0x11;
2597 phy_error_log_request->request_length = 2;
2598 phy_error_log_request->allocated_response_length = 0;
2599 phy_error_log_request->phy_identifier = phy->number;
2600
2601 memset(&mpi_request, 0, request_sz);
2602 memset(&mpi_reply, 0, reply_sz);
2603 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2604 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2605 mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2606 mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2607
2608 psge = &mpi_request.request_sge;
2609 mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2610
2611 psge = &mpi_request.response_sge;
2612 mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2613
2614 dprint_transport_info(mrioc,
2615 "sending phy error log SMP request to sas_address(0x%016llx), phy_id(%d)\n",
2616 (unsigned long long)phy->identify.sas_address, phy->number);
2617
2618 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2619 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2620 goto out;
2621
2622 dprint_transport_info(mrioc,
2623 "phy error log SMP request completed with ioc_status(0x%04x)\n",
2624 ioc_status);
2625
2626 if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2627 dprint_transport_info(mrioc,
2628 "phy error log - reply data transfer size(%d)\n",
2629 le16_to_cpu(mpi_reply.response_data_length));
2630
2631 if (le16_to_cpu(mpi_reply.response_data_length) !=
2632 sizeof(struct phy_error_log_reply))
2633 goto out;
2634
2635 dprint_transport_info(mrioc,
2636 "phy error log - function_result(%d)\n",
2637 phy_error_log_reply->function_result);
2638
2639 phy->invalid_dword_count =
2640 be32_to_cpu(phy_error_log_reply->invalid_dword);
2641 phy->running_disparity_error_count =
2642 be32_to_cpu(phy_error_log_reply->running_disparity_error);
2643 phy->loss_of_dword_sync_count =
2644 be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
2645 phy->phy_reset_problem_count =
2646 be32_to_cpu(phy_error_log_reply->phy_reset_problem);
2647 rc = 0;
2648 }
2649
2650 out:
2651 if (data_out)
2652 dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2653 data_out_dma);
2654
2655 return rc;
2656 }
2657
2658 /**
2659 * mpi3mr_transport_get_linkerrors - return phy error counters
2660 * @phy: The SAS transport layer phy object
2661 *
2662 * This function retrieves the phy error log information of the
2663 * HBA or expander for which the phy belongs to
2664 *
2665 * Return: 0 for success, non-zero for failure.
2666 */
mpi3mr_transport_get_linkerrors(struct sas_phy * phy)2667 static int mpi3mr_transport_get_linkerrors(struct sas_phy *phy)
2668 {
2669 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2670 struct mpi3_sas_phy_page1 phy_pg1;
2671 int rc = 0;
2672 u16 ioc_status;
2673
2674 rc = mpi3mr_parent_present(mrioc, phy);
2675 if (rc)
2676 return rc;
2677
2678 if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2679 return mpi3mr_get_expander_phy_error_log(mrioc, phy);
2680
2681 memset(&phy_pg1, 0, sizeof(struct mpi3_sas_phy_page1));
2682 /* get hba phy error logs */
2683 if ((mpi3mr_cfg_get_sas_phy_pg1(mrioc, &ioc_status, &phy_pg1,
2684 sizeof(struct mpi3_sas_phy_page1),
2685 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number))) {
2686 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2687 __FILE__, __LINE__, __func__);
2688 return -ENXIO;
2689 }
2690
2691 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2692 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2693 __FILE__, __LINE__, __func__);
2694 return -ENXIO;
2695 }
2696 phy->invalid_dword_count = le32_to_cpu(phy_pg1.invalid_dword_count);
2697 phy->running_disparity_error_count =
2698 le32_to_cpu(phy_pg1.running_disparity_error_count);
2699 phy->loss_of_dword_sync_count =
2700 le32_to_cpu(phy_pg1.loss_dword_synch_count);
2701 phy->phy_reset_problem_count =
2702 le32_to_cpu(phy_pg1.phy_reset_problem_count);
2703 return 0;
2704 }
2705
2706 /**
2707 * mpi3mr_transport_get_enclosure_identifier - Get Enclosure ID
2708 * @rphy: The SAS transport layer remote phy object
2709 * @identifier: Enclosure identifier to be returned
2710 *
2711 * Returns the enclosure id for the device pointed by the remote
2712 * phy object.
2713 *
2714 * Return: 0 on success or -ENXIO
2715 */
2716 static int
mpi3mr_transport_get_enclosure_identifier(struct sas_rphy * rphy,u64 * identifier)2717 mpi3mr_transport_get_enclosure_identifier(struct sas_rphy *rphy,
2718 u64 *identifier)
2719 {
2720 struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2721 struct mpi3mr_tgt_dev *tgtdev = NULL;
2722 unsigned long flags;
2723 int rc;
2724
2725 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2726 tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2727 rphy->identify.sas_address, rphy);
2728 if (tgtdev) {
2729 *identifier =
2730 tgtdev->enclosure_logical_id;
2731 rc = 0;
2732 mpi3mr_tgtdev_put(tgtdev);
2733 } else {
2734 *identifier = 0;
2735 rc = -ENXIO;
2736 }
2737 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2738
2739 return rc;
2740 }
2741
2742 /**
2743 * mpi3mr_transport_get_bay_identifier - Get bay ID
2744 * @rphy: The SAS transport layer remote phy object
2745 *
2746 * Returns the slot id for the device pointed by the remote phy
2747 * object.
2748 *
2749 * Return: Valid slot ID on success or -ENXIO
2750 */
2751 static int
mpi3mr_transport_get_bay_identifier(struct sas_rphy * rphy)2752 mpi3mr_transport_get_bay_identifier(struct sas_rphy *rphy)
2753 {
2754 struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2755 struct mpi3mr_tgt_dev *tgtdev = NULL;
2756 unsigned long flags;
2757 int rc;
2758
2759 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2760 tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2761 rphy->identify.sas_address, rphy);
2762 if (tgtdev) {
2763 rc = tgtdev->slot;
2764 mpi3mr_tgtdev_put(tgtdev);
2765 } else
2766 rc = -ENXIO;
2767 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2768
2769 return rc;
2770 }
2771
2772 /* phy control request structure */
2773 struct phy_control_request {
2774 u8 smp_frame_type; /* 0x40 */
2775 u8 function; /* 0x91 */
2776 u8 allocated_response_length;
2777 u8 request_length; /* 0x09 */
2778 u16 expander_change_count;
2779 u8 reserved_1[3];
2780 u8 phy_identifier;
2781 u8 phy_operation;
2782 u8 reserved_2[13];
2783 u64 attached_device_name;
2784 u8 programmed_min_physical_link_rate;
2785 u8 programmed_max_physical_link_rate;
2786 u8 reserved_3[6];
2787 };
2788
2789 /* phy control reply structure */
2790 struct phy_control_reply {
2791 u8 smp_frame_type; /* 0x41 */
2792 u8 function; /* 0x11 */
2793 u8 function_result;
2794 u8 response_length;
2795 };
2796
2797 #define SMP_PHY_CONTROL_LINK_RESET (0x01)
2798 #define SMP_PHY_CONTROL_HARD_RESET (0x02)
2799 #define SMP_PHY_CONTROL_DISABLE (0x03)
2800
2801 /**
2802 * mpi3mr_expander_phy_control - expander phy control
2803 * @mrioc: Adapter instance reference
2804 * @phy: The SAS transport layer phy object
2805 * @phy_operation: The phy operation to be executed
2806 *
2807 * Issues SMP passthru phy control request to execute a specific
2808 * phy operation for a given expander device.
2809 *
2810 * Return: 0 for success, non-zero for failure.
2811 */
2812 static int
mpi3mr_expander_phy_control(struct mpi3mr_ioc * mrioc,struct sas_phy * phy,u8 phy_operation)2813 mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
2814 struct sas_phy *phy, u8 phy_operation)
2815 {
2816 struct mpi3_smp_passthrough_request mpi_request;
2817 struct mpi3_smp_passthrough_reply mpi_reply;
2818 struct phy_control_request *phy_control_request;
2819 struct phy_control_reply *phy_control_reply;
2820 int rc;
2821 void *psge;
2822 void *data_out = NULL;
2823 dma_addr_t data_out_dma;
2824 dma_addr_t data_in_dma;
2825 size_t data_in_sz;
2826 size_t data_out_sz;
2827 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2828 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2829 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2830 u16 ioc_status;
2831 u16 sz;
2832
2833 if (mrioc->reset_in_progress) {
2834 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2835 return -EFAULT;
2836 }
2837
2838 if (mrioc->pci_err_recovery) {
2839 ioc_err(mrioc, "%s: pci error recovery in progress!\n",
2840 __func__);
2841 return -EFAULT;
2842 }
2843
2844 data_out_sz = sizeof(struct phy_control_request);
2845 data_in_sz = sizeof(struct phy_control_reply);
2846 sz = data_out_sz + data_in_sz;
2847 data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2848 GFP_KERNEL);
2849 if (!data_out) {
2850 rc = -ENOMEM;
2851 goto out;
2852 }
2853
2854 data_in_dma = data_out_dma + data_out_sz;
2855 phy_control_reply = data_out + data_out_sz;
2856
2857 rc = -EINVAL;
2858 memset(data_out, 0, sz);
2859
2860 phy_control_request = data_out;
2861 phy_control_request->smp_frame_type = 0x40;
2862 phy_control_request->function = 0x91;
2863 phy_control_request->request_length = 9;
2864 phy_control_request->allocated_response_length = 0;
2865 phy_control_request->phy_identifier = phy->number;
2866 phy_control_request->phy_operation = phy_operation;
2867 phy_control_request->programmed_min_physical_link_rate =
2868 phy->minimum_linkrate << 4;
2869 phy_control_request->programmed_max_physical_link_rate =
2870 phy->maximum_linkrate << 4;
2871
2872 memset(&mpi_request, 0, request_sz);
2873 memset(&mpi_reply, 0, reply_sz);
2874 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2875 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2876 mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2877 mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2878
2879 psge = &mpi_request.request_sge;
2880 mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2881
2882 psge = &mpi_request.response_sge;
2883 mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2884
2885 dprint_transport_info(mrioc,
2886 "sending phy control SMP request to sas_address(0x%016llx), phy_id(%d) opcode(%d)\n",
2887 (unsigned long long)phy->identify.sas_address, phy->number,
2888 phy_operation);
2889
2890 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2891 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2892 goto out;
2893
2894 dprint_transport_info(mrioc,
2895 "phy control SMP request completed with ioc_status(0x%04x)\n",
2896 ioc_status);
2897
2898 if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2899 dprint_transport_info(mrioc,
2900 "phy control - reply data transfer size(%d)\n",
2901 le16_to_cpu(mpi_reply.response_data_length));
2902
2903 if (le16_to_cpu(mpi_reply.response_data_length) !=
2904 sizeof(struct phy_control_reply))
2905 goto out;
2906 dprint_transport_info(mrioc,
2907 "phy control - function_result(%d)\n",
2908 phy_control_reply->function_result);
2909 rc = 0;
2910 }
2911 out:
2912 if (data_out)
2913 dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2914 data_out_dma);
2915
2916 return rc;
2917 }
2918
2919 /**
2920 * mpi3mr_transport_phy_reset - Reset a given phy
2921 * @phy: The SAS transport layer phy object
2922 * @hard_reset: Flag to indicate the type of reset
2923 *
2924 * Return: 0 for success, non-zero for failure.
2925 */
2926 static int
mpi3mr_transport_phy_reset(struct sas_phy * phy,int hard_reset)2927 mpi3mr_transport_phy_reset(struct sas_phy *phy, int hard_reset)
2928 {
2929 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2930 struct mpi3_iounit_control_request mpi_request;
2931 struct mpi3_iounit_control_reply mpi_reply;
2932 u16 request_sz = sizeof(struct mpi3_iounit_control_request);
2933 u16 reply_sz = sizeof(struct mpi3_iounit_control_reply);
2934 int rc = 0;
2935 u16 ioc_status;
2936
2937 rc = mpi3mr_parent_present(mrioc, phy);
2938 if (rc)
2939 return rc;
2940
2941 /* handle expander phys */
2942 if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2943 return mpi3mr_expander_phy_control(mrioc, phy,
2944 (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
2945 SMP_PHY_CONTROL_LINK_RESET);
2946
2947 /* handle hba phys */
2948 memset(&mpi_request, 0, request_sz);
2949 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2950 mpi_request.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
2951 mpi_request.operation = MPI3_CTRL_OP_SAS_PHY_CONTROL;
2952 mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX] =
2953 (hard_reset ? MPI3_CTRL_ACTION_HARD_RESET :
2954 MPI3_CTRL_ACTION_LINK_RESET);
2955 mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX] =
2956 phy->number;
2957
2958 dprint_transport_info(mrioc,
2959 "sending phy reset request to sas_address(0x%016llx), phy_id(%d) hard_reset(%d)\n",
2960 (unsigned long long)phy->identify.sas_address, phy->number,
2961 hard_reset);
2962
2963 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2964 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status)) {
2965 rc = -EAGAIN;
2966 goto out;
2967 }
2968
2969 dprint_transport_info(mrioc,
2970 "phy reset request completed with ioc_status(0x%04x)\n",
2971 ioc_status);
2972 out:
2973 return rc;
2974 }
2975
2976 /**
2977 * mpi3mr_transport_phy_enable - enable/disable phys
2978 * @phy: The SAS transport layer phy object
2979 * @enable: flag to enable/disable, enable phy when true
2980 *
2981 * This function enables/disables a given by executing required
2982 * configuration page changes or expander phy control command
2983 *
2984 * Return: 0 for success, non-zero for failure.
2985 */
2986 static int
mpi3mr_transport_phy_enable(struct sas_phy * phy,int enable)2987 mpi3mr_transport_phy_enable(struct sas_phy *phy, int enable)
2988 {
2989 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2990 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
2991 struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
2992 u16 sz;
2993 int rc = 0;
2994 int i, discovery_active;
2995
2996 rc = mpi3mr_parent_present(mrioc, phy);
2997 if (rc)
2998 return rc;
2999
3000 /* handle expander phys */
3001 if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
3002 return mpi3mr_expander_phy_control(mrioc, phy,
3003 (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
3004 SMP_PHY_CONTROL_DISABLE);
3005
3006 /* handle hba phys */
3007 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
3008 (mrioc->sas_hba.num_phys *
3009 sizeof(struct mpi3_sas_io_unit0_phy_data));
3010 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
3011 if (!sas_io_unit_pg0) {
3012 rc = -ENOMEM;
3013 goto out;
3014 }
3015 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
3016 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3017 __FILE__, __LINE__, __func__);
3018 rc = -ENXIO;
3019 goto out;
3020 }
3021
3022 /* unable to enable/disable phys when discovery is active */
3023 for (i = 0, discovery_active = 0; i < mrioc->sas_hba.num_phys ; i++) {
3024 if (sas_io_unit_pg0->phy_data[i].port_flags &
3025 MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS) {
3026 ioc_err(mrioc,
3027 "discovery is active on port = %d, phy = %d\n"
3028 "\tunable to enable/disable phys, try again later!\n",
3029 sas_io_unit_pg0->phy_data[i].io_unit_port, i);
3030 discovery_active = 1;
3031 }
3032 }
3033
3034 if (discovery_active) {
3035 rc = -EAGAIN;
3036 goto out;
3037 }
3038
3039 if ((sas_io_unit_pg0->phy_data[phy->number].phy_flags &
3040 (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
3041 MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))) {
3042 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3043 __FILE__, __LINE__, __func__);
3044 rc = -ENXIO;
3045 goto out;
3046 }
3047
3048 /* read sas_iounit page 1 */
3049 sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3050 (mrioc->sas_hba.num_phys *
3051 sizeof(struct mpi3_sas_io_unit1_phy_data));
3052 sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3053 if (!sas_io_unit_pg1) {
3054 rc = -ENOMEM;
3055 goto out;
3056 }
3057
3058 if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3059 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3060 __FILE__, __LINE__, __func__);
3061 rc = -ENXIO;
3062 goto out;
3063 }
3064
3065 if (enable)
3066 sas_io_unit_pg1->phy_data[phy->number].phy_flags
3067 &= ~MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3068 else
3069 sas_io_unit_pg1->phy_data[phy->number].phy_flags
3070 |= MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3071
3072 mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz);
3073
3074 /* link reset */
3075 if (enable)
3076 mpi3mr_transport_phy_reset(phy, 0);
3077
3078 out:
3079 kfree(sas_io_unit_pg1);
3080 kfree(sas_io_unit_pg0);
3081 return rc;
3082 }
3083
3084 /**
3085 * mpi3mr_transport_phy_speed - set phy min/max speed
3086 * @phy: The SAS transport later phy object
3087 * @rates: Rates defined as in sas_phy_linkrates
3088 *
3089 * This function sets the link rates given in the rates
3090 * argument to the given phy by executing required configuration
3091 * page changes or expander phy control command
3092 *
3093 * Return: 0 for success, non-zero for failure.
3094 */
3095 static int
mpi3mr_transport_phy_speed(struct sas_phy * phy,struct sas_phy_linkrates * rates)3096 mpi3mr_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
3097 {
3098 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
3099 struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
3100 struct mpi3_sas_phy_page0 phy_pg0;
3101 u16 sz, ioc_status;
3102 int rc = 0;
3103
3104 rc = mpi3mr_parent_present(mrioc, phy);
3105 if (rc)
3106 return rc;
3107
3108 if (!rates->minimum_linkrate)
3109 rates->minimum_linkrate = phy->minimum_linkrate;
3110 else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
3111 rates->minimum_linkrate = phy->minimum_linkrate_hw;
3112
3113 if (!rates->maximum_linkrate)
3114 rates->maximum_linkrate = phy->maximum_linkrate;
3115 else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
3116 rates->maximum_linkrate = phy->maximum_linkrate_hw;
3117
3118 /* handle expander phys */
3119 if (phy->identify.sas_address != mrioc->sas_hba.sas_address) {
3120 phy->minimum_linkrate = rates->minimum_linkrate;
3121 phy->maximum_linkrate = rates->maximum_linkrate;
3122 return mpi3mr_expander_phy_control(mrioc, phy,
3123 SMP_PHY_CONTROL_LINK_RESET);
3124 }
3125
3126 /* handle hba phys */
3127 sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3128 (mrioc->sas_hba.num_phys *
3129 sizeof(struct mpi3_sas_io_unit1_phy_data));
3130 sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3131 if (!sas_io_unit_pg1) {
3132 rc = -ENOMEM;
3133 goto out;
3134 }
3135
3136 if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3137 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3138 __FILE__, __LINE__, __func__);
3139 rc = -ENXIO;
3140 goto out;
3141 }
3142
3143 sas_io_unit_pg1->phy_data[phy->number].max_min_link_rate =
3144 (rates->minimum_linkrate + (rates->maximum_linkrate << 4));
3145
3146 if (mpi3mr_cfg_set_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 /* link reset */
3154 mpi3mr_transport_phy_reset(phy, 0);
3155
3156 /* read phy page 0, then update the rates in the sas transport phy */
3157 if (!mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
3158 sizeof(struct mpi3_sas_phy_page0),
3159 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number) &&
3160 (ioc_status == MPI3_IOCSTATUS_SUCCESS)) {
3161 phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
3162 phy_pg0.programmed_link_rate &
3163 MPI3_SAS_PRATE_MIN_RATE_MASK);
3164 phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
3165 phy_pg0.programmed_link_rate >> 4);
3166 phy->negotiated_linkrate =
3167 mpi3mr_convert_phy_link_rate(
3168 (phy_pg0.negotiated_link_rate &
3169 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK)
3170 >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
3171 }
3172
3173 out:
3174 kfree(sas_io_unit_pg1);
3175 return rc;
3176 }
3177
3178 /**
3179 * mpi3mr_map_smp_buffer - map BSG dma buffer
3180 * @dev: Generic device reference
3181 * @buf: BSG buffer pointer
3182 * @dma_addr: Physical address holder
3183 * @dma_len: Mapped DMA buffer length.
3184 * @p: Virtual address holder
3185 *
3186 * This function maps the DMAable buffer
3187 *
3188 * Return: 0 on success, non-zero on failure
3189 */
3190 static int
mpi3mr_map_smp_buffer(struct device * dev,struct bsg_buffer * buf,dma_addr_t * dma_addr,size_t * dma_len,void ** p)3191 mpi3mr_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3192 dma_addr_t *dma_addr, size_t *dma_len, void **p)
3193 {
3194 /* Check if the request is split across multiple segments */
3195 if (buf->sg_cnt > 1) {
3196 *p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
3197 GFP_KERNEL);
3198 if (!*p)
3199 return -ENOMEM;
3200 *dma_len = buf->payload_len;
3201 } else {
3202 if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))
3203 return -ENOMEM;
3204 *dma_addr = sg_dma_address(buf->sg_list);
3205 *dma_len = sg_dma_len(buf->sg_list);
3206 *p = NULL;
3207 }
3208
3209 return 0;
3210 }
3211
3212 /**
3213 * mpi3mr_unmap_smp_buffer - unmap BSG dma buffer
3214 * @dev: Generic device reference
3215 * @buf: BSG buffer pointer
3216 * @dma_addr: Physical address to be unmapped
3217 * @p: Virtual address
3218 *
3219 * This function unmaps the DMAable buffer
3220 */
3221 static void
mpi3mr_unmap_smp_buffer(struct device * dev,struct bsg_buffer * buf,dma_addr_t dma_addr,void * p)3222 mpi3mr_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3223 dma_addr_t dma_addr, void *p)
3224 {
3225 if (p)
3226 dma_free_coherent(dev, buf->payload_len, p, dma_addr);
3227 else
3228 dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
3229 }
3230
3231 /**
3232 * mpi3mr_transport_smp_handler - handler for smp passthru
3233 * @job: BSG job reference
3234 * @shost: SCSI host object reference
3235 * @rphy: SAS transport rphy object pointing the expander
3236 *
3237 * This is used primarily by smp utils for sending the SMP
3238 * commands to the expanders attached to the controller
3239 */
3240 static void
mpi3mr_transport_smp_handler(struct bsg_job * job,struct Scsi_Host * shost,struct sas_rphy * rphy)3241 mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
3242 struct sas_rphy *rphy)
3243 {
3244 struct mpi3mr_ioc *mrioc = shost_priv(shost);
3245 struct mpi3_smp_passthrough_request mpi_request;
3246 struct mpi3_smp_passthrough_reply mpi_reply;
3247 int rc;
3248 void *psge;
3249 dma_addr_t dma_addr_in;
3250 dma_addr_t dma_addr_out;
3251 void *addr_in = NULL;
3252 void *addr_out = NULL;
3253 size_t dma_len_in;
3254 size_t dma_len_out;
3255 unsigned int reslen = 0;
3256 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
3257 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
3258 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
3259 u16 ioc_status;
3260
3261 if (mrioc->reset_in_progress) {
3262 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
3263 rc = -EFAULT;
3264 goto out;
3265 }
3266
3267 if (mrioc->pci_err_recovery) {
3268 ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
3269 rc = -EFAULT;
3270 goto out;
3271 }
3272
3273 rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3274 &dma_addr_out, &dma_len_out, &addr_out);
3275 if (rc)
3276 goto out;
3277
3278 if (addr_out)
3279 sg_copy_to_buffer(job->request_payload.sg_list,
3280 job->request_payload.sg_cnt, addr_out,
3281 job->request_payload.payload_len);
3282
3283 rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3284 &dma_addr_in, &dma_len_in, &addr_in);
3285 if (rc)
3286 goto unmap_out;
3287
3288 memset(&mpi_request, 0, request_sz);
3289 memset(&mpi_reply, 0, reply_sz);
3290 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
3291 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
3292 mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_rphy(mrioc, rphy);
3293 mpi_request.sas_address = ((rphy) ?
3294 cpu_to_le64(rphy->identify.sas_address) :
3295 cpu_to_le64(mrioc->sas_hba.sas_address));
3296 psge = &mpi_request.request_sge;
3297 mpi3mr_add_sg_single(psge, sgl_flags, dma_len_out - 4, dma_addr_out);
3298
3299 psge = &mpi_request.response_sge;
3300 mpi3mr_add_sg_single(psge, sgl_flags, dma_len_in - 4, dma_addr_in);
3301
3302 dprint_transport_info(mrioc, "sending SMP request\n");
3303
3304 rc = mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
3305 &mpi_reply, reply_sz,
3306 MPI3MR_INTADMCMD_TIMEOUT, &ioc_status);
3307 if (rc)
3308 goto unmap_in;
3309
3310 dprint_transport_info(mrioc,
3311 "SMP request completed with ioc_status(0x%04x)\n", ioc_status);
3312
3313 dprint_transport_info(mrioc,
3314 "SMP request - reply data transfer size(%d)\n",
3315 le16_to_cpu(mpi_reply.response_data_length));
3316
3317 memcpy(job->reply, &mpi_reply, reply_sz);
3318 job->reply_len = reply_sz;
3319 reslen = le16_to_cpu(mpi_reply.response_data_length);
3320
3321 if (addr_in)
3322 sg_copy_from_buffer(job->reply_payload.sg_list,
3323 job->reply_payload.sg_cnt, addr_in,
3324 job->reply_payload.payload_len);
3325
3326 rc = 0;
3327 unmap_in:
3328 mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3329 dma_addr_in, addr_in);
3330 unmap_out:
3331 mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3332 dma_addr_out, addr_out);
3333 out:
3334 bsg_job_done(job, rc, reslen);
3335 }
3336
3337 struct sas_function_template mpi3mr_transport_functions = {
3338 .get_linkerrors = mpi3mr_transport_get_linkerrors,
3339 .get_enclosure_identifier = mpi3mr_transport_get_enclosure_identifier,
3340 .get_bay_identifier = mpi3mr_transport_get_bay_identifier,
3341 .phy_reset = mpi3mr_transport_phy_reset,
3342 .phy_enable = mpi3mr_transport_phy_enable,
3343 .set_phy_speed = mpi3mr_transport_phy_speed,
3344 .smp_handler = mpi3mr_transport_smp_handler,
3345 };
3346
3347 struct scsi_transport_template *mpi3mr_transport_template;
3348