609 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/******************************************************************************3 *4 * (C)Copyright 1998,1999 SysKonnect,5 * a business unit of Schneider & Koch & Co. Datensysteme GmbH.6 *7 * See the file "skfddi.c" for further information.8 *9 * The information in this file is provided "AS IS" without warranty.10 *11 ******************************************************************************/12 13/*14 SMT CFM15 Configuration Management16 DAS with single MAC17*/18 19/*20 * Hardware independent state machine implemantation21 * The following external SMT functions are referenced :22 *23 * queue_event()24 *25 * The following external HW dependent functions are referenced :26 * config_mux()27 *28 * The following HW dependent events are required :29 * NONE 30 */31 32#include "h/types.h"33#include "h/fddi.h"34#include "h/smc.h"35 36#define KERNEL37#include "h/smtstate.h"38 39/*40 * FSM Macros41 */42#define AFLAG 0x1043#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)46 47/*48 * symbolic state names49 */50static 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"54} ;55 56/*57 * symbolic event names58 */59static const char * const cfm_events[] = {60 "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"61} ;62 63/*64 * map from state to downstream port type65 */66static const unsigned char cf_to_ptype[] = {67 TNONE,TNONE,TNONE,TNONE,TNONE,68 TNONE,TB,TB,TS,69 TA,TB,TS,TB70} ;71 72/*73 * CEM port states74 */75#define CEM_PST_DOWN 076#define CEM_PST_UP 177#define CEM_PST_HOLD 278/* define portstate array only for A and B port */79/* Do this within the smc structure (use in multiple cards) */80 81/*82 * all Globals are defined in smc.h83 * struct s_cfm84 */85 86/*87 * function declarations88 */89static void cfm_fsm(struct s_smc *smc, int cmd);90 91/*92 init CFM state machine93 clear all CFM vars and flags94*/95void cfm_init(struct s_smc *smc)96{97 smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ;98 smc->r.rm_join = 0 ;99 smc->r.rm_loop = 0 ;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 ;104}105 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 */110static void selection_criteria (struct s_smc *smc, struct s_phy *phy)111{112 113 switch (phy->mib->fddiPORTMy_Type) {114 case TA:115 if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) {116 phy->wc_flag = TRUE ;117 } else {118 phy->wc_flag = FALSE ;119 }120 121 break;122 case TB:123 /* take precedence over PA */124 phy->wc_flag = FALSE ;125 break;126 case TS:127 phy->wc_flag = FALSE ;128 break;129 case TM:130 phy->wc_flag = FALSE ;131 break;132 }133 134}135 136void all_selection_criteria(struct s_smc *smc)137{138 struct s_phy *phy ;139 int p ;140 141 for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) {142 /* Do the selection criteria */143 selection_criteria (smc,phy);144 }145}146 147static void cem_priv_state(struct s_smc *smc, int event)148/* State machine for private PORT states: used to optimize dual homing */149{150 int np; /* Number of the port */151 int i;152 153 /* Do this only in a DAS */154 if (smc->s.sas != SMT_DAS )155 return ;156 157 np = event - CF_JOIN;158 159 if (np != PA && np != PB) {160 return ;161 }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 ;168 }169 170 /* Don't set an hold port to down */171 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) ;178 }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) ;182 }183 if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) {184 /*185 * The port must be restarted when the wc_flag186 * will be reset. So set the port on hold.187 */188 smc->y[i].cem_pst = CEM_PST_HOLD;189 }190 }191 return ;192}193 194/*195 CFM state machine196 called by dispatcher197 198 do199 display state change200 process event201 until SM is stable202*/203void cfm(struct s_smc *smc, int event)204{205 int state ; /* remember last state */206 int cond ;207 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 */213 214 all_selection_criteria (smc);215 216 /* We will check now whether a state transition is allowed or not */217 /* - change the portstates */218 cem_priv_state (smc, event);219 220 do {221 DB_CFM("CFM : state %s%s event %s",222 smc->mib.fddiSMTCF_State & AFLAG ? "ACTIONS " : "",223 cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG],224 cfm_events[event]);225 state = smc->mib.fddiSMTCF_State ;226 cfm_fsm(smc,event) ;227 event = 0 ;228 } while (state != smc->mib.fddiSMTCF_State) ;229 230#ifndef SLIM_SMT231 /*232 * check peer wrap condition233 */234 cond = FALSE ;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 ) ) {242 cond = TRUE ;243 }244 if (cond != smc->mib.fddiSMTPeerWrapFlag)245 smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ;246 247 /*248 * Don't ever send MAC_PATH_CHANGE events. Our MAC is hard-wired249 * to the primary path.250 */251 252#endif /* no SLIM_SMT */253 254 /*255 * set MAC port type256 */257 smc->mib.m[MAC0].fddiMACDownstreamPORTType =258 cf_to_ptype[smc->mib.fddiSMTCF_State] ;259 cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ;260}261 262/*263 process CFM event264*/265/*ARGSUSED1*/266static void cfm_fsm(struct s_smc *smc, int cmd)267{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 */280 ACTIONS_DONE() ;281 DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);282 break;283 case SC0_ISOLATED :284 /*SC07*/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) ;289 break ;290 }291 /*SC01*/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) ;295 break ;296 }297 /*SC02*/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) ;301 break ;302 }303 break ;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 */315 }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 */320 }321 ACTIONS_DONE() ;322 DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);323 break ;324 case SC9_C_WRAP_A :325 /*SC10*/326 if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) &&327 !smc->y[PA].cf_loop ) {328 GO_STATE(SC0_ISOLATED) ;329 break ;330 }331 /*SC12*/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) ;341 break ;342 }343 /*SC14*/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) ;353 break ;354 }355 /*SC15*/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) ;366 break ;367 }368 break ;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 */380 }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 */385 }386 ACTIONS_DONE() ;387 DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);388 break ;389 case SC10_C_WRAP_B :390 /*SC20*/391 if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) {392 GO_STATE(SC0_ISOLATED) ;393 break ;394 }395 /*SC21*/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) ;400 break ;401 }402 /*SC24*/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) ;409 break ;410 }411 /*SC25*/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) ;418 break ;419 }420 break ;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 */431 ACTIONS_DONE() ;432 DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);433 break ;434 case SC4_THRU_A :435 /*SC41*/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) ;439 break ;440 }441 /*SC42*/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) ;445 break ;446 }447 /*SC45*/448 else if (smc->s.attach_s) {449 smc->y[PB].scrub = TRUE ;450 GO_STATE(SC5_THRU_B) ;451 break ;452 }453 break ;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 */464 ACTIONS_DONE() ;465 DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);466 break ;467 case SC5_THRU_B :468 /*SC51*/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) ;472 break ;473 }474 /*SC52*/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) ;478 break ;479 }480 /*SC54*/481 else if (!smc->s.attach_s) {482 smc->y[PA].scrub = TRUE ;483 GO_STATE(SC4_THRU_A) ;484 break ;485 }486 break ;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 */496 }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 */501 }502 ACTIONS_DONE() ;503 DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);504 break ;505 case SC11_C_WRAP_S :506 /*SC70*/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) ;510 break ;511 }512 break ;513 default:514 SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ;515 break;516 }517}518 519/*520 * get MAC's input Port521 * return :522 * PA or PB523 */524int cfm_get_mac_input(struct s_smc *smc)525{526 return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||527 smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA;528}529 530/*531 * get MAC's output Port532 * return :533 * PA or PB534 */535int cfm_get_mac_output(struct s_smc *smc)536{537 return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||538 smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA;539}540 541static 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_ISO545} ;546 547static 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_ISO551} ;552 553static 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_ISO557} ;558 559static 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_PRIM563} ;564 565static 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,568} ;569 570static 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,573} ;574 575int cem_build_path(struct s_smc *smc, char *to, int path_index)576{577 char *path ;578 int len ;579 580 switch (smc->mib.fddiSMTCF_State) {581 default :582 case SC0_ISOLATED :583 path = smc->s.sas ? path_iso_s : path_iso ;584 len = smc->s.sas ? sizeof(path_iso_s) : sizeof(path_iso) ;585 break ;586 case SC9_C_WRAP_A :587 path = path_wrap_a ;588 len = sizeof(path_wrap_a) ;589 break ;590 case SC10_C_WRAP_B :591 path = path_wrap_b ;592 len = sizeof(path_wrap_b) ;593 break ;594 case SC4_THRU_A :595 path = path_thru ;596 len = sizeof(path_thru) ;597 break ;598 case SC11_C_WRAP_S :599 path = path_wrap_s ;600 len = sizeof(path_wrap_s) ;601 break ;602 }603 memcpy(to,path,len) ;604 605 LINT_USE(path_index);606 607 return len;608}609