Back to home page

LXR

 
 

    


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