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