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