ecm.c 13 KB

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