ecm.c 12 KB

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