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