// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 Broadcom. All Rights Reserved. The term * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
/* * NPORT * * Port object for physical port and NPIV ports.
*/
/* * NPORT REFERENCE COUNTING * * A nport reference should be taken when: * - an nport is allocated * - a vport populates associated nport * - a remote node is allocated * - a unsolicited frame is processed * The reference should be dropped when: * - the unsolicited frame processesing is done * - the remote node is removed * - the vport is removed * - the nport is removed
*/
/* Update the nport's service parameters for the new wwn's */
nport->wwpn = wwpn;
nport->wwnn = wwnn;
snprintf(nport->wwnn_str, sizeof(nport->wwnn_str), "%016llX",
(unsignedlonglong)wwnn);
/* * if this is the "first" nport of the domain, * then make it the "phys" nport
*/ if (list_empty(&domain->nport_list))
domain->nport = nport;
domain = nport->domain;
efc_log_debug(domain->efc, "[%s] free nport\n", nport->display_name);
list_del(&nport->list_entry); /* * if this is the physical nport, * then clear it out of the domain
*/ if (nport == domain->nport)
domain->nport = NULL;
/* * If this is a vport, logout of the fabric * controller so that it deletes the vport * on the switch.
*/ /* if link is down, don't send logo */ if (efc->link_status == EFC_LINK_STATUS_DOWN) {
efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL); continue;
}
switch (evt) { case EFC_EVT_ENTER: case EFC_EVT_REENTER: case EFC_EVT_EXIT: case EFC_EVT_ALL_CHILD_NODES_FREE: break; case EFC_EVT_NPORT_ATTACH_OK:
efc_sm_transition(ctx, __efc_nport_attached, NULL); break; case EFC_EVT_SHUTDOWN: /* Flag this nport as shutting down */
nport->shutting_down = true;
if (nport->is_vport)
efc_vport_link_down(nport);
if (xa_empty(&nport->lookup)) { /* Remove the nport from the domain's lookup table */
xa_erase(&domain->lookup, nport->fc_id);
efc_sm_transition(ctx, __efc_nport_wait_port_free,
NULL); if (efc_cmd_nport_free(efc, nport)) {
efc_log_debug(nport->efc, "efc_hw_port_free failed\n"); /* Not much we can do, free the nport anyways */
efc_nport_free(nport);
}
} else { /* sm: node list is not empty / shutdown nodes */
efc_sm_transition(ctx,
__efc_nport_wait_shutdown, NULL);
efc_nport_shutdown(nport);
} break; default:
efc_log_debug(nport->efc, "[%s] %-20s %-20s not handled\n",
nport->display_name, funcname,
efc_sm_event_name(evt));
}
}
/* Update the nport's service parameters */
sp->fl_wwpn = cpu_to_be64(nport->wwpn);
sp->fl_wwnn = cpu_to_be64(nport->wwnn);
/* * if nport->fc_id is uninitialized, * then request that the fabric node use FDISC * to find an fc_id. * Otherwise we're restoring vports, or we're in * fabric emulation mode, so attach the fc_id
*/ if (nport->fc_id == U32_MAX) { struct efc_node *fabric;
/* * This state is entered after the nport is allocated; * it then waits for a fabric node * FDISC to complete, which requests a nport attach. * The nport attach complete is handled in this state.
*/ switch (evt) { case EFC_EVT_NPORT_ATTACH_OK: { struct efc_node *node;
switch (evt) { case EFC_EVT_NPORT_ALLOC_OK: case EFC_EVT_NPORT_ALLOC_FAIL: case EFC_EVT_NPORT_ATTACH_OK: case EFC_EVT_NPORT_ATTACH_FAIL: /* ignore these events - just wait for the all free event */ break;
case EFC_EVT_ALL_CHILD_NODES_FREE: { /* * Remove the nport from the domain's * sparse vector lookup table
*/
xa_erase(&domain->lookup, nport->fc_id);
efc_sm_transition(ctx, __efc_nport_wait_port_free, NULL); if (efc_cmd_nport_free(efc, nport)) {
efc_log_err(nport->efc, "efc_hw_port_free failed\n"); /* Not much we can do, free the nport anyways */
efc_nport_free(nport);
} break;
} default:
__efc_nport_common(__func__, ctx, evt, arg);
}
}
switch (evt) { case EFC_EVT_NPORT_ATTACH_OK: /* Ignore as we are waiting for the free CB */ break; case EFC_EVT_NPORT_FREE_OK: { /* All done, free myself */
efc_nport_free(nport); break;
} default:
__efc_nport_common(__func__, ctx, evt, arg);
}
}
/* Use the vport spec to find the associated vports and start them */
spin_lock_irqsave(&efc->vport_lock, flags);
list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) { if (!vport->nport) { if (efc_vport_nport_alloc(domain, vport))
rc = -EIO;
}
}
spin_unlock_irqrestore(&efc->vport_lock, flags);
if (ini && domain->efc->enable_ini == 0) {
efc_log_debug(efc, "driver initiator mode not enabled\n"); return -EIO;
}
if (tgt && domain->efc->enable_tgt == 0) {
efc_log_debug(efc, "driver target mode not enabled\n"); return -EIO;
}
/* * Create a vport spec if we need to recreate * this vport after a link up event
*/
vport = efc_vport_create_spec(domain->efc, wwnn, wwpn, fc_id, ini, tgt,
tgt_data, ini_data); if (!vport) {
efc_log_err(efc, "failed to create vport object entry\n"); return -EIO;
}
/* * walk the efc_vport_list and return failure * if a valid(vport with non zero WWPN and WWNN) vport entry * is already created
*/
spin_lock_irqsave(&efc->vport_lock, flags);
list_for_each_entry(vport, &efc->vport_list, list_entry) { if ((wwpn && vport->wwpn == wwpn) &&
(wwnn && vport->wwnn == wwnn)) {
efc_log_err(efc, "VPORT %016llX %016llX already allocated\n",
wwnn, wwpn);
spin_unlock_irqrestore(&efc->vport_lock, flags); return NULL;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.