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
) ;
261 * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired
262 * to the primary path.
267 if (smc
->mib
.fddiSMTCF_State
!= oldstate
) {
268 smt_srf_event(smc
,SMT_EVENT_MAC_PATH_CHANGE
,INDEX_MAC
,0) ;
271 #endif /* no SLIM_SMT */
276 smc
->mib
.m
[MAC0
].fddiMACDownstreamPORTType
=
277 cf_to_ptype
[smc
->mib
.fddiSMTCF_State
] ;
278 cfm_state_change(smc
,(int)smc
->mib
.fddiSMTCF_State
) ;
285 static void cfm_fsm(struct s_smc
*smc
, int cmd
)
287 switch(smc
->mib
.fddiSMTCF_State
) {
288 case ACTIONS(SC0_ISOLATED
) :
289 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
290 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
291 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= 0 ;
292 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= 0 ;
293 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_SEPA
;
294 config_mux(smc
,MUX_ISOLATE
) ; /* configure PHY Mux */
295 smc
->r
.rm_loop
= FALSE
;
296 smc
->r
.rm_join
= FALSE
;
297 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
298 /* Don't do the WC-Flag changing here */
300 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
304 /*SAS port can be PA or PB ! */
305 if (smc
->s
.sas
&& (smc
->y
[PA
].cf_join
|| smc
->y
[PA
].cf_loop
||
306 smc
->y
[PB
].cf_join
|| smc
->y
[PB
].cf_loop
)) {
307 GO_STATE(SC11_C_WRAP_S
) ;
311 if ((smc
->y
[PA
].cem_pst
== CEM_PST_UP
&& smc
->y
[PA
].cf_join
&&
312 !smc
->y
[PA
].wc_flag
) || smc
->y
[PA
].cf_loop
) {
313 GO_STATE(SC9_C_WRAP_A
) ;
317 if ((smc
->y
[PB
].cem_pst
== CEM_PST_UP
&& smc
->y
[PB
].cf_join
&&
318 !smc
->y
[PB
].wc_flag
) || smc
->y
[PB
].cf_loop
) {
319 GO_STATE(SC10_C_WRAP_B
) ;
323 case ACTIONS(SC9_C_WRAP_A
) :
324 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_CONCATENATED
;
325 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
326 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= INDEX_MAC
;
327 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= 0 ;
328 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_CON
;
329 config_mux(smc
,MUX_WRAPA
) ; /* configure PHY mux */
330 if (smc
->y
[PA
].cf_loop
) {
331 smc
->r
.rm_join
= FALSE
;
332 smc
->r
.rm_loop
= TRUE
;
333 queue_event(smc
,EVENT_RMT
,RM_LOOP
) ;/* signal RMT */
335 if (smc
->y
[PA
].cf_join
) {
336 smc
->r
.rm_loop
= FALSE
;
337 smc
->r
.rm_join
= TRUE
;
338 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
341 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
345 if ( (smc
->y
[PA
].wc_flag
|| !smc
->y
[PA
].cf_join
) &&
346 !smc
->y
[PA
].cf_loop
) {
347 GO_STATE(SC0_ISOLATED
) ;
351 else if ( (smc
->y
[PB
].cf_loop
&& smc
->y
[PA
].cf_join
&&
352 smc
->y
[PA
].cem_pst
== CEM_PST_UP
) ||
353 ((smc
->y
[PB
].cf_loop
||
354 (smc
->y
[PB
].cf_join
&&
355 smc
->y
[PB
].cem_pst
== CEM_PST_UP
)) &&
356 (smc
->y
[PA
].pc_mode
== PM_TREE
||
357 smc
->y
[PB
].pc_mode
== PM_TREE
))) {
358 smc
->y
[PA
].scrub
= TRUE
;
359 GO_STATE(SC10_C_WRAP_B
) ;
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
&& smc
->y
[PB
].cf_join
&&
367 smc
->y
[PB
].cem_pst
== CEM_PST_UP
&&
368 smc
->y
[PB
].pc_mode
== PM_PEER
) {
369 smc
->y
[PA
].scrub
= TRUE
;
370 smc
->y
[PB
].scrub
= TRUE
;
371 GO_STATE(SC4_THRU_A
) ;
375 else if ( smc
->s
.attach_s
&&
376 smc
->y
[PA
].cf_join
&&
377 smc
->y
[PA
].cem_pst
== CEM_PST_UP
&&
378 smc
->y
[PA
].pc_mode
== PM_PEER
&&
379 smc
->y
[PB
].cf_join
&&
380 smc
->y
[PB
].cem_pst
== CEM_PST_UP
&&
381 smc
->y
[PB
].pc_mode
== PM_PEER
) {
382 smc
->y
[PA
].scrub
= TRUE
;
383 smc
->y
[PB
].scrub
= TRUE
;
384 GO_STATE(SC5_THRU_B
) ;
388 case ACTIONS(SC10_C_WRAP_B
) :
389 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
390 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_CONCATENATED
;
391 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= 0 ;
392 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= INDEX_MAC
;
393 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_CON
;
394 config_mux(smc
,MUX_WRAPB
) ; /* configure PHY mux */
395 if (smc
->y
[PB
].cf_loop
) {
396 smc
->r
.rm_join
= FALSE
;
397 smc
->r
.rm_loop
= TRUE
;
398 queue_event(smc
,EVENT_RMT
,RM_LOOP
) ;/* signal RMT */
400 if (smc
->y
[PB
].cf_join
) {
401 smc
->r
.rm_loop
= FALSE
;
402 smc
->r
.rm_join
= TRUE
;
403 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
406 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
410 if ( !smc
->y
[PB
].cf_join
&& !smc
->y
[PB
].cf_loop
) {
411 GO_STATE(SC0_ISOLATED
) ;
415 else if ( smc
->y
[PA
].cf_loop
&& smc
->y
[PA
].pc_mode
== PM_PEER
&&
416 smc
->y
[PB
].cf_join
&& smc
->y
[PB
].pc_mode
== PM_PEER
) {
417 smc
->y
[PB
].scrub
= TRUE
;
418 GO_STATE(SC9_C_WRAP_A
) ;
422 else if (!smc
->s
.attach_s
&&
423 smc
->y
[PA
].cf_join
&& smc
->y
[PA
].pc_mode
== PM_PEER
&&
424 smc
->y
[PB
].cf_join
&& smc
->y
[PB
].pc_mode
== PM_PEER
) {
425 smc
->y
[PA
].scrub
= TRUE
;
426 smc
->y
[PB
].scrub
= TRUE
;
427 GO_STATE(SC4_THRU_A
) ;
431 else if ( smc
->s
.attach_s
&&
432 smc
->y
[PA
].cf_join
&& smc
->y
[PA
].pc_mode
== PM_PEER
&&
433 smc
->y
[PB
].cf_join
&& smc
->y
[PB
].pc_mode
== PM_PEER
) {
434 smc
->y
[PA
].scrub
= TRUE
;
435 smc
->y
[PB
].scrub
= TRUE
;
436 GO_STATE(SC5_THRU_B
) ;
440 case ACTIONS(SC4_THRU_A
) :
441 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
442 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
443 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= 0 ;
444 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= INDEX_MAC
;
445 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_THRU
;
446 config_mux(smc
,MUX_THRUA
) ; /* configure PHY mux */
447 smc
->r
.rm_loop
= FALSE
;
448 smc
->r
.rm_join
= TRUE
;
449 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
451 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
455 if (smc
->y
[PB
].wc_flag
|| !smc
->y
[PB
].cf_join
) {
456 smc
->y
[PA
].scrub
= TRUE
;
457 GO_STATE(SC9_C_WRAP_A
) ;
461 else if (!smc
->y
[PA
].cf_join
|| smc
->y
[PA
].wc_flag
) {
462 smc
->y
[PB
].scrub
= TRUE
;
463 GO_STATE(SC10_C_WRAP_B
) ;
467 else if (smc
->s
.attach_s
) {
468 smc
->y
[PB
].scrub
= TRUE
;
469 GO_STATE(SC5_THRU_B
) ;
473 case ACTIONS(SC5_THRU_B
) :
474 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
475 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
476 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= INDEX_MAC
;
477 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= 0 ;
478 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_THRU
;
479 config_mux(smc
,MUX_THRUB
) ; /* configure PHY mux */
480 smc
->r
.rm_loop
= FALSE
;
481 smc
->r
.rm_join
= TRUE
;
482 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
484 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
488 if (!smc
->y
[PB
].cf_join
|| smc
->y
[PB
].wc_flag
) {
489 smc
->y
[PA
].scrub
= TRUE
;
490 GO_STATE(SC9_C_WRAP_A
) ;
494 else if (!smc
->y
[PA
].cf_join
|| smc
->y
[PA
].wc_flag
) {
495 smc
->y
[PB
].scrub
= TRUE
;
496 GO_STATE(SC10_C_WRAP_B
) ;
500 else if (!smc
->s
.attach_s
) {
501 smc
->y
[PA
].scrub
= TRUE
;
502 GO_STATE(SC4_THRU_A
) ;
506 case ACTIONS(SC11_C_WRAP_S
) :
507 smc
->mib
.p
[PS
].fddiPORTCurrentPath
= MIB_PATH_CONCATENATED
;
508 smc
->mib
.p
[PS
].fddiPORTMACPlacement
= INDEX_MAC
;
509 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_CON
;
510 config_mux(smc
,MUX_WRAPS
) ; /* configure PHY mux */
511 if (smc
->y
[PA
].cf_loop
|| smc
->y
[PB
].cf_loop
) {
512 smc
->r
.rm_join
= FALSE
;
513 smc
->r
.rm_loop
= TRUE
;
514 queue_event(smc
,EVENT_RMT
,RM_LOOP
) ;/* signal RMT */
516 if (smc
->y
[PA
].cf_join
|| smc
->y
[PB
].cf_join
) {
517 smc
->r
.rm_loop
= FALSE
;
518 smc
->r
.rm_join
= TRUE
;
519 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
522 DB_CFMN(1,"CFM : %s\n",cfm_states
[smc
->mib
.fddiSMTCF_State
],0) ;
526 if ( !smc
->y
[PA
].cf_join
&& !smc
->y
[PA
].cf_loop
&&
527 !smc
->y
[PB
].cf_join
&& !smc
->y
[PB
].cf_loop
) {
528 GO_STATE(SC0_ISOLATED
) ;
533 SMT_PANIC(smc
,SMT_E0106
, SMT_E0106_MSG
) ;
539 * get MAC's input Port
543 int cfm_get_mac_input(struct s_smc
*smc
)
545 return (smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
||
546 smc
->mib
.fddiSMTCF_State
== SC5_THRU_B
) ? PB
: PA
;
550 * get MAC's output Port
554 int cfm_get_mac_output(struct s_smc
*smc
)
556 return (smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
||
557 smc
->mib
.fddiSMTCF_State
== SC4_THRU_A
) ? PB
: PA
;
560 static char path_iso
[] = {
561 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_ISO
,
562 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_ISO
,
563 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_ISO
566 static char path_wrap_a
[] = {
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_ISO
572 static char path_wrap_b
[] = {
573 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_PRIM
,
574 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
575 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_ISO
578 static char path_thru
[] = {
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_PRIM
584 static char path_wrap_s
[] = {
585 0,0, 0,RES_PORT
, 0,PS
+ INDEX_PORT
, 0,PATH_PRIM
,
586 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
589 static char path_iso_s
[] = {
590 0,0, 0,RES_PORT
, 0,PS
+ INDEX_PORT
, 0,PATH_ISO
,
591 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_ISO
,
594 int cem_build_path(struct s_smc
*smc
, char *to
, int path_index
)
599 switch (smc
->mib
.fddiSMTCF_State
) {
602 path
= smc
->s
.sas
? path_iso_s
: path_iso
;
603 len
= smc
->s
.sas
? sizeof(path_iso_s
) : sizeof(path_iso
) ;
607 len
= sizeof(path_wrap_a
) ;
611 len
= sizeof(path_wrap_b
) ;
615 len
= sizeof(path_thru
) ;
619 len
= sizeof(path_wrap_s
) ;
622 memcpy(to
,path
,len
) ;
624 LINT_USE(path_index
);