xref: /openbmc/linux/drivers/net/fddi/skfp/cfm.c (revision 81dbf219)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
233f810b2SJeff Kirsher /******************************************************************************
333f810b2SJeff Kirsher  *
433f810b2SJeff Kirsher  *	(C)Copyright 1998,1999 SysKonnect,
533f810b2SJeff Kirsher  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
633f810b2SJeff Kirsher  *
733f810b2SJeff Kirsher  *	See the file "skfddi.c" for further information.
833f810b2SJeff Kirsher  *
933f810b2SJeff Kirsher  *	The information in this file is provided "AS IS" without warranty.
1033f810b2SJeff Kirsher  *
1133f810b2SJeff Kirsher  ******************************************************************************/
1233f810b2SJeff Kirsher 
1333f810b2SJeff Kirsher /*
1433f810b2SJeff Kirsher 	SMT CFM
1533f810b2SJeff Kirsher 	Configuration Management
1633f810b2SJeff Kirsher 	DAS with single MAC
1733f810b2SJeff Kirsher */
1833f810b2SJeff Kirsher 
1933f810b2SJeff Kirsher /*
2033f810b2SJeff Kirsher  *	Hardware independent state machine implemantation
2133f810b2SJeff Kirsher  *	The following external SMT functions are referenced :
2233f810b2SJeff Kirsher  *
2333f810b2SJeff Kirsher  *		queue_event()
2433f810b2SJeff Kirsher  *
2533f810b2SJeff Kirsher  *	The following external HW dependent functions are referenced :
2633f810b2SJeff Kirsher  *		config_mux()
2733f810b2SJeff Kirsher  *
2833f810b2SJeff Kirsher  *	The following HW dependent events are required :
2933f810b2SJeff Kirsher  *		NONE
3033f810b2SJeff Kirsher  */
3133f810b2SJeff Kirsher 
3233f810b2SJeff Kirsher #include "h/types.h"
3333f810b2SJeff Kirsher #include "h/fddi.h"
3433f810b2SJeff Kirsher #include "h/smc.h"
3533f810b2SJeff Kirsher 
3633f810b2SJeff Kirsher #define KERNEL
3733f810b2SJeff Kirsher #include "h/smtstate.h"
3833f810b2SJeff Kirsher 
3933f810b2SJeff Kirsher /*
4033f810b2SJeff Kirsher  * FSM Macros
4133f810b2SJeff Kirsher  */
4233f810b2SJeff Kirsher #define AFLAG	0x10
4333f810b2SJeff Kirsher #define GO_STATE(x)	(smc->mib.fddiSMTCF_State = (x)|AFLAG)
4433f810b2SJeff Kirsher #define ACTIONS_DONE()	(smc->mib.fddiSMTCF_State &= ~AFLAG)
4533f810b2SJeff Kirsher #define ACTIONS(x)	(x|AFLAG)
4633f810b2SJeff Kirsher 
4733f810b2SJeff Kirsher /*
4833f810b2SJeff Kirsher  * symbolic state names
4933f810b2SJeff Kirsher  */
5033f810b2SJeff Kirsher static const char * const cfm_states[] = {
5133f810b2SJeff Kirsher 	"SC0_ISOLATED","CF1","CF2","CF3","CF4",
5233f810b2SJeff Kirsher 	"SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S",
5333f810b2SJeff Kirsher 	"SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A"
5433f810b2SJeff Kirsher } ;
5533f810b2SJeff Kirsher 
5633f810b2SJeff Kirsher /*
5733f810b2SJeff Kirsher  * symbolic event names
5833f810b2SJeff Kirsher  */
5933f810b2SJeff Kirsher static const char * const cfm_events[] = {
6033f810b2SJeff Kirsher 	"NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
6133f810b2SJeff Kirsher } ;
6233f810b2SJeff Kirsher 
6333f810b2SJeff Kirsher /*
6433f810b2SJeff Kirsher  * map from state to downstream port type
6533f810b2SJeff Kirsher  */
6633f810b2SJeff Kirsher static const unsigned char cf_to_ptype[] = {
6733f810b2SJeff Kirsher 	TNONE,TNONE,TNONE,TNONE,TNONE,
6833f810b2SJeff Kirsher 	TNONE,TB,TB,TS,
6933f810b2SJeff Kirsher 	TA,TB,TS,TB
7033f810b2SJeff Kirsher } ;
7133f810b2SJeff Kirsher 
7233f810b2SJeff Kirsher /*
7333f810b2SJeff Kirsher  * CEM port states
7433f810b2SJeff Kirsher  */
7533f810b2SJeff Kirsher #define	CEM_PST_DOWN	0
7633f810b2SJeff Kirsher #define	CEM_PST_UP	1
7733f810b2SJeff Kirsher #define	CEM_PST_HOLD	2
7833f810b2SJeff Kirsher /* define portstate array only for A and B port */
7933f810b2SJeff Kirsher /* Do this within the smc structure (use in multiple cards) */
8033f810b2SJeff Kirsher 
8133f810b2SJeff Kirsher /*
8233f810b2SJeff Kirsher  * all Globals  are defined in smc.h
8333f810b2SJeff Kirsher  * struct s_cfm
8433f810b2SJeff Kirsher  */
8533f810b2SJeff Kirsher 
8633f810b2SJeff Kirsher /*
8733f810b2SJeff Kirsher  * function declarations
8833f810b2SJeff Kirsher  */
8933f810b2SJeff Kirsher static void cfm_fsm(struct s_smc *smc, int cmd);
9033f810b2SJeff Kirsher 
9133f810b2SJeff Kirsher /*
9233f810b2SJeff Kirsher 	init CFM state machine
9333f810b2SJeff Kirsher 	clear all CFM vars and flags
9433f810b2SJeff Kirsher */
cfm_init(struct s_smc * smc)9533f810b2SJeff Kirsher void cfm_init(struct s_smc *smc)
9633f810b2SJeff Kirsher {
9733f810b2SJeff Kirsher 	smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ;
9833f810b2SJeff Kirsher 	smc->r.rm_join = 0 ;
9933f810b2SJeff Kirsher 	smc->r.rm_loop = 0 ;
10033f810b2SJeff Kirsher 	smc->y[PA].scrub = 0 ;
10133f810b2SJeff Kirsher 	smc->y[PB].scrub = 0 ;
10233f810b2SJeff Kirsher 	smc->y[PA].cem_pst = CEM_PST_DOWN ;
10333f810b2SJeff Kirsher 	smc->y[PB].cem_pst = CEM_PST_DOWN ;
10433f810b2SJeff Kirsher }
10533f810b2SJeff Kirsher 
10633f810b2SJeff Kirsher /* Some terms conditions used by the selection criteria */
10733f810b2SJeff Kirsher #define THRU_ENABLED(smc)	(smc->y[PA].pc_mode != PM_TREE && \
10833f810b2SJeff Kirsher 				 smc->y[PB].pc_mode != PM_TREE)
10933f810b2SJeff Kirsher /* Selection criteria for the ports */
selection_criteria(struct s_smc * smc,struct s_phy * phy)11033f810b2SJeff Kirsher static void selection_criteria (struct s_smc *smc, struct s_phy *phy)
11133f810b2SJeff Kirsher {
11233f810b2SJeff Kirsher 
11333f810b2SJeff Kirsher 	switch (phy->mib->fddiPORTMy_Type) {
11433f810b2SJeff Kirsher 	case TA:
11533f810b2SJeff Kirsher 		if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) {
11633f810b2SJeff Kirsher 			phy->wc_flag = TRUE ;
11733f810b2SJeff Kirsher 		} else {
11833f810b2SJeff Kirsher 			phy->wc_flag = FALSE ;
11933f810b2SJeff Kirsher 		}
12033f810b2SJeff Kirsher 
12133f810b2SJeff Kirsher 		break;
12233f810b2SJeff Kirsher 	case TB:
12333f810b2SJeff Kirsher 		/* take precedence over PA */
12433f810b2SJeff Kirsher 		phy->wc_flag = FALSE ;
12533f810b2SJeff Kirsher 		break;
12633f810b2SJeff Kirsher 	case TS:
12733f810b2SJeff Kirsher 		phy->wc_flag = FALSE ;
12833f810b2SJeff Kirsher 		break;
12933f810b2SJeff Kirsher 	case TM:
13033f810b2SJeff Kirsher 		phy->wc_flag = FALSE ;
13133f810b2SJeff Kirsher 		break;
13233f810b2SJeff Kirsher 	}
13333f810b2SJeff Kirsher 
13433f810b2SJeff Kirsher }
13533f810b2SJeff Kirsher 
all_selection_criteria(struct s_smc * smc)13633f810b2SJeff Kirsher void all_selection_criteria(struct s_smc *smc)
13733f810b2SJeff Kirsher {
13833f810b2SJeff Kirsher 	struct s_phy	*phy ;
13933f810b2SJeff Kirsher 	int		p ;
14033f810b2SJeff Kirsher 
14133f810b2SJeff Kirsher 	for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) {
14233f810b2SJeff Kirsher 		/* Do the selection criteria */
14333f810b2SJeff Kirsher 		selection_criteria (smc,phy);
14433f810b2SJeff Kirsher 	}
14533f810b2SJeff Kirsher }
14633f810b2SJeff Kirsher 
cem_priv_state(struct s_smc * smc,int event)14733f810b2SJeff Kirsher static void cem_priv_state(struct s_smc *smc, int event)
14833f810b2SJeff Kirsher /* State machine for private PORT states: used to optimize dual homing */
14933f810b2SJeff Kirsher {
15033f810b2SJeff Kirsher 	int	np;	/* Number of the port */
15133f810b2SJeff Kirsher 	int	i;
15233f810b2SJeff Kirsher 
15333f810b2SJeff Kirsher 	/* Do this only in a DAS */
15433f810b2SJeff Kirsher 	if (smc->s.sas != SMT_DAS )
15533f810b2SJeff Kirsher 		return ;
15633f810b2SJeff Kirsher 
15733f810b2SJeff Kirsher 	np = event - CF_JOIN;
15833f810b2SJeff Kirsher 
15933f810b2SJeff Kirsher 	if (np != PA && np != PB) {
16033f810b2SJeff Kirsher 		return ;
16133f810b2SJeff Kirsher 	}
16233f810b2SJeff Kirsher 	/* Change the port state according to the event (portnumber) */
16333f810b2SJeff Kirsher 	if (smc->y[np].cf_join) {
16433f810b2SJeff Kirsher 		smc->y[np].cem_pst = CEM_PST_UP ;
16533f810b2SJeff Kirsher 	} else if (!smc->y[np].wc_flag) {
16633f810b2SJeff Kirsher 		/* set the port to done only if it is not withheld */
16733f810b2SJeff Kirsher 		smc->y[np].cem_pst = CEM_PST_DOWN ;
16833f810b2SJeff Kirsher 	}
16933f810b2SJeff Kirsher 
17033f810b2SJeff Kirsher 	/* Don't set an hold port to down */
17133f810b2SJeff Kirsher 
17233f810b2SJeff Kirsher 	/* Check all ports of restart conditions */
17333f810b2SJeff Kirsher 	for (i = 0 ; i < 2 ; i ++ ) {
17433f810b2SJeff Kirsher 		/* Check all port for PORT is on hold and no withhold is done */
17533f810b2SJeff Kirsher 		if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) {
17633f810b2SJeff Kirsher 			smc->y[i].cem_pst = CEM_PST_DOWN;
17733f810b2SJeff Kirsher 			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
17833f810b2SJeff Kirsher 		}
17933f810b2SJeff Kirsher 		if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) {
18033f810b2SJeff Kirsher 			smc->y[i].cem_pst = CEM_PST_HOLD;
18133f810b2SJeff Kirsher 			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
18233f810b2SJeff Kirsher 		}
18333f810b2SJeff Kirsher 		if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) {
18433f810b2SJeff Kirsher 			/*
18533f810b2SJeff Kirsher 			 * The port must be restarted when the wc_flag
18633f810b2SJeff Kirsher 			 * will be reset. So set the port on hold.
18733f810b2SJeff Kirsher 			 */
18833f810b2SJeff Kirsher 			smc->y[i].cem_pst = CEM_PST_HOLD;
18933f810b2SJeff Kirsher 		}
19033f810b2SJeff Kirsher 	}
19133f810b2SJeff Kirsher 	return ;
19233f810b2SJeff Kirsher }
19333f810b2SJeff Kirsher 
19433f810b2SJeff Kirsher /*
19533f810b2SJeff Kirsher 	CFM state machine
19633f810b2SJeff Kirsher 	called by dispatcher
19733f810b2SJeff Kirsher 
19833f810b2SJeff Kirsher 	do
19933f810b2SJeff Kirsher 		display state change
20033f810b2SJeff Kirsher 		process event
20133f810b2SJeff Kirsher 	until SM is stable
20233f810b2SJeff Kirsher */
cfm(struct s_smc * smc,int event)20333f810b2SJeff Kirsher void cfm(struct s_smc *smc, int event)
20433f810b2SJeff Kirsher {
20533f810b2SJeff Kirsher 	int	state ;		/* remember last state */
20633f810b2SJeff Kirsher 	int	cond ;
20733f810b2SJeff Kirsher 
20833f810b2SJeff Kirsher 	/* We will do the following: */
20933f810b2SJeff Kirsher 	/*  - compute the variable WC_Flag for every port (This is where */
21033f810b2SJeff Kirsher 	/*    we can extend the requested path checking !!) */
21133f810b2SJeff Kirsher 	/*  - do the old (SMT 6.2 like) state machine */
21233f810b2SJeff Kirsher 	/*  - do the resulting station states */
21333f810b2SJeff Kirsher 
21433f810b2SJeff Kirsher 	all_selection_criteria (smc);
21533f810b2SJeff Kirsher 
21633f810b2SJeff Kirsher 	/* We will check now whether a state transition is allowed or not */
21733f810b2SJeff Kirsher 	/*  - change the portstates */
21833f810b2SJeff Kirsher 	cem_priv_state (smc, event);
21933f810b2SJeff Kirsher 
22033f810b2SJeff Kirsher 	do {
2215671e8c1SJoe Perches 		DB_CFM("CFM : state %s%s event %s",
2225671e8c1SJoe Perches 		       smc->mib.fddiSMTCF_State & AFLAG ? "ACTIONS " : "",
2235671e8c1SJoe Perches 		       cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG],
2245671e8c1SJoe Perches 		       cfm_events[event]);
22533f810b2SJeff Kirsher 		state = smc->mib.fddiSMTCF_State ;
22633f810b2SJeff Kirsher 		cfm_fsm(smc,event) ;
22733f810b2SJeff Kirsher 		event = 0 ;
22833f810b2SJeff Kirsher 	} while (state != smc->mib.fddiSMTCF_State) ;
22933f810b2SJeff Kirsher 
23033f810b2SJeff Kirsher #ifndef	SLIM_SMT
23133f810b2SJeff Kirsher 	/*
23233f810b2SJeff Kirsher 	 * check peer wrap condition
23333f810b2SJeff Kirsher 	 */
23433f810b2SJeff Kirsher 	cond = FALSE ;
23533f810b2SJeff Kirsher 	if (	(smc->mib.fddiSMTCF_State == SC9_C_WRAP_A &&
23633f810b2SJeff Kirsher 		smc->y[PA].pc_mode == PM_PEER) 	||
23733f810b2SJeff Kirsher 		(smc->mib.fddiSMTCF_State == SC10_C_WRAP_B &&
23833f810b2SJeff Kirsher 		smc->y[PB].pc_mode == PM_PEER) 	||
23933f810b2SJeff Kirsher 		(smc->mib.fddiSMTCF_State == SC11_C_WRAP_S &&
24033f810b2SJeff Kirsher 		smc->y[PS].pc_mode == PM_PEER &&
24133f810b2SJeff Kirsher 		smc->y[PS].mib->fddiPORTNeighborType != TS ) ) {
24233f810b2SJeff Kirsher 			cond = TRUE ;
24333f810b2SJeff Kirsher 	}
24433f810b2SJeff Kirsher 	if (cond != smc->mib.fddiSMTPeerWrapFlag)
24533f810b2SJeff Kirsher 		smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ;
24633f810b2SJeff Kirsher 
24733f810b2SJeff Kirsher 	/*
248d1ad06baSLee Jones 	 * Don't ever send MAC_PATH_CHANGE events. Our MAC is hard-wired
24933f810b2SJeff Kirsher 	 * to the primary path.
25033f810b2SJeff Kirsher 	 */
251d1ad06baSLee Jones 
25233f810b2SJeff Kirsher #endif	/* no SLIM_SMT */
25333f810b2SJeff Kirsher 
25433f810b2SJeff Kirsher 	/*
25533f810b2SJeff Kirsher 	 * set MAC port type
25633f810b2SJeff Kirsher 	 */
25733f810b2SJeff Kirsher 	smc->mib.m[MAC0].fddiMACDownstreamPORTType =
25833f810b2SJeff Kirsher 		cf_to_ptype[smc->mib.fddiSMTCF_State] ;
25933f810b2SJeff Kirsher 	cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ;
26033f810b2SJeff Kirsher }
26133f810b2SJeff Kirsher 
26233f810b2SJeff Kirsher /*
26333f810b2SJeff Kirsher 	process CFM event
26433f810b2SJeff Kirsher */
26533f810b2SJeff Kirsher /*ARGSUSED1*/
cfm_fsm(struct s_smc * smc,int cmd)26633f810b2SJeff Kirsher static void cfm_fsm(struct s_smc *smc, int cmd)
26733f810b2SJeff Kirsher {
26833f810b2SJeff Kirsher 	switch(smc->mib.fddiSMTCF_State) {
26933f810b2SJeff Kirsher 	case ACTIONS(SC0_ISOLATED) :
27033f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
27133f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
27233f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
27333f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
27433f810b2SJeff Kirsher 		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;
27533f810b2SJeff Kirsher 		config_mux(smc,MUX_ISOLATE) ;	/* configure PHY Mux */
27633f810b2SJeff Kirsher 		smc->r.rm_loop = FALSE ;
27733f810b2SJeff Kirsher 		smc->r.rm_join = FALSE ;
27833f810b2SJeff Kirsher 		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
27933f810b2SJeff Kirsher 		/* Don't do the WC-Flag changing here */
28033f810b2SJeff Kirsher 		ACTIONS_DONE() ;
2815671e8c1SJoe Perches 		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
28233f810b2SJeff Kirsher 		break;
28333f810b2SJeff Kirsher 	case SC0_ISOLATED :
28433f810b2SJeff Kirsher 		/*SC07*/
28533f810b2SJeff Kirsher 		/*SAS port can be PA or PB ! */
28633f810b2SJeff Kirsher 		if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop ||
28733f810b2SJeff Kirsher 				smc->y[PB].cf_join || smc->y[PB].cf_loop)) {
28833f810b2SJeff Kirsher 			GO_STATE(SC11_C_WRAP_S) ;
28933f810b2SJeff Kirsher 			break ;
29033f810b2SJeff Kirsher 		}
29133f810b2SJeff Kirsher 		/*SC01*/
29233f810b2SJeff Kirsher 		if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join &&
29333f810b2SJeff Kirsher 		     !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) {
29433f810b2SJeff Kirsher 			GO_STATE(SC9_C_WRAP_A) ;
29533f810b2SJeff Kirsher 			break ;
29633f810b2SJeff Kirsher 		}
29733f810b2SJeff Kirsher 		/*SC02*/
29833f810b2SJeff Kirsher 		if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join &&
29933f810b2SJeff Kirsher 		     !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) {
30033f810b2SJeff Kirsher 			GO_STATE(SC10_C_WRAP_B) ;
30133f810b2SJeff Kirsher 			break ;
30233f810b2SJeff Kirsher 		}
30333f810b2SJeff Kirsher 		break ;
30433f810b2SJeff Kirsher 	case ACTIONS(SC9_C_WRAP_A) :
30533f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
30633f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
30733f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
30833f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
30933f810b2SJeff Kirsher 		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
31033f810b2SJeff Kirsher 		config_mux(smc,MUX_WRAPA) ;		/* configure PHY mux */
31133f810b2SJeff Kirsher 		if (smc->y[PA].cf_loop) {
31233f810b2SJeff Kirsher 			smc->r.rm_join = FALSE ;
31333f810b2SJeff Kirsher 			smc->r.rm_loop = TRUE ;
31433f810b2SJeff Kirsher 			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
31533f810b2SJeff Kirsher 		}
31633f810b2SJeff Kirsher 		if (smc->y[PA].cf_join) {
31733f810b2SJeff Kirsher 			smc->r.rm_loop = FALSE ;
31833f810b2SJeff Kirsher 			smc->r.rm_join = TRUE ;
31933f810b2SJeff Kirsher 			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
32033f810b2SJeff Kirsher 		}
32133f810b2SJeff Kirsher 		ACTIONS_DONE() ;
3225671e8c1SJoe Perches 		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
32333f810b2SJeff Kirsher 		break ;
32433f810b2SJeff Kirsher 	case SC9_C_WRAP_A :
32533f810b2SJeff Kirsher 		/*SC10*/
32633f810b2SJeff Kirsher 		if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) &&
32733f810b2SJeff Kirsher 		      !smc->y[PA].cf_loop ) {
32833f810b2SJeff Kirsher 			GO_STATE(SC0_ISOLATED) ;
32933f810b2SJeff Kirsher 			break ;
33033f810b2SJeff Kirsher 		}
33133f810b2SJeff Kirsher 		/*SC12*/
33233f810b2SJeff Kirsher 		else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join &&
33333f810b2SJeff Kirsher 			   smc->y[PA].cem_pst == CEM_PST_UP) ||
33433f810b2SJeff Kirsher 			  ((smc->y[PB].cf_loop ||
33533f810b2SJeff Kirsher 			   (smc->y[PB].cf_join &&
33633f810b2SJeff Kirsher 			    smc->y[PB].cem_pst == CEM_PST_UP)) &&
33733f810b2SJeff Kirsher 			    (smc->y[PA].pc_mode == PM_TREE ||
33833f810b2SJeff Kirsher 			     smc->y[PB].pc_mode == PM_TREE))) {
33933f810b2SJeff Kirsher 			smc->y[PA].scrub = TRUE ;
34033f810b2SJeff Kirsher 			GO_STATE(SC10_C_WRAP_B) ;
34133f810b2SJeff Kirsher 			break ;
34233f810b2SJeff Kirsher 		}
34333f810b2SJeff Kirsher 		/*SC14*/
34433f810b2SJeff Kirsher 		else if (!smc->s.attach_s &&
34533f810b2SJeff Kirsher 			  smc->y[PA].cf_join &&
34633f810b2SJeff Kirsher 			  smc->y[PA].cem_pst == CEM_PST_UP &&
34733f810b2SJeff Kirsher 			  smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join &&
34833f810b2SJeff Kirsher 			  smc->y[PB].cem_pst == CEM_PST_UP &&
34933f810b2SJeff Kirsher 			  smc->y[PB].pc_mode == PM_PEER) {
35033f810b2SJeff Kirsher 			smc->y[PA].scrub = TRUE ;
35133f810b2SJeff Kirsher 			smc->y[PB].scrub = TRUE ;
35233f810b2SJeff Kirsher 			GO_STATE(SC4_THRU_A) ;
35333f810b2SJeff Kirsher 			break ;
35433f810b2SJeff Kirsher 		}
35533f810b2SJeff Kirsher 		/*SC15*/
35633f810b2SJeff Kirsher 		else if ( smc->s.attach_s &&
35733f810b2SJeff Kirsher 			  smc->y[PA].cf_join &&
35833f810b2SJeff Kirsher 			  smc->y[PA].cem_pst == CEM_PST_UP &&
35933f810b2SJeff Kirsher 			  smc->y[PA].pc_mode == PM_PEER &&
36033f810b2SJeff Kirsher 			  smc->y[PB].cf_join &&
36133f810b2SJeff Kirsher 			  smc->y[PB].cem_pst == CEM_PST_UP &&
36233f810b2SJeff Kirsher 			  smc->y[PB].pc_mode == PM_PEER) {
36333f810b2SJeff Kirsher 			smc->y[PA].scrub = TRUE ;
36433f810b2SJeff Kirsher 			smc->y[PB].scrub = TRUE ;
36533f810b2SJeff Kirsher 			GO_STATE(SC5_THRU_B) ;
36633f810b2SJeff Kirsher 			break ;
36733f810b2SJeff Kirsher 		}
36833f810b2SJeff Kirsher 		break ;
36933f810b2SJeff Kirsher 	case ACTIONS(SC10_C_WRAP_B) :
37033f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
37133f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
37233f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
37333f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
37433f810b2SJeff Kirsher 		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
37533f810b2SJeff Kirsher 		config_mux(smc,MUX_WRAPB) ;		/* configure PHY mux */
37633f810b2SJeff Kirsher 		if (smc->y[PB].cf_loop) {
37733f810b2SJeff Kirsher 			smc->r.rm_join = FALSE ;
37833f810b2SJeff Kirsher 			smc->r.rm_loop = TRUE ;
37933f810b2SJeff Kirsher 			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
38033f810b2SJeff Kirsher 		}
38133f810b2SJeff Kirsher 		if (smc->y[PB].cf_join) {
38233f810b2SJeff Kirsher 			smc->r.rm_loop = FALSE ;
38333f810b2SJeff Kirsher 			smc->r.rm_join = TRUE ;
38433f810b2SJeff Kirsher 			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
38533f810b2SJeff Kirsher 		}
38633f810b2SJeff Kirsher 		ACTIONS_DONE() ;
3875671e8c1SJoe Perches 		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
38833f810b2SJeff Kirsher 		break ;
38933f810b2SJeff Kirsher 	case SC10_C_WRAP_B :
39033f810b2SJeff Kirsher 		/*SC20*/
39133f810b2SJeff Kirsher 		if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) {
39233f810b2SJeff Kirsher 			GO_STATE(SC0_ISOLATED) ;
39333f810b2SJeff Kirsher 			break ;
39433f810b2SJeff Kirsher 		}
39533f810b2SJeff Kirsher 		/*SC21*/
39633f810b2SJeff Kirsher 		else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER &&
39733f810b2SJeff Kirsher 			  smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
39833f810b2SJeff Kirsher 			smc->y[PB].scrub = TRUE ;
39933f810b2SJeff Kirsher 			GO_STATE(SC9_C_WRAP_A) ;
40033f810b2SJeff Kirsher 			break ;
40133f810b2SJeff Kirsher 		}
40233f810b2SJeff Kirsher 		/*SC24*/
40333f810b2SJeff Kirsher 		else if (!smc->s.attach_s &&
40433f810b2SJeff Kirsher 			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
40533f810b2SJeff Kirsher 			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
40633f810b2SJeff Kirsher 			smc->y[PA].scrub = TRUE ;
40733f810b2SJeff Kirsher 			smc->y[PB].scrub = TRUE ;
40833f810b2SJeff Kirsher 			GO_STATE(SC4_THRU_A) ;
40933f810b2SJeff Kirsher 			break ;
41033f810b2SJeff Kirsher 		}
41133f810b2SJeff Kirsher 		/*SC25*/
41233f810b2SJeff Kirsher 		else if ( smc->s.attach_s &&
41333f810b2SJeff Kirsher 			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
41433f810b2SJeff Kirsher 			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
41533f810b2SJeff Kirsher 			smc->y[PA].scrub = TRUE ;
41633f810b2SJeff Kirsher 			smc->y[PB].scrub = TRUE ;
41733f810b2SJeff Kirsher 			GO_STATE(SC5_THRU_B) ;
41833f810b2SJeff Kirsher 			break ;
41933f810b2SJeff Kirsher 		}
42033f810b2SJeff Kirsher 		break ;
42133f810b2SJeff Kirsher 	case ACTIONS(SC4_THRU_A) :
42233f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
42333f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
42433f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
42533f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
42633f810b2SJeff Kirsher 		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
42733f810b2SJeff Kirsher 		config_mux(smc,MUX_THRUA) ;		/* configure PHY mux */
42833f810b2SJeff Kirsher 		smc->r.rm_loop = FALSE ;
42933f810b2SJeff Kirsher 		smc->r.rm_join = TRUE ;
43033f810b2SJeff Kirsher 		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
43133f810b2SJeff Kirsher 		ACTIONS_DONE() ;
4325671e8c1SJoe Perches 		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
43333f810b2SJeff Kirsher 		break ;
43433f810b2SJeff Kirsher 	case SC4_THRU_A :
43533f810b2SJeff Kirsher 		/*SC41*/
43633f810b2SJeff Kirsher 		if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) {
43733f810b2SJeff Kirsher 			smc->y[PA].scrub = TRUE ;
43833f810b2SJeff Kirsher 			GO_STATE(SC9_C_WRAP_A) ;
43933f810b2SJeff Kirsher 			break ;
44033f810b2SJeff Kirsher 		}
44133f810b2SJeff Kirsher 		/*SC42*/
44233f810b2SJeff Kirsher 		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
44333f810b2SJeff Kirsher 			smc->y[PB].scrub = TRUE ;
44433f810b2SJeff Kirsher 			GO_STATE(SC10_C_WRAP_B) ;
44533f810b2SJeff Kirsher 			break ;
44633f810b2SJeff Kirsher 		}
44733f810b2SJeff Kirsher 		/*SC45*/
44833f810b2SJeff Kirsher 		else if (smc->s.attach_s) {
44933f810b2SJeff Kirsher 			smc->y[PB].scrub = TRUE ;
45033f810b2SJeff Kirsher 			GO_STATE(SC5_THRU_B) ;
45133f810b2SJeff Kirsher 			break ;
45233f810b2SJeff Kirsher 		}
45333f810b2SJeff Kirsher 		break ;
45433f810b2SJeff Kirsher 	case ACTIONS(SC5_THRU_B) :
45533f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
45633f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
45733f810b2SJeff Kirsher 		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
45833f810b2SJeff Kirsher 		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
45933f810b2SJeff Kirsher 		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
46033f810b2SJeff Kirsher 		config_mux(smc,MUX_THRUB) ;		/* configure PHY mux */
46133f810b2SJeff Kirsher 		smc->r.rm_loop = FALSE ;
46233f810b2SJeff Kirsher 		smc->r.rm_join = TRUE ;
46333f810b2SJeff Kirsher 		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
46433f810b2SJeff Kirsher 		ACTIONS_DONE() ;
4655671e8c1SJoe Perches 		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
46633f810b2SJeff Kirsher 		break ;
46733f810b2SJeff Kirsher 	case SC5_THRU_B :
46833f810b2SJeff Kirsher 		/*SC51*/
46933f810b2SJeff Kirsher 		if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) {
47033f810b2SJeff Kirsher 			smc->y[PA].scrub = TRUE ;
47133f810b2SJeff Kirsher 			GO_STATE(SC9_C_WRAP_A) ;
47233f810b2SJeff Kirsher 			break ;
47333f810b2SJeff Kirsher 		}
47433f810b2SJeff Kirsher 		/*SC52*/
47533f810b2SJeff Kirsher 		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
47633f810b2SJeff Kirsher 			smc->y[PB].scrub = TRUE ;
47733f810b2SJeff Kirsher 			GO_STATE(SC10_C_WRAP_B) ;
47833f810b2SJeff Kirsher 			break ;
47933f810b2SJeff Kirsher 		}
48033f810b2SJeff Kirsher 		/*SC54*/
48133f810b2SJeff Kirsher 		else if (!smc->s.attach_s) {
48233f810b2SJeff Kirsher 			smc->y[PA].scrub = TRUE ;
48333f810b2SJeff Kirsher 			GO_STATE(SC4_THRU_A) ;
48433f810b2SJeff Kirsher 			break ;
48533f810b2SJeff Kirsher 		}
48633f810b2SJeff Kirsher 		break ;
48733f810b2SJeff Kirsher 	case ACTIONS(SC11_C_WRAP_S) :
48833f810b2SJeff Kirsher 		smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
48933f810b2SJeff Kirsher 		smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ;
49033f810b2SJeff Kirsher 		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
49133f810b2SJeff Kirsher 		config_mux(smc,MUX_WRAPS) ;		/* configure PHY mux */
49233f810b2SJeff Kirsher 		if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) {
49333f810b2SJeff Kirsher 			smc->r.rm_join = FALSE ;
49433f810b2SJeff Kirsher 			smc->r.rm_loop = TRUE ;
49533f810b2SJeff Kirsher 			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
49633f810b2SJeff Kirsher 		}
49733f810b2SJeff Kirsher 		if (smc->y[PA].cf_join || smc->y[PB].cf_join) {
49833f810b2SJeff Kirsher 			smc->r.rm_loop = FALSE ;
49933f810b2SJeff Kirsher 			smc->r.rm_join = TRUE ;
50033f810b2SJeff Kirsher 			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
50133f810b2SJeff Kirsher 		}
50233f810b2SJeff Kirsher 		ACTIONS_DONE() ;
5035671e8c1SJoe Perches 		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
50433f810b2SJeff Kirsher 		break ;
50533f810b2SJeff Kirsher 	case SC11_C_WRAP_S :
50633f810b2SJeff Kirsher 		/*SC70*/
50733f810b2SJeff Kirsher 		if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop &&
50833f810b2SJeff Kirsher 		     !smc->y[PB].cf_join && !smc->y[PB].cf_loop) {
50933f810b2SJeff Kirsher 			GO_STATE(SC0_ISOLATED) ;
51033f810b2SJeff Kirsher 			break ;
51133f810b2SJeff Kirsher 		}
51233f810b2SJeff Kirsher 		break ;
51333f810b2SJeff Kirsher 	default:
51433f810b2SJeff Kirsher 		SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ;
51533f810b2SJeff Kirsher 		break;
51633f810b2SJeff Kirsher 	}
51733f810b2SJeff Kirsher }
51833f810b2SJeff Kirsher 
51933f810b2SJeff Kirsher /*
52033f810b2SJeff Kirsher  * get MAC's input Port
52133f810b2SJeff Kirsher  *	return :
52233f810b2SJeff Kirsher  *		PA or PB
52333f810b2SJeff Kirsher  */
cfm_get_mac_input(struct s_smc * smc)52433f810b2SJeff Kirsher int cfm_get_mac_input(struct s_smc *smc)
52533f810b2SJeff Kirsher {
52633f810b2SJeff Kirsher 	return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
52733f810b2SJeff Kirsher 		smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA;
52833f810b2SJeff Kirsher }
52933f810b2SJeff Kirsher 
53033f810b2SJeff Kirsher /*
53133f810b2SJeff Kirsher  * get MAC's output Port
53233f810b2SJeff Kirsher  *	return :
53333f810b2SJeff Kirsher  *		PA or PB
53433f810b2SJeff Kirsher  */
cfm_get_mac_output(struct s_smc * smc)53533f810b2SJeff Kirsher int cfm_get_mac_output(struct s_smc *smc)
53633f810b2SJeff Kirsher {
53733f810b2SJeff Kirsher 	return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
53833f810b2SJeff Kirsher 		smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA;
53933f810b2SJeff Kirsher }
54033f810b2SJeff Kirsher 
54133f810b2SJeff Kirsher static char path_iso[] = {
54233f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO,
54333f810b2SJeff Kirsher 	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
54433f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
54533f810b2SJeff Kirsher } ;
54633f810b2SJeff Kirsher 
54733f810b2SJeff Kirsher static char path_wrap_a[] = {
54833f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
54933f810b2SJeff Kirsher 	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
55033f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
55133f810b2SJeff Kirsher } ;
55233f810b2SJeff Kirsher 
55333f810b2SJeff Kirsher static char path_wrap_b[] = {
55433f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM,
55533f810b2SJeff Kirsher 	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
55633f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO
55733f810b2SJeff Kirsher } ;
55833f810b2SJeff Kirsher 
55933f810b2SJeff Kirsher static char path_thru[] = {
56033f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
56133f810b2SJeff Kirsher 	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
56233f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM
56333f810b2SJeff Kirsher } ;
56433f810b2SJeff Kirsher 
56533f810b2SJeff Kirsher static char path_wrap_s[] = {
56633f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_PRIM,
56733f810b2SJeff Kirsher 	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
56833f810b2SJeff Kirsher } ;
56933f810b2SJeff Kirsher 
57033f810b2SJeff Kirsher static char path_iso_s[] = {
57133f810b2SJeff Kirsher 	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_ISO,
57233f810b2SJeff Kirsher 	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
57333f810b2SJeff Kirsher } ;
57433f810b2SJeff Kirsher 
cem_build_path(struct s_smc * smc,char * to,int path_index)57533f810b2SJeff Kirsher int cem_build_path(struct s_smc *smc, char *to, int path_index)
57633f810b2SJeff Kirsher {
57733f810b2SJeff Kirsher 	char	*path ;
57833f810b2SJeff Kirsher 	int	len ;
57933f810b2SJeff Kirsher 
58033f810b2SJeff Kirsher 	switch (smc->mib.fddiSMTCF_State) {
58133f810b2SJeff Kirsher 	default :
58233f810b2SJeff Kirsher 	case SC0_ISOLATED :
58333f810b2SJeff Kirsher 		path = smc->s.sas ? path_iso_s : path_iso ;
58433f810b2SJeff Kirsher 		len = smc->s.sas ? sizeof(path_iso_s) :  sizeof(path_iso) ;
58533f810b2SJeff Kirsher 		break ;
58633f810b2SJeff Kirsher 	case SC9_C_WRAP_A :
58733f810b2SJeff Kirsher 		path = path_wrap_a ;
58833f810b2SJeff Kirsher 		len = sizeof(path_wrap_a) ;
58933f810b2SJeff Kirsher 		break ;
59033f810b2SJeff Kirsher 	case SC10_C_WRAP_B :
59133f810b2SJeff Kirsher 		path = path_wrap_b ;
59233f810b2SJeff Kirsher 		len = sizeof(path_wrap_b) ;
59333f810b2SJeff Kirsher 		break ;
59433f810b2SJeff Kirsher 	case SC4_THRU_A :
59533f810b2SJeff Kirsher 		path = path_thru ;
59633f810b2SJeff Kirsher 		len = sizeof(path_thru) ;
59733f810b2SJeff Kirsher 		break ;
59833f810b2SJeff Kirsher 	case SC11_C_WRAP_S :
59933f810b2SJeff Kirsher 		path = path_wrap_s ;
60033f810b2SJeff Kirsher 		len = sizeof(path_wrap_s) ;
60133f810b2SJeff Kirsher 		break ;
60233f810b2SJeff Kirsher 	}
60333f810b2SJeff Kirsher 	memcpy(to,path,len) ;
60433f810b2SJeff Kirsher 
60533f810b2SJeff Kirsher 	LINT_USE(path_index);
60633f810b2SJeff Kirsher 
60733f810b2SJeff Kirsher 	return len;
60833f810b2SJeff Kirsher }
609