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