xref: /openbmc/linux/drivers/net/fddi/skfp/ecm.c (revision 9745aab8)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
233f810b2SJeff Kirsher /******************************************************************************
333f810b2SJeff Kirsher  *
433f810b2SJeff Kirsher  *	(C)Copyright 1998,1999 SysKonnect,
533f810b2SJeff Kirsher  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
633f810b2SJeff Kirsher  *
733f810b2SJeff Kirsher  *	See the file "skfddi.c" for further information.
833f810b2SJeff Kirsher  *
933f810b2SJeff Kirsher  *	The information in this file is provided "AS IS" without warranty.
1033f810b2SJeff Kirsher  *
1133f810b2SJeff Kirsher  ******************************************************************************/
1233f810b2SJeff Kirsher 
1333f810b2SJeff Kirsher /*
1433f810b2SJeff Kirsher 	SMT ECM
1533f810b2SJeff Kirsher 	Entity Coordination Management
1633f810b2SJeff Kirsher 	Hardware independent state machine
1733f810b2SJeff Kirsher */
1833f810b2SJeff Kirsher 
1933f810b2SJeff Kirsher /*
2033f810b2SJeff Kirsher  * Hardware independent state machine implemantation
2133f810b2SJeff Kirsher  * The following external SMT functions are referenced :
2233f810b2SJeff Kirsher  *
2333f810b2SJeff Kirsher  * 		queue_event()
2433f810b2SJeff Kirsher  * 		smt_timer_start()
2533f810b2SJeff Kirsher  * 		smt_timer_stop()
2633f810b2SJeff Kirsher  *
2733f810b2SJeff Kirsher  * 	The following external HW dependent functions are referenced :
2833f810b2SJeff Kirsher  * 		sm_pm_bypass_req()
2933f810b2SJeff Kirsher  * 		sm_pm_get_ls()
3033f810b2SJeff Kirsher  *
3133f810b2SJeff Kirsher  * 	The following HW dependent events are required :
3233f810b2SJeff Kirsher  *		NONE
3333f810b2SJeff Kirsher  *
3433f810b2SJeff Kirsher  */
3533f810b2SJeff Kirsher 
3633f810b2SJeff Kirsher #include "h/types.h"
3733f810b2SJeff Kirsher #include "h/fddi.h"
3833f810b2SJeff Kirsher #include "h/smc.h"
3933f810b2SJeff Kirsher 
4033f810b2SJeff Kirsher #define KERNEL
4133f810b2SJeff Kirsher #include "h/smtstate.h"
4233f810b2SJeff Kirsher 
4333f810b2SJeff Kirsher /*
4433f810b2SJeff Kirsher  * FSM Macros
4533f810b2SJeff Kirsher  */
4633f810b2SJeff Kirsher #define AFLAG	0x10
4733f810b2SJeff Kirsher #define GO_STATE(x)	(smc->mib.fddiSMTECMState = (x)|AFLAG)
4833f810b2SJeff Kirsher #define ACTIONS_DONE()	(smc->mib.fddiSMTECMState &= ~AFLAG)
4933f810b2SJeff Kirsher #define ACTIONS(x)	(x|AFLAG)
5033f810b2SJeff Kirsher 
5133f810b2SJeff Kirsher #define EC0_OUT		0			/* not inserted */
5233f810b2SJeff Kirsher #define EC1_IN		1			/* inserted */
5333f810b2SJeff Kirsher #define EC2_TRACE	2			/* tracing */
5433f810b2SJeff Kirsher #define EC3_LEAVE	3			/* leaving the ring */
5533f810b2SJeff Kirsher #define EC4_PATH_TEST	4			/* performing path test */
5633f810b2SJeff Kirsher #define EC5_INSERT	5			/* bypass being turned on */
5733f810b2SJeff Kirsher #define EC6_CHECK	6			/* checking bypass */
5833f810b2SJeff Kirsher #define EC7_DEINSERT	7			/* bypass being turnde off */
5933f810b2SJeff Kirsher 
6033f810b2SJeff Kirsher /*
6133f810b2SJeff Kirsher  * symbolic state names
6233f810b2SJeff Kirsher  */
6333f810b2SJeff Kirsher static const char * const ecm_states[] = {
6433f810b2SJeff Kirsher 	"EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",
6533f810b2SJeff Kirsher 	"EC5_INSERT","EC6_CHECK","EC7_DEINSERT"
6633f810b2SJeff Kirsher } ;
6733f810b2SJeff Kirsher 
6833f810b2SJeff Kirsher /*
6933f810b2SJeff Kirsher  * symbolic event names
7033f810b2SJeff Kirsher  */
7133f810b2SJeff Kirsher static const char * const ecm_events[] = {
7233f810b2SJeff Kirsher 	"NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",
7333f810b2SJeff Kirsher 	"EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",
7433f810b2SJeff Kirsher 	"EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"
7533f810b2SJeff Kirsher } ;
7633f810b2SJeff Kirsher 
7733f810b2SJeff Kirsher /*
7833f810b2SJeff Kirsher  * all Globals  are defined in smc.h
7933f810b2SJeff Kirsher  * struct s_ecm
8033f810b2SJeff Kirsher  */
8133f810b2SJeff Kirsher 
8233f810b2SJeff Kirsher /*
8333f810b2SJeff Kirsher  * function declarations
8433f810b2SJeff Kirsher  */
8533f810b2SJeff Kirsher 
8633f810b2SJeff Kirsher static void ecm_fsm(struct s_smc *smc, int cmd);
8733f810b2SJeff Kirsher static void start_ecm_timer(struct s_smc *smc, u_long value, int event);
8833f810b2SJeff Kirsher static void stop_ecm_timer(struct s_smc *smc);
8933f810b2SJeff Kirsher static void prop_actions(struct s_smc *smc);
9033f810b2SJeff Kirsher 
9133f810b2SJeff Kirsher /*
9233f810b2SJeff Kirsher 	init ECM state machine
9333f810b2SJeff Kirsher 	clear all ECM vars and flags
9433f810b2SJeff Kirsher */
ecm_init(struct s_smc * smc)9533f810b2SJeff Kirsher void ecm_init(struct s_smc *smc)
9633f810b2SJeff Kirsher {
9733f810b2SJeff Kirsher 	smc->e.path_test = PT_PASSED ;
9833f810b2SJeff Kirsher 	smc->e.trace_prop = 0 ;
9933f810b2SJeff Kirsher 	smc->e.sb_flag = 0 ;
10033f810b2SJeff Kirsher 	smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;
10133f810b2SJeff Kirsher 	smc->e.ecm_line_state = FALSE ;
10233f810b2SJeff Kirsher }
10333f810b2SJeff Kirsher 
10433f810b2SJeff Kirsher /*
10533f810b2SJeff Kirsher 	ECM state machine
10633f810b2SJeff Kirsher 	called by dispatcher
10733f810b2SJeff Kirsher 
10833f810b2SJeff Kirsher 	do
10933f810b2SJeff Kirsher 		display state change
11033f810b2SJeff Kirsher 		process event
11133f810b2SJeff Kirsher 	until SM is stable
11233f810b2SJeff Kirsher */
ecm(struct s_smc * smc,int event)11333f810b2SJeff Kirsher void ecm(struct s_smc *smc, int event)
11433f810b2SJeff Kirsher {
11533f810b2SJeff Kirsher 	int	state ;
11633f810b2SJeff Kirsher 
11733f810b2SJeff Kirsher 	do {
1185671e8c1SJoe Perches 		DB_ECM("ECM : state %s%s event %s",
1195671e8c1SJoe Perches 		       smc->mib.fddiSMTECMState & AFLAG ? "ACTIONS " : "",
1205671e8c1SJoe Perches 		       ecm_states[smc->mib.fddiSMTECMState & ~AFLAG],
1215671e8c1SJoe Perches 		       ecm_events[event]);
12233f810b2SJeff Kirsher 		state = smc->mib.fddiSMTECMState ;
12333f810b2SJeff Kirsher 		ecm_fsm(smc,event) ;
12433f810b2SJeff Kirsher 		event = 0 ;
12533f810b2SJeff Kirsher 	} while (state != smc->mib.fddiSMTECMState) ;
12633f810b2SJeff Kirsher 	ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;
12733f810b2SJeff Kirsher }
12833f810b2SJeff Kirsher 
12933f810b2SJeff Kirsher /*
13033f810b2SJeff Kirsher 	process ECM event
13133f810b2SJeff Kirsher */
ecm_fsm(struct s_smc * smc,int cmd)13233f810b2SJeff Kirsher static void ecm_fsm(struct s_smc *smc, int cmd)
13333f810b2SJeff Kirsher {
13433f810b2SJeff Kirsher 	int ls_a ;			/* current line state PHY A */
13533f810b2SJeff Kirsher 	int ls_b ;			/* current line state PHY B */
13633f810b2SJeff Kirsher 	int	p ;			/* ports */
13733f810b2SJeff Kirsher 
13833f810b2SJeff Kirsher 
13933f810b2SJeff Kirsher 	smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;
14033f810b2SJeff Kirsher 	if (cmd == EC_CONNECT)
14133f810b2SJeff Kirsher 		smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
14233f810b2SJeff Kirsher 
14333f810b2SJeff Kirsher 	/* For AIX event notification: */
14433f810b2SJeff Kirsher 	/* Is a disconnect  command remotely issued ? */
14533f810b2SJeff Kirsher 	if (cmd == EC_DISCONNECT &&
146*918895bfSLee Jones 	    smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) {
14733f810b2SJeff Kirsher 		AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)
14833f810b2SJeff Kirsher 			FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),
14933f810b2SJeff Kirsher 			smt_get_error_word(smc) );
150*918895bfSLee Jones 	}
15133f810b2SJeff Kirsher 
15233f810b2SJeff Kirsher 	/*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/
15333f810b2SJeff Kirsher 	if (cmd == EC_CONNECT) {
15433f810b2SJeff Kirsher 		smc->e.DisconnectFlag = FALSE ;
15533f810b2SJeff Kirsher 	}
15633f810b2SJeff Kirsher 	else if (cmd == EC_DISCONNECT) {
15733f810b2SJeff Kirsher 		smc->e.DisconnectFlag = TRUE ;
15833f810b2SJeff Kirsher 	}
15933f810b2SJeff Kirsher 
16033f810b2SJeff Kirsher 	switch(smc->mib.fddiSMTECMState) {
16133f810b2SJeff Kirsher 	case ACTIONS(EC0_OUT) :
16233f810b2SJeff Kirsher 		/*
16333f810b2SJeff Kirsher 		 * We do not perform a path test
16433f810b2SJeff Kirsher 		 */
16533f810b2SJeff Kirsher 		smc->e.path_test = PT_PASSED ;
16633f810b2SJeff Kirsher 		smc->e.ecm_line_state = FALSE ;
16733f810b2SJeff Kirsher 		stop_ecm_timer(smc) ;
16833f810b2SJeff Kirsher 		ACTIONS_DONE() ;
16933f810b2SJeff Kirsher 		break ;
17033f810b2SJeff Kirsher 	case EC0_OUT:
17133f810b2SJeff Kirsher 		/*EC01*/
17233f810b2SJeff Kirsher 		if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent
17333f810b2SJeff Kirsher 			&& smc->e.path_test==PT_PASSED) {
17433f810b2SJeff Kirsher 			GO_STATE(EC1_IN) ;
17533f810b2SJeff Kirsher 			break ;
17633f810b2SJeff Kirsher 		}
17733f810b2SJeff Kirsher 		/*EC05*/
17833f810b2SJeff Kirsher 		else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&
17933f810b2SJeff Kirsher 			smc->mib.fddiSMTBypassPresent &&
18033f810b2SJeff Kirsher 			(smc->s.sas == SMT_DAS)) {
18133f810b2SJeff Kirsher 			GO_STATE(EC5_INSERT) ;
18233f810b2SJeff Kirsher 			break ;
18333f810b2SJeff Kirsher 		}
18433f810b2SJeff Kirsher 		break;
18533f810b2SJeff Kirsher 	case ACTIONS(EC1_IN) :
18633f810b2SJeff Kirsher 		stop_ecm_timer(smc) ;
18733f810b2SJeff Kirsher 		smc->e.trace_prop = 0 ;
18833f810b2SJeff Kirsher 		sm_ma_control(smc,MA_TREQ) ;
18933f810b2SJeff Kirsher 		for (p = 0 ; p < NUMPHYS ; p++)
19033f810b2SJeff Kirsher 			if (smc->mib.p[p].fddiPORTHardwarePresent)
19133f810b2SJeff Kirsher 				queue_event(smc,EVENT_PCMA+p,PC_START) ;
19233f810b2SJeff Kirsher 		ACTIONS_DONE() ;
19333f810b2SJeff Kirsher 		break ;
19433f810b2SJeff Kirsher 	case EC1_IN:
19533f810b2SJeff Kirsher 		/*EC12*/
19633f810b2SJeff Kirsher 		if (cmd == EC_TRACE_PROP) {
19733f810b2SJeff Kirsher 			prop_actions(smc) ;
19833f810b2SJeff Kirsher 			GO_STATE(EC2_TRACE) ;
19933f810b2SJeff Kirsher 			break ;
20033f810b2SJeff Kirsher 		}
20133f810b2SJeff Kirsher 		/*EC13*/
20233f810b2SJeff Kirsher 		else if (cmd == EC_DISCONNECT) {
20333f810b2SJeff Kirsher 			GO_STATE(EC3_LEAVE) ;
20433f810b2SJeff Kirsher 			break ;
20533f810b2SJeff Kirsher 		}
20633f810b2SJeff Kirsher 		break;
20733f810b2SJeff Kirsher 	case ACTIONS(EC2_TRACE) :
20833f810b2SJeff Kirsher 		start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),
20933f810b2SJeff Kirsher 			EC_TIMEOUT_TMAX) ;
21033f810b2SJeff Kirsher 		ACTIONS_DONE() ;
21133f810b2SJeff Kirsher 		break ;
21233f810b2SJeff Kirsher 	case EC2_TRACE :
21333f810b2SJeff Kirsher 		/*EC22*/
21433f810b2SJeff Kirsher 		if (cmd == EC_TRACE_PROP) {
21533f810b2SJeff Kirsher 			prop_actions(smc) ;
21633f810b2SJeff Kirsher 			GO_STATE(EC2_TRACE) ;
21733f810b2SJeff Kirsher 			break ;
21833f810b2SJeff Kirsher 		}
21933f810b2SJeff Kirsher 		/*EC23a*/
22033f810b2SJeff Kirsher 		else if (cmd == EC_DISCONNECT) {
22133f810b2SJeff Kirsher 			smc->e.path_test = PT_EXITING ;
22233f810b2SJeff Kirsher 			GO_STATE(EC3_LEAVE) ;
22333f810b2SJeff Kirsher 			break ;
22433f810b2SJeff Kirsher 		}
22533f810b2SJeff Kirsher 		/*EC23b*/
22633f810b2SJeff Kirsher 		else if (smc->e.path_test == PT_PENDING) {
22733f810b2SJeff Kirsher 			GO_STATE(EC3_LEAVE) ;
22833f810b2SJeff Kirsher 			break ;
22933f810b2SJeff Kirsher 		}
23033f810b2SJeff Kirsher 		/*EC23c*/
23133f810b2SJeff Kirsher 		else if (cmd == EC_TIMEOUT_TMAX) {
23233f810b2SJeff Kirsher 			/* Trace_Max is expired */
23333f810b2SJeff Kirsher 			/* -> send AIX_EVENT */
23433f810b2SJeff Kirsher 			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
23533f810b2SJeff Kirsher 				(u_long) FDDI_SMT_ERROR, (u_long)
23633f810b2SJeff Kirsher 				FDDI_TRACE_MAX, smt_get_error_word(smc));
23733f810b2SJeff Kirsher 			smc->e.path_test = PT_PENDING ;
23833f810b2SJeff Kirsher 			GO_STATE(EC3_LEAVE) ;
23933f810b2SJeff Kirsher 			break ;
24033f810b2SJeff Kirsher 		}
24133f810b2SJeff Kirsher 		break ;
24233f810b2SJeff Kirsher 	case ACTIONS(EC3_LEAVE) :
24333f810b2SJeff Kirsher 		start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;
24433f810b2SJeff Kirsher 		for (p = 0 ; p < NUMPHYS ; p++)
24533f810b2SJeff Kirsher 			queue_event(smc,EVENT_PCMA+p,PC_STOP) ;
24633f810b2SJeff Kirsher 		ACTIONS_DONE() ;
24733f810b2SJeff Kirsher 		break ;
24833f810b2SJeff Kirsher 	case EC3_LEAVE:
24933f810b2SJeff Kirsher 		/*EC30*/
25033f810b2SJeff Kirsher 		if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&
25133f810b2SJeff Kirsher 			(smc->e.path_test != PT_PENDING)) {
25233f810b2SJeff Kirsher 			GO_STATE(EC0_OUT) ;
25333f810b2SJeff Kirsher 			break ;
25433f810b2SJeff Kirsher 		}
25533f810b2SJeff Kirsher 		/*EC34*/
25633f810b2SJeff Kirsher 		else if (cmd == EC_TIMEOUT_TD &&
25733f810b2SJeff Kirsher 			(smc->e.path_test == PT_PENDING)) {
25833f810b2SJeff Kirsher 			GO_STATE(EC4_PATH_TEST) ;
25933f810b2SJeff Kirsher 			break ;
26033f810b2SJeff Kirsher 		}
26133f810b2SJeff Kirsher 		/*EC31*/
26233f810b2SJeff Kirsher 		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
26333f810b2SJeff Kirsher 			GO_STATE(EC1_IN) ;
26433f810b2SJeff Kirsher 			break ;
26533f810b2SJeff Kirsher 		}
26633f810b2SJeff Kirsher 		/*EC33*/
26733f810b2SJeff Kirsher 		else if (cmd == EC_DISCONNECT &&
26833f810b2SJeff Kirsher 			smc->e.path_test == PT_PENDING) {
26933f810b2SJeff Kirsher 			smc->e.path_test = PT_EXITING ;
27033f810b2SJeff Kirsher 			/*
27133f810b2SJeff Kirsher 			 * stay in state - state will be left via timeout
27233f810b2SJeff Kirsher 			 */
27333f810b2SJeff Kirsher 		}
27433f810b2SJeff Kirsher 		/*EC37*/
27533f810b2SJeff Kirsher 		else if (cmd == EC_TIMEOUT_TD &&
27633f810b2SJeff Kirsher 			smc->mib.fddiSMTBypassPresent &&
27733f810b2SJeff Kirsher 			smc->e.path_test != PT_PENDING) {
27833f810b2SJeff Kirsher 			GO_STATE(EC7_DEINSERT) ;
27933f810b2SJeff Kirsher 			break ;
28033f810b2SJeff Kirsher 		}
28133f810b2SJeff Kirsher 		break ;
28233f810b2SJeff Kirsher 	case ACTIONS(EC4_PATH_TEST) :
28333f810b2SJeff Kirsher 		stop_ecm_timer(smc) ;
28433f810b2SJeff Kirsher 		smc->e.path_test = PT_TESTING ;
28533f810b2SJeff Kirsher 		start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;
28633f810b2SJeff Kirsher 		/* now perform path test ... just a simulation */
28733f810b2SJeff Kirsher 		ACTIONS_DONE() ;
28833f810b2SJeff Kirsher 		break ;
28933f810b2SJeff Kirsher 	case EC4_PATH_TEST :
29033f810b2SJeff Kirsher 		/* path test done delay */
29133f810b2SJeff Kirsher 		if (cmd == EC_TEST_DONE)
29233f810b2SJeff Kirsher 			smc->e.path_test = PT_PASSED ;
29333f810b2SJeff Kirsher 
29433f810b2SJeff Kirsher 		if (smc->e.path_test == PT_FAILED)
29533f810b2SJeff Kirsher 			RS_SET(smc,RS_PATHTEST) ;
29633f810b2SJeff Kirsher 
29733f810b2SJeff Kirsher 		/*EC40a*/
29833f810b2SJeff Kirsher 		if (smc->e.path_test == PT_FAILED &&
29933f810b2SJeff Kirsher 			!smc->mib.fddiSMTBypassPresent) {
30033f810b2SJeff Kirsher 			GO_STATE(EC0_OUT) ;
30133f810b2SJeff Kirsher 			break ;
30233f810b2SJeff Kirsher 		}
30333f810b2SJeff Kirsher 		/*EC40b*/
30433f810b2SJeff Kirsher 		else if (cmd == EC_DISCONNECT &&
30533f810b2SJeff Kirsher 			!smc->mib.fddiSMTBypassPresent) {
30633f810b2SJeff Kirsher 			GO_STATE(EC0_OUT) ;
30733f810b2SJeff Kirsher 			break ;
30833f810b2SJeff Kirsher 		}
30933f810b2SJeff Kirsher 		/*EC41*/
31033f810b2SJeff Kirsher 		else if (smc->e.path_test == PT_PASSED) {
31133f810b2SJeff Kirsher 			GO_STATE(EC1_IN) ;
31233f810b2SJeff Kirsher 			break ;
31333f810b2SJeff Kirsher 		}
31433f810b2SJeff Kirsher 		/*EC47a*/
31533f810b2SJeff Kirsher 		else if (smc->e.path_test == PT_FAILED &&
31633f810b2SJeff Kirsher 			smc->mib.fddiSMTBypassPresent) {
31733f810b2SJeff Kirsher 			GO_STATE(EC7_DEINSERT) ;
31833f810b2SJeff Kirsher 			break ;
31933f810b2SJeff Kirsher 		}
32033f810b2SJeff Kirsher 		/*EC47b*/
32133f810b2SJeff Kirsher 		else if (cmd == EC_DISCONNECT &&
32233f810b2SJeff Kirsher 			smc->mib.fddiSMTBypassPresent) {
32333f810b2SJeff Kirsher 			GO_STATE(EC7_DEINSERT) ;
32433f810b2SJeff Kirsher 			break ;
32533f810b2SJeff Kirsher 		}
32633f810b2SJeff Kirsher 		break ;
32733f810b2SJeff Kirsher 	case ACTIONS(EC5_INSERT) :
32833f810b2SJeff Kirsher 		sm_pm_bypass_req(smc,BP_INSERT);
32933f810b2SJeff Kirsher 		start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;
33033f810b2SJeff Kirsher 		ACTIONS_DONE() ;
33133f810b2SJeff Kirsher 		break ;
33233f810b2SJeff Kirsher 	case EC5_INSERT :
33333f810b2SJeff Kirsher 		/*EC56*/
33433f810b2SJeff Kirsher 		if (cmd == EC_TIMEOUT_INMAX) {
33533f810b2SJeff Kirsher 			GO_STATE(EC6_CHECK) ;
33633f810b2SJeff Kirsher 			break ;
33733f810b2SJeff Kirsher 		}
33833f810b2SJeff Kirsher 		/*EC57*/
33933f810b2SJeff Kirsher 		else if (cmd == EC_DISCONNECT) {
34033f810b2SJeff Kirsher 			GO_STATE(EC7_DEINSERT) ;
34133f810b2SJeff Kirsher 			break ;
34233f810b2SJeff Kirsher 		}
34333f810b2SJeff Kirsher 		break ;
34433f810b2SJeff Kirsher 	case ACTIONS(EC6_CHECK) :
34533f810b2SJeff Kirsher 		/*
34633f810b2SJeff Kirsher 		 * in EC6_CHECK, we *POLL* the line state !
34733f810b2SJeff Kirsher 		 * check whether both bypass switches have switched.
34833f810b2SJeff Kirsher 		 */
34933f810b2SJeff Kirsher 		start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
35033f810b2SJeff Kirsher 		smc->e.ecm_line_state = TRUE ;	/* flag to pcm: report Q/HLS */
35133f810b2SJeff Kirsher 		ACTIONS_DONE() ;
35233f810b2SJeff Kirsher 		break ;
35333f810b2SJeff Kirsher 	case EC6_CHECK :
35433f810b2SJeff Kirsher 		ls_a = sm_pm_get_ls(smc,PA) ;
35533f810b2SJeff Kirsher 		ls_b = sm_pm_get_ls(smc,PB) ;
35633f810b2SJeff Kirsher 
35733f810b2SJeff Kirsher 		/*EC61*/
35833f810b2SJeff Kirsher 		if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&
35933f810b2SJeff Kirsher 		    ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {
36033f810b2SJeff Kirsher 			smc->e.sb_flag = FALSE ;
36133f810b2SJeff Kirsher 			smc->e.ecm_line_state = FALSE ;
36233f810b2SJeff Kirsher 			GO_STATE(EC1_IN) ;
36333f810b2SJeff Kirsher 			break ;
36433f810b2SJeff Kirsher 		}
36533f810b2SJeff Kirsher 		/*EC66*/
36633f810b2SJeff Kirsher 		else if (!smc->e.sb_flag &&
36733f810b2SJeff Kirsher 			 (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||
36833f810b2SJeff Kirsher 			  ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){
36933f810b2SJeff Kirsher 			smc->e.sb_flag = TRUE ;
3705671e8c1SJoe Perches 			DB_ECMN(1, "ECM : EC6_CHECK - stuck bypass");
37133f810b2SJeff Kirsher 			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
37233f810b2SJeff Kirsher 				FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,
37333f810b2SJeff Kirsher 				smt_get_error_word(smc));
37433f810b2SJeff Kirsher 		}
37533f810b2SJeff Kirsher 		/*EC67*/
37633f810b2SJeff Kirsher 		else if (cmd == EC_DISCONNECT) {
37733f810b2SJeff Kirsher 			smc->e.ecm_line_state = FALSE ;
37833f810b2SJeff Kirsher 			GO_STATE(EC7_DEINSERT) ;
37933f810b2SJeff Kirsher 			break ;
38033f810b2SJeff Kirsher 		}
38133f810b2SJeff Kirsher 		else {
38233f810b2SJeff Kirsher 			/*
38333f810b2SJeff Kirsher 			 * restart poll
38433f810b2SJeff Kirsher 			 */
38533f810b2SJeff Kirsher 			start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
38633f810b2SJeff Kirsher 		}
38733f810b2SJeff Kirsher 		break ;
38833f810b2SJeff Kirsher 	case ACTIONS(EC7_DEINSERT) :
38933f810b2SJeff Kirsher 		sm_pm_bypass_req(smc,BP_DEINSERT);
39033f810b2SJeff Kirsher 		start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;
39133f810b2SJeff Kirsher 		ACTIONS_DONE() ;
39233f810b2SJeff Kirsher 		break ;
39333f810b2SJeff Kirsher 	case EC7_DEINSERT:
39433f810b2SJeff Kirsher 		/*EC70*/
39533f810b2SJeff Kirsher 		if (cmd == EC_TIMEOUT_IMAX) {
39633f810b2SJeff Kirsher 			GO_STATE(EC0_OUT) ;
39733f810b2SJeff Kirsher 			break ;
39833f810b2SJeff Kirsher 		}
39933f810b2SJeff Kirsher 		/*EC75*/
40033f810b2SJeff Kirsher 		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
40133f810b2SJeff Kirsher 			GO_STATE(EC5_INSERT) ;
40233f810b2SJeff Kirsher 			break ;
40333f810b2SJeff Kirsher 		}
40433f810b2SJeff Kirsher 		break;
40533f810b2SJeff Kirsher 	default:
40633f810b2SJeff Kirsher 		SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;
40733f810b2SJeff Kirsher 		break;
40833f810b2SJeff Kirsher 	}
40933f810b2SJeff Kirsher }
41033f810b2SJeff Kirsher 
41133f810b2SJeff Kirsher #ifndef	CONCENTRATOR
41233f810b2SJeff Kirsher /*
41333f810b2SJeff Kirsher  * trace propagation actions for SAS & DAS
41433f810b2SJeff Kirsher  */
prop_actions(struct s_smc * smc)41533f810b2SJeff Kirsher static void prop_actions(struct s_smc *smc)
41633f810b2SJeff Kirsher {
41733f810b2SJeff Kirsher 	int	port_in = 0 ;
41833f810b2SJeff Kirsher 	int	port_out = 0 ;
41933f810b2SJeff Kirsher 
42033f810b2SJeff Kirsher 	RS_SET(smc,RS_EVENT) ;
42133f810b2SJeff Kirsher 	switch (smc->s.sas) {
42233f810b2SJeff Kirsher 	case SMT_SAS :
42333f810b2SJeff Kirsher 		port_in = port_out = pcm_get_s_port(smc) ;
42433f810b2SJeff Kirsher 		break ;
42533f810b2SJeff Kirsher 	case SMT_DAS :
42633f810b2SJeff Kirsher 		port_in = cfm_get_mac_input(smc) ;	/* PA or PB */
42733f810b2SJeff Kirsher 		port_out = cfm_get_mac_output(smc) ;	/* PA or PB */
42833f810b2SJeff Kirsher 		break ;
42933f810b2SJeff Kirsher 	case SMT_NAC :
43033f810b2SJeff Kirsher 		SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;
43133f810b2SJeff Kirsher 		return ;
43233f810b2SJeff Kirsher 	}
43333f810b2SJeff Kirsher 
4345671e8c1SJoe Perches 	DB_ECM("ECM : prop_actions - trace_prop %lu", smc->e.trace_prop);
4355671e8c1SJoe Perches 	DB_ECM("ECM : prop_actions - in %d out %d", port_in, port_out);
43633f810b2SJeff Kirsher 
43733f810b2SJeff Kirsher 	if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
43833f810b2SJeff Kirsher 		/* trace initiatior */
4395671e8c1SJoe Perches 		DB_ECM("ECM : initiate TRACE on PHY %c", 'A' + port_in - PA);
44033f810b2SJeff Kirsher 		queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;
44133f810b2SJeff Kirsher 	}
44233f810b2SJeff Kirsher 	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&
44333f810b2SJeff Kirsher 		port_out != PA) {
44433f810b2SJeff Kirsher 		/* trace propagate upstream */
4455671e8c1SJoe Perches 		DB_ECM("ECM : propagate TRACE on PHY B");
44633f810b2SJeff Kirsher 		queue_event(smc,EVENT_PCMB,PC_TRACE) ;
44733f810b2SJeff Kirsher 	}
44833f810b2SJeff Kirsher 	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&
44933f810b2SJeff Kirsher 		port_out != PB) {
45033f810b2SJeff Kirsher 		/* trace propagate upstream */
4515671e8c1SJoe Perches 		DB_ECM("ECM : propagate TRACE on PHY A");
45233f810b2SJeff Kirsher 		queue_event(smc,EVENT_PCMA,PC_TRACE) ;
45333f810b2SJeff Kirsher 	}
45433f810b2SJeff Kirsher 	else {
45533f810b2SJeff Kirsher 		/* signal trace termination */
4565671e8c1SJoe Perches 		DB_ECM("ECM : TRACE terminated");
45733f810b2SJeff Kirsher 		smc->e.path_test = PT_PENDING ;
45833f810b2SJeff Kirsher 	}
45933f810b2SJeff Kirsher 	smc->e.trace_prop = 0 ;
46033f810b2SJeff Kirsher }
46133f810b2SJeff Kirsher #else
46233f810b2SJeff Kirsher /*
46333f810b2SJeff Kirsher  * trace propagation actions for Concentrator
46433f810b2SJeff Kirsher  */
prop_actions(struct s_smc * smc)46533f810b2SJeff Kirsher static void prop_actions(struct s_smc *smc)
46633f810b2SJeff Kirsher {
46733f810b2SJeff Kirsher 	int	initiator ;
46833f810b2SJeff Kirsher 	int	upstream ;
46933f810b2SJeff Kirsher 	int	p ;
47033f810b2SJeff Kirsher 
47133f810b2SJeff Kirsher 	RS_SET(smc,RS_EVENT) ;
47233f810b2SJeff Kirsher 	while (smc->e.trace_prop) {
4735671e8c1SJoe Perches 		DB_ECM("ECM : prop_actions - trace_prop %d",
4745671e8c1SJoe Perches 		       smc->e.trace_prop);
47533f810b2SJeff Kirsher 
47633f810b2SJeff Kirsher 		if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
47733f810b2SJeff Kirsher 			initiator = ENTITY_MAC ;
47833f810b2SJeff Kirsher 			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;
4795671e8c1SJoe Perches 			DB_ECM("ECM: MAC initiates trace");
48033f810b2SJeff Kirsher 		}
48133f810b2SJeff Kirsher 		else {
48233f810b2SJeff Kirsher 			for (p = NUMPHYS-1 ; p >= 0 ; p--) {
48333f810b2SJeff Kirsher 				if (smc->e.trace_prop &
48433f810b2SJeff Kirsher 					ENTITY_BIT(ENTITY_PHY(p)))
48533f810b2SJeff Kirsher 					break ;
48633f810b2SJeff Kirsher 			}
48733f810b2SJeff Kirsher 			initiator = ENTITY_PHY(p) ;
48833f810b2SJeff Kirsher 			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;
48933f810b2SJeff Kirsher 		}
49033f810b2SJeff Kirsher 		upstream = cem_get_upstream(smc,initiator) ;
49133f810b2SJeff Kirsher 
49233f810b2SJeff Kirsher 		if (upstream == ENTITY_MAC) {
49333f810b2SJeff Kirsher 			/* signal trace termination */
4945671e8c1SJoe Perches 			DB_ECM("ECM : TRACE terminated");
49533f810b2SJeff Kirsher 			smc->e.path_test = PT_PENDING ;
49633f810b2SJeff Kirsher 		}
49733f810b2SJeff Kirsher 		else {
49833f810b2SJeff Kirsher 			/* trace propagate upstream */
4995671e8c1SJoe Perches 			DB_ECM("ECM : propagate TRACE on PHY %d", upstream);
50033f810b2SJeff Kirsher 			queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;
50133f810b2SJeff Kirsher 		}
50233f810b2SJeff Kirsher 	}
50333f810b2SJeff Kirsher }
50433f810b2SJeff Kirsher #endif
50533f810b2SJeff Kirsher 
50633f810b2SJeff Kirsher 
50733f810b2SJeff Kirsher /*
50833f810b2SJeff Kirsher  * SMT timer interface
50933f810b2SJeff Kirsher  *	start ECM timer
51033f810b2SJeff Kirsher  */
start_ecm_timer(struct s_smc * smc,u_long value,int event)51133f810b2SJeff Kirsher static void start_ecm_timer(struct s_smc *smc, u_long value, int event)
51233f810b2SJeff Kirsher {
51333f810b2SJeff Kirsher 	smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));
51433f810b2SJeff Kirsher }
51533f810b2SJeff Kirsher 
51633f810b2SJeff Kirsher /*
51733f810b2SJeff Kirsher  * SMT timer interface
51833f810b2SJeff Kirsher  *	stop ECM timer
51933f810b2SJeff Kirsher  */
stop_ecm_timer(struct s_smc * smc)52033f810b2SJeff Kirsher static void stop_ecm_timer(struct s_smc *smc)
52133f810b2SJeff Kirsher {
52233f810b2SJeff Kirsher 	if (smc->e.ecm_timer.tm_active)
52333f810b2SJeff Kirsher 		smt_timer_stop(smc,&smc->e.ecm_timer) ;
52433f810b2SJeff Kirsher }
525