ecm.c 13 KB

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