xref: /kernel/linux/linux-5.10/drivers/net/fddi/skfp/cfm.c (revision 8c2ecf20)
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}
609