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 PCM 19 Physical Connection Management 20 */ 21 22 /* 23 * Hardware independent state machine implemantation 24 * The following external SMT functions are referenced : 25 * 26 * queue_event() 27 * smt_timer_start() 28 * smt_timer_stop() 29 * 30 * The following external HW dependent functions are referenced : 31 * sm_pm_control() 32 * sm_ph_linestate() 33 * 34 * The following HW dependent events are required : 35 * PC_QLS 36 * PC_ILS 37 * PC_HLS 38 * PC_MLS 39 * PC_NSE 40 * PC_LEM 41 * 42 */ 43 44 45 #include "h/types.h" 46 #include "h/fddi.h" 47 #include "h/smc.h" 48 #include "h/supern_2.h" 49 #define KERNEL 50 #include "h/smtstate.h" 51 52 #ifndef lint 53 static const char ID_sccs[] = "@(#)pcmplc.c 2.55 99/08/05 (C) SK " ; 54 #endif 55 56 #ifdef FDDI_MIB 57 extern int snmp_fddi_trap( 58 #ifdef ANSIC 59 struct s_smc * smc, int type, int index 60 #endif 61 ); 62 #endif 63 #ifdef CONCENTRATOR 64 extern int plc_is_installed( 65 #ifdef ANSIC 66 struct s_smc *smc , 67 int p 68 #endif 69 ) ; 70 #endif 71 /* 72 * FSM Macros 73 */ 74 #define AFLAG (0x20) 75 #define GO_STATE(x) (mib->fddiPORTPCMState = (x)|AFLAG) 76 #define ACTIONS_DONE() (mib->fddiPORTPCMState &= ~AFLAG) 77 #define ACTIONS(x) (x|AFLAG) 78 79 /* 80 * PCM states 81 */ 82 #define PC0_OFF 0 83 #define PC1_BREAK 1 84 #define PC2_TRACE 2 85 #define PC3_CONNECT 3 86 #define PC4_NEXT 4 87 #define PC5_SIGNAL 5 88 #define PC6_JOIN 6 89 #define PC7_VERIFY 7 90 #define PC8_ACTIVE 8 91 #define PC9_MAINT 9 92 93 /* 94 * symbolic state names 95 */ 96 static const char * const pcm_states[] = { 97 "PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT", 98 "PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT" 99 } ; 100 101 /* 102 * symbolic event names 103 */ 104 static const char * const pcm_events[] = { 105 "NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL", 106 "PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR", 107 "PC_ENABLE","PC_DISABLE", 108 "PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE", 109 "PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN", 110 "PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT", 111 "PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT", 112 "PC_NSE","PC_LEM" 113 } ; 114 115 #ifdef MOT_ELM 116 /* 117 * PCL-S control register 118 * this register in the PLC-S controls the scrambling parameters 119 */ 120 #define PLCS_CONTROL_C_U 0 121 #define PLCS_CONTROL_C_S (PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \ 122 PL_C_CIPHER_ENABLE) 123 #define PLCS_FASSERT_U 0 124 #define PLCS_FASSERT_S 0xFd76 /* 52.0 us */ 125 #define PLCS_FDEASSERT_U 0 126 #define PLCS_FDEASSERT_S 0 127 #else /* nMOT_ELM */ 128 /* 129 * PCL-S control register 130 * this register in the PLC-S controls the scrambling parameters 131 * can be patched for ANSI compliance if standard changes 132 */ 133 static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ; 134 static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ; 135 136 #define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8)) 137 #define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8)) 138 #endif /* nMOT_ELM */ 139 140 /* 141 * external vars 142 */ 143 /* struct definition see 'cmtdef.h' (also used by CFM) */ 144 145 #define PS_OFF 0 146 #define PS_BIT3 1 147 #define PS_BIT4 2 148 #define PS_BIT7 3 149 #define PS_LCT 4 150 #define PS_BIT8 5 151 #define PS_JOIN 6 152 #define PS_ACTIVE 7 153 154 #define LCT_LEM_MAX 255 155 156 /* 157 * PLC timing parameter 158 */ 159 160 #define PLC_MS(m) ((int)((0x10000L-(m*100000L/2048)))) 161 #define SLOW_TL_MIN PLC_MS(6) 162 #define SLOW_C_MIN PLC_MS(10) 163 164 static const struct plt { 165 int timer ; /* relative plc timer address */ 166 int para ; /* default timing parameters */ 167 } pltm[] = { 168 { PL_C_MIN, SLOW_C_MIN }, /* min t. to remain Connect State */ 169 { PL_TL_MIN, SLOW_TL_MIN }, /* min t. to transmit a Line State */ 170 { PL_TB_MIN, TP_TB_MIN }, /* min break time */ 171 { PL_T_OUT, TP_T_OUT }, /* Signaling timeout */ 172 { PL_LC_LENGTH, TP_LC_LENGTH }, /* Link Confidence Test Time */ 173 { PL_T_SCRUB, TP_T_SCRUB }, /* Scrub Time == MAC TVX time ! */ 174 { PL_NS_MAX, TP_NS_MAX }, /* max t. that noise is tolerated */ 175 { 0,0 } 176 } ; 177 178 /* 179 * interrupt mask 180 */ 181 #ifdef SUPERNET_3 182 /* 183 * Do we need the EBUF error during signaling, too, to detect SUPERNET_3 184 * PLL bug? 185 */ 186 static const int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | 187 PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; 188 #else /* SUPERNET_3 */ 189 /* 190 * We do NOT need the elasticity buffer error during signaling. 191 */ 192 static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | 193 PL_PCM_ENABLED | PL_SELF_TEST ; 194 #endif /* SUPERNET_3 */ 195 static const int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | 196 PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; 197 198 /* internal functions */ 199 static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd); 200 static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy); 201 static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy); 202 static void reset_lem_struct(struct s_phy *phy); 203 static void plc_init(struct s_smc *smc, int p); 204 static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold); 205 static void sm_ph_lem_stop(struct s_smc *smc, int np); 206 static void sm_ph_linestate(struct s_smc *smc, int phy, int ls); 207 static void real_init_plc(struct s_smc *smc); 208 209 /* 210 * SMT timer interface 211 * start PCM timer 0 212 */ 213 static void start_pcm_timer0(struct s_smc *smc, u_long value, int event, 214 struct s_phy *phy) 215 { 216 phy->timer0_exp = FALSE ; /* clear timer event flag */ 217 smt_timer_start(smc,&phy->pcm_timer0,value, 218 EV_TOKEN(EVENT_PCM+phy->np,event)) ; 219 } 220 /* 221 * SMT timer interface 222 * stop PCM timer 0 223 */ 224 static void stop_pcm_timer0(struct s_smc *smc, struct s_phy *phy) 225 { 226 if (phy->pcm_timer0.tm_active) 227 smt_timer_stop(smc,&phy->pcm_timer0) ; 228 } 229 230 /* 231 init PCM state machine (called by driver) 232 clear all PCM vars and flags 233 */ 234 void pcm_init(struct s_smc *smc) 235 { 236 int i ; 237 int np ; 238 struct s_phy *phy ; 239 struct fddi_mib_p *mib ; 240 241 for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) { 242 /* Indicates the type of PHY being used */ 243 mib = phy->mib ; 244 mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ; 245 phy->np = np ; 246 switch (smc->s.sas) { 247 #ifdef CONCENTRATOR 248 case SMT_SAS : 249 mib->fddiPORTMy_Type = (np == PS) ? TS : TM ; 250 break ; 251 case SMT_DAS : 252 mib->fddiPORTMy_Type = (np == PA) ? TA : 253 (np == PB) ? TB : TM ; 254 break ; 255 case SMT_NAC : 256 mib->fddiPORTMy_Type = TM ; 257 break; 258 #else 259 case SMT_SAS : 260 mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ; 261 mib->fddiPORTHardwarePresent = (np == PS) ? TRUE : 262 FALSE ; 263 #ifndef SUPERNET_3 264 smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ; 265 #else 266 smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ; 267 #endif 268 break ; 269 case SMT_DAS : 270 mib->fddiPORTMy_Type = (np == PB) ? TB : TA ; 271 break ; 272 #endif 273 } 274 /* 275 * set PMD-type 276 */ 277 phy->pmd_scramble = 0 ; 278 switch (phy->pmd_type[PMD_SK_PMD]) { 279 case 'P' : 280 mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; 281 break ; 282 case 'L' : 283 mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ; 284 break ; 285 case 'D' : 286 mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; 287 break ; 288 case 'S' : 289 mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; 290 phy->pmd_scramble = TRUE ; 291 break ; 292 case 'U' : 293 mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; 294 phy->pmd_scramble = TRUE ; 295 break ; 296 case '1' : 297 mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; 298 break ; 299 case '2' : 300 mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; 301 break ; 302 case '3' : 303 mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; 304 break ; 305 case '4' : 306 mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; 307 break ; 308 case 'H' : 309 mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; 310 break ; 311 case 'I' : 312 mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; 313 break ; 314 case 'G' : 315 mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; 316 break ; 317 default: 318 mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; 319 break ; 320 } 321 /* 322 * A and B port can be on primary and secondary path 323 */ 324 switch (mib->fddiPORTMy_Type) { 325 case TA : 326 mib->fddiPORTAvailablePaths |= MIB_PATH_S ; 327 mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; 328 mib->fddiPORTRequestedPaths[2] = 329 MIB_P_PATH_LOCAL | 330 MIB_P_PATH_CON_ALTER | 331 MIB_P_PATH_SEC_PREFER ; 332 mib->fddiPORTRequestedPaths[3] = 333 MIB_P_PATH_LOCAL | 334 MIB_P_PATH_CON_ALTER | 335 MIB_P_PATH_SEC_PREFER | 336 MIB_P_PATH_THRU ; 337 break ; 338 case TB : 339 mib->fddiPORTAvailablePaths |= MIB_PATH_S ; 340 mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; 341 mib->fddiPORTRequestedPaths[2] = 342 MIB_P_PATH_LOCAL | 343 MIB_P_PATH_PRIM_PREFER ; 344 mib->fddiPORTRequestedPaths[3] = 345 MIB_P_PATH_LOCAL | 346 MIB_P_PATH_PRIM_PREFER | 347 MIB_P_PATH_CON_PREFER | 348 MIB_P_PATH_THRU ; 349 break ; 350 case TS : 351 mib->fddiPORTAvailablePaths |= MIB_PATH_S ; 352 mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; 353 mib->fddiPORTRequestedPaths[2] = 354 MIB_P_PATH_LOCAL | 355 MIB_P_PATH_CON_ALTER | 356 MIB_P_PATH_PRIM_PREFER ; 357 mib->fddiPORTRequestedPaths[3] = 358 MIB_P_PATH_LOCAL | 359 MIB_P_PATH_CON_ALTER | 360 MIB_P_PATH_PRIM_PREFER ; 361 break ; 362 case TM : 363 mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; 364 mib->fddiPORTRequestedPaths[2] = 365 MIB_P_PATH_LOCAL | 366 MIB_P_PATH_SEC_ALTER | 367 MIB_P_PATH_PRIM_ALTER ; 368 mib->fddiPORTRequestedPaths[3] = 0 ; 369 break ; 370 } 371 372 phy->pc_lem_fail = FALSE ; 373 mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ; 374 mib->fddiPORTLCTFail_Ct = 0 ; 375 mib->fddiPORTBS_Flag = 0 ; 376 mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ; 377 mib->fddiPORTNeighborType = TNONE ; 378 phy->ls_flag = 0 ; 379 phy->rc_flag = 0 ; 380 phy->tc_flag = 0 ; 381 phy->td_flag = 0 ; 382 if (np >= PM) 383 phy->phy_name = '0' + np - PM ; 384 else 385 phy->phy_name = 'A' + np ; 386 phy->wc_flag = FALSE ; /* set by SMT */ 387 memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ; 388 reset_lem_struct(phy) ; 389 memset((char *)&phy->plc,0,sizeof(struct s_plc)) ; 390 phy->plc.p_state = PS_OFF ; 391 for (i = 0 ; i < NUMBITS ; i++) { 392 phy->t_next[i] = 0 ; 393 } 394 } 395 real_init_plc(smc) ; 396 } 397 398 void init_plc(struct s_smc *smc) 399 { 400 SK_UNUSED(smc) ; 401 402 /* 403 * dummy 404 * this is an obsolete public entry point that has to remain 405 * for compat. It is used by various drivers. 406 * the work is now done in real_init_plc() 407 * which is called from pcm_init() ; 408 */ 409 } 410 411 static void real_init_plc(struct s_smc *smc) 412 { 413 int p ; 414 415 for (p = 0 ; p < NUMPHYS ; p++) 416 plc_init(smc,p) ; 417 } 418 419 static void plc_init(struct s_smc *smc, int p) 420 { 421 int i ; 422 #ifndef MOT_ELM 423 int rev ; /* Revision of PLC-x */ 424 #endif /* MOT_ELM */ 425 426 /* transit PCM state machine to MAINT state */ 427 outpw(PLC(p,PL_CNTRL_B),0) ; 428 outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ; 429 outpw(PLC(p,PL_CNTRL_A),0) ; 430 431 /* 432 * if PLC-S then set control register C 433 */ 434 #ifndef MOT_ELM 435 rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ; 436 if (rev != PLC_REVISION_A) 437 #endif /* MOT_ELM */ 438 { 439 if (smc->y[p].pmd_scramble) { 440 outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ; 441 #ifdef MOT_ELM 442 outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ; 443 outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ; 444 #endif /* MOT_ELM */ 445 } 446 else { 447 outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ; 448 #ifdef MOT_ELM 449 outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ; 450 outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ; 451 #endif /* MOT_ELM */ 452 } 453 } 454 455 /* 456 * set timer register 457 */ 458 for ( i = 0 ; pltm[i].timer; i++) /* set timer parameter reg */ 459 outpw(PLC(p,pltm[i].timer),pltm[i].para) ; 460 461 (void)inpw(PLC(p,PL_INTR_EVENT)) ; /* clear interrupt event reg */ 462 plc_clear_irq(smc,p) ; 463 outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */ 464 465 /* 466 * if PCM is configured for class s, it will NOT go to the 467 * REMOVE state if offline (page 3-36;) 468 * in the concentrator, all inactive PHYS always must be in 469 * the remove state 470 * there's no real need to use this feature at all .. 471 */ 472 #ifndef CONCENTRATOR 473 if ((smc->s.sas == SMT_SAS) && (p == PS)) { 474 outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ; 475 } 476 #endif 477 } 478 479 /* 480 * control PCM state machine 481 */ 482 static void plc_go_state(struct s_smc *smc, int p, int state) 483 { 484 HW_PTR port ; 485 int val ; 486 487 SK_UNUSED(smc) ; 488 489 port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ; 490 val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ; 491 outpw(port,val) ; 492 outpw(port,val | state) ; 493 } 494 495 /* 496 * read current line state (called by ECM & PCM) 497 */ 498 int sm_pm_get_ls(struct s_smc *smc, int phy) 499 { 500 int state ; 501 502 #ifdef CONCENTRATOR 503 if (!plc_is_installed(smc,phy)) 504 return PC_QLS; 505 #endif 506 507 state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ; 508 switch(state) { 509 case PL_L_QLS: 510 state = PC_QLS ; 511 break ; 512 case PL_L_MLS: 513 state = PC_MLS ; 514 break ; 515 case PL_L_HLS: 516 state = PC_HLS ; 517 break ; 518 case PL_L_ILS4: 519 case PL_L_ILS16: 520 state = PC_ILS ; 521 break ; 522 case PL_L_ALS: 523 state = PC_LS_PDR ; 524 break ; 525 default : 526 state = PC_LS_NONE ; 527 } 528 return state; 529 } 530 531 static int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len) 532 { 533 int np = phy->np ; /* PHY index */ 534 int n ; 535 int i ; 536 537 SK_UNUSED(smc) ; 538 539 /* create bit vector */ 540 for (i = len-1,n = 0 ; i >= 0 ; i--) { 541 n = (n<<1) | phy->t_val[phy->bitn+i] ; 542 } 543 if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { 544 #if 0 545 printf("PL_PCM_SIGNAL is set\n") ; 546 #endif 547 return 1; 548 } 549 /* write bit[n] & length = 1 to regs */ 550 outpw(PLC(np,PL_VECTOR_LEN),len-1) ; /* len=nr-1 */ 551 outpw(PLC(np,PL_XMIT_VECTOR),n) ; 552 #ifdef DEBUG 553 #if 1 554 #ifdef DEBUG_BRD 555 if (smc->debug.d_plc & 0x80) 556 #else 557 if (debug.d_plc & 0x80) 558 #endif 559 printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ; 560 #endif 561 #endif 562 return 0; 563 } 564 565 /* 566 * config plc muxes 567 */ 568 void plc_config_mux(struct s_smc *smc, int mux) 569 { 570 if (smc->s.sas != SMT_DAS) 571 return ; 572 if (mux == MUX_WRAPB) { 573 SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; 574 SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; 575 } 576 else { 577 CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ; 578 CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ; 579 } 580 CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ; 581 CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ; 582 } 583 584 /* 585 PCM state machine 586 called by dispatcher & fddi_init() (driver) 587 do 588 display state change 589 process event 590 until SM is stable 591 */ 592 void pcm(struct s_smc *smc, const int np, int event) 593 { 594 int state ; 595 int oldstate ; 596 struct s_phy *phy ; 597 struct fddi_mib_p *mib ; 598 599 #ifndef CONCENTRATOR 600 /* 601 * ignore 2nd PHY if SAS 602 */ 603 if ((np != PS) && (smc->s.sas == SMT_SAS)) 604 return ; 605 #endif 606 phy = &smc->y[np] ; 607 mib = phy->mib ; 608 oldstate = mib->fddiPORTPCMState ; 609 do { 610 DB_PCM("PCM %c: state %s%s, event %s", 611 phy->phy_name, 612 mib->fddiPORTPCMState & AFLAG ? "ACTIONS " : "", 613 pcm_states[mib->fddiPORTPCMState & ~AFLAG], 614 pcm_events[event]); 615 state = mib->fddiPORTPCMState ; 616 pcm_fsm(smc,phy,event) ; 617 event = 0 ; 618 } while (state != mib->fddiPORTPCMState) ; 619 /* 620 * because the PLC does the bit signaling for us, 621 * we're always in SIGNAL state 622 * the MIB want's to see CONNECT 623 * we therefore fake an entry in the MIB 624 */ 625 if (state == PC5_SIGNAL) 626 mib->fddiPORTPCMStateX = PC3_CONNECT ; 627 else 628 mib->fddiPORTPCMStateX = state ; 629 630 #ifndef SLIM_SMT 631 /* 632 * path change 633 */ 634 if ( mib->fddiPORTPCMState != oldstate && 635 ((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) { 636 smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE, 637 (int) (INDEX_PORT+ phy->np),0) ; 638 } 639 #endif 640 641 #ifdef FDDI_MIB 642 /* check whether a snmp-trap has to be sent */ 643 644 if ( mib->fddiPORTPCMState != oldstate ) { 645 /* a real state change took place */ 646 DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState); 647 if ( mib->fddiPORTPCMState == PC0_OFF ) { 648 /* send first trap */ 649 snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex ); 650 } else if ( oldstate == PC0_OFF ) { 651 /* send second trap */ 652 snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex ); 653 } else if ( mib->fddiPORTPCMState != PC2_TRACE && 654 oldstate == PC8_ACTIVE ) { 655 /* send third trap */ 656 snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex ); 657 } else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) { 658 /* send fourth trap */ 659 snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex ); 660 } 661 } 662 #endif 663 664 pcm_state_change(smc,np,state) ; 665 } 666 667 /* 668 * PCM state machine 669 */ 670 static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd) 671 { 672 int i ; 673 int np = phy->np ; /* PHY index */ 674 struct s_plc *plc ; 675 struct fddi_mib_p *mib ; 676 #ifndef MOT_ELM 677 u_short plc_rev ; /* Revision of the plc */ 678 #endif /* nMOT_ELM */ 679 680 plc = &phy->plc ; 681 mib = phy->mib ; 682 683 /* 684 * general transitions independent of state 685 */ 686 switch (cmd) { 687 case PC_STOP : 688 /*PC00-PC80*/ 689 if (mib->fddiPORTPCMState != PC9_MAINT) { 690 GO_STATE(PC0_OFF) ; 691 AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) 692 FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP, 693 smt_get_port_event_word(smc)); 694 } 695 return ; 696 case PC_START : 697 /*PC01-PC81*/ 698 if (mib->fddiPORTPCMState != PC9_MAINT) 699 GO_STATE(PC1_BREAK) ; 700 return ; 701 case PC_DISABLE : 702 /* PC09-PC99 */ 703 GO_STATE(PC9_MAINT) ; 704 AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) 705 FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED, 706 smt_get_port_event_word(smc)); 707 return ; 708 case PC_TIMEOUT_LCT : 709 /* if long or extended LCT */ 710 stop_pcm_timer0(smc,phy) ; 711 CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; 712 /* end of LCT is indicate by PCM_CODE (initiate PCM event) */ 713 return ; 714 } 715 716 switch(mib->fddiPORTPCMState) { 717 case ACTIONS(PC0_OFF) : 718 stop_pcm_timer0(smc,phy) ; 719 outpw(PLC(np,PL_CNTRL_A),0) ; 720 CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; 721 CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; 722 sm_ph_lem_stop(smc,np) ; /* disable LEM */ 723 phy->cf_loop = FALSE ; 724 phy->cf_join = FALSE ; 725 queue_event(smc,EVENT_CFM,CF_JOIN+np) ; 726 plc_go_state(smc,np,PL_PCM_STOP) ; 727 mib->fddiPORTConnectState = PCM_DISABLED ; 728 ACTIONS_DONE() ; 729 break ; 730 case PC0_OFF: 731 /*PC09*/ 732 if (cmd == PC_MAINT) { 733 GO_STATE(PC9_MAINT) ; 734 break ; 735 } 736 break ; 737 case ACTIONS(PC1_BREAK) : 738 /* Stop the LCT timer if we came from Signal state */ 739 stop_pcm_timer0(smc,phy) ; 740 ACTIONS_DONE() ; 741 plc_go_state(smc,np,0) ; 742 CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; 743 CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; 744 sm_ph_lem_stop(smc,np) ; /* disable LEM */ 745 /* 746 * if vector is already loaded, go to OFF to clear PCM_SIGNAL 747 */ 748 #if 0 749 if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { 750 plc_go_state(smc,np,PL_PCM_STOP) ; 751 /* TB_MIN ? */ 752 } 753 #endif 754 /* 755 * Go to OFF state in any case. 756 */ 757 plc_go_state(smc,np,PL_PCM_STOP) ; 758 759 if (mib->fddiPORTPC_Withhold == PC_WH_NONE) 760 mib->fddiPORTConnectState = PCM_CONNECTING ; 761 phy->cf_loop = FALSE ; 762 phy->cf_join = FALSE ; 763 queue_event(smc,EVENT_CFM,CF_JOIN+np) ; 764 phy->ls_flag = FALSE ; 765 phy->pc_mode = PM_NONE ; /* needed by CFM */ 766 phy->bitn = 0 ; /* bit signaling start bit */ 767 for (i = 0 ; i < 3 ; i++) 768 pc_tcode_actions(smc,i,phy) ; 769 770 /* Set the non-active interrupt mask register */ 771 outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ; 772 773 /* 774 * If the LCT was stopped. There might be a 775 * PCM_CODE interrupt event present. 776 * This must be cleared. 777 */ 778 (void)inpw(PLC(np,PL_INTR_EVENT)) ; 779 #ifndef MOT_ELM 780 /* Get the plc revision for revision dependent code */ 781 plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ; 782 783 if (plc_rev != PLC_REV_SN3) 784 #endif /* MOT_ELM */ 785 { 786 /* 787 * No supernet III PLC, so set Xmit verctor and 788 * length BEFORE starting the state machine. 789 */ 790 if (plc_send_bits(smc,phy,3)) { 791 return ; 792 } 793 } 794 795 /* 796 * Now give the Start command. 797 * - The start command shall be done before setting the bits 798 * to be signaled. (In PLC-S description and PLCS in SN3. 799 * - The start command shall be issued AFTER setting the 800 * XMIT vector and the XMIT length register. 801 * 802 * We do it exactly according this specs for the old PLC and 803 * the new PLCS inside the SN3. 804 * For the usual PLCS we try it the way it is done for the 805 * old PLC and set the XMIT registers again, if the PLC is 806 * not in SIGNAL state. This is done according to an PLCS 807 * errata workaround. 808 */ 809 810 plc_go_state(smc,np,PL_PCM_START) ; 811 812 /* 813 * workaround for PLC-S eng. sample errata 814 */ 815 #ifdef MOT_ELM 816 if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) 817 #else /* nMOT_ELM */ 818 if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) != 819 PLC_REVISION_A) && 820 !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) 821 #endif /* nMOT_ELM */ 822 { 823 /* 824 * Set register again (PLCS errata) or the first time 825 * (new SN3 PLCS). 826 */ 827 (void) plc_send_bits(smc,phy,3) ; 828 } 829 /* 830 * end of workaround 831 */ 832 833 GO_STATE(PC5_SIGNAL) ; 834 plc->p_state = PS_BIT3 ; 835 plc->p_bits = 3 ; 836 plc->p_start = 0 ; 837 838 break ; 839 case PC1_BREAK : 840 break ; 841 case ACTIONS(PC2_TRACE) : 842 plc_go_state(smc,np,PL_PCM_TRACE) ; 843 ACTIONS_DONE() ; 844 break ; 845 case PC2_TRACE : 846 break ; 847 848 case PC3_CONNECT : /* these states are done by hardware */ 849 case PC4_NEXT : 850 break ; 851 852 case ACTIONS(PC5_SIGNAL) : 853 ACTIONS_DONE() ; 854 case PC5_SIGNAL : 855 if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT)) 856 break ; 857 switch (plc->p_state) { 858 case PS_BIT3 : 859 for (i = 0 ; i <= 2 ; i++) 860 pc_rcode_actions(smc,i,phy) ; 861 pc_tcode_actions(smc,3,phy) ; 862 plc->p_state = PS_BIT4 ; 863 plc->p_bits = 1 ; 864 plc->p_start = 3 ; 865 phy->bitn = 3 ; 866 if (plc_send_bits(smc,phy,1)) { 867 return ; 868 } 869 break ; 870 case PS_BIT4 : 871 pc_rcode_actions(smc,3,phy) ; 872 for (i = 4 ; i <= 6 ; i++) 873 pc_tcode_actions(smc,i,phy) ; 874 plc->p_state = PS_BIT7 ; 875 plc->p_bits = 3 ; 876 plc->p_start = 4 ; 877 phy->bitn = 4 ; 878 if (plc_send_bits(smc,phy,3)) { 879 return ; 880 } 881 break ; 882 case PS_BIT7 : 883 for (i = 3 ; i <= 6 ; i++) 884 pc_rcode_actions(smc,i,phy) ; 885 plc->p_state = PS_LCT ; 886 plc->p_bits = 0 ; 887 plc->p_start = 7 ; 888 phy->bitn = 7 ; 889 sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */ 890 /* start LCT */ 891 i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ; 892 outpw(PLC(np,PL_CNTRL_B),i) ; /* must be cleared */ 893 outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ; 894 break ; 895 case PS_LCT : 896 /* check for local LCT failure */ 897 pc_tcode_actions(smc,7,phy) ; 898 /* 899 * set tval[7] 900 */ 901 plc->p_state = PS_BIT8 ; 902 plc->p_bits = 1 ; 903 plc->p_start = 7 ; 904 phy->bitn = 7 ; 905 if (plc_send_bits(smc,phy,1)) { 906 return ; 907 } 908 break ; 909 case PS_BIT8 : 910 /* check for remote LCT failure */ 911 pc_rcode_actions(smc,7,phy) ; 912 if (phy->t_val[7] || phy->r_val[7]) { 913 plc_go_state(smc,np,PL_PCM_STOP) ; 914 GO_STATE(PC1_BREAK) ; 915 break ; 916 } 917 for (i = 8 ; i <= 9 ; i++) 918 pc_tcode_actions(smc,i,phy) ; 919 plc->p_state = PS_JOIN ; 920 plc->p_bits = 2 ; 921 plc->p_start = 8 ; 922 phy->bitn = 8 ; 923 if (plc_send_bits(smc,phy,2)) { 924 return ; 925 } 926 break ; 927 case PS_JOIN : 928 for (i = 8 ; i <= 9 ; i++) 929 pc_rcode_actions(smc,i,phy) ; 930 plc->p_state = PS_ACTIVE ; 931 GO_STATE(PC6_JOIN) ; 932 break ; 933 } 934 break ; 935 936 case ACTIONS(PC6_JOIN) : 937 /* 938 * prevent mux error when going from WRAP_A to WRAP_B 939 */ 940 if (smc->s.sas == SMT_DAS && np == PB && 941 (smc->y[PA].pc_mode == PM_TREE || 942 smc->y[PB].pc_mode == PM_TREE)) { 943 SETMASK(PLC(np,PL_CNTRL_A), 944 PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; 945 SETMASK(PLC(np,PL_CNTRL_B), 946 PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; 947 } 948 SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; 949 SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; 950 ACTIONS_DONE() ; 951 cmd = 0 ; 952 /* fall thru */ 953 case PC6_JOIN : 954 switch (plc->p_state) { 955 case PS_ACTIVE: 956 /*PC88b*/ 957 if (!phy->cf_join) { 958 phy->cf_join = TRUE ; 959 queue_event(smc,EVENT_CFM,CF_JOIN+np) ; 960 } 961 if (cmd == PC_JOIN) 962 GO_STATE(PC8_ACTIVE) ; 963 /*PC82*/ 964 if (cmd == PC_TRACE) { 965 GO_STATE(PC2_TRACE) ; 966 break ; 967 } 968 break ; 969 } 970 break ; 971 972 case PC7_VERIFY : 973 break ; 974 975 case ACTIONS(PC8_ACTIVE) : 976 /* 977 * start LEM for SMT 978 */ 979 sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ; 980 981 phy->tr_flag = FALSE ; 982 mib->fddiPORTConnectState = PCM_ACTIVE ; 983 984 /* Set the active interrupt mask register */ 985 outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ; 986 987 ACTIONS_DONE() ; 988 break ; 989 case PC8_ACTIVE : 990 /*PC81 is done by PL_TNE_EXPIRED irq */ 991 /*PC82*/ 992 if (cmd == PC_TRACE) { 993 GO_STATE(PC2_TRACE) ; 994 break ; 995 } 996 /*PC88c: is done by TRACE_PROP irq */ 997 998 break ; 999 case ACTIONS(PC9_MAINT) : 1000 stop_pcm_timer0(smc,phy) ; 1001 CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; 1002 CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; 1003 CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */ 1004 sm_ph_lem_stop(smc,np) ; /* disable LEM */ 1005 phy->cf_loop = FALSE ; 1006 phy->cf_join = FALSE ; 1007 queue_event(smc,EVENT_CFM,CF_JOIN+np) ; 1008 plc_go_state(smc,np,PL_PCM_STOP) ; 1009 mib->fddiPORTConnectState = PCM_DISABLED ; 1010 SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ; 1011 sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ; 1012 outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ; 1013 ACTIONS_DONE() ; 1014 break ; 1015 case PC9_MAINT : 1016 DB_PCMN(1, "PCM %c : MAINT", phy->phy_name); 1017 /*PC90*/ 1018 if (cmd == PC_ENABLE) { 1019 GO_STATE(PC0_OFF) ; 1020 break ; 1021 } 1022 break ; 1023 1024 default: 1025 SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ; 1026 break ; 1027 } 1028 } 1029 1030 /* 1031 * force line state on a PHY output (only in MAINT state) 1032 */ 1033 static void sm_ph_linestate(struct s_smc *smc, int phy, int ls) 1034 { 1035 int cntrl ; 1036 1037 SK_UNUSED(smc) ; 1038 1039 cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) | 1040 PL_PCM_STOP | PL_MAINT ; 1041 switch(ls) { 1042 case PC_QLS: /* Force Quiet */ 1043 cntrl |= PL_M_QUI0 ; 1044 break ; 1045 case PC_MLS: /* Force Master */ 1046 cntrl |= PL_M_MASTR ; 1047 break ; 1048 case PC_HLS: /* Force Halt */ 1049 cntrl |= PL_M_HALT ; 1050 break ; 1051 default : 1052 case PC_ILS: /* Force Idle */ 1053 cntrl |= PL_M_IDLE ; 1054 break ; 1055 case PC_LS_PDR: /* Enable repeat filter */ 1056 cntrl |= PL_M_TPDR ; 1057 break ; 1058 } 1059 outpw(PLC(phy,PL_CNTRL_B),cntrl) ; 1060 } 1061 1062 static void reset_lem_struct(struct s_phy *phy) 1063 { 1064 struct lem_counter *lem = &phy->lem ; 1065 1066 phy->mib->fddiPORTLer_Estimate = 15 ; 1067 lem->lem_float_ber = 15 * 100 ; 1068 } 1069 1070 /* 1071 * link error monitor 1072 */ 1073 static void lem_evaluate(struct s_smc *smc, struct s_phy *phy) 1074 { 1075 int ber ; 1076 u_long errors ; 1077 struct lem_counter *lem = &phy->lem ; 1078 struct fddi_mib_p *mib ; 1079 int cond ; 1080 1081 mib = phy->mib ; 1082 1083 if (!lem->lem_on) 1084 return ; 1085 1086 errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ; 1087 lem->lem_errors += errors ; 1088 mib->fddiPORTLem_Ct += errors ; 1089 1090 errors = lem->lem_errors ; 1091 /* 1092 * calculation is called on a intervall of 8 seconds 1093 * -> this means, that one error in 8 sec. is one of 8*125*10E6 1094 * the same as BER = 10E-9 1095 * Please note: 1096 * -> 9 errors in 8 seconds mean: 1097 * BER = 9 * 10E-9 and this is 1098 * < 10E-8, so the limit of 10E-8 is not reached! 1099 */ 1100 1101 if (!errors) ber = 15 ; 1102 else if (errors <= 9) ber = 9 ; 1103 else if (errors <= 99) ber = 8 ; 1104 else if (errors <= 999) ber = 7 ; 1105 else if (errors <= 9999) ber = 6 ; 1106 else if (errors <= 99999) ber = 5 ; 1107 else if (errors <= 999999) ber = 4 ; 1108 else if (errors <= 9999999) ber = 3 ; 1109 else if (errors <= 99999999) ber = 2 ; 1110 else if (errors <= 999999999) ber = 1 ; 1111 else ber = 0 ; 1112 1113 /* 1114 * weighted average 1115 */ 1116 ber *= 100 ; 1117 lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ; 1118 lem->lem_float_ber /= 10 ; 1119 mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ; 1120 if (mib->fddiPORTLer_Estimate < 4) { 1121 mib->fddiPORTLer_Estimate = 4 ; 1122 } 1123 1124 if (lem->lem_errors) { 1125 DB_PCMN(1, "LEM %c :", phy->np == PB ? 'B' : 'A'); 1126 DB_PCMN(1, "errors : %ld", lem->lem_errors); 1127 DB_PCMN(1, "sum_errors : %ld", mib->fddiPORTLem_Ct); 1128 DB_PCMN(1, "current BER : 10E-%d", ber / 100); 1129 DB_PCMN(1, "float BER : 10E-(%d/100)", lem->lem_float_ber); 1130 DB_PCMN(1, "avg. BER : 10E-%d", mib->fddiPORTLer_Estimate); 1131 } 1132 1133 lem->lem_errors = 0L ; 1134 1135 #ifndef SLIM_SMT 1136 cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ? 1137 TRUE : FALSE ; 1138 #ifdef SMT_EXT_CUTOFF 1139 smt_ler_alarm_check(smc,phy,cond) ; 1140 #endif /* nSMT_EXT_CUTOFF */ 1141 if (cond != mib->fddiPORTLerFlag) { 1142 smt_srf_event(smc,SMT_COND_PORT_LER, 1143 (int) (INDEX_PORT+ phy->np) ,cond) ; 1144 } 1145 #endif 1146 1147 if ( mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) { 1148 phy->pc_lem_fail = TRUE ; /* flag */ 1149 mib->fddiPORTLem_Reject_Ct++ ; 1150 /* 1151 * "forgive 10e-2" if we cutoff so we can come 1152 * up again .. 1153 */ 1154 lem->lem_float_ber += 2*100 ; 1155 1156 /*PC81b*/ 1157 #ifdef CONCENTRATOR 1158 DB_PCMN(1, "PCM: LER cutoff on port %d cutoff %d", 1159 phy->np, mib->fddiPORTLer_Cutoff); 1160 #endif 1161 #ifdef SMT_EXT_CUTOFF 1162 smt_port_off_event(smc,phy->np); 1163 #else /* nSMT_EXT_CUTOFF */ 1164 queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; 1165 #endif /* nSMT_EXT_CUTOFF */ 1166 } 1167 } 1168 1169 /* 1170 * called by SMT to calculate LEM bit error rate 1171 */ 1172 void sm_lem_evaluate(struct s_smc *smc) 1173 { 1174 int np ; 1175 1176 for (np = 0 ; np < NUMPHYS ; np++) 1177 lem_evaluate(smc,&smc->y[np]) ; 1178 } 1179 1180 static void lem_check_lct(struct s_smc *smc, struct s_phy *phy) 1181 { 1182 struct lem_counter *lem = &phy->lem ; 1183 struct fddi_mib_p *mib ; 1184 int errors ; 1185 1186 mib = phy->mib ; 1187 1188 phy->pc_lem_fail = FALSE ; /* flag */ 1189 errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ; 1190 lem->lem_errors += errors ; 1191 mib->fddiPORTLem_Ct += errors ; 1192 if (lem->lem_errors) { 1193 switch(phy->lc_test) { 1194 case LC_SHORT: 1195 if (lem->lem_errors >= smc->s.lct_short) 1196 phy->pc_lem_fail = TRUE ; 1197 break ; 1198 case LC_MEDIUM: 1199 if (lem->lem_errors >= smc->s.lct_medium) 1200 phy->pc_lem_fail = TRUE ; 1201 break ; 1202 case LC_LONG: 1203 if (lem->lem_errors >= smc->s.lct_long) 1204 phy->pc_lem_fail = TRUE ; 1205 break ; 1206 case LC_EXTENDED: 1207 if (lem->lem_errors >= smc->s.lct_extended) 1208 phy->pc_lem_fail = TRUE ; 1209 break ; 1210 } 1211 DB_PCMN(1, " >>errors : %lu", lem->lem_errors); 1212 } 1213 if (phy->pc_lem_fail) { 1214 mib->fddiPORTLCTFail_Ct++ ; 1215 mib->fddiPORTLem_Reject_Ct++ ; 1216 } 1217 else 1218 mib->fddiPORTLCTFail_Ct = 0 ; 1219 } 1220 1221 /* 1222 * LEM functions 1223 */ 1224 static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold) 1225 { 1226 struct lem_counter *lem = &smc->y[np].lem ; 1227 1228 lem->lem_on = 1 ; 1229 lem->lem_errors = 0L ; 1230 1231 /* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too 1232 * often. 1233 */ 1234 1235 outpw(PLC(np,PL_LE_THRESHOLD),threshold) ; 1236 (void)inpw(PLC(np,PL_LINK_ERR_CTR)) ; /* clear error counter */ 1237 1238 /* enable LE INT */ 1239 SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ; 1240 } 1241 1242 static void sm_ph_lem_stop(struct s_smc *smc, int np) 1243 { 1244 struct lem_counter *lem = &smc->y[np].lem ; 1245 1246 lem->lem_on = 0 ; 1247 CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; 1248 } 1249 1250 /* 1251 * PCM pseudo code 1252 * receive actions are called AFTER the bit n is received, 1253 * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received 1254 */ 1255 1256 /* 1257 * PCM pseudo code 5.1 .. 6.1 1258 */ 1259 static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy) 1260 { 1261 struct fddi_mib_p *mib ; 1262 1263 mib = phy->mib ; 1264 1265 DB_PCMN(1, "SIG rec %x %x:", bit, phy->r_val[bit]); 1266 bit++ ; 1267 1268 switch(bit) { 1269 case 0: 1270 case 1: 1271 case 2: 1272 break ; 1273 case 3 : 1274 if (phy->r_val[1] == 0 && phy->r_val[2] == 0) 1275 mib->fddiPORTNeighborType = TA ; 1276 else if (phy->r_val[1] == 0 && phy->r_val[2] == 1) 1277 mib->fddiPORTNeighborType = TB ; 1278 else if (phy->r_val[1] == 1 && phy->r_val[2] == 0) 1279 mib->fddiPORTNeighborType = TS ; 1280 else if (phy->r_val[1] == 1 && phy->r_val[2] == 1) 1281 mib->fddiPORTNeighborType = TM ; 1282 break ; 1283 case 4: 1284 if (mib->fddiPORTMy_Type == TM && 1285 mib->fddiPORTNeighborType == TM) { 1286 DB_PCMN(1, "PCM %c : E100 withhold M-M", 1287 phy->phy_name); 1288 mib->fddiPORTPC_Withhold = PC_WH_M_M ; 1289 RS_SET(smc,RS_EVENT) ; 1290 } 1291 else if (phy->t_val[3] || phy->r_val[3]) { 1292 mib->fddiPORTPC_Withhold = PC_WH_NONE ; 1293 if (mib->fddiPORTMy_Type == TM || 1294 mib->fddiPORTNeighborType == TM) 1295 phy->pc_mode = PM_TREE ; 1296 else 1297 phy->pc_mode = PM_PEER ; 1298 1299 /* reevaluate the selection criteria (wc_flag) */ 1300 all_selection_criteria (smc); 1301 1302 if (phy->wc_flag) { 1303 mib->fddiPORTPC_Withhold = PC_WH_PATH ; 1304 } 1305 } 1306 else { 1307 mib->fddiPORTPC_Withhold = PC_WH_OTHER ; 1308 RS_SET(smc,RS_EVENT) ; 1309 DB_PCMN(1, "PCM %c : E101 withhold other", 1310 phy->phy_name); 1311 } 1312 phy->twisted = ((mib->fddiPORTMy_Type != TS) && 1313 (mib->fddiPORTMy_Type != TM) && 1314 (mib->fddiPORTNeighborType == 1315 mib->fddiPORTMy_Type)) ; 1316 if (phy->twisted) { 1317 DB_PCMN(1, "PCM %c : E102 !!! TWISTED !!!", 1318 phy->phy_name); 1319 } 1320 break ; 1321 case 5 : 1322 break ; 1323 case 6: 1324 if (phy->t_val[4] || phy->r_val[4]) { 1325 if ((phy->t_val[4] && phy->t_val[5]) || 1326 (phy->r_val[4] && phy->r_val[5]) ) 1327 phy->lc_test = LC_EXTENDED ; 1328 else 1329 phy->lc_test = LC_LONG ; 1330 } 1331 else if (phy->t_val[5] || phy->r_val[5]) 1332 phy->lc_test = LC_MEDIUM ; 1333 else 1334 phy->lc_test = LC_SHORT ; 1335 switch (phy->lc_test) { 1336 case LC_SHORT : /* 50ms */ 1337 outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ; 1338 phy->t_next[7] = smc->s.pcm_lc_short ; 1339 break ; 1340 case LC_MEDIUM : /* 500ms */ 1341 outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ; 1342 phy->t_next[7] = smc->s.pcm_lc_medium ; 1343 break ; 1344 case LC_LONG : 1345 SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; 1346 phy->t_next[7] = smc->s.pcm_lc_long ; 1347 break ; 1348 case LC_EXTENDED : 1349 SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; 1350 phy->t_next[7] = smc->s.pcm_lc_extended ; 1351 break ; 1352 } 1353 if (phy->t_next[7] > smc->s.pcm_lc_medium) { 1354 start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy); 1355 } 1356 DB_PCMN(1, "LCT timer = %ld us", phy->t_next[7]); 1357 phy->t_next[9] = smc->s.pcm_t_next_9 ; 1358 break ; 1359 case 7: 1360 if (phy->t_val[6]) { 1361 phy->cf_loop = TRUE ; 1362 } 1363 phy->td_flag = TRUE ; 1364 break ; 1365 case 8: 1366 if (phy->t_val[7] || phy->r_val[7]) { 1367 DB_PCMN(1, "PCM %c : E103 LCT fail %s", 1368 phy->phy_name, 1369 phy->t_val[7] ? "local" : "remote"); 1370 queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; 1371 } 1372 break ; 1373 case 9: 1374 if (phy->t_val[8] || phy->r_val[8]) { 1375 if (phy->t_val[8]) 1376 phy->cf_loop = TRUE ; 1377 phy->td_flag = TRUE ; 1378 } 1379 break ; 1380 case 10: 1381 if (phy->r_val[9]) { 1382 /* neighbor intends to have MAC on output */ ; 1383 mib->fddiPORTMacIndicated.R_val = TRUE ; 1384 } 1385 else { 1386 /* neighbor does not intend to have MAC on output */ ; 1387 mib->fddiPORTMacIndicated.R_val = FALSE ; 1388 } 1389 break ; 1390 } 1391 } 1392 1393 /* 1394 * PCM pseudo code 5.1 .. 6.1 1395 */ 1396 static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy) 1397 { 1398 int np = phy->np ; 1399 struct fddi_mib_p *mib ; 1400 1401 mib = phy->mib ; 1402 1403 switch(bit) { 1404 case 0: 1405 phy->t_val[0] = 0 ; /* no escape used */ 1406 break ; 1407 case 1: 1408 if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM) 1409 phy->t_val[1] = 1 ; 1410 else 1411 phy->t_val[1] = 0 ; 1412 break ; 1413 case 2 : 1414 if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM) 1415 phy->t_val[2] = 1 ; 1416 else 1417 phy->t_val[2] = 0 ; 1418 break ; 1419 case 3: 1420 { 1421 int type,ne ; 1422 int policy ; 1423 1424 type = mib->fddiPORTMy_Type ; 1425 ne = mib->fddiPORTNeighborType ; 1426 policy = smc->mib.fddiSMTConnectionPolicy ; 1427 1428 phy->t_val[3] = 1 ; /* Accept connection */ 1429 switch (type) { 1430 case TA : 1431 if ( 1432 ((policy & POLICY_AA) && ne == TA) || 1433 ((policy & POLICY_AB) && ne == TB) || 1434 ((policy & POLICY_AS) && ne == TS) || 1435 ((policy & POLICY_AM) && ne == TM) ) 1436 phy->t_val[3] = 0 ; /* Reject */ 1437 break ; 1438 case TB : 1439 if ( 1440 ((policy & POLICY_BA) && ne == TA) || 1441 ((policy & POLICY_BB) && ne == TB) || 1442 ((policy & POLICY_BS) && ne == TS) || 1443 ((policy & POLICY_BM) && ne == TM) ) 1444 phy->t_val[3] = 0 ; /* Reject */ 1445 break ; 1446 case TS : 1447 if ( 1448 ((policy & POLICY_SA) && ne == TA) || 1449 ((policy & POLICY_SB) && ne == TB) || 1450 ((policy & POLICY_SS) && ne == TS) || 1451 ((policy & POLICY_SM) && ne == TM) ) 1452 phy->t_val[3] = 0 ; /* Reject */ 1453 break ; 1454 case TM : 1455 if ( ne == TM || 1456 ((policy & POLICY_MA) && ne == TA) || 1457 ((policy & POLICY_MB) && ne == TB) || 1458 ((policy & POLICY_MS) && ne == TS) || 1459 ((policy & POLICY_MM) && ne == TM) ) 1460 phy->t_val[3] = 0 ; /* Reject */ 1461 break ; 1462 } 1463 #ifndef SLIM_SMT 1464 /* 1465 * detect undesirable connection attempt event 1466 */ 1467 if ( (type == TA && ne == TA ) || 1468 (type == TA && ne == TS ) || 1469 (type == TB && ne == TB ) || 1470 (type == TB && ne == TS ) || 1471 (type == TS && ne == TA ) || 1472 (type == TS && ne == TB ) ) { 1473 smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION, 1474 (int) (INDEX_PORT+ phy->np) ,0) ; 1475 } 1476 #endif 1477 } 1478 break ; 1479 case 4: 1480 if (mib->fddiPORTPC_Withhold == PC_WH_NONE) { 1481 if (phy->pc_lem_fail) { 1482 phy->t_val[4] = 1 ; /* long */ 1483 phy->t_val[5] = 0 ; 1484 } 1485 else { 1486 phy->t_val[4] = 0 ; 1487 if (mib->fddiPORTLCTFail_Ct > 0) 1488 phy->t_val[5] = 1 ; /* medium */ 1489 else 1490 phy->t_val[5] = 0 ; /* short */ 1491 1492 /* 1493 * Implementers choice: use medium 1494 * instead of short when undesired 1495 * connection attempt is made. 1496 */ 1497 if (phy->wc_flag) 1498 phy->t_val[5] = 1 ; /* medium */ 1499 } 1500 mib->fddiPORTConnectState = PCM_CONNECTING ; 1501 } 1502 else { 1503 mib->fddiPORTConnectState = PCM_STANDBY ; 1504 phy->t_val[4] = 1 ; /* extended */ 1505 phy->t_val[5] = 1 ; 1506 } 1507 break ; 1508 case 5: 1509 break ; 1510 case 6: 1511 /* we do NOT have a MAC for LCT */ 1512 phy->t_val[6] = 0 ; 1513 break ; 1514 case 7: 1515 phy->cf_loop = FALSE ; 1516 lem_check_lct(smc,phy) ; 1517 if (phy->pc_lem_fail) { 1518 DB_PCMN(1, "PCM %c : E104 LCT failed", phy->phy_name); 1519 phy->t_val[7] = 1 ; 1520 } 1521 else 1522 phy->t_val[7] = 0 ; 1523 break ; 1524 case 8: 1525 phy->t_val[8] = 0 ; /* Don't request MAC loopback */ 1526 break ; 1527 case 9: 1528 phy->cf_loop = 0 ; 1529 if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) || 1530 ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) { 1531 queue_event(smc,EVENT_PCM+np,PC_START) ; 1532 break ; 1533 } 1534 phy->t_val[9] = FALSE ; 1535 switch (smc->s.sas) { 1536 case SMT_DAS : 1537 /* 1538 * MAC intended on output 1539 */ 1540 if (phy->pc_mode == PM_TREE) { 1541 if ((np == PB) || ((np == PA) && 1542 (smc->y[PB].mib->fddiPORTConnectState != 1543 PCM_ACTIVE))) 1544 phy->t_val[9] = TRUE ; 1545 } 1546 else { 1547 if (np == PB) 1548 phy->t_val[9] = TRUE ; 1549 } 1550 break ; 1551 case SMT_SAS : 1552 if (np == PS) 1553 phy->t_val[9] = TRUE ; 1554 break ; 1555 #ifdef CONCENTRATOR 1556 case SMT_NAC : 1557 /* 1558 * MAC intended on output 1559 */ 1560 if (np == PB) 1561 phy->t_val[9] = TRUE ; 1562 break ; 1563 #endif 1564 } 1565 mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ; 1566 break ; 1567 } 1568 DB_PCMN(1, "SIG snd %x %x:", bit, phy->t_val[bit]); 1569 } 1570 1571 /* 1572 * return status twisted (called by SMT) 1573 */ 1574 int pcm_status_twisted(struct s_smc *smc) 1575 { 1576 int twist = 0 ; 1577 if (smc->s.sas != SMT_DAS) 1578 return 0; 1579 if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE)) 1580 twist |= 1 ; 1581 if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE)) 1582 twist |= 2 ; 1583 return twist; 1584 } 1585 1586 /* 1587 * return status (called by SMT) 1588 * type 1589 * state 1590 * remote phy type 1591 * remote mac yes/no 1592 */ 1593 void pcm_status_state(struct s_smc *smc, int np, int *type, int *state, 1594 int *remote, int *mac) 1595 { 1596 struct s_phy *phy = &smc->y[np] ; 1597 struct fddi_mib_p *mib ; 1598 1599 mib = phy->mib ; 1600 1601 /* remote PHY type and MAC - set only if active */ 1602 *mac = 0 ; 1603 *type = mib->fddiPORTMy_Type ; /* our PHY type */ 1604 *state = mib->fddiPORTConnectState ; 1605 *remote = mib->fddiPORTNeighborType ; 1606 1607 switch(mib->fddiPORTPCMState) { 1608 case PC8_ACTIVE : 1609 *mac = mib->fddiPORTMacIndicated.R_val ; 1610 break ; 1611 } 1612 } 1613 1614 /* 1615 * return rooted station status (called by SMT) 1616 */ 1617 int pcm_rooted_station(struct s_smc *smc) 1618 { 1619 int n ; 1620 1621 for (n = 0 ; n < NUMPHYS ; n++) { 1622 if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE && 1623 smc->y[n].mib->fddiPORTNeighborType == TM) 1624 return 0; 1625 } 1626 return 1; 1627 } 1628 1629 /* 1630 * Interrupt actions for PLC & PCM events 1631 */ 1632 void plc_irq(struct s_smc *smc, int np, unsigned int cmd) 1633 /* int np; PHY index */ 1634 { 1635 struct s_phy *phy = &smc->y[np] ; 1636 struct s_plc *plc = &phy->plc ; 1637 int n ; 1638 #ifdef SUPERNET_3 1639 int corr_mask ; 1640 #endif /* SUPERNET_3 */ 1641 int i ; 1642 1643 if (np >= smc->s.numphys) { 1644 plc->soft_err++ ; 1645 return ; 1646 } 1647 if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/ 1648 /* 1649 * Check whether the SRF Condition occurred. 1650 */ 1651 if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){ 1652 /* 1653 * This is the real Elasticity Error. 1654 * More than one in a row are treated as a 1655 * single one. 1656 * Only count this in the active state. 1657 */ 1658 phy->mib->fddiPORTEBError_Ct ++ ; 1659 1660 } 1661 1662 plc->ebuf_err++ ; 1663 if (plc->ebuf_cont <= 1000) { 1664 /* 1665 * Prevent counter from being wrapped after 1666 * hanging years in that interrupt. 1667 */ 1668 plc->ebuf_cont++ ; /* Ebuf continuous error */ 1669 } 1670 1671 #ifdef SUPERNET_3 1672 if (plc->ebuf_cont == 1000 && 1673 ((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) == 1674 PLC_REV_SN3)) { 1675 /* 1676 * This interrupt remeained high for at least 1677 * 1000 consecutive interrupt calls. 1678 * 1679 * This is caused by a hardware error of the 1680 * ORION part of the Supernet III chipset. 1681 * 1682 * Disable this bit from the mask. 1683 */ 1684 corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ; 1685 outpw(PLC(np,PL_INTR_MASK),corr_mask); 1686 1687 /* 1688 * Disconnect from the ring. 1689 * Call the driver with the reset indication. 1690 */ 1691 queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; 1692 1693 /* 1694 * Make an error log entry. 1695 */ 1696 SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ; 1697 1698 /* 1699 * Indicate the Reset. 1700 */ 1701 drv_reset_indication(smc) ; 1702 } 1703 #endif /* SUPERNET_3 */ 1704 } else { 1705 /* Reset the continuous error variable */ 1706 plc->ebuf_cont = 0 ; /* reset Ebuf continuous error */ 1707 } 1708 if (cmd & PL_PHYINV) { /* physical layer invalid signal */ 1709 plc->phyinv++ ; 1710 } 1711 if (cmd & PL_VSYM_CTR) { /* violation symbol counter has incr.*/ 1712 plc->vsym_ctr++ ; 1713 } 1714 if (cmd & PL_MINI_CTR) { /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ 1715 plc->mini_ctr++ ; 1716 } 1717 if (cmd & PL_LE_CTR) { /* link error event counter */ 1718 int j ; 1719 1720 /* 1721 * note: PL_LINK_ERR_CTR MUST be read to clear it 1722 */ 1723 j = inpw(PLC(np,PL_LE_THRESHOLD)) ; 1724 i = inpw(PLC(np,PL_LINK_ERR_CTR)) ; 1725 1726 if (i < j) { 1727 /* wrapped around */ 1728 i += 256 ; 1729 } 1730 1731 if (phy->lem.lem_on) { 1732 /* Note: Lem errors shall only be counted when 1733 * link is ACTIVE or LCT is active. 1734 */ 1735 phy->lem.lem_errors += i ; 1736 phy->mib->fddiPORTLem_Ct += i ; 1737 } 1738 } 1739 if (cmd & PL_TPC_EXPIRED) { /* TPC timer reached zero */ 1740 if (plc->p_state == PS_LCT) { 1741 /* 1742 * end of LCT 1743 */ 1744 ; 1745 } 1746 plc->tpc_exp++ ; 1747 } 1748 if (cmd & PL_LS_MATCH) { /* LS == LS in PLC_CNTRL_B's MATCH_LS*/ 1749 switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) { 1750 case PL_I_IDLE : phy->curr_ls = PC_ILS ; break ; 1751 case PL_I_HALT : phy->curr_ls = PC_HLS ; break ; 1752 case PL_I_MASTR : phy->curr_ls = PC_MLS ; break ; 1753 case PL_I_QUIET : phy->curr_ls = PC_QLS ; break ; 1754 } 1755 } 1756 if (cmd & PL_PCM_BREAK) { /* PCM has entered the BREAK state */ 1757 int reason; 1758 1759 reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ; 1760 1761 switch (reason) { 1762 case PL_B_PCS : plc->b_pcs++ ; break ; 1763 case PL_B_TPC : plc->b_tpc++ ; break ; 1764 case PL_B_TNE : plc->b_tne++ ; break ; 1765 case PL_B_QLS : plc->b_qls++ ; break ; 1766 case PL_B_ILS : plc->b_ils++ ; break ; 1767 case PL_B_HLS : plc->b_hls++ ; break ; 1768 } 1769 1770 /*jd 05-Aug-1999 changed: Bug #10419 */ 1771 DB_PCMN(1, "PLC %d: MDcF = %x", np, smc->e.DisconnectFlag); 1772 if (smc->e.DisconnectFlag == FALSE) { 1773 DB_PCMN(1, "PLC %d: restart (reason %x)", np, reason); 1774 queue_event(smc,EVENT_PCM+np,PC_START) ; 1775 } 1776 else { 1777 DB_PCMN(1, "PLC %d: NO!! restart (reason %x)", 1778 np, reason); 1779 } 1780 return ; 1781 } 1782 /* 1783 * If both CODE & ENABLE are set ignore enable 1784 */ 1785 if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */ 1786 queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ; 1787 n = inpw(PLC(np,PL_RCV_VECTOR)) ; 1788 for (i = 0 ; i < plc->p_bits ; i++) { 1789 phy->r_val[plc->p_start+i] = n & 1 ; 1790 n >>= 1 ; 1791 } 1792 } 1793 else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/ 1794 queue_event(smc,EVENT_PCM+np,PC_JOIN) ; 1795 } 1796 if (cmd & PL_TRACE_PROP) { /* MLS while PC8_ACTIV || PC2_TRACE */ 1797 /*PC22b*/ 1798 if (!phy->tr_flag) { 1799 DB_PCMN(1, "PCM : irq TRACE_PROP %d %d", 1800 np, smc->mib.fddiSMTECMState); 1801 phy->tr_flag = TRUE ; 1802 smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ; 1803 queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; 1804 } 1805 } 1806 /* 1807 * filter PLC glitch ??? 1808 * QLS || HLS only while in PC2_TRACE state 1809 */ 1810 if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) { 1811 /*PC22a*/ 1812 if (smc->e.path_test == PT_PASSED) { 1813 DB_PCMN(1, "PCM : state = %s %d", 1814 get_pcmstate(smc, np), 1815 phy->mib->fddiPORTPCMState); 1816 1817 smc->e.path_test = PT_PENDING ; 1818 queue_event(smc,EVENT_ECM,EC_PATH_TEST) ; 1819 } 1820 } 1821 if (cmd & PL_TNE_EXPIRED) { /* TNE: length of noise events */ 1822 /* break_required (TNE > NS_Max) */ 1823 if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) { 1824 if (!phy->tr_flag) { 1825 DB_PCMN(1, "PCM %c : PC81 %s", 1826 phy->phy_name, "NSE"); 1827 queue_event(smc, EVENT_PCM + np, PC_START); 1828 return; 1829 } 1830 } 1831 } 1832 #if 0 1833 if (cmd & PL_NP_ERR) { /* NP has requested to r/w an inv reg*/ 1834 /* 1835 * It's a bug by AMD 1836 */ 1837 plc->np_err++ ; 1838 } 1839 /* pin inactiv (GND) */ 1840 if (cmd & PL_PARITY_ERR) { /* p. error dedected on TX9-0 inp */ 1841 plc->parity_err++ ; 1842 } 1843 if (cmd & PL_LSDO) { /* carrier detected */ 1844 ; 1845 } 1846 #endif 1847 } 1848 1849 #ifdef DEBUG 1850 /* 1851 * fill state struct 1852 */ 1853 void pcm_get_state(struct s_smc *smc, struct smt_state *state) 1854 { 1855 struct s_phy *phy ; 1856 struct pcm_state *pcs ; 1857 int i ; 1858 int ii ; 1859 short rbits ; 1860 short tbits ; 1861 struct fddi_mib_p *mib ; 1862 1863 for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ; 1864 i++ , phy++, pcs++ ) { 1865 mib = phy->mib ; 1866 pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ; 1867 pcs->pcm_state = (u_char) mib->fddiPORTPCMState ; 1868 pcs->pcm_mode = phy->pc_mode ; 1869 pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ; 1870 pcs->pcm_bsf = mib->fddiPORTBS_Flag ; 1871 pcs->pcm_lsf = phy->ls_flag ; 1872 pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ; 1873 pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ; 1874 for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) { 1875 rbits <<= 1 ; 1876 tbits <<= 1 ; 1877 if (phy->r_val[NUMBITS-1-ii]) 1878 rbits |= 1 ; 1879 if (phy->t_val[NUMBITS-1-ii]) 1880 tbits |= 1 ; 1881 } 1882 pcs->pcm_r_val = rbits ; 1883 pcs->pcm_t_val = tbits ; 1884 } 1885 } 1886 1887 int get_pcm_state(struct s_smc *smc, int np) 1888 { 1889 int pcs ; 1890 1891 SK_UNUSED(smc) ; 1892 1893 switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { 1894 case PL_PC0 : pcs = PC_STOP ; break ; 1895 case PL_PC1 : pcs = PC_START ; break ; 1896 case PL_PC2 : pcs = PC_TRACE ; break ; 1897 case PL_PC3 : pcs = PC_SIGNAL ; break ; 1898 case PL_PC4 : pcs = PC_SIGNAL ; break ; 1899 case PL_PC5 : pcs = PC_SIGNAL ; break ; 1900 case PL_PC6 : pcs = PC_JOIN ; break ; 1901 case PL_PC7 : pcs = PC_JOIN ; break ; 1902 case PL_PC8 : pcs = PC_ENABLE ; break ; 1903 case PL_PC9 : pcs = PC_MAINT ; break ; 1904 default : pcs = PC_DISABLE ; break ; 1905 } 1906 return pcs; 1907 } 1908 1909 char *get_linestate(struct s_smc *smc, int np) 1910 { 1911 char *ls = "" ; 1912 1913 SK_UNUSED(smc) ; 1914 1915 switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) { 1916 case PL_L_NLS : ls = "NOISE" ; break ; 1917 case PL_L_ALS : ls = "ACTIV" ; break ; 1918 case PL_L_UND : ls = "UNDEF" ; break ; 1919 case PL_L_ILS4: ls = "ILS 4" ; break ; 1920 case PL_L_QLS : ls = "QLS" ; break ; 1921 case PL_L_MLS : ls = "MLS" ; break ; 1922 case PL_L_HLS : ls = "HLS" ; break ; 1923 case PL_L_ILS16:ls = "ILS16" ; break ; 1924 #ifdef lint 1925 default: ls = "unknown" ; break ; 1926 #endif 1927 } 1928 return ls; 1929 } 1930 1931 char *get_pcmstate(struct s_smc *smc, int np) 1932 { 1933 char *pcs ; 1934 1935 SK_UNUSED(smc) ; 1936 1937 switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { 1938 case PL_PC0 : pcs = "OFF" ; break ; 1939 case PL_PC1 : pcs = "BREAK" ; break ; 1940 case PL_PC2 : pcs = "TRACE" ; break ; 1941 case PL_PC3 : pcs = "CONNECT"; break ; 1942 case PL_PC4 : pcs = "NEXT" ; break ; 1943 case PL_PC5 : pcs = "SIGNAL" ; break ; 1944 case PL_PC6 : pcs = "JOIN" ; break ; 1945 case PL_PC7 : pcs = "VERIFY" ; break ; 1946 case PL_PC8 : pcs = "ACTIV" ; break ; 1947 case PL_PC9 : pcs = "MAINT" ; break ; 1948 default : pcs = "UNKNOWN" ; break ; 1949 } 1950 return pcs; 1951 } 1952 1953 void list_phy(struct s_smc *smc) 1954 { 1955 struct s_plc *plc ; 1956 int np ; 1957 1958 for (np = 0 ; np < NUMPHYS ; np++) { 1959 plc = &smc->y[np].plc ; 1960 printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ; 1961 printf("\tsoft_error: %ld \t\tPC_Start : %ld\n", 1962 plc->soft_err,plc->b_pcs); 1963 printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n", 1964 plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ; 1965 printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n", 1966 plc->ebuf_err,plc->b_tne) ; 1967 printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n", 1968 plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ; 1969 printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n", 1970 plc->vsym_ctr,plc->b_ils) ; 1971 printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n", 1972 plc->mini_ctr,plc->b_hls) ; 1973 printf("\tnodepr_err: %ld\n",plc->np_err) ; 1974 printf("\tTPC_exp : %ld\n",plc->tpc_exp) ; 1975 printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ; 1976 } 1977 } 1978 1979 1980 #ifdef CONCENTRATOR 1981 void pcm_lem_dump(struct s_smc *smc) 1982 { 1983 int i ; 1984 struct s_phy *phy ; 1985 struct fddi_mib_p *mib ; 1986 1987 char *entostring() ; 1988 1989 printf("PHY errors BER\n") ; 1990 printf("----------------------\n") ; 1991 for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) { 1992 if (!plc_is_installed(smc,i)) 1993 continue ; 1994 mib = phy->mib ; 1995 printf("%s\t%ld\t10E-%d\n", 1996 entostring(smc,ENTITY_PHY(i)), 1997 mib->fddiPORTLem_Ct, 1998 mib->fddiPORTLer_Estimate) ; 1999 } 2000 } 2001 #endif 2002 #endif 2003