ecm.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:13k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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