1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /******************************************************************************
4 * (C)Copyright 1998,1999 SysKonnect,
5 * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
7 * See the file "skfddi.c" for further information.
9 * The information in this file is provided "AS IS" without warranty.
11 ******************************************************************************/
15 Configuration Management
20 * Hardware independent state machine implemantation
21 * The following external SMT functions are referenced :
25 * The following external HW dependent functions are referenced :
28 * The following HW dependent events are required :
37 #include "h/smtstate.h"
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)
48 * symbolic state names
50 static 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"
57 * symbolic event names
59 static const char * const cfm_events
[] = {
60 "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
64 * map from state to downstream port type
66 static const unsigned char cf_to_ptype
[] = {
67 TNONE
,TNONE
,TNONE
,TNONE
,TNONE
,
75 #define CEM_PST_DOWN 0
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) */
82 * all Globals are defined in smc.h
87 * function declarations
89 static void cfm_fsm(struct s_smc
*smc
, int cmd
);
92 init CFM state machine
93 clear all CFM vars and flags
95 void cfm_init(struct s_smc
*smc
)
97 smc
->mib
.fddiSMTCF_State
= ACTIONS(SC0_ISOLATED
) ;
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
;
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 */
110 static void selection_criteria (struct s_smc
*smc
, struct s_phy
*phy
)
113 switch (phy
->mib
->fddiPORTMy_Type
) {
115 if ( !THRU_ENABLED(smc
) && smc
->y
[PB
].cf_join
) {
116 phy
->wc_flag
= TRUE
;
118 phy
->wc_flag
= FALSE
;
123 /* take precedence over PA */
124 phy
->wc_flag
= FALSE
;
127 phy
->wc_flag
= FALSE
;
130 phy
->wc_flag
= FALSE
;
136 void all_selection_criteria(struct s_smc
*smc
)
141 for ( p
= 0,phy
= smc
->y
; p
< NUMPHYS
; p
++, phy
++ ) {
142 /* Do the selection criteria */
143 selection_criteria (smc
,phy
);
147 static void cem_priv_state(struct s_smc
*smc
, int event
)
148 /* State machine for private PORT states: used to optimize dual homing */
150 int np
; /* Number of the port */
153 /* Do this only in a DAS */
154 if (smc
->s
.sas
!= SMT_DAS
)
157 np
= event
- CF_JOIN
;
159 if (np
!= PA
&& np
!= PB
) {
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
;
170 /* Don't set an hold port to down */
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
) ;
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
) ;
183 if ( smc
->y
[i
].cem_pst
== CEM_PST_DOWN
&& smc
->y
[i
].wc_flag
) {
185 * The port must be restarted when the wc_flag
186 * will be reset. So set the port on hold.
188 smc
->y
[i
].cem_pst
= CEM_PST_HOLD
;
203 void cfm(struct s_smc
*smc
, int event
)
205 int state
; /* remember last state */
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 */
214 all_selection_criteria (smc
);
216 /* We will check now whether a state transition is allowed or not */
217 /* - change the portstates */
218 cem_priv_state (smc
, event
);
221 DB_CFM("CFM : state %s%s event %s",
222 smc
->mib
.fddiSMTCF_State
& AFLAG
? "ACTIONS " : "",
223 cfm_states
[smc
->mib
.fddiSMTCF_State
& ~AFLAG
],
225 state
= smc
->mib
.fddiSMTCF_State
;
228 } while (state
!= smc
->mib
.fddiSMTCF_State
) ;
232 * check peer wrap condition
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
) ) {
244 if (cond
!= smc
->mib
.fddiSMTPeerWrapFlag
)
245 smt_srf_event(smc
,SMT_COND_SMT_PEER_WRAP
,0,cond
) ;
248 * Don't ever send MAC_PATH_CHANGE events. Our MAC is hard-wired
249 * to the primary path.
252 #endif /* no SLIM_SMT */
257 smc
->mib
.m
[MAC0
].fddiMACDownstreamPORTType
=
258 cf_to_ptype
[smc
->mib
.fddiSMTCF_State
] ;
259 cfm_state_change(smc
,(int)smc
->mib
.fddiSMTCF_State
) ;
266 static void cfm_fsm(struct s_smc
*smc
, int cmd
)
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 */
281 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
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
) ;
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
) ;
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
) ;
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 */
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 */
322 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
326 if ( (smc
->y
[PA
].wc_flag
|| !smc
->y
[PA
].cf_join
) &&
327 !smc
->y
[PA
].cf_loop
) {
328 GO_STATE(SC0_ISOLATED
) ;
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
) ;
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
) ;
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
) ;
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 */
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 */
387 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
391 if ( !smc
->y
[PB
].cf_join
&& !smc
->y
[PB
].cf_loop
) {
392 GO_STATE(SC0_ISOLATED
) ;
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
) ;
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
) ;
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
) ;
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 */
432 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
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
) ;
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
) ;
448 else if (smc
->s
.attach_s
) {
449 smc
->y
[PB
].scrub
= TRUE
;
450 GO_STATE(SC5_THRU_B
) ;
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 */
465 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
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
) ;
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
) ;
481 else if (!smc
->s
.attach_s
) {
482 smc
->y
[PA
].scrub
= TRUE
;
483 GO_STATE(SC4_THRU_A
) ;
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 */
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 */
503 DB_CFMN(1, "CFM : %s", cfm_states
[smc
->mib
.fddiSMTCF_State
]);
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
) ;
514 SMT_PANIC(smc
,SMT_E0106
, SMT_E0106_MSG
) ;
520 * get MAC's input Port
524 int cfm_get_mac_input(struct s_smc
*smc
)
526 return (smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
||
527 smc
->mib
.fddiSMTCF_State
== SC5_THRU_B
) ? PB
: PA
;
531 * get MAC's output Port
535 int cfm_get_mac_output(struct s_smc
*smc
)
537 return (smc
->mib
.fddiSMTCF_State
== SC10_C_WRAP_B
||
538 smc
->mib
.fddiSMTCF_State
== SC4_THRU_A
) ? PB
: PA
;
541 static 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
547 static 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
553 static 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
559 static 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
565 static 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
,
570 static 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
,
575 int cem_build_path(struct s_smc
*smc
, char *to
, int path_index
)
580 switch (smc
->mib
.fddiSMTCF_State
) {
583 path
= smc
->s
.sas
? path_iso_s
: path_iso
;
584 len
= smc
->s
.sas
? sizeof(path_iso_s
) : sizeof(path_iso
) ;
588 len
= sizeof(path_wrap_a
) ;
592 len
= sizeof(path_wrap_b
) ;
596 len
= sizeof(path_thru
) ;
600 len
= sizeof(path_wrap_s
) ;
603 memcpy(to
,path
,len
) ;
605 LINT_USE(path_index
);