162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *	(C)Copyright 1998,1999 SysKonnect,
562306a36Sopenharmony_ci *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *	See the file "skfddi.c" for further information.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *	The information in this file is provided "AS IS" without warranty.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci ******************************************************************************/
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci	PCM
1562306a36Sopenharmony_ci	Physical Connection Management
1662306a36Sopenharmony_ci*/
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * Hardware independent state machine implemantation
2062306a36Sopenharmony_ci * The following external SMT functions are referenced :
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * 		queue_event()
2362306a36Sopenharmony_ci * 		smt_timer_start()
2462306a36Sopenharmony_ci * 		smt_timer_stop()
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * 	The following external HW dependent functions are referenced :
2762306a36Sopenharmony_ci * 		sm_pm_control()
2862306a36Sopenharmony_ci *		sm_ph_linestate()
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * 	The following HW dependent events are required :
3162306a36Sopenharmony_ci *		PC_QLS
3262306a36Sopenharmony_ci *		PC_ILS
3362306a36Sopenharmony_ci *		PC_HLS
3462306a36Sopenharmony_ci *		PC_MLS
3562306a36Sopenharmony_ci *		PC_NSE
3662306a36Sopenharmony_ci *		PC_LEM
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "h/types.h"
4262306a36Sopenharmony_ci#include "h/fddi.h"
4362306a36Sopenharmony_ci#include "h/smc.h"
4462306a36Sopenharmony_ci#include "h/supern_2.h"
4562306a36Sopenharmony_ci#define KERNEL
4662306a36Sopenharmony_ci#include "h/smtstate.h"
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#ifdef	FDDI_MIB
4962306a36Sopenharmony_ciextern int snmp_fddi_trap(
5062306a36Sopenharmony_ci#ifdef	ANSIC
5162306a36Sopenharmony_cistruct s_smc	* smc, int  type, int  index
5262306a36Sopenharmony_ci#endif
5362306a36Sopenharmony_ci);
5462306a36Sopenharmony_ci#endif
5562306a36Sopenharmony_ci#ifdef	CONCENTRATOR
5662306a36Sopenharmony_ciextern int plc_is_installed(
5762306a36Sopenharmony_ci#ifdef	ANSIC
5862306a36Sopenharmony_cistruct s_smc *smc ,
5962306a36Sopenharmony_ciint p
6062306a36Sopenharmony_ci#endif
6162306a36Sopenharmony_ci) ;
6262306a36Sopenharmony_ci#endif
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * FSM Macros
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ci#define AFLAG		(0x20)
6762306a36Sopenharmony_ci#define GO_STATE(x)	(mib->fddiPORTPCMState = (x)|AFLAG)
6862306a36Sopenharmony_ci#define ACTIONS_DONE()	(mib->fddiPORTPCMState &= ~AFLAG)
6962306a36Sopenharmony_ci#define ACTIONS(x)	(x|AFLAG)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/*
7262306a36Sopenharmony_ci * PCM states
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_ci#define PC0_OFF			0
7562306a36Sopenharmony_ci#define PC1_BREAK		1
7662306a36Sopenharmony_ci#define PC2_TRACE		2
7762306a36Sopenharmony_ci#define PC3_CONNECT		3
7862306a36Sopenharmony_ci#define PC4_NEXT		4
7962306a36Sopenharmony_ci#define PC5_SIGNAL		5
8062306a36Sopenharmony_ci#define PC6_JOIN		6
8162306a36Sopenharmony_ci#define PC7_VERIFY		7
8262306a36Sopenharmony_ci#define PC8_ACTIVE		8
8362306a36Sopenharmony_ci#define PC9_MAINT		9
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*
8662306a36Sopenharmony_ci * symbolic state names
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_cistatic const char * const pcm_states[] =  {
8962306a36Sopenharmony_ci	"PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT",
9062306a36Sopenharmony_ci	"PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT"
9162306a36Sopenharmony_ci} ;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/*
9462306a36Sopenharmony_ci * symbolic event names
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistatic const char * const pcm_events[] = {
9762306a36Sopenharmony_ci	"NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL",
9862306a36Sopenharmony_ci	"PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR",
9962306a36Sopenharmony_ci	"PC_ENABLE","PC_DISABLE",
10062306a36Sopenharmony_ci	"PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE",
10162306a36Sopenharmony_ci	"PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN",
10262306a36Sopenharmony_ci	"PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT",
10362306a36Sopenharmony_ci	"PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT",
10462306a36Sopenharmony_ci	"PC_NSE","PC_LEM"
10562306a36Sopenharmony_ci} ;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#ifdef	MOT_ELM
10862306a36Sopenharmony_ci/*
10962306a36Sopenharmony_ci * PCL-S control register
11062306a36Sopenharmony_ci * this register in the PLC-S controls the scrambling parameters
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_ci#define PLCS_CONTROL_C_U	0
11362306a36Sopenharmony_ci#define PLCS_CONTROL_C_S	(PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \
11462306a36Sopenharmony_ci				 PL_C_CIPHER_ENABLE)
11562306a36Sopenharmony_ci#define	PLCS_FASSERT_U		0
11662306a36Sopenharmony_ci#define	PLCS_FASSERT_S		0xFd76	/* 52.0 us */
11762306a36Sopenharmony_ci#define	PLCS_FDEASSERT_U	0
11862306a36Sopenharmony_ci#define	PLCS_FDEASSERT_S	0
11962306a36Sopenharmony_ci#else	/* nMOT_ELM */
12062306a36Sopenharmony_ci/*
12162306a36Sopenharmony_ci * PCL-S control register
12262306a36Sopenharmony_ci * this register in the PLC-S controls the scrambling parameters
12362306a36Sopenharmony_ci * can be patched for ANSI compliance if standard changes
12462306a36Sopenharmony_ci */
12562306a36Sopenharmony_cistatic const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ;
12662306a36Sopenharmony_cistatic const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8))
12962306a36Sopenharmony_ci#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8))
13062306a36Sopenharmony_ci#endif	/* nMOT_ELM */
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/*
13362306a36Sopenharmony_ci * external vars
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_ci/* struct definition see 'cmtdef.h' (also used by CFM) */
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#define PS_OFF		0
13862306a36Sopenharmony_ci#define PS_BIT3		1
13962306a36Sopenharmony_ci#define PS_BIT4		2
14062306a36Sopenharmony_ci#define PS_BIT7		3
14162306a36Sopenharmony_ci#define PS_LCT		4
14262306a36Sopenharmony_ci#define PS_BIT8		5
14362306a36Sopenharmony_ci#define PS_JOIN		6
14462306a36Sopenharmony_ci#define PS_ACTIVE	7
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#define LCT_LEM_MAX	255
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/*
14962306a36Sopenharmony_ci * PLC timing parameter
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#define PLC_MS(m)	((int)((0x10000L-(m*100000L/2048))))
15362306a36Sopenharmony_ci#define SLOW_TL_MIN	PLC_MS(6)
15462306a36Sopenharmony_ci#define SLOW_C_MIN	PLC_MS(10)
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic	const struct plt {
15762306a36Sopenharmony_ci	int	timer ;			/* relative plc timer address */
15862306a36Sopenharmony_ci	int	para ;			/* default timing parameters */
15962306a36Sopenharmony_ci} pltm[] = {
16062306a36Sopenharmony_ci	{ PL_C_MIN, SLOW_C_MIN },	/* min t. to remain Connect State */
16162306a36Sopenharmony_ci	{ PL_TL_MIN, SLOW_TL_MIN },	/* min t. to transmit a Line State */
16262306a36Sopenharmony_ci	{ PL_TB_MIN, TP_TB_MIN },	/* min break time */
16362306a36Sopenharmony_ci	{ PL_T_OUT, TP_T_OUT },		/* Signaling timeout */
16462306a36Sopenharmony_ci	{ PL_LC_LENGTH, TP_LC_LENGTH },	/* Link Confidence Test Time */
16562306a36Sopenharmony_ci	{ PL_T_SCRUB, TP_T_SCRUB },	/* Scrub Time == MAC TVX time ! */
16662306a36Sopenharmony_ci	{ PL_NS_MAX, TP_NS_MAX },	/* max t. that noise is tolerated */
16762306a36Sopenharmony_ci	{ 0,0 }
16862306a36Sopenharmony_ci} ;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/*
17162306a36Sopenharmony_ci * interrupt mask
17262306a36Sopenharmony_ci */
17362306a36Sopenharmony_ci#ifdef	SUPERNET_3
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci * Do we need the EBUF error during signaling, too, to detect SUPERNET_3
17662306a36Sopenharmony_ci * PLL bug?
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_cistatic const int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
17962306a36Sopenharmony_ci			PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
18062306a36Sopenharmony_ci#else	/* SUPERNET_3 */
18162306a36Sopenharmony_ci/*
18262306a36Sopenharmony_ci * We do NOT need the elasticity buffer error during signaling.
18362306a36Sopenharmony_ci */
18462306a36Sopenharmony_cistatic int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
18562306a36Sopenharmony_ci			PL_PCM_ENABLED | PL_SELF_TEST ;
18662306a36Sopenharmony_ci#endif	/* SUPERNET_3 */
18762306a36Sopenharmony_cistatic const int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
18862306a36Sopenharmony_ci			PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* internal functions */
19162306a36Sopenharmony_cistatic void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd);
19262306a36Sopenharmony_cistatic void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy);
19362306a36Sopenharmony_cistatic void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy);
19462306a36Sopenharmony_cistatic void reset_lem_struct(struct s_phy *phy);
19562306a36Sopenharmony_cistatic void plc_init(struct s_smc *smc, int p);
19662306a36Sopenharmony_cistatic void sm_ph_lem_start(struct s_smc *smc, int np, int threshold);
19762306a36Sopenharmony_cistatic void sm_ph_lem_stop(struct s_smc *smc, int np);
19862306a36Sopenharmony_cistatic void sm_ph_linestate(struct s_smc *smc, int phy, int ls);
19962306a36Sopenharmony_cistatic void real_init_plc(struct s_smc *smc);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/*
20262306a36Sopenharmony_ci * SMT timer interface
20362306a36Sopenharmony_ci *      start PCM timer 0
20462306a36Sopenharmony_ci */
20562306a36Sopenharmony_cistatic void start_pcm_timer0(struct s_smc *smc, u_long value, int event,
20662306a36Sopenharmony_ci			     struct s_phy *phy)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	phy->timer0_exp = FALSE ;       /* clear timer event flag */
20962306a36Sopenharmony_ci	smt_timer_start(smc,&phy->pcm_timer0,value,
21062306a36Sopenharmony_ci		EV_TOKEN(EVENT_PCM+phy->np,event)) ;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci/*
21362306a36Sopenharmony_ci * SMT timer interface
21462306a36Sopenharmony_ci *      stop PCM timer 0
21562306a36Sopenharmony_ci */
21662306a36Sopenharmony_cistatic void stop_pcm_timer0(struct s_smc *smc, struct s_phy *phy)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	if (phy->pcm_timer0.tm_active)
21962306a36Sopenharmony_ci		smt_timer_stop(smc,&phy->pcm_timer0) ;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/*
22362306a36Sopenharmony_ci	init PCM state machine (called by driver)
22462306a36Sopenharmony_ci	clear all PCM vars and flags
22562306a36Sopenharmony_ci*/
22662306a36Sopenharmony_civoid pcm_init(struct s_smc *smc)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	int		i ;
22962306a36Sopenharmony_ci	int		np ;
23062306a36Sopenharmony_ci	struct s_phy	*phy ;
23162306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) {
23462306a36Sopenharmony_ci		/* Indicates the type of PHY being used */
23562306a36Sopenharmony_ci		mib = phy->mib ;
23662306a36Sopenharmony_ci		mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ;
23762306a36Sopenharmony_ci		phy->np = np ;
23862306a36Sopenharmony_ci		switch (smc->s.sas) {
23962306a36Sopenharmony_ci#ifdef	CONCENTRATOR
24062306a36Sopenharmony_ci		case SMT_SAS :
24162306a36Sopenharmony_ci			mib->fddiPORTMy_Type = (np == PS) ? TS : TM ;
24262306a36Sopenharmony_ci			break ;
24362306a36Sopenharmony_ci		case SMT_DAS :
24462306a36Sopenharmony_ci			mib->fddiPORTMy_Type = (np == PA) ? TA :
24562306a36Sopenharmony_ci					(np == PB) ? TB : TM ;
24662306a36Sopenharmony_ci			break ;
24762306a36Sopenharmony_ci		case SMT_NAC :
24862306a36Sopenharmony_ci			mib->fddiPORTMy_Type = TM ;
24962306a36Sopenharmony_ci			break;
25062306a36Sopenharmony_ci#else
25162306a36Sopenharmony_ci		case SMT_SAS :
25262306a36Sopenharmony_ci			mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ;
25362306a36Sopenharmony_ci			mib->fddiPORTHardwarePresent = (np == PS) ? TRUE :
25462306a36Sopenharmony_ci					FALSE ;
25562306a36Sopenharmony_ci#ifndef	SUPERNET_3
25662306a36Sopenharmony_ci			smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ;
25762306a36Sopenharmony_ci#else
25862306a36Sopenharmony_ci			smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ;
25962306a36Sopenharmony_ci#endif
26062306a36Sopenharmony_ci			break ;
26162306a36Sopenharmony_ci		case SMT_DAS :
26262306a36Sopenharmony_ci			mib->fddiPORTMy_Type = (np == PB) ? TB : TA ;
26362306a36Sopenharmony_ci			break ;
26462306a36Sopenharmony_ci#endif
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci		/*
26762306a36Sopenharmony_ci		 * set PMD-type
26862306a36Sopenharmony_ci		 */
26962306a36Sopenharmony_ci		phy->pmd_scramble = 0 ;
27062306a36Sopenharmony_ci		switch (phy->pmd_type[PMD_SK_PMD]) {
27162306a36Sopenharmony_ci		case 'P' :
27262306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
27362306a36Sopenharmony_ci			break ;
27462306a36Sopenharmony_ci		case 'L' :
27562306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ;
27662306a36Sopenharmony_ci			break ;
27762306a36Sopenharmony_ci		case 'D' :
27862306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
27962306a36Sopenharmony_ci			break ;
28062306a36Sopenharmony_ci		case 'S' :
28162306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
28262306a36Sopenharmony_ci			phy->pmd_scramble = TRUE ;
28362306a36Sopenharmony_ci			break ;
28462306a36Sopenharmony_ci		case 'U' :
28562306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
28662306a36Sopenharmony_ci			phy->pmd_scramble = TRUE ;
28762306a36Sopenharmony_ci			break ;
28862306a36Sopenharmony_ci		case '1' :
28962306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
29062306a36Sopenharmony_ci			break ;
29162306a36Sopenharmony_ci		case '2' :
29262306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
29362306a36Sopenharmony_ci			break ;
29462306a36Sopenharmony_ci		case '3' :
29562306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
29662306a36Sopenharmony_ci			break ;
29762306a36Sopenharmony_ci		case '4' :
29862306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
29962306a36Sopenharmony_ci			break ;
30062306a36Sopenharmony_ci		case 'H' :
30162306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
30262306a36Sopenharmony_ci			break ;
30362306a36Sopenharmony_ci		case 'I' :
30462306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
30562306a36Sopenharmony_ci			break ;
30662306a36Sopenharmony_ci		case 'G' :
30762306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
30862306a36Sopenharmony_ci			break ;
30962306a36Sopenharmony_ci		default:
31062306a36Sopenharmony_ci			mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
31162306a36Sopenharmony_ci			break ;
31262306a36Sopenharmony_ci		}
31362306a36Sopenharmony_ci		/*
31462306a36Sopenharmony_ci		 * A and B port can be on primary and secondary path
31562306a36Sopenharmony_ci		 */
31662306a36Sopenharmony_ci		switch (mib->fddiPORTMy_Type) {
31762306a36Sopenharmony_ci		case TA :
31862306a36Sopenharmony_ci			mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
31962306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
32062306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[2] =
32162306a36Sopenharmony_ci				MIB_P_PATH_LOCAL |
32262306a36Sopenharmony_ci				MIB_P_PATH_CON_ALTER |
32362306a36Sopenharmony_ci				MIB_P_PATH_SEC_PREFER ;
32462306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[3] =
32562306a36Sopenharmony_ci				MIB_P_PATH_LOCAL |
32662306a36Sopenharmony_ci				MIB_P_PATH_CON_ALTER |
32762306a36Sopenharmony_ci				MIB_P_PATH_SEC_PREFER |
32862306a36Sopenharmony_ci				MIB_P_PATH_THRU ;
32962306a36Sopenharmony_ci			break ;
33062306a36Sopenharmony_ci		case TB :
33162306a36Sopenharmony_ci			mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
33262306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
33362306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[2] =
33462306a36Sopenharmony_ci				MIB_P_PATH_LOCAL |
33562306a36Sopenharmony_ci				MIB_P_PATH_PRIM_PREFER ;
33662306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[3] =
33762306a36Sopenharmony_ci				MIB_P_PATH_LOCAL |
33862306a36Sopenharmony_ci				MIB_P_PATH_PRIM_PREFER |
33962306a36Sopenharmony_ci				MIB_P_PATH_CON_PREFER |
34062306a36Sopenharmony_ci				MIB_P_PATH_THRU ;
34162306a36Sopenharmony_ci			break ;
34262306a36Sopenharmony_ci		case TS :
34362306a36Sopenharmony_ci			mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
34462306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
34562306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[2] =
34662306a36Sopenharmony_ci				MIB_P_PATH_LOCAL |
34762306a36Sopenharmony_ci				MIB_P_PATH_CON_ALTER |
34862306a36Sopenharmony_ci				MIB_P_PATH_PRIM_PREFER ;
34962306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[3] =
35062306a36Sopenharmony_ci				MIB_P_PATH_LOCAL |
35162306a36Sopenharmony_ci				MIB_P_PATH_CON_ALTER |
35262306a36Sopenharmony_ci				MIB_P_PATH_PRIM_PREFER ;
35362306a36Sopenharmony_ci			break ;
35462306a36Sopenharmony_ci		case TM :
35562306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
35662306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[2] =
35762306a36Sopenharmony_ci				MIB_P_PATH_LOCAL |
35862306a36Sopenharmony_ci				MIB_P_PATH_SEC_ALTER |
35962306a36Sopenharmony_ci				MIB_P_PATH_PRIM_ALTER ;
36062306a36Sopenharmony_ci			mib->fddiPORTRequestedPaths[3] = 0 ;
36162306a36Sopenharmony_ci			break ;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		phy->pc_lem_fail = FALSE ;
36562306a36Sopenharmony_ci		mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ;
36662306a36Sopenharmony_ci		mib->fddiPORTLCTFail_Ct = 0 ;
36762306a36Sopenharmony_ci		mib->fddiPORTBS_Flag = 0 ;
36862306a36Sopenharmony_ci		mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
36962306a36Sopenharmony_ci		mib->fddiPORTNeighborType = TNONE ;
37062306a36Sopenharmony_ci		phy->ls_flag = 0 ;
37162306a36Sopenharmony_ci		phy->rc_flag = 0 ;
37262306a36Sopenharmony_ci		phy->tc_flag = 0 ;
37362306a36Sopenharmony_ci		phy->td_flag = 0 ;
37462306a36Sopenharmony_ci		if (np >= PM)
37562306a36Sopenharmony_ci			phy->phy_name = '0' + np - PM ;
37662306a36Sopenharmony_ci		else
37762306a36Sopenharmony_ci			phy->phy_name = 'A' + np ;
37862306a36Sopenharmony_ci		phy->wc_flag = FALSE ;		/* set by SMT */
37962306a36Sopenharmony_ci		memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ;
38062306a36Sopenharmony_ci		reset_lem_struct(phy) ;
38162306a36Sopenharmony_ci		memset((char *)&phy->plc,0,sizeof(struct s_plc)) ;
38262306a36Sopenharmony_ci		phy->plc.p_state = PS_OFF ;
38362306a36Sopenharmony_ci		for (i = 0 ; i < NUMBITS ; i++) {
38462306a36Sopenharmony_ci			phy->t_next[i] = 0 ;
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	real_init_plc(smc) ;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_civoid init_plc(struct s_smc *smc)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	SK_UNUSED(smc) ;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/*
39562306a36Sopenharmony_ci	 * dummy
39662306a36Sopenharmony_ci	 * this is an obsolete public entry point that has to remain
39762306a36Sopenharmony_ci	 * for compat. It is used by various drivers.
39862306a36Sopenharmony_ci	 * the work is now done in real_init_plc()
39962306a36Sopenharmony_ci	 * which is called from pcm_init() ;
40062306a36Sopenharmony_ci	 */
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic void real_init_plc(struct s_smc *smc)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	int	p ;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	for (p = 0 ; p < NUMPHYS ; p++)
40862306a36Sopenharmony_ci		plc_init(smc,p) ;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic void plc_init(struct s_smc *smc, int p)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	int	i ;
41462306a36Sopenharmony_ci#ifndef	MOT_ELM
41562306a36Sopenharmony_ci	int	rev ;	/* Revision of PLC-x */
41662306a36Sopenharmony_ci#endif	/* MOT_ELM */
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* transit PCM state machine to MAINT state */
41962306a36Sopenharmony_ci	outpw(PLC(p,PL_CNTRL_B),0) ;
42062306a36Sopenharmony_ci	outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ;
42162306a36Sopenharmony_ci	outpw(PLC(p,PL_CNTRL_A),0) ;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/*
42462306a36Sopenharmony_ci	 * if PLC-S then set control register C
42562306a36Sopenharmony_ci	 */
42662306a36Sopenharmony_ci#ifndef	MOT_ELM
42762306a36Sopenharmony_ci	rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ;
42862306a36Sopenharmony_ci	if (rev != PLC_REVISION_A)
42962306a36Sopenharmony_ci#endif	/* MOT_ELM */
43062306a36Sopenharmony_ci	{
43162306a36Sopenharmony_ci		if (smc->y[p].pmd_scramble) {
43262306a36Sopenharmony_ci			outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ;
43362306a36Sopenharmony_ci#ifdef	MOT_ELM
43462306a36Sopenharmony_ci			outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ;
43562306a36Sopenharmony_ci			outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ;
43662306a36Sopenharmony_ci#endif	/* MOT_ELM */
43762306a36Sopenharmony_ci		}
43862306a36Sopenharmony_ci		else {
43962306a36Sopenharmony_ci			outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ;
44062306a36Sopenharmony_ci#ifdef	MOT_ELM
44162306a36Sopenharmony_ci			outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ;
44262306a36Sopenharmony_ci			outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ;
44362306a36Sopenharmony_ci#endif	/* MOT_ELM */
44462306a36Sopenharmony_ci		}
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/*
44862306a36Sopenharmony_ci	 * set timer register
44962306a36Sopenharmony_ci	 */
45062306a36Sopenharmony_ci	for ( i = 0 ; pltm[i].timer; i++)	/* set timer parameter reg */
45162306a36Sopenharmony_ci		outpw(PLC(p,pltm[i].timer),pltm[i].para) ;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	(void)inpw(PLC(p,PL_INTR_EVENT)) ;	/* clear interrupt event reg */
45462306a36Sopenharmony_ci	plc_clear_irq(smc,p) ;
45562306a36Sopenharmony_ci	outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	/*
45862306a36Sopenharmony_ci	 * if PCM is configured for class s, it will NOT go to the
45962306a36Sopenharmony_ci	 * REMOVE state if offline (page 3-36;)
46062306a36Sopenharmony_ci	 * in the concentrator, all inactive PHYS always must be in
46162306a36Sopenharmony_ci	 * the remove state
46262306a36Sopenharmony_ci	 * there's no real need to use this feature at all ..
46362306a36Sopenharmony_ci	 */
46462306a36Sopenharmony_ci#ifndef	CONCENTRATOR
46562306a36Sopenharmony_ci	if ((smc->s.sas == SMT_SAS) && (p == PS)) {
46662306a36Sopenharmony_ci		outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci#endif
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci/*
47262306a36Sopenharmony_ci * control PCM state machine
47362306a36Sopenharmony_ci */
47462306a36Sopenharmony_cistatic void plc_go_state(struct s_smc *smc, int p, int state)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	HW_PTR port ;
47762306a36Sopenharmony_ci	int val ;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	SK_UNUSED(smc) ;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ;
48262306a36Sopenharmony_ci	val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ;
48362306a36Sopenharmony_ci	outpw(port,val) ;
48462306a36Sopenharmony_ci	outpw(port,val | state) ;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/*
48862306a36Sopenharmony_ci * read current line state (called by ECM & PCM)
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_ciint sm_pm_get_ls(struct s_smc *smc, int phy)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	int	state ;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci#ifdef	CONCENTRATOR
49562306a36Sopenharmony_ci	if (!plc_is_installed(smc,phy))
49662306a36Sopenharmony_ci		return PC_QLS;
49762306a36Sopenharmony_ci#endif
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ;
50062306a36Sopenharmony_ci	switch(state) {
50162306a36Sopenharmony_ci	case PL_L_QLS:
50262306a36Sopenharmony_ci		state = PC_QLS ;
50362306a36Sopenharmony_ci		break ;
50462306a36Sopenharmony_ci	case PL_L_MLS:
50562306a36Sopenharmony_ci		state = PC_MLS ;
50662306a36Sopenharmony_ci		break ;
50762306a36Sopenharmony_ci	case PL_L_HLS:
50862306a36Sopenharmony_ci		state = PC_HLS ;
50962306a36Sopenharmony_ci		break ;
51062306a36Sopenharmony_ci	case PL_L_ILS4:
51162306a36Sopenharmony_ci	case PL_L_ILS16:
51262306a36Sopenharmony_ci		state = PC_ILS ;
51362306a36Sopenharmony_ci		break ;
51462306a36Sopenharmony_ci	case PL_L_ALS:
51562306a36Sopenharmony_ci		state = PC_LS_PDR ;
51662306a36Sopenharmony_ci		break ;
51762306a36Sopenharmony_ci	default :
51862306a36Sopenharmony_ci		state = PC_LS_NONE ;
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci	return state;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	int np = phy->np ;		/* PHY index */
52662306a36Sopenharmony_ci	int	n ;
52762306a36Sopenharmony_ci	int	i ;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	SK_UNUSED(smc) ;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* create bit vector */
53262306a36Sopenharmony_ci	for (i = len-1,n = 0 ; i >= 0 ; i--) {
53362306a36Sopenharmony_ci		n = (n<<1) | phy->t_val[phy->bitn+i] ;
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci	if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
53662306a36Sopenharmony_ci#if	0
53762306a36Sopenharmony_ci		printf("PL_PCM_SIGNAL is set\n") ;
53862306a36Sopenharmony_ci#endif
53962306a36Sopenharmony_ci		return 1;
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci	/* write bit[n] & length = 1 to regs */
54262306a36Sopenharmony_ci	outpw(PLC(np,PL_VECTOR_LEN),len-1) ;	/* len=nr-1 */
54362306a36Sopenharmony_ci	outpw(PLC(np,PL_XMIT_VECTOR),n) ;
54462306a36Sopenharmony_ci#ifdef	DEBUG
54562306a36Sopenharmony_ci#if 1
54662306a36Sopenharmony_ci#ifdef	DEBUG_BRD
54762306a36Sopenharmony_ci	if (smc->debug.d_plc & 0x80)
54862306a36Sopenharmony_ci#else
54962306a36Sopenharmony_ci	if (debug.d_plc & 0x80)
55062306a36Sopenharmony_ci#endif
55162306a36Sopenharmony_ci		printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ;
55262306a36Sopenharmony_ci#endif
55362306a36Sopenharmony_ci#endif
55462306a36Sopenharmony_ci	return 0;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/*
55862306a36Sopenharmony_ci * config plc muxes
55962306a36Sopenharmony_ci */
56062306a36Sopenharmony_civoid plc_config_mux(struct s_smc *smc, int mux)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	if (smc->s.sas != SMT_DAS)
56362306a36Sopenharmony_ci		return ;
56462306a36Sopenharmony_ci	if (mux == MUX_WRAPB) {
56562306a36Sopenharmony_ci		SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
56662306a36Sopenharmony_ci		SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci	else {
56962306a36Sopenharmony_ci		CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
57062306a36Sopenharmony_ci		CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci	CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
57362306a36Sopenharmony_ci	CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci/*
57762306a36Sopenharmony_ci	PCM state machine
57862306a36Sopenharmony_ci	called by dispatcher  & fddi_init() (driver)
57962306a36Sopenharmony_ci	do
58062306a36Sopenharmony_ci		display state change
58162306a36Sopenharmony_ci		process event
58262306a36Sopenharmony_ci	until SM is stable
58362306a36Sopenharmony_ci*/
58462306a36Sopenharmony_civoid pcm(struct s_smc *smc, const int np, int event)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	int	state ;
58762306a36Sopenharmony_ci	int	oldstate ;
58862306a36Sopenharmony_ci	struct s_phy	*phy ;
58962306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci#ifndef	CONCENTRATOR
59262306a36Sopenharmony_ci	/*
59362306a36Sopenharmony_ci	 * ignore 2nd PHY if SAS
59462306a36Sopenharmony_ci	 */
59562306a36Sopenharmony_ci	if ((np != PS) && (smc->s.sas == SMT_SAS))
59662306a36Sopenharmony_ci		return ;
59762306a36Sopenharmony_ci#endif
59862306a36Sopenharmony_ci	phy = &smc->y[np] ;
59962306a36Sopenharmony_ci	mib = phy->mib ;
60062306a36Sopenharmony_ci	oldstate = mib->fddiPORTPCMState ;
60162306a36Sopenharmony_ci	do {
60262306a36Sopenharmony_ci		DB_PCM("PCM %c: state %s%s, event %s",
60362306a36Sopenharmony_ci		       phy->phy_name,
60462306a36Sopenharmony_ci		       mib->fddiPORTPCMState & AFLAG ? "ACTIONS " : "",
60562306a36Sopenharmony_ci		       pcm_states[mib->fddiPORTPCMState & ~AFLAG],
60662306a36Sopenharmony_ci		       pcm_events[event]);
60762306a36Sopenharmony_ci		state = mib->fddiPORTPCMState ;
60862306a36Sopenharmony_ci		pcm_fsm(smc,phy,event) ;
60962306a36Sopenharmony_ci		event = 0 ;
61062306a36Sopenharmony_ci	} while (state != mib->fddiPORTPCMState) ;
61162306a36Sopenharmony_ci	/*
61262306a36Sopenharmony_ci	 * because the PLC does the bit signaling for us,
61362306a36Sopenharmony_ci	 * we're always in SIGNAL state
61462306a36Sopenharmony_ci	 * the MIB want's to see CONNECT
61562306a36Sopenharmony_ci	 * we therefore fake an entry in the MIB
61662306a36Sopenharmony_ci	 */
61762306a36Sopenharmony_ci	if (state == PC5_SIGNAL)
61862306a36Sopenharmony_ci		mib->fddiPORTPCMStateX = PC3_CONNECT ;
61962306a36Sopenharmony_ci	else
62062306a36Sopenharmony_ci		mib->fddiPORTPCMStateX = state ;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci#ifndef	SLIM_SMT
62362306a36Sopenharmony_ci	/*
62462306a36Sopenharmony_ci	 * path change
62562306a36Sopenharmony_ci	 */
62662306a36Sopenharmony_ci	if (	mib->fddiPORTPCMState != oldstate &&
62762306a36Sopenharmony_ci		((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) {
62862306a36Sopenharmony_ci		smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE,
62962306a36Sopenharmony_ci			(int) (INDEX_PORT+ phy->np),0) ;
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci#endif
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci#ifdef FDDI_MIB
63462306a36Sopenharmony_ci	/* check whether a snmp-trap has to be sent */
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	if ( mib->fddiPORTPCMState != oldstate ) {
63762306a36Sopenharmony_ci		/* a real state change took place */
63862306a36Sopenharmony_ci		DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState);
63962306a36Sopenharmony_ci		if ( mib->fddiPORTPCMState == PC0_OFF ) {
64062306a36Sopenharmony_ci			/* send first trap */
64162306a36Sopenharmony_ci			snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex );
64262306a36Sopenharmony_ci		} else if ( oldstate == PC0_OFF ) {
64362306a36Sopenharmony_ci			/* send second trap */
64462306a36Sopenharmony_ci			snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex );
64562306a36Sopenharmony_ci		} else if ( mib->fddiPORTPCMState != PC2_TRACE &&
64662306a36Sopenharmony_ci			oldstate == PC8_ACTIVE ) {
64762306a36Sopenharmony_ci			/* send third trap */
64862306a36Sopenharmony_ci			snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex );
64962306a36Sopenharmony_ci		} else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) {
65062306a36Sopenharmony_ci			/* send fourth trap */
65162306a36Sopenharmony_ci			snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex );
65262306a36Sopenharmony_ci		}
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci#endif
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	pcm_state_change(smc,np,state) ;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/*
66062306a36Sopenharmony_ci * PCM state machine
66162306a36Sopenharmony_ci */
66262306a36Sopenharmony_cistatic void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	int	i ;
66562306a36Sopenharmony_ci	int	np = phy->np ;		/* PHY index */
66662306a36Sopenharmony_ci	struct s_plc	*plc ;
66762306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
66862306a36Sopenharmony_ci#ifndef	MOT_ELM
66962306a36Sopenharmony_ci	u_short	plc_rev ;		/* Revision of the plc */
67062306a36Sopenharmony_ci#endif	/* nMOT_ELM */
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	plc = &phy->plc ;
67362306a36Sopenharmony_ci	mib = phy->mib ;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/*
67662306a36Sopenharmony_ci	 * general transitions independent of state
67762306a36Sopenharmony_ci	 */
67862306a36Sopenharmony_ci	switch (cmd) {
67962306a36Sopenharmony_ci	case PC_STOP :
68062306a36Sopenharmony_ci		/*PC00-PC80*/
68162306a36Sopenharmony_ci		if (mib->fddiPORTPCMState != PC9_MAINT) {
68262306a36Sopenharmony_ci			GO_STATE(PC0_OFF) ;
68362306a36Sopenharmony_ci			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
68462306a36Sopenharmony_ci				FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP,
68562306a36Sopenharmony_ci				smt_get_port_event_word(smc));
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci		return ;
68862306a36Sopenharmony_ci	case PC_START :
68962306a36Sopenharmony_ci		/*PC01-PC81*/
69062306a36Sopenharmony_ci		if (mib->fddiPORTPCMState != PC9_MAINT)
69162306a36Sopenharmony_ci			GO_STATE(PC1_BREAK) ;
69262306a36Sopenharmony_ci		return ;
69362306a36Sopenharmony_ci	case PC_DISABLE :
69462306a36Sopenharmony_ci		/* PC09-PC99 */
69562306a36Sopenharmony_ci		GO_STATE(PC9_MAINT) ;
69662306a36Sopenharmony_ci		AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
69762306a36Sopenharmony_ci			FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED,
69862306a36Sopenharmony_ci			smt_get_port_event_word(smc));
69962306a36Sopenharmony_ci		return ;
70062306a36Sopenharmony_ci	case PC_TIMEOUT_LCT :
70162306a36Sopenharmony_ci		/* if long or extended LCT */
70262306a36Sopenharmony_ci		stop_pcm_timer0(smc,phy) ;
70362306a36Sopenharmony_ci		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
70462306a36Sopenharmony_ci		/* end of LCT is indicate by PCM_CODE (initiate PCM event) */
70562306a36Sopenharmony_ci		return ;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	switch(mib->fddiPORTPCMState) {
70962306a36Sopenharmony_ci	case ACTIONS(PC0_OFF) :
71062306a36Sopenharmony_ci		stop_pcm_timer0(smc,phy) ;
71162306a36Sopenharmony_ci		outpw(PLC(np,PL_CNTRL_A),0) ;
71262306a36Sopenharmony_ci		CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
71362306a36Sopenharmony_ci		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
71462306a36Sopenharmony_ci		sm_ph_lem_stop(smc,np) ;		/* disable LEM */
71562306a36Sopenharmony_ci		phy->cf_loop = FALSE ;
71662306a36Sopenharmony_ci		phy->cf_join = FALSE ;
71762306a36Sopenharmony_ci		queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
71862306a36Sopenharmony_ci		plc_go_state(smc,np,PL_PCM_STOP) ;
71962306a36Sopenharmony_ci		mib->fddiPORTConnectState = PCM_DISABLED ;
72062306a36Sopenharmony_ci		ACTIONS_DONE() ;
72162306a36Sopenharmony_ci		break ;
72262306a36Sopenharmony_ci	case PC0_OFF:
72362306a36Sopenharmony_ci		/*PC09*/
72462306a36Sopenharmony_ci		if (cmd == PC_MAINT) {
72562306a36Sopenharmony_ci			GO_STATE(PC9_MAINT) ;
72662306a36Sopenharmony_ci			break ;
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci		break ;
72962306a36Sopenharmony_ci	case ACTIONS(PC1_BREAK) :
73062306a36Sopenharmony_ci		/* Stop the LCT timer if we came from Signal state */
73162306a36Sopenharmony_ci		stop_pcm_timer0(smc,phy) ;
73262306a36Sopenharmony_ci		ACTIONS_DONE() ;
73362306a36Sopenharmony_ci		plc_go_state(smc,np,0) ;
73462306a36Sopenharmony_ci		CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
73562306a36Sopenharmony_ci		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
73662306a36Sopenharmony_ci		sm_ph_lem_stop(smc,np) ;		/* disable LEM */
73762306a36Sopenharmony_ci		/*
73862306a36Sopenharmony_ci		 * if vector is already loaded, go to OFF to clear PCM_SIGNAL
73962306a36Sopenharmony_ci		 */
74062306a36Sopenharmony_ci#if	0
74162306a36Sopenharmony_ci		if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
74262306a36Sopenharmony_ci			plc_go_state(smc,np,PL_PCM_STOP) ;
74362306a36Sopenharmony_ci			/* TB_MIN ? */
74462306a36Sopenharmony_ci		}
74562306a36Sopenharmony_ci#endif
74662306a36Sopenharmony_ci		/*
74762306a36Sopenharmony_ci		 * Go to OFF state in any case.
74862306a36Sopenharmony_ci		 */
74962306a36Sopenharmony_ci		plc_go_state(smc,np,PL_PCM_STOP) ;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		if (mib->fddiPORTPC_Withhold == PC_WH_NONE)
75262306a36Sopenharmony_ci			mib->fddiPORTConnectState = PCM_CONNECTING ;
75362306a36Sopenharmony_ci		phy->cf_loop = FALSE ;
75462306a36Sopenharmony_ci		phy->cf_join = FALSE ;
75562306a36Sopenharmony_ci		queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
75662306a36Sopenharmony_ci		phy->ls_flag = FALSE ;
75762306a36Sopenharmony_ci		phy->pc_mode = PM_NONE ;	/* needed by CFM */
75862306a36Sopenharmony_ci		phy->bitn = 0 ;			/* bit signaling start bit */
75962306a36Sopenharmony_ci		for (i = 0 ; i < 3 ; i++)
76062306a36Sopenharmony_ci			pc_tcode_actions(smc,i,phy) ;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci		/* Set the non-active interrupt mask register */
76362306a36Sopenharmony_ci		outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		/*
76662306a36Sopenharmony_ci		 * If the LCT was stopped. There might be a
76762306a36Sopenharmony_ci		 * PCM_CODE interrupt event present.
76862306a36Sopenharmony_ci		 * This must be cleared.
76962306a36Sopenharmony_ci		 */
77062306a36Sopenharmony_ci		(void)inpw(PLC(np,PL_INTR_EVENT)) ;
77162306a36Sopenharmony_ci#ifndef	MOT_ELM
77262306a36Sopenharmony_ci		/* Get the plc revision for revision dependent code */
77362306a36Sopenharmony_ci		plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		if (plc_rev != PLC_REV_SN3)
77662306a36Sopenharmony_ci#endif	/* MOT_ELM */
77762306a36Sopenharmony_ci		{
77862306a36Sopenharmony_ci			/*
77962306a36Sopenharmony_ci			 * No supernet III PLC, so set Xmit verctor and
78062306a36Sopenharmony_ci			 * length BEFORE starting the state machine.
78162306a36Sopenharmony_ci			 */
78262306a36Sopenharmony_ci			if (plc_send_bits(smc,phy,3)) {
78362306a36Sopenharmony_ci				return ;
78462306a36Sopenharmony_ci			}
78562306a36Sopenharmony_ci		}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci		/*
78862306a36Sopenharmony_ci		 * Now give the Start command.
78962306a36Sopenharmony_ci		 * - The start command shall be done before setting the bits
79062306a36Sopenharmony_ci		 *   to be signaled. (In PLC-S description and PLCS in SN3.
79162306a36Sopenharmony_ci		 * - The start command shall be issued AFTER setting the
79262306a36Sopenharmony_ci		 *   XMIT vector and the XMIT length register.
79362306a36Sopenharmony_ci		 *
79462306a36Sopenharmony_ci		 * We do it exactly according this specs for the old PLC and
79562306a36Sopenharmony_ci		 * the new PLCS inside the SN3.
79662306a36Sopenharmony_ci		 * For the usual PLCS we try it the way it is done for the
79762306a36Sopenharmony_ci		 * old PLC and set the XMIT registers again, if the PLC is
79862306a36Sopenharmony_ci		 * not in SIGNAL state. This is done according to an PLCS
79962306a36Sopenharmony_ci		 * errata workaround.
80062306a36Sopenharmony_ci		 */
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci		plc_go_state(smc,np,PL_PCM_START) ;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		/*
80562306a36Sopenharmony_ci		 * workaround for PLC-S eng. sample errata
80662306a36Sopenharmony_ci		 */
80762306a36Sopenharmony_ci#ifdef	MOT_ELM
80862306a36Sopenharmony_ci		if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
80962306a36Sopenharmony_ci#else	/* nMOT_ELM */
81062306a36Sopenharmony_ci		if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) !=
81162306a36Sopenharmony_ci			PLC_REVISION_A) &&
81262306a36Sopenharmony_ci			!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
81362306a36Sopenharmony_ci#endif	/* nMOT_ELM */
81462306a36Sopenharmony_ci		{
81562306a36Sopenharmony_ci			/*
81662306a36Sopenharmony_ci			 * Set register again (PLCS errata) or the first time
81762306a36Sopenharmony_ci			 * (new SN3 PLCS).
81862306a36Sopenharmony_ci			 */
81962306a36Sopenharmony_ci			(void) plc_send_bits(smc,phy,3) ;
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci		/*
82262306a36Sopenharmony_ci		 * end of workaround
82362306a36Sopenharmony_ci		 */
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		GO_STATE(PC5_SIGNAL) ;
82662306a36Sopenharmony_ci		plc->p_state = PS_BIT3 ;
82762306a36Sopenharmony_ci		plc->p_bits = 3 ;
82862306a36Sopenharmony_ci		plc->p_start = 0 ;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		break ;
83162306a36Sopenharmony_ci	case PC1_BREAK :
83262306a36Sopenharmony_ci		break ;
83362306a36Sopenharmony_ci	case ACTIONS(PC2_TRACE) :
83462306a36Sopenharmony_ci		plc_go_state(smc,np,PL_PCM_TRACE) ;
83562306a36Sopenharmony_ci		ACTIONS_DONE() ;
83662306a36Sopenharmony_ci		break ;
83762306a36Sopenharmony_ci	case PC2_TRACE :
83862306a36Sopenharmony_ci		break ;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	case PC3_CONNECT :	/* these states are done by hardware */
84162306a36Sopenharmony_ci	case PC4_NEXT :
84262306a36Sopenharmony_ci		break ;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	case ACTIONS(PC5_SIGNAL) :
84562306a36Sopenharmony_ci		ACTIONS_DONE() ;
84662306a36Sopenharmony_ci		fallthrough;
84762306a36Sopenharmony_ci	case PC5_SIGNAL :
84862306a36Sopenharmony_ci		if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT))
84962306a36Sopenharmony_ci			break ;
85062306a36Sopenharmony_ci		switch (plc->p_state) {
85162306a36Sopenharmony_ci		case PS_BIT3 :
85262306a36Sopenharmony_ci			for (i = 0 ; i <= 2 ; i++)
85362306a36Sopenharmony_ci				pc_rcode_actions(smc,i,phy) ;
85462306a36Sopenharmony_ci			pc_tcode_actions(smc,3,phy) ;
85562306a36Sopenharmony_ci			plc->p_state = PS_BIT4 ;
85662306a36Sopenharmony_ci			plc->p_bits = 1 ;
85762306a36Sopenharmony_ci			plc->p_start = 3 ;
85862306a36Sopenharmony_ci			phy->bitn = 3 ;
85962306a36Sopenharmony_ci			if (plc_send_bits(smc,phy,1)) {
86062306a36Sopenharmony_ci				return ;
86162306a36Sopenharmony_ci			}
86262306a36Sopenharmony_ci			break ;
86362306a36Sopenharmony_ci		case PS_BIT4 :
86462306a36Sopenharmony_ci			pc_rcode_actions(smc,3,phy) ;
86562306a36Sopenharmony_ci			for (i = 4 ; i <= 6 ; i++)
86662306a36Sopenharmony_ci				pc_tcode_actions(smc,i,phy) ;
86762306a36Sopenharmony_ci			plc->p_state = PS_BIT7 ;
86862306a36Sopenharmony_ci			plc->p_bits = 3 ;
86962306a36Sopenharmony_ci			plc->p_start = 4 ;
87062306a36Sopenharmony_ci			phy->bitn = 4 ;
87162306a36Sopenharmony_ci			if (plc_send_bits(smc,phy,3)) {
87262306a36Sopenharmony_ci				return ;
87362306a36Sopenharmony_ci			}
87462306a36Sopenharmony_ci			break ;
87562306a36Sopenharmony_ci		case PS_BIT7 :
87662306a36Sopenharmony_ci			for (i = 3 ; i <= 6 ; i++)
87762306a36Sopenharmony_ci				pc_rcode_actions(smc,i,phy) ;
87862306a36Sopenharmony_ci			plc->p_state = PS_LCT ;
87962306a36Sopenharmony_ci			plc->p_bits = 0 ;
88062306a36Sopenharmony_ci			plc->p_start = 7 ;
88162306a36Sopenharmony_ci			phy->bitn = 7 ;
88262306a36Sopenharmony_ci		sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */
88362306a36Sopenharmony_ci			/* start LCT */
88462306a36Sopenharmony_ci			i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ;
88562306a36Sopenharmony_ci			outpw(PLC(np,PL_CNTRL_B),i) ;	/* must be cleared */
88662306a36Sopenharmony_ci			outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ;
88762306a36Sopenharmony_ci			break ;
88862306a36Sopenharmony_ci		case PS_LCT :
88962306a36Sopenharmony_ci			/* check for local LCT failure */
89062306a36Sopenharmony_ci			pc_tcode_actions(smc,7,phy) ;
89162306a36Sopenharmony_ci			/*
89262306a36Sopenharmony_ci			 * set tval[7]
89362306a36Sopenharmony_ci			 */
89462306a36Sopenharmony_ci			plc->p_state = PS_BIT8 ;
89562306a36Sopenharmony_ci			plc->p_bits = 1 ;
89662306a36Sopenharmony_ci			plc->p_start = 7 ;
89762306a36Sopenharmony_ci			phy->bitn = 7 ;
89862306a36Sopenharmony_ci			if (plc_send_bits(smc,phy,1)) {
89962306a36Sopenharmony_ci				return ;
90062306a36Sopenharmony_ci			}
90162306a36Sopenharmony_ci			break ;
90262306a36Sopenharmony_ci		case PS_BIT8 :
90362306a36Sopenharmony_ci			/* check for remote LCT failure */
90462306a36Sopenharmony_ci			pc_rcode_actions(smc,7,phy) ;
90562306a36Sopenharmony_ci			if (phy->t_val[7] || phy->r_val[7]) {
90662306a36Sopenharmony_ci				plc_go_state(smc,np,PL_PCM_STOP) ;
90762306a36Sopenharmony_ci				GO_STATE(PC1_BREAK) ;
90862306a36Sopenharmony_ci				break ;
90962306a36Sopenharmony_ci			}
91062306a36Sopenharmony_ci			for (i = 8 ; i <= 9 ; i++)
91162306a36Sopenharmony_ci				pc_tcode_actions(smc,i,phy) ;
91262306a36Sopenharmony_ci			plc->p_state = PS_JOIN ;
91362306a36Sopenharmony_ci			plc->p_bits = 2 ;
91462306a36Sopenharmony_ci			plc->p_start = 8 ;
91562306a36Sopenharmony_ci			phy->bitn = 8 ;
91662306a36Sopenharmony_ci			if (plc_send_bits(smc,phy,2)) {
91762306a36Sopenharmony_ci				return ;
91862306a36Sopenharmony_ci			}
91962306a36Sopenharmony_ci			break ;
92062306a36Sopenharmony_ci		case PS_JOIN :
92162306a36Sopenharmony_ci			for (i = 8 ; i <= 9 ; i++)
92262306a36Sopenharmony_ci				pc_rcode_actions(smc,i,phy) ;
92362306a36Sopenharmony_ci			plc->p_state = PS_ACTIVE ;
92462306a36Sopenharmony_ci			GO_STATE(PC6_JOIN) ;
92562306a36Sopenharmony_ci			break ;
92662306a36Sopenharmony_ci		}
92762306a36Sopenharmony_ci		break ;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	case ACTIONS(PC6_JOIN) :
93062306a36Sopenharmony_ci		/*
93162306a36Sopenharmony_ci		 * prevent mux error when going from WRAP_A to WRAP_B
93262306a36Sopenharmony_ci		 */
93362306a36Sopenharmony_ci		if (smc->s.sas == SMT_DAS && np == PB &&
93462306a36Sopenharmony_ci			(smc->y[PA].pc_mode == PM_TREE ||
93562306a36Sopenharmony_ci			 smc->y[PB].pc_mode == PM_TREE)) {
93662306a36Sopenharmony_ci			SETMASK(PLC(np,PL_CNTRL_A),
93762306a36Sopenharmony_ci				PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
93862306a36Sopenharmony_ci			SETMASK(PLC(np,PL_CNTRL_B),
93962306a36Sopenharmony_ci				PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
94062306a36Sopenharmony_ci		}
94162306a36Sopenharmony_ci		SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
94262306a36Sopenharmony_ci		SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
94362306a36Sopenharmony_ci		ACTIONS_DONE() ;
94462306a36Sopenharmony_ci		cmd = 0 ;
94562306a36Sopenharmony_ci		fallthrough;
94662306a36Sopenharmony_ci	case PC6_JOIN :
94762306a36Sopenharmony_ci		switch (plc->p_state) {
94862306a36Sopenharmony_ci		case PS_ACTIVE:
94962306a36Sopenharmony_ci			/*PC88b*/
95062306a36Sopenharmony_ci			if (!phy->cf_join) {
95162306a36Sopenharmony_ci				phy->cf_join = TRUE ;
95262306a36Sopenharmony_ci				queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
95362306a36Sopenharmony_ci			}
95462306a36Sopenharmony_ci			if (cmd == PC_JOIN)
95562306a36Sopenharmony_ci				GO_STATE(PC8_ACTIVE) ;
95662306a36Sopenharmony_ci			/*PC82*/
95762306a36Sopenharmony_ci			if (cmd == PC_TRACE) {
95862306a36Sopenharmony_ci				GO_STATE(PC2_TRACE) ;
95962306a36Sopenharmony_ci				break ;
96062306a36Sopenharmony_ci			}
96162306a36Sopenharmony_ci			break ;
96262306a36Sopenharmony_ci		}
96362306a36Sopenharmony_ci		break ;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	case PC7_VERIFY :
96662306a36Sopenharmony_ci		break ;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	case ACTIONS(PC8_ACTIVE) :
96962306a36Sopenharmony_ci		/*
97062306a36Sopenharmony_ci		 * start LEM for SMT
97162306a36Sopenharmony_ci		 */
97262306a36Sopenharmony_ci		sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci		phy->tr_flag = FALSE ;
97562306a36Sopenharmony_ci		mib->fddiPORTConnectState = PCM_ACTIVE ;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci		/* Set the active interrupt mask register */
97862306a36Sopenharmony_ci		outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci		ACTIONS_DONE() ;
98162306a36Sopenharmony_ci		break ;
98262306a36Sopenharmony_ci	case PC8_ACTIVE :
98362306a36Sopenharmony_ci		/*PC81 is done by PL_TNE_EXPIRED irq */
98462306a36Sopenharmony_ci		/*PC82*/
98562306a36Sopenharmony_ci		if (cmd == PC_TRACE) {
98662306a36Sopenharmony_ci			GO_STATE(PC2_TRACE) ;
98762306a36Sopenharmony_ci			break ;
98862306a36Sopenharmony_ci		}
98962306a36Sopenharmony_ci		/*PC88c: is done by TRACE_PROP irq */
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci		break ;
99262306a36Sopenharmony_ci	case ACTIONS(PC9_MAINT) :
99362306a36Sopenharmony_ci		stop_pcm_timer0(smc,phy) ;
99462306a36Sopenharmony_ci		CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
99562306a36Sopenharmony_ci		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
99662306a36Sopenharmony_ci		CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;	/* disable LEM int. */
99762306a36Sopenharmony_ci		sm_ph_lem_stop(smc,np) ;		/* disable LEM */
99862306a36Sopenharmony_ci		phy->cf_loop = FALSE ;
99962306a36Sopenharmony_ci		phy->cf_join = FALSE ;
100062306a36Sopenharmony_ci		queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
100162306a36Sopenharmony_ci		plc_go_state(smc,np,PL_PCM_STOP) ;
100262306a36Sopenharmony_ci		mib->fddiPORTConnectState = PCM_DISABLED ;
100362306a36Sopenharmony_ci		SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ;
100462306a36Sopenharmony_ci		sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ;
100562306a36Sopenharmony_ci		outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ;
100662306a36Sopenharmony_ci		ACTIONS_DONE() ;
100762306a36Sopenharmony_ci		break ;
100862306a36Sopenharmony_ci	case PC9_MAINT :
100962306a36Sopenharmony_ci		DB_PCMN(1, "PCM %c : MAINT", phy->phy_name);
101062306a36Sopenharmony_ci		/*PC90*/
101162306a36Sopenharmony_ci		if (cmd == PC_ENABLE) {
101262306a36Sopenharmony_ci			GO_STATE(PC0_OFF) ;
101362306a36Sopenharmony_ci			break ;
101462306a36Sopenharmony_ci		}
101562306a36Sopenharmony_ci		break ;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	default:
101862306a36Sopenharmony_ci		SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ;
101962306a36Sopenharmony_ci		break ;
102062306a36Sopenharmony_ci	}
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci/*
102462306a36Sopenharmony_ci * force line state on a PHY output	(only in MAINT state)
102562306a36Sopenharmony_ci */
102662306a36Sopenharmony_cistatic void sm_ph_linestate(struct s_smc *smc, int phy, int ls)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	int	cntrl ;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	SK_UNUSED(smc) ;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) |
103362306a36Sopenharmony_ci						PL_PCM_STOP | PL_MAINT ;
103462306a36Sopenharmony_ci	switch(ls) {
103562306a36Sopenharmony_ci	case PC_QLS: 		/* Force Quiet */
103662306a36Sopenharmony_ci		cntrl |= PL_M_QUI0 ;
103762306a36Sopenharmony_ci		break ;
103862306a36Sopenharmony_ci	case PC_MLS: 		/* Force Master */
103962306a36Sopenharmony_ci		cntrl |= PL_M_MASTR ;
104062306a36Sopenharmony_ci		break ;
104162306a36Sopenharmony_ci	case PC_HLS: 		/* Force Halt */
104262306a36Sopenharmony_ci		cntrl |= PL_M_HALT ;
104362306a36Sopenharmony_ci		break ;
104462306a36Sopenharmony_ci	default :
104562306a36Sopenharmony_ci	case PC_ILS: 		/* Force Idle */
104662306a36Sopenharmony_ci		cntrl |= PL_M_IDLE ;
104762306a36Sopenharmony_ci		break ;
104862306a36Sopenharmony_ci	case PC_LS_PDR: 	/* Enable repeat filter */
104962306a36Sopenharmony_ci		cntrl |= PL_M_TPDR ;
105062306a36Sopenharmony_ci		break ;
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci	outpw(PLC(phy,PL_CNTRL_B),cntrl) ;
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic void reset_lem_struct(struct s_phy *phy)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	struct lem_counter *lem = &phy->lem ;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	phy->mib->fddiPORTLer_Estimate = 15 ;
106062306a36Sopenharmony_ci	lem->lem_float_ber = 15 * 100 ;
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci/*
106462306a36Sopenharmony_ci * link error monitor
106562306a36Sopenharmony_ci */
106662306a36Sopenharmony_cistatic void lem_evaluate(struct s_smc *smc, struct s_phy *phy)
106762306a36Sopenharmony_ci{
106862306a36Sopenharmony_ci	int ber ;
106962306a36Sopenharmony_ci	u_long errors ;
107062306a36Sopenharmony_ci	struct lem_counter *lem = &phy->lem ;
107162306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
107262306a36Sopenharmony_ci	int			cond ;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	mib = phy->mib ;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	if (!lem->lem_on)
107762306a36Sopenharmony_ci		return ;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ;
108062306a36Sopenharmony_ci	lem->lem_errors += errors ;
108162306a36Sopenharmony_ci	mib->fddiPORTLem_Ct += errors ;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	errors = lem->lem_errors ;
108462306a36Sopenharmony_ci	/*
108562306a36Sopenharmony_ci	 * calculation is called on a intervall of 8 seconds
108662306a36Sopenharmony_ci	 *	-> this means, that one error in 8 sec. is one of 8*125*10E6
108762306a36Sopenharmony_ci	 *	the same as BER = 10E-9
108862306a36Sopenharmony_ci	 * Please note:
108962306a36Sopenharmony_ci	 *	-> 9 errors in 8 seconds mean:
109062306a36Sopenharmony_ci	 *	   BER = 9 * 10E-9  and this is
109162306a36Sopenharmony_ci	 *	    < 10E-8, so the limit of 10E-8 is not reached!
109262306a36Sopenharmony_ci	 */
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci		if (!errors)		ber = 15 ;
109562306a36Sopenharmony_ci	else	if (errors <= 9)	ber = 9 ;
109662306a36Sopenharmony_ci	else	if (errors <= 99)	ber = 8 ;
109762306a36Sopenharmony_ci	else	if (errors <= 999)	ber = 7 ;
109862306a36Sopenharmony_ci	else	if (errors <= 9999)	ber = 6 ;
109962306a36Sopenharmony_ci	else	if (errors <= 99999)	ber = 5 ;
110062306a36Sopenharmony_ci	else	if (errors <= 999999)	ber = 4 ;
110162306a36Sopenharmony_ci	else	if (errors <= 9999999)	ber = 3 ;
110262306a36Sopenharmony_ci	else	if (errors <= 99999999)	ber = 2 ;
110362306a36Sopenharmony_ci	else	if (errors <= 999999999) ber = 1 ;
110462306a36Sopenharmony_ci	else				ber = 0 ;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	/*
110762306a36Sopenharmony_ci	 * weighted average
110862306a36Sopenharmony_ci	 */
110962306a36Sopenharmony_ci	ber *= 100 ;
111062306a36Sopenharmony_ci	lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ;
111162306a36Sopenharmony_ci	lem->lem_float_ber /= 10 ;
111262306a36Sopenharmony_ci	mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ;
111362306a36Sopenharmony_ci	if (mib->fddiPORTLer_Estimate < 4) {
111462306a36Sopenharmony_ci		mib->fddiPORTLer_Estimate = 4 ;
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (lem->lem_errors) {
111862306a36Sopenharmony_ci		DB_PCMN(1, "LEM %c :", phy->np == PB ? 'B' : 'A');
111962306a36Sopenharmony_ci		DB_PCMN(1, "errors      : %ld", lem->lem_errors);
112062306a36Sopenharmony_ci		DB_PCMN(1, "sum_errors  : %ld", mib->fddiPORTLem_Ct);
112162306a36Sopenharmony_ci		DB_PCMN(1, "current BER : 10E-%d", ber / 100);
112262306a36Sopenharmony_ci		DB_PCMN(1, "float BER   : 10E-(%d/100)", lem->lem_float_ber);
112362306a36Sopenharmony_ci		DB_PCMN(1, "avg. BER    : 10E-%d", mib->fddiPORTLer_Estimate);
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	lem->lem_errors = 0L ;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci#ifndef	SLIM_SMT
112962306a36Sopenharmony_ci	cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ?
113062306a36Sopenharmony_ci		TRUE : FALSE ;
113162306a36Sopenharmony_ci#ifdef	SMT_EXT_CUTOFF
113262306a36Sopenharmony_ci	smt_ler_alarm_check(smc,phy,cond) ;
113362306a36Sopenharmony_ci#endif	/* nSMT_EXT_CUTOFF */
113462306a36Sopenharmony_ci	if (cond != mib->fddiPORTLerFlag) {
113562306a36Sopenharmony_ci		smt_srf_event(smc,SMT_COND_PORT_LER,
113662306a36Sopenharmony_ci			(int) (INDEX_PORT+ phy->np) ,cond) ;
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci#endif
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	if (	mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) {
114162306a36Sopenharmony_ci		phy->pc_lem_fail = TRUE ;		/* flag */
114262306a36Sopenharmony_ci		mib->fddiPORTLem_Reject_Ct++ ;
114362306a36Sopenharmony_ci		/*
114462306a36Sopenharmony_ci		 * "forgive 10e-2" if we cutoff so we can come
114562306a36Sopenharmony_ci		 * up again ..
114662306a36Sopenharmony_ci		 */
114762306a36Sopenharmony_ci		lem->lem_float_ber += 2*100 ;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci		/*PC81b*/
115062306a36Sopenharmony_ci#ifdef	CONCENTRATOR
115162306a36Sopenharmony_ci		DB_PCMN(1, "PCM: LER cutoff on port %d cutoff %d",
115262306a36Sopenharmony_ci			phy->np, mib->fddiPORTLer_Cutoff);
115362306a36Sopenharmony_ci#endif
115462306a36Sopenharmony_ci#ifdef	SMT_EXT_CUTOFF
115562306a36Sopenharmony_ci		smt_port_off_event(smc,phy->np);
115662306a36Sopenharmony_ci#else	/* nSMT_EXT_CUTOFF */
115762306a36Sopenharmony_ci		queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
115862306a36Sopenharmony_ci#endif	/* nSMT_EXT_CUTOFF */
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci/*
116362306a36Sopenharmony_ci * called by SMT to calculate LEM bit error rate
116462306a36Sopenharmony_ci */
116562306a36Sopenharmony_civoid sm_lem_evaluate(struct s_smc *smc)
116662306a36Sopenharmony_ci{
116762306a36Sopenharmony_ci	int np ;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	for (np = 0 ; np < NUMPHYS ; np++)
117062306a36Sopenharmony_ci		lem_evaluate(smc,&smc->y[np]) ;
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic void lem_check_lct(struct s_smc *smc, struct s_phy *phy)
117462306a36Sopenharmony_ci{
117562306a36Sopenharmony_ci	struct lem_counter	*lem = &phy->lem ;
117662306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
117762306a36Sopenharmony_ci	int errors ;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	mib = phy->mib ;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	phy->pc_lem_fail = FALSE ;		/* flag */
118262306a36Sopenharmony_ci	errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ;
118362306a36Sopenharmony_ci	lem->lem_errors += errors ;
118462306a36Sopenharmony_ci	mib->fddiPORTLem_Ct += errors ;
118562306a36Sopenharmony_ci	if (lem->lem_errors) {
118662306a36Sopenharmony_ci		switch(phy->lc_test) {
118762306a36Sopenharmony_ci		case LC_SHORT:
118862306a36Sopenharmony_ci			if (lem->lem_errors >= smc->s.lct_short)
118962306a36Sopenharmony_ci				phy->pc_lem_fail = TRUE ;
119062306a36Sopenharmony_ci			break ;
119162306a36Sopenharmony_ci		case LC_MEDIUM:
119262306a36Sopenharmony_ci			if (lem->lem_errors >= smc->s.lct_medium)
119362306a36Sopenharmony_ci				phy->pc_lem_fail = TRUE ;
119462306a36Sopenharmony_ci			break ;
119562306a36Sopenharmony_ci		case LC_LONG:
119662306a36Sopenharmony_ci			if (lem->lem_errors >= smc->s.lct_long)
119762306a36Sopenharmony_ci				phy->pc_lem_fail = TRUE ;
119862306a36Sopenharmony_ci			break ;
119962306a36Sopenharmony_ci		case LC_EXTENDED:
120062306a36Sopenharmony_ci			if (lem->lem_errors >= smc->s.lct_extended)
120162306a36Sopenharmony_ci				phy->pc_lem_fail = TRUE ;
120262306a36Sopenharmony_ci			break ;
120362306a36Sopenharmony_ci		}
120462306a36Sopenharmony_ci		DB_PCMN(1, " >>errors : %lu", lem->lem_errors);
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci	if (phy->pc_lem_fail) {
120762306a36Sopenharmony_ci		mib->fddiPORTLCTFail_Ct++ ;
120862306a36Sopenharmony_ci		mib->fddiPORTLem_Reject_Ct++ ;
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci	else
121162306a36Sopenharmony_ci		mib->fddiPORTLCTFail_Ct = 0 ;
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci/*
121562306a36Sopenharmony_ci * LEM functions
121662306a36Sopenharmony_ci */
121762306a36Sopenharmony_cistatic void sm_ph_lem_start(struct s_smc *smc, int np, int threshold)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct lem_counter *lem = &smc->y[np].lem ;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	lem->lem_on = 1 ;
122262306a36Sopenharmony_ci	lem->lem_errors = 0L ;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	/* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too
122562306a36Sopenharmony_ci	 * often.
122662306a36Sopenharmony_ci	 */
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	outpw(PLC(np,PL_LE_THRESHOLD),threshold) ;
122962306a36Sopenharmony_ci	(void)inpw(PLC(np,PL_LINK_ERR_CTR)) ;	/* clear error counter */
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	/* enable LE INT */
123262306a36Sopenharmony_ci	SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ;
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic void sm_ph_lem_stop(struct s_smc *smc, int np)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct lem_counter *lem = &smc->y[np].lem ;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	lem->lem_on = 0 ;
124062306a36Sopenharmony_ci	CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;
124162306a36Sopenharmony_ci}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci/*
124462306a36Sopenharmony_ci * PCM pseudo code
124562306a36Sopenharmony_ci * receive actions are called AFTER the bit n is received,
124662306a36Sopenharmony_ci * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received
124762306a36Sopenharmony_ci */
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci/*
125062306a36Sopenharmony_ci * PCM pseudo code 5.1 .. 6.1
125162306a36Sopenharmony_ci */
125262306a36Sopenharmony_cistatic void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	mib = phy->mib ;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	DB_PCMN(1, "SIG rec %x %x:", bit, phy->r_val[bit]);
125962306a36Sopenharmony_ci	bit++ ;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	switch(bit) {
126262306a36Sopenharmony_ci	case 0:
126362306a36Sopenharmony_ci	case 1:
126462306a36Sopenharmony_ci	case 2:
126562306a36Sopenharmony_ci		break ;
126662306a36Sopenharmony_ci	case 3 :
126762306a36Sopenharmony_ci		if (phy->r_val[1] == 0 && phy->r_val[2] == 0)
126862306a36Sopenharmony_ci			mib->fddiPORTNeighborType = TA ;
126962306a36Sopenharmony_ci		else if (phy->r_val[1] == 0 && phy->r_val[2] == 1)
127062306a36Sopenharmony_ci			mib->fddiPORTNeighborType = TB ;
127162306a36Sopenharmony_ci		else if (phy->r_val[1] == 1 && phy->r_val[2] == 0)
127262306a36Sopenharmony_ci			mib->fddiPORTNeighborType = TS ;
127362306a36Sopenharmony_ci		else if (phy->r_val[1] == 1 && phy->r_val[2] == 1)
127462306a36Sopenharmony_ci			mib->fddiPORTNeighborType = TM ;
127562306a36Sopenharmony_ci		break ;
127662306a36Sopenharmony_ci	case 4:
127762306a36Sopenharmony_ci		if (mib->fddiPORTMy_Type == TM &&
127862306a36Sopenharmony_ci			mib->fddiPORTNeighborType == TM) {
127962306a36Sopenharmony_ci			DB_PCMN(1, "PCM %c : E100 withhold M-M",
128062306a36Sopenharmony_ci				phy->phy_name);
128162306a36Sopenharmony_ci			mib->fddiPORTPC_Withhold = PC_WH_M_M ;
128262306a36Sopenharmony_ci			RS_SET(smc,RS_EVENT) ;
128362306a36Sopenharmony_ci		}
128462306a36Sopenharmony_ci		else if (phy->t_val[3] || phy->r_val[3]) {
128562306a36Sopenharmony_ci			mib->fddiPORTPC_Withhold = PC_WH_NONE ;
128662306a36Sopenharmony_ci			if (mib->fddiPORTMy_Type == TM ||
128762306a36Sopenharmony_ci			    mib->fddiPORTNeighborType == TM)
128862306a36Sopenharmony_ci				phy->pc_mode = PM_TREE ;
128962306a36Sopenharmony_ci			else
129062306a36Sopenharmony_ci				phy->pc_mode = PM_PEER ;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci			/* reevaluate the selection criteria (wc_flag) */
129362306a36Sopenharmony_ci			all_selection_criteria (smc);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci			if (phy->wc_flag) {
129662306a36Sopenharmony_ci				mib->fddiPORTPC_Withhold = PC_WH_PATH ;
129762306a36Sopenharmony_ci			}
129862306a36Sopenharmony_ci		}
129962306a36Sopenharmony_ci		else {
130062306a36Sopenharmony_ci			mib->fddiPORTPC_Withhold = PC_WH_OTHER ;
130162306a36Sopenharmony_ci			RS_SET(smc,RS_EVENT) ;
130262306a36Sopenharmony_ci			DB_PCMN(1, "PCM %c : E101 withhold other",
130362306a36Sopenharmony_ci				phy->phy_name);
130462306a36Sopenharmony_ci		}
130562306a36Sopenharmony_ci		phy->twisted = ((mib->fddiPORTMy_Type != TS) &&
130662306a36Sopenharmony_ci				(mib->fddiPORTMy_Type != TM) &&
130762306a36Sopenharmony_ci				(mib->fddiPORTNeighborType ==
130862306a36Sopenharmony_ci				mib->fddiPORTMy_Type)) ;
130962306a36Sopenharmony_ci		if (phy->twisted) {
131062306a36Sopenharmony_ci			DB_PCMN(1, "PCM %c : E102 !!! TWISTED !!!",
131162306a36Sopenharmony_ci				phy->phy_name);
131262306a36Sopenharmony_ci		}
131362306a36Sopenharmony_ci		break ;
131462306a36Sopenharmony_ci	case 5 :
131562306a36Sopenharmony_ci		break ;
131662306a36Sopenharmony_ci	case 6:
131762306a36Sopenharmony_ci		if (phy->t_val[4] || phy->r_val[4]) {
131862306a36Sopenharmony_ci			if ((phy->t_val[4] && phy->t_val[5]) ||
131962306a36Sopenharmony_ci			    (phy->r_val[4] && phy->r_val[5]) )
132062306a36Sopenharmony_ci				phy->lc_test = LC_EXTENDED ;
132162306a36Sopenharmony_ci			else
132262306a36Sopenharmony_ci				phy->lc_test = LC_LONG ;
132362306a36Sopenharmony_ci		}
132462306a36Sopenharmony_ci		else if (phy->t_val[5] || phy->r_val[5])
132562306a36Sopenharmony_ci			phy->lc_test = LC_MEDIUM ;
132662306a36Sopenharmony_ci		else
132762306a36Sopenharmony_ci			phy->lc_test = LC_SHORT ;
132862306a36Sopenharmony_ci		switch (phy->lc_test) {
132962306a36Sopenharmony_ci		case LC_SHORT :				/* 50ms */
133062306a36Sopenharmony_ci			outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ;
133162306a36Sopenharmony_ci			phy->t_next[7] = smc->s.pcm_lc_short ;
133262306a36Sopenharmony_ci			break ;
133362306a36Sopenharmony_ci		case LC_MEDIUM :			/* 500ms */
133462306a36Sopenharmony_ci			outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ;
133562306a36Sopenharmony_ci			phy->t_next[7] = smc->s.pcm_lc_medium ;
133662306a36Sopenharmony_ci			break ;
133762306a36Sopenharmony_ci		case LC_LONG :
133862306a36Sopenharmony_ci			SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
133962306a36Sopenharmony_ci			phy->t_next[7] = smc->s.pcm_lc_long ;
134062306a36Sopenharmony_ci			break ;
134162306a36Sopenharmony_ci		case LC_EXTENDED :
134262306a36Sopenharmony_ci			SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
134362306a36Sopenharmony_ci			phy->t_next[7] = smc->s.pcm_lc_extended ;
134462306a36Sopenharmony_ci			break ;
134562306a36Sopenharmony_ci		}
134662306a36Sopenharmony_ci		if (phy->t_next[7] > smc->s.pcm_lc_medium) {
134762306a36Sopenharmony_ci			start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy);
134862306a36Sopenharmony_ci		}
134962306a36Sopenharmony_ci		DB_PCMN(1, "LCT timer = %ld us", phy->t_next[7]);
135062306a36Sopenharmony_ci		phy->t_next[9] = smc->s.pcm_t_next_9 ;
135162306a36Sopenharmony_ci		break ;
135262306a36Sopenharmony_ci	case 7:
135362306a36Sopenharmony_ci		if (phy->t_val[6]) {
135462306a36Sopenharmony_ci			phy->cf_loop = TRUE ;
135562306a36Sopenharmony_ci		}
135662306a36Sopenharmony_ci		phy->td_flag = TRUE ;
135762306a36Sopenharmony_ci		break ;
135862306a36Sopenharmony_ci	case 8:
135962306a36Sopenharmony_ci		if (phy->t_val[7] || phy->r_val[7]) {
136062306a36Sopenharmony_ci			DB_PCMN(1, "PCM %c : E103 LCT fail %s",
136162306a36Sopenharmony_ci				phy->phy_name,
136262306a36Sopenharmony_ci				phy->t_val[7] ? "local" : "remote");
136362306a36Sopenharmony_ci			queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
136462306a36Sopenharmony_ci		}
136562306a36Sopenharmony_ci		break ;
136662306a36Sopenharmony_ci	case 9:
136762306a36Sopenharmony_ci		if (phy->t_val[8] || phy->r_val[8]) {
136862306a36Sopenharmony_ci			if (phy->t_val[8])
136962306a36Sopenharmony_ci				phy->cf_loop = TRUE ;
137062306a36Sopenharmony_ci			phy->td_flag = TRUE ;
137162306a36Sopenharmony_ci		}
137262306a36Sopenharmony_ci		break ;
137362306a36Sopenharmony_ci	case 10:
137462306a36Sopenharmony_ci		if (phy->r_val[9]) {
137562306a36Sopenharmony_ci			/* neighbor intends to have MAC on output */ ;
137662306a36Sopenharmony_ci			mib->fddiPORTMacIndicated.R_val = TRUE ;
137762306a36Sopenharmony_ci		}
137862306a36Sopenharmony_ci		else {
137962306a36Sopenharmony_ci			/* neighbor does not intend to have MAC on output */ ;
138062306a36Sopenharmony_ci			mib->fddiPORTMacIndicated.R_val = FALSE ;
138162306a36Sopenharmony_ci		}
138262306a36Sopenharmony_ci		break ;
138362306a36Sopenharmony_ci	}
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci/*
138762306a36Sopenharmony_ci * PCM pseudo code 5.1 .. 6.1
138862306a36Sopenharmony_ci */
138962306a36Sopenharmony_cistatic void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	int	np = phy->np ;
139262306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	mib = phy->mib ;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	switch(bit) {
139762306a36Sopenharmony_ci	case 0:
139862306a36Sopenharmony_ci		phy->t_val[0] = 0 ;		/* no escape used */
139962306a36Sopenharmony_ci		break ;
140062306a36Sopenharmony_ci	case 1:
140162306a36Sopenharmony_ci		if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM)
140262306a36Sopenharmony_ci			phy->t_val[1] = 1 ;
140362306a36Sopenharmony_ci		else
140462306a36Sopenharmony_ci			phy->t_val[1] = 0 ;
140562306a36Sopenharmony_ci		break ;
140662306a36Sopenharmony_ci	case 2 :
140762306a36Sopenharmony_ci		if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM)
140862306a36Sopenharmony_ci			phy->t_val[2] = 1 ;
140962306a36Sopenharmony_ci		else
141062306a36Sopenharmony_ci			phy->t_val[2] = 0 ;
141162306a36Sopenharmony_ci		break ;
141262306a36Sopenharmony_ci	case 3:
141362306a36Sopenharmony_ci		{
141462306a36Sopenharmony_ci		int	type,ne ;
141562306a36Sopenharmony_ci		int	policy ;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci		type = mib->fddiPORTMy_Type ;
141862306a36Sopenharmony_ci		ne = mib->fddiPORTNeighborType ;
141962306a36Sopenharmony_ci		policy = smc->mib.fddiSMTConnectionPolicy ;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci		phy->t_val[3] = 1 ;	/* Accept connection */
142262306a36Sopenharmony_ci		switch (type) {
142362306a36Sopenharmony_ci		case TA :
142462306a36Sopenharmony_ci			if (
142562306a36Sopenharmony_ci				((policy & POLICY_AA) && ne == TA) ||
142662306a36Sopenharmony_ci				((policy & POLICY_AB) && ne == TB) ||
142762306a36Sopenharmony_ci				((policy & POLICY_AS) && ne == TS) ||
142862306a36Sopenharmony_ci				((policy & POLICY_AM) && ne == TM) )
142962306a36Sopenharmony_ci				phy->t_val[3] = 0 ;	/* Reject */
143062306a36Sopenharmony_ci			break ;
143162306a36Sopenharmony_ci		case TB :
143262306a36Sopenharmony_ci			if (
143362306a36Sopenharmony_ci				((policy & POLICY_BA) && ne == TA) ||
143462306a36Sopenharmony_ci				((policy & POLICY_BB) && ne == TB) ||
143562306a36Sopenharmony_ci				((policy & POLICY_BS) && ne == TS) ||
143662306a36Sopenharmony_ci				((policy & POLICY_BM) && ne == TM) )
143762306a36Sopenharmony_ci				phy->t_val[3] = 0 ;	/* Reject */
143862306a36Sopenharmony_ci			break ;
143962306a36Sopenharmony_ci		case TS :
144062306a36Sopenharmony_ci			if (
144162306a36Sopenharmony_ci				((policy & POLICY_SA) && ne == TA) ||
144262306a36Sopenharmony_ci				((policy & POLICY_SB) && ne == TB) ||
144362306a36Sopenharmony_ci				((policy & POLICY_SS) && ne == TS) ||
144462306a36Sopenharmony_ci				((policy & POLICY_SM) && ne == TM) )
144562306a36Sopenharmony_ci				phy->t_val[3] = 0 ;	/* Reject */
144662306a36Sopenharmony_ci			break ;
144762306a36Sopenharmony_ci		case TM :
144862306a36Sopenharmony_ci			if (	ne == TM ||
144962306a36Sopenharmony_ci				((policy & POLICY_MA) && ne == TA) ||
145062306a36Sopenharmony_ci				((policy & POLICY_MB) && ne == TB) ||
145162306a36Sopenharmony_ci				((policy & POLICY_MS) && ne == TS) ||
145262306a36Sopenharmony_ci				((policy & POLICY_MM) && ne == TM) )
145362306a36Sopenharmony_ci				phy->t_val[3] = 0 ;	/* Reject */
145462306a36Sopenharmony_ci			break ;
145562306a36Sopenharmony_ci		}
145662306a36Sopenharmony_ci#ifndef	SLIM_SMT
145762306a36Sopenharmony_ci		/*
145862306a36Sopenharmony_ci		 * detect undesirable connection attempt event
145962306a36Sopenharmony_ci		 */
146062306a36Sopenharmony_ci		if (	(type == TA && ne == TA ) ||
146162306a36Sopenharmony_ci			(type == TA && ne == TS ) ||
146262306a36Sopenharmony_ci			(type == TB && ne == TB ) ||
146362306a36Sopenharmony_ci			(type == TB && ne == TS ) ||
146462306a36Sopenharmony_ci			(type == TS && ne == TA ) ||
146562306a36Sopenharmony_ci			(type == TS && ne == TB ) ) {
146662306a36Sopenharmony_ci			smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION,
146762306a36Sopenharmony_ci				(int) (INDEX_PORT+ phy->np) ,0) ;
146862306a36Sopenharmony_ci		}
146962306a36Sopenharmony_ci#endif
147062306a36Sopenharmony_ci		}
147162306a36Sopenharmony_ci		break ;
147262306a36Sopenharmony_ci	case 4:
147362306a36Sopenharmony_ci		if (mib->fddiPORTPC_Withhold == PC_WH_NONE) {
147462306a36Sopenharmony_ci			if (phy->pc_lem_fail) {
147562306a36Sopenharmony_ci				phy->t_val[4] = 1 ;	/* long */
147662306a36Sopenharmony_ci				phy->t_val[5] = 0 ;
147762306a36Sopenharmony_ci			}
147862306a36Sopenharmony_ci			else {
147962306a36Sopenharmony_ci				phy->t_val[4] = 0 ;
148062306a36Sopenharmony_ci				if (mib->fddiPORTLCTFail_Ct > 0)
148162306a36Sopenharmony_ci					phy->t_val[5] = 1 ;	/* medium */
148262306a36Sopenharmony_ci				else
148362306a36Sopenharmony_ci					phy->t_val[5] = 0 ;	/* short */
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci				/*
148662306a36Sopenharmony_ci				 * Implementers choice: use medium
148762306a36Sopenharmony_ci				 * instead of short when undesired
148862306a36Sopenharmony_ci				 * connection attempt is made.
148962306a36Sopenharmony_ci				 */
149062306a36Sopenharmony_ci				if (phy->wc_flag)
149162306a36Sopenharmony_ci					phy->t_val[5] = 1 ;	/* medium */
149262306a36Sopenharmony_ci			}
149362306a36Sopenharmony_ci			mib->fddiPORTConnectState = PCM_CONNECTING ;
149462306a36Sopenharmony_ci		}
149562306a36Sopenharmony_ci		else {
149662306a36Sopenharmony_ci			mib->fddiPORTConnectState = PCM_STANDBY ;
149762306a36Sopenharmony_ci			phy->t_val[4] = 1 ;	/* extended */
149862306a36Sopenharmony_ci			phy->t_val[5] = 1 ;
149962306a36Sopenharmony_ci		}
150062306a36Sopenharmony_ci		break ;
150162306a36Sopenharmony_ci	case 5:
150262306a36Sopenharmony_ci		break ;
150362306a36Sopenharmony_ci	case 6:
150462306a36Sopenharmony_ci		/* we do NOT have a MAC for LCT */
150562306a36Sopenharmony_ci		phy->t_val[6] = 0 ;
150662306a36Sopenharmony_ci		break ;
150762306a36Sopenharmony_ci	case 7:
150862306a36Sopenharmony_ci		phy->cf_loop = FALSE ;
150962306a36Sopenharmony_ci		lem_check_lct(smc,phy) ;
151062306a36Sopenharmony_ci		if (phy->pc_lem_fail) {
151162306a36Sopenharmony_ci			DB_PCMN(1, "PCM %c : E104 LCT failed", phy->phy_name);
151262306a36Sopenharmony_ci			phy->t_val[7] = 1 ;
151362306a36Sopenharmony_ci		}
151462306a36Sopenharmony_ci		else
151562306a36Sopenharmony_ci			phy->t_val[7] = 0 ;
151662306a36Sopenharmony_ci		break ;
151762306a36Sopenharmony_ci	case 8:
151862306a36Sopenharmony_ci		phy->t_val[8] = 0 ;	/* Don't request MAC loopback */
151962306a36Sopenharmony_ci		break ;
152062306a36Sopenharmony_ci	case 9:
152162306a36Sopenharmony_ci		phy->cf_loop = 0 ;
152262306a36Sopenharmony_ci		if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) ||
152362306a36Sopenharmony_ci		     ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) {
152462306a36Sopenharmony_ci			queue_event(smc,EVENT_PCM+np,PC_START) ;
152562306a36Sopenharmony_ci			break ;
152662306a36Sopenharmony_ci		}
152762306a36Sopenharmony_ci		phy->t_val[9] = FALSE ;
152862306a36Sopenharmony_ci		switch (smc->s.sas) {
152962306a36Sopenharmony_ci		case SMT_DAS :
153062306a36Sopenharmony_ci			/*
153162306a36Sopenharmony_ci			 * MAC intended on output
153262306a36Sopenharmony_ci			 */
153362306a36Sopenharmony_ci			if (phy->pc_mode == PM_TREE) {
153462306a36Sopenharmony_ci				if ((np == PB) || ((np == PA) &&
153562306a36Sopenharmony_ci				(smc->y[PB].mib->fddiPORTConnectState !=
153662306a36Sopenharmony_ci					PCM_ACTIVE)))
153762306a36Sopenharmony_ci					phy->t_val[9] = TRUE ;
153862306a36Sopenharmony_ci			}
153962306a36Sopenharmony_ci			else {
154062306a36Sopenharmony_ci				if (np == PB)
154162306a36Sopenharmony_ci					phy->t_val[9] = TRUE ;
154262306a36Sopenharmony_ci			}
154362306a36Sopenharmony_ci			break ;
154462306a36Sopenharmony_ci		case SMT_SAS :
154562306a36Sopenharmony_ci			if (np == PS)
154662306a36Sopenharmony_ci				phy->t_val[9] = TRUE ;
154762306a36Sopenharmony_ci			break ;
154862306a36Sopenharmony_ci#ifdef	CONCENTRATOR
154962306a36Sopenharmony_ci		case SMT_NAC :
155062306a36Sopenharmony_ci			/*
155162306a36Sopenharmony_ci			 * MAC intended on output
155262306a36Sopenharmony_ci			 */
155362306a36Sopenharmony_ci			if (np == PB)
155462306a36Sopenharmony_ci				phy->t_val[9] = TRUE ;
155562306a36Sopenharmony_ci			break ;
155662306a36Sopenharmony_ci#endif
155762306a36Sopenharmony_ci		}
155862306a36Sopenharmony_ci		mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ;
155962306a36Sopenharmony_ci		break ;
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci	DB_PCMN(1, "SIG snd %x %x:", bit, phy->t_val[bit]);
156262306a36Sopenharmony_ci}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci/*
156562306a36Sopenharmony_ci * return status twisted (called by SMT)
156662306a36Sopenharmony_ci */
156762306a36Sopenharmony_ciint pcm_status_twisted(struct s_smc *smc)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	int	twist = 0 ;
157062306a36Sopenharmony_ci	if (smc->s.sas != SMT_DAS)
157162306a36Sopenharmony_ci		return 0;
157262306a36Sopenharmony_ci	if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE))
157362306a36Sopenharmony_ci		twist |= 1 ;
157462306a36Sopenharmony_ci	if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE))
157562306a36Sopenharmony_ci		twist |= 2 ;
157662306a36Sopenharmony_ci	return twist;
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci/*
158062306a36Sopenharmony_ci * return status	(called by SMT)
158162306a36Sopenharmony_ci *	type
158262306a36Sopenharmony_ci *	state
158362306a36Sopenharmony_ci *	remote phy type
158462306a36Sopenharmony_ci *	remote mac yes/no
158562306a36Sopenharmony_ci */
158662306a36Sopenharmony_civoid pcm_status_state(struct s_smc *smc, int np, int *type, int *state,
158762306a36Sopenharmony_ci		      int *remote, int *mac)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	struct s_phy	*phy = &smc->y[np] ;
159062306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	mib = phy->mib ;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* remote PHY type and MAC - set only if active */
159562306a36Sopenharmony_ci	*mac = 0 ;
159662306a36Sopenharmony_ci	*type = mib->fddiPORTMy_Type ;		/* our PHY type */
159762306a36Sopenharmony_ci	*state = mib->fddiPORTConnectState ;
159862306a36Sopenharmony_ci	*remote = mib->fddiPORTNeighborType ;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	switch(mib->fddiPORTPCMState) {
160162306a36Sopenharmony_ci	case PC8_ACTIVE :
160262306a36Sopenharmony_ci		*mac = mib->fddiPORTMacIndicated.R_val ;
160362306a36Sopenharmony_ci		break ;
160462306a36Sopenharmony_ci	}
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci/*
160862306a36Sopenharmony_ci * return rooted station status (called by SMT)
160962306a36Sopenharmony_ci */
161062306a36Sopenharmony_ciint pcm_rooted_station(struct s_smc *smc)
161162306a36Sopenharmony_ci{
161262306a36Sopenharmony_ci	int	n ;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	for (n = 0 ; n < NUMPHYS ; n++) {
161562306a36Sopenharmony_ci		if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE &&
161662306a36Sopenharmony_ci		    smc->y[n].mib->fddiPORTNeighborType == TM)
161762306a36Sopenharmony_ci			return 0;
161862306a36Sopenharmony_ci	}
161962306a36Sopenharmony_ci	return 1;
162062306a36Sopenharmony_ci}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci/*
162362306a36Sopenharmony_ci * Interrupt actions for PLC & PCM events
162462306a36Sopenharmony_ci */
162562306a36Sopenharmony_civoid plc_irq(struct s_smc *smc, int np, unsigned int cmd)
162662306a36Sopenharmony_ci/* int np;	PHY index */
162762306a36Sopenharmony_ci{
162862306a36Sopenharmony_ci	struct s_phy *phy = &smc->y[np] ;
162962306a36Sopenharmony_ci	struct s_plc *plc = &phy->plc ;
163062306a36Sopenharmony_ci	int		n ;
163162306a36Sopenharmony_ci#ifdef	SUPERNET_3
163262306a36Sopenharmony_ci	int		corr_mask ;
163362306a36Sopenharmony_ci#endif	/* SUPERNET_3 */
163462306a36Sopenharmony_ci	int		i ;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	if (np >= smc->s.numphys) {
163762306a36Sopenharmony_ci		plc->soft_err++ ;
163862306a36Sopenharmony_ci		return ;
163962306a36Sopenharmony_ci	}
164062306a36Sopenharmony_ci	if (cmd & PL_EBUF_ERR) {	/* elastic buff. det. over-|underflow*/
164162306a36Sopenharmony_ci		/*
164262306a36Sopenharmony_ci		 * Check whether the SRF Condition occurred.
164362306a36Sopenharmony_ci		 */
164462306a36Sopenharmony_ci		if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){
164562306a36Sopenharmony_ci			/*
164662306a36Sopenharmony_ci			 * This is the real Elasticity Error.
164762306a36Sopenharmony_ci			 * More than one in a row are treated as a
164862306a36Sopenharmony_ci			 * single one.
164962306a36Sopenharmony_ci			 * Only count this in the active state.
165062306a36Sopenharmony_ci			 */
165162306a36Sopenharmony_ci			phy->mib->fddiPORTEBError_Ct ++ ;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci		}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci		plc->ebuf_err++ ;
165662306a36Sopenharmony_ci		if (plc->ebuf_cont <= 1000) {
165762306a36Sopenharmony_ci			/*
165862306a36Sopenharmony_ci			 * Prevent counter from being wrapped after
165962306a36Sopenharmony_ci			 * hanging years in that interrupt.
166062306a36Sopenharmony_ci			 */
166162306a36Sopenharmony_ci			plc->ebuf_cont++ ;	/* Ebuf continuous error */
166262306a36Sopenharmony_ci		}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci#ifdef	SUPERNET_3
166562306a36Sopenharmony_ci		if (plc->ebuf_cont == 1000 &&
166662306a36Sopenharmony_ci			((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) ==
166762306a36Sopenharmony_ci			PLC_REV_SN3)) {
166862306a36Sopenharmony_ci			/*
166962306a36Sopenharmony_ci			 * This interrupt remeained high for at least
167062306a36Sopenharmony_ci			 * 1000 consecutive interrupt calls.
167162306a36Sopenharmony_ci			 *
167262306a36Sopenharmony_ci			 * This is caused by a hardware error of the
167362306a36Sopenharmony_ci			 * ORION part of the Supernet III chipset.
167462306a36Sopenharmony_ci			 *
167562306a36Sopenharmony_ci			 * Disable this bit from the mask.
167662306a36Sopenharmony_ci			 */
167762306a36Sopenharmony_ci			corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ;
167862306a36Sopenharmony_ci			outpw(PLC(np,PL_INTR_MASK),corr_mask);
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci			/*
168162306a36Sopenharmony_ci			 * Disconnect from the ring.
168262306a36Sopenharmony_ci			 * Call the driver with the reset indication.
168362306a36Sopenharmony_ci			 */
168462306a36Sopenharmony_ci			queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci			/*
168762306a36Sopenharmony_ci			 * Make an error log entry.
168862306a36Sopenharmony_ci			 */
168962306a36Sopenharmony_ci			SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci			/*
169262306a36Sopenharmony_ci			 * Indicate the Reset.
169362306a36Sopenharmony_ci			 */
169462306a36Sopenharmony_ci			drv_reset_indication(smc) ;
169562306a36Sopenharmony_ci		}
169662306a36Sopenharmony_ci#endif	/* SUPERNET_3 */
169762306a36Sopenharmony_ci	} else {
169862306a36Sopenharmony_ci		/* Reset the continuous error variable */
169962306a36Sopenharmony_ci		plc->ebuf_cont = 0 ;	/* reset Ebuf continuous error */
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci	if (cmd & PL_PHYINV) {		/* physical layer invalid signal */
170262306a36Sopenharmony_ci		plc->phyinv++ ;
170362306a36Sopenharmony_ci	}
170462306a36Sopenharmony_ci	if (cmd & PL_VSYM_CTR) {	/* violation symbol counter has incr.*/
170562306a36Sopenharmony_ci		plc->vsym_ctr++ ;
170662306a36Sopenharmony_ci	}
170762306a36Sopenharmony_ci	if (cmd & PL_MINI_CTR) {	/* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
170862306a36Sopenharmony_ci		plc->mini_ctr++ ;
170962306a36Sopenharmony_ci	}
171062306a36Sopenharmony_ci	if (cmd & PL_LE_CTR) {		/* link error event counter */
171162306a36Sopenharmony_ci		int	j ;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci		/*
171462306a36Sopenharmony_ci		 * note: PL_LINK_ERR_CTR MUST be read to clear it
171562306a36Sopenharmony_ci		 */
171662306a36Sopenharmony_ci		j = inpw(PLC(np,PL_LE_THRESHOLD)) ;
171762306a36Sopenharmony_ci		i = inpw(PLC(np,PL_LINK_ERR_CTR)) ;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci		if (i < j) {
172062306a36Sopenharmony_ci			/* wrapped around */
172162306a36Sopenharmony_ci			i += 256 ;
172262306a36Sopenharmony_ci		}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci		if (phy->lem.lem_on) {
172562306a36Sopenharmony_ci			/* Note: Lem errors shall only be counted when
172662306a36Sopenharmony_ci			 * link is ACTIVE or LCT is active.
172762306a36Sopenharmony_ci			 */
172862306a36Sopenharmony_ci			phy->lem.lem_errors += i ;
172962306a36Sopenharmony_ci			phy->mib->fddiPORTLem_Ct += i ;
173062306a36Sopenharmony_ci		}
173162306a36Sopenharmony_ci	}
173262306a36Sopenharmony_ci	if (cmd & PL_TPC_EXPIRED) {	/* TPC timer reached zero */
173362306a36Sopenharmony_ci		if (plc->p_state == PS_LCT) {
173462306a36Sopenharmony_ci			/*
173562306a36Sopenharmony_ci			 * end of LCT
173662306a36Sopenharmony_ci			 */
173762306a36Sopenharmony_ci			;
173862306a36Sopenharmony_ci		}
173962306a36Sopenharmony_ci		plc->tpc_exp++ ;
174062306a36Sopenharmony_ci	}
174162306a36Sopenharmony_ci	if (cmd & PL_LS_MATCH) {	/* LS == LS in PLC_CNTRL_B's MATCH_LS*/
174262306a36Sopenharmony_ci		switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) {
174362306a36Sopenharmony_ci		case PL_I_IDLE :	phy->curr_ls = PC_ILS ;		break ;
174462306a36Sopenharmony_ci		case PL_I_HALT :	phy->curr_ls = PC_HLS ;		break ;
174562306a36Sopenharmony_ci		case PL_I_MASTR :	phy->curr_ls = PC_MLS ;		break ;
174662306a36Sopenharmony_ci		case PL_I_QUIET :	phy->curr_ls = PC_QLS ;		break ;
174762306a36Sopenharmony_ci		}
174862306a36Sopenharmony_ci	}
174962306a36Sopenharmony_ci	if (cmd & PL_PCM_BREAK) {	/* PCM has entered the BREAK state */
175062306a36Sopenharmony_ci		int	reason;
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci		reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci		switch (reason) {
175562306a36Sopenharmony_ci		case PL_B_PCS :		plc->b_pcs++ ;	break ;
175662306a36Sopenharmony_ci		case PL_B_TPC :		plc->b_tpc++ ;	break ;
175762306a36Sopenharmony_ci		case PL_B_TNE :		plc->b_tne++ ;	break ;
175862306a36Sopenharmony_ci		case PL_B_QLS :		plc->b_qls++ ;	break ;
175962306a36Sopenharmony_ci		case PL_B_ILS :		plc->b_ils++ ;	break ;
176062306a36Sopenharmony_ci		case PL_B_HLS :		plc->b_hls++ ;	break ;
176162306a36Sopenharmony_ci		}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci		/*jd 05-Aug-1999 changed: Bug #10419 */
176462306a36Sopenharmony_ci		DB_PCMN(1, "PLC %d: MDcF = %x", np, smc->e.DisconnectFlag);
176562306a36Sopenharmony_ci		if (smc->e.DisconnectFlag == FALSE) {
176662306a36Sopenharmony_ci			DB_PCMN(1, "PLC %d: restart (reason %x)", np, reason);
176762306a36Sopenharmony_ci			queue_event(smc,EVENT_PCM+np,PC_START) ;
176862306a36Sopenharmony_ci		}
176962306a36Sopenharmony_ci		else {
177062306a36Sopenharmony_ci			DB_PCMN(1, "PLC %d: NO!! restart (reason %x)",
177162306a36Sopenharmony_ci				np, reason);
177262306a36Sopenharmony_ci		}
177362306a36Sopenharmony_ci		return ;
177462306a36Sopenharmony_ci	}
177562306a36Sopenharmony_ci	/*
177662306a36Sopenharmony_ci	 * If both CODE & ENABLE are set ignore enable
177762306a36Sopenharmony_ci	 */
177862306a36Sopenharmony_ci	if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */
177962306a36Sopenharmony_ci		queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ;
178062306a36Sopenharmony_ci		n = inpw(PLC(np,PL_RCV_VECTOR)) ;
178162306a36Sopenharmony_ci		for (i = 0 ; i < plc->p_bits ; i++) {
178262306a36Sopenharmony_ci			phy->r_val[plc->p_start+i] = n & 1 ;
178362306a36Sopenharmony_ci			n >>= 1 ;
178462306a36Sopenharmony_ci		}
178562306a36Sopenharmony_ci	}
178662306a36Sopenharmony_ci	else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/
178762306a36Sopenharmony_ci		queue_event(smc,EVENT_PCM+np,PC_JOIN) ;
178862306a36Sopenharmony_ci	}
178962306a36Sopenharmony_ci	if (cmd & PL_TRACE_PROP) {	/* MLS while PC8_ACTIV || PC2_TRACE */
179062306a36Sopenharmony_ci		/*PC22b*/
179162306a36Sopenharmony_ci		if (!phy->tr_flag) {
179262306a36Sopenharmony_ci			DB_PCMN(1, "PCM : irq TRACE_PROP %d %d",
179362306a36Sopenharmony_ci				np, smc->mib.fddiSMTECMState);
179462306a36Sopenharmony_ci			phy->tr_flag = TRUE ;
179562306a36Sopenharmony_ci			smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ;
179662306a36Sopenharmony_ci			queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
179762306a36Sopenharmony_ci		}
179862306a36Sopenharmony_ci	}
179962306a36Sopenharmony_ci	/*
180062306a36Sopenharmony_ci	 * filter PLC glitch ???
180162306a36Sopenharmony_ci	 * QLS || HLS only while in PC2_TRACE state
180262306a36Sopenharmony_ci	 */
180362306a36Sopenharmony_ci	if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) {
180462306a36Sopenharmony_ci		/*PC22a*/
180562306a36Sopenharmony_ci		if (smc->e.path_test == PT_PASSED) {
180662306a36Sopenharmony_ci			DB_PCMN(1, "PCM : state = %s %d",
180762306a36Sopenharmony_ci				get_pcmstate(smc, np),
180862306a36Sopenharmony_ci				phy->mib->fddiPORTPCMState);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci			smc->e.path_test = PT_PENDING ;
181162306a36Sopenharmony_ci			queue_event(smc,EVENT_ECM,EC_PATH_TEST) ;
181262306a36Sopenharmony_ci		}
181362306a36Sopenharmony_ci	}
181462306a36Sopenharmony_ci	if (cmd & PL_TNE_EXPIRED) {	/* TNE: length of noise events */
181562306a36Sopenharmony_ci		/* break_required (TNE > NS_Max) */
181662306a36Sopenharmony_ci		if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) {
181762306a36Sopenharmony_ci			if (!phy->tr_flag) {
181862306a36Sopenharmony_ci				DB_PCMN(1, "PCM %c : PC81 %s",
181962306a36Sopenharmony_ci					phy->phy_name, "NSE");
182062306a36Sopenharmony_ci				queue_event(smc, EVENT_PCM + np, PC_START);
182162306a36Sopenharmony_ci				return;
182262306a36Sopenharmony_ci			}
182362306a36Sopenharmony_ci		}
182462306a36Sopenharmony_ci	}
182562306a36Sopenharmony_ci#if	0
182662306a36Sopenharmony_ci	if (cmd & PL_NP_ERR) {		/* NP has requested to r/w an inv reg*/
182762306a36Sopenharmony_ci		/*
182862306a36Sopenharmony_ci		 * It's a bug by AMD
182962306a36Sopenharmony_ci		 */
183062306a36Sopenharmony_ci		plc->np_err++ ;
183162306a36Sopenharmony_ci	}
183262306a36Sopenharmony_ci	/* pin inactiv (GND) */
183362306a36Sopenharmony_ci	if (cmd & PL_PARITY_ERR) {	/* p. error dedected on TX9-0 inp */
183462306a36Sopenharmony_ci		plc->parity_err++ ;
183562306a36Sopenharmony_ci	}
183662306a36Sopenharmony_ci	if (cmd & PL_LSDO) {		/* carrier detected */
183762306a36Sopenharmony_ci		;
183862306a36Sopenharmony_ci	}
183962306a36Sopenharmony_ci#endif
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci#ifdef	DEBUG
184362306a36Sopenharmony_ci/*
184462306a36Sopenharmony_ci * fill state struct
184562306a36Sopenharmony_ci */
184662306a36Sopenharmony_civoid pcm_get_state(struct s_smc *smc, struct smt_state *state)
184762306a36Sopenharmony_ci{
184862306a36Sopenharmony_ci	struct s_phy	*phy ;
184962306a36Sopenharmony_ci	struct pcm_state *pcs ;
185062306a36Sopenharmony_ci	int	i ;
185162306a36Sopenharmony_ci	int	ii ;
185262306a36Sopenharmony_ci	short	rbits ;
185362306a36Sopenharmony_ci	short	tbits ;
185462306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ;
185762306a36Sopenharmony_ci		i++ , phy++, pcs++ ) {
185862306a36Sopenharmony_ci		mib = phy->mib ;
185962306a36Sopenharmony_ci		pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ;
186062306a36Sopenharmony_ci		pcs->pcm_state = (u_char) mib->fddiPORTPCMState ;
186162306a36Sopenharmony_ci		pcs->pcm_mode = phy->pc_mode ;
186262306a36Sopenharmony_ci		pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ;
186362306a36Sopenharmony_ci		pcs->pcm_bsf = mib->fddiPORTBS_Flag ;
186462306a36Sopenharmony_ci		pcs->pcm_lsf = phy->ls_flag ;
186562306a36Sopenharmony_ci		pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ;
186662306a36Sopenharmony_ci		pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ;
186762306a36Sopenharmony_ci		for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) {
186862306a36Sopenharmony_ci			rbits <<= 1 ;
186962306a36Sopenharmony_ci			tbits <<= 1 ;
187062306a36Sopenharmony_ci			if (phy->r_val[NUMBITS-1-ii])
187162306a36Sopenharmony_ci				rbits |= 1 ;
187262306a36Sopenharmony_ci			if (phy->t_val[NUMBITS-1-ii])
187362306a36Sopenharmony_ci				tbits |= 1 ;
187462306a36Sopenharmony_ci		}
187562306a36Sopenharmony_ci		pcs->pcm_r_val = rbits ;
187662306a36Sopenharmony_ci		pcs->pcm_t_val = tbits ;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ciint get_pcm_state(struct s_smc *smc, int np)
188162306a36Sopenharmony_ci{
188262306a36Sopenharmony_ci	int pcs ;
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	SK_UNUSED(smc) ;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
188762306a36Sopenharmony_ci		case PL_PC0 :	pcs = PC_STOP ;		break ;
188862306a36Sopenharmony_ci		case PL_PC1 :	pcs = PC_START ;	break ;
188962306a36Sopenharmony_ci		case PL_PC2 :	pcs = PC_TRACE ;	break ;
189062306a36Sopenharmony_ci		case PL_PC3 :	pcs = PC_SIGNAL ;	break ;
189162306a36Sopenharmony_ci		case PL_PC4 :	pcs = PC_SIGNAL ;	break ;
189262306a36Sopenharmony_ci		case PL_PC5 :	pcs = PC_SIGNAL ;	break ;
189362306a36Sopenharmony_ci		case PL_PC6 :	pcs = PC_JOIN ;		break ;
189462306a36Sopenharmony_ci		case PL_PC7 :	pcs = PC_JOIN ;		break ;
189562306a36Sopenharmony_ci		case PL_PC8 :	pcs = PC_ENABLE ;	break ;
189662306a36Sopenharmony_ci		case PL_PC9 :	pcs = PC_MAINT ;	break ;
189762306a36Sopenharmony_ci		default :	pcs = PC_DISABLE ; 	break ;
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci	return pcs;
190062306a36Sopenharmony_ci}
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_cichar *get_linestate(struct s_smc *smc, int np)
190362306a36Sopenharmony_ci{
190462306a36Sopenharmony_ci	char *ls = "" ;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	SK_UNUSED(smc) ;
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) {
190962306a36Sopenharmony_ci		case PL_L_NLS :	ls = "NOISE" ;	break ;
191062306a36Sopenharmony_ci		case PL_L_ALS :	ls = "ACTIV" ;	break ;
191162306a36Sopenharmony_ci		case PL_L_UND :	ls = "UNDEF" ;	break ;
191262306a36Sopenharmony_ci		case PL_L_ILS4:	ls = "ILS 4" ;	break ;
191362306a36Sopenharmony_ci		case PL_L_QLS :	ls = "QLS" ;	break ;
191462306a36Sopenharmony_ci		case PL_L_MLS :	ls = "MLS" ;	break ;
191562306a36Sopenharmony_ci		case PL_L_HLS :	ls = "HLS" ;	break ;
191662306a36Sopenharmony_ci		case PL_L_ILS16:ls = "ILS16" ;	break ;
191762306a36Sopenharmony_ci#ifdef	lint
191862306a36Sopenharmony_ci		default:	ls = "unknown" ; break ;
191962306a36Sopenharmony_ci#endif
192062306a36Sopenharmony_ci	}
192162306a36Sopenharmony_ci	return ls;
192262306a36Sopenharmony_ci}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_cichar *get_pcmstate(struct s_smc *smc, int np)
192562306a36Sopenharmony_ci{
192662306a36Sopenharmony_ci	char *pcs ;
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	SK_UNUSED(smc) ;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
193162306a36Sopenharmony_ci		case PL_PC0 :	pcs = "OFF" ;		break ;
193262306a36Sopenharmony_ci		case PL_PC1 :	pcs = "BREAK" ;		break ;
193362306a36Sopenharmony_ci		case PL_PC2 :	pcs = "TRACE" ;		break ;
193462306a36Sopenharmony_ci		case PL_PC3 :	pcs = "CONNECT";	break ;
193562306a36Sopenharmony_ci		case PL_PC4 :	pcs = "NEXT" ;		break ;
193662306a36Sopenharmony_ci		case PL_PC5 :	pcs = "SIGNAL" ;	break ;
193762306a36Sopenharmony_ci		case PL_PC6 :	pcs = "JOIN" ;		break ;
193862306a36Sopenharmony_ci		case PL_PC7 :	pcs = "VERIFY" ;	break ;
193962306a36Sopenharmony_ci		case PL_PC8 :	pcs = "ACTIV" ;		break ;
194062306a36Sopenharmony_ci		case PL_PC9 :	pcs = "MAINT" ;		break ;
194162306a36Sopenharmony_ci		default :	pcs = "UNKNOWN" ; 	break ;
194262306a36Sopenharmony_ci	}
194362306a36Sopenharmony_ci	return pcs;
194462306a36Sopenharmony_ci}
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_civoid list_phy(struct s_smc *smc)
194762306a36Sopenharmony_ci{
194862306a36Sopenharmony_ci	struct s_plc *plc ;
194962306a36Sopenharmony_ci	int np ;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	for (np = 0 ; np < NUMPHYS ; np++) {
195262306a36Sopenharmony_ci		plc  = &smc->y[np].plc ;
195362306a36Sopenharmony_ci		printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ;
195462306a36Sopenharmony_ci		printf("\tsoft_error: %ld \t\tPC_Start : %ld\n",
195562306a36Sopenharmony_ci						plc->soft_err,plc->b_pcs);
195662306a36Sopenharmony_ci		printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n",
195762306a36Sopenharmony_ci			plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ;
195862306a36Sopenharmony_ci		printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n",
195962306a36Sopenharmony_ci						plc->ebuf_err,plc->b_tne) ;
196062306a36Sopenharmony_ci		printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n",
196162306a36Sopenharmony_ci			plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ;
196262306a36Sopenharmony_ci		printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n",
196362306a36Sopenharmony_ci						plc->vsym_ctr,plc->b_ils)  ;
196462306a36Sopenharmony_ci		printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n",
196562306a36Sopenharmony_ci						plc->mini_ctr,plc->b_hls) ;
196662306a36Sopenharmony_ci		printf("\tnodepr_err: %ld\n",plc->np_err) ;
196762306a36Sopenharmony_ci		printf("\tTPC_exp : %ld\n",plc->tpc_exp) ;
196862306a36Sopenharmony_ci		printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ;
196962306a36Sopenharmony_ci	}
197062306a36Sopenharmony_ci}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci#ifdef	CONCENTRATOR
197462306a36Sopenharmony_civoid pcm_lem_dump(struct s_smc *smc)
197562306a36Sopenharmony_ci{
197662306a36Sopenharmony_ci	int		i ;
197762306a36Sopenharmony_ci	struct s_phy	*phy ;
197862306a36Sopenharmony_ci	struct fddi_mib_p	*mib ;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	char		*entostring() ;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	printf("PHY	errors	BER\n") ;
198362306a36Sopenharmony_ci	printf("----------------------\n") ;
198462306a36Sopenharmony_ci	for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) {
198562306a36Sopenharmony_ci		if (!plc_is_installed(smc,i))
198662306a36Sopenharmony_ci			continue ;
198762306a36Sopenharmony_ci		mib = phy->mib ;
198862306a36Sopenharmony_ci		printf("%s\t%ld\t10E-%d\n",
198962306a36Sopenharmony_ci			entostring(smc,ENTITY_PHY(i)),
199062306a36Sopenharmony_ci			mib->fddiPORTLem_Ct,
199162306a36Sopenharmony_ci			mib->fddiPORTLer_Estimate) ;
199262306a36Sopenharmony_ci	}
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci#endif
199562306a36Sopenharmony_ci#endif
1996