2009-09-24 04:46:15 +04:00
/*
* Copyright ( c ) 2005 - 2009 Brocade Communications Systems , Inc .
* All rights reserved
* www . brocade . com
*
* Linux driver for Brocade Fibre Channel Host Bus Adapter .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License ( GPL ) Version 2 as
* published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*/
/**
* bfa_fcs_port . c BFA FCS port
*/
# include <fcs/bfa_fcs.h>
# include <fcs/bfa_fcs_lport.h>
# include <fcs/bfa_fcs_rport.h>
# include <fcb/bfa_fcb_port.h>
# include <bfa_svc.h>
# include <log/bfa_log_fcs.h>
# include "fcs.h"
# include "fcs_lport.h"
# include "fcs_vport.h"
# include "fcs_rport.h"
# include "fcs_fcxp.h"
# include "fcs_trcmod.h"
# include "lport_priv.h"
# include <aen/bfa_aen_lport.h>
BFA_TRC_FILE ( FCS , PORT ) ;
/**
* Forward declarations
*/
static void bfa_fcs_port_aen_post ( struct bfa_fcs_port_s * port ,
enum bfa_lport_aen_event event ) ;
static void bfa_fcs_port_send_ls_rjt ( struct bfa_fcs_port_s * port ,
struct fchs_s * rx_fchs , u8 reason_code ,
u8 reason_code_expl ) ;
static void bfa_fcs_port_plogi ( struct bfa_fcs_port_s * port ,
struct fchs_s * rx_fchs ,
struct fc_logi_s * plogi ) ;
static void bfa_fcs_port_online_actions ( struct bfa_fcs_port_s * port ) ;
static void bfa_fcs_port_offline_actions ( struct bfa_fcs_port_s * port ) ;
static void bfa_fcs_port_unknown_init ( struct bfa_fcs_port_s * port ) ;
static void bfa_fcs_port_unknown_online ( struct bfa_fcs_port_s * port ) ;
static void bfa_fcs_port_unknown_offline ( struct bfa_fcs_port_s * port ) ;
static void bfa_fcs_port_deleted ( struct bfa_fcs_port_s * port ) ;
static void bfa_fcs_port_echo ( struct bfa_fcs_port_s * port ,
struct fchs_s * rx_fchs ,
struct fc_echo_s * echo , u16 len ) ;
static void bfa_fcs_port_rnid ( struct bfa_fcs_port_s * port ,
struct fchs_s * rx_fchs ,
struct fc_rnid_cmd_s * rnid , u16 len ) ;
static void bfa_fs_port_get_gen_topo_data ( struct bfa_fcs_port_s * port ,
struct fc_rnid_general_topology_data_s * gen_topo_data ) ;
static struct {
void ( * init ) ( struct bfa_fcs_port_s * port ) ;
void ( * online ) ( struct bfa_fcs_port_s * port ) ;
void ( * offline ) ( struct bfa_fcs_port_s * port ) ;
} __port_action [ ] = {
{
bfa_fcs_port_unknown_init , bfa_fcs_port_unknown_online ,
bfa_fcs_port_unknown_offline } , {
bfa_fcs_port_fab_init , bfa_fcs_port_fab_online ,
bfa_fcs_port_fab_offline } , {
bfa_fcs_port_loop_init , bfa_fcs_port_loop_online ,
bfa_fcs_port_loop_offline } , {
bfa_fcs_port_n2n_init , bfa_fcs_port_n2n_online ,
bfa_fcs_port_n2n_offline } , } ;
/**
* fcs_port_sm FCS logical port state machine
*/
enum bfa_fcs_port_event {
BFA_FCS_PORT_SM_CREATE = 1 ,
BFA_FCS_PORT_SM_ONLINE = 2 ,
BFA_FCS_PORT_SM_OFFLINE = 3 ,
BFA_FCS_PORT_SM_DELETE = 4 ,
BFA_FCS_PORT_SM_DELRPORT = 5 ,
} ;
static void bfa_fcs_port_sm_uninit ( struct bfa_fcs_port_s * port ,
enum bfa_fcs_port_event event ) ;
static void bfa_fcs_port_sm_init ( struct bfa_fcs_port_s * port ,
enum bfa_fcs_port_event event ) ;
static void bfa_fcs_port_sm_online ( struct bfa_fcs_port_s * port ,
enum bfa_fcs_port_event event ) ;
static void bfa_fcs_port_sm_offline ( struct bfa_fcs_port_s * port ,
enum bfa_fcs_port_event event ) ;
static void bfa_fcs_port_sm_deleting ( struct bfa_fcs_port_s * port ,
enum bfa_fcs_port_event event ) ;
static void
bfa_fcs_port_sm_uninit ( struct bfa_fcs_port_s * port ,
enum bfa_fcs_port_event event )
{
bfa_trc ( port - > fcs , port - > port_cfg . pwwn ) ;
bfa_trc ( port - > fcs , event ) ;
switch ( event ) {
case BFA_FCS_PORT_SM_CREATE :
bfa_sm_set_state ( port , bfa_fcs_port_sm_init ) ;
break ;
default :
2010-03-06 06:35:02 +03:00
bfa_sm_fault ( port - > fcs , event ) ;
2009-09-24 04:46:15 +04:00
}
}
static void
bfa_fcs_port_sm_init ( struct bfa_fcs_port_s * port , enum bfa_fcs_port_event event )
{
bfa_trc ( port - > fcs , port - > port_cfg . pwwn ) ;
bfa_trc ( port - > fcs , event ) ;
switch ( event ) {
case BFA_FCS_PORT_SM_ONLINE :
bfa_sm_set_state ( port , bfa_fcs_port_sm_online ) ;
bfa_fcs_port_online_actions ( port ) ;
break ;
case BFA_FCS_PORT_SM_DELETE :
bfa_sm_set_state ( port , bfa_fcs_port_sm_uninit ) ;
bfa_fcs_port_deleted ( port ) ;
break ;
2010-07-09 06:52:46 +04:00
case BFA_FCS_PORT_SM_OFFLINE :
break ;
2009-09-24 04:46:15 +04:00
default :
2010-03-06 06:35:02 +03:00
bfa_sm_fault ( port - > fcs , event ) ;
2009-09-24 04:46:15 +04:00
}
}
static void
bfa_fcs_port_sm_online ( struct bfa_fcs_port_s * port ,
enum bfa_fcs_port_event event )
{
struct bfa_fcs_rport_s * rport ;
struct list_head * qe , * qen ;
bfa_trc ( port - > fcs , port - > port_cfg . pwwn ) ;
bfa_trc ( port - > fcs , event ) ;
switch ( event ) {
case BFA_FCS_PORT_SM_OFFLINE :
bfa_sm_set_state ( port , bfa_fcs_port_sm_offline ) ;
bfa_fcs_port_offline_actions ( port ) ;
break ;
case BFA_FCS_PORT_SM_DELETE :
__port_action [ port - > fabric - > fab_type ] . offline ( port ) ;
if ( port - > num_rports = = 0 ) {
bfa_sm_set_state ( port , bfa_fcs_port_sm_uninit ) ;
bfa_fcs_port_deleted ( port ) ;
} else {
bfa_sm_set_state ( port , bfa_fcs_port_sm_deleting ) ;
list_for_each_safe ( qe , qen , & port - > rport_q ) {
rport = ( struct bfa_fcs_rport_s * ) qe ;
bfa_fcs_rport_delete ( rport ) ;
}
}
break ;
case BFA_FCS_PORT_SM_DELRPORT :
break ;
default :
2010-03-06 06:35:02 +03:00
bfa_sm_fault ( port - > fcs , event ) ;
2009-09-24 04:46:15 +04:00
}
}
static void
bfa_fcs_port_sm_offline ( struct bfa_fcs_port_s * port ,
enum bfa_fcs_port_event event )
{
struct bfa_fcs_rport_s * rport ;
struct list_head * qe , * qen ;
bfa_trc ( port - > fcs , port - > port_cfg . pwwn ) ;
bfa_trc ( port - > fcs , event ) ;
switch ( event ) {
case BFA_FCS_PORT_SM_ONLINE :
bfa_sm_set_state ( port , bfa_fcs_port_sm_online ) ;
bfa_fcs_port_online_actions ( port ) ;
break ;
case BFA_FCS_PORT_SM_DELETE :
if ( port - > num_rports = = 0 ) {
bfa_sm_set_state ( port , bfa_fcs_port_sm_uninit ) ;
bfa_fcs_port_deleted ( port ) ;
} else {
bfa_sm_set_state ( port , bfa_fcs_port_sm_deleting ) ;
list_for_each_safe ( qe , qen , & port - > rport_q ) {
rport = ( struct bfa_fcs_rport_s * ) qe ;
bfa_fcs_rport_delete ( rport ) ;
}
}
break ;
case BFA_FCS_PORT_SM_DELRPORT :
case BFA_FCS_PORT_SM_OFFLINE :
break ;
default :
2010-03-06 06:35:02 +03:00
bfa_sm_fault ( port - > fcs , event ) ;
2009-09-24 04:46:15 +04:00
}
}
static void
bfa_fcs_port_sm_deleting ( struct bfa_fcs_port_s * port ,
enum bfa_fcs_port_event event )
{
bfa_trc ( port - > fcs , port - > port_cfg . pwwn ) ;
bfa_trc ( port - > fcs , event ) ;
switch ( event ) {
case BFA_FCS_PORT_SM_DELRPORT :
if ( port - > num_rports = = 0 ) {
bfa_sm_set_state ( port , bfa_fcs_port_sm_uninit ) ;
bfa_fcs_port_deleted ( port ) ;
}
break ;
default :
2010-03-06 06:35:02 +03:00
bfa_sm_fault ( port - > fcs , event ) ;
2009-09-24 04:46:15 +04:00
}
}
/**
* fcs_port_pvt
*/
/**
* Send AEN notification
*/
static void
bfa_fcs_port_aen_post ( struct bfa_fcs_port_s * port ,
enum bfa_lport_aen_event event )
{
union bfa_aen_data_u aen_data ;
struct bfa_log_mod_s * logmod = port - > fcs - > logm ;
enum bfa_port_role role = port - > port_cfg . roles ;
wwn_t lpwwn = bfa_fcs_port_get_pwwn ( port ) ;
char lpwwn_ptr [ BFA_STRING_32 ] ;
char * role_str [ BFA_PORT_ROLE_FCP_MAX / 2 + 1 ] =
{ " Initiator " , " Target " , " IPFC " } ;
wwn2str ( lpwwn_ptr , lpwwn ) ;
bfa_assert ( role < = BFA_PORT_ROLE_FCP_MAX ) ;
2010-03-06 06:37:57 +03:00
bfa_log ( logmod , BFA_LOG_CREATE_ID ( BFA_AEN_CAT_LPORT , event ) , lpwwn_ptr ,
role_str [ role / 2 ] ) ;
2009-09-24 04:46:15 +04:00
aen_data . lport . vf_id = port - > fabric - > vf_id ;
aen_data . lport . roles = role ;
aen_data . lport . ppwwn =
bfa_fcs_port_get_pwwn ( bfa_fcs_get_base_port ( port - > fcs ) ) ;
aen_data . lport . lpwwn = lpwwn ;
}
/*
* Send a LS reject
*/
static void
bfa_fcs_port_send_ls_rjt ( struct bfa_fcs_port_s * port , struct fchs_s * rx_fchs ,
u8 reason_code , u8 reason_code_expl )
{
struct fchs_s fchs ;
struct bfa_fcxp_s * fcxp ;
struct bfa_rport_s * bfa_rport = NULL ;
int len ;
bfa_trc ( port - > fcs , rx_fchs - > s_id ) ;
fcxp = bfa_fcs_fcxp_alloc ( port - > fcs ) ;
if ( ! fcxp )
return ;
len = fc_ls_rjt_build ( & fchs , bfa_fcxp_get_reqbuf ( fcxp ) , rx_fchs - > s_id ,
bfa_fcs_port_get_fcid ( port ) , rx_fchs - > ox_id ,
reason_code , reason_code_expl ) ;
bfa_fcxp_send ( fcxp , bfa_rport , port - > fabric - > vf_id , port - > lp_tag ,
BFA_FALSE , FC_CLASS_3 , len , & fchs , NULL , NULL ,
FC_MAX_PDUSZ , 0 ) ;
}
/**
* Process incoming plogi from a remote port .
*/
static void
bfa_fcs_port_plogi ( struct bfa_fcs_port_s * port , struct fchs_s * rx_fchs ,
struct fc_logi_s * plogi )
{
struct bfa_fcs_rport_s * rport ;
bfa_trc ( port - > fcs , rx_fchs - > d_id ) ;
bfa_trc ( port - > fcs , rx_fchs - > s_id ) ;
/*
* If min cfg mode is enabled , drop any incoming PLOGIs
*/
if ( __fcs_min_cfg ( port - > fcs ) ) {
bfa_trc ( port - > fcs , rx_fchs - > s_id ) ;
return ;
}
if ( fc_plogi_parse ( rx_fchs ) ! = FC_PARSE_OK ) {
bfa_trc ( port - > fcs , rx_fchs - > s_id ) ;
/*
* send a LS reject
*/
bfa_fcs_port_send_ls_rjt ( port , rx_fchs ,
FC_LS_RJT_RSN_PROTOCOL_ERROR ,
FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS ) ;
return ;
}
/**
* Direct Attach P2P mode : verify address assigned by the r - port .
*/
if ( ( ! bfa_fcs_fabric_is_switched ( port - > fabric ) )
& &
( memcmp
( ( void * ) & bfa_fcs_port_get_pwwn ( port ) , ( void * ) & plogi - > port_name ,
sizeof ( wwn_t ) ) < 0 ) ) {
if ( BFA_FCS_PID_IS_WKA ( rx_fchs - > d_id ) ) {
/*
* Address assigned to us cannot be a WKA
*/
bfa_fcs_port_send_ls_rjt ( port , rx_fchs ,
FC_LS_RJT_RSN_PROTOCOL_ERROR ,
FC_LS_RJT_EXP_INVALID_NPORT_ID ) ;
return ;
}
port - > pid = rx_fchs - > d_id ;
}
/**
* First , check if we know the device by pwwn .
*/
rport = bfa_fcs_port_get_rport_by_pwwn ( port , plogi - > port_name ) ;
if ( rport ) {
/**
* Direct Attach P2P mode : handle address assigned by the rport .
*/
if ( ( ! bfa_fcs_fabric_is_switched ( port - > fabric ) )
& &
( memcmp
( ( void * ) & bfa_fcs_port_get_pwwn ( port ) ,
( void * ) & plogi - > port_name , sizeof ( wwn_t ) ) < 0 ) ) {
port - > pid = rx_fchs - > d_id ;
rport - > pid = rx_fchs - > s_id ;
}
bfa_fcs_rport_plogi ( rport , rx_fchs , plogi ) ;
return ;
}
/**
* Next , lookup rport by PID .
*/
rport = bfa_fcs_port_get_rport_by_pid ( port , rx_fchs - > s_id ) ;
if ( ! rport ) {
/**
* Inbound PLOGI from a new device .
*/
bfa_fcs_rport_plogi_create ( port , rx_fchs , plogi ) ;
return ;
}
/**
* Rport is known only by PID .
*/
if ( rport - > pwwn ) {
/**
* This is a different device with the same pid . Old device
* disappeared . Send implicit LOGO to old device .
*/
bfa_assert ( rport - > pwwn ! = plogi - > port_name ) ;
bfa_fcs_rport_logo_imp ( rport ) ;
/**
* Inbound PLOGI from a new device ( with old PID ) .
*/
bfa_fcs_rport_plogi_create ( port , rx_fchs , plogi ) ;
return ;
}
/**
* PLOGI crossing each other .
*/
bfa_assert ( rport - > pwwn = = WWN_NULL ) ;
bfa_fcs_rport_plogi ( rport , rx_fchs , plogi ) ;
}
/*
* Process incoming ECHO .
* Since it does not require a login , it is processed here .
*/
static void
bfa_fcs_port_echo ( struct bfa_fcs_port_s * port , struct fchs_s * rx_fchs ,
struct fc_echo_s * echo , u16 rx_len )
{
struct fchs_s fchs ;
struct bfa_fcxp_s * fcxp ;
struct bfa_rport_s * bfa_rport = NULL ;
int len , pyld_len ;
bfa_trc ( port - > fcs , rx_fchs - > s_id ) ;
bfa_trc ( port - > fcs , rx_fchs - > d_id ) ;
bfa_trc ( port - > fcs , rx_len ) ;
fcxp = bfa_fcs_fcxp_alloc ( port - > fcs ) ;
if ( ! fcxp )
return ;
len = fc_ls_acc_build ( & fchs , bfa_fcxp_get_reqbuf ( fcxp ) , rx_fchs - > s_id ,
bfa_fcs_port_get_fcid ( port ) , rx_fchs - > ox_id ) ;
/*
* Copy the payload ( if any ) from the echo frame
*/
pyld_len = rx_len - sizeof ( struct fchs_s ) ;
bfa_trc ( port - > fcs , pyld_len ) ;
if ( pyld_len > len )
memcpy ( ( ( u8 * ) bfa_fcxp_get_reqbuf ( fcxp ) ) +
sizeof ( struct fc_echo_s ) , ( echo + 1 ) ,
( pyld_len - sizeof ( struct fc_echo_s ) ) ) ;
bfa_fcxp_send ( fcxp , bfa_rport , port - > fabric - > vf_id , port - > lp_tag ,
BFA_FALSE , FC_CLASS_3 , pyld_len , & fchs , NULL , NULL ,
FC_MAX_PDUSZ , 0 ) ;
}
/*
* Process incoming RNID .
* Since it does not require a login , it is processed here .
*/
static void
bfa_fcs_port_rnid ( struct bfa_fcs_port_s * port , struct fchs_s * rx_fchs ,
struct fc_rnid_cmd_s * rnid , u16 rx_len )
{
struct fc_rnid_common_id_data_s common_id_data ;
struct fc_rnid_general_topology_data_s gen_topo_data ;
struct fchs_s fchs ;
struct bfa_fcxp_s * fcxp ;
struct bfa_rport_s * bfa_rport = NULL ;
u16 len ;
u32 data_format ;
bfa_trc ( port - > fcs , rx_fchs - > s_id ) ;
bfa_trc ( port - > fcs , rx_fchs - > d_id ) ;
bfa_trc ( port - > fcs , rx_len ) ;
fcxp = bfa_fcs_fcxp_alloc ( port - > fcs ) ;
if ( ! fcxp )
return ;
/*
* Check Node Indentification Data Format
* We only support General Topology Discovery Format .
* For any other requested Data Formats , we return Common Node Id Data
* only , as per FC - LS .
*/
bfa_trc ( port - > fcs , rnid - > node_id_data_format ) ;
if ( rnid - > node_id_data_format = = RNID_NODEID_DATA_FORMAT_DISCOVERY ) {
data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY ;
/*
* Get General topology data for this port
*/
bfa_fs_port_get_gen_topo_data ( port , & gen_topo_data ) ;
} else {
data_format = RNID_NODEID_DATA_FORMAT_COMMON ;
}
/*
* Copy the Node Id Info
*/
common_id_data . port_name = bfa_fcs_port_get_pwwn ( port ) ;
common_id_data . node_name = bfa_fcs_port_get_nwwn ( port ) ;
len = fc_rnid_acc_build ( & fchs , bfa_fcxp_get_reqbuf ( fcxp ) , rx_fchs - > s_id ,
bfa_fcs_port_get_fcid ( port ) , rx_fchs - > ox_id ,
data_format , & common_id_data , & gen_topo_data ) ;
bfa_fcxp_send ( fcxp , bfa_rport , port - > fabric - > vf_id , port - > lp_tag ,
BFA_FALSE , FC_CLASS_3 , len , & fchs , NULL , NULL ,
FC_MAX_PDUSZ , 0 ) ;
return ;
}
/*
* Fill out General Topolpgy Discovery Data for RNID ELS .
*/
static void
bfa_fs_port_get_gen_topo_data ( struct bfa_fcs_port_s * port ,
struct fc_rnid_general_topology_data_s * gen_topo_data )
{
bfa_os_memset ( gen_topo_data , 0 ,
sizeof ( struct fc_rnid_general_topology_data_s ) ) ;
gen_topo_data - > asso_type = bfa_os_htonl ( RNID_ASSOCIATED_TYPE_HOST ) ;
gen_topo_data - > phy_port_num = 0 ; /* @todo */
gen_topo_data - > num_attached_nodes = bfa_os_htonl ( 1 ) ;
}
static void
bfa_fcs_port_online_actions ( struct bfa_fcs_port_s * port )
{
bfa_trc ( port - > fcs , port - > fabric - > oper_type ) ;
__port_action [ port - > fabric - > fab_type ] . init ( port ) ;
__port_action [ port - > fabric - > fab_type ] . online ( port ) ;
bfa_fcs_port_aen_post ( port , BFA_LPORT_AEN_ONLINE ) ;
bfa_fcb_port_online ( port - > fcs - > bfad , port - > port_cfg . roles ,
port - > fabric - > vf_drv , ( port - > vport = = NULL ) ?
NULL : port - > vport - > vport_drv ) ;
}
static void
bfa_fcs_port_offline_actions ( struct bfa_fcs_port_s * port )
{
struct list_head * qe , * qen ;
struct bfa_fcs_rport_s * rport ;
bfa_trc ( port - > fcs , port - > fabric - > oper_type ) ;
__port_action [ port - > fabric - > fab_type ] . offline ( port ) ;
2009-09-25 23:29:54 +04:00
if ( bfa_fcs_fabric_is_online ( port - > fabric ) = = BFA_TRUE )
2009-09-24 04:46:15 +04:00
bfa_fcs_port_aen_post ( port , BFA_LPORT_AEN_DISCONNECT ) ;
2009-09-25 23:29:54 +04:00
else
2009-09-24 04:46:15 +04:00
bfa_fcs_port_aen_post ( port , BFA_LPORT_AEN_OFFLINE ) ;
bfa_fcb_port_offline ( port - > fcs - > bfad , port - > port_cfg . roles ,
port - > fabric - > vf_drv ,
( port - > vport = = NULL ) ? NULL : port - > vport - > vport_drv ) ;
list_for_each_safe ( qe , qen , & port - > rport_q ) {
rport = ( struct bfa_fcs_rport_s * ) qe ;
bfa_fcs_rport_offline ( rport ) ;
}
}
static void
bfa_fcs_port_unknown_init ( struct bfa_fcs_port_s * port )
{
bfa_assert ( 0 ) ;
}
static void
bfa_fcs_port_unknown_online ( struct bfa_fcs_port_s * port )
{
bfa_assert ( 0 ) ;
}
static void
bfa_fcs_port_unknown_offline ( struct bfa_fcs_port_s * port )
{
bfa_assert ( 0 ) ;
}
static void
bfa_fcs_port_deleted ( struct bfa_fcs_port_s * port )
{
bfa_fcs_port_aen_post ( port , BFA_LPORT_AEN_DELETE ) ;
/*
* Base port will be deleted by the OS driver
*/
if ( port - > vport ) {
bfa_fcb_port_delete ( port - > fcs - > bfad , port - > port_cfg . roles ,
port - > fabric - > vf_drv ,
port - > vport ? port - > vport - > vport_drv : NULL ) ;
bfa_fcs_vport_delete_comp ( port - > vport ) ;
} else {
bfa_fcs_fabric_port_delete_comp ( port - > fabric ) ;
}
}
/**
* fcs_lport_api BFA FCS port API
*/
/**
* Module initialization
*/
void
bfa_fcs_port_modinit ( struct bfa_fcs_s * fcs )
{
}
/**
* Module cleanup
*/
void
bfa_fcs_port_modexit ( struct bfa_fcs_s * fcs )
{
bfa_fcs_modexit_comp ( fcs ) ;
}
/**
* Unsolicited frame receive handling .
*/
void
bfa_fcs_port_uf_recv ( struct bfa_fcs_port_s * lport , struct fchs_s * fchs ,
u16 len )
{
u32 pid = fchs - > s_id ;
struct bfa_fcs_rport_s * rport = NULL ;
struct fc_els_cmd_s * els_cmd = ( struct fc_els_cmd_s * ) ( fchs + 1 ) ;
bfa_stats ( lport , uf_recvs ) ;
if ( ! bfa_fcs_port_is_online ( lport ) ) {
bfa_stats ( lport , uf_recv_drops ) ;
return ;
}
/**
* First , handle ELSs that donot require a login .
*/
/*
* Handle PLOGI first
*/
if ( ( fchs - > type = = FC_TYPE_ELS ) & &
( els_cmd - > els_code = = FC_ELS_PLOGI ) ) {
bfa_fcs_port_plogi ( lport , fchs , ( struct fc_logi_s * ) els_cmd ) ;
return ;
}
/*
* Handle ECHO separately .
*/
if ( ( fchs - > type = = FC_TYPE_ELS ) & & ( els_cmd - > els_code = = FC_ELS_ECHO ) ) {
bfa_fcs_port_echo ( lport , fchs ,
( struct fc_echo_s * ) els_cmd , len ) ;
return ;
}
/*
* Handle RNID separately .
*/
if ( ( fchs - > type = = FC_TYPE_ELS ) & & ( els_cmd - > els_code = = FC_ELS_RNID ) ) {
bfa_fcs_port_rnid ( lport , fchs ,
( struct fc_rnid_cmd_s * ) els_cmd , len ) ;
return ;
}
/**
* look for a matching remote port ID
*/
rport = bfa_fcs_port_get_rport_by_pid ( lport , pid ) ;
if ( rport ) {
bfa_trc ( rport - > fcs , fchs - > s_id ) ;
bfa_trc ( rport - > fcs , fchs - > d_id ) ;
bfa_trc ( rport - > fcs , fchs - > type ) ;
bfa_fcs_rport_uf_recv ( rport , fchs , len ) ;
return ;
}
/**
* Only handles ELS frames for now .
*/
if ( fchs - > type ! = FC_TYPE_ELS ) {
bfa_trc ( lport - > fcs , fchs - > type ) ;
bfa_assert ( 0 ) ;
return ;
}
bfa_trc ( lport - > fcs , els_cmd - > els_code ) ;
if ( els_cmd - > els_code = = FC_ELS_RSCN ) {
bfa_fcs_port_scn_process_rscn ( lport , fchs , len ) ;
return ;
}
if ( els_cmd - > els_code = = FC_ELS_LOGO ) {
/**
* @ todo Handle LOGO frames received .
*/
bfa_trc ( lport - > fcs , els_cmd - > els_code ) ;
return ;
}
if ( els_cmd - > els_code = = FC_ELS_PRLI ) {
/**
* @ todo Handle PRLI frames received .
*/
bfa_trc ( lport - > fcs , els_cmd - > els_code ) ;
return ;
}
/**
* Unhandled ELS frames . Send a LS_RJT .
*/
bfa_fcs_port_send_ls_rjt ( lport , fchs , FC_LS_RJT_RSN_CMD_NOT_SUPP ,
FC_LS_RJT_EXP_NO_ADDL_INFO ) ;
}
/**
* PID based Lookup for a R - Port in the Port R - Port Queue
*/
struct bfa_fcs_rport_s *
bfa_fcs_port_get_rport_by_pid ( struct bfa_fcs_port_s * port , u32 pid )
{
struct bfa_fcs_rport_s * rport ;
struct list_head * qe ;
list_for_each ( qe , & port - > rport_q ) {
rport = ( struct bfa_fcs_rport_s * ) qe ;
if ( rport - > pid = = pid )
return rport ;
}
bfa_trc ( port - > fcs , pid ) ;
return NULL ;
}
/**
* PWWN based Lookup for a R - Port in the Port R - Port Queue
*/
struct bfa_fcs_rport_s *
bfa_fcs_port_get_rport_by_pwwn ( struct bfa_fcs_port_s * port , wwn_t pwwn )
{
struct bfa_fcs_rport_s * rport ;
struct list_head * qe ;
list_for_each ( qe , & port - > rport_q ) {
rport = ( struct bfa_fcs_rport_s * ) qe ;
if ( wwn_is_equal ( rport - > pwwn , pwwn ) )
return rport ;
}
bfa_trc ( port - > fcs , pwwn ) ;
2009-09-25 23:29:54 +04:00
return NULL ;
2009-09-24 04:46:15 +04:00
}
/**
* NWWN based Lookup for a R - Port in the Port R - Port Queue
*/
struct bfa_fcs_rport_s *
bfa_fcs_port_get_rport_by_nwwn ( struct bfa_fcs_port_s * port , wwn_t nwwn )
{
struct bfa_fcs_rport_s * rport ;
struct list_head * qe ;
list_for_each ( qe , & port - > rport_q ) {
rport = ( struct bfa_fcs_rport_s * ) qe ;
if ( wwn_is_equal ( rport - > nwwn , nwwn ) )
return rport ;
}
bfa_trc ( port - > fcs , nwwn ) ;
2009-09-25 23:29:54 +04:00
return NULL ;
2009-09-24 04:46:15 +04:00
}
/**
* Called by rport module when new rports are discovered .
*/
void
bfa_fcs_port_add_rport ( struct bfa_fcs_port_s * port ,
struct bfa_fcs_rport_s * rport )
{
list_add_tail ( & rport - > qe , & port - > rport_q ) ;
port - > num_rports + + ;
}
/**
* Called by rport module to when rports are deleted .
*/
void
bfa_fcs_port_del_rport ( struct bfa_fcs_port_s * port ,
struct bfa_fcs_rport_s * rport )
{
bfa_assert ( bfa_q_is_on_q ( & port - > rport_q , rport ) ) ;
list_del ( & rport - > qe ) ;
port - > num_rports - - ;
bfa_sm_send_event ( port , BFA_FCS_PORT_SM_DELRPORT ) ;
}
/**
* Called by fabric for base port when fabric login is complete .
* Called by vport for virtual ports when FDISC is complete .
*/
void
bfa_fcs_port_online ( struct bfa_fcs_port_s * port )
{
bfa_sm_send_event ( port , BFA_FCS_PORT_SM_ONLINE ) ;
}
/**
* Called by fabric for base port when fabric goes offline .
* Called by vport for virtual ports when virtual port becomes offline .
*/
void
bfa_fcs_port_offline ( struct bfa_fcs_port_s * port )
{
bfa_sm_send_event ( port , BFA_FCS_PORT_SM_OFFLINE ) ;
}
/**
* Called by fabric to delete base lport and associated resources .
*
* Called by vport to delete lport and associated resources . Should call
* bfa_fcs_vport_delete_comp ( ) for vports on completion .
*/
void
bfa_fcs_port_delete ( struct bfa_fcs_port_s * port )
{
bfa_sm_send_event ( port , BFA_FCS_PORT_SM_DELETE ) ;
}
/**
* Called by fabric in private loop topology to process LIP event .
*/
void
bfa_fcs_port_lip ( struct bfa_fcs_port_s * port )
{
}
/**
* Return TRUE if port is online , else return FALSE
*/
bfa_boolean_t
bfa_fcs_port_is_online ( struct bfa_fcs_port_s * port )
{
2009-09-25 23:29:54 +04:00
return bfa_sm_cmp_state ( port , bfa_fcs_port_sm_online ) ;
2009-09-24 04:46:15 +04:00
}
/**
2010-03-04 04:44:02 +03:00
* Attach time initialization of logical ports .
2009-09-24 04:46:15 +04:00
*/
void
2010-03-04 04:44:02 +03:00
bfa_fcs_lport_attach ( struct bfa_fcs_port_s * lport , struct bfa_fcs_s * fcs ,
uint16_t vf_id , struct bfa_fcs_vport_s * vport )
2009-09-24 04:46:15 +04:00
{
lport - > fcs = fcs ;
lport - > fabric = bfa_fcs_vf_lookup ( fcs , vf_id ) ;
lport - > vport = vport ;
lport - > lp_tag = ( vport ) ? bfa_lps_get_tag ( vport - > lps ) :
bfa_lps_get_tag ( lport - > fabric - > lps ) ;
INIT_LIST_HEAD ( & lport - > rport_q ) ;
lport - > num_rports = 0 ;
2010-03-04 04:44:02 +03:00
}
/**
* Logical port initialization of base or virtual port .
* Called by fabric for base port or by vport for virtual ports .
*/
2009-09-24 04:46:15 +04:00
2010-03-04 04:44:02 +03:00
void
bfa_fcs_lport_init ( struct bfa_fcs_port_s * lport ,
struct bfa_port_cfg_s * port_cfg )
{
struct bfa_fcs_vport_s * vport = lport - > vport ;
bfa_os_assign ( lport - > port_cfg , * port_cfg ) ;
lport - > bfad_port = bfa_fcb_port_new ( lport - > fcs - > bfad , lport ,
lport - > port_cfg . roles ,
2009-09-24 04:46:15 +04:00
lport - > fabric - > vf_drv ,
vport ? vport - > vport_drv : NULL ) ;
2010-03-04 04:44:02 +03:00
2009-09-24 04:46:15 +04:00
bfa_fcs_port_aen_post ( lport , BFA_LPORT_AEN_NEW ) ;
bfa_sm_set_state ( lport , bfa_fcs_port_sm_uninit ) ;
bfa_sm_send_event ( lport , BFA_FCS_PORT_SM_CREATE ) ;
}
/**
* fcs_lport_api
*/
void
bfa_fcs_port_get_attr ( struct bfa_fcs_port_s * port ,
struct bfa_port_attr_s * port_attr )
{
if ( bfa_sm_cmp_state ( port , bfa_fcs_port_sm_online ) )
port_attr - > pid = port - > pid ;
else
port_attr - > pid = 0 ;
port_attr - > port_cfg = port - > port_cfg ;
if ( port - > fabric ) {
port_attr - > port_type = bfa_fcs_fabric_port_type ( port - > fabric ) ;
port_attr - > loopback = bfa_fcs_fabric_is_loopback ( port - > fabric ) ;
2010-03-06 06:36:00 +03:00
port_attr - > authfail =
bfa_fcs_fabric_is_auth_failed ( port - > fabric ) ;
2009-09-24 04:46:15 +04:00
port_attr - > fabric_name = bfa_fcs_port_get_fabric_name ( port ) ;
memcpy ( port_attr - > fabric_ip_addr ,
bfa_fcs_port_get_fabric_ipaddr ( port ) ,
BFA_FCS_FABRIC_IPADDR_SZ ) ;
2010-03-06 06:35:33 +03:00
if ( port - > vport ! = NULL ) {
2009-09-24 04:46:15 +04:00
port_attr - > port_type = BFA_PPORT_TYPE_VPORT ;
2010-03-06 06:35:33 +03:00
port_attr - > fpma_mac =
bfa_lps_get_lp_mac ( port - > vport - > lps ) ;
} else
port_attr - > fpma_mac =
bfa_lps_get_lp_mac ( port - > fabric - > lps ) ;
2009-09-24 04:46:15 +04:00
} else {
port_attr - > port_type = BFA_PPORT_TYPE_UNKNOWN ;
port_attr - > state = BFA_PORT_UNINIT ;
}
}