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