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 /*
248*d1ad06baSLee Jones * Don't ever send MAC_PATH_CHANGE events. Our MAC is hard-wired
24933f810b2SJeff Kirsher * to the primary path.
25033f810b2SJeff Kirsher */
251*d1ad06baSLee 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