1*ef270ab1SKenneth D. Merry /*- 2*ef270ab1SKenneth D. Merry * Copyright (c) 2017 Broadcom. All rights reserved. 3*ef270ab1SKenneth D. Merry * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4*ef270ab1SKenneth D. Merry * 5*ef270ab1SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 6*ef270ab1SKenneth D. Merry * modification, are permitted provided that the following conditions are met: 7*ef270ab1SKenneth D. Merry * 8*ef270ab1SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright notice, 9*ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer. 10*ef270ab1SKenneth D. Merry * 11*ef270ab1SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright notice, 12*ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer in the documentation 13*ef270ab1SKenneth D. Merry * and/or other materials provided with the distribution. 14*ef270ab1SKenneth D. Merry * 15*ef270ab1SKenneth D. Merry * 3. Neither the name of the copyright holder nor the names of its contributors 16*ef270ab1SKenneth D. Merry * may be used to endorse or promote products derived from this software 17*ef270ab1SKenneth D. Merry * without specific prior written permission. 18*ef270ab1SKenneth D. Merry * 19*ef270ab1SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20*ef270ab1SKenneth D. Merry * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*ef270ab1SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*ef270ab1SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23*ef270ab1SKenneth D. Merry * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24*ef270ab1SKenneth D. Merry * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25*ef270ab1SKenneth D. Merry * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26*ef270ab1SKenneth D. Merry * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27*ef270ab1SKenneth D. Merry * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28*ef270ab1SKenneth D. Merry * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29*ef270ab1SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGE. 30*ef270ab1SKenneth D. Merry * 31*ef270ab1SKenneth D. Merry * $FreeBSD$ 32*ef270ab1SKenneth D. Merry */ 33*ef270ab1SKenneth D. Merry 34*ef270ab1SKenneth D. Merry /** 35*ef270ab1SKenneth D. Merry * @file 36*ef270ab1SKenneth D. Merry * 37*ef270ab1SKenneth D. Merry * This file implements remote node state machines for: 38*ef270ab1SKenneth D. Merry * - Fabric logins. 39*ef270ab1SKenneth D. Merry * - Fabric controller events. 40*ef270ab1SKenneth D. Merry * - Name/directory services interaction. 41*ef270ab1SKenneth D. Merry * - Point-to-point logins. 42*ef270ab1SKenneth D. Merry */ 43*ef270ab1SKenneth D. Merry 44*ef270ab1SKenneth D. Merry /*! 45*ef270ab1SKenneth D. Merry @defgroup fabric_sm Node State Machine: Fabric States 46*ef270ab1SKenneth D. Merry @defgroup ns_sm Node State Machine: Name/Directory Services States 47*ef270ab1SKenneth D. Merry @defgroup p2p_sm Node State Machine: Point-to-Point Node States 48*ef270ab1SKenneth D. Merry */ 49*ef270ab1SKenneth D. Merry 50*ef270ab1SKenneth D. Merry #include "ocs.h" 51*ef270ab1SKenneth D. Merry #include "ocs_fabric.h" 52*ef270ab1SKenneth D. Merry #include "ocs_els.h" 53*ef270ab1SKenneth D. Merry #include "ocs_device.h" 54*ef270ab1SKenneth D. Merry 55*ef270ab1SKenneth D. Merry static void ocs_fabric_initiate_shutdown(ocs_node_t *node); 56*ef270ab1SKenneth D. Merry static void * __ocs_fabric_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg); 57*ef270ab1SKenneth D. Merry static int32_t ocs_start_ns_node(ocs_sport_t *sport); 58*ef270ab1SKenneth D. Merry static int32_t ocs_start_fabctl_node(ocs_sport_t *sport); 59*ef270ab1SKenneth D. Merry static int32_t ocs_process_gidpt_payload(ocs_node_t *node, fcct_gidpt_acc_t *gidpt, uint32_t gidpt_len); 60*ef270ab1SKenneth D. Merry static void ocs_process_rscn(ocs_node_t *node, ocs_node_cb_t *cbdata); 61*ef270ab1SKenneth D. Merry static uint64_t ocs_get_wwpn(fc_plogi_payload_t *sp); 62*ef270ab1SKenneth D. Merry static void gidpt_delay_timer_cb(void *arg); 63*ef270ab1SKenneth D. Merry 64*ef270ab1SKenneth D. Merry /** 65*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 66*ef270ab1SKenneth D. Merry * @brief Fabric node state machine: Initial state. 67*ef270ab1SKenneth D. Merry * 68*ef270ab1SKenneth D. Merry * @par Description 69*ef270ab1SKenneth D. Merry * Send an FLOGI to a well-known fabric. 70*ef270ab1SKenneth D. Merry * 71*ef270ab1SKenneth D. Merry * @param ctx Remote node sm context. 72*ef270ab1SKenneth D. Merry * @param evt Event to process. 73*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 74*ef270ab1SKenneth D. Merry * 75*ef270ab1SKenneth D. Merry * @return Returns NULL. 76*ef270ab1SKenneth D. Merry */ 77*ef270ab1SKenneth D. Merry void * 78*ef270ab1SKenneth D. Merry __ocs_fabric_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 79*ef270ab1SKenneth D. Merry { 80*ef270ab1SKenneth D. Merry std_node_state_decl(); 81*ef270ab1SKenneth D. Merry 82*ef270ab1SKenneth D. Merry node_sm_trace(); 83*ef270ab1SKenneth D. Merry 84*ef270ab1SKenneth D. Merry switch(evt) { 85*ef270ab1SKenneth D. Merry case OCS_EVT_REENTER: /* not sure why we're getting these ... */ 86*ef270ab1SKenneth D. Merry ocs_log_debug(node->ocs, ">>> reenter !!\n"); 87*ef270ab1SKenneth D. Merry /* fall through */ 88*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 89*ef270ab1SKenneth D. Merry /* sm: / send FLOGI */ 90*ef270ab1SKenneth D. Merry ocs_send_flogi(node, OCS_FC_FLOGI_TIMEOUT_SEC, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 91*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabric_flogi_wait_rsp, NULL); 92*ef270ab1SKenneth D. Merry break; 93*ef270ab1SKenneth D. Merry 94*ef270ab1SKenneth D. Merry default: 95*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 96*ef270ab1SKenneth D. Merry break; 97*ef270ab1SKenneth D. Merry } 98*ef270ab1SKenneth D. Merry 99*ef270ab1SKenneth D. Merry return NULL; 100*ef270ab1SKenneth D. Merry } 101*ef270ab1SKenneth D. Merry 102*ef270ab1SKenneth D. Merry /** 103*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 104*ef270ab1SKenneth D. Merry * @brief Set sport topology. 105*ef270ab1SKenneth D. Merry * 106*ef270ab1SKenneth D. Merry * @par Description 107*ef270ab1SKenneth D. Merry * Set sport topology. 108*ef270ab1SKenneth D. Merry * 109*ef270ab1SKenneth D. Merry * @param node Pointer to the node for which the topology is set. 110*ef270ab1SKenneth D. Merry * @param topology Topology to set. 111*ef270ab1SKenneth D. Merry * 112*ef270ab1SKenneth D. Merry * @return Returns NULL. 113*ef270ab1SKenneth D. Merry */ 114*ef270ab1SKenneth D. Merry void 115*ef270ab1SKenneth D. Merry ocs_fabric_set_topology(ocs_node_t *node, ocs_sport_topology_e topology) 116*ef270ab1SKenneth D. Merry { 117*ef270ab1SKenneth D. Merry node->sport->topology = topology; 118*ef270ab1SKenneth D. Merry } 119*ef270ab1SKenneth D. Merry 120*ef270ab1SKenneth D. Merry /** 121*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 122*ef270ab1SKenneth D. Merry * @brief Notify sport topology. 123*ef270ab1SKenneth D. Merry * @par Description 124*ef270ab1SKenneth D. Merry * notify sport topology. 125*ef270ab1SKenneth D. Merry * @param node Pointer to the node for which the topology is set. 126*ef270ab1SKenneth D. Merry * @return Returns NULL. 127*ef270ab1SKenneth D. Merry */ 128*ef270ab1SKenneth D. Merry void 129*ef270ab1SKenneth D. Merry ocs_fabric_notify_topology(ocs_node_t *node) 130*ef270ab1SKenneth D. Merry { 131*ef270ab1SKenneth D. Merry ocs_node_t *tmp_node; 132*ef270ab1SKenneth D. Merry ocs_node_t *next; 133*ef270ab1SKenneth D. Merry ocs_sport_topology_e topology = node->sport->topology; 134*ef270ab1SKenneth D. Merry 135*ef270ab1SKenneth D. Merry /* now loop through the nodes in the sport and send topology notification */ 136*ef270ab1SKenneth D. Merry ocs_sport_lock(node->sport); 137*ef270ab1SKenneth D. Merry ocs_list_foreach_safe(&node->sport->node_list, tmp_node, next) { 138*ef270ab1SKenneth D. Merry if (tmp_node != node) { 139*ef270ab1SKenneth D. Merry ocs_node_post_event(tmp_node, OCS_EVT_SPORT_TOPOLOGY_NOTIFY, (void *)topology); 140*ef270ab1SKenneth D. Merry } 141*ef270ab1SKenneth D. Merry } 142*ef270ab1SKenneth D. Merry ocs_sport_unlock(node->sport); 143*ef270ab1SKenneth D. Merry } 144*ef270ab1SKenneth D. Merry 145*ef270ab1SKenneth D. Merry /** 146*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 147*ef270ab1SKenneth D. Merry * @brief Fabric node state machine: Wait for an FLOGI response. 148*ef270ab1SKenneth D. Merry * 149*ef270ab1SKenneth D. Merry * @par Description 150*ef270ab1SKenneth D. Merry * Wait for an FLOGI response event. 151*ef270ab1SKenneth D. Merry * 152*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 153*ef270ab1SKenneth D. Merry * @param evt Event to process. 154*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 155*ef270ab1SKenneth D. Merry * 156*ef270ab1SKenneth D. Merry * @return Returns NULL. 157*ef270ab1SKenneth D. Merry */ 158*ef270ab1SKenneth D. Merry 159*ef270ab1SKenneth D. Merry void * 160*ef270ab1SKenneth D. Merry __ocs_fabric_flogi_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 161*ef270ab1SKenneth D. Merry { 162*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 163*ef270ab1SKenneth D. Merry std_node_state_decl(); 164*ef270ab1SKenneth D. Merry 165*ef270ab1SKenneth D. Merry node_sm_trace(); 166*ef270ab1SKenneth D. Merry 167*ef270ab1SKenneth D. Merry switch(evt) { 168*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: { 169*ef270ab1SKenneth D. Merry 170*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FLOGI, __ocs_fabric_common, __func__)) { 171*ef270ab1SKenneth D. Merry return NULL; 172*ef270ab1SKenneth D. Merry } 173*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 174*ef270ab1SKenneth D. Merry node->els_req_cnt--; 175*ef270ab1SKenneth D. Merry 176*ef270ab1SKenneth D. Merry ocs_domain_save_sparms(node->sport->domain, cbdata->els->els_rsp.virt); 177*ef270ab1SKenneth D. Merry 178*ef270ab1SKenneth D. Merry ocs_display_sparams(node->display_name, "flogi rcvd resp", 0, NULL, 179*ef270ab1SKenneth D. Merry ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 180*ef270ab1SKenneth D. Merry 181*ef270ab1SKenneth D. Merry /* Check to see if the fabric is an F_PORT or and N_PORT */ 182*ef270ab1SKenneth D. Merry if (ocs_rnode_is_nport(cbdata->els->els_rsp.virt)) { 183*ef270ab1SKenneth D. Merry /* sm: if nport and p2p_winner / ocs_domain_attach */ 184*ef270ab1SKenneth D. Merry ocs_fabric_set_topology(node, OCS_SPORT_TOPOLOGY_P2P); 185*ef270ab1SKenneth D. Merry if (ocs_p2p_setup(node->sport)) { 186*ef270ab1SKenneth D. Merry node_printf(node, "p2p setup failed, shutting down node\n"); 187*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 188*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 189*ef270ab1SKenneth D. Merry } else { 190*ef270ab1SKenneth D. Merry if (node->sport->p2p_winner) { 191*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_p2p_wait_domain_attach, NULL); 192*ef270ab1SKenneth D. Merry if (!node->sport->domain->attached) { 193*ef270ab1SKenneth D. Merry node_printf(node, "p2p winner, domain not attached\n"); 194*ef270ab1SKenneth D. Merry ocs_domain_attach(node->sport->domain, node->sport->p2p_port_id); 195*ef270ab1SKenneth D. Merry } else { 196*ef270ab1SKenneth D. Merry /* already attached, just send ATTACH_OK */ 197*ef270ab1SKenneth D. Merry node_printf(node, "p2p winner, domain already attached\n"); 198*ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_DOMAIN_ATTACH_OK, NULL); 199*ef270ab1SKenneth D. Merry } 200*ef270ab1SKenneth D. Merry } else { 201*ef270ab1SKenneth D. Merry /* peer is p2p winner; PLOGI will be received on the 202*ef270ab1SKenneth D. Merry * remote SID=1 node; this node has served its purpose 203*ef270ab1SKenneth D. Merry */ 204*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 205*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 206*ef270ab1SKenneth D. Merry } 207*ef270ab1SKenneth D. Merry } 208*ef270ab1SKenneth D. Merry } else { 209*ef270ab1SKenneth D. Merry /* sm: if not nport / ocs_domain_attach */ 210*ef270ab1SKenneth D. Merry /* ext_status has the fc_id, attach domain */ 211*ef270ab1SKenneth D. Merry ocs_fabric_set_topology(node, OCS_SPORT_TOPOLOGY_FABRIC); 212*ef270ab1SKenneth D. Merry ocs_fabric_notify_topology(node); 213*ef270ab1SKenneth D. Merry ocs_assert(!node->sport->domain->attached, NULL); 214*ef270ab1SKenneth D. Merry ocs_domain_attach(node->sport->domain, cbdata->ext_status); 215*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabric_wait_domain_attach, NULL); 216*ef270ab1SKenneth D. Merry } 217*ef270ab1SKenneth D. Merry 218*ef270ab1SKenneth D. Merry break; 219*ef270ab1SKenneth D. Merry } 220*ef270ab1SKenneth D. Merry 221*ef270ab1SKenneth D. Merry case OCS_EVT_ELS_REQ_ABORTED: 222*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_RJT: 223*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_FAIL: { 224*ef270ab1SKenneth D. Merry ocs_sport_t *sport = node->sport; 225*ef270ab1SKenneth D. Merry /* 226*ef270ab1SKenneth D. Merry * with these errors, we have no recovery, so shutdown the sport, leave the link 227*ef270ab1SKenneth D. Merry * up and the domain ready 228*ef270ab1SKenneth D. Merry */ 229*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FLOGI, __ocs_fabric_common, __func__)) { 230*ef270ab1SKenneth D. Merry return NULL; 231*ef270ab1SKenneth D. Merry } 232*ef270ab1SKenneth D. Merry node_printf(node, "FLOGI failed evt=%s, shutting down sport [%s]\n", ocs_sm_event_name(evt), 233*ef270ab1SKenneth D. Merry sport->display_name); 234*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 235*ef270ab1SKenneth D. Merry node->els_req_cnt--; 236*ef270ab1SKenneth D. Merry ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL); 237*ef270ab1SKenneth D. Merry break; 238*ef270ab1SKenneth D. Merry } 239*ef270ab1SKenneth D. Merry 240*ef270ab1SKenneth D. Merry default: 241*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 242*ef270ab1SKenneth D. Merry break; 243*ef270ab1SKenneth D. Merry } 244*ef270ab1SKenneth D. Merry 245*ef270ab1SKenneth D. Merry return NULL; 246*ef270ab1SKenneth D. Merry } 247*ef270ab1SKenneth D. Merry 248*ef270ab1SKenneth D. Merry /** 249*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 250*ef270ab1SKenneth D. Merry * @brief Fabric node state machine: Initial state for a virtual port. 251*ef270ab1SKenneth D. Merry * 252*ef270ab1SKenneth D. Merry * @par Description 253*ef270ab1SKenneth D. Merry * State entered when a virtual port is created. Send FDISC. 254*ef270ab1SKenneth D. Merry * 255*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 256*ef270ab1SKenneth D. Merry * @param evt Event to process. 257*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 258*ef270ab1SKenneth D. Merry * 259*ef270ab1SKenneth D. Merry * @return Returns NULL. 260*ef270ab1SKenneth D. Merry */ 261*ef270ab1SKenneth D. Merry void * 262*ef270ab1SKenneth D. Merry __ocs_vport_fabric_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 263*ef270ab1SKenneth D. Merry { 264*ef270ab1SKenneth D. Merry std_node_state_decl(); 265*ef270ab1SKenneth D. Merry 266*ef270ab1SKenneth D. Merry node_sm_trace(); 267*ef270ab1SKenneth D. Merry 268*ef270ab1SKenneth D. Merry switch(evt) { 269*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 270*ef270ab1SKenneth D. Merry /* sm: send FDISC */ 271*ef270ab1SKenneth D. Merry ocs_send_fdisc(node, OCS_FC_FLOGI_TIMEOUT_SEC, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 272*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabric_fdisc_wait_rsp, NULL); 273*ef270ab1SKenneth D. Merry break; 274*ef270ab1SKenneth D. Merry 275*ef270ab1SKenneth D. Merry default: 276*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 277*ef270ab1SKenneth D. Merry break; 278*ef270ab1SKenneth D. Merry } 279*ef270ab1SKenneth D. Merry 280*ef270ab1SKenneth D. Merry return NULL; 281*ef270ab1SKenneth D. Merry } 282*ef270ab1SKenneth D. Merry 283*ef270ab1SKenneth D. Merry /** 284*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 285*ef270ab1SKenneth D. Merry * @brief Fabric node state machine: Wait for an FDISC response 286*ef270ab1SKenneth D. Merry * 287*ef270ab1SKenneth D. Merry * @par Description 288*ef270ab1SKenneth D. Merry * Used for a virtual port. Waits for an FDISC response. If OK, issue a HW port attach. 289*ef270ab1SKenneth D. Merry * 290*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 291*ef270ab1SKenneth D. Merry * @param evt Event to process. 292*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 293*ef270ab1SKenneth D. Merry * 294*ef270ab1SKenneth D. Merry * @return Returns NULL. 295*ef270ab1SKenneth D. Merry */ 296*ef270ab1SKenneth D. Merry void * 297*ef270ab1SKenneth D. Merry __ocs_fabric_fdisc_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 298*ef270ab1SKenneth D. Merry { 299*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 300*ef270ab1SKenneth D. Merry std_node_state_decl(); 301*ef270ab1SKenneth D. Merry 302*ef270ab1SKenneth D. Merry node_sm_trace(); 303*ef270ab1SKenneth D. Merry 304*ef270ab1SKenneth D. Merry switch(evt) { 305*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: { 306*ef270ab1SKenneth D. Merry /* fc_id is in ext_status */ 307*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FDISC, __ocs_fabric_common, __func__)) { 308*ef270ab1SKenneth D. Merry return NULL; 309*ef270ab1SKenneth D. Merry } 310*ef270ab1SKenneth D. Merry 311*ef270ab1SKenneth D. Merry ocs_display_sparams(node->display_name, "fdisc rcvd resp", 0, NULL, 312*ef270ab1SKenneth D. Merry ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 313*ef270ab1SKenneth D. Merry 314*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 315*ef270ab1SKenneth D. Merry node->els_req_cnt--; 316*ef270ab1SKenneth D. Merry /* sm: ocs_sport_attach */ 317*ef270ab1SKenneth D. Merry ocs_sport_attach(node->sport, cbdata->ext_status); 318*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabric_wait_domain_attach, NULL); 319*ef270ab1SKenneth D. Merry break; 320*ef270ab1SKenneth D. Merry 321*ef270ab1SKenneth D. Merry } 322*ef270ab1SKenneth D. Merry 323*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_RJT: 324*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_FAIL: { 325*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_FDISC, __ocs_fabric_common, __func__)) { 326*ef270ab1SKenneth D. Merry return NULL; 327*ef270ab1SKenneth D. Merry } 328*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 329*ef270ab1SKenneth D. Merry node->els_req_cnt--; 330*ef270ab1SKenneth D. Merry ocs_log_err(ocs, "FDISC failed, shutting down sport\n"); 331*ef270ab1SKenneth D. Merry /* sm: shutdown sport */ 332*ef270ab1SKenneth D. Merry ocs_sm_post_event(&node->sport->sm, OCS_EVT_SHUTDOWN, NULL); 333*ef270ab1SKenneth D. Merry break; 334*ef270ab1SKenneth D. Merry } 335*ef270ab1SKenneth D. Merry 336*ef270ab1SKenneth D. Merry default: 337*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 338*ef270ab1SKenneth D. Merry break; 339*ef270ab1SKenneth D. Merry } 340*ef270ab1SKenneth D. Merry 341*ef270ab1SKenneth D. Merry return NULL; 342*ef270ab1SKenneth D. Merry } 343*ef270ab1SKenneth D. Merry 344*ef270ab1SKenneth D. Merry /** 345*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 346*ef270ab1SKenneth D. Merry * @brief Fabric node state machine: Wait for a domain/sport attach event. 347*ef270ab1SKenneth D. Merry * 348*ef270ab1SKenneth D. Merry * @par Description 349*ef270ab1SKenneth D. Merry * Waits for a domain/sport attach event. 350*ef270ab1SKenneth D. Merry * 351*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 352*ef270ab1SKenneth D. Merry * @param evt Event to process. 353*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 354*ef270ab1SKenneth D. Merry * 355*ef270ab1SKenneth D. Merry * @return Returns NULL. 356*ef270ab1SKenneth D. Merry */ 357*ef270ab1SKenneth D. Merry void * 358*ef270ab1SKenneth D. Merry __ocs_fabric_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 359*ef270ab1SKenneth D. Merry { 360*ef270ab1SKenneth D. Merry std_node_state_decl(); 361*ef270ab1SKenneth D. Merry 362*ef270ab1SKenneth D. Merry node_sm_trace(); 363*ef270ab1SKenneth D. Merry 364*ef270ab1SKenneth D. Merry switch(evt) { 365*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 366*ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 367*ef270ab1SKenneth D. Merry break; 368*ef270ab1SKenneth D. Merry 369*ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 370*ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 371*ef270ab1SKenneth D. Merry break; 372*ef270ab1SKenneth D. Merry case OCS_EVT_DOMAIN_ATTACH_OK: 373*ef270ab1SKenneth D. Merry case OCS_EVT_SPORT_ATTACH_OK: { 374*ef270ab1SKenneth D. Merry int rc; 375*ef270ab1SKenneth D. Merry 376*ef270ab1SKenneth D. Merry rc = ocs_start_ns_node(node->sport); 377*ef270ab1SKenneth D. Merry if (rc) 378*ef270ab1SKenneth D. Merry return NULL; 379*ef270ab1SKenneth D. Merry 380*ef270ab1SKenneth D. Merry /* sm: if enable_ini / start fabctl node 381*ef270ab1SKenneth D. Merry * Instantiate the fabric controller (sends SCR) */ 382*ef270ab1SKenneth D. Merry if (node->sport->enable_rscn) { 383*ef270ab1SKenneth D. Merry rc = ocs_start_fabctl_node(node->sport); 384*ef270ab1SKenneth D. Merry if (rc) 385*ef270ab1SKenneth D. Merry return NULL; 386*ef270ab1SKenneth D. Merry } 387*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabric_idle, NULL); 388*ef270ab1SKenneth D. Merry break; 389*ef270ab1SKenneth D. Merry } 390*ef270ab1SKenneth D. Merry default: 391*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 392*ef270ab1SKenneth D. Merry return NULL; 393*ef270ab1SKenneth D. Merry } 394*ef270ab1SKenneth D. Merry 395*ef270ab1SKenneth D. Merry return NULL; 396*ef270ab1SKenneth D. Merry } 397*ef270ab1SKenneth D. Merry 398*ef270ab1SKenneth D. Merry /** 399*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 400*ef270ab1SKenneth D. Merry * @brief Fabric node state machine: Fabric node is idle. 401*ef270ab1SKenneth D. Merry * 402*ef270ab1SKenneth D. Merry * @par Description 403*ef270ab1SKenneth D. Merry * Wait for fabric node events. 404*ef270ab1SKenneth D. Merry * 405*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 406*ef270ab1SKenneth D. Merry * @param evt Event to process. 407*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 408*ef270ab1SKenneth D. Merry * 409*ef270ab1SKenneth D. Merry * @return Returns NULL. 410*ef270ab1SKenneth D. Merry */ 411*ef270ab1SKenneth D. Merry void * 412*ef270ab1SKenneth D. Merry __ocs_fabric_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 413*ef270ab1SKenneth D. Merry { 414*ef270ab1SKenneth D. Merry std_node_state_decl(); 415*ef270ab1SKenneth D. Merry 416*ef270ab1SKenneth D. Merry node_sm_trace(); 417*ef270ab1SKenneth D. Merry 418*ef270ab1SKenneth D. Merry switch(evt) { 419*ef270ab1SKenneth D. Merry case OCS_EVT_DOMAIN_ATTACH_OK: 420*ef270ab1SKenneth D. Merry break; 421*ef270ab1SKenneth D. Merry default: 422*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 423*ef270ab1SKenneth D. Merry return NULL; 424*ef270ab1SKenneth D. Merry } 425*ef270ab1SKenneth D. Merry 426*ef270ab1SKenneth D. Merry return NULL; 427*ef270ab1SKenneth D. Merry } 428*ef270ab1SKenneth D. Merry 429*ef270ab1SKenneth D. Merry /** 430*ef270ab1SKenneth D. Merry * @ingroup ns_sm 431*ef270ab1SKenneth D. Merry * @brief Name services node state machine: Initialize. 432*ef270ab1SKenneth D. Merry * 433*ef270ab1SKenneth D. Merry * @par Description 434*ef270ab1SKenneth D. Merry * A PLOGI is sent to the well-known name/directory services node. 435*ef270ab1SKenneth D. Merry * 436*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 437*ef270ab1SKenneth D. Merry * @param evt Event to process. 438*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 439*ef270ab1SKenneth D. Merry * 440*ef270ab1SKenneth D. Merry * @return Returns NULL. 441*ef270ab1SKenneth D. Merry */ 442*ef270ab1SKenneth D. Merry void * 443*ef270ab1SKenneth D. Merry __ocs_ns_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 444*ef270ab1SKenneth D. Merry { 445*ef270ab1SKenneth D. Merry std_node_state_decl(); 446*ef270ab1SKenneth D. Merry 447*ef270ab1SKenneth D. Merry node_sm_trace(); 448*ef270ab1SKenneth D. Merry 449*ef270ab1SKenneth D. Merry switch(evt) { 450*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 451*ef270ab1SKenneth D. Merry /* sm: send PLOGI */ 452*ef270ab1SKenneth D. Merry ocs_send_plogi(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 453*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_plogi_wait_rsp, NULL); 454*ef270ab1SKenneth D. Merry break; 455*ef270ab1SKenneth D. Merry default: 456*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 457*ef270ab1SKenneth D. Merry break; 458*ef270ab1SKenneth D. Merry } 459*ef270ab1SKenneth D. Merry 460*ef270ab1SKenneth D. Merry return NULL; 461*ef270ab1SKenneth D. Merry } 462*ef270ab1SKenneth D. Merry 463*ef270ab1SKenneth D. Merry /** 464*ef270ab1SKenneth D. Merry * @ingroup ns_sm 465*ef270ab1SKenneth D. Merry * @brief Name services node state machine: Wait for a PLOGI response. 466*ef270ab1SKenneth D. Merry * 467*ef270ab1SKenneth D. Merry * @par Description 468*ef270ab1SKenneth D. Merry * Waits for a response from PLOGI to name services node, then issues a 469*ef270ab1SKenneth D. Merry * node attach request to the HW. 470*ef270ab1SKenneth D. Merry * 471*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 472*ef270ab1SKenneth D. Merry * @param evt Event to process. 473*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 474*ef270ab1SKenneth D. Merry * 475*ef270ab1SKenneth D. Merry * @return Returns NULL. 476*ef270ab1SKenneth D. Merry */ 477*ef270ab1SKenneth D. Merry void * 478*ef270ab1SKenneth D. Merry __ocs_ns_plogi_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 479*ef270ab1SKenneth D. Merry { 480*ef270ab1SKenneth D. Merry int32_t rc; 481*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 482*ef270ab1SKenneth D. Merry std_node_state_decl(); 483*ef270ab1SKenneth D. Merry 484*ef270ab1SKenneth D. Merry node_sm_trace(); 485*ef270ab1SKenneth D. Merry 486*ef270ab1SKenneth D. Merry switch(evt) { 487*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: { 488*ef270ab1SKenneth D. Merry /* Save service parameters */ 489*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 490*ef270ab1SKenneth D. Merry return NULL; 491*ef270ab1SKenneth D. Merry } 492*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 493*ef270ab1SKenneth D. Merry node->els_req_cnt--; 494*ef270ab1SKenneth D. Merry /* sm: save sparams, ocs_node_attach */ 495*ef270ab1SKenneth D. Merry ocs_node_save_sparms(node, cbdata->els->els_rsp.virt); 496*ef270ab1SKenneth D. Merry ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL, 497*ef270ab1SKenneth D. Merry ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 498*ef270ab1SKenneth D. Merry rc = ocs_node_attach(node); 499*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_wait_node_attach, NULL); 500*ef270ab1SKenneth D. Merry if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 501*ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 502*ef270ab1SKenneth D. Merry } 503*ef270ab1SKenneth D. Merry break; 504*ef270ab1SKenneth D. Merry } 505*ef270ab1SKenneth D. Merry default: 506*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 507*ef270ab1SKenneth D. Merry return NULL; 508*ef270ab1SKenneth D. Merry } 509*ef270ab1SKenneth D. Merry 510*ef270ab1SKenneth D. Merry return NULL; 511*ef270ab1SKenneth D. Merry } 512*ef270ab1SKenneth D. Merry 513*ef270ab1SKenneth D. Merry /** 514*ef270ab1SKenneth D. Merry * @ingroup ns_sm 515*ef270ab1SKenneth D. Merry * @brief Name services node state machine: Wait for a node attach completion. 516*ef270ab1SKenneth D. Merry * 517*ef270ab1SKenneth D. Merry * @par Description 518*ef270ab1SKenneth D. Merry * Waits for a node attach completion, then issues an RFTID name services 519*ef270ab1SKenneth D. Merry * request. 520*ef270ab1SKenneth D. Merry * 521*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 522*ef270ab1SKenneth D. Merry * @param evt Event to process. 523*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 524*ef270ab1SKenneth D. Merry * 525*ef270ab1SKenneth D. Merry * @return Returns NULL. 526*ef270ab1SKenneth D. Merry */ 527*ef270ab1SKenneth D. Merry void * 528*ef270ab1SKenneth D. Merry __ocs_ns_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 529*ef270ab1SKenneth D. Merry { 530*ef270ab1SKenneth D. Merry std_node_state_decl(); 531*ef270ab1SKenneth D. Merry 532*ef270ab1SKenneth D. Merry node_sm_trace(); 533*ef270ab1SKenneth D. Merry 534*ef270ab1SKenneth D. Merry switch(evt) { 535*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 536*ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 537*ef270ab1SKenneth D. Merry break; 538*ef270ab1SKenneth D. Merry 539*ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 540*ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 541*ef270ab1SKenneth D. Merry break; 542*ef270ab1SKenneth D. Merry 543*ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_OK: 544*ef270ab1SKenneth D. Merry node->attached = TRUE; 545*ef270ab1SKenneth D. Merry /* sm: send RFTID */ 546*ef270ab1SKenneth D. Merry ocs_ns_send_rftid(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 547*ef270ab1SKenneth D. Merry OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 548*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_rftid_wait_rsp, NULL); 549*ef270ab1SKenneth D. Merry break; 550*ef270ab1SKenneth D. Merry 551*ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_FAIL: 552*ef270ab1SKenneth D. Merry /* node attach failed, shutdown the node */ 553*ef270ab1SKenneth D. Merry node->attached = FALSE; 554*ef270ab1SKenneth D. Merry node_printf(node, "Node attach failed\n"); 555*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 556*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 557*ef270ab1SKenneth D. Merry break; 558*ef270ab1SKenneth D. Merry 559*ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN: 560*ef270ab1SKenneth D. Merry node_printf(node, "Shutdown event received\n"); 561*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 562*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabric_wait_attach_evt_shutdown, NULL); 563*ef270ab1SKenneth D. Merry break; 564*ef270ab1SKenneth D. Merry 565*ef270ab1SKenneth D. Merry /* if receive RSCN just ignore, 566*ef270ab1SKenneth D. Merry * we haven't sent GID_PT yet (ACC sent by fabctl node) */ 567*ef270ab1SKenneth D. Merry case OCS_EVT_RSCN_RCVD: 568*ef270ab1SKenneth D. Merry break; 569*ef270ab1SKenneth D. Merry 570*ef270ab1SKenneth D. Merry default: 571*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 572*ef270ab1SKenneth D. Merry return NULL; 573*ef270ab1SKenneth D. Merry } 574*ef270ab1SKenneth D. Merry 575*ef270ab1SKenneth D. Merry return NULL; 576*ef270ab1SKenneth D. Merry } 577*ef270ab1SKenneth D. Merry 578*ef270ab1SKenneth D. Merry /** 579*ef270ab1SKenneth D. Merry * @ingroup ns_sm 580*ef270ab1SKenneth D. Merry * @brief Wait for a domain/sport/node attach completion, then 581*ef270ab1SKenneth D. Merry * shutdown. 582*ef270ab1SKenneth D. Merry * 583*ef270ab1SKenneth D. Merry * @par Description 584*ef270ab1SKenneth D. Merry * Waits for a domain/sport/node attach completion, then shuts 585*ef270ab1SKenneth D. Merry * node down. 586*ef270ab1SKenneth D. Merry * 587*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 588*ef270ab1SKenneth D. Merry * @param evt Event to process. 589*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 590*ef270ab1SKenneth D. Merry * 591*ef270ab1SKenneth D. Merry * @return Returns NULL. 592*ef270ab1SKenneth D. Merry */ 593*ef270ab1SKenneth D. Merry void * 594*ef270ab1SKenneth D. Merry __ocs_fabric_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 595*ef270ab1SKenneth D. Merry { 596*ef270ab1SKenneth D. Merry std_node_state_decl(); 597*ef270ab1SKenneth D. Merry 598*ef270ab1SKenneth D. Merry node_sm_trace(); 599*ef270ab1SKenneth D. Merry 600*ef270ab1SKenneth D. Merry switch(evt) { 601*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 602*ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 603*ef270ab1SKenneth D. Merry break; 604*ef270ab1SKenneth D. Merry 605*ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 606*ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 607*ef270ab1SKenneth D. Merry break; 608*ef270ab1SKenneth D. Merry 609*ef270ab1SKenneth D. Merry /* wait for any of these attach events and then shutdown */ 610*ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_OK: 611*ef270ab1SKenneth D. Merry node->attached = TRUE; 612*ef270ab1SKenneth D. Merry node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt)); 613*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 614*ef270ab1SKenneth D. Merry break; 615*ef270ab1SKenneth D. Merry 616*ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_FAIL: 617*ef270ab1SKenneth D. Merry node->attached = FALSE; 618*ef270ab1SKenneth D. Merry node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt)); 619*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 620*ef270ab1SKenneth D. Merry break; 621*ef270ab1SKenneth D. Merry 622*ef270ab1SKenneth D. Merry /* ignore shutdown event as we're already in shutdown path */ 623*ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN: 624*ef270ab1SKenneth D. Merry node_printf(node, "Shutdown event received\n"); 625*ef270ab1SKenneth D. Merry break; 626*ef270ab1SKenneth D. Merry 627*ef270ab1SKenneth D. Merry default: 628*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 629*ef270ab1SKenneth D. Merry return NULL; 630*ef270ab1SKenneth D. Merry } 631*ef270ab1SKenneth D. Merry 632*ef270ab1SKenneth D. Merry return NULL; 633*ef270ab1SKenneth D. Merry } 634*ef270ab1SKenneth D. Merry 635*ef270ab1SKenneth D. Merry /** 636*ef270ab1SKenneth D. Merry * @ingroup ns_sm 637*ef270ab1SKenneth D. Merry * @brief Name services node state machine: Wait for an RFTID response event. 638*ef270ab1SKenneth D. Merry * 639*ef270ab1SKenneth D. Merry * @par Description 640*ef270ab1SKenneth D. Merry * Waits for an RFTID response event; if configured for an initiator operation, 641*ef270ab1SKenneth D. Merry * a GIDPT name services request is issued. 642*ef270ab1SKenneth D. Merry * 643*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 644*ef270ab1SKenneth D. Merry * @param evt Event to process. 645*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 646*ef270ab1SKenneth D. Merry * 647*ef270ab1SKenneth D. Merry * @return Returns NULL. 648*ef270ab1SKenneth D. Merry */ 649*ef270ab1SKenneth D. Merry void * 650*ef270ab1SKenneth D. Merry __ocs_ns_rftid_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 651*ef270ab1SKenneth D. Merry { 652*ef270ab1SKenneth D. Merry std_node_state_decl(); 653*ef270ab1SKenneth D. Merry 654*ef270ab1SKenneth D. Merry node_sm_trace(); 655*ef270ab1SKenneth D. Merry 656*ef270ab1SKenneth D. Merry switch(evt) { 657*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: 658*ef270ab1SKenneth D. Merry if (node_check_ns_req(ctx, evt, arg, FC_GS_NAMESERVER_RFT_ID, __ocs_fabric_common, __func__)) { 659*ef270ab1SKenneth D. Merry return NULL; 660*ef270ab1SKenneth D. Merry } 661*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 662*ef270ab1SKenneth D. Merry node->els_req_cnt--; 663*ef270ab1SKenneth D. Merry /*sm: send RFFID */ 664*ef270ab1SKenneth D. Merry ocs_ns_send_rffid(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 665*ef270ab1SKenneth D. Merry OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 666*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_rffid_wait_rsp, NULL); 667*ef270ab1SKenneth D. Merry break; 668*ef270ab1SKenneth D. Merry 669*ef270ab1SKenneth D. Merry /* if receive RSCN just ignore, 670*ef270ab1SKenneth D. Merry * we haven't sent GID_PT yet (ACC sent by fabctl node) */ 671*ef270ab1SKenneth D. Merry case OCS_EVT_RSCN_RCVD: 672*ef270ab1SKenneth D. Merry break; 673*ef270ab1SKenneth D. Merry 674*ef270ab1SKenneth D. Merry default: 675*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 676*ef270ab1SKenneth D. Merry return NULL; 677*ef270ab1SKenneth D. Merry } 678*ef270ab1SKenneth D. Merry 679*ef270ab1SKenneth D. Merry return NULL; 680*ef270ab1SKenneth D. Merry } 681*ef270ab1SKenneth D. Merry 682*ef270ab1SKenneth D. Merry /** 683*ef270ab1SKenneth D. Merry * @ingroup ns_sm 684*ef270ab1SKenneth D. Merry * @brief Fabric node state machine: Wait for RFFID response event. 685*ef270ab1SKenneth D. Merry * 686*ef270ab1SKenneth D. Merry * @par Description 687*ef270ab1SKenneth D. Merry * Waits for an RFFID response event; if configured for an initiator operation, 688*ef270ab1SKenneth D. Merry * a GIDPT name services request is issued. 689*ef270ab1SKenneth D. Merry * 690*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 691*ef270ab1SKenneth D. Merry * @param evt Event to process. 692*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 693*ef270ab1SKenneth D. Merry * 694*ef270ab1SKenneth D. Merry * @return Returns NULL. 695*ef270ab1SKenneth D. Merry */ 696*ef270ab1SKenneth D. Merry void * 697*ef270ab1SKenneth D. Merry __ocs_ns_rffid_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 698*ef270ab1SKenneth D. Merry { 699*ef270ab1SKenneth D. Merry std_node_state_decl(); 700*ef270ab1SKenneth D. Merry 701*ef270ab1SKenneth D. Merry node_sm_trace(); 702*ef270ab1SKenneth D. Merry 703*ef270ab1SKenneth D. Merry switch(evt) { 704*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: { 705*ef270ab1SKenneth D. Merry if (node_check_ns_req(ctx, evt, arg, FC_GS_NAMESERVER_RFF_ID, __ocs_fabric_common, __func__)) { 706*ef270ab1SKenneth D. Merry return NULL; 707*ef270ab1SKenneth D. Merry } 708*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 709*ef270ab1SKenneth D. Merry node->els_req_cnt--; 710*ef270ab1SKenneth D. Merry if (node->sport->enable_rscn) { 711*ef270ab1SKenneth D. Merry /* sm: if enable_rscn / send GIDPT */ 712*ef270ab1SKenneth D. Merry ocs_ns_send_gidpt(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 713*ef270ab1SKenneth D. Merry OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 714*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_gidpt_wait_rsp, NULL); 715*ef270ab1SKenneth D. Merry } else { 716*ef270ab1SKenneth D. Merry /* if 'T' only, we're done, go to idle */ 717*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_idle, NULL); 718*ef270ab1SKenneth D. Merry } 719*ef270ab1SKenneth D. Merry break; 720*ef270ab1SKenneth D. Merry } 721*ef270ab1SKenneth D. Merry /* if receive RSCN just ignore, 722*ef270ab1SKenneth D. Merry * we haven't sent GID_PT yet (ACC sent by fabctl node) */ 723*ef270ab1SKenneth D. Merry case OCS_EVT_RSCN_RCVD: 724*ef270ab1SKenneth D. Merry break; 725*ef270ab1SKenneth D. Merry 726*ef270ab1SKenneth D. Merry default: 727*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 728*ef270ab1SKenneth D. Merry return NULL; 729*ef270ab1SKenneth D. Merry } 730*ef270ab1SKenneth D. Merry 731*ef270ab1SKenneth D. Merry return NULL; 732*ef270ab1SKenneth D. Merry } 733*ef270ab1SKenneth D. Merry 734*ef270ab1SKenneth D. Merry /** 735*ef270ab1SKenneth D. Merry * @ingroup ns_sm 736*ef270ab1SKenneth D. Merry * @brief Name services node state machine: Wait for a GIDPT response. 737*ef270ab1SKenneth D. Merry * 738*ef270ab1SKenneth D. Merry * @par Description 739*ef270ab1SKenneth D. Merry * Wait for a GIDPT response from the name server. Process the FC_IDs that are 740*ef270ab1SKenneth D. Merry * reported by creating new remote ports, as needed. 741*ef270ab1SKenneth D. Merry * 742*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 743*ef270ab1SKenneth D. Merry * @param evt Event to process. 744*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 745*ef270ab1SKenneth D. Merry * 746*ef270ab1SKenneth D. Merry * @return Returns NULL. 747*ef270ab1SKenneth D. Merry */ 748*ef270ab1SKenneth D. Merry void * 749*ef270ab1SKenneth D. Merry __ocs_ns_gidpt_wait_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 750*ef270ab1SKenneth D. Merry { 751*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 752*ef270ab1SKenneth D. Merry std_node_state_decl(); 753*ef270ab1SKenneth D. Merry 754*ef270ab1SKenneth D. Merry node_sm_trace(); 755*ef270ab1SKenneth D. Merry 756*ef270ab1SKenneth D. Merry switch(evt) { 757*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: { 758*ef270ab1SKenneth D. Merry if (node_check_ns_req(ctx, evt, arg, FC_GS_NAMESERVER_GID_PT, __ocs_fabric_common, __func__)) { 759*ef270ab1SKenneth D. Merry return NULL; 760*ef270ab1SKenneth D. Merry } 761*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 762*ef270ab1SKenneth D. Merry node->els_req_cnt--; 763*ef270ab1SKenneth D. Merry /* sm: / process GIDPT payload */ 764*ef270ab1SKenneth D. Merry ocs_process_gidpt_payload(node, cbdata->els->els_rsp.virt, cbdata->els->els_rsp.len); 765*ef270ab1SKenneth D. Merry /* TODO: should we logout at this point or just go idle */ 766*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_idle, NULL); 767*ef270ab1SKenneth D. Merry break; 768*ef270ab1SKenneth D. Merry } 769*ef270ab1SKenneth D. Merry 770*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_FAIL: { 771*ef270ab1SKenneth D. Merry /* not much we can do; will retry with the next RSCN */ 772*ef270ab1SKenneth D. Merry node_printf(node, "GID_PT failed to complete\n"); 773*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 774*ef270ab1SKenneth D. Merry node->els_req_cnt--; 775*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_idle, NULL); 776*ef270ab1SKenneth D. Merry break; 777*ef270ab1SKenneth D. Merry } 778*ef270ab1SKenneth D. Merry 779*ef270ab1SKenneth D. Merry /* if receive RSCN here, queue up another discovery processing */ 780*ef270ab1SKenneth D. Merry case OCS_EVT_RSCN_RCVD: { 781*ef270ab1SKenneth D. Merry node_printf(node, "RSCN received during GID_PT processing\n"); 782*ef270ab1SKenneth D. Merry node->rscn_pending = 1; 783*ef270ab1SKenneth D. Merry break; 784*ef270ab1SKenneth D. Merry } 785*ef270ab1SKenneth D. Merry 786*ef270ab1SKenneth D. Merry default: 787*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 788*ef270ab1SKenneth D. Merry return NULL; 789*ef270ab1SKenneth D. Merry } 790*ef270ab1SKenneth D. Merry 791*ef270ab1SKenneth D. Merry return NULL; 792*ef270ab1SKenneth D. Merry } 793*ef270ab1SKenneth D. Merry 794*ef270ab1SKenneth D. Merry 795*ef270ab1SKenneth D. Merry /** 796*ef270ab1SKenneth D. Merry * @ingroup ns_sm 797*ef270ab1SKenneth D. Merry * @brief Name services node state machine: Idle state. 798*ef270ab1SKenneth D. Merry * 799*ef270ab1SKenneth D. Merry * @par Description 800*ef270ab1SKenneth D. Merry * Idle. Waiting for RSCN received events (posted from the fabric controller), and 801*ef270ab1SKenneth D. Merry * restarts the GIDPT name services query and processing. 802*ef270ab1SKenneth D. Merry * 803*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 804*ef270ab1SKenneth D. Merry * @param evt Event to process. 805*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 806*ef270ab1SKenneth D. Merry * 807*ef270ab1SKenneth D. Merry * @return Returns NULL. 808*ef270ab1SKenneth D. Merry */ 809*ef270ab1SKenneth D. Merry void * 810*ef270ab1SKenneth D. Merry __ocs_ns_idle(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 811*ef270ab1SKenneth D. Merry { 812*ef270ab1SKenneth D. Merry std_node_state_decl(); 813*ef270ab1SKenneth D. Merry 814*ef270ab1SKenneth D. Merry node_sm_trace(); 815*ef270ab1SKenneth D. Merry 816*ef270ab1SKenneth D. Merry switch(evt) { 817*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 818*ef270ab1SKenneth D. Merry if (!node->rscn_pending) { 819*ef270ab1SKenneth D. Merry break; 820*ef270ab1SKenneth D. Merry } 821*ef270ab1SKenneth D. Merry node_printf(node, "RSCN pending, restart discovery\n"); 822*ef270ab1SKenneth D. Merry node->rscn_pending = 0; 823*ef270ab1SKenneth D. Merry 824*ef270ab1SKenneth D. Merry /* fall through */ 825*ef270ab1SKenneth D. Merry 826*ef270ab1SKenneth D. Merry case OCS_EVT_RSCN_RCVD: { 827*ef270ab1SKenneth D. Merry /* sm: / send GIDPT 828*ef270ab1SKenneth D. Merry * If target RSCN processing is enabled, and this is target only 829*ef270ab1SKenneth D. Merry * (not initiator), and tgt_rscn_delay is non-zero, 830*ef270ab1SKenneth D. Merry * then we delay issuing the GID_PT 831*ef270ab1SKenneth D. Merry */ 832*ef270ab1SKenneth D. Merry if ((ocs->tgt_rscn_delay_msec != 0) && !node->sport->enable_ini && node->sport->enable_tgt && 833*ef270ab1SKenneth D. Merry enable_target_rscn(ocs)) { 834*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_gidpt_delay, NULL); 835*ef270ab1SKenneth D. Merry } else { 836*ef270ab1SKenneth D. Merry ocs_ns_send_gidpt(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 837*ef270ab1SKenneth D. Merry OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 838*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_gidpt_wait_rsp, NULL); 839*ef270ab1SKenneth D. Merry } 840*ef270ab1SKenneth D. Merry break; 841*ef270ab1SKenneth D. Merry } 842*ef270ab1SKenneth D. Merry 843*ef270ab1SKenneth D. Merry default: 844*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 845*ef270ab1SKenneth D. Merry break; 846*ef270ab1SKenneth D. Merry } 847*ef270ab1SKenneth D. Merry 848*ef270ab1SKenneth D. Merry return NULL; 849*ef270ab1SKenneth D. Merry } 850*ef270ab1SKenneth D. Merry 851*ef270ab1SKenneth D. Merry /** 852*ef270ab1SKenneth D. Merry * @brief Handle GIDPT delay timer callback 853*ef270ab1SKenneth D. Merry * 854*ef270ab1SKenneth D. Merry * @par Description 855*ef270ab1SKenneth D. Merry * Post an OCS_EVT_GIDPT_DEIALY_EXPIRED event to the passed in node. 856*ef270ab1SKenneth D. Merry * 857*ef270ab1SKenneth D. Merry * @param arg Pointer to node. 858*ef270ab1SKenneth D. Merry * 859*ef270ab1SKenneth D. Merry * @return None. 860*ef270ab1SKenneth D. Merry */ 861*ef270ab1SKenneth D. Merry static void 862*ef270ab1SKenneth D. Merry gidpt_delay_timer_cb(void *arg) 863*ef270ab1SKenneth D. Merry { 864*ef270ab1SKenneth D. Merry ocs_node_t *node = arg; 865*ef270ab1SKenneth D. Merry int32_t rc; 866*ef270ab1SKenneth D. Merry 867*ef270ab1SKenneth D. Merry ocs_del_timer(&node->gidpt_delay_timer); 868*ef270ab1SKenneth D. Merry rc = ocs_xport_control(node->ocs->xport, OCS_XPORT_POST_NODE_EVENT, node, OCS_EVT_GIDPT_DELAY_EXPIRED, NULL); 869*ef270ab1SKenneth D. Merry if (rc) { 870*ef270ab1SKenneth D. Merry ocs_log_err(node->ocs, "ocs_xport_control(OCS_XPORT_POST_NODE_EVENT) failed: %d\n", rc); 871*ef270ab1SKenneth D. Merry } 872*ef270ab1SKenneth D. Merry } 873*ef270ab1SKenneth D. Merry 874*ef270ab1SKenneth D. Merry /** 875*ef270ab1SKenneth D. Merry * @ingroup ns_sm 876*ef270ab1SKenneth D. Merry * @brief Name services node state machine: Delayed GIDPT. 877*ef270ab1SKenneth D. Merry * 878*ef270ab1SKenneth D. Merry * @par Description 879*ef270ab1SKenneth D. Merry * Waiting for GIDPT delay to expire before submitting GIDPT to name server. 880*ef270ab1SKenneth D. Merry * 881*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 882*ef270ab1SKenneth D. Merry * @param evt Event to process. 883*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 884*ef270ab1SKenneth D. Merry * 885*ef270ab1SKenneth D. Merry * @return Returns NULL. 886*ef270ab1SKenneth D. Merry */ 887*ef270ab1SKenneth D. Merry void * 888*ef270ab1SKenneth D. Merry __ocs_ns_gidpt_delay(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 889*ef270ab1SKenneth D. Merry { 890*ef270ab1SKenneth D. Merry std_node_state_decl(); 891*ef270ab1SKenneth D. Merry 892*ef270ab1SKenneth D. Merry node_sm_trace(); 893*ef270ab1SKenneth D. Merry 894*ef270ab1SKenneth D. Merry switch(evt) { 895*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: { 896*ef270ab1SKenneth D. Merry time_t delay_msec; 897*ef270ab1SKenneth D. Merry 898*ef270ab1SKenneth D. Merry ocs_assert(ocs->tgt_rscn_delay_msec != 0, NULL); 899*ef270ab1SKenneth D. Merry 900*ef270ab1SKenneth D. Merry /* 901*ef270ab1SKenneth D. Merry * Compute the delay time. Set to tgt_rscn_delay, if the time since last GIDPT 902*ef270ab1SKenneth D. Merry * is less than tgt_rscn_period, then use tgt_rscn_period. 903*ef270ab1SKenneth D. Merry */ 904*ef270ab1SKenneth D. Merry delay_msec = ocs->tgt_rscn_delay_msec; 905*ef270ab1SKenneth D. Merry if ((ocs_msectime() - node->time_last_gidpt_msec) < ocs->tgt_rscn_period_msec) { 906*ef270ab1SKenneth D. Merry delay_msec = ocs->tgt_rscn_period_msec; 907*ef270ab1SKenneth D. Merry } 908*ef270ab1SKenneth D. Merry 909*ef270ab1SKenneth D. Merry ocs_setup_timer(ocs, &node->gidpt_delay_timer, gidpt_delay_timer_cb, node, delay_msec); 910*ef270ab1SKenneth D. Merry 911*ef270ab1SKenneth D. Merry break; 912*ef270ab1SKenneth D. Merry } 913*ef270ab1SKenneth D. Merry 914*ef270ab1SKenneth D. Merry case OCS_EVT_GIDPT_DELAY_EXPIRED: 915*ef270ab1SKenneth D. Merry node->time_last_gidpt_msec = ocs_msectime(); 916*ef270ab1SKenneth D. Merry ocs_ns_send_gidpt(node, OCS_FC_ELS_CT_SEND_DEFAULT_TIMEOUT, 917*ef270ab1SKenneth D. Merry OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 918*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_ns_gidpt_wait_rsp, NULL); 919*ef270ab1SKenneth D. Merry break; 920*ef270ab1SKenneth D. Merry 921*ef270ab1SKenneth D. Merry case OCS_EVT_RSCN_RCVD: { 922*ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "RSCN received while in GIDPT delay - no action\n"); 923*ef270ab1SKenneth D. Merry break; 924*ef270ab1SKenneth D. Merry } 925*ef270ab1SKenneth D. Merry 926*ef270ab1SKenneth D. Merry default: 927*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 928*ef270ab1SKenneth D. Merry break; 929*ef270ab1SKenneth D. Merry } 930*ef270ab1SKenneth D. Merry 931*ef270ab1SKenneth D. Merry return NULL; 932*ef270ab1SKenneth D. Merry } 933*ef270ab1SKenneth D. Merry 934*ef270ab1SKenneth D. Merry /** 935*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 936*ef270ab1SKenneth D. Merry * @brief Fabric controller node state machine: Initial state. 937*ef270ab1SKenneth D. Merry * 938*ef270ab1SKenneth D. Merry * @par Description 939*ef270ab1SKenneth D. Merry * Issue a PLOGI to a well-known fabric controller address. 940*ef270ab1SKenneth D. Merry * 941*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 942*ef270ab1SKenneth D. Merry * @param evt Event to process. 943*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 944*ef270ab1SKenneth D. Merry * 945*ef270ab1SKenneth D. Merry * @return Returns NULL. 946*ef270ab1SKenneth D. Merry */ 947*ef270ab1SKenneth D. Merry void * 948*ef270ab1SKenneth D. Merry __ocs_fabctl_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 949*ef270ab1SKenneth D. Merry { 950*ef270ab1SKenneth D. Merry ocs_node_t *node = ctx->app; 951*ef270ab1SKenneth D. Merry 952*ef270ab1SKenneth D. Merry node_sm_trace(); 953*ef270ab1SKenneth D. Merry 954*ef270ab1SKenneth D. Merry switch(evt) { 955*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 956*ef270ab1SKenneth D. Merry /* no need to login to fabric controller, just send SCR */ 957*ef270ab1SKenneth D. Merry ocs_send_scr(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 958*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabctl_wait_scr_rsp, NULL); 959*ef270ab1SKenneth D. Merry break; 960*ef270ab1SKenneth D. Merry 961*ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_OK: 962*ef270ab1SKenneth D. Merry node->attached = TRUE; 963*ef270ab1SKenneth D. Merry break; 964*ef270ab1SKenneth D. Merry 965*ef270ab1SKenneth D. Merry default: 966*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 967*ef270ab1SKenneth D. Merry return NULL; 968*ef270ab1SKenneth D. Merry } 969*ef270ab1SKenneth D. Merry 970*ef270ab1SKenneth D. Merry return NULL; 971*ef270ab1SKenneth D. Merry } 972*ef270ab1SKenneth D. Merry 973*ef270ab1SKenneth D. Merry /** 974*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 975*ef270ab1SKenneth D. Merry * @brief Fabric controller node state machine: Wait for a node attach request 976*ef270ab1SKenneth D. Merry * to complete. 977*ef270ab1SKenneth D. Merry * 978*ef270ab1SKenneth D. Merry * @par Description 979*ef270ab1SKenneth D. Merry * Wait for a node attach to complete. If successful, issue an SCR 980*ef270ab1SKenneth D. Merry * to the fabric controller, subscribing to all RSCN. 981*ef270ab1SKenneth D. Merry * 982*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 983*ef270ab1SKenneth D. Merry * @param evt Event to process. 984*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 985*ef270ab1SKenneth D. Merry * 986*ef270ab1SKenneth D. Merry * @return Returns NULL. 987*ef270ab1SKenneth D. Merry * 988*ef270ab1SKenneth D. Merry */ 989*ef270ab1SKenneth D. Merry void * 990*ef270ab1SKenneth D. Merry __ocs_fabctl_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 991*ef270ab1SKenneth D. Merry { 992*ef270ab1SKenneth D. Merry std_node_state_decl(); 993*ef270ab1SKenneth D. Merry 994*ef270ab1SKenneth D. Merry node_sm_trace(); 995*ef270ab1SKenneth D. Merry 996*ef270ab1SKenneth D. Merry switch(evt) { 997*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 998*ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 999*ef270ab1SKenneth D. Merry break; 1000*ef270ab1SKenneth D. Merry 1001*ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1002*ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 1003*ef270ab1SKenneth D. Merry break; 1004*ef270ab1SKenneth D. Merry 1005*ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_OK: 1006*ef270ab1SKenneth D. Merry node->attached = TRUE; 1007*ef270ab1SKenneth D. Merry /* sm: / send SCR */ 1008*ef270ab1SKenneth D. Merry ocs_send_scr(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 1009*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabctl_wait_scr_rsp, NULL); 1010*ef270ab1SKenneth D. Merry break; 1011*ef270ab1SKenneth D. Merry 1012*ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_FAIL: 1013*ef270ab1SKenneth D. Merry /* node attach failed, shutdown the node */ 1014*ef270ab1SKenneth D. Merry node->attached = FALSE; 1015*ef270ab1SKenneth D. Merry node_printf(node, "Node attach failed\n"); 1016*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1017*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 1018*ef270ab1SKenneth D. Merry break; 1019*ef270ab1SKenneth D. Merry 1020*ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN: 1021*ef270ab1SKenneth D. Merry node_printf(node, "Shutdown event received\n"); 1022*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1023*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabric_wait_attach_evt_shutdown, NULL); 1024*ef270ab1SKenneth D. Merry break; 1025*ef270ab1SKenneth D. Merry 1026*ef270ab1SKenneth D. Merry default: 1027*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1028*ef270ab1SKenneth D. Merry return NULL; 1029*ef270ab1SKenneth D. Merry } 1030*ef270ab1SKenneth D. Merry 1031*ef270ab1SKenneth D. Merry return NULL; 1032*ef270ab1SKenneth D. Merry } 1033*ef270ab1SKenneth D. Merry 1034*ef270ab1SKenneth D. Merry /** 1035*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 1036*ef270ab1SKenneth D. Merry * @brief Fabric controller node state machine: Wait for an SCR response from the 1037*ef270ab1SKenneth D. Merry * fabric controller. 1038*ef270ab1SKenneth D. Merry * 1039*ef270ab1SKenneth D. Merry * @par Description 1040*ef270ab1SKenneth D. Merry * Waits for an SCR response from the fabric controller. 1041*ef270ab1SKenneth D. Merry * 1042*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1043*ef270ab1SKenneth D. Merry * @param evt Event to process. 1044*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1045*ef270ab1SKenneth D. Merry * 1046*ef270ab1SKenneth D. Merry * @return Returns NULL. 1047*ef270ab1SKenneth D. Merry */ 1048*ef270ab1SKenneth D. Merry void * 1049*ef270ab1SKenneth D. Merry __ocs_fabctl_wait_scr_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1050*ef270ab1SKenneth D. Merry { 1051*ef270ab1SKenneth D. Merry std_node_state_decl(); 1052*ef270ab1SKenneth D. Merry 1053*ef270ab1SKenneth D. Merry node_sm_trace(); 1054*ef270ab1SKenneth D. Merry 1055*ef270ab1SKenneth D. Merry switch(evt) { 1056*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: 1057*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_SCR, __ocs_fabric_common, __func__)) { 1058*ef270ab1SKenneth D. Merry return NULL; 1059*ef270ab1SKenneth D. Merry } 1060*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 1061*ef270ab1SKenneth D. Merry node->els_req_cnt--; 1062*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabctl_ready, NULL); 1063*ef270ab1SKenneth D. Merry break; 1064*ef270ab1SKenneth D. Merry 1065*ef270ab1SKenneth D. Merry default: 1066*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1067*ef270ab1SKenneth D. Merry return NULL; 1068*ef270ab1SKenneth D. Merry } 1069*ef270ab1SKenneth D. Merry 1070*ef270ab1SKenneth D. Merry return NULL; 1071*ef270ab1SKenneth D. Merry } 1072*ef270ab1SKenneth D. Merry 1073*ef270ab1SKenneth D. Merry /** 1074*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 1075*ef270ab1SKenneth D. Merry * @brief Fabric controller node state machine: Ready. 1076*ef270ab1SKenneth D. Merry * 1077*ef270ab1SKenneth D. Merry * @par Description 1078*ef270ab1SKenneth D. Merry * In this state, the fabric controller sends a RSCN, which is received 1079*ef270ab1SKenneth D. Merry * by this node and is forwarded to the name services node object; and 1080*ef270ab1SKenneth D. Merry * the RSCN LS_ACC is sent. 1081*ef270ab1SKenneth D. Merry * 1082*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1083*ef270ab1SKenneth D. Merry * @param evt Event to process. 1084*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1085*ef270ab1SKenneth D. Merry * 1086*ef270ab1SKenneth D. Merry * @return Returns NULL. 1087*ef270ab1SKenneth D. Merry */ 1088*ef270ab1SKenneth D. Merry 1089*ef270ab1SKenneth D. Merry void * 1090*ef270ab1SKenneth D. Merry __ocs_fabctl_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1091*ef270ab1SKenneth D. Merry { 1092*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 1093*ef270ab1SKenneth D. Merry std_node_state_decl(); 1094*ef270ab1SKenneth D. Merry 1095*ef270ab1SKenneth D. Merry node_sm_trace(); 1096*ef270ab1SKenneth D. Merry 1097*ef270ab1SKenneth D. Merry switch(evt) { 1098*ef270ab1SKenneth D. Merry case OCS_EVT_RSCN_RCVD: { 1099*ef270ab1SKenneth D. Merry fc_header_t *hdr = cbdata->header->dma.virt; 1100*ef270ab1SKenneth D. Merry 1101*ef270ab1SKenneth D. Merry /* sm: / process RSCN (forward to name services node), 1102*ef270ab1SKenneth D. Merry * send LS_ACC */ 1103*ef270ab1SKenneth D. Merry ocs_process_rscn(node, cbdata); 1104*ef270ab1SKenneth D. Merry ocs_send_ls_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1105*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabctl_wait_ls_acc_cmpl, NULL); 1106*ef270ab1SKenneth D. Merry break; 1107*ef270ab1SKenneth D. Merry } 1108*ef270ab1SKenneth D. Merry 1109*ef270ab1SKenneth D. Merry default: 1110*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1111*ef270ab1SKenneth D. Merry return NULL; 1112*ef270ab1SKenneth D. Merry } 1113*ef270ab1SKenneth D. Merry 1114*ef270ab1SKenneth D. Merry return NULL; 1115*ef270ab1SKenneth D. Merry } 1116*ef270ab1SKenneth D. Merry 1117*ef270ab1SKenneth D. Merry /** 1118*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 1119*ef270ab1SKenneth D. Merry * @brief Fabric controller node state machine: Wait for LS_ACC. 1120*ef270ab1SKenneth D. Merry * 1121*ef270ab1SKenneth D. Merry * @par Description 1122*ef270ab1SKenneth D. Merry * Waits for the LS_ACC from the fabric controller. 1123*ef270ab1SKenneth D. Merry * 1124*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1125*ef270ab1SKenneth D. Merry * @param evt Event to process. 1126*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1127*ef270ab1SKenneth D. Merry * 1128*ef270ab1SKenneth D. Merry * @return Returns NULL. 1129*ef270ab1SKenneth D. Merry */ 1130*ef270ab1SKenneth D. Merry 1131*ef270ab1SKenneth D. Merry void * 1132*ef270ab1SKenneth D. Merry __ocs_fabctl_wait_ls_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1133*ef270ab1SKenneth D. Merry { 1134*ef270ab1SKenneth D. Merry std_node_state_decl(); 1135*ef270ab1SKenneth D. Merry 1136*ef270ab1SKenneth D. Merry node_sm_trace(); 1137*ef270ab1SKenneth D. Merry 1138*ef270ab1SKenneth D. Merry switch(evt) { 1139*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 1140*ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 1141*ef270ab1SKenneth D. Merry break; 1142*ef270ab1SKenneth D. Merry 1143*ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1144*ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 1145*ef270ab1SKenneth D. Merry break; 1146*ef270ab1SKenneth D. Merry 1147*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_CMPL_OK: 1148*ef270ab1SKenneth D. Merry ocs_assert(node->els_cmpl_cnt, NULL); 1149*ef270ab1SKenneth D. Merry node->els_cmpl_cnt--; 1150*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabctl_ready, NULL); 1151*ef270ab1SKenneth D. Merry break; 1152*ef270ab1SKenneth D. Merry 1153*ef270ab1SKenneth D. Merry default: 1154*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1155*ef270ab1SKenneth D. Merry return NULL; 1156*ef270ab1SKenneth D. Merry } 1157*ef270ab1SKenneth D. Merry 1158*ef270ab1SKenneth D. Merry return NULL; 1159*ef270ab1SKenneth D. Merry } 1160*ef270ab1SKenneth D. Merry 1161*ef270ab1SKenneth D. Merry /** 1162*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 1163*ef270ab1SKenneth D. Merry * @brief Initiate fabric node shutdown. 1164*ef270ab1SKenneth D. Merry * 1165*ef270ab1SKenneth D. Merry * @param node Node for which shutdown is initiated. 1166*ef270ab1SKenneth D. Merry * 1167*ef270ab1SKenneth D. Merry * @return Returns None. 1168*ef270ab1SKenneth D. Merry */ 1169*ef270ab1SKenneth D. Merry 1170*ef270ab1SKenneth D. Merry static void 1171*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(ocs_node_t *node) 1172*ef270ab1SKenneth D. Merry { 1173*ef270ab1SKenneth D. Merry ocs_hw_rtn_e rc; 1174*ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 1175*ef270ab1SKenneth D. Merry ocs_scsi_io_alloc_disable(node); 1176*ef270ab1SKenneth D. Merry 1177*ef270ab1SKenneth D. Merry if (node->attached) { 1178*ef270ab1SKenneth D. Merry /* issue hw node free; don't care if succeeds right away 1179*ef270ab1SKenneth D. Merry * or sometime later, will check node->attached later in 1180*ef270ab1SKenneth D. Merry * shutdown process 1181*ef270ab1SKenneth D. Merry */ 1182*ef270ab1SKenneth D. Merry rc = ocs_hw_node_detach(&ocs->hw, &node->rnode); 1183*ef270ab1SKenneth D. Merry if (node->rnode.free_group) { 1184*ef270ab1SKenneth D. Merry ocs_remote_node_group_free(node->node_group); 1185*ef270ab1SKenneth D. Merry node->node_group = NULL; 1186*ef270ab1SKenneth D. Merry node->rnode.free_group = FALSE; 1187*ef270ab1SKenneth D. Merry } 1188*ef270ab1SKenneth D. Merry if (rc != OCS_HW_RTN_SUCCESS && rc != OCS_HW_RTN_SUCCESS_SYNC) { 1189*ef270ab1SKenneth D. Merry node_printf(node, "Failed freeing HW node, rc=%d\n", rc); 1190*ef270ab1SKenneth D. Merry } 1191*ef270ab1SKenneth D. Merry } 1192*ef270ab1SKenneth D. Merry /* 1193*ef270ab1SKenneth D. Merry * node has either been detached or is in the process of being detached, 1194*ef270ab1SKenneth D. Merry * call common node's initiate cleanup function 1195*ef270ab1SKenneth D. Merry */ 1196*ef270ab1SKenneth D. Merry ocs_node_initiate_cleanup(node); 1197*ef270ab1SKenneth D. Merry } 1198*ef270ab1SKenneth D. Merry 1199*ef270ab1SKenneth D. Merry /** 1200*ef270ab1SKenneth D. Merry * @ingroup fabric_sm 1201*ef270ab1SKenneth D. Merry * @brief Fabric node state machine: Handle the common fabric node events. 1202*ef270ab1SKenneth D. Merry * 1203*ef270ab1SKenneth D. Merry * @param funcname Function name text. 1204*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1205*ef270ab1SKenneth D. Merry * @param evt Event to process. 1206*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1207*ef270ab1SKenneth D. Merry * 1208*ef270ab1SKenneth D. Merry * @return Returns NULL. 1209*ef270ab1SKenneth D. Merry */ 1210*ef270ab1SKenneth D. Merry 1211*ef270ab1SKenneth D. Merry static void * 1212*ef270ab1SKenneth D. Merry __ocs_fabric_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1213*ef270ab1SKenneth D. Merry { 1214*ef270ab1SKenneth D. Merry ocs_node_t *node = NULL; 1215*ef270ab1SKenneth D. Merry ocs_assert(ctx, NULL); 1216*ef270ab1SKenneth D. Merry ocs_assert(ctx->app, NULL); 1217*ef270ab1SKenneth D. Merry node = ctx->app; 1218*ef270ab1SKenneth D. Merry 1219*ef270ab1SKenneth D. Merry switch(evt) { 1220*ef270ab1SKenneth D. Merry case OCS_EVT_DOMAIN_ATTACH_OK: 1221*ef270ab1SKenneth D. Merry break; 1222*ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN: 1223*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1224*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 1225*ef270ab1SKenneth D. Merry break; 1226*ef270ab1SKenneth D. Merry 1227*ef270ab1SKenneth D. Merry default: 1228*ef270ab1SKenneth D. Merry /* call default event handler common to all nodes */ 1229*ef270ab1SKenneth D. Merry __ocs_node_common(funcname, ctx, evt, arg); 1230*ef270ab1SKenneth D. Merry break; 1231*ef270ab1SKenneth D. Merry } 1232*ef270ab1SKenneth D. Merry return NULL; 1233*ef270ab1SKenneth D. Merry } 1234*ef270ab1SKenneth D. Merry 1235*ef270ab1SKenneth D. Merry /** 1236*ef270ab1SKenneth D. Merry * @brief Return TRUE if the remote node is an NPORT. 1237*ef270ab1SKenneth D. Merry * 1238*ef270ab1SKenneth D. Merry * @par Description 1239*ef270ab1SKenneth D. Merry * Examines the service parameters. Returns TRUE if the node reports itself as 1240*ef270ab1SKenneth D. Merry * an NPORT. 1241*ef270ab1SKenneth D. Merry * 1242*ef270ab1SKenneth D. Merry * @param remote_sparms Remote node service parameters. 1243*ef270ab1SKenneth D. Merry * 1244*ef270ab1SKenneth D. Merry * @return Returns TRUE if NPORT. 1245*ef270ab1SKenneth D. Merry */ 1246*ef270ab1SKenneth D. Merry 1247*ef270ab1SKenneth D. Merry int32_t 1248*ef270ab1SKenneth D. Merry ocs_rnode_is_nport(fc_plogi_payload_t *remote_sparms) 1249*ef270ab1SKenneth D. Merry { 1250*ef270ab1SKenneth D. Merry return (ocs_be32toh(remote_sparms->common_service_parameters[1]) & (1U << 28)) == 0; 1251*ef270ab1SKenneth D. Merry } 1252*ef270ab1SKenneth D. Merry 1253*ef270ab1SKenneth D. Merry /** 1254*ef270ab1SKenneth D. Merry * @brief Return the node's WWPN as an uint64_t. 1255*ef270ab1SKenneth D. Merry * 1256*ef270ab1SKenneth D. Merry * @par Description 1257*ef270ab1SKenneth D. Merry * The WWPN is computed from service parameters, and returned as a uint64_t. 1258*ef270ab1SKenneth D. Merry * 1259*ef270ab1SKenneth D. Merry * @param sp Pointer to service parameters. 1260*ef270ab1SKenneth D. Merry * 1261*ef270ab1SKenneth D. Merry * @return Returns WWPN. 1262*ef270ab1SKenneth D. Merry * 1263*ef270ab1SKenneth D. Merry */ 1264*ef270ab1SKenneth D. Merry 1265*ef270ab1SKenneth D. Merry static uint64_t 1266*ef270ab1SKenneth D. Merry ocs_get_wwpn(fc_plogi_payload_t *sp) 1267*ef270ab1SKenneth D. Merry { 1268*ef270ab1SKenneth D. Merry return (((uint64_t)ocs_be32toh(sp->port_name_hi) << 32ll) | (ocs_be32toh(sp->port_name_lo))); 1269*ef270ab1SKenneth D. Merry } 1270*ef270ab1SKenneth D. Merry 1271*ef270ab1SKenneth D. Merry /** 1272*ef270ab1SKenneth D. Merry * @brief Return TRUE if the remote node is the point-to-point winner. 1273*ef270ab1SKenneth D. Merry * 1274*ef270ab1SKenneth D. Merry * @par Description 1275*ef270ab1SKenneth D. Merry * Compares WWPNs. Returns TRUE if the remote node's WWPN is numerically 1276*ef270ab1SKenneth D. Merry * higher than the local node's WWPN. 1277*ef270ab1SKenneth D. Merry * 1278*ef270ab1SKenneth D. Merry * @param sport Pointer to the sport object. 1279*ef270ab1SKenneth D. Merry * 1280*ef270ab1SKenneth D. Merry * @return 1281*ef270ab1SKenneth D. Merry * - 0, if the remote node is the loser. 1282*ef270ab1SKenneth D. Merry * - 1, if the remote node is the winner. 1283*ef270ab1SKenneth D. Merry * - (-1), if remote node is neither the loser nor the winner 1284*ef270ab1SKenneth D. Merry * (WWPNs match) 1285*ef270ab1SKenneth D. Merry */ 1286*ef270ab1SKenneth D. Merry 1287*ef270ab1SKenneth D. Merry static int32_t 1288*ef270ab1SKenneth D. Merry ocs_rnode_is_winner(ocs_sport_t *sport) 1289*ef270ab1SKenneth D. Merry { 1290*ef270ab1SKenneth D. Merry fc_plogi_payload_t *remote_sparms = (fc_plogi_payload_t*) sport->domain->flogi_service_params; 1291*ef270ab1SKenneth D. Merry uint64_t remote_wwpn = ocs_get_wwpn(remote_sparms); 1292*ef270ab1SKenneth D. Merry uint64_t local_wwpn = sport->wwpn; 1293*ef270ab1SKenneth D. Merry char prop_buf[32]; 1294*ef270ab1SKenneth D. Merry uint64_t wwn_bump = 0; 1295*ef270ab1SKenneth D. Merry 1296*ef270ab1SKenneth D. Merry if (ocs_get_property("wwn_bump", prop_buf, sizeof(prop_buf)) == 0) { 1297*ef270ab1SKenneth D. Merry wwn_bump = ocs_strtoull(prop_buf, 0, 0); 1298*ef270ab1SKenneth D. Merry } 1299*ef270ab1SKenneth D. Merry local_wwpn ^= wwn_bump; 1300*ef270ab1SKenneth D. Merry 1301*ef270ab1SKenneth D. Merry remote_wwpn = ocs_get_wwpn(remote_sparms); 1302*ef270ab1SKenneth D. Merry 1303*ef270ab1SKenneth D. Merry ocs_log_debug(sport->ocs, "r: %08x %08x\n", ocs_be32toh(remote_sparms->port_name_hi), ocs_be32toh(remote_sparms->port_name_lo)); 1304*ef270ab1SKenneth D. Merry ocs_log_debug(sport->ocs, "l: %08x %08x\n", (uint32_t) (local_wwpn >> 32ll), (uint32_t) local_wwpn); 1305*ef270ab1SKenneth D. Merry 1306*ef270ab1SKenneth D. Merry if (remote_wwpn == local_wwpn) { 1307*ef270ab1SKenneth D. Merry ocs_log_warn(sport->ocs, "WWPN of remote node [%08x %08x] matches local WWPN\n", 1308*ef270ab1SKenneth D. Merry (uint32_t) (local_wwpn >> 32ll), (uint32_t) local_wwpn); 1309*ef270ab1SKenneth D. Merry return (-1); 1310*ef270ab1SKenneth D. Merry } 1311*ef270ab1SKenneth D. Merry 1312*ef270ab1SKenneth D. Merry return (remote_wwpn > local_wwpn); 1313*ef270ab1SKenneth D. Merry } 1314*ef270ab1SKenneth D. Merry 1315*ef270ab1SKenneth D. Merry /** 1316*ef270ab1SKenneth D. Merry * @ingroup p2p_sm 1317*ef270ab1SKenneth D. Merry * @brief Point-to-point state machine: Wait for the domain attach to complete. 1318*ef270ab1SKenneth D. Merry * 1319*ef270ab1SKenneth D. Merry * @par Description 1320*ef270ab1SKenneth D. Merry * Once the domain attach has completed, a PLOGI is sent (if we're the 1321*ef270ab1SKenneth D. Merry * winning point-to-point node). 1322*ef270ab1SKenneth D. Merry * 1323*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1324*ef270ab1SKenneth D. Merry * @param evt Event to process. 1325*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1326*ef270ab1SKenneth D. Merry * 1327*ef270ab1SKenneth D. Merry * @return Returns NULL. 1328*ef270ab1SKenneth D. Merry */ 1329*ef270ab1SKenneth D. Merry 1330*ef270ab1SKenneth D. Merry void * 1331*ef270ab1SKenneth D. Merry __ocs_p2p_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1332*ef270ab1SKenneth D. Merry { 1333*ef270ab1SKenneth D. Merry std_node_state_decl(); 1334*ef270ab1SKenneth D. Merry 1335*ef270ab1SKenneth D. Merry node_sm_trace(); 1336*ef270ab1SKenneth D. Merry 1337*ef270ab1SKenneth D. Merry switch(evt) { 1338*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 1339*ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 1340*ef270ab1SKenneth D. Merry break; 1341*ef270ab1SKenneth D. Merry 1342*ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1343*ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 1344*ef270ab1SKenneth D. Merry break; 1345*ef270ab1SKenneth D. Merry 1346*ef270ab1SKenneth D. Merry case OCS_EVT_DOMAIN_ATTACH_OK: { 1347*ef270ab1SKenneth D. Merry ocs_sport_t *sport = node->sport; 1348*ef270ab1SKenneth D. Merry ocs_node_t *rnode; 1349*ef270ab1SKenneth D. Merry 1350*ef270ab1SKenneth D. Merry /* this transient node (SID=0 (recv'd FLOGI) or DID=fabric (sent FLOGI)) 1351*ef270ab1SKenneth D. Merry * is the p2p winner, will use a separate node to send PLOGI to peer 1352*ef270ab1SKenneth D. Merry */ 1353*ef270ab1SKenneth D. Merry ocs_assert (node->sport->p2p_winner, NULL); 1354*ef270ab1SKenneth D. Merry 1355*ef270ab1SKenneth D. Merry rnode = ocs_node_find(sport, node->sport->p2p_remote_port_id); 1356*ef270ab1SKenneth D. Merry if (rnode != NULL) { 1357*ef270ab1SKenneth D. Merry /* the "other" transient p2p node has already kicked off the 1358*ef270ab1SKenneth D. Merry * new node from which PLOGI is sent */ 1359*ef270ab1SKenneth D. Merry node_printf(node, "Node with fc_id x%x already exists\n", rnode->rnode.fc_id); 1360*ef270ab1SKenneth D. Merry ocs_assert (rnode != node, NULL); 1361*ef270ab1SKenneth D. Merry } else { 1362*ef270ab1SKenneth D. Merry /* create new node (SID=1, DID=2) from which to send PLOGI */ 1363*ef270ab1SKenneth D. Merry rnode = ocs_node_alloc(sport, sport->p2p_remote_port_id, FALSE, FALSE); 1364*ef270ab1SKenneth D. Merry if (rnode == NULL) { 1365*ef270ab1SKenneth D. Merry ocs_log_err(ocs, "node alloc failed\n"); 1366*ef270ab1SKenneth D. Merry return NULL; 1367*ef270ab1SKenneth D. Merry } 1368*ef270ab1SKenneth D. Merry 1369*ef270ab1SKenneth D. Merry ocs_fabric_notify_topology(node); 1370*ef270ab1SKenneth D. Merry /* sm: allocate p2p remote node */ 1371*ef270ab1SKenneth D. Merry ocs_node_transition(rnode, __ocs_p2p_rnode_init, NULL); 1372*ef270ab1SKenneth D. Merry } 1373*ef270ab1SKenneth D. Merry 1374*ef270ab1SKenneth D. Merry /* the transient node (SID=0 or DID=fabric) has served its purpose */ 1375*ef270ab1SKenneth D. Merry if (node->rnode.fc_id == 0) { 1376*ef270ab1SKenneth D. Merry /* if this is the SID=0 node, move to the init state in case peer 1377*ef270ab1SKenneth D. Merry * has restarted FLOGI discovery and FLOGI is pending 1378*ef270ab1SKenneth D. Merry */ 1379*ef270ab1SKenneth D. Merry /* don't send PLOGI on ocs_d_init entry */ 1380*ef270ab1SKenneth D. Merry ocs_node_init_device(node, FALSE); 1381*ef270ab1SKenneth D. Merry } else { 1382*ef270ab1SKenneth D. Merry /* if this is the DID=fabric node (we initiated FLOGI), shut it down */ 1383*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1384*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 1385*ef270ab1SKenneth D. Merry } 1386*ef270ab1SKenneth D. Merry break; 1387*ef270ab1SKenneth D. Merry } 1388*ef270ab1SKenneth D. Merry 1389*ef270ab1SKenneth D. Merry default: 1390*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1391*ef270ab1SKenneth D. Merry return NULL; 1392*ef270ab1SKenneth D. Merry } 1393*ef270ab1SKenneth D. Merry 1394*ef270ab1SKenneth D. Merry return NULL; 1395*ef270ab1SKenneth D. Merry } 1396*ef270ab1SKenneth D. Merry 1397*ef270ab1SKenneth D. Merry /** 1398*ef270ab1SKenneth D. Merry * @ingroup p2p_sm 1399*ef270ab1SKenneth D. Merry * @brief Point-to-point state machine: Remote node initialization state. 1400*ef270ab1SKenneth D. Merry * 1401*ef270ab1SKenneth D. Merry * @par Description 1402*ef270ab1SKenneth D. Merry * This state is entered after winning point-to-point, and the remote node 1403*ef270ab1SKenneth D. Merry * is instantiated. 1404*ef270ab1SKenneth D. Merry * 1405*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1406*ef270ab1SKenneth D. Merry * @param evt Event to process. 1407*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1408*ef270ab1SKenneth D. Merry * 1409*ef270ab1SKenneth D. Merry * @return Returns NULL. 1410*ef270ab1SKenneth D. Merry */ 1411*ef270ab1SKenneth D. Merry 1412*ef270ab1SKenneth D. Merry void * 1413*ef270ab1SKenneth D. Merry __ocs_p2p_rnode_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1414*ef270ab1SKenneth D. Merry { 1415*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 1416*ef270ab1SKenneth D. Merry std_node_state_decl(); 1417*ef270ab1SKenneth D. Merry 1418*ef270ab1SKenneth D. Merry node_sm_trace(); 1419*ef270ab1SKenneth D. Merry 1420*ef270ab1SKenneth D. Merry switch(evt) { 1421*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 1422*ef270ab1SKenneth D. Merry /* sm: / send PLOGI */ 1423*ef270ab1SKenneth D. Merry ocs_send_plogi(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 1424*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_p2p_wait_plogi_rsp, NULL); 1425*ef270ab1SKenneth D. Merry break; 1426*ef270ab1SKenneth D. Merry 1427*ef270ab1SKenneth D. Merry case OCS_EVT_ABTS_RCVD: 1428*ef270ab1SKenneth D. Merry /* sm: send BA_ACC */ 1429*ef270ab1SKenneth D. Merry ocs_bls_send_acc_hdr(cbdata->io, cbdata->header->dma.virt); 1430*ef270ab1SKenneth D. Merry break; 1431*ef270ab1SKenneth D. Merry 1432*ef270ab1SKenneth D. Merry default: 1433*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1434*ef270ab1SKenneth D. Merry return NULL; 1435*ef270ab1SKenneth D. Merry } 1436*ef270ab1SKenneth D. Merry 1437*ef270ab1SKenneth D. Merry return NULL; 1438*ef270ab1SKenneth D. Merry } 1439*ef270ab1SKenneth D. Merry 1440*ef270ab1SKenneth D. Merry /** 1441*ef270ab1SKenneth D. Merry * @ingroup p2p_sm 1442*ef270ab1SKenneth D. Merry * @brief Point-to-point node state machine: Wait for the FLOGI accept completion. 1443*ef270ab1SKenneth D. Merry * 1444*ef270ab1SKenneth D. Merry * @par Description 1445*ef270ab1SKenneth D. Merry * Wait for the FLOGI accept completion. 1446*ef270ab1SKenneth D. Merry * 1447*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1448*ef270ab1SKenneth D. Merry * @param evt Event to process. 1449*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1450*ef270ab1SKenneth D. Merry * 1451*ef270ab1SKenneth D. Merry * @return Returns NULL. 1452*ef270ab1SKenneth D. Merry */ 1453*ef270ab1SKenneth D. Merry 1454*ef270ab1SKenneth D. Merry void * 1455*ef270ab1SKenneth D. Merry __ocs_p2p_wait_flogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1456*ef270ab1SKenneth D. Merry { 1457*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 1458*ef270ab1SKenneth D. Merry std_node_state_decl(); 1459*ef270ab1SKenneth D. Merry 1460*ef270ab1SKenneth D. Merry node_sm_trace(); 1461*ef270ab1SKenneth D. Merry 1462*ef270ab1SKenneth D. Merry switch(evt) { 1463*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 1464*ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 1465*ef270ab1SKenneth D. Merry break; 1466*ef270ab1SKenneth D. Merry 1467*ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1468*ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 1469*ef270ab1SKenneth D. Merry break; 1470*ef270ab1SKenneth D. Merry 1471*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_CMPL_OK: 1472*ef270ab1SKenneth D. Merry ocs_assert(node->els_cmpl_cnt, NULL); 1473*ef270ab1SKenneth D. Merry node->els_cmpl_cnt--; 1474*ef270ab1SKenneth D. Merry 1475*ef270ab1SKenneth D. Merry /* sm: if p2p_winner / domain_attach */ 1476*ef270ab1SKenneth D. Merry if (node->sport->p2p_winner) { 1477*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_p2p_wait_domain_attach, NULL); 1478*ef270ab1SKenneth D. Merry if (node->sport->domain->attached && 1479*ef270ab1SKenneth D. Merry !(node->sport->domain->domain_notify_pend)) { 1480*ef270ab1SKenneth D. Merry node_printf(node, "Domain already attached\n"); 1481*ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_DOMAIN_ATTACH_OK, NULL); 1482*ef270ab1SKenneth D. Merry } 1483*ef270ab1SKenneth D. Merry } else { 1484*ef270ab1SKenneth D. Merry /* this node has served its purpose; we'll expect a PLOGI on a separate 1485*ef270ab1SKenneth D. Merry * node (remote SID=0x1); return this node to init state in case peer 1486*ef270ab1SKenneth D. Merry * restarts discovery -- it may already have (pending frames may exist). 1487*ef270ab1SKenneth D. Merry */ 1488*ef270ab1SKenneth D. Merry /* don't send PLOGI on ocs_d_init entry */ 1489*ef270ab1SKenneth D. Merry ocs_node_init_device(node, FALSE); 1490*ef270ab1SKenneth D. Merry } 1491*ef270ab1SKenneth D. Merry break; 1492*ef270ab1SKenneth D. Merry 1493*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_CMPL_FAIL: 1494*ef270ab1SKenneth D. Merry /* LS_ACC failed, possibly due to link down; shutdown node and wait 1495*ef270ab1SKenneth D. Merry * for FLOGI discovery to restart */ 1496*ef270ab1SKenneth D. Merry node_printf(node, "FLOGI LS_ACC failed, shutting down\n"); 1497*ef270ab1SKenneth D. Merry ocs_assert(node->els_cmpl_cnt, NULL); 1498*ef270ab1SKenneth D. Merry node->els_cmpl_cnt--; 1499*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1500*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 1501*ef270ab1SKenneth D. Merry break; 1502*ef270ab1SKenneth D. Merry 1503*ef270ab1SKenneth D. Merry case OCS_EVT_ABTS_RCVD: { 1504*ef270ab1SKenneth D. Merry /* sm: / send BA_ACC */ 1505*ef270ab1SKenneth D. Merry ocs_bls_send_acc_hdr(cbdata->io, cbdata->header->dma.virt); 1506*ef270ab1SKenneth D. Merry break; 1507*ef270ab1SKenneth D. Merry } 1508*ef270ab1SKenneth D. Merry 1509*ef270ab1SKenneth D. Merry default: 1510*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1511*ef270ab1SKenneth D. Merry return NULL; 1512*ef270ab1SKenneth D. Merry } 1513*ef270ab1SKenneth D. Merry 1514*ef270ab1SKenneth D. Merry return NULL; 1515*ef270ab1SKenneth D. Merry } 1516*ef270ab1SKenneth D. Merry 1517*ef270ab1SKenneth D. Merry 1518*ef270ab1SKenneth D. Merry /** 1519*ef270ab1SKenneth D. Merry * @ingroup p2p_sm 1520*ef270ab1SKenneth D. Merry * @brief Point-to-point node state machine: Wait for a PLOGI response 1521*ef270ab1SKenneth D. Merry * as a point-to-point winner. 1522*ef270ab1SKenneth D. Merry * 1523*ef270ab1SKenneth D. Merry * @par Description 1524*ef270ab1SKenneth D. Merry * Wait for a PLOGI response from the remote node as a point-to-point winner. 1525*ef270ab1SKenneth D. Merry * Submit node attach request to the HW. 1526*ef270ab1SKenneth D. Merry * 1527*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1528*ef270ab1SKenneth D. Merry * @param evt Event to process. 1529*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1530*ef270ab1SKenneth D. Merry * 1531*ef270ab1SKenneth D. Merry * @return Returns NULL. 1532*ef270ab1SKenneth D. Merry */ 1533*ef270ab1SKenneth D. Merry 1534*ef270ab1SKenneth D. Merry void * 1535*ef270ab1SKenneth D. Merry __ocs_p2p_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1536*ef270ab1SKenneth D. Merry { 1537*ef270ab1SKenneth D. Merry int32_t rc; 1538*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 1539*ef270ab1SKenneth D. Merry std_node_state_decl(); 1540*ef270ab1SKenneth D. Merry 1541*ef270ab1SKenneth D. Merry node_sm_trace(); 1542*ef270ab1SKenneth D. Merry 1543*ef270ab1SKenneth D. Merry switch(evt) { 1544*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: { 1545*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 1546*ef270ab1SKenneth D. Merry return NULL; 1547*ef270ab1SKenneth D. Merry } 1548*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 1549*ef270ab1SKenneth D. Merry node->els_req_cnt--; 1550*ef270ab1SKenneth D. Merry /* sm: / save sparams, ocs_node_attach */ 1551*ef270ab1SKenneth D. Merry ocs_node_save_sparms(node, cbdata->els->els_rsp.virt); 1552*ef270ab1SKenneth D. Merry rc = ocs_node_attach(node); 1553*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_p2p_wait_node_attach, NULL); 1554*ef270ab1SKenneth D. Merry if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 1555*ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 1556*ef270ab1SKenneth D. Merry } 1557*ef270ab1SKenneth D. Merry break; 1558*ef270ab1SKenneth D. Merry } 1559*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_FAIL: { 1560*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 1561*ef270ab1SKenneth D. Merry return NULL; 1562*ef270ab1SKenneth D. Merry } 1563*ef270ab1SKenneth D. Merry node_printf(node, "PLOGI failed, shutting down\n"); 1564*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 1565*ef270ab1SKenneth D. Merry node->els_req_cnt--; 1566*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1567*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 1568*ef270ab1SKenneth D. Merry break; 1569*ef270ab1SKenneth D. Merry } 1570*ef270ab1SKenneth D. Merry 1571*ef270ab1SKenneth D. Merry case OCS_EVT_PLOGI_RCVD: { 1572*ef270ab1SKenneth D. Merry fc_header_t *hdr = cbdata->header->dma.virt; 1573*ef270ab1SKenneth D. Merry /* if we're in external loopback mode, just send LS_ACC */ 1574*ef270ab1SKenneth D. Merry if (node->ocs->external_loopback) { 1575*ef270ab1SKenneth D. Merry ocs_send_plogi_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1576*ef270ab1SKenneth D. Merry break; 1577*ef270ab1SKenneth D. Merry } else{ 1578*ef270ab1SKenneth D. Merry /* if this isn't external loopback, pass to default handler */ 1579*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1580*ef270ab1SKenneth D. Merry } 1581*ef270ab1SKenneth D. Merry break; 1582*ef270ab1SKenneth D. Merry } 1583*ef270ab1SKenneth D. Merry case OCS_EVT_PRLI_RCVD: 1584*ef270ab1SKenneth D. Merry /* I, or I+T */ 1585*ef270ab1SKenneth D. Merry /* sent PLOGI and before completion was seen, received the 1586*ef270ab1SKenneth D. Merry * PRLI from the remote node (WCQEs and RCQEs come in on 1587*ef270ab1SKenneth D. Merry * different queues and order of processing cannot be assumed) 1588*ef270ab1SKenneth D. Merry * Save OXID so PRLI can be sent after the attach and continue 1589*ef270ab1SKenneth D. Merry * to wait for PLOGI response 1590*ef270ab1SKenneth D. Merry */ 1591*ef270ab1SKenneth D. Merry ocs_process_prli_payload(node, cbdata->payload->dma.virt); 1592*ef270ab1SKenneth D. Merry ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI); 1593*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_p2p_wait_plogi_rsp_recvd_prli, NULL); 1594*ef270ab1SKenneth D. Merry break; 1595*ef270ab1SKenneth D. Merry default: 1596*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1597*ef270ab1SKenneth D. Merry return NULL; 1598*ef270ab1SKenneth D. Merry } 1599*ef270ab1SKenneth D. Merry 1600*ef270ab1SKenneth D. Merry return NULL; 1601*ef270ab1SKenneth D. Merry } 1602*ef270ab1SKenneth D. Merry 1603*ef270ab1SKenneth D. Merry /** 1604*ef270ab1SKenneth D. Merry * @ingroup p2p_sm 1605*ef270ab1SKenneth D. Merry * @brief Point-to-point node state machine: Waiting on a response for a 1606*ef270ab1SKenneth D. Merry * sent PLOGI. 1607*ef270ab1SKenneth D. Merry * 1608*ef270ab1SKenneth D. Merry * @par Description 1609*ef270ab1SKenneth D. Merry * State is entered when the point-to-point winner has sent 1610*ef270ab1SKenneth D. Merry * a PLOGI and is waiting for a response. Before receiving the 1611*ef270ab1SKenneth D. Merry * response, a PRLI was received, implying that the PLOGI was 1612*ef270ab1SKenneth D. Merry * successful. 1613*ef270ab1SKenneth D. Merry * 1614*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1615*ef270ab1SKenneth D. Merry * @param evt Event to process. 1616*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1617*ef270ab1SKenneth D. Merry * 1618*ef270ab1SKenneth D. Merry * @return Returns NULL. 1619*ef270ab1SKenneth D. Merry */ 1620*ef270ab1SKenneth D. Merry 1621*ef270ab1SKenneth D. Merry void * 1622*ef270ab1SKenneth D. Merry __ocs_p2p_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1623*ef270ab1SKenneth D. Merry { 1624*ef270ab1SKenneth D. Merry int32_t rc; 1625*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 1626*ef270ab1SKenneth D. Merry std_node_state_decl(); 1627*ef270ab1SKenneth D. Merry 1628*ef270ab1SKenneth D. Merry node_sm_trace(); 1629*ef270ab1SKenneth D. Merry 1630*ef270ab1SKenneth D. Merry switch(evt) { 1631*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 1632*ef270ab1SKenneth D. Merry /* 1633*ef270ab1SKenneth D. Merry * Since we've received a PRLI, we have a port login and will 1634*ef270ab1SKenneth D. Merry * just need to wait for the PLOGI response to do the node 1635*ef270ab1SKenneth D. Merry * attach and then we can send the LS_ACC for the PRLI. If, 1636*ef270ab1SKenneth D. Merry * during this time, we receive FCP_CMNDs (which is possible 1637*ef270ab1SKenneth D. Merry * since we've already sent a PRLI and our peer may have accepted). 1638*ef270ab1SKenneth D. Merry * At this time, we are not waiting on any other unsolicited 1639*ef270ab1SKenneth D. Merry * frames to continue with the login process. Thus, it will not 1640*ef270ab1SKenneth D. Merry * hurt to hold frames here. 1641*ef270ab1SKenneth D. Merry */ 1642*ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 1643*ef270ab1SKenneth D. Merry break; 1644*ef270ab1SKenneth D. Merry 1645*ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1646*ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 1647*ef270ab1SKenneth D. Merry break; 1648*ef270ab1SKenneth D. Merry 1649*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: /* PLOGI response received */ 1650*ef270ab1SKenneth D. Merry /* Completion from PLOGI sent */ 1651*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 1652*ef270ab1SKenneth D. Merry return NULL; 1653*ef270ab1SKenneth D. Merry } 1654*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 1655*ef270ab1SKenneth D. Merry node->els_req_cnt--; 1656*ef270ab1SKenneth D. Merry /* sm: / save sparams, ocs_node_attach */ 1657*ef270ab1SKenneth D. Merry ocs_node_save_sparms(node, cbdata->els->els_rsp.virt); 1658*ef270ab1SKenneth D. Merry ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL, 1659*ef270ab1SKenneth D. Merry ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 1660*ef270ab1SKenneth D. Merry rc = ocs_node_attach(node); 1661*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_p2p_wait_node_attach, NULL); 1662*ef270ab1SKenneth D. Merry if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 1663*ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 1664*ef270ab1SKenneth D. Merry } 1665*ef270ab1SKenneth D. Merry break; 1666*ef270ab1SKenneth D. Merry 1667*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */ 1668*ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_RJT: 1669*ef270ab1SKenneth D. Merry /* PLOGI failed, shutdown the node */ 1670*ef270ab1SKenneth D. Merry if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_fabric_common, __func__)) { 1671*ef270ab1SKenneth D. Merry return NULL; 1672*ef270ab1SKenneth D. Merry } 1673*ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 1674*ef270ab1SKenneth D. Merry node->els_req_cnt--; 1675*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1676*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 1677*ef270ab1SKenneth D. Merry break; 1678*ef270ab1SKenneth D. Merry 1679*ef270ab1SKenneth D. Merry default: 1680*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1681*ef270ab1SKenneth D. Merry return NULL; 1682*ef270ab1SKenneth D. Merry } 1683*ef270ab1SKenneth D. Merry 1684*ef270ab1SKenneth D. Merry return NULL; 1685*ef270ab1SKenneth D. Merry } 1686*ef270ab1SKenneth D. Merry 1687*ef270ab1SKenneth D. Merry /** 1688*ef270ab1SKenneth D. Merry * @ingroup p2p_sm 1689*ef270ab1SKenneth D. Merry * @brief Point-to-point node state machine: Wait for a point-to-point node attach 1690*ef270ab1SKenneth D. Merry * to complete. 1691*ef270ab1SKenneth D. Merry * 1692*ef270ab1SKenneth D. Merry * @par Description 1693*ef270ab1SKenneth D. Merry * Waits for the point-to-point node attach to complete. 1694*ef270ab1SKenneth D. Merry * 1695*ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1696*ef270ab1SKenneth D. Merry * @param evt Event to process. 1697*ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1698*ef270ab1SKenneth D. Merry * 1699*ef270ab1SKenneth D. Merry * @return Returns NULL. 1700*ef270ab1SKenneth D. Merry */ 1701*ef270ab1SKenneth D. Merry 1702*ef270ab1SKenneth D. Merry void * 1703*ef270ab1SKenneth D. Merry __ocs_p2p_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1704*ef270ab1SKenneth D. Merry { 1705*ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 1706*ef270ab1SKenneth D. Merry std_node_state_decl(); 1707*ef270ab1SKenneth D. Merry 1708*ef270ab1SKenneth D. Merry node_sm_trace(); 1709*ef270ab1SKenneth D. Merry 1710*ef270ab1SKenneth D. Merry switch(evt) { 1711*ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 1712*ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 1713*ef270ab1SKenneth D. Merry break; 1714*ef270ab1SKenneth D. Merry 1715*ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1716*ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 1717*ef270ab1SKenneth D. Merry break; 1718*ef270ab1SKenneth D. Merry 1719*ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_OK: 1720*ef270ab1SKenneth D. Merry node->attached = TRUE; 1721*ef270ab1SKenneth D. Merry switch (node->send_ls_acc) { 1722*ef270ab1SKenneth D. Merry case OCS_NODE_SEND_LS_ACC_PRLI: { 1723*ef270ab1SKenneth D. Merry ocs_d_send_prli_rsp(node->ls_acc_io, node->ls_acc_oxid); 1724*ef270ab1SKenneth D. Merry node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE; 1725*ef270ab1SKenneth D. Merry node->ls_acc_io = NULL; 1726*ef270ab1SKenneth D. Merry break; 1727*ef270ab1SKenneth D. Merry } 1728*ef270ab1SKenneth D. Merry case OCS_NODE_SEND_LS_ACC_PLOGI: /* Can't happen in P2P */ 1729*ef270ab1SKenneth D. Merry case OCS_NODE_SEND_LS_ACC_NONE: 1730*ef270ab1SKenneth D. Merry default: 1731*ef270ab1SKenneth D. Merry /* Normal case for I */ 1732*ef270ab1SKenneth D. Merry /* sm: send_plogi_acc is not set / send PLOGI acc */ 1733*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_d_port_logged_in, NULL); 1734*ef270ab1SKenneth D. Merry break; 1735*ef270ab1SKenneth D. Merry } 1736*ef270ab1SKenneth D. Merry break; 1737*ef270ab1SKenneth D. Merry 1738*ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_FAIL: 1739*ef270ab1SKenneth D. Merry /* node attach failed, shutdown the node */ 1740*ef270ab1SKenneth D. Merry node->attached = FALSE; 1741*ef270ab1SKenneth D. Merry node_printf(node, "Node attach failed\n"); 1742*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1743*ef270ab1SKenneth D. Merry ocs_fabric_initiate_shutdown(node); 1744*ef270ab1SKenneth D. Merry break; 1745*ef270ab1SKenneth D. Merry 1746*ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN: 1747*ef270ab1SKenneth D. Merry node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 1748*ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1749*ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_fabric_wait_attach_evt_shutdown, NULL); 1750*ef270ab1SKenneth D. Merry break; 1751*ef270ab1SKenneth D. Merry case OCS_EVT_PRLI_RCVD: 1752*ef270ab1SKenneth D. Merry node_printf(node, "%s: PRLI received before node is attached\n", ocs_sm_event_name(evt)); 1753*ef270ab1SKenneth D. Merry ocs_process_prli_payload(node, cbdata->payload->dma.virt); 1754*ef270ab1SKenneth D. Merry ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI); 1755*ef270ab1SKenneth D. Merry break; 1756*ef270ab1SKenneth D. Merry default: 1757*ef270ab1SKenneth D. Merry __ocs_fabric_common(__func__, ctx, evt, arg); 1758*ef270ab1SKenneth D. Merry return NULL; 1759*ef270ab1SKenneth D. Merry } 1760*ef270ab1SKenneth D. Merry 1761*ef270ab1SKenneth D. Merry return NULL; 1762*ef270ab1SKenneth D. Merry } 1763*ef270ab1SKenneth D. Merry 1764*ef270ab1SKenneth D. Merry /** 1765*ef270ab1SKenneth D. Merry * @brief Start up the name services node. 1766*ef270ab1SKenneth D. Merry * 1767*ef270ab1SKenneth D. Merry * @par Description 1768*ef270ab1SKenneth D. Merry * Allocates and starts up the name services node. 1769*ef270ab1SKenneth D. Merry * 1770*ef270ab1SKenneth D. Merry * @param sport Pointer to the sport structure. 1771*ef270ab1SKenneth D. Merry * 1772*ef270ab1SKenneth D. Merry * @return Returns 0 on success, or a negative error value on failure. 1773*ef270ab1SKenneth D. Merry */ 1774*ef270ab1SKenneth D. Merry 1775*ef270ab1SKenneth D. Merry static int32_t 1776*ef270ab1SKenneth D. Merry ocs_start_ns_node(ocs_sport_t *sport) 1777*ef270ab1SKenneth D. Merry { 1778*ef270ab1SKenneth D. Merry ocs_node_t *ns; 1779*ef270ab1SKenneth D. Merry 1780*ef270ab1SKenneth D. Merry /* Instantiate a name services node */ 1781*ef270ab1SKenneth D. Merry ns = ocs_node_find(sport, FC_ADDR_NAMESERVER); 1782*ef270ab1SKenneth D. Merry if (ns == NULL) { 1783*ef270ab1SKenneth D. Merry ns = ocs_node_alloc(sport, FC_ADDR_NAMESERVER, FALSE, FALSE); 1784*ef270ab1SKenneth D. Merry if (ns == NULL) { 1785*ef270ab1SKenneth D. Merry return -1; 1786*ef270ab1SKenneth D. Merry } 1787*ef270ab1SKenneth D. Merry } 1788*ef270ab1SKenneth D. Merry /* TODO: for found ns, should we be transitioning from here? 1789*ef270ab1SKenneth D. Merry * breaks transition only 1. from within state machine or 1790*ef270ab1SKenneth D. Merry * 2. if after alloc 1791*ef270ab1SKenneth D. Merry */ 1792*ef270ab1SKenneth D. Merry if (ns->ocs->nodedb_mask & OCS_NODEDB_PAUSE_NAMESERVER) { 1793*ef270ab1SKenneth D. Merry ocs_node_pause(ns, __ocs_ns_init); 1794*ef270ab1SKenneth D. Merry } else { 1795*ef270ab1SKenneth D. Merry ocs_node_transition(ns, __ocs_ns_init, NULL); 1796*ef270ab1SKenneth D. Merry } 1797*ef270ab1SKenneth D. Merry return 0; 1798*ef270ab1SKenneth D. Merry } 1799*ef270ab1SKenneth D. Merry 1800*ef270ab1SKenneth D. Merry /** 1801*ef270ab1SKenneth D. Merry * @brief Start up the fabric controller node. 1802*ef270ab1SKenneth D. Merry * 1803*ef270ab1SKenneth D. Merry * @par Description 1804*ef270ab1SKenneth D. Merry * Allocates and starts up the fabric controller node. 1805*ef270ab1SKenneth D. Merry * 1806*ef270ab1SKenneth D. Merry * @param sport Pointer to the sport structure. 1807*ef270ab1SKenneth D. Merry * 1808*ef270ab1SKenneth D. Merry * @return Returns 0 on success, or a negative error value on failure. 1809*ef270ab1SKenneth D. Merry */ 1810*ef270ab1SKenneth D. Merry 1811*ef270ab1SKenneth D. Merry static int32_t 1812*ef270ab1SKenneth D. Merry ocs_start_fabctl_node(ocs_sport_t *sport) 1813*ef270ab1SKenneth D. Merry { 1814*ef270ab1SKenneth D. Merry ocs_node_t *fabctl; 1815*ef270ab1SKenneth D. Merry 1816*ef270ab1SKenneth D. Merry fabctl = ocs_node_find(sport, FC_ADDR_CONTROLLER); 1817*ef270ab1SKenneth D. Merry if (fabctl == NULL) { 1818*ef270ab1SKenneth D. Merry fabctl = ocs_node_alloc(sport, FC_ADDR_CONTROLLER, FALSE, FALSE); 1819*ef270ab1SKenneth D. Merry if (fabctl == NULL) { 1820*ef270ab1SKenneth D. Merry return -1; 1821*ef270ab1SKenneth D. Merry } 1822*ef270ab1SKenneth D. Merry } 1823*ef270ab1SKenneth D. Merry /* TODO: for found ns, should we be transitioning from here? 1824*ef270ab1SKenneth D. Merry * breaks transition only 1. from within state machine or 1825*ef270ab1SKenneth D. Merry * 2. if after alloc 1826*ef270ab1SKenneth D. Merry */ 1827*ef270ab1SKenneth D. Merry ocs_node_transition(fabctl, __ocs_fabctl_init, NULL); 1828*ef270ab1SKenneth D. Merry return 0; 1829*ef270ab1SKenneth D. Merry } 1830*ef270ab1SKenneth D. Merry 1831*ef270ab1SKenneth D. Merry /** 1832*ef270ab1SKenneth D. Merry * @brief Process the GIDPT payload. 1833*ef270ab1SKenneth D. Merry * 1834*ef270ab1SKenneth D. Merry * @par Description 1835*ef270ab1SKenneth D. Merry * The GIDPT payload is parsed, and new nodes are created, as needed. 1836*ef270ab1SKenneth D. Merry * 1837*ef270ab1SKenneth D. Merry * @param node Pointer to the node structure. 1838*ef270ab1SKenneth D. Merry * @param gidpt Pointer to the GIDPT payload. 1839*ef270ab1SKenneth D. Merry * @param gidpt_len Payload length 1840*ef270ab1SKenneth D. Merry * 1841*ef270ab1SKenneth D. Merry * @return Returns 0 on success, or a negative error value on failure. 1842*ef270ab1SKenneth D. Merry */ 1843*ef270ab1SKenneth D. Merry 1844*ef270ab1SKenneth D. Merry static int32_t 1845*ef270ab1SKenneth D. Merry ocs_process_gidpt_payload(ocs_node_t *node, fcct_gidpt_acc_t *gidpt, uint32_t gidpt_len) 1846*ef270ab1SKenneth D. Merry { 1847*ef270ab1SKenneth D. Merry uint32_t i; 1848*ef270ab1SKenneth D. Merry uint32_t j; 1849*ef270ab1SKenneth D. Merry ocs_node_t *newnode; 1850*ef270ab1SKenneth D. Merry ocs_sport_t *sport = node->sport; 1851*ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 1852*ef270ab1SKenneth D. Merry uint32_t port_id; 1853*ef270ab1SKenneth D. Merry uint32_t port_count; 1854*ef270ab1SKenneth D. Merry ocs_node_t *n; 1855*ef270ab1SKenneth D. Merry ocs_node_t **active_nodes; 1856*ef270ab1SKenneth D. Merry uint32_t portlist_count; 1857*ef270ab1SKenneth D. Merry uint16_t residual; 1858*ef270ab1SKenneth D. Merry 1859*ef270ab1SKenneth D. Merry residual = ocs_be16toh(gidpt->hdr.max_residual_size); 1860*ef270ab1SKenneth D. Merry 1861*ef270ab1SKenneth D. Merry if (residual != 0) { 1862*ef270ab1SKenneth D. Merry ocs_log_debug(node->ocs, "residual is %u words\n", residual); 1863*ef270ab1SKenneth D. Merry } 1864*ef270ab1SKenneth D. Merry 1865*ef270ab1SKenneth D. Merry if (ocs_be16toh(gidpt->hdr.cmd_rsp_code) == FCCT_HDR_CMDRSP_REJECT) { 1866*ef270ab1SKenneth D. Merry node_printf(node, "GIDPT request failed: rsn x%x rsn_expl x%x\n", 1867*ef270ab1SKenneth D. Merry gidpt->hdr.reason_code, gidpt->hdr.reason_code_explanation); 1868*ef270ab1SKenneth D. Merry return -1; 1869*ef270ab1SKenneth D. Merry } 1870*ef270ab1SKenneth D. Merry 1871*ef270ab1SKenneth D. Merry portlist_count = (gidpt_len - sizeof(fcct_iu_header_t)) / sizeof(gidpt->port_list); 1872*ef270ab1SKenneth D. Merry 1873*ef270ab1SKenneth D. Merry /* Count the number of nodes */ 1874*ef270ab1SKenneth D. Merry port_count = 0; 1875*ef270ab1SKenneth D. Merry ocs_sport_lock(sport); 1876*ef270ab1SKenneth D. Merry ocs_list_foreach(&sport->node_list, n) { 1877*ef270ab1SKenneth D. Merry port_count ++; 1878*ef270ab1SKenneth D. Merry } 1879*ef270ab1SKenneth D. Merry 1880*ef270ab1SKenneth D. Merry /* Allocate a buffer for all nodes */ 1881*ef270ab1SKenneth D. Merry active_nodes = ocs_malloc(node->ocs, port_count * sizeof(*active_nodes), OCS_M_NOWAIT | OCS_M_ZERO); 1882*ef270ab1SKenneth D. Merry if (active_nodes == NULL) { 1883*ef270ab1SKenneth D. Merry node_printf(node, "ocs_malloc failed\n"); 1884*ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 1885*ef270ab1SKenneth D. Merry return -1; 1886*ef270ab1SKenneth D. Merry } 1887*ef270ab1SKenneth D. Merry 1888*ef270ab1SKenneth D. Merry /* Fill buffer with fc_id of active nodes */ 1889*ef270ab1SKenneth D. Merry i = 0; 1890*ef270ab1SKenneth D. Merry ocs_list_foreach(&sport->node_list, n) { 1891*ef270ab1SKenneth D. Merry port_id = n->rnode.fc_id; 1892*ef270ab1SKenneth D. Merry switch (port_id) { 1893*ef270ab1SKenneth D. Merry case FC_ADDR_FABRIC: 1894*ef270ab1SKenneth D. Merry case FC_ADDR_CONTROLLER: 1895*ef270ab1SKenneth D. Merry case FC_ADDR_NAMESERVER: 1896*ef270ab1SKenneth D. Merry break; 1897*ef270ab1SKenneth D. Merry default: 1898*ef270ab1SKenneth D. Merry if (!FC_ADDR_IS_DOMAIN_CTRL(port_id)) { 1899*ef270ab1SKenneth D. Merry active_nodes[i++] = n; 1900*ef270ab1SKenneth D. Merry } 1901*ef270ab1SKenneth D. Merry break; 1902*ef270ab1SKenneth D. Merry } 1903*ef270ab1SKenneth D. Merry } 1904*ef270ab1SKenneth D. Merry 1905*ef270ab1SKenneth D. Merry /* update the active nodes buffer */ 1906*ef270ab1SKenneth D. Merry for (i = 0; i < portlist_count; i ++) { 1907*ef270ab1SKenneth D. Merry port_id = fc_be24toh(gidpt->port_list[i].port_id); 1908*ef270ab1SKenneth D. Merry 1909*ef270ab1SKenneth D. Merry for (j = 0; j < port_count; j ++) { 1910*ef270ab1SKenneth D. Merry if ((active_nodes[j] != NULL) && (port_id == active_nodes[j]->rnode.fc_id)) { 1911*ef270ab1SKenneth D. Merry active_nodes[j] = NULL; 1912*ef270ab1SKenneth D. Merry } 1913*ef270ab1SKenneth D. Merry } 1914*ef270ab1SKenneth D. Merry 1915*ef270ab1SKenneth D. Merry if (gidpt->port_list[i].ctl & FCCT_GID_PT_LAST_ID) 1916*ef270ab1SKenneth D. Merry break; 1917*ef270ab1SKenneth D. Merry } 1918*ef270ab1SKenneth D. Merry 1919*ef270ab1SKenneth D. Merry /* Those remaining in the active_nodes[] are now gone ! */ 1920*ef270ab1SKenneth D. Merry for (i = 0; i < port_count; i ++) { 1921*ef270ab1SKenneth D. Merry /* if we're an initiator and the remote node is a target, then 1922*ef270ab1SKenneth D. Merry * post the node missing event. if we're target and we have enabled 1923*ef270ab1SKenneth D. Merry * target RSCN, then post the node missing event. 1924*ef270ab1SKenneth D. Merry */ 1925*ef270ab1SKenneth D. Merry if (active_nodes[i] != NULL) { 1926*ef270ab1SKenneth D. Merry if ((node->sport->enable_ini && active_nodes[i]->targ) || 1927*ef270ab1SKenneth D. Merry (node->sport->enable_tgt && enable_target_rscn(ocs))) { 1928*ef270ab1SKenneth D. Merry ocs_node_post_event(active_nodes[i], OCS_EVT_NODE_MISSING, NULL); 1929*ef270ab1SKenneth D. Merry } else { 1930*ef270ab1SKenneth D. Merry node_printf(node, "GID_PT: skipping non-tgt port_id x%06x\n", 1931*ef270ab1SKenneth D. Merry active_nodes[i]->rnode.fc_id); 1932*ef270ab1SKenneth D. Merry } 1933*ef270ab1SKenneth D. Merry } 1934*ef270ab1SKenneth D. Merry } 1935*ef270ab1SKenneth D. Merry ocs_free(ocs, active_nodes, port_count * sizeof(*active_nodes)); 1936*ef270ab1SKenneth D. Merry 1937*ef270ab1SKenneth D. Merry for(i = 0; i < portlist_count; i ++) { 1938*ef270ab1SKenneth D. Merry uint32_t port_id = fc_be24toh(gidpt->port_list[i].port_id); 1939*ef270ab1SKenneth D. Merry 1940*ef270ab1SKenneth D. Merry /* node_printf(node, "GID_PT: port_id x%06x\n", port_id); */ 1941*ef270ab1SKenneth D. Merry 1942*ef270ab1SKenneth D. Merry /* Don't create node for ourselves or the associated NPIV ports */ 1943*ef270ab1SKenneth D. Merry if (port_id != node->rnode.sport->fc_id && !ocs_sport_find(sport->domain, port_id)) { 1944*ef270ab1SKenneth D. Merry newnode = ocs_node_find(sport, port_id); 1945*ef270ab1SKenneth D. Merry if (newnode) { 1946*ef270ab1SKenneth D. Merry /* TODO: what if node deleted here?? */ 1947*ef270ab1SKenneth D. Merry if (node->sport->enable_ini && newnode->targ) { 1948*ef270ab1SKenneth D. Merry ocs_node_post_event(newnode, OCS_EVT_NODE_REFOUND, NULL); 1949*ef270ab1SKenneth D. Merry } 1950*ef270ab1SKenneth D. Merry /* original code sends ADISC, has notion of "refound" */ 1951*ef270ab1SKenneth D. Merry } else { 1952*ef270ab1SKenneth D. Merry if (node->sport->enable_ini) { 1953*ef270ab1SKenneth D. Merry newnode = ocs_node_alloc(sport, port_id, 0, 0); 1954*ef270ab1SKenneth D. Merry if (newnode == NULL) { 1955*ef270ab1SKenneth D. Merry ocs_log_err(ocs, "ocs_node_alloc() failed\n"); 1956*ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 1957*ef270ab1SKenneth D. Merry return -1; 1958*ef270ab1SKenneth D. Merry } 1959*ef270ab1SKenneth D. Merry /* send PLOGI automatically if initiator */ 1960*ef270ab1SKenneth D. Merry ocs_node_init_device(newnode, TRUE); 1961*ef270ab1SKenneth D. Merry } 1962*ef270ab1SKenneth D. Merry } 1963*ef270ab1SKenneth D. Merry } 1964*ef270ab1SKenneth D. Merry 1965*ef270ab1SKenneth D. Merry if (gidpt->port_list[i].ctl & FCCT_GID_PT_LAST_ID) { 1966*ef270ab1SKenneth D. Merry break; 1967*ef270ab1SKenneth D. Merry } 1968*ef270ab1SKenneth D. Merry } 1969*ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 1970*ef270ab1SKenneth D. Merry return 0; 1971*ef270ab1SKenneth D. Merry } 1972*ef270ab1SKenneth D. Merry 1973*ef270ab1SKenneth D. Merry /** 1974*ef270ab1SKenneth D. Merry * @brief Set up the domain point-to-point parameters. 1975*ef270ab1SKenneth D. Merry * 1976*ef270ab1SKenneth D. Merry * @par Description 1977*ef270ab1SKenneth D. Merry * The remote node service parameters are examined, and various point-to-point 1978*ef270ab1SKenneth D. Merry * variables are set. 1979*ef270ab1SKenneth D. Merry * 1980*ef270ab1SKenneth D. Merry * @param sport Pointer to the sport object. 1981*ef270ab1SKenneth D. Merry * 1982*ef270ab1SKenneth D. Merry * @return Returns 0 on success, or a negative error value on failure. 1983*ef270ab1SKenneth D. Merry */ 1984*ef270ab1SKenneth D. Merry 1985*ef270ab1SKenneth D. Merry int32_t 1986*ef270ab1SKenneth D. Merry ocs_p2p_setup(ocs_sport_t *sport) 1987*ef270ab1SKenneth D. Merry { 1988*ef270ab1SKenneth D. Merry ocs_t *ocs = sport->ocs; 1989*ef270ab1SKenneth D. Merry int32_t rnode_winner; 1990*ef270ab1SKenneth D. Merry rnode_winner = ocs_rnode_is_winner(sport); 1991*ef270ab1SKenneth D. Merry 1992*ef270ab1SKenneth D. Merry /* set sport flags to indicate p2p "winner" */ 1993*ef270ab1SKenneth D. Merry if (rnode_winner == 1) { 1994*ef270ab1SKenneth D. Merry sport->p2p_remote_port_id = 0; 1995*ef270ab1SKenneth D. Merry sport->p2p_port_id = 0; 1996*ef270ab1SKenneth D. Merry sport->p2p_winner = FALSE; 1997*ef270ab1SKenneth D. Merry } else if (rnode_winner == 0) { 1998*ef270ab1SKenneth D. Merry sport->p2p_remote_port_id = 2; 1999*ef270ab1SKenneth D. Merry sport->p2p_port_id = 1; 2000*ef270ab1SKenneth D. Merry sport->p2p_winner = TRUE; 2001*ef270ab1SKenneth D. Merry } else { 2002*ef270ab1SKenneth D. Merry /* no winner; only okay if external loopback enabled */ 2003*ef270ab1SKenneth D. Merry if (sport->ocs->external_loopback) { 2004*ef270ab1SKenneth D. Merry /* 2005*ef270ab1SKenneth D. Merry * External loopback mode enabled; local sport and remote node 2006*ef270ab1SKenneth D. Merry * will be registered with an NPortID = 1; 2007*ef270ab1SKenneth D. Merry */ 2008*ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "External loopback mode enabled\n"); 2009*ef270ab1SKenneth D. Merry sport->p2p_remote_port_id = 1; 2010*ef270ab1SKenneth D. Merry sport->p2p_port_id = 1; 2011*ef270ab1SKenneth D. Merry sport->p2p_winner = TRUE; 2012*ef270ab1SKenneth D. Merry } else { 2013*ef270ab1SKenneth D. Merry ocs_log_warn(ocs, "failed to determine p2p winner\n"); 2014*ef270ab1SKenneth D. Merry return rnode_winner; 2015*ef270ab1SKenneth D. Merry } 2016*ef270ab1SKenneth D. Merry } 2017*ef270ab1SKenneth D. Merry return 0; 2018*ef270ab1SKenneth D. Merry } 2019*ef270ab1SKenneth D. Merry 2020*ef270ab1SKenneth D. Merry /** 2021*ef270ab1SKenneth D. Merry * @brief Process the FABCTL node RSCN. 2022*ef270ab1SKenneth D. Merry * 2023*ef270ab1SKenneth D. Merry * <h3 class="desc">Description</h3> 2024*ef270ab1SKenneth D. Merry * Processes the FABCTL node RSCN payload, simply passes the event to the name server. 2025*ef270ab1SKenneth D. Merry * 2026*ef270ab1SKenneth D. Merry * @param node Pointer to the node structure. 2027*ef270ab1SKenneth D. Merry * @param cbdata Callback data to pass forward. 2028*ef270ab1SKenneth D. Merry * 2029*ef270ab1SKenneth D. Merry * @return None. 2030*ef270ab1SKenneth D. Merry */ 2031*ef270ab1SKenneth D. Merry 2032*ef270ab1SKenneth D. Merry static void 2033*ef270ab1SKenneth D. Merry ocs_process_rscn(ocs_node_t *node, ocs_node_cb_t *cbdata) 2034*ef270ab1SKenneth D. Merry { 2035*ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 2036*ef270ab1SKenneth D. Merry ocs_sport_t *sport = node->sport; 2037*ef270ab1SKenneth D. Merry ocs_node_t *ns; 2038*ef270ab1SKenneth D. Merry 2039*ef270ab1SKenneth D. Merry /* Forward this event to the name-services node */ 2040*ef270ab1SKenneth D. Merry ns = ocs_node_find(sport, FC_ADDR_NAMESERVER); 2041*ef270ab1SKenneth D. Merry if (ns != NULL) { 2042*ef270ab1SKenneth D. Merry ocs_node_post_event(ns, OCS_EVT_RSCN_RCVD, cbdata); 2043*ef270ab1SKenneth D. Merry } else { 2044*ef270ab1SKenneth D. Merry ocs_log_warn(ocs, "can't find name server node\n"); 2045*ef270ab1SKenneth D. Merry } 2046*ef270ab1SKenneth D. Merry } 2047