0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include "h/types.h"
0037 #include "h/fddi.h"
0038 #include "h/smc.h"
0039
0040 #define KERNEL
0041 #include "h/smtstate.h"
0042
0043
0044
0045
0046 #define AFLAG 0x10
0047 #define GO_STATE(x) (smc->mib.fddiSMTECMState = (x)|AFLAG)
0048 #define ACTIONS_DONE() (smc->mib.fddiSMTECMState &= ~AFLAG)
0049 #define ACTIONS(x) (x|AFLAG)
0050
0051 #define EC0_OUT 0
0052 #define EC1_IN 1
0053 #define EC2_TRACE 2
0054 #define EC3_LEAVE 3
0055 #define EC4_PATH_TEST 4
0056 #define EC5_INSERT 5
0057 #define EC6_CHECK 6
0058 #define EC7_DEINSERT 7
0059
0060
0061
0062
0063 static const char * const ecm_states[] = {
0064 "EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",
0065 "EC5_INSERT","EC6_CHECK","EC7_DEINSERT"
0066 } ;
0067
0068
0069
0070
0071 static const char * const ecm_events[] = {
0072 "NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",
0073 "EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",
0074 "EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"
0075 } ;
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 static void ecm_fsm(struct s_smc *smc, int cmd);
0087 static void start_ecm_timer(struct s_smc *smc, u_long value, int event);
0088 static void stop_ecm_timer(struct s_smc *smc);
0089 static void prop_actions(struct s_smc *smc);
0090
0091
0092
0093
0094
0095 void ecm_init(struct s_smc *smc)
0096 {
0097 smc->e.path_test = PT_PASSED ;
0098 smc->e.trace_prop = 0 ;
0099 smc->e.sb_flag = 0 ;
0100 smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;
0101 smc->e.ecm_line_state = FALSE ;
0102 }
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 void ecm(struct s_smc *smc, int event)
0114 {
0115 int state ;
0116
0117 do {
0118 DB_ECM("ECM : state %s%s event %s",
0119 smc->mib.fddiSMTECMState & AFLAG ? "ACTIONS " : "",
0120 ecm_states[smc->mib.fddiSMTECMState & ~AFLAG],
0121 ecm_events[event]);
0122 state = smc->mib.fddiSMTECMState ;
0123 ecm_fsm(smc,event) ;
0124 event = 0 ;
0125 } while (state != smc->mib.fddiSMTECMState) ;
0126 ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;
0127 }
0128
0129
0130
0131
0132 static void ecm_fsm(struct s_smc *smc, int cmd)
0133 {
0134 int ls_a ;
0135 int ls_b ;
0136 int p ;
0137
0138
0139 smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;
0140 if (cmd == EC_CONNECT)
0141 smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
0142
0143
0144
0145 if (cmd == EC_DISCONNECT &&
0146 smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) {
0147 AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)
0148 FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),
0149 smt_get_error_word(smc) );
0150 }
0151
0152
0153 if (cmd == EC_CONNECT) {
0154 smc->e.DisconnectFlag = FALSE ;
0155 }
0156 else if (cmd == EC_DISCONNECT) {
0157 smc->e.DisconnectFlag = TRUE ;
0158 }
0159
0160 switch(smc->mib.fddiSMTECMState) {
0161 case ACTIONS(EC0_OUT) :
0162
0163
0164
0165 smc->e.path_test = PT_PASSED ;
0166 smc->e.ecm_line_state = FALSE ;
0167 stop_ecm_timer(smc) ;
0168 ACTIONS_DONE() ;
0169 break ;
0170 case EC0_OUT:
0171
0172 if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent
0173 && smc->e.path_test==PT_PASSED) {
0174 GO_STATE(EC1_IN) ;
0175 break ;
0176 }
0177
0178 else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&
0179 smc->mib.fddiSMTBypassPresent &&
0180 (smc->s.sas == SMT_DAS)) {
0181 GO_STATE(EC5_INSERT) ;
0182 break ;
0183 }
0184 break;
0185 case ACTIONS(EC1_IN) :
0186 stop_ecm_timer(smc) ;
0187 smc->e.trace_prop = 0 ;
0188 sm_ma_control(smc,MA_TREQ) ;
0189 for (p = 0 ; p < NUMPHYS ; p++)
0190 if (smc->mib.p[p].fddiPORTHardwarePresent)
0191 queue_event(smc,EVENT_PCMA+p,PC_START) ;
0192 ACTIONS_DONE() ;
0193 break ;
0194 case EC1_IN:
0195
0196 if (cmd == EC_TRACE_PROP) {
0197 prop_actions(smc) ;
0198 GO_STATE(EC2_TRACE) ;
0199 break ;
0200 }
0201
0202 else if (cmd == EC_DISCONNECT) {
0203 GO_STATE(EC3_LEAVE) ;
0204 break ;
0205 }
0206 break;
0207 case ACTIONS(EC2_TRACE) :
0208 start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),
0209 EC_TIMEOUT_TMAX) ;
0210 ACTIONS_DONE() ;
0211 break ;
0212 case EC2_TRACE :
0213
0214 if (cmd == EC_TRACE_PROP) {
0215 prop_actions(smc) ;
0216 GO_STATE(EC2_TRACE) ;
0217 break ;
0218 }
0219
0220 else if (cmd == EC_DISCONNECT) {
0221 smc->e.path_test = PT_EXITING ;
0222 GO_STATE(EC3_LEAVE) ;
0223 break ;
0224 }
0225
0226 else if (smc->e.path_test == PT_PENDING) {
0227 GO_STATE(EC3_LEAVE) ;
0228 break ;
0229 }
0230
0231 else if (cmd == EC_TIMEOUT_TMAX) {
0232
0233
0234 AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
0235 (u_long) FDDI_SMT_ERROR, (u_long)
0236 FDDI_TRACE_MAX, smt_get_error_word(smc));
0237 smc->e.path_test = PT_PENDING ;
0238 GO_STATE(EC3_LEAVE) ;
0239 break ;
0240 }
0241 break ;
0242 case ACTIONS(EC3_LEAVE) :
0243 start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;
0244 for (p = 0 ; p < NUMPHYS ; p++)
0245 queue_event(smc,EVENT_PCMA+p,PC_STOP) ;
0246 ACTIONS_DONE() ;
0247 break ;
0248 case EC3_LEAVE:
0249
0250 if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&
0251 (smc->e.path_test != PT_PENDING)) {
0252 GO_STATE(EC0_OUT) ;
0253 break ;
0254 }
0255
0256 else if (cmd == EC_TIMEOUT_TD &&
0257 (smc->e.path_test == PT_PENDING)) {
0258 GO_STATE(EC4_PATH_TEST) ;
0259 break ;
0260 }
0261
0262 else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
0263 GO_STATE(EC1_IN) ;
0264 break ;
0265 }
0266
0267 else if (cmd == EC_DISCONNECT &&
0268 smc->e.path_test == PT_PENDING) {
0269 smc->e.path_test = PT_EXITING ;
0270
0271
0272
0273 }
0274
0275 else if (cmd == EC_TIMEOUT_TD &&
0276 smc->mib.fddiSMTBypassPresent &&
0277 smc->e.path_test != PT_PENDING) {
0278 GO_STATE(EC7_DEINSERT) ;
0279 break ;
0280 }
0281 break ;
0282 case ACTIONS(EC4_PATH_TEST) :
0283 stop_ecm_timer(smc) ;
0284 smc->e.path_test = PT_TESTING ;
0285 start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;
0286
0287 ACTIONS_DONE() ;
0288 break ;
0289 case EC4_PATH_TEST :
0290
0291 if (cmd == EC_TEST_DONE)
0292 smc->e.path_test = PT_PASSED ;
0293
0294 if (smc->e.path_test == PT_FAILED)
0295 RS_SET(smc,RS_PATHTEST) ;
0296
0297
0298 if (smc->e.path_test == PT_FAILED &&
0299 !smc->mib.fddiSMTBypassPresent) {
0300 GO_STATE(EC0_OUT) ;
0301 break ;
0302 }
0303
0304 else if (cmd == EC_DISCONNECT &&
0305 !smc->mib.fddiSMTBypassPresent) {
0306 GO_STATE(EC0_OUT) ;
0307 break ;
0308 }
0309
0310 else if (smc->e.path_test == PT_PASSED) {
0311 GO_STATE(EC1_IN) ;
0312 break ;
0313 }
0314
0315 else if (smc->e.path_test == PT_FAILED &&
0316 smc->mib.fddiSMTBypassPresent) {
0317 GO_STATE(EC7_DEINSERT) ;
0318 break ;
0319 }
0320
0321 else if (cmd == EC_DISCONNECT &&
0322 smc->mib.fddiSMTBypassPresent) {
0323 GO_STATE(EC7_DEINSERT) ;
0324 break ;
0325 }
0326 break ;
0327 case ACTIONS(EC5_INSERT) :
0328 sm_pm_bypass_req(smc,BP_INSERT);
0329 start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;
0330 ACTIONS_DONE() ;
0331 break ;
0332 case EC5_INSERT :
0333
0334 if (cmd == EC_TIMEOUT_INMAX) {
0335 GO_STATE(EC6_CHECK) ;
0336 break ;
0337 }
0338
0339 else if (cmd == EC_DISCONNECT) {
0340 GO_STATE(EC7_DEINSERT) ;
0341 break ;
0342 }
0343 break ;
0344 case ACTIONS(EC6_CHECK) :
0345
0346
0347
0348
0349 start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
0350 smc->e.ecm_line_state = TRUE ;
0351 ACTIONS_DONE() ;
0352 break ;
0353 case EC6_CHECK :
0354 ls_a = sm_pm_get_ls(smc,PA) ;
0355 ls_b = sm_pm_get_ls(smc,PB) ;
0356
0357
0358 if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&
0359 ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {
0360 smc->e.sb_flag = FALSE ;
0361 smc->e.ecm_line_state = FALSE ;
0362 GO_STATE(EC1_IN) ;
0363 break ;
0364 }
0365
0366 else if (!smc->e.sb_flag &&
0367 (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||
0368 ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){
0369 smc->e.sb_flag = TRUE ;
0370 DB_ECMN(1, "ECM : EC6_CHECK - stuck bypass");
0371 AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
0372 FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,
0373 smt_get_error_word(smc));
0374 }
0375
0376 else if (cmd == EC_DISCONNECT) {
0377 smc->e.ecm_line_state = FALSE ;
0378 GO_STATE(EC7_DEINSERT) ;
0379 break ;
0380 }
0381 else {
0382
0383
0384
0385 start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
0386 }
0387 break ;
0388 case ACTIONS(EC7_DEINSERT) :
0389 sm_pm_bypass_req(smc,BP_DEINSERT);
0390 start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;
0391 ACTIONS_DONE() ;
0392 break ;
0393 case EC7_DEINSERT:
0394
0395 if (cmd == EC_TIMEOUT_IMAX) {
0396 GO_STATE(EC0_OUT) ;
0397 break ;
0398 }
0399
0400 else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
0401 GO_STATE(EC5_INSERT) ;
0402 break ;
0403 }
0404 break;
0405 default:
0406 SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;
0407 break;
0408 }
0409 }
0410
0411 #ifndef CONCENTRATOR
0412
0413
0414
0415 static void prop_actions(struct s_smc *smc)
0416 {
0417 int port_in = 0 ;
0418 int port_out = 0 ;
0419
0420 RS_SET(smc,RS_EVENT) ;
0421 switch (smc->s.sas) {
0422 case SMT_SAS :
0423 port_in = port_out = pcm_get_s_port(smc) ;
0424 break ;
0425 case SMT_DAS :
0426 port_in = cfm_get_mac_input(smc) ;
0427 port_out = cfm_get_mac_output(smc) ;
0428 break ;
0429 case SMT_NAC :
0430 SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;
0431 return ;
0432 }
0433
0434 DB_ECM("ECM : prop_actions - trace_prop %lu", smc->e.trace_prop);
0435 DB_ECM("ECM : prop_actions - in %d out %d", port_in, port_out);
0436
0437 if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
0438
0439 DB_ECM("ECM : initiate TRACE on PHY %c", 'A' + port_in - PA);
0440 queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;
0441 }
0442 else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&
0443 port_out != PA) {
0444
0445 DB_ECM("ECM : propagate TRACE on PHY B");
0446 queue_event(smc,EVENT_PCMB,PC_TRACE) ;
0447 }
0448 else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&
0449 port_out != PB) {
0450
0451 DB_ECM("ECM : propagate TRACE on PHY A");
0452 queue_event(smc,EVENT_PCMA,PC_TRACE) ;
0453 }
0454 else {
0455
0456 DB_ECM("ECM : TRACE terminated");
0457 smc->e.path_test = PT_PENDING ;
0458 }
0459 smc->e.trace_prop = 0 ;
0460 }
0461 #else
0462
0463
0464
0465 static void prop_actions(struct s_smc *smc)
0466 {
0467 int initiator ;
0468 int upstream ;
0469 int p ;
0470
0471 RS_SET(smc,RS_EVENT) ;
0472 while (smc->e.trace_prop) {
0473 DB_ECM("ECM : prop_actions - trace_prop %d",
0474 smc->e.trace_prop);
0475
0476 if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
0477 initiator = ENTITY_MAC ;
0478 smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;
0479 DB_ECM("ECM: MAC initiates trace");
0480 }
0481 else {
0482 for (p = NUMPHYS-1 ; p >= 0 ; p--) {
0483 if (smc->e.trace_prop &
0484 ENTITY_BIT(ENTITY_PHY(p)))
0485 break ;
0486 }
0487 initiator = ENTITY_PHY(p) ;
0488 smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;
0489 }
0490 upstream = cem_get_upstream(smc,initiator) ;
0491
0492 if (upstream == ENTITY_MAC) {
0493
0494 DB_ECM("ECM : TRACE terminated");
0495 smc->e.path_test = PT_PENDING ;
0496 }
0497 else {
0498
0499 DB_ECM("ECM : propagate TRACE on PHY %d", upstream);
0500 queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;
0501 }
0502 }
0503 }
0504 #endif
0505
0506
0507
0508
0509
0510
0511 static void start_ecm_timer(struct s_smc *smc, u_long value, int event)
0512 {
0513 smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));
0514 }
0515
0516
0517
0518
0519
0520 static void stop_ecm_timer(struct s_smc *smc)
0521 {
0522 if (smc->e.ecm_timer.tm_active)
0523 smt_timer_stop(smc,&smc->e.ecm_timer) ;
0524 }