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 44 static 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 */ 58 static 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 */ 67 static 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 */ 74 static 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 */ 97 static void cfm_fsm(struct s_smc *smc, int cmd); 98 99 /* 100 init CFM state machine 101 clear all CFM vars and flags 102 */ 103 void 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 */ 118 static 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 144 void 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 155 static 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 */ 211 void 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*/ 283 static 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 */ 541 int 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 */ 552 int 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 558 static 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 564 static 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 570 static 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 576 static 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 582 static 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 587 static 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 592 int 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