1 /******************************************************************************
3 * (C)Copyright 1998,1999 SysKonnect,
4 * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
6 * See the file "skfddi.c" for further information.
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.
13 * The information in this file is provided "AS IS" without warranty.
15 ******************************************************************************/
19 Configuration Management
24 * Hardware independent state machine implemantation
25 * The following external SMT functions are referenced :
29 * The following external HW dependent functions are referenced :
32 * The following HW dependent events are required :
41 #include "h/smtstate.h"
44 static const char ID_sccs
[] = "@(#)cfm.c 2.18 98/10/06 (C) SK " ;
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)
57 * symbolic state names
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"
66 * symbolic event names
68 static const char * const cfm_events
[] = {
69 "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
74 * map from state to downstream port type
76 static const unsigned char cf_to_ptype
[] = {
77 TNONE
,TNONE
,TNONE
,TNONE
,TNONE
,
85 #define CEM_PST_DOWN 0
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) */
92 * all Globals are defined in smc.h
97 * function declarations
99 static void cfm_fsm(struct s_smc
*smc
, int cmd
);
102 init CFM state machine
103 clear all CFM vars and flags
105 void cfm_init(struct s_smc
*smc
)
107 smc
->mib
.fddiSMTCF_State
= ACTIONS(SC0_ISOLATED
) ;
110 smc
->y
[PA
].scrub
= 0 ;
111 smc
->y
[PB
].scrub
= 0 ;
112 smc
->y
[PA
].cem_pst
= CEM_PST_DOWN
;
113 smc
->y
[PB
].cem_pst
= CEM_PST_DOWN
;
116 /* Some terms conditions used by the selection criteria */
117 #define THRU_ENABLED(smc) (smc->y[PA].pc_mode != PM_TREE && \
118 smc->y[PB].pc_mode != PM_TREE)
119 /* Selection criteria for the ports */
120 static void selection_criteria (struct s_smc
*smc
, struct s_phy
*phy
)
123 switch (phy
->mib
->fddiPORTMy_Type
) {
125 if ( !THRU_ENABLED(smc
) && smc
->y
[PB
].cf_join
) {
126 phy
->wc_flag
= TRUE
;
128 phy
->wc_flag
= FALSE
;
133 /* take precedence over PA */
134 phy
->wc_flag
= FALSE
;
137 phy
->wc_flag
= FALSE
;
140 phy
->wc_flag
= FALSE
;
146 void all_selection_criteria(struct s_smc
*smc
)
151 for ( p
= 0,phy
= smc
->y
; p
< NUMPHYS
; p
++, phy
++ ) {
152 /* Do the selection criteria */
153 selection_criteria (smc
,phy
);
157 static void cem_priv_state(struct s_smc
*smc
, int event
)
158 /* State machine for private PORT states: used to optimize dual homing */
160 int np
; /* Number of the port */
163 /* Do this only in a DAS */
164 if (smc
->s
.sas
!= SMT_DAS
)
167 np
= event
- CF_JOIN
;
169 if (np
!= PA
&& np
!= PB
) {
172 /* Change the port state according to the event (portnumber) */
173 if (smc
->y
[np
].cf_join
) {
174 smc
->y
[np
].cem_pst
= CEM_PST_UP
;
175 } else if (!smc
->y
[np
].wc_flag
) {
176 /* set the port to done only if it is not withheld */
177 smc
->y
[np
].cem_pst
= CEM_PST_DOWN
;
180 /* Don't set an hold port to down */
182 /* Check all ports of restart conditions */
183 for (i
= 0 ; i
< 2 ; i
++ ) {
184 /* Check all port for PORT is on hold and no withhold is done */
185 if ( smc
->y
[i
].cem_pst
== CEM_PST_HOLD
&& !smc
->y
[i
].wc_flag
) {
186 smc
->y
[i
].cem_pst
= CEM_PST_DOWN
;
187 queue_event(smc
,(int)(EVENT_PCM
+i
),PC_START
) ;
189 if ( smc
->y
[i
].cem_pst
== CEM_PST_UP
&& smc
->y
[i
].wc_flag
) {
190 smc
->y
[i
].cem_pst
= CEM_PST_HOLD
;
191 queue_event(smc
,(int)(EVENT_PCM
+i
),PC_START
) ;
193 if ( smc
->y
[i
].cem_pst
== CEM_PST_DOWN
&& smc
->y
[i
].wc_flag
) {
195 * The port must be restarted when the wc_flag
196 * will be reset. So set the port on hold.
198 smc
->y
[i
].cem_pst
= CEM_PST_HOLD
;
213 void cfm(struct s_smc
*smc
, int event
)
215 int state
; /* remember last state */
219 /* We will do the following: */
220 /* - compute the variable WC_Flag for every port (This is where */
221 /* we can extend the requested path checking !!) */
222 /* - do the old (SMT 6.2 like) state machine */
223 /* - do the resulting station states */
225 all_selection_criteria (smc
);
227 /* We will check now whether a state transition is allowed or not */
228 /* - change the portstates */
229 cem_priv_state (smc
, event
);
231 oldstate
= smc
->mib
.fddiSMTCF_State
;
233 DB_CFM("CFM : state %s%s",
234 (smc
->mib
.fddiSMTCF_State
& AFLAG
) ? "ACTIONS " : "",
235 cfm_states
[smc
->mib
.fddiSMTCF_State
& ~AFLAG
]) ;
236 DB_CFM(" event %s\n",cfm_events
[event
],0) ;
237 state
= smc
->mib
.fddiSMTCF_State
;
240 } while (state
!= smc
->mib
.fddiSMTCF_State
) ;
244 * check peer wrap condition
247 if ( (smc
->mib
.fddiSMTCF_State
== SC9_C_WRAP_A
&&
248 smc
->y
[PA
].pc_mode
== PM_PEER
) ||
249 (smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
&&
250 smc
->y
[PB
].pc_mode
== PM_PEER
) ||
251 (smc
->mib
.fddiSMTCF_State
== SC11_C_WRAP_S
&&
252 smc
->y
[PS
].pc_mode
== PM_PEER
&&
253 smc
->y
[PS
].mib
->fddiPORTNeighborType
!= TS
) ) {
256 if (cond
!= smc
->mib
.fddiSMTPeerWrapFlag
)
257 smt_srf_event(smc
,SMT_COND_SMT_PEER_WRAP
,0,cond
) ;
259 #endif /* no SLIM_SMT */
264 smc
->mib
.m
[MAC0
].fddiMACDownstreamPORTType
=
265 cf_to_ptype
[smc
->mib
.fddiSMTCF_State
] ;
266 cfm_state_change(smc
,(int)smc
->mib
.fddiSMTCF_State
) ;
273 static void cfm_fsm(struct s_smc
*smc
, int cmd
)
275 switch(smc
->mib
.fddiSMTCF_State
) {
276 case ACTIONS(SC0_ISOLATED
) :
277 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
278 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
279 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= 0 ;
280 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= 0 ;
281 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_SEPA
;
282 config_mux(smc
,MUX_ISOLATE
) ; /* configure PHY Mux */
283 smc
->r
.rm_loop
= FALSE
;
284 smc
->r
.rm_join
= FALSE
;
285 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
286 /* Don't do the WC-Flag changing here */
288 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
292 /*SAS port can be PA or PB ! */
293 if (smc
->s
.sas
&& (smc
->y
[PA
].cf_join
|| smc
->y
[PA
].cf_loop
||
294 smc
->y
[PB
].cf_join
|| smc
->y
[PB
].cf_loop
)) {
295 GO_STATE(SC11_C_WRAP_S
) ;
299 if ((smc
->y
[PA
].cem_pst
== CEM_PST_UP
&& smc
->y
[PA
].cf_join
&&
300 !smc
->y
[PA
].wc_flag
) || smc
->y
[PA
].cf_loop
) {
301 GO_STATE(SC9_C_WRAP_A
) ;
305 if ((smc
->y
[PB
].cem_pst
== CEM_PST_UP
&& smc
->y
[PB
].cf_join
&&
306 !smc
->y
[PB
].wc_flag
) || smc
->y
[PB
].cf_loop
) {
307 GO_STATE(SC10_C_WRAP_B
) ;
311 case ACTIONS(SC9_C_WRAP_A
) :
312 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_CONCATENATED
;
313 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
314 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= INDEX_MAC
;
315 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= 0 ;
316 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_CON
;
317 config_mux(smc
,MUX_WRAPA
) ; /* configure PHY mux */
318 if (smc
->y
[PA
].cf_loop
) {
319 smc
->r
.rm_join
= FALSE
;
320 smc
->r
.rm_loop
= TRUE
;
321 queue_event(smc
,EVENT_RMT
,RM_LOOP
) ;/* signal RMT */
323 if (smc
->y
[PA
].cf_join
) {
324 smc
->r
.rm_loop
= FALSE
;
325 smc
->r
.rm_join
= TRUE
;
326 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
329 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
333 if ( (smc
->y
[PA
].wc_flag
|| !smc
->y
[PA
].cf_join
) &&
334 !smc
->y
[PA
].cf_loop
) {
335 GO_STATE(SC0_ISOLATED
) ;
339 else if ( (smc
->y
[PB
].cf_loop
&& smc
->y
[PA
].cf_join
&&
340 smc
->y
[PA
].cem_pst
== CEM_PST_UP
) ||
341 ((smc
->y
[PB
].cf_loop
||
342 (smc
->y
[PB
].cf_join
&&
343 smc
->y
[PB
].cem_pst
== CEM_PST_UP
)) &&
344 (smc
->y
[PA
].pc_mode
== PM_TREE
||
345 smc
->y
[PB
].pc_mode
== PM_TREE
))) {
346 smc
->y
[PA
].scrub
= TRUE
;
347 GO_STATE(SC10_C_WRAP_B
) ;
351 else if (!smc
->s
.attach_s
&&
352 smc
->y
[PA
].cf_join
&&
353 smc
->y
[PA
].cem_pst
== CEM_PST_UP
&&
354 smc
->y
[PA
].pc_mode
== PM_PEER
&& smc
->y
[PB
].cf_join
&&
355 smc
->y
[PB
].cem_pst
== CEM_PST_UP
&&
356 smc
->y
[PB
].pc_mode
== PM_PEER
) {
357 smc
->y
[PA
].scrub
= TRUE
;
358 smc
->y
[PB
].scrub
= TRUE
;
359 GO_STATE(SC4_THRU_A
) ;
363 else if ( smc
->s
.attach_s
&&
364 smc
->y
[PA
].cf_join
&&
365 smc
->y
[PA
].cem_pst
== CEM_PST_UP
&&
366 smc
->y
[PA
].pc_mode
== PM_PEER
&&
367 smc
->y
[PB
].cf_join
&&
368 smc
->y
[PB
].cem_pst
== CEM_PST_UP
&&
369 smc
->y
[PB
].pc_mode
== PM_PEER
) {
370 smc
->y
[PA
].scrub
= TRUE
;
371 smc
->y
[PB
].scrub
= TRUE
;
372 GO_STATE(SC5_THRU_B
) ;
376 case ACTIONS(SC10_C_WRAP_B
) :
377 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
378 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_CONCATENATED
;
379 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= 0 ;
380 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= INDEX_MAC
;
381 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_CON
;
382 config_mux(smc
,MUX_WRAPB
) ; /* configure PHY mux */
383 if (smc
->y
[PB
].cf_loop
) {
384 smc
->r
.rm_join
= FALSE
;
385 smc
->r
.rm_loop
= TRUE
;
386 queue_event(smc
,EVENT_RMT
,RM_LOOP
) ;/* signal RMT */
388 if (smc
->y
[PB
].cf_join
) {
389 smc
->r
.rm_loop
= FALSE
;
390 smc
->r
.rm_join
= TRUE
;
391 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
394 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
398 if ( !smc
->y
[PB
].cf_join
&& !smc
->y
[PB
].cf_loop
) {
399 GO_STATE(SC0_ISOLATED
) ;
403 else if ( smc
->y
[PA
].cf_loop
&& smc
->y
[PA
].pc_mode
== PM_PEER
&&
404 smc
->y
[PB
].cf_join
&& smc
->y
[PB
].pc_mode
== PM_PEER
) {
405 smc
->y
[PB
].scrub
= TRUE
;
406 GO_STATE(SC9_C_WRAP_A
) ;
410 else if (!smc
->s
.attach_s
&&
411 smc
->y
[PA
].cf_join
&& smc
->y
[PA
].pc_mode
== PM_PEER
&&
412 smc
->y
[PB
].cf_join
&& smc
->y
[PB
].pc_mode
== PM_PEER
) {
413 smc
->y
[PA
].scrub
= TRUE
;
414 smc
->y
[PB
].scrub
= TRUE
;
415 GO_STATE(SC4_THRU_A
) ;
419 else if ( smc
->s
.attach_s
&&
420 smc
->y
[PA
].cf_join
&& smc
->y
[PA
].pc_mode
== PM_PEER
&&
421 smc
->y
[PB
].cf_join
&& smc
->y
[PB
].pc_mode
== PM_PEER
) {
422 smc
->y
[PA
].scrub
= TRUE
;
423 smc
->y
[PB
].scrub
= TRUE
;
424 GO_STATE(SC5_THRU_B
) ;
428 case ACTIONS(SC4_THRU_A
) :
429 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
430 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
431 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= 0 ;
432 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= INDEX_MAC
;
433 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_THRU
;
434 config_mux(smc
,MUX_THRUA
) ; /* configure PHY mux */
435 smc
->r
.rm_loop
= FALSE
;
436 smc
->r
.rm_join
= TRUE
;
437 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
439 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
443 if (smc
->y
[PB
].wc_flag
|| !smc
->y
[PB
].cf_join
) {
444 smc
->y
[PA
].scrub
= TRUE
;
445 GO_STATE(SC9_C_WRAP_A
) ;
449 else if (!smc
->y
[PA
].cf_join
|| smc
->y
[PA
].wc_flag
) {
450 smc
->y
[PB
].scrub
= TRUE
;
451 GO_STATE(SC10_C_WRAP_B
) ;
455 else if (smc
->s
.attach_s
) {
456 smc
->y
[PB
].scrub
= TRUE
;
457 GO_STATE(SC5_THRU_B
) ;
461 case ACTIONS(SC5_THRU_B
) :
462 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
463 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
464 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= INDEX_MAC
;
465 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= 0 ;
466 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_THRU
;
467 config_mux(smc
,MUX_THRUB
) ; /* configure PHY mux */
468 smc
->r
.rm_loop
= FALSE
;
469 smc
->r
.rm_join
= TRUE
;
470 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
472 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
476 if (!smc
->y
[PB
].cf_join
|| smc
->y
[PB
].wc_flag
) {
477 smc
->y
[PA
].scrub
= TRUE
;
478 GO_STATE(SC9_C_WRAP_A
) ;
482 else if (!smc
->y
[PA
].cf_join
|| smc
->y
[PA
].wc_flag
) {
483 smc
->y
[PB
].scrub
= TRUE
;
484 GO_STATE(SC10_C_WRAP_B
) ;
488 else if (!smc
->s
.attach_s
) {
489 smc
->y
[PA
].scrub
= TRUE
;
490 GO_STATE(SC4_THRU_A
) ;
494 case ACTIONS(SC11_C_WRAP_S
) :
495 smc
->mib
.p
[PS
].fddiPORTCurrentPath
= MIB_PATH_CONCATENATED
;
496 smc
->mib
.p
[PS
].fddiPORTMACPlacement
= INDEX_MAC
;
497 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_CON
;
498 config_mux(smc
,MUX_WRAPS
) ; /* configure PHY mux */
499 if (smc
->y
[PA
].cf_loop
|| smc
->y
[PB
].cf_loop
) {
500 smc
->r
.rm_join
= FALSE
;
501 smc
->r
.rm_loop
= TRUE
;
502 queue_event(smc
,EVENT_RMT
,RM_LOOP
) ;/* signal RMT */
504 if (smc
->y
[PA
].cf_join
|| smc
->y
[PB
].cf_join
) {
505 smc
->r
.rm_loop
= FALSE
;
506 smc
->r
.rm_join
= TRUE
;
507 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
510 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
514 if ( !smc
->y
[PA
].cf_join
&& !smc
->y
[PA
].cf_loop
&&
515 !smc
->y
[PB
].cf_join
&& !smc
->y
[PB
].cf_loop
) {
516 GO_STATE(SC0_ISOLATED
) ;
521 SMT_PANIC(smc
,SMT_E0106
, SMT_E0106_MSG
) ;
527 * get MAC's input Port
531 int cfm_get_mac_input(struct s_smc
*smc
)
533 return((smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
||
534 smc
->mib
.fddiSMTCF_State
== SC5_THRU_B
) ? PB
: PA
) ;
538 * get MAC's output Port
542 int cfm_get_mac_output(struct s_smc
*smc
)
544 return((smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
||
545 smc
->mib
.fddiSMTCF_State
== SC4_THRU_A
) ? PB
: PA
) ;
548 static char path_iso
[] = {
549 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_ISO
,
550 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_ISO
,
551 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_ISO
554 static char path_wrap_a
[] = {
555 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_PRIM
,
556 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
557 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_ISO
560 static char path_wrap_b
[] = {
561 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_PRIM
,
562 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
563 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_ISO
566 static char path_thru
[] = {
567 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_PRIM
,
568 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
569 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_PRIM
572 static char path_wrap_s
[] = {
573 0,0, 0,RES_PORT
, 0,PS
+ INDEX_PORT
, 0,PATH_PRIM
,
574 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
577 static char path_iso_s
[] = {
578 0,0, 0,RES_PORT
, 0,PS
+ INDEX_PORT
, 0,PATH_ISO
,
579 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_ISO
,
582 int cem_build_path(struct s_smc
*smc
, char *to
, int path_index
)
587 switch (smc
->mib
.fddiSMTCF_State
) {
590 path
= smc
->s
.sas
? path_iso_s
: path_iso
;
591 len
= smc
->s
.sas
? sizeof(path_iso_s
) : sizeof(path_iso
) ;
595 len
= sizeof(path_wrap_a
) ;
599 len
= sizeof(path_wrap_b
) ;
603 len
= sizeof(path_thru
) ;
607 len
= sizeof(path_wrap_s
) ;
610 memcpy(to
,path
,len
) ;
612 LINT_USE(path_index
);