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