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