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