Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /******************************************************************************
0003  *
0004  *  (C)Copyright 1998,1999 SysKonnect,
0005  *  a business unit of Schneider & Koch & Co. Datensysteme GmbH.
0006  *
0007  *  See the file "skfddi.c" for further information.
0008  *
0009  *  The information in this file is provided "AS IS" without warranty.
0010  *
0011  ******************************************************************************/
0012 
0013 /*
0014     SMT CFM
0015     Configuration Management
0016     DAS with single MAC
0017 */
0018 
0019 /*
0020  *  Hardware independent state machine implemantation
0021  *  The following external SMT functions are referenced :
0022  *
0023  *      queue_event()
0024  *
0025  *  The following external HW dependent functions are referenced :
0026  *      config_mux()
0027  *
0028  *  The following HW dependent events are required :
0029  *      NONE 
0030  */
0031 
0032 #include "h/types.h"
0033 #include "h/fddi.h"
0034 #include "h/smc.h"
0035 
0036 #define KERNEL
0037 #include "h/smtstate.h"
0038 
0039 /*
0040  * FSM Macros
0041  */
0042 #define AFLAG   0x10
0043 #define GO_STATE(x) (smc->mib.fddiSMTCF_State = (x)|AFLAG)
0044 #define ACTIONS_DONE()  (smc->mib.fddiSMTCF_State &= ~AFLAG)
0045 #define ACTIONS(x)  (x|AFLAG)
0046 
0047 /*
0048  * symbolic state names
0049  */
0050 static const char * const cfm_states[] = {
0051     "SC0_ISOLATED","CF1","CF2","CF3","CF4",
0052     "SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S",
0053     "SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A"
0054 } ;
0055 
0056 /*
0057  * symbolic event names
0058  */
0059 static const char * const cfm_events[] = {
0060     "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
0061 } ;
0062 
0063 /*
0064  * map from state to downstream port type
0065  */
0066 static const unsigned char cf_to_ptype[] = {
0067     TNONE,TNONE,TNONE,TNONE,TNONE,
0068     TNONE,TB,TB,TS,
0069     TA,TB,TS,TB
0070 } ;
0071 
0072 /*
0073  * CEM port states
0074  */
0075 #define CEM_PST_DOWN    0
0076 #define CEM_PST_UP  1
0077 #define CEM_PST_HOLD    2
0078 /* define portstate array only for A and B port */
0079 /* Do this within the smc structure (use in multiple cards) */
0080 
0081 /*
0082  * all Globals  are defined in smc.h
0083  * struct s_cfm
0084  */
0085 
0086 /*
0087  * function declarations
0088  */
0089 static void cfm_fsm(struct s_smc *smc, int cmd);
0090 
0091 /*
0092     init CFM state machine
0093     clear all CFM vars and flags
0094 */
0095 void cfm_init(struct s_smc *smc)
0096 {
0097     smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ;
0098     smc->r.rm_join = 0 ;
0099     smc->r.rm_loop = 0 ;
0100     smc->y[PA].scrub = 0 ;
0101     smc->y[PB].scrub = 0 ;
0102     smc->y[PA].cem_pst = CEM_PST_DOWN ;
0103     smc->y[PB].cem_pst = CEM_PST_DOWN ;
0104 }
0105 
0106 /* Some terms conditions used by the selection criteria */
0107 #define THRU_ENABLED(smc)   (smc->y[PA].pc_mode != PM_TREE && \
0108                  smc->y[PB].pc_mode != PM_TREE)
0109 /* Selection criteria for the ports */
0110 static void selection_criteria (struct s_smc *smc, struct s_phy *phy)
0111 {
0112 
0113     switch (phy->mib->fddiPORTMy_Type) {
0114     case TA:
0115         if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) {
0116             phy->wc_flag = TRUE ;
0117         } else {
0118             phy->wc_flag = FALSE ;
0119         }
0120 
0121         break;
0122     case TB:
0123         /* take precedence over PA */
0124         phy->wc_flag = FALSE ;
0125         break;
0126     case TS:
0127         phy->wc_flag = FALSE ;
0128         break;
0129     case TM:
0130         phy->wc_flag = FALSE ;
0131         break;
0132     }
0133 
0134 }
0135 
0136 void all_selection_criteria(struct s_smc *smc)
0137 {
0138     struct s_phy    *phy ;
0139     int     p ;
0140 
0141     for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) {
0142         /* Do the selection criteria */
0143         selection_criteria (smc,phy);
0144     }
0145 }
0146 
0147 static void cem_priv_state(struct s_smc *smc, int event)
0148 /* State machine for private PORT states: used to optimize dual homing */
0149 {
0150     int np; /* Number of the port */
0151     int i;
0152 
0153     /* Do this only in a DAS */
0154     if (smc->s.sas != SMT_DAS )
0155         return ;
0156 
0157     np = event - CF_JOIN;
0158 
0159     if (np != PA && np != PB) {
0160         return ;
0161     }
0162     /* Change the port state according to the event (portnumber) */
0163     if (smc->y[np].cf_join) {
0164         smc->y[np].cem_pst = CEM_PST_UP ;
0165     } else if (!smc->y[np].wc_flag) {
0166         /* set the port to done only if it is not withheld */
0167         smc->y[np].cem_pst = CEM_PST_DOWN ;
0168     }
0169 
0170     /* Don't set an hold port to down */
0171 
0172     /* Check all ports of restart conditions */
0173     for (i = 0 ; i < 2 ; i ++ ) {
0174         /* Check all port for PORT is on hold and no withhold is done */
0175         if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) {
0176             smc->y[i].cem_pst = CEM_PST_DOWN;
0177             queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
0178         }
0179         if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) {
0180             smc->y[i].cem_pst = CEM_PST_HOLD;
0181             queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
0182         }
0183         if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) {
0184             /*
0185              * The port must be restarted when the wc_flag
0186              * will be reset. So set the port on hold.
0187              */
0188             smc->y[i].cem_pst = CEM_PST_HOLD;
0189         }
0190     }
0191     return ;
0192 }
0193 
0194 /*
0195     CFM state machine
0196     called by dispatcher
0197 
0198     do
0199         display state change
0200         process event
0201     until SM is stable
0202 */
0203 void cfm(struct s_smc *smc, int event)
0204 {
0205     int state ;     /* remember last state */
0206     int cond ;
0207 
0208     /* We will do the following: */
0209     /*  - compute the variable WC_Flag for every port (This is where */
0210     /*    we can extend the requested path checking !!) */
0211     /*  - do the old (SMT 6.2 like) state machine */
0212     /*  - do the resulting station states */
0213 
0214     all_selection_criteria (smc);
0215 
0216     /* We will check now whether a state transition is allowed or not */
0217     /*  - change the portstates */
0218     cem_priv_state (smc, event);
0219 
0220     do {
0221         DB_CFM("CFM : state %s%s event %s",
0222                smc->mib.fddiSMTCF_State & AFLAG ? "ACTIONS " : "",
0223                cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG],
0224                cfm_events[event]);
0225         state = smc->mib.fddiSMTCF_State ;
0226         cfm_fsm(smc,event) ;
0227         event = 0 ;
0228     } while (state != smc->mib.fddiSMTCF_State) ;
0229 
0230 #ifndef SLIM_SMT
0231     /*
0232      * check peer wrap condition
0233      */
0234     cond = FALSE ;
0235     if (    (smc->mib.fddiSMTCF_State == SC9_C_WRAP_A &&
0236         smc->y[PA].pc_mode == PM_PEER)  ||
0237         (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B &&
0238         smc->y[PB].pc_mode == PM_PEER)  ||
0239         (smc->mib.fddiSMTCF_State == SC11_C_WRAP_S &&
0240         smc->y[PS].pc_mode == PM_PEER &&
0241         smc->y[PS].mib->fddiPORTNeighborType != TS ) ) {
0242             cond = TRUE ;
0243     }
0244     if (cond != smc->mib.fddiSMTPeerWrapFlag)
0245         smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ;
0246 
0247     /*
0248      * Don't ever send MAC_PATH_CHANGE events. Our MAC is hard-wired
0249      * to the primary path.
0250      */
0251 
0252 #endif  /* no SLIM_SMT */
0253 
0254     /*
0255      * set MAC port type
0256      */
0257     smc->mib.m[MAC0].fddiMACDownstreamPORTType =
0258         cf_to_ptype[smc->mib.fddiSMTCF_State] ;
0259     cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ;
0260 }
0261 
0262 /*
0263     process CFM event
0264 */
0265 /*ARGSUSED1*/
0266 static void cfm_fsm(struct s_smc *smc, int cmd)
0267 {
0268     switch(smc->mib.fddiSMTCF_State) {
0269     case ACTIONS(SC0_ISOLATED) :
0270         smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
0271         smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
0272         smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
0273         smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
0274         smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;
0275         config_mux(smc,MUX_ISOLATE) ;   /* configure PHY Mux */
0276         smc->r.rm_loop = FALSE ;
0277         smc->r.rm_join = FALSE ;
0278         queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
0279         /* Don't do the WC-Flag changing here */
0280         ACTIONS_DONE() ;
0281         DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
0282         break;
0283     case SC0_ISOLATED :
0284         /*SC07*/
0285         /*SAS port can be PA or PB ! */
0286         if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop ||
0287                 smc->y[PB].cf_join || smc->y[PB].cf_loop)) {
0288             GO_STATE(SC11_C_WRAP_S) ;
0289             break ;
0290         }
0291         /*SC01*/
0292         if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join &&
0293              !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) {
0294             GO_STATE(SC9_C_WRAP_A) ;
0295             break ;
0296         }
0297         /*SC02*/
0298         if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join &&
0299              !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) {
0300             GO_STATE(SC10_C_WRAP_B) ;
0301             break ;
0302         }
0303         break ;
0304     case ACTIONS(SC9_C_WRAP_A) :
0305         smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
0306         smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
0307         smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
0308         smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
0309         smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
0310         config_mux(smc,MUX_WRAPA) ;     /* configure PHY mux */
0311         if (smc->y[PA].cf_loop) {
0312             smc->r.rm_join = FALSE ;
0313             smc->r.rm_loop = TRUE ;
0314             queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
0315         }
0316         if (smc->y[PA].cf_join) {
0317             smc->r.rm_loop = FALSE ;
0318             smc->r.rm_join = TRUE ;
0319             queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
0320         }
0321         ACTIONS_DONE() ;
0322         DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
0323         break ;
0324     case SC9_C_WRAP_A :
0325         /*SC10*/
0326         if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) &&
0327               !smc->y[PA].cf_loop ) {
0328             GO_STATE(SC0_ISOLATED) ;
0329             break ;
0330         }
0331         /*SC12*/
0332         else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join &&
0333                smc->y[PA].cem_pst == CEM_PST_UP) ||
0334               ((smc->y[PB].cf_loop ||
0335                (smc->y[PB].cf_join &&
0336                 smc->y[PB].cem_pst == CEM_PST_UP)) &&
0337                 (smc->y[PA].pc_mode == PM_TREE ||
0338                  smc->y[PB].pc_mode == PM_TREE))) {
0339             smc->y[PA].scrub = TRUE ;
0340             GO_STATE(SC10_C_WRAP_B) ;
0341             break ;
0342         }
0343         /*SC14*/
0344         else if (!smc->s.attach_s &&
0345               smc->y[PA].cf_join &&
0346               smc->y[PA].cem_pst == CEM_PST_UP &&
0347               smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join &&
0348               smc->y[PB].cem_pst == CEM_PST_UP &&
0349               smc->y[PB].pc_mode == PM_PEER) {
0350             smc->y[PA].scrub = TRUE ;
0351             smc->y[PB].scrub = TRUE ;
0352             GO_STATE(SC4_THRU_A) ;
0353             break ;
0354         }
0355         /*SC15*/
0356         else if ( smc->s.attach_s &&
0357               smc->y[PA].cf_join &&
0358               smc->y[PA].cem_pst == CEM_PST_UP &&
0359               smc->y[PA].pc_mode == PM_PEER &&
0360               smc->y[PB].cf_join &&
0361               smc->y[PB].cem_pst == CEM_PST_UP &&
0362               smc->y[PB].pc_mode == PM_PEER) {
0363             smc->y[PA].scrub = TRUE ;
0364             smc->y[PB].scrub = TRUE ;
0365             GO_STATE(SC5_THRU_B) ;
0366             break ;
0367         }
0368         break ;
0369     case ACTIONS(SC10_C_WRAP_B) :
0370         smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
0371         smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
0372         smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
0373         smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
0374         smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
0375         config_mux(smc,MUX_WRAPB) ;     /* configure PHY mux */
0376         if (smc->y[PB].cf_loop) {
0377             smc->r.rm_join = FALSE ;
0378             smc->r.rm_loop = TRUE ;
0379             queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
0380         }
0381         if (smc->y[PB].cf_join) {
0382             smc->r.rm_loop = FALSE ;
0383             smc->r.rm_join = TRUE ;
0384             queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
0385         }
0386         ACTIONS_DONE() ;
0387         DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
0388         break ;
0389     case SC10_C_WRAP_B :
0390         /*SC20*/
0391         if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) {
0392             GO_STATE(SC0_ISOLATED) ;
0393             break ;
0394         }
0395         /*SC21*/
0396         else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER &&
0397               smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
0398             smc->y[PB].scrub = TRUE ;
0399             GO_STATE(SC9_C_WRAP_A) ;
0400             break ;
0401         }
0402         /*SC24*/
0403         else if (!smc->s.attach_s &&
0404              smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
0405              smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
0406             smc->y[PA].scrub = TRUE ;
0407             smc->y[PB].scrub = TRUE ;
0408             GO_STATE(SC4_THRU_A) ;
0409             break ;
0410         }
0411         /*SC25*/
0412         else if ( smc->s.attach_s &&
0413              smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
0414              smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
0415             smc->y[PA].scrub = TRUE ;
0416             smc->y[PB].scrub = TRUE ;
0417             GO_STATE(SC5_THRU_B) ;
0418             break ;
0419         }
0420         break ;
0421     case ACTIONS(SC4_THRU_A) :
0422         smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
0423         smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
0424         smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
0425         smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
0426         smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
0427         config_mux(smc,MUX_THRUA) ;     /* configure PHY mux */
0428         smc->r.rm_loop = FALSE ;
0429         smc->r.rm_join = TRUE ;
0430         queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
0431         ACTIONS_DONE() ;
0432         DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
0433         break ;
0434     case SC4_THRU_A :
0435         /*SC41*/
0436         if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) {
0437             smc->y[PA].scrub = TRUE ;
0438             GO_STATE(SC9_C_WRAP_A) ;
0439             break ;
0440         }
0441         /*SC42*/
0442         else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
0443             smc->y[PB].scrub = TRUE ;
0444             GO_STATE(SC10_C_WRAP_B) ;
0445             break ;
0446         }
0447         /*SC45*/
0448         else if (smc->s.attach_s) {
0449             smc->y[PB].scrub = TRUE ;
0450             GO_STATE(SC5_THRU_B) ;
0451             break ;
0452         }
0453         break ;
0454     case ACTIONS(SC5_THRU_B) :
0455         smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
0456         smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
0457         smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
0458         smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
0459         smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
0460         config_mux(smc,MUX_THRUB) ;     /* configure PHY mux */
0461         smc->r.rm_loop = FALSE ;
0462         smc->r.rm_join = TRUE ;
0463         queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
0464         ACTIONS_DONE() ;
0465         DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
0466         break ;
0467     case SC5_THRU_B :
0468         /*SC51*/
0469         if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) {
0470             smc->y[PA].scrub = TRUE ;
0471             GO_STATE(SC9_C_WRAP_A) ;
0472             break ;
0473         }
0474         /*SC52*/
0475         else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
0476             smc->y[PB].scrub = TRUE ;
0477             GO_STATE(SC10_C_WRAP_B) ;
0478             break ;
0479         }
0480         /*SC54*/
0481         else if (!smc->s.attach_s) {
0482             smc->y[PA].scrub = TRUE ;
0483             GO_STATE(SC4_THRU_A) ;
0484             break ;
0485         }
0486         break ;
0487     case ACTIONS(SC11_C_WRAP_S) :
0488         smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
0489         smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ;
0490         smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
0491         config_mux(smc,MUX_WRAPS) ;     /* configure PHY mux */
0492         if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) {
0493             smc->r.rm_join = FALSE ;
0494             smc->r.rm_loop = TRUE ;
0495             queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
0496         }
0497         if (smc->y[PA].cf_join || smc->y[PB].cf_join) {
0498             smc->r.rm_loop = FALSE ;
0499             smc->r.rm_join = TRUE ;
0500             queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
0501         }
0502         ACTIONS_DONE() ;
0503         DB_CFMN(1, "CFM : %s", cfm_states[smc->mib.fddiSMTCF_State]);
0504         break ;
0505     case SC11_C_WRAP_S :
0506         /*SC70*/
0507         if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop &&
0508              !smc->y[PB].cf_join && !smc->y[PB].cf_loop) {
0509             GO_STATE(SC0_ISOLATED) ;
0510             break ;
0511         }
0512         break ;
0513     default:
0514         SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ;
0515         break;
0516     }
0517 }
0518 
0519 /*
0520  * get MAC's input Port
0521  *  return :
0522  *      PA or PB
0523  */
0524 int cfm_get_mac_input(struct s_smc *smc)
0525 {
0526     return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
0527         smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA;
0528 }
0529 
0530 /*
0531  * get MAC's output Port
0532  *  return :
0533  *      PA or PB
0534  */
0535 int cfm_get_mac_output(struct s_smc *smc)
0536 {
0537     return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
0538         smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA;
0539 }
0540 
0541 static char path_iso[] = {
0542     0,0,    0,RES_PORT, 0,PA + INDEX_PORT,  0,PATH_ISO,
0543     0,0,    0,RES_MAC,  0,INDEX_MAC,        0,PATH_ISO,
0544     0,0,    0,RES_PORT, 0,PB + INDEX_PORT,  0,PATH_ISO
0545 } ;
0546 
0547 static char path_wrap_a[] = {
0548     0,0,    0,RES_PORT, 0,PA + INDEX_PORT,  0,PATH_PRIM,
0549     0,0,    0,RES_MAC,  0,INDEX_MAC,        0,PATH_PRIM,
0550     0,0,    0,RES_PORT, 0,PB + INDEX_PORT,  0,PATH_ISO
0551 } ;
0552 
0553 static char path_wrap_b[] = {
0554     0,0,    0,RES_PORT, 0,PB + INDEX_PORT,  0,PATH_PRIM,
0555     0,0,    0,RES_MAC,  0,INDEX_MAC,        0,PATH_PRIM,
0556     0,0,    0,RES_PORT, 0,PA + INDEX_PORT,  0,PATH_ISO
0557 } ;
0558 
0559 static char path_thru[] = {
0560     0,0,    0,RES_PORT, 0,PA + INDEX_PORT,  0,PATH_PRIM,
0561     0,0,    0,RES_MAC,  0,INDEX_MAC,        0,PATH_PRIM,
0562     0,0,    0,RES_PORT, 0,PB + INDEX_PORT,  0,PATH_PRIM
0563 } ;
0564 
0565 static char path_wrap_s[] = {
0566     0,0,    0,RES_PORT, 0,PS + INDEX_PORT,  0,PATH_PRIM,
0567     0,0,    0,RES_MAC,  0,INDEX_MAC,        0,PATH_PRIM,
0568 } ;
0569 
0570 static char path_iso_s[] = {
0571     0,0,    0,RES_PORT, 0,PS + INDEX_PORT,  0,PATH_ISO,
0572     0,0,    0,RES_MAC,  0,INDEX_MAC,        0,PATH_ISO,
0573 } ;
0574 
0575 int cem_build_path(struct s_smc *smc, char *to, int path_index)
0576 {
0577     char    *path ;
0578     int len ;
0579 
0580     switch (smc->mib.fddiSMTCF_State) {
0581     default :
0582     case SC0_ISOLATED :
0583         path = smc->s.sas ? path_iso_s : path_iso ;
0584         len = smc->s.sas ? sizeof(path_iso_s) :  sizeof(path_iso) ;
0585         break ;
0586     case SC9_C_WRAP_A :
0587         path = path_wrap_a ;
0588         len = sizeof(path_wrap_a) ;
0589         break ;
0590     case SC10_C_WRAP_B :
0591         path = path_wrap_b ;
0592         len = sizeof(path_wrap_b) ;
0593         break ;
0594     case SC4_THRU_A :
0595         path = path_thru ;
0596         len = sizeof(path_thru) ;
0597         break ;
0598     case SC11_C_WRAP_S :
0599         path = path_wrap_s ;
0600         len = sizeof(path_wrap_s) ;
0601         break ;
0602     }
0603     memcpy(to,path,len) ;
0604 
0605     LINT_USE(path_index);
0606 
0607     return len;
0608 }