~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/net/fddi/skfp/pcmplc.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 continuous 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 continuous error variable */
 
1721
                plc->ebuf_cont = 0 ;    /* reset Ebuf continuous 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