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)
56 * symbolic state names
58 static const char * const cfm_states
[] = {
59 "SC0_ISOLATED","CF1","CF2","CF3","CF4",
60 "SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S",
61 "SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A"
65 * symbolic event names
67 static const char * const cfm_events
[] = {
68 "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
72 * map from state to downstream port type
74 static const unsigned char cf_to_ptype
[] = {
75 TNONE
,TNONE
,TNONE
,TNONE
,TNONE
,
83 #define CEM_PST_DOWN 0
85 #define CEM_PST_HOLD 2
86 /* define portstate array only for A and B port */
87 /* Do this within the smc structure (use in multiple cards) */
90 * all Globals are defined in smc.h
95 * function declarations
97 static void cfm_fsm(struct s_smc
*smc
, int cmd
);
100 init CFM state machine
101 clear all CFM vars and flags
103 void cfm_init(struct s_smc
*smc
)
105 smc
->mib
.fddiSMTCF_State
= ACTIONS(SC0_ISOLATED
) ;
108 smc
->y
[PA
].scrub
= 0 ;
109 smc
->y
[PB
].scrub
= 0 ;
110 smc
->y
[PA
].cem_pst
= CEM_PST_DOWN
;
111 smc
->y
[PB
].cem_pst
= CEM_PST_DOWN
;
114 /* Some terms conditions used by the selection criteria */
115 #define THRU_ENABLED(smc) (smc->y[PA].pc_mode != PM_TREE && \
116 smc->y[PB].pc_mode != PM_TREE)
117 /* Selection criteria for the ports */
118 static void selection_criteria (struct s_smc
*smc
, struct s_phy
*phy
)
121 switch (phy
->mib
->fddiPORTMy_Type
) {
123 if ( !THRU_ENABLED(smc
) && smc
->y
[PB
].cf_join
) {
124 phy
->wc_flag
= TRUE
;
126 phy
->wc_flag
= FALSE
;
131 /* take precedence over PA */
132 phy
->wc_flag
= FALSE
;
135 phy
->wc_flag
= FALSE
;
138 phy
->wc_flag
= FALSE
;
144 void all_selection_criteria(struct s_smc
*smc
)
149 for ( p
= 0,phy
= smc
->y
; p
< NUMPHYS
; p
++, phy
++ ) {
150 /* Do the selection criteria */
151 selection_criteria (smc
,phy
);
155 static void cem_priv_state(struct s_smc
*smc
, int event
)
156 /* State machine for private PORT states: used to optimize dual homing */
158 int np
; /* Number of the port */
161 /* Do this only in a DAS */
162 if (smc
->s
.sas
!= SMT_DAS
)
165 np
= event
- CF_JOIN
;
167 if (np
!= PA
&& np
!= PB
) {
170 /* Change the port state according to the event (portnumber) */
171 if (smc
->y
[np
].cf_join
) {
172 smc
->y
[np
].cem_pst
= CEM_PST_UP
;
173 } else if (!smc
->y
[np
].wc_flag
) {
174 /* set the port to done only if it is not withheld */
175 smc
->y
[np
].cem_pst
= CEM_PST_DOWN
;
178 /* Don't set an hold port to down */
180 /* Check all ports of restart conditions */
181 for (i
= 0 ; i
< 2 ; i
++ ) {
182 /* Check all port for PORT is on hold and no withhold is done */
183 if ( smc
->y
[i
].cem_pst
== CEM_PST_HOLD
&& !smc
->y
[i
].wc_flag
) {
184 smc
->y
[i
].cem_pst
= CEM_PST_DOWN
;
185 queue_event(smc
,(int)(EVENT_PCM
+i
),PC_START
) ;
187 if ( smc
->y
[i
].cem_pst
== CEM_PST_UP
&& smc
->y
[i
].wc_flag
) {
188 smc
->y
[i
].cem_pst
= CEM_PST_HOLD
;
189 queue_event(smc
,(int)(EVENT_PCM
+i
),PC_START
) ;
191 if ( smc
->y
[i
].cem_pst
== CEM_PST_DOWN
&& smc
->y
[i
].wc_flag
) {
193 * The port must be restarted when the wc_flag
194 * will be reset. So set the port on hold.
196 smc
->y
[i
].cem_pst
= CEM_PST_HOLD
;
211 void cfm(struct s_smc
*smc
, int event
)
213 int state
; /* remember last state */
217 /* We will do the following: */
218 /* - compute the variable WC_Flag for every port (This is where */
219 /* we can extend the requested path checking !!) */
220 /* - do the old (SMT 6.2 like) state machine */
221 /* - do the resulting station states */
223 all_selection_criteria (smc
);
225 /* We will check now whether a state transition is allowed or not */
226 /* - change the portstates */
227 cem_priv_state (smc
, event
);
229 oldstate
= smc
->mib
.fddiSMTCF_State
;
231 DB_CFM("CFM : state %s%s event %s",
232 smc
->mib
.fddiSMTCF_State
& AFLAG
? "ACTIONS " : "",
233 cfm_states
[smc
->mib
.fddiSMTCF_State
& ~AFLAG
],
235 state
= smc
->mib
.fddiSMTCF_State
;
238 } while (state
!= smc
->mib
.fddiSMTCF_State
) ;
242 * check peer wrap condition
245 if ( (smc
->mib
.fddiSMTCF_State
== SC9_C_WRAP_A
&&
246 smc
->y
[PA
].pc_mode
== PM_PEER
) ||
247 (smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
&&
248 smc
->y
[PB
].pc_mode
== PM_PEER
) ||
249 (smc
->mib
.fddiSMTCF_State
== SC11_C_WRAP_S
&&
250 smc
->y
[PS
].pc_mode
== PM_PEER
&&
251 smc
->y
[PS
].mib
->fddiPORTNeighborType
!= TS
) ) {
254 if (cond
!= smc
->mib
.fddiSMTPeerWrapFlag
)
255 smt_srf_event(smc
,SMT_COND_SMT_PEER_WRAP
,0,cond
) ;
259 * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired
260 * to the primary path.
265 if (smc
->mib
.fddiSMTCF_State
!= oldstate
) {
266 smt_srf_event(smc
,SMT_EVENT_MAC_PATH_CHANGE
,INDEX_MAC
,0) ;
269 #endif /* no SLIM_SMT */
274 smc
->mib
.m
[MAC0
].fddiMACDownstreamPORTType
=
275 cf_to_ptype
[smc
->mib
.fddiSMTCF_State
] ;
276 cfm_state_change(smc
,(int)smc
->mib
.fddiSMTCF_State
) ;
283 static void cfm_fsm(struct s_smc
*smc
, int cmd
)
285 switch(smc
->mib
.fddiSMTCF_State
) {
286 case ACTIONS(SC0_ISOLATED
) :
287 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
288 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
289 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= 0 ;
290 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= 0 ;
291 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_SEPA
;
292 config_mux(smc
,MUX_ISOLATE
) ; /* configure PHY Mux */
293 smc
->r
.rm_loop
= FALSE
;
294 smc
->r
.rm_join
= FALSE
;
295 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
296 /* Don't do the WC-Flag changing here */
298 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
302 /*SAS port can be PA or PB ! */
303 if (smc
->s
.sas
&& (smc
->y
[PA
].cf_join
|| smc
->y
[PA
].cf_loop
||
304 smc
->y
[PB
].cf_join
|| smc
->y
[PB
].cf_loop
)) {
305 GO_STATE(SC11_C_WRAP_S
) ;
309 if ((smc
->y
[PA
].cem_pst
== CEM_PST_UP
&& smc
->y
[PA
].cf_join
&&
310 !smc
->y
[PA
].wc_flag
) || smc
->y
[PA
].cf_loop
) {
311 GO_STATE(SC9_C_WRAP_A
) ;
315 if ((smc
->y
[PB
].cem_pst
== CEM_PST_UP
&& smc
->y
[PB
].cf_join
&&
316 !smc
->y
[PB
].wc_flag
) || smc
->y
[PB
].cf_loop
) {
317 GO_STATE(SC10_C_WRAP_B
) ;
321 case ACTIONS(SC9_C_WRAP_A
) :
322 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_CONCATENATED
;
323 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
324 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= INDEX_MAC
;
325 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= 0 ;
326 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_CON
;
327 config_mux(smc
,MUX_WRAPA
) ; /* configure PHY mux */
328 if (smc
->y
[PA
].cf_loop
) {
329 smc
->r
.rm_join
= FALSE
;
330 smc
->r
.rm_loop
= TRUE
;
331 queue_event(smc
,EVENT_RMT
,RM_LOOP
) ;/* signal RMT */
333 if (smc
->y
[PA
].cf_join
) {
334 smc
->r
.rm_loop
= FALSE
;
335 smc
->r
.rm_join
= TRUE
;
336 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
339 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
343 if ( (smc
->y
[PA
].wc_flag
|| !smc
->y
[PA
].cf_join
) &&
344 !smc
->y
[PA
].cf_loop
) {
345 GO_STATE(SC0_ISOLATED
) ;
349 else if ( (smc
->y
[PB
].cf_loop
&& smc
->y
[PA
].cf_join
&&
350 smc
->y
[PA
].cem_pst
== CEM_PST_UP
) ||
351 ((smc
->y
[PB
].cf_loop
||
352 (smc
->y
[PB
].cf_join
&&
353 smc
->y
[PB
].cem_pst
== CEM_PST_UP
)) &&
354 (smc
->y
[PA
].pc_mode
== PM_TREE
||
355 smc
->y
[PB
].pc_mode
== PM_TREE
))) {
356 smc
->y
[PA
].scrub
= TRUE
;
357 GO_STATE(SC10_C_WRAP_B
) ;
361 else if (!smc
->s
.attach_s
&&
362 smc
->y
[PA
].cf_join
&&
363 smc
->y
[PA
].cem_pst
== CEM_PST_UP
&&
364 smc
->y
[PA
].pc_mode
== PM_PEER
&& smc
->y
[PB
].cf_join
&&
365 smc
->y
[PB
].cem_pst
== CEM_PST_UP
&&
366 smc
->y
[PB
].pc_mode
== PM_PEER
) {
367 smc
->y
[PA
].scrub
= TRUE
;
368 smc
->y
[PB
].scrub
= TRUE
;
369 GO_STATE(SC4_THRU_A
) ;
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
&&
377 smc
->y
[PB
].cf_join
&&
378 smc
->y
[PB
].cem_pst
== CEM_PST_UP
&&
379 smc
->y
[PB
].pc_mode
== PM_PEER
) {
380 smc
->y
[PA
].scrub
= TRUE
;
381 smc
->y
[PB
].scrub
= TRUE
;
382 GO_STATE(SC5_THRU_B
) ;
386 case ACTIONS(SC10_C_WRAP_B
) :
387 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_ISOLATED
;
388 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_CONCATENATED
;
389 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= 0 ;
390 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= INDEX_MAC
;
391 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_CON
;
392 config_mux(smc
,MUX_WRAPB
) ; /* configure PHY mux */
393 if (smc
->y
[PB
].cf_loop
) {
394 smc
->r
.rm_join
= FALSE
;
395 smc
->r
.rm_loop
= TRUE
;
396 queue_event(smc
,EVENT_RMT
,RM_LOOP
) ;/* signal RMT */
398 if (smc
->y
[PB
].cf_join
) {
399 smc
->r
.rm_loop
= FALSE
;
400 smc
->r
.rm_join
= TRUE
;
401 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
404 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
408 if ( !smc
->y
[PB
].cf_join
&& !smc
->y
[PB
].cf_loop
) {
409 GO_STATE(SC0_ISOLATED
) ;
413 else if ( smc
->y
[PA
].cf_loop
&& smc
->y
[PA
].pc_mode
== PM_PEER
&&
414 smc
->y
[PB
].cf_join
&& smc
->y
[PB
].pc_mode
== PM_PEER
) {
415 smc
->y
[PB
].scrub
= TRUE
;
416 GO_STATE(SC9_C_WRAP_A
) ;
420 else if (!smc
->s
.attach_s
&&
421 smc
->y
[PA
].cf_join
&& smc
->y
[PA
].pc_mode
== PM_PEER
&&
422 smc
->y
[PB
].cf_join
&& smc
->y
[PB
].pc_mode
== PM_PEER
) {
423 smc
->y
[PA
].scrub
= TRUE
;
424 smc
->y
[PB
].scrub
= TRUE
;
425 GO_STATE(SC4_THRU_A
) ;
429 else if ( smc
->s
.attach_s
&&
430 smc
->y
[PA
].cf_join
&& smc
->y
[PA
].pc_mode
== PM_PEER
&&
431 smc
->y
[PB
].cf_join
&& smc
->y
[PB
].pc_mode
== PM_PEER
) {
432 smc
->y
[PA
].scrub
= TRUE
;
433 smc
->y
[PB
].scrub
= TRUE
;
434 GO_STATE(SC5_THRU_B
) ;
438 case ACTIONS(SC4_THRU_A
) :
439 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
440 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
441 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= 0 ;
442 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= INDEX_MAC
;
443 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_THRU
;
444 config_mux(smc
,MUX_THRUA
) ; /* configure PHY mux */
445 smc
->r
.rm_loop
= FALSE
;
446 smc
->r
.rm_join
= TRUE
;
447 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
449 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
453 if (smc
->y
[PB
].wc_flag
|| !smc
->y
[PB
].cf_join
) {
454 smc
->y
[PA
].scrub
= TRUE
;
455 GO_STATE(SC9_C_WRAP_A
) ;
459 else if (!smc
->y
[PA
].cf_join
|| smc
->y
[PA
].wc_flag
) {
460 smc
->y
[PB
].scrub
= TRUE
;
461 GO_STATE(SC10_C_WRAP_B
) ;
465 else if (smc
->s
.attach_s
) {
466 smc
->y
[PB
].scrub
= TRUE
;
467 GO_STATE(SC5_THRU_B
) ;
471 case ACTIONS(SC5_THRU_B
) :
472 smc
->mib
.p
[PA
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
473 smc
->mib
.p
[PB
].fddiPORTCurrentPath
= MIB_PATH_THRU
;
474 smc
->mib
.p
[PA
].fddiPORTMACPlacement
= INDEX_MAC
;
475 smc
->mib
.p
[PB
].fddiPORTMACPlacement
= 0 ;
476 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_THRU
;
477 config_mux(smc
,MUX_THRUB
) ; /* configure PHY mux */
478 smc
->r
.rm_loop
= FALSE
;
479 smc
->r
.rm_join
= TRUE
;
480 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
482 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
486 if (!smc
->y
[PB
].cf_join
|| smc
->y
[PB
].wc_flag
) {
487 smc
->y
[PA
].scrub
= TRUE
;
488 GO_STATE(SC9_C_WRAP_A
) ;
492 else if (!smc
->y
[PA
].cf_join
|| smc
->y
[PA
].wc_flag
) {
493 smc
->y
[PB
].scrub
= TRUE
;
494 GO_STATE(SC10_C_WRAP_B
) ;
498 else if (!smc
->s
.attach_s
) {
499 smc
->y
[PA
].scrub
= TRUE
;
500 GO_STATE(SC4_THRU_A
) ;
504 case ACTIONS(SC11_C_WRAP_S
) :
505 smc
->mib
.p
[PS
].fddiPORTCurrentPath
= MIB_PATH_CONCATENATED
;
506 smc
->mib
.p
[PS
].fddiPORTMACPlacement
= INDEX_MAC
;
507 smc
->mib
.fddiSMTStationStatus
= MIB_SMT_STASTA_CON
;
508 config_mux(smc
,MUX_WRAPS
) ; /* configure PHY mux */
509 if (smc
->y
[PA
].cf_loop
|| smc
->y
[PB
].cf_loop
) {
510 smc
->r
.rm_join
= FALSE
;
511 smc
->r
.rm_loop
= TRUE
;
512 queue_event(smc
,EVENT_RMT
,RM_LOOP
) ;/* signal RMT */
514 if (smc
->y
[PA
].cf_join
|| smc
->y
[PB
].cf_join
) {
515 smc
->r
.rm_loop
= FALSE
;
516 smc
->r
.rm_join
= TRUE
;
517 queue_event(smc
,EVENT_RMT
,RM_JOIN
) ;/* signal RMT */
520 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
524 if ( !smc
->y
[PA
].cf_join
&& !smc
->y
[PA
].cf_loop
&&
525 !smc
->y
[PB
].cf_join
&& !smc
->y
[PB
].cf_loop
) {
526 GO_STATE(SC0_ISOLATED
) ;
531 SMT_PANIC(smc
,SMT_E0106
, SMT_E0106_MSG
) ;
537 * get MAC's input Port
541 int cfm_get_mac_input(struct s_smc
*smc
)
543 return (smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
||
544 smc
->mib
.fddiSMTCF_State
== SC5_THRU_B
) ? PB
: PA
;
548 * get MAC's output Port
552 int cfm_get_mac_output(struct s_smc
*smc
)
554 return (smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
||
555 smc
->mib
.fddiSMTCF_State
== SC4_THRU_A
) ? PB
: PA
;
558 static char path_iso
[] = {
559 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_ISO
,
560 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_ISO
,
561 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_ISO
564 static char path_wrap_a
[] = {
565 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_PRIM
,
566 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
567 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_ISO
570 static char path_wrap_b
[] = {
571 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_PRIM
,
572 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
573 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_ISO
576 static char path_thru
[] = {
577 0,0, 0,RES_PORT
, 0,PA
+ INDEX_PORT
, 0,PATH_PRIM
,
578 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
579 0,0, 0,RES_PORT
, 0,PB
+ INDEX_PORT
, 0,PATH_PRIM
582 static char path_wrap_s
[] = {
583 0,0, 0,RES_PORT
, 0,PS
+ INDEX_PORT
, 0,PATH_PRIM
,
584 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_PRIM
,
587 static char path_iso_s
[] = {
588 0,0, 0,RES_PORT
, 0,PS
+ INDEX_PORT
, 0,PATH_ISO
,
589 0,0, 0,RES_MAC
, 0,INDEX_MAC
, 0,PATH_ISO
,
592 int cem_build_path(struct s_smc
*smc
, char *to
, int path_index
)
597 switch (smc
->mib
.fddiSMTCF_State
) {
600 path
= smc
->s
.sas
? path_iso_s
: path_iso
;
601 len
= smc
->s
.sas
? sizeof(path_iso_s
) : sizeof(path_iso
) ;
605 len
= sizeof(path_wrap_a
) ;
609 len
= sizeof(path_wrap_b
) ;
613 len
= sizeof(path_thru
) ;
617 len
= sizeof(path_wrap_s
) ;
620 memcpy(to
,path
,len
) ;
622 LINT_USE(path_index
);