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