1331766Sken/*- 2331766Sken * Copyright (c) 2017 Broadcom. All rights reserved. 3331766Sken * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4331766Sken * 5331766Sken * Redistribution and use in source and binary forms, with or without 6331766Sken * modification, are permitted provided that the following conditions are met: 7331766Sken * 8331766Sken * 1. Redistributions of source code must retain the above copyright notice, 9331766Sken * this list of conditions and the following disclaimer. 10331766Sken * 11331766Sken * 2. Redistributions in binary form must reproduce the above copyright notice, 12331766Sken * this list of conditions and the following disclaimer in the documentation 13331766Sken * and/or other materials provided with the distribution. 14331766Sken * 15331766Sken * 3. Neither the name of the copyright holder nor the names of its contributors 16331766Sken * may be used to endorse or promote products derived from this software 17331766Sken * without specific prior written permission. 18331766Sken * 19331766Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20331766Sken * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21331766Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22331766Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23331766Sken * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24331766Sken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25331766Sken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26331766Sken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27331766Sken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28331766Sken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29331766Sken * POSSIBILITY OF SUCH DAMAGE. 30331766Sken * 31331766Sken * $FreeBSD: stable/11/sys/dev/ocs_fc/ocs_device.c 360415 2020-04-27 23:49:13Z brooks $ 32331766Sken */ 33331766Sken 34331766Sken/** 35331766Sken * @file 36331766Sken * Implement remote device state machine for target and initiator. 37331766Sken */ 38331766Sken 39331766Sken/*! 40331766Sken@defgroup device_sm Node State Machine: Remote Device States 41331766Sken*/ 42331766Sken 43331766Sken#include "ocs.h" 44331766Sken#include "ocs_device.h" 45331766Sken#include "ocs_fabric.h" 46331766Sken#include "ocs_els.h" 47331766Sken 48331766Skenstatic void *__ocs_d_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg); 49331766Skenstatic void *__ocs_d_wait_del_node(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg); 50331766Skenstatic void *__ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg); 51331766Skenstatic int32_t ocs_process_abts(ocs_io_t *io, fc_header_t *hdr); 52331766Sken 53331766Sken/** 54331766Sken * @ingroup device_sm 55331766Sken * @brief Send response to PRLI. 56331766Sken * 57331766Sken * <h3 class="desc">Description</h3> 58331766Sken * For device nodes, this function sends a PRLI response. 59331766Sken * 60331766Sken * @param io Pointer to a SCSI IO object. 61331766Sken * @param ox_id OX_ID of PRLI 62331766Sken * 63331766Sken * @return Returns None. 64331766Sken */ 65331766Sken 66331766Skenvoid 67331766Skenocs_d_send_prli_rsp(ocs_io_t *io, uint16_t ox_id) 68331766Sken{ 69331766Sken ocs_t *ocs = io->ocs; 70331766Sken ocs_node_t *node = io->node; 71331766Sken 72331766Sken /* If the back-end doesn't support the fc-type, we send an LS_RJT */ 73331766Sken if (ocs->fc_type != node->fc_type) { 74331766Sken node_printf(node, "PRLI rejected by target-server, fc-type not supported\n"); 75331766Sken ocs_send_ls_rjt(io, ox_id, FC_REASON_UNABLE_TO_PERFORM, 76331766Sken FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL); 77331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 78331766Sken ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL); 79331766Sken } 80331766Sken 81331766Sken /* If the back-end doesn't want to talk to this initiator, we send an LS_RJT */ 82331766Sken if (node->sport->enable_tgt && (ocs_scsi_validate_initiator(node) == 0)) { 83331766Sken node_printf(node, "PRLI rejected by target-server\n"); 84331766Sken ocs_send_ls_rjt(io, ox_id, FC_REASON_UNABLE_TO_PERFORM, 85331766Sken FC_EXPL_NO_ADDITIONAL, 0, NULL, NULL); 86331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 87331766Sken ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL); 88331766Sken } else { 89331766Sken /*sm: process PRLI payload, send PRLI acc */ 90331766Sken ocs_send_prli_acc(io, ox_id, ocs->fc_type, NULL, NULL); 91331766Sken 92331766Sken /* Immediately go to ready state to avoid window where we're 93331766Sken * waiting for the PRLI LS_ACC to complete while holding FCP_CMNDs 94331766Sken */ 95331766Sken ocs_node_transition(node, __ocs_d_device_ready, NULL); 96331766Sken } 97331766Sken} 98331766Sken 99331766Sken/** 100331766Sken * @ingroup device_sm 101331766Sken * @brief Device node state machine: Initiate node shutdown 102331766Sken * 103331766Sken * @param ctx Remote node state machine context. 104331766Sken * @param evt Event to process. 105331766Sken * @param arg Per event optional argument. 106331766Sken * 107331766Sken * @return Returns NULL. 108331766Sken */ 109331766Sken 110331766Skenvoid * 111331766Sken__ocs_d_initiate_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 112331766Sken{ 113331766Sken std_node_state_decl(); 114331766Sken 115331766Sken node_sm_trace(); 116331766Sken 117331766Sken switch(evt) { 118331766Sken case OCS_EVT_ENTER: { 119331766Sken int32_t rc = OCS_SCSI_CALL_COMPLETE; /* assume no wait needed */ 120331766Sken 121331766Sken ocs_scsi_io_alloc_disable(node); 122331766Sken 123331766Sken /* make necessary delete upcall(s) */ 124331766Sken if (node->init && !node->targ) { 125331766Sken ocs_log_debug(node->ocs, 126331766Sken "[%s] delete (initiator) WWPN %s WWNN %s\n", 127331766Sken node->display_name, node->wwpn, node->wwnn); 128331766Sken ocs_node_transition(node, __ocs_d_wait_del_node, NULL); 129331766Sken if (node->sport->enable_tgt) { 130331766Sken rc = ocs_scsi_del_initiator(node, 131331766Sken OCS_SCSI_INITIATOR_DELETED); 132331766Sken } 133331766Sken if (rc == OCS_SCSI_CALL_COMPLETE) { 134331766Sken ocs_node_post_event(node, 135331766Sken OCS_EVT_NODE_DEL_INI_COMPLETE, NULL); 136331766Sken } 137331766Sken } else if (node->targ && !node->init) { 138331766Sken ocs_log_debug(node->ocs, 139331766Sken "[%s] delete (target) WWPN %s WWNN %s\n", 140331766Sken node->display_name, node->wwpn, node->wwnn); 141331766Sken ocs_node_transition(node, __ocs_d_wait_del_node, NULL); 142331766Sken if (node->sport->enable_ini) { 143331766Sken rc = ocs_scsi_del_target(node, 144331766Sken OCS_SCSI_TARGET_DELETED); 145331766Sken } 146331766Sken if (rc == OCS_SCSI_CALL_COMPLETE) { 147331766Sken ocs_node_post_event(node, 148331766Sken OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL); 149331766Sken } 150331766Sken } else if (node->init && node->targ) { 151331766Sken ocs_log_debug(node->ocs, 152331766Sken "[%s] delete (initiator+target) WWPN %s WWNN %s\n", 153331766Sken node->display_name, node->wwpn, node->wwnn); 154331766Sken ocs_node_transition(node, __ocs_d_wait_del_ini_tgt, NULL); 155331766Sken if (node->sport->enable_tgt) { 156331766Sken rc = ocs_scsi_del_initiator(node, 157331766Sken OCS_SCSI_INITIATOR_DELETED); 158331766Sken } 159331766Sken if (rc == OCS_SCSI_CALL_COMPLETE) { 160331766Sken ocs_node_post_event(node, 161331766Sken OCS_EVT_NODE_DEL_INI_COMPLETE, NULL); 162331766Sken } 163331766Sken rc = OCS_SCSI_CALL_COMPLETE; /* assume no wait needed */ 164331766Sken if (node->sport->enable_ini) { 165331766Sken rc = ocs_scsi_del_target(node, 166331766Sken OCS_SCSI_TARGET_DELETED); 167331766Sken } 168331766Sken if (rc == OCS_SCSI_CALL_COMPLETE) { 169331766Sken ocs_node_post_event(node, 170331766Sken OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL); 171331766Sken } 172331766Sken } 173331766Sken 174331766Sken /* we've initiated the upcalls as needed, now kick off the node 175331766Sken * detach to precipitate the aborting of outstanding exchanges 176331766Sken * associated with said node 177331766Sken * 178331766Sken * Beware: if we've made upcall(s), we've already transitioned 179331766Sken * to a new state by the time we execute this. 180331766Sken * TODO: consider doing this before the upcalls... 181331766Sken */ 182331766Sken if (node->attached) { 183331766Sken /* issue hw node free; don't care if succeeds right away 184331766Sken * or sometime later, will check node->attached later in 185331766Sken * shutdown process 186331766Sken */ 187331766Sken rc = ocs_hw_node_detach(&ocs->hw, &node->rnode); 188331766Sken if (node->rnode.free_group) { 189331766Sken ocs_remote_node_group_free(node->node_group); 190331766Sken node->node_group = NULL; 191331766Sken node->rnode.free_group = FALSE; 192331766Sken } 193331766Sken if (rc != OCS_HW_RTN_SUCCESS && 194331766Sken rc != OCS_HW_RTN_SUCCESS_SYNC) { 195331766Sken node_printf(node, 196331766Sken "Failed freeing HW node, rc=%d\n", rc); 197331766Sken } 198331766Sken } 199331766Sken 200331766Sken /* if neither initiator nor target, proceed to cleanup */ 201331766Sken if (!node->init && !node->targ){ 202331766Sken /* 203331766Sken * node has either been detached or is in the process 204331766Sken * of being detached, call common node's initiate 205331766Sken * cleanup function. 206331766Sken */ 207331766Sken ocs_node_initiate_cleanup(node); 208331766Sken } 209331766Sken break; 210331766Sken } 211331766Sken case OCS_EVT_ALL_CHILD_NODES_FREE: 212331766Sken /* Ignore, this can happen if an ELS is aborted, 213331766Sken * while in a delay/retry state */ 214331766Sken break; 215331766Sken default: 216331766Sken __ocs_d_common(__func__, ctx, evt, arg); 217331766Sken return NULL; 218331766Sken } 219331766Sken return NULL; 220331766Sken} 221331766Sken 222331766Sken/** 223331766Sken * @ingroup device_sm 224331766Sken * @brief Device node state machine: Common device event handler. 225331766Sken * 226331766Sken * <h3 class="desc">Description</h3> 227331766Sken * For device nodes, this event handler manages default and common events. 228331766Sken * 229331766Sken * @param funcname Function name text. 230331766Sken * @param ctx Remote node state machine context. 231331766Sken * @param evt Event to process. 232331766Sken * @param arg Per event optional argument. 233331766Sken * 234331766Sken * @return Returns NULL. 235331766Sken */ 236331766Sken 237331766Skenstatic void * 238331766Sken__ocs_d_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 239331766Sken{ 240331766Sken ocs_node_t *node = NULL; 241331766Sken ocs_t *ocs = NULL; 242331766Sken ocs_assert(ctx, NULL); 243331766Sken node = ctx->app; 244331766Sken ocs_assert(node, NULL); 245331766Sken ocs = node->ocs; 246331766Sken ocs_assert(ocs, NULL); 247331766Sken 248331766Sken switch(evt) { 249331766Sken 250331766Sken /* Handle shutdown events */ 251331766Sken case OCS_EVT_SHUTDOWN: 252331766Sken ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt)); 253331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 254331766Sken ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL); 255331766Sken break; 256331766Sken case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO: 257331766Sken ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt)); 258331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_EXPLICIT_LOGO; 259331766Sken ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL); 260331766Sken break; 261331766Sken case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO: 262331766Sken ocs_log_debug(ocs, "[%s] %-20s %-20s\n", node->display_name, funcname, ocs_sm_event_name(evt)); 263331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_IMPLICIT_LOGO; 264331766Sken ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL); 265331766Sken break; 266331766Sken 267331766Sken default: 268331766Sken /* call default event handler common to all nodes */ 269331766Sken __ocs_node_common(funcname, ctx, evt, arg); 270331766Sken break; 271331766Sken } 272331766Sken return NULL; 273331766Sken} 274331766Sken 275331766Sken/** 276331766Sken * @ingroup device_sm 277331766Sken * @brief Device node state machine: Wait for a domain-attach completion in loop topology. 278331766Sken * 279331766Sken * <h3 class="desc">Description</h3> 280331766Sken * State waits for a domain-attached completion while in loop topology. 281331766Sken * 282331766Sken * @param ctx Remote node state machine context. 283331766Sken * @param evt Event to process. 284331766Sken * @param arg Per event optional argument. 285331766Sken * 286331766Sken * @return Returns NULL. 287331766Sken */ 288331766Sken 289331766Skenvoid * 290331766Sken__ocs_d_wait_loop(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 291331766Sken{ 292331766Sken std_node_state_decl(); 293331766Sken 294331766Sken node_sm_trace(); 295331766Sken 296331766Sken switch(evt) { 297331766Sken case OCS_EVT_ENTER: 298331766Sken ocs_node_hold_frames(node); 299331766Sken break; 300331766Sken 301331766Sken case OCS_EVT_EXIT: 302331766Sken ocs_node_accept_frames(node); 303331766Sken break; 304331766Sken 305331766Sken case OCS_EVT_DOMAIN_ATTACH_OK: { 306331766Sken /* send PLOGI automatically if initiator */ 307331766Sken ocs_node_init_device(node, TRUE); 308331766Sken break; 309331766Sken } 310331766Sken default: 311331766Sken __ocs_d_common(__func__, ctx, evt, arg); 312331766Sken return NULL; 313331766Sken } 314331766Sken 315331766Sken return NULL; 316331766Sken} 317331766Sken 318331766Sken 319331766Sken 320331766Sken 321331766Sken/** 322331766Sken * @ingroup device_sm 323331766Sken * @brief state: wait for node resume event 324331766Sken * 325331766Sken * State is entered when a node is in I+T mode and sends a delete initiator/target 326331766Sken * call to the target-server/initiator-client and needs to wait for that work to complete. 327331766Sken * 328331766Sken * @param ctx Remote node state machine context. 329331766Sken * @param evt Event to process. 330331766Sken * @param arg per event optional argument 331331766Sken * 332331766Sken * @return returns NULL 333331766Sken */ 334331766Sken 335331766Skenvoid * 336331766Sken__ocs_d_wait_del_ini_tgt(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 337331766Sken{ 338331766Sken std_node_state_decl(); 339331766Sken 340331766Sken node_sm_trace(); 341331766Sken 342331766Sken switch(evt) { 343331766Sken case OCS_EVT_ENTER: 344331766Sken ocs_node_hold_frames(node); 345331766Sken /* Fall through */ 346331766Sken 347331766Sken case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY: 348331766Sken case OCS_EVT_ALL_CHILD_NODES_FREE: 349331766Sken /* These are expected events. */ 350331766Sken break; 351331766Sken 352331766Sken case OCS_EVT_NODE_DEL_INI_COMPLETE: 353331766Sken case OCS_EVT_NODE_DEL_TGT_COMPLETE: 354331766Sken ocs_node_transition(node, __ocs_d_wait_del_node, NULL); 355331766Sken break; 356331766Sken 357331766Sken case OCS_EVT_EXIT: 358331766Sken ocs_node_accept_frames(node); 359331766Sken break; 360331766Sken 361331766Sken case OCS_EVT_SRRS_ELS_REQ_FAIL: 362331766Sken /* Can happen as ELS IO IO's complete */ 363331766Sken ocs_assert(node->els_req_cnt, NULL); 364331766Sken node->els_req_cnt--; 365331766Sken break; 366331766Sken 367331766Sken /* ignore shutdown events as we're already in shutdown path */ 368331766Sken case OCS_EVT_SHUTDOWN: 369331766Sken /* have default shutdown event take precedence */ 370331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 371331766Sken /* fall through */ 372331766Sken case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO: 373331766Sken case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO: 374331766Sken node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 375331766Sken break; 376331766Sken case OCS_EVT_DOMAIN_ATTACH_OK: 377331766Sken /* don't care about domain_attach_ok */ 378331766Sken break; 379331766Sken default: 380331766Sken __ocs_d_common(__func__, ctx, evt, arg); 381331766Sken return NULL; 382331766Sken } 383331766Sken 384331766Sken return NULL; 385331766Sken} 386331766Sken 387331766Sken 388331766Sken/** 389331766Sken * @ingroup device_sm 390331766Sken * @brief state: Wait for node resume event. 391331766Sken * 392331766Sken * State is entered when a node sends a delete initiator/target call to the 393331766Sken * target-server/initiator-client and needs to wait for that work to complete. 394331766Sken * 395331766Sken * @param ctx Remote node state machine context. 396331766Sken * @param evt Event to process. 397331766Sken * @param arg Per event optional argument. 398331766Sken * 399331766Sken * @return Returns NULL. 400331766Sken */ 401331766Sken 402331766Skenvoid * 403331766Sken__ocs_d_wait_del_node(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 404331766Sken{ 405331766Sken std_node_state_decl(); 406331766Sken 407331766Sken node_sm_trace(); 408331766Sken 409331766Sken switch(evt) { 410331766Sken case OCS_EVT_ENTER: 411331766Sken ocs_node_hold_frames(node); 412331766Sken /* Fall through */ 413331766Sken 414331766Sken case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY: 415331766Sken case OCS_EVT_ALL_CHILD_NODES_FREE: 416331766Sken /* These are expected events. */ 417331766Sken break; 418331766Sken 419331766Sken case OCS_EVT_NODE_DEL_INI_COMPLETE: 420331766Sken case OCS_EVT_NODE_DEL_TGT_COMPLETE: 421331766Sken /* 422331766Sken * node has either been detached or is in the process of being detached, 423331766Sken * call common node's initiate cleanup function 424331766Sken */ 425331766Sken ocs_node_initiate_cleanup(node); 426331766Sken break; 427331766Sken 428331766Sken case OCS_EVT_EXIT: 429331766Sken ocs_node_accept_frames(node); 430331766Sken break; 431331766Sken 432331766Sken case OCS_EVT_SRRS_ELS_REQ_FAIL: 433331766Sken /* Can happen as ELS IO IO's complete */ 434331766Sken ocs_assert(node->els_req_cnt, NULL); 435331766Sken node->els_req_cnt--; 436331766Sken break; 437331766Sken 438331766Sken /* ignore shutdown events as we're already in shutdown path */ 439331766Sken case OCS_EVT_SHUTDOWN: 440331766Sken /* have default shutdown event take precedence */ 441331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 442331766Sken /* fall through */ 443331766Sken case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO: 444331766Sken case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO: 445331766Sken node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 446331766Sken break; 447331766Sken case OCS_EVT_DOMAIN_ATTACH_OK: 448331766Sken /* don't care about domain_attach_ok */ 449331766Sken break; 450331766Sken default: 451331766Sken __ocs_d_common(__func__, ctx, evt, arg); 452331766Sken return NULL; 453331766Sken } 454331766Sken 455331766Sken return NULL; 456331766Sken} 457331766Sken 458331766Sken 459331766Sken 460331766Sken/** 461331766Sken * @brief Save the OX_ID for sending LS_ACC sometime later. 462331766Sken * 463331766Sken * <h3 class="desc">Description</h3> 464331766Sken * When deferring the response to an ELS request, the OX_ID of the request 465331766Sken * is saved using this function. 466331766Sken * 467331766Sken * @param io Pointer to a SCSI IO object. 468331766Sken * @param hdr Pointer to the FC header. 469331766Sken * @param ls Defines the type of ELS to send: LS_ACC, LS_ACC for PLOGI; 470331766Sken * or LSS_ACC for PRLI. 471331766Sken * 472331766Sken * @return None. 473331766Sken */ 474331766Sken 475331766Skenvoid 476331766Skenocs_send_ls_acc_after_attach(ocs_io_t *io, fc_header_t *hdr, ocs_node_send_ls_acc_e ls) 477331766Sken{ 478331766Sken ocs_node_t *node = io->node; 479331766Sken uint16_t ox_id = ocs_be16toh(hdr->ox_id); 480331766Sken 481331766Sken ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_NONE); 482331766Sken 483331766Sken node->ls_acc_oxid = ox_id; 484331766Sken node->send_ls_acc = ls; 485331766Sken node->ls_acc_io = io; 486331766Sken node->ls_acc_did = fc_be24toh(hdr->d_id); 487331766Sken} 488331766Sken 489331766Sken/** 490331766Sken * @brief Process the PRLI payload. 491331766Sken * 492331766Sken * <h3 class="desc">Description</h3> 493331766Sken * The PRLI payload is processed; the initiator/target capabilities of the 494331766Sken * remote node are extracted and saved in the node object. 495331766Sken * 496331766Sken * @param node Pointer to the node object. 497331766Sken * @param prli Pointer to the PRLI payload. 498331766Sken * 499331766Sken * @return None. 500331766Sken */ 501331766Sken 502331766Skenvoid 503331766Skenocs_process_prli_payload(ocs_node_t *node, fc_prli_payload_t *prli) 504331766Sken{ 505331766Sken node->init = (ocs_be16toh(prli->service_params) & FC_PRLI_INITIATOR_FUNCTION) != 0; 506331766Sken node->targ = (ocs_be16toh(prli->service_params) & FC_PRLI_TARGET_FUNCTION) != 0; 507331766Sken node->fcp2device = (ocs_be16toh(prli->service_params) & FC_PRLI_RETRY) != 0; 508331766Sken node->fc_type = prli->type; 509331766Sken} 510331766Sken 511331766Sken/** 512331766Sken * @brief Process the ABTS. 513331766Sken * 514331766Sken * <h3 class="desc">Description</h3> 515331766Sken * Common code to process a received ABTS. If an active IO can be found 516331766Sken * that matches the OX_ID of the ABTS request, a call is made to the 517331766Sken * backend. Otherwise, a BA_ACC is returned to the initiator. 518331766Sken * 519331766Sken * @param io Pointer to a SCSI IO object. 520331766Sken * @param hdr Pointer to the FC header. 521331766Sken * 522331766Sken * @return Returns 0 on success, or a negative error value on failure. 523331766Sken */ 524331766Sken 525331766Skenstatic int32_t 526331766Skenocs_process_abts(ocs_io_t *io, fc_header_t *hdr) 527331766Sken{ 528331766Sken ocs_node_t *node = io->node; 529331766Sken ocs_t *ocs = node->ocs; 530331766Sken uint16_t ox_id = ocs_be16toh(hdr->ox_id); 531331766Sken uint16_t rx_id = ocs_be16toh(hdr->rx_id); 532331766Sken ocs_io_t *abortio; 533331766Sken 534331766Sken abortio = ocs_io_find_tgt_io(ocs, node, ox_id, rx_id); 535331766Sken 536331766Sken /* If an IO was found, attempt to take a reference on it */ 537331766Sken if (abortio != NULL && (ocs_ref_get_unless_zero(&abortio->ref) != 0)) { 538331766Sken 539331766Sken /* Got a reference on the IO. Hold it until backend is notified below */ 540331766Sken node_printf(node, "Abort request: ox_id [%04x] rx_id [%04x]\n", 541331766Sken ox_id, rx_id); 542331766Sken 543331766Sken /* 544331766Sken * Save the ox_id for the ABTS as the init_task_tag in our manufactured 545331766Sken * TMF IO object 546331766Sken */ 547331766Sken io->display_name = "abts"; 548331766Sken io->init_task_tag = ox_id; 549331766Sken /* don't set tgt_task_tag, don't want to confuse with XRI */ 550331766Sken 551331766Sken /* 552331766Sken * Save the rx_id from the ABTS as it is needed for the BLS response, 553331766Sken * regardless of the IO context's rx_id 554331766Sken */ 555331766Sken io->abort_rx_id = rx_id; 556331766Sken 557331766Sken /* Call target server command abort */ 558331766Sken io->tmf_cmd = OCS_SCSI_TMF_ABORT_TASK; 559331766Sken ocs_scsi_recv_tmf(io, abortio->tgt_io.lun, OCS_SCSI_TMF_ABORT_TASK, abortio, 0); 560331766Sken 561331766Sken /* 562331766Sken * Backend will have taken an additional reference on the IO if needed; 563331766Sken * done with current reference. 564331766Sken */ 565331766Sken ocs_ref_put(&abortio->ref); /* ocs_ref_get(): same function */ 566331766Sken } else { 567331766Sken /* 568331766Sken * Either IO was not found or it has been freed between finding it 569331766Sken * and attempting to get the reference, 570331766Sken */ 571331766Sken node_printf(node, "Abort request: ox_id [%04x], IO not found (exists=%d)\n", 572331766Sken ox_id, (abortio != NULL)); 573331766Sken 574331766Sken /* Send a BA_ACC */ 575331766Sken ocs_bls_send_acc_hdr(io, hdr); 576331766Sken } 577331766Sken return 0; 578331766Sken} 579331766Sken 580331766Sken/** 581331766Sken * @ingroup device_sm 582331766Sken * @brief Device node state machine: Wait for the PLOGI accept to complete. 583331766Sken * 584331766Sken * @param ctx Remote node state machine context. 585331766Sken * @param evt Event to process. 586331766Sken * @param arg Per event optional argument. 587331766Sken * 588331766Sken * @return Returns NULL. 589331766Sken */ 590331766Sken 591331766Skenvoid * 592331766Sken__ocs_d_wait_plogi_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 593331766Sken{ 594331766Sken std_node_state_decl(); 595331766Sken 596331766Sken node_sm_trace(); 597331766Sken 598331766Sken switch(evt) { 599331766Sken case OCS_EVT_ENTER: 600331766Sken ocs_node_hold_frames(node); 601331766Sken break; 602331766Sken 603331766Sken case OCS_EVT_EXIT: 604331766Sken ocs_node_accept_frames(node); 605331766Sken break; 606331766Sken 607331766Sken case OCS_EVT_SRRS_ELS_CMPL_FAIL: 608331766Sken ocs_assert(node->els_cmpl_cnt, NULL); 609331766Sken node->els_cmpl_cnt--; 610331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 611331766Sken ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL); 612331766Sken break; 613331766Sken 614331766Sken case OCS_EVT_SRRS_ELS_CMPL_OK: /* PLOGI ACC completions */ 615331766Sken ocs_assert(node->els_cmpl_cnt, NULL); 616331766Sken node->els_cmpl_cnt--; 617331766Sken ocs_node_transition(node, __ocs_d_port_logged_in, NULL); 618331766Sken break; 619331766Sken 620331766Sken default: 621331766Sken __ocs_d_common(__func__, ctx, evt, arg); 622331766Sken return NULL; 623331766Sken } 624331766Sken 625331766Sken return NULL; 626331766Sken} 627331766Sken 628331766Sken/** 629331766Sken * @ingroup device_sm 630331766Sken * @brief Device node state machine: Wait for the LOGO response. 631331766Sken * 632331766Sken * @param ctx Remote node state machine context. 633331766Sken * @param evt Event to process. 634331766Sken * @param arg Per event optional argument. 635331766Sken * 636331766Sken * @return Returns NULL. 637331766Sken */ 638331766Sken 639331766Skenvoid * 640331766Sken__ocs_d_wait_logo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 641331766Sken{ 642331766Sken std_node_state_decl(); 643331766Sken 644331766Sken node_sm_trace(); 645331766Sken 646331766Sken switch(evt) { 647331766Sken case OCS_EVT_ENTER: 648331766Sken /* TODO: may want to remove this; 649331766Sken * if we'll want to know about PLOGI */ 650331766Sken ocs_node_hold_frames(node); 651331766Sken break; 652331766Sken 653331766Sken case OCS_EVT_EXIT: 654331766Sken ocs_node_accept_frames(node); 655331766Sken break; 656331766Sken 657331766Sken case OCS_EVT_SRRS_ELS_REQ_OK: 658331766Sken case OCS_EVT_SRRS_ELS_REQ_RJT: 659331766Sken case OCS_EVT_SRRS_ELS_REQ_FAIL: 660331766Sken /* LOGO response received, sent shutdown */ 661331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_LOGO, __ocs_d_common, __func__)) { 662331766Sken return NULL; 663331766Sken } 664331766Sken ocs_assert(node->els_req_cnt, NULL); 665331766Sken node->els_req_cnt--; 666331766Sken node_printf(node, "LOGO sent (evt=%s), shutdown node\n", ocs_sm_event_name(evt)); 667331766Sken /* sm: post explicit logout */ 668331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL); 669331766Sken break; 670331766Sken 671331766Sken /* TODO: PLOGI: abort LOGO and process PLOGI? (SHUTDOWN_EXPLICIT/IMPLICIT_LOGO?) */ 672331766Sken 673331766Sken default: 674331766Sken __ocs_d_common(__func__, ctx, evt, arg); 675331766Sken return NULL; 676331766Sken } 677331766Sken return NULL; 678331766Sken} 679331766Sken 680331766Sken 681331766Sken/** 682331766Sken * @ingroup device_sm 683331766Sken * @brief Device node state machine: Wait for the PRLO response. 684331766Sken * 685331766Sken * @param ctx Remote node state machine context. 686331766Sken * @param evt Event to process. 687331766Sken * @param arg Per event optional argument. 688331766Sken * 689331766Sken * @return Returns NULL. 690331766Sken */ 691331766Sken 692331766Skenvoid * 693331766Sken__ocs_d_wait_prlo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 694331766Sken{ 695331766Sken std_node_state_decl(); 696331766Sken 697331766Sken node_sm_trace(); 698331766Sken 699331766Sken switch(evt) { 700331766Sken case OCS_EVT_ENTER: 701331766Sken ocs_node_hold_frames(node); 702331766Sken break; 703331766Sken 704331766Sken case OCS_EVT_EXIT: 705331766Sken ocs_node_accept_frames(node); 706331766Sken break; 707331766Sken 708331766Sken case OCS_EVT_SRRS_ELS_REQ_OK: 709331766Sken case OCS_EVT_SRRS_ELS_REQ_RJT: 710331766Sken case OCS_EVT_SRRS_ELS_REQ_FAIL: 711331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLO, __ocs_d_common, __func__)) { 712331766Sken return NULL; 713331766Sken } 714331766Sken ocs_assert(node->els_req_cnt, NULL); 715331766Sken node->els_req_cnt--; 716331766Sken node_printf(node, "PRLO sent (evt=%s)\n", ocs_sm_event_name(evt)); 717331766Sken ocs_node_transition(node, __ocs_d_port_logged_in, NULL); 718331766Sken break; 719331766Sken 720331766Sken default: 721331766Sken __ocs_node_common(__func__, ctx, evt, arg); 722331766Sken return NULL; 723331766Sken } 724331766Sken return NULL; 725331766Sken} 726331766Sken 727331766Sken 728331766Sken/** 729331766Sken * @brief Initialize device node. 730331766Sken * 731331766Sken * Initialize device node. If a node is an initiator, then send a PLOGI and transition 732331766Sken * to __ocs_d_wait_plogi_rsp, otherwise transition to __ocs_d_init. 733331766Sken * 734331766Sken * @param node Pointer to the node object. 735331766Sken * @param send_plogi Boolean indicating to send PLOGI command or not. 736331766Sken * 737331766Sken * @return none 738331766Sken */ 739331766Sken 740331766Skenvoid 741331766Skenocs_node_init_device(ocs_node_t *node, int send_plogi) 742331766Sken{ 743331766Sken node->send_plogi = send_plogi; 744331766Sken if ((node->ocs->nodedb_mask & OCS_NODEDB_PAUSE_NEW_NODES) && !FC_ADDR_IS_DOMAIN_CTRL(node->rnode.fc_id)) { 745331766Sken node->nodedb_state = __ocs_d_init; 746331766Sken ocs_node_transition(node, __ocs_node_paused, NULL); 747331766Sken } else { 748331766Sken ocs_node_transition(node, __ocs_d_init, NULL); 749331766Sken } 750331766Sken} 751331766Sken 752331766Sken/** 753331766Sken * @ingroup device_sm 754331766Sken * @brief Device node state machine: Initial node state for an initiator or a target. 755331766Sken * 756331766Sken * <h3 class="desc">Description</h3> 757331766Sken * This state is entered when a node is instantiated, either having been 758331766Sken * discovered from a name services query, or having received a PLOGI/FLOGI. 759331766Sken * 760331766Sken * @param ctx Remote node state machine context. 761331766Sken * @param evt Event to process. 762331766Sken * @param arg Per event optional argument. 763331766Sken * - OCS_EVT_ENTER: (uint8_t *) - 1 to send a PLOGI on 764331766Sken * entry (initiator-only); 0 indicates a PLOGI is 765331766Sken * not sent on entry (initiator-only). Not applicable for a target. 766331766Sken * 767331766Sken * @return Returns NULL. 768331766Sken */ 769331766Sken 770331766Skenvoid * 771331766Sken__ocs_d_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 772331766Sken{ 773331766Sken int32_t rc; 774331766Sken ocs_node_cb_t *cbdata = arg; 775331766Sken std_node_state_decl(); 776331766Sken 777331766Sken node_sm_trace(); 778331766Sken 779331766Sken switch(evt) { 780331766Sken case OCS_EVT_ENTER: 781331766Sken /* check if we need to send PLOGI */ 782331766Sken if (node->send_plogi) { 783331766Sken /* only send if we have initiator capability, and domain is attached */ 784331766Sken if (node->sport->enable_ini && node->sport->domain->attached) { 785331766Sken ocs_send_plogi(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, 786331766Sken OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 787331766Sken ocs_node_transition(node, __ocs_d_wait_plogi_rsp, NULL); 788331766Sken } else { 789331766Sken node_printf(node, "not sending plogi sport.ini=%d, domain attached=%d\n", 790331766Sken node->sport->enable_ini, node->sport->domain->attached); 791331766Sken } 792331766Sken } 793331766Sken break; 794331766Sken case OCS_EVT_PLOGI_RCVD: { 795331766Sken /* T, or I+T */ 796331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 797331766Sken uint32_t d_id = fc_be24toh(hdr->d_id); 798331766Sken 799331766Sken ocs_node_save_sparms(node, cbdata->payload->dma.virt); 800331766Sken ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI); 801331766Sken 802331766Sken /* domain already attached */ 803331766Sken if (node->sport->domain->attached) { 804331766Sken rc = ocs_node_attach(node); 805331766Sken ocs_node_transition(node, __ocs_d_wait_node_attach, NULL); 806331766Sken if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 807331766Sken ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 808331766Sken } 809331766Sken break; 810331766Sken } 811331766Sken 812331766Sken /* domain not attached; several possibilities: */ 813331766Sken switch (node->sport->topology) { 814331766Sken case OCS_SPORT_TOPOLOGY_P2P: 815331766Sken /* we're not attached and sport is p2p, need to attach */ 816331766Sken ocs_domain_attach(node->sport->domain, d_id); 817331766Sken ocs_node_transition(node, __ocs_d_wait_domain_attach, NULL); 818331766Sken break; 819331766Sken case OCS_SPORT_TOPOLOGY_FABRIC: 820331766Sken /* we're not attached and sport is fabric, domain attach should have 821331766Sken * already been requested as part of the fabric state machine, wait for it 822331766Sken */ 823331766Sken ocs_node_transition(node, __ocs_d_wait_domain_attach, NULL); 824331766Sken break; 825331766Sken case OCS_SPORT_TOPOLOGY_UNKNOWN: 826331766Sken /* Two possibilities: 827331766Sken * 1. received a PLOGI before our FLOGI has completed (possible since 828331766Sken * completion comes in on another CQ), thus we don't know what we're 829331766Sken * connected to yet; transition to a state to wait for the fabric 830331766Sken * node to tell us; 831331766Sken * 2. PLOGI received before link went down and we haven't performed 832331766Sken * domain attach yet. 833331766Sken * Note: we cannot distinguish between 1. and 2. so have to assume PLOGI 834331766Sken * was received after link back up. 835331766Sken */ 836331766Sken node_printf(node, "received PLOGI, with unknown topology did=0x%x\n", d_id); 837331766Sken ocs_node_transition(node, __ocs_d_wait_topology_notify, NULL); 838331766Sken break; 839331766Sken default: 840331766Sken node_printf(node, "received PLOGI, with unexpectd topology %d\n", 841331766Sken node->sport->topology); 842331766Sken ocs_assert(FALSE, NULL); 843331766Sken break; 844331766Sken } 845331766Sken break; 846331766Sken } 847331766Sken 848331766Sken case OCS_EVT_FDISC_RCVD: { 849331766Sken __ocs_d_common(__func__, ctx, evt, arg); 850331766Sken break; 851331766Sken } 852331766Sken 853331766Sken case OCS_EVT_FLOGI_RCVD: { 854331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 855331766Sken 856331766Sken /* this better be coming from an NPort */ 857331766Sken ocs_assert(ocs_rnode_is_nport(cbdata->payload->dma.virt), NULL); 858331766Sken 859331766Sken /* sm: save sparams, send FLOGI acc */ 860331766Sken ocs_domain_save_sparms(node->sport->domain, cbdata->payload->dma.virt); 861331766Sken 862331766Sken /* send FC LS_ACC response, override s_id */ 863331766Sken ocs_fabric_set_topology(node, OCS_SPORT_TOPOLOGY_P2P); 864331766Sken ocs_send_flogi_p2p_acc(cbdata->io, ocs_be16toh(hdr->ox_id), fc_be24toh(hdr->d_id), NULL, NULL); 865331766Sken if (ocs_p2p_setup(node->sport)) { 866331766Sken node_printf(node, "p2p setup failed, shutting down node\n"); 867331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL); 868331766Sken } else { 869331766Sken ocs_node_transition(node, __ocs_p2p_wait_flogi_acc_cmpl, NULL); 870331766Sken } 871331766Sken 872331766Sken break; 873331766Sken } 874331766Sken 875331766Sken case OCS_EVT_LOGO_RCVD: { 876331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 877331766Sken 878331766Sken if (!node->sport->domain->attached) { 879331766Sken /* most likely a frame left over from before a link down; drop and 880331766Sken * shut node down w/ "explicit logout" so pending frames are processed */ 881331766Sken node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt)); 882331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL); 883331766Sken break; 884331766Sken } 885331766Sken ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 886331766Sken ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL); 887331766Sken break; 888331766Sken } 889331766Sken 890331766Sken case OCS_EVT_PRLI_RCVD: 891331766Sken case OCS_EVT_PRLO_RCVD: 892331766Sken case OCS_EVT_PDISC_RCVD: 893331766Sken case OCS_EVT_ADISC_RCVD: 894331766Sken case OCS_EVT_RSCN_RCVD: { 895331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 896331766Sken if (!node->sport->domain->attached) { 897331766Sken /* most likely a frame left over from before a link down; drop and 898331766Sken * shut node down w/ "explicit logout" so pending frames are processed */ 899331766Sken node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt)); 900331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL); 901331766Sken break; 902331766Sken } 903331766Sken node_printf(node, "%s received, sending reject\n", ocs_sm_event_name(evt)); 904331766Sken ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), 905331766Sken FC_REASON_UNABLE_TO_PERFORM, FC_EXPL_NPORT_LOGIN_REQUIRED, 0, 906331766Sken NULL, NULL); 907331766Sken 908331766Sken break; 909331766Sken } 910331766Sken 911331766Sken case OCS_EVT_FCP_CMD_RCVD: { 912331766Sken /* note: problem, we're now expecting an ELS REQ completion 913331766Sken * from both the LOGO and PLOGI */ 914331766Sken if (!node->sport->domain->attached) { 915331766Sken /* most likely a frame left over from before a link down; drop and 916331766Sken * shut node down w/ "explicit logout" so pending frames are processed */ 917331766Sken node_printf(node, "%s domain not attached, dropping\n", ocs_sm_event_name(evt)); 918331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL); 919331766Sken break; 920331766Sken } 921331766Sken 922331766Sken /* Send LOGO */ 923331766Sken node_printf(node, "FCP_CMND received, send LOGO\n"); 924331766Sken if (ocs_send_logo(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, 0, NULL, NULL) == NULL) { 925331766Sken /* failed to send LOGO, go ahead and cleanup node anyways */ 926331766Sken node_printf(node, "Failed to send LOGO\n"); 927331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL); 928331766Sken } else { 929331766Sken /* sent LOGO, wait for response */ 930331766Sken ocs_node_transition(node, __ocs_d_wait_logo_rsp, NULL); 931331766Sken } 932331766Sken break; 933331766Sken } 934331766Sken case OCS_EVT_DOMAIN_ATTACH_OK: 935331766Sken /* don't care about domain_attach_ok */ 936331766Sken break; 937331766Sken 938331766Sken default: 939331766Sken __ocs_d_common(__func__, ctx, evt, arg); 940331766Sken return NULL; 941331766Sken } 942331766Sken 943331766Sken return NULL; 944331766Sken} 945331766Sken 946331766Sken/** 947331766Sken * @ingroup device_sm 948331766Sken * @brief Device node state machine: Wait on a response for a sent PLOGI. 949331766Sken * 950331766Sken * <h3 class="desc">Description</h3> 951331766Sken * State is entered when an initiator-capable node has sent 952331766Sken * a PLOGI and is waiting for a response. 953331766Sken * 954331766Sken * @param ctx Remote node state machine context. 955331766Sken * @param evt Event to process. 956331766Sken * @param arg Per event optional argument. 957331766Sken * 958331766Sken * @return Returns NULL. 959331766Sken */ 960331766Sken 961331766Skenvoid * 962331766Sken__ocs_d_wait_plogi_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 963331766Sken{ 964331766Sken int32_t rc; 965331766Sken ocs_node_cb_t *cbdata = arg; 966331766Sken std_node_state_decl(); 967331766Sken 968331766Sken node_sm_trace(); 969331766Sken 970331766Sken switch(evt) { 971331766Sken case OCS_EVT_PLOGI_RCVD: { 972331766Sken /* T, or I+T */ 973331766Sken /* received PLOGI with svc parms, go ahead and attach node 974331766Sken * when PLOGI that was sent ultimately completes, it'll be a no-op 975331766Sken */ 976331766Sken 977331766Sken /* TODO: there is an outstanding PLOGI sent, can we set a flag 978331766Sken * to indicate that we don't want to retry it if it times out? */ 979331766Sken ocs_node_save_sparms(node, cbdata->payload->dma.virt); 980331766Sken ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI); 981331766Sken /* sm: domain->attached / ocs_node_attach */ 982331766Sken rc = ocs_node_attach(node); 983331766Sken ocs_node_transition(node, __ocs_d_wait_node_attach, NULL); 984331766Sken if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 985331766Sken ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 986331766Sken } 987331766Sken break; 988331766Sken } 989331766Sken 990331766Sken case OCS_EVT_PRLI_RCVD: 991331766Sken /* I, or I+T */ 992331766Sken /* sent PLOGI and before completion was seen, received the 993331766Sken * PRLI from the remote node (WCQEs and RCQEs come in on 994331766Sken * different queues and order of processing cannot be assumed) 995331766Sken * Save OXID so PRLI can be sent after the attach and continue 996331766Sken * to wait for PLOGI response 997331766Sken */ 998331766Sken ocs_process_prli_payload(node, cbdata->payload->dma.virt); 999331766Sken if (ocs->fc_type == node->fc_type) { 1000331766Sken ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PRLI); 1001331766Sken ocs_node_transition(node, __ocs_d_wait_plogi_rsp_recvd_prli, NULL); 1002331766Sken } else { 1003331766Sken /* TODO this need to be looked at. What do we do here ? */ 1004331766Sken } 1005331766Sken break; 1006331766Sken 1007331766Sken /* TODO this need to be looked at. we could very well be logged in */ 1008331766Sken case OCS_EVT_LOGO_RCVD: /* why don't we do a shutdown here?? */ 1009331766Sken case OCS_EVT_PRLO_RCVD: 1010331766Sken case OCS_EVT_PDISC_RCVD: 1011331766Sken case OCS_EVT_FDISC_RCVD: 1012331766Sken case OCS_EVT_ADISC_RCVD: 1013331766Sken case OCS_EVT_RSCN_RCVD: 1014331766Sken case OCS_EVT_SCR_RCVD: { 1015331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1016331766Sken node_printf(node, "%s received, sending reject\n", ocs_sm_event_name(evt)); 1017331766Sken ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), 1018331766Sken FC_REASON_UNABLE_TO_PERFORM, FC_EXPL_NPORT_LOGIN_REQUIRED, 0, 1019331766Sken NULL, NULL); 1020331766Sken 1021331766Sken break; 1022331766Sken } 1023331766Sken 1024331766Sken case OCS_EVT_SRRS_ELS_REQ_OK: /* PLOGI response received */ 1025331766Sken /* Completion from PLOGI sent */ 1026331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) { 1027331766Sken return NULL; 1028331766Sken } 1029331766Sken ocs_assert(node->els_req_cnt, NULL); 1030331766Sken node->els_req_cnt--; 1031331766Sken /* sm: save sparams, ocs_node_attach */ 1032331766Sken ocs_node_save_sparms(node, cbdata->els->els_rsp.virt); 1033331766Sken ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL, 1034331766Sken ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 1035331766Sken rc = ocs_node_attach(node); 1036331766Sken ocs_node_transition(node, __ocs_d_wait_node_attach, NULL); 1037331766Sken if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 1038331766Sken ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 1039331766Sken } 1040331766Sken break; 1041331766Sken 1042331766Sken case OCS_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */ 1043331766Sken /* PLOGI failed, shutdown the node */ 1044331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) { 1045331766Sken return NULL; 1046331766Sken } 1047331766Sken ocs_assert(node->els_req_cnt, NULL); 1048331766Sken node->els_req_cnt--; 1049331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL); 1050331766Sken break; 1051331766Sken 1052331766Sken case OCS_EVT_SRRS_ELS_REQ_RJT: /* Our PLOGI was rejected, this is ok in some cases */ 1053331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) { 1054331766Sken return NULL; 1055331766Sken } 1056331766Sken ocs_assert(node->els_req_cnt, NULL); 1057331766Sken node->els_req_cnt--; 1058331766Sken break; 1059331766Sken 1060331766Sken case OCS_EVT_FCP_CMD_RCVD: { 1061331766Sken /* not logged in yet and outstanding PLOGI so don't send LOGO, 1062331766Sken * just drop 1063331766Sken */ 1064331766Sken node_printf(node, "FCP_CMND received, drop\n"); 1065331766Sken break; 1066331766Sken } 1067331766Sken 1068331766Sken default: 1069331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1070331766Sken return NULL; 1071331766Sken } 1072331766Sken 1073331766Sken return NULL; 1074331766Sken} 1075331766Sken 1076331766Sken/** 1077331766Sken * @ingroup device_sm 1078331766Sken * @brief Device node state machine: Waiting on a response for a 1079331766Sken * sent PLOGI. 1080331766Sken * 1081331766Sken * <h3 class="desc">Description</h3> 1082331766Sken * State is entered when an initiator-capable node has sent 1083331766Sken * a PLOGI and is waiting for a response. Before receiving the 1084331766Sken * response, a PRLI was received, implying that the PLOGI was 1085331766Sken * successful. 1086331766Sken * 1087331766Sken * @param ctx Remote node state machine context. 1088331766Sken * @param evt Event to process. 1089331766Sken * @param arg Per event optional argument. 1090331766Sken * 1091331766Sken * @return Returns NULL. 1092331766Sken */ 1093331766Sken 1094331766Skenvoid * 1095331766Sken__ocs_d_wait_plogi_rsp_recvd_prli(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1096331766Sken{ 1097331766Sken int32_t rc; 1098331766Sken ocs_node_cb_t *cbdata = arg; 1099331766Sken std_node_state_decl(); 1100331766Sken 1101331766Sken node_sm_trace(); 1102331766Sken 1103331766Sken switch(evt) { 1104331766Sken case OCS_EVT_ENTER: 1105331766Sken /* 1106331766Sken * Since we've received a PRLI, we have a port login and will 1107331766Sken * just need to wait for the PLOGI response to do the node 1108331766Sken * attach and then we can send the LS_ACC for the PRLI. If, 1109331766Sken * during this time, we receive FCP_CMNDs (which is possible 1110331766Sken * since we've already sent a PRLI and our peer may have accepted). 1111331766Sken * At this time, we are not waiting on any other unsolicited 1112331766Sken * frames to continue with the login process. Thus, it will not 1113331766Sken * hurt to hold frames here. 1114331766Sken */ 1115331766Sken ocs_node_hold_frames(node); 1116331766Sken break; 1117331766Sken 1118331766Sken case OCS_EVT_EXIT: 1119331766Sken ocs_node_accept_frames(node); 1120331766Sken break; 1121331766Sken 1122331766Sken case OCS_EVT_SRRS_ELS_REQ_OK: /* PLOGI response received */ 1123331766Sken /* Completion from PLOGI sent */ 1124331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) { 1125331766Sken return NULL; 1126331766Sken } 1127331766Sken ocs_assert(node->els_req_cnt, NULL); 1128331766Sken node->els_req_cnt--; 1129331766Sken /* sm: save sparams, ocs_node_attach */ 1130331766Sken ocs_node_save_sparms(node, cbdata->els->els_rsp.virt); 1131331766Sken ocs_display_sparams(node->display_name, "plogi rcvd resp", 0, NULL, 1132331766Sken ((uint8_t*)cbdata->els->els_rsp.virt) + 4); 1133331766Sken rc = ocs_node_attach(node); 1134331766Sken ocs_node_transition(node, __ocs_d_wait_node_attach, NULL); 1135331766Sken if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 1136331766Sken ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 1137331766Sken } 1138331766Sken break; 1139331766Sken 1140331766Sken case OCS_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */ 1141331766Sken case OCS_EVT_SRRS_ELS_REQ_RJT: 1142331766Sken /* PLOGI failed, shutdown the node */ 1143331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PLOGI, __ocs_d_common, __func__)) { 1144331766Sken return NULL; 1145331766Sken } 1146331766Sken ocs_assert(node->els_req_cnt, NULL); 1147331766Sken node->els_req_cnt--; 1148331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL); 1149331766Sken break; 1150331766Sken 1151331766Sken default: 1152331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1153331766Sken return NULL; 1154331766Sken } 1155331766Sken 1156331766Sken return NULL; 1157331766Sken} 1158331766Sken 1159331766Sken/** 1160331766Sken * @ingroup device_sm 1161331766Sken * @brief Device node state machine: Wait for a domain attach. 1162331766Sken * 1163331766Sken * <h3 class="desc">Description</h3> 1164331766Sken * Waits for a domain-attach complete ok event. 1165331766Sken * 1166331766Sken * @param ctx Remote node state machine context. 1167331766Sken * @param evt Event to process. 1168331766Sken * @param arg Per event optional argument. 1169331766Sken * 1170331766Sken * @return Returns NULL. 1171331766Sken */ 1172331766Sken 1173331766Skenvoid * 1174331766Sken__ocs_d_wait_domain_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1175331766Sken{ 1176331766Sken int32_t rc; 1177331766Sken std_node_state_decl(); 1178331766Sken 1179331766Sken node_sm_trace(); 1180331766Sken 1181331766Sken switch(evt) { 1182331766Sken case OCS_EVT_ENTER: 1183331766Sken ocs_node_hold_frames(node); 1184331766Sken break; 1185331766Sken 1186331766Sken case OCS_EVT_EXIT: 1187331766Sken ocs_node_accept_frames(node); 1188331766Sken break; 1189331766Sken 1190331766Sken case OCS_EVT_DOMAIN_ATTACH_OK: 1191331766Sken ocs_assert(node->sport->domain->attached, NULL); 1192331766Sken /* sm: ocs_node_attach */ 1193331766Sken rc = ocs_node_attach(node); 1194331766Sken ocs_node_transition(node, __ocs_d_wait_node_attach, NULL); 1195331766Sken if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 1196331766Sken ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 1197331766Sken } 1198331766Sken break; 1199331766Sken 1200331766Sken default: 1201331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1202331766Sken return NULL; 1203331766Sken } 1204331766Sken return NULL; 1205331766Sken} 1206331766Sken 1207331766Sken/** 1208331766Sken * @ingroup device_sm 1209331766Sken * @brief Device node state machine: Wait for topology 1210331766Sken * notification 1211331766Sken * 1212331766Sken * <h3 class="desc">Description</h3> 1213331766Sken * Waits for topology notification from fabric node, then 1214331766Sken * attaches domain and node. 1215331766Sken * 1216331766Sken * @param ctx Remote node state machine context. 1217331766Sken * @param evt Event to process. 1218331766Sken * @param arg Per event optional argument. 1219331766Sken * 1220331766Sken * @return Returns NULL. 1221331766Sken */ 1222331766Sken 1223331766Skenvoid * 1224331766Sken__ocs_d_wait_topology_notify(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1225331766Sken{ 1226331766Sken int32_t rc; 1227331766Sken std_node_state_decl(); 1228331766Sken 1229331766Sken node_sm_trace(); 1230331766Sken 1231331766Sken switch(evt) { 1232331766Sken case OCS_EVT_ENTER: 1233331766Sken ocs_node_hold_frames(node); 1234331766Sken break; 1235331766Sken 1236331766Sken case OCS_EVT_EXIT: 1237331766Sken ocs_node_accept_frames(node); 1238331766Sken break; 1239331766Sken 1240331766Sken case OCS_EVT_SPORT_TOPOLOGY_NOTIFY: { 1241360415Sbrooks ocs_sport_topology_e topology = (ocs_sport_topology_e)(uintptr_t)arg; 1242331766Sken ocs_assert(!node->sport->domain->attached, NULL); 1243331766Sken ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI, NULL); 1244331766Sken node_printf(node, "topology notification, topology=%d\n", topology); 1245331766Sken 1246331766Sken /* At the time the PLOGI was received, the topology was unknown, 1247331766Sken * so we didn't know which node would perform the domain attach: 1248331766Sken * 1. The node from which the PLOGI was sent (p2p) or 1249331766Sken * 2. The node to which the FLOGI was sent (fabric). 1250331766Sken */ 1251331766Sken if (topology == OCS_SPORT_TOPOLOGY_P2P) { 1252331766Sken /* if this is p2p, need to attach to the domain using the 1253331766Sken * d_id from the PLOGI received 1254331766Sken */ 1255331766Sken ocs_domain_attach(node->sport->domain, node->ls_acc_did); 1256331766Sken } 1257331766Sken /* else, if this is fabric, the domain attach should be performed 1258331766Sken * by the fabric node (node sending FLOGI); just wait for attach 1259331766Sken * to complete 1260331766Sken */ 1261331766Sken 1262331766Sken ocs_node_transition(node, __ocs_d_wait_domain_attach, NULL); 1263331766Sken break; 1264331766Sken } 1265331766Sken case OCS_EVT_DOMAIN_ATTACH_OK: 1266331766Sken ocs_assert(node->sport->domain->attached, NULL); 1267331766Sken node_printf(node, "domain attach ok\n"); 1268331766Sken /*sm: ocs_node_attach */ 1269331766Sken rc = ocs_node_attach(node); 1270331766Sken ocs_node_transition(node, __ocs_d_wait_node_attach, NULL); 1271331766Sken if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 1272331766Sken ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 1273331766Sken } 1274331766Sken break; 1275331766Sken 1276331766Sken default: 1277331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1278331766Sken return NULL; 1279331766Sken } 1280331766Sken return NULL; 1281331766Sken} 1282331766Sken 1283331766Sken/** 1284331766Sken * @ingroup device_sm 1285331766Sken * @brief Device node state machine: Wait for a node attach when found by a remote node. 1286331766Sken * 1287331766Sken * @param ctx Remote node state machine context. 1288331766Sken * @param evt Event to process. 1289331766Sken * @param arg Per event optional argument. 1290331766Sken * 1291331766Sken * @return Returns NULL. 1292331766Sken */ 1293331766Sken 1294331766Skenvoid * 1295331766Sken__ocs_d_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1296331766Sken{ 1297331766Sken std_node_state_decl(); 1298331766Sken 1299331766Sken node_sm_trace(); 1300331766Sken 1301331766Sken switch(evt) { 1302331766Sken case OCS_EVT_ENTER: 1303331766Sken ocs_node_hold_frames(node); 1304331766Sken break; 1305331766Sken 1306331766Sken case OCS_EVT_EXIT: 1307331766Sken ocs_node_accept_frames(node); 1308331766Sken break; 1309331766Sken 1310331766Sken case OCS_EVT_NODE_ATTACH_OK: 1311331766Sken node->attached = TRUE; 1312331766Sken switch (node->send_ls_acc) { 1313331766Sken case OCS_NODE_SEND_LS_ACC_PLOGI: { 1314331766Sken /* sm: send_plogi_acc is set / send PLOGI acc */ 1315331766Sken /* Normal case for T, or I+T */ 1316331766Sken ocs_send_plogi_acc(node->ls_acc_io, node->ls_acc_oxid, NULL, NULL); 1317331766Sken ocs_node_transition(node, __ocs_d_wait_plogi_acc_cmpl, NULL); 1318331766Sken node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE; 1319331766Sken node->ls_acc_io = NULL; 1320331766Sken break; 1321331766Sken } 1322331766Sken case OCS_NODE_SEND_LS_ACC_PRLI: { 1323331766Sken ocs_d_send_prli_rsp(node->ls_acc_io, node->ls_acc_oxid); 1324331766Sken node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE; 1325331766Sken node->ls_acc_io = NULL; 1326331766Sken break; 1327331766Sken } 1328331766Sken case OCS_NODE_SEND_LS_ACC_NONE: 1329331766Sken default: 1330331766Sken /* Normal case for I */ 1331331766Sken /* sm: send_plogi_acc is not set / send PLOGI acc */ 1332331766Sken ocs_node_transition(node, __ocs_d_port_logged_in, NULL); 1333331766Sken break; 1334331766Sken } 1335331766Sken break; 1336331766Sken 1337331766Sken case OCS_EVT_NODE_ATTACH_FAIL: 1338331766Sken /* node attach failed, shutdown the node */ 1339331766Sken node->attached = FALSE; 1340331766Sken node_printf(node, "node attach failed\n"); 1341331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1342331766Sken ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL); 1343331766Sken break; 1344331766Sken 1345331766Sken /* Handle shutdown events */ 1346331766Sken case OCS_EVT_SHUTDOWN: 1347331766Sken node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 1348331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1349331766Sken ocs_node_transition(node, __ocs_d_wait_attach_evt_shutdown, NULL); 1350331766Sken break; 1351331766Sken case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO: 1352331766Sken node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 1353331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_EXPLICIT_LOGO; 1354331766Sken ocs_node_transition(node, __ocs_d_wait_attach_evt_shutdown, NULL); 1355331766Sken break; 1356331766Sken case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO: 1357331766Sken node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 1358331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_IMPLICIT_LOGO; 1359331766Sken ocs_node_transition(node, __ocs_d_wait_attach_evt_shutdown, NULL); 1360331766Sken break; 1361331766Sken default: 1362331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1363331766Sken return NULL; 1364331766Sken } 1365331766Sken 1366331766Sken return NULL; 1367331766Sken} 1368331766Sken 1369331766Sken/** 1370331766Sken * @ingroup device_sm 1371331766Sken * @brief Device node state machine: Wait for a node/domain 1372331766Sken * attach then shutdown node. 1373331766Sken * 1374331766Sken * @param ctx Remote node state machine context. 1375331766Sken * @param evt Event to process. 1376331766Sken * @param arg Per event optional argument. 1377331766Sken * 1378331766Sken * @return Returns NULL. 1379331766Sken */ 1380331766Sken 1381331766Skenvoid * 1382331766Sken__ocs_d_wait_attach_evt_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1383331766Sken{ 1384331766Sken std_node_state_decl(); 1385331766Sken 1386331766Sken node_sm_trace(); 1387331766Sken 1388331766Sken switch(evt) { 1389331766Sken case OCS_EVT_ENTER: 1390331766Sken ocs_node_hold_frames(node); 1391331766Sken break; 1392331766Sken 1393331766Sken case OCS_EVT_EXIT: 1394331766Sken ocs_node_accept_frames(node); 1395331766Sken break; 1396331766Sken 1397331766Sken /* wait for any of these attach events and then shutdown */ 1398331766Sken case OCS_EVT_NODE_ATTACH_OK: 1399331766Sken node->attached = TRUE; 1400331766Sken node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt)); 1401331766Sken ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL); 1402331766Sken break; 1403331766Sken 1404331766Sken case OCS_EVT_NODE_ATTACH_FAIL: 1405331766Sken /* node attach failed, shutdown the node */ 1406331766Sken node->attached = FALSE; 1407331766Sken node_printf(node, "Attach evt=%s, proceed to shutdown\n", ocs_sm_event_name(evt)); 1408331766Sken ocs_node_transition(node, __ocs_d_initiate_shutdown, NULL); 1409331766Sken break; 1410331766Sken 1411331766Sken /* ignore shutdown events as we're already in shutdown path */ 1412331766Sken case OCS_EVT_SHUTDOWN: 1413331766Sken /* have default shutdown event take precedence */ 1414331766Sken node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1415331766Sken /* fall through */ 1416331766Sken case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO: 1417331766Sken case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO: 1418331766Sken node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 1419331766Sken break; 1420331766Sken 1421331766Sken default: 1422331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1423331766Sken return NULL; 1424331766Sken } 1425331766Sken 1426331766Sken return NULL; 1427331766Sken} 1428331766Sken 1429331766Sken/** 1430331766Sken * @ingroup device_sm 1431331766Sken * @brief Device node state machine: Port is logged in. 1432331766Sken * 1433331766Sken * <h3 class="desc">Description</h3> 1434331766Sken * This state is entered when a remote port has completed port login (PLOGI). 1435331766Sken * 1436331766Sken * @param ctx Remote node state machine context. 1437331766Sken * @param evt Event to process 1438331766Sken * @param arg Per event optional argument 1439331766Sken * 1440331766Sken * @return Returns NULL. 1441331766Sken */ 1442331766Skenvoid * 1443331766Sken__ocs_d_port_logged_in(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1444331766Sken{ 1445331766Sken ocs_node_cb_t *cbdata = arg; 1446331766Sken std_node_state_decl(); 1447331766Sken 1448331766Sken node_sm_trace(); 1449331766Sken 1450331766Sken /* TODO: I+T: what if PLOGI response not yet received ? */ 1451331766Sken 1452331766Sken switch(evt) { 1453331766Sken case OCS_EVT_ENTER: 1454331766Sken /* Normal case for I or I+T */ 1455331766Sken if (node->sport->enable_ini && !FC_ADDR_IS_DOMAIN_CTRL(node->rnode.fc_id) 1456331766Sken && !node->sent_prli) { 1457331766Sken /* sm: if enable_ini / send PRLI */ 1458331766Sken ocs_send_prli(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 1459331766Sken node->sent_prli = TRUE; 1460331766Sken /* can now expect ELS_REQ_OK/FAIL/RJT */ 1461331766Sken } 1462331766Sken break; 1463331766Sken 1464331766Sken case OCS_EVT_FCP_CMD_RCVD: { 1465331766Sken /* For target functionality send PRLO and drop the CMD frame. */ 1466331766Sken if (node->sport->enable_tgt) { 1467331766Sken if (ocs_send_prlo(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, 1468331766Sken OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL)) { 1469331766Sken ocs_node_transition(node, __ocs_d_wait_prlo_rsp, NULL); 1470331766Sken } 1471331766Sken } 1472331766Sken break; 1473331766Sken } 1474331766Sken 1475331766Sken case OCS_EVT_PRLI_RCVD: { 1476331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1477331766Sken 1478331766Sken /* Normal for T or I+T */ 1479331766Sken 1480331766Sken ocs_process_prli_payload(node, cbdata->payload->dma.virt); 1481331766Sken ocs_d_send_prli_rsp(cbdata->io, ocs_be16toh(hdr->ox_id)); 1482331766Sken break; 1483331766Sken } 1484331766Sken 1485331766Sken case OCS_EVT_SRRS_ELS_REQ_OK: { /* PRLI response */ 1486331766Sken /* Normal case for I or I+T */ 1487331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) { 1488331766Sken return NULL; 1489331766Sken } 1490331766Sken ocs_assert(node->els_req_cnt, NULL); 1491331766Sken node->els_req_cnt--; 1492331766Sken /* sm: process PRLI payload */ 1493331766Sken ocs_process_prli_payload(node, cbdata->els->els_rsp.virt); 1494331766Sken ocs_node_transition(node, __ocs_d_device_ready, NULL); 1495331766Sken break; 1496331766Sken } 1497331766Sken 1498331766Sken case OCS_EVT_SRRS_ELS_REQ_FAIL: { /* PRLI response failed */ 1499331766Sken /* I, I+T, assume some link failure, shutdown node */ 1500331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) { 1501331766Sken return NULL; 1502331766Sken } 1503331766Sken ocs_assert(node->els_req_cnt, NULL); 1504331766Sken node->els_req_cnt--; 1505331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL); 1506331766Sken break; 1507331766Sken } 1508331766Sken 1509331766Sken case OCS_EVT_SRRS_ELS_REQ_RJT: {/* PRLI rejected by remote */ 1510331766Sken /* Normal for I, I+T (connected to an I) */ 1511331766Sken /* Node doesn't want to be a target, stay here and wait for a PRLI from the remote node 1512331766Sken * if it really wants to connect to us as target */ 1513331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_PRLI, __ocs_d_common, __func__)) { 1514331766Sken return NULL; 1515331766Sken } 1516331766Sken ocs_assert(node->els_req_cnt, NULL); 1517331766Sken node->els_req_cnt--; 1518331766Sken break; 1519331766Sken } 1520331766Sken 1521331766Sken case OCS_EVT_SRRS_ELS_CMPL_OK: { 1522331766Sken /* Normal T, I+T, target-server rejected the process login */ 1523331766Sken /* This would be received only in the case where we sent LS_RJT for the PRLI, so 1524331766Sken * do nothing. (note: as T only we could shutdown the node) 1525331766Sken */ 1526331766Sken ocs_assert(node->els_cmpl_cnt, NULL); 1527331766Sken node->els_cmpl_cnt--; 1528331766Sken break; 1529331766Sken } 1530331766Sken 1531331766Sken case OCS_EVT_PLOGI_RCVD: { 1532331766Sken /* sm: save sparams, set send_plogi_acc, post implicit logout 1533331766Sken * Save plogi parameters */ 1534331766Sken ocs_node_save_sparms(node, cbdata->payload->dma.virt); 1535331766Sken ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI); 1536331766Sken 1537331766Sken /* Restart node attach with new service parameters, and send ACC */ 1538331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL); 1539331766Sken break; 1540331766Sken } 1541331766Sken 1542331766Sken case OCS_EVT_LOGO_RCVD: { 1543331766Sken /* I, T, I+T */ 1544331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1545331766Sken node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached); 1546331766Sken ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1547331766Sken ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL); 1548331766Sken break; 1549331766Sken } 1550331766Sken 1551331766Sken default: 1552331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1553331766Sken return NULL; 1554331766Sken } 1555331766Sken 1556331766Sken return NULL; 1557331766Sken} 1558331766Sken 1559331766Sken/** 1560331766Sken * @ingroup device_sm 1561331766Sken * @brief Device node state machine: Wait for a LOGO accept. 1562331766Sken * 1563331766Sken * <h3 class="desc">Description</h3> 1564331766Sken * Waits for a LOGO accept completion. 1565331766Sken * 1566331766Sken * @param ctx Remote node state machine context. 1567331766Sken * @param evt Event to process 1568331766Sken * @param arg Per event optional argument 1569331766Sken * 1570331766Sken * @return Returns NULL. 1571331766Sken */ 1572331766Sken 1573331766Skenvoid * 1574331766Sken__ocs_d_wait_logo_acc_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1575331766Sken{ 1576331766Sken std_node_state_decl(); 1577331766Sken 1578331766Sken node_sm_trace(); 1579331766Sken 1580331766Sken switch(evt) { 1581331766Sken case OCS_EVT_ENTER: 1582331766Sken ocs_node_hold_frames(node); 1583331766Sken break; 1584331766Sken 1585331766Sken case OCS_EVT_EXIT: 1586331766Sken ocs_node_accept_frames(node); 1587331766Sken break; 1588331766Sken 1589331766Sken case OCS_EVT_SRRS_ELS_CMPL_OK: 1590331766Sken case OCS_EVT_SRRS_ELS_CMPL_FAIL: 1591331766Sken /* sm: / post explicit logout */ 1592331766Sken ocs_assert(node->els_cmpl_cnt, NULL); 1593331766Sken node->els_cmpl_cnt--; 1594331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL); 1595331766Sken break; 1596331766Sken default: 1597331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1598331766Sken return NULL; 1599331766Sken } 1600331766Sken 1601331766Sken return NULL; 1602331766Sken} 1603331766Sken 1604331766Sken/** 1605331766Sken * @ingroup device_sm 1606331766Sken * @brief Device node state machine: Device is ready. 1607331766Sken * 1608331766Sken * @param ctx Remote node state machine context. 1609331766Sken * @param evt Event to process. 1610331766Sken * @param arg Per event optional argument. 1611331766Sken * 1612331766Sken * @return Returns NULL. 1613331766Sken */ 1614331766Sken 1615331766Skenvoid * 1616331766Sken__ocs_d_device_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1617331766Sken{ 1618331766Sken ocs_node_cb_t *cbdata = arg; 1619331766Sken std_node_state_decl(); 1620331766Sken 1621331766Sken if (evt != OCS_EVT_FCP_CMD_RCVD) { 1622331766Sken node_sm_trace(); 1623331766Sken } 1624331766Sken 1625331766Sken switch(evt) { 1626331766Sken case OCS_EVT_ENTER: 1627331766Sken node->fcp_enabled = TRUE; 1628331766Sken if (node->init) { 1629331766Sken device_printf(ocs->dev, "[%s] found (initiator) WWPN %s WWNN %s\n", node->display_name, 1630331766Sken node->wwpn, node->wwnn); 1631331766Sken if (node->sport->enable_tgt) 1632331766Sken ocs_scsi_new_initiator(node); 1633331766Sken } 1634331766Sken if (node->targ) { 1635331766Sken device_printf(ocs->dev, "[%s] found (target) WWPN %s WWNN %s\n", node->display_name, 1636331766Sken node->wwpn, node->wwnn); 1637331766Sken if (node->sport->enable_ini) 1638331766Sken ocs_scsi_new_target(node); 1639331766Sken } 1640331766Sken break; 1641331766Sken 1642331766Sken case OCS_EVT_EXIT: 1643331766Sken node->fcp_enabled = FALSE; 1644331766Sken break; 1645331766Sken 1646331766Sken case OCS_EVT_PLOGI_RCVD: { 1647331766Sken /* sm: save sparams, set send_plogi_acc, post implicit logout 1648331766Sken * Save plogi parameters */ 1649331766Sken ocs_node_save_sparms(node, cbdata->payload->dma.virt); 1650331766Sken ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI); 1651331766Sken 1652331766Sken /* Restart node attach with new service parameters, and send ACC */ 1653331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL); 1654331766Sken break; 1655331766Sken } 1656331766Sken 1657331766Sken 1658331766Sken case OCS_EVT_PDISC_RCVD: { 1659331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1660331766Sken ocs_send_plogi_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1661331766Sken break; 1662331766Sken } 1663331766Sken 1664331766Sken case OCS_EVT_PRLI_RCVD: { 1665331766Sken /* T, I+T: remote initiator is slow to get started */ 1666331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1667331766Sken 1668331766Sken ocs_process_prli_payload(node, cbdata->payload->dma.virt); 1669331766Sken 1670331766Sken /* sm: send PRLI acc/reject */ 1671331766Sken if (ocs->fc_type == node->fc_type) 1672331766Sken ocs_send_prli_acc(cbdata->io, ocs_be16toh(hdr->ox_id), ocs->fc_type, NULL, NULL); 1673331766Sken else 1674331766Sken ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), FC_REASON_UNABLE_TO_PERFORM, 1675331766Sken FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL); 1676331766Sken break; 1677331766Sken } 1678331766Sken 1679331766Sken case OCS_EVT_PRLO_RCVD: { 1680331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1681331766Sken fc_prlo_payload_t *prlo = cbdata->payload->dma.virt; 1682331766Sken 1683331766Sken /* sm: send PRLO acc/reject */ 1684331766Sken if (ocs->fc_type == prlo->type) 1685331766Sken ocs_send_prlo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), ocs->fc_type, NULL, NULL); 1686331766Sken else 1687331766Sken ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), FC_REASON_UNABLE_TO_PERFORM, 1688331766Sken FC_EXPL_REQUEST_NOT_SUPPORTED, 0, NULL, NULL); 1689331766Sken /*TODO: need implicit logout */ 1690331766Sken break; 1691331766Sken } 1692331766Sken 1693331766Sken case OCS_EVT_LOGO_RCVD: { 1694331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1695331766Sken node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached); 1696331766Sken ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1697331766Sken ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL); 1698331766Sken break; 1699331766Sken } 1700331766Sken 1701331766Sken case OCS_EVT_ADISC_RCVD: { 1702331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1703331766Sken ocs_send_adisc_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1704331766Sken break; 1705331766Sken } 1706331766Sken 1707331766Sken case OCS_EVT_RRQ_RCVD: { 1708331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1709331766Sken /* Send LS_ACC */ 1710331766Sken ocs_send_ls_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1711331766Sken break; 1712331766Sken } 1713331766Sken 1714331766Sken case OCS_EVT_ABTS_RCVD: 1715331766Sken ocs_process_abts(cbdata->io, cbdata->header->dma.virt); 1716331766Sken break; 1717331766Sken 1718331766Sken case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY: 1719331766Sken break; 1720331766Sken 1721331766Sken case OCS_EVT_NODE_REFOUND: 1722331766Sken break; 1723331766Sken 1724331766Sken case OCS_EVT_NODE_MISSING: 1725331766Sken if (node->sport->enable_rscn) { 1726331766Sken ocs_node_transition(node, __ocs_d_device_gone, NULL); 1727331766Sken } 1728331766Sken break; 1729331766Sken 1730331766Sken case OCS_EVT_SRRS_ELS_CMPL_OK: 1731331766Sken /* T, or I+T, PRLI accept completed ok */ 1732331766Sken ocs_assert(node->els_cmpl_cnt, NULL); 1733331766Sken node->els_cmpl_cnt--; 1734331766Sken break; 1735331766Sken 1736331766Sken case OCS_EVT_SRRS_ELS_CMPL_FAIL: 1737331766Sken /* T, or I+T, PRLI accept failed to complete */ 1738331766Sken ocs_assert(node->els_cmpl_cnt, NULL); 1739331766Sken node->els_cmpl_cnt--; 1740331766Sken node_printf(node, "Failed to send PRLI LS_ACC\n"); 1741331766Sken break; 1742331766Sken 1743331766Sken default: 1744331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1745331766Sken return NULL; 1746331766Sken } 1747331766Sken 1748331766Sken return NULL; 1749331766Sken} 1750331766Sken 1751331766Sken/** 1752331766Sken * @ingroup device_sm 1753331766Sken * @brief Device node state machine: Node is gone (absent from GID_PT). 1754331766Sken * 1755331766Sken * <h3 class="desc">Description</h3> 1756331766Sken * State entered when a node is detected as being gone (absent from GID_PT). 1757331766Sken * 1758331766Sken * @param ctx Remote node state machine context. 1759331766Sken * @param evt Event to process 1760331766Sken * @param arg Per event optional argument 1761331766Sken * 1762331766Sken * @return Returns NULL. 1763331766Sken */ 1764331766Sken 1765331766Skenvoid * 1766331766Sken__ocs_d_device_gone(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1767331766Sken{ 1768331766Sken int32_t rc = OCS_SCSI_CALL_COMPLETE; 1769331766Sken int32_t rc_2 = OCS_SCSI_CALL_COMPLETE; 1770331766Sken ocs_node_cb_t *cbdata = arg; 1771331766Sken std_node_state_decl(); 1772331766Sken 1773331766Sken node_sm_trace(); 1774331766Sken 1775331766Sken switch(evt) { 1776331766Sken case OCS_EVT_ENTER: { 1777331766Sken const char *labels[] = {"none", "initiator", "target", "initiator+target"}; 1778331766Sken 1779331766Sken device_printf(ocs->dev, "[%s] missing (%s) WWPN %s WWNN %s\n", node->display_name, 1780331766Sken labels[(node->targ << 1) | (node->init)], node->wwpn, node->wwnn); 1781331766Sken 1782331766Sken switch(ocs_node_get_enable(node)) { 1783331766Sken case OCS_NODE_ENABLE_T_TO_T: 1784331766Sken case OCS_NODE_ENABLE_I_TO_T: 1785331766Sken case OCS_NODE_ENABLE_IT_TO_T: 1786331766Sken rc = ocs_scsi_del_target(node, OCS_SCSI_TARGET_MISSING); 1787331766Sken break; 1788331766Sken 1789331766Sken case OCS_NODE_ENABLE_T_TO_I: 1790331766Sken case OCS_NODE_ENABLE_I_TO_I: 1791331766Sken case OCS_NODE_ENABLE_IT_TO_I: 1792331766Sken rc = ocs_scsi_del_initiator(node, OCS_SCSI_INITIATOR_MISSING); 1793331766Sken break; 1794331766Sken 1795331766Sken case OCS_NODE_ENABLE_T_TO_IT: 1796331766Sken rc = ocs_scsi_del_initiator(node, OCS_SCSI_INITIATOR_MISSING); 1797331766Sken break; 1798331766Sken 1799331766Sken case OCS_NODE_ENABLE_I_TO_IT: 1800331766Sken rc = ocs_scsi_del_target(node, OCS_SCSI_TARGET_MISSING); 1801331766Sken break; 1802331766Sken 1803331766Sken case OCS_NODE_ENABLE_IT_TO_IT: 1804331766Sken rc = ocs_scsi_del_initiator(node, OCS_SCSI_INITIATOR_MISSING); 1805331766Sken rc_2 = ocs_scsi_del_target(node, OCS_SCSI_TARGET_MISSING); 1806331766Sken break; 1807331766Sken 1808331766Sken default: 1809331766Sken rc = OCS_SCSI_CALL_COMPLETE; 1810331766Sken break; 1811331766Sken 1812331766Sken } 1813331766Sken 1814331766Sken if ((rc == OCS_SCSI_CALL_COMPLETE) && (rc_2 == OCS_SCSI_CALL_COMPLETE)) { 1815331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN, NULL); 1816331766Sken } 1817331766Sken 1818331766Sken break; 1819331766Sken } 1820331766Sken case OCS_EVT_NODE_REFOUND: 1821331766Sken /* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */ 1822331766Sken 1823331766Sken /* reauthenticate with PLOGI/PRLI */ 1824331766Sken /* ocs_node_transition(node, __ocs_d_discovered, NULL); */ 1825331766Sken 1826331766Sken /* reauthenticate with ADISC 1827331766Sken * sm: send ADISC */ 1828331766Sken ocs_send_adisc(node, OCS_FC_ELS_SEND_DEFAULT_TIMEOUT, OCS_FC_ELS_DEFAULT_RETRIES, NULL, NULL); 1829331766Sken ocs_node_transition(node, __ocs_d_wait_adisc_rsp, NULL); 1830331766Sken break; 1831331766Sken 1832331766Sken case OCS_EVT_PLOGI_RCVD: { 1833331766Sken /* sm: save sparams, set send_plogi_acc, post implicit logout 1834331766Sken * Save plogi parameters */ 1835331766Sken ocs_node_save_sparms(node, cbdata->payload->dma.virt); 1836331766Sken ocs_send_ls_acc_after_attach(cbdata->io, cbdata->header->dma.virt, OCS_NODE_SEND_LS_ACC_PLOGI); 1837331766Sken 1838331766Sken /* Restart node attach with new service parameters, and send ACC */ 1839331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL); 1840331766Sken break; 1841331766Sken } 1842331766Sken 1843331766Sken case OCS_EVT_FCP_CMD_RCVD: { 1844331766Sken /* most likely a stale frame (received prior to link down), if attempt 1845331766Sken * to send LOGO, will probably timeout and eat up 20s; thus, drop FCP_CMND 1846331766Sken */ 1847331766Sken node_printf(node, "FCP_CMND received, drop\n"); 1848331766Sken break; 1849331766Sken } 1850331766Sken case OCS_EVT_LOGO_RCVD: { 1851331766Sken /* I, T, I+T */ 1852331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1853331766Sken node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached); 1854331766Sken /* sm: send LOGO acc */ 1855331766Sken ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1856331766Sken ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL); 1857331766Sken break; 1858331766Sken } 1859331766Sken default: 1860331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1861331766Sken return NULL; 1862331766Sken } 1863331766Sken 1864331766Sken return NULL; 1865331766Sken} 1866331766Sken 1867331766Sken/** 1868331766Sken * @ingroup device_sm 1869331766Sken * @brief Device node state machine: Wait for the ADISC response. 1870331766Sken * 1871331766Sken * <h3 class="desc">Description</h3> 1872331766Sken * Waits for the ADISC response from the remote node. 1873331766Sken * 1874331766Sken * @param ctx Remote node state machine context. 1875331766Sken * @param evt Event to process. 1876331766Sken * @param arg Per event optional argument. 1877331766Sken * 1878331766Sken * @return Returns NULL. 1879331766Sken */ 1880331766Sken 1881331766Skenvoid * 1882331766Sken__ocs_d_wait_adisc_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1883331766Sken{ 1884331766Sken ocs_node_cb_t *cbdata = arg; 1885331766Sken std_node_state_decl(); 1886331766Sken 1887331766Sken node_sm_trace(); 1888331766Sken 1889331766Sken switch(evt) { 1890331766Sken case OCS_EVT_SRRS_ELS_REQ_OK: 1891331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_ADISC, __ocs_d_common, __func__)) { 1892331766Sken return NULL; 1893331766Sken } 1894331766Sken ocs_assert(node->els_req_cnt, NULL); 1895331766Sken node->els_req_cnt--; 1896331766Sken ocs_node_transition(node, __ocs_d_device_ready, NULL); 1897331766Sken break; 1898331766Sken 1899331766Sken case OCS_EVT_SRRS_ELS_REQ_RJT: 1900331766Sken /* received an LS_RJT, in this case, send shutdown (explicit logo) 1901331766Sken * event which will unregister the node, and start over with PLOGI 1902331766Sken */ 1903331766Sken if (node_check_els_req(ctx, evt, arg, FC_ELS_CMD_ADISC, __ocs_d_common, __func__)) { 1904331766Sken return NULL; 1905331766Sken } 1906331766Sken ocs_assert(node->els_req_cnt, NULL); 1907331766Sken node->els_req_cnt--; 1908331766Sken /*sm: post explicit logout */ 1909331766Sken ocs_node_post_event(node, OCS_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL); 1910331766Sken break; 1911331766Sken 1912331766Sken case OCS_EVT_LOGO_RCVD: { 1913331766Sken /* In this case, we have the equivalent of an LS_RJT for the ADISC, 1914331766Sken * so we need to abort the ADISC, and re-login with PLOGI 1915331766Sken */ 1916331766Sken /*sm: request abort, send LOGO acc */ 1917331766Sken fc_header_t *hdr = cbdata->header->dma.virt; 1918331766Sken node_printf(node, "%s received attached=%d\n", ocs_sm_event_name(evt), node->attached); 1919331766Sken ocs_send_logo_acc(cbdata->io, ocs_be16toh(hdr->ox_id), NULL, NULL); 1920331766Sken ocs_node_transition(node, __ocs_d_wait_logo_acc_cmpl, NULL); 1921331766Sken break; 1922331766Sken } 1923331766Sken default: 1924331766Sken __ocs_d_common(__func__, ctx, evt, arg); 1925331766Sken return NULL; 1926331766Sken } 1927331766Sken 1928331766Sken return NULL; 1929331766Sken} 1930