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