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