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);