/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at * http://www.opensource.org/licenses/cddl1.txt. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2004-2012 Emulex. All rights reserved. * Use is subject to license terms. */ #include /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ EMLXS_MSG_DEF(EMLXS_FCF_C); /* * STATE MACHINE RULES: * * - State change requests to an XXXX object when operating within * an emlxs_XXXX state management function must be made * using the emlxs_XXXX_state() call. * * - State change requests to an XXXX object when operating outside * an emlxs_XXXX state management function must be made * using the emlxs_XXXX_alloc(), emlxs_XXXX_free(), emlxs_XXXX_event() * or emlxs_XXXX_..._notify() calls. * * - emlxs_XXXX_..._notify() calls are used by routines outside * this fcf module to enter the state machine. * * - It is forbidden to make direct calls to emlxs_XXXX_...._action() * functions. Only emlxs_XXXX_action() routines may make calls to * emlxs_XXXX_...._action() functions. * * - Its is forbidden to make direct calls to emlxs_XXXX_action(). * Only emlxs_XXXX_state() and emlxs_XXXX_event() routines may make * calls to emlxs_XXXX_action(). * * - The EMLXS_FCF_LOCK must be held before calling: * emlxs_XXXX_state(), emlxs_XXXX_event() and emlxs_XXXX_action(). * * - All other calls touching fcftab, fcfi, vfi, vpi, rpi objects * must hold the EMLXS_FCF_LOCK to protect these objects. */ /* * DEBUG MESSAGE TERMINATION RULES: * * - A message should end in ">" if a thread operating outside the * XXXX state machine enters the XXXX state machine with a call to * emlxs_XXXX_event() or emlxs_XXXX_state(). This includes calls made * from emlxs_..._notify(), emlxs_..._mbcmpl() and emlxs_..._timer() * routines since they represent the beginnning of new threads. * * - A message should end in "<" if the thread is about exit * an emlxs_XXXX_..._action() without previously calling the * next emlxs_XXXX_state(). This includes the emlxs_XXXX_action() * and emlxs_XXXX_state() routines themselves since errors * in these routines represent the termination of state change * thread. * * - A message should end in "." if none of the previous * conditions apply. */ /* ************************************************************************** */ /* FCF Generic */ /* ************************************************************************** */ /* * EVENT ARG1 * -------------------------------------------- * FCF_EVENT_STATE_ENTER None * * FCF_EVENT_LINKUP None * FCF_EVENT_LINKDOWN None * FCF_EVENT_CVL vpi * FCF_EVENT_FCFTAB_FULL None * FCF_EVENT_FCF_FOUND fcf_index * FCF_EVENT_FCF_LOST fcf_index * FCF_EVENT_FCF_CHANGED fcf_index * * FCF_EVENT_FCFI_ONLINE FCFIobj_t* * FCF_EVENT_FCFI_OFFLINE FCFIobj_t* * FCF_EVENT_FCFI_PAUSE FCFIobj_t* * * FCF_EVENT_VFI_ONLINE VFIobj_t* * FCF_EVENT_VFI_OFFLINE VFIobj_t* * FCF_EVENT_VFI_PAUSE VFIobj_t* * * FCF_EVENT_VPI_ONLINE VPIobj_t* * FCF_EVENT_VPI_OFFLINE VPIobj_t* * FCF_EVENT_VPI_PAUSE VPIobj_t* * * FCF_EVENT_RPI_ONLINE RPIobj_t* * FCF_EVENT_RPI_OFFLINE RPIobj_t* * FCF_EVENT_RPI_PAUSE RPIobj_t* * FCF_EVENT_RPI_RESUME RPIobj_t* * FCF_EVENT_RPI_TIMEOUT RPIobj_t* */ /* Order does not matter */ emlxs_table_t emlxs_fcf_event_table[] = { {FCF_EVENT_STATE_ENTER, "E_ENTER"}, {FCF_EVENT_SHUTDOWN, "E_SHUTDOWN"}, {FCF_EVENT_LINKUP, "E_LINKUP"}, {FCF_EVENT_LINKDOWN, "E_LINKDOWN"}, {FCF_EVENT_CVL, "E_CVL"}, {FCF_EVENT_FCFTAB_FULL, "E_TABLE_FULL"}, {FCF_EVENT_FCF_FOUND, "E_FCF_FOUND"}, {FCF_EVENT_FCF_LOST, "E_FCF_LOST"}, {FCF_EVENT_FCF_CHANGED, "E_FCF_CHANGED"}, {FCF_EVENT_FCFI_ONLINE, "E_FCFI_ONLINE"}, {FCF_EVENT_FCFI_OFFLINE, "E_FCFI_OFFLINE"}, {FCF_EVENT_FCFI_PAUSE, "E_FCFI_PAUSE"}, {FCF_EVENT_VFI_ONLINE, "E_VFI_ONLINE"}, {FCF_EVENT_VFI_OFFLINE, "E_VFI_OFFLINE"}, {FCF_EVENT_VFI_PAUSE, "E_VFI_PAUSE"}, {FCF_EVENT_VPI_ONLINE, "E_VPI_ONLINE"}, {FCF_EVENT_VPI_OFFLINE, "E_VPI_OFFLINE"}, {FCF_EVENT_VPI_PAUSE, "E_VPI_PAUSE"}, {FCF_EVENT_RPI_ONLINE, "E_RPI_ONLINE"}, {FCF_EVENT_RPI_OFFLINE, "E_RPI_OFFLINE"}, {FCF_EVENT_RPI_PAUSE, "E_RPI_PAUSE"}, {FCF_EVENT_RPI_RESUME, "E_RPI_RESUME"}, }; /* emlxs_fcf_event_table */ /* Order does not matter */ emlxs_table_t emlxs_fcf_reason_table[] = { {FCF_REASON_NONE, "R_NONE"}, {FCF_REASON_REENTER, "R_REENTER"}, {FCF_REASON_EVENT, "R_EVENT"}, {FCF_REASON_REQUESTED, "R_REQUESTED"}, {FCF_REASON_NO_MBOX, "R_NO_MBOX"}, {FCF_REASON_NO_BUFFER, "R_NO_BUFFER"}, {FCF_REASON_SEND_FAILED, "R_SEND_FAILED"}, {FCF_REASON_MBOX_FAILED, "R_MBOX_FAILED"}, {FCF_REASON_MBOX_BUSY, "R_MBOX_BUSY"}, {FCF_REASON_NO_FCFI, "R_NO_FCFI"}, {FCF_REASON_NO_VFI, "R_NO_VFI"}, {FCF_REASON_ONLINE_FAILED, "R_ONLINE_FAILED"}, {FCF_REASON_OFFLINE_FAILED, "R_OFFLINE_FAILED"}, {FCF_REASON_OP_FAILED, "R_OP_FAILED"}, {FCF_REASON_NO_PKT, "R_NO_PKT"}, {FCF_REASON_NO_NODE, "R_NO_NODE"}, {FCF_REASON_NOT_ALLOWED, "R_NOT_ALLOWED"}, {FCF_REASON_UNUSED, "R_UNUSED"}, {FCF_REASON_INVALID, "R_INVALID"}, }; /* emlxs_fcf_reason_table */ /* ********************************************************************** */ /* FCFTAB Generic */ /* ********************************************************************** */ static char *emlxs_fcftab_state_xlate(emlxs_port_t *port, uint32_t state); static uint32_t emlxs_fcftab_event(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcftab_shutdown_action(emlxs_port_t *port, uint32_t evt, void *arg1); /* ********************************************************************** */ /* FC FCFTAB */ /* ********************************************************************** */ /* Order does not matter */ emlxs_table_t emlxs_fc_fcftab_state_table[] = { {FC_FCFTAB_STATE_SHUTDOWN, "FCFTAB_SHUTDOWN"}, {FC_FCFTAB_STATE_OFFLINE, "FCFTAB_OFFLINE"}, {FC_FCFTAB_STATE_TOPO, "FCFTAB_TOPO"}, {FC_FCFTAB_STATE_TOPO_FAILED, "FCFTAB_TOPO_FAILED"}, {FC_FCFTAB_STATE_TOPO_CMPL, "FCFTAB_TOPO_CMPL"}, {FC_FCFTAB_STATE_CFGLINK, "FCFTAB_CFGLINK"}, {FC_FCFTAB_STATE_CFGLINK_FAILED, "FCFTAB_CFGLINK_FAILED"}, {FC_FCFTAB_STATE_CFGLINK_CMPL, "FCFTAB_CFGLINK_CMPL"}, {FC_FCFTAB_STATE_SPARM, "FCFTAB_SPARM"}, {FC_FCFTAB_STATE_SPARM_FAILED, "FCFTAB_SPARM_FAILED"}, {FC_FCFTAB_STATE_SPARM_CMPL, "FCFTAB_SPARM_CMPL"}, {FC_FCFTAB_STATE_FCFI_OFFLINE_CMPL, "FCFTAB_FCFI_OFFLINE_CMPL"}, {FC_FCFTAB_STATE_FCFI_OFFLINE, "FCFTAB_FCFI_OFFLINE"}, {FC_FCFTAB_STATE_FCFI_ONLINE, "FCFTAB_FCFI_ONLINE"}, {FC_FCFTAB_STATE_FCFI_ONLINE_CMPL, "FCFTAB_FCFI_ONLINE_CMPL"}, {FC_FCFTAB_STATE_ONLINE, "FCFTAB_ONLINE"}, }; /* emlxs_fc_fcftab_state_table */ static void emlxs_fc_fcftab_online_timer(emlxs_hba_t *hba); static uint32_t emlxs_fc_fcftab_offline_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_online_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_topo_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_topo_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_topo_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_cfglink_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_cfglink_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_cfglink_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_sparm_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_sparm_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_sparm_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_linkup_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_linkdown_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_fcfi_online_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_fcfi_offline_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_shutdown_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_fcfi_offline_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_fcfi_offline_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_fcfi_online_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_fcfi_online_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1); static char *emlxs_fc_fcftab_state_xlate(uint32_t state); static uint32_t emlxs_fc_fcftab_event(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fc_fcftab_req_handler(emlxs_port_t *port, void *arg1); /* * - Online sequencing can start from FC_FCFTAB_STATE_OFFLINE state * * - Offline sequencing can interrupt the online sequencing at the * entry of the next wait state. * * NORMAL ONLINE SEQ * --------------------------- * LINK_UP event <-- Adapter * FC_FCFTAB_STATE_OFFLINE * FC_FCFTAB_STATE_TOPO * FC_FCFTAB_STATE_TOPO_CMPL * FC_FCFTAB_STATE_CFGLINK * FC_FCFTAB_STATE_CFGLINK_CMPL * FC_FCFTAB_STATE_SPARM * FC_FCFTAB_STATE_SPARM_CMPL * FC_FCFTAB_STATE_FCFI_ONLINE * FC_FCFTAB_STATE_FCFI_ONLINE_CMPL * FC_FCFTAB_STATE_ONLINE * * * NORMAL OFFLINE SEQ * --------------------------- * LINK_DOWN event <-- Adapter * FC_FCFTAB_STATE_ONLINE * FC_FCFTAB_STATE_FCFI_OFFLINE * FC_FCFTAB_STATE_FCFI_OFFLINE_CMPL * FC_FCFTAB_STATE_OFFLINE * */ /* Order does matter */ static void *emlxs_fc_fcftab_action_table[] = { /* Action routine Event */ /* FC_FCFTAB_STATE_SHUTDOWN 0 (Requires adapter reset) */ (void *) emlxs_fcftab_shutdown_action, /* STATE_ENTER */ (void *) NULL, /* SHUTDOWN */ (void *) NULL, /* LINK_UP */ (void *) NULL, /* LINK_DOWN */ (void *) NULL, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_OFFLINE 1 (Wait for LINK_UP event) */ (void *) emlxs_fc_fcftab_offline_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_TOPO 2 (Wait for topo mbcmpl) */ (void *) emlxs_fc_fcftab_topo_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_TOPO_FAILED 3 (Transitional) */ (void *) emlxs_fc_fcftab_topo_failed_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_TOPO_CMPL 4 (Transitional) */ (void *) emlxs_fc_fcftab_topo_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_CFGLINK 5 (Wait for cfglink mbcmpl) */ (void *) emlxs_fc_fcftab_cfglink_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_CFGLINK_FAILED 6 (Transitional) */ (void *) emlxs_fc_fcftab_cfglink_failed_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_CFGLINK_CMPL 7 (Transitional) */ (void *) emlxs_fc_fcftab_cfglink_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_SPARM 8 (Wait for sparm mbcmpl) */ (void *) emlxs_fc_fcftab_sparm_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_SPARM_FAILED 9 (Transitional) */ (void *) emlxs_fc_fcftab_sparm_failed_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_SPARM_CMPL 10 (Transitional) */ (void *) emlxs_fc_fcftab_sparm_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_FCFI_OFFLINE_CMPL 11 (Transitional) */ (void *) emlxs_fc_fcftab_fcfi_offline_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_FCFI_OFFLINE 12 (Wait for FCFI_OFFLINE event) */ (void *) emlxs_fc_fcftab_fcfi_offline_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_FCFI_ONLINE 13 (Wait for FCFI_ONLINE event) */ (void *) emlxs_fc_fcftab_fcfi_online_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_FCFI_ONLINE_CMPL 14 (Transitional) */ (void *) emlxs_fc_fcftab_fcfi_online_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FC_FCFTAB_STATE_ONLINE 15 (Wait for LINK_DOWN evt) */ (void *) emlxs_fc_fcftab_online_action, /* STATE_ENTER */ (void *) emlxs_fc_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fc_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fc_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fc_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fc_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ }; /* emlxs_fc_fcftab_action_table[] */ #define FC_FCFTAB_ACTION_EVENTS 6 #define FC_FCFTAB_ACTION_STATES \ (sizeof (emlxs_fc_fcftab_action_table)/ \ (FC_FCFTAB_ACTION_EVENTS * sizeof (void *))) /* ********************************************************************** */ /* FCOE FCFTAB */ /* ********************************************************************** */ /* Order does not matter */ emlxs_table_t emlxs_fcoe_fcftab_state_table[] = { {FCOE_FCFTAB_STATE_SHUTDOWN, "FCFTAB_SHUTDOWN"}, {FCOE_FCFTAB_STATE_OFFLINE, "FCFTAB_OFFLINE"}, {FCOE_FCFTAB_STATE_SOLICIT, "FCFTAB_SOLICIT"}, {FCOE_FCFTAB_STATE_SOLICIT_FAILED, "FCFTAB_SOLICIT_FAILED"}, {FCOE_FCFTAB_STATE_SOLICIT_CMPL, "FCFTAB_SOLICIT_CMPL"}, {FCOE_FCFTAB_STATE_READ, "FCFTAB_READ"}, {FCOE_FCFTAB_STATE_READ_FAILED, "FCFTAB_READ_FAILED"}, {FCOE_FCFTAB_STATE_READ_CMPL, "FCFTAB_READ_CMPL"}, {FCOE_FCFTAB_STATE_FCFI_OFFLINE_CMPL, "FCFTAB_FCFI_OFFLINE_CMPL"}, {FCOE_FCFTAB_STATE_FCFI_OFFLINE, "FCFTAB_FCFI_OFFLINE"}, {FCOE_FCFTAB_STATE_FCFI_ONLINE, "FCFTAB_FCFI_ONLINE"}, {FCOE_FCFTAB_STATE_FCFI_ONLINE_CMPL, "FCFTAB_FCFI_ONLINE_CMPL"}, {FCOE_FCFTAB_STATE_ONLINE, "FCFTAB_ONLINE"}, }; /* emlxs_fcoe_fcftab_state_table */ static uint32_t emlxs_fcoe_fcftab_sol_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_sol_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_sol_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_shutdown_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_linkdown_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_read_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_read_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_read_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_fcfi_online_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_fcfi_online_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_fcfi_offline_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_fcfi_offline_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_found_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_lost_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_changed_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_full_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_linkup_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_cvl_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_online_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_offline_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_fcfi_offline_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_fcfi_online_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1); static void emlxs_fcoe_fcftab_read_timer(emlxs_hba_t *hba); static void emlxs_fcoe_fcftab_sol_timer(emlxs_hba_t *hba); static void emlxs_fcoe_fcftab_offline_timer(emlxs_hba_t *hba); static char *emlxs_fcoe_fcftab_state_xlate(uint32_t state); static uint32_t emlxs_fcoe_fcftab_event(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_fcoe_fcftab_state(emlxs_port_t *port, uint16_t state, uint16_t reason, uint32_t explain, void *arg1); /* * - Online sequencing can start from FCOE_FCFTAB_STATE_OFFLINE state * * - Offline sequencing can interrupt the online sequencing at the * entry of the next wait state. * * NORMAL ONLINE SEQ * --------------------------- * LINK_UP event <-- Adapter * FCOE_FCFTAB_STATE_OFFLINE * FCOE_FCFTAB_STATE_SOLICIT * FCOE_FCFTAB_STATE_SOLICIT_CMPL * FCOE_FCFTAB_STATE_READ * FCOE_FCFTAB_STATE_READ_CMPL * FCOE_FCFTAB_STATE_FCFI_OFFLINE * FCOE_FCFTAB_STATE_FCFI_OFFLINE_CMPL * FCOE_FCFTAB_STATE_FCFI_ONLINE * FCOE_FCFTAB_STATE_FCFI_ONLINE_CMPL * FCOE_FCFTAB_STATE_ONLINE * * * NORMAL OFFLINE SEQ * --------------------------- * LINK_DOWN event <-- Adapter * FCOE_FCFTAB_STATE_ONLINE * FCOE_FCFTAB_STATE_FCFI_OFFLINE * FCOE_FCFTAB_STATE_FCFI_OFFLINE_CMPL * FCOE_FCFTAB_STATE_OFFLINE * */ /* Order does matter */ static void *emlxs_fcoe_fcftab_action_table[] = { /* Action routine Event */ /* FCOE_FCFTAB_STATE_SHUTDOWN 0 (Requires adapter reset) */ (void *) emlxs_fcftab_shutdown_action, /* STATE_ENTER */ (void *) NULL, /* SHUTDOWN */ (void *) NULL, /* LINK_UP */ (void *) NULL, /* LINK_DOWN */ (void *) NULL, /* CVL_RECD */ (void *) NULL, /* FCF_FOUND */ (void *) NULL, /* FCF_LOST */ (void *) NULL, /* FCF_CHANGED */ (void *) NULL, /* TABLE_FULL */ (void *) NULL, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_OFFLINE 1 (Wait for LINK_UP event) */ (void *) emlxs_fcoe_fcftab_offline_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_SOLICIT 2 (Wait on fcf_solicit cmpl) */ (void *) emlxs_fcoe_fcftab_sol_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_SOLICIT_FAILED 3 (Transitional) */ (void *) emlxs_fcoe_fcftab_sol_failed_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_SOLICIT_CMPL 4 (Wait on fcf timer cmpl) */ (void *) emlxs_fcoe_fcftab_sol_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_READ 5 (Wait on fcf_read cmpl) */ (void *) emlxs_fcoe_fcftab_read_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_READ_FAILED 6 (Transitional) */ (void *) emlxs_fcoe_fcftab_read_failed_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_READ_CMPL 7 (Transitional) */ (void *) emlxs_fcoe_fcftab_read_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_FCFI_OFFLINE_CMPL 8 (Transitional) */ (void *) emlxs_fcoe_fcftab_fcfi_offline_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_FCFI_OFFLINE 9 (Wait for FCFI_OFFLINE event) */ (void *) emlxs_fcoe_fcftab_fcfi_offline_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_FCFI_ONLINE 10 (Wait on FCFI_ONLINE event) */ (void *) emlxs_fcoe_fcftab_fcfi_online_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_FCFI_ONLINE_CMPL 11 (Transitional) */ (void *) emlxs_fcoe_fcftab_fcfi_online_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ /* FCOE_FCFTAB_STATE_ONLINE 12 (Wait for LINK_DOWN event) */ (void *) emlxs_fcoe_fcftab_online_action, /* STATE_ENTER */ (void *) emlxs_fcoe_fcftab_shutdown_evt_action, /* SHUTDOWN */ (void *) emlxs_fcoe_fcftab_linkup_evt_action, /* LINK_UP */ (void *) emlxs_fcoe_fcftab_linkdown_evt_action, /* LINK_DOWN */ (void *) emlxs_fcoe_fcftab_cvl_evt_action, /* CVL_RECD */ (void *) emlxs_fcoe_fcftab_found_evt_action, /* FCF_FOUND */ (void *) emlxs_fcoe_fcftab_lost_evt_action, /* FCF_LOST */ (void *) emlxs_fcoe_fcftab_changed_evt_action, /* FCF_CHANGED */ (void *) emlxs_fcoe_fcftab_full_evt_action, /* TABLE_FULL */ (void *) emlxs_fcoe_fcftab_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcoe_fcftab_fcfi_offline_evt_action, /* FCFI_OFFLINE */ }; /* emlxs_fcoe_fcftab_action_table[] */ #define FCOE_FCFTAB_ACTION_EVENTS 11 #define FCOE_FCFTAB_ACTION_STATES \ (sizeof (emlxs_fcoe_fcftab_action_table)/ \ (FCOE_FCFTAB_ACTION_EVENTS * sizeof (void *))) /* ********************************************************************** */ /* FCFI */ /* ********************************************************************** */ /* Order does not matter */ emlxs_table_t emlxs_fcfi_state_table[] = { {FCFI_STATE_FREE, "FCFI_FREE"}, {FCFI_STATE_OFFLINE, "FCFI_OFFLINE"}, {FCFI_STATE_UNREG_CMPL, "FCFI_UNREG_CMPL"}, {FCFI_STATE_UNREG_FAILED, "FCFI_UNREG_FAILED"}, {FCFI_STATE_UNREG, "FCFI_UNREG"}, {FCFI_STATE_REG, "FCFI_REG"}, {FCFI_STATE_REG_FAILED, "FCFI_REG_FAILED"}, {FCFI_STATE_REG_CMPL, "FCFI_REG_CMPL"}, {FCFI_STATE_VFI_OFFLINE_CMPL, "FCFI_VFI_OFFLINE_CMPL"}, {FCFI_STATE_VFI_OFFLINE, "FCFI_VFI_OFFLINE"}, {FCFI_STATE_VFI_ONLINE, "FCFI_VFI_ONLINE"}, {FCFI_STATE_VFI_ONLINE_CMPL, "FCFI_VFI_ONLINE_CMPL"}, {FCFI_STATE_PAUSED, "FCFI_PAUSED"}, {FCFI_STATE_ONLINE, "FCFI_ONLINE"}, }; /* emlxs_fcfi_state_table */ static uint32_t emlxs_fcfi_free_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_online_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_offline_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_pause_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_reg_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_unreg_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_reg_cmpl_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_unreg_cmpl_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_vfi_online_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_vfi_online_cmpl_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_reg_failed_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_unreg_failed_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_vfi_offline_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_vfi_offline_cmpl_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_online_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_paused_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_offline_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_vfi_online_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_vfi_offline_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1); static uint32_t emlxs_fcfi_event(emlxs_port_t *port, uint32_t evt, void *arg1); static FCFIobj_t *emlxs_fcfi_find(emlxs_port_t *port, FCF_RECORD_t *fcfrec, uint32_t *fcf_index); static FCFIobj_t *emlxs_fcfi_alloc(emlxs_port_t *port); static uint32_t emlxs_fcfi_free(emlxs_port_t *port, FCFIobj_t *fcfp); static void emlxs_fcfi_update(emlxs_port_t *port, FCFIobj_t *fcfp, FCF_RECORD_t *fcf_rec, uint32_t event_tag); static char *emlxs_fcfi_state_xlate(uint32_t state); /* * - Online sequencing can start from FCFI_STATE_OFFLINE state or * the FCFI_STATE_VFI_OFFLINE state. * * - Offline sequencing can interrupt the online sequencing at the * entry of the next wait state. * * NORMAL ONLINE SEQ * --------------------------- * FCFI_ONLINE event <-- FCFTAB * FCFI_STATE_OFFLINE * FCFI_STATE_REG * FCFI_STATE_REG_CMPL * FCFI_STATE_VFI_ONLINE * FCFI_STATE_VFI_ONLINE_CMPL * FCFI_STATE_ONLINE * FCFI_ONLINE event-->FCFTAB * * * NORMAL OFFLINE SEQ * --------------------------- * FCFI_OFFLINE event <-- FCFTAB * FCFI_STATE_ONLINE * FCFI_STATE_VFI_OFFLINE * FCFI_STATE_VFI_OFFLINE_CMPL * FCFI_STATE_UNREG * FCFI_STATE_UNREG_CMPL * FCFI_STATE_OFFLINE * FCFI_OFFLINE event-->FCFTAB * * * NORMAL PAUSE SEQ * --------------------------- * FCFI_PAUSE event <-- FCFTAB * FCFI_STATE_ONLINE * FCFI_STATE_PAUSED * */ /* Order does matter */ static void *emlxs_fcfi_action_table[] = { /* Action routine Event */ /* FCFI_STATE_FREE 0 (Wait for allocation) */ (void *) emlxs_fcfi_free_action, /* STATE_ENTER */ (void *) NULL, /* FCFI_ONLINE */ (void *) NULL, /* FCFI_OFFLINE */ (void *) NULL, /* FCFI_PAUSE */ (void *) NULL, /* VFI_ONLINE */ (void *) NULL, /* VFI_OFFLINE */ /* FCFI_STATE_OFFLINE 1 (Wait for FCFI_ONLINE event) */ (void *) emlxs_fcfi_offline_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_UNREG_CMPL 2 (Transitional) */ (void *) emlxs_fcfi_unreg_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_UNREG_FAILED 3 (Transitional) */ (void *) emlxs_fcfi_unreg_failed_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_UNREG 4 (Wait for unreg_fcfi cmpl) */ (void *) emlxs_fcfi_unreg_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_REG 5 (Wait for reg_fcfi cmpl) */ (void *) emlxs_fcfi_reg_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_REG_FAILED 6 (Transitional) */ (void *) emlxs_fcfi_reg_failed_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_REG_CMPL 7 (Transitional) */ (void *) emlxs_fcfi_reg_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_VFI_OFFLINE_CMPL 8 (Transitional) */ (void *) emlxs_fcfi_vfi_offline_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_VFI_OFFLINE 9 (Wait for VFI_OFFLINE event) */ (void *) emlxs_fcfi_vfi_offline_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE * */ /* FCFI_STATE_VFI_ONLINE 10 (Wait for VFI_ONLINE event) */ (void *) emlxs_fcfi_vfi_online_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_VFI_ONLINE_CMPL 11 (Transitional) */ (void *) emlxs_fcfi_vfi_online_cmpl_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_PAUSED 12 (Wait for FCFI_ONLINE event) */ (void *) emlxs_fcfi_paused_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ /* FCFI_STATE_ONLINE 13 (Wait for FCFI_OFFLINE event) */ (void *) emlxs_fcfi_online_action, /* STATE_ENTER */ (void *) emlxs_fcfi_online_evt_action, /* FCFI_ONLINE */ (void *) emlxs_fcfi_offline_evt_action, /* FCFI_OFFLINE */ (void *) emlxs_fcfi_pause_evt_action, /* FCFI_PAUSE */ (void *) emlxs_fcfi_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_fcfi_vfi_offline_evt_action, /* VFI_OFFLINE */ }; /* emlxs_fcfi_action_table[] */ #define FCFI_ACTION_EVENTS 6 #define FCFI_ACTION_STATES \ (sizeof (emlxs_fcfi_action_table)/ \ (FCFI_ACTION_EVENTS * sizeof (void *))) /* ********************************************************************** */ /* VFI */ /* ********************************************************************** */ /* Order does not matter */ emlxs_table_t emlxs_vfi_state_table[] = { {VFI_STATE_OFFLINE, "VFI_OFFLINE"}, {VFI_STATE_INIT, "VFI_INIT"}, {VFI_STATE_INIT_FAILED, "VFI_INIT_FAILED"}, {VFI_STATE_INIT_CMPL, "VFI_INIT_CMPL"}, {VFI_STATE_VPI_OFFLINE_CMPL, "VFI_VPI_OFFLINE_CMPL"}, {VFI_STATE_VPI_OFFLINE, "VFI_VPI_OFFLINE"}, {VFI_STATE_VPI_ONLINE, "VFI_VPI_ONLINE"}, {VFI_STATE_VPI_ONLINE_CMPL, "VFI_VPI_ONLINE_CMPL"}, {VFI_STATE_UNREG_CMPL, "VFI_UNREG_CMPL"}, {VFI_STATE_UNREG_FAILED, "VFI_UNREG_FAILED"}, {VFI_STATE_UNREG, "VFI_UNREG"}, {VFI_STATE_REG, "VFI_REG"}, {VFI_STATE_REG_FAILED, "VFI_REG_FAILED"}, {VFI_STATE_REG_CMPL, "VFI_REG_CMPL"}, {VFI_STATE_PAUSED, "VFI_PAUSED"}, {VFI_STATE_ONLINE, "VFI_ONLINE"}, }; /* emlxs_vfi_state_table */ static uint32_t emlxs_vfi_pause_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_online_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_offline_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_init_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_init_failed_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_init_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_offline_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_online_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_paused_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_vpi_online_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_vpi_online_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_vpi_offline_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_vpi_offline_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_reg_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_reg_failed_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_reg_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_unreg_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_unreg_failed_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_unreg_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_vpi_online_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_vpi_offline_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1); static uint32_t emlxs_vfi_event(emlxs_port_t *port, uint32_t evt, void *arg1); /* * - Online sequencing can start from VFI_STATE_OFFLINE state or * the VFI_STATE_VPI_OFFLINE state. * * - Offline sequencing can interrupt the online sequencing at the * entry of the next wait state. * * NORMAL ONLINE SEQ * --------------------------- * VFI_ONLINE event <-- FCFI * VFI_STATE_OFFLINE * VFI_STATE_INIT * VFI_STATE_INIT_CMPL * VFI_STATE_VPI_ONLINE * VFI_STATE_VPI_ONLINE_CMPL * VFI_STATE_REG * VFI_STATE_REG_CMPL * VFI_STATE_ONLINE * VFI_ONLINE event-->FCFI * * * NORMAL OFFLINE SEQ * --------------------------- * VFI_OFFLINE event <-- FCFI * VFI_STATE_ONLINE * VFI_STATE_VPI_OFFLINE * VFI_STATE_VPI_OFFLINE_CMPL * VFI_STATE_UNREG * VFI_STATE_UNREG_CMPL * VFI_STATE_OFFLINE * VFI_OFFLINE event-->FCFI * * * NORMAL PAUSE SEQ * --------------------------- * VFI_PAUSE event <-- FCFI * VFI_STATE_ONLINE * VFI_STATE_PAUSED * */ /* Order does matter */ static void *emlxs_vfi_action_table[] = { /* Action routine Event */ /* VFI_STATE_OFFLINE 0 (Wait for VFI_ONLINE event) */ (void *) emlxs_vfi_offline_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_INIT 1 (Wait for init_vfi cmpl) */ (void *) emlxs_vfi_init_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_INIT_FAILED 2 (Transitional) */ (void *) emlxs_vfi_init_failed_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_INIT_CMPL 3 (Transitional) */ (void *) emlxs_vfi_init_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_VPI_OFFLINE_CMPL 4 (Wait for VPI_OFFLINE event) */ (void *) emlxs_vfi_vpi_offline_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_VPI_OFFLINE 5 (Wait for VPI_OFFLINE event) */ (void *) emlxs_vfi_vpi_offline_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_VPI_ONLINE 6 (Wait for VPI_ONLINE event) */ (void *) emlxs_vfi_vpi_online_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_VPI_ONLINE_CMPL 7 (Transitional) */ (void *) emlxs_vfi_vpi_online_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_UNREG_CMPL 8 (Transitional) */ (void *) emlxs_vfi_unreg_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_UNREG_FAILED 9 (Transitional) */ (void *) emlxs_vfi_unreg_failed_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_UNREG 10 (Wait for unreg_vfi cmpl) */ (void *) emlxs_vfi_unreg_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_REG 11 (Wait for reg_vfi cmpl) */ (void *) emlxs_vfi_reg_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_REG_FAILED 12 (Transitional) */ (void *) emlxs_vfi_reg_failed_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_REG_CMPL 13 (Transitional) */ (void *) emlxs_vfi_reg_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_PAUSED 14 (Wait for VFI_OFFLINE event) */ (void *) emlxs_vfi_paused_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ /* VFI_STATE_ONLINE 14 (Wait for VFI_OFFLINE event) */ (void *) emlxs_vfi_online_action, /* STATE_ENTER */ (void *) emlxs_vfi_online_evt_action, /* VFI_ONLINE */ (void *) emlxs_vfi_offline_evt_action, /* VFI_OFFLINE */ (void *) emlxs_vfi_pause_evt_action, /* VFI_PAUSE */ (void *) emlxs_vfi_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vfi_vpi_offline_evt_action, /* VPI_OFFLINE */ }; /* emlxs_vfi_action_table[] */ #define VFI_ACTION_EVENTS 6 #define VFI_ACTION_STATES \ (sizeof (emlxs_vfi_action_table)/ \ (VFI_ACTION_EVENTS * sizeof (void *))) /* ********************************************************************** */ /* VPI */ /* ********************************************************************** */ /* Order does not matter */ emlxs_table_t emlxs_vpi_state_table[] = { {VPI_STATE_OFFLINE, "VPI_OFFLINE"}, {VPI_STATE_INIT, "VPI_INIT"}, {VPI_STATE_INIT_FAILED, "VPI_INIT_FAILED"}, {VPI_STATE_INIT_CMPL, "VPI_INIT_CMPL"}, {VPI_STATE_UNREG_CMPL, "VPI_UNREG_CMPL"}, {VPI_STATE_UNREG_FAILED, "VPI_UNREG_FAILED"}, {VPI_STATE_UNREG, "VPI_UNREG"}, {VPI_STATE_LOGO_CMPL, "VPI_LOGO_CMPL"}, {VPI_STATE_LOGO_FAILED, "VPI_LOGO_FAILED"}, {VPI_STATE_LOGO, "VPI_LOGO"}, {VPI_STATE_PORT_OFFLINE, "VPI_PORT_OFFLINE"}, {VPI_STATE_PORT_ONLINE, "VPI_PORT_ONLINE"}, {VPI_STATE_LOGI, "VPI_LOGI"}, {VPI_STATE_LOGI_FAILED, "VPI_LOGI_FAILED"}, {VPI_STATE_LOGI_CMPL, "VPI_LOGI_CMPL"}, {VPI_STATE_REG, "VPI_REG"}, {VPI_STATE_REG_FAILED, "VPI_REG_FAILED"}, {VPI_STATE_REG_CMPL, "VPI_REG_CMPL"}, {VPI_STATE_PAUSED, "VPI_PAUSED"}, {VPI_STATE_ONLINE, "VPI_ONLINE"}, }; /* emlxs_vpi_state_table */ static uint32_t emlxs_vpi_online_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_offline_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_pause_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_rpi_online_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_rpi_offline_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_rpi_pause_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_init_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_init_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_init_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_offline_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_online_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_paused_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_port_online_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_port_offline_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_logi_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_logi_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_logi_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_reg_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_reg_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_reg_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_unreg_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_unreg_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_unreg_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_logo_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_logo_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_logo_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_event(emlxs_port_t *port, uint32_t evt, void *arg1); static uint32_t emlxs_vpi_logi_cmpl_notify(emlxs_port_t *port, RPIobj_t *rpip); static void emlxs_vpi_logo_handler(emlxs_port_t *port, VPIobj_t *vpip); /* * - Online sequencing can only start from VPI_STATE_OFFLINE or * VPI_STATE_PORT_OFFLINE state. * * - Offline sequencing can interrupt the online sequencing at the * entry of the next wait state. * * NORMAL ONLINE SEQ * --------------------------- * VPI_ONLINE event <-- VFI * VPI_STATE_OFFLINE * VPI_STATE_INIT * VPI_STATE_INIT_CMPL * VPI_STATE_PORT_ONLINE * VPI_STATE_LOGI * VPI_STATE_LOGI_CMPL * VPI_STATE_REG * VPI_STATE_REG_CMPL * VPI_STATE_ONLINE * VPI_ONLINE event-->VFI * * * NORMAL OFFLINE SEQ * --------------------------- * VPI_OFFLINE event <-- VFI * VPI_STATE_ONLINE * VPI_STATE_PORT_OFFLINE * VPI_STATE_LOGO * VPI_STATE_LOGO_CMPL * VPI_STATE_UNREG * VPI_STATE_UNREG_CMPL * VPI_STATE_OFFLINE * VPI_OFFLINE event-->VFI * * * NORMAL PAUSE SEQ * --------------------------- * VPI_PAUSE event <-- VFI * VPI_STATE_ONLINE * VPI_STATE_PORT_OFFLINE * VPI_STATE_PAUSED * */ /* Order does matter */ static void *emlxs_vpi_action_table[] = { /* Action routine Event */ /* VPI_STATE_OFFLINE 0 (Wait for VPI_ONLINE event) */ (void *) emlxs_vpi_offline_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_INIT 1 (Wait for init_vpi cmpl) */ (void *) emlxs_vpi_init_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_INIT_FAILED 2 (Transitional) */ (void *) emlxs_vpi_init_failed_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_INIT_CMPL 3 (Transitional) */ (void *) emlxs_vpi_init_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_UNREG_CMPL 4 (Transitional) */ (void *) emlxs_vpi_unreg_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_UNREG_FAILED 5 (Transitional) */ (void *) emlxs_vpi_unreg_failed_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_UNREG 6 (Wait for unreg_vpi cmpl) */ (void *) emlxs_vpi_unreg_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_LOGO_CMPL 7 (Transitional) */ (void *) emlxs_vpi_logo_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_LOGO_FAILED 8 (Transitional) */ (void *) emlxs_vpi_logo_failed_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_LOGO 9 (Transitional) */ (void *) emlxs_vpi_logo_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_PORT_OFFLINE 10 (Wait for RPI_OFFLINE or VPI_ONLINE) */ (void *) emlxs_vpi_port_offline_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_PORT_ONLINE 11 (Wait for emlxs_vpi_logi_notify() ) */ (void *) emlxs_vpi_port_online_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_LOGI 12 (Wait for emlxs_vpi_logi_cmpl_notify() ) */ (void *) emlxs_vpi_logi_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_LOGI_FAILED 13 (Transitional) */ (void *) emlxs_vpi_logi_failed_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_LOGI_CMPL 14 (Transitional) */ (void *) emlxs_vpi_logi_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_REG 15 (Wait for reg_vpi cmpl) */ (void *) emlxs_vpi_reg_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_REG_FAILED 16 (Transitional) */ (void *) emlxs_vpi_reg_failed_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_REG_CMPL 17 (Transitional) */ (void *) emlxs_vpi_reg_cmpl_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_PAUSED 18 (Wait for VPI_ONLINE() ) */ (void *) emlxs_vpi_paused_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ /* VPI_STATE_ONLINE 19 (Wait for VPI_OFFLINE event) */ (void *) emlxs_vpi_online_action, /* STATE_ENTER */ (void *) emlxs_vpi_online_evt_action, /* VPI_ONLINE */ (void *) emlxs_vpi_offline_evt_action, /* VPI_OFFLINE */ (void *) emlxs_vpi_pause_evt_action, /* VPI_PAUSE */ (void *) emlxs_vpi_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_vpi_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_vpi_rpi_pause_evt_action, /* RPI_PAUSE */ }; /* emlxs_vpi_action_table() */ #define VPI_ACTION_EVENTS 7 #define VPI_ACTION_STATES \ (sizeof (emlxs_vpi_action_table)/ \ (VPI_ACTION_EVENTS * sizeof (void *))) /* ********************************************************************** */ /* RPI */ /* ********************************************************************** */ /* Order does not matter */ emlxs_table_t emlxs_rpi_state_table[] = { {RPI_STATE_FREE, "RPI_FREE"}, {RPI_STATE_RESERVED, "RPI_RESERVED"}, {RPI_STATE_OFFLINE, "RPI_OFFLINE"}, {RPI_STATE_UNREG_CMPL, "RPI_UNREG_CMPL"}, {RPI_STATE_UNREG_FAILED, "RPI_UNREG_FAILED"}, {RPI_STATE_UNREG, "RPI_UNREG"}, {RPI_STATE_REG, "RPI_REG"}, {RPI_STATE_REG_FAILED, "RPI_REG_FAILED"}, {RPI_STATE_REG_CMPL, "RPI_REG_CMPL"}, {RPI_STATE_PAUSED, "RPI_PAUSED"}, {RPI_STATE_RESUME, "RPI_RESUME"}, {RPI_STATE_RESUME_FAILED, "RPI_RESUME_FAILED"}, {RPI_STATE_RESUME_CMPL, "RPI_RESUME_CMPL"}, {RPI_STATE_ONLINE, "RPI_ONLINE"}, }; /* emlxs_rpi_state_table */ static uint32_t emlxs_rpi_free_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_online_evt_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_offline_evt_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_pause_evt_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_resume_evt_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_reg_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_reg_cmpl_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_reg_failed_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_unreg_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_unreg_cmpl_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_unreg_failed_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_online_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_paused_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_offline_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_reserved_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_resume_failed_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_resume_cmpl_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_resume_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1); static uint32_t emlxs_rpi_event(emlxs_port_t *port, uint32_t evt, void *arg1); static RPIobj_t *emlxs_rpi_alloc(emlxs_port_t *port, uint32_t did); static uint32_t emlxs_rpi_free(emlxs_port_t *port, RPIobj_t *rpip); static RPIobj_t *emlxs_rpi_find_did(emlxs_port_t *port, uint32_t did); static void emlxs_rpi_resume_handler(emlxs_port_t *port, RPIobj_t *rpip); static void emlxs_rpi_unreg_handler(emlxs_port_t *port, RPIobj_t *rpip); static uint32_t emlxs_rpi_reg_handler(emlxs_port_t *port, RPIobj_t *rpip); static void emlxs_rpi_idle_timer(emlxs_hba_t *hba); static uint32_t emlxs_rpi_state(emlxs_port_t *port, RPIobj_t *rpip, uint16_t state, uint16_t reason, uint32_t explain, void *arg1); static void emlxs_rpi_alloc_fabric_rpi(emlxs_port_t *port); static void emlxs_rpi_deferred_cmpl(emlxs_port_t *port, RPIobj_t *rpip, uint32_t status); /* * - Online sequencing can start from RPI_STATE_RESERVED state or * the RPI_STATE_PAUSED state. * * - Offline sequencing can interrupt the online sequencing at the * entry of the next wait state. * * NORMAL ONLINE SEQ * --------------------------- * RPI_ONLINE event <-- VPI * RPI_STATE_RESERVED * RPI_STATE_REG * RPI_STATE_REG_CMPL * RPI_STATE_ONLINE * RPI_ONLINE event-->VPI * * * NORMAL OFFLINE SEQ * --------------------------- * RPI_OFFLINE event <-- VPI * RPI_STATE_ONLINE * RPI_STATE_UNREG * RPI_STATE_UNREG_CMPL * RPI_STATE_OFFLINE * RPI_OFFLINE event-->VPI * * * NORMAL PAUSE SEQ * --------------------------- * RPI_PAUSE event <-- VPI * RPI_STATE_ONLINE * RPI_STATE_PAUSED * */ /* Order does matter */ static void *emlxs_rpi_action_table[] = { /* Action routine Event */ /* RPI_STATE_FREE 0 (Wait for allocation) */ (void *) emlxs_rpi_free_action, /* STATE_ENTER */ (void *) NULL, /* RPI_ONLINE */ (void *) NULL, /* RPI_OFFLINE */ (void *) NULL, /* RPI_PAUSE */ (void *) NULL, /* RPI_RESUME */ /* RPI_STATE_RESERVED 1 (Wait for RPI_ONLINE event) */ (void *) emlxs_rpi_reserved_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_OFFLINE 2 (Transitional) */ (void *) emlxs_rpi_offline_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_UNREG_CMPL 3 (Transitional) */ (void *) emlxs_rpi_unreg_cmpl_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_UNREG_FAILED 4 (Transitional) */ (void *) emlxs_rpi_unreg_failed_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_UNREG 5 (Wait for unreg_rpi cmpl) */ (void *) emlxs_rpi_unreg_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_REG 6 (Wait for reg_rpi cmpl) */ (void *) emlxs_rpi_reg_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_REG_FAILED 7 (Transitional) */ (void *) emlxs_rpi_reg_failed_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_REG_CMPL 8 (Transitional) */ (void *) emlxs_rpi_reg_cmpl_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_PAUSED 9 (Wait for RPI_ONLINE) */ (void *) emlxs_rpi_paused_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_RESUME 10 (Wait for resume_rpi mbcmpl) */ (void *) emlxs_rpi_resume_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_RESUME_FAILED 11 (Transitional) */ (void *) emlxs_rpi_resume_failed_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_RESUME_CMPL 12 (Transitional) */ (void *) emlxs_rpi_resume_cmpl_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ /* RPI_STATE_ONLINE 13 (Wait for RPI_OFFLINE event) */ (void *) emlxs_rpi_online_action, /* STATE_ENTER */ (void *) emlxs_rpi_online_evt_action, /* RPI_ONLINE */ (void *) emlxs_rpi_offline_evt_action, /* RPI_OFFLINE */ (void *) emlxs_rpi_pause_evt_action, /* RPI_PAUSE */ (void *) emlxs_rpi_resume_evt_action, /* RPI_RESUME */ }; /* emlxs_rpi_action_table[] */ #define RPI_ACTION_EVENTS 5 #define RPI_ACTION_STATES \ (sizeof (emlxs_rpi_action_table)/ \ (RPI_ACTION_EVENTS * sizeof (void *))) /* ************************************************************************** */ /* FCF Generic */ /* ************************************************************************** */ static void emlxs_fcf_linkdown(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; if (hba->state <= FC_LINK_DOWN) { return; } mutex_enter(&EMLXS_PORT_LOCK); if (hba->state <= FC_LINK_DOWN) { mutex_exit(&EMLXS_PORT_LOCK); return; } HBASTATS.LinkDown++; EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_DOWN); hba->flag &= FC_LINKDOWN_MASK; hba->discovery_timer = 0; hba->linkup_timer = 0; mutex_exit(&EMLXS_PORT_LOCK); emlxs_log_link_event(port); return; } /* emlxs_fcf_linkdown() */ static void emlxs_fcf_linkup(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; emlxs_config_t *cfg = &CFG; if (hba->state >= FC_LINK_UP) { return; } mutex_enter(&EMLXS_PORT_LOCK); if (hba->state >= FC_LINK_UP) { mutex_exit(&EMLXS_PORT_LOCK); return; } /* Check for any mode changes */ emlxs_mode_set(hba); HBASTATS.LinkUp++; EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_UP); hba->discovery_timer = hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current + cfg[CFG_DISC_TIMEOUT].current; mutex_exit(&EMLXS_PORT_LOCK); emlxs_log_link_event(port); return; } /* emlxs_fcf_linkup() */ extern void emlxs_fcf_fini(emlxs_hba_t *hba) { emlxs_port_t *port = &PPORT; emlxs_port_t *vport; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t i; RPIobj_t *rpip; if (!(hba->sli.sli4.flag & EMLXS_SLI4_FCF_INIT)) { return; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_fini: %s flag=%x fcfi_online=%d.", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); if (!(fcftab->flag & EMLXS_FCFTAB_SHUTDOWN)) { (void) emlxs_fcf_shutdown_notify(port, 1); } mutex_enter(&EMLXS_FCF_LOCK); hba->sli.sli4.flag &= ~EMLXS_SLI4_FCF_INIT; /* Free the FCF memory */ kmem_free(fcftab->table, (sizeof (FCFIobj_t) * fcftab->table_count)); fcftab->table = NULL; fcftab->table_count = 0; /* Free the VFI memory */ kmem_free(hba->sli.sli4.VFI_table, (sizeof (VFIobj_t) * hba->sli.sli4.VFICount)); hba->sli.sli4.VFI_table = NULL; hba->sli.sli4.VFICount = 0; /* Free the VPI Fabric RPI's */ for (i = 0; i < MAX_VPORTS; i++) { vport = &VPORT(i); rpip = vport->vpip->fabric_rpip; if (rpip->state == RPI_STATE_FREE) { continue; } (void) emlxs_rpi_free(port, rpip); } /* Free the RPI memory */ rpip = hba->sli.sli4.RPIp; for (i = 0; i < hba->sli.sli4.RPICount; i++, rpip++) { if (rpip->state == RPI_STATE_FREE) { continue; } (void) emlxs_rpi_free(port, rpip); } kmem_free(hba->sli.sli4.RPIp, (sizeof (RPIobj_t) * hba->sli.sli4.RPICount)); hba->sli.sli4.RPIp = NULL; hba->sli.sli4.RPICount = 0; /* Free the mutex */ mutex_exit(&EMLXS_FCF_LOCK); mutex_destroy(&EMLXS_FCF_LOCK); return; } /* emlxs_fcf_fini() */ extern void emlxs_fcf_init(emlxs_hba_t *hba) { emlxs_port_t *port = &PPORT; emlxs_port_t *vport; uint16_t i; FCFIobj_t *fcfp; VPIobj_t *vpip; VFIobj_t *vfip; RPIobj_t *rpip; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; if (hba->sli.sli4.flag & EMLXS_SLI4_FCF_INIT) { return; } mutex_init(&EMLXS_FCF_LOCK, NULL, MUTEX_DRIVER, NULL); mutex_enter(&EMLXS_FCF_LOCK); /* FCFTAB */ bzero(fcftab, sizeof (FCFTable_t)); fcftab->state = FCFTAB_STATE_OFFLINE; /* FCFI */ fcftab->table_count = hba->sli.sli4.FCFICount; fcftab->table = (FCFIobj_t *)kmem_zalloc( (sizeof (FCFIobj_t) * fcftab->table_count), KM_SLEEP); fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { fcfp->index = i; fcfp->FCFI = 0xFFFF; fcfp->state = FCFI_STATE_FREE; } /* VFI */ hba->sli.sli4.VFI_table = (VFIobj_t *)kmem_zalloc( (sizeof (VFIobj_t) * hba->sli.sli4.VFICount), KM_SLEEP); vfip = hba->sli.sli4.VFI_table; for (i = 0; i < hba->sli.sli4.VFICount; i++, vfip++) { vfip->VFI = emlxs_sli4_index_to_vfi(hba, i); vfip->index = i; vfip->state = VFI_STATE_OFFLINE; } /* VPI */ for (i = 0; i < MAX_VPORTS; i++) { vport = &VPORT(i); vpip = &vport->VPIobj; bzero(vpip, sizeof (VPIobj_t)); vpip->index = i; vpip->VPI = emlxs_sli4_index_to_vpi(hba, i); vpip->port = vport; vpip->state = VPI_STATE_OFFLINE; vport->vpip = vpip; /* Init the Fabric RPI's */ rpip = &vpip->fabric_rpi; rpip->state = RPI_STATE_FREE; rpip->index = 0xffff; rpip->RPI = FABRIC_RPI; rpip->did = FABRIC_DID; rpip->vpip = vpip; vpip->fabric_rpip = rpip; } /* RPI */ hba->sli.sli4.RPIp = (RPIobj_t *)kmem_zalloc( (sizeof (RPIobj_t) * hba->sli.sli4.RPICount), KM_SLEEP); rpip = hba->sli.sli4.RPIp; for (i = 0; i < hba->sli.sli4.RPICount; i++, rpip++) { rpip->state = RPI_STATE_FREE; rpip->RPI = emlxs_sli4_index_to_rpi(hba, i); rpip->index = i; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_init: %s flag=%x fcfi=%d vfi=%d vpi=%d rpi=%d.", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->table_count, hba->sli.sli4.VFICount, MAX_VPORTS, hba->sli.sli4.RPICount); hba->sli.sli4.flag |= EMLXS_SLI4_FCF_INIT; mutex_exit(&EMLXS_FCF_LOCK); return; } /* emlxs_fcf_init() */ static char * emlxs_fcf_event_xlate(uint32_t state) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_fcf_event_table) / sizeof (emlxs_table_t); for (i = 0; i < count; i++) { if (state == emlxs_fcf_event_table[i].code) { return (emlxs_fcf_event_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "event=0x%x", state); return (buffer); } /* emlxs_fcf_event_xlate() */ static char * emlxs_fcf_reason_xlate(uint32_t reason) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_fcf_reason_table) / sizeof (emlxs_table_t); for (i = 0; i < count; i++) { if (reason == emlxs_fcf_reason_table[i].code) { return (emlxs_fcf_reason_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "reason=0x%x", reason); return (buffer); } /* emlxs_fcf_reason_xlate() */ extern void emlxs_fcf_timer_notify(emlxs_hba_t *hba) { FCFTable_t *fcftab = &hba->sli.sli4.fcftab; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return; } if (fcftab->table == 0) { return; } mutex_enter(&EMLXS_FCF_LOCK); if (SLI4_FCOE_MODE) { emlxs_fcoe_fcftab_sol_timer(hba); emlxs_fcoe_fcftab_read_timer(hba); emlxs_fcoe_fcftab_offline_timer(hba); } else { emlxs_fc_fcftab_online_timer(hba); } emlxs_rpi_idle_timer(hba); mutex_exit(&EMLXS_FCF_LOCK); return; } /* emlxs_fcf_timer_notify() */ extern uint32_t emlxs_fcf_shutdown_notify(emlxs_port_t *port, uint32_t wait) { emlxs_hba_t *hba = HBA; emlxs_port_t *pport = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; uint32_t i; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (!(pport->flag & EMLXS_PORT_BOUND) || (pport->vpip->flag & EMLXS_VPI_PORT_UNBIND)) { return (1); } if (fcftab->flag & EMLXS_FCFTAB_SHUTDOWN) { return (0); } mutex_enter(&EMLXS_FCF_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_shutdown_notify: %s flag=%x " "fcfi_online=%d. Shutting down FCFTAB. >", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); rval = emlxs_fcftab_event(port, FCF_EVENT_SHUTDOWN, 0); if (wait && (rval == 0)) { /* Wait for shutdown flag */ i = 0; while (!(fcftab->flag & EMLXS_FCFTAB_SHUTDOWN) && (i++ < 120)) { mutex_exit(&EMLXS_FCF_LOCK); BUSYWAIT_MS(1000); mutex_enter(&EMLXS_FCF_LOCK); } if (!(fcftab->flag & EMLXS_FCFTAB_SHUTDOWN)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcf_shutdown_notify: %s flag=%x " "fcfi_online=%d. Shutdown timeout.", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); rval = 1; } } mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_fcf_shutdown_notify() */ extern uint32_t emlxs_fcf_linkup_notify(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; emlxs_port_t *pport = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (!(pport->flag & EMLXS_PORT_BOUND) || (pport->vpip->flag & EMLXS_VPI_PORT_UNBIND)) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_linkup_notify: %s flag=%x " "fcfi_online=%d. FCFTAB Link up. >", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); rval = emlxs_fcftab_event(port, FCF_EVENT_LINKUP, 0); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_fcf_linkup_notify() */ extern uint32_t emlxs_fcf_linkdown_notify(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; emlxs_port_t *pport = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (!(pport->flag & EMLXS_PORT_BOUND) || (pport->vpip->flag & EMLXS_VPI_PORT_UNBIND)) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_linkdown_notify: %s flag=%x " "fcfi_online=%d. FCFTAB Link down. >", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); rval = emlxs_fcftab_event(port, FCF_EVENT_LINKDOWN, 0); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_fcf_linkdown_notify() */ extern uint32_t emlxs_fcf_cvl_notify(emlxs_port_t *port, uint32_t vpi) { emlxs_hba_t *hba = HBA; emlxs_port_t *pport = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (!(pport->flag & EMLXS_PORT_BOUND) || (pport->vpip->flag & EMLXS_VPI_PORT_UNBIND)) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_cvl_notify: %s flag=%x " "fcfi_online=%d. FCFTAB FCF CVL. >", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); rval = emlxs_fcftab_event(port, FCF_EVENT_CVL, (void *)((unsigned long)vpi)); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_fcf_cvl_notify() */ extern uint32_t emlxs_fcf_full_notify(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; emlxs_port_t *pport = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (!(pport->flag & EMLXS_PORT_BOUND) || (pport->vpip->flag & EMLXS_VPI_PORT_UNBIND)) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_full_notify: %s flag=%x " "fcfi_online=%d. FCFTAB FCF full. >", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); rval = emlxs_fcftab_event(port, FCF_EVENT_FCFTAB_FULL, 0); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_fcf_full_notify() */ extern uint32_t emlxs_fcf_found_notify(emlxs_port_t *port, uint32_t fcf_index) { emlxs_hba_t *hba = HBA; emlxs_port_t *pport = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (!(pport->flag & EMLXS_PORT_BOUND) || (pport->vpip->flag & EMLXS_VPI_PORT_UNBIND)) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_found_notify: %s flag=%x " "fcfi_online=%d. FCFTAB FCF found. >", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); rval = emlxs_fcftab_event(port, FCF_EVENT_FCF_FOUND, (void *)((unsigned long)fcf_index)); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_fcf_found_notify() */ extern uint32_t emlxs_fcf_changed_notify(emlxs_port_t *port, uint32_t fcf_index) { emlxs_hba_t *hba = HBA; emlxs_port_t *pport = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (!(pport->flag & EMLXS_PORT_BOUND) || (pport->vpip->flag & EMLXS_VPI_PORT_UNBIND)) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_changes_notify: %s flag=%x " "fcfi_online=%d. FCFTAB FCF changed. >", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); rval = emlxs_fcftab_event(port, FCF_EVENT_FCF_CHANGED, (void *)((unsigned long)fcf_index)); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_fcf_changed_notify() */ extern uint32_t emlxs_fcf_lost_notify(emlxs_port_t *port, uint32_t fcf_index) { emlxs_hba_t *hba = HBA; emlxs_port_t *pport = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (!(pport->flag & EMLXS_PORT_BOUND) || (pport->vpip->flag & EMLXS_VPI_PORT_UNBIND)) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcf_lost_notify: %s flag=%x " "fcfi_online=%d. FCFTAB FCF lost. >", emlxs_fcftab_state_xlate(port, fcftab->state), fcftab->flag, fcftab->fcfi_online); rval = emlxs_fcftab_event(port, FCF_EVENT_FCF_LOST, (void *)((unsigned long)fcf_index)); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_fcf_lost_notify() */ /* ************************************************************************** */ /* FCFTAB Generic */ /* ************************************************************************** */ static char * emlxs_fcftab_state_xlate(emlxs_port_t *port, uint32_t state) { emlxs_hba_t *hba = HBA; if (SLI4_FCOE_MODE) { return (emlxs_fcoe_fcftab_state_xlate(state)); } else { return (emlxs_fc_fcftab_state_xlate(state)); } } /* emlxs_fcftab_state_xlate() */ static uint32_t emlxs_fcftab_event(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; if (SLI4_FCOE_MODE) { return (emlxs_fcoe_fcftab_event(port, evt, arg1)); } else { return (emlxs_fc_fcftab_event(port, evt, arg1)); } } /* emlxs_fcftab_event() */ /*ARGSUSED*/ static uint32_t emlxs_fcftab_shutdown_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; FCFIobj_t *fcfp; uint32_t i; uint32_t online; if (fcftab->state != FCFTAB_STATE_SHUTDOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcftab_shutdown_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcftab_state_xlate(port, fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; if (fcftab->prev_state != FCFTAB_STATE_SHUTDOWN) { /* Offline all FCF's */ online = 0; fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { if (fcfp->state <= FCFI_STATE_OFFLINE) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcftab_shutdown_action:%x fcfi_online=%d. " "Offlining FCFI:%d. >", fcftab->TID, fcftab->fcfi_online, fcfp->fcf_index); (void) emlxs_fcfi_event(port, FCF_EVENT_FCFI_OFFLINE, fcfp); online++; } if (!online) { goto done; } return (0); } /* Check FCF states */ online = 0; fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { if (fcfp->state <= FCFI_STATE_OFFLINE) { continue; } online++; } if (online) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcftab_shutdown_action:%x %s:%s arg=%p. " "fcfi_online=%d,%d <", fcftab->TID, emlxs_fcftab_state_xlate(port, fcftab->state), emlxs_fcf_event_xlate(evt), arg1, online, fcftab->fcfi_online); return (0); } done: /* Free FCF table */ fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { if (fcfp->state == FCFI_STATE_FREE) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcftab_shutdown_action:%x. Freeing FCFI:%d. >", fcftab->TID, fcfp->fcf_index); (void) emlxs_fcfi_free(port, fcfp); } /* Clean the selection table */ bzero(fcftab->fcfi, sizeof (fcftab->fcfi)); fcftab->fcfi_count = 0; fcftab->flag |= EMLXS_FCFTAB_SHUTDOWN; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcftab_shutdown_action:%x %s:%s arg=%p flag=%x fcfi_online=%d. " "Shutdown. <", fcftab->TID, emlxs_fcftab_state_xlate(port, fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag, fcftab->fcfi_online); return (0); } /* emlxs_fcftab_shutdown_action() */ /* ************************************************************************** */ /* FC FCFTAB */ /* ************************************************************************** */ static char * emlxs_fc_fcftab_state_xlate(uint32_t state) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_fc_fcftab_state_table) / sizeof (emlxs_table_t); for (i = 0; i < count; i++) { if (state == emlxs_fc_fcftab_state_table[i].code) { return (emlxs_fc_fcftab_state_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "state=0x%x", state); return (buffer); } /* emlxs_fc_fcftab_state_xlate() */ static uint32_t emlxs_fc_fcftab_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; uint32_t(*func) (emlxs_port_t *, uint32_t, void *); uint32_t index; uint32_t events; uint16_t state; /* Convert event to action table index */ switch (evt) { case FCF_EVENT_STATE_ENTER: index = 0; break; case FCF_EVENT_SHUTDOWN: index = 1; break; case FCF_EVENT_LINKUP: index = 2; break; case FCF_EVENT_LINKDOWN: index = 3; break; case FCF_EVENT_FCFI_ONLINE: index = 4; break; case FCF_EVENT_FCFI_OFFLINE: index = 5; break; default: return (1); } events = FC_FCFTAB_ACTION_EVENTS; state = fcftab->state; index += (state * events); func = (uint32_t(*) (emlxs_port_t *, uint32_t, void *)) emlxs_fc_fcftab_action_table[index]; if (!func) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "fc_fcftab_action:%x %s:%s arg=%p. No action. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } rval = (func)(port, evt, arg1); return (rval); } /* emlxs_fc_fcftab_action() */ static uint32_t emlxs_fc_fcftab_event(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; /* Filter events */ switch (evt) { case FCF_EVENT_SHUTDOWN: case FCF_EVENT_LINKUP: case FCF_EVENT_LINKDOWN: case FCF_EVENT_FCFI_ONLINE: case FCF_EVENT_FCFI_OFFLINE: break; default: return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "fc_fcftab_event:%x %s:%s arg=%p.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fc_fcftab_action(port, evt, arg1); return (rval); } /* emlxs_fc_fcftab_event() */ /* EMLXS_FCF_LOCK must be held to enter */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_state(emlxs_port_t *port, uint16_t state, uint16_t reason, uint32_t explain, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (state >= FC_FCFTAB_ACTION_STATES) { return (1); } if ((fcftab->state == state) && (reason != FCF_REASON_REENTER)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcftab_state:%x %s:%s:0x%x arg=%p. " "State not changed. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(state), emlxs_fcf_reason_xlate(reason), explain, arg1); return (1); } if (!reason) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcftab_state:%x %s-->%s arg=%p", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fc_fcftab_state_xlate(state), arg1); } else if (reason == FCF_REASON_EVENT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcftab_state:%x %s-->%s:%s:%s arg=%p", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fc_fcftab_state_xlate(state), emlxs_fcf_reason_xlate(reason), emlxs_fcf_event_xlate(explain), arg1); } else if (explain) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcftab_state:%x %s-->%s:%s:0x%x arg=%p", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fc_fcftab_state_xlate(state), emlxs_fcf_reason_xlate(reason), explain, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcftab_state:%x %s-->%s:%s arg=%p", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fc_fcftab_state_xlate(state), emlxs_fcf_reason_xlate(reason), arg1); } fcftab->prev_state = fcftab->state; fcftab->prev_reason = fcftab->reason; fcftab->state = state; fcftab->reason = reason; rval = emlxs_fc_fcftab_action(port, FCF_EVENT_STATE_ENTER, arg1); return (rval); } /* emlxs_fc_fcftab_state() */ static void emlxs_fc_fcftab_online_timer(emlxs_hba_t *hba) { emlxs_port_t *port = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; /* Check FCF timer */ if (!fcftab->online_timer || (hba->timer_tics < fcftab->online_timer)) { return; } fcftab->online_timer = 0; switch (fcftab->state) { case FC_FCFTAB_STATE_ONLINE: emlxs_fcf_linkup(port); fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FC_FCFTAB_TOPO_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_online_timer:%x %s gen=%x. Read topology. >", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), fcftab->generation); (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO, FCF_REASON_EVENT, 0, 0); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_online_timer:%x %s", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state)); break; } return; } /* emlxs_fc_fcftab_online_timer() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_offline_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FC_FCFTAB_STATE_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_offline_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } fcftab->flag &= ~EMLXS_FC_FCFTAB_OFFLINE_REQ; if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_offline_action:%x %s:%s arg=%p flag=%x. " "Handling request.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); rval = emlxs_fc_fcftab_req_handler(port, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_offline_action:%x %s:%s arg=%p fcfi_online=%d. " "Offline. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->fcfi_online); return (0); } /* emlxs_fc_fcftab_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_online_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; emlxs_port_t *pport = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FC_FCFTAB_STATE_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_online_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_online_action:%x flag=%x. " "Handling requested.", fcftab->TID, fcftab->flag); rval = emlxs_fc_fcftab_req_handler(port, arg1); return (rval); } if (fcftab->fcfi_online == 0) { if (!(pport->flag & EMLXS_PORT_BOUND) || (pport->vpip->flag & EMLXS_VPI_PORT_UNBIND)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_online_action:%x %s:%s " "fcfi_online=0. Pport not bound. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt)); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_online_action:%x %s:%s " "fcfi_online=0. Starting online timer. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt)); /* Start the online timer */ fcftab->online_timer = hba->timer_tics + 1; } emlxs_fcf_linkdown(port); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_online_action:%x flag=%x fcfi_online=%d. " "Online. <", fcftab->TID, fcftab->flag, fcftab->fcfi_online); emlxs_fcf_linkup(port); return (0); } /* emlxs_fc_fcftab_online_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_topo_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOX4 *mb4 = (MAILBOX4 *)mbq; MATCHMAP *mp; uint8_t *alpa_map; uint32_t j; uint16_t TID; mutex_enter(&EMLXS_FCF_LOCK); TID = (uint16_t)((unsigned long)mbq->context); if (fcftab->state != FC_FCFTAB_STATE_TOPO) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_topo_mbcmpl:%x state=%s.", TID, emlxs_fc_fcftab_state_xlate(fcftab->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (TID != fcftab->generation) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_topo_mbcmpl:%x %s. " "Incorrect generation %x. Dropping.", TID, emlxs_fc_fcftab_state_xlate(fcftab->state), fcftab->generation); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_topo_mbcmpl:%x failed. %s. >", fcftab->TID, emlxs_mb_xlate_status(mb4->mbxStatus)); if (mb4->mbxStatus == MBXERR_NO_RESOURCES) { (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO_FAILED, FCF_REASON_MBOX_BUSY, mb4->mbxStatus, 0); } else { (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); } mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->un.varReadLA.attType == AT_LINK_DOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_topo_mbcmpl:%x Linkdown attention. " "Offline requested.", fcftab->TID); fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FC_FCFTAB_OFFLINE_REQ; (void) emlxs_fc_fcftab_req_handler(port, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (hba->link_event_tag != mb4->un.varReadLA.eventTag) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_topo_mbcmpl:%x Event tag invalid. %x != %x", fcftab->TID, hba->link_event_tag, mb4->un.varReadLA.eventTag); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_topo_mbcmpl:%x state=%s type=%s iotag=%d " "alpa=%x. >", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), (mb4->un.varReadLA.attType == AT_LINK_UP)?"linkup":"linkdown", hba->link_event_tag, (uint32_t)mb4->un.varReadLA.granted_AL_PA); /* Link is up */ /* Save the linkspeed & topology */ hba->linkspeed = mb4->un.varReadLA.UlnkSpeed; hba->topology = mb4->un.varReadLA.topology; if (hba->topology != TOPOLOGY_LOOP) { port->did = 0; port->lip_type = 0; hba->flag &= ~FC_BYPASSED_MODE; bzero((caddr_t)port->alpa_map, 128); goto done; } /* TOPOLOGY_LOOP */ port->lip_type = mb4->un.varReadLA.lipType; if (mb4->un.varReadLA.pb) { hba->flag |= FC_BYPASSED_MODE; } else { hba->flag &= ~FC_BYPASSED_MODE; } /* Save the granted_alpa and alpa_map */ port->granted_alpa = mb4->un.varReadLA.granted_AL_PA; mp = (MATCHMAP *)mbq->bp; alpa_map = (uint8_t *)port->alpa_map; bcopy((caddr_t)mp->virt, (caddr_t)alpa_map, 128); /* Check number of devices in map */ if (alpa_map[0] > 127) { alpa_map[0] = 127; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_atten_msg, "alpa_map: %d device(s): " "%02x %02x %02x %02x %02x %02x %02x %02x", alpa_map[0], alpa_map[1], alpa_map[2], alpa_map[3], alpa_map[4], alpa_map[5], alpa_map[6], alpa_map[7], alpa_map[8]); for (j = 9; j <= alpa_map[0]; j += 8) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_atten_msg, "alpa_map: " "%02x %02x %02x %02x %02x %02x %02x %02x", alpa_map[j], alpa_map[j + 1], alpa_map[j + 2], alpa_map[j + 3], alpa_map[j + 4], alpa_map[j + 5], alpa_map[j + 6], alpa_map[j + 7]); } done: (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_fc_fcftab_topo_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_topo_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOXQ *mbq; MAILBOX4 *mb4; uint32_t rval = 0; MATCHMAP *mp; if (fcftab->state != FC_FCFTAB_STATE_TOPO) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_topo_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if ((fcftab->prev_state != FC_FCFTAB_STATE_TOPO_FAILED) || (fcftab->flag & EMLXS_FC_FCFTAB_TOPO_REQ)) { fcftab->flag &= ~EMLXS_FC_FCFTAB_TOPO_REQ; fcftab->attempts = 0; } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sol_action:%x %s:%s arg=%p gen=%d flag=%x. " "Handling request.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, fcftab->flag); rval = emlxs_fc_fcftab_req_handler(port, arg1); return (rval); } if (fcftab->attempts == 0) { fcftab->TID = fcftab->generation; } if (hba->topology != TOPOLOGY_LOOP) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sol_action:%x %s:%s arg=%p gen=%d flag=%x. " "Fabric Topology. Skipping READ_TOPO.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, fcftab->flag); port->did = 0; port->lip_type = 0; hba->flag &= ~FC_BYPASSED_MODE; bzero((caddr_t)port->alpa_map, 128); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK, FCF_REASON_EVENT, evt, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sol_action:%x %s:%s arg=%p gen=%d flag=%x. " "Sending READ_TOPO. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, fcftab->flag); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF)) == 0) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO_FAILED, FCF_REASON_NO_BUFFER, 0, arg1); return (rval); } bzero(mp->virt, mp->size); mbq->nonembed = NULL; mbq->bp = (void *)mp; mbq->mbox_cmpl = emlxs_fc_fcftab_topo_mbcmpl; mbq->context = (void *)((unsigned long)fcftab->TID); mbq->port = (void *)port; mb4->un.varSLIConfig.be.embedded = 0; mb4->mbxCommand = MBX_READ_TOPOLOGY; mb4->mbxOwner = OWN_HOST; mb4->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128; mb4->un.varReadLA.un.lilpBde64.addrHigh = PADDR_HI(mp->phys); mb4->un.varReadLA.un.lilpBde64.addrLow = PADDR_LO(mp->phys); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_BUF, (void *)mp); emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_fc_fcftab_topo_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_topo_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; fcftab->attempts++; if (fcftab->state != FC_FCFTAB_STATE_TOPO_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_topo_failed_action:%x %s:%s arg=%p " "attempt=%d. Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts); return (1); } if ((fcftab->reason == FCF_REASON_MBOX_FAILED) || (fcftab->reason == FCF_REASON_SEND_FAILED) || (fcftab->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_topo_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Giving up.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO_CMPL, FCF_REASON_OP_FAILED, fcftab->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_topo_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Retrying.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO, FCF_REASON_OP_FAILED, fcftab->attempts, arg1); } return (rval); } /* emlxs_fc_fcftab_topo_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_topo_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FC_FCFTAB_STATE_TOPO_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_topo_cmpl_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_topo_cmpl_action:%x attempts=%d. " "Config link.", fcftab->TID, fcftab->attempts); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fc_fcftab_topo_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_cfglink_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOX4 *mb4 = (MAILBOX4 *)mbq; uint16_t TID; mutex_enter(&EMLXS_FCF_LOCK); TID = (uint16_t)((unsigned long)mbq->context); if (fcftab->state != FC_FCFTAB_STATE_CFGLINK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_cfglink_mbcmpl:%x state=%s.", TID, emlxs_fc_fcftab_state_xlate(fcftab->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (TID != fcftab->generation) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_cfglink_mbcmpl:%x %s. " "Incorrect generation %x. Dropping.", TID, emlxs_fc_fcftab_state_xlate(fcftab->state), fcftab->generation); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_cfglink_mbcmpl:%x failed. %s. >", fcftab->TID, emlxs_mb_xlate_status(mb4->mbxStatus)); if (mb4->mbxStatus == MBXERR_NO_RESOURCES) { (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK_FAILED, FCF_REASON_MBOX_BUSY, mb4->mbxStatus, 0); } else { (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); } mutex_exit(&EMLXS_FCF_LOCK); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg, "fc_fcftab_cfglink_mbcmpl:%x. >", fcftab->TID); (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_fc_fcftab_cfglink_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_cfglink_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; emlxs_config_t *cfg = &CFG; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOXQ *mbq; MAILBOX4 *mb4; uint32_t rval = 0; if (fcftab->state != FC_FCFTAB_STATE_CFGLINK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_cfglink_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if ((fcftab->prev_state != FC_FCFTAB_STATE_CFGLINK_FAILED) || (fcftab->flag & EMLXS_FC_FCFTAB_CFGLINK_REQ)) { fcftab->flag &= ~EMLXS_FC_FCFTAB_CFGLINK_REQ; fcftab->attempts = 0; } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sol_action:%x %s:%s arg=%p gen=%d flag=%x. " "Handling request.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, fcftab->flag); rval = emlxs_fc_fcftab_req_handler(port, arg1); return (rval); } if (fcftab->attempts == 0) { fcftab->TID = fcftab->generation; } if (hba->topology != TOPOLOGY_LOOP) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sol_action:%x %s:%s arg=%p gen=%d flag=%x. " "Fabric Topology. Skipping CONFIG_LINK.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, fcftab->flag); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM, FCF_REASON_EVENT, evt, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sol_action:%x %s:%s arg=%p gen=%d flag=%x. " "Sending CONFIG_LINK. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, fcftab->flag); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_fc_fcftab_cfglink_mbcmpl; mbq->context = (void *)((unsigned long)fcftab->TID); mbq->port = (void *)port; mb4->un.varSLIConfig.be.embedded = 0; mb4->mbxCommand = MBX_CONFIG_LINK; mb4->mbxOwner = OWN_HOST; if (cfg[CFG_CR_DELAY].current) { mb4->un.varCfgLnk.cr = 1; mb4->un.varCfgLnk.ci = 1; mb4->un.varCfgLnk.cr_delay = cfg[CFG_CR_DELAY].current; mb4->un.varCfgLnk.cr_count = cfg[CFG_CR_COUNT].current; } if (cfg[CFG_ACK0].current) { mb4->un.varCfgLnk.ack0_enable = 1; } mb4->un.varCfgLnk.myId = port->did; mb4->un.varCfgLnk.edtov = hba->fc_edtov; mb4->un.varCfgLnk.arbtov = hba->fc_arbtov; mb4->un.varCfgLnk.ratov = hba->fc_ratov; mb4->un.varCfgLnk.rttov = hba->fc_rttov; mb4->un.varCfgLnk.altov = hba->fc_altov; mb4->un.varCfgLnk.crtov = hba->fc_crtov; rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_fc_fcftab_cfglink_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_cfglink_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; fcftab->attempts++; if (fcftab->state != FC_FCFTAB_STATE_CFGLINK_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_cfglink_failed_action:%x %s:%s arg=%p " "attempt=%d. Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts); return (1); } if ((fcftab->reason == FCF_REASON_MBOX_FAILED) || (fcftab->reason == FCF_REASON_SEND_FAILED) || (fcftab->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_cfglink_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Giving up.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK_CMPL, FCF_REASON_OP_FAILED, fcftab->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_cfglink_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Retrying.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK, FCF_REASON_OP_FAILED, fcftab->attempts, arg1); } return (rval); } /* emlxs_fc_fcftab_cfglink_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_cfglink_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FC_FCFTAB_STATE_CFGLINK_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_cfglink_cmpl_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_cfglink_cmpl_action:%x attempts=%d. " "Read SPARM.", fcftab->TID, fcftab->attempts); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fc_fcftab_cfglink_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_sparm_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOX4 *mb4 = (MAILBOX4 *)mbq; MATCHMAP *mp; emlxs_port_t *vport; VPIobj_t *vpip; int32_t i; uint8_t null_wwn[8]; uint16_t TID; mutex_enter(&EMLXS_FCF_LOCK); TID = (uint16_t)((unsigned long)mbq->context); if (fcftab->state != FC_FCFTAB_STATE_SPARM) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sparm_mbcmpl:%x state=%s.", TID, emlxs_fc_fcftab_state_xlate(fcftab->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (TID != fcftab->generation) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sparm_mbcmpl:%x %s. " "Incorrect generation %x. Dropping.", TID, emlxs_fc_fcftab_state_xlate(fcftab->state), fcftab->generation); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sparm_mbcmpl:%x failed. %s. >", fcftab->TID, emlxs_mb_xlate_status(mb4->mbxStatus)); if (mb4->mbxStatus == MBXERR_NO_RESOURCES) { (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM_FAILED, FCF_REASON_MBOX_BUSY, mb4->mbxStatus, 0); } else { (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); } mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* Save the parameters */ mp = (MATCHMAP *)mbq->bp; bcopy((caddr_t)mp->virt, (caddr_t)&hba->sparam, sizeof (SERV_PARM)); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg, "fc_fcftab_sparm_mbcmpl:%x edtov=%x,%x bbc=%x. >", fcftab->TID, hba->fc_edtov, hba->sparam.cmn.e_d_tov, hba->sparam.cmn.bbCreditlsb); /* Initialize the node name and port name only once */ bzero(null_wwn, 8); if ((bcmp((caddr_t)&hba->wwnn, (caddr_t)null_wwn, 8) == 0) && (bcmp((caddr_t)&hba->wwpn, (caddr_t)null_wwn, 8) == 0)) { bcopy((caddr_t)&hba->sparam.nodeName, (caddr_t)&hba->wwnn, sizeof (NAME_TYPE)); bcopy((caddr_t)&hba->sparam.portName, (caddr_t)&hba->wwpn, sizeof (NAME_TYPE)); } else { bcopy((caddr_t)&hba->wwnn, (caddr_t)&hba->sparam.nodeName, sizeof (NAME_TYPE)); bcopy((caddr_t)&hba->wwpn, (caddr_t)&hba->sparam.portName, sizeof (NAME_TYPE)); } /* Update all bound ports */ for (i = 0; i < MAX_VPORTS; i++) { vport = &VPORT(i); vpip = vport->vpip; if (!(vport->flag & EMLXS_PORT_BOUND) || (vpip->flag & EMLXS_VPI_PORT_UNBIND)) { continue; } bcopy((caddr_t)&hba->sparam, (caddr_t)&vport->sparam, sizeof (SERV_PARM)); bcopy((caddr_t)&vport->wwnn, (caddr_t)&vport->sparam.nodeName, sizeof (NAME_TYPE)); bcopy((caddr_t)&vport->wwpn, (caddr_t)&vport->sparam.portName, sizeof (NAME_TYPE)); } (void) emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_fc_fcftab_sparm_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_sparm_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOXQ *mbq; MAILBOX4 *mb4; uint32_t rval = 0; MATCHMAP *mp; if (fcftab->state != FC_FCFTAB_STATE_SPARM) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_sparm_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if ((fcftab->prev_state != FC_FCFTAB_STATE_SPARM_FAILED) || (fcftab->flag & EMLXS_FC_FCFTAB_SPARM_REQ)) { fcftab->flag &= ~EMLXS_FC_FCFTAB_SPARM_REQ; fcftab->attempts = 0; } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_read_action:%x %s:%s arg=%p flag=%x. " "Handling request.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); rval = emlxs_fc_fcftab_req_handler(port, arg1); return (rval); } if (fcftab->attempts == 0) { fcftab->TID = fcftab->generation; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_read_action:%x %s:%s arg=%p attempts=%d. " "Reading SPARM. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF)) == 0) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM_FAILED, FCF_REASON_NO_BUFFER, 0, arg1); return (rval); } bzero(mp->virt, mp->size); mbq->nonembed = NULL; mbq->bp = (void *)mp; mbq->mbox_cmpl = emlxs_fc_fcftab_sparm_mbcmpl; mbq->context = (void *)((unsigned long)fcftab->TID); mbq->port = (void *)port; mb4->un.varSLIConfig.be.embedded = 0; mb4->mbxCommand = MBX_READ_SPARM64; mb4->mbxOwner = OWN_HOST; mb4->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (SERV_PARM); mb4->un.varRdSparm.un.sp64.addrHigh = PADDR_HI(mp->phys); mb4->un.varRdSparm.un.sp64.addrLow = PADDR_LO(mp->phys); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_BUF, (void *)mp); emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_fc_fcftab_sparm_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_sparm_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; fcftab->attempts++; if (fcftab->state != FC_FCFTAB_STATE_SPARM_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_sparm_failed_action:%x %s:%s arg=%p " "attempt=%d. Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts); return (1); } if ((fcftab->reason == FCF_REASON_MBOX_FAILED) || (fcftab->reason == FCF_REASON_SEND_FAILED) || (fcftab->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_read_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Giving up.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM_CMPL, FCF_REASON_OP_FAILED, fcftab->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_read_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Retrying.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM, FCF_REASON_OP_FAILED, fcftab->attempts, arg1); } return (rval); } /* emlxs_fc_fcftab_sparm_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_sparm_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FC_FCFTAB_STATE_SPARM_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_sparm_cmpl_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_sparm_cmpl_action:%x attempts=%d. " "Bring FCFTAB online.", fcftab->TID, fcftab->attempts); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_FCFI_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fc_fcftab_sparm_cmpl_action() */ /*ARGSUSED*/ static void emlxs_fc_fcftab_process(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; FCFIobj_t *fcfp; FCF_RECORD_t fcf_record; FCF_RECORD_t *fcf_rec; uint8_t bitmap[512]; uint16_t i; /* Get the FCFI */ fcfp = fcftab->fcfi[0]; if (!fcfp) { /* Allocate an fcfi */ fcfp = emlxs_fcfi_alloc(port); } if (!fcfp) { fcftab->fcfi_count = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_process:%x No FCF available.", fcftab->TID); return; } if (fcfp->flag & EMLXS_FCFI_SELECTED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_process:%x fcfi=%d %s. " "FCF still selected.", fcftab->TID, fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state)); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_process:%x fcfi=%d %s. " "New FCF selected.", fcftab->TID, fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state)); } /* Initalize an fcf_rec */ fcf_rec = &fcf_record; bzero(fcf_rec, sizeof (FCF_RECORD_t)); fcf_rec->max_recv_size = EMLXS_FCOE_MAX_RCV_SZ; fcf_rec->fka_adv_period = 0; fcf_rec->fip_priority = 128; #ifdef EMLXS_BIG_ENDIAN fcf_rec->fcf_mac_address_hi[0] = FCOE_FCF_MAC3; fcf_rec->fcf_mac_address_hi[1] = FCOE_FCF_MAC2; fcf_rec->fcf_mac_address_hi[2] = FCOE_FCF_MAC1; fcf_rec->fcf_mac_address_hi[3] = FCOE_FCF_MAC0; fcf_rec->fcf_mac_address_low[0] = FCOE_FCF_MAC5; fcf_rec->fcf_mac_address_low[1] = FCOE_FCF_MAC4; fcf_rec->fc_map[0] = hba->sli.sli4.cfgFCOE.FCMap[2]; fcf_rec->fc_map[1] = hba->sli.sli4.cfgFCOE.FCMap[1]; fcf_rec->fc_map[2] = hba->sli.sli4.cfgFCOE.FCMap[0]; #endif /* EMLXS_BIG_ENDIAN */ #ifdef EMLXS_LITTLE_ENDIAN fcf_rec->fcf_mac_address_hi[0] = FCOE_FCF_MAC0; fcf_rec->fcf_mac_address_hi[1] = FCOE_FCF_MAC1; fcf_rec->fcf_mac_address_hi[2] = FCOE_FCF_MAC2; fcf_rec->fcf_mac_address_hi[3] = FCOE_FCF_MAC3; fcf_rec->fcf_mac_address_low[0] = FCOE_FCF_MAC4; fcf_rec->fcf_mac_address_low[1] = FCOE_FCF_MAC5; fcf_rec->fc_map[0] = hba->sli.sli4.cfgFCOE.FCMap[0]; fcf_rec->fc_map[1] = hba->sli.sli4.cfgFCOE.FCMap[1]; fcf_rec->fc_map[2] = hba->sli.sli4.cfgFCOE.FCMap[2]; #endif /* EMLXS_LITTLE_ENDIAN */ if (hba->sli.sli4.cfgFCOE.fip_flags & TLV_FCOE_VLAN) { bzero((void *) bitmap, 512); i = hba->sli.sli4.cfgFCOE.VLanId; bitmap[i / 8] = (1 << (i % 8)); BE_SWAP32_BCOPY(bitmap, fcf_rec->vlan_bitmap, 512); } else { bzero((void *) bitmap, 512); bitmap[0] = 1; /* represents bit 0 */ BE_SWAP32_BCOPY(bitmap, fcf_rec->vlan_bitmap, 512); } fcf_rec->fcf_valid = 1; fcf_rec->fcf_available = 1; /* Update the FCFI */ emlxs_fcfi_update(port, fcfp, fcf_rec, hba->link_event_tag); /* Select the FCFI */ fcfp->flag &= ~EMLXS_FCFI_FAILED; fcfp->flag |= EMLXS_FCFI_SELECTED; fcftab->fcfi[0] = fcfp; fcftab->fcfi_count = 1; return; } /* emlxs_fc_fcftab_process() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_fcfi_online_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; FCFIobj_t *fcfp; if (fcftab->state != FC_FCFTAB_STATE_FCFI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_fcfi_online_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_online_action:%x flag=%x. " "Handling request.", fcftab->TID, fcftab->flag); rval = emlxs_fc_fcftab_req_handler(port, arg1); return (rval); } emlxs_fc_fcftab_process(port); fcfp = fcftab->fcfi[0]; if (!fcfp) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_online_action:%x. " "No FCF available. Offlining.", fcftab->TID); fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FC_FCFTAB_OFFLINE_REQ; rval = emlxs_fc_fcftab_req_handler(port, arg1); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_online_action:%x fcfi_count=%d. " "Onlining FCFI:%d. >", fcftab->TID, fcftab->fcfi_count, fcfp->fcf_index); (void) emlxs_fcfi_event(port, FCF_EVENT_FCFI_ONLINE, fcfp); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_FCFI_ONLINE_CMPL, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fc_fcftab_fcfi_online_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_fcfi_online_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FC_FCFTAB_STATE_FCFI_ONLINE_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_fcfi_online_cmpl_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_online_cmpl_action:%x %s:%s arg=%p " "flag=%x. Handling request.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); rval = emlxs_fc_fcftab_req_handler(port, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_online_cmpl_action:%x %s:%s arg=%p. " "Going online.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fc_fcftab_fcfi_online_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_fcfi_offline_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; FCFIobj_t *fcfp; if (fcftab->state != FC_FCFTAB_STATE_FCFI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_fcftab_offline_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->fcfi_online) { fcfp = fcftab->fcfi[0]; if (!(fcfp->flag & EMLXS_FCFI_OFFLINE_REQ)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_offline_action:%d. " "Offlining FCFI:%d. >", fcftab->TID, fcfp->fcf_index); rval = emlxs_fcfi_event(port, FCF_EVENT_FCFI_OFFLINE, fcfp); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_offline_action:%x fcfi_online=%d. " "Waiting on FCF. <", fcftab->TID, fcftab->fcfi_online); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_offline_action:%x %s:%s arg=%p.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_FCFI_OFFLINE_CMPL, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fc_fcftab_fcfi_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_fcfi_offline_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FC_FCFTAB_STATE_FCFI_OFFLINE_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_fcftab_offline_cmpl_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_offline_cmpl_action:%x %s:%s arg=%p. " "Handling request.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fc_fcftab_req_handler(port, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcftab_offline_cmpl_action:%x %s:%s arg=%p. " "Returning FCF(s) online.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_FCFI_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fc_fcftab_fcfi_offline_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_linkup_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (evt != FCF_EVENT_LINKUP) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_linkup_evt_action:%x %s:%s arg=%p flag=%x. " "Invalid event type. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_linkup_evt_action:%x %s:%s arg=%p gen=%x. Link up.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation); emlxs_fcf_linkup(port); fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FC_FCFTAB_TOPO_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_linkup_evt_action:%x %s gen=%x. " "Read topology.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), fcftab->generation); switch (fcftab->state) { case FC_FCFTAB_STATE_TOPO: rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO, FCF_REASON_REENTER, evt, arg1); break; default: rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO, FCF_REASON_EVENT, evt, arg1); break; } return (rval); } /* emlxs_fc_fcftab_linkup_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_linkdown_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; uint32_t i; FCFIobj_t *fcfp; if (evt != FCF_EVENT_LINKDOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_linkdown_evt_action:%x %s:%s arg=%p flag=%x. " "Invalid event type. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FC_FCFTAB_OFFLINE_REQ; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_linkdown_evt_action:%x %s:%s arg=%p flag=%x. Linkdown.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); emlxs_fcf_linkdown(port); /* Pause all active FCFI's */ for (i = 0; i < fcftab->fcfi_count; i++) { fcfp = fcftab->fcfi[i]; if ((fcfp->state == FCFI_STATE_OFFLINE) || (fcfp->state == FCFI_STATE_PAUSED)) { break; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_linkdown_evt_action:%x. " "Pausing FCFI:%d. >", fcftab->TID, fcfp->fcf_index); (void) emlxs_fcfi_event(port, FCF_EVENT_FCFI_PAUSE, fcfp); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_linkdown_evt_action:%x " "Going offline.", fcftab->TID); switch (fcftab->state) { case FC_FCFTAB_STATE_OFFLINE: rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_OFFLINE, FCF_REASON_REENTER, evt, arg1); break; default: rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); break; } return (rval); } /* emlxs_fc_fcftab_linkdown_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_fcfi_offline_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; FCFIobj_t *fcfp; if (evt != FCF_EVENT_FCFI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_fcftab_offline_evt_action:%x %s:%s arg=%p " "flag=%x. Invalid event type. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } fcfp = (FCFIobj_t *)arg1; switch (fcftab->state) { case FC_FCFTAB_STATE_SHUTDOWN: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_offline_evt_action:%x fcfi:%d. " "Shutting down.", fcftab->TID, fcfp->fcf_index); /* This will trigger final shutdown */ rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SHUTDOWN, FCF_REASON_REENTER, evt, arg1); break; case FC_FCFTAB_STATE_FCFI_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_offline_evt_action:%x fcfi:%d. Offlining.", fcftab->TID, fcfp->fcf_index); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_FCFI_OFFLINE, FCF_REASON_REENTER, evt, arg1); break; case FC_FCFTAB_STATE_FCFI_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_offline_evt_action:%x fcfi:%d. " "Retrying FCF.", fcftab->TID, fcfp->fcf_index); fcfp->flag |= EMLXS_FCFI_FAILED; rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_FCFI_ONLINE, FCF_REASON_REENTER, evt, arg1); break; case FC_FCFTAB_STATE_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_offline_evt_action:%x fcfi:%d.", fcftab->TID, fcfp->fcf_index); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_ONLINE, FCF_REASON_REENTER, evt, arg1); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_offline_evt_action:%x %s fcfi:%d.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), fcfp->fcf_index); break; } return (rval); } /* emlxs_fc_fcftab_fcfi_offline_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_fcfi_online_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; FCFIobj_t *fcfp; if (evt != FCF_EVENT_FCFI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_fcftab_online_evt_action:%x %s:%s arg=%p " "flag=%x. Invalid event type. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } fcfp = (FCFIobj_t *)arg1; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_fcfi_online_evt_action:%d fcfi:%d. <", fcftab->TID, fcfp->fcf_index); return (rval); } /* emlxs_fc_fcftab_fcfi_online_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fc_fcftab_shutdown_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (evt != FCF_EVENT_SHUTDOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fc_fcftab_shutdown_evt_action:%x %s:%s arg=%p flag=%x. " "Invalid event type. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } if (fcftab->flag & EMLXS_FCFTAB_SHUTDOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_shutdown_evt_action:%x %s:%s arg=%p flag=%x. " "Already shut down. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } if (fcftab->state == FC_FCFTAB_STATE_SHUTDOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_shutdown_evt_action:%x %s:%s arg=%p flag=%x. " "Already shutting down. <", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fc_fcftab_shutdown_evt_action:%x %s:%s arg=%p flag=%x. " "Shutting down.", fcftab->TID, emlxs_fc_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); emlxs_fcf_linkdown(port); rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SHUTDOWN, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fc_fcftab_shutdown_evt_action() */ static uint32_t emlxs_fc_fcftab_req_handler(emlxs_port_t *port, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (!(fcftab->flag & EMLXS_FCFTAB_REQ_MASK)) { return (1); } if (fcftab->flag & EMLXS_FC_FCFTAB_OFFLINE_REQ) { rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_OFFLINE, FCF_REASON_REQUESTED, 0, arg1); } else if (fcftab->flag & EMLXS_FC_FCFTAB_TOPO_REQ) { rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_TOPO, FCF_REASON_REQUESTED, 0, arg1); } else if (fcftab->flag & EMLXS_FC_FCFTAB_CFGLINK_REQ) { rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_CFGLINK, FCF_REASON_REQUESTED, 0, arg1); } else if (fcftab->flag & EMLXS_FC_FCFTAB_SPARM_REQ) { rval = emlxs_fc_fcftab_state(port, FC_FCFTAB_STATE_SPARM, FCF_REASON_REQUESTED, 0, arg1); } return (rval); } /* emlxs_fc_fcftab_req_handler() */ /* ************************************************************************** */ /* FCOE FCFTAB */ /* ************************************************************************** */ static char * emlxs_fcoe_fcftab_state_xlate(uint32_t state) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_fcoe_fcftab_state_table) / sizeof (emlxs_table_t); for (i = 0; i < count; i++) { if (state == emlxs_fcoe_fcftab_state_table[i].code) { return (emlxs_fcoe_fcftab_state_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "state=0x%x", state); return (buffer); } /* emlxs_fcoe_fcftab_state_xlate() */ static uint32_t emlxs_fcoe_fcftab_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; uint32_t(*func) (emlxs_port_t *, uint32_t, void *); uint32_t index; uint32_t events; uint16_t state; /* Convert event to action table index */ switch (evt) { case FCF_EVENT_STATE_ENTER: index = 0; break; case FCF_EVENT_SHUTDOWN: index = 1; break; case FCF_EVENT_LINKUP: index = 2; break; case FCF_EVENT_LINKDOWN: index = 3; break; case FCF_EVENT_CVL: index = 4; break; case FCF_EVENT_FCF_FOUND: index = 5; break; case FCF_EVENT_FCF_LOST: index = 6; break; case FCF_EVENT_FCF_CHANGED: index = 7; break; case FCF_EVENT_FCFTAB_FULL: index = 8; break; case FCF_EVENT_FCFI_ONLINE: index = 9; break; case FCF_EVENT_FCFI_OFFLINE: index = 10; break; default: return (1); } events = FCOE_FCFTAB_ACTION_EVENTS; state = fcftab->state; index += (state * events); func = (uint32_t(*) (emlxs_port_t *, uint32_t, void *)) emlxs_fcoe_fcftab_action_table[index]; if (!func) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "fcoe_fcftab_action:%x %s:%s arg=%p. No action. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } rval = (func)(port, evt, arg1); return (rval); } /* emlxs_fcoe_fcftab_action() */ static uint32_t emlxs_fcoe_fcftab_event(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; /* Filter events */ switch (evt) { case FCF_EVENT_SHUTDOWN: case FCF_EVENT_LINKUP: case FCF_EVENT_LINKDOWN: case FCF_EVENT_CVL: case FCF_EVENT_FCF_FOUND: case FCF_EVENT_FCF_LOST: case FCF_EVENT_FCF_CHANGED: case FCF_EVENT_FCFTAB_FULL: case FCF_EVENT_FCFI_OFFLINE: case FCF_EVENT_FCFI_ONLINE: break; default: return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "fcoe_fcftab_event:%x %s:%s arg=%p.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fcoe_fcftab_action(port, evt, arg1); return (rval); } /* emlxs_fcoe_fcftab_event() */ /* EMLXS_FCF_LOCK must be held to enter */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_state(emlxs_port_t *port, uint16_t state, uint16_t reason, uint32_t explain, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (state >= FCOE_FCFTAB_ACTION_STATES) { return (1); } if ((fcftab->state == state) && (reason != FCF_REASON_REENTER)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcftab_state:%x %s:%s:0x%x arg=%p. " "State not changed. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(state), emlxs_fcf_reason_xlate(reason), explain, arg1); return (1); } if (!reason) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcftab_state:%x %s-->%s arg=%p", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcoe_fcftab_state_xlate(state), arg1); } else if (reason == FCF_REASON_EVENT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcftab_state:%x %s-->%s:%s:%s arg=%p", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcoe_fcftab_state_xlate(state), emlxs_fcf_reason_xlate(reason), emlxs_fcf_event_xlate(explain), arg1); } else if (explain) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcftab_state:%x %s-->%s:%s:0x%x arg=%p", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcoe_fcftab_state_xlate(state), emlxs_fcf_reason_xlate(reason), explain, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcftab_state:%x %s-->%s:%s arg=%p", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcoe_fcftab_state_xlate(state), emlxs_fcf_reason_xlate(reason), arg1); } fcftab->prev_state = fcftab->state; fcftab->prev_reason = fcftab->reason; fcftab->state = state; fcftab->reason = reason; rval = emlxs_fcoe_fcftab_action(port, FCF_EVENT_STATE_ENTER, arg1); return (rval); } /* emlxs_fcoe_fcftab_state() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_fcfi_offline_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; FCFIobj_t *fcfp; if (evt != FCF_EVENT_FCFI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_fcfi_offline_evt_action:%x %s:%s arg=%p " "flag=%x. Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } fcfp = (FCFIobj_t *)arg1; switch (fcftab->state) { case FCOE_FCFTAB_STATE_SHUTDOWN: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_offline_evt_action:%x fcfi:%d. " "Shutting down.", fcftab->TID, fcfp->fcf_index); /* This will trigger final shutdown */ rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SHUTDOWN, FCF_REASON_REENTER, evt, arg1); break; case FCOE_FCFTAB_STATE_FCFI_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_offline_evt_action:%x fcfi:%d. " "Offlining.", fcftab->TID, fcfp->fcf_index); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_FCFI_OFFLINE, FCF_REASON_REENTER, evt, arg1); break; case FCOE_FCFTAB_STATE_FCFI_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_offline_evt_action:%x fcfi:%d. " "Attempting failover.", fcftab->TID, fcfp->fcf_index); fcfp->flag |= EMLXS_FCFI_FAILED; rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_FCFI_ONLINE, FCF_REASON_REENTER, evt, arg1); break; case FCOE_FCFTAB_STATE_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_offline_evt_action:%x fcfi:%d.", fcftab->TID, fcfp->fcf_index); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_ONLINE, FCF_REASON_REENTER, evt, arg1); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_offline_evt_action:%x %s fcfi:%d.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcfp->fcf_index); break; } return (rval); } /* emlxs_fcoe_fcftab_fcfi_offline_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_fcfi_online_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; FCFIobj_t *fcfp; if (evt != FCF_EVENT_FCFI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_fcfi_online_evt_action:%x %s:%s arg=%p " "flag=%x. Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } fcfp = (FCFIobj_t *)arg1; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_online_evt_action:%x fcfi:%d. <", fcftab->TID, fcfp->fcf_index); return (rval); } /* emlxs_fcoe_fcftab_fcfi_online_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_cvl_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; emlxs_port_t *vport; uint32_t vpi; VPIobj_t *vpip; if (evt != FCF_EVENT_CVL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_cvl_evt_action:%x %s:%s arg=%p flag=%x. " "Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } /* Pause VPI */ vpi = (uint32_t)((unsigned long)arg1); vport = &VPORT(vpi); vpip = vport->vpip; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_cvl_evt_action:%x %s gen=%x. Pausing VPI:%d. >", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation, vpip->VPI); rval = emlxs_vpi_event(vport, FCF_EVENT_VPI_PAUSE, vpip); switch (fcftab->state) { case FCOE_FCFTAB_STATE_SOLICIT: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_cvl_evt_action:%x %s gen=%x. " "Already soliciting. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); break; default: fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_SOL_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_cvl_evt_action:%x %s gen=%x. Soliciting.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT, FCF_REASON_EVENT, evt, arg1); break; } return (rval); } /* emlxs_fcoe_fcftab_cvl_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_linkup_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (evt != FCF_EVENT_LINKUP) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_linkup_evt_action:%x %s:%s arg=%p flag=%x. " "Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_linkup_evt_action:%x %s:%s arg=%p gen=%x. Link up.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation); emlxs_fcf_linkup(port); switch (fcftab->state) { case FCOE_FCFTAB_STATE_SOLICIT: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_linkup_evt_action:%x %s gen=%x. " "Already soliciting. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); break; default: fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_SOL_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_linkup_evt_action:%x %s gen=%x. Soliciting.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT, FCF_REASON_EVENT, evt, arg1); break; } return (rval); } /* emlxs_fcoe_fcftab_linkup_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_linkdown_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; int32_t i; FCFIobj_t *fcfp; if (evt != FCF_EVENT_LINKDOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_linkdown_evt_action:%x %s:%s arg=%p " "flag=%x. Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_OFFLINE_REQ; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_linkdown_evt_action:%x %s:%s arg=%p flag=%x. " "Linkdown.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); emlxs_fcf_linkdown(port); /* Pause all active FCFI's */ for (i = 0; i < fcftab->fcfi_count; i++) { fcfp = fcftab->fcfi[i]; if ((fcfp->state == FCFI_STATE_OFFLINE) || (fcfp->state == FCFI_STATE_PAUSED)) { break; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_linkdown_evt_action:%x Pausing FCFI:%d. >", fcftab->TID, fcfp->fcf_index); (void) emlxs_fcfi_event(port, FCF_EVENT_FCFI_PAUSE, fcfp); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_linkdown_evt_action:%x " "Going offline.", fcftab->TID); switch (fcftab->state) { case FCOE_FCFTAB_STATE_OFFLINE: rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_OFFLINE, FCF_REASON_REENTER, evt, arg1); break; default: rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); break; } return (rval); } /* emlxs_fcoe_fcftab_linkdown_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_shutdown_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (evt != FCF_EVENT_SHUTDOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_shutdown_evt_action:%x %s:%s arg=%p flag=%x. " "Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } if (fcftab->flag & EMLXS_FCFTAB_SHUTDOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_shutdown_evt_action:%x %s:%s arg=%p flag=%x. " "Already shut down. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } if (fcftab->state == FCOE_FCFTAB_STATE_SHUTDOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_shutdown_evt_action:%x %s:%s arg=%p flag=%x. " "Already shutting down. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_shutdown_evt_action:%x %s:%s arg=%p flag=%x. " "Shutting down.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); emlxs_fcf_linkdown(port); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SHUTDOWN, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fcoe_fcftab_shutdown_evt_action() */ static uint32_t emlxs_fcoe_fcftab_req_handler(emlxs_port_t *port, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (!(fcftab->flag & EMLXS_FCFTAB_REQ_MASK)) { return (1); } if (fcftab->flag & EMLXS_FCOE_FCFTAB_OFFLINE_REQ) { rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_OFFLINE, FCF_REASON_REQUESTED, 0, arg1); } else if (fcftab->flag & EMLXS_FCOE_FCFTAB_SOL_REQ) { rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT, FCF_REASON_REQUESTED, 0, arg1); } else if (fcftab->flag & EMLXS_FCOE_FCFTAB_READ_REQ) { rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ, FCF_REASON_REQUESTED, 0, FCFTAB_READ_ALL); } return (rval); } /* emlxs_fcoe_fcftab_req_handler() */ static void emlxs_fcoe_fcftab_read_timer(emlxs_hba_t *hba) { emlxs_port_t *port = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; /* Check FCF timer */ if (!fcftab->read_timer || (hba->timer_tics < fcftab->read_timer)) { return; } fcftab->read_timer = 0; fcftab->flag |= EMLXS_FCOE_FCFTAB_READ_REQ; switch (fcftab->state) { case FCOE_FCFTAB_STATE_SOLICIT_CMPL: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_timer:%x %s >", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state)); (void) emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ, 0, 0, FCFTAB_READ_ALL); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_timer:%x %s", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state)); break; } return; } /* emlxs_fcoe_fcftab_read_timer() */ static void emlxs_fcoe_fcftab_sol_timer(emlxs_hba_t *hba) { emlxs_port_t *port = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; /* Check FCF timer */ if (!fcftab->sol_timer || (hba->timer_tics < fcftab->sol_timer)) { return; } fcftab->sol_timer = 0; switch (fcftab->state) { case FCOE_FCFTAB_STATE_ONLINE: fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_SOL_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_timer:%x %s gen=%x. Soliciting. >", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); (void) emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT, FCF_REASON_EVENT, 0, 0); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_timer:%x %s", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state)); break; } return; } /* emlxs_fcoe_fcftab_sol_timer() */ static void emlxs_fcoe_fcftab_offline_timer(emlxs_hba_t *hba) { emlxs_port_t *port = &PPORT; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t i; FCFIobj_t *fcfp; for (i = 0; i < fcftab->fcfi_count; i++) { fcfp = fcftab->fcfi[i]; /* Check offline timer */ if (!fcfp->offline_timer || (hba->timer_tics < fcfp->offline_timer)) { continue; } fcfp->offline_timer = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_offline_timer:%x. Offlining FCFI:%d. >", fcftab->TID, fcfp->fcf_index); (void) emlxs_fcfi_event(port, FCF_EVENT_FCFI_OFFLINE, fcfp); } return; } /* emlxs_fcoe_fcftab_offline_timer() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_sol_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; fcftab->attempts++; if (fcftab->state != FCOE_FCFTAB_STATE_SOLICIT_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_sol_failed_action:%x %s:%s arg=%p " "attempt=%d. Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts); return (1); } if ((fcftab->reason == FCF_REASON_MBOX_FAILED) || (fcftab->reason == FCF_REASON_SEND_FAILED) || (fcftab->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Giving up.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT_CMPL, FCF_REASON_OP_FAILED, 0, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Retrying.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT, FCF_REASON_OP_FAILED, 0, arg1); } return (rval); } /* emlxs_fcoe_fcftab_sol_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_sol_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOX4 *mb4 = (MAILBOX4 *)mbq; uint16_t TID; mbox_rsp_hdr_t *hdr_rsp; MATCHMAP *mp; uint32_t status = MGMT_STATUS_FCF_IN_USE; uint32_t xstatus = 0; uint32_t fip_mode = 1; mutex_enter(&EMLXS_FCF_LOCK); TID = (uint16_t)((unsigned long)mbq->context); if (mbq->nonembed) { fip_mode = 0; mp = (MATCHMAP *)mbq->nonembed; mbq->nonembed = NULL; hdr_rsp = (mbox_rsp_hdr_t *)mp->virt; status = hdr_rsp->status; xstatus = hdr_rsp->extra_status; emlxs_mem_put(hba, MEM_BUF, (void *)mp); } if (fcftab->state != FCOE_FCFTAB_STATE_SOLICIT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_mbcmpl:%x %s.", TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (TID != fcftab->generation) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_mbcmpl:%x %s. " "Incorrect generation %x. Dropping.", TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { if (fip_mode) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_mbcmpl:%x failed. %s. >", fcftab->TID, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } else if ((status == 0)||(status != MGMT_STATUS_FCF_IN_USE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_mbcmpl:%x failed. %s %x,%x. >", fcftab->TID, emlxs_mb_xlate_status(mb4->mbxStatus), status, xstatus); (void) emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_mbcmpl:%x %s gen=%x. Solicit complete. >", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); (void) emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_fcoe_fcftab_sol_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_sol_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOXQ *mbq; MAILBOX4 *mb4; MATCHMAP *mp = NULL; uint32_t rval = 0; if (fcftab->state != FCOE_FCFTAB_STATE_SOLICIT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_sol_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if ((fcftab->prev_state != FCOE_FCFTAB_STATE_SOLICIT_FAILED) || (fcftab->flag & EMLXS_FCOE_FCFTAB_SOL_REQ)) { fcftab->flag &= ~EMLXS_FCOE_FCFTAB_SOL_REQ; fcftab->attempts = 0; } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_action:%x %s:%s arg=%p gen=%d flag=%x. " "Handling request.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, fcftab->flag); rval = emlxs_fcoe_fcftab_req_handler(port, arg1); return (rval); } if (fcftab->attempts == 0) { fcftab->TID = fcftab->generation; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_action:%x %s:%s arg=%p gen=%x fip=%x. " "Requesting solicit. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, ((hba->flag & FC_FIP_SUPPORTED)? 1:0)); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT_FAILED, FCF_REASON_NO_MBOX, 0, 0); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); if (hba->flag & FC_FIP_SUPPORTED) { IOCTL_FCOE_REDISCOVER_FCF_TABLE *fcf; mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_fcoe_fcftab_sol_mbcmpl; mbq->context = (void *)((unsigned long)fcftab->TID); mbq->port = (void *)port; mb4->un.varSLIConfig.be.embedded = 1; mb4->mbxCommand = MBX_SLI_CONFIG; mb4->mbxOwner = OWN_HOST; mb4->un.varSLIConfig.be.payload_length = sizeof (IOCTL_FCOE_REDISCOVER_FCF_TABLE) + IOCTL_HEADER_SZ; mb4->un.varSLIConfig.be.un_hdr.hdr_req.subsystem = IOCTL_SUBSYSTEM_FCOE; mb4->un.varSLIConfig.be.un_hdr.hdr_req.opcode = FCOE_OPCODE_REDISCOVER_FCF_TABLE; mb4->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0; mb4->un.varSLIConfig.be.un_hdr.hdr_req.req_length = sizeof (IOCTL_FCOE_REDISCOVER_FCF_TABLE); fcf = (IOCTL_FCOE_REDISCOVER_FCF_TABLE *) &mb4->un.varSLIConfig.payload; fcf->params.request.fcf_count = 0; /* invalidate FCF table */ } else { /* Non-FIP */ /* Non-FIP uses a persistent FCF entry that */ /* we must add to the table */ IOCTL_FCOE_ADD_FCF_TABLE *fcf; mbox_req_hdr_t *hdr_req; FCF_RECORD_t *fcf_rec; uint8_t bitmap[512]; uint16_t i; if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF)) == 0) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT_FAILED, FCF_REASON_NO_BUFFER, 0, arg1); return (rval); } bzero(mp->virt, mp->size); mbq->nonembed = (void *)mp; mbq->mbox_cmpl = emlxs_fcoe_fcftab_sol_mbcmpl; mbq->context = (void *)((unsigned long)fcftab->generation); mbq->port = (void *)port; mb4->un.varSLIConfig.be.embedded = 0; mb4->mbxCommand = MBX_SLI_CONFIG; mb4->mbxOwner = OWN_HOST; hdr_req = (mbox_req_hdr_t *)mp->virt; hdr_req->subsystem = IOCTL_SUBSYSTEM_FCOE; hdr_req->opcode = FCOE_OPCODE_ADD_FCF_TABLE; hdr_req->timeout = 0; hdr_req->req_length = sizeof (IOCTL_FCOE_ADD_FCF_TABLE); fcf = (IOCTL_FCOE_ADD_FCF_TABLE *)(hdr_req + 1); fcf->params.request.fcf_index = 0; fcf_rec = &fcf->params.request.fcf_entry; fcf_rec->max_recv_size = EMLXS_FCOE_MAX_RCV_SZ; fcf_rec->fka_adv_period = 0; fcf_rec->fip_priority = 128; #ifdef EMLXS_BIG_ENDIAN fcf_rec->fcf_mac_address_hi[0] = FCOE_FCF_MAC3; fcf_rec->fcf_mac_address_hi[1] = FCOE_FCF_MAC2; fcf_rec->fcf_mac_address_hi[2] = FCOE_FCF_MAC1; fcf_rec->fcf_mac_address_hi[3] = FCOE_FCF_MAC0; fcf_rec->fcf_mac_address_low[0] = FCOE_FCF_MAC5; fcf_rec->fcf_mac_address_low[1] = FCOE_FCF_MAC4; fcf_rec->fc_map[0] = hba->sli.sli4.cfgFCOE.FCMap[2]; fcf_rec->fc_map[1] = hba->sli.sli4.cfgFCOE.FCMap[1]; fcf_rec->fc_map[2] = hba->sli.sli4.cfgFCOE.FCMap[0]; #endif /* EMLXS_BIG_ENDIAN */ #ifdef EMLXS_LITTLE_ENDIAN fcf_rec->fcf_mac_address_hi[0] = FCOE_FCF_MAC0; fcf_rec->fcf_mac_address_hi[1] = FCOE_FCF_MAC1; fcf_rec->fcf_mac_address_hi[2] = FCOE_FCF_MAC2; fcf_rec->fcf_mac_address_hi[3] = FCOE_FCF_MAC3; fcf_rec->fcf_mac_address_low[0] = FCOE_FCF_MAC4; fcf_rec->fcf_mac_address_low[1] = FCOE_FCF_MAC5; fcf_rec->fc_map[0] = hba->sli.sli4.cfgFCOE.FCMap[0]; fcf_rec->fc_map[1] = hba->sli.sli4.cfgFCOE.FCMap[1]; fcf_rec->fc_map[2] = hba->sli.sli4.cfgFCOE.FCMap[2]; #endif /* EMLXS_LITTLE_ENDIAN */ if (hba->sli.sli4.cfgFCOE.fip_flags & TLV_FCOE_VLAN) { bzero((void *) bitmap, 512); i = hba->sli.sli4.cfgFCOE.VLanId; bitmap[i / 8] = (1 << (i % 8)); BE_SWAP32_BCOPY(bitmap, fcf_rec->vlan_bitmap, 512); } else { bzero((void *) bitmap, 512); bitmap[0] = 1; /* represents bit 0 */ BE_SWAP32_BCOPY(bitmap, fcf_rec->vlan_bitmap, 512); } fcf_rec->fcf_valid = 1; fcf_rec->fcf_available = 1; } rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { if (mp) { emlxs_mem_put(hba, MEM_BUF, (void *)mp); } emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT_FAILED, FCF_REASON_SEND_FAILED, rval, 0); return (rval); } return (0); } /* emlxs_fcoe_fcftab_sol_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_sol_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; emlxs_config_t *cfg = &CFG; if (fcftab->state != FCOE_FCFTAB_STATE_SOLICIT_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_sol_cmpl_action:%x %s:%s arg=%p " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_cmpl_action:%x %s:%s arg=%p gen=%d " "flag=%x. Handling request.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, fcftab->flag); rval = emlxs_fcoe_fcftab_req_handler(port, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_sol_cmpl_action:%x %s:%s arg=%p gen=%d. " "Starting timer (%d secs).", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->generation, cfg[CFG_FCF_SOLICIT_DELAY].current); /* Start the read timer */ fcftab->read_timer = hba->timer_tics + cfg[CFG_FCF_SOLICIT_DELAY].current; return (0); } /* emlxs_fcoe_fcftab_sol_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_read_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOX4 *mb4 = (MAILBOX4 *)mbq; mbox_rsp_hdr_t *hdr_rsp; IOCTL_FCOE_READ_FCF_TABLE *fcf; FCF_RECORD_t *fcfrec; FCFIobj_t *fcfp; MATCHMAP *mp; uint32_t context; uint16_t index; uint16_t TID; uint32_t event_tag; mutex_enter(&EMLXS_FCF_LOCK); context = (uint32_t)((unsigned long)mbq->context); TID = (uint16_t)(context >> 16); index = (uint16_t)(context & 0xFFFF); if (fcftab->state != FCOE_FCFTAB_STATE_READ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_mbcmpl:%x index=%d %s.", TID, index, emlxs_fcoe_fcftab_state_xlate(fcftab->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (TID != fcftab->generation) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_mbcmpl:%x index=%d %s. " "Incorrect generation %x. Dropping.", TID, index, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); mutex_exit(&EMLXS_FCF_LOCK); return (0); } mp = (MATCHMAP *)mbq->nonembed; hdr_rsp = (mbox_rsp_hdr_t *)mp->virt; if (mb4->mbxStatus || hdr_rsp->status) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_mbcmpl:%x index=%d failed. %s %x,%x. >", fcftab->TID, index, emlxs_mb_xlate_status(mb4->mbxStatus), hdr_rsp->status, hdr_rsp->extra_status); (void) emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, (void*)((unsigned long)index)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_mbcmpl:%x index=%d %s", fcftab->TID, index, emlxs_fcoe_fcftab_state_xlate(fcftab->state)); fcf = (IOCTL_FCOE_READ_FCF_TABLE *)(hdr_rsp + 1); fcfrec = &fcf->params.response.fcf_entry[0]; #ifdef EMLXS_BIG_ENDIAN { uint32_t *iptr; uint32_t i; uint8_t j; uint16_t s; uint16_t *sptr; /* Fix up data in FCF record */ SWAP32_BUFFER(&fcfrec->fabric_name_identifier[0], 8); SWAP32_BUFFER(&fcfrec->switch_name_identifier[0], 8); SWAP32_BUFFER(&fcfrec->vlan_bitmap[0], 512); iptr = (uint32_t *)&fcfrec->fcf_mac_address_hi[0]; i = *iptr; *iptr = SWAP32(i); sptr = (uint16_t *)&fcfrec->fcf_mac_address_low[0]; s = *sptr; *sptr = SWAP16(s); j = fcfrec->fc_map[0]; fcfrec->fc_map[0] = fcfrec->fc_map[2]; fcfrec->fc_map[2] = j; } #endif /* EMLXS_BIG_ENDIAN */ event_tag = fcf->params.response.event_tag; /* Try to find existing fcfrec */ fcfp = emlxs_fcfi_find(port, fcfrec, 0); /* If not found, allocate a new one */ if (!fcfp) { fcfp = emlxs_fcfi_alloc(port); } if (!fcfp) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_mbcmpl:%x index=%d failed. " "Unable to allocate fcfi. >", fcftab->TID, index); (void) emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ_FAILED, FCF_REASON_NO_FCFI, 0, (void*)((unsigned long)index)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* Update the FCFI */ emlxs_fcfi_update(port, fcfp, fcfrec, event_tag); /* Check if another record needs to be acquired */ if (fcf->params.response.next_valid_fcf_index != 0xffff) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_mbcmpl:%x. Read next. >", fcftab->TID); (void) emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ, FCF_REASON_REENTER, 0, (void *)((unsigned long)fcf->params.response. next_valid_fcf_index)); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_mbcmpl:%x. Read complete. >", fcftab->TID); (void) emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ_CMPL, 0, 0, (void*)((unsigned long)index)); } mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_fcoe_fcftab_read_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_read_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOXQ *mbq; MAILBOX4 *mb4; IOCTL_FCOE_READ_FCF_TABLE *fcf; uint32_t rval = 0; MATCHMAP *mp; mbox_req_hdr_t *hdr_req; uint16_t index = (uint16_t)((unsigned long)arg1); uint32_t context; if (fcftab->state != FCOE_FCFTAB_STATE_READ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_read_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if ((fcftab->prev_state != FCOE_FCFTAB_STATE_READ_FAILED) || (fcftab->flag & EMLXS_FCOE_FCFTAB_READ_REQ)) { fcftab->flag &= ~EMLXS_FCOE_FCFTAB_READ_REQ; fcftab->attempts = 0; } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_action:%x %s:%s arg=%p flag=%x. " "Handling request.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); rval = emlxs_fcoe_fcftab_req_handler(port, arg1); return (rval); } if (fcftab->attempts == 0) { fcftab->TID = fcftab->generation; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_action:%x %s:%s arg=%p attempts=%d. " "Reading FCF. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF)) == 0) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ_FAILED, FCF_REASON_NO_BUFFER, 0, arg1); return (rval); } bzero(mp->virt, mp->size); mbq->nonembed = (void *)mp; mbq->mbox_cmpl = emlxs_fcoe_fcftab_read_mbcmpl; context = ((uint32_t)fcftab->TID << 16) | (uint32_t)index; mbq->context = (void *)((unsigned long)context); mbq->port = (void *)port; mb4->un.varSLIConfig.be.embedded = 0; mb4->mbxCommand = MBX_SLI_CONFIG; mb4->mbxOwner = OWN_HOST; hdr_req = (mbox_req_hdr_t *)mp->virt; hdr_req->subsystem = IOCTL_SUBSYSTEM_FCOE; hdr_req->opcode = FCOE_OPCODE_READ_FCF_TABLE; hdr_req->timeout = 0; hdr_req->req_length = sizeof (IOCTL_FCOE_READ_FCF_TABLE); fcf = (IOCTL_FCOE_READ_FCF_TABLE *)(hdr_req + 1); fcf->params.request.fcf_index = index; rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_BUF, (void *)mp); emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_fcoe_fcftab_read_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_read_failed_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; fcftab->attempts++; if (fcftab->state != FCOE_FCFTAB_STATE_READ_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_read_failed_action:%x %s:%s arg=%p " "attempt=%d. Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts); return (1); } if ((fcftab->reason == FCF_REASON_MBOX_FAILED) || (fcftab->reason == FCF_REASON_SEND_FAILED) || (fcftab->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Giving up.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ_CMPL, FCF_REASON_OP_FAILED, fcftab->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_failed_action:%x %s:%s arg=%p " "attempt=%d reason=%x. Retrying.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts, fcftab->reason); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ, FCF_REASON_OP_FAILED, fcftab->attempts, FCFTAB_READ_ALL); } return (rval); } /* emlxs_fcoe_fcftab_read_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_read_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; FCFIobj_t *fcfp; uint32_t i; if (fcftab->state != FCOE_FCFTAB_STATE_READ_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_read_cmpl_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_cmpl_action:%x %s:%s arg=%p attempts=%d. " "Cleaning table.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->attempts); /* Clean FCFI table */ fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { if (fcfp->state == FCFI_STATE_FREE) { continue; } /* Adjust the freshness flag */ if (fcfp->generation == fcftab->generation) { fcfp->flag |= EMLXS_FCFI_FRESH; } else { fcfp->flag &= ~EMLXS_FCFI_FRESH; } /* Clear the failed bit */ fcfp->flag &= ~EMLXS_FCFI_FAILED; /* Free all stale unselected entries now */ if (!(fcfp->flag & EMLXS_FCFI_FRESH) && !(fcfp->flag & EMLXS_FCFI_SELECTED)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_read_cmpl_action:%x. FCF stale. " "Freeing FCFI:%d. >", fcftab->TID, fcfp->fcf_index); (void) emlxs_fcfi_free(port, fcfp); continue; } } rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_FCFI_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fcoe_fcftab_read_cmpl_action() */ static FCFIobj_t * emlxs_fcoe_fcftab_fcfi_select(emlxs_port_t *port, char *fabric_wwn) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; FCFIobj_t *fcfp; FCFIobj_t *fcfp1; uint32_t mask; uint32_t viable; uint32_t i; uint32_t j; uint32_t rnum; timespec_t time; FCFIobj_t **fcf_table; uint32_t fcf_table_count; mask = (EMLXS_FCFI_VALID|EMLXS_FCFI_AVAILABLE| EMLXS_FCFI_CONFIGURED|EMLXS_FCFI_FRESH| EMLXS_FCFI_FAILED|EMLXS_FCFI_SELECTED); viable = (EMLXS_FCFI_VALID|EMLXS_FCFI_AVAILABLE| EMLXS_FCFI_CONFIGURED|EMLXS_FCFI_FRESH); /* Tag & count viable entries */ fcf_table_count = 0; fcfp = 0; fcfp1 = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp1++) { if (fcfp1->state == FCFI_STATE_FREE) { fcfp1->flag &= ~EMLXS_FCFI_TAGGED; continue; } if ((fcfp1->flag & mask) != viable) { fcfp1->flag &= ~EMLXS_FCFI_TAGGED; continue; } if (fabric_wwn && bcmp(fabric_wwn, fcfp1->fcf_rec.fabric_name_identifier, 8)) { fcfp1->flag &= ~EMLXS_FCFI_TAGGED; continue; } fcfp1->flag |= EMLXS_FCFI_TAGGED; fcfp = fcfp1; fcf_table_count++; } if (fcf_table_count == 0) { return (NULL); } if (fcf_table_count == 1) { return (fcfp); } /* We found more than one viable entry */ fcf_table = (FCFIobj_t **)kmem_zalloc( (sizeof (uintptr_t) * fcf_table_count), KM_SLEEP); /* Find the highest priority tagged entry(s) */ for (i = 0; i < fcf_table_count; i++) { fcfp = 0; fcfp1 = fcftab->table; for (j = 0; j < fcftab->table_count; j++, fcfp1++) { if (!(fcfp1->flag & EMLXS_FCFI_TAGGED)) { continue; } if (!fcfp || (fcfp1->priority > fcfp->priority)) { fcfp = fcfp1; } } if (fcf_table[0] && (fcf_table[0]->priority > fcfp->priority)) { break; } fcfp->flag &= ~EMLXS_FCFI_TAGGED; fcf_table[i] = fcfp; } /* If more than one entry has the highest priority, */ /* then randomly select one of the highest. */ if (i > 1) { /* Pick a random number from 0 to (i-1) */ /* This algorithm uses the lower 16 bits of the nanosecond */ /* clock to determine the value */ bzero(&time, sizeof (timespec_t)); gethrestime(&time); rnum = (uint32_t)(time.tv_nsec & 0xFFFF); fcfp = fcf_table[(rnum%i)]; } else { fcfp = fcf_table[0]; } /* Free the priority table */ kmem_free(fcf_table, (sizeof (uintptr_t) * fcf_table_count)); return (fcfp); } /* emlxs_fcoe_fcftab_fcfi_select() */ /*ARGSUSED*/ static void emlxs_fcoe_fcftab_process(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; FCFIobj_t *fcfp; FCFIobj_t *prev_fcfp; uint32_t i; uint32_t j; uint32_t count; uint32_t mask; uint32_t viable; emlxs_config_t *cfg = &CFG; mask = (EMLXS_FCFI_VALID|EMLXS_FCFI_AVAILABLE| EMLXS_FCFI_CONFIGURED|EMLXS_FCFI_FRESH| EMLXS_FCFI_FAILED); viable = (EMLXS_FCFI_VALID|EMLXS_FCFI_AVAILABLE| EMLXS_FCFI_CONFIGURED|EMLXS_FCFI_FRESH); /* Deselection process */ for (i = 0; i < FCFTAB_MAX_FCFI_COUNT; i++) { fcfp = fcftab->fcfi[i]; if (!fcfp) { continue; } /* Check if entry is viable */ if ((fcfp->flag & mask) == viable) { if (fcfp->offline_timer) { fcfp->offline_timer = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d fcfi=%d %s. " "FCF viable. Offline timer disabled.", fcftab->TID, i, fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), cfg[CFG_FCF_FAILOVER_DELAY].current); } continue; } /* Previous entry is no longer viable */ /* If FCF is still online */ if (fcfp->state > FCFI_STATE_OFFLINE) { if (fcfp->offline_timer == 0) { /* Set the offline timer */ fcfp->offline_timer = hba->timer_tics + cfg[CFG_FCF_FAILOVER_DELAY].current; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d fcfi=%d %s. " "No longer viable. " "Offlining FCF (%d secs).", fcftab->TID, i, fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), cfg[CFG_FCF_FAILOVER_DELAY].current); } continue; } /* Deselect it */ fcfp->flag &= ~EMLXS_FCFI_SELECTED; if (!(fcfp->flag & EMLXS_FCFI_FRESH)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d. " "No longer viable. Freeing FCFI:%d. >", fcftab->TID, i, fcfp->fcf_index); (void) emlxs_fcfi_free(port, fcfp); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d fcfi=%d %s. " "No longer viable. FCF deselected.", fcftab->TID, i, fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state)); } } /* Reselection process */ for (i = 0; i < FCFTAB_MAX_FCFI_COUNT; i++) { prev_fcfp = fcftab->fcfi[i]; fcftab->fcfi[i] = NULL; /* If no previous selection, then make new one */ if (!prev_fcfp) { /* Select an fcf on any fabric */ fcfp = emlxs_fcoe_fcftab_fcfi_select(port, 0); if (fcfp) { fcfp->flag |= EMLXS_FCFI_SELECTED; fcftab->fcfi[i] = fcfp; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d fcfi=%d %s. " "New FCF selected.", fcftab->TID, i, fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state)); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d. " "No FCF available.", fcftab->TID, i); } continue; } /* If previous entry is still selected, keep it */ if (prev_fcfp->flag & EMLXS_FCFI_SELECTED) { fcfp = prev_fcfp; fcftab->fcfi[i] = fcfp; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d fcfi=%d %s. " "FCF still selected.", fcftab->TID, i, fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state)); continue; } /* Previous entry is no longer selected */ /* Select a new fcf from same fabric */ fcfp = emlxs_fcoe_fcftab_fcfi_select(port, (char *)prev_fcfp->fcf_rec.fabric_name_identifier); if (fcfp) { fcfp->flag |= EMLXS_FCFI_SELECTED; fcftab->fcfi[i] = fcfp; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d fcfi=%d %s. " "New FCF, same fabric selected.", fcftab->TID, i, fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state)); continue; } /* Select fcf from any fabric */ fcfp = emlxs_fcoe_fcftab_fcfi_select(port, 0); if (fcfp) { fcfp->flag |= EMLXS_FCFI_SELECTED; fcftab->fcfi[i] = fcfp; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d fcfi=%d %s. " "New FCF, new fabric selected.", fcftab->TID, i, fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state)); continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_process:%x %d. No FCF available.", fcftab->TID, i); } /* Pack entries */ count = 0; for (i = 0; i < FCFTAB_MAX_FCFI_COUNT; i++) { if (fcftab->fcfi[i]) { count++; continue; } for (j = i+1; j < FCFTAB_MAX_FCFI_COUNT; j++) { if (fcftab->fcfi[j] == NULL) { continue; } fcftab->fcfi[i] = fcftab->fcfi[j]; fcftab->fcfi[j] = NULL; count++; break; } if (j == FCFTAB_MAX_FCFI_COUNT) { break; } } fcftab->fcfi_count = count; return; } /* emlxs_fcoe_fcftab_process() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_fcfi_online_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; FCFIobj_t *fcfp; uint32_t rval = 0; uint32_t i; uint32_t offline_count = 0; uint32_t online_count = 0; if (fcftab->state != FCOE_FCFTAB_STATE_FCFI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_online_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_online_action:%x flag=%x. " "Handling request.", fcftab->TID, fcftab->flag); rval = emlxs_fcoe_fcftab_req_handler(port, arg1); return (rval); } emlxs_fcoe_fcftab_process(port); for (i = 0; i < fcftab->fcfi_count; i++) { fcfp = fcftab->fcfi[i]; if (fcfp->offline_timer == 0) { online_count++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_online_action:%x fcfi_count=%d. " "Onlining FCFI:%d. >", fcftab->TID, fcftab->fcfi_count, fcfp->fcf_index); (void) emlxs_fcfi_event(port, FCF_EVENT_FCFI_ONLINE, fcfp); } else { offline_count++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_online_action:%x fcfi_count=%d. " "Offlining fcfi:%d.", fcftab->TID, fcftab->fcfi_count, fcfp->fcf_index); } } if (offline_count) { /* Wait for FCF's to go offline */ rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_FCFI_OFFLINE, FCF_REASON_EVENT, evt, arg1); /* Service timer now */ emlxs_fcoe_fcftab_offline_timer(hba); return (rval); } if (!online_count) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_online_action:%x fcfi_count=%d.", fcftab->TID, fcftab->fcfi_count); } rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_FCFI_ONLINE_CMPL, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fcoe_fcftab_fcfi_online_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_fcfi_online_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FCOE_FCFTAB_STATE_FCFI_ONLINE_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_fcfi_online_cmpl_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_online_cmpl_action:%x %s:%s " "arg=%p flag=%x. Handling request.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); rval = emlxs_fcoe_fcftab_req_handler(port, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_online_cmpl_action:%x %s:%s arg=%p. " "Going online.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fcoe_fcftab_fcfi_online_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_fcfi_offline_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; FCFIobj_t *fcfp; uint32_t rval = 0; int32_t i; uint32_t fcfi_offline; if (fcftab->state != FCOE_FCFTAB_STATE_FCFI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_fcfi_offline_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } /* Check for FCF's going offline */ fcfi_offline = 0; for (i = 0; i < fcftab->fcfi_count; i++) { fcfp = fcftab->fcfi[i]; if (fcfp->state <= FCFI_STATE_OFFLINE) { continue; } if (fcfp->offline_timer || (fcfp->flag & EMLXS_FCFI_OFFLINE_REQ)) { fcfi_offline++; } } if (fcfi_offline) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_offline_action:%x %s:%s arg=%p " "fcfi_offline=%d. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcfi_offline); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_offline_action:%x %s:%s arg=%p.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_FCFI_OFFLINE_CMPL, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fcoe_fcftab_fcfi_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_fcfi_offline_cmpl_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FCOE_FCFTAB_STATE_FCFI_OFFLINE_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_fcfi_offline_cmpl_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_offline_cmpl_action:%x %s:%s arg=%p. " "Handling request.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fcoe_fcftab_req_handler(port, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcfi_offline_cmpl_action:%x %s:%s arg=%p. " "Returning FCF(s) online.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_FCFI_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fcoe_fcftab_fcfi_offline_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_found_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t fcf_index = (uint32_t)((unsigned long)arg1); FCFIobj_t *fcfp; uint32_t rval = 0; if (evt != FCF_EVENT_FCF_FOUND) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_found_evt_action:%x %s:%s fcf_index=%d. " "Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index); return (1); } switch (fcftab->state) { case FCOE_FCFTAB_STATE_SOLICIT: case FCOE_FCFTAB_STATE_SOLICIT_CMPL: case FCOE_FCFTAB_STATE_READ: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_found_evt_action:%x %s:%s " "fcf_index=%d gen=%x. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index, fcftab->generation); break; /* case FCOE_FCFTAB_STATE_FCFI_OFFLINE: */ default: /* Scan for matching fcf index in table */ fcfp = emlxs_fcfi_find(port, 0, &fcf_index); if (fcfp && (fcfp->flag & EMLXS_FCFI_SELECTED)) { /* Trigger table read */ fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_READ_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_found_evt_action:%x %s:%s " "fcf_index=%d gen=%x. Read FCF table.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index, fcftab->generation); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ, FCF_REASON_EVENT, evt, arg1); break; } /* Check if we need more FCF's */ if (fcftab->fcfi_online < FCFTAB_MAX_FCFI_COUNT) { /* Trigger table read */ fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_READ_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_found_evt_action:%x %s:%s " "fcf_index=%d gen=%x fcfi_online=%d. " "Read FCF table.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index, fcftab->generation, fcftab->fcfi_online); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ, FCF_REASON_EVENT, evt, arg1); break; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_found_evt_action:%x %s:%s fcfi=%d. " "FCF not needed. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index); break; } return (rval); } /* emlxs_fcoe_fcftab_found_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_lost_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; FCFIobj_t *fcfp; uint32_t fcf_index = (uint32_t)((unsigned long)arg1); emlxs_port_t *vport; VPIobj_t *vpip; uint32_t i; uint32_t rval = 0; if (evt != FCF_EVENT_FCF_LOST) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_lost_evt_action:%x %s:%s fcf_index=%d. " "Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index); return (1); } /* Scan for matching fcf index in table */ fcfp = emlxs_fcfi_find(port, 0, &fcf_index); if (!fcfp) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_lost_evt_action:%x %s:%s fcf_index=%d. " "FCF not found. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index); return (0); } if (!(fcfp->flag & EMLXS_FCFI_SELECTED)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_changed_evt_action:%x %s:%s fcf_index=%d. " "FCF not selected. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index); return (0); } /* Offline VPI's of this FCFI */ for (i = 0; i <= hba->vpi_max; i++) { vport = &VPORT(i); vpip = vport->vpip; if ((vpip->state == VPI_STATE_OFFLINE) || (vpip->vfip->fcfp != fcfp)) { continue; } /* Fabric logo is implied */ emlxs_vpi_logo_handler(port, vpip); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_lost_evt_action:%x %s:%s fcf_index=%d gen=%x. " "Offlining VPI:%d. >", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index, fcftab->generation, vpip->VPI); (void) emlxs_vpi_event(port, FCF_EVENT_VPI_OFFLINE, vpip); } switch (fcftab->state) { case FCOE_FCFTAB_STATE_SOLICIT: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_lost_evt_action:%x %s gen=%x. " "Already soliciting. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); break; default: fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_SOL_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_lost_evt_action:%x %s gen=%x. Soliciting.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT, FCF_REASON_EVENT, evt, arg1); break; } return (rval); } /* emlxs_fcoe_fcftab_lost_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_changed_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; FCFIobj_t *fcfp; uint32_t fcf_index = (uint32_t)((unsigned long)arg1); uint32_t rval = 0; if (evt != FCF_EVENT_FCF_CHANGED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_changed_evt_action:%x %s:%s fcf_index=%d. " "Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index); return (1); } switch (fcftab->state) { case FCOE_FCFTAB_STATE_SOLICIT: case FCOE_FCFTAB_STATE_SOLICIT_CMPL: case FCOE_FCFTAB_STATE_READ: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_changed_evt_action:%x %s:%s " "fcf_index=%d gen=%x. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index, fcftab->generation); break; /* case FCOE_FCFTAB_STATE_FCFI_OFFLINE: */ default: /* Scan for matching fcf index in table */ fcfp = emlxs_fcfi_find(port, 0, &fcf_index); if (fcfp && (fcfp->flag & EMLXS_FCFI_SELECTED)) { /* Trigger table read */ fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_READ_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_changed_evt_action:%x %s:%s " "fcf_index=%d gen=%x. Read FCF table.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index, fcftab->generation); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ, FCF_REASON_EVENT, evt, arg1); break; } /* Check if we need more FCF's */ if (fcftab->fcfi_online < FCFTAB_MAX_FCFI_COUNT) { /* Trigger table read */ fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_READ_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_changed_evt_action:%x %s:%s " "fcf_index=%d gen=%x fcfi_online=%d. " "Read FCF table.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index, fcftab->generation, fcftab->fcfi_online); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_READ, FCF_REASON_EVENT, evt, arg1); break; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_changed_evt_action:%x %s:%s fcfi=%d. " "FCF not needed. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcf_index); break; } return (rval); } /* emlxs_fcoe_fcftab_changed_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_fcf_delete(emlxs_port_t *port, uint32_t fcf_index) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOXQ *mbq; MAILBOX4 *mb4; MATCHMAP *mp = NULL; uint32_t rval = 0; IOCTL_FCOE_DELETE_FCF_TABLE *fcf; mbox_req_hdr_t *hdr_req; if (fcf_index >= fcftab->fcfi_count) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcf_delete:%x fcfi:%d failed. " "Out of range.", fcftab->TID, fcf_index); return (1); } if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcf_delete:%x fcfi:%d failed. " "Unable to allocate mailbox.", fcftab->TID, fcf_index); return (1); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcf_delete:%x fcfi:%d failed. " "Unable to allocate buffer.", fcftab->TID, fcf_index); emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); return (1); } bzero(mp->virt, mp->size); mbq->nonembed = (void *)mp; mbq->mbox_cmpl = NULL; mbq->context = (void *)((unsigned long)fcf_index); mbq->port = (void *)port; mb4->un.varSLIConfig.be.embedded = 0; mb4->mbxCommand = MBX_SLI_CONFIG; mb4->mbxOwner = OWN_HOST; hdr_req = (mbox_req_hdr_t *)mp->virt; hdr_req->subsystem = IOCTL_SUBSYSTEM_FCOE; hdr_req->opcode = FCOE_OPCODE_DELETE_FCF_TABLE; hdr_req->timeout = 0; hdr_req->req_length = sizeof (IOCTL_FCOE_DELETE_FCF_TABLE); fcf = (IOCTL_FCOE_DELETE_FCF_TABLE *)(hdr_req + 1); fcf->params.request.fcf_count = 1; fcf->params.request.fcf_indexes[0] = (uint16_t)fcf_index; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcf_delete:%x fcfi:%d. <", fcftab->TID, fcf_index); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_fcf_delete:%x fcfi:%d failed. " "Unable to send request.", fcftab->TID, fcf_index); if (mp) { emlxs_mem_put(hba, MEM_BUF, (void *)mp); } emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); return (1); } return (0); } /* emlxs_fcoe_fcftab_fcf_delete() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_full_evt_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; FCFIobj_t *fcfp; uint32_t rval = 0; uint32_t mask; uint32_t viable; uint32_t i; uint32_t count; if (evt != FCF_EVENT_FCFTAB_FULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_full_evt_action:%x %s:%s arg=%p. " "Invalid event type. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->fcfi_online == FCFTAB_MAX_FCFI_COUNT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_full_evt_action:%x %s:%s arg=%p " "fcfi_online=%d. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->fcfi_online); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_full_evt_action:%x %s:%s arg=%p fcfi_online=%d. " "Cleaning table...", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->fcfi_online); mask = (EMLXS_FCFI_VALID|EMLXS_FCFI_AVAILABLE| EMLXS_FCFI_CONFIGURED); viable = (EMLXS_FCFI_VALID|EMLXS_FCFI_AVAILABLE| EMLXS_FCFI_CONFIGURED); count = 0; fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { if (fcfp->state == FCFI_STATE_FREE) { continue; } if (fcfp->flag & EMLXS_FCFI_SELECTED) { continue; } if ((fcfp->flag & mask) == viable) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_full_evt_action:%x. " "Deleting FCFI:%d %x. >", fcftab->TID, fcfp->fcf_index, fcfp->flag); (void) emlxs_fcfi_free(port, fcfp); (void) emlxs_fcoe_fcftab_fcf_delete(port, fcfp->fcf_index); count++; } if (!count) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_full_evt_action:%x %s:%s arg=%p. " "All FCF's are viable. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (0); } switch (fcftab->state) { case FCOE_FCFTAB_STATE_SOLICIT: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_full_evt_action:%x %s gen=%x. " "Already soliciting. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); break; default: fcftab->flag &= ~EMLXS_FCFTAB_REQ_MASK; fcftab->flag |= EMLXS_FCOE_FCFTAB_SOL_REQ; fcftab->generation++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_full_evt_action:%x %s gen=%x. Soliciting.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), fcftab->generation); rval = emlxs_fcoe_fcftab_state(port, FCOE_FCFTAB_STATE_SOLICIT, FCF_REASON_EVENT, evt, arg1); break; } return (rval); } /* emlxs_fcoe_fcftab_full_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_online_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; emlxs_config_t *cfg = &CFG; FCFIobj_t *fcfp; uint32_t rval = 0; uint32_t mask; uint32_t viable; uint32_t i; uint32_t count = 0; if (fcftab->state != FCOE_FCFTAB_STATE_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_online_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_online_action:%x flag=%x. " "Handling request.", fcftab->TID, fcftab->flag); rval = emlxs_fcoe_fcftab_req_handler(port, arg1); return (rval); } if (fcftab->fcfi_online == 0) { mask = (EMLXS_FCFI_VALID|EMLXS_FCFI_AVAILABLE| EMLXS_FCFI_CONFIGURED); viable = (EMLXS_FCFI_VALID|EMLXS_FCFI_AVAILABLE| EMLXS_FCFI_CONFIGURED); /* Count viable FCF's in table */ count = 0; fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { if (fcfp->state == FCFI_STATE_FREE) { continue; } if ((fcfp->flag & mask) == viable) { count++; } } if (count) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_online_action:%x %s:%s " "fcfi_online=0,%d,%d. Starting resolicit timer. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcftab->fcfi_count, count); /* Start the solicit timer */ fcftab->sol_timer = hba->timer_tics + cfg[CFG_FCF_RESOLICIT_DELAY].current; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_online_action:%x %s:%s " "fcfi_online=0,%d,0. Wait for FCF event. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), fcftab->fcfi_count); } emlxs_fcf_linkdown(port); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_online_action:%x flag=%x fcfi_online=%d. " "Online. <", fcftab->TID, fcftab->flag, fcftab->fcfi_online); emlxs_fcf_linkup(port); return (rval); } /* emlxs_fcoe_fcftab_online_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcoe_fcftab_offline_action(emlxs_port_t *port, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcftab->state != FCOE_FCFTAB_STATE_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcoe_fcftab_offline_action:%x %s:%s arg=%p. " "Invalid state. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } fcftab->flag &= ~EMLXS_FCOE_FCFTAB_OFFLINE_REQ; if (fcftab->flag & EMLXS_FCFTAB_REQ_MASK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_offline_action:%x %s:%s arg=%p flag=%x. " "Handling request.", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->flag); rval = emlxs_fcoe_fcftab_req_handler(port, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcoe_fcftab_offline_action:%x %s:%s arg=%p fcfi_online=%d. " "Offline. <", fcftab->TID, emlxs_fcoe_fcftab_state_xlate(fcftab->state), emlxs_fcf_event_xlate(evt), arg1, fcftab->fcfi_online); return (rval); } /* emlxs_fcoe_fcftab_offline_action() */ /* ************************************************************************** */ /* FCFI */ /* ************************************************************************** */ static char * emlxs_fcfi_state_xlate(uint32_t state) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_fcfi_state_table) / sizeof (emlxs_table_t); for (i = 0; i < count; i++) { if (state == emlxs_fcfi_state_table[i].code) { return (emlxs_fcfi_state_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "state=0x%x", state); return (buffer); } /* emlxs_fcfi_state_xlate() */ static uint32_t emlxs_fcfi_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; uint32_t(*func) (emlxs_port_t *, FCFIobj_t *, uint32_t, void *); uint32_t index; uint32_t events; uint16_t state; /* Convert event to action table index */ switch (evt) { case FCF_EVENT_STATE_ENTER: index = 0; break; case FCF_EVENT_FCFI_ONLINE: index = 1; break; case FCF_EVENT_FCFI_OFFLINE: index = 2; break; case FCF_EVENT_FCFI_PAUSE: index = 3; break; case FCF_EVENT_VFI_ONLINE: index = 4; break; case FCF_EVENT_VFI_OFFLINE: index = 5; break; default: return (1); } events = FCFI_ACTION_EVENTS; state = fcfp->state; index += (state * events); func = (uint32_t(*) (emlxs_port_t *, FCFIobj_t *, uint32_t, void *)) emlxs_fcfi_action_table[index]; if (!func) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "fcfi_action:%d %s:%s arg=%p. No action. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } rval = (func)(port, fcfp, evt, arg1); return (rval); } /* emlxs_fcfi_action() */ static uint32_t emlxs_fcfi_event(emlxs_port_t *port, uint32_t evt, void *arg1) { FCFIobj_t *fcfp = NULL; VFIobj_t *vfip = NULL; uint32_t rval = 0; /* Filter events and acquire fcfi context */ switch (evt) { case FCF_EVENT_VFI_ONLINE: case FCF_EVENT_VFI_OFFLINE: vfip = (VFIobj_t *)arg1; if (!vfip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "fcfi_event: %s arg=%p. Null VFI found. <", emlxs_fcf_event_xlate(evt), arg1); return (1); } fcfp = vfip->fcfp; if (!fcfp) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "fcfi_event: %s arg=%p. FCF not found. <", emlxs_fcf_event_xlate(evt), arg1); return (1); } break; case FCF_EVENT_FCFI_ONLINE: case FCF_EVENT_FCFI_OFFLINE: case FCF_EVENT_FCFI_PAUSE: fcfp = (FCFIobj_t *)arg1; if (!fcfp) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "fcfi_event: %s arg=%p. Null FCFI found. <", emlxs_fcf_event_xlate(evt), arg1); return (1); } break; default: return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "fcfi_event:%d %s:%s arg=%p", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_fcfi_action(port, fcfp, evt, arg1); return (rval); } /* emlxs_fcfi_event() */ /* EMLXS_FCF_LOCK must be held to enter */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_state(emlxs_port_t *port, FCFIobj_t *fcfp, uint16_t state, uint16_t reason, uint32_t explain, void *arg1) { uint32_t rval = 0; if (state >= FCFI_ACTION_STATES) { return (1); } if ((fcfp->state == state) && (reason != FCF_REASON_REENTER)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_state:%d %s:%s:0x%x arg=%p. " "State not changed. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(state), emlxs_fcf_reason_xlate(reason), explain, arg1); return (1); } if (!reason) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcfi_state:%d %s-->%s arg=%p", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcfi_state_xlate(state), arg1); } else if (reason == FCF_REASON_EVENT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcfi_state:%d %s-->%s:%s:%s arg=%p", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcfi_state_xlate(state), emlxs_fcf_reason_xlate(reason), emlxs_fcf_event_xlate(explain), arg1); } else if (explain) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcfi_state:%d %s-->%s:%s:0x%x arg=%p", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcfi_state_xlate(state), emlxs_fcf_reason_xlate(reason), explain, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "fcfi_state:%d %s-->%s:%s arg=%p", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcfi_state_xlate(state), emlxs_fcf_reason_xlate(reason), arg1); } fcfp->prev_state = fcfp->state; fcfp->prev_reason = fcfp->reason; fcfp->state = state; fcfp->reason = reason; rval = emlxs_fcfi_action(port, fcfp, FCF_EVENT_STATE_ENTER, arg1); return (rval); } /* emlxs_fcfi_state() */ static FCFIobj_t * emlxs_fcfi_alloc(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint16_t i; FCFIobj_t *fcfp; fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { if (fcfp->state == FCFI_STATE_FREE) { bzero(fcfp, sizeof (FCFIobj_t)); fcfp->index = i; fcfp->FCFI = 0xFFFF; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_alloc:%d. Allocating FCFI. >", fcfp->index); (void) emlxs_fcfi_state(port, fcfp, FCFI_STATE_OFFLINE, 0, 0, 0); return (fcfp); } } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_alloc: Out of FCFI objects.", fcfp->index); return (NULL); } /* emlxs_fcfi_alloc() */ static uint32_t emlxs_fcfi_free(emlxs_port_t *port, FCFIobj_t *fcfp) { uint32_t rval = 0; rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_FREE, 0, 0, 0); return (rval); } /* emlxs_fcfi_free() */ static FCFIobj_t * emlxs_fcfi_find(emlxs_port_t *port, FCF_RECORD_t *fcfrec, uint32_t *fcf_index) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t i; uint32_t index; FCFIobj_t *fcfp; if (fcfrec) { /* Check for a matching FCF index, fabric name, */ /* and mac address */ fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { if (fcfp->state == FCFI_STATE_FREE) { continue; } if ((fcfp->fcf_index == fcfrec->fcf_index) && (bcmp((char *)fcfrec->fabric_name_identifier, fcfp->fcf_rec.fabric_name_identifier, 8) == 0) && (bcmp((char *)fcfrec->fcf_mac_address_hi, fcfp->fcf_rec.fcf_mac_address_hi, 4) == 0) && (bcmp((char *)fcfrec->fcf_mac_address_low, fcfp->fcf_rec.fcf_mac_address_low, 2) == 0)) { return (fcfp); } } } else if (fcf_index) { /* Check for a matching FCF index only */ index = *fcf_index; fcfp = fcftab->table; for (i = 0; i < fcftab->table_count; i++, fcfp++) { if (fcfp->state == FCFI_STATE_FREE) { continue; } if (fcfp->fcf_index == index) { return (fcfp); } } } return (NULL); } /* emlxs_fcfi_find() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_free_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { if (fcfp->state != FCFI_STATE_FREE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_free_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcfp->vfi_online) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_free_action:%d flag=%x vfi_online=%d", fcfp->fcf_index, fcfp->flag, fcfp->vfi_online); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_free_action:%d flag=%x. FCF freed. <", fcfp->fcf_index, fcfp->flag); fcfp->flag = 0; return (0); } /* emlxs_fcfi_free_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_offline_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; if (fcfp->state != FCFI_STATE_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_offline_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } fcfp->flag &= ~(EMLXS_FCFI_OFFLINE_REQ | EMLXS_FCFI_PAUSE_REQ); if (fcfp->prev_state == FCFI_STATE_FREE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_offline_action:%d fcfi_online=%d. <", fcfp->fcf_index, fcftab->fcfi_online); return (0); } if (fcfp->vfi_online) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_offline_action:%d vfi_online=%d.", fcfp->fcf_index, fcfp->vfi_online); } if (fcfp->flag & EMLXS_FCFI_FCFTAB) { fcfp->flag &= ~EMLXS_FCFI_FCFTAB; if (fcftab->fcfi_online) { fcftab->fcfi_online--; } } /* Check if online was requested */ if (fcfp->flag & EMLXS_FCFI_ONLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_offline_action:%d fcfi_online=%d. " "Online requested.", fcfp->fcf_index, fcftab->fcfi_online); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_REG, FCF_REASON_REQUESTED, 0, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_offline_action:%d fcfi_online=%d. " "FCFI offline. Notifying fcftab. >", fcfp->fcf_index, fcftab->fcfi_online); /* Notify FCFTAB */ rval = emlxs_fcftab_event(port, FCF_EVENT_FCFI_OFFLINE, fcfp); return (rval); } /* emlxs_fcfi_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_vfi_online_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; if (evt != FCF_EVENT_VFI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_vfi_online_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1, fcfp->flag); return (1); } switch (fcfp->state) { case FCFI_STATE_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_online_evt_action:%d flag=%x vfi_online=%d. " "Reentering online.", fcfp->fcf_index, fcfp->flag, fcfp->vfi_online); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_ONLINE, FCF_REASON_REENTER, evt, arg1); break; case FCFI_STATE_VFI_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_online_evt_action:%d flag=%x vfi_online=%d. " "Online cmpl.", fcfp->fcf_index, fcfp->flag, fcfp->vfi_online); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_VFI_ONLINE_CMPL, FCF_REASON_EVENT, evt, arg1); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_online_evt_action:%d flag=%x vfi_online=%d. <", fcfp->fcf_index, fcfp->flag, fcfp->vfi_online); return (0); } return (rval); } /* emlxs_fcfi_vfi_online_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_offline_handler(emlxs_port_t *port, FCFIobj_t *fcfp, void *arg1) { uint32_t rval = 0; if (!(fcfp->flag & EMLXS_FCFI_OFFLINE_REQ)) { return (0); } if (fcfp->vfi_online) { if (fcfp->flag & EMLXS_FCFI_PAUSE_REQ) { rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_PAUSED, FCF_REASON_REQUESTED, 0, arg1); } else { rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_VFI_OFFLINE, FCF_REASON_REQUESTED, 0, arg1); } } else if (fcfp->flag & EMLXS_FCFI_REG) { rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_UNREG, FCF_REASON_REQUESTED, 0, arg1); } else { rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_OFFLINE, FCF_REASON_REQUESTED, 0, arg1); } return (rval); } /* emlxs_fcfi_offline_handler() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_vfi_offline_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; VFIobj_t *vfip; if (evt != FCF_EVENT_VFI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_vfi_offline_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1, fcfp->flag); return (1); } vfip = (VFIobj_t *)arg1; vfip->fcfp = NULL; switch (fcfp->state) { case FCFI_STATE_VFI_ONLINE: case FCFI_STATE_ONLINE: if (fcfp->vfi_online == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_evt_action:%d flag=%x " "vfi_online=%d. Offlining.", fcfp->fcf_index, fcfp->flag, fcfp->vfi_online); fcfp->flag &= ~EMLXS_FCFI_REQ_MASK; fcfp->flag |= EMLXS_FCFI_OFFLINE_REQ; rval = emlxs_fcfi_offline_handler(port, fcfp, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_evt_action:%d flag=%x " "vfi_online=%d. <", fcfp->fcf_index, fcfp->flag, fcfp->vfi_online); } break; case FCFI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_evt_action:%d flag=%x vfi_online=%d. <", fcfp->fcf_index, fcfp->flag, fcfp->vfi_online); break; case FCFI_STATE_VFI_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_evt_action:%d flag=%x. Offline cmpl.", fcfp->fcf_index, fcfp->flag); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_VFI_OFFLINE_CMPL, FCF_REASON_EVENT, evt, arg1); break; case FCFI_STATE_VFI_OFFLINE_CMPL: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_evt_action:%d flag=%x. Offline cmpl.", fcfp->fcf_index, fcfp->flag); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_VFI_OFFLINE_CMPL, FCF_REASON_REENTER, evt, arg1); break; default: if (fcfp->vfi_online == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_evt_action:%d flag=%x " "vfi_online=%d. Offline requested. <", fcfp->fcf_index, fcfp->flag, fcfp->vfi_online); fcfp->flag &= ~EMLXS_FCFI_REQ_MASK; fcfp->flag |= EMLXS_FCFI_OFFLINE_REQ; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_evt_action:%d flag = %x " "vfi_online=%d. <", fcfp->fcf_index, fcfp->flag, fcfp->vfi_online); } return (0); } return (rval); } /* emlxs_fcfi_vfi_offline_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_online_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; if (evt != FCF_EVENT_FCFI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_online_evt_action:%d %s:%s arg=%p. " "Invalid event type. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcfp->flag & EMLXS_FCFI_ONLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_online_evt_action:%d. " "Online already requested. <", fcfp->fcf_index); return (1); } fcfp->flag &= ~EMLXS_FCFI_REQ_MASK; fcfp->flag |= EMLXS_FCFI_ONLINE_REQ; switch (fcfp->state) { case FCFI_STATE_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_online_evt_action:%d flag=%x. Initiating online.", fcfp->fcf_index, fcfp->flag); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_REG, FCF_REASON_EVENT, evt, arg1); break; case FCFI_STATE_VFI_OFFLINE: case FCFI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_online_evt_action:%d flag=%x. Initiating online.", fcfp->fcf_index, fcfp->flag); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_VFI_ONLINE, FCF_REASON_EVENT, evt, arg1); break; case FCFI_STATE_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_online_evt_action:%d flag=%x. Reentering online.", fcfp->fcf_index, fcfp->flag); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_ONLINE, FCF_REASON_REENTER, evt, arg1); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_online_evt_action:%d flag=%x. <", fcfp->fcf_index, fcfp->flag); break; } return (rval); } /* emlxs_fcfi_online_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_vfi_online_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t i; uint32_t rval = 0; VFIobj_t *vfip; if (fcfp->state != FCFI_STATE_VFI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_vfi_online_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcfp->flag & EMLXS_FCFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_online_action:%d. Offline requested.", fcfp->fcf_index); rval = emlxs_fcfi_offline_handler(port, fcfp, arg1); return (rval); } if (fcfp->vfi_online > 0) { /* Waking up out after being paused */ /* Find first VFI of this FCFI */ vfip = hba->sli.sli4.VFI_table; for (i = 0; i < hba->sli.sli4.VFICount; i++, vfip++) { if (vfip->fcfp == fcfp) { break; } } } else { /* Find first available VFI */ vfip = hba->sli.sli4.VFI_table; for (i = 0; i < hba->sli.sli4.VFICount; i++, vfip++) { if (vfip->fcfp == NULL) { vfip->fcfp = fcfp; break; } } } if (i == hba->sli.sli4.VFICount) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_online_action:%d vfi_online=%d. " "No VFI found. Offlining.", fcfp->fcf_index, fcfp->vfi_online); fcfp->flag &= ~EMLXS_FCFI_REQ_MASK; fcfp->flag |= EMLXS_FCFI_OFFLINE_REQ; rval = emlxs_fcfi_offline_handler(port, fcfp, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_online_action:%d vfi_online=%d. Onlining VFI:%d. >", fcfp->fcf_index, fcfp->vfi_online, vfip->VFI); rval = emlxs_vfi_event(port, FCF_EVENT_VFI_ONLINE, vfip); /* Wait for FCF_EVENT_VFI_ONLINE in return */ return (rval); } /* emlxs_fcfi_vfi_online_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_vfi_online_cmpl_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; if (fcfp->state != FCFI_STATE_VFI_ONLINE_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_vfi_online_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_online_cmpl_action:%d. Going online.", fcfp->fcf_index); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fcfi_vfi_online_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_vfi_offline_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; VFIobj_t *vfip; uint32_t rval = 0; int32_t i; if (fcfp->state != FCFI_STATE_VFI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcfp->flag & EMLXS_FCFI_PAUSE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_action:%d vfi_online=%d. Pausing.", fcfp->fcf_index, fcfp->vfi_online); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_PAUSED, FCF_REASON_EVENT, evt, arg1); return (rval); } if (fcfp->vfi_online == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_action:%d. " "VFI already offline. Skipping VFI offline.", fcfp->fcf_index); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_UNREG, FCF_REASON_EVENT, evt, arg1); return (rval); } /* Offline VFI's of this FCFI */ for (i = (hba->sli.sli4.VFICount-1); i >= 0; i--) { vfip = &hba->sli.sli4.VFI_table[i]; if ((vfip->fcfp != fcfp) || (vfip->state == VFI_STATE_OFFLINE) || (vfip->flag & EMLXS_VFI_OFFLINE_REQ)) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_action:%d. Offlining VFI:%d >", fcfp->fcf_index, vfip->VFI); (void) emlxs_vfi_event(port, FCF_EVENT_VFI_OFFLINE, vfip); } /* Wait for FCF_EVENT_VFI_OFFLINE in return */ return (0); } /* emlxs_fcfi_vfi_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_paused_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; VFIobj_t *vfip; int32_t i; if (fcfp->state != FCFI_STATE_PAUSED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_paused_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } fcfp->flag &= ~(EMLXS_FCFI_OFFLINE_REQ | EMLXS_FCFI_PAUSE_REQ); /* Pause all VFI's of this FCFI */ for (i = (hba->sli.sli4.VFICount-1); i >= 0; i--) { vfip = &hba->sli.sli4.VFI_table[i]; if ((vfip->state == VFI_STATE_OFFLINE) || (vfip->state == VFI_STATE_PAUSED) || (vfip->fcfp != fcfp)) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_paused_action:%d vfi_online=%d. Pausing VFI:%d. >", fcfp->fcf_index, fcfp->vfi_online, vfip->VFI); (void) emlxs_vfi_event(port, FCF_EVENT_VFI_PAUSE, vfip); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_paused_action:%d vfi_online=%d. FCFI paused. <", fcfp->fcf_index, fcfp->vfi_online); return (0); } /* emlxs_fcfi_paused_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_vfi_offline_cmpl_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; if (fcfp->state != FCFI_STATE_VFI_OFFLINE_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_vfi_offline_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if ((fcfp->vfi_online == 0) && (fcfp->flag & EMLXS_FCFI_OFFLINE_REQ)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_cmpl_action:%d vfi_online=%d. " "Unregistering.", fcfp->fcf_index, fcfp->vfi_online); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_UNREG, FCF_REASON_EVENT, evt, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_vfi_offline_cmpl_action:%d vfi_online=%d. <", fcfp->fcf_index, fcfp->vfi_online); } return (rval); } /* emlxs_fcfi_vfi_offline_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_offline_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; if (evt != FCF_EVENT_FCFI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_offline_evt_action:%d %s:%s arg=%p. " "Invalid event type. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if ((fcfp->flag & EMLXS_FCFI_OFFLINE_REQ) && !(fcfp->flag & EMLXS_FCFI_PAUSE_REQ)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_offline_evt_action:%d. Offline already requested. <", fcfp->fcf_index); return (1); } switch (fcfp->state) { case FCFI_STATE_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_offline_evt_action:%d flag=%x. Already offline. <", fcfp->fcf_index, fcfp->flag); break; /* Wait states */ case FCFI_STATE_VFI_ONLINE: case FCFI_STATE_VFI_OFFLINE: case FCFI_STATE_REG: case FCFI_STATE_ONLINE: case FCFI_STATE_PAUSED: fcfp->flag &= ~EMLXS_FCFI_REQ_MASK; fcfp->flag |= EMLXS_FCFI_OFFLINE_REQ; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_offline_evt_action:%d flag=%x. Handling offline.", fcfp->fcf_index, fcfp->flag); /* Handle offline now */ rval = emlxs_fcfi_offline_handler(port, fcfp, arg1); break; /* Transitional states */ default: fcfp->flag &= ~EMLXS_FCFI_REQ_MASK; fcfp->flag |= EMLXS_FCFI_OFFLINE_REQ; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_offline_evt_action:%d. " "Invalid state. <", fcfp->fcf_index); break; } return (rval); } /* emlxs_fcfi_offline_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_pause_evt_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; if (evt != FCF_EVENT_FCFI_PAUSE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_pause_evt_action:%d %s:%s arg=%p. " "Invalid event type. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcfp->flag & EMLXS_FCFI_PAUSE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_pause_evt_action:%d. Pause already requested. <", fcfp->fcf_index); return (1); } if (fcfp->flag & EMLXS_FCFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_pause_evt_action:%d. Offline already requested. <", fcfp->fcf_index); return (1); } switch (fcfp->state) { case FCFI_STATE_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_pause_evt_action:%d flag=%x. Already offline. <", fcfp->fcf_index, fcfp->flag); break; case FCFI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_pause_evt_action:%d flag=%x. Already paused. <", fcfp->fcf_index, fcfp->flag); break; /* Wait states */ case FCFI_STATE_VFI_ONLINE: case FCFI_STATE_VFI_OFFLINE: case FCFI_STATE_REG: case FCFI_STATE_ONLINE: fcfp->flag &= ~EMLXS_FCFI_REQ_MASK; fcfp->flag |= (EMLXS_FCFI_OFFLINE_REQ | EMLXS_FCFI_PAUSE_REQ); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_pause_evt_action:%d flag=%x. Handle pause request.", fcfp->fcf_index, fcfp->flag); /* Handle offline now */ rval = emlxs_fcfi_offline_handler(port, fcfp, arg1); break; /* Transitional states */ default: fcfp->flag &= ~EMLXS_FCFI_REQ_MASK; fcfp->flag |= (EMLXS_FCFI_OFFLINE_REQ | EMLXS_FCFI_PAUSE_REQ); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_pause_evt_action:%d. " "Invalid state. <", fcfp->fcf_index); break; } return (rval); } /* emlxs_fcfi_pause_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_unreg_failed_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; fcfp->attempts++; if (fcfp->state != FCFI_STATE_UNREG_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_unreg_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1, fcfp->attempts); return (1); } if ((fcfp->reason == FCF_REASON_SEND_FAILED) || (fcfp->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_unreg_failed_action:%d attempt=%d reason=%x. " "Unreg cmpl.", fcfp->fcf_index, fcfp->attempts, fcfp->reason); fcfp->flag &= ~EMLXS_FCFI_REG; rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_UNREG_CMPL, FCF_REASON_OP_FAILED, fcfp->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_unreg_failed_action:%d attempt=%d. Unregistering.", fcfp->fcf_index, arg1, fcfp->attempts); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_UNREG, FCF_REASON_OP_FAILED, fcfp->attempts, arg1); } return (rval); } /* emlxs_fcfi_unreg_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_reg_failed_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; fcfp->attempts++; if (fcfp->state != FCFI_STATE_REG_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_reg_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1, fcfp->attempts); return (1); } if ((fcfp->reason == FCF_REASON_SEND_FAILED) || (fcfp->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_failed_action:%d attempt=%d reason=%x. Reg cmpl.", fcfp->fcf_index, fcfp->attempts, fcfp->reason); fcfp->flag &= ~EMLXS_FCFI_REQ_MASK; fcfp->flag |= EMLXS_FCFI_OFFLINE_REQ; rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_REG_CMPL, FCF_REASON_OP_FAILED, fcfp->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_failed_action:%d attempt=%d. Registering.", fcfp->fcf_index, fcfp->attempts); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_REG, FCF_REASON_OP_FAILED, fcfp->attempts, arg1); } return (rval); } /* emlxs_fcfi_reg_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_reg_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; MAILBOX4 *mb4; FCFIobj_t *fcfp; fcfp = (FCFIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; mutex_enter(&EMLXS_FCF_LOCK); if (fcfp->state != FCFI_STATE_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_mbcmpl:%d state=%s.", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_mbcmpl:%d failed. %s. >", fcfp->fcf_index, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_fcfi_state(port, fcfp, FCFI_STATE_REG_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } fcfp->FCFI = mb4->un.varRegFCFI.FCFI; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_mbcmpl:%d FCFI=%d. Reg complete. >", fcfp->fcf_index, fcfp->FCFI); fcfp->flag |= EMLXS_FCFI_REG; (void) emlxs_fcfi_state(port, fcfp, FCFI_STATE_REG_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_fcfi_reg_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_reg_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; MAILBOX4 *mb4; MAILBOXQ *mbq; uint32_t rval = 0; if (fcfp->state != FCFI_STATE_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_reg_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!(fcfp->flag & EMLXS_FCFI_FCFTAB)) { fcfp->flag |= EMLXS_FCFI_FCFTAB; fcftab->fcfi_online++; } if (fcfp->prev_state != FCFI_STATE_REG_FAILED) { fcfp->attempts = 0; } if (fcfp->flag & EMLXS_FCFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_action:%d attempts=%d. Offline requested.", fcfp->fcf_index, fcfp->attempts); rval = emlxs_fcfi_offline_handler(port, fcfp, arg1); return (rval); } if (fcfp->flag & EMLXS_FCFI_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_action:%d. Already registered. " "Skipping REG_FCFI update.", fcfp->fcf_index); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_VFI_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_action:%d attempts=%d. Sending REG_FCFI. <", fcfp->fcf_index, fcfp->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_REG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); mbq->mbox_cmpl = emlxs_fcfi_reg_mbcmpl; mbq->context = (void *)fcfp; mbq->port = (void *)port; mb4->mbxCommand = MBX_REG_FCFI; mb4->mbxOwner = OWN_HOST; mb4->un.varRegFCFI.FCFI = 0; /* FCFI will be returned by firmware */ mb4->un.varRegFCFI.InfoIndex = fcfp->fcf_index; mb4->un.varRegFCFI.RQId0 = hba->sli.sli4.rq[EMLXS_FCFI_RQ0_INDEX].qid; mb4->un.varRegFCFI.Id0_rctl_mask = EMLXS_FCFI_RQ0_RMASK; mb4->un.varRegFCFI.Id0_rctl = EMLXS_FCFI_RQ0_RCTL; mb4->un.varRegFCFI.Id0_type_mask = EMLXS_FCFI_RQ0_TMASK; mb4->un.varRegFCFI.Id0_type = EMLXS_FCFI_RQ0_TYPE; mb4->un.varRegFCFI.RQId1 = 0xffff; mb4->un.varRegFCFI.RQId2 = 0xffff; mb4->un.varRegFCFI.RQId3 = 0xffff; if (fcfp->flag & EMLXS_FCFI_VLAN_ID) { mb4->un.varRegFCFI.vv = 1; mb4->un.varRegFCFI.vlanTag = fcfp->vlan_id; } /* Ignore the fcf record and force FPMA */ mb4->un.varRegFCFI.mam = EMLXS_REG_FCFI_MAM_FPMA; rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_REG_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_fcfi_reg_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_reg_cmpl_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; if (fcfp->state != FCFI_STATE_REG_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_reg_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (fcfp->flag & EMLXS_FCFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_cmpl_action:%d. Offline requested.", fcfp->fcf_index); rval = emlxs_fcfi_offline_handler(port, fcfp, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_reg_cmpl_action:%d attempts=%d. Reg cmpl.", fcfp->fcf_index, fcfp->attempts); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_VFI_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fcfi_reg_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_unreg_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; MAILBOX4 *mb4; FCFIobj_t *fcfp; fcfp = (FCFIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; mutex_enter(&EMLXS_FCF_LOCK); if (fcfp->state != FCFI_STATE_UNREG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_unreg_mbcmpl:%d state=%s.", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_unreg_mbcmpl:%d failed. %s. >", fcfp->fcf_index, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_fcfi_state(port, fcfp, FCFI_STATE_UNREG_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_unreg_mbcmpl:%d. Unreg complete. >", fcfp->fcf_index); fcfp->flag &= ~EMLXS_FCFI_REG; (void) emlxs_fcfi_state(port, fcfp, FCFI_STATE_UNREG_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_fcfi_unreg_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_unreg_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; MAILBOX4 *mb4; MAILBOXQ *mbq; uint32_t rval = 0; if (fcfp->state != FCFI_STATE_UNREG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_unreg_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!(fcfp->flag & EMLXS_FCFI_REG)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_unreg_action:%d. Not registered. " "Skipping UNREG_FCFI.", fcfp->fcf_index); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (fcfp->prev_state != FCFI_STATE_UNREG_FAILED) { fcfp->attempts = 0; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_unreg_action:%d attempts=%d. Sending UNREG_FCFI. <", fcfp->fcf_index, fcfp->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_UNREG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); mbq->mbox_cmpl = emlxs_fcfi_unreg_mbcmpl; mbq->context = (void *)fcfp; mbq->port = (void *)port; mb4->mbxCommand = MBX_UNREG_FCFI; mb4->mbxOwner = OWN_HOST; mb4->un.varUnRegFCFI.FCFI = fcfp->FCFI; rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_UNREG_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_fcfi_unreg_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_unreg_cmpl_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { uint32_t rval = 0; if (fcfp->state != FCFI_STATE_UNREG_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_unreg_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_unreg_cmpl_action:%d attempts=%d. Going offline.", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1, fcfp->attempts); rval = emlxs_fcfi_state(port, fcfp, FCFI_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_fcfi_unreg_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_fcfi_online_action(emlxs_port_t *port, FCFIobj_t *fcfp, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t rval = 0; VFIobj_t *vfip; uint32_t i; if (fcfp->state != FCFI_STATE_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "fcfi_online_action:%d %s:%s arg=%p. " "Invalid state. <", fcfp->fcf_index, emlxs_fcfi_state_xlate(fcfp->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } fcfp->flag &= ~EMLXS_FCFI_ONLINE_REQ; if (fcfp->flag & EMLXS_FCFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_online_action:%d attempts=%d. Offline requested.", fcfp->fcf_index, fcfp->attempts); rval = emlxs_fcfi_offline_handler(port, fcfp, arg1); return (rval); } /* Online remaining VFI's for this FCFI */ vfip = hba->sli.sli4.VFI_table; for (i = 0; i < hba->sli.sli4.VFICount; i++, vfip++) { if (vfip->fcfp != fcfp) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_online_action:%d vfi_online=%d. Onlining VFI:%d. >", fcfp->fcf_index, fcfp->vfi_online, vfip->VFI); (void) emlxs_vfi_event(port, FCF_EVENT_VFI_ONLINE, vfip); } if (fcfp->prev_state != FCFI_STATE_ONLINE) { /* Perform VSAN discovery check when first VFI goes online */ if (fcfp->vfi_online < FCFI_MAX_VFI_COUNT) { /* Perform VSAN Discovery (TBD) */ /* For now we only need 1 VFI */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_online_action:%d vfi_online=%d. " "VSAN discovery required.", fcfp->fcf_index, fcfp->vfi_online); } } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi_online_action:%d vfi_online=%d. " "FCFI online. Notifying fcftab. >", fcfp->fcf_index, fcfp->vfi_online); /* Notify FCFTAB */ rval = emlxs_fcftab_event(port, FCF_EVENT_FCFI_ONLINE, fcfp); return (rval); } /* emlxs_fcfi_online_action() */ /*ARGSUSED*/ static int emlxs_fcf_configured(emlxs_port_t *port, FCFIobj_t *fcfp) { emlxs_hba_t *hba = HBA; int i; uint32_t entry_count; uint32_t valid_entry; uint32_t match_found; uint16_t VLanId; FCF_RECORD_t *fcfrec = &fcfp->fcf_rec; uint32_t j; uint32_t k; /* Init the primary flag, we may set it later */ fcfp->flag &= ~(EMLXS_FCFI_PRIMARY|EMLXS_FCFI_BOOT); if (!(hba->flag & FC_FIP_SUPPORTED)) { if (!hba->sli.sli4.cfgFCOE.length) { /* Nothing specified, so everything matches */ /* For nonFIP only use index 0 */ if (fcfrec->fcf_index == 0) { return (1); /* success */ } return (0); } /* Just check FCMap for now */ if (bcmp((char *)fcfrec->fc_map, hba->sli.sli4.cfgFCOE.FCMap, 3) == 0) { return (1); /* success */ } return (0); } /* For FIP mode, the FCF record must match Config Region 23 */ entry_count = (hba->sli.sli4.cfgFCF.length * sizeof (uint32_t)) / sizeof (tlv_fcfconnectentry_t); valid_entry = 0; match_found = 0; for (i = 0; i < entry_count; i++) { if (!hba->sli.sli4.cfgFCF.entry[i].Valid) { continue; } if (hba->sli.sli4.cfgFCF.entry[i].FabricNameValid) { valid_entry = 1; if (bcmp((char *)fcfrec->fabric_name_identifier, hba->sli.sli4.cfgFCF.entry[i].FabricName, 8)) { match_found = 0; continue; } match_found = 1; } if (hba->sli.sli4.cfgFCF.entry[i].SwitchNameValid) { valid_entry = 1; if (bcmp((char *)fcfrec->switch_name_identifier, hba->sli.sli4.cfgFCF.entry[i].SwitchName, 8)) { match_found = 0; continue; } match_found = 1; } if (hba->sli.sli4.cfgFCF.entry[i].VLanValid) { valid_entry = 1; if (!(fcfp->flag & EMLXS_FCFI_VLAN_ID)) { match_found = 0; continue; } VLanId = hba->sli.sli4.cfgFCF.entry[i].VLanId; j = VLanId / 8; k = 1 << (VLanId % 8); if (!(fcfrec->vlan_bitmap[j] & k)) { match_found = 0; continue; } /* Assign requested vlan_id to this FCF */ fcfp->vlan_id = VLanId; match_found = 1; } /* If a match was found */ if (match_found) { if (hba->sli.sli4.cfgFCF.entry[i].Primary) { fcfp->flag |= EMLXS_FCFI_PRIMARY; } if (hba->sli.sli4.cfgFCF.entry[i].Boot) { fcfp->flag |= EMLXS_FCFI_BOOT; } return (1); } } /* If no valid entries found, then allow any fabric */ if (!valid_entry) { return (1); } return (0); } /* emlxs_fcf_configured() */ static void emlxs_fcfi_update(emlxs_port_t *port, FCFIobj_t *fcfp, FCF_RECORD_t *fcf_rec, uint32_t event_tag) { emlxs_hba_t *hba = HBA; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint16_t i; bcopy((char *)fcf_rec, &fcfp->fcf_rec, sizeof (FCF_RECORD_t)); fcfp->fcf_index = fcf_rec->fcf_index; /* Clear VLAN info */ fcfp->vlan_id = 0; fcfp->flag &= ~EMLXS_FCFI_VLAN_ID; /* Check if fcf is a member of a VLAN */ for (i = 0; i < 4096; i++) { if (fcf_rec->vlan_bitmap[i / 8] & (1 << (i % 8))) { /* For now assign the VLAN id of the first VLAN found */ fcfp->vlan_id = i; fcfp->flag |= EMLXS_FCFI_VLAN_ID; break; } } if (fcf_rec->fcf_available) { fcfp->flag |= EMLXS_FCFI_AVAILABLE; } else { fcfp->flag &= ~EMLXS_FCFI_AVAILABLE; } if (fcf_rec->fcf_valid && !fcf_rec->fcf_sol) { fcfp->flag |= EMLXS_FCFI_VALID; } else { fcfp->flag &= ~EMLXS_FCFI_VALID; } /* Check config region 23 */ /* Also sets BOOT and PRIMARY cfg bits as needed */ if (emlxs_fcf_configured(port, fcfp)) { fcfp->flag |= EMLXS_FCFI_CONFIGURED; } else { fcfp->flag &= ~EMLXS_FCFI_CONFIGURED; } /* Set fcfp priority. Used by selection alogithm */ /* Combination of BOOT:PRIMARY:~fip_priority */ fcfp->priority = (fcfp->flag & EMLXS_FCFI_BOOT)? 0x200:0; fcfp->priority |= (fcfp->flag & EMLXS_FCFI_PRIMARY)? 0x100:0; fcfp->priority |= ~(fcf_rec->fip_priority & 0xff); fcfp->event_tag = event_tag; fcfp->generation = fcftab->generation; fcfp->flag |= EMLXS_FCFI_FRESH; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi:%d gen=%x iotag=%d flag=%x sol=%x avl=%x val=%x state=%x " "map=%x pri=%x vid=%x", fcf_rec->fcf_index, fcfp->generation, fcfp->event_tag, fcfp->flag, fcf_rec->fcf_sol, fcf_rec->fcf_available, fcf_rec->fcf_valid, fcf_rec->fcf_state, fcf_rec->mac_address_provider, fcfp->priority, fcfp->vlan_id); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "fcfi:%d mac=%02x:%02x:%02x:%02x:%02x:%02x " "fabric=%02x%02x%02x%02x%02x%02x%02x%02x " "switch=%02x%02x%02x%02x%02x%02x%02x%02x", fcfp->fcf_index, fcf_rec->fcf_mac_address_hi[0], fcf_rec->fcf_mac_address_hi[1], fcf_rec->fcf_mac_address_hi[2], fcf_rec->fcf_mac_address_hi[3], fcf_rec->fcf_mac_address_low[0], fcf_rec->fcf_mac_address_low[1], fcf_rec->fabric_name_identifier[0], fcf_rec->fabric_name_identifier[1], fcf_rec->fabric_name_identifier[2], fcf_rec->fabric_name_identifier[3], fcf_rec->fabric_name_identifier[4], fcf_rec->fabric_name_identifier[5], fcf_rec->fabric_name_identifier[6], fcf_rec->fabric_name_identifier[7], fcf_rec->switch_name_identifier[0], fcf_rec->switch_name_identifier[1], fcf_rec->switch_name_identifier[2], fcf_rec->switch_name_identifier[3], fcf_rec->switch_name_identifier[4], fcf_rec->switch_name_identifier[5], fcf_rec->switch_name_identifier[6], fcf_rec->switch_name_identifier[7]); return; } /* emlxs_fcfi_update() */ /* ************************************************************************** */ /* VFI */ /* ************************************************************************** */ static char * emlxs_vfi_state_xlate(uint32_t state) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_vfi_state_table) / sizeof (emlxs_table_t); for (i = 0; i < count; i++) { if (state == emlxs_vfi_state_table[i].code) { return (emlxs_vfi_state_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "state=0x%x", state); return (buffer); } /* emlxs_vfi_state_xlate() */ static uint32_t emlxs_vfi_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; uint32_t(*func) (emlxs_port_t *, VFIobj_t *, uint32_t, void *); uint32_t index; uint32_t events; uint16_t state; /* Convert event to action table index */ switch (evt) { case FCF_EVENT_STATE_ENTER: index = 0; break; case FCF_EVENT_VFI_ONLINE: index = 1; break; case FCF_EVENT_VFI_OFFLINE: index = 2; break; case FCF_EVENT_VFI_PAUSE: index = 3; break; case FCF_EVENT_VPI_ONLINE: index = 4; break; case FCF_EVENT_VPI_OFFLINE: index = 5; break; default: return (1); } events = VFI_ACTION_EVENTS; state = vfip->state; index += (state * events); func = (uint32_t(*) (emlxs_port_t *, VFIobj_t *, uint32_t, void *)) emlxs_vfi_action_table[index]; if (!func) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "vfi_action:%d %s:%s arg=%p. No action. <", vfip->VFI, emlxs_vfi_state_xlate(state), emlxs_fcf_event_xlate(evt), arg1); return (1); } rval = (func)(port, vfip, evt, arg1); return (rval); } /* emlxs_vfi_action() */ static uint32_t emlxs_vfi_event(emlxs_port_t *port, uint32_t evt, void *arg1) { VPIobj_t *vpip = NULL; VFIobj_t *vfip = NULL; uint32_t rval = 0; /* Filter events and acquire fcfi context */ switch (evt) { case FCF_EVENT_VPI_ONLINE: case FCF_EVENT_VPI_OFFLINE: vpip = (VPIobj_t *)arg1; if (!vpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "vfi_event: %s arg=%p. Null VPI found. <", emlxs_fcf_event_xlate(evt), arg1); return (1); } vfip = vpip->vfip; if (!vfip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "vfi_event: %s arg=%p. VFI not found. <", emlxs_fcf_event_xlate(evt), arg1); return (1); } break; case FCF_EVENT_VFI_ONLINE: case FCF_EVENT_VFI_OFFLINE: case FCF_EVENT_VFI_PAUSE: vfip = (VFIobj_t *)arg1; if (!vfip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "vfi_event: %s arg=%p. VFI not found. <", emlxs_fcf_event_xlate(evt), arg1); return (1); } break; default: return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "vfi_event:%d %s:%s arg=%p", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_vfi_action(port, vfip, evt, arg1); return (rval); } /* emlxs_vfi_event() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_state(emlxs_port_t *port, VFIobj_t *vfip, uint16_t state, uint16_t reason, uint32_t explain, void *arg1) { uint32_t rval = 0; if (state >= VFI_ACTION_STATES) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_state:%d %s. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state)); return (1); } if ((vfip->state == state) && (reason != FCF_REASON_REENTER)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_state:%d %s:%s:0x%x arg=%p. " "State not changed. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_reason_xlate(reason), explain, arg1); return (1); } if (!reason) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "vfi_state:%d %s-->%s arg=%p", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_vfi_state_xlate(state), arg1); } else if (reason == FCF_REASON_EVENT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "vfi_state:%d %s-->%s:%s:%s arg=%p", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_vfi_state_xlate(state), emlxs_fcf_reason_xlate(reason), emlxs_fcf_event_xlate(explain), arg1); } else if (explain) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "vfi_state:%d %s-->%s:%s:0x%x arg=%p", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_vfi_state_xlate(state), emlxs_fcf_reason_xlate(reason), explain, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "vfi_state:%d %s-->%s:%s arg=%p", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_vfi_state_xlate(state), emlxs_fcf_reason_xlate(reason), arg1); } vfip->prev_state = vfip->state; vfip->prev_reason = vfip->reason; vfip->state = state; vfip->reason = reason; rval = emlxs_vfi_action(port, vfip, FCF_EVENT_STATE_ENTER, arg1); return (rval); } /* emlxs_vfi_state() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_vpi_online_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (evt != FCF_EVENT_VPI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_vpi_online_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1, vfip->flag); return (1); } switch (vfip->state) { case VFI_STATE_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_evt_action:%d flag=%x vpi_online=%d. " "Reentering online.", vfip->VFI, vfip->flag, vfip->vpi_online); rval = emlxs_vfi_state(port, vfip, VFI_STATE_ONLINE, FCF_REASON_REENTER, evt, arg1); break; case VFI_STATE_VPI_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_evt_action:%d flag=%x vpi_online=%d. " "Online cmpl.", vfip->VFI, vfip->flag, vfip->vpi_online); rval = emlxs_vfi_state(port, vfip, VFI_STATE_VPI_ONLINE_CMPL, FCF_REASON_EVENT, evt, arg1); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_evt_action:%d flag=%x vpi_online=%d. <", vfip->VFI, vfip->flag, vfip->vpi_online); return (1); } return (rval); } /* emlxs_vfi_vpi_online_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_offline_handler(emlxs_port_t *port, VFIobj_t *vfip, void *arg1) { uint32_t rval = 0; if (!(vfip->flag & EMLXS_VFI_OFFLINE_REQ)) { return (0); } if (vfip->vpi_online) { if (vfip->flag & EMLXS_VFI_PAUSE_REQ) { rval = emlxs_vfi_state(port, vfip, VFI_STATE_PAUSED, FCF_REASON_REQUESTED, 0, arg1); } else { rval = emlxs_vfi_state(port, vfip, VFI_STATE_VPI_OFFLINE, FCF_REASON_REQUESTED, 0, arg1); } } else if (vfip->flag & EMLXS_VFI_REG) { rval = emlxs_vfi_state(port, vfip, VFI_STATE_UNREG, FCF_REASON_REQUESTED, 0, arg1); } else if (vfip->flag & EMLXS_VFI_INIT) { rval = emlxs_vfi_state(port, vfip, VFI_STATE_UNREG, FCF_REASON_REQUESTED, 0, arg1); } else { rval = emlxs_vfi_state(port, vfip, VFI_STATE_OFFLINE, FCF_REASON_REQUESTED, 0, arg1); } return (rval); } /* emlxs_vfi_offline_handler() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_vpi_offline_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; VPIobj_t *vpip; if (evt != FCF_EVENT_VPI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_vpi_offline_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1, vfip->flag); return (1); } /* Disconnect VPI object from VFI */ vpip = (VPIobj_t *)arg1; vpip->vfip = NULL; switch (vfip->state) { case VFI_STATE_ONLINE: case VFI_STATE_VPI_ONLINE: if (vfip->vpi_online == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_evt_action:%d flag=%x " "vpi_online=%d. Offlining.", vfip->VFI, vfip->flag, vfip->vpi_online); vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= EMLXS_VFI_OFFLINE_REQ; rval = emlxs_vfi_offline_handler(port, vfip, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_evt_action:%d flag=%x " "vpi_online=%d. <", vfip->VFI, vfip->flag, vfip->vpi_online); } break; case VFI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_evt_action:%d flag=%x vpi_online=%d. <", vfip->VFI, vfip->flag, vfip->vpi_online); break; case VFI_STATE_VPI_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_evt_action:%d flag=%x. VPI offline cmpl.", vfip->VFI, vfip->flag); rval = emlxs_vfi_state(port, vfip, VFI_STATE_VPI_OFFLINE_CMPL, FCF_REASON_EVENT, evt, arg1); break; case VFI_STATE_VPI_OFFLINE_CMPL: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_evt_action:%d flag=%x. VPI offline cmpl.", vfip->VFI, vfip->flag); rval = emlxs_vfi_state(port, vfip, VFI_STATE_VPI_OFFLINE_CMPL, FCF_REASON_REENTER, evt, arg1); break; default: if (vfip->vpi_online == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_evt_action:%d flag=%x " "vpi_online=%d. Requesting offline. <", vfip->VFI, vfip->flag, vfip->vpi_online); vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= EMLXS_VFI_OFFLINE_REQ; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_evt_action:%d flag=%x " "vpi_online=%d. <", vfip->VFI, vfip->flag, vfip->vpi_online); } return (1); } return (rval); } /* emlxs_vfi_vpi_offline_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_online_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; emlxs_port_t *vport; VPIobj_t *vpip; uint32_t rval = 0; uint32_t i; if (evt != FCF_EVENT_VFI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_online_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1, vfip->flag); return (1); } if (vfip->flag & EMLXS_VFI_ONLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_evt_action:%d flag=%x. " "Online already requested. <", vfip->VFI, vfip->flag); return (0); } vfip->flag &= ~EMLXS_VFI_REQ_MASK; switch (vfip->state) { case VFI_STATE_OFFLINE: vfip->flag |= EMLXS_VFI_ONLINE_REQ; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_evt_action:%d flag=%x. Initiating online.", vfip->VFI, vfip->flag); rval = emlxs_vfi_state(port, vfip, VFI_STATE_INIT, FCF_REASON_EVENT, evt, arg1); break; case VFI_STATE_VPI_OFFLINE: case VFI_STATE_PAUSED: vfip->flag |= EMLXS_VFI_ONLINE_REQ; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_evt_action:%d flag=%x. Initiating online.", vfip->VFI, vfip->flag); rval = emlxs_vfi_state(port, vfip, VFI_STATE_VPI_ONLINE, FCF_REASON_EVENT, evt, arg1); break; case VFI_STATE_ONLINE: /* Online all VPI's belonging to this vfi */ for (i = 0; i <= hba->vpi_max; i++) { vport = &VPORT(i); vpip = vport->vpip; if (!(vport->flag & EMLXS_PORT_BOUND) || (vpip->flag & EMLXS_VPI_PORT_UNBIND)) { continue; } if (vpip->vfip != vfip) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_evt_action:%d. Onlining VPI:%d >", vfip->VFI, vpip->VPI); (void) emlxs_vpi_event(vport, FCF_EVENT_VPI_ONLINE, vpip); } break; default: vfip->flag |= EMLXS_VFI_ONLINE_REQ; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_evt_action:%d flag=%x. <", vfip->VFI, vfip->flag); return (1); } return (rval); } /* emlxs_vfi_online_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_offline_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (evt != FCF_EVENT_VFI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_offline_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1, vfip->flag); return (1); } if ((vfip->flag & EMLXS_VFI_OFFLINE_REQ) && !(vfip->flag & EMLXS_VFI_PAUSE_REQ)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_offline_evt_action:%d flag=%x. " "Offline already requested. <", vfip->VFI, vfip->flag); return (0); } switch (vfip->state) { case VFI_STATE_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_offline_evt_action:%d flag=%x. " "Already offline. <", vfip->VFI, vfip->flag); break; /* Wait states */ case VFI_STATE_VPI_ONLINE: case VFI_STATE_VPI_OFFLINE: case VFI_STATE_VPI_OFFLINE_CMPL: case VFI_STATE_INIT: case VFI_STATE_REG: case VFI_STATE_ONLINE: case VFI_STATE_PAUSED: vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= EMLXS_VFI_OFFLINE_REQ; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_offline_evt_action:%d flag=%x. Handling offline.", vfip->VFI, vfip->flag); /* Handle offline now */ rval = emlxs_vfi_offline_handler(port, vfip, arg1); break; default: vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= EMLXS_VFI_OFFLINE_REQ; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_offline_evt_action:%d flag=%x. <", vfip->VFI, vfip->flag); break; } return (rval); } /* emlxs_vfi_offline_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_pause_evt_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (evt != FCF_EVENT_VFI_PAUSE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_pause_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1, vfip->flag); return (1); } if (vfip->flag & EMLXS_VFI_PAUSE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_pause_evt_action:%d flag=%x. " "Pause already requested. <", vfip->VFI, vfip->flag); return (0); } if (vfip->flag & EMLXS_VFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_pause_evt_action:%d flag=%x. " "Offline already requested. <", vfip->VFI, vfip->flag); return (0); } switch (vfip->state) { case VFI_STATE_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_pause_evt_action:%d flag=%x. " "Already offline. <", vfip->VFI, vfip->flag); break; case VFI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_pause_evt_action:%d flag=%x. " "Already paused. <", vfip->VFI, vfip->flag); break; /* Wait states */ case VFI_STATE_VPI_ONLINE: case VFI_STATE_VPI_OFFLINE_CMPL: case VFI_STATE_INIT: case VFI_STATE_REG: case VFI_STATE_ONLINE: vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= (EMLXS_VFI_OFFLINE_REQ | EMLXS_VFI_PAUSE_REQ); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_pause_evt_action:%d flag=%x. Handling offline.", vfip->VFI, vfip->flag); /* Handle offline now */ rval = emlxs_vfi_offline_handler(port, vfip, arg1); break; default: vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= (EMLXS_VFI_OFFLINE_REQ | EMLXS_VFI_PAUSE_REQ); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_pause_evt_action:%d flag=%x. <", vfip->VFI, vfip->flag); break; } return (rval); } /* emlxs_vfi_pause_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_offline_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vfip->state != VFI_STATE_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_offline_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!vfip->fcfp) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_offline_action:%d %s:%s arg=%p flag=%x. " "Null fcfp found. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1, vfip->flag); return (1); } vfip->flag &= ~(EMLXS_VFI_OFFLINE_REQ | EMLXS_VFI_PAUSE_REQ); if (vfip->prev_state == VFI_STATE_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_offline_action:%d vfi_online=%d. <", vfip->VFI, vfip->fcfp->vfi_online); return (0); } if (vfip->vpi_online) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_offline_action:%d vpi_online=%d. VPI's still online.", vfip->VFI, vfip->vpi_online); } if (vfip->flag & EMLXS_VFI_FCFI) { vfip->flag &= ~EMLXS_VFI_FCFI; if (vfip->fcfp->vfi_online) { vfip->fcfp->vfi_online--; } } /* Check if online was requested */ if (vfip->flag & EMLXS_VFI_ONLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_offline_action:%d vfi_online=%d. Online requested.", vfip->VFI, vfip->fcfp->vfi_online); rval = emlxs_vfi_state(port, vfip, VFI_STATE_INIT, FCF_REASON_REQUESTED, 0, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_offline_action:%d vfi_online=%d. " "VFI offline. Notifying FCFI:%d >", vfip->VFI, vfip->fcfp->vfi_online, vfip->fcfp->fcf_index); /* Notify FCFI */ rval = emlxs_fcfi_event(port, FCF_EVENT_VFI_OFFLINE, vfip); return (rval); } /* emlxs_vfi_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_init_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; VFIobj_t *vfip; MAILBOX4 *mb4; vfip = (VFIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; mutex_enter(&EMLXS_FCF_LOCK); if (vfip->state != VFI_STATE_INIT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_mbcmpl:%d %s.", vfip->VFI, emlxs_vfi_state_xlate(vfip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_mbcmpl:%d failed. %s. >", vfip->VFI, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_vfi_state(port, vfip, VFI_STATE_INIT_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_mbcmpl:%d. Init complete. >", vfip->VFI, mb4->mbxStatus); vfip->flag |= EMLXS_VFI_INIT; (void) emlxs_vfi_state(port, vfip, VFI_STATE_INIT_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_vfi_init_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_init_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; MAILBOXQ *mbq; MAILBOX4 *mb4; uint32_t rval = 0; if (vfip->state != VFI_STATE_INIT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!(vfip->flag & EMLXS_VFI_FCFI)) { vfip->flag |= EMLXS_VFI_FCFI; vfip->fcfp->vfi_online++; } if (vfip->prev_state != VFI_STATE_INIT_FAILED) { vfip->attempts = 0; } if (vfip->flag & EMLXS_VFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_action:%d attempts=%d. Offline requested.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_offline_handler(port, vfip, arg1); return (rval); } if (vfip->flag & EMLXS_VFI_INIT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_action:%d flag=%x. " "Already init'd. Skipping INIT_VFI.", vfip->VFI); rval = emlxs_vfi_state(port, vfip, VFI_STATE_VPI_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (((hba->sli_intf & SLI_INTF_IF_TYPE_MASK) == SLI_INTF_IF_TYPE_0) && (vfip->fcfp->vfi_online == 1)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_action:%d. First VFI. Skipping INIT_VFI.", vfip->VFI); rval = emlxs_vfi_state(port, vfip, VFI_STATE_VPI_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_action:%d vfi_online=%d attempts=%d. Sending INIT_VFI. <", vfip->VFI, vfip->fcfp->vfi_online, vfip->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_vfi_state(port, vfip, FCFI_STATE_REG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_vfi_init_mbcmpl; mbq->context = (void *)vfip; mbq->port = (void *)port; mb4->mbxCommand = MBX_INIT_VFI; mb4->mbxOwner = OWN_HOST; mb4->un.varInitVFI4.fcfi = vfip->fcfp->FCFI; mb4->un.varInitVFI4.vfi = vfip->VFI; /* ??? This function is untested and incomplete */ rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_vfi_state(port, vfip, VFI_STATE_INIT_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_vfi_init_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_init_failed_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; vfip->attempts++; if (vfip->state != VFI_STATE_INIT_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_init_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1, vfip->attempts); return (1); } if ((vfip->reason == FCF_REASON_SEND_FAILED) || (vfip->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_action:%d attempt=%d reason=%x. Init cmpl.", vfip->VFI, vfip->attempts, vfip->reason); vfip->flag &= ~(EMLXS_VFI_REG | EMLXS_VFI_INIT); vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= EMLXS_VFI_OFFLINE_REQ; rval = emlxs_vfi_state(port, vfip, VFI_STATE_INIT_CMPL, FCF_REASON_OP_FAILED, vfip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_action:%d attempt=%d. Initializing.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_state(port, vfip, VFI_STATE_INIT, FCF_REASON_OP_FAILED, vfip->attempts, arg1); } return (rval); } /* emlxs_vfi_init_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_init_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vfip->state != VFI_STATE_INIT_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_init_cmpl_action:%d attempts=%d. Init cmpl.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_state(port, vfip, VFI_STATE_VPI_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vfi_init_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_vpi_online_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t rval = 0; uint32_t i; emlxs_port_t *vport; VPIobj_t *vpip; if (vfip->state != VFI_STATE_VPI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vfip->flag & EMLXS_VFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_action:%d. Offline requested.", vfip->VFI); rval = emlxs_vfi_offline_handler(port, vfip, arg1); return (rval); } if (vfip->logi_count) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_vpi_online_action:%d vpi_online=%d logi_count=%d. " "VPI already logged in.", vfip->VFI, vfip->vpi_online, vfip->logi_count); } if (vfip->vpi_online) { /* Waking up after being paused */ /* Find first VPI of this VFI */ for (i = 0; i <= hba->vpi_max; i++) { vport = &VPORT(i); vpip = vport->vpip; if (!(vport->flag & EMLXS_PORT_BOUND) || (vpip->flag & EMLXS_VPI_PORT_UNBIND)) { continue; } if (vpip->vfip == vfip) { break; } } } else { /* Find first available VPI */ for (i = 0; i <= hba->vpi_max; i++) { vport = &VPORT(i); vpip = vport->vpip; if (!(vport->flag & EMLXS_PORT_BOUND) || (vpip->flag & EMLXS_VPI_PORT_UNBIND)) { continue; } if (vpip->vfip == NULL) { vpip->vfip = vfip; break; } } } if (i > hba->vpi_max) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_action:%d vpi_online=%d logi_count=%d. " "No VPI found. Offlining.", vfip->VFI, vfip->vpi_online, vfip->logi_count); vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= EMLXS_VFI_OFFLINE_REQ; rval = emlxs_vfi_offline_handler(port, vfip, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_action:%d vpi_online=%d logi_count=%d. " "Onlining VPI:%d >", vfip->VFI, vfip->vpi_online, vfip->logi_count, vpip->VPI); rval = emlxs_vpi_event(port, FCF_EVENT_VPI_ONLINE, vpip); /* Wait for FCF_EVENT_VPI_ONLINE in return */ return (rval); } /* emlxs_vfi_vpi_online_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_vpi_online_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; VPIobj_t *vpip = (VPIobj_t *)arg1; if (vfip->state != VFI_STATE_VPI_ONLINE_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vpip == vfip->flogi_vpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_cmpl_action:%d flag=%x vpi_online=%d " "logi_count=%d. flogi_vpi. Registering.", vfip->VFI, vfip->flag, vfip->vpi_online, vfip->logi_count); rval = emlxs_vfi_state(port, vfip, VFI_STATE_REG, FCF_REASON_EVENT, evt, arg1); } else { /* Waking up after pause */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_online_cmpl_action:%d flag=%x vpi_online=%d " "logi_count=%d. Going online.", vfip->VFI, vfip->flag, vfip->vpi_online, vfip->logi_count); rval = emlxs_vfi_state(port, vfip, VFI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); } return (rval); } /* emlxs_vfi_vpi_online_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_vpi_offline_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vfip->state != VFI_STATE_VPI_OFFLINE_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if ((vfip->vpi_online == 0) && (vfip->flag & EMLXS_VFI_OFFLINE_REQ)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_cmpl_action:%d vpi_online=%d. " "Unregistering.", vfip->VFI, vfip->vpi_online); rval = emlxs_vfi_state(port, vfip, VFI_STATE_UNREG, FCF_REASON_EVENT, evt, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_cmpl_action:%d vpi_online=%d. <", vfip->VFI, vfip->vpi_online); } return (rval); } /* emlxs_vfi_vpi_offline_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_vpi_offline_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; emlxs_port_t *vport; uint32_t rval = 0; int32_t i; VPIobj_t *vpip; if (vfip->state != VFI_STATE_VPI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vfip->flag & EMLXS_VFI_PAUSE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_action:%d vpi_online=%d. Pausing.", vfip->VFI, vfip->vpi_online); rval = emlxs_vfi_state(port, vfip, VFI_STATE_PAUSED, FCF_REASON_EVENT, evt, arg1); return (rval); } if (vfip->vpi_online == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_action:%d vpi_online=%d. " "VPI already offline. Skipping VPI offline.", vfip->VFI, vfip->vpi_online); rval = emlxs_vfi_state(port, vfip, VFI_STATE_UNREG, FCF_REASON_EVENT, evt, arg1); return (rval); } /* Offline all VPI's of this VFI */ for (i = hba->vpi_max; i >= 0; i--) { vport = &VPORT(i); vpip = vport->vpip; if ((vpip->state == VPI_STATE_OFFLINE) || (vpip->vfip != vfip)) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_vpi_offline_action:%d. Offlining VPI:%d. >", vfip->VFI, vpip->VPI); (void) emlxs_vpi_event(vport, FCF_EVENT_VPI_OFFLINE, vpip); } /* Wait for FCF_EVENT_VPI_OFFLINE in return */ return (0); } /* emlxs_vfi_vpi_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_paused_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; emlxs_port_t *vport; int32_t i; VPIobj_t *vpip; if (vfip->state != VFI_STATE_PAUSED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_paused_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } vfip->flag &= ~(EMLXS_VFI_OFFLINE_REQ | EMLXS_VFI_PAUSE_REQ); /* Pause all VPI's of this VFI */ for (i = hba->vpi_max; i >= 0; i--) { vport = &VPORT(i); vpip = vport->vpip; if ((vpip->state == VPI_STATE_PAUSED) || (vpip->vfip != vfip)) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_paused_action:%d vpi_online=%d. Pausing VPI:%d. >", vfip->VFI, vfip->vpi_online, vpip->VPI); (void) emlxs_vpi_event(vport, FCF_EVENT_VPI_PAUSE, vpip); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_paused_action:%d vpi_online=%d. VFI paused. <", vfip->VFI, vfip->vpi_online); return (0); } /* emlxs_vfi_paused_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_unreg_failed_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; vfip->attempts++; if (vfip->state != VFI_STATE_UNREG_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_unreg_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1, vfip->attempts); return (1); } if (vfip->attempts >= 3) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_unreg_failed_action:%d attempt=%d. Unreg cmpl.", vfip->VFI, vfip->attempts); vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= EMLXS_VFI_OFFLINE_REQ; rval = emlxs_vfi_state(port, vfip, VFI_STATE_UNREG_CMPL, FCF_REASON_OP_FAILED, vfip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_unreg_failed_action:%d attempt=%d. Unregistering.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_state(port, vfip, VFI_STATE_UNREG, FCF_REASON_OP_FAILED, vfip->attempts, arg1); } return (rval); } /* emlxs_vfi_unreg_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_unreg_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; MAILBOX4 *mb4; VFIobj_t *vfip; vfip = (VFIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; mutex_enter(&EMLXS_FCF_LOCK); if (vfip->state != VFI_STATE_UNREG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_unreg_mbcmpl:%d state=%s.", vfip->VFI, emlxs_vfi_state_xlate(vfip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_unreg_mbcmpl:%d failed. %s. >", vfip->VFI, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_vfi_state(port, vfip, VFI_STATE_UNREG_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, (void *)mbq->sbp); mutex_exit(&EMLXS_FCF_LOCK); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_unreg_mbcmpl:%d. Unreg complete. >", vfip->VFI); vfip->flag &= ~(EMLXS_VFI_REG | EMLXS_VFI_INIT); (void) emlxs_vfi_state(port, vfip, VFI_STATE_UNREG_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_vfi_unreg_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_unreg_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; MAILBOX4 *mb4; MAILBOXQ *mbq; uint32_t rval = 0; if (vfip->state != VFI_STATE_UNREG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_unreg_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!(vfip->flag & EMLXS_VFI_REG)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_unreg_action:%d. Not registered. Skipping UNREG_VFI.", vfip->VFI); rval = emlxs_vfi_state(port, vfip, VFI_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (vfip->prev_state != VFI_STATE_UNREG_FAILED) { vfip->attempts = 0; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_unreg_action:%d attempts=%d. Sending UNREG_VFI. <", vfip->VFI, vfip->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_vfi_state(port, vfip, VFI_STATE_UNREG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_vfi_unreg_mbcmpl; mbq->context = (void *)vfip; mbq->port = (void *)port; mb4->un.varUnRegVFI4.vfi = vfip->VFI; mb4->mbxCommand = MBX_UNREG_VFI; mb4->mbxOwner = OWN_HOST; rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_vfi_state(port, vfip, VFI_STATE_UNREG_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_vfi_unreg_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_unreg_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vfip->state != VFI_STATE_UNREG_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_unreg_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_unreg_cmpl_action:%d attempts=%d. Going offline.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_state(port, vfip, VFI_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vfi_unreg_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_reg_failed_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; vfip->attempts++; if (vfip->state != VFI_STATE_REG_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_reg_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1, vfip->attempts); return (1); } if ((vfip->reason == FCF_REASON_SEND_FAILED) || (vfip->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_failed_action:%d attempt=%d reason=%x. Reg cmpl.", vfip->VFI, vfip->attempts, vfip->reason); vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= EMLXS_VFI_OFFLINE_REQ; rval = emlxs_vfi_state(port, vfip, VFI_STATE_REG_CMPL, FCF_REASON_OP_FAILED, vfip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_failed_action:%d attempt=%d. Registering.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_state(port, vfip, VFI_STATE_REG, FCF_REASON_OP_FAILED, vfip->attempts, arg1); } return (rval); } /* emlxs_vfi_reg_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_reg_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; MAILBOX4 *mb4; VFIobj_t *vfip; MATCHMAP *mp; vfip = (VFIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; mutex_enter(&EMLXS_FCF_LOCK); if (vfip->state != VFI_STATE_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_mbcmpl:%d state=%s.", vfip->VFI, emlxs_vfi_state_xlate(vfip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_mbcmpl:%d failed. %s. >", vfip->VFI, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_vfi_state(port, vfip, VFI_STATE_REG_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, (void *)mbq->sbp); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* Archive a copy of the sparams in case we need them later */ mp = (MATCHMAP *)mbq->bp; bcopy((uint32_t *)mp->virt, (uint32_t *)&vfip->sparam, sizeof (SERV_PARM)); if (vfip->flogi_vpip) { if (mb4->un.varRegVFI4.vp == 1) { vfip->flogi_vpip->flag |= EMLXS_VPI_REG; } vfip->flogi_vpip = NULL; } vfip->flag |= EMLXS_VFI_REG; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_mbcmpl:%d. Reg complete. >", vfip->VFI); (void) emlxs_vfi_state(port, vfip, VFI_STATE_REG_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_vfi_reg_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_reg_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; MAILBOX4 *mb4; MAILBOXQ *mbq; MATCHMAP *mp; uint32_t rval = 0; uint32_t edtov; uint32_t ratov; SERV_PARM *flogi_sparam; uint32_t *wwpn; if (vfip->state != VFI_STATE_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_reg_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vfip->prev_state != VFI_STATE_REG_FAILED) { vfip->attempts = 0; } if (vfip->flag & EMLXS_VFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_action:%d %attempts=%d. Offline requested.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_offline_handler(port, vfip, arg1); return (rval); } if (!vfip->flogi_vpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_action:%d %attempts=%d. No flogi_vpi found.", vfip->VFI, vfip->attempts); vfip->flag &= ~EMLXS_VFI_REQ_MASK; vfip->flag |= EMLXS_VFI_OFFLINE_REQ; rval = emlxs_vfi_offline_handler(port, vfip, arg1); return (rval); } if ((hba->model_info.chip & EMLXS_BE_CHIPS) && (vfip->flag & EMLXS_VFI_REG)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_action:%d flag=%x. " "Already registered. Skipping REG_VFI update.", vfip->VFI); rval = emlxs_vfi_state(port, vfip, VFI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* Get the flogi_vpip's fabric_rpip's service parameters */ flogi_sparam = &vfip->flogi_vpip->fabric_rpip->sparam; if (flogi_sparam->cmn.edtovResolution) { edtov = (LE_SWAP32(flogi_sparam->cmn.e_d_tov) + 999999) / 1000000; } else { edtov = LE_SWAP32(flogi_sparam->cmn.e_d_tov); } ratov = (LE_SWAP32(flogi_sparam->cmn.w2.r_a_tov) + 999) / 1000; if (vfip->flag & EMLXS_VFI_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_action:%d attempts=%d edtov=%d ratov=%d. " "Updating REG_VFI. <", vfip->VFI, vfip->attempts, edtov, ratov); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_action:%d attempts=%d edtov=%d ratov=%d. " "Sending REG_VFI. <", vfip->VFI, vfip->attempts, edtov, ratov); } if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_vfi_state(port, vfip, VFI_STATE_REG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF)) == 0) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_vfi_state(port, vfip, VFI_STATE_REG_FAILED, FCF_REASON_NO_BUFFER, 0, arg1); return (1); } mbq->bp = (void *)mp; mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_vfi_reg_mbcmpl; mbq->context = (void *)vfip; mbq->port = (void *)port; mb4->mbxCommand = MBX_REG_VFI; mb4->mbxOwner = OWN_HOST; mb4->un.varRegVFI4.vfi = vfip->VFI; mb4->un.varRegVFI4.upd = (vfip->flag & EMLXS_VFI_REG)? 1:0; /* If the flogi_vpip was not previously registered, */ /* perform the REG_VPI now */ if (!(vfip->flogi_vpip->flag & EMLXS_VPI_REG)) { mb4->un.varRegVFI4.vp = 1; mb4->un.varRegVFI4.vpi = vfip->flogi_vpip->VPI; } mb4->un.varRegVFI4.fcfi = vfip->fcfp->FCFI; wwpn = (uint32_t *)&port->wwpn; mb4->un.varRegVFI4.portname[0] = BE_SWAP32(*wwpn); wwpn++; mb4->un.varRegVFI4.portname[1] = BE_SWAP32(*wwpn); mb4->un.varRegVFI4.sid = port->did; mb4->un.varRegVFI4.edtov = edtov; mb4->un.varRegVFI4.ratov = ratov; mb4->un.varRegVFI4.bde.tus.f.bdeSize = sizeof (SERV_PARM); mb4->un.varRegVFI4.bde.addrHigh = PADDR_HI(mp->phys); mb4->un.varRegVFI4.bde.addrLow = PADDR_LO(mp->phys); bcopy((uint32_t *)flogi_sparam, (uint32_t *)mp->virt, sizeof (SERV_PARM)); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_BUF, (void *)mp); emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_vfi_state(port, vfip, VFI_STATE_REG_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_vfi_reg_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_reg_cmpl_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vfip->state != VFI_STATE_REG_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vfi_reg_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vfip->flag & EMLXS_VFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_cmpl_action:%d attempts=%d. Offline requested.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_offline_handler(port, vfip, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_reg_cmpl_action:%d attempts=%d. Going online.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_state(port, vfip, VFI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vfi_reg_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vfi_online_action(emlxs_port_t *port, VFIobj_t *vfip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t i; uint32_t rval = 0; VPIobj_t *vpip = port->vpip; emlxs_port_t *vport; if (vfip->state != VFI_STATE_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_action:%d %s:%s arg=%p. " "Invalid state. <", vfip->VFI, emlxs_vfi_state_xlate(vfip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } vfip->flag &= ~EMLXS_VFI_ONLINE_REQ; if (vfip->flag & EMLXS_VFI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_action:%d attempts=%d. Offline requested.", vfip->VFI, vfip->attempts); rval = emlxs_vfi_offline_handler(port, vfip, arg1); return (rval); } /* Take the port's Fabric RPI online now */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_action:%d. Onlining Fabric RPI. >", vfip->VFI); /* This will complete the FLOGI/FDISC back to Leadville */ (void) emlxs_rpi_event(port, FCF_EVENT_RPI_ONLINE, vpip->fabric_rpip); /* FLOGI/FDISC has been completed back to Leadville */ /* It is now safe to accept unsolicited requests */ vpip->flag |= EMLXS_VPI_PORT_ENABLED; /* Online remaining VPI's */ for (i = 0; i <= hba->vpi_max; i++) { vport = &VPORT(i); vpip = vport->vpip; if (!(vport->flag & EMLXS_PORT_BOUND) || (vpip->flag & EMLXS_VPI_PORT_UNBIND)) { continue; } if ((vpip->state == VPI_STATE_ONLINE) || (vpip->flag & EMLXS_VPI_ONLINE_REQ)) { continue; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_action:%d vpi_online=%d logi_count=%d. " "Onlining VPI:%d >", vfip->VFI, vfip->vpi_online, vfip->logi_count, vpip->VPI); vpip->vfip = vfip; (void) emlxs_vpi_event(vport, FCF_EVENT_VPI_ONLINE, vpip); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vfi_online_action:%d vpi_online=%d logi_count=%d. " "VFI online. Notifying FCFI:%d. >", vfip->VFI, vfip->vpi_online, vfip->logi_count, vfip->fcfp->fcf_index); /* Notify FCFI */ rval = emlxs_fcfi_event(port, FCF_EVENT_VFI_ONLINE, vfip); return (rval); } /* emlxs_vfi_online_action() */ /* ************************************************************************** */ /* VPI */ /* ************************************************************************** */ static char * emlxs_vpi_state_xlate(uint32_t state) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_vpi_state_table) / sizeof (emlxs_table_t); for (i = 0; i < count; i++) { if (state == emlxs_vpi_state_table[i].code) { return (emlxs_vpi_state_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "state=0x%x", state); return (buffer); } /* emlxs_vpi_state_xlate() */ static uint32_t emlxs_vpi_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; uint32_t(*func) (emlxs_port_t *, VPIobj_t *, uint32_t, void *); uint32_t index; uint32_t events; uint16_t state; /* Convert event to action table index */ switch (evt) { case FCF_EVENT_STATE_ENTER: index = 0; break; case FCF_EVENT_VPI_ONLINE: index = 1; break; case FCF_EVENT_VPI_OFFLINE: index = 2; break; case FCF_EVENT_VPI_PAUSE: index = 3; break; case FCF_EVENT_RPI_ONLINE: index = 4; break; case FCF_EVENT_RPI_OFFLINE: index = 5; break; case FCF_EVENT_RPI_PAUSE: index = 6; break; default: return (1); } events = VPI_ACTION_EVENTS; state = vpip->state; index += (state * events); func = (uint32_t(*) (emlxs_port_t *, VPIobj_t *, uint32_t, void *)) emlxs_vpi_action_table[index]; if (!func) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "vpi_action:%d %s:%s arg=%p. No action. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } rval = (func)(port, vpip, evt, arg1); return (rval); } /* emlxs_vpi_action() */ static uint32_t emlxs_vpi_event(emlxs_port_t *port, uint32_t evt, void *arg1) { VPIobj_t *vpip = NULL; RPIobj_t *rpip; uint32_t rval = 0; /* Filter events and acquire fcfi context */ switch (evt) { case FCF_EVENT_RPI_ONLINE: case FCF_EVENT_RPI_OFFLINE: case FCF_EVENT_RPI_PAUSE: rpip = (RPIobj_t *)arg1; if (!rpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "vpi_event: %s arg=%p. Null RPI found. <", emlxs_fcf_event_xlate(evt), arg1); return (1); } vpip = rpip->vpip; break; case FCF_EVENT_VPI_ONLINE: case FCF_EVENT_VPI_PAUSE: case FCF_EVENT_VPI_OFFLINE: vpip = (VPIobj_t *)arg1; if (!vpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "vpi_event: %s arg=%p. Null VPI found. <", emlxs_fcf_event_xlate(evt), arg1); return (1); } break; default: return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "vpi_event:%d %s:%s arg=%p", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_vpi_action(port, vpip, evt, arg1); return (rval); } /* emlxs_vpi_event() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_state(emlxs_port_t *port, VPIobj_t *vpip, uint16_t state, uint16_t reason, uint32_t explain, void *arg1) { uint32_t rval = 0; if (state >= VPI_ACTION_STATES) { return (1); } if ((vpip->state == state) && (reason != FCF_REASON_REENTER)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_state:%d %s:%s:0x%x arg=%p. " "State not changed. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_reason_xlate(reason), explain, arg1); return (1); } if (!reason) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "vpi_state:%d %s-->%s arg=%p", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_vpi_state_xlate(state), arg1); } else if (reason == FCF_REASON_EVENT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "vpi_state:%d %s-->%s:%s:%s arg=%p", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_vpi_state_xlate(state), emlxs_fcf_reason_xlate(reason), emlxs_fcf_event_xlate(explain), arg1); } else if (explain) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "vpi_state:%d %s-->%s:%s:0x%x arg=%p", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_vpi_state_xlate(state), emlxs_fcf_reason_xlate(reason), explain, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "vpi_state:%d %s-->%s:%s arg=%p", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_vpi_state_xlate(state), emlxs_fcf_reason_xlate(reason), arg1); } vpip->prev_state = vpip->state; vpip->prev_reason = vpip->reason; vpip->state = state; vpip->reason = reason; rval = emlxs_vpi_action(port, vpip, FCF_EVENT_STATE_ENTER, arg1); return (rval); } /* emlxs_vpi_state() */ extern uint32_t emlxs_vpi_port_bind_notify(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; VPIobj_t *vpip = port->vpip; FCFTable_t *fcftab = &hba->sli.sli4.fcftab; uint32_t rval = 0; VFIobj_t *vfip; VFIobj_t *vfip1; uint32_t i = 0; FCFIobj_t *fcfp; FCFIobj_t *fcfp1; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (hba->state < FC_LINK_UP) { if (port->vpi == 0) { (void) emlxs_reset_link(hba, 1, 0); /* Wait for VPI to go online */ while ((vpip->state != VPI_STATE_PORT_ONLINE) && (hba->state != FC_ERROR)) { delay(drv_usectohz(500000)); if (i++ > 30) { break; } } } return (0); } mutex_enter(&EMLXS_FCF_LOCK); if (vpip->vfip) { vfip = vpip->vfip; fcfp = vfip->fcfp; goto done; } /* We need to select a VFI for this VPI */ /* First find a selected Fabric */ fcfp = NULL; for (i = 0; i < fcftab->fcfi_count; i++) { fcfp1 = fcftab->fcfi[i]; if (fcfp1->flag & EMLXS_FCFI_SELECTED) { fcfp = fcfp1; break; } } if (!fcfp) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_bind_notify:%d %s. " "No FCF available yet.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* Find first available VFI for this FCFI */ vfip = NULL; vfip1 = hba->sli.sli4.VFI_table; for (i = 0; i < hba->sli.sli4.VFICount; i++, vfip1++) { if (vfip1->fcfp == fcfp) { vfip = vfip1; break; } } if (!vfip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_bind_notify:%d %s fcfi:%d. " "No VFI available yet.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), fcfp->fcf_index); mutex_exit(&EMLXS_FCF_LOCK); return (0); } vpip->vfip = vfip; done: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_bind_notify:%d %s fcfi:%d vfi:%d. Onlining VPI:%d >", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), fcfp->fcf_index, vfip->VFI, vpip->VPI); rval = emlxs_vpi_event(port, FCF_EVENT_VPI_ONLINE, vpip); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_vpi_port_bind_notify() */ extern uint32_t emlxs_vpi_port_unbind_notify(emlxs_port_t *port, uint32_t wait) { emlxs_hba_t *hba = HBA; VPIobj_t *vpip = port->vpip; uint32_t rval = 0; VFIobj_t *vfip; uint32_t i; FCFIobj_t *fcfp; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } if (!(hba->sli.sli4.flag & EMLXS_SLI4_FCF_INIT)) { return (0); } mutex_enter(&EMLXS_FCF_LOCK); if (vpip->state == VPI_STATE_OFFLINE) { mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* * Set flag to indicate that emlxs_vpi_port_unbind_notify * has been called */ vpip->flag |= EMLXS_VPI_PORT_UNBIND; vfip = vpip->vfip; fcfp = vfip->fcfp; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_unbind_notify:%d %s fcfi:%d vfi:%d. " "Offlining VPI:%d,%d >", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), fcfp->fcf_index, vfip->VFI, vpip->index, vpip->VPI); rval = emlxs_vpi_event(port, FCF_EVENT_VPI_OFFLINE, vpip); if (wait && (rval == 0)) { /* Wait for VPI to go offline */ i = 0; while (i++ < 120) { if (vpip->state == VPI_STATE_OFFLINE) { break; } mutex_exit(&EMLXS_FCF_LOCK); BUSYWAIT_MS(1000); mutex_enter(&EMLXS_FCF_LOCK); } if (i >= 120) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_port_unbind_notify:%d %s fcfi:%d vfi:%d " "rpi_online=%d,%d. Offline timeout.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), fcfp->fcf_index, vfip->VFI, vpip->rpi_online, vpip->rpi_paused); } } vpip->flag &= ~EMLXS_VPI_PORT_UNBIND; mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_vpi_port_unbind_notify() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_rpi_offline_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; RPIobj_t *rpip = (RPIobj_t *)arg1; if (evt != FCF_EVENT_RPI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_rpi_offline_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->flag); return (1); } switch (vpip->state) { case VPI_STATE_LOGO: /* rpi_online will be checked when LOGO is complete */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_offline_evt_action:%d rpi_online=%d,%d did=%x " "rpi=%d. Waiting for LOGO. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); rval = 0; break; case VPI_STATE_PORT_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_offline_evt_action:%d rpi_online=%d,%d did=%x " "rpi=%d.", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_REENTER, evt, arg1); break; case VPI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_offline_evt_action:%d rpi_online=%d,%d did=%x " "rpi=%d. VPI paused. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); rval = 0; break; case VPI_STATE_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_offline_evt_action:%d rpi_online=%d,%d did=%x " "rpi=%d. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); rval = 0; break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_offline_evt_action:%d rpi_online=%d,%d did=%x " "rpi=%d. " "Invalid state. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); rval = 1; break; } return (rval); } /* emlxs_vpi_rpi_offline_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_rpi_pause_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; RPIobj_t *rpip = (RPIobj_t *)arg1; if (evt != FCF_EVENT_RPI_PAUSE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_rpi_pause_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->flag); return (1); } switch (vpip->state) { case VPI_STATE_LOGO: /* rpi_online will be checked when LOGO is complete */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_pause_evt_action:%d rpi_online=%d,%d did=%x " "rpi=%d. Waiting for LOGO. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); rval = 0; break; case VPI_STATE_PORT_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_pause_evt_action:%d rpi_online=%d,%d did=%x " "rpi=%d.", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_REENTER, 0, 0); break; case VPI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_pause_evt_action:%d rpi_online=%d,%d did=%x " "rpi=%d. VPI already paused. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); rval = 0; break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_pause_evt_action:%d rpi_online=%d,%d did=%x " "rpi=%d. " "Invalid state. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); rval = 1; break; } return (rval); } /* emlxs_vpi_rpi_pause_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_rpi_online_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { RPIobj_t *rpip = (RPIobj_t *)arg1; if (evt != FCF_EVENT_RPI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_rpi_online_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->flag); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_rpi_online_evt_action:%d rpi_online=%d,%d did=%x rpi=%d. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, rpip->did, rpip->RPI); return (0); } /* emlxs_vpi_rpi_online_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_online_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (evt != FCF_EVENT_VPI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_online_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->flag); return (1); } if (vpip->flag & EMLXS_VPI_ONLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_online_evt_action:%d flag=%x. " "Online already requested. <", vpip->VPI, vpip->flag); return (1); } vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= EMLXS_VPI_ONLINE_REQ; switch (vpip->state) { case VPI_STATE_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_online_evt_action:%d flag=%x. Initiating online.", vpip->VPI, vpip->flag); rval = emlxs_vpi_state(port, vpip, VPI_STATE_INIT, FCF_REASON_EVENT, evt, arg1); break; case VPI_STATE_PORT_OFFLINE: case VPI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_online_evt_action:%d flag=%x. Initiating online.", vpip->VPI, vpip->flag); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_ONLINE, FCF_REASON_EVENT, evt, arg1); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_online_evt_action:%d flag=%x. <", vpip->VPI, vpip->flag); return (1); } return (rval); } /* emlxs_vpi_online_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_offline_handler(emlxs_port_t *port, VPIobj_t *vpip, void *arg1) { uint32_t rval = 0; if (!(vpip->flag & EMLXS_VPI_OFFLINE_REQ)) { return (0); } if (vpip->flag & EMLXS_VPI_PORT_ONLINE) { rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_REQUESTED, 0, arg1); } else if (vpip->flag & EMLXS_VPI_LOGI) { rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGO, FCF_REASON_REQUESTED, 0, arg1); } else if (vpip->flag & EMLXS_VPI_REG) { rval = emlxs_vpi_state(port, vpip, VPI_STATE_UNREG, FCF_REASON_REQUESTED, 0, arg1); } else if (vpip->flag & EMLXS_VPI_INIT) { rval = emlxs_vpi_state(port, vpip, VPI_STATE_UNREG, FCF_REASON_REQUESTED, 0, arg1); } else { rval = emlxs_vpi_state(port, vpip, VPI_STATE_OFFLINE, FCF_REASON_REQUESTED, 0, arg1); } return (rval); } /* emlxs_vpi_offline_handler() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_offline_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; uint32_t pause_req; if (evt != FCF_EVENT_VPI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_offline_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->flag); return (1); } if ((vpip->flag & EMLXS_VPI_OFFLINE_REQ) && !(vpip->flag & EMLXS_VPI_PAUSE_REQ)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_evt_action:%d flag=%x. " "Offline already requested. <", vpip->VPI, vpip->flag); return (1); } pause_req = vpip->flag & EMLXS_VPI_PAUSE_REQ; vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= EMLXS_VPI_OFFLINE_REQ; switch (vpip->state) { case VPI_STATE_PORT_OFFLINE: if (pause_req || vpip->rpi_paused) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_evt_action:%d flag=%x. Clear nodes.", vpip->VPI, vpip->flag); vpip->flag |= EMLXS_VPI_PORT_ONLINE; rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_REENTER, evt, arg1); break; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_evt_action:%d flag=%x. Handling offline.", vpip->VPI, vpip->flag); /* Handle offline now */ rval = emlxs_vpi_offline_handler(port, vpip, arg1); break; case VPI_STATE_PAUSED: if (vpip->rpi_paused) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_evt_action:%d flag=%x. Clear nodes.", vpip->VPI, vpip->flag); vpip->flag |= EMLXS_VPI_PORT_ONLINE; rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_EVENT, evt, arg1); break; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_evt_action:%d flag=%x. Handling offline.", vpip->VPI, vpip->flag); /* Handle offline now */ rval = emlxs_vpi_offline_handler(port, vpip, arg1); break; /* wait states */ case VPI_STATE_UNREG: case VPI_STATE_PORT_ONLINE: case VPI_STATE_LOGI: case VPI_STATE_INIT: case VPI_STATE_REG: case VPI_STATE_ONLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_evt_action:%d flag=%x. Handling offline.", vpip->VPI, vpip->flag); /* Handle offline now */ rval = emlxs_vpi_offline_handler(port, vpip, arg1); break; /* Transitional states */ default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_evt_action:%d flag=%x. <", vpip->VPI, vpip->flag); break; } return (rval); } /* emlxs_vpi_offline_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_pause_evt_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t rval = 0; if (evt != FCF_EVENT_VPI_PAUSE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_pause_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->flag); return (1); } if (vpip->flag & EMLXS_VPI_PAUSE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_pause_evt_action:%d flag=%x. " "Pause already requested. <", vpip->VPI, vpip->flag); return (1); } if (vpip->flag & EMLXS_VPI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_pause_evt_action:%d flag=%x. " "Offline already requested. <", vpip->VPI, vpip->flag); return (1); } if (SLI4_FC_MODE || !(hba->sli.sli4.flag & EMLXS_SLI4_DOWN_LINK)) { /* Fabric logo is implied */ emlxs_vpi_logo_handler(port, vpip); } switch (vpip->state) { case VPI_STATE_PORT_OFFLINE: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_pause_evt_action:%d flag=%x. " "Already offline. <", vpip->VPI, vpip->flag); break; case VPI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_pause_evt_action:%d flag=%x. " "Already paused. <", vpip->VPI, vpip->flag); break; /* Wait states */ case VPI_STATE_UNREG: case VPI_STATE_PORT_ONLINE: case VPI_STATE_LOGI: case VPI_STATE_INIT: case VPI_STATE_REG: case VPI_STATE_ONLINE: vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= (EMLXS_VPI_OFFLINE_REQ | EMLXS_VPI_PAUSE_REQ); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_pause_evt_action:%d flag=%x. Handling offline.", vpip->VPI, vpip->flag); /* Handle offline now */ rval = emlxs_vpi_offline_handler(port, vpip, arg1); break; /* Transitional states */ default: vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= (EMLXS_VPI_OFFLINE_REQ | EMLXS_VPI_PAUSE_REQ); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_pause_evt_action:%d flag=%x. <", vpip->VPI, vpip->flag); break; } return (rval); } /* emlxs_vpi_pause_evt_action() */ /* ARGSUSED */ static void emlxs_deferred_cmpl_thread(emlxs_hba_t *hba, void *arg1, void *arg2) { emlxs_deferred_cmpl_t *cmpl = (emlxs_deferred_cmpl_t *)arg1; uint32_t status = (uint32_t)((unsigned long)arg2); emlxs_port_t *port; uint32_t mbxStatus; emlxs_buf_t *sbp; fc_unsol_buf_t *ubp; IOCBQ *iocbq; mbxStatus = (status)? MBX_FAILURE:MBX_SUCCESS; port = cmpl->port; sbp = (emlxs_buf_t *)cmpl->arg1; ubp = (fc_unsol_buf_t *)cmpl->arg2; iocbq = (IOCBQ *)cmpl->arg3; kmem_free(cmpl, sizeof (emlxs_deferred_cmpl_t)); emlxs_mb_deferred_cmpl(port, mbxStatus, sbp, ubp, iocbq); return; } /* emlxs_deferred_cmpl_thread() */ /* ARGSUSED */ static void emlxs_port_offline_thread(emlxs_hba_t *hba, void *arg1, void *arg2) { emlxs_port_t *port = (emlxs_port_t *)arg1; uint32_t scope = (uint32_t)((unsigned long)arg2); (void) emlxs_port_offline(port, scope); return; } /* emlxs_port_offline_thread() */ /* ARGSUSED */ static void emlxs_port_online_thread(emlxs_hba_t *hba, void *arg1, void *arg2) { emlxs_port_t *port = (emlxs_port_t *)arg1; (void) emlxs_port_online(port); return; } /* emlxs_port_online_thread() */ /*ARGSUSED*/ static void emlxs_vpi_logo_handler(emlxs_port_t *port, VPIobj_t *vpip) { vpip->flag &= ~EMLXS_VPI_LOGI; if (vpip->flag & EMLXS_VPI_VFI_LOGI) { vpip->flag &= ~EMLXS_VPI_VFI_LOGI; if (vpip->vfip == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "emlxs_vpi_logo_handler: invalid state " "(vpip->vfip == NULL), vpip=%p", vpip); return; } if (vpip->vfip->logi_count) { vpip->vfip->logi_count--; } if (vpip == vpip->vfip->flogi_vpip) { vpip->vfip->flogi_vpip = NULL; } } } /* emlxs_vpi_logo_handler() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_port_offline_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t rval = 0; uint32_t scope; if (vpip->state != VPI_STATE_PORT_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_offline_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vpip->flag & EMLXS_VPI_PORT_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_offline_action:%d flag=%x. Offlining port...", vpip->VPI, vpip->flag); vpip->flag &= ~(EMLXS_VPI_PORT_ONLINE|EMLXS_VPI_PORT_ENABLED); if (vpip->flag & EMLXS_VPI_PAUSE_REQ) { scope = 0xFFFFFFFF; /* Clear all non-FCP2 nodes */ /* Pause FCP2 nodes */ } else { scope = 0xFDFFFFFF; /* Clear all nodes */ } emlxs_thread_spawn(hba, emlxs_port_offline_thread, (void *)vpip->port, (void *)((unsigned long)scope)); if (vpip->flag & EMLXS_VPI_LOGI) { rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGO, FCF_REASON_EVENT, evt, arg1); return (rval); } } if (vpip->flag & EMLXS_VPI_PAUSE_REQ) { if (vpip->rpi_online > vpip->rpi_paused) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_offline_action:%d rpi_online=%d,%d. " "Pausing. Waiting for RPI's. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused); return (0); } /* Take the Fabric RPI offline now */ if (vpip->fabric_rpip->state != RPI_STATE_FREE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_offline_action:%d. " "Offlining Fabric RPI. >", vpip->VPI); (void) emlxs_rpi_event(port, FCF_EVENT_RPI_OFFLINE, vpip->fabric_rpip); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_offline_action:%d rpi_online=%d,%d. Pausing.", vpip->VPI, vpip->rpi_online, vpip->rpi_paused); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PAUSED, FCF_REASON_EVENT, evt, arg1); return (rval); } if (vpip->rpi_online > 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_offline_action:%d rpi_online=%d,%d. Offlining. " "Waiting for RPI's. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused); return (0); } /* Take the Fabric RPI offline now */ if (vpip->fabric_rpip->state != RPI_STATE_FREE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_offline_action:%d. Offlining Fabric RPI. >", vpip->VPI); (void) emlxs_rpi_event(port, FCF_EVENT_RPI_OFFLINE, vpip->fabric_rpip); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_offline_action:%d rpi_online=%d,%d. Offlining. " "Unreg VPI.", vpip->VPI, vpip->rpi_online, vpip->rpi_paused); rval = emlxs_vpi_state(port, vpip, VPI_STATE_UNREG, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vpi_port_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_paused_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { if (vpip->state != VPI_STATE_PAUSED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_paused_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } vpip->flag &= ~(EMLXS_VPI_OFFLINE_REQ | EMLXS_VPI_PAUSE_REQ); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_paused_action:%d rpi_online=%d,%d. VPI paused. <", vpip->VPI, vpip->rpi_online, vpip->rpi_paused); return (0); } /* emlxs_vpi_paused_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_offline_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vpip->state != VPI_STATE_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!vpip->vfip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_action:%d %s:%s arg=%p flag=%x. " "Null vfip found. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->flag); return (1); } /* Take the Fabric RPI offline, if still active */ if (vpip->fabric_rpip->state != RPI_STATE_FREE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_action:%d. Offlining Fabric RPI. >", vpip->VPI); (void) emlxs_rpi_event(port, FCF_EVENT_RPI_OFFLINE, vpip->fabric_rpip); } vpip->flag &= ~(EMLXS_VPI_OFFLINE_REQ | EMLXS_VPI_PAUSE_REQ); if (vpip->flag & EMLXS_VPI_VFI) { vpip->flag &= ~EMLXS_VPI_VFI; if (vpip->vfip->vpi_online) { vpip->vfip->vpi_online--; } } /* Check if online was requested */ if (vpip->flag & EMLXS_VPI_ONLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_action:%d vpi_online=%d. Online requested.", vpip->VPI, vpip->vfip->vpi_online); rval = emlxs_vpi_state(port, vpip, VPI_STATE_INIT, FCF_REASON_REQUESTED, 0, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_offline_action:%d vpi_online=%d. " "VPI offline. Notifying VFI:%d. >", vpip->VPI, vpip->vfip->vpi_online, vpip->vfip->VFI); /* Notify VFI */ rval = emlxs_vfi_event(port, FCF_EVENT_VPI_OFFLINE, vpip); return (rval); } /* emlxs_vpi_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_init_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; VPIobj_t *vpip; MAILBOX4 *mb4; vpip = (VPIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; mutex_enter(&EMLXS_FCF_LOCK); if (vpip->state != VPI_STATE_INIT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_mbcmpl:%d %s.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_mbcmpl:%d failed. %s. >", vpip->VPI, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_vpi_state(port, vpip, VPI_STATE_INIT_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_mbcmpl:%d. Init complete. >", vpip->VPI, mb4->mbxStatus); vpip->flag |= EMLXS_VPI_INIT; (void) emlxs_vpi_state(port, vpip, VPI_STATE_INIT_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_vpi_init_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_init_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; MAILBOXQ *mbq; MAILBOX4 *mb4; uint32_t rval = 0; if (vpip->state != VPI_STATE_INIT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vpip->prev_state != VPI_STATE_INIT_FAILED) { vpip->attempts = 0; } if (vpip->flag & EMLXS_VPI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_action:%d attempts=%d. Offline requested.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_offline_handler(port, vpip, arg1); return (rval); } if (!(vpip->flag & EMLXS_VPI_VFI)) { vpip->flag |= EMLXS_VPI_VFI; vpip->vfip->vpi_online++; } if (((hba->sli_intf & SLI_INTF_IF_TYPE_MASK) == SLI_INTF_IF_TYPE_0) && (vpip->vfip->vpi_online == 1)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_action:%d. First VPI. Skipping INIT_VPI.", vpip->VPI); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (vpip->flag & EMLXS_VPI_INIT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_action:%d flag=%x. " "Already init'd. Skipping INIT_VPI.", vpip->VPI); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_action:%d vpi_online=%d attempts=%d. Sending INIT_VPI. <", vpip->VPI, vpip->vfip->vpi_online, vpip->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_vpi_state(port, vpip, FCFI_STATE_REG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_vpi_init_mbcmpl; mbq->context = (void *)vpip; mbq->port = (void *)port; mb4->mbxCommand = MBX_INIT_VPI; mb4->mbxOwner = OWN_HOST; mb4->un.varInitVPI4.vfi = vpip->vfip->VFI; mb4->un.varInitVPI4.vpi = vpip->VPI; rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_vpi_state(port, vpip, VPI_STATE_INIT_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_vpi_init_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_init_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; vpip->attempts++; if (vpip->state != VPI_STATE_INIT_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_init_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->attempts); return (1); } if ((vpip->reason == FCF_REASON_SEND_FAILED) || (vpip->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_action:%d attempt=%d reason=%x. Init cmpl.", vpip->VPI, vpip->attempts, vpip->reason); vpip->flag &= ~(EMLXS_VPI_REG | EMLXS_VPI_INIT); vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= EMLXS_VPI_OFFLINE_REQ; rval = emlxs_vpi_state(port, vpip, VPI_STATE_INIT_CMPL, FCF_REASON_OP_FAILED, vpip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_action:%d attempt=%d. Initializing.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_INIT, FCF_REASON_OP_FAILED, vpip->attempts, arg1); } return (rval); } /* emlxs_vpi_init_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_init_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vpip->state != VPI_STATE_INIT_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_init_cmpl_action:%d attempts=%d. Onlining port.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vpi_init_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_port_online_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; emlxs_config_t *cfg = &CFG; uint32_t rval = 0; if (vpip->state != VPI_STATE_PORT_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_online_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vpip->flag & EMLXS_VPI_PORT_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_online_action:%d. Port already online.", vpip->VPI); } if (vpip->flag & EMLXS_VPI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_online_action:%d. Offline requested.", vpip->VPI); rval = emlxs_vpi_offline_handler(port, vpip, arg1); return (rval); } /* Initialize the Fabric RPI */ if (vpip->fabric_rpip->state == RPI_STATE_FREE) { emlxs_rpi_alloc_fabric_rpi(vpip->port); } /* Notify ULP */ vpip->flag |= EMLXS_VPI_PORT_ONLINE; if (hba->flag & FC_LOOPBACK_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_online_action:%d. Loopback mode. " "Registering VPI.", vpip->VPI); if (hba->topology != TOPOLOGY_LOOP) { port->did = 1; } vpip->vfip->flogi_vpip = vpip; bcopy((void *)&vpip->port->sparam, (void *)&vpip->fabric_rpip->sparam, sizeof (SERV_PARM)); /* Update the VPI Fabric RPI */ vpip->fabric_rpip->sparam.cmn.w2.r_a_tov = LE_SWAP32((FF_DEF_RATOV * 1000)); rval = emlxs_vpi_state(port, vpip, VPI_STATE_REG, FCF_REASON_EVENT, evt, arg1); return (rval); } if ((hba->topology == TOPOLOGY_LOOP) && ! (port->did)) { port->did = port->granted_alpa; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_port_online_action:%d vpi_online=%d. Onlining port... <", vpip->VPI, vpip->vfip->vpi_online); if (SLI4_FC_MODE && (port->vpi == 0)) { mutex_enter(&EMLXS_PORT_LOCK); hba->linkup_timer = hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current; mutex_exit(&EMLXS_PORT_LOCK); } else { emlxs_thread_spawn(hba, emlxs_port_online_thread, (void *)vpip->port, 0); } /* Wait for emlxs_vpi_logi_notify() */ return (0); } /* emlxs_vpi_port_online_action() */ extern uint32_t emlxs_vpi_logi_notify(emlxs_port_t *port, emlxs_buf_t *sbp) { VPIobj_t *vpip = port->vpip; emlxs_hba_t *hba = HBA; uint32_t rval = 0; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); if (vpip->state == VPI_STATE_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_notify:%d %s.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (1); } if (vpip->state != VPI_STATE_PORT_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_logi_notify:%d %s. " "Invalid state.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_notify:%d %s. " "Logging in. >", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGI, 0, 0, sbp); if (rval) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_notify:%d %s rval=%d.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), rval); } mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_vpi_logi_notify() */ static uint32_t emlxs_vpi_logi_cmpl_notify(emlxs_port_t *port, RPIobj_t *rpip) { emlxs_hba_t *hba = HBA; VPIobj_t *vpip = port->vpip; uint32_t rval = 0; /* EMLXS_FCF_LOCK must be held when calling this routine */ if (vpip->state != VPI_STATE_LOGI) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_logi_cmpl_notify:%d %s. " "Invalid state.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); return (1); } if (rpip->RPI == FABRIC_RPI) { if (hba->flag & FC_PT_TO_PT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_notify:%d %s. P2P mode. " "Completing FLOGI.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); /* Complete the FLOGI/FDISC now */ if (rpip->cmpl) { emlxs_rpi_deferred_cmpl(port, rpip, 0); } /* Wait for P2P PLOGI completion to continue */ return (0); } if (!rpip->cmpl || !rpip->cmpl->arg1) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_logi_cmpl_notify:%d. Null sbp.", vpip->VPI); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_notify:%d %s. Fabric mode. " "Completing login. >", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGI_CMPL, 0, 0, 0); if (rval) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_notify:%d %s rval=%d.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), rval); } return (rval); } if (hba->flag & FC_PT_TO_PT) { if (port->did == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_notify:%d %s did=0. P2P mode. " "Wait for PLOGI compl.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); if (rpip->cmpl) { emlxs_rpi_deferred_cmpl(port, rpip, 0); } /* Wait for P2P PLOGI completion to continue */ return (0); } vpip->p2p_rpip = rpip; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_notify:%d %s. P2P mode. " "Completing login. >", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGI_CMPL, 0, 0, 0); if (rval) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_notify:%d %s rval=%d.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), rval); } return (rval); } return (1); } /* emlxs_vpi_logi_cmpl_notify() */ extern uint32_t emlxs_vpi_logi_failed_notify(emlxs_port_t *port, emlxs_buf_t *sbp) { emlxs_hba_t *hba = HBA; VPIobj_t *vpip = port->vpip; RPIobj_t *rpip = vpip->fabric_rpip; uint32_t rval = 0; emlxs_deferred_cmpl_t *cmpl; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); if (vpip->state != VPI_STATE_LOGI) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_failed_notify:%d %s. " "Invalid state.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); /* Fabric logo is implied */ emlxs_vpi_logo_handler(port, vpip); mutex_exit(&EMLXS_FCF_LOCK); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_failed_notify:%d %s. " "Failing login. >", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); /* For safety */ if (rpip->cmpl) { emlxs_rpi_deferred_cmpl(port, rpip, 1); } if (sbp) { cmpl = (emlxs_deferred_cmpl_t *)kmem_zalloc( sizeof (emlxs_deferred_cmpl_t), KM_SLEEP); cmpl->port = port; cmpl->arg1 = (void *)sbp; cmpl->arg2 = 0; cmpl->arg3 = 0; rpip->cmpl = cmpl; } rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGI_FAILED, FCF_REASON_OP_FAILED, 1, 0); if (rval && rpip->cmpl) { kmem_free(rpip->cmpl, sizeof (emlxs_deferred_cmpl_t)); rpip->cmpl = 0; } mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_vpi_logi_failed_notify() */ extern uint32_t emlxs_vpi_logo_cmpl_notify(emlxs_port_t *port) { emlxs_hba_t *hba = HBA; VPIobj_t *vpip = port->vpip; uint32_t rval = 0; VFIobj_t *vfip; FCFIobj_t *fcfp; if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); /* Fabric logo is complete */ emlxs_vpi_logo_handler(port, vpip); if ((vpip->state == VPI_STATE_OFFLINE) || (vpip->flag & EMLXS_VPI_OFFLINE_REQ)) { /* Already offline. Do nothing */ mutex_exit(&EMLXS_FCF_LOCK); return (0); } vfip = vpip->vfip; fcfp = vfip->fcfp; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logo_cmpl_notify:%d %s fcfi:%d vfi:%d. " "Offlining VPI:%d,%d >", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), fcfp->fcf_index, vfip->VFI, vpip->index, vpip->VPI); rval = emlxs_vpi_event(port, FCF_EVENT_VPI_OFFLINE, vpip); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_vpi_logo_cmpl_notify() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_logi_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; emlxs_buf_t *sbp = (emlxs_buf_t *)arg1; fc_packet_t *pkt = PRIV2PKT(sbp); uint32_t rval = 0; if (vpip->state != VPI_STATE_LOGI) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vpip->flag & EMLXS_VPI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_action:%d. Offline requested.", vpip->VPI); rval = emlxs_vpi_offline_handler(port, vpip, arg1); return (rval); } if (vpip->flag & EMLXS_VPI_LOGI) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_logi_action:%d flag=%x. LOGI already set.", vpip->VPI, vpip->flag); /* Fabric logo is implied */ emlxs_vpi_logo_handler(port, vpip); } /* Check if FC_PT_TO_PT is set */ if (hba->flag & FC_PT_TO_PT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_action:%d logi_count=%d. FLOGI set. P2P. <", vpip->VPI, vpip->vfip->logi_count); *((uint32_t *)pkt->pkt_cmd) = (uint32_t)ELS_CMD_FLOGI; vpip->vfip->flogi_vpip = vpip; if (vpip->vfip->logi_count == 0) { vpip->vfip->logi_count++; vpip->flag |= EMLXS_VPI_VFI_LOGI; } return (0); } /* Set login command based on vfi logi_count */ if (vpip->vfip->logi_count == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_action:%d logi_count=%d. FLOGI set. <", vpip->VPI, vpip->vfip->logi_count); *((uint32_t *)pkt->pkt_cmd) = (uint32_t)ELS_CMD_FLOGI; vpip->vfip->flogi_vpip = vpip; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_action:%d logi_count=%d. FDISC set. <", vpip->VPI, vpip->vfip->logi_count); *((uint32_t *)pkt->pkt_cmd) = (uint32_t)ELS_CMD_FDISC; } vpip->vfip->logi_count++; vpip->flag |= EMLXS_VPI_VFI_LOGI; return (0); } /* emlxs_vpi_logi_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_logi_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t rval = 0; if (vpip->state != VPI_STATE_LOGI_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_failed_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } /* Fabric logo is implied */ emlxs_vpi_logo_handler(port, vpip); if (hba->topology == TOPOLOGY_LOOP) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_failed_action:%d. Private loop. " "Registering VPI.", vpip->VPI); /* Update the VPI flogi_vpip pointer for loop */ /* because the vpi_logo_handler cleared it */ vpip->vfip->flogi_vpip = vpip; bcopy((void *)&vpip->port->sparam, (void *)&vpip->fabric_rpip->sparam, sizeof (SERV_PARM)); /* Update the VPI Fabric RPI */ vpip->fabric_rpip->sparam.cmn.w2.r_a_tov = LE_SWAP32((FF_DEF_RATOV * 1000)); rval = emlxs_vpi_state(port, vpip, VPI_STATE_REG, FCF_REASON_EVENT, evt, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_failed_action:%d. Requesting offline.", vpip->VPI); vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= EMLXS_VPI_OFFLINE_REQ; rval = emlxs_vpi_offline_handler(port, vpip, arg1); return (rval); } /* emlxs_vpi_logi_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_logi_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t rval = 0; char buffer1[64]; char buffer2[64]; uint32_t new_config = 0; if (vpip->state != VPI_STATE_LOGI_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } vpip->flag |= EMLXS_VPI_LOGI; /* Check for new fabric */ if (port->prev_did) { if (SLI4_FCOE_MODE) { /* Check for FCF change */ if (((port->prev_did != port->did) || bcmp(&port->prev_fabric_sparam.portName, &port->fabric_sparam.portName, 8)) && emlxs_nport_count(port)) { new_config = 1; } } else { uint32_t old_topo; uint32_t new_topo; /* Check for topology change (0=loop 1=fabric) */ old_topo = ((port->prev_did && 0xFFFF00) == 0)? 0:1; new_topo = ((port->did && 0xFFFF00) == 0)? 0:1; if (old_topo != new_topo) { new_config = 1; /* Check for any switch change */ } else if ((port->prev_did != port->did) || bcmp(&port->prev_fabric_sparam.portName, &port->fabric_sparam.portName, 8)) { new_config = 1; } } } if (new_config) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_action:%d. " "New config. Offlining port.", vpip->VPI); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_action: prev_wwpn=%s wwpn=%s prev_did=%x " "did=%x.", emlxs_wwn_xlate(buffer1, sizeof (buffer1), (uint8_t *)&port->prev_fabric_sparam.portName), emlxs_wwn_xlate(buffer2, sizeof (buffer2), (uint8_t *)&port->fabric_sparam.portName), port->prev_did, port->did); vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= EMLXS_VPI_OFFLINE_REQ; rval = emlxs_vpi_offline_handler(port, vpip, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logi_cmpl_action:%d. Registering.", vpip->VPI); rval = emlxs_vpi_state(port, vpip, VPI_STATE_REG, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vpi_logi_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_logo_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t rval = 0; vpip->attempts++; if (vpip->state != VPI_STATE_LOGO_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_logo_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->attempts); return (1); } if (hba->state <= FC_LINK_DOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logo_failed_action:%d attempt=%d. Logo cmpl.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGO_CMPL, FCF_REASON_OP_FAILED, vpip->attempts, arg1); } else if (vpip->attempts >= 3) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logo_failed_action:%d attempt=%d. Logo cmpl.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGO_CMPL, FCF_REASON_OP_FAILED, vpip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logo_failed_action:%d attempt=%d. Logging out.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGO, FCF_REASON_OP_FAILED, vpip->attempts, arg1); } return (rval); } /* emlxs_vpi_logo_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_logo_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; emlxs_port_t *vport = vpip->port; uint32_t rval = 0; uint32_t did; uint32_t sid; fc_packet_t *pkt; ELS_PKT *els; if (vpip->state != VPI_STATE_LOGO) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_logo_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!(vpip->flag & EMLXS_VPI_LOGI)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logo_action:%d. No login. Skipping LOGO.", vpip->VPI); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (!(hba->flag & FC_ONLINE_MODE) && !(hba->flag & FC_OFFLINING_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logo_action:%d. HBA offline. Skipping LOGO.", vpip->VPI); /* Fabric logo is implied */ emlxs_vpi_logo_handler(port, vpip); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (SLI4_FC_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logo_action:%d. FC mode. Skipping LOGO.", vpip->VPI); /* Fabric logo is implied */ emlxs_vpi_logo_handler(port, vpip); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (vpip->prev_state != VPI_STATE_LOGO_FAILED) { vpip->attempts = 0; } did = FABRIC_DID; sid = (vport->did)? vport->did:vport->prev_did; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logo_action:%d attempts=%d sid=%x did=%x. Sending LOGO. <", vpip->VPI, vpip->attempts, sid, did); pkt = emlxs_pkt_alloc(vport, (sizeof (uint32_t) + sizeof (LOGO)), (sizeof (uint32_t) + sizeof (LOGO)), 0, KM_NOSLEEP); if (!pkt) { rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGO_FAILED, FCF_REASON_NO_PKT, 0, arg1); return (rval); } pkt->pkt_tran_type = FC_PKT_EXCHANGE; pkt->pkt_timeout = (2 * hba->fc_ratov); /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | R_CTL_SOLICITED_CONTROL; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(sid); pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xffff; pkt->pkt_cmd_fhdr.rx_id = 0xffff; pkt->pkt_cmd_fhdr.ro = 0; /* Build the command */ els = (ELS_PKT *)pkt->pkt_cmd; els->elsCode = 0x05; els->un.logo.un.nPortId32 = pkt->pkt_cmd_fhdr.s_id; bcopy((uint8_t *)&vport->wwpn, (uint8_t *)&els->un.logo.portName, 8); /* Send the pkt now */ rval = emlxs_pkt_send(pkt, 0); if (rval != FC_SUCCESS) { /* Free the pkt */ emlxs_pkt_free(pkt); rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGO_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } /* For now we will send and forget */ rval = emlxs_vpi_state(port, vpip, VPI_STATE_LOGO_CMPL, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vpi_logo_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_logo_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vpip->state != VPI_STATE_LOGO_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_logo_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } /* Fabric logo is complete */ emlxs_vpi_logo_handler(port, vpip); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_logo_cmpl_action:%d attempts=%d. Offline RPI's.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vpi_logo_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_unreg_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; vpip->attempts++; if (vpip->state != VPI_STATE_UNREG_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_unreg_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->attempts); return (1); } if ((vpip->reason == FCF_REASON_SEND_FAILED) || (vpip->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_failed_action:%d attempt=%d. Unreg cmpl.", vpip->VPI, vpip->attempts); vpip->flag &= ~(EMLXS_VPI_REG | EMLXS_VPI_INIT); vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= EMLXS_VPI_OFFLINE_REQ; rval = emlxs_vpi_state(port, vpip, VPI_STATE_UNREG_CMPL, FCF_REASON_OP_FAILED, vpip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_failed_action:%d attempt=%d. Unregistering.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_UNREG, FCF_REASON_OP_FAILED, vpip->attempts, arg1); } return (rval); } /* emlxs_vpi_unreg_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_unreg_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; MAILBOX4 *mb4; VPIobj_t *vpip; vpip = (VPIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; mutex_enter(&EMLXS_FCF_LOCK); if (vpip->state != VPI_STATE_UNREG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_mbcmpl:%d state=%s.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_mbcmpl:%d failed. %s. >", vpip->VPI, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_vpi_state(port, vpip, VPI_STATE_UNREG_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, (void *)mbq->sbp); mutex_exit(&EMLXS_FCF_LOCK); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_mbcmpl:%d. Unreg complete. >", vpip->VPI); vpip->flag &= ~(EMLXS_VPI_REG | EMLXS_VPI_INIT); (void) emlxs_vpi_state(port, vpip, VPI_STATE_UNREG_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_vpi_unreg_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_unreg_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; MAILBOX4 *mb4; MAILBOXQ *mbq; uint32_t rval = 0; if (vpip->state != VPI_STATE_UNREG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_unreg_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if ((vpip->rpi_online > vpip->rpi_paused) || (vpip->fabric_rpip->state != RPI_STATE_FREE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_action:%d rpi_online=%d,%d fstate=%x. " "Waiting for RPI's.", vpip->VPI, vpip->rpi_online, vpip->rpi_paused, vpip->fabric_rpip->state); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PORT_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (!(vpip->flag & EMLXS_VPI_REG)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_action:%d. Not registered. Skipping UNREG_VPI.", vpip->VPI); rval = emlxs_vpi_state(port, vpip, VPI_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (vpip->flag & EMLXS_VPI_PAUSE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_action:%d rpi_online=%d,%d. Pausing.", vpip->VPI, vpip->rpi_online, vpip->rpi_paused); rval = emlxs_vpi_state(port, vpip, VPI_STATE_PAUSED, FCF_REASON_EVENT, evt, arg1); return (rval); } if (vpip->prev_state != VPI_STATE_UNREG_FAILED) { vpip->attempts = 0; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_action:%d attempts=%d. Sending UNREG_VPI. <", vpip->VPI, vpip->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_vpi_state(port, vpip, VPI_STATE_UNREG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_vpi_unreg_mbcmpl; mbq->context = (void *)vpip; mbq->port = (void *)vpip->port; mb4->un.varUnRegVPI4.ii = 0; /* index is a VPI */ mb4->un.varUnRegVPI4.index = vpip->VPI; mb4->mbxCommand = MBX_UNREG_VPI; mb4->mbxOwner = OWN_HOST; rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_vpi_state(port, vpip, VPI_STATE_UNREG_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_vpi_unreg_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_unreg_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vpip->state != VPI_STATE_UNREG_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_unreg_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_unreg_cmpl_action:%d attempts=%d. Going offline.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vpi_unreg_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_reg_failed_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; vpip->attempts++; if (vpip->state != VPI_STATE_REG_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_reg_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1, vpip->attempts); return (1); } if ((vpip->reason == FCF_REASON_SEND_FAILED) || (vpip->attempts >= 3)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_failed_action:%d attempt=%d reason=%x. Reg cmpl.", vpip->VPI, vpip->attempts, vpip->reason); vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= EMLXS_VPI_OFFLINE_REQ; rval = emlxs_vpi_state(port, vpip, VPI_STATE_REG_CMPL, FCF_REASON_OP_FAILED, vpip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_failed_action:%d attempt=%d. Registering.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_REG, FCF_REASON_OP_FAILED, vpip->attempts, arg1); } return (rval); } /* emlxs_vpi_reg_failed_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_reg_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; MAILBOX4 *mb4; VPIobj_t *vpip; vpip = (VPIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; mutex_enter(&EMLXS_FCF_LOCK); if (vpip->state != VPI_STATE_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_mbcmpl:%d state=%s.", vpip->VPI, emlxs_vpi_state_xlate(vpip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_mbcmpl:%d failed. %s. >", vpip->VPI, emlxs_mb_xlate_status(mb4->mbxStatus)); if (mb4->mbxStatus == MBXERR_DID_INCONSISTENT) { vpip->flag |= EMLXS_VPI_OFFLINE_REQ; } (void) emlxs_vpi_state(port, vpip, VPI_STATE_REG_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_mbcmpl:%d. Reg complete. >", vpip->VPI); vpip->flag |= EMLXS_VPI_REG; (void) emlxs_vpi_state(port, vpip, VPI_STATE_REG_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_vpi_reg_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_reg_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t *wwpn; MAILBOX *mb; MAILBOXQ *mbq; uint32_t rval = 0; if (vpip->state != VPI_STATE_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_reg_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vpip->prev_state != VPI_STATE_REG_FAILED) { vpip->attempts = 0; } if (vpip->flag & EMLXS_VPI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_action:%d attempts=%d. Offline requested.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_offline_handler(port, vpip, 0); return (rval); } if (!(vpip->vfip->flag & EMLXS_VFI_REG)) { /* We can't register the VPI until our VFI is registered */ /* If this is the flogi_vpip, then we can skip the REG_VPI. */ /* REG_VPI will be performed later during REG_VFI */ if (vpip == vpip->vfip->flogi_vpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_action:%d. flogi_vpi. Skipping REG_VPI.", vpip->VPI); rval = emlxs_vpi_state(port, vpip, VPI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_action:%d attempts=%d. VFI not registered. " "Offlining.", vpip->VPI, vpip->attempts); vpip->flag &= ~EMLXS_VPI_REQ_MASK; vpip->flag |= EMLXS_VPI_OFFLINE_REQ; rval = emlxs_vpi_offline_handler(port, vpip, 0); return (rval); } if (vpip->flag & EMLXS_VPI_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_action:%d attempts=%d. Updating REG_VPI. <", vpip->VPI, vpip->attempts); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_action:%d attempts=%d. Sending REG_VPI. <", vpip->VPI, vpip->attempts); } if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_vpi_state(port, vpip, VPI_STATE_REG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb = (MAILBOX*)mbq; bzero((void *) mb, MAILBOX_CMD_BSIZE); mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_vpi_reg_mbcmpl; mbq->context = (void *)vpip; mbq->port = (void *)vpip->port; mb->un.varRegVpi.vfi = vpip->vfip->VFI; mb->un.varRegVpi.upd = (vpip->flag & EMLXS_VPI_REG)? 1:0; wwpn = (uint32_t *)&port->wwpn; mb->un.varRegVpi.portname[0] = BE_SWAP32(*wwpn); wwpn++; mb->un.varRegVpi.portname[1] = BE_SWAP32(*wwpn); mb->un.varRegVpi.vpi = vpip->VPI; mb->un.varRegVpi.sid = vpip->port->did; mb->mbxCommand = MBX_REG_VPI; mb->mbxOwner = OWN_HOST; rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_vpi_state(port, vpip, VPI_STATE_REG_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } return (0); } /* emlxs_vpi_reg_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_reg_cmpl_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vpip->state != VPI_STATE_REG_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "vpi_reg_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (vpip->flag & EMLXS_VPI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_cmpl_action:%d attempts=%d. Offline requested.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_offline_handler(port, vpip, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_reg_cmpl_action:%d attempts=%d. Going online.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_state(port, vpip, VPI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_vpi_reg_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_vpi_online_action(emlxs_port_t *port, VPIobj_t *vpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (vpip->state != VPI_STATE_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_online_action:%d %s:%s arg=%p. " "Invalid state. <", vpip->VPI, emlxs_vpi_state_xlate(vpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } vpip->flag &= ~EMLXS_VPI_ONLINE_REQ; if (vpip->flag & EMLXS_VPI_OFFLINE_REQ) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_online_action:%d attempts=%d. Offline requested.", vpip->VPI, vpip->attempts); rval = emlxs_vpi_offline_handler(port, vpip, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "vpi_online_action:%d. VPI online. Notifying VFI:%d >", vpip->VPI, vpip->vfip->VFI); /* Notify VFI */ rval = emlxs_vfi_event(port, FCF_EVENT_VPI_ONLINE, vpip); return (rval); } /* emlxs_vpi_online_action() */ /* ************************************************************************** */ /* RPI */ /* ************************************************************************** */ static char * emlxs_rpi_state_xlate(uint32_t state) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_rpi_state_table) / sizeof (emlxs_table_t); for (i = 0; i < count; i++) { if (state == emlxs_rpi_state_table[i].code) { return (emlxs_rpi_state_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "state=0x%x", state); return (buffer); } /* emlxs_rpi_state_xlate() */ static uint32_t emlxs_rpi_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 0; uint32_t(*func) (emlxs_port_t *, RPIobj_t *, uint32_t, void *); uint32_t index; uint32_t events; uint16_t state; /* Convert event to action table index */ switch (evt) { case FCF_EVENT_STATE_ENTER: index = 0; break; case FCF_EVENT_RPI_ONLINE: index = 1; break; case FCF_EVENT_RPI_OFFLINE: index = 2; break; case FCF_EVENT_RPI_PAUSE: index = 3; break; case FCF_EVENT_RPI_RESUME: index = 4; break; default: return (1); } events = RPI_ACTION_EVENTS; state = rpip->state; index += (state * events); func = (uint32_t(*) (emlxs_port_t *, RPIobj_t *, uint32_t, void *)) emlxs_rpi_action_table[index]; if (!func) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "rpi_action:%d %s:%s arg=%p. No action. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } rval = (func)(port, rpip, evt, arg1); return (rval); } /* emlxs_rpi_action() */ static uint32_t emlxs_rpi_event(emlxs_port_t *port, uint32_t evt, void *arg1) { RPIobj_t *rpip = NULL; uint32_t rval = 0; /* Filter events and acquire fcfi context */ switch (evt) { case FCF_EVENT_RPI_ONLINE: case FCF_EVENT_RPI_OFFLINE: case FCF_EVENT_RPI_PAUSE: case FCF_EVENT_RPI_RESUME: rpip = (RPIobj_t *)arg1; if (!rpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "rpi_event: %s arg=%p. Null RPI found. <", emlxs_fcf_event_xlate(evt), arg1); return (1); } break; default: return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_event_msg, "rpi_event:%d %s:%s arg=%p", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); rval = emlxs_rpi_action(port, rpip, evt, arg1); return (rval); } /* emlxs_rpi_event() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_state(emlxs_port_t *port, RPIobj_t *rpip, uint16_t state, uint16_t reason, uint32_t explain, void *arg1) { uint32_t rval = 0; if (state >= RPI_ACTION_STATES) { return (1); } if ((rpip->state == state) && (reason != FCF_REASON_REENTER)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_state:%d %s:%s:0x%x arg=%p. State not changed. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_reason_xlate(reason), explain, arg1); return (1); } if (!reason) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "rpi_state:%d %s-->%s arg=%p", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_rpi_state_xlate(state), arg1); } else if (reason == FCF_REASON_EVENT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "rpi_state:%d %s-->%s:%s:%s arg=%p", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_rpi_state_xlate(state), emlxs_fcf_reason_xlate(reason), emlxs_fcf_event_xlate(explain), arg1); } else if (explain) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "rpi_state:%d %s-->%s:%s:0x%x arg=%p", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_rpi_state_xlate(state), emlxs_fcf_reason_xlate(reason), explain, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_state_msg, "rpi_state:%d %s-->%s:%s arg=%p", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_rpi_state_xlate(state), emlxs_fcf_reason_xlate(reason), arg1); } rpip->prev_state = rpip->state; rpip->prev_reason = rpip->reason; rpip->state = state; rpip->reason = reason; rval = emlxs_rpi_action(port, rpip, FCF_EVENT_STATE_ENTER, arg1); return (rval); } /* emlxs_rpi_state() */ static void emlxs_rpi_deferred_cmpl(emlxs_port_t *port, RPIobj_t *rpip, uint32_t status) { emlxs_hba_t *hba = HBA; emlxs_deferred_cmpl_t *cmpl; if (!rpip->cmpl) { return; } cmpl = rpip->cmpl; rpip->cmpl = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_deferred_cmpl:%d. status=%x ...", port->vpip->VPI, status); emlxs_thread_spawn(hba, emlxs_deferred_cmpl_thread, (void *)cmpl, (void*)(uintptr_t)status); return; } /* emlxs_rpi_deferred_cmpl() */ static void emlxs_rpi_idle_timer(emlxs_hba_t *hba) { emlxs_config_t *cfg = &CFG; RPIobj_t *rpip; uint32_t i; /* This timer monitors for idle timeout of an RPI in a */ /* RESERVED state. */ /* This means that the RPI was reserved, but never registered. */ /* If the RPI sits for too long (~2 secs) in this state we free it */ rpip = hba->sli.sli4.RPIp; for (i = 0; i < hba->sli.sli4.RPICount; i++, rpip++) { if (rpip->state != RPI_STATE_RESERVED) { continue; } /* If RPI is active, then clear timer. */ if (rpip->xri_count) { rpip->idle_timer = 0; continue; } /* If an F-port RPI is found idle, then free it. */ /* Since an F-port RPI is never registered after the login */ /* completes, it is safe to free it immediately. */ if ((rpip->did == FABRIC_DID) || (rpip->did == SCR_DID)) { goto free_it; } /* Start idle timer if not already active */ if (!rpip->idle_timer) { rpip->idle_timer = hba->timer_tics + cfg[CFG_FCF_RPI_IDLE_TIMEOUT].current; } /* Check for idle timeout */ if (hba->timer_tics < rpip->idle_timer) { continue; } rpip->idle_timer = 0; free_it: (void) emlxs_rpi_state(rpip->vpip->port, rpip, RPI_STATE_FREE, FCF_REASON_UNUSED, 0, 0); } return; } /* emlxs_rpi_idle_timer() */ static RPIobj_t * emlxs_rpi_alloc(emlxs_port_t *port, uint32_t did) { emlxs_hba_t *hba = HBA; uint16_t i; RPIobj_t *rpip; rpip = hba->sli.sli4.RPIp; for (i = 0; i < hba->sli.sli4.RPICount; i++, rpip++) { /* To be consistent with SLI3, the RPI assignment */ /* starts with 1. ONLY one SLI4 HBA in the entire */ /* system will be sacrificed by one RPI and that */ /* is the one having RPI base equal 0. */ if ((rpip->state == RPI_STATE_FREE) && (rpip->RPI != 0)) { bzero(rpip, sizeof (RPIobj_t)); rpip->index = i; rpip->RPI = emlxs_sli4_index_to_rpi(hba, i); rpip->vpip = port->vpip; rpip->did = did; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_alloc:%d. RPI allocated. >", rpip->RPI); (void) emlxs_rpi_state(port, rpip, RPI_STATE_RESERVED, 0, 0, 0); return (rpip); } } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_alloc: Out of RPI objects."); return (NULL); } /* emlxs_rpi_alloc() */ /* Special routine for VPI object */ static void emlxs_rpi_alloc_fabric_rpi(emlxs_port_t *port) { RPIobj_t *fabric_rpip; fabric_rpip = port->vpip->fabric_rpip; if (fabric_rpip->state != RPI_STATE_FREE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_alloc_fabric_rpi: Fabric RPI active:%s.", emlxs_rpi_state_xlate(fabric_rpip->state)); return; } bzero(fabric_rpip, sizeof (RPIobj_t)); fabric_rpip->index = 0xffff; fabric_rpip->RPI = FABRIC_RPI; fabric_rpip->did = FABRIC_DID; fabric_rpip->vpip = port->vpip; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_alloc_fabric_rpi: Allocating Fabric RPI. >"); (void) emlxs_rpi_state(port, fabric_rpip, RPI_STATE_RESERVED, 0, 0, 0); return; } /* emlxs_rpi_alloc_fabric_rpi() */ static uint32_t emlxs_rpi_free(emlxs_port_t *port, RPIobj_t *rpip) { uint32_t rval = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_free:%d did=%x. Freeing RPI. >", rpip->RPI, rpip->did); rval = emlxs_rpi_state(port, rpip, RPI_STATE_FREE, 0, 0, 0); return (rval); } /* emlxs_rpi_free() */ extern RPIobj_t * emlxs_rpi_find(emlxs_port_t *port, uint16_t rpi) { emlxs_hba_t *hba = HBA; RPIobj_t *rpip; uint32_t index; /* Special handling for Fabric RPI */ if (rpi == FABRIC_RPI) { return (port->vpip->fabric_rpip); } index = emlxs_sli4_rpi_to_index(hba, rpi); if (index >= hba->sli.sli4.RPICount) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_find:%d. RPI Invalid.", rpi); return (NULL); } rpip = &hba->sli.sli4.RPIp[index]; if (rpip->state == RPI_STATE_FREE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_find:%d RPI not active", rpi); return (NULL); } return (rpip); } /* emlxs_rpi_find() */ static RPIobj_t * emlxs_rpi_find_did(emlxs_port_t *port, uint32_t did) { emlxs_hba_t *hba = HBA; RPIobj_t *rpip; RPIobj_t *rpip1; uint32_t i; rpip1 = NULL; rpip = hba->sli.sli4.RPIp; for (i = 0; i < hba->sli.sli4.RPICount; i++, rpip++) { if (rpip->state == RPI_STATE_FREE) { continue; } if ((rpip->did == did) && (rpip->vpip == port->vpip)) { rpip1 = rpip; break; } } return (rpip1); } /* emlxs_rpi_find_did() */ extern RPIobj_t * emlxs_rpi_reserve_notify(emlxs_port_t *port, uint32_t did, XRIobj_t *xrip) { emlxs_hba_t *hba = HBA; RPIobj_t *rpip; /* xrip will be NULL for unsolicited BLS requests */ if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) { return (NULL); } mutex_enter(&EMLXS_FCF_LOCK); rpip = emlxs_rpi_find_did(port, did); if (!rpip) { rpip = emlxs_rpi_alloc(port, did); } if (!rpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reserve_notify: Unable to reserve an rpi. " "did=%x xri=%d.", did, ((xrip)?xrip->XRI:0)); mutex_exit(&EMLXS_FCF_LOCK); return (NULL); } /* Bind the XRI */ if (xrip) { mutex_enter(&EMLXS_FCTAB_LOCK); xrip->reserved_rpip = rpip; rpip->xri_count++; mutex_exit(&EMLXS_FCTAB_LOCK); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reserve_notify:%d did=%x xri=%d.", rpip->RPI, rpip->did, ((xrip)?xrip->XRI:0)); mutex_exit(&EMLXS_FCF_LOCK); return (rpip); } /* emlxs_rpi_reserve_notify() */ extern RPIobj_t * emlxs_rpi_alloc_notify(emlxs_port_t *port, uint32_t did) { emlxs_hba_t *hba = HBA; RPIobj_t *rpip; if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) { return (NULL); } mutex_enter(&EMLXS_FCF_LOCK); rpip = emlxs_rpi_alloc(port, did); mutex_exit(&EMLXS_FCF_LOCK); return (rpip); } /* emlxs_rpi_alloc_notify() */ extern uint32_t emlxs_rpi_free_notify(emlxs_port_t *port, RPIobj_t *rpip) { emlxs_hba_t *hba = HBA; uint32_t rval = 0; if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) { return (1); } if (!rpip) { return (1); } /* Fabric RPI will be handled automatically */ if (rpip->RPI == FABRIC_RPI) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); rval = emlxs_rpi_free(port, rpip); mutex_exit(&EMLXS_FCF_LOCK); return (rval); } /* emlxs_rpi_free_notify() */ extern uint32_t emlxs_rpi_pause_notify(emlxs_port_t *port, RPIobj_t *rpip) { emlxs_hba_t *hba = HBA; if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) { return (1); } if (!rpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_pause_notify: No RPI provided."); return (1); } /* Fabric RPI will be handled automatically */ if (rpip->RPI == FABRIC_RPI) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_pause_notify:%d %s. Pausing RPI. >", rpip->RPI, emlxs_rpi_state_xlate(rpip->state)); (void) emlxs_rpi_event(port, FCF_EVENT_RPI_PAUSE, rpip); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_rpi_pause_notify() */ extern uint32_t emlxs_rpi_online_notify(emlxs_port_t *port, RPIobj_t *rpip, uint32_t did, SERV_PARM *sparam, void *arg1, void *arg2, void *arg3) { emlxs_hba_t *hba = HBA; emlxs_deferred_cmpl_t *cmpl; uint32_t allocated = 0; uint32_t rval = 0; if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) { return (1); } if ((did == port->did) && (!(hba->flag & FC_LOOPBACK_MODE))) { /* We never register our local port */ return (1); } mutex_enter(&EMLXS_FCF_LOCK); if (!rpip && (did == FABRIC_DID)) { /* We never online the Fabric DID other */ /* than the fabric_rpip */ rpip = port->vpip->fabric_rpip; } if (!rpip) { rpip = emlxs_rpi_find_did(port, did); } if (!rpip) { rpip = emlxs_rpi_alloc(port, did); allocated = 1; } if (!rpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_online_notify: Unable to allocate an rpi. did=%x", did); mutex_exit(&EMLXS_FCF_LOCK); return (1); } /* Initialize RPI node info */ bcopy((void *)sparam, (void *)&rpip->sparam, sizeof (SERV_PARM)); if (arg1 || arg2 || arg3) { cmpl = (emlxs_deferred_cmpl_t *)kmem_zalloc( sizeof (emlxs_deferred_cmpl_t), KM_SLEEP); cmpl->port = port; cmpl->arg1 = arg1; cmpl->arg2 = arg2; cmpl->arg3 = arg3; /* For safety */ if (rpip->cmpl) { emlxs_rpi_deferred_cmpl(port, rpip, 1); } rpip->cmpl = cmpl; } if ((rpip->RPI == FABRIC_RPI) || (hba->flag & FC_PT_TO_PT)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_online_notify:%d %s. %s. Login cmpl.", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), ((allocated)? "Allocated":"Updated")); rval = emlxs_vpi_logi_cmpl_notify(port, rpip); if (rval && rpip->cmpl) { kmem_free(rpip->cmpl, sizeof (emlxs_deferred_cmpl_t)); rpip->cmpl = 0; } mutex_exit(&EMLXS_FCF_LOCK); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_online_notify:%d %s. %s. Onlining RPI. >", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), ((allocated)? "Allocated":"Updated")); (void) emlxs_rpi_event(port, FCF_EVENT_RPI_ONLINE, rpip); if (rpip->cmpl) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_online_notify:%d %s. Deferred args not completed.", rpip->RPI, emlxs_rpi_state_xlate(rpip->state)); kmem_free(rpip->cmpl, sizeof (emlxs_deferred_cmpl_t)); rpip->cmpl = 0; mutex_exit(&EMLXS_FCF_LOCK); return (1); } mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_rpi_online_notify() */ extern uint32_t emlxs_rpi_offline_notify(emlxs_port_t *port, RPIobj_t *rpip, void *arg1, void *arg2, void *arg3) { emlxs_hba_t *hba = HBA; emlxs_deferred_cmpl_t *cmpl; if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) { return (1); } if (!rpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_offline_notify: No RPI provided."); return (1); } /* Fabric RPI will be handled automatically */ if (rpip->RPI == FABRIC_RPI) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); if (arg1 || arg2 || arg3) { cmpl = (emlxs_deferred_cmpl_t *)kmem_zalloc( sizeof (emlxs_deferred_cmpl_t), KM_SLEEP); cmpl->port = port; cmpl->arg1 = arg1; cmpl->arg2 = arg2; cmpl->arg3 = arg3; rpip->cmpl = cmpl; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_offline_notify:%d %s. Offlining RPI. >", rpip->RPI, emlxs_rpi_state_xlate(rpip->state)); (void) emlxs_rpi_event(port, FCF_EVENT_RPI_OFFLINE, rpip); if (rpip->cmpl) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_offline_notify:%d %s. Deferred args not completed.", rpip->RPI, emlxs_rpi_state_xlate(rpip->state)); kmem_free(rpip->cmpl, sizeof (emlxs_deferred_cmpl_t)); rpip->cmpl = 0; mutex_exit(&EMLXS_FCF_LOCK); return (1); } mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_rpi_offline_notify() */ extern uint32_t emlxs_rpi_resume_notify(emlxs_port_t *port, RPIobj_t *rpip, emlxs_buf_t *sbp) { emlxs_hba_t *hba = HBA; emlxs_deferred_cmpl_t *cmpl; if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) { return (1); } if (!rpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_resume_notify: No RPI provided."); return (1); } /* Fabric RPI will be handled automatically */ if (rpip->RPI == FABRIC_RPI) { return (1); } mutex_enter(&EMLXS_FCF_LOCK); if (rpip->state != RPI_STATE_PAUSED) { mutex_exit(&EMLXS_FCF_LOCK); return (1); } if (sbp) { cmpl = (emlxs_deferred_cmpl_t *)kmem_zalloc( sizeof (emlxs_deferred_cmpl_t), KM_SLEEP); cmpl->port = port; cmpl->arg1 = (void *)sbp; cmpl->arg2 = 0; cmpl->arg3 = 0; rpip->cmpl = cmpl; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_notify:%d %s. Resuming RPI. >", rpip->RPI, emlxs_rpi_state_xlate(rpip->state)); (void) emlxs_rpi_event(port, FCF_EVENT_RPI_RESUME, rpip); if (rpip->cmpl) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_resume_notify:%d %s. Deferred args not completed.", rpip->RPI, emlxs_rpi_state_xlate(rpip->state)); kmem_free(rpip->cmpl, sizeof (emlxs_deferred_cmpl_t)); rpip->cmpl = 0; mutex_exit(&EMLXS_FCF_LOCK); return (1); } mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_rpi_resume_notify() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_free_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; XRIobj_t *xrip; XRIobj_t *next_xrip; if (rpip->state != RPI_STATE_FREE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_free_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (rpip->cmpl) { emlxs_rpi_deferred_cmpl(port, rpip, 1); } if (rpip->vpip->p2p_rpip == rpip) { rpip->vpip->p2p_rpip = NULL; } /* Break node/RPI binding */ rw_enter(&port->node_rwlock, RW_WRITER); if (rpip->node) { rpip->node->rpip = NULL; rpip->node = NULL; } rw_exit(&port->node_rwlock); /* Remove all XRIs under this RPI */ mutex_enter(&EMLXS_FCTAB_LOCK); xrip = (XRIobj_t *)hba->sli.sli4.XRIinuse_f; while (xrip != (XRIobj_t *)&hba->sli.sli4.XRIinuse_f) { next_xrip = xrip->_f; if (xrip->rpip == rpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_free_action:%d xri_count=%d. " "Removing XRI:%d iotag:%d.", rpip->RPI, rpip->xri_count, xrip->XRI, xrip->iotag); rpip->xri_count--; xrip->rpip = NULL; } if (xrip->reserved_rpip == rpip) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_free_action:%d xri_count=%d. " "Removing XRI:%d iotag:%d.", rpip->RPI, rpip->xri_count, xrip->XRI, xrip->iotag); rpip->xri_count--; xrip->reserved_rpip = NULL; } xrip = next_xrip; } mutex_exit(&EMLXS_FCTAB_LOCK); if (rpip->xri_count) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_free_action:%d. xri_count=%d", rpip->RPI, rpip->xri_count); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_free_action:%d flag=%x. RPI freed. <", rpip->RPI, rpip->flag); rpip->flag = 0; return (0); } /* emlxs_rpi_free_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_online_evt_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 1; if (evt != FCF_EVENT_RPI_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_online_evt_action:%d %s:%s arg=%p. " "Invalid event type. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } switch (rpip->state) { case RPI_STATE_REG: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_online_evt_action:%d flag=%x. Registering.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_REG, FCF_REASON_REENTER, evt, arg1); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_online_evt_action:%d flag=%x. Registering.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_REG, FCF_REASON_EVENT, evt, arg1); break; } return (rval); } /* emlxs_rpi_online_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_offline_evt_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 1; if (evt != FCF_EVENT_RPI_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_offline_evt_action:%d %s:%s arg=%p. " "Invalid event type. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } switch (rpip->state) { case RPI_STATE_RESERVED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_offline_evt_action:%d flag=%x. Freeing RPI.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_FREE, FCF_REASON_EVENT, evt, arg1); break; case RPI_STATE_UNREG: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_offline_evt_action:%d flag=%x. " "Already unregistering. <", rpip->RPI, rpip->flag); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_offline_evt_action:%d flag=%x. Unregistering.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_UNREG, FCF_REASON_EVENT, evt, arg1); break; } return (rval); } /* emlxs_rpi_offline_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_pause_evt_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { VPIobj_t *vpip; uint32_t rval = 1; vpip = rpip->vpip; if (evt != FCF_EVENT_RPI_PAUSE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_pause_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1, rpip->flag); return (1); } switch (rpip->state) { case RPI_STATE_RESERVED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_pause_evt_action:%d flag=%x. Freeing RPI.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_FREE, FCF_REASON_EVENT, evt, arg1); break; case RPI_STATE_UNREG: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_pause_evt_action:%d flag=%x. Not online. <", rpip->RPI, rpip->flag); break; case RPI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_pause_evt_action:%d flag=%x. Already paused. <", rpip->RPI, rpip->flag); break; case RPI_STATE_REG: case RPI_STATE_ONLINE: case RPI_STATE_RESUME: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_pause_evt_action:%d flag=%x. Pausing.", rpip->RPI, rpip->flag); /* Don't pause an RPI, if the VPI is not pausing too */ if (!(vpip->flag & EMLXS_VPI_PAUSE_REQ)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_pause_evt_action:%d rpi_online=%d,%d " "xri_count=%d. VPI:%d pause not requested. " "Unregistering.", rpip->RPI, vpip->rpi_online, vpip->rpi_paused, rpip->xri_count, vpip->VPI); rval = emlxs_rpi_state(port, rpip, RPI_STATE_UNREG, FCF_REASON_EVENT, evt, arg1); break; } rval = emlxs_rpi_state(port, rpip, RPI_STATE_PAUSED, FCF_REASON_EVENT, evt, arg1); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_pause_evt_action:%d flag=%x. <", rpip->RPI, rpip->flag); break; } return (rval); } /* emlxs_rpi_pause_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_resume_evt_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 1; if (evt != FCF_EVENT_RPI_RESUME) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_resume_evt_action:%d %s:%s arg=%p flag=%x. " "Invalid event type. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1, rpip->flag); return (1); } switch (rpip->state) { case RPI_STATE_PAUSED: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_evt_action:%d flag=%x. Resuming.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_RESUME, FCF_REASON_EVENT, evt, arg1); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_evt_action:%d flag=%x. Not paused. <", rpip->RPI, rpip->flag); break; } return (rval); } /* emlxs_rpi_resume_evt_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_reserved_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { VPIobj_t *vpip; vpip = rpip->vpip; if (rpip->state != RPI_STATE_RESERVED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reserved_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (rpip->prev_state != RPI_STATE_FREE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reserved_action:%d %s:%s arg=%p. " "Invalid previous state. %s <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1, emlxs_rpi_state_xlate(rpip->prev_state)); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reserved_action:%d rpi_online=%d,%d. <", rpip->RPI, vpip->rpi_online, vpip->rpi_paused); return (0); } /* emlxs_rpi_reserved_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_offline_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 0; VPIobj_t *vpip; vpip = rpip->vpip; if (rpip->state != RPI_STATE_OFFLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_offline_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (rpip->flag & EMLXS_RPI_PAUSED) { rpip->flag &= ~EMLXS_RPI_PAUSED; if (vpip->rpi_paused) { vpip->rpi_paused--; } } if (rpip->flag & EMLXS_RPI_VPI) { rpip->flag &= ~EMLXS_RPI_VPI; if (vpip->rpi_online) { vpip->rpi_online--; } /* Added protection */ if (vpip->rpi_online < vpip->rpi_paused) { vpip->rpi_paused = vpip->rpi_online; } } if (rpip->RPI == FABRIC_RPI) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_offline_action:%d rpi_online=%d,%d xri_count=%d. " "Fabric RPI offline. Freeing.", rpip->RPI, vpip->rpi_online, vpip->rpi_paused, rpip->xri_count); /* Free RPI */ rval = emlxs_rpi_state(port, rpip, RPI_STATE_FREE, 0, 0, 0); return (rval); } if ((vpip->rpi_online == 0) || (vpip->rpi_online == vpip->rpi_paused)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_offline_action:%d rpi_online=%d,%d xri_count=%d. " "RPI offline. " "Notifying VPI:%d >", rpip->RPI, vpip->rpi_online, vpip->rpi_paused, rpip->xri_count, vpip->VPI); /* Notify VPI */ (void) emlxs_vpi_event(port, FCF_EVENT_RPI_OFFLINE, rpip); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_offline_action:%d rpi_online=%d,%d xri_count=%d. " "RPI offline. Freeing.", rpip->RPI, vpip->rpi_online, vpip->rpi_paused, rpip->xri_count); } /* Free RPI */ rval = emlxs_rpi_state(port, rpip, RPI_STATE_FREE, 0, 0, 0); return (rval); } /* emlxs_rpi_offline_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_paused_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { VPIobj_t *vpip; uint32_t rval = 0; vpip = rpip->vpip; if (rpip->state != RPI_STATE_PAUSED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_paused_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!(vpip->flag & EMLXS_VPI_PAUSE_REQ)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_paused_action:%d rpi_online=%d,%d xri_count=%d. " "VPI:%d pause not requested. Unregistering.", rpip->RPI, vpip->rpi_online, vpip->rpi_paused, rpip->xri_count, vpip->VPI); rval = emlxs_rpi_state(port, rpip, RPI_STATE_UNREG, FCF_REASON_EVENT, evt, arg1); return (rval); } if (!(rpip->flag & EMLXS_RPI_PAUSED)) { rpip->flag |= EMLXS_RPI_PAUSED; vpip->rpi_paused++; } /* Check if all RPI's have been paused for a VPI */ if (vpip->rpi_online == vpip->rpi_paused) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_paused_action:%d rpi_online=%d,%d xri_count=%d. " "RPI paused. " "Notifying VPI:%d >", rpip->RPI, vpip->rpi_online, vpip->rpi_paused, rpip->xri_count, vpip->VPI); /* Notify VPI */ (void) emlxs_vpi_event(port, FCF_EVENT_RPI_PAUSE, rpip); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_paused_action:%d rpi_online=%d,%d xri_count=%d. " "RPI paused. <", rpip->RPI, vpip->rpi_online, vpip->rpi_paused, rpip->xri_count); } return (0); } /* emlxs_rpi_paused_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_unreg_failed_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 0; rpip->attempts++; if (rpip->state != RPI_STATE_UNREG_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_unreg_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1, rpip->attempts); return (1); } if ((rpip->reason == FCF_REASON_SEND_FAILED) || !(rpip->flag & EMLXS_RPI_REG)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_failed_action:%d reason=%x flag=%x. " "Going offline.", rpip->RPI, rpip->reason, rpip->flag); rpip->flag &= ~EMLXS_RPI_REG; rval = emlxs_rpi_state(port, rpip, RPI_STATE_OFFLINE, FCF_REASON_OP_FAILED, rpip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_failed_action:%d flag=%x. Going online.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_ONLINE, FCF_REASON_OP_FAILED, rpip->attempts, arg1); } return (rval); } /* emlxs_rpi_unreg_failed_action() */ static void emlxs_rpi_unreg_handler(emlxs_port_t *port, RPIobj_t *rpip) { emlxs_hba_t *hba = HBA; VPIobj_t *vpip = rpip->vpip; emlxs_node_t *node = rpip->node; XRIobj_t *xrip; XRIobj_t *next_xrip; /* Special handling for Fabric RPI */ if (rpip->RPI == FABRIC_RPI) { if (node) { (void) emlxs_tx_node_flush(port, node, 0, 0, 0); (void) emlxs_chipq_node_flush(port, 0, node, 0); } /* Clear all reserved XRIs under this RPI */ mutex_enter(&EMLXS_FCTAB_LOCK); xrip = (XRIobj_t *)hba->sli.sli4.XRIinuse_f; while (xrip != (XRIobj_t *)&hba->sli.sli4.XRIinuse_f) { next_xrip = xrip->_f; /* We don't need to worry about xrip->reserved_rpip */ /* here because the Fabric RPI can never be reserved */ /* by an xri. */ if ((xrip->rpip == rpip) && (xrip->flag & EMLXS_XRI_RESERVED)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_handler:%d xri_count=%d. " "Unreserving XRI:%d iotag:%d.", rpip->RPI, rpip->xri_count, xrip->XRI, xrip->iotag); (void) emlxs_sli4_unreserve_xri(port, xrip->XRI, 0); } xrip = next_xrip; } mutex_exit(&EMLXS_FCTAB_LOCK); } rpip->flag &= ~EMLXS_RPI_REG; if (rpip->flag & EMLXS_RPI_PAUSED) { rpip->flag &= ~EMLXS_RPI_PAUSED; if (vpip->rpi_paused) { vpip->rpi_paused--; } } if (rpip->flag & EMLXS_RPI_VPI) { rpip->flag &= ~EMLXS_RPI_VPI; if (vpip->rpi_online) { vpip->rpi_online--; } /* Added protection */ if (vpip->rpi_online < vpip->rpi_paused) { vpip->rpi_paused = vpip->rpi_online; } } rw_enter(&port->node_rwlock, RW_WRITER); if (node) { rpip->node = NULL; node->rpip = NULL; } rw_exit(&port->node_rwlock); if (node) { emlxs_node_rm(port, node); } return; } /* emlxs_rpi_unreg_handler() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_unreg_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; MAILBOX4 *mb4; RPIobj_t *rpip; mutex_enter(&EMLXS_FCF_LOCK); rpip = (RPIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; if (rpip->state != RPI_STATE_UNREG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_mbcmpl:%d state=%s. " "No longer in RPI_STATE_UNREG.", rpip->RPI, emlxs_rpi_state_xlate(rpip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_mbcmpl:%d failed. %s. >", rpip->RPI, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_rpi_state(port, rpip, RPI_STATE_UNREG_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } emlxs_rpi_unreg_handler(port, rpip); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_mbcmpl:%d Unregistered. Unreg complete. >", rpip->RPI); (void) emlxs_rpi_state(port, rpip, RPI_STATE_UNREG_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_rpi_unreg_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_unreg_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; MAILBOX4 *mb4; MAILBOXQ *mbq; uint32_t rval = 0; VPIobj_t *vpip = rpip->vpip; if (rpip->state != RPI_STATE_UNREG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_unreg_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!(rpip->flag & EMLXS_RPI_REG)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_action:%d. Not registered. Going offline.", rpip->RPI); rval = emlxs_rpi_state(port, rpip, RPI_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (rpip->prev_state != RPI_STATE_UNREG_FAILED) { rpip->attempts = 0; } if (rpip->RPI == FABRIC_RPI) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_action:%d did=%x vpi=%d. Fabric RPI. " "Going offline.", rpip->RPI, rpip->did, rpip->vpip->VPI); /* Don't send UNREG_RPI, but process it as if we did */ emlxs_rpi_unreg_handler(port, rpip); rval = emlxs_rpi_state(port, rpip, RPI_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_action:%d attempts=%d. Sending UNREG_RPI. <", rpip->RPI, rpip->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_rpi_state(port, rpip, RPI_STATE_UNREG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_rpi_unreg_mbcmpl; mbq->context = (void *)rpip; mbq->port = (void *)port; mb4->mbxCommand = MBX_UNREG_RPI; mb4->mbxOwner = OWN_HOST; mb4->un.varUnregLogin.rpi = rpip->RPI; mb4->un.varUnregLogin.vpi = vpip->VPI; if (rpip->cmpl) { mbq->sbp = rpip->cmpl->arg1; mbq->ubp = rpip->cmpl->arg2; mbq->iocbq = rpip->cmpl->arg3; } rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_rpi_state(port, rpip, RPI_STATE_UNREG_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } if (rpip->cmpl) { kmem_free(rpip->cmpl, sizeof (emlxs_deferred_cmpl_t)); rpip->cmpl = 0; } return (0); } /* emlxs_rpi_unreg_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_unreg_cmpl_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (rpip->state != RPI_STATE_UNREG_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_unreg_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_unreg_cmpl_action:%d flag=%x. Going offline.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_OFFLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } /* emlxs_rpi_unreg_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_reg_failed_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 0; rpip->attempts++; if (rpip->state != RPI_STATE_REG_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_reg_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1, rpip->attempts); return (1); } if ((rpip->reason == FCF_REASON_SEND_FAILED) || !(rpip->flag & EMLXS_RPI_REG)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_failed_action:%d reason=%x flag=%x. " "Going offline.", rpip->RPI, rpip->reason, rpip->flag); rpip->flag &= ~EMLXS_RPI_REG; rval = emlxs_rpi_state(port, rpip, RPI_STATE_OFFLINE, FCF_REASON_OP_FAILED, rpip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_failed_action:%d flag=%x. Unregistering", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_UNREG, FCF_REASON_OP_FAILED, rpip->attempts, arg1); } return (rval); } /* emlxs_rpi_reg_failed_action() */ static uint32_t emlxs_rpi_reg_handler(emlxs_port_t *port, RPIobj_t *rpip) { emlxs_hba_t *hba = HBA; VPIobj_t *vpip; emlxs_node_t *node; vpip = rpip->vpip; rpip->flag |= EMLXS_RPI_REG; if (rpip->flag & EMLXS_RPI_PAUSED) { rpip->flag &= ~EMLXS_RPI_PAUSED; if (vpip->rpi_paused) { vpip->rpi_paused--; } } if (!(rpip->flag & EMLXS_RPI_VPI) && (rpip->RPI != FABRIC_RPI)) { rpip->flag |= EMLXS_RPI_VPI; vpip->rpi_online++; } /* If private loop and this is fabric RPI, then exit now */ if (!(hba->flag & FC_FABRIC_ATTACHED) && (rpip->RPI == FABRIC_RPI)) { return (0); } /* Create or update the node */ node = emlxs_node_create(port, rpip->did, rpip->RPI, &rpip->sparam); if (!node) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_handler:%d. Node create failed. Reg failed.", rpip->RPI); return (FCF_REASON_NO_NODE); } return (0); } /* emlxs_rpi_reg_handler() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_reg_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; MAILBOX4 *mb4; RPIobj_t *rpip; emlxs_node_t *node; uint32_t rval = 0; mutex_enter(&EMLXS_FCF_LOCK); rpip = (RPIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; if (rpip->state != RPI_STATE_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_mbcmpl:%d state=%s. No longer in RPI_STATE_REG.", rpip->RPI, emlxs_rpi_state_xlate(rpip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_mbcmpl:%d failed. %s. >", rpip->RPI, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_rpi_state(port, rpip, RPI_STATE_REG_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } rval = emlxs_rpi_reg_handler(port, rpip); if (rval) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_mbcmpl:%d. Reg failed. >", rpip->RPI); mb4->mbxStatus = MBX_FAILURE; (void) emlxs_rpi_state(port, rpip, RPI_STATE_REG_FAILED, rval, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } node = rpip->node; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_mbcmpl:%d Registered. Reg complete. >", rpip->RPI); (void) emlxs_rpi_state(port, rpip, RPI_STATE_REG_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); /* Needed for FCT trigger in emlxs_mb_deferred_cmpl */ if (mbq->sbp) { ((emlxs_buf_t *)mbq->sbp)->node = node; } #ifdef DHCHAP_SUPPORT if (mbq->sbp || mbq->ubp) { if (emlxs_dhc_auth_start(port, node, (uint8_t *)mbq->sbp, (uint8_t *)mbq->ubp) == 0) { /* Auth started - auth completion will */ /* handle sbp and ubp now */ mbq->sbp = NULL; mbq->ubp = NULL; } } #endif /* DHCHAP_SUPPORT */ return (0); } /* emlxs_rpi_reg_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_reg_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; MAILBOX4 *mb4; MAILBOXQ *mbq; MATCHMAP *mp; uint32_t rval = 0; if (rpip->state != RPI_STATE_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_reg_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (rpip->RPI == FABRIC_RPI) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_action:%d did=%x vpi=%d. Fabric RPI. " "Going online.", rpip->RPI, rpip->did, rpip->vpip->VPI); /* Don't send REG_RPI, but process it as if we did */ rval = emlxs_rpi_reg_handler(port, rpip); if (rval) { rval = emlxs_rpi_state(port, rpip, RPI_STATE_REG_FAILED, rval, 0, 0); return (rval); } rval = emlxs_rpi_state(port, rpip, RPI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (rpip->prev_state != RPI_STATE_REG_FAILED) { rpip->attempts = 0; } if (rpip->flag & EMLXS_RPI_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_action:%d attempts=%d. " "Updating REG_RPI. <", rpip->RPI, rpip->attempts); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_action:%d attempts=%d. " "Sending REG_RPI. <", rpip->RPI, rpip->attempts); } if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_rpi_state(port, rpip, RPI_STATE_REG_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF)) == 0) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_rpi_state(port, rpip, RPI_STATE_REG_FAILED, FCF_REASON_NO_BUFFER, 0, arg1); return (rval); } mbq->bp = (void *)mp; mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_rpi_reg_mbcmpl; mbq->context = (void *)rpip; mbq->port = (void *)port; mb4->mbxCommand = MBX_REG_RPI; mb4->mbxOwner = OWN_HOST; mb4->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (SERV_PARM); mb4->un.varRegLogin.un.sp64.addrHigh = PADDR_HI(mp->phys); mb4->un.varRegLogin.un.sp64.addrLow = PADDR_LO(mp->phys); mb4->un.varRegLogin.did = rpip->did; mb4->un.varWords[30] = 0; /* flags */ mb4->un.varRegLogin.vpi = rpip->vpip->VPI; mb4->un.varRegLogin.rpi = rpip->RPI; mb4->un.varRegLogin.update = (rpip->flag & EMLXS_RPI_REG)? 1:0; bcopy((void *)&rpip->sparam, (void *)mp->virt, sizeof (SERV_PARM)); if (rpip->cmpl) { mbq->sbp = rpip->cmpl->arg1; mbq->ubp = rpip->cmpl->arg2; mbq->iocbq = rpip->cmpl->arg3; } rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_BUF, (void *)mp); emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_rpi_state(port, rpip, RPI_STATE_REG_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } if (rpip->cmpl) { kmem_free(rpip->cmpl, sizeof (emlxs_deferred_cmpl_t)); rpip->cmpl = 0; } return (0); } /* emlxs_rpi_reg_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_reg_cmpl_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (rpip->state != RPI_STATE_REG_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_reg_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (rpip->flag & EMLXS_RPI_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_cmpl_action:%d flag=%x. Going online.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_cmpl_action:%d flag=%x. Going offline.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_OFFLINE, FCF_REASON_OP_FAILED, rpip->attempts, arg1); } return (rval); } /* emlxs_rpi_reg_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_resume_failed_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 0; rpip->attempts++; if (rpip->state != RPI_STATE_RESUME_FAILED) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_resume_failed_action:%d %s:%s arg=%p attempt=%d. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1, rpip->attempts); return (1); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_failed_action:%d attempt=%d. Unregistering.", rpip->RPI, rpip->attempts); rval = emlxs_rpi_state(port, rpip, RPI_STATE_UNREG, FCF_REASON_OP_FAILED, rpip->attempts, arg1); return (rval); } /* emlxs_rpi_resume_failed_action() */ /*ARGSUSED*/ static void emlxs_rpi_resume_handler(emlxs_port_t *port, RPIobj_t *rpip) { if (rpip->flag & EMLXS_RPI_PAUSED) { rpip->flag &= ~EMLXS_RPI_PAUSED; if (rpip->vpip->rpi_paused) { rpip->vpip->rpi_paused--; } } return; } /* emlxs_rpi_resume_handler() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_resume_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq) { emlxs_port_t *port = (emlxs_port_t *)mbq->port; MAILBOX4 *mb4; RPIobj_t *rpip; mutex_enter(&EMLXS_FCF_LOCK); rpip = (RPIobj_t *)mbq->context; mb4 = (MAILBOX4 *)mbq; if (rpip->state != RPI_STATE_RESUME) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_mbcmpl:%d state=%s. " "No longer in RPI_STATE_RESUME.", rpip->RPI, emlxs_rpi_state_xlate(rpip->state)); mutex_exit(&EMLXS_FCF_LOCK); return (0); } if (mb4->mbxStatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_mbcmpl:%d failed. %s. >", rpip->RPI, emlxs_mb_xlate_status(mb4->mbxStatus)); (void) emlxs_rpi_state(port, rpip, RPI_STATE_RESUME_FAILED, FCF_REASON_MBOX_FAILED, mb4->mbxStatus, (void *)mbq->sbp); mutex_exit(&EMLXS_FCF_LOCK); return (0); } emlxs_rpi_resume_handler(port, rpip); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_mbcmpl:%d Resumed. Resume complete. >", rpip->RPI); (void) emlxs_rpi_state(port, rpip, RPI_STATE_RESUME_CMPL, 0, 0, 0); mutex_exit(&EMLXS_FCF_LOCK); return (0); } /* emlxs_rpi_resume_mbcmpl() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_resume_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; MAILBOX4 *mb4; MAILBOXQ *mbq; uint32_t rval = 0; if (rpip->state != RPI_STATE_RESUME) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_resume_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (!(rpip->flag & EMLXS_RPI_PAUSED)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_action:%d flag=%x. Not Paused. Going online.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (rpip->RPI == FABRIC_RPI) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_action:%d. Fabric RPI. " "Going online.", rpip->RPI); /* Don't send RESUME_RPI, but process it as if we did */ emlxs_rpi_resume_handler(port, rpip); rval = emlxs_rpi_state(port, rpip, RPI_STATE_ONLINE, FCF_REASON_EVENT, evt, arg1); return (rval); } if (rpip->prev_state != RPI_STATE_RESUME_FAILED) { rpip->attempts = 0; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_action:%d attempts=%d. Sending RESUME_RPI. <", rpip->RPI, rpip->attempts); if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))) { rval = emlxs_rpi_state(port, rpip, RPI_STATE_RESUME_FAILED, FCF_REASON_NO_MBOX, 0, arg1); return (rval); } mb4 = (MAILBOX4*)mbq; bzero((void *) mb4, MAILBOX_CMD_SLI4_BSIZE); mbq->nonembed = NULL; mbq->mbox_cmpl = emlxs_rpi_resume_mbcmpl; mbq->context = (void *)rpip; mbq->port = (void *)port; mb4->mbxCommand = MBX_RESUME_RPI; mb4->mbxOwner = OWN_HOST; mb4->un.varResumeRPI.EventTag = hba->link_event_tag; mb4->un.varResumeRPI.RPI = rpip->RPI; if (rpip->cmpl) { mbq->sbp = rpip->cmpl->arg1; mbq->ubp = rpip->cmpl->arg2; mbq->iocbq = rpip->cmpl->arg3; } rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0); if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) { emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); rval = emlxs_rpi_state(port, rpip, RPI_STATE_RESUME_FAILED, FCF_REASON_SEND_FAILED, rval, arg1); return (rval); } if (rpip->cmpl) { kmem_free(rpip->cmpl, sizeof (emlxs_deferred_cmpl_t)); rpip->cmpl = 0; } return (0); } /* emlxs_rpi_resume_action() */ static uint32_t emlxs_rpi_resume_cmpl_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { uint32_t rval = 0; if (rpip->state != RPI_STATE_RESUME_CMPL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_error_msg, "rpi_resume_cmpl_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (rpip->flag & EMLXS_RPI_PAUSED) { if (rpip->flag & EMLXS_RPI_REG) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_cmpl_action:%d flag=%x. Unregistering.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_UNREG, FCF_REASON_OP_FAILED, rpip->attempts, arg1); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_reg_cmpl_action:%d flag=%x. Going offline.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_OFFLINE, FCF_REASON_OP_FAILED, rpip->attempts, arg1); } } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_resume_cmpl_action:%d flag=%x. Going online.", rpip->RPI, rpip->flag); rval = emlxs_rpi_state(port, rpip, RPI_STATE_ONLINE, FCF_REASON_OP_FAILED, rpip->attempts, arg1); } return (rval); } /* emlxs_rpi_resume_cmpl_action() */ /*ARGSUSED*/ static uint32_t emlxs_rpi_online_action(emlxs_port_t *port, RPIobj_t *rpip, uint32_t evt, void *arg1) { emlxs_hba_t *hba = HBA; uint32_t rval = 0; RPIobj_t *p2p_rpip; if (rpip->state != RPI_STATE_ONLINE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_online_action:%d %s:%s arg=%p. " "Invalid state. <", rpip->RPI, emlxs_rpi_state_xlate(rpip->state), emlxs_fcf_event_xlate(evt), arg1); return (1); } if (rpip->RPI == FABRIC_RPI) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_online_action:%d did=%x. Fabric RPI online. <", rpip->RPI, rpip->did, rpip->vpip->VPI); /* Now register the p2p_rpip */ p2p_rpip = rpip->vpip->p2p_rpip; if (p2p_rpip) { rpip->vpip->p2p_rpip = NULL; rval = emlxs_rpi_state(port, p2p_rpip, RPI_STATE_REG, FCF_REASON_EVENT, evt, arg1); } EMLXS_STATE_CHANGE(hba, FC_READY); if (rpip->cmpl) { emlxs_rpi_deferred_cmpl(port, rpip, 0); } return (0); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcf_detail_msg, "rpi_online_action:%d did=%x. RPI online. Notifying VPI:%d. >", rpip->RPI, rpip->did, rpip->vpip->VPI); /* Notify VPI */ rval = emlxs_vpi_event(port, FCF_EVENT_RPI_ONLINE, rpip); return (rval); } /* emlxs_rpi_online_action() */