2005-04-16 15:20:36 -07:00
/******************************************************************************
*
* ( C ) Copyright 1998 , 1999 SysKonnect ,
* a business unit of Schneider & Koch & Co . Datensysteme GmbH .
*
* See the file " skfddi.c " for further information .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* The information in this file is provided " AS IS " without warranty .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
PCM
Physical Connection Management
*/
/*
* Hardware independent state machine implemantation
* The following external SMT functions are referenced :
*
* queue_event ( )
* smt_timer_start ( )
* smt_timer_stop ( )
*
* The following external HW dependent functions are referenced :
* sm_pm_control ( )
* sm_ph_linestate ( )
* sm_pm_ls_latch ( )
*
* The following HW dependent events are required :
* PC_QLS
* PC_ILS
* PC_HLS
* PC_MLS
* PC_NSE
* PC_LEM
*
*/
# include "h/types.h"
# include "h/fddi.h"
# include "h/smc.h"
# include "h/supern_2.h"
# define KERNEL
# include "h/smtstate.h"
# ifndef lint
static const char ID_sccs [ ] = " @(#)pcmplc.c 2.55 99/08/05 (C) SK " ;
# endif
# ifdef FDDI_MIB
extern int snmp_fddi_trap (
# ifdef ANSIC
struct s_smc * smc , int type , int index
# endif
) ;
# endif
# ifdef CONCENTRATOR
extern int plc_is_installed (
# ifdef ANSIC
struct s_smc * smc ,
int p
# endif
) ;
# endif
/*
* FSM Macros
*/
# define AFLAG (0x20)
# define GO_STATE(x) (mib->fddiPORTPCMState = (x)|AFLAG)
# define ACTIONS_DONE() (mib->fddiPORTPCMState &= ~AFLAG)
# define ACTIONS(x) (x|AFLAG)
/*
* PCM states
*/
# define PC0_OFF 0
# define PC1_BREAK 1
# define PC2_TRACE 2
# define PC3_CONNECT 3
# define PC4_NEXT 4
# define PC5_SIGNAL 5
# define PC6_JOIN 6
# define PC7_VERIFY 7
# define PC8_ACTIVE 8
# define PC9_MAINT 9
# ifdef DEBUG
/*
* symbolic state names
*/
static const char * const pcm_states [ ] = {
" PC0_OFF " , " PC1_BREAK " , " PC2_TRACE " , " PC3_CONNECT " , " PC4_NEXT " ,
" PC5_SIGNAL " , " PC6_JOIN " , " PC7_VERIFY " , " PC8_ACTIVE " , " PC9_MAINT "
} ;
/*
* symbolic event names
*/
static const char * const pcm_events [ ] = {
" NONE " , " PC_START " , " PC_STOP " , " PC_LOOP " , " PC_JOIN " , " PC_SIGNAL " ,
" PC_REJECT " , " PC_MAINT " , " PC_TRACE " , " PC_PDR " ,
" PC_ENABLE " , " PC_DISABLE " ,
" PC_QLS " , " PC_ILS " , " PC_MLS " , " PC_HLS " , " PC_LS_PDR " , " PC_LS_NONE " ,
" PC_TIMEOUT_TB_MAX " , " PC_TIMEOUT_TB_MIN " ,
" PC_TIMEOUT_C_MIN " , " PC_TIMEOUT_T_OUT " ,
" PC_TIMEOUT_TL_MIN " , " PC_TIMEOUT_T_NEXT " , " PC_TIMEOUT_LCT " ,
" PC_NSE " , " PC_LEM "
} ;
# endif
# ifdef MOT_ELM
/*
* PCL - S control register
* this register in the PLC - S controls the scrambling parameters
*/
# define PLCS_CONTROL_C_U 0
# define PLCS_CONTROL_C_S (PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \
PL_C_CIPHER_ENABLE )
# define PLCS_FASSERT_U 0
# define PLCS_FASSERT_S 0xFd76 /* 52.0 us */
# define PLCS_FDEASSERT_U 0
# define PLCS_FDEASSERT_S 0
# else /* nMOT_ELM */
/*
* PCL - S control register
* this register in the PLC - S controls the scrambling parameters
* can be patched for ANSI compliance if standard changes
*/
static const u_char plcs_control_c_u [ 17 ] = " PLC_CNTRL_C_U= \0 \0 " ;
static const u_char plcs_control_c_s [ 17 ] = " PLC_CNTRL_C_S= \01 \02 " ;
# define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8))
# define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8))
# endif /* nMOT_ELM */
/*
* external vars
*/
/* struct definition see 'cmtdef.h' (also used by CFM) */
# define PS_OFF 0
# define PS_BIT3 1
# define PS_BIT4 2
# define PS_BIT7 3
# define PS_LCT 4
# define PS_BIT8 5
# define PS_JOIN 6
# define PS_ACTIVE 7
# define LCT_LEM_MAX 255
/*
* PLC timing parameter
*/
# define PLC_MS(m) ((int)((0x10000L-(m*100000L / 2048))))
# define SLOW_TL_MIN PLC_MS(6)
# define SLOW_C_MIN PLC_MS(10)
static const struct plt {
int timer ; /* relative plc timer address */
int para ; /* default timing parameters */
} pltm [ ] = {
{ PL_C_MIN , SLOW_C_MIN } , /* min t. to remain Connect State */
{ PL_TL_MIN , SLOW_TL_MIN } , /* min t. to transmit a Line State */
{ PL_TB_MIN , TP_TB_MIN } , /* min break time */
{ PL_T_OUT , TP_T_OUT } , /* Signaling timeout */
{ PL_LC_LENGTH , TP_LC_LENGTH } , /* Link Confidence Test Time */
{ PL_T_SCRUB , TP_T_SCRUB } , /* Scrub Time == MAC TVX time ! */
{ PL_NS_MAX , TP_NS_MAX } , /* max t. that noise is tolerated */
{ 0 , 0 }
} ;
/*
* interrupt mask
*/
# ifdef SUPERNET_3
/*
* Do we need the EBUF error during signaling , too , to detect SUPERNET_3
* PLL bug ?
*/
2006-03-03 21:33:57 -05:00
static const int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
2005-04-16 15:20:36 -07:00
PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR ;
# else /* SUPERNET_3 */
/*
* We do NOT need the elasticity buffer error during signaling .
*/
static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
PL_PCM_ENABLED | PL_SELF_TEST ;
# endif /* SUPERNET_3 */
2006-03-03 21:33:57 -05:00
static const int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
2005-04-16 15:20:36 -07:00
PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR ;
/* external functions */
void all_selection_criteria ( struct s_smc * smc ) ;
/* internal functions */
static void pcm_fsm ( struct s_smc * smc , struct s_phy * phy , int cmd ) ;
static void pc_rcode_actions ( struct s_smc * smc , int bit , struct s_phy * phy ) ;
static void pc_tcode_actions ( struct s_smc * smc , const int bit , struct s_phy * phy ) ;
static void reset_lem_struct ( struct s_phy * phy ) ;
static void plc_init ( struct s_smc * smc , int p ) ;
static void sm_ph_lem_start ( struct s_smc * smc , int np , int threshold ) ;
static void sm_ph_lem_stop ( struct s_smc * smc , int np ) ;
static void sm_ph_linestate ( struct s_smc * smc , int phy , int ls ) ;
static void real_init_plc ( struct s_smc * smc ) ;
/*
* SMT timer interface
* start PCM timer 0
*/
static void start_pcm_timer0 ( struct s_smc * smc , u_long value , int event ,
struct s_phy * phy )
{
phy - > timer0_exp = FALSE ; /* clear timer event flag */
smt_timer_start ( smc , & phy - > pcm_timer0 , value ,
EV_TOKEN ( EVENT_PCM + phy - > np , event ) ) ;
}
/*
* SMT timer interface
* stop PCM timer 0
*/
static void stop_pcm_timer0 ( struct s_smc * smc , struct s_phy * phy )
{
if ( phy - > pcm_timer0 . tm_active )
smt_timer_stop ( smc , & phy - > pcm_timer0 ) ;
}
/*
init PCM state machine ( called by driver )
clear all PCM vars and flags
*/
void pcm_init ( struct s_smc * smc )
{
int i ;
int np ;
struct s_phy * phy ;
struct fddi_mib_p * mib ;
for ( np = 0 , phy = smc - > y ; np < NUMPHYS ; np + + , phy + + ) {
/* Indicates the type of PHY being used */
mib = phy - > mib ;
mib - > fddiPORTPCMState = ACTIONS ( PC0_OFF ) ;
phy - > np = np ;
switch ( smc - > s . sas ) {
# ifdef CONCENTRATOR
case SMT_SAS :
mib - > fddiPORTMy_Type = ( np = = PS ) ? TS : TM ;
break ;
case SMT_DAS :
mib - > fddiPORTMy_Type = ( np = = PA ) ? TA :
( np = = PB ) ? TB : TM ;
break ;
case SMT_NAC :
mib - > fddiPORTMy_Type = TM ;
break ;
# else
case SMT_SAS :
mib - > fddiPORTMy_Type = ( np = = PS ) ? TS : TNONE ;
mib - > fddiPORTHardwarePresent = ( np = = PS ) ? TRUE :
FALSE ;
# ifndef SUPERNET_3
smc - > y [ PA ] . mib - > fddiPORTPCMState = PC0_OFF ;
# else
smc - > y [ PB ] . mib - > fddiPORTPCMState = PC0_OFF ;
# endif
break ;
case SMT_DAS :
mib - > fddiPORTMy_Type = ( np = = PB ) ? TB : TA ;
break ;
# endif
}
/*
* set PMD - type
*/
phy - > pmd_scramble = 0 ;
switch ( phy - > pmd_type [ PMD_SK_PMD ] ) {
case ' P ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
break ;
case ' L ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_LCF ;
break ;
case ' D ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_TP ;
break ;
case ' S ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_TP ;
phy - > pmd_scramble = TRUE ;
break ;
case ' U ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_TP ;
phy - > pmd_scramble = TRUE ;
break ;
case ' 1 ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
break ;
case ' 2 ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
break ;
case ' 3 ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
break ;
case ' 4 ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
break ;
case ' H ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
break ;
case ' I ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_TP ;
break ;
case ' G ' :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_TP ;
break ;
default :
mib - > fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
break ;
}
/*
* A and B port can be on primary and secondary path
*/
switch ( mib - > fddiPORTMy_Type ) {
case TA :
mib - > fddiPORTAvailablePaths | = MIB_PATH_S ;
mib - > fddiPORTRequestedPaths [ 1 ] = MIB_P_PATH_LOCAL ;
mib - > fddiPORTRequestedPaths [ 2 ] =
MIB_P_PATH_LOCAL |
MIB_P_PATH_CON_ALTER |
MIB_P_PATH_SEC_PREFER ;
mib - > fddiPORTRequestedPaths [ 3 ] =
MIB_P_PATH_LOCAL |
MIB_P_PATH_CON_ALTER |
MIB_P_PATH_SEC_PREFER |
MIB_P_PATH_THRU ;
break ;
case TB :
mib - > fddiPORTAvailablePaths | = MIB_PATH_S ;
mib - > fddiPORTRequestedPaths [ 1 ] = MIB_P_PATH_LOCAL ;
mib - > fddiPORTRequestedPaths [ 2 ] =
MIB_P_PATH_LOCAL |
MIB_P_PATH_PRIM_PREFER ;
mib - > fddiPORTRequestedPaths [ 3 ] =
MIB_P_PATH_LOCAL |
MIB_P_PATH_PRIM_PREFER |
MIB_P_PATH_CON_PREFER |
MIB_P_PATH_THRU ;
break ;
case TS :
mib - > fddiPORTAvailablePaths | = MIB_PATH_S ;
mib - > fddiPORTRequestedPaths [ 1 ] = MIB_P_PATH_LOCAL ;
mib - > fddiPORTRequestedPaths [ 2 ] =
MIB_P_PATH_LOCAL |
MIB_P_PATH_CON_ALTER |
MIB_P_PATH_PRIM_PREFER ;
mib - > fddiPORTRequestedPaths [ 3 ] =
MIB_P_PATH_LOCAL |
MIB_P_PATH_CON_ALTER |
MIB_P_PATH_PRIM_PREFER ;
break ;
case TM :
mib - > fddiPORTRequestedPaths [ 1 ] = MIB_P_PATH_LOCAL ;
mib - > fddiPORTRequestedPaths [ 2 ] =
MIB_P_PATH_LOCAL |
MIB_P_PATH_SEC_ALTER |
MIB_P_PATH_PRIM_ALTER ;
mib - > fddiPORTRequestedPaths [ 3 ] = 0 ;
break ;
}
phy - > pc_lem_fail = FALSE ;
mib - > fddiPORTPCMStateX = mib - > fddiPORTPCMState ;
mib - > fddiPORTLCTFail_Ct = 0 ;
mib - > fddiPORTBS_Flag = 0 ;
mib - > fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
mib - > fddiPORTNeighborType = TNONE ;
phy - > ls_flag = 0 ;
phy - > rc_flag = 0 ;
phy - > tc_flag = 0 ;
phy - > td_flag = 0 ;
if ( np > = PM )
phy - > phy_name = ' 0 ' + np - PM ;
else
phy - > phy_name = ' A ' + np ;
phy - > wc_flag = FALSE ; /* set by SMT */
memset ( ( char * ) & phy - > lem , 0 , sizeof ( struct lem_counter ) ) ;
reset_lem_struct ( phy ) ;
memset ( ( char * ) & phy - > plc , 0 , sizeof ( struct s_plc ) ) ;
phy - > plc . p_state = PS_OFF ;
for ( i = 0 ; i < NUMBITS ; i + + ) {
phy - > t_next [ i ] = 0 ;
}
}
real_init_plc ( smc ) ;
}
void init_plc ( struct s_smc * smc )
{
SK_UNUSED ( smc ) ;
/*
* dummy
* this is an obsolete public entry point that has to remain
* for compat . It is used by various drivers .
* the work is now done in real_init_plc ( )
* which is called from pcm_init ( ) ;
*/
}
static void real_init_plc ( struct s_smc * smc )
{
int p ;
for ( p = 0 ; p < NUMPHYS ; p + + )
plc_init ( smc , p ) ;
}
static void plc_init ( struct s_smc * smc , int p )
{
int i ;
# ifndef MOT_ELM
int rev ; /* Revision of PLC-x */
# endif /* MOT_ELM */
/* transit PCM state machine to MAINT state */
outpw ( PLC ( p , PL_CNTRL_B ) , 0 ) ;
outpw ( PLC ( p , PL_CNTRL_B ) , PL_PCM_STOP ) ;
outpw ( PLC ( p , PL_CNTRL_A ) , 0 ) ;
/*
* if PLC - S then set control register C
*/
# ifndef MOT_ELM
rev = inpw ( PLC ( p , PL_STATUS_A ) ) & PLC_REV_MASK ;
if ( rev ! = PLC_REVISION_A )
# endif /* MOT_ELM */
{
if ( smc - > y [ p ] . pmd_scramble ) {
outpw ( PLC ( p , PL_CNTRL_C ) , PLCS_CONTROL_C_S ) ;
# ifdef MOT_ELM
outpw ( PLC ( p , PL_T_FOT_ASS ) , PLCS_FASSERT_S ) ;
outpw ( PLC ( p , PL_T_FOT_DEASS ) , PLCS_FDEASSERT_S ) ;
# endif /* MOT_ELM */
}
else {
outpw ( PLC ( p , PL_CNTRL_C ) , PLCS_CONTROL_C_U ) ;
# ifdef MOT_ELM
outpw ( PLC ( p , PL_T_FOT_ASS ) , PLCS_FASSERT_U ) ;
outpw ( PLC ( p , PL_T_FOT_DEASS ) , PLCS_FDEASSERT_U ) ;
# endif /* MOT_ELM */
}
}
/*
* set timer register
*/
for ( i = 0 ; pltm [ i ] . timer ; i + + ) /* set timer parameter reg */
outpw ( PLC ( p , pltm [ i ] . timer ) , pltm [ i ] . para ) ;
( void ) inpw ( PLC ( p , PL_INTR_EVENT ) ) ; /* clear interrupt event reg */
plc_clear_irq ( smc , p ) ;
outpw ( PLC ( p , PL_INTR_MASK ) , plc_imsk_na ) ; /* enable non active irq's */
/*
* if PCM is configured for class s , it will NOT go to the
* REMOVE state if offline ( page 3 - 36 ; )
* in the concentrator , all inactive PHYS always must be in
* the remove state
* there ' s no real need to use this feature at all . .
*/
# ifndef CONCENTRATOR
if ( ( smc - > s . sas = = SMT_SAS ) & & ( p = = PS ) ) {
outpw ( PLC ( p , PL_CNTRL_B ) , PL_CLASS_S ) ;
}
# endif
}
/*
* control PCM state machine
*/
static void plc_go_state ( struct s_smc * smc , int p , int state )
{
HW_PTR port ;
int val ;
SK_UNUSED ( smc ) ;
port = ( HW_PTR ) ( PLC ( p , PL_CNTRL_B ) ) ;
val = inpw ( port ) & ~ ( PL_PCM_CNTRL | PL_MAINT ) ;
outpw ( port , val ) ;
outpw ( port , val | state ) ;
}
/*
* read current line state ( called by ECM & PCM )
*/
int sm_pm_get_ls ( struct s_smc * smc , int phy )
{
int state ;
# ifdef CONCENTRATOR
if ( ! plc_is_installed ( smc , phy ) )
return ( PC_QLS ) ;
# endif
state = inpw ( PLC ( phy , PL_STATUS_A ) ) & PL_LINE_ST ;
switch ( state ) {
case PL_L_QLS :
state = PC_QLS ;
break ;
case PL_L_MLS :
state = PC_MLS ;
break ;
case PL_L_HLS :
state = PC_HLS ;
break ;
case PL_L_ILS4 :
case PL_L_ILS16 :
state = PC_ILS ;
break ;
case PL_L_ALS :
state = PC_LS_PDR ;
break ;
default :
state = PC_LS_NONE ;
}
return ( state ) ;
}
static int plc_send_bits ( struct s_smc * smc , struct s_phy * phy , int len )
{
int np = phy - > np ; /* PHY index */
int n ;
int i ;
SK_UNUSED ( smc ) ;
/* create bit vector */
for ( i = len - 1 , n = 0 ; i > = 0 ; i - - ) {
n = ( n < < 1 ) | phy - > t_val [ phy - > bitn + i ] ;
}
if ( inpw ( PLC ( np , PL_STATUS_B ) ) & PL_PCM_SIGNAL ) {
#if 0
printf ( " PL_PCM_SIGNAL is set \n " ) ;
# endif
return ( 1 ) ;
}
/* write bit[n] & length = 1 to regs */
outpw ( PLC ( np , PL_VECTOR_LEN ) , len - 1 ) ; /* len=nr-1 */
outpw ( PLC ( np , PL_XMIT_VECTOR ) , n ) ;
# ifdef DEBUG
# if 1
# ifdef DEBUG_BRD
if ( smc - > debug . d_plc & 0x80 )
# else
if ( debug . d_plc & 0x80 )
# endif
printf ( " SIGNALING bit %d .. %d \n " , phy - > bitn , phy - > bitn + len - 1 ) ;
# endif
# endif
return ( 0 ) ;
}
/*
* config plc muxes
*/
void plc_config_mux ( struct s_smc * smc , int mux )
{
if ( smc - > s . sas ! = SMT_DAS )
return ;
if ( mux = = MUX_WRAPB ) {
SETMASK ( PLC ( PA , PL_CNTRL_B ) , PL_CONFIG_CNTRL , PL_CONFIG_CNTRL ) ;
SETMASK ( PLC ( PA , PL_CNTRL_A ) , PL_SC_REM_LOOP , PL_SC_REM_LOOP ) ;
}
else {
CLEAR ( PLC ( PA , PL_CNTRL_B ) , PL_CONFIG_CNTRL ) ;
CLEAR ( PLC ( PA , PL_CNTRL_A ) , PL_SC_REM_LOOP ) ;
}
CLEAR ( PLC ( PB , PL_CNTRL_B ) , PL_CONFIG_CNTRL ) ;
CLEAR ( PLC ( PB , PL_CNTRL_A ) , PL_SC_REM_LOOP ) ;
}
/*
PCM state machine
called by dispatcher & fddi_init ( ) ( driver )
do
display state change
process event
until SM is stable
*/
void pcm ( struct s_smc * smc , const int np , int event )
{
int state ;
int oldstate ;
struct s_phy * phy ;
struct fddi_mib_p * mib ;
# ifndef CONCENTRATOR
/*
* ignore 2 nd PHY if SAS
*/
if ( ( np ! = PS ) & & ( smc - > s . sas = = SMT_SAS ) )
return ;
# endif
phy = & smc - > y [ np ] ;
mib = phy - > mib ;
oldstate = mib - > fddiPORTPCMState ;
do {
DB_PCM ( " PCM %c: state %s " ,
phy - > phy_name ,
( mib - > fddiPORTPCMState & AFLAG ) ? " ACTIONS " : " " ) ;
DB_PCM ( " %s, event %s \n " ,
pcm_states [ mib - > fddiPORTPCMState & ~ AFLAG ] ,
pcm_events [ event ] ) ;
state = mib - > fddiPORTPCMState ;
pcm_fsm ( smc , phy , event ) ;
event = 0 ;
} while ( state ! = mib - > fddiPORTPCMState ) ;
/*
* because the PLC does the bit signaling for us ,
* we ' re always in SIGNAL state
* the MIB want ' s to see CONNECT
* we therefore fake an entry in the MIB
*/
if ( state = = PC5_SIGNAL )
mib - > fddiPORTPCMStateX = PC3_CONNECT ;
else
mib - > fddiPORTPCMStateX = state ;
# ifndef SLIM_SMT
/*
* path change
*/
if ( mib - > fddiPORTPCMState ! = oldstate & &
( ( oldstate = = PC8_ACTIVE ) | | ( mib - > fddiPORTPCMState = = PC8_ACTIVE ) ) ) {
smt_srf_event ( smc , SMT_EVENT_PORT_PATH_CHANGE ,
( int ) ( INDEX_PORT + phy - > np ) , 0 ) ;
}
# endif
# ifdef FDDI_MIB
/* check whether a snmp-trap has to be sent */
if ( mib - > fddiPORTPCMState ! = oldstate ) {
/* a real state change took place */
DB_SNMP ( " PCM from %d to %d \n " , oldstate , mib - > fddiPORTPCMState ) ;
if ( mib - > fddiPORTPCMState = = PC0_OFF ) {
/* send first trap */
snmp_fddi_trap ( smc , 1 , ( int ) mib - > fddiPORTIndex ) ;
} else if ( oldstate = = PC0_OFF ) {
/* send second trap */
snmp_fddi_trap ( smc , 2 , ( int ) mib - > fddiPORTIndex ) ;
} else if ( mib - > fddiPORTPCMState ! = PC2_TRACE & &
oldstate = = PC8_ACTIVE ) {
/* send third trap */
snmp_fddi_trap ( smc , 3 , ( int ) mib - > fddiPORTIndex ) ;
} else if ( mib - > fddiPORTPCMState = = PC8_ACTIVE ) {
/* send fourth trap */
snmp_fddi_trap ( smc , 4 , ( int ) mib - > fddiPORTIndex ) ;
}
}
# endif
pcm_state_change ( smc , np , state ) ;
}
/*
* PCM state machine
*/
static void pcm_fsm ( struct s_smc * smc , struct s_phy * phy , int cmd )
{
int i ;
int np = phy - > np ; /* PHY index */
struct s_plc * plc ;
struct fddi_mib_p * mib ;
# ifndef MOT_ELM
u_short plc_rev ; /* Revision of the plc */
# endif /* nMOT_ELM */
plc = & phy - > plc ;
mib = phy - > mib ;
/*
* general transitions independent of state
*/
switch ( cmd ) {
case PC_STOP :
/*PC00-PC80*/
if ( mib - > fddiPORTPCMState ! = PC9_MAINT ) {
GO_STATE ( PC0_OFF ) ;
AIX_EVENT ( smc , ( u_long ) FDDI_RING_STATUS , ( u_long )
FDDI_PORT_EVENT , ( u_long ) FDDI_PORT_STOP ,
smt_get_port_event_word ( smc ) ) ;
}
return ;
case PC_START :
/*PC01-PC81*/
if ( mib - > fddiPORTPCMState ! = PC9_MAINT )
GO_STATE ( PC1_BREAK ) ;
return ;
case PC_DISABLE :
/* PC09-PC99 */
GO_STATE ( PC9_MAINT ) ;
AIX_EVENT ( smc , ( u_long ) FDDI_RING_STATUS , ( u_long )
FDDI_PORT_EVENT , ( u_long ) FDDI_PORT_DISABLED ,
smt_get_port_event_word ( smc ) ) ;
return ;
case PC_TIMEOUT_LCT :
/* if long or extended LCT */
stop_pcm_timer0 ( smc , phy ) ;
CLEAR ( PLC ( np , PL_CNTRL_B ) , PL_LONG ) ;
/* end of LCT is indicate by PCM_CODE (initiate PCM event) */
return ;
}
switch ( mib - > fddiPORTPCMState ) {
case ACTIONS ( PC0_OFF ) :
stop_pcm_timer0 ( smc , phy ) ;
outpw ( PLC ( np , PL_CNTRL_A ) , 0 ) ;
CLEAR ( PLC ( np , PL_CNTRL_B ) , PL_PC_JOIN ) ;
CLEAR ( PLC ( np , PL_CNTRL_B ) , PL_LONG ) ;
sm_ph_lem_stop ( smc , np ) ; /* disable LEM */
phy - > cf_loop = FALSE ;
phy - > cf_join = FALSE ;
queue_event ( smc , EVENT_CFM , CF_JOIN + np ) ;
plc_go_state ( smc , np , PL_PCM_STOP ) ;
mib - > fddiPORTConnectState = PCM_DISABLED ;
ACTIONS_DONE ( ) ;
break ;
case PC0_OFF :
/*PC09*/
if ( cmd = = PC_MAINT ) {
GO_STATE ( PC9_MAINT ) ;
break ;
}
break ;
case ACTIONS ( PC1_BREAK ) :
/* Stop the LCT timer if we came from Signal state */
stop_pcm_timer0 ( smc , phy ) ;
ACTIONS_DONE ( ) ;
plc_go_state ( smc , np , 0 ) ;
CLEAR ( PLC ( np , PL_CNTRL_B ) , PL_PC_JOIN ) ;
CLEAR ( PLC ( np , PL_CNTRL_B ) , PL_LONG ) ;
sm_ph_lem_stop ( smc , np ) ; /* disable LEM */
/*
* if vector is already loaded , go to OFF to clear PCM_SIGNAL
*/
#if 0
if ( inpw ( PLC ( np , PL_STATUS_B ) ) & PL_PCM_SIGNAL ) {
plc_go_state ( smc , np , PL_PCM_STOP ) ;
/* TB_MIN ? */
}
# endif
/*
* Go to OFF state in any case .
*/
plc_go_state ( smc , np , PL_PCM_STOP ) ;
if ( mib - > fddiPORTPC_Withhold = = PC_WH_NONE )
mib - > fddiPORTConnectState = PCM_CONNECTING ;
phy - > cf_loop = FALSE ;
phy - > cf_join = FALSE ;
queue_event ( smc , EVENT_CFM , CF_JOIN + np ) ;
phy - > ls_flag = FALSE ;
phy - > pc_mode = PM_NONE ; /* needed by CFM */
phy - > bitn = 0 ; /* bit signaling start bit */
for ( i = 0 ; i < 3 ; i + + )
pc_tcode_actions ( smc , i , phy ) ;
/* Set the non-active interrupt mask register */
outpw ( PLC ( np , PL_INTR_MASK ) , plc_imsk_na ) ;
/*
* If the LCT was stopped . There might be a
* PCM_CODE interrupt event present .
* This must be cleared .
*/
( void ) inpw ( PLC ( np , PL_INTR_EVENT ) ) ;
# ifndef MOT_ELM
/* Get the plc revision for revision dependent code */
plc_rev = inpw ( PLC ( np , PL_STATUS_A ) ) & PLC_REV_MASK ;
if ( plc_rev ! = PLC_REV_SN3 )
# endif /* MOT_ELM */
{
/*
* No supernet III PLC , so set Xmit verctor and
* length BEFORE starting the state machine .
*/
if ( plc_send_bits ( smc , phy , 3 ) ) {
return ;
}
}
/*
* Now give the Start command .
* - The start command shall be done before setting the bits
* to be signaled . ( In PLC - S description and PLCS in SN3 .
* - The start command shall be issued AFTER setting the
* XMIT vector and the XMIT length register .
*
* We do it exactly according this specs for the old PLC and
* the new PLCS inside the SN3 .
* For the usual PLCS we try it the way it is done for the
* old PLC and set the XMIT registers again , if the PLC is
* not in SIGNAL state . This is done according to an PLCS
* errata workaround .
*/
plc_go_state ( smc , np , PL_PCM_START ) ;
/*
* workaround for PLC - S eng . sample errata
*/
# ifdef MOT_ELM
if ( ! ( inpw ( PLC ( np , PL_STATUS_B ) ) & PL_PCM_SIGNAL ) )
# else /* nMOT_ELM */
if ( ( ( inpw ( PLC ( np , PL_STATUS_A ) ) & PLC_REV_MASK ) ! =
PLC_REVISION_A ) & &
! ( inpw ( PLC ( np , PL_STATUS_B ) ) & PL_PCM_SIGNAL ) )
# endif /* nMOT_ELM */
{
/*
* Set register again ( PLCS errata ) or the first time
* ( new SN3 PLCS ) .
*/
( void ) plc_send_bits ( smc , phy , 3 ) ;
}
/*
* end of workaround
*/
GO_STATE ( PC5_SIGNAL ) ;
plc - > p_state = PS_BIT3 ;
plc - > p_bits = 3 ;
plc - > p_start = 0 ;
break ;
case PC1_BREAK :
break ;
case ACTIONS ( PC2_TRACE ) :
plc_go_state ( smc , np , PL_PCM_TRACE ) ;
ACTIONS_DONE ( ) ;
break ;
case PC2_TRACE :
break ;
case PC3_CONNECT : /* these states are done by hardware */
case PC4_NEXT :
break ;
case ACTIONS ( PC5_SIGNAL ) :
ACTIONS_DONE ( ) ;
case PC5_SIGNAL :
if ( ( cmd ! = PC_SIGNAL ) & & ( cmd ! = PC_TIMEOUT_LCT ) )
break ;
switch ( plc - > p_state ) {
case PS_BIT3 :
for ( i = 0 ; i < = 2 ; i + + )
pc_rcode_actions ( smc , i , phy ) ;
pc_tcode_actions ( smc , 3 , phy ) ;
plc - > p_state = PS_BIT4 ;
plc - > p_bits = 1 ;
plc - > p_start = 3 ;
phy - > bitn = 3 ;
if ( plc_send_bits ( smc , phy , 1 ) ) {
return ;
}
break ;
case PS_BIT4 :
pc_rcode_actions ( smc , 3 , phy ) ;
for ( i = 4 ; i < = 6 ; i + + )
pc_tcode_actions ( smc , i , phy ) ;
plc - > p_state = PS_BIT7 ;
plc - > p_bits = 3 ;
plc - > p_start = 4 ;
phy - > bitn = 4 ;
if ( plc_send_bits ( smc , phy , 3 ) ) {
return ;
}
break ;
case PS_BIT7 :
for ( i = 3 ; i < = 6 ; i + + )
pc_rcode_actions ( smc , i , phy ) ;
plc - > p_state = PS_LCT ;
plc - > p_bits = 0 ;
plc - > p_start = 7 ;
phy - > bitn = 7 ;
sm_ph_lem_start ( smc , np , ( int ) smc - > s . lct_short ) ; /* enable LEM */
/* start LCT */
i = inpw ( PLC ( np , PL_CNTRL_B ) ) & ~ PL_PC_LOOP ;
outpw ( PLC ( np , PL_CNTRL_B ) , i ) ; /* must be cleared */
outpw ( PLC ( np , PL_CNTRL_B ) , i | PL_RLBP ) ;
break ;
case PS_LCT :
/* check for local LCT failure */
pc_tcode_actions ( smc , 7 , phy ) ;
/*
* set tval [ 7 ]
*/
plc - > p_state = PS_BIT8 ;
plc - > p_bits = 1 ;
plc - > p_start = 7 ;
phy - > bitn = 7 ;
if ( plc_send_bits ( smc , phy , 1 ) ) {
return ;
}
break ;
case PS_BIT8 :
/* check for remote LCT failure */
pc_rcode_actions ( smc , 7 , phy ) ;
if ( phy - > t_val [ 7 ] | | phy - > r_val [ 7 ] ) {
plc_go_state ( smc , np , PL_PCM_STOP ) ;
GO_STATE ( PC1_BREAK ) ;
break ;
}
for ( i = 8 ; i < = 9 ; i + + )
pc_tcode_actions ( smc , i , phy ) ;
plc - > p_state = PS_JOIN ;
plc - > p_bits = 2 ;
plc - > p_start = 8 ;
phy - > bitn = 8 ;
if ( plc_send_bits ( smc , phy , 2 ) ) {
return ;
}
break ;
case PS_JOIN :
for ( i = 8 ; i < = 9 ; i + + )
pc_rcode_actions ( smc , i , phy ) ;
plc - > p_state = PS_ACTIVE ;
GO_STATE ( PC6_JOIN ) ;
break ;
}
break ;
case ACTIONS ( PC6_JOIN ) :
/*
* prevent mux error when going from WRAP_A to WRAP_B
*/
if ( smc - > s . sas = = SMT_DAS & & np = = PB & &
( smc - > y [ PA ] . pc_mode = = PM_TREE | |
smc - > y [ PB ] . pc_mode = = PM_TREE ) ) {
SETMASK ( PLC ( np , PL_CNTRL_A ) ,
PL_SC_REM_LOOP , PL_SC_REM_LOOP ) ;
SETMASK ( PLC ( np , PL_CNTRL_B ) ,
PL_CONFIG_CNTRL , PL_CONFIG_CNTRL ) ;
}
SETMASK ( PLC ( np , PL_CNTRL_B ) , PL_PC_JOIN , PL_PC_JOIN ) ;
SETMASK ( PLC ( np , PL_CNTRL_B ) , PL_PC_JOIN , PL_PC_JOIN ) ;
ACTIONS_DONE ( ) ;
cmd = 0 ;
/* fall thru */
case PC6_JOIN :
switch ( plc - > p_state ) {
case PS_ACTIVE :
/*PC88b*/
if ( ! phy - > cf_join ) {
phy - > cf_join = TRUE ;
queue_event ( smc , EVENT_CFM , CF_JOIN + np ) ; ;
}
if ( cmd = = PC_JOIN )
GO_STATE ( PC8_ACTIVE ) ;
/*PC82*/
if ( cmd = = PC_TRACE ) {
GO_STATE ( PC2_TRACE ) ;
break ;
}
break ;
}
break ;
case PC7_VERIFY :
break ;
case ACTIONS ( PC8_ACTIVE ) :
/*
* start LEM for SMT
*/
sm_ph_lem_start ( smc , ( int ) phy - > np , LCT_LEM_MAX ) ;
phy - > tr_flag = FALSE ;
mib - > fddiPORTConnectState = PCM_ACTIVE ;
/* Set the active interrupt mask register */
outpw ( PLC ( np , PL_INTR_MASK ) , plc_imsk_act ) ;
ACTIONS_DONE ( ) ;
break ;
case PC8_ACTIVE :
/*PC81 is done by PL_TNE_EXPIRED irq */
/*PC82*/
if ( cmd = = PC_TRACE ) {
GO_STATE ( PC2_TRACE ) ;
break ;
}
/*PC88c: is done by TRACE_PROP irq */
break ;
case ACTIONS ( PC9_MAINT ) :
stop_pcm_timer0 ( smc , phy ) ;
CLEAR ( PLC ( np , PL_CNTRL_B ) , PL_PC_JOIN ) ;
CLEAR ( PLC ( np , PL_CNTRL_B ) , PL_LONG ) ;
CLEAR ( PLC ( np , PL_INTR_MASK ) , PL_LE_CTR ) ; /* disable LEM int. */
sm_ph_lem_stop ( smc , np ) ; /* disable LEM */
phy - > cf_loop = FALSE ;
phy - > cf_join = FALSE ;
queue_event ( smc , EVENT_CFM , CF_JOIN + np ) ;
plc_go_state ( smc , np , PL_PCM_STOP ) ;
mib - > fddiPORTConnectState = PCM_DISABLED ;
SETMASK ( PLC ( np , PL_CNTRL_B ) , PL_MAINT , PL_MAINT ) ;
sm_ph_linestate ( smc , np , ( int ) MIB2LS ( mib - > fddiPORTMaint_LS ) ) ;
outpw ( PLC ( np , PL_CNTRL_A ) , PL_SC_BYPASS ) ;
ACTIONS_DONE ( ) ;
break ;
case PC9_MAINT :
DB_PCMN ( 1 , " PCM %c : MAINT \n " , phy - > phy_name , 0 ) ;
/*PC90*/
if ( cmd = = PC_ENABLE ) {
GO_STATE ( PC0_OFF ) ;
break ;
}
break ;
default :
SMT_PANIC ( smc , SMT_E0118 , SMT_E0118_MSG ) ;
break ;
}
}
/*
* force line state on a PHY output ( only in MAINT state )
*/
static void sm_ph_linestate ( struct s_smc * smc , int phy , int ls )
{
int cntrl ;
SK_UNUSED ( smc ) ;
cntrl = ( inpw ( PLC ( phy , PL_CNTRL_B ) ) & ~ PL_MAINT_LS ) |
PL_PCM_STOP | PL_MAINT ;
switch ( ls ) {
case PC_QLS : /* Force Quiet */
cntrl | = PL_M_QUI0 ;
break ;
case PC_MLS : /* Force Master */
cntrl | = PL_M_MASTR ;
break ;
case PC_HLS : /* Force Halt */
cntrl | = PL_M_HALT ;
break ;
default :
case PC_ILS : /* Force Idle */
cntrl | = PL_M_IDLE ;
break ;
case PC_LS_PDR : /* Enable repeat filter */
cntrl | = PL_M_TPDR ;
break ;
}
outpw ( PLC ( phy , PL_CNTRL_B ) , cntrl ) ;
}
static void reset_lem_struct ( struct s_phy * phy )
{
struct lem_counter * lem = & phy - > lem ;
phy - > mib - > fddiPORTLer_Estimate = 15 ;
lem - > lem_float_ber = 15 * 100 ;
}
/*
* link error monitor
*/
static void lem_evaluate ( struct s_smc * smc , struct s_phy * phy )
{
int ber ;
u_long errors ;
struct lem_counter * lem = & phy - > lem ;
struct fddi_mib_p * mib ;
int cond ;
mib = phy - > mib ;
if ( ! lem - > lem_on )
return ;
errors = inpw ( PLC ( ( ( int ) phy - > np ) , PL_LINK_ERR_CTR ) ) ;
lem - > lem_errors + = errors ;
mib - > fddiPORTLem_Ct + = errors ;
errors = lem - > lem_errors ;
/*
* calculation is called on a intervall of 8 seconds
* - > this means , that one error in 8 sec . is one of 8 * 125 * 10E6
* the same as BER = 10E-9
* Please note :
* - > 9 errors in 8 seconds mean :
* BER = 9 * 10E-9 and this is
* < 10E-8 , so the limit of 10E-8 is not reached !
*/
if ( ! errors ) ber = 15 ;
else if ( errors < = 9 ) ber = 9 ;
else if ( errors < = 99 ) ber = 8 ;
else if ( errors < = 999 ) ber = 7 ;
else if ( errors < = 9999 ) ber = 6 ;
else if ( errors < = 99999 ) ber = 5 ;
else if ( errors < = 999999 ) ber = 4 ;
else if ( errors < = 9999999 ) ber = 3 ;
else if ( errors < = 99999999 ) ber = 2 ;
else if ( errors < = 999999999 ) ber = 1 ;
else ber = 0 ;
/*
* weighted average
*/
ber * = 100 ;
lem - > lem_float_ber = lem - > lem_float_ber * 7 + ber * 3 ;
lem - > lem_float_ber / = 10 ;
mib - > fddiPORTLer_Estimate = lem - > lem_float_ber / 100 ;
if ( mib - > fddiPORTLer_Estimate < 4 ) {
mib - > fddiPORTLer_Estimate = 4 ;
}
if ( lem - > lem_errors ) {
DB_PCMN ( 1 , " LEM %c : \n " , phy - > np = = PB ? ' B ' : ' A ' , 0 ) ;
DB_PCMN ( 1 , " errors : %ld \n " , lem - > lem_errors , 0 ) ;
DB_PCMN ( 1 , " sum_errors : %ld \n " , mib - > fddiPORTLem_Ct , 0 ) ;
DB_PCMN ( 1 , " current BER : 10E-%d \n " , ber / 100 , 0 ) ;
DB_PCMN ( 1 , " float BER : 10E-(%d/100) \n " , lem - > lem_float_ber , 0 ) ;
DB_PCMN ( 1 , " avg. BER : 10E-%d \n " ,
mib - > fddiPORTLer_Estimate , 0 ) ;
}
lem - > lem_errors = 0L ;
# ifndef SLIM_SMT
cond = ( mib - > fddiPORTLer_Estimate < = mib - > fddiPORTLer_Alarm ) ?
TRUE : FALSE ;
# ifdef SMT_EXT_CUTOFF
smt_ler_alarm_check ( smc , phy , cond ) ;
# endif /* nSMT_EXT_CUTOFF */
if ( cond ! = mib - > fddiPORTLerFlag ) {
smt_srf_event ( smc , SMT_COND_PORT_LER ,
( int ) ( INDEX_PORT + phy - > np ) , cond ) ;
}
# endif
if ( mib - > fddiPORTLer_Estimate < = mib - > fddiPORTLer_Cutoff ) {
phy - > pc_lem_fail = TRUE ; /* flag */
mib - > fddiPORTLem_Reject_Ct + + ;
/*
* " forgive 10e-2 " if we cutoff so we can come
* up again . .
*/
lem - > lem_float_ber + = 2 * 100 ;
/*PC81b*/
# ifdef CONCENTRATOR
DB_PCMN ( 1 , " PCM: LER cutoff on port %d cutoff %d \n " ,
phy - > np , mib - > fddiPORTLer_Cutoff ) ;
# endif
# ifdef SMT_EXT_CUTOFF
smt_port_off_event ( smc , phy - > np ) ;
# else /* nSMT_EXT_CUTOFF */
queue_event ( smc , ( int ) ( EVENT_PCM + phy - > np ) , PC_START ) ;
# endif /* nSMT_EXT_CUTOFF */
}
}
/*
* called by SMT to calculate LEM bit error rate
*/
void sm_lem_evaluate ( struct s_smc * smc )
{
int np ;
for ( np = 0 ; np < NUMPHYS ; np + + )
lem_evaluate ( smc , & smc - > y [ np ] ) ;
}
static void lem_check_lct ( struct s_smc * smc , struct s_phy * phy )
{
struct lem_counter * lem = & phy - > lem ;
struct fddi_mib_p * mib ;
int errors ;
mib = phy - > mib ;
phy - > pc_lem_fail = FALSE ; /* flag */
errors = inpw ( PLC ( ( ( int ) phy - > np ) , PL_LINK_ERR_CTR ) ) ;
lem - > lem_errors + = errors ;
mib - > fddiPORTLem_Ct + = errors ;
if ( lem - > lem_errors ) {
switch ( phy - > lc_test ) {
case LC_SHORT :
if ( lem - > lem_errors > = smc - > s . lct_short )
phy - > pc_lem_fail = TRUE ;
break ;
case LC_MEDIUM :
if ( lem - > lem_errors > = smc - > s . lct_medium )
phy - > pc_lem_fail = TRUE ;
break ;
case LC_LONG :
if ( lem - > lem_errors > = smc - > s . lct_long )
phy - > pc_lem_fail = TRUE ;
break ;
case LC_EXTENDED :
if ( lem - > lem_errors > = smc - > s . lct_extended )
phy - > pc_lem_fail = TRUE ;
break ;
}
DB_PCMN ( 1 , " >>errors : %d \n " , lem - > lem_errors , 0 ) ;
}
if ( phy - > pc_lem_fail ) {
mib - > fddiPORTLCTFail_Ct + + ;
mib - > fddiPORTLem_Reject_Ct + + ;
}
else
mib - > fddiPORTLCTFail_Ct = 0 ;
}
/*
* LEM functions
*/
static void sm_ph_lem_start ( struct s_smc * smc , int np , int threshold )
{
struct lem_counter * lem = & smc - > y [ np ] . lem ;
lem - > lem_on = 1 ;
lem - > lem_errors = 0L ;
/* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too
* often .
*/
outpw ( PLC ( np , PL_LE_THRESHOLD ) , threshold ) ;
( void ) inpw ( PLC ( np , PL_LINK_ERR_CTR ) ) ; /* clear error counter */
/* enable LE INT */
SETMASK ( PLC ( np , PL_INTR_MASK ) , PL_LE_CTR , PL_LE_CTR ) ;
}
static void sm_ph_lem_stop ( struct s_smc * smc , int np )
{
struct lem_counter * lem = & smc - > y [ np ] . lem ;
lem - > lem_on = 0 ;
CLEAR ( PLC ( np , PL_INTR_MASK ) , PL_LE_CTR ) ;
}
/* ARGSUSED */
void sm_pm_ls_latch ( struct s_smc * smc , int phy , int on_off )
/* int on_off; en- or disable ident. ls */
{
SK_UNUSED ( smc ) ;
phy = phy ; on_off = on_off ;
}
/*
* PCM pseudo code
* receive actions are called AFTER the bit n is received ,
* i . e . if pc_rcode_actions ( 5 ) is called , bit 6 is the next bit to be received
*/
/*
* PCM pseudo code 5.1 . . 6.1
*/
static void pc_rcode_actions ( struct s_smc * smc , int bit , struct s_phy * phy )
{
struct fddi_mib_p * mib ;
mib = phy - > mib ;
DB_PCMN ( 1 , " SIG rec %x %x: \n " , bit , phy - > r_val [ bit ] ) ;
bit + + ;
switch ( bit ) {
case 0 :
case 1 :
case 2 :
break ;
case 3 :
if ( phy - > r_val [ 1 ] = = 0 & & phy - > r_val [ 2 ] = = 0 )
mib - > fddiPORTNeighborType = TA ;
else if ( phy - > r_val [ 1 ] = = 0 & & phy - > r_val [ 2 ] = = 1 )
mib - > fddiPORTNeighborType = TB ;
else if ( phy - > r_val [ 1 ] = = 1 & & phy - > r_val [ 2 ] = = 0 )
mib - > fddiPORTNeighborType = TS ;
else if ( phy - > r_val [ 1 ] = = 1 & & phy - > r_val [ 2 ] = = 1 )
mib - > fddiPORTNeighborType = TM ;
break ;
case 4 :
if ( mib - > fddiPORTMy_Type = = TM & &
mib - > fddiPORTNeighborType = = TM ) {
DB_PCMN ( 1 , " PCM %c : E100 withhold M-M \n " ,
phy - > phy_name , 0 ) ;
mib - > fddiPORTPC_Withhold = PC_WH_M_M ;
RS_SET ( smc , RS_EVENT ) ;
}
else if ( phy - > t_val [ 3 ] | | phy - > r_val [ 3 ] ) {
mib - > fddiPORTPC_Withhold = PC_WH_NONE ;
if ( mib - > fddiPORTMy_Type = = TM | |
mib - > fddiPORTNeighborType = = TM )
phy - > pc_mode = PM_TREE ;
else
phy - > pc_mode = PM_PEER ;
/* reevaluate the selection criteria (wc_flag) */
all_selection_criteria ( smc ) ;
if ( phy - > wc_flag ) {
mib - > fddiPORTPC_Withhold = PC_WH_PATH ;
}
}
else {
mib - > fddiPORTPC_Withhold = PC_WH_OTHER ;
RS_SET ( smc , RS_EVENT ) ;
DB_PCMN ( 1 , " PCM %c : E101 withhold other \n " ,
phy - > phy_name , 0 ) ;
}
phy - > twisted = ( ( mib - > fddiPORTMy_Type ! = TS ) & &
( mib - > fddiPORTMy_Type ! = TM ) & &
( mib - > fddiPORTNeighborType = =
mib - > fddiPORTMy_Type ) ) ;
if ( phy - > twisted ) {
DB_PCMN ( 1 , " PCM %c : E102 !!! TWISTED !!! \n " ,
phy - > phy_name , 0 ) ;
}
break ;
case 5 :
break ;
case 6 :
if ( phy - > t_val [ 4 ] | | phy - > r_val [ 4 ] ) {
if ( ( phy - > t_val [ 4 ] & & phy - > t_val [ 5 ] ) | |
( phy - > r_val [ 4 ] & & phy - > r_val [ 5 ] ) )
phy - > lc_test = LC_EXTENDED ;
else
phy - > lc_test = LC_LONG ;
}
else if ( phy - > t_val [ 5 ] | | phy - > r_val [ 5 ] )
phy - > lc_test = LC_MEDIUM ;
else
phy - > lc_test = LC_SHORT ;
switch ( phy - > lc_test ) {
case LC_SHORT : /* 50ms */
outpw ( PLC ( ( int ) phy - > np , PL_LC_LENGTH ) , TP_LC_LENGTH ) ;
phy - > t_next [ 7 ] = smc - > s . pcm_lc_short ;
break ;
case LC_MEDIUM : /* 500ms */
outpw ( PLC ( ( int ) phy - > np , PL_LC_LENGTH ) , TP_LC_LONGLN ) ;
phy - > t_next [ 7 ] = smc - > s . pcm_lc_medium ;
break ;
case LC_LONG :
SETMASK ( PLC ( ( int ) phy - > np , PL_CNTRL_B ) , PL_LONG , PL_LONG ) ;
phy - > t_next [ 7 ] = smc - > s . pcm_lc_long ;
break ;
case LC_EXTENDED :
SETMASK ( PLC ( ( int ) phy - > np , PL_CNTRL_B ) , PL_LONG , PL_LONG ) ;
phy - > t_next [ 7 ] = smc - > s . pcm_lc_extended ;
break ;
}
if ( phy - > t_next [ 7 ] > smc - > s . pcm_lc_medium ) {
start_pcm_timer0 ( smc , phy - > t_next [ 7 ] , PC_TIMEOUT_LCT , phy ) ;
}
DB_PCMN ( 1 , " LCT timer = %ld us \n " , phy - > t_next [ 7 ] , 0 ) ;
phy - > t_next [ 9 ] = smc - > s . pcm_t_next_9 ;
break ;
case 7 :
if ( phy - > t_val [ 6 ] ) {
phy - > cf_loop = TRUE ;
}
phy - > td_flag = TRUE ;
break ;
case 8 :
if ( phy - > t_val [ 7 ] | | phy - > r_val [ 7 ] ) {
DB_PCMN ( 1 , " PCM %c : E103 LCT fail %s \n " ,
phy - > phy_name , phy - > t_val [ 7 ] ? " local " : " remote " ) ;
queue_event ( smc , ( int ) ( EVENT_PCM + phy - > np ) , PC_START ) ;
}
break ;
case 9 :
if ( phy - > t_val [ 8 ] | | phy - > r_val [ 8 ] ) {
if ( phy - > t_val [ 8 ] )
phy - > cf_loop = TRUE ;
phy - > td_flag = TRUE ;
}
break ;
case 10 :
if ( phy - > r_val [ 9 ] ) {
/* neighbor intends to have MAC on output */ ;
mib - > fddiPORTMacIndicated . R_val = TRUE ;
}
else {
/* neighbor does not intend to have MAC on output */ ;
mib - > fddiPORTMacIndicated . R_val = FALSE ;
}
break ;
}
}
/*
* PCM pseudo code 5.1 . . 6.1
*/
static void pc_tcode_actions ( struct s_smc * smc , const int bit , struct s_phy * phy )
{
int np = phy - > np ;
struct fddi_mib_p * mib ;
mib = phy - > mib ;
switch ( bit ) {
case 0 :
phy - > t_val [ 0 ] = 0 ; /* no escape used */
break ;
case 1 :
if ( mib - > fddiPORTMy_Type = = TS | | mib - > fddiPORTMy_Type = = TM )
phy - > t_val [ 1 ] = 1 ;
else
phy - > t_val [ 1 ] = 0 ;
break ;
case 2 :
if ( mib - > fddiPORTMy_Type = = TB | | mib - > fddiPORTMy_Type = = TM )
phy - > t_val [ 2 ] = 1 ;
else
phy - > t_val [ 2 ] = 0 ;
break ;
case 3 :
{
int type , ne ;
int policy ;
type = mib - > fddiPORTMy_Type ;
ne = mib - > fddiPORTNeighborType ;
policy = smc - > mib . fddiSMTConnectionPolicy ;
phy - > t_val [ 3 ] = 1 ; /* Accept connection */
switch ( type ) {
case TA :
if (
( ( policy & POLICY_AA ) & & ne = = TA ) | |
( ( policy & POLICY_AB ) & & ne = = TB ) | |
( ( policy & POLICY_AS ) & & ne = = TS ) | |
( ( policy & POLICY_AM ) & & ne = = TM ) )
phy - > t_val [ 3 ] = 0 ; /* Reject */
break ;
case TB :
if (
( ( policy & POLICY_BA ) & & ne = = TA ) | |
( ( policy & POLICY_BB ) & & ne = = TB ) | |
( ( policy & POLICY_BS ) & & ne = = TS ) | |
( ( policy & POLICY_BM ) & & ne = = TM ) )
phy - > t_val [ 3 ] = 0 ; /* Reject */
break ;
case TS :
if (
( ( policy & POLICY_SA ) & & ne = = TA ) | |
( ( policy & POLICY_SB ) & & ne = = TB ) | |
( ( policy & POLICY_SS ) & & ne = = TS ) | |
( ( policy & POLICY_SM ) & & ne = = TM ) )
phy - > t_val [ 3 ] = 0 ; /* Reject */
break ;
case TM :
if ( ne = = TM | |
( ( policy & POLICY_MA ) & & ne = = TA ) | |
( ( policy & POLICY_MB ) & & ne = = TB ) | |
( ( policy & POLICY_MS ) & & ne = = TS ) | |
( ( policy & POLICY_MM ) & & ne = = TM ) )
phy - > t_val [ 3 ] = 0 ; /* Reject */
break ;
}
# ifndef SLIM_SMT
/*
* detect undesirable connection attempt event
*/
if ( ( type = = TA & & ne = = TA ) | |
( type = = TA & & ne = = TS ) | |
( type = = TB & & ne = = TB ) | |
( type = = TB & & ne = = TS ) | |
( type = = TS & & ne = = TA ) | |
( type = = TS & & ne = = TB ) ) {
smt_srf_event ( smc , SMT_EVENT_PORT_CONNECTION ,
( int ) ( INDEX_PORT + phy - > np ) , 0 ) ;
}
# endif
}
break ;
case 4 :
if ( mib - > fddiPORTPC_Withhold = = PC_WH_NONE ) {
if ( phy - > pc_lem_fail ) {
phy - > t_val [ 4 ] = 1 ; /* long */
phy - > t_val [ 5 ] = 0 ;
}
else {
phy - > t_val [ 4 ] = 0 ;
if ( mib - > fddiPORTLCTFail_Ct > 0 )
phy - > t_val [ 5 ] = 1 ; /* medium */
else
phy - > t_val [ 5 ] = 0 ; /* short */
/*
* Implementers choice : use medium
* instead of short when undesired
* connection attempt is made .
*/
if ( phy - > wc_flag )
phy - > t_val [ 5 ] = 1 ; /* medium */
}
mib - > fddiPORTConnectState = PCM_CONNECTING ;
}
else {
mib - > fddiPORTConnectState = PCM_STANDBY ;
phy - > t_val [ 4 ] = 1 ; /* extended */
phy - > t_val [ 5 ] = 1 ;
}
break ;
case 5 :
break ;
case 6 :
/* we do NOT have a MAC for LCT */
phy - > t_val [ 6 ] = 0 ;
break ;
case 7 :
phy - > cf_loop = FALSE ;
lem_check_lct ( smc , phy ) ;
if ( phy - > pc_lem_fail ) {
DB_PCMN ( 1 , " PCM %c : E104 LCT failed \n " ,
phy - > phy_name , 0 ) ;
phy - > t_val [ 7 ] = 1 ;
}
else
phy - > t_val [ 7 ] = 0 ;
break ;
case 8 :
phy - > t_val [ 8 ] = 0 ; /* Don't request MAC loopback */
break ;
case 9 :
phy - > cf_loop = 0 ;
if ( ( mib - > fddiPORTPC_Withhold ! = PC_WH_NONE ) | |
( ( smc - > s . sas = = SMT_DAS ) & & ( phy - > wc_flag ) ) ) {
queue_event ( smc , EVENT_PCM + np , PC_START ) ;
break ;
}
phy - > t_val [ 9 ] = FALSE ;
switch ( smc - > s . sas ) {
case SMT_DAS :
/*
* MAC intended on output
*/
if ( phy - > pc_mode = = PM_TREE ) {
if ( ( np = = PB ) | | ( ( np = = PA ) & &
( smc - > y [ PB ] . mib - > fddiPORTConnectState ! =
PCM_ACTIVE ) ) )
phy - > t_val [ 9 ] = TRUE ;
}
else {
if ( np = = PB )
phy - > t_val [ 9 ] = TRUE ;
}
break ;
case SMT_SAS :
if ( np = = PS )
phy - > t_val [ 9 ] = TRUE ;
break ;
# ifdef CONCENTRATOR
case SMT_NAC :
/*
* MAC intended on output
*/
if ( np = = PB )
phy - > t_val [ 9 ] = TRUE ;
break ;
# endif
}
mib - > fddiPORTMacIndicated . T_val = phy - > t_val [ 9 ] ;
break ;
}
DB_PCMN ( 1 , " SIG snd %x %x: \n " , bit , phy - > t_val [ bit ] ) ;
}
/*
* return status twisted ( called by SMT )
*/
int pcm_status_twisted ( struct s_smc * smc )
{
int twist = 0 ;
if ( smc - > s . sas ! = SMT_DAS )
return ( 0 ) ;
if ( smc - > y [ PA ] . twisted & & ( smc - > y [ PA ] . mib - > fddiPORTPCMState = = PC8_ACTIVE ) )
twist | = 1 ;
if ( smc - > y [ PB ] . twisted & & ( smc - > y [ PB ] . mib - > fddiPORTPCMState = = PC8_ACTIVE ) )
twist | = 2 ;
return ( twist ) ;
}
/*
* return status ( called by SMT )
* type
* state
* remote phy type
* remote mac yes / no
*/
void pcm_status_state ( struct s_smc * smc , int np , int * type , int * state ,
int * remote , int * mac )
{
struct s_phy * phy = & smc - > y [ np ] ;
struct fddi_mib_p * mib ;
mib = phy - > mib ;
/* remote PHY type and MAC - set only if active */
* mac = 0 ;
* type = mib - > fddiPORTMy_Type ; /* our PHY type */
* state = mib - > fddiPORTConnectState ;
* remote = mib - > fddiPORTNeighborType ;
switch ( mib - > fddiPORTPCMState ) {
case PC8_ACTIVE :
* mac = mib - > fddiPORTMacIndicated . R_val ;
break ;
}
}
/*
* return rooted station status ( called by SMT )
*/
int pcm_rooted_station ( struct s_smc * smc )
{
int n ;
for ( n = 0 ; n < NUMPHYS ; n + + ) {
if ( smc - > y [ n ] . mib - > fddiPORTPCMState = = PC8_ACTIVE & &
smc - > y [ n ] . mib - > fddiPORTNeighborType = = TM )
return ( 0 ) ;
}
return ( 1 ) ;
}
/*
* Interrupt actions for PLC & PCM events
*/
void plc_irq ( struct s_smc * smc , int np , unsigned int cmd )
/* int np; PHY index */
{
struct s_phy * phy = & smc - > y [ np ] ;
struct s_plc * plc = & phy - > plc ;
int n ;
# ifdef SUPERNET_3
int corr_mask ;
# endif /* SUPERNET_3 */
int i ;
if ( np > = smc - > s . numphys ) {
plc - > soft_err + + ;
return ;
}
if ( cmd & PL_EBUF_ERR ) { /* elastic buff. det. over-|underflow*/
/*
* Check whether the SRF Condition occurred .
*/
if ( ! plc - > ebuf_cont & & phy - > mib - > fddiPORTPCMState = = PC8_ACTIVE ) {
/*
* This is the real Elasticity Error .
* More than one in a row are treated as a
* single one .
* Only count this in the active state .
*/
phy - > mib - > fddiPORTEBError_Ct + + ;
}
plc - > ebuf_err + + ;
if ( plc - > ebuf_cont < = 1000 ) {
/*
* Prevent counter from being wrapped after
* hanging years in that interrupt .
*/
plc - > ebuf_cont + + ; /* Ebuf continous error */
}
# ifdef SUPERNET_3
if ( plc - > ebuf_cont = = 1000 & &
( ( inpw ( PLC ( np , PL_STATUS_A ) ) & PLC_REV_MASK ) = =
PLC_REV_SN3 ) ) {
/*
* This interrupt remeained high for at least
* 1000 consecutive interrupt calls .
*
* This is caused by a hardware error of the
* ORION part of the Supernet III chipset .
*
* Disable this bit from the mask .
*/
corr_mask = ( plc_imsk_na & ~ PL_EBUF_ERR ) ;
outpw ( PLC ( np , PL_INTR_MASK ) , corr_mask ) ;
/*
* Disconnect from the ring .
* Call the driver with the reset indication .
*/
queue_event ( smc , EVENT_ECM , EC_DISCONNECT ) ;
/*
* Make an error log entry .
*/
SMT_ERR_LOG ( smc , SMT_E0136 , SMT_E0136_MSG ) ;
/*
* Indicate the Reset .
*/
drv_reset_indication ( smc ) ;
}
# endif /* SUPERNET_3 */
} else {
/* Reset the continous error variable */
plc - > ebuf_cont = 0 ; /* reset Ebuf continous error */
}
if ( cmd & PL_PHYINV ) { /* physical layer invalid signal */
plc - > phyinv + + ;
}
if ( cmd & PL_VSYM_CTR ) { /* violation symbol counter has incr.*/
plc - > vsym_ctr + + ;
}
if ( cmd & PL_MINI_CTR ) { /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
plc - > mini_ctr + + ;
}
if ( cmd & PL_LE_CTR ) { /* link error event counter */
int j ;
/*
* note : PL_LINK_ERR_CTR MUST be read to clear it
*/
j = inpw ( PLC ( np , PL_LE_THRESHOLD ) ) ;
i = inpw ( PLC ( np , PL_LINK_ERR_CTR ) ) ;
if ( i < j ) {
/* wrapped around */
i + = 256 ;
}
if ( phy - > lem . lem_on ) {
/* Note: Lem errors shall only be counted when
* link is ACTIVE or LCT is active .
*/
phy - > lem . lem_errors + = i ;
phy - > mib - > fddiPORTLem_Ct + = i ;
}
}
if ( cmd & PL_TPC_EXPIRED ) { /* TPC timer reached zero */
if ( plc - > p_state = = PS_LCT ) {
/*
* end of LCT
*/
;
}
plc - > tpc_exp + + ;
}
if ( cmd & PL_LS_MATCH ) { /* LS == LS in PLC_CNTRL_B's MATCH_LS*/
switch ( inpw ( PLC ( np , PL_CNTRL_B ) ) & PL_MATCH_LS ) {
case PL_I_IDLE : phy - > curr_ls = PC_ILS ; break ;
case PL_I_HALT : phy - > curr_ls = PC_HLS ; break ;
case PL_I_MASTR : phy - > curr_ls = PC_MLS ; break ;
case PL_I_QUIET : phy - > curr_ls = PC_QLS ; break ;
}
}
if ( cmd & PL_PCM_BREAK ) { /* PCM has entered the BREAK state */
int reason ;
reason = inpw ( PLC ( np , PL_STATUS_B ) ) & PL_BREAK_REASON ;
switch ( reason ) {
case PL_B_PCS : plc - > b_pcs + + ; break ;
case PL_B_TPC : plc - > b_tpc + + ; break ;
case PL_B_TNE : plc - > b_tne + + ; break ;
case PL_B_QLS : plc - > b_qls + + ; break ;
case PL_B_ILS : plc - > b_ils + + ; break ;
case PL_B_HLS : plc - > b_hls + + ; break ;
}
/*jd 05-Aug-1999 changed: Bug #10419 */
DB_PCMN ( 1 , " PLC %d: MDcF = %x \n " , np , smc - > e . DisconnectFlag ) ;
if ( smc - > e . DisconnectFlag = = FALSE ) {
DB_PCMN ( 1 , " PLC %d: restart (reason %x) \n " , np , reason ) ;
queue_event ( smc , EVENT_PCM + np , PC_START ) ;
}
else {
DB_PCMN ( 1 , " PLC %d: NO!! restart (reason %x) \n " , np , reason ) ;
}
return ;
}
/*
* If both CODE & ENABLE are set ignore enable
*/
if ( cmd & PL_PCM_CODE ) { /* receive last sign.-bit | LCT complete */
queue_event ( smc , EVENT_PCM + np , PC_SIGNAL ) ;
n = inpw ( PLC ( np , PL_RCV_VECTOR ) ) ;
for ( i = 0 ; i < plc - > p_bits ; i + + ) {
phy - > r_val [ plc - > p_start + i ] = n & 1 ;
n > > = 1 ;
}
}
else if ( cmd & PL_PCM_ENABLED ) { /* asserted SC_JOIN, scrub.completed*/
queue_event ( smc , EVENT_PCM + np , PC_JOIN ) ;
}
if ( cmd & PL_TRACE_PROP ) { /* MLS while PC8_ACTIV || PC2_TRACE */
/*PC22b*/
if ( ! phy - > tr_flag ) {
DB_PCMN ( 1 , " PCM : irq TRACE_PROP %d %d \n " ,
np , smc - > mib . fddiSMTECMState ) ;
phy - > tr_flag = TRUE ;
smc - > e . trace_prop | = ENTITY_BIT ( ENTITY_PHY ( np ) ) ;
queue_event ( smc , EVENT_ECM , EC_TRACE_PROP ) ;
}
}
/*
* filter PLC glitch ? ? ?
* QLS | | HLS only while in PC2_TRACE state
*/
if ( ( cmd & PL_SELF_TEST ) & & ( phy - > mib - > fddiPORTPCMState = = PC2_TRACE ) ) {
/*PC22a*/
if ( smc - > e . path_test = = PT_PASSED ) {
DB_PCMN ( 1 , " PCM : state = %s %d \n " , get_pcmstate ( smc , np ) ,
phy - > mib - > fddiPORTPCMState ) ;
smc - > e . path_test = PT_PENDING ;
queue_event ( smc , EVENT_ECM , EC_PATH_TEST ) ;
}
}
if ( cmd & PL_TNE_EXPIRED ) { /* TNE: length of noise events */
/* break_required (TNE > NS_Max) */
if ( phy - > mib - > fddiPORTPCMState = = PC8_ACTIVE ) {
if ( ! phy - > tr_flag ) {
DB_PCMN ( 1 , " PCM %c : PC81 %s \n " , phy - > phy_name , " NSE " ) ;
queue_event ( smc , EVENT_PCM + np , PC_START ) ;
return ;
}
}
}
#if 0
if ( cmd & PL_NP_ERR ) { /* NP has requested to r/w an inv reg*/
/*
* It ' s a bug by AMD
*/
plc - > np_err + + ;
}
/* pin inactiv (GND) */
if ( cmd & PL_PARITY_ERR ) { /* p. error dedected on TX9-0 inp */
plc - > parity_err + + ;
}
if ( cmd & PL_LSDO ) { /* carrier detected */
;
}
# endif
}
# ifdef DEBUG
/*
* fill state struct
*/
void pcm_get_state ( struct s_smc * smc , struct smt_state * state )
{
struct s_phy * phy ;
struct pcm_state * pcs ;
int i ;
int ii ;
short rbits ;
short tbits ;
struct fddi_mib_p * mib ;
for ( i = 0 , phy = smc - > y , pcs = state - > pcm_state ; i < NUMPHYS ;
i + + , phy + + , pcs + + ) {
mib = phy - > mib ;
pcs - > pcm_type = ( u_char ) mib - > fddiPORTMy_Type ;
pcs - > pcm_state = ( u_char ) mib - > fddiPORTPCMState ;
pcs - > pcm_mode = phy - > pc_mode ;
pcs - > pcm_neighbor = ( u_char ) mib - > fddiPORTNeighborType ;
pcs - > pcm_bsf = mib - > fddiPORTBS_Flag ;
pcs - > pcm_lsf = phy - > ls_flag ;
pcs - > pcm_lct_fail = ( u_char ) mib - > fddiPORTLCTFail_Ct ;
pcs - > pcm_ls_rx = LS2MIB ( sm_pm_get_ls ( smc , i ) ) ;
for ( ii = 0 , rbits = tbits = 0 ; ii < NUMBITS ; ii + + ) {
rbits < < = 1 ;
tbits < < = 1 ;
if ( phy - > r_val [ NUMBITS - 1 - ii ] )
rbits | = 1 ;
if ( phy - > t_val [ NUMBITS - 1 - ii ] )
tbits | = 1 ;
}
pcs - > pcm_r_val = rbits ;
pcs - > pcm_t_val = tbits ;
}
}
int get_pcm_state ( struct s_smc * smc , int np )
{
int pcs ;
SK_UNUSED ( smc ) ;
switch ( inpw ( PLC ( np , PL_STATUS_B ) ) & PL_PCM_STATE ) {
case PL_PC0 : pcs = PC_STOP ; break ;
case PL_PC1 : pcs = PC_START ; break ;
case PL_PC2 : pcs = PC_TRACE ; break ;
case PL_PC3 : pcs = PC_SIGNAL ; break ;
case PL_PC4 : pcs = PC_SIGNAL ; break ;
case PL_PC5 : pcs = PC_SIGNAL ; break ;
case PL_PC6 : pcs = PC_JOIN ; break ;
case PL_PC7 : pcs = PC_JOIN ; break ;
case PL_PC8 : pcs = PC_ENABLE ; break ;
case PL_PC9 : pcs = PC_MAINT ; break ;
default : pcs = PC_DISABLE ; break ;
}
return ( pcs ) ;
}
char * get_linestate ( struct s_smc * smc , int np )
{
char * ls = " " ;
SK_UNUSED ( smc ) ;
switch ( inpw ( PLC ( np , PL_STATUS_A ) ) & PL_LINE_ST ) {
case PL_L_NLS : ls = " NOISE " ; break ;
case PL_L_ALS : ls = " ACTIV " ; break ;
case PL_L_UND : ls = " UNDEF " ; break ;
case PL_L_ILS4 : ls = " ILS 4 " ; break ;
case PL_L_QLS : ls = " QLS " ; break ;
case PL_L_MLS : ls = " MLS " ; break ;
case PL_L_HLS : ls = " HLS " ; break ;
case PL_L_ILS16 : ls = " ILS16 " ; break ;
# ifdef lint
default : ls = " unknown " ; break ;
# endif
}
return ( ls ) ;
}
char * get_pcmstate ( struct s_smc * smc , int np )
{
char * pcs ;
SK_UNUSED ( smc ) ;
switch ( inpw ( PLC ( np , PL_STATUS_B ) ) & PL_PCM_STATE ) {
case PL_PC0 : pcs = " OFF " ; break ;
case PL_PC1 : pcs = " BREAK " ; break ;
case PL_PC2 : pcs = " TRACE " ; break ;
case PL_PC3 : pcs = " CONNECT " ; break ;
case PL_PC4 : pcs = " NEXT " ; break ;
case PL_PC5 : pcs = " SIGNAL " ; break ;
case PL_PC6 : pcs = " JOIN " ; break ;
case PL_PC7 : pcs = " VERIFY " ; break ;
case PL_PC8 : pcs = " ACTIV " ; break ;
case PL_PC9 : pcs = " MAINT " ; break ;
default : pcs = " UNKNOWN " ; break ;
}
return ( pcs ) ;
}
void list_phy ( struct s_smc * smc )
{
struct s_plc * plc ;
int np ;
for ( np = 0 ; np < NUMPHYS ; np + + ) {
plc = & smc - > y [ np ] . plc ;
printf ( " PHY %d: \t ERRORS \t \t \t BREAK_REASONS \t \t STATES: \n " , np ) ;
printf ( " \t soft_error: %ld \t \t PC_Start : %ld \n " ,
plc - > soft_err , plc - > b_pcs ) ;
printf ( " \t parity_err: %ld \t \t TPC exp. : %ld \t \t Line: %s \n " ,
plc - > parity_err , plc - > b_tpc , get_linestate ( smc , np ) ) ;
printf ( " \t ebuf_error: %ld \t \t TNE exp. : %ld \n " ,
plc - > ebuf_err , plc - > b_tne ) ;
printf ( " \t phyinvalid: %ld \t \t QLS det. : %ld \t \t PCM : %s \n " ,
plc - > phyinv , plc - > b_qls , get_pcmstate ( smc , np ) ) ;
printf ( " \t viosym_ctr: %ld \t \t ILS det. : %ld \n " ,
plc - > vsym_ctr , plc - > b_ils ) ;
printf ( " \t mingap_ctr: %ld \t \t HLS det. : %ld \n " ,
plc - > mini_ctr , plc - > b_hls ) ;
printf ( " \t nodepr_err: %ld \n " , plc - > np_err ) ;
printf ( " \t TPC_exp : %ld \n " , plc - > tpc_exp ) ;
printf ( " \t LEM_err : %ld \n " , smc - > y [ np ] . lem . lem_errors ) ;
}
}
# ifdef CONCENTRATOR
void pcm_lem_dump ( struct s_smc * smc )
{
int i ;
struct s_phy * phy ;
struct fddi_mib_p * mib ;
char * entostring ( ) ;
printf ( " PHY errors BER \n " ) ;
printf ( " ---------------------- \n " ) ;
for ( i = 0 , phy = smc - > y ; i < NUMPHYS ; i + + , phy + + ) {
if ( ! plc_is_installed ( smc , i ) )
continue ;
mib = phy - > mib ;
printf ( " %s \t %ld \t 10E-%d \n " ,
entostring ( smc , ENTITY_PHY ( i ) ) ,
mib - > fddiPORTLem_Ct ,
mib - > fddiPORTLer_Estimate ) ;
}
}
# endif
# endif