brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · 2f5f5f2 Raw
525 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 ECM15	Entity Coordination Management16	Hardware independent state machine17*/18 19/*20 * Hardware independent state machine implemantation21 * The following external SMT functions are referenced :22 *23 * 		queue_event()24 * 		smt_timer_start()25 * 		smt_timer_stop()26 *27 * 	The following external HW dependent functions are referenced :28 * 		sm_pm_bypass_req()29 * 		sm_pm_get_ls()30 * 31 * 	The following HW dependent events are required :32 *		NONE33 *34 */35 36#include "h/types.h"37#include "h/fddi.h"38#include "h/smc.h"39 40#define KERNEL41#include "h/smtstate.h"42 43/*44 * FSM Macros45 */46#define AFLAG	0x1047#define GO_STATE(x)	(smc->mib.fddiSMTECMState = (x)|AFLAG)48#define ACTIONS_DONE()	(smc->mib.fddiSMTECMState &= ~AFLAG)49#define ACTIONS(x)	(x|AFLAG)50 51#define EC0_OUT		0			/* not inserted */52#define EC1_IN		1			/* inserted */53#define EC2_TRACE	2			/* tracing */54#define EC3_LEAVE	3			/* leaving the ring */55#define EC4_PATH_TEST	4			/* performing path test */56#define EC5_INSERT	5			/* bypass being turned on */57#define EC6_CHECK	6			/* checking bypass */58#define EC7_DEINSERT	7			/* bypass being turnde off */59 60/*61 * symbolic state names62 */63static const char * const ecm_states[] = {64	"EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",65	"EC5_INSERT","EC6_CHECK","EC7_DEINSERT"66} ;67 68/*69 * symbolic event names70 */71static const char * const ecm_events[] = {72	"NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",73	"EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",74	"EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"75} ;76 77/*78 * all Globals  are defined in smc.h79 * struct s_ecm80 */81 82/*83 * function declarations84 */85 86static void ecm_fsm(struct s_smc *smc, int cmd);87static void start_ecm_timer(struct s_smc *smc, u_long value, int event);88static void stop_ecm_timer(struct s_smc *smc);89static void prop_actions(struct s_smc *smc);90 91/*92	init ECM state machine93	clear all ECM vars and flags94*/95void ecm_init(struct s_smc *smc)96{97	smc->e.path_test = PT_PASSED ;98	smc->e.trace_prop = 0 ;99	smc->e.sb_flag = 0 ;100	smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;101	smc->e.ecm_line_state = FALSE ;102}103 104/*105	ECM state machine106	called by dispatcher107 108	do109		display state change110		process event111	until SM is stable112*/113void ecm(struct s_smc *smc, int event)114{115	int	state ;116 117	do {118		DB_ECM("ECM : state %s%s event %s",119		       smc->mib.fddiSMTECMState & AFLAG ? "ACTIONS " : "",120		       ecm_states[smc->mib.fddiSMTECMState & ~AFLAG],121		       ecm_events[event]);122		state = smc->mib.fddiSMTECMState ;123		ecm_fsm(smc,event) ;124		event = 0 ;125	} while (state != smc->mib.fddiSMTECMState) ;126	ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;127}128 129/*130	process ECM event131*/132static void ecm_fsm(struct s_smc *smc, int cmd)133{134	int ls_a ;			/* current line state PHY A */135	int ls_b ;			/* current line state PHY B */136	int	p ;			/* ports */137 138 139	smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;140	if (cmd == EC_CONNECT)141		smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;142 143	/* For AIX event notification: */144	/* Is a disconnect  command remotely issued ? */145	if (cmd == EC_DISCONNECT &&146	    smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) {147		AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)148			FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),149			smt_get_error_word(smc) );150	}151 152	/*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/153	if (cmd == EC_CONNECT) {154		smc->e.DisconnectFlag = FALSE ;155	}156	else if (cmd == EC_DISCONNECT) {157		smc->e.DisconnectFlag = TRUE ;158	}159	160	switch(smc->mib.fddiSMTECMState) {161	case ACTIONS(EC0_OUT) :162		/*163		 * We do not perform a path test164		 */165		smc->e.path_test = PT_PASSED ;166		smc->e.ecm_line_state = FALSE ;167		stop_ecm_timer(smc) ;168		ACTIONS_DONE() ;169		break ;170	case EC0_OUT:171		/*EC01*/172		if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent173			&& smc->e.path_test==PT_PASSED) {174			GO_STATE(EC1_IN) ;175			break ;176		}177		/*EC05*/178		else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&179			smc->mib.fddiSMTBypassPresent &&180			(smc->s.sas == SMT_DAS)) {181			GO_STATE(EC5_INSERT) ;182			break ;183		}184		break;185	case ACTIONS(EC1_IN) :186		stop_ecm_timer(smc) ;187		smc->e.trace_prop = 0 ;188		sm_ma_control(smc,MA_TREQ) ;189		for (p = 0 ; p < NUMPHYS ; p++)190			if (smc->mib.p[p].fddiPORTHardwarePresent)191				queue_event(smc,EVENT_PCMA+p,PC_START) ;192		ACTIONS_DONE() ;193		break ;194	case EC1_IN:195		/*EC12*/196		if (cmd == EC_TRACE_PROP) {197			prop_actions(smc) ;198			GO_STATE(EC2_TRACE) ;199			break ;200		}201		/*EC13*/202		else if (cmd == EC_DISCONNECT) {203			GO_STATE(EC3_LEAVE) ;204			break ;205		}206		break;207	case ACTIONS(EC2_TRACE) :208		start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),209			EC_TIMEOUT_TMAX) ;210		ACTIONS_DONE() ;211		break ;212	case EC2_TRACE :213		/*EC22*/214		if (cmd == EC_TRACE_PROP) {215			prop_actions(smc) ;216			GO_STATE(EC2_TRACE) ;217			break ;218		}219		/*EC23a*/220		else if (cmd == EC_DISCONNECT) {221			smc->e.path_test = PT_EXITING ;222			GO_STATE(EC3_LEAVE) ;223			break ;224		}225		/*EC23b*/226		else if (smc->e.path_test == PT_PENDING) {227			GO_STATE(EC3_LEAVE) ;228			break ;229		}230		/*EC23c*/231		else if (cmd == EC_TIMEOUT_TMAX) {232			/* Trace_Max is expired */233			/* -> send AIX_EVENT */234			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,235				(u_long) FDDI_SMT_ERROR, (u_long)236				FDDI_TRACE_MAX, smt_get_error_word(smc));237			smc->e.path_test = PT_PENDING ;238			GO_STATE(EC3_LEAVE) ;239			break ;240		}241		break ;242	case ACTIONS(EC3_LEAVE) :243		start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;244		for (p = 0 ; p < NUMPHYS ; p++)245			queue_event(smc,EVENT_PCMA+p,PC_STOP) ;246		ACTIONS_DONE() ;247		break ;248	case EC3_LEAVE:249		/*EC30*/250		if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&251			(smc->e.path_test != PT_PENDING)) {252			GO_STATE(EC0_OUT) ;253			break ;254		}255		/*EC34*/256		else if (cmd == EC_TIMEOUT_TD &&257			(smc->e.path_test == PT_PENDING)) {258			GO_STATE(EC4_PATH_TEST) ;259			break ;260		}261		/*EC31*/262		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {263			GO_STATE(EC1_IN) ;264			break ;265		}266		/*EC33*/267		else if (cmd == EC_DISCONNECT &&268			smc->e.path_test == PT_PENDING) {269			smc->e.path_test = PT_EXITING ;270			/*271			 * stay in state - state will be left via timeout272			 */273		}274		/*EC37*/275		else if (cmd == EC_TIMEOUT_TD &&276			smc->mib.fddiSMTBypassPresent &&277			smc->e.path_test != PT_PENDING) {278			GO_STATE(EC7_DEINSERT) ;279			break ;280		}281		break ;282	case ACTIONS(EC4_PATH_TEST) :283		stop_ecm_timer(smc) ;284		smc->e.path_test = PT_TESTING ;285		start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;286		/* now perform path test ... just a simulation */287		ACTIONS_DONE() ;288		break ;289	case EC4_PATH_TEST :290		/* path test done delay */291		if (cmd == EC_TEST_DONE)292			smc->e.path_test = PT_PASSED ;293 294		if (smc->e.path_test == PT_FAILED)295			RS_SET(smc,RS_PATHTEST) ;296 297		/*EC40a*/298		if (smc->e.path_test == PT_FAILED &&299			!smc->mib.fddiSMTBypassPresent) {300			GO_STATE(EC0_OUT) ;301			break ;302		}303		/*EC40b*/304		else if (cmd == EC_DISCONNECT &&305			!smc->mib.fddiSMTBypassPresent) {306			GO_STATE(EC0_OUT) ;307			break ;308		}309		/*EC41*/310		else if (smc->e.path_test == PT_PASSED) {311			GO_STATE(EC1_IN) ;312			break ;313		}314		/*EC47a*/315		else if (smc->e.path_test == PT_FAILED &&316			smc->mib.fddiSMTBypassPresent) {317			GO_STATE(EC7_DEINSERT) ;318			break ;319		}320		/*EC47b*/321		else if (cmd == EC_DISCONNECT &&322			smc->mib.fddiSMTBypassPresent) {323			GO_STATE(EC7_DEINSERT) ;324			break ;325		}326		break ;327	case ACTIONS(EC5_INSERT) :328		sm_pm_bypass_req(smc,BP_INSERT);329		start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;330		ACTIONS_DONE() ;331		break ;332	case EC5_INSERT :333		/*EC56*/334		if (cmd == EC_TIMEOUT_INMAX) {335			GO_STATE(EC6_CHECK) ;336			break ;337		}338		/*EC57*/339		else if (cmd == EC_DISCONNECT) {340			GO_STATE(EC7_DEINSERT) ;341			break ;342		}343		break ;344	case ACTIONS(EC6_CHECK) :345		/*346		 * in EC6_CHECK, we *POLL* the line state !347		 * check whether both bypass switches have switched.348		 */349		start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;350		smc->e.ecm_line_state = TRUE ;	/* flag to pcm: report Q/HLS */351		ACTIONS_DONE() ;352		break ;353	case EC6_CHECK :354		ls_a = sm_pm_get_ls(smc,PA) ;355		ls_b = sm_pm_get_ls(smc,PB) ;356 357		/*EC61*/358		if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&359		    ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {360			smc->e.sb_flag = FALSE ;361			smc->e.ecm_line_state = FALSE ;362			GO_STATE(EC1_IN) ;363			break ;364		}365		/*EC66*/366		else if (!smc->e.sb_flag &&367			 (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||368			  ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){369			smc->e.sb_flag = TRUE ;370			DB_ECMN(1, "ECM : EC6_CHECK - stuck bypass");371			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)372				FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,373				smt_get_error_word(smc));374		}375		/*EC67*/376		else if (cmd == EC_DISCONNECT) {377			smc->e.ecm_line_state = FALSE ;378			GO_STATE(EC7_DEINSERT) ;379			break ;380		}381		else {382			/*383			 * restart poll384			 */385			start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;386		}387		break ;388	case ACTIONS(EC7_DEINSERT) :389		sm_pm_bypass_req(smc,BP_DEINSERT);390		start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;391		ACTIONS_DONE() ;392		break ;393	case EC7_DEINSERT:394		/*EC70*/395		if (cmd == EC_TIMEOUT_IMAX) {396			GO_STATE(EC0_OUT) ;397			break ;398		}399		/*EC75*/400		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {401			GO_STATE(EC5_INSERT) ;402			break ;403		}404		break;405	default:406		SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;407		break;408	}409}410 411#ifndef	CONCENTRATOR412/*413 * trace propagation actions for SAS & DAS414 */415static void prop_actions(struct s_smc *smc)416{417	int	port_in = 0 ;418	int	port_out = 0 ;419 420	RS_SET(smc,RS_EVENT) ;421	switch (smc->s.sas) {422	case SMT_SAS :423		port_in = port_out = pcm_get_s_port(smc) ;424		break ;425	case SMT_DAS :426		port_in = cfm_get_mac_input(smc) ;	/* PA or PB */427		port_out = cfm_get_mac_output(smc) ;	/* PA or PB */428		break ;429	case SMT_NAC :430		SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;431		return ;432	}433 434	DB_ECM("ECM : prop_actions - trace_prop %lu", smc->e.trace_prop);435	DB_ECM("ECM : prop_actions - in %d out %d", port_in, port_out);436 437	if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {438		/* trace initiatior */439		DB_ECM("ECM : initiate TRACE on PHY %c", 'A' + port_in - PA);440		queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;441	}442	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&443		port_out != PA) {444		/* trace propagate upstream */445		DB_ECM("ECM : propagate TRACE on PHY B");446		queue_event(smc,EVENT_PCMB,PC_TRACE) ;447	}448	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&449		port_out != PB) {450		/* trace propagate upstream */451		DB_ECM("ECM : propagate TRACE on PHY A");452		queue_event(smc,EVENT_PCMA,PC_TRACE) ;453	}454	else {455		/* signal trace termination */456		DB_ECM("ECM : TRACE terminated");457		smc->e.path_test = PT_PENDING ;458	}459	smc->e.trace_prop = 0 ;460}461#else462/*463 * trace propagation actions for Concentrator464 */465static void prop_actions(struct s_smc *smc)466{467	int	initiator ;468	int	upstream ;469	int	p ;470 471	RS_SET(smc,RS_EVENT) ;472	while (smc->e.trace_prop) {473		DB_ECM("ECM : prop_actions - trace_prop %d",474		       smc->e.trace_prop);475 476		if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {477			initiator = ENTITY_MAC ;478			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;479			DB_ECM("ECM: MAC initiates trace");480		}481		else {482			for (p = NUMPHYS-1 ; p >= 0 ; p--) {483				if (smc->e.trace_prop &484					ENTITY_BIT(ENTITY_PHY(p)))485					break ;486			}487			initiator = ENTITY_PHY(p) ;488			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;489		}490		upstream = cem_get_upstream(smc,initiator) ;491 492		if (upstream == ENTITY_MAC) {493			/* signal trace termination */494			DB_ECM("ECM : TRACE terminated");495			smc->e.path_test = PT_PENDING ;496		}497		else {498			/* trace propagate upstream */499			DB_ECM("ECM : propagate TRACE on PHY %d", upstream);500			queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;501		}502	}503}504#endif505 506 507/*508 * SMT timer interface509 *	start ECM timer510 */511static void start_ecm_timer(struct s_smc *smc, u_long value, int event)512{513	smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));514}515 516/*517 * SMT timer interface518 *	stop ECM timer519 */520static void stop_ecm_timer(struct s_smc *smc)521{522	if (smc->e.ecm_timer.tm_active)523		smt_timer_stop(smc,&smc->e.ecm_timer) ;524}525