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