cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cfm.c (15940B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/******************************************************************************
      3 *
      4 *	(C)Copyright 1998,1999 SysKonnect,
      5 *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
      6 *
      7 *	See the file "skfddi.c" for further information.
      8 *
      9 *	The information in this file is provided "AS IS" without warranty.
     10 *
     11 ******************************************************************************/
     12
     13/*
     14	SMT CFM
     15	Configuration Management
     16	DAS with single MAC
     17*/
     18
     19/*
     20 *	Hardware independent state machine implemantation
     21 *	The following external SMT functions are referenced :
     22 *
     23 *		queue_event()
     24 *
     25 *	The following external HW dependent functions are referenced :
     26 *		config_mux()
     27 *
     28 *	The following HW dependent events are required :
     29 *		NONE 
     30 */
     31
     32#include "h/types.h"
     33#include "h/fddi.h"
     34#include "h/smc.h"
     35
     36#define KERNEL
     37#include "h/smtstate.h"
     38
     39/*
     40 * FSM Macros
     41 */
     42#define AFLAG	0x10
     43#define GO_STATE(x)	(smc->mib.fddiSMTCF_State = (x)|AFLAG)
     44#define ACTIONS_DONE()	(smc->mib.fddiSMTCF_State &= ~AFLAG)
     45#define ACTIONS(x)	(x|AFLAG)
     46
     47/*
     48 * symbolic state names
     49 */
     50static const char * const cfm_states[] = {
     51	"SC0_ISOLATED","CF1","CF2","CF3","CF4",
     52	"SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S",
     53	"SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A"
     54} ;
     55
     56/*
     57 * symbolic event names
     58 */
     59static const char * const cfm_events[] = {
     60	"NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
     61} ;
     62
     63/*
     64 * map from state to downstream port type
     65 */
     66static const unsigned char cf_to_ptype[] = {
     67	TNONE,TNONE,TNONE,TNONE,TNONE,
     68	TNONE,TB,TB,TS,
     69	TA,TB,TS,TB
     70} ;
     71
     72/*
     73 * CEM port states
     74 */
     75#define	CEM_PST_DOWN	0
     76#define	CEM_PST_UP	1
     77#define	CEM_PST_HOLD	2
     78/* define portstate array only for A and B port */
     79/* Do this within the smc structure (use in multiple cards) */
     80
     81/*
     82 * all Globals  are defined in smc.h
     83 * struct s_cfm
     84 */
     85
     86/*
     87 * function declarations
     88 */
     89static void cfm_fsm(struct s_smc *smc, int cmd);
     90
     91/*
     92	init CFM state machine
     93	clear all CFM vars and flags
     94*/
     95void cfm_init(struct s_smc *smc)
     96{
     97	smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ;
     98	smc->r.rm_join = 0 ;
     99	smc->r.rm_loop = 0 ;
    100	smc->y[PA].scrub = 0 ;
    101	smc->y[PB].scrub = 0 ;
    102	smc->y[PA].cem_pst = CEM_PST_DOWN ;
    103	smc->y[PB].cem_pst = CEM_PST_DOWN ;
    104}
    105
    106/* Some terms conditions used by the selection criteria */
    107#define THRU_ENABLED(smc)	(smc->y[PA].pc_mode != PM_TREE && \
    108				 smc->y[PB].pc_mode != PM_TREE)
    109/* Selection criteria for the ports */
    110static void selection_criteria (struct s_smc *smc, struct s_phy *phy)
    111{
    112
    113	switch (phy->mib->fddiPORTMy_Type) {
    114	case TA:
    115		if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) {
    116			phy->wc_flag = TRUE ;
    117		} else {
    118			phy->wc_flag = FALSE ;
    119		}
    120
    121		break;
    122	case TB:
    123		/* take precedence over PA */
    124		phy->wc_flag = FALSE ;
    125		break;
    126	case TS:
    127		phy->wc_flag = FALSE ;
    128		break;
    129	case TM:
    130		phy->wc_flag = FALSE ;
    131		break;
    132	}
    133
    134}
    135
    136void all_selection_criteria(struct s_smc *smc)
    137{
    138	struct s_phy	*phy ;
    139	int		p ;
    140
    141	for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) {
    142		/* Do the selection criteria */
    143		selection_criteria (smc,phy);
    144	}
    145}
    146
    147static void cem_priv_state(struct s_smc *smc, int event)
    148/* State machine for private PORT states: used to optimize dual homing */
    149{
    150	int	np;	/* Number of the port */
    151	int	i;
    152
    153	/* Do this only in a DAS */
    154	if (smc->s.sas != SMT_DAS )
    155		return ;
    156
    157	np = event - CF_JOIN;
    158
    159	if (np != PA && np != PB) {
    160		return ;
    161	}
    162	/* Change the port state according to the event (portnumber) */
    163	if (smc->y[np].cf_join) {
    164		smc->y[np].cem_pst = CEM_PST_UP ;
    165	} else if (!smc->y[np].wc_flag) {
    166		/* set the port to done only if it is not withheld */
    167		smc->y[np].cem_pst = CEM_PST_DOWN ;
    168	}
    169
    170	/* Don't set an hold port to down */
    171
    172	/* Check all ports of restart conditions */
    173	for (i = 0 ; i < 2 ; i ++ ) {
    174		/* Check all port for PORT is on hold and no withhold is done */
    175		if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) {
    176			smc->y[i].cem_pst = CEM_PST_DOWN;
    177			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
    178		}
    179		if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) {
    180			smc->y[i].cem_pst = CEM_PST_HOLD;
    181			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
    182		}
    183		if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) {
    184			/*
    185			 * The port must be restarted when the wc_flag
    186			 * will be reset. So set the port on hold.
    187			 */
    188			smc->y[i].cem_pst = CEM_PST_HOLD;
    189		}
    190	}
    191	return ;
    192}
    193
    194/*
    195	CFM state machine
    196	called by dispatcher
    197
    198	do
    199		display state change
    200		process event
    201	until SM is stable
    202*/
    203void cfm(struct s_smc *smc, int event)
    204{
    205	int	state ;		/* remember last state */
    206	int	cond ;
    207
    208	/* We will do the following: */
    209	/*  - compute the variable WC_Flag for every port (This is where */
    210	/*    we can extend the requested path checking !!) */
    211	/*  - do the old (SMT 6.2 like) state machine */
    212	/*  - do the resulting station states */
    213
    214	all_selection_criteria (smc);
    215
    216	/* We will check now whether a state transition is allowed or not */
    217	/*  - change the portstates */
    218	cem_priv_state (smc, event);
    219
    220	do {
    221		DB_CFM("CFM : state %s%s event %s",
    222		       smc->mib.fddiSMTCF_State & AFLAG ? "ACTIONS " : "",
    223		       cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG],
    224		       cfm_events[event]);
    225		state = smc->mib.fddiSMTCF_State ;
    226		cfm_fsm(smc,event) ;
    227		event = 0 ;
    228	} while (state != smc->mib.fddiSMTCF_State) ;
    229
    230#ifndef	SLIM_SMT
    231	/*
    232	 * check peer wrap condition
    233	 */
    234	cond = FALSE ;
    235	if (	(smc->mib.fddiSMTCF_State == SC9_C_WRAP_A &&
    236		smc->y[PA].pc_mode == PM_PEER) 	||
    237		(smc->mib.fddiSMTCF_State == SC10_C_WRAP_B &&
    238		smc->y[PB].pc_mode == PM_PEER) 	||
    239		(smc->mib.fddiSMTCF_State == SC11_C_WRAP_S &&
    240		smc->y[PS].pc_mode == PM_PEER &&
    241		smc->y[PS].mib->fddiPORTNeighborType != TS ) ) {
    242			cond = TRUE ;
    243	}
    244	if (cond != smc->mib.fddiSMTPeerWrapFlag)
    245		smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ;
    246
    247	/*
    248	 * Don't ever send MAC_PATH_CHANGE events. Our MAC is hard-wired
    249	 * to the primary path.
    250	 */
    251
    252#endif	/* no SLIM_SMT */
    253
    254	/*
    255	 * set MAC port type
    256	 */
    257	smc->mib.m[MAC0].fddiMACDownstreamPORTType =
    258		cf_to_ptype[smc->mib.fddiSMTCF_State] ;
    259	cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ;
    260}
    261
    262/*
    263	process CFM event
    264*/
    265/*ARGSUSED1*/
    266static void cfm_fsm(struct s_smc *smc, int cmd)
    267{
    268	switch(smc->mib.fddiSMTCF_State) {
    269	case ACTIONS(SC0_ISOLATED) :
    270		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
    271		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
    272		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
    273		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
    274		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;
    275		config_mux(smc,MUX_ISOLATE) ;	/* configure PHY Mux */
    276		smc->r.rm_loop = FALSE ;
    277		smc->r.rm_join = FALSE ;
    278		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
    279		/* Don't do the WC-Flag changing here */
    280		ACTIONS_DONE() ;
    281		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
    282		break;
    283	case SC0_ISOLATED :
    284		/*SC07*/
    285		/*SAS port can be PA or PB ! */
    286		if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop ||
    287				smc->y[PB].cf_join || smc->y[PB].cf_loop)) {
    288			GO_STATE(SC11_C_WRAP_S) ;
    289			break ;
    290		}
    291		/*SC01*/
    292		if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join &&
    293		     !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) {
    294			GO_STATE(SC9_C_WRAP_A) ;
    295			break ;
    296		}
    297		/*SC02*/
    298		if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join &&
    299		     !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) {
    300			GO_STATE(SC10_C_WRAP_B) ;
    301			break ;
    302		}
    303		break ;
    304	case ACTIONS(SC9_C_WRAP_A) :
    305		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
    306		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
    307		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
    308		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
    309		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
    310		config_mux(smc,MUX_WRAPA) ;		/* configure PHY mux */
    311		if (smc->y[PA].cf_loop) {
    312			smc->r.rm_join = FALSE ;
    313			smc->r.rm_loop = TRUE ;
    314			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
    315		}
    316		if (smc->y[PA].cf_join) {
    317			smc->r.rm_loop = FALSE ;
    318			smc->r.rm_join = TRUE ;
    319			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
    320		}
    321		ACTIONS_DONE() ;
    322		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
    323		break ;
    324	case SC9_C_WRAP_A :
    325		/*SC10*/
    326		if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) &&
    327		      !smc->y[PA].cf_loop ) {
    328			GO_STATE(SC0_ISOLATED) ;
    329			break ;
    330		}
    331		/*SC12*/
    332		else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join &&
    333			   smc->y[PA].cem_pst == CEM_PST_UP) ||
    334			  ((smc->y[PB].cf_loop ||
    335			   (smc->y[PB].cf_join &&
    336			    smc->y[PB].cem_pst == CEM_PST_UP)) &&
    337			    (smc->y[PA].pc_mode == PM_TREE ||
    338			     smc->y[PB].pc_mode == PM_TREE))) {
    339			smc->y[PA].scrub = TRUE ;
    340			GO_STATE(SC10_C_WRAP_B) ;
    341			break ;
    342		}
    343		/*SC14*/
    344		else if (!smc->s.attach_s &&
    345			  smc->y[PA].cf_join &&
    346			  smc->y[PA].cem_pst == CEM_PST_UP &&
    347			  smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join &&
    348			  smc->y[PB].cem_pst == CEM_PST_UP &&
    349			  smc->y[PB].pc_mode == PM_PEER) {
    350			smc->y[PA].scrub = TRUE ;
    351			smc->y[PB].scrub = TRUE ;
    352			GO_STATE(SC4_THRU_A) ;
    353			break ;
    354		}
    355		/*SC15*/
    356		else if ( smc->s.attach_s &&
    357			  smc->y[PA].cf_join &&
    358			  smc->y[PA].cem_pst == CEM_PST_UP &&
    359			  smc->y[PA].pc_mode == PM_PEER &&
    360			  smc->y[PB].cf_join &&
    361			  smc->y[PB].cem_pst == CEM_PST_UP &&
    362			  smc->y[PB].pc_mode == PM_PEER) {
    363			smc->y[PA].scrub = TRUE ;
    364			smc->y[PB].scrub = TRUE ;
    365			GO_STATE(SC5_THRU_B) ;
    366			break ;
    367		}
    368		break ;
    369	case ACTIONS(SC10_C_WRAP_B) :
    370		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
    371		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
    372		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
    373		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
    374		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
    375		config_mux(smc,MUX_WRAPB) ;		/* configure PHY mux */
    376		if (smc->y[PB].cf_loop) {
    377			smc->r.rm_join = FALSE ;
    378			smc->r.rm_loop = TRUE ;
    379			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
    380		}
    381		if (smc->y[PB].cf_join) {
    382			smc->r.rm_loop = FALSE ;
    383			smc->r.rm_join = TRUE ;
    384			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
    385		}
    386		ACTIONS_DONE() ;
    387		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
    388		break ;
    389	case SC10_C_WRAP_B :
    390		/*SC20*/
    391		if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) {
    392			GO_STATE(SC0_ISOLATED) ;
    393			break ;
    394		}
    395		/*SC21*/
    396		else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER &&
    397			  smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
    398			smc->y[PB].scrub = TRUE ;
    399			GO_STATE(SC9_C_WRAP_A) ;
    400			break ;
    401		}
    402		/*SC24*/
    403		else if (!smc->s.attach_s &&
    404			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
    405			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
    406			smc->y[PA].scrub = TRUE ;
    407			smc->y[PB].scrub = TRUE ;
    408			GO_STATE(SC4_THRU_A) ;
    409			break ;
    410		}
    411		/*SC25*/
    412		else if ( smc->s.attach_s &&
    413			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
    414			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
    415			smc->y[PA].scrub = TRUE ;
    416			smc->y[PB].scrub = TRUE ;
    417			GO_STATE(SC5_THRU_B) ;
    418			break ;
    419		}
    420		break ;
    421	case ACTIONS(SC4_THRU_A) :
    422		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
    423		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
    424		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
    425		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
    426		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
    427		config_mux(smc,MUX_THRUA) ;		/* configure PHY mux */
    428		smc->r.rm_loop = FALSE ;
    429		smc->r.rm_join = TRUE ;
    430		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
    431		ACTIONS_DONE() ;
    432		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
    433		break ;
    434	case SC4_THRU_A :
    435		/*SC41*/
    436		if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) {
    437			smc->y[PA].scrub = TRUE ;
    438			GO_STATE(SC9_C_WRAP_A) ;
    439			break ;
    440		}
    441		/*SC42*/
    442		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
    443			smc->y[PB].scrub = TRUE ;
    444			GO_STATE(SC10_C_WRAP_B) ;
    445			break ;
    446		}
    447		/*SC45*/
    448		else if (smc->s.attach_s) {
    449			smc->y[PB].scrub = TRUE ;
    450			GO_STATE(SC5_THRU_B) ;
    451			break ;
    452		}
    453		break ;
    454	case ACTIONS(SC5_THRU_B) :
    455		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
    456		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
    457		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
    458		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
    459		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
    460		config_mux(smc,MUX_THRUB) ;		/* configure PHY mux */
    461		smc->r.rm_loop = FALSE ;
    462		smc->r.rm_join = TRUE ;
    463		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
    464		ACTIONS_DONE() ;
    465		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
    466		break ;
    467	case SC5_THRU_B :
    468		/*SC51*/
    469		if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) {
    470			smc->y[PA].scrub = TRUE ;
    471			GO_STATE(SC9_C_WRAP_A) ;
    472			break ;
    473		}
    474		/*SC52*/
    475		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
    476			smc->y[PB].scrub = TRUE ;
    477			GO_STATE(SC10_C_WRAP_B) ;
    478			break ;
    479		}
    480		/*SC54*/
    481		else if (!smc->s.attach_s) {
    482			smc->y[PA].scrub = TRUE ;
    483			GO_STATE(SC4_THRU_A) ;
    484			break ;
    485		}
    486		break ;
    487	case ACTIONS(SC11_C_WRAP_S) :
    488		smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
    489		smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ;
    490		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
    491		config_mux(smc,MUX_WRAPS) ;		/* configure PHY mux */
    492		if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) {
    493			smc->r.rm_join = FALSE ;
    494			smc->r.rm_loop = TRUE ;
    495			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
    496		}
    497		if (smc->y[PA].cf_join || smc->y[PB].cf_join) {
    498			smc->r.rm_loop = FALSE ;
    499			smc->r.rm_join = TRUE ;
    500			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
    501		}
    502		ACTIONS_DONE() ;
    503		DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
    504		break ;
    505	case SC11_C_WRAP_S :
    506		/*SC70*/
    507		if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop &&
    508		     !smc->y[PB].cf_join && !smc->y[PB].cf_loop) {
    509			GO_STATE(SC0_ISOLATED) ;
    510			break ;
    511		}
    512		break ;
    513	default:
    514		SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ;
    515		break;
    516	}
    517}
    518
    519/*
    520 * get MAC's input Port
    521 *	return :
    522 *		PA or PB
    523 */
    524int cfm_get_mac_input(struct s_smc *smc)
    525{
    526	return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
    527		smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA;
    528}
    529
    530/*
    531 * get MAC's output Port
    532 *	return :
    533 *		PA or PB
    534 */
    535int cfm_get_mac_output(struct s_smc *smc)
    536{
    537	return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
    538		smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA;
    539}
    540
    541static char path_iso[] = {
    542	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO,
    543	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
    544	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
    545} ;
    546
    547static char path_wrap_a[] = {
    548	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
    549	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
    550	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
    551} ;
    552
    553static char path_wrap_b[] = {
    554	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM,
    555	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
    556	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO
    557} ;
    558
    559static char path_thru[] = {
    560	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
    561	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
    562	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM
    563} ;
    564
    565static char path_wrap_s[] = {
    566	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_PRIM,
    567	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
    568} ;
    569
    570static char path_iso_s[] = {
    571	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_ISO,
    572	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
    573} ;
    574
    575int cem_build_path(struct s_smc *smc, char *to, int path_index)
    576{
    577	char	*path ;
    578	int	len ;
    579
    580	switch (smc->mib.fddiSMTCF_State) {
    581	default :
    582	case SC0_ISOLATED :
    583		path = smc->s.sas ? path_iso_s : path_iso ;
    584		len = smc->s.sas ? sizeof(path_iso_s) :  sizeof(path_iso) ;
    585		break ;
    586	case SC9_C_WRAP_A :
    587		path = path_wrap_a ;
    588		len = sizeof(path_wrap_a) ;
    589		break ;
    590	case SC10_C_WRAP_B :
    591		path = path_wrap_b ;
    592		len = sizeof(path_wrap_b) ;
    593		break ;
    594	case SC4_THRU_A :
    595		path = path_thru ;
    596		len = sizeof(path_thru) ;
    597		break ;
    598	case SC11_C_WRAP_S :
    599		path = path_wrap_s ;
    600		len = sizeof(path_wrap_s) ;
    601		break ;
    602	}
    603	memcpy(to,path,len) ;
    604
    605	LINT_USE(path_index);
    606
    607	return len;
    608}