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