PageRenderTime 52ms CodeModel.GetById 13ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/net/fddi/skfp/cfm.c

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