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