1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Driver for Broadcom MPI3 Storage Controllers
5 * Copyright (C) 2017-2022 Broadcom Inc.
6 * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
12 static void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
13 struct mpi3mr_sas_node *sas_expander);
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
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.
31 * On successful completion of the request this function returns
32 * appropriate ioc status from the firmware back to the caller.
34 * Return: 0 on success, non-zero on failure.
36 static int mpi3mr_post_transport_req(struct mpi3mr_ioc *mrioc, void *request,
37 u16 request_sz, void *reply, u16 reply_sz, int timeout,
42 mutex_lock(&mrioc->transport_cmds.mutex);
43 if (mrioc->transport_cmds.state & MPI3MR_CMD_PENDING) {
45 ioc_err(mrioc, "sending transport request failed due to command in use\n");
46 mutex_unlock(&mrioc->transport_cmds.mutex);
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;
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);
61 ioc_err(mrioc, "posting transport request failed\n");
64 wait_for_completion_timeout(&mrioc->transport_cmds.done,
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");
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);
80 if ((reply) && (mrioc->transport_cmds.state & MPI3MR_CMD_REPLY_VALID))
81 memcpy((u8 *)reply, mrioc->transport_cmds.reply, reply_sz);
84 mrioc->transport_cmds.state = MPI3MR_CMD_NOTUSED;
85 mutex_unlock(&mrioc->transport_cmds.mutex);
91 /* report manufacture request structure */
92 struct rep_manu_request {
99 /* report manufacture reply structure */
100 struct rep_manu_reply {
101 u8 smp_frame_type; /* 0x41 */
102 u8 function; /* 0x01 */
105 u16 expander_change_count;
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];
114 u8 component_revision_id;
116 u8 vendor_specific[8];
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
126 * Fills in the sas_expander_device with manufacturing info.
128 * Return: 0 for success, non-zero for failure.
130 static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
131 u64 sas_address, struct sas_expander_device *edev, u8 port_id)
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;
139 void *data_out = NULL;
140 dma_addr_t data_out_dma;
141 dma_addr_t data_in_dma;
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);
149 if (mrioc->reset_in_progress) {
150 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
154 data_out_sz = sizeof(struct rep_manu_request);
155 data_in_sz = sizeof(struct rep_manu_reply);
156 data_out = dma_alloc_coherent(&mrioc->pdev->dev,
157 data_out_sz + data_in_sz, &data_out_dma, GFP_KERNEL);
163 data_in_dma = data_out_dma + data_out_sz;
164 manufacture_reply = data_out + data_out_sz;
166 manufacture_request = data_out;
167 manufacture_request->smp_frame_type = 0x40;
168 manufacture_request->function = 1;
169 manufacture_request->reserved = 0;
170 manufacture_request->request_length = 0;
172 memset(&mpi_request, 0, request_sz);
173 memset(&mpi_reply, 0, reply_sz);
174 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
175 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
176 mpi_request.io_unit_port = (u8) port_id;
177 mpi_request.sas_address = cpu_to_le64(sas_address);
179 psge = &mpi_request.request_sge;
180 mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
182 psge = &mpi_request.response_sge;
183 mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
185 dprint_transport_info(mrioc,
186 "sending report manufacturer SMP request to sas_address(0x%016llx), port(%d)\n",
187 (unsigned long long)sas_address, port_id);
189 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
190 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
193 dprint_transport_info(mrioc,
194 "report manufacturer SMP request completed with ioc_status(0x%04x)\n",
197 if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
200 dprint_transport_info(mrioc,
201 "report manufacturer - reply data transfer size(%d)\n",
202 le16_to_cpu(mpi_reply.response_data_length));
204 if (le16_to_cpu(mpi_reply.response_data_length) !=
205 sizeof(struct rep_manu_reply))
208 strscpy(edev->vendor_id, manufacture_reply->vendor_id,
209 SAS_EXPANDER_VENDOR_ID_LEN);
210 strscpy(edev->product_id, manufacture_reply->product_id,
211 SAS_EXPANDER_PRODUCT_ID_LEN);
212 strscpy(edev->product_rev, manufacture_reply->product_rev,
213 SAS_EXPANDER_PRODUCT_REV_LEN);
214 edev->level = manufacture_reply->sas_format & 1;
216 strscpy(edev->component_vendor_id,
217 manufacture_reply->component_vendor_id,
218 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
219 tmp = (u8 *)&manufacture_reply->component_id;
220 edev->component_id = tmp[0] << 8 | tmp[1];
221 edev->component_revision_id =
222 manufacture_reply->component_revision_id;
228 dma_free_coherent(&mrioc->pdev->dev, data_out_sz + data_in_sz,
229 data_out, data_out_dma);
235 * __mpi3mr_expander_find_by_handle - expander search by handle
236 * @mrioc: Adapter instance reference
237 * @handle: Firmware device handle of the expander
239 * Context: The caller should acquire sas_node_lock
241 * This searches for expander device based on handle, then
242 * returns the sas_node object.
244 * Return: Expander sas_node object reference or NULL
246 struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc
249 struct mpi3mr_sas_node *sas_expander, *r;
252 list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
253 if (sas_expander->handle != handle)
263 * mpi3mr_is_expander_device - if device is an expander
264 * @device_info: Bitfield providing information about the device
266 * Return: 1 if the device is expander device, else 0.
268 u8 mpi3mr_is_expander_device(u16 device_info)
270 if ((device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) ==
271 MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER)
278 * mpi3mr_get_sas_address - retrieve sas_address for handle
279 * @mrioc: Adapter instance reference
280 * @handle: Firmware device handle
281 * @sas_address: Address to hold sas address
283 * This function issues device page0 read for a given device
284 * handle and gets the SAS address and return it back
286 * Return: 0 for success, non-zero for failure
288 static int mpi3mr_get_sas_address(struct mpi3mr_ioc *mrioc, u16 handle,
291 struct mpi3_device_page0 dev_pg0;
293 struct mpi3_device0_sas_sata_format *sasinf;
297 if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
298 sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
300 ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
304 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
305 ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
306 handle, ioc_status, __FILE__, __LINE__, __func__);
310 if (le16_to_cpu(dev_pg0.flags) &
311 MPI3_DEVICE0_FLAGS_CONTROLLER_DEV_HANDLE)
312 *sas_address = mrioc->sas_hba.sas_address;
313 else if (dev_pg0.device_form == MPI3_DEVICE_DEVFORM_SAS_SATA) {
314 sasinf = &dev_pg0.device_specific.sas_sata_format;
315 *sas_address = le64_to_cpu(sasinf->sas_address);
317 ioc_err(mrioc, "%s: device_form(%d) is not SAS_SATA\n",
318 __func__, dev_pg0.device_form);
325 * __mpi3mr_get_tgtdev_by_addr - target device search
326 * @mrioc: Adapter instance reference
327 * @sas_address: SAS address of the device
328 * @hba_port: HBA port entry
330 * This searches for target device from sas address and hba port
331 * pointer then return mpi3mr_tgt_dev object.
333 * Return: Valid tget_dev or NULL
335 static struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc,
336 u64 sas_address, struct mpi3mr_hba_port *hba_port)
338 struct mpi3mr_tgt_dev *tgtdev;
340 assert_spin_locked(&mrioc->tgtdev_lock);
342 list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
343 if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&
344 (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)
345 && (tgtdev->dev_spec.sas_sata_inf.hba_port == hba_port))
349 mpi3mr_tgtdev_get(tgtdev);
354 * mpi3mr_get_tgtdev_by_addr - target device search
355 * @mrioc: Adapter instance reference
356 * @sas_address: SAS address of the device
357 * @hba_port: HBA port entry
359 * This searches for target device from sas address and hba port
360 * pointer then return mpi3mr_tgt_dev object.
362 * Context: This function will acquire tgtdev_lock and will
363 * release before returning the mpi3mr_tgt_dev object.
365 * Return: Valid tget_dev or NULL
367 static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc,
368 u64 sas_address, struct mpi3mr_hba_port *hba_port)
370 struct mpi3mr_tgt_dev *tgtdev = NULL;
376 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
377 tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc, sas_address, hba_port);
378 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
385 * mpi3mr_remove_device_by_sas_address - remove the device
386 * @mrioc: Adapter instance reference
387 * @sas_address: SAS address of the device
388 * @hba_port: HBA port entry
390 * This searches for target device using sas address and hba
391 * port pointer then removes it from the OS.
395 static void mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc,
396 u64 sas_address, struct mpi3mr_hba_port *hba_port)
398 struct mpi3mr_tgt_dev *tgtdev = NULL;
400 u8 was_on_tgtdev_list = 0;
405 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
406 tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc,
407 sas_address, hba_port);
409 if (!list_empty(&tgtdev->list)) {
410 list_del_init(&tgtdev->list);
411 was_on_tgtdev_list = 1;
412 mpi3mr_tgtdev_put(tgtdev);
415 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
416 if (was_on_tgtdev_list) {
417 if (tgtdev->host_exposed)
418 mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
419 mpi3mr_tgtdev_put(tgtdev);
424 * __mpi3mr_get_tgtdev_by_addr_and_rphy - target device search
425 * @mrioc: Adapter instance reference
426 * @sas_address: SAS address of the device
427 * @rphy: SAS transport layer rphy object
429 * This searches for target device from sas address and rphy
430 * pointer then return mpi3mr_tgt_dev object.
432 * Return: Valid tget_dev or NULL
434 struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
435 struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy)
437 struct mpi3mr_tgt_dev *tgtdev;
439 assert_spin_locked(&mrioc->tgtdev_lock);
441 list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
442 if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&
443 (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)
444 && (tgtdev->dev_spec.sas_sata_inf.rphy == rphy))
448 mpi3mr_tgtdev_get(tgtdev);
453 * mpi3mr_expander_find_by_sas_address - sas expander search
454 * @mrioc: Adapter instance reference
455 * @sas_address: SAS address of expander
456 * @hba_port: HBA port entry
458 * Return: A valid SAS expander node or NULL.
461 static struct mpi3mr_sas_node *mpi3mr_expander_find_by_sas_address(
462 struct mpi3mr_ioc *mrioc, u64 sas_address,
463 struct mpi3mr_hba_port *hba_port)
465 struct mpi3mr_sas_node *sas_expander, *r = NULL;
470 list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
471 if ((sas_expander->sas_address != sas_address) ||
472 (sas_expander->hba_port != hba_port))
482 * __mpi3mr_sas_node_find_by_sas_address - sas node search
483 * @mrioc: Adapter instance reference
484 * @sas_address: SAS address of expander or sas host
485 * @hba_port: HBA port entry
486 * Context: Caller should acquire mrioc->sas_node_lock.
488 * If the SAS address indicates the device is direct attached to
489 * the controller (controller's SAS address) then the SAS node
490 * associated with the controller is returned back else the SAS
491 * address and hba port are used to identify the exact expander
492 * and the associated sas_node object is returned. If there is
493 * no match NULL is returned.
495 * Return: A valid SAS node or NULL.
498 static struct mpi3mr_sas_node *__mpi3mr_sas_node_find_by_sas_address(
499 struct mpi3mr_ioc *mrioc, u64 sas_address,
500 struct mpi3mr_hba_port *hba_port)
503 if (mrioc->sas_hba.sas_address == sas_address)
504 return &mrioc->sas_hba;
505 return mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
510 * mpi3mr_parent_present - Is parent present for a phy
511 * @mrioc: Adapter instance reference
512 * @phy: SAS transport layer phy object
514 * Return: 0 if parent is present else non-zero
516 static int mpi3mr_parent_present(struct mpi3mr_ioc *mrioc, struct sas_phy *phy)
519 struct mpi3mr_hba_port *hba_port = phy->hostdata;
521 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
522 if (__mpi3mr_sas_node_find_by_sas_address(mrioc,
523 phy->identify.sas_address,
525 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
528 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
533 * mpi3mr_convert_phy_link_rate -
534 * @link_rate: link rate as defined in the MPI header
536 * Convert link_rate from mpi format into sas_transport layer
539 * Return: A valid SAS transport layer defined link rate
541 static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
543 enum sas_linkrate rc;
546 case MPI3_SAS_NEG_LINK_RATE_1_5:
547 rc = SAS_LINK_RATE_1_5_GBPS;
549 case MPI3_SAS_NEG_LINK_RATE_3_0:
550 rc = SAS_LINK_RATE_3_0_GBPS;
552 case MPI3_SAS_NEG_LINK_RATE_6_0:
553 rc = SAS_LINK_RATE_6_0_GBPS;
555 case MPI3_SAS_NEG_LINK_RATE_12_0:
556 rc = SAS_LINK_RATE_12_0_GBPS;
558 case MPI3_SAS_NEG_LINK_RATE_22_5:
559 rc = SAS_LINK_RATE_22_5_GBPS;
561 case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:
562 rc = SAS_PHY_DISABLED;
564 case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
565 rc = SAS_LINK_RATE_FAILED;
567 case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:
568 rc = SAS_SATA_PORT_SELECTOR;
570 case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
571 rc = SAS_PHY_RESET_IN_PROGRESS;
573 case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
574 case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
576 rc = SAS_LINK_RATE_UNKNOWN;
583 * mpi3mr_delete_sas_phy - Remove a single phy from port
584 * @mrioc: Adapter instance reference
585 * @mr_sas_port: Internal Port object
586 * @mr_sas_phy: Internal Phy object
590 static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
591 struct mpi3mr_sas_port *mr_sas_port,
592 struct mpi3mr_sas_phy *mr_sas_phy)
594 u64 sas_address = mr_sas_port->remote_identify.sas_address;
596 dev_info(&mr_sas_phy->phy->dev,
597 "remove: sas_address(0x%016llx), phy(%d)\n",
598 (unsigned long long) sas_address, mr_sas_phy->phy_id);
600 list_del(&mr_sas_phy->port_siblings);
601 mr_sas_port->num_phys--;
602 mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);
603 if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)
604 mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
605 sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
606 mr_sas_phy->phy_belongs_to_port = 0;
610 * mpi3mr_add_sas_phy - Adding a single phy to a port
611 * @mrioc: Adapter instance reference
612 * @mr_sas_port: Internal Port object
613 * @mr_sas_phy: Internal Phy object
617 static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
618 struct mpi3mr_sas_port *mr_sas_port,
619 struct mpi3mr_sas_phy *mr_sas_phy)
621 u64 sas_address = mr_sas_port->remote_identify.sas_address;
623 dev_info(&mr_sas_phy->phy->dev,
624 "add: sas_address(0x%016llx), phy(%d)\n", (unsigned long long)
625 sas_address, mr_sas_phy->phy_id);
627 list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
628 mr_sas_port->num_phys++;
629 mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);
630 if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)
631 mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
632 sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
633 mr_sas_phy->phy_belongs_to_port = 1;
637 * mpi3mr_add_phy_to_an_existing_port - add phy to existing port
638 * @mrioc: Adapter instance reference
639 * @mr_sas_node: Internal sas node object (expander or host)
640 * @mr_sas_phy: Internal Phy object *
641 * @sas_address: SAS address of device/expander were phy needs
643 * @hba_port: HBA port entry
647 static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,
648 struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy,
649 u64 sas_address, struct mpi3mr_hba_port *hba_port)
651 struct mpi3mr_sas_port *mr_sas_port;
652 struct mpi3mr_sas_phy *srch_phy;
654 if (mr_sas_phy->phy_belongs_to_port == 1)
660 list_for_each_entry(mr_sas_port, &mr_sas_node->sas_port_list,
662 if (mr_sas_port->remote_identify.sas_address !=
665 if (mr_sas_port->hba_port != hba_port)
667 list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
669 if (srch_phy == mr_sas_phy)
672 mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy);
678 * mpi3mr_delete_sas_port - helper function to removing a port
679 * @mrioc: Adapter instance reference
680 * @mr_sas_port: Internal Port object
684 static void mpi3mr_delete_sas_port(struct mpi3mr_ioc *mrioc,
685 struct mpi3mr_sas_port *mr_sas_port)
687 u64 sas_address = mr_sas_port->remote_identify.sas_address;
688 struct mpi3mr_hba_port *hba_port = mr_sas_port->hba_port;
689 enum sas_device_type device_type =
690 mr_sas_port->remote_identify.device_type;
692 dev_info(&mr_sas_port->port->dev,
693 "remove: sas_address(0x%016llx)\n",
694 (unsigned long long) sas_address);
696 if (device_type == SAS_END_DEVICE)
697 mpi3mr_remove_device_by_sas_address(mrioc, sas_address,
700 else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
701 device_type == SAS_FANOUT_EXPANDER_DEVICE)
702 mpi3mr_expander_remove(mrioc, sas_address, hba_port);
706 * mpi3mr_del_phy_from_an_existing_port - del phy from a port
707 * @mrioc: Adapter instance reference
708 * @mr_sas_node: Internal sas node object (expander or host)
709 * @mr_sas_phy: Internal Phy object
713 static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
714 struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy)
716 struct mpi3mr_sas_port *mr_sas_port, *next;
717 struct mpi3mr_sas_phy *srch_phy;
719 if (mr_sas_phy->phy_belongs_to_port == 0)
722 list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
724 list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
726 if (srch_phy != mr_sas_phy)
728 if ((mr_sas_port->num_phys == 1) &&
729 !mrioc->reset_in_progress)
730 mpi3mr_delete_sas_port(mrioc, mr_sas_port);
732 mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
740 * mpi3mr_sas_port_sanity_check - sanity check while adding port
741 * @mrioc: Adapter instance reference
742 * @mr_sas_node: Internal sas node object (expander or host)
743 * @sas_address: SAS address of device/expander
744 * @hba_port: HBA port entry
746 * Verifies whether the Phys attached to a device with the given
747 * SAS address already belongs to an existing sas port if so
748 * will remove those phys from the sas port
752 static void mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc,
753 struct mpi3mr_sas_node *mr_sas_node, u64 sas_address,
754 struct mpi3mr_hba_port *hba_port)
758 for (i = 0; i < mr_sas_node->num_phys; i++) {
759 if ((mr_sas_node->phy[i].remote_identify.sas_address !=
760 sas_address) || (mr_sas_node->phy[i].hba_port != hba_port))
762 if (mr_sas_node->phy[i].phy_belongs_to_port == 1)
763 mpi3mr_del_phy_from_an_existing_port(mrioc,
764 mr_sas_node, &mr_sas_node->phy[i]);
769 * mpi3mr_set_identify - set identify for phys and end devices
770 * @mrioc: Adapter instance reference
771 * @handle: Firmware device handle
772 * @identify: SAS transport layer's identify info
774 * Populates sas identify info for a specific device.
776 * Return: 0 for success, non-zero for failure.
778 static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
779 struct sas_identify *identify)
782 struct mpi3_device_page0 device_pg0;
783 struct mpi3_device0_sas_sata_format *sasinf;
787 if (mrioc->reset_in_progress) {
788 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
792 if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
793 sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {
794 ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
798 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
799 ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
800 handle, ioc_status, __FILE__, __LINE__, __func__);
804 memset(identify, 0, sizeof(struct sas_identify));
805 sasinf = &device_pg0.device_specific.sas_sata_format;
806 device_info = le16_to_cpu(sasinf->device_info);
809 identify->sas_address = le64_to_cpu(sasinf->sas_address);
811 /* phy number of the parent device this device is linked to */
812 identify->phy_identifier = sasinf->phy_num;
815 switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) {
816 case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:
817 identify->device_type = SAS_PHY_UNUSED;
819 case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:
820 identify->device_type = SAS_END_DEVICE;
822 case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:
823 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
827 /* initiator_port_protocols */
828 if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)
829 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
830 /* MPI3.0 doesn't have define for SATA INIT so setting both here*/
831 if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)
832 identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |
834 if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)
835 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
837 /* target_port_protocols */
838 if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)
839 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
840 /* MPI3.0 doesn't have define for STP Target so setting both here*/
841 if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)
842 identify->target_port_protocols |= (SAS_PROTOCOL_STP |
844 if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)
845 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
850 * mpi3mr_add_host_phy - report sas_host phy to SAS transport
851 * @mrioc: Adapter instance reference
852 * @mr_sas_phy: Internal Phy object
853 * @phy_pg0: SAS phy page 0
854 * @parent_dev: Prent device class object
856 * Return: 0 for success, non-zero for failure.
858 static int mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc,
859 struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0,
860 struct device *parent_dev)
863 int phy_index = mr_sas_phy->phy_id;
866 INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
867 phy = sas_phy_alloc(parent_dev, phy_index);
869 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
870 __FILE__, __LINE__, __func__);
873 if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
874 &mr_sas_phy->identify))) {
875 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
876 __FILE__, __LINE__, __func__);
880 phy->identify = mr_sas_phy->identify;
881 mr_sas_phy->attached_handle = le16_to_cpu(phy_pg0.attached_dev_handle);
882 if (mr_sas_phy->attached_handle)
883 mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
884 &mr_sas_phy->remote_identify);
885 phy->identify.phy_identifier = mr_sas_phy->phy_id;
886 phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
887 (phy_pg0.negotiated_link_rate &
888 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
889 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
890 phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
891 phy_pg0.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
892 phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
893 phy_pg0.hw_link_rate >> 4);
894 phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
895 phy_pg0.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
896 phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
897 phy_pg0.programmed_link_rate >> 4);
898 phy->hostdata = mr_sas_phy->hba_port;
900 if ((sas_phy_add(phy))) {
901 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
902 __FILE__, __LINE__, __func__);
906 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
908 "add: handle(0x%04x), sas_address(0x%016llx)\n"
909 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
910 mr_sas_phy->handle, (unsigned long long)
911 mr_sas_phy->identify.sas_address,
912 mr_sas_phy->attached_handle,
914 mr_sas_phy->remote_identify.sas_address);
915 mr_sas_phy->phy = phy;
920 * mpi3mr_add_expander_phy - report expander phy to transport
921 * @mrioc: Adapter instance reference
922 * @mr_sas_phy: Internal Phy object
923 * @expander_pg1: SAS Expander page 1
924 * @parent_dev: Parent device class object
926 * Return: 0 for success, non-zero for failure.
928 static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc,
929 struct mpi3mr_sas_phy *mr_sas_phy,
930 struct mpi3_sas_expander_page1 expander_pg1,
931 struct device *parent_dev)
934 int phy_index = mr_sas_phy->phy_id;
936 INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
937 phy = sas_phy_alloc(parent_dev, phy_index);
939 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
940 __FILE__, __LINE__, __func__);
943 if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
944 &mr_sas_phy->identify))) {
945 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
946 __FILE__, __LINE__, __func__);
950 phy->identify = mr_sas_phy->identify;
951 mr_sas_phy->attached_handle =
952 le16_to_cpu(expander_pg1.attached_dev_handle);
953 if (mr_sas_phy->attached_handle)
954 mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
955 &mr_sas_phy->remote_identify);
956 phy->identify.phy_identifier = mr_sas_phy->phy_id;
957 phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
958 (expander_pg1.negotiated_link_rate &
959 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
960 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
961 phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
962 expander_pg1.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
963 phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
964 expander_pg1.hw_link_rate >> 4);
965 phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
966 expander_pg1.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
967 phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
968 expander_pg1.programmed_link_rate >> 4);
969 phy->hostdata = mr_sas_phy->hba_port;
971 if ((sas_phy_add(phy))) {
972 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
973 __FILE__, __LINE__, __func__);
977 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
979 "add: handle(0x%04x), sas_address(0x%016llx)\n"
980 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
981 mr_sas_phy->handle, (unsigned long long)
982 mr_sas_phy->identify.sas_address,
983 mr_sas_phy->attached_handle,
985 mr_sas_phy->remote_identify.sas_address);
986 mr_sas_phy->phy = phy;
991 * mpi3mr_alloc_hba_port - alloc hba port object
992 * @mrioc: Adapter instance reference
993 * @port_id: Port number
995 * Alloc memory for hba port object.
997 static struct mpi3mr_hba_port *
998 mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)
1000 struct mpi3mr_hba_port *hba_port;
1002 hba_port = kzalloc(sizeof(struct mpi3mr_hba_port),
1006 hba_port->port_id = port_id;
1007 ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
1008 hba_port, hba_port->port_id);
1009 list_add_tail(&hba_port->list, &mrioc->hba_port_table_list);
1014 * mpi3mr_get_hba_port_by_id - find hba port by id
1015 * @mrioc: Adapter instance reference
1016 * @port_id - Port ID to search
1018 * Return: mpi3mr_hba_port reference for the matched port
1021 struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,
1024 struct mpi3mr_hba_port *port, *port_next;
1026 list_for_each_entry_safe(port, port_next,
1027 &mrioc->hba_port_table_list, list) {
1028 if (port->port_id != port_id)
1030 if (port->flags & MPI3MR_HBA_PORT_FLAG_DIRTY)
1039 * mpi3mr_update_links - refreshing SAS phy link changes
1040 * @mrioc: Adapter instance reference
1041 * @sas_address_parent: SAS address of parent expander or host
1042 * @handle: Firmware device handle of attached device
1043 * @phy_number: Phy number
1044 * @link_rate: New link rate
1045 * @hba_port: HBA port entry
1049 void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
1050 u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate,
1051 struct mpi3mr_hba_port *hba_port)
1053 unsigned long flags;
1054 struct mpi3mr_sas_node *mr_sas_node;
1055 struct mpi3mr_sas_phy *mr_sas_phy;
1057 if (mrioc->reset_in_progress)
1060 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1061 mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1062 sas_address_parent, hba_port);
1064 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1068 mr_sas_phy = &mr_sas_node->phy[phy_number];
1069 mr_sas_phy->attached_handle = handle;
1070 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1071 if (handle && (link_rate >= MPI3_SAS_NEG_LINK_RATE_1_5)) {
1072 mpi3mr_set_identify(mrioc, handle,
1073 &mr_sas_phy->remote_identify);
1074 mpi3mr_add_phy_to_an_existing_port(mrioc, mr_sas_node,
1075 mr_sas_phy, mr_sas_phy->remote_identify.sas_address,
1078 memset(&mr_sas_phy->remote_identify, 0, sizeof(struct
1081 if (mr_sas_phy->phy)
1082 mr_sas_phy->phy->negotiated_linkrate =
1083 mpi3mr_convert_phy_link_rate(link_rate);
1085 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1086 dev_info(&mr_sas_phy->phy->dev,
1087 "refresh: parent sas_address(0x%016llx),\n"
1088 "\tlink_rate(0x%02x), phy(%d)\n"
1089 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
1090 (unsigned long long)sas_address_parent,
1091 link_rate, phy_number, handle, (unsigned long long)
1092 mr_sas_phy->remote_identify.sas_address);
1096 * mpi3mr_sas_host_refresh - refreshing sas host object contents
1097 * @mrioc: Adapter instance reference
1099 * This function refreshes the controllers phy information and
1100 * updates the SAS transport layer with updated information,
1101 * this is executed for each device addition or device info
1106 void mpi3mr_sas_host_refresh(struct mpi3mr_ioc *mrioc)
1110 u16 sz, port_id, attached_handle;
1111 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1113 dprint_transport_info(mrioc,
1114 "updating handles for sas_host(0x%016llx)\n",
1115 (unsigned long long)mrioc->sas_hba.sas_address);
1117 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1118 (mrioc->sas_hba.num_phys *
1119 sizeof(struct mpi3_sas_io_unit0_phy_data));
1120 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1121 if (!sas_io_unit_pg0)
1123 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1124 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1125 __FILE__, __LINE__, __func__);
1129 mrioc->sas_hba.handle = 0;
1130 for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1131 if (sas_io_unit_pg0->phy_data[i].phy_flags &
1132 (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
1133 MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
1136 sas_io_unit_pg0->phy_data[i].negotiated_link_rate >> 4;
1137 if (!mrioc->sas_hba.handle)
1138 mrioc->sas_hba.handle = le16_to_cpu(
1139 sas_io_unit_pg0->phy_data[i].controller_dev_handle);
1140 port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1141 if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
1142 if (!mpi3mr_alloc_hba_port(mrioc, port_id))
1145 mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
1146 attached_handle = le16_to_cpu(
1147 sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1148 if (attached_handle && link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)
1149 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;
1150 mrioc->sas_hba.phy[i].hba_port =
1151 mpi3mr_get_hba_port_by_id(mrioc, port_id);
1152 mpi3mr_update_links(mrioc, mrioc->sas_hba.sas_address,
1153 attached_handle, i, link_rate,
1154 mrioc->sas_hba.phy[i].hba_port);
1157 kfree(sas_io_unit_pg0);
1161 * mpi3mr_sas_host_add - create sas host object
1162 * @mrioc: Adapter instance reference
1164 * This function creates the controllers phy information and
1165 * updates the SAS transport layer with updated information,
1166 * this is executed for first device addition or device info
1171 void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
1174 u16 sz, num_phys = 1, port_id, ioc_status;
1175 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1176 struct mpi3_sas_phy_page0 phy_pg0;
1177 struct mpi3_device_page0 dev_pg0;
1178 struct mpi3_enclosure_page0 encl_pg0;
1179 struct mpi3_device0_sas_sata_format *sasinf;
1181 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1182 (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
1183 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1184 if (!sas_io_unit_pg0)
1187 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1188 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1189 __FILE__, __LINE__, __func__);
1192 num_phys = sas_io_unit_pg0->num_phys;
1193 kfree(sas_io_unit_pg0);
1195 mrioc->sas_hba.host_node = 1;
1196 INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list);
1197 mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev;
1198 mrioc->sas_hba.phy = kcalloc(num_phys,
1199 sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);
1200 if (!mrioc->sas_hba.phy)
1203 mrioc->sas_hba.num_phys = num_phys;
1205 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1206 (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
1207 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1208 if (!sas_io_unit_pg0)
1211 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1212 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1213 __FILE__, __LINE__, __func__);
1217 mrioc->sas_hba.handle = 0;
1218 for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1219 if (sas_io_unit_pg0->phy_data[i].phy_flags &
1220 (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
1221 MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
1223 if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
1224 sizeof(struct mpi3_sas_phy_page0),
1225 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, i)) {
1226 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1227 __FILE__, __LINE__, __func__);
1230 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1231 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1232 __FILE__, __LINE__, __func__);
1236 if (!mrioc->sas_hba.handle)
1237 mrioc->sas_hba.handle = le16_to_cpu(
1238 sas_io_unit_pg0->phy_data[i].controller_dev_handle);
1239 port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1241 if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
1242 if (!mpi3mr_alloc_hba_port(mrioc, port_id))
1245 mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
1246 mrioc->sas_hba.phy[i].phy_id = i;
1247 mrioc->sas_hba.phy[i].hba_port =
1248 mpi3mr_get_hba_port_by_id(mrioc, port_id);
1249 mpi3mr_add_host_phy(mrioc, &mrioc->sas_hba.phy[i],
1250 phy_pg0, mrioc->sas_hba.parent_dev);
1252 if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
1253 sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
1254 mrioc->sas_hba.handle))) {
1255 ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
1258 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1259 ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
1260 mrioc->sas_hba.handle, ioc_status, __FILE__, __LINE__,
1264 mrioc->sas_hba.enclosure_handle =
1265 le16_to_cpu(dev_pg0.enclosure_handle);
1266 sasinf = &dev_pg0.device_specific.sas_sata_format;
1267 mrioc->sas_hba.sas_address =
1268 le64_to_cpu(sasinf->sas_address);
1270 "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
1271 mrioc->sas_hba.handle,
1272 (unsigned long long) mrioc->sas_hba.sas_address,
1273 mrioc->sas_hba.num_phys);
1275 if (mrioc->sas_hba.enclosure_handle) {
1276 if (!(mpi3mr_cfg_get_enclosure_pg0(mrioc, &ioc_status,
1277 &encl_pg0, sizeof(dev_pg0),
1278 MPI3_ENCLOS_PGAD_FORM_HANDLE,
1279 mrioc->sas_hba.enclosure_handle)) &&
1280 (ioc_status == MPI3_IOCSTATUS_SUCCESS))
1281 mrioc->sas_hba.enclosure_logical_id =
1282 le64_to_cpu(encl_pg0.enclosure_logical_id);
1286 kfree(sas_io_unit_pg0);
1290 * mpi3mr_sas_port_add - Expose the SAS device to the SAS TL
1291 * @mrioc: Adapter instance reference
1292 * @handle: Firmware device handle of the attached device
1293 * @sas_address_parent: sas address of parent expander or host
1294 * @hba_port: HBA port entry
1296 * This function creates a new sas port object for the given end
1297 * device matching sas address and hba_port and adds it to the
1298 * sas_node's sas_port_list and expose the attached sas device
1299 * to the SAS transport layer through sas_rphy_add.
1301 * Returns a valid mpi3mr_sas_port reference or NULL.
1303 static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
1304 u16 handle, u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
1306 struct mpi3mr_sas_phy *mr_sas_phy, *next;
1307 struct mpi3mr_sas_port *mr_sas_port;
1308 unsigned long flags;
1309 struct mpi3mr_sas_node *mr_sas_node;
1310 struct sas_rphy *rphy;
1311 struct mpi3mr_tgt_dev *tgtdev = NULL;
1313 struct sas_port *port;
1316 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1317 __FILE__, __LINE__, __func__);
1321 mr_sas_port = kzalloc(sizeof(struct mpi3mr_sas_port), GFP_KERNEL);
1325 INIT_LIST_HEAD(&mr_sas_port->port_list);
1326 INIT_LIST_HEAD(&mr_sas_port->phy_list);
1327 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1328 mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1329 sas_address_parent, hba_port);
1330 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1333 ioc_err(mrioc, "%s:could not find parent sas_address(0x%016llx)!\n",
1334 __func__, (unsigned long long)sas_address_parent);
1338 if ((mpi3mr_set_identify(mrioc, handle,
1339 &mr_sas_port->remote_identify))) {
1340 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1341 __FILE__, __LINE__, __func__);
1345 if (mr_sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
1346 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1347 __FILE__, __LINE__, __func__);
1351 mr_sas_port->hba_port = hba_port;
1352 mpi3mr_sas_port_sanity_check(mrioc, mr_sas_node,
1353 mr_sas_port->remote_identify.sas_address, hba_port);
1355 for (i = 0; i < mr_sas_node->num_phys; i++) {
1356 if ((mr_sas_node->phy[i].remote_identify.sas_address !=
1357 mr_sas_port->remote_identify.sas_address) ||
1358 (mr_sas_node->phy[i].hba_port != hba_port))
1360 list_add_tail(&mr_sas_node->phy[i].port_siblings,
1361 &mr_sas_port->phy_list);
1362 mr_sas_port->num_phys++;
1363 mr_sas_port->phy_mask |= (1 << i);
1366 if (!mr_sas_port->num_phys) {
1367 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1368 __FILE__, __LINE__, __func__);
1372 mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
1374 if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1375 tgtdev = mpi3mr_get_tgtdev_by_addr(mrioc,
1376 mr_sas_port->remote_identify.sas_address,
1377 mr_sas_port->hba_port);
1380 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1381 __FILE__, __LINE__, __func__);
1384 tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 1;
1387 if (!mr_sas_node->parent_dev) {
1388 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1389 __FILE__, __LINE__, __func__);
1393 port = sas_port_alloc_num(mr_sas_node->parent_dev);
1394 if ((sas_port_add(port))) {
1395 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1396 __FILE__, __LINE__, __func__);
1400 list_for_each_entry(mr_sas_phy, &mr_sas_port->phy_list,
1402 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1403 dev_info(&port->dev,
1404 "add: handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
1405 handle, (unsigned long long)
1406 mr_sas_port->remote_identify.sas_address,
1407 mr_sas_phy->phy_id);
1408 sas_port_add_phy(port, mr_sas_phy->phy);
1409 mr_sas_phy->phy_belongs_to_port = 1;
1410 mr_sas_phy->hba_port = hba_port;
1413 mr_sas_port->port = port;
1414 if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1415 rphy = sas_end_device_alloc(port);
1416 tgtdev->dev_spec.sas_sata_inf.rphy = rphy;
1418 rphy = sas_expander_alloc(port,
1419 mr_sas_port->remote_identify.device_type);
1421 rphy->identify = mr_sas_port->remote_identify;
1423 if (mrioc->current_event)
1424 mrioc->current_event->pending_at_sml = 1;
1426 if ((sas_rphy_add(rphy))) {
1427 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1428 __FILE__, __LINE__, __func__);
1430 if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1431 tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;
1432 tgtdev->dev_spec.sas_sata_inf.sas_transport_attached = 1;
1433 mpi3mr_tgtdev_put(tgtdev);
1436 dev_info(&rphy->dev,
1437 "%s: added: handle(0x%04x), sas_address(0x%016llx)\n",
1438 __func__, handle, (unsigned long long)
1439 mr_sas_port->remote_identify.sas_address);
1441 mr_sas_port->rphy = rphy;
1442 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1443 list_add_tail(&mr_sas_port->port_list, &mr_sas_node->sas_port_list);
1444 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1446 if (mrioc->current_event) {
1447 mrioc->current_event->pending_at_sml = 0;
1448 if (mrioc->current_event->discard)
1449 mpi3mr_print_device_event_notice(mrioc, true);
1452 /* fill in report manufacture */
1453 if (mr_sas_port->remote_identify.device_type ==
1454 SAS_EDGE_EXPANDER_DEVICE ||
1455 mr_sas_port->remote_identify.device_type ==
1456 SAS_FANOUT_EXPANDER_DEVICE)
1457 mpi3mr_report_manufacture(mrioc,
1458 mr_sas_port->remote_identify.sas_address,
1459 rphy_to_expander_device(rphy), hba_port->port_id);
1464 list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,
1466 list_del(&mr_sas_phy->port_siblings);
1472 * mpi3mr_sas_port_remove - remove port from the list
1473 * @mrioc: Adapter instance reference
1474 * @sas_address: SAS address of attached device
1475 * @sas_address_parent: SAS address of parent expander or host
1476 * @hba_port: HBA port entry
1478 * Removing object and freeing associated memory from the
1483 static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
1484 u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
1487 unsigned long flags;
1488 struct mpi3mr_sas_port *mr_sas_port, *next;
1489 struct mpi3mr_sas_node *mr_sas_node;
1491 struct mpi3mr_sas_phy *mr_sas_phy, *next_phy;
1492 struct mpi3mr_hba_port *srch_port, *hba_port_next = NULL;
1497 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1498 mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1499 sas_address_parent, hba_port);
1501 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1504 list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
1506 if (mr_sas_port->remote_identify.sas_address != sas_address)
1508 if (mr_sas_port->hba_port != hba_port)
1511 list_del(&mr_sas_port->port_list);
1517 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1521 if (mr_sas_node->host_node) {
1522 list_for_each_entry_safe(srch_port, hba_port_next,
1523 &mrioc->hba_port_table_list, list) {
1524 if (srch_port != hba_port)
1527 "removing hba_port entry: %p port: %d from hba_port list\n",
1528 srch_port, srch_port->port_id);
1529 list_del(&hba_port->list);
1535 for (i = 0; i < mr_sas_node->num_phys; i++) {
1536 if (mr_sas_node->phy[i].remote_identify.sas_address ==
1538 memset(&mr_sas_node->phy[i].remote_identify, 0,
1539 sizeof(struct sas_identify));
1542 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1544 if (mrioc->current_event)
1545 mrioc->current_event->pending_at_sml = 1;
1547 list_for_each_entry_safe(mr_sas_phy, next_phy,
1548 &mr_sas_port->phy_list, port_siblings) {
1549 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1550 dev_info(&mr_sas_port->port->dev,
1551 "remove: sas_address(0x%016llx), phy(%d)\n",
1552 (unsigned long long)
1553 mr_sas_port->remote_identify.sas_address,
1554 mr_sas_phy->phy_id);
1555 mr_sas_phy->phy_belongs_to_port = 0;
1556 if (!mrioc->stop_drv_processing)
1557 sas_port_delete_phy(mr_sas_port->port,
1559 list_del(&mr_sas_phy->port_siblings);
1561 if (!mrioc->stop_drv_processing)
1562 sas_port_delete(mr_sas_port->port);
1563 ioc_info(mrioc, "%s: removed sas_address(0x%016llx)\n",
1564 __func__, (unsigned long long)sas_address);
1566 if (mrioc->current_event) {
1567 mrioc->current_event->pending_at_sml = 0;
1568 if (mrioc->current_event->discard)
1569 mpi3mr_print_device_event_notice(mrioc, false);
1576 * struct host_port - host port details
1577 * @sas_address: SAS Address of the attached device
1578 * @phy_mask: phy mask of host port
1579 * @handle: Device Handle of attached device
1580 * @iounit_port_id: port ID
1581 * @used: host port is already matched with sas port from sas_port_list
1582 * @lowest_phy: lowest phy ID of host port
1594 * mpi3mr_update_mr_sas_port - update sas port objects during reset
1595 * @mrioc: Adapter instance reference
1596 * @h_port: host_port object
1597 * @mr_sas_port: sas_port objects which needs to be updated
1599 * Update the port ID of sas port object. Also add the phys if new phys got
1600 * added to current sas port and remove the phys if some phys are moved
1601 * out of the current sas port.
1606 mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port,
1607 struct mpi3mr_sas_port *mr_sas_port)
1609 struct mpi3mr_sas_phy *mr_sas_phy;
1611 u64 phys_to_be_added, phys_to_be_removed;
1615 mr_sas_port->marked_responding = 1;
1617 dev_info(&mr_sas_port->port->dev,
1618 "sas_address(0x%016llx), old: port_id %d phy_mask 0x%x, new: port_id %d phy_mask:0x%x\n",
1619 mr_sas_port->remote_identify.sas_address,
1620 mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask,
1621 h_port->iounit_port_id, h_port->phy_mask);
1623 mr_sas_port->hba_port->port_id = h_port->iounit_port_id;
1624 mr_sas_port->hba_port->flags &= ~MPI3MR_HBA_PORT_FLAG_DIRTY;
1626 /* Get the newly added phys bit map & removed phys bit map */
1627 phy_mask_xor = mr_sas_port->phy_mask ^ h_port->phy_mask;
1628 phys_to_be_added = h_port->phy_mask & phy_mask_xor;
1629 phys_to_be_removed = mr_sas_port->phy_mask & phy_mask_xor;
1632 * Register these new phys to current mr_sas_port's port.
1633 * if these phys are previously registered with another port
1634 * then delete these phys from that port first.
1636 for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u32)) {
1637 mr_sas_phy = &mrioc->sas_hba.phy[i];
1638 if (mr_sas_phy->phy_belongs_to_port)
1639 mpi3mr_del_phy_from_an_existing_port(mrioc,
1640 &mrioc->sas_hba, mr_sas_phy);
1641 mpi3mr_add_phy_to_an_existing_port(mrioc,
1642 &mrioc->sas_hba, mr_sas_phy,
1643 mr_sas_port->remote_identify.sas_address,
1644 mr_sas_port->hba_port);
1647 /* Delete the phys which are not part of current mr_sas_port's port. */
1648 for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u32)) {
1649 mr_sas_phy = &mrioc->sas_hba.phy[i];
1650 if (mr_sas_phy->phy_belongs_to_port)
1651 mpi3mr_del_phy_from_an_existing_port(mrioc,
1652 &mrioc->sas_hba, mr_sas_phy);
1657 * mpi3mr_refresh_sas_ports - update host's sas ports during reset
1658 * @mrioc: Adapter instance reference
1660 * Update the host's sas ports during reset by checking whether
1661 * sas ports are still intact or not. Add/remove phys if any hba
1662 * phys are (moved in)/(moved out) of sas port. Also update
1663 * io_unit_port if it got changed during reset.
1668 mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
1670 struct host_port h_port[32];
1671 int i, j, found, host_port_count = 0, port_idx;
1672 u16 sz, attached_handle, ioc_status;
1673 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1674 struct mpi3_device_page0 dev_pg0;
1675 struct mpi3_device0_sas_sata_format *sasinf;
1676 struct mpi3mr_sas_port *mr_sas_port;
1678 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1679 (mrioc->sas_hba.num_phys *
1680 sizeof(struct mpi3_sas_io_unit0_phy_data));
1681 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1682 if (!sas_io_unit_pg0)
1684 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1685 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1686 __FILE__, __LINE__, __func__);
1690 /* Create a new expander port table */
1691 for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1692 attached_handle = le16_to_cpu(
1693 sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1694 if (!attached_handle)
1697 for (j = 0; j < host_port_count; j++) {
1698 if (h_port[j].handle == attached_handle) {
1699 h_port[j].phy_mask |= (1 << i);
1706 if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
1707 sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
1708 attached_handle))) {
1710 "failed to read dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1711 attached_handle, __FILE__, __LINE__, __func__);
1714 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1716 "ioc_status(0x%x) while reading dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1717 ioc_status, attached_handle,
1718 __FILE__, __LINE__, __func__);
1721 sasinf = &dev_pg0.device_specific.sas_sata_format;
1723 port_idx = host_port_count;
1724 h_port[port_idx].sas_address = le64_to_cpu(sasinf->sas_address);
1725 h_port[port_idx].handle = attached_handle;
1726 h_port[port_idx].phy_mask = (1 << i);
1727 h_port[port_idx].iounit_port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1728 h_port[port_idx].lowest_phy = sasinf->phy_num;
1729 h_port[port_idx].used = 0;
1733 if (!host_port_count)
1736 if (mrioc->logging_level & MPI3_DEBUG_RESET) {
1737 ioc_info(mrioc, "Host port details before reset\n");
1738 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1741 "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n",
1742 mr_sas_port->hba_port->port_id,
1743 mr_sas_port->remote_identify.sas_address,
1744 mr_sas_port->phy_mask, mr_sas_port->lowest_phy);
1747 ioc_info(mrioc, "Host port details after reset\n");
1748 for (i = 0; i < host_port_count; i++) {
1750 "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n",
1751 h_port[i].iounit_port_id, h_port[i].sas_address,
1752 h_port[i].phy_mask, h_port[i].lowest_phy);
1756 /* mark all host sas port entries as dirty */
1757 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1759 mr_sas_port->marked_responding = 0;
1760 mr_sas_port->hba_port->flags |= MPI3MR_HBA_PORT_FLAG_DIRTY;
1763 /* First check for matching lowest phy */
1764 for (i = 0; i < host_port_count; i++) {
1766 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1768 if (mr_sas_port->marked_responding)
1770 if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1772 if (h_port[i].lowest_phy == mr_sas_port->lowest_phy) {
1773 mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1779 /* In case if lowest phy is got enabled or disabled during reset */
1780 for (i = 0; i < host_port_count; i++) {
1784 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1786 if (mr_sas_port->marked_responding)
1788 if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1790 if (h_port[i].phy_mask & mr_sas_port->phy_mask) {
1791 mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1797 /* In case if expander cable is removed & connected to another HBA port during reset */
1798 for (i = 0; i < host_port_count; i++) {
1802 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1804 if (mr_sas_port->marked_responding)
1806 if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1808 mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1813 kfree(sas_io_unit_pg0);
1817 * mpi3mr_refresh_expanders - Refresh expander device exposure
1818 * @mrioc: Adapter instance reference
1820 * This is executed post controller reset to identify any
1821 * missing expander devices during reset and remove from the upper layers
1822 * or expose any newly detected expander device to the upper layers.
1827 mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc)
1829 struct mpi3mr_sas_node *sas_expander, *sas_expander_next;
1830 struct mpi3_sas_expander_page0 expander_pg0;
1831 u16 ioc_status, handle;
1834 unsigned long flags;
1835 struct mpi3mr_hba_port *hba_port;
1837 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1838 list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
1839 sas_expander->non_responding = 1;
1841 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1843 sas_expander = NULL;
1847 /* Search for responding expander devices and add them if they are newly got added */
1849 if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
1850 sizeof(struct mpi3_sas_expander_page0),
1851 MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
1853 "failed to read exp pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1854 handle, __FILE__, __LINE__, __func__);
1858 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1860 "ioc_status(0x%x) while reading exp pg0 for handle:(0x%04x), %s:%d/%s()!\n",
1861 ioc_status, handle, __FILE__, __LINE__, __func__);
1865 handle = le16_to_cpu(expander_pg0.dev_handle);
1866 sas_address = le64_to_cpu(expander_pg0.sas_address);
1867 hba_port = mpi3mr_get_hba_port_by_id(mrioc, expander_pg0.io_unit_port);
1870 mpi3mr_sas_host_refresh(mrioc);
1871 mpi3mr_expander_add(mrioc, handle);
1875 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1877 mpi3mr_expander_find_by_sas_address(mrioc,
1878 sas_address, hba_port);
1879 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1881 if (!sas_expander) {
1882 mpi3mr_sas_host_refresh(mrioc);
1883 mpi3mr_expander_add(mrioc, handle);
1887 sas_expander->non_responding = 0;
1888 if (sas_expander->handle == handle)
1891 sas_expander->handle = handle;
1892 for (i = 0 ; i < sas_expander->num_phys ; i++)
1893 sas_expander->phy[i].handle = handle;
1897 * Delete non responding expander devices and the corresponding
1898 * hba_port if the non responding expander device's parent device
1901 sas_expander = NULL;
1902 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1903 list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
1904 &mrioc->sas_expander_list, list) {
1905 if (sas_expander->non_responding) {
1906 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1907 mpi3mr_expander_node_remove(mrioc, sas_expander);
1908 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1911 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1915 * mpi3mr_expander_node_add - insert an expander to the list.
1916 * @mrioc: Adapter instance reference
1917 * @sas_expander: Expander sas node
1918 * Context: This function will acquire sas_node_lock.
1920 * Adding new object to the ioc->sas_expander_list.
1924 static void mpi3mr_expander_node_add(struct mpi3mr_ioc *mrioc,
1925 struct mpi3mr_sas_node *sas_expander)
1927 unsigned long flags;
1929 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1930 list_add_tail(&sas_expander->list, &mrioc->sas_expander_list);
1931 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1935 * mpi3mr_expander_add - Create expander object
1936 * @mrioc: Adapter instance reference
1937 * @handle: Expander firmware device handle
1939 * This function creating expander object, stored in
1940 * sas_expander_list and expose it to the SAS transport
1943 * Return: 0 for success, non-zero for failure.
1945 int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)
1947 struct mpi3mr_sas_node *sas_expander;
1948 struct mpi3mr_enclosure_node *enclosure_dev;
1949 struct mpi3_sas_expander_page0 expander_pg0;
1950 struct mpi3_sas_expander_page1 expander_pg1;
1951 u16 ioc_status, parent_handle, temp_handle;
1952 u64 sas_address, sas_address_parent = 0;
1954 unsigned long flags;
1955 u8 port_id, link_rate;
1956 struct mpi3mr_sas_port *mr_sas_port = NULL;
1957 struct mpi3mr_hba_port *hba_port;
1964 if (mrioc->reset_in_progress)
1967 if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
1968 sizeof(expander_pg0), MPI3_SAS_EXPAND_PGAD_FORM_HANDLE, handle))) {
1969 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1970 __FILE__, __LINE__, __func__);
1974 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1975 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1976 __FILE__, __LINE__, __func__);
1980 parent_handle = le16_to_cpu(expander_pg0.parent_dev_handle);
1981 if (mpi3mr_get_sas_address(mrioc, parent_handle, &sas_address_parent)
1983 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1984 __FILE__, __LINE__, __func__);
1988 port_id = expander_pg0.io_unit_port;
1989 hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
1991 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1992 __FILE__, __LINE__, __func__);
1996 if (sas_address_parent != mrioc->sas_hba.sas_address) {
1997 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1999 mpi3mr_expander_find_by_sas_address(mrioc,
2000 sas_address_parent, hba_port);
2001 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2002 if (!sas_expander) {
2003 rc = mpi3mr_expander_add(mrioc, parent_handle);
2008 * When there is a parent expander present, update it's
2009 * phys where child expander is connected with the link
2010 * speed, attached dev handle and sas address.
2012 for (i = 0 ; i < sas_expander->num_phys ; i++) {
2014 (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2016 if (mpi3mr_cfg_get_sas_exp_pg1(mrioc,
2017 &ioc_status, &expander_pg1,
2018 sizeof(expander_pg1),
2019 MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2021 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2022 __FILE__, __LINE__, __func__);
2026 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2027 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2028 __FILE__, __LINE__, __func__);
2032 temp_handle = le16_to_cpu(
2033 expander_pg1.attached_dev_handle);
2034 if (temp_handle != handle)
2036 link_rate = (expander_pg1.negotiated_link_rate &
2037 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2038 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2039 mpi3mr_update_links(mrioc, sas_address_parent,
2040 handle, i, link_rate, hba_port);
2045 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2046 sas_address = le64_to_cpu(expander_pg0.sas_address);
2047 sas_expander = mpi3mr_expander_find_by_sas_address(mrioc,
2048 sas_address, hba_port);
2049 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2054 sas_expander = kzalloc(sizeof(struct mpi3mr_sas_node),
2059 sas_expander->handle = handle;
2060 sas_expander->num_phys = expander_pg0.num_phys;
2061 sas_expander->sas_address_parent = sas_address_parent;
2062 sas_expander->sas_address = sas_address;
2063 sas_expander->hba_port = hba_port;
2066 "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
2067 handle, parent_handle, (unsigned long long)
2068 sas_expander->sas_address, sas_expander->num_phys);
2070 if (!sas_expander->num_phys) {
2074 sas_expander->phy = kcalloc(sas_expander->num_phys,
2075 sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);
2076 if (!sas_expander->phy) {
2081 INIT_LIST_HEAD(&sas_expander->sas_port_list);
2082 mr_sas_port = mpi3mr_sas_port_add(mrioc, handle, sas_address_parent,
2083 sas_expander->hba_port);
2085 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2086 __FILE__, __LINE__, __func__);
2090 sas_expander->parent_dev = &mr_sas_port->rphy->dev;
2091 sas_expander->rphy = mr_sas_port->rphy;
2093 for (i = 0 ; i < sas_expander->num_phys ; i++) {
2094 phynum_handle = (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2096 if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2097 &expander_pg1, sizeof(expander_pg1),
2098 MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2100 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2101 __FILE__, __LINE__, __func__);
2105 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2106 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2107 __FILE__, __LINE__, __func__);
2112 sas_expander->phy[i].handle = handle;
2113 sas_expander->phy[i].phy_id = i;
2114 sas_expander->phy[i].hba_port = hba_port;
2116 if ((mpi3mr_add_expander_phy(mrioc, &sas_expander->phy[i],
2117 expander_pg1, sas_expander->parent_dev))) {
2118 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2119 __FILE__, __LINE__, __func__);
2125 if (sas_expander->enclosure_handle) {
2127 mpi3mr_enclosure_find_by_handle(mrioc,
2128 sas_expander->enclosure_handle);
2130 sas_expander->enclosure_logical_id = le64_to_cpu(
2131 enclosure_dev->pg0.enclosure_logical_id);
2134 mpi3mr_expander_node_add(mrioc, sas_expander);
2140 mpi3mr_sas_port_remove(mrioc,
2141 sas_expander->sas_address,
2142 sas_address_parent, sas_expander->hba_port);
2143 kfree(sas_expander->phy);
2144 kfree(sas_expander);
2149 * mpi3mr_expander_node_remove - recursive removal of expander.
2150 * @mrioc: Adapter instance reference
2151 * @sas_expander: Expander device object
2153 * Removes expander object and freeing associated memory from
2154 * the sas_expander_list and removes the same from SAS TL, if
2155 * one of the attached device is an expander then it recursively
2156 * removes the expander device too.
2160 static void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
2161 struct mpi3mr_sas_node *sas_expander)
2163 struct mpi3mr_sas_port *mr_sas_port, *next;
2164 unsigned long flags;
2167 /* remove sibling ports attached to this expander */
2168 list_for_each_entry_safe(mr_sas_port, next,
2169 &sas_expander->sas_port_list, port_list) {
2170 if (mrioc->reset_in_progress)
2172 if (mr_sas_port->remote_identify.device_type ==
2174 mpi3mr_remove_device_by_sas_address(mrioc,
2175 mr_sas_port->remote_identify.sas_address,
2176 mr_sas_port->hba_port);
2177 else if (mr_sas_port->remote_identify.device_type ==
2178 SAS_EDGE_EXPANDER_DEVICE ||
2179 mr_sas_port->remote_identify.device_type ==
2180 SAS_FANOUT_EXPANDER_DEVICE)
2181 mpi3mr_expander_remove(mrioc,
2182 mr_sas_port->remote_identify.sas_address,
2183 mr_sas_port->hba_port);
2186 port_id = sas_expander->hba_port->port_id;
2187 mpi3mr_sas_port_remove(mrioc, sas_expander->sas_address,
2188 sas_expander->sas_address_parent, sas_expander->hba_port);
2190 ioc_info(mrioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n",
2191 sas_expander->handle, (unsigned long long)
2192 sas_expander->sas_address, port_id);
2194 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2195 list_del(&sas_expander->list);
2196 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2198 kfree(sas_expander->phy);
2199 kfree(sas_expander);
2203 * mpi3mr_expander_remove - Remove expander object
2204 * @mrioc: Adapter instance reference
2205 * @sas_address: Remove expander sas_address
2206 * @hba_port: HBA port reference
2208 * This function remove expander object, stored in
2209 * mrioc->sas_expander_list and removes it from the SAS TL by
2210 * calling mpi3mr_expander_node_remove().
2214 void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
2215 struct mpi3mr_hba_port *hba_port)
2217 struct mpi3mr_sas_node *sas_expander;
2218 unsigned long flags;
2220 if (mrioc->reset_in_progress)
2226 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2227 sas_expander = mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
2229 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2231 mpi3mr_expander_node_remove(mrioc, sas_expander);
2236 * mpi3mr_get_sas_negotiated_logical_linkrate - get linkrate
2237 * @mrioc: Adapter instance reference
2238 * @tgtdev: Target device
2240 * This function identifies whether the target device is
2241 * attached directly or through expander and issues sas phy
2242 * page0 or expander phy page1 and gets the link rate, if there
2243 * is any failure in reading the pages then this returns link
2246 * Return: logical link rate.
2248 static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc,
2249 struct mpi3mr_tgt_dev *tgtdev)
2251 u8 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5, phy_number;
2252 struct mpi3_sas_expander_page1 expander_pg1;
2253 struct mpi3_sas_phy_page0 phy_pg0;
2257 phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2258 if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) {
2259 phynum_handle = ((phy_number<<MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT)
2260 | tgtdev->parent_handle);
2261 if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2262 &expander_pg1, sizeof(expander_pg1),
2263 MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2265 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2266 __FILE__, __LINE__, __func__);
2269 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2270 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2271 __FILE__, __LINE__, __func__);
2274 link_rate = (expander_pg1.negotiated_link_rate &
2275 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2276 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2279 if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
2280 sizeof(struct mpi3_sas_phy_page0),
2281 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy_number)) {
2282 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2283 __FILE__, __LINE__, __func__);
2286 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2287 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2288 __FILE__, __LINE__, __func__);
2291 link_rate = (phy_pg0.negotiated_link_rate &
2292 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2293 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2299 * mpi3mr_report_tgtdev_to_sas_transport - expose dev to SAS TL
2300 * @mrioc: Adapter instance reference
2301 * @tgtdev: Target device
2303 * This function exposes the target device after
2304 * preparing host_phy, setting up link rate etc.
2306 * Return: 0 on success, non-zero for failure.
2308 int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc,
2309 struct mpi3mr_tgt_dev *tgtdev)
2312 u8 link_rate, parent_phy_number;
2313 u64 sas_address_parent, sas_address;
2314 struct mpi3mr_hba_port *hba_port;
2317 if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2318 !mrioc->sas_transport_enabled)
2321 sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2322 if (!mrioc->sas_hba.num_phys)
2323 mpi3mr_sas_host_add(mrioc);
2325 mpi3mr_sas_host_refresh(mrioc);
2327 if (mpi3mr_get_sas_address(mrioc, tgtdev->parent_handle,
2328 &sas_address_parent) != 0) {
2329 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2330 __FILE__, __LINE__, __func__);
2333 tgtdev->dev_spec.sas_sata_inf.sas_address_parent = sas_address_parent;
2335 parent_phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2336 port_id = tgtdev->io_unit_port;
2338 hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
2340 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2341 __FILE__, __LINE__, __func__);
2344 tgtdev->dev_spec.sas_sata_inf.hba_port = hba_port;
2346 link_rate = mpi3mr_get_sas_negotiated_logical_linkrate(mrioc, tgtdev);
2348 mpi3mr_update_links(mrioc, sas_address_parent, tgtdev->dev_handle,
2349 parent_phy_number, link_rate, hba_port);
2351 tgtdev->host_exposed = 1;
2352 if (!mpi3mr_sas_port_add(mrioc, tgtdev->dev_handle,
2353 sas_address_parent, hba_port)) {
2354 tgtdev->host_exposed = 0;
2356 } else if ((!tgtdev->starget)) {
2357 if (!mrioc->is_driver_loading)
2358 mpi3mr_sas_port_remove(mrioc, sas_address,
2359 sas_address_parent, hba_port);
2360 tgtdev->host_exposed = 0;
2367 * mpi3mr_remove_tgtdev_from_sas_transport - remove from SAS TL
2368 * @mrioc: Adapter instance reference
2369 * @tgtdev: Target device
2371 * This function removes the target device
2375 void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
2376 struct mpi3mr_tgt_dev *tgtdev)
2378 u64 sas_address_parent, sas_address;
2379 struct mpi3mr_hba_port *hba_port;
2381 if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2382 !mrioc->sas_transport_enabled)
2385 hba_port = tgtdev->dev_spec.sas_sata_inf.hba_port;
2386 sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2387 sas_address_parent = tgtdev->dev_spec.sas_sata_inf.sas_address_parent;
2388 mpi3mr_sas_port_remove(mrioc, sas_address, sas_address_parent,
2390 tgtdev->host_exposed = 0;
2394 * mpi3mr_get_port_id_by_sas_phy - Get port ID of the given phy
2395 * @phy: SAS transport layer phy object
2397 * Return: Port number for valid ID else 0xFFFF
2399 static inline u8 mpi3mr_get_port_id_by_sas_phy(struct sas_phy *phy)
2402 struct mpi3mr_hba_port *hba_port = phy->hostdata;
2405 port_id = hba_port->port_id;
2411 * mpi3mr_get_port_id_by_rphy - Get Port number from SAS rphy
2413 * @mrioc: Adapter instance reference
2414 * @rphy: SAS transport layer remote phy object
2416 * Retrieves HBA port number in which the device pointed by the
2417 * rphy object is attached with.
2419 * Return: Valid port number on success else OxFFFF.
2421 static u8 mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc *mrioc, struct sas_rphy *rphy)
2423 struct mpi3mr_sas_node *sas_expander;
2424 struct mpi3mr_tgt_dev *tgtdev;
2425 unsigned long flags;
2431 if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
2432 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {
2433 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2434 list_for_each_entry(sas_expander, &mrioc->sas_expander_list,
2436 if (sas_expander->rphy == rphy) {
2437 port_id = sas_expander->hba_port->port_id;
2441 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2442 } else if (rphy->identify.device_type == SAS_END_DEVICE) {
2443 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2445 tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2446 rphy->identify.sas_address, rphy);
2449 tgtdev->dev_spec.sas_sata_inf.hba_port->port_id;
2450 mpi3mr_tgtdev_put(tgtdev);
2452 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2457 static inline struct mpi3mr_ioc *phy_to_mrioc(struct sas_phy *phy)
2459 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
2461 return shost_priv(shost);
2464 static inline struct mpi3mr_ioc *rphy_to_mrioc(struct sas_rphy *rphy)
2466 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
2468 return shost_priv(shost);
2471 /* report phy error log structure */
2472 struct phy_error_log_request {
2473 u8 smp_frame_type; /* 0x40 */
2474 u8 function; /* 0x11 */
2475 u8 allocated_response_length;
2476 u8 request_length; /* 02 */
2482 /* report phy error log reply structure */
2483 struct phy_error_log_reply {
2484 u8 smp_frame_type; /* 0x41 */
2485 u8 function; /* 0x11 */
2488 __be16 expander_change_count;
2492 __be32 invalid_dword;
2493 __be32 running_disparity_error;
2494 __be32 loss_of_dword_sync;
2495 __be32 phy_reset_problem;
2500 * mpi3mr_get_expander_phy_error_log - return expander counters:
2501 * @mrioc: Adapter instance reference
2502 * @phy: The SAS transport layer phy object
2504 * Return: 0 for success, non-zero for failure.
2507 static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
2508 struct sas_phy *phy)
2510 struct mpi3_smp_passthrough_request mpi_request;
2511 struct mpi3_smp_passthrough_reply mpi_reply;
2512 struct phy_error_log_request *phy_error_log_request;
2513 struct phy_error_log_reply *phy_error_log_reply;
2516 void *data_out = NULL;
2517 dma_addr_t data_out_dma, data_in_dma;
2518 u32 data_out_sz, data_in_sz, sz;
2519 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2520 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2521 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2524 if (mrioc->reset_in_progress) {
2525 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2529 data_out_sz = sizeof(struct phy_error_log_request);
2530 data_in_sz = sizeof(struct phy_error_log_reply);
2531 sz = data_out_sz + data_in_sz;
2532 data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2539 data_in_dma = data_out_dma + data_out_sz;
2540 phy_error_log_reply = data_out + data_out_sz;
2543 memset(data_out, 0, sz);
2544 phy_error_log_request = data_out;
2545 phy_error_log_request->smp_frame_type = 0x40;
2546 phy_error_log_request->function = 0x11;
2547 phy_error_log_request->request_length = 2;
2548 phy_error_log_request->allocated_response_length = 0;
2549 phy_error_log_request->phy_identifier = phy->number;
2551 memset(&mpi_request, 0, request_sz);
2552 memset(&mpi_reply, 0, reply_sz);
2553 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2554 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2555 mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2556 mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2558 psge = &mpi_request.request_sge;
2559 mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2561 psge = &mpi_request.response_sge;
2562 mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2564 dprint_transport_info(mrioc,
2565 "sending phy error log SMP request to sas_address(0x%016llx), phy_id(%d)\n",
2566 (unsigned long long)phy->identify.sas_address, phy->number);
2568 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2569 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2572 dprint_transport_info(mrioc,
2573 "phy error log SMP request completed with ioc_status(0x%04x)\n",
2576 if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2577 dprint_transport_info(mrioc,
2578 "phy error log - reply data transfer size(%d)\n",
2579 le16_to_cpu(mpi_reply.response_data_length));
2581 if (le16_to_cpu(mpi_reply.response_data_length) !=
2582 sizeof(struct phy_error_log_reply))
2585 dprint_transport_info(mrioc,
2586 "phy error log - function_result(%d)\n",
2587 phy_error_log_reply->function_result);
2589 phy->invalid_dword_count =
2590 be32_to_cpu(phy_error_log_reply->invalid_dword);
2591 phy->running_disparity_error_count =
2592 be32_to_cpu(phy_error_log_reply->running_disparity_error);
2593 phy->loss_of_dword_sync_count =
2594 be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
2595 phy->phy_reset_problem_count =
2596 be32_to_cpu(phy_error_log_reply->phy_reset_problem);
2602 dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2609 * mpi3mr_transport_get_linkerrors - return phy error counters
2610 * @phy: The SAS transport layer phy object
2612 * This function retrieves the phy error log information of the
2613 * HBA or expander for which the phy belongs to
2615 * Return: 0 for success, non-zero for failure.
2617 static int mpi3mr_transport_get_linkerrors(struct sas_phy *phy)
2619 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2620 struct mpi3_sas_phy_page1 phy_pg1;
2624 rc = mpi3mr_parent_present(mrioc, phy);
2628 if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2629 return mpi3mr_get_expander_phy_error_log(mrioc, phy);
2631 memset(&phy_pg1, 0, sizeof(struct mpi3_sas_phy_page1));
2632 /* get hba phy error logs */
2633 if ((mpi3mr_cfg_get_sas_phy_pg1(mrioc, &ioc_status, &phy_pg1,
2634 sizeof(struct mpi3_sas_phy_page1),
2635 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number))) {
2636 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2637 __FILE__, __LINE__, __func__);
2641 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2642 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2643 __FILE__, __LINE__, __func__);
2646 phy->invalid_dword_count = le32_to_cpu(phy_pg1.invalid_dword_count);
2647 phy->running_disparity_error_count =
2648 le32_to_cpu(phy_pg1.running_disparity_error_count);
2649 phy->loss_of_dword_sync_count =
2650 le32_to_cpu(phy_pg1.loss_dword_synch_count);
2651 phy->phy_reset_problem_count =
2652 le32_to_cpu(phy_pg1.phy_reset_problem_count);
2657 * mpi3mr_transport_get_enclosure_identifier - Get Enclosure ID
2658 * @rphy: The SAS transport layer remote phy object
2659 * @identifier: Enclosure identifier to be returned
2661 * Returns the enclosure id for the device pointed by the remote
2664 * Return: 0 on success or -ENXIO
2667 mpi3mr_transport_get_enclosure_identifier(struct sas_rphy *rphy,
2670 struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2671 struct mpi3mr_tgt_dev *tgtdev = NULL;
2672 unsigned long flags;
2675 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2676 tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2677 rphy->identify.sas_address, rphy);
2680 tgtdev->enclosure_logical_id;
2682 mpi3mr_tgtdev_put(tgtdev);
2687 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2693 * mpi3mr_transport_get_bay_identifier - Get bay ID
2694 * @rphy: The SAS transport layer remote phy object
2696 * Returns the slot id for the device pointed by the remote phy
2699 * Return: Valid slot ID on success or -ENXIO
2702 mpi3mr_transport_get_bay_identifier(struct sas_rphy *rphy)
2704 struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2705 struct mpi3mr_tgt_dev *tgtdev = NULL;
2706 unsigned long flags;
2709 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2710 tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2711 rphy->identify.sas_address, rphy);
2714 mpi3mr_tgtdev_put(tgtdev);
2717 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2722 /* phy control request structure */
2723 struct phy_control_request {
2724 u8 smp_frame_type; /* 0x40 */
2725 u8 function; /* 0x91 */
2726 u8 allocated_response_length;
2727 u8 request_length; /* 0x09 */
2728 u16 expander_change_count;
2733 u64 attached_device_name;
2734 u8 programmed_min_physical_link_rate;
2735 u8 programmed_max_physical_link_rate;
2739 /* phy control reply structure */
2740 struct phy_control_reply {
2741 u8 smp_frame_type; /* 0x41 */
2742 u8 function; /* 0x11 */
2747 #define SMP_PHY_CONTROL_LINK_RESET (0x01)
2748 #define SMP_PHY_CONTROL_HARD_RESET (0x02)
2749 #define SMP_PHY_CONTROL_DISABLE (0x03)
2752 * mpi3mr_expander_phy_control - expander phy control
2753 * @mrioc: Adapter instance reference
2754 * @phy: The SAS transport layer phy object
2755 * @phy_operation: The phy operation to be executed
2757 * Issues SMP passthru phy control request to execute a specific
2758 * phy operation for a given expander device.
2760 * Return: 0 for success, non-zero for failure.
2763 mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
2764 struct sas_phy *phy, u8 phy_operation)
2766 struct mpi3_smp_passthrough_request mpi_request;
2767 struct mpi3_smp_passthrough_reply mpi_reply;
2768 struct phy_control_request *phy_control_request;
2769 struct phy_control_reply *phy_control_reply;
2772 void *data_out = NULL;
2773 dma_addr_t data_out_dma;
2774 dma_addr_t data_in_dma;
2777 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2778 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2779 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2783 if (mrioc->reset_in_progress) {
2784 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2788 data_out_sz = sizeof(struct phy_control_request);
2789 data_in_sz = sizeof(struct phy_control_reply);
2790 sz = data_out_sz + data_in_sz;
2791 data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2798 data_in_dma = data_out_dma + data_out_sz;
2799 phy_control_reply = data_out + data_out_sz;
2802 memset(data_out, 0, sz);
2804 phy_control_request = data_out;
2805 phy_control_request->smp_frame_type = 0x40;
2806 phy_control_request->function = 0x91;
2807 phy_control_request->request_length = 9;
2808 phy_control_request->allocated_response_length = 0;
2809 phy_control_request->phy_identifier = phy->number;
2810 phy_control_request->phy_operation = phy_operation;
2811 phy_control_request->programmed_min_physical_link_rate =
2812 phy->minimum_linkrate << 4;
2813 phy_control_request->programmed_max_physical_link_rate =
2814 phy->maximum_linkrate << 4;
2816 memset(&mpi_request, 0, request_sz);
2817 memset(&mpi_reply, 0, reply_sz);
2818 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2819 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2820 mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2821 mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2823 psge = &mpi_request.request_sge;
2824 mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2826 psge = &mpi_request.response_sge;
2827 mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2829 dprint_transport_info(mrioc,
2830 "sending phy control SMP request to sas_address(0x%016llx), phy_id(%d) opcode(%d)\n",
2831 (unsigned long long)phy->identify.sas_address, phy->number,
2834 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2835 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2838 dprint_transport_info(mrioc,
2839 "phy control SMP request completed with ioc_status(0x%04x)\n",
2842 if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2843 dprint_transport_info(mrioc,
2844 "phy control - reply data transfer size(%d)\n",
2845 le16_to_cpu(mpi_reply.response_data_length));
2847 if (le16_to_cpu(mpi_reply.response_data_length) !=
2848 sizeof(struct phy_control_reply))
2850 dprint_transport_info(mrioc,
2851 "phy control - function_result(%d)\n",
2852 phy_control_reply->function_result);
2857 dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2864 * mpi3mr_transport_phy_reset - Reset a given phy
2865 * @phy: The SAS transport layer phy object
2866 * @hard_reset: Flag to indicate the type of reset
2868 * Return: 0 for success, non-zero for failure.
2871 mpi3mr_transport_phy_reset(struct sas_phy *phy, int hard_reset)
2873 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2874 struct mpi3_iounit_control_request mpi_request;
2875 struct mpi3_iounit_control_reply mpi_reply;
2876 u16 request_sz = sizeof(struct mpi3_iounit_control_request);
2877 u16 reply_sz = sizeof(struct mpi3_iounit_control_reply);
2881 rc = mpi3mr_parent_present(mrioc, phy);
2885 /* handle expander phys */
2886 if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2887 return mpi3mr_expander_phy_control(mrioc, phy,
2888 (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
2889 SMP_PHY_CONTROL_LINK_RESET);
2891 /* handle hba phys */
2892 memset(&mpi_request, 0, request_sz);
2893 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2894 mpi_request.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
2895 mpi_request.operation = MPI3_CTRL_OP_SAS_PHY_CONTROL;
2896 mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX] =
2897 (hard_reset ? MPI3_CTRL_ACTION_HARD_RESET :
2898 MPI3_CTRL_ACTION_LINK_RESET);
2899 mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX] =
2902 dprint_transport_info(mrioc,
2903 "sending phy reset request to sas_address(0x%016llx), phy_id(%d) hard_reset(%d)\n",
2904 (unsigned long long)phy->identify.sas_address, phy->number,
2907 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2908 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status)) {
2913 dprint_transport_info(mrioc,
2914 "phy reset request completed with ioc_status(0x%04x)\n",
2921 * mpi3mr_transport_phy_enable - enable/disable phys
2922 * @phy: The SAS transport layer phy object
2923 * @enable: flag to enable/disable, enable phy when true
2925 * This function enables/disables a given by executing required
2926 * configuration page changes or expander phy control command
2928 * Return: 0 for success, non-zero for failure.
2931 mpi3mr_transport_phy_enable(struct sas_phy *phy, int enable)
2933 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2934 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
2935 struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
2938 int i, discovery_active;
2940 rc = mpi3mr_parent_present(mrioc, phy);
2944 /* handle expander phys */
2945 if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2946 return mpi3mr_expander_phy_control(mrioc, phy,
2947 (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
2948 SMP_PHY_CONTROL_DISABLE);
2950 /* handle hba phys */
2951 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
2952 (mrioc->sas_hba.num_phys *
2953 sizeof(struct mpi3_sas_io_unit0_phy_data));
2954 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
2955 if (!sas_io_unit_pg0) {
2959 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
2960 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2961 __FILE__, __LINE__, __func__);
2966 /* unable to enable/disable phys when discovery is active */
2967 for (i = 0, discovery_active = 0; i < mrioc->sas_hba.num_phys ; i++) {
2968 if (sas_io_unit_pg0->phy_data[i].port_flags &
2969 MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS) {
2971 "discovery is active on port = %d, phy = %d\n"
2972 "\tunable to enable/disable phys, try again later!\n",
2973 sas_io_unit_pg0->phy_data[i].io_unit_port, i);
2974 discovery_active = 1;
2978 if (discovery_active) {
2983 if ((sas_io_unit_pg0->phy_data[phy->number].phy_flags &
2984 (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
2985 MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))) {
2986 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2987 __FILE__, __LINE__, __func__);
2992 /* read sas_iounit page 1 */
2993 sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
2994 (mrioc->sas_hba.num_phys *
2995 sizeof(struct mpi3_sas_io_unit1_phy_data));
2996 sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
2997 if (!sas_io_unit_pg1) {
3002 if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3003 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3004 __FILE__, __LINE__, __func__);
3010 sas_io_unit_pg1->phy_data[phy->number].phy_flags
3011 &= ~MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3013 sas_io_unit_pg1->phy_data[phy->number].phy_flags
3014 |= MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3016 mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz);
3020 mpi3mr_transport_phy_reset(phy, 0);
3023 kfree(sas_io_unit_pg1);
3024 kfree(sas_io_unit_pg0);
3029 * mpi3mr_transport_phy_speed - set phy min/max speed
3030 * @phy: The SAS transport later phy object
3031 * @rates: Rates defined as in sas_phy_linkrates
3033 * This function sets the link rates given in the rates
3034 * argument to the given phy by executing required configuration
3035 * page changes or expander phy control command
3037 * Return: 0 for success, non-zero for failure.
3040 mpi3mr_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
3042 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
3043 struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
3044 struct mpi3_sas_phy_page0 phy_pg0;
3048 rc = mpi3mr_parent_present(mrioc, phy);
3052 if (!rates->minimum_linkrate)
3053 rates->minimum_linkrate = phy->minimum_linkrate;
3054 else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
3055 rates->minimum_linkrate = phy->minimum_linkrate_hw;
3057 if (!rates->maximum_linkrate)
3058 rates->maximum_linkrate = phy->maximum_linkrate;
3059 else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
3060 rates->maximum_linkrate = phy->maximum_linkrate_hw;
3062 /* handle expander phys */
3063 if (phy->identify.sas_address != mrioc->sas_hba.sas_address) {
3064 phy->minimum_linkrate = rates->minimum_linkrate;
3065 phy->maximum_linkrate = rates->maximum_linkrate;
3066 return mpi3mr_expander_phy_control(mrioc, phy,
3067 SMP_PHY_CONTROL_LINK_RESET);
3070 /* handle hba phys */
3071 sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3072 (mrioc->sas_hba.num_phys *
3073 sizeof(struct mpi3_sas_io_unit1_phy_data));
3074 sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3075 if (!sas_io_unit_pg1) {
3080 if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3081 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3082 __FILE__, __LINE__, __func__);
3087 sas_io_unit_pg1->phy_data[phy->number].max_min_link_rate =
3088 (rates->minimum_linkrate + (rates->maximum_linkrate << 4));
3090 if (mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3091 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3092 __FILE__, __LINE__, __func__);
3098 mpi3mr_transport_phy_reset(phy, 0);
3100 /* read phy page 0, then update the rates in the sas transport phy */
3101 if (!mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
3102 sizeof(struct mpi3_sas_phy_page0),
3103 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number) &&
3104 (ioc_status == MPI3_IOCSTATUS_SUCCESS)) {
3105 phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
3106 phy_pg0.programmed_link_rate &
3107 MPI3_SAS_PRATE_MIN_RATE_MASK);
3108 phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
3109 phy_pg0.programmed_link_rate >> 4);
3110 phy->negotiated_linkrate =
3111 mpi3mr_convert_phy_link_rate(
3112 (phy_pg0.negotiated_link_rate &
3113 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK)
3114 >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
3118 kfree(sas_io_unit_pg1);
3123 * mpi3mr_map_smp_buffer - map BSG dma buffer
3124 * @dev: Generic device reference
3125 * @buf: BSG buffer pointer
3126 * @dma_addr: Physical address holder
3127 * @dma_len: Mapped DMA buffer length.
3128 * @p: Virtual address holder
3130 * This function maps the DMAable buffer
3132 * Return: 0 on success, non-zero on failure
3135 mpi3mr_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3136 dma_addr_t *dma_addr, size_t *dma_len, void **p)
3138 /* Check if the request is split across multiple segments */
3139 if (buf->sg_cnt > 1) {
3140 *p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
3144 *dma_len = buf->payload_len;
3146 if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))
3148 *dma_addr = sg_dma_address(buf->sg_list);
3149 *dma_len = sg_dma_len(buf->sg_list);
3157 * mpi3mr_unmap_smp_buffer - unmap BSG dma buffer
3158 * @dev: Generic device reference
3159 * @buf: BSG buffer pointer
3160 * @dma_addr: Physical address to be unmapped
3161 * @p: Virtual address
3163 * This function unmaps the DMAable buffer
3166 mpi3mr_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3167 dma_addr_t dma_addr, void *p)
3170 dma_free_coherent(dev, buf->payload_len, p, dma_addr);
3172 dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
3176 * mpi3mr_transport_smp_handler - handler for smp passthru
3177 * @job: BSG job reference
3178 * @shost: SCSI host object reference
3179 * @rphy: SAS transport rphy object pointing the expander
3181 * This is used primarily by smp utils for sending the SMP
3182 * commands to the expanders attached to the controller
3185 mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
3186 struct sas_rphy *rphy)
3188 struct mpi3mr_ioc *mrioc = shost_priv(shost);
3189 struct mpi3_smp_passthrough_request mpi_request;
3190 struct mpi3_smp_passthrough_reply mpi_reply;
3193 dma_addr_t dma_addr_in;
3194 dma_addr_t dma_addr_out;
3195 void *addr_in = NULL;
3196 void *addr_out = NULL;
3199 unsigned int reslen = 0;
3200 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
3201 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
3202 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
3205 if (mrioc->reset_in_progress) {
3206 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
3211 rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3212 &dma_addr_out, &dma_len_out, &addr_out);
3217 sg_copy_to_buffer(job->request_payload.sg_list,
3218 job->request_payload.sg_cnt, addr_out,
3219 job->request_payload.payload_len);
3221 rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3222 &dma_addr_in, &dma_len_in, &addr_in);
3226 memset(&mpi_request, 0, request_sz);
3227 memset(&mpi_reply, 0, reply_sz);
3228 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
3229 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
3230 mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_rphy(mrioc, rphy);
3231 mpi_request.sas_address = ((rphy) ?
3232 cpu_to_le64(rphy->identify.sas_address) :
3233 cpu_to_le64(mrioc->sas_hba.sas_address));
3234 psge = &mpi_request.request_sge;
3235 mpi3mr_add_sg_single(psge, sgl_flags, dma_len_out - 4, dma_addr_out);
3237 psge = &mpi_request.response_sge;
3238 mpi3mr_add_sg_single(psge, sgl_flags, dma_len_in - 4, dma_addr_in);
3240 dprint_transport_info(mrioc, "sending SMP request\n");
3242 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
3243 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
3246 dprint_transport_info(mrioc,
3247 "SMP request completed with ioc_status(0x%04x)\n", ioc_status);
3249 dprint_transport_info(mrioc,
3250 "SMP request - reply data transfer size(%d)\n",
3251 le16_to_cpu(mpi_reply.response_data_length));
3253 memcpy(job->reply, &mpi_reply, reply_sz);
3254 job->reply_len = reply_sz;
3255 reslen = le16_to_cpu(mpi_reply.response_data_length);
3258 sg_copy_from_buffer(job->reply_payload.sg_list,
3259 job->reply_payload.sg_cnt, addr_in,
3260 job->reply_payload.payload_len);
3264 mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3265 dma_addr_in, addr_in);
3267 mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3268 dma_addr_out, addr_out);
3270 bsg_job_done(job, rc, reslen);
3273 struct sas_function_template mpi3mr_transport_functions = {
3274 .get_linkerrors = mpi3mr_transport_get_linkerrors,
3275 .get_enclosure_identifier = mpi3mr_transport_get_enclosure_identifier,
3276 .get_bay_identifier = mpi3mr_transport_get_bay_identifier,
3277 .phy_reset = mpi3mr_transport_phy_reset,
3278 .phy_enable = mpi3mr_transport_phy_enable,
3279 .set_phy_speed = mpi3mr_transport_phy_speed,
3280 .smp_handler = mpi3mr_transport_smp_handler,
3283 struct scsi_transport_template *mpi3mr_transport_template;