162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *	(C)Copyright 1998,1999 SysKonnect,
562306a36Sopenharmony_ci *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *	See the file "skfddi.c" for further information.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *	The information in this file is provided "AS IS" without warranty.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci ******************************************************************************/
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci	SMT ECM
1562306a36Sopenharmony_ci	Entity Coordination Management
1662306a36Sopenharmony_ci	Hardware independent state machine
1762306a36Sopenharmony_ci*/
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * Hardware independent state machine implemantation
2162306a36Sopenharmony_ci * The following external SMT functions are referenced :
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * 		queue_event()
2462306a36Sopenharmony_ci * 		smt_timer_start()
2562306a36Sopenharmony_ci * 		smt_timer_stop()
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * 	The following external HW dependent functions are referenced :
2862306a36Sopenharmony_ci * 		sm_pm_bypass_req()
2962306a36Sopenharmony_ci * 		sm_pm_get_ls()
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * 	The following HW dependent events are required :
3262306a36Sopenharmony_ci *		NONE
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "h/types.h"
3762306a36Sopenharmony_ci#include "h/fddi.h"
3862306a36Sopenharmony_ci#include "h/smc.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define KERNEL
4162306a36Sopenharmony_ci#include "h/smtstate.h"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/*
4462306a36Sopenharmony_ci * FSM Macros
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ci#define AFLAG	0x10
4762306a36Sopenharmony_ci#define GO_STATE(x)	(smc->mib.fddiSMTECMState = (x)|AFLAG)
4862306a36Sopenharmony_ci#define ACTIONS_DONE()	(smc->mib.fddiSMTECMState &= ~AFLAG)
4962306a36Sopenharmony_ci#define ACTIONS(x)	(x|AFLAG)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define EC0_OUT		0			/* not inserted */
5262306a36Sopenharmony_ci#define EC1_IN		1			/* inserted */
5362306a36Sopenharmony_ci#define EC2_TRACE	2			/* tracing */
5462306a36Sopenharmony_ci#define EC3_LEAVE	3			/* leaving the ring */
5562306a36Sopenharmony_ci#define EC4_PATH_TEST	4			/* performing path test */
5662306a36Sopenharmony_ci#define EC5_INSERT	5			/* bypass being turned on */
5762306a36Sopenharmony_ci#define EC6_CHECK	6			/* checking bypass */
5862306a36Sopenharmony_ci#define EC7_DEINSERT	7			/* bypass being turnde off */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/*
6162306a36Sopenharmony_ci * symbolic state names
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistatic const char * const ecm_states[] = {
6462306a36Sopenharmony_ci	"EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",
6562306a36Sopenharmony_ci	"EC5_INSERT","EC6_CHECK","EC7_DEINSERT"
6662306a36Sopenharmony_ci} ;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*
6962306a36Sopenharmony_ci * symbolic event names
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_cistatic const char * const ecm_events[] = {
7262306a36Sopenharmony_ci	"NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",
7362306a36Sopenharmony_ci	"EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",
7462306a36Sopenharmony_ci	"EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"
7562306a36Sopenharmony_ci} ;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * all Globals  are defined in smc.h
7962306a36Sopenharmony_ci * struct s_ecm
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*
8362306a36Sopenharmony_ci * function declarations
8462306a36Sopenharmony_ci */
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic void ecm_fsm(struct s_smc *smc, int cmd);
8762306a36Sopenharmony_cistatic void start_ecm_timer(struct s_smc *smc, u_long value, int event);
8862306a36Sopenharmony_cistatic void stop_ecm_timer(struct s_smc *smc);
8962306a36Sopenharmony_cistatic void prop_actions(struct s_smc *smc);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci	init ECM state machine
9362306a36Sopenharmony_ci	clear all ECM vars and flags
9462306a36Sopenharmony_ci*/
9562306a36Sopenharmony_civoid ecm_init(struct s_smc *smc)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	smc->e.path_test = PT_PASSED ;
9862306a36Sopenharmony_ci	smc->e.trace_prop = 0 ;
9962306a36Sopenharmony_ci	smc->e.sb_flag = 0 ;
10062306a36Sopenharmony_ci	smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;
10162306a36Sopenharmony_ci	smc->e.ecm_line_state = FALSE ;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/*
10562306a36Sopenharmony_ci	ECM state machine
10662306a36Sopenharmony_ci	called by dispatcher
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	do
10962306a36Sopenharmony_ci		display state change
11062306a36Sopenharmony_ci		process event
11162306a36Sopenharmony_ci	until SM is stable
11262306a36Sopenharmony_ci*/
11362306a36Sopenharmony_civoid ecm(struct s_smc *smc, int event)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	int	state ;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	do {
11862306a36Sopenharmony_ci		DB_ECM("ECM : state %s%s event %s",
11962306a36Sopenharmony_ci		       smc->mib.fddiSMTECMState & AFLAG ? "ACTIONS " : "",
12062306a36Sopenharmony_ci		       ecm_states[smc->mib.fddiSMTECMState & ~AFLAG],
12162306a36Sopenharmony_ci		       ecm_events[event]);
12262306a36Sopenharmony_ci		state = smc->mib.fddiSMTECMState ;
12362306a36Sopenharmony_ci		ecm_fsm(smc,event) ;
12462306a36Sopenharmony_ci		event = 0 ;
12562306a36Sopenharmony_ci	} while (state != smc->mib.fddiSMTECMState) ;
12662306a36Sopenharmony_ci	ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/*
13062306a36Sopenharmony_ci	process ECM event
13162306a36Sopenharmony_ci*/
13262306a36Sopenharmony_cistatic void ecm_fsm(struct s_smc *smc, int cmd)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	int ls_a ;			/* current line state PHY A */
13562306a36Sopenharmony_ci	int ls_b ;			/* current line state PHY B */
13662306a36Sopenharmony_ci	int	p ;			/* ports */
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;
14062306a36Sopenharmony_ci	if (cmd == EC_CONNECT)
14162306a36Sopenharmony_ci		smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* For AIX event notification: */
14462306a36Sopenharmony_ci	/* Is a disconnect  command remotely issued ? */
14562306a36Sopenharmony_ci	if (cmd == EC_DISCONNECT &&
14662306a36Sopenharmony_ci	    smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) {
14762306a36Sopenharmony_ci		AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)
14862306a36Sopenharmony_ci			FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),
14962306a36Sopenharmony_ci			smt_get_error_word(smc) );
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/
15362306a36Sopenharmony_ci	if (cmd == EC_CONNECT) {
15462306a36Sopenharmony_ci		smc->e.DisconnectFlag = FALSE ;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	else if (cmd == EC_DISCONNECT) {
15762306a36Sopenharmony_ci		smc->e.DisconnectFlag = TRUE ;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	switch(smc->mib.fddiSMTECMState) {
16162306a36Sopenharmony_ci	case ACTIONS(EC0_OUT) :
16262306a36Sopenharmony_ci		/*
16362306a36Sopenharmony_ci		 * We do not perform a path test
16462306a36Sopenharmony_ci		 */
16562306a36Sopenharmony_ci		smc->e.path_test = PT_PASSED ;
16662306a36Sopenharmony_ci		smc->e.ecm_line_state = FALSE ;
16762306a36Sopenharmony_ci		stop_ecm_timer(smc) ;
16862306a36Sopenharmony_ci		ACTIONS_DONE() ;
16962306a36Sopenharmony_ci		break ;
17062306a36Sopenharmony_ci	case EC0_OUT:
17162306a36Sopenharmony_ci		/*EC01*/
17262306a36Sopenharmony_ci		if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent
17362306a36Sopenharmony_ci			&& smc->e.path_test==PT_PASSED) {
17462306a36Sopenharmony_ci			GO_STATE(EC1_IN) ;
17562306a36Sopenharmony_ci			break ;
17662306a36Sopenharmony_ci		}
17762306a36Sopenharmony_ci		/*EC05*/
17862306a36Sopenharmony_ci		else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&
17962306a36Sopenharmony_ci			smc->mib.fddiSMTBypassPresent &&
18062306a36Sopenharmony_ci			(smc->s.sas == SMT_DAS)) {
18162306a36Sopenharmony_ci			GO_STATE(EC5_INSERT) ;
18262306a36Sopenharmony_ci			break ;
18362306a36Sopenharmony_ci		}
18462306a36Sopenharmony_ci		break;
18562306a36Sopenharmony_ci	case ACTIONS(EC1_IN) :
18662306a36Sopenharmony_ci		stop_ecm_timer(smc) ;
18762306a36Sopenharmony_ci		smc->e.trace_prop = 0 ;
18862306a36Sopenharmony_ci		sm_ma_control(smc,MA_TREQ) ;
18962306a36Sopenharmony_ci		for (p = 0 ; p < NUMPHYS ; p++)
19062306a36Sopenharmony_ci			if (smc->mib.p[p].fddiPORTHardwarePresent)
19162306a36Sopenharmony_ci				queue_event(smc,EVENT_PCMA+p,PC_START) ;
19262306a36Sopenharmony_ci		ACTIONS_DONE() ;
19362306a36Sopenharmony_ci		break ;
19462306a36Sopenharmony_ci	case EC1_IN:
19562306a36Sopenharmony_ci		/*EC12*/
19662306a36Sopenharmony_ci		if (cmd == EC_TRACE_PROP) {
19762306a36Sopenharmony_ci			prop_actions(smc) ;
19862306a36Sopenharmony_ci			GO_STATE(EC2_TRACE) ;
19962306a36Sopenharmony_ci			break ;
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci		/*EC13*/
20262306a36Sopenharmony_ci		else if (cmd == EC_DISCONNECT) {
20362306a36Sopenharmony_ci			GO_STATE(EC3_LEAVE) ;
20462306a36Sopenharmony_ci			break ;
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci		break;
20762306a36Sopenharmony_ci	case ACTIONS(EC2_TRACE) :
20862306a36Sopenharmony_ci		start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),
20962306a36Sopenharmony_ci			EC_TIMEOUT_TMAX) ;
21062306a36Sopenharmony_ci		ACTIONS_DONE() ;
21162306a36Sopenharmony_ci		break ;
21262306a36Sopenharmony_ci	case EC2_TRACE :
21362306a36Sopenharmony_ci		/*EC22*/
21462306a36Sopenharmony_ci		if (cmd == EC_TRACE_PROP) {
21562306a36Sopenharmony_ci			prop_actions(smc) ;
21662306a36Sopenharmony_ci			GO_STATE(EC2_TRACE) ;
21762306a36Sopenharmony_ci			break ;
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci		/*EC23a*/
22062306a36Sopenharmony_ci		else if (cmd == EC_DISCONNECT) {
22162306a36Sopenharmony_ci			smc->e.path_test = PT_EXITING ;
22262306a36Sopenharmony_ci			GO_STATE(EC3_LEAVE) ;
22362306a36Sopenharmony_ci			break ;
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci		/*EC23b*/
22662306a36Sopenharmony_ci		else if (smc->e.path_test == PT_PENDING) {
22762306a36Sopenharmony_ci			GO_STATE(EC3_LEAVE) ;
22862306a36Sopenharmony_ci			break ;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci		/*EC23c*/
23162306a36Sopenharmony_ci		else if (cmd == EC_TIMEOUT_TMAX) {
23262306a36Sopenharmony_ci			/* Trace_Max is expired */
23362306a36Sopenharmony_ci			/* -> send AIX_EVENT */
23462306a36Sopenharmony_ci			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
23562306a36Sopenharmony_ci				(u_long) FDDI_SMT_ERROR, (u_long)
23662306a36Sopenharmony_ci				FDDI_TRACE_MAX, smt_get_error_word(smc));
23762306a36Sopenharmony_ci			smc->e.path_test = PT_PENDING ;
23862306a36Sopenharmony_ci			GO_STATE(EC3_LEAVE) ;
23962306a36Sopenharmony_ci			break ;
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci		break ;
24262306a36Sopenharmony_ci	case ACTIONS(EC3_LEAVE) :
24362306a36Sopenharmony_ci		start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;
24462306a36Sopenharmony_ci		for (p = 0 ; p < NUMPHYS ; p++)
24562306a36Sopenharmony_ci			queue_event(smc,EVENT_PCMA+p,PC_STOP) ;
24662306a36Sopenharmony_ci		ACTIONS_DONE() ;
24762306a36Sopenharmony_ci		break ;
24862306a36Sopenharmony_ci	case EC3_LEAVE:
24962306a36Sopenharmony_ci		/*EC30*/
25062306a36Sopenharmony_ci		if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&
25162306a36Sopenharmony_ci			(smc->e.path_test != PT_PENDING)) {
25262306a36Sopenharmony_ci			GO_STATE(EC0_OUT) ;
25362306a36Sopenharmony_ci			break ;
25462306a36Sopenharmony_ci		}
25562306a36Sopenharmony_ci		/*EC34*/
25662306a36Sopenharmony_ci		else if (cmd == EC_TIMEOUT_TD &&
25762306a36Sopenharmony_ci			(smc->e.path_test == PT_PENDING)) {
25862306a36Sopenharmony_ci			GO_STATE(EC4_PATH_TEST) ;
25962306a36Sopenharmony_ci			break ;
26062306a36Sopenharmony_ci		}
26162306a36Sopenharmony_ci		/*EC31*/
26262306a36Sopenharmony_ci		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
26362306a36Sopenharmony_ci			GO_STATE(EC1_IN) ;
26462306a36Sopenharmony_ci			break ;
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci		/*EC33*/
26762306a36Sopenharmony_ci		else if (cmd == EC_DISCONNECT &&
26862306a36Sopenharmony_ci			smc->e.path_test == PT_PENDING) {
26962306a36Sopenharmony_ci			smc->e.path_test = PT_EXITING ;
27062306a36Sopenharmony_ci			/*
27162306a36Sopenharmony_ci			 * stay in state - state will be left via timeout
27262306a36Sopenharmony_ci			 */
27362306a36Sopenharmony_ci		}
27462306a36Sopenharmony_ci		/*EC37*/
27562306a36Sopenharmony_ci		else if (cmd == EC_TIMEOUT_TD &&
27662306a36Sopenharmony_ci			smc->mib.fddiSMTBypassPresent &&
27762306a36Sopenharmony_ci			smc->e.path_test != PT_PENDING) {
27862306a36Sopenharmony_ci			GO_STATE(EC7_DEINSERT) ;
27962306a36Sopenharmony_ci			break ;
28062306a36Sopenharmony_ci		}
28162306a36Sopenharmony_ci		break ;
28262306a36Sopenharmony_ci	case ACTIONS(EC4_PATH_TEST) :
28362306a36Sopenharmony_ci		stop_ecm_timer(smc) ;
28462306a36Sopenharmony_ci		smc->e.path_test = PT_TESTING ;
28562306a36Sopenharmony_ci		start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;
28662306a36Sopenharmony_ci		/* now perform path test ... just a simulation */
28762306a36Sopenharmony_ci		ACTIONS_DONE() ;
28862306a36Sopenharmony_ci		break ;
28962306a36Sopenharmony_ci	case EC4_PATH_TEST :
29062306a36Sopenharmony_ci		/* path test done delay */
29162306a36Sopenharmony_ci		if (cmd == EC_TEST_DONE)
29262306a36Sopenharmony_ci			smc->e.path_test = PT_PASSED ;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		if (smc->e.path_test == PT_FAILED)
29562306a36Sopenharmony_ci			RS_SET(smc,RS_PATHTEST) ;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		/*EC40a*/
29862306a36Sopenharmony_ci		if (smc->e.path_test == PT_FAILED &&
29962306a36Sopenharmony_ci			!smc->mib.fddiSMTBypassPresent) {
30062306a36Sopenharmony_ci			GO_STATE(EC0_OUT) ;
30162306a36Sopenharmony_ci			break ;
30262306a36Sopenharmony_ci		}
30362306a36Sopenharmony_ci		/*EC40b*/
30462306a36Sopenharmony_ci		else if (cmd == EC_DISCONNECT &&
30562306a36Sopenharmony_ci			!smc->mib.fddiSMTBypassPresent) {
30662306a36Sopenharmony_ci			GO_STATE(EC0_OUT) ;
30762306a36Sopenharmony_ci			break ;
30862306a36Sopenharmony_ci		}
30962306a36Sopenharmony_ci		/*EC41*/
31062306a36Sopenharmony_ci		else if (smc->e.path_test == PT_PASSED) {
31162306a36Sopenharmony_ci			GO_STATE(EC1_IN) ;
31262306a36Sopenharmony_ci			break ;
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci		/*EC47a*/
31562306a36Sopenharmony_ci		else if (smc->e.path_test == PT_FAILED &&
31662306a36Sopenharmony_ci			smc->mib.fddiSMTBypassPresent) {
31762306a36Sopenharmony_ci			GO_STATE(EC7_DEINSERT) ;
31862306a36Sopenharmony_ci			break ;
31962306a36Sopenharmony_ci		}
32062306a36Sopenharmony_ci		/*EC47b*/
32162306a36Sopenharmony_ci		else if (cmd == EC_DISCONNECT &&
32262306a36Sopenharmony_ci			smc->mib.fddiSMTBypassPresent) {
32362306a36Sopenharmony_ci			GO_STATE(EC7_DEINSERT) ;
32462306a36Sopenharmony_ci			break ;
32562306a36Sopenharmony_ci		}
32662306a36Sopenharmony_ci		break ;
32762306a36Sopenharmony_ci	case ACTIONS(EC5_INSERT) :
32862306a36Sopenharmony_ci		sm_pm_bypass_req(smc,BP_INSERT);
32962306a36Sopenharmony_ci		start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;
33062306a36Sopenharmony_ci		ACTIONS_DONE() ;
33162306a36Sopenharmony_ci		break ;
33262306a36Sopenharmony_ci	case EC5_INSERT :
33362306a36Sopenharmony_ci		/*EC56*/
33462306a36Sopenharmony_ci		if (cmd == EC_TIMEOUT_INMAX) {
33562306a36Sopenharmony_ci			GO_STATE(EC6_CHECK) ;
33662306a36Sopenharmony_ci			break ;
33762306a36Sopenharmony_ci		}
33862306a36Sopenharmony_ci		/*EC57*/
33962306a36Sopenharmony_ci		else if (cmd == EC_DISCONNECT) {
34062306a36Sopenharmony_ci			GO_STATE(EC7_DEINSERT) ;
34162306a36Sopenharmony_ci			break ;
34262306a36Sopenharmony_ci		}
34362306a36Sopenharmony_ci		break ;
34462306a36Sopenharmony_ci	case ACTIONS(EC6_CHECK) :
34562306a36Sopenharmony_ci		/*
34662306a36Sopenharmony_ci		 * in EC6_CHECK, we *POLL* the line state !
34762306a36Sopenharmony_ci		 * check whether both bypass switches have switched.
34862306a36Sopenharmony_ci		 */
34962306a36Sopenharmony_ci		start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
35062306a36Sopenharmony_ci		smc->e.ecm_line_state = TRUE ;	/* flag to pcm: report Q/HLS */
35162306a36Sopenharmony_ci		ACTIONS_DONE() ;
35262306a36Sopenharmony_ci		break ;
35362306a36Sopenharmony_ci	case EC6_CHECK :
35462306a36Sopenharmony_ci		ls_a = sm_pm_get_ls(smc,PA) ;
35562306a36Sopenharmony_ci		ls_b = sm_pm_get_ls(smc,PB) ;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		/*EC61*/
35862306a36Sopenharmony_ci		if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&
35962306a36Sopenharmony_ci		    ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {
36062306a36Sopenharmony_ci			smc->e.sb_flag = FALSE ;
36162306a36Sopenharmony_ci			smc->e.ecm_line_state = FALSE ;
36262306a36Sopenharmony_ci			GO_STATE(EC1_IN) ;
36362306a36Sopenharmony_ci			break ;
36462306a36Sopenharmony_ci		}
36562306a36Sopenharmony_ci		/*EC66*/
36662306a36Sopenharmony_ci		else if (!smc->e.sb_flag &&
36762306a36Sopenharmony_ci			 (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||
36862306a36Sopenharmony_ci			  ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){
36962306a36Sopenharmony_ci			smc->e.sb_flag = TRUE ;
37062306a36Sopenharmony_ci			DB_ECMN(1, "ECM : EC6_CHECK - stuck bypass");
37162306a36Sopenharmony_ci			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
37262306a36Sopenharmony_ci				FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,
37362306a36Sopenharmony_ci				smt_get_error_word(smc));
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci		/*EC67*/
37662306a36Sopenharmony_ci		else if (cmd == EC_DISCONNECT) {
37762306a36Sopenharmony_ci			smc->e.ecm_line_state = FALSE ;
37862306a36Sopenharmony_ci			GO_STATE(EC7_DEINSERT) ;
37962306a36Sopenharmony_ci			break ;
38062306a36Sopenharmony_ci		}
38162306a36Sopenharmony_ci		else {
38262306a36Sopenharmony_ci			/*
38362306a36Sopenharmony_ci			 * restart poll
38462306a36Sopenharmony_ci			 */
38562306a36Sopenharmony_ci			start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci		break ;
38862306a36Sopenharmony_ci	case ACTIONS(EC7_DEINSERT) :
38962306a36Sopenharmony_ci		sm_pm_bypass_req(smc,BP_DEINSERT);
39062306a36Sopenharmony_ci		start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;
39162306a36Sopenharmony_ci		ACTIONS_DONE() ;
39262306a36Sopenharmony_ci		break ;
39362306a36Sopenharmony_ci	case EC7_DEINSERT:
39462306a36Sopenharmony_ci		/*EC70*/
39562306a36Sopenharmony_ci		if (cmd == EC_TIMEOUT_IMAX) {
39662306a36Sopenharmony_ci			GO_STATE(EC0_OUT) ;
39762306a36Sopenharmony_ci			break ;
39862306a36Sopenharmony_ci		}
39962306a36Sopenharmony_ci		/*EC75*/
40062306a36Sopenharmony_ci		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
40162306a36Sopenharmony_ci			GO_STATE(EC5_INSERT) ;
40262306a36Sopenharmony_ci			break ;
40362306a36Sopenharmony_ci		}
40462306a36Sopenharmony_ci		break;
40562306a36Sopenharmony_ci	default:
40662306a36Sopenharmony_ci		SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;
40762306a36Sopenharmony_ci		break;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci#ifndef	CONCENTRATOR
41262306a36Sopenharmony_ci/*
41362306a36Sopenharmony_ci * trace propagation actions for SAS & DAS
41462306a36Sopenharmony_ci */
41562306a36Sopenharmony_cistatic void prop_actions(struct s_smc *smc)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	int	port_in = 0 ;
41862306a36Sopenharmony_ci	int	port_out = 0 ;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	RS_SET(smc,RS_EVENT) ;
42162306a36Sopenharmony_ci	switch (smc->s.sas) {
42262306a36Sopenharmony_ci	case SMT_SAS :
42362306a36Sopenharmony_ci		port_in = port_out = pcm_get_s_port(smc) ;
42462306a36Sopenharmony_ci		break ;
42562306a36Sopenharmony_ci	case SMT_DAS :
42662306a36Sopenharmony_ci		port_in = cfm_get_mac_input(smc) ;	/* PA or PB */
42762306a36Sopenharmony_ci		port_out = cfm_get_mac_output(smc) ;	/* PA or PB */
42862306a36Sopenharmony_ci		break ;
42962306a36Sopenharmony_ci	case SMT_NAC :
43062306a36Sopenharmony_ci		SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;
43162306a36Sopenharmony_ci		return ;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	DB_ECM("ECM : prop_actions - trace_prop %lu", smc->e.trace_prop);
43562306a36Sopenharmony_ci	DB_ECM("ECM : prop_actions - in %d out %d", port_in, port_out);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
43862306a36Sopenharmony_ci		/* trace initiatior */
43962306a36Sopenharmony_ci		DB_ECM("ECM : initiate TRACE on PHY %c", 'A' + port_in - PA);
44062306a36Sopenharmony_ci		queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&
44362306a36Sopenharmony_ci		port_out != PA) {
44462306a36Sopenharmony_ci		/* trace propagate upstream */
44562306a36Sopenharmony_ci		DB_ECM("ECM : propagate TRACE on PHY B");
44662306a36Sopenharmony_ci		queue_event(smc,EVENT_PCMB,PC_TRACE) ;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&
44962306a36Sopenharmony_ci		port_out != PB) {
45062306a36Sopenharmony_ci		/* trace propagate upstream */
45162306a36Sopenharmony_ci		DB_ECM("ECM : propagate TRACE on PHY A");
45262306a36Sopenharmony_ci		queue_event(smc,EVENT_PCMA,PC_TRACE) ;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci	else {
45562306a36Sopenharmony_ci		/* signal trace termination */
45662306a36Sopenharmony_ci		DB_ECM("ECM : TRACE terminated");
45762306a36Sopenharmony_ci		smc->e.path_test = PT_PENDING ;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci	smc->e.trace_prop = 0 ;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci#else
46262306a36Sopenharmony_ci/*
46362306a36Sopenharmony_ci * trace propagation actions for Concentrator
46462306a36Sopenharmony_ci */
46562306a36Sopenharmony_cistatic void prop_actions(struct s_smc *smc)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	int	initiator ;
46862306a36Sopenharmony_ci	int	upstream ;
46962306a36Sopenharmony_ci	int	p ;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	RS_SET(smc,RS_EVENT) ;
47262306a36Sopenharmony_ci	while (smc->e.trace_prop) {
47362306a36Sopenharmony_ci		DB_ECM("ECM : prop_actions - trace_prop %d",
47462306a36Sopenharmony_ci		       smc->e.trace_prop);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
47762306a36Sopenharmony_ci			initiator = ENTITY_MAC ;
47862306a36Sopenharmony_ci			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;
47962306a36Sopenharmony_ci			DB_ECM("ECM: MAC initiates trace");
48062306a36Sopenharmony_ci		}
48162306a36Sopenharmony_ci		else {
48262306a36Sopenharmony_ci			for (p = NUMPHYS-1 ; p >= 0 ; p--) {
48362306a36Sopenharmony_ci				if (smc->e.trace_prop &
48462306a36Sopenharmony_ci					ENTITY_BIT(ENTITY_PHY(p)))
48562306a36Sopenharmony_ci					break ;
48662306a36Sopenharmony_ci			}
48762306a36Sopenharmony_ci			initiator = ENTITY_PHY(p) ;
48862306a36Sopenharmony_ci			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;
48962306a36Sopenharmony_ci		}
49062306a36Sopenharmony_ci		upstream = cem_get_upstream(smc,initiator) ;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		if (upstream == ENTITY_MAC) {
49362306a36Sopenharmony_ci			/* signal trace termination */
49462306a36Sopenharmony_ci			DB_ECM("ECM : TRACE terminated");
49562306a36Sopenharmony_ci			smc->e.path_test = PT_PENDING ;
49662306a36Sopenharmony_ci		}
49762306a36Sopenharmony_ci		else {
49862306a36Sopenharmony_ci			/* trace propagate upstream */
49962306a36Sopenharmony_ci			DB_ECM("ECM : propagate TRACE on PHY %d", upstream);
50062306a36Sopenharmony_ci			queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci#endif
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci/*
50862306a36Sopenharmony_ci * SMT timer interface
50962306a36Sopenharmony_ci *	start ECM timer
51062306a36Sopenharmony_ci */
51162306a36Sopenharmony_cistatic void start_ecm_timer(struct s_smc *smc, u_long value, int event)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci/*
51762306a36Sopenharmony_ci * SMT timer interface
51862306a36Sopenharmony_ci *	stop ECM timer
51962306a36Sopenharmony_ci */
52062306a36Sopenharmony_cistatic void stop_ecm_timer(struct s_smc *smc)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	if (smc->e.ecm_timer.tm_active)
52362306a36Sopenharmony_ci		smt_timer_stop(smc,&smc->e.ecm_timer) ;
52462306a36Sopenharmony_ci}
525