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