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