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