2021-06-01 16:54:55 -07:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2021 Broadcom . All Rights Reserved . The term
* “ Broadcom ” refers to Broadcom Inc . and / or its subsidiaries .
*/
/*
* device_sm Node State Machine : Remote Device States
*/
# include "efc.h"
# include "efc_device.h"
# include "efc_fabric.h"
void
efc_d_send_prli_rsp ( struct efc_node * node , u16 ox_id )
{
2021-06-16 18:04:01 +01:00
int rc = EFC_SCSI_CALL_COMPLETE ;
2021-06-01 16:54:55 -07:00
struct efc * efc = node - > efc ;
node - > ls_acc_oxid = ox_id ;
node - > send_ls_acc = EFC_NODE_SEND_LS_ACC_PRLI ;
/*
* Wait for backend session registration
* to complete before sending PRLI resp
*/
if ( node - > init ) {
efc_log_info ( efc , " [%s] found(initiator) WWPN:%s WWNN:%s \n " ,
node - > display_name , node - > wwpn , node - > wwnn ) ;
if ( node - > nport - > enable_tgt )
rc = efc - > tt . scsi_new_node ( efc , node ) ;
}
if ( rc < 0 )
efc_node_post_event ( node , EFC_EVT_NODE_SESS_REG_FAIL , NULL ) ;
if ( rc = = EFC_SCSI_CALL_COMPLETE )
efc_node_post_event ( node , EFC_EVT_NODE_SESS_REG_OK , NULL ) ;
}
static void
__efc_d_common ( const char * funcname , struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = NULL ;
struct efc * efc = NULL ;
node = ctx - > app ;
efc = node - > efc ;
switch ( evt ) {
/* Handle shutdown events */
case EFC_EVT_SHUTDOWN :
efc_log_debug ( efc , " [%s] %-20s %-20s \n " , node - > display_name ,
funcname , efc_sm_event_name ( evt ) ) ;
node - > shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT ;
efc_node_transition ( node , __efc_d_initiate_shutdown , NULL ) ;
break ;
case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO :
efc_log_debug ( efc , " [%s] %-20s %-20s \n " ,
node - > display_name , funcname ,
efc_sm_event_name ( evt ) ) ;
node - > shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO ;
efc_node_transition ( node , __efc_d_initiate_shutdown , NULL ) ;
break ;
case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO :
efc_log_debug ( efc , " [%s] %-20s %-20s \n " , node - > display_name ,
funcname , efc_sm_event_name ( evt ) ) ;
node - > shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO ;
efc_node_transition ( node , __efc_d_initiate_shutdown , NULL ) ;
break ;
default :
/* call default event handler common to all nodes */
__efc_node_common ( funcname , ctx , evt , arg ) ;
}
}
static void
__efc_d_wait_del_node ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
/*
* State is entered when a node sends a delete initiator / target call
* to the target - server / initiator - client and needs to wait for that
* work to complete .
*/
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
fallthrough ;
case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY :
case EFC_EVT_ALL_CHILD_NODES_FREE :
/* These are expected events. */
break ;
case EFC_EVT_NODE_DEL_INI_COMPLETE :
case EFC_EVT_NODE_DEL_TGT_COMPLETE :
/*
* node has either been detached or is in the process
* of being detached ,
* call common node ' s initiate cleanup function
*/
efc_node_initiate_cleanup ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_SRRS_ELS_REQ_FAIL :
/* Can happen as ELS IO IO's complete */
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
break ;
/* ignore shutdown events as we're already in shutdown path */
case EFC_EVT_SHUTDOWN :
/* have default shutdown event take precedence */
node - > shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT ;
fallthrough ;
case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO :
case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO :
node_printf ( node , " %s received \n " , efc_sm_event_name ( evt ) ) ;
break ;
case EFC_EVT_DOMAIN_ATTACH_OK :
/* don't care about domain_attach_ok */
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
static void
__efc_d_wait_del_ini_tgt ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
fallthrough ;
case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY :
case EFC_EVT_ALL_CHILD_NODES_FREE :
/* These are expected events. */
break ;
case EFC_EVT_NODE_DEL_INI_COMPLETE :
case EFC_EVT_NODE_DEL_TGT_COMPLETE :
efc_node_transition ( node , __efc_d_wait_del_node , NULL ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_SRRS_ELS_REQ_FAIL :
/* Can happen as ELS IO IO's complete */
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
break ;
/* ignore shutdown events as we're already in shutdown path */
case EFC_EVT_SHUTDOWN :
/* have default shutdown event take precedence */
node - > shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT ;
fallthrough ;
case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO :
case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO :
node_printf ( node , " %s received \n " , efc_sm_event_name ( evt ) ) ;
break ;
case EFC_EVT_DOMAIN_ATTACH_OK :
/* don't care about domain_attach_ok */
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_initiate_shutdown ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = ctx - > app ;
struct efc * efc = node - > efc ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER : {
int rc = EFC_SCSI_CALL_COMPLETE ;
/* assume no wait needed */
node - > els_io_enabled = false ;
/* make necessary delete upcall(s) */
if ( node - > init & & ! node - > targ ) {
efc_log_info ( node - > efc ,
" [%s] delete (initiator) WWPN %s WWNN %s \n " ,
node - > display_name ,
node - > wwpn , node - > wwnn ) ;
efc_node_transition ( node ,
__efc_d_wait_del_node ,
NULL ) ;
if ( node - > nport - > enable_tgt )
rc = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_INITIATOR_DELETED ) ;
if ( rc = = EFC_SCSI_CALL_COMPLETE | | rc < 0 )
efc_node_post_event ( node ,
EFC_EVT_NODE_DEL_INI_COMPLETE , NULL ) ;
} else if ( node - > targ & & ! node - > init ) {
efc_log_info ( node - > efc ,
" [%s] delete (target) WWPN %s WWNN %s \n " ,
node - > display_name ,
node - > wwpn , node - > wwnn ) ;
efc_node_transition ( node ,
__efc_d_wait_del_node ,
NULL ) ;
if ( node - > nport - > enable_ini )
rc = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_TARGET_DELETED ) ;
if ( rc = = EFC_SCSI_CALL_COMPLETE )
efc_node_post_event ( node ,
EFC_EVT_NODE_DEL_TGT_COMPLETE , NULL ) ;
} else if ( node - > init & & node - > targ ) {
efc_log_info ( node - > efc ,
" [%s] delete (I+T) WWPN %s WWNN %s \n " ,
node - > display_name , node - > wwpn , node - > wwnn ) ;
efc_node_transition ( node , __efc_d_wait_del_ini_tgt ,
NULL ) ;
if ( node - > nport - > enable_tgt )
rc = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_INITIATOR_DELETED ) ;
if ( rc = = EFC_SCSI_CALL_COMPLETE )
efc_node_post_event ( node ,
EFC_EVT_NODE_DEL_INI_COMPLETE , NULL ) ;
/* assume no wait needed */
rc = EFC_SCSI_CALL_COMPLETE ;
if ( node - > nport - > enable_ini )
rc = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_TARGET_DELETED ) ;
if ( rc = = EFC_SCSI_CALL_COMPLETE )
efc_node_post_event ( node ,
EFC_EVT_NODE_DEL_TGT_COMPLETE , NULL ) ;
}
/* we've initiated the upcalls as needed, now kick off the node
* detach to precipitate the aborting of outstanding exchanges
* associated with said node
*
* Beware : if we ' ve made upcall ( s ) , we ' ve already transitioned
* to a new state by the time we execute this .
* consider doing this before the upcalls ?
*/
if ( node - > attached ) {
/* issue hw node free; don't care if succeeds right
* away or sometime later , will check node - > attached
* later in shutdown process
*/
rc = efc_cmd_node_detach ( efc , & node - > rnode ) ;
if ( rc < 0 )
node_printf ( node ,
" Failed freeing HW node, rc=%d \n " ,
rc ) ;
}
/* if neither initiator nor target, proceed to cleanup */
if ( ! node - > init & & ! node - > targ ) {
/*
* node has either been detached or is in
* the process of being detached ,
* call common node ' s initiate cleanup function
*/
efc_node_initiate_cleanup ( node ) ;
}
break ;
}
case EFC_EVT_ALL_CHILD_NODES_FREE :
/* Ignore, this can happen if an ELS is
* aborted while in a delay / retry state
*/
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_loop ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_DOMAIN_ATTACH_OK : {
/* send PLOGI automatically if initiator */
efc_node_init_device ( node , true ) ;
break ;
}
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
efc_send_ls_acc_after_attach ( struct efc_node * node ,
struct fc_frame_header * hdr ,
enum efc_node_send_ls_acc ls )
{
u16 ox_id = be16_to_cpu ( hdr - > fh_ox_id ) ;
/* Save the OX_ID for sending LS_ACC sometime later */
WARN_ON ( node - > send_ls_acc ! = EFC_NODE_SEND_LS_ACC_NONE ) ;
node - > ls_acc_oxid = ox_id ;
node - > send_ls_acc = ls ;
node - > ls_acc_did = ntoh24 ( hdr - > fh_d_id ) ;
}
void
efc_process_prli_payload ( struct efc_node * node , void * prli )
{
struct {
struct fc_els_prli prli ;
struct fc_els_spp sp ;
} * pp ;
pp = prli ;
node - > init = ( pp - > sp . spp_flags & FCP_SPPF_INIT_FCN ) ! = 0 ;
node - > targ = ( pp - > sp . spp_flags & FCP_SPPF_TARG_FCN ) ! = 0 ;
}
void
__efc_d_wait_plogi_acc_cmpl ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_SRRS_ELS_CMPL_FAIL :
WARN_ON ( ! node - > els_cmpl_cnt ) ;
node - > els_cmpl_cnt - - ;
node - > shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT ;
efc_node_transition ( node , __efc_d_initiate_shutdown , NULL ) ;
break ;
case EFC_EVT_SRRS_ELS_CMPL_OK : /* PLOGI ACC completions */
WARN_ON ( ! node - > els_cmpl_cnt ) ;
node - > els_cmpl_cnt - - ;
efc_node_transition ( node , __efc_d_port_logged_in , NULL ) ;
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_logo_rsp ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_SRRS_ELS_REQ_OK :
case EFC_EVT_SRRS_ELS_REQ_RJT :
case EFC_EVT_SRRS_ELS_REQ_FAIL :
/* LOGO response received, sent shutdown */
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_LOGO ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
node_printf ( node ,
" LOGO sent (evt=%s), shutdown node \n " ,
efc_sm_event_name ( evt ) ) ;
/* sm: / post explicit logout */
efc_node_post_event ( node , EFC_EVT_SHUTDOWN_EXPLICIT_LOGO ,
NULL ) ;
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
efc_node_init_device ( struct efc_node * node , bool send_plogi )
{
node - > send_plogi = send_plogi ;
if ( ( node - > efc - > nodedb_mask & EFC_NODEDB_PAUSE_NEW_NODES ) & &
( node - > rnode . fc_id ! = FC_FID_DOM_MGR ) ) {
node - > nodedb_state = __efc_d_init ;
efc_node_transition ( node , __efc_node_paused , NULL ) ;
} else {
efc_node_transition ( node , __efc_d_init , NULL ) ;
}
}
static void
efc_d_check_plogi_topology ( struct efc_node * node , u32 d_id )
{
switch ( node - > nport - > topology ) {
case EFC_NPORT_TOPO_P2P :
/* we're not attached and nport is p2p,
* need to attach
*/
efc_domain_attach ( node - > nport - > domain , d_id ) ;
efc_node_transition ( node , __efc_d_wait_domain_attach , NULL ) ;
break ;
case EFC_NPORT_TOPO_FABRIC :
/* we're not attached and nport is fabric, domain
* attach should have already been requested as part
* of the fabric state machine , wait for it
*/
efc_node_transition ( node , __efc_d_wait_domain_attach , NULL ) ;
break ;
case EFC_NPORT_TOPO_UNKNOWN :
/* Two possibilities:
* 1. received a PLOGI before our FLOGI has completed
* ( possible since completion comes in on another
* CQ ) , thus we don ' t know what we ' re connected to
* yet ; transition to a state to wait for the
* fabric node to tell us ;
* 2. PLOGI received before link went down and we
* haven ' t performed domain attach yet .
* Note : we cannot distinguish between 1. and 2.
* so have to assume PLOGI
* was received after link back up .
*/
node_printf ( node , " received PLOGI, unknown topology did=0x%x \n " ,
d_id ) ;
efc_node_transition ( node , __efc_d_wait_topology_notify , NULL ) ;
break ;
default :
node_printf ( node , " received PLOGI, unexpected topology %d \n " ,
node - > nport - > topology ) ;
}
}
void
__efc_d_init ( struct efc_sm_ctx * ctx , enum efc_sm_event evt , void * arg )
{
struct efc_node_cb * cbdata = arg ;
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
/*
* This state is entered when a node is instantiated ,
* either having been discovered from a name services query ,
* or having received a PLOGI / FLOGI .
*/
switch ( evt ) {
case EFC_EVT_ENTER :
if ( ! node - > send_plogi )
break ;
/* only send if we have initiator capability,
* and domain is attached
*/
if ( node - > nport - > enable_ini & &
node - > nport - > domain - > attached ) {
efc_send_plogi ( node ) ;
efc_node_transition ( node , __efc_d_wait_plogi_rsp , NULL ) ;
} else {
node_printf ( node , " not sending plogi nport.ini=%d, " ,
node - > nport - > enable_ini ) ;
node_printf ( node , " domain attached=%d \n " ,
node - > nport - > domain - > attached ) ;
}
break ;
case EFC_EVT_PLOGI_RCVD : {
/* T, or I+T */
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
int rc ;
efc_node_save_sparms ( node , cbdata - > payload - > dma . virt ) ;
efc_send_ls_acc_after_attach ( node ,
cbdata - > header - > dma . virt ,
EFC_NODE_SEND_LS_ACC_PLOGI ) ;
/* domain not attached; several possibilities: */
if ( ! node - > nport - > domain - > attached ) {
efc_d_check_plogi_topology ( node , ntoh24 ( hdr - > fh_d_id ) ) ;
break ;
}
/* domain already attached */
rc = efc_node_attach ( node ) ;
efc_node_transition ( node , __efc_d_wait_node_attach , NULL ) ;
if ( rc < 0 )
efc_node_post_event ( node , EFC_EVT_NODE_ATTACH_FAIL , NULL ) ;
break ;
}
case EFC_EVT_FDISC_RCVD : {
__efc_d_common ( __func__ , ctx , evt , arg ) ;
break ;
}
case EFC_EVT_FLOGI_RCVD : {
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
u32 d_id = ntoh24 ( hdr - > fh_d_id ) ;
/* sm: / save sparams, send FLOGI acc */
memcpy ( node - > nport - > domain - > flogi_service_params ,
cbdata - > payload - > dma . virt ,
sizeof ( struct fc_els_flogi ) ) ;
/* send FC LS_ACC response, override s_id */
efc_fabric_set_topology ( node , EFC_NPORT_TOPO_P2P ) ;
efc_send_flogi_p2p_acc ( node , be16_to_cpu ( hdr - > fh_ox_id ) , d_id ) ;
if ( efc_p2p_setup ( node - > nport ) ) {
node_printf ( node , " p2p failed, shutting down node \n " ) ;
efc_node_post_event ( node , EFC_EVT_SHUTDOWN , NULL ) ;
break ;
}
efc_node_transition ( node , __efc_p2p_wait_flogi_acc_cmpl , NULL ) ;
break ;
}
case EFC_EVT_LOGO_RCVD : {
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
if ( ! node - > nport - > domain - > attached ) {
/* most likely a frame left over from before a link
* down ; drop and
* shut node down w / " explicit logout " so pending
* frames are processed
*/
node_printf ( node , " %s domain not attached, dropping \n " ,
efc_sm_event_name ( evt ) ) ;
efc_node_post_event ( node ,
EFC_EVT_SHUTDOWN_EXPLICIT_LOGO , NULL ) ;
break ;
}
efc_send_logo_acc ( node , be16_to_cpu ( hdr - > fh_ox_id ) ) ;
efc_node_transition ( node , __efc_d_wait_logo_acc_cmpl , NULL ) ;
break ;
}
case EFC_EVT_PRLI_RCVD :
case EFC_EVT_PRLO_RCVD :
case EFC_EVT_PDISC_RCVD :
case EFC_EVT_ADISC_RCVD :
case EFC_EVT_RSCN_RCVD : {
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
if ( ! node - > nport - > domain - > attached ) {
/* most likely a frame left over from before a link
* down ; drop and shut node down w / " explicit logout "
* so pending frames are processed
*/
node_printf ( node , " %s domain not attached, dropping \n " ,
efc_sm_event_name ( evt ) ) ;
efc_node_post_event ( node ,
EFC_EVT_SHUTDOWN_EXPLICIT_LOGO ,
NULL ) ;
break ;
}
node_printf ( node , " %s received, sending reject \n " ,
efc_sm_event_name ( evt ) ) ;
efc_send_ls_rjt ( node , be16_to_cpu ( hdr - > fh_ox_id ) ,
ELS_RJT_UNAB , ELS_EXPL_PLOGI_REQD , 0 ) ;
break ;
}
case EFC_EVT_FCP_CMD_RCVD : {
/* note: problem, we're now expecting an ELS REQ completion
* from both the LOGO and PLOGI
*/
if ( ! node - > nport - > domain - > attached ) {
/* most likely a frame left over from before a
* link down ; drop and
* shut node down w / " explicit logout " so pending
* frames are processed
*/
node_printf ( node , " %s domain not attached, dropping \n " ,
efc_sm_event_name ( evt ) ) ;
efc_node_post_event ( node ,
EFC_EVT_SHUTDOWN_EXPLICIT_LOGO ,
NULL ) ;
break ;
}
/* Send LOGO */
node_printf ( node , " FCP_CMND received, send LOGO \n " ) ;
if ( efc_send_logo ( node ) ) {
/*
* failed to send LOGO , go ahead and cleanup node
* anyways
*/
node_printf ( node , " Failed to send LOGO \n " ) ;
efc_node_post_event ( node ,
EFC_EVT_SHUTDOWN_EXPLICIT_LOGO ,
NULL ) ;
} else {
/* sent LOGO, wait for response */
efc_node_transition ( node ,
__efc_d_wait_logo_rsp , NULL ) ;
}
break ;
}
case EFC_EVT_DOMAIN_ATTACH_OK :
/* don't care about domain_attach_ok */
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_plogi_rsp ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
int rc ;
struct efc_node_cb * cbdata = arg ;
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_PLOGI_RCVD : {
/* T, or I+T */
/* received PLOGI with svc parms, go ahead and attach node
* when PLOGI that was sent ultimately completes , it ' ll be a
* no - op
*
* If there is an outstanding PLOGI sent , can we set a flag
* to indicate that we don ' t want to retry it if it times out ?
*/
efc_node_save_sparms ( node , cbdata - > payload - > dma . virt ) ;
efc_send_ls_acc_after_attach ( node ,
cbdata - > header - > dma . virt ,
EFC_NODE_SEND_LS_ACC_PLOGI ) ;
/* sm: domain->attached / efc_node_attach */
rc = efc_node_attach ( node ) ;
efc_node_transition ( node , __efc_d_wait_node_attach , NULL ) ;
if ( rc < 0 )
efc_node_post_event ( node ,
EFC_EVT_NODE_ATTACH_FAIL , NULL ) ;
break ;
}
case EFC_EVT_PRLI_RCVD :
/* I, or I+T */
/* sent PLOGI and before completion was seen, received the
* PRLI from the remote node ( WCQEs and RCQEs come in on
* different queues and order of processing cannot be assumed )
* Save OXID so PRLI can be sent after the attach and continue
* to wait for PLOGI response
*/
efc_process_prli_payload ( node , cbdata - > payload - > dma . virt ) ;
efc_send_ls_acc_after_attach ( node ,
cbdata - > header - > dma . virt ,
EFC_NODE_SEND_LS_ACC_PRLI ) ;
efc_node_transition ( node , __efc_d_wait_plogi_rsp_recvd_prli ,
NULL ) ;
break ;
case EFC_EVT_LOGO_RCVD : /* why don't we do a shutdown here?? */
case EFC_EVT_PRLO_RCVD :
case EFC_EVT_PDISC_RCVD :
case EFC_EVT_FDISC_RCVD :
case EFC_EVT_ADISC_RCVD :
case EFC_EVT_RSCN_RCVD :
case EFC_EVT_SCR_RCVD : {
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
node_printf ( node , " %s received, sending reject \n " ,
efc_sm_event_name ( evt ) ) ;
efc_send_ls_rjt ( node , be16_to_cpu ( hdr - > fh_ox_id ) ,
ELS_RJT_UNAB , ELS_EXPL_PLOGI_REQD , 0 ) ;
break ;
}
case EFC_EVT_SRRS_ELS_REQ_OK : /* PLOGI response received */
/* Completion from PLOGI sent */
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_PLOGI ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
/* sm: / save sparams, efc_node_attach */
efc_node_save_sparms ( node , cbdata - > els_rsp . virt ) ;
rc = efc_node_attach ( node ) ;
efc_node_transition ( node , __efc_d_wait_node_attach , NULL ) ;
if ( rc < 0 )
efc_node_post_event ( node ,
EFC_EVT_NODE_ATTACH_FAIL , NULL ) ;
break ;
case EFC_EVT_SRRS_ELS_REQ_FAIL : /* PLOGI response received */
/* PLOGI failed, shutdown the node */
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_PLOGI ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
efc_node_post_event ( node , EFC_EVT_SHUTDOWN , NULL ) ;
break ;
case EFC_EVT_SRRS_ELS_REQ_RJT :
/* Our PLOGI was rejected, this is ok in some cases */
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_PLOGI ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
break ;
case EFC_EVT_FCP_CMD_RCVD : {
/* not logged in yet and outstanding PLOGI so don't send LOGO,
* just drop
*/
node_printf ( node , " FCP_CMND received, drop \n " ) ;
break ;
}
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_plogi_rsp_recvd_prli ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
int rc ;
struct efc_node_cb * cbdata = arg ;
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
/*
* Since we ' ve received a PRLI , we have a port login and will
* just need to wait for the PLOGI response to do the node
* attach and then we can send the LS_ACC for the PRLI . If ,
* during this time , we receive FCP_CMNDs ( which is possible
* since we ' ve already sent a PRLI and our peer may have
* accepted ) . At this time , we are not waiting on any other
* unsolicited frames to continue with the login process . Thus ,
* it will not hurt to hold frames here .
*/
efc_node_hold_frames ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_SRRS_ELS_REQ_OK : /* PLOGI response received */
/* Completion from PLOGI sent */
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_PLOGI ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
/* sm: / save sparams, efc_node_attach */
efc_node_save_sparms ( node , cbdata - > els_rsp . virt ) ;
rc = efc_node_attach ( node ) ;
efc_node_transition ( node , __efc_d_wait_node_attach , NULL ) ;
if ( rc < 0 )
efc_node_post_event ( node , EFC_EVT_NODE_ATTACH_FAIL ,
NULL ) ;
break ;
case EFC_EVT_SRRS_ELS_REQ_FAIL : /* PLOGI response received */
case EFC_EVT_SRRS_ELS_REQ_RJT :
/* PLOGI failed, shutdown the node */
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_PLOGI ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
efc_node_post_event ( node , EFC_EVT_SHUTDOWN , NULL ) ;
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_domain_attach ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
int rc ;
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_DOMAIN_ATTACH_OK :
WARN_ON ( ! node - > nport - > domain - > attached ) ;
/* sm: / efc_node_attach */
rc = efc_node_attach ( node ) ;
efc_node_transition ( node , __efc_d_wait_node_attach , NULL ) ;
if ( rc < 0 )
efc_node_post_event ( node , EFC_EVT_NODE_ATTACH_FAIL ,
NULL ) ;
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_topology_notify ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
int rc ;
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_NPORT_TOPOLOGY_NOTIFY : {
2021-08-30 16:10:50 -07:00
enum efc_nport_topology * topology = arg ;
2021-06-01 16:54:55 -07:00
WARN_ON ( node - > nport - > domain - > attached ) ;
WARN_ON ( node - > send_ls_acc ! = EFC_NODE_SEND_LS_ACC_PLOGI ) ;
node_printf ( node , " topology notification, topology=%d \n " ,
2021-08-30 16:10:50 -07:00
* topology ) ;
2021-06-01 16:54:55 -07:00
/* At the time the PLOGI was received, the topology was unknown,
* so we didn ' t know which node would perform the domain attach :
* 1. The node from which the PLOGI was sent ( p2p ) or
* 2. The node to which the FLOGI was sent ( fabric ) .
*/
2021-08-30 16:10:50 -07:00
if ( * topology = = EFC_NPORT_TOPO_P2P ) {
2021-06-01 16:54:55 -07:00
/* if this is p2p, need to attach to the domain using
* the d_id from the PLOGI received
*/
efc_domain_attach ( node - > nport - > domain ,
node - > ls_acc_did ) ;
}
/* else, if this is fabric, the domain attach
* should be performed by the fabric node ( node sending FLOGI ) ;
* just wait for attach to complete
*/
efc_node_transition ( node , __efc_d_wait_domain_attach , NULL ) ;
break ;
}
case EFC_EVT_DOMAIN_ATTACH_OK :
WARN_ON ( ! node - > nport - > domain - > attached ) ;
node_printf ( node , " domain attach ok \n " ) ;
/* sm: / efc_node_attach */
rc = efc_node_attach ( node ) ;
efc_node_transition ( node , __efc_d_wait_node_attach , NULL ) ;
if ( rc < 0 )
efc_node_post_event ( node ,
EFC_EVT_NODE_ATTACH_FAIL , NULL ) ;
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_node_attach ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_NODE_ATTACH_OK :
node - > attached = true ;
switch ( node - > send_ls_acc ) {
case EFC_NODE_SEND_LS_ACC_PLOGI : {
/* sm: send_plogi_acc is set / send PLOGI acc */
/* Normal case for T, or I+T */
efc_send_plogi_acc ( node , node - > ls_acc_oxid ) ;
efc_node_transition ( node , __efc_d_wait_plogi_acc_cmpl ,
NULL ) ;
node - > send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE ;
node - > ls_acc_io = NULL ;
break ;
}
case EFC_NODE_SEND_LS_ACC_PRLI : {
efc_d_send_prli_rsp ( node , node - > ls_acc_oxid ) ;
node - > send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE ;
node - > ls_acc_io = NULL ;
break ;
}
case EFC_NODE_SEND_LS_ACC_NONE :
default :
/* Normal case for I */
/* sm: send_plogi_acc is not set / send PLOGI acc */
efc_node_transition ( node ,
__efc_d_port_logged_in , NULL ) ;
break ;
}
break ;
case EFC_EVT_NODE_ATTACH_FAIL :
/* node attach failed, shutdown the node */
node - > attached = false ;
node_printf ( node , " node attach failed \n " ) ;
node - > shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT ;
efc_node_transition ( node , __efc_d_initiate_shutdown , NULL ) ;
break ;
/* Handle shutdown events */
case EFC_EVT_SHUTDOWN :
node_printf ( node , " %s received \n " , efc_sm_event_name ( evt ) ) ;
node - > shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT ;
efc_node_transition ( node , __efc_d_wait_attach_evt_shutdown ,
NULL ) ;
break ;
case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO :
node_printf ( node , " %s received \n " , efc_sm_event_name ( evt ) ) ;
node - > shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO ;
efc_node_transition ( node , __efc_d_wait_attach_evt_shutdown ,
NULL ) ;
break ;
case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO :
node_printf ( node , " %s received \n " , efc_sm_event_name ( evt ) ) ;
node - > shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO ;
efc_node_transition ( node ,
__efc_d_wait_attach_evt_shutdown , NULL ) ;
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_attach_evt_shutdown ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
/* wait for any of these attach events and then shutdown */
case EFC_EVT_NODE_ATTACH_OK :
node - > attached = true ;
node_printf ( node , " Attach evt=%s, proceed to shutdown \n " ,
efc_sm_event_name ( evt ) ) ;
efc_node_transition ( node , __efc_d_initiate_shutdown , NULL ) ;
break ;
case EFC_EVT_NODE_ATTACH_FAIL :
/* node attach failed, shutdown the node */
node - > attached = false ;
node_printf ( node , " Attach evt=%s, proceed to shutdown \n " ,
efc_sm_event_name ( evt ) ) ;
efc_node_transition ( node , __efc_d_initiate_shutdown , NULL ) ;
break ;
/* ignore shutdown events as we're already in shutdown path */
case EFC_EVT_SHUTDOWN :
/* have default shutdown event take precedence */
node - > shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT ;
fallthrough ;
case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO :
case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO :
node_printf ( node , " %s received \n " , efc_sm_event_name ( evt ) ) ;
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_port_logged_in ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node_cb * cbdata = arg ;
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
/* Normal case for I or I+T */
if ( node - > nport - > enable_ini & &
! ( node - > rnode . fc_id ! = FC_FID_DOM_MGR ) ) {
/* sm: if enable_ini / send PRLI */
efc_send_prli ( node ) ;
/* can now expect ELS_REQ_OK/FAIL/RJT */
}
break ;
case EFC_EVT_FCP_CMD_RCVD : {
break ;
}
case EFC_EVT_PRLI_RCVD : {
/* Normal case for T or I+T */
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
struct {
struct fc_els_prli prli ;
struct fc_els_spp sp ;
} * pp ;
pp = cbdata - > payload - > dma . virt ;
if ( pp - > sp . spp_type ! = FC_TYPE_FCP ) {
/*Only FCP is supported*/
efc_send_ls_rjt ( node , be16_to_cpu ( hdr - > fh_ox_id ) ,
ELS_RJT_UNAB , ELS_EXPL_UNSUPR , 0 ) ;
break ;
}
efc_process_prli_payload ( node , cbdata - > payload - > dma . virt ) ;
efc_d_send_prli_rsp ( node , be16_to_cpu ( hdr - > fh_ox_id ) ) ;
break ;
}
case EFC_EVT_NODE_SESS_REG_OK :
if ( node - > send_ls_acc = = EFC_NODE_SEND_LS_ACC_PRLI )
efc_send_prli_acc ( node , node - > ls_acc_oxid ) ;
node - > send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE ;
efc_node_transition ( node , __efc_d_device_ready , NULL ) ;
break ;
case EFC_EVT_NODE_SESS_REG_FAIL :
efc_send_ls_rjt ( node , node - > ls_acc_oxid , ELS_RJT_UNAB ,
ELS_EXPL_UNSUPR , 0 ) ;
node - > send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE ;
break ;
case EFC_EVT_SRRS_ELS_REQ_OK : { /* PRLI response */
/* Normal case for I or I+T */
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_PRLI ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
/* sm: / process PRLI payload */
efc_process_prli_payload ( node , cbdata - > els_rsp . virt ) ;
efc_node_transition ( node , __efc_d_device_ready , NULL ) ;
break ;
}
case EFC_EVT_SRRS_ELS_REQ_FAIL : { /* PRLI response failed */
/* I, I+T, assume some link failure, shutdown node */
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_PRLI ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
efc_node_post_event ( node , EFC_EVT_SHUTDOWN , NULL ) ;
break ;
}
case EFC_EVT_SRRS_ELS_REQ_RJT : {
/* PRLI rejected by remote
* Normal for I , I + T ( connected to an I )
* Node doesn ' t want to be a target , stay here and wait for a
* PRLI from the remote node
* if it really wants to connect to us as target
*/
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_PRLI ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
break ;
}
case EFC_EVT_SRRS_ELS_CMPL_OK : {
/* Normal T, I+T, target-server rejected the process login */
/* This would be received only in the case where we sent
* LS_RJT for the PRLI , so
* do nothing . ( note : as T only we could shutdown the node )
*/
WARN_ON ( ! node - > els_cmpl_cnt ) ;
node - > els_cmpl_cnt - - ;
break ;
}
case EFC_EVT_PLOGI_RCVD : {
/*sm: / save sparams, set send_plogi_acc,
* post implicit logout
* Save plogi parameters
*/
efc_node_save_sparms ( node , cbdata - > payload - > dma . virt ) ;
efc_send_ls_acc_after_attach ( node ,
cbdata - > header - > dma . virt ,
EFC_NODE_SEND_LS_ACC_PLOGI ) ;
/* Restart node attach with new service parameters,
* and send ACC
*/
efc_node_post_event ( node , EFC_EVT_SHUTDOWN_IMPLICIT_LOGO ,
NULL ) ;
break ;
}
case EFC_EVT_LOGO_RCVD : {
/* I, T, I+T */
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
node_printf ( node , " %s received attached=%d \n " ,
efc_sm_event_name ( evt ) ,
node - > attached ) ;
/* sm: / send LOGO acc */
efc_send_logo_acc ( node , be16_to_cpu ( hdr - > fh_ox_id ) ) ;
efc_node_transition ( node , __efc_d_wait_logo_acc_cmpl , NULL ) ;
break ;
}
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_logo_acc_cmpl ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
efc_node_hold_frames ( node ) ;
break ;
case EFC_EVT_EXIT :
efc_node_accept_frames ( node ) ;
break ;
case EFC_EVT_SRRS_ELS_CMPL_OK :
case EFC_EVT_SRRS_ELS_CMPL_FAIL :
/* sm: / post explicit logout */
WARN_ON ( ! node - > els_cmpl_cnt ) ;
node - > els_cmpl_cnt - - ;
efc_node_post_event ( node ,
EFC_EVT_SHUTDOWN_EXPLICIT_LOGO , NULL ) ;
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_device_ready ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node_cb * cbdata = arg ;
struct efc_node * node = ctx - > app ;
struct efc * efc = node - > efc ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
if ( evt ! = EFC_EVT_FCP_CMD_RCVD )
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER :
node - > fcp_enabled = true ;
if ( node - > targ ) {
efc_log_info ( efc ,
" [%s] found (target) WWPN %s WWNN %s \n " ,
node - > display_name ,
node - > wwpn , node - > wwnn ) ;
if ( node - > nport - > enable_ini )
efc - > tt . scsi_new_node ( efc , node ) ;
}
break ;
case EFC_EVT_EXIT :
node - > fcp_enabled = false ;
break ;
case EFC_EVT_PLOGI_RCVD : {
/* sm: / save sparams, set send_plogi_acc, post implicit
* logout
* Save plogi parameters
*/
efc_node_save_sparms ( node , cbdata - > payload - > dma . virt ) ;
efc_send_ls_acc_after_attach ( node ,
cbdata - > header - > dma . virt ,
EFC_NODE_SEND_LS_ACC_PLOGI ) ;
/*
* Restart node attach with new service parameters ,
* and send ACC
*/
efc_node_post_event ( node ,
EFC_EVT_SHUTDOWN_IMPLICIT_LOGO , NULL ) ;
break ;
}
case EFC_EVT_PRLI_RCVD : {
/* T, I+T: remote initiator is slow to get started */
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
struct {
struct fc_els_prli prli ;
struct fc_els_spp sp ;
} * pp ;
pp = cbdata - > payload - > dma . virt ;
if ( pp - > sp . spp_type ! = FC_TYPE_FCP ) {
/*Only FCP is supported*/
efc_send_ls_rjt ( node , be16_to_cpu ( hdr - > fh_ox_id ) ,
ELS_RJT_UNAB , ELS_EXPL_UNSUPR , 0 ) ;
break ;
}
efc_process_prli_payload ( node , cbdata - > payload - > dma . virt ) ;
efc_send_prli_acc ( node , be16_to_cpu ( hdr - > fh_ox_id ) ) ;
break ;
}
case EFC_EVT_PRLO_RCVD : {
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
/* sm: / send PRLO acc */
efc_send_prlo_acc ( node , be16_to_cpu ( hdr - > fh_ox_id ) ) ;
/* need implicit logout? */
break ;
}
case EFC_EVT_LOGO_RCVD : {
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
node_printf ( node , " %s received attached=%d \n " ,
efc_sm_event_name ( evt ) , node - > attached ) ;
/* sm: / send LOGO acc */
efc_send_logo_acc ( node , be16_to_cpu ( hdr - > fh_ox_id ) ) ;
efc_node_transition ( node , __efc_d_wait_logo_acc_cmpl , NULL ) ;
break ;
}
case EFC_EVT_ADISC_RCVD : {
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
/* sm: / send ADISC acc */
efc_send_adisc_acc ( node , be16_to_cpu ( hdr - > fh_ox_id ) ) ;
break ;
}
case EFC_EVT_ABTS_RCVD :
/* sm: / process ABTS */
efc_log_err ( efc , " Unexpected event:%s \n " ,
efc_sm_event_name ( evt ) ) ;
break ;
case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY :
break ;
case EFC_EVT_NODE_REFOUND :
break ;
case EFC_EVT_NODE_MISSING :
if ( node - > nport - > enable_rscn )
efc_node_transition ( node , __efc_d_device_gone , NULL ) ;
break ;
case EFC_EVT_SRRS_ELS_CMPL_OK :
/* T, or I+T, PRLI accept completed ok */
WARN_ON ( ! node - > els_cmpl_cnt ) ;
node - > els_cmpl_cnt - - ;
break ;
case EFC_EVT_SRRS_ELS_CMPL_FAIL :
/* T, or I+T, PRLI accept failed to complete */
WARN_ON ( ! node - > els_cmpl_cnt ) ;
node - > els_cmpl_cnt - - ;
node_printf ( node , " Failed to send PRLI LS_ACC \n " ) ;
break ;
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_device_gone ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node_cb * cbdata = arg ;
struct efc_node * node = ctx - > app ;
struct efc * efc = node - > efc ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_ENTER : {
int rc = EFC_SCSI_CALL_COMPLETE ;
int rc_2 = EFC_SCSI_CALL_COMPLETE ;
static const char * const labels [ ] = {
" none " , " initiator " , " target " , " initiator+target "
} ;
efc_log_info ( efc , " [%s] missing (%s) WWPN %s WWNN %s \n " ,
node - > display_name ,
labels [ ( node - > targ < < 1 ) | ( node - > init ) ] ,
node - > wwpn , node - > wwnn ) ;
switch ( efc_node_get_enable ( node ) ) {
case EFC_NODE_ENABLE_T_TO_T :
case EFC_NODE_ENABLE_I_TO_T :
case EFC_NODE_ENABLE_IT_TO_T :
rc = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_TARGET_MISSING ) ;
break ;
case EFC_NODE_ENABLE_T_TO_I :
case EFC_NODE_ENABLE_I_TO_I :
case EFC_NODE_ENABLE_IT_TO_I :
rc = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_INITIATOR_MISSING ) ;
break ;
case EFC_NODE_ENABLE_T_TO_IT :
rc = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_INITIATOR_MISSING ) ;
break ;
case EFC_NODE_ENABLE_I_TO_IT :
rc = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_TARGET_MISSING ) ;
break ;
case EFC_NODE_ENABLE_IT_TO_IT :
rc = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_INITIATOR_MISSING ) ;
rc_2 = efc - > tt . scsi_del_node ( efc , node ,
EFC_SCSI_TARGET_MISSING ) ;
break ;
default :
rc = EFC_SCSI_CALL_COMPLETE ;
break ;
}
if ( rc = = EFC_SCSI_CALL_COMPLETE & &
rc_2 = = EFC_SCSI_CALL_COMPLETE )
efc_node_post_event ( node , EFC_EVT_SHUTDOWN , NULL ) ;
break ;
}
case EFC_EVT_NODE_REFOUND :
/* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */
/* reauthenticate with PLOGI/PRLI */
/* efc_node_transition(node, __efc_d_discovered, NULL); */
/* reauthenticate with ADISC */
/* sm: / send ADISC */
efc_send_adisc ( node ) ;
efc_node_transition ( node , __efc_d_wait_adisc_rsp , NULL ) ;
break ;
case EFC_EVT_PLOGI_RCVD : {
/* sm: / save sparams, set send_plogi_acc, post implicit
* logout
* Save plogi parameters
*/
efc_node_save_sparms ( node , cbdata - > payload - > dma . virt ) ;
efc_send_ls_acc_after_attach ( node ,
cbdata - > header - > dma . virt ,
EFC_NODE_SEND_LS_ACC_PLOGI ) ;
/*
* Restart node attach with new service parameters , and send
* ACC
*/
efc_node_post_event ( node , EFC_EVT_SHUTDOWN_IMPLICIT_LOGO ,
NULL ) ;
break ;
}
case EFC_EVT_FCP_CMD_RCVD : {
/* most likely a stale frame (received prior to link down),
* if attempt to send LOGO , will probably timeout and eat
* up 20 s ; thus , drop FCP_CMND
*/
node_printf ( node , " FCP_CMND received, drop \n " ) ;
break ;
}
case EFC_EVT_LOGO_RCVD : {
/* I, T, I+T */
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
node_printf ( node , " %s received attached=%d \n " ,
efc_sm_event_name ( evt ) , node - > attached ) ;
/* sm: / send LOGO acc */
efc_send_logo_acc ( node , be16_to_cpu ( hdr - > fh_ox_id ) ) ;
efc_node_transition ( node , __efc_d_wait_logo_acc_cmpl , NULL ) ;
break ;
}
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}
void
__efc_d_wait_adisc_rsp ( struct efc_sm_ctx * ctx ,
enum efc_sm_event evt , void * arg )
{
struct efc_node_cb * cbdata = arg ;
struct efc_node * node = ctx - > app ;
efc_node_evt_set ( ctx , evt , __func__ ) ;
node_sm_trace ( ) ;
switch ( evt ) {
case EFC_EVT_SRRS_ELS_REQ_OK :
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_ADISC ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
efc_node_transition ( node , __efc_d_device_ready , NULL ) ;
break ;
case EFC_EVT_SRRS_ELS_REQ_RJT :
/* received an LS_RJT, in this case, send shutdown
* ( explicit logo ) event which will unregister the node ,
* and start over with PLOGI
*/
if ( efc_node_check_els_req ( ctx , evt , arg , ELS_ADISC ,
__efc_d_common , __func__ ) )
return ;
WARN_ON ( ! node - > els_req_cnt ) ;
node - > els_req_cnt - - ;
/* sm: / post explicit logout */
efc_node_post_event ( node ,
EFC_EVT_SHUTDOWN_EXPLICIT_LOGO ,
NULL ) ;
break ;
case EFC_EVT_LOGO_RCVD : {
/* In this case, we have the equivalent of an LS_RJT for
* the ADISC , so we need to abort the ADISC , and re - login
* with PLOGI
*/
/* sm: / request abort, send LOGO acc */
struct fc_frame_header * hdr = cbdata - > header - > dma . virt ;
node_printf ( node , " %s received attached=%d \n " ,
efc_sm_event_name ( evt ) , node - > attached ) ;
efc_send_logo_acc ( node , be16_to_cpu ( hdr - > fh_ox_id ) ) ;
efc_node_transition ( node , __efc_d_wait_logo_acc_cmpl , NULL ) ;
break ;
}
default :
__efc_d_common ( __func__ , ctx , evt , arg ) ;
}
}