1 /******************************************************************************
3 * (C)Copyright 1998,1999 SysKonnect,
4 * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
6 * See the file "skfddi.c" for further information.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * The information in this file is provided "AS IS" without warranty.
15 ******************************************************************************/
19 Entity Coordination Management
20 Hardware independent state machine
24 * Hardware independent state machine implemantation
25 * The following external SMT functions are referenced :
31 * The following external HW dependent functions are referenced :
35 * The following HW dependent events are required :
45 #include "h/smtstate.h"
48 static const char ID_sccs[] = "@(#)ecm.c 2.7 99/08/05 (C) SK " ;
55 #define GO_STATE(x) (smc->mib.fddiSMTECMState = (x)|AFLAG)
56 #define ACTIONS_DONE() (smc->mib.fddiSMTECMState &= ~AFLAG)
57 #define ACTIONS(x) (x|AFLAG)
59 #define EC0_OUT 0 /* not inserted */
60 #define EC1_IN 1 /* inserted */
61 #define EC2_TRACE 2 /* tracing */
62 #define EC3_LEAVE 3 /* leaving the ring */
63 #define EC4_PATH_TEST 4 /* performing path test */
64 #define EC5_INSERT 5 /* bypass being turned on */
65 #define EC6_CHECK 6 /* checking bypass */
66 #define EC7_DEINSERT 7 /* bypass being turnde off */
69 * symbolic state names
71 static const char * const ecm_states[] = {
72 "EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",
73 "EC5_INSERT","EC6_CHECK","EC7_DEINSERT"
77 * symbolic event names
79 static const char * const ecm_events[] = {
80 "NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",
81 "EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",
82 "EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"
86 * all Globals are defined in smc.h
91 * function declarations
94 static void ecm_fsm(struct s_smc *smc, int cmd);
95 static void start_ecm_timer(struct s_smc *smc, u_long value, int event);
96 static void stop_ecm_timer(struct s_smc *smc);
97 static void prop_actions(struct s_smc *smc);
100 init ECM state machine
101 clear all ECM vars and flags
103 void ecm_init(struct s_smc *smc)
105 smc->e.path_test = PT_PASSED ;
106 smc->e.trace_prop = 0 ;
108 smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;
109 smc->e.ecm_line_state = FALSE ;
121 void ecm(struct s_smc *smc, int event)
126 DB_ECM("ECM : state %s%s event %s",
127 smc->mib.fddiSMTECMState & AFLAG ? "ACTIONS " : "",
128 ecm_states[smc->mib.fddiSMTECMState & ~AFLAG],
130 state = smc->mib.fddiSMTECMState ;
133 } while (state != smc->mib.fddiSMTECMState) ;
134 ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;
140 static void ecm_fsm(struct s_smc *smc, int cmd)
142 int ls_a ; /* current line state PHY A */
143 int ls_b ; /* current line state PHY B */
147 smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;
148 if (cmd == EC_CONNECT)
149 smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
151 /* For AIX event notification: */
152 /* Is a disconnect command remotely issued ? */
153 if (cmd == EC_DISCONNECT &&
154 smc->mib.fddiSMTRemoteDisconnectFlag == TRUE)
155 AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)
156 FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),
157 smt_get_error_word(smc) );
159 /*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/
160 if (cmd == EC_CONNECT) {
161 smc->e.DisconnectFlag = FALSE ;
163 else if (cmd == EC_DISCONNECT) {
164 smc->e.DisconnectFlag = TRUE ;
167 switch(smc->mib.fddiSMTECMState) {
168 case ACTIONS(EC0_OUT) :
170 * We do not perform a path test
172 smc->e.path_test = PT_PASSED ;
173 smc->e.ecm_line_state = FALSE ;
174 stop_ecm_timer(smc) ;
179 if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent
180 && smc->e.path_test==PT_PASSED) {
185 else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&
186 smc->mib.fddiSMTBypassPresent &&
187 (smc->s.sas == SMT_DAS)) {
188 GO_STATE(EC5_INSERT) ;
192 case ACTIONS(EC1_IN) :
193 stop_ecm_timer(smc) ;
194 smc->e.trace_prop = 0 ;
195 sm_ma_control(smc,MA_TREQ) ;
196 for (p = 0 ; p < NUMPHYS ; p++)
197 if (smc->mib.p[p].fddiPORTHardwarePresent)
198 queue_event(smc,EVENT_PCMA+p,PC_START) ;
203 if (cmd == EC_TRACE_PROP) {
205 GO_STATE(EC2_TRACE) ;
209 else if (cmd == EC_DISCONNECT) {
210 GO_STATE(EC3_LEAVE) ;
214 case ACTIONS(EC2_TRACE) :
215 start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),
221 if (cmd == EC_TRACE_PROP) {
223 GO_STATE(EC2_TRACE) ;
227 else if (cmd == EC_DISCONNECT) {
228 smc->e.path_test = PT_EXITING ;
229 GO_STATE(EC3_LEAVE) ;
233 else if (smc->e.path_test == PT_PENDING) {
234 GO_STATE(EC3_LEAVE) ;
238 else if (cmd == EC_TIMEOUT_TMAX) {
239 /* Trace_Max is expired */
240 /* -> send AIX_EVENT */
241 AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
242 (u_long) FDDI_SMT_ERROR, (u_long)
243 FDDI_TRACE_MAX, smt_get_error_word(smc));
244 smc->e.path_test = PT_PENDING ;
245 GO_STATE(EC3_LEAVE) ;
249 case ACTIONS(EC3_LEAVE) :
250 start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;
251 for (p = 0 ; p < NUMPHYS ; p++)
252 queue_event(smc,EVENT_PCMA+p,PC_STOP) ;
257 if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&
258 (smc->e.path_test != PT_PENDING)) {
263 else if (cmd == EC_TIMEOUT_TD &&
264 (smc->e.path_test == PT_PENDING)) {
265 GO_STATE(EC4_PATH_TEST) ;
269 else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
274 else if (cmd == EC_DISCONNECT &&
275 smc->e.path_test == PT_PENDING) {
276 smc->e.path_test = PT_EXITING ;
278 * stay in state - state will be left via timeout
282 else if (cmd == EC_TIMEOUT_TD &&
283 smc->mib.fddiSMTBypassPresent &&
284 smc->e.path_test != PT_PENDING) {
285 GO_STATE(EC7_DEINSERT) ;
289 case ACTIONS(EC4_PATH_TEST) :
290 stop_ecm_timer(smc) ;
291 smc->e.path_test = PT_TESTING ;
292 start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;
293 /* now perform path test ... just a simulation */
297 /* path test done delay */
298 if (cmd == EC_TEST_DONE)
299 smc->e.path_test = PT_PASSED ;
301 if (smc->e.path_test == PT_FAILED)
302 RS_SET(smc,RS_PATHTEST) ;
305 if (smc->e.path_test == PT_FAILED &&
306 !smc->mib.fddiSMTBypassPresent) {
311 else if (cmd == EC_DISCONNECT &&
312 !smc->mib.fddiSMTBypassPresent) {
317 else if (smc->e.path_test == PT_PASSED) {
322 else if (smc->e.path_test == PT_FAILED &&
323 smc->mib.fddiSMTBypassPresent) {
324 GO_STATE(EC7_DEINSERT) ;
328 else if (cmd == EC_DISCONNECT &&
329 smc->mib.fddiSMTBypassPresent) {
330 GO_STATE(EC7_DEINSERT) ;
334 case ACTIONS(EC5_INSERT) :
335 sm_pm_bypass_req(smc,BP_INSERT);
336 start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;
341 if (cmd == EC_TIMEOUT_INMAX) {
342 GO_STATE(EC6_CHECK) ;
346 else if (cmd == EC_DISCONNECT) {
347 GO_STATE(EC7_DEINSERT) ;
351 case ACTIONS(EC6_CHECK) :
353 * in EC6_CHECK, we *POLL* the line state !
354 * check whether both bypass switches have switched.
356 start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
357 smc->e.ecm_line_state = TRUE ; /* flag to pcm: report Q/HLS */
361 ls_a = sm_pm_get_ls(smc,PA) ;
362 ls_b = sm_pm_get_ls(smc,PB) ;
365 if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&
366 ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {
367 smc->e.sb_flag = FALSE ;
368 smc->e.ecm_line_state = FALSE ;
373 else if (!smc->e.sb_flag &&
374 (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||
375 ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){
376 smc->e.sb_flag = TRUE ;
377 DB_ECMN(1, "ECM : EC6_CHECK - stuck bypass");
378 AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
379 FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,
380 smt_get_error_word(smc));
383 else if (cmd == EC_DISCONNECT) {
384 smc->e.ecm_line_state = FALSE ;
385 GO_STATE(EC7_DEINSERT) ;
392 start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
395 case ACTIONS(EC7_DEINSERT) :
396 sm_pm_bypass_req(smc,BP_DEINSERT);
397 start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;
402 if (cmd == EC_TIMEOUT_IMAX) {
407 else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
408 GO_STATE(EC5_INSERT) ;
413 SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;
420 * trace propagation actions for SAS & DAS
422 static void prop_actions(struct s_smc *smc)
427 RS_SET(smc,RS_EVENT) ;
428 switch (smc->s.sas) {
430 port_in = port_out = pcm_get_s_port(smc) ;
433 port_in = cfm_get_mac_input(smc) ; /* PA or PB */
434 port_out = cfm_get_mac_output(smc) ; /* PA or PB */
437 SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;
441 DB_ECM("ECM : prop_actions - trace_prop %lu", smc->e.trace_prop);
442 DB_ECM("ECM : prop_actions - in %d out %d", port_in, port_out);
444 if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
445 /* trace initiatior */
446 DB_ECM("ECM : initiate TRACE on PHY %c", 'A' + port_in - PA);
447 queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;
449 else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&
451 /* trace propagate upstream */
452 DB_ECM("ECM : propagate TRACE on PHY B");
453 queue_event(smc,EVENT_PCMB,PC_TRACE) ;
455 else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&
457 /* trace propagate upstream */
458 DB_ECM("ECM : propagate TRACE on PHY A");
459 queue_event(smc,EVENT_PCMA,PC_TRACE) ;
462 /* signal trace termination */
463 DB_ECM("ECM : TRACE terminated");
464 smc->e.path_test = PT_PENDING ;
466 smc->e.trace_prop = 0 ;
470 * trace propagation actions for Concentrator
472 static void prop_actions(struct s_smc *smc)
478 RS_SET(smc,RS_EVENT) ;
479 while (smc->e.trace_prop) {
480 DB_ECM("ECM : prop_actions - trace_prop %d",
483 if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
484 initiator = ENTITY_MAC ;
485 smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;
486 DB_ECM("ECM: MAC initiates trace");
489 for (p = NUMPHYS-1 ; p >= 0 ; p--) {
490 if (smc->e.trace_prop &
491 ENTITY_BIT(ENTITY_PHY(p)))
494 initiator = ENTITY_PHY(p) ;
495 smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;
497 upstream = cem_get_upstream(smc,initiator) ;
499 if (upstream == ENTITY_MAC) {
500 /* signal trace termination */
501 DB_ECM("ECM : TRACE terminated");
502 smc->e.path_test = PT_PENDING ;
505 /* trace propagate upstream */
506 DB_ECM("ECM : propagate TRACE on PHY %d", upstream);
507 queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;
515 * SMT timer interface
518 static void start_ecm_timer(struct s_smc *smc, u_long value, int event)
520 smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));
524 * SMT timer interface
527 static void stop_ecm_timer(struct s_smc *smc)
529 if (smc->e.ecm_timer.tm_active)
530 smt_timer_stop(smc,&smc->e.ecm_timer) ;