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