brintos

brintos / linux-shallow public Read only

0
0
Text · 15.8 KiB · 3146236 Raw
643 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 RMT15	Ring Management16*/17 18/*19 * Hardware independent state machine implemantation20 * The following external SMT functions are referenced :21 *22 * 		queue_event()23 * 		smt_timer_start()24 * 		smt_timer_stop()25 *26 * 	The following external HW dependent functions are referenced :27 *		sm_ma_control()28 *		sm_mac_check_beacon_claim()29 *30 * 	The following HW dependent events are required :31 *		RM_RING_OP32 *		RM_RING_NON_OP33 *		RM_MY_BEACON34 *		RM_OTHER_BEACON35 *		RM_MY_CLAIM36 *		RM_TRT_EXP37 *		RM_VALID_CLAIM38 *39 */40 41#include "h/types.h"42#include "h/fddi.h"43#include "h/smc.h"44 45#define KERNEL46#include "h/smtstate.h"47 48/*49 * FSM Macros50 */51#define AFLAG	0x1052#define GO_STATE(x)	(smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)53#define ACTIONS_DONE()	(smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)54#define ACTIONS(x)	(x|AFLAG)55 56#define RM0_ISOLATED	057#define RM1_NON_OP	1		/* not operational */58#define RM2_RING_OP	2		/* ring operational */59#define RM3_DETECT	3		/* detect dupl addresses */60#define RM4_NON_OP_DUP	4		/* dupl. addr detected */61#define RM5_RING_OP_DUP	5		/* ring oper. with dupl. addr */62#define RM6_DIRECTED	6		/* sending directed beacons */63#define RM7_TRACE	7		/* trace initiated */64 65/*66 * symbolic state names67 */68static const char * const rmt_states[] = {69	"RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",70	"RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",71	"RM7_TRACE"72} ;73 74/*75 * symbolic event names76 */77static const char * const rmt_events[] = {78	"NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",79	"RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",80	"RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",81	"RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",82	"RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",83	"RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"84} ;85 86/*87 * Globals88 * in struct s_rmt89 */90 91 92/*93 * function declarations94 */95static void rmt_fsm(struct s_smc *smc, int cmd);96static void start_rmt_timer0(struct s_smc *smc, u_long value, int event);97static void start_rmt_timer1(struct s_smc *smc, u_long value, int event);98static void start_rmt_timer2(struct s_smc *smc, u_long value, int event);99static void stop_rmt_timer0(struct s_smc *smc);100static void stop_rmt_timer1(struct s_smc *smc);101static void stop_rmt_timer2(struct s_smc *smc);102static void rmt_dup_actions(struct s_smc *smc);103static void rmt_reinsert_actions(struct s_smc *smc);104static void rmt_leave_actions(struct s_smc *smc);105static void rmt_new_dup_actions(struct s_smc *smc);106 107#ifndef SUPERNET_3108extern void restart_trt_for_dbcn() ;109#endif /*SUPERNET_3*/110 111/*112	init RMT state machine113	clear all RMT vars and flags114*/115void rmt_init(struct s_smc *smc)116{117	smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;118	smc->r.dup_addr_test = DA_NONE ;119	smc->r.da_flag = 0 ;120	smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;121	smc->r.sm_ma_avail = FALSE ;122	smc->r.loop_avail = 0 ;123	smc->r.bn_flag = 0 ;124	smc->r.jm_flag = 0 ;125	smc->r.no_flag = TRUE ;126}127 128/*129	RMT state machine130	called by dispatcher131 132	do133		display state change134		process event135	until SM is stable136*/137void rmt(struct s_smc *smc, int event)138{139	int	state ;140 141	do {142		DB_RMT("RMT : state %s%s event %s",143		       smc->mib.m[MAC0].fddiMACRMTState & AFLAG ? "ACTIONS " : "",144		       rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG],145		       rmt_events[event]);146		state = smc->mib.m[MAC0].fddiMACRMTState ;147		rmt_fsm(smc,event) ;148		event = 0 ;149	} while (state != smc->mib.m[MAC0].fddiMACRMTState) ;150	rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;151}152 153/*154	process RMT event155*/156static void rmt_fsm(struct s_smc *smc, int cmd)157{158	/*159	 * RM00-RM70 : from all states160	 */161	if (!smc->r.rm_join && !smc->r.rm_loop &&162		smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&163		smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {164		RS_SET(smc,RS_NORINGOP) ;165		rmt_indication(smc,0) ;166		GO_STATE(RM0_ISOLATED) ;167		return ;168	}169 170	switch(smc->mib.m[MAC0].fddiMACRMTState) {171	case ACTIONS(RM0_ISOLATED) :172		stop_rmt_timer0(smc) ;173		stop_rmt_timer1(smc) ;174		stop_rmt_timer2(smc) ;175 176		/*177		 * Disable MAC.178		 */179		sm_ma_control(smc,MA_OFFLINE) ;180		smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;181		smc->r.loop_avail = FALSE ;182		smc->r.sm_ma_avail = FALSE ;183		smc->r.no_flag = TRUE ;184		DB_RMTN(1, "RMT : ISOLATED");185		ACTIONS_DONE() ;186		break ;187	case RM0_ISOLATED :188		/*RM01*/189		if (smc->r.rm_join || smc->r.rm_loop) {190			/*191			 * According to the standard the MAC must be reset192			 * here. The FORMAC will be initialized and Claim193			 * and Beacon Frames will be uploaded to the MAC.194			 * So any change of Treq will take effect NOW.195			 */196			sm_ma_control(smc,MA_RESET) ;197			GO_STATE(RM1_NON_OP) ;198			break ;199		}200		break ;201	case ACTIONS(RM1_NON_OP) :202		start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;203		stop_rmt_timer1(smc) ;204		stop_rmt_timer2(smc) ;205		sm_ma_control(smc,MA_BEACON) ;206		DB_RMTN(1, "RMT : RING DOWN");207		RS_SET(smc,RS_NORINGOP) ;208		smc->r.sm_ma_avail = FALSE ;209		rmt_indication(smc,0) ;210		ACTIONS_DONE() ;211		break ;212	case RM1_NON_OP :213		/*RM12*/214		if (cmd == RM_RING_OP) {215			RS_SET(smc,RS_RINGOPCHANGE) ;216			GO_STATE(RM2_RING_OP) ;217			break ;218		}219		/*RM13*/220		else if (cmd == RM_TIMEOUT_NON_OP) {221			smc->r.bn_flag = FALSE ;222			smc->r.no_flag = TRUE ;223			GO_STATE(RM3_DETECT) ;224			break ;225		}226		break ;227	case ACTIONS(RM2_RING_OP) :228		stop_rmt_timer0(smc) ;229		stop_rmt_timer1(smc) ;230		stop_rmt_timer2(smc) ;231		smc->r.no_flag = FALSE ;232		if (smc->r.rm_loop)233			smc->r.loop_avail = TRUE ;234		if (smc->r.rm_join) {235			smc->r.sm_ma_avail = TRUE ;236			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)237				smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE;238			else239				smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE;240		}241		DB_RMTN(1, "RMT : RING UP");242		RS_CLEAR(smc,RS_NORINGOP) ;243		RS_SET(smc,RS_RINGOPCHANGE) ;244		rmt_indication(smc,1) ;245		smt_stat_counter(smc,0) ;246		ACTIONS_DONE() ;247		break ;248	case RM2_RING_OP :249		/*RM21*/250		if (cmd == RM_RING_NON_OP) {251			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;252			smc->r.loop_avail = FALSE ;253			RS_SET(smc,RS_RINGOPCHANGE) ;254			GO_STATE(RM1_NON_OP) ;255			break ;256		}257		/*RM22a*/258		else if (cmd == RM_ENABLE_FLAG) {259			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)260			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;261				else262			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;263		}264		/*RM25*/265		else if (smc->r.dup_addr_test == DA_FAILED) {266			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;267			smc->r.loop_avail = FALSE ;268			smc->r.da_flag = TRUE ;269			GO_STATE(RM5_RING_OP_DUP) ;270			break ;271		}272		break ;273	case ACTIONS(RM3_DETECT) :274		start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;275		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;276		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;277		sm_mac_check_beacon_claim(smc) ;278		DB_RMTN(1, "RMT : RM3_DETECT");279		ACTIONS_DONE() ;280		break ;281	case RM3_DETECT :282		if (cmd == RM_TIMEOUT_POLL) {283			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);284			sm_mac_check_beacon_claim(smc) ;285			break ;286		}287		if (cmd == RM_TIMEOUT_D_MAX) {288			smc->r.timer0_exp = TRUE ;289		}290		/*291		 *jd(22-Feb-1999)292		 * We need a time ">= 2*mac_d_max" since we had finished293		 * Claim or Beacon state. So we will restart timer0 at294		 * every state change.295		 */296		if (cmd == RM_TX_STATE_CHANGE) {297			start_rmt_timer0(smc,298					 smc->s.mac_d_max*2,299					 RM_TIMEOUT_D_MAX) ;300		}301		/*RM32*/302		if (cmd == RM_RING_OP) {303			GO_STATE(RM2_RING_OP) ;304			break ;305		}306		/*RM33a*/307		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)308			&& smc->r.bn_flag) {309			smc->r.bn_flag = FALSE ;310		}311		/*RM33b*/312		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {313			int	tx ;314			/*315			 * set bn_flag only if in state T4 or T5:316			 * only if we're the beaconer should we start the317			 * trace !318			 */319			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {320			DB_RMTN(2, "RMT : DETECT && TRT_EXPIRED && T4/T5");321				smc->r.bn_flag = TRUE ;322				/*323				 * If one of the upstream stations beaconed324				 * and the link to the upstream neighbor is325				 * lost we need to restart the stuck timer to326				 * check the "stuck beacon" condition.327				 */328				start_rmt_timer1(smc,smc->s.rmt_t_stuck,329					RM_TIMEOUT_T_STUCK) ;330			}331			/*332			 * We do NOT need to clear smc->r.bn_flag in case of333			 * not being in state T4 or T5, because the flag334			 * must be cleared in order to get in this condition.335			 */336 337			DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",338				tx, smc->r.bn_flag);339		}340		/*RM34a*/341		else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {342			rmt_new_dup_actions(smc) ;343			GO_STATE(RM4_NON_OP_DUP) ;344			break ;345		}346		/*RM34b*/347		else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {348			rmt_new_dup_actions(smc) ;349			GO_STATE(RM4_NON_OP_DUP) ;350			break ;351		}352		/*RM34c*/353		else if (cmd == RM_VALID_CLAIM) {354			rmt_new_dup_actions(smc) ;355			GO_STATE(RM4_NON_OP_DUP) ;356			break ;357		}358		/*RM36*/359		else if (cmd == RM_TIMEOUT_T_STUCK &&360			smc->r.rm_join && smc->r.bn_flag) {361			GO_STATE(RM6_DIRECTED) ;362			break ;363		}364		break ;365	case ACTIONS(RM4_NON_OP_DUP) :366		start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);367		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;368		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;369		sm_mac_check_beacon_claim(smc) ;370		DB_RMTN(1, "RMT : RM4_NON_OP_DUP");371		ACTIONS_DONE() ;372		break ;373	case RM4_NON_OP_DUP :374		if (cmd == RM_TIMEOUT_POLL) {375			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);376			sm_mac_check_beacon_claim(smc) ;377			break ;378		}379		/*RM41*/380		if (!smc->r.da_flag) {381			GO_STATE(RM1_NON_OP) ;382			break ;383		}384		/*RM44a*/385		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&386			smc->r.bn_flag) {387			smc->r.bn_flag = FALSE ;388		}389		/*RM44b*/390		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {391			int	tx ;392			/*393			 * set bn_flag only if in state T4 or T5:394			 * only if we're the beaconer should we start the395			 * trace !396			 */397			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {398			DB_RMTN(2, "RMT : NOPDUP && TRT_EXPIRED && T4/T5");399				smc->r.bn_flag = TRUE ;400				/*401				 * If one of the upstream stations beaconed402				 * and the link to the upstream neighbor is403				 * lost we need to restart the stuck timer to404				 * check the "stuck beacon" condition.405				 */406				start_rmt_timer1(smc,smc->s.rmt_t_stuck,407					RM_TIMEOUT_T_STUCK) ;408			}409			/*410			 * We do NOT need to clear smc->r.bn_flag in case of411			 * not being in state T4 or T5, because the flag412			 * must be cleared in order to get in this condition.413			 */414 415			DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",416				tx, smc->r.bn_flag);417		}418		/*RM44c*/419		else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {420			rmt_dup_actions(smc) ;421		}422		/*RM45*/423		else if (cmd == RM_RING_OP) {424			smc->r.no_flag = FALSE ;425			GO_STATE(RM5_RING_OP_DUP) ;426			break ;427		}428		/*RM46*/429		else if (cmd == RM_TIMEOUT_T_STUCK &&430			smc->r.rm_join && smc->r.bn_flag) {431			GO_STATE(RM6_DIRECTED) ;432			break ;433		}434		break ;435	case ACTIONS(RM5_RING_OP_DUP) :436		stop_rmt_timer0(smc) ;437		stop_rmt_timer1(smc) ;438		stop_rmt_timer2(smc) ;439		DB_RMTN(1, "RMT : RM5_RING_OP_DUP");440		ACTIONS_DONE() ;441		break;442	case RM5_RING_OP_DUP :443		/*RM52*/444		if (smc->r.dup_addr_test == DA_PASSED) {445			smc->r.da_flag = FALSE ;446			GO_STATE(RM2_RING_OP) ;447			break ;448		}449		/*RM54*/450		else if (cmd == RM_RING_NON_OP) {451			smc->r.jm_flag = FALSE ;452			smc->r.bn_flag = FALSE ;453			GO_STATE(RM4_NON_OP_DUP) ;454			break ;455		}456		break ;457	case ACTIONS(RM6_DIRECTED) :458		start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;459		stop_rmt_timer1(smc) ;460		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;461		sm_ma_control(smc,MA_DIRECTED) ;462		RS_SET(smc,RS_BEACON) ;463		DB_RMTN(1, "RMT : RM6_DIRECTED");464		ACTIONS_DONE() ;465		break ;466	case RM6_DIRECTED :467		/*RM63*/468		if (cmd == RM_TIMEOUT_POLL) {469			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);470			sm_mac_check_beacon_claim(smc) ;471#ifndef SUPERNET_3472			/* Because of problems with the Supernet II chip set473			 * sending of Directed Beacon will stop after 165ms474			 * therefore restart_trt_for_dbcn(smc) will be called475			 * to prevent this.476			 */477			restart_trt_for_dbcn(smc) ;478#endif /*SUPERNET_3*/479			break ;480		}481		if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&482			!smc->r.da_flag) {483			smc->r.bn_flag = FALSE ;484			GO_STATE(RM3_DETECT) ;485			break ;486		}487		/*RM64*/488		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&489			smc->r.da_flag) {490			smc->r.bn_flag = FALSE ;491			GO_STATE(RM4_NON_OP_DUP) ;492			break ;493		}494		/*RM67*/495		else if (cmd == RM_TIMEOUT_T_DIRECT) {496			GO_STATE(RM7_TRACE) ;497			break ;498		}499		break ;500	case ACTIONS(RM7_TRACE) :501		stop_rmt_timer0(smc) ;502		stop_rmt_timer1(smc) ;503		stop_rmt_timer2(smc) ;504		smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;505		queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;506		DB_RMTN(1, "RMT : RM7_TRACE");507		ACTIONS_DONE() ;508		break ;509	case RM7_TRACE :510		break ;511	default:512		SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;513		break;514	}515}516 517/*518 * (jd) RMT duplicate address actions519 * leave the ring or reinsert just as configured520 */521static void rmt_dup_actions(struct s_smc *smc)522{523	if (smc->r.jm_flag) {524	}525	else {526		if (smc->s.rmt_dup_mac_behavior) {527			SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;528                        rmt_reinsert_actions(smc) ;529		}530		else {531			SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;532			rmt_leave_actions(smc) ;533		}534	}535}536 537/*538 * Reconnect to the Ring539 */540static void rmt_reinsert_actions(struct s_smc *smc)541{542	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;543	queue_event(smc,EVENT_ECM,EC_CONNECT) ;544}545 546/*547 * duplicate address detected548 */549static void rmt_new_dup_actions(struct s_smc *smc)550{551	smc->r.da_flag = TRUE ;552	smc->r.bn_flag = FALSE ;553	smc->r.jm_flag = FALSE ;554	/*555	 * we have three options : change address, jam or leave556	 * we leave the ring as default 557	 * Optionally it's possible to reinsert after leaving the Ring558	 * but this will not conform with SMT Spec.559	 */560	if (smc->s.rmt_dup_mac_behavior) {561		SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;562		rmt_reinsert_actions(smc) ;563	}564	else {565		SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;566		rmt_leave_actions(smc) ;567	}568}569 570 571/*572 * leave the ring573 */574static void rmt_leave_actions(struct s_smc *smc)575{576	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;577	/*578	 * Note: Do NOT try again later. (with please reconnect)579	 * The station must be left from the ring!580	 */581}582 583/*584 * SMT timer interface585 *	start RMT timer 0586 */587static void start_rmt_timer0(struct s_smc *smc, u_long value, int event)588{589	smc->r.timer0_exp = FALSE ;		/* clear timer event flag */590	smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));591}592 593/*594 * SMT timer interface595 *	start RMT timer 1596 */597static void start_rmt_timer1(struct s_smc *smc, u_long value, int event)598{599	smc->r.timer1_exp = FALSE ;	/* clear timer event flag */600	smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));601}602 603/*604 * SMT timer interface605 *	start RMT timer 2606 */607static void start_rmt_timer2(struct s_smc *smc, u_long value, int event)608{609	smc->r.timer2_exp = FALSE ;		/* clear timer event flag */610	smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));611}612 613/*614 * SMT timer interface615 *	stop RMT timer 0616 */617static void stop_rmt_timer0(struct s_smc *smc)618{619	if (smc->r.rmt_timer0.tm_active)620		smt_timer_stop(smc,&smc->r.rmt_timer0) ;621}622 623/*624 * SMT timer interface625 *	stop RMT timer 1626 */627static void stop_rmt_timer1(struct s_smc *smc)628{629	if (smc->r.rmt_timer1.tm_active)630		smt_timer_stop(smc,&smc->r.rmt_timer1) ;631}632 633/*634 * SMT timer interface635 *	stop RMT timer 2636 */637static void stop_rmt_timer2(struct s_smc *smc)638{639	if (smc->r.rmt_timer2.tm_active)640		smt_timer_stop(smc,&smc->r.rmt_timer2) ;641}642 643