cfm.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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 CFM
  14. Configuration Management
  15. DAS with single MAC
  16. */
  17. /*
  18. * Hardware independent state machine implemantation
  19. * The following external SMT functions are referenced :
  20. *
  21. * queue_event()
  22. *
  23. * The following external HW dependent functions are referenced :
  24. * config_mux()
  25. *
  26. * The following HW dependent events are required :
  27. * NONE
  28. */
  29. #include "h/types.h"
  30. #include "h/fddi.h"
  31. #include "h/smc.h"
  32. #define KERNEL
  33. #include "h/smtstate.h"
  34. /*
  35. * FSM Macros
  36. */
  37. #define AFLAG 0x10
  38. #define GO_STATE(x) (smc->mib.fddiSMTCF_State = (x)|AFLAG)
  39. #define ACTIONS_DONE() (smc->mib.fddiSMTCF_State &= ~AFLAG)
  40. #define ACTIONS(x) (x|AFLAG)
  41. /*
  42. * symbolic state names
  43. */
  44. static const char * const cfm_states[] = {
  45. "SC0_ISOLATED","CF1","CF2","CF3","CF4",
  46. "SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S",
  47. "SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A"
  48. } ;
  49. /*
  50. * symbolic event names
  51. */
  52. static const char * const cfm_events[] = {
  53. "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
  54. } ;
  55. /*
  56. * map from state to downstream port type
  57. */
  58. static const unsigned char cf_to_ptype[] = {
  59. TNONE,TNONE,TNONE,TNONE,TNONE,
  60. TNONE,TB,TB,TS,
  61. TA,TB,TS,TB
  62. } ;
  63. /*
  64. * CEM port states
  65. */
  66. #define CEM_PST_DOWN 0
  67. #define CEM_PST_UP 1
  68. #define CEM_PST_HOLD 2
  69. /* define portstate array only for A and B port */
  70. /* Do this within the smc structure (use in multiple cards) */
  71. /*
  72. * all Globals are defined in smc.h
  73. * struct s_cfm
  74. */
  75. /*
  76. * function declarations
  77. */
  78. static void cfm_fsm(struct s_smc *smc, int cmd);
  79. /*
  80. init CFM state machine
  81. clear all CFM vars and flags
  82. */
  83. void cfm_init(struct s_smc *smc)
  84. {
  85. smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ;
  86. smc->r.rm_join = 0 ;
  87. smc->r.rm_loop = 0 ;
  88. smc->y[PA].scrub = 0 ;
  89. smc->y[PB].scrub = 0 ;
  90. smc->y[PA].cem_pst = CEM_PST_DOWN ;
  91. smc->y[PB].cem_pst = CEM_PST_DOWN ;
  92. }
  93. /* Some terms conditions used by the selection criteria */
  94. #define THRU_ENABLED(smc) (smc->y[PA].pc_mode != PM_TREE && \
  95. smc->y[PB].pc_mode != PM_TREE)
  96. /* Selection criteria for the ports */
  97. static void selection_criteria (struct s_smc *smc, struct s_phy *phy)
  98. {
  99. switch (phy->mib->fddiPORTMy_Type) {
  100. case TA:
  101. if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) {
  102. phy->wc_flag = TRUE ;
  103. } else {
  104. phy->wc_flag = FALSE ;
  105. }
  106. break;
  107. case TB:
  108. /* take precedence over PA */
  109. phy->wc_flag = FALSE ;
  110. break;
  111. case TS:
  112. phy->wc_flag = FALSE ;
  113. break;
  114. case TM:
  115. phy->wc_flag = FALSE ;
  116. break;
  117. }
  118. }
  119. void all_selection_criteria(struct s_smc *smc)
  120. {
  121. struct s_phy *phy ;
  122. int p ;
  123. for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) {
  124. /* Do the selection criteria */
  125. selection_criteria (smc,phy);
  126. }
  127. }
  128. static void cem_priv_state(struct s_smc *smc, int event)
  129. /* State machine for private PORT states: used to optimize dual homing */
  130. {
  131. int np; /* Number of the port */
  132. int i;
  133. /* Do this only in a DAS */
  134. if (smc->s.sas != SMT_DAS )
  135. return ;
  136. np = event - CF_JOIN;
  137. if (np != PA && np != PB) {
  138. return ;
  139. }
  140. /* Change the port state according to the event (portnumber) */
  141. if (smc->y[np].cf_join) {
  142. smc->y[np].cem_pst = CEM_PST_UP ;
  143. } else if (!smc->y[np].wc_flag) {
  144. /* set the port to done only if it is not withheld */
  145. smc->y[np].cem_pst = CEM_PST_DOWN ;
  146. }
  147. /* Don't set an hold port to down */
  148. /* Check all ports of restart conditions */
  149. for (i = 0 ; i < 2 ; i ++ ) {
  150. /* Check all port for PORT is on hold and no withhold is done */
  151. if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) {
  152. smc->y[i].cem_pst = CEM_PST_DOWN;
  153. queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
  154. }
  155. if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) {
  156. smc->y[i].cem_pst = CEM_PST_HOLD;
  157. queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
  158. }
  159. if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) {
  160. /*
  161. * The port must be restarted when the wc_flag
  162. * will be reset. So set the port on hold.
  163. */
  164. smc->y[i].cem_pst = CEM_PST_HOLD;
  165. }
  166. }
  167. return ;
  168. }
  169. /*
  170. CFM state machine
  171. called by dispatcher
  172. do
  173. display state change
  174. process event
  175. until SM is stable
  176. */
  177. void cfm(struct s_smc *smc, int event)
  178. {
  179. int state ; /* remember last state */
  180. int cond ;
  181. /* We will do the following: */
  182. /* - compute the variable WC_Flag for every port (This is where */
  183. /* we can extend the requested path checking !!) */
  184. /* - do the old (SMT 6.2 like) state machine */
  185. /* - do the resulting station states */
  186. all_selection_criteria (smc);
  187. /* We will check now whether a state transition is allowed or not */
  188. /* - change the portstates */
  189. cem_priv_state (smc, event);
  190. do {
  191. DB_CFM("CFM : state %s%s event %s",
  192. smc->mib.fddiSMTCF_State & AFLAG ? "ACTIONS " : "",
  193. cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG],
  194. cfm_events[event]);
  195. state = smc->mib.fddiSMTCF_State ;
  196. cfm_fsm(smc,event) ;
  197. event = 0 ;
  198. } while (state != smc->mib.fddiSMTCF_State) ;
  199. #ifndef SLIM_SMT
  200. /*
  201. * check peer wrap condition
  202. */
  203. cond = FALSE ;
  204. if ( (smc->mib.fddiSMTCF_State == SC9_C_WRAP_A &&
  205. smc->y[PA].pc_mode == PM_PEER) ||
  206. (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B &&
  207. smc->y[PB].pc_mode == PM_PEER) ||
  208. (smc->mib.fddiSMTCF_State == SC11_C_WRAP_S &&
  209. smc->y[PS].pc_mode == PM_PEER &&
  210. smc->y[PS].mib->fddiPORTNeighborType != TS ) ) {
  211. cond = TRUE ;
  212. }
  213. if (cond != smc->mib.fddiSMTPeerWrapFlag)
  214. smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ;
  215. /*
  216. * Don't ever send MAC_PATH_CHANGE events. Our MAC is hard-wired
  217. * to the primary path.
  218. */
  219. #endif /* no SLIM_SMT */
  220. /*
  221. * set MAC port type
  222. */
  223. smc->mib.m[MAC0].fddiMACDownstreamPORTType =
  224. cf_to_ptype[smc->mib.fddiSMTCF_State] ;
  225. cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ;
  226. }
  227. /*
  228. process CFM event
  229. */
  230. /*ARGSUSED1*/
  231. static void cfm_fsm(struct s_smc *smc, int cmd)
  232. {
  233. switch(smc->mib.fddiSMTCF_State) {
  234. case ACTIONS(SC0_ISOLATED) :
  235. smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
  236. smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
  237. smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
  238. smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
  239. smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;
  240. config_mux(smc,MUX_ISOLATE) ; /* configure PHY Mux */
  241. smc->r.rm_loop = FALSE ;
  242. smc->r.rm_join = FALSE ;
  243. queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
  244. /* Don't do the WC-Flag changing here */
  245. ACTIONS_DONE() ;
  246. DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
  247. break;
  248. case SC0_ISOLATED :
  249. /*SC07*/
  250. /*SAS port can be PA or PB ! */
  251. if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop ||
  252. smc->y[PB].cf_join || smc->y[PB].cf_loop)) {
  253. GO_STATE(SC11_C_WRAP_S) ;
  254. break ;
  255. }
  256. /*SC01*/
  257. if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join &&
  258. !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) {
  259. GO_STATE(SC9_C_WRAP_A) ;
  260. break ;
  261. }
  262. /*SC02*/
  263. if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join &&
  264. !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) {
  265. GO_STATE(SC10_C_WRAP_B) ;
  266. break ;
  267. }
  268. break ;
  269. case ACTIONS(SC9_C_WRAP_A) :
  270. smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
  271. smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
  272. smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
  273. smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
  274. smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
  275. config_mux(smc,MUX_WRAPA) ; /* configure PHY mux */
  276. if (smc->y[PA].cf_loop) {
  277. smc->r.rm_join = FALSE ;
  278. smc->r.rm_loop = TRUE ;
  279. queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
  280. }
  281. if (smc->y[PA].cf_join) {
  282. smc->r.rm_loop = FALSE ;
  283. smc->r.rm_join = TRUE ;
  284. queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
  285. }
  286. ACTIONS_DONE() ;
  287. DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
  288. break ;
  289. case SC9_C_WRAP_A :
  290. /*SC10*/
  291. if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) &&
  292. !smc->y[PA].cf_loop ) {
  293. GO_STATE(SC0_ISOLATED) ;
  294. break ;
  295. }
  296. /*SC12*/
  297. else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join &&
  298. smc->y[PA].cem_pst == CEM_PST_UP) ||
  299. ((smc->y[PB].cf_loop ||
  300. (smc->y[PB].cf_join &&
  301. smc->y[PB].cem_pst == CEM_PST_UP)) &&
  302. (smc->y[PA].pc_mode == PM_TREE ||
  303. smc->y[PB].pc_mode == PM_TREE))) {
  304. smc->y[PA].scrub = TRUE ;
  305. GO_STATE(SC10_C_WRAP_B) ;
  306. break ;
  307. }
  308. /*SC14*/
  309. else if (!smc->s.attach_s &&
  310. smc->y[PA].cf_join &&
  311. smc->y[PA].cem_pst == CEM_PST_UP &&
  312. smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join &&
  313. smc->y[PB].cem_pst == CEM_PST_UP &&
  314. smc->y[PB].pc_mode == PM_PEER) {
  315. smc->y[PA].scrub = TRUE ;
  316. smc->y[PB].scrub = TRUE ;
  317. GO_STATE(SC4_THRU_A) ;
  318. break ;
  319. }
  320. /*SC15*/
  321. else if ( smc->s.attach_s &&
  322. smc->y[PA].cf_join &&
  323. smc->y[PA].cem_pst == CEM_PST_UP &&
  324. smc->y[PA].pc_mode == PM_PEER &&
  325. smc->y[PB].cf_join &&
  326. smc->y[PB].cem_pst == CEM_PST_UP &&
  327. smc->y[PB].pc_mode == PM_PEER) {
  328. smc->y[PA].scrub = TRUE ;
  329. smc->y[PB].scrub = TRUE ;
  330. GO_STATE(SC5_THRU_B) ;
  331. break ;
  332. }
  333. break ;
  334. case ACTIONS(SC10_C_WRAP_B) :
  335. smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
  336. smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
  337. smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
  338. smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
  339. smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
  340. config_mux(smc,MUX_WRAPB) ; /* configure PHY mux */
  341. if (smc->y[PB].cf_loop) {
  342. smc->r.rm_join = FALSE ;
  343. smc->r.rm_loop = TRUE ;
  344. queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
  345. }
  346. if (smc->y[PB].cf_join) {
  347. smc->r.rm_loop = FALSE ;
  348. smc->r.rm_join = TRUE ;
  349. queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
  350. }
  351. ACTIONS_DONE() ;
  352. DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
  353. break ;
  354. case SC10_C_WRAP_B :
  355. /*SC20*/
  356. if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) {
  357. GO_STATE(SC0_ISOLATED) ;
  358. break ;
  359. }
  360. /*SC21*/
  361. else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER &&
  362. smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
  363. smc->y[PB].scrub = TRUE ;
  364. GO_STATE(SC9_C_WRAP_A) ;
  365. break ;
  366. }
  367. /*SC24*/
  368. else if (!smc->s.attach_s &&
  369. smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
  370. smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
  371. smc->y[PA].scrub = TRUE ;
  372. smc->y[PB].scrub = TRUE ;
  373. GO_STATE(SC4_THRU_A) ;
  374. break ;
  375. }
  376. /*SC25*/
  377. else if ( smc->s.attach_s &&
  378. smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
  379. smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
  380. smc->y[PA].scrub = TRUE ;
  381. smc->y[PB].scrub = TRUE ;
  382. GO_STATE(SC5_THRU_B) ;
  383. break ;
  384. }
  385. break ;
  386. case ACTIONS(SC4_THRU_A) :
  387. smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
  388. smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
  389. smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
  390. smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
  391. smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
  392. config_mux(smc,MUX_THRUA) ; /* configure PHY mux */
  393. smc->r.rm_loop = FALSE ;
  394. smc->r.rm_join = TRUE ;
  395. queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
  396. ACTIONS_DONE() ;
  397. DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
  398. break ;
  399. case SC4_THRU_A :
  400. /*SC41*/
  401. if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) {
  402. smc->y[PA].scrub = TRUE ;
  403. GO_STATE(SC9_C_WRAP_A) ;
  404. break ;
  405. }
  406. /*SC42*/
  407. else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
  408. smc->y[PB].scrub = TRUE ;
  409. GO_STATE(SC10_C_WRAP_B) ;
  410. break ;
  411. }
  412. /*SC45*/
  413. else if (smc->s.attach_s) {
  414. smc->y[PB].scrub = TRUE ;
  415. GO_STATE(SC5_THRU_B) ;
  416. break ;
  417. }
  418. break ;
  419. case ACTIONS(SC5_THRU_B) :
  420. smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
  421. smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
  422. smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
  423. smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
  424. smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
  425. config_mux(smc,MUX_THRUB) ; /* configure PHY mux */
  426. smc->r.rm_loop = FALSE ;
  427. smc->r.rm_join = TRUE ;
  428. queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
  429. ACTIONS_DONE() ;
  430. DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
  431. break ;
  432. case SC5_THRU_B :
  433. /*SC51*/
  434. if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) {
  435. smc->y[PA].scrub = TRUE ;
  436. GO_STATE(SC9_C_WRAP_A) ;
  437. break ;
  438. }
  439. /*SC52*/
  440. else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
  441. smc->y[PB].scrub = TRUE ;
  442. GO_STATE(SC10_C_WRAP_B) ;
  443. break ;
  444. }
  445. /*SC54*/
  446. else if (!smc->s.attach_s) {
  447. smc->y[PA].scrub = TRUE ;
  448. GO_STATE(SC4_THRU_A) ;
  449. break ;
  450. }
  451. break ;
  452. case ACTIONS(SC11_C_WRAP_S) :
  453. smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
  454. smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ;
  455. smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
  456. config_mux(smc,MUX_WRAPS) ; /* configure PHY mux */
  457. if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) {
  458. smc->r.rm_join = FALSE ;
  459. smc->r.rm_loop = TRUE ;
  460. queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
  461. }
  462. if (smc->y[PA].cf_join || smc->y[PB].cf_join) {
  463. smc->r.rm_loop = FALSE ;
  464. smc->r.rm_join = TRUE ;
  465. queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
  466. }
  467. ACTIONS_DONE() ;
  468. DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
  469. break ;
  470. case SC11_C_WRAP_S :
  471. /*SC70*/
  472. if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop &&
  473. !smc->y[PB].cf_join && !smc->y[PB].cf_loop) {
  474. GO_STATE(SC0_ISOLATED) ;
  475. break ;
  476. }
  477. break ;
  478. default:
  479. SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ;
  480. break;
  481. }
  482. }
  483. /*
  484. * get MAC's input Port
  485. * return :
  486. * PA or PB
  487. */
  488. int cfm_get_mac_input(struct s_smc *smc)
  489. {
  490. return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
  491. smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA;
  492. }
  493. /*
  494. * get MAC's output Port
  495. * return :
  496. * PA or PB
  497. */
  498. int cfm_get_mac_output(struct s_smc *smc)
  499. {
  500. return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
  501. smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA;
  502. }
  503. static char path_iso[] = {
  504. 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO,
  505. 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO,
  506. 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO
  507. } ;
  508. static char path_wrap_a[] = {
  509. 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM,
  510. 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM,
  511. 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO
  512. } ;
  513. static char path_wrap_b[] = {
  514. 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM,
  515. 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM,
  516. 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO
  517. } ;
  518. static char path_thru[] = {
  519. 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM,
  520. 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM,
  521. 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM
  522. } ;
  523. static char path_wrap_s[] = {
  524. 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_PRIM,
  525. 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM,
  526. } ;
  527. static char path_iso_s[] = {
  528. 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_ISO,
  529. 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO,
  530. } ;
  531. int cem_build_path(struct s_smc *smc, char *to, int path_index)
  532. {
  533. char *path ;
  534. int len ;
  535. switch (smc->mib.fddiSMTCF_State) {
  536. default :
  537. case SC0_ISOLATED :
  538. path = smc->s.sas ? path_iso_s : path_iso ;
  539. len = smc->s.sas ? sizeof(path_iso_s) : sizeof(path_iso) ;
  540. break ;
  541. case SC9_C_WRAP_A :
  542. path = path_wrap_a ;
  543. len = sizeof(path_wrap_a) ;
  544. break ;
  545. case SC10_C_WRAP_B :
  546. path = path_wrap_b ;
  547. len = sizeof(path_wrap_b) ;
  548. break ;
  549. case SC4_THRU_A :
  550. path = path_thru ;
  551. len = sizeof(path_thru) ;
  552. break ;
  553. case SC11_C_WRAP_S :
  554. path = path_wrap_s ;
  555. len = sizeof(path_wrap_s) ;
  556. break ;
  557. }
  558. memcpy(to,path,len) ;
  559. LINT_USE(path_index);
  560. return len;
  561. }