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