// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 Broadcom. All Rights Reserved. The term * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
struct efc_node *
efc_node_find(struct efc_nport *nport, u32 port_id)
{ /* Find an FC node structure given the FC port ID */ return xa_load(&nport->lookup, port_id);
}
if (node->refound) { /* * Save the name server node. We will send fake RSCN event at * the end to handle ignored RSCN event during node deletion
*/
ns = efc_node_find(node->nport, FC_FID_DIR_SERV);
}
if (!node->nport) {
efc_log_err(efc, "Node already Freed\n"); return;
}
/* if the gidpt_delay_timer is still running, then delete it */ if (timer_pending(&node->gidpt_delay_timer))
timer_delete(&node->gidpt_delay_timer);
xa_erase(&nport->lookup, node->rnode.fc_id);
/* * If the node_list is empty, * then post a ALL_CHILD_NODES_FREE event to the nport, * after the lock is released. * The nport may be free'd as a result of the event.
*/ if (xa_empty(&nport->lookup))
efc_sm_post_event(&nport->sm, EFC_EVT_ALL_CHILD_NODES_FREE,
NULL);
staticvoid efc_node_handle_implicit_logo(struct efc_node *node)
{ int rc;
/* * currently, only case for implicit logo is PLOGI * recvd. Thus, node's ELS IO pending list won't be * empty (PLOGI will be on it)
*/
WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_PLOGI);
node_printf(node, "Reason: implicit logout, re-authenticate\n");
/* Re-attach node with the same HW node resources */
node->req_free = false;
rc = efc_node_attach(node);
efc_node_transition(node, __efc_d_wait_node_attach, NULL);
node->els_io_enabled = true;
if (rc < 0)
efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL, NULL);
}
/* * there are two scenarios where we want to keep * this node alive: * 1. there are pending frames that need to be * processed or * 2. we're an initiator and the remote node is * a target and we need to re-authenticate
*/
node_printf(node, "Shutdown: explicit logo pend=%d ", !pend_frames_empty);
node_printf(node, "nport.ini=%d node.tgt=%d\n",
node->nport->enable_ini, node->targ); if (!pend_frames_empty || (node->nport->enable_ini && node->targ)) {
u8 send_plogi = false;
if (node->nport->enable_ini && node->targ) { /* * we're an initiator and * node shutting down is a target; * we'll need to re-authenticate in * initial state
*/
send_plogi = true;
}
/* * either pending frames exist or we are re-authenticating * with PLOGI (or both); in either case, return to initial * state
*/
efc_node_init_device(node, send_plogi);
} /* else: let node shutdown occur */
}
switch (evt) { case EFC_EVT_ENTER: {
efc_node_hold_frames(node);
WARN_ON(!efc_els_io_list_empty(node, &node->els_ios_list)); /* by default, we will be freeing node after we unwind */
node->req_free = true;
switch (node->shutdown_reason) { case EFC_NODE_SHUTDOWN_IMPLICIT_LOGO: /* Node shutdown b/c of PLOGI received when node * already logged in. We have PLOGI service * parameters, so submit node attach; we won't be * freeing this node
*/
efc_node_handle_implicit_logo(node); break;
case EFC_NODE_SHUTDOWN_EXPLICIT_LOGO:
efc_node_handle_explicit_logo(node); break;
case EFC_NODE_SHUTDOWN_DEFAULT: default: { /* * shutdown due to link down, * node going away (xport event) or * nport shutdown, purge pending and * proceed to cleanup node
*/
/* cleanup any pending LS_ACC ELSs */
efc_node_send_ls_io_cleanup(node);
staticbool
efc_node_check_els_quiesced(struct efc_node *node)
{ /* check to see if ELS requests, completions are quiesced */ if (node->els_req_cnt == 0 && node->els_cmpl_cnt == 0 &&
efc_els_io_list_empty(node, &node->els_ios_list)) { if (!node->attached) { /* hw node detach already completed, proceed */
node_printf(node, "HW node not attached\n");
efc_node_transition(node,
__efc_node_wait_ios_shutdown,
NULL);
} else { /* * hw node detach hasn't completed, * transition and wait
*/
node_printf(node, "HW node still attached\n");
efc_node_transition(node, __efc_node_wait_node_free,
NULL);
} returntrue;
} returnfalse;
}
void
efc_node_initiate_cleanup(struct efc_node *node)
{ /* * if ELS's have already been quiesced, will move to next state * if ELS's have not been quiesced, abort them
*/ if (!efc_node_check_els_quiesced(node)) {
efc_node_hold_frames(node);
efc_node_transition(node, __efc_node_wait_els_shutdown, NULL);
}
}
node_sm_trace(); /* Node state machine: Wait for all ELSs to complete */ switch (evt) { case EFC_EVT_ENTER:
efc_node_hold_frames(node); if (efc_els_io_list_empty(node, &node->els_ios_list)) {
node_printf(node, "All ELS IOs complete\n");
check_quiesce = true;
} break; case EFC_EVT_EXIT:
efc_node_accept_frames(node); break;
case EFC_EVT_SRRS_ELS_REQ_OK: case EFC_EVT_SRRS_ELS_REQ_FAIL: case EFC_EVT_SRRS_ELS_REQ_RJT: case EFC_EVT_ELS_REQ_ABORTED: if (WARN_ON(!node->els_req_cnt)) break;
node->els_req_cnt--;
check_quiesce = true; break;
case EFC_EVT_SRRS_ELS_CMPL_OK: case EFC_EVT_SRRS_ELS_CMPL_FAIL: if (WARN_ON(!node->els_cmpl_cnt)) break;
node->els_cmpl_cnt--;
check_quiesce = true; break;
case EFC_EVT_ALL_CHILD_NODES_FREE: /* all ELS IO's complete */
node_printf(node, "All ELS IOs complete\n");
WARN_ON(!efc_els_io_list_empty(node, &node->els_ios_list));
check_quiesce = true; break;
case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
check_quiesce = true; break;
case EFC_EVT_DOMAIN_ATTACH_OK: /* don't care about domain_attach_ok */ break;
/* ignore shutdown events as we're already in shutdown path */ case EFC_EVT_SHUTDOWN: /* have default shutdown event take precedence */
node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
fallthrough;
case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO: case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
node_printf(node, "%s received\n", efc_sm_event_name(evt)); break;
switch (evt) { case EFC_EVT_ENTER:
efc_node_hold_frames(node); break;
case EFC_EVT_EXIT:
efc_node_accept_frames(node); break;
case EFC_EVT_NODE_FREE_OK: /* node is officially no longer attached */
node->attached = false;
efc_node_transition(node, __efc_node_wait_ios_shutdown, NULL); break;
case EFC_EVT_ALL_CHILD_NODES_FREE: case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY: /* As IOs and ELS IO's complete we expect to get these events */ break;
case EFC_EVT_DOMAIN_ATTACH_OK: /* don't care about domain_attach_ok */ break;
/* ignore shutdown events as we're already in shutdown path */ case EFC_EVT_SHUTDOWN: /* have default shutdown event take precedence */
node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
fallthrough;
case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO: case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
node_printf(node, "%s received\n", efc_sm_event_name(evt)); break; default:
__efc_node_common(__func__, ctx, evt, arg);
}
}
switch (evt) { case EFC_EVT_ENTER:
efc_node_hold_frames(node);
/* first check to see if no ELS IOs are outstanding */ if (efc_els_io_list_empty(node, &node->els_ios_list)) /* If there are any active IOS, Free them. */
efc_node_transition(node, __efc_node_shutdown, NULL); break;
case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY: case EFC_EVT_ALL_CHILD_NODES_FREE: if (efc_els_io_list_empty(node, &node->els_ios_list))
efc_node_transition(node, __efc_node_shutdown, NULL); break;
case EFC_EVT_EXIT:
efc_node_accept_frames(node); break;
case EFC_EVT_SRRS_ELS_REQ_FAIL: /* Can happen as ELS IO IO's complete */ if (WARN_ON(!node->els_req_cnt)) break;
node->els_req_cnt--; break;
/* ignore shutdown events as we're already in shutdown path */ case EFC_EVT_SHUTDOWN: /* have default shutdown event take precedence */
node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
fallthrough;
case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO: case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
efc_log_debug(efc, "[%s] %-20s\n", node->display_name,
efc_sm_event_name(evt)); break; case EFC_EVT_DOMAIN_ATTACH_OK: /* don't care about domain_attach_ok */ break; default:
__efc_node_common(__func__, ctx, evt, arg);
}
}
switch (evt) { case EFC_EVT_ENTER: case EFC_EVT_REENTER: case EFC_EVT_EXIT: case EFC_EVT_NPORT_TOPOLOGY_NOTIFY: case EFC_EVT_NODE_MISSING: case EFC_EVT_FCP_CMD_RCVD: break;
case EFC_EVT_NODE_REFOUND:
node->refound = true; break;
/* * node->attached must be set appropriately * for all node attach/detach events
*/ case EFC_EVT_NODE_ATTACH_OK:
node->attached = true; break;
case EFC_EVT_NODE_FREE_OK: case EFC_EVT_NODE_ATTACH_FAIL:
node->attached = false; break;
/* * handle any ELS completions that * other states either didn't care about * or forgot about
*/ case EFC_EVT_SRRS_ELS_CMPL_OK: case EFC_EVT_SRRS_ELS_CMPL_FAIL: if (WARN_ON(!node->els_cmpl_cnt)) break;
node->els_cmpl_cnt--; break;
/* * handle any ELS request completions that * other states either didn't care about * or forgot about
*/ case EFC_EVT_SRRS_ELS_REQ_OK: case EFC_EVT_SRRS_ELS_REQ_FAIL: case EFC_EVT_SRRS_ELS_REQ_RJT: case EFC_EVT_ELS_REQ_ABORTED: if (WARN_ON(!node->els_req_cnt)) break;
node->els_req_cnt--; break;
case EFC_EVT_ELS_RCVD: { struct fc_frame_header *hdr = cbdata->header->dma.virt;
/* * Unsupported ELS was received, * send LS_RJT, command not supported
*/
efc_log_debug(efc, "[%s] (%s) ELS x%02x, LS_RJT not supported\n",
node->display_name, funcname,
((u8 *)cbdata->payload->dma.virt)[0]);
case EFC_EVT_PLOGI_RCVD: case EFC_EVT_FLOGI_RCVD: case EFC_EVT_LOGO_RCVD: case EFC_EVT_PRLI_RCVD: case EFC_EVT_PRLO_RCVD: case EFC_EVT_PDISC_RCVD: case EFC_EVT_FDISC_RCVD: case EFC_EVT_ADISC_RCVD: case EFC_EVT_RSCN_RCVD: case EFC_EVT_SCR_RCVD: { struct fc_frame_header *hdr = cbdata->header->dma.virt;
/* sm: / send ELS_RJT */
efc_log_debug(efc, "[%s] (%s) %s sending ELS_RJT\n",
node->display_name, funcname,
efc_sm_event_name(evt)); /* if we didn't catch this in a state, send generic LS_RJT */
efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
ELS_RJT_UNAB, ELS_EXPL_NONE, 0); break;
} case EFC_EVT_ABTS_RCVD: {
efc_log_debug(efc, "[%s] (%s) %s sending BA_ACC\n",
node->display_name, funcname,
efc_sm_event_name(evt));
/* If our event call depth is one and * we're not holding frames * then we can dispatch any pending frames. * We don't want to allow the efc_process_node_pending() * call to recurse.
*/ if (!node->hold_frames && node->evtdepth == 1)
efc_process_node_pending(node);
node->evtdepth--;
/* * Free the node object if so requested, * and we're at an event call depth of zero
*/ if (node->evtdepth == 0 && node->req_free)
free_node = true;
/* * This state is entered when a state is "paused". When resumed, the * node is transitioned to a previously saved state (node->ndoedb_state)
*/ switch (evt) { case EFC_EVT_ENTER:
node_printf(node, "Paused\n"); break;
/* find a matching event for the ELS command */ for (i = 0; i < ARRAY_SIZE(els_cmd_list); i++) { if (els_cmd_list[i].cmd == buf[0]) {
evt = els_cmd_list[i].evt; break;
}
}
for (;;) { /* need to check for hold frames condition after each frame * processed because any given frame could cause a transition * to a state that holds frames
*/ if (node->hold_frames) break;
seq = NULL; /* Get next frame/sequence */
spin_lock_irqsave(&node->pend_frames_lock, flags);
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.