brintos

brintos / linux-shallow public Read only

0
0
Text · 15.6 KiB · 4eea340 Raw
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