/*
 * (jd) RMT duplicate address actions
 * leave the ring or reinsert just as configured
 */
static void rmt_dup_actions(struct s_smc *smc)
{
	if (smc->r.jm_flag) {
	}
	else {
		if (smc->s.rmt_dup_mac_behavior) {
			SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
                        rmt_reinsert_actions(smc) ;
		}
		else {
			SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
			rmt_leave_actions(smc) ;
		}
	}
}
/*
 * duplicate address detected
 */
static void rmt_new_dup_actions(struct s_smc *smc)
{
	smc->r.da_flag = TRUE ;
	smc->r.bn_flag = FALSE ;
	smc->r.jm_flag = FALSE ;
	/*
	 * we have three options : change address, jam or leave
	 * we leave the ring as default
	 * Optionally it's possible to reinsert after leaving the Ring
	 * but this will not conform with SMT Spec.
	 */
	if (smc->s.rmt_dup_mac_behavior) {
		SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
		rmt_reinsert_actions(smc) ;
	}
	else {
		SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
		rmt_leave_actions(smc) ;
	}
}
Beispiel #3
0
/*
 * Interrupt actions for PLC & PCM events
 */
void plc_irq(struct s_smc *smc, int np, unsigned int cmd)
/* int np;	PHY index */
{
	struct s_phy *phy = &smc->y[np] ;
	struct s_plc *plc = &phy->plc ;
	int		n ;
#ifdef	SUPERNET_3
	int		corr_mask ;
#endif	/* SUPERNET_3 */
	int		i ;

	if (np >= smc->s.numphys) {
		plc->soft_err++ ;
		return ;
	}
	if (cmd & PL_EBUF_ERR) {	/* elastic buff. det. over-|underflow*/
		/*
		 * Check whether the SRF Condition occurred.
		 */
		if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){
			/*
			 * This is the real Elasticity Error.
			 * More than one in a row are treated as a
			 * single one.
			 * Only count this in the active state.
			 */
			phy->mib->fddiPORTEBError_Ct ++ ;

		}

		plc->ebuf_err++ ;
		if (plc->ebuf_cont <= 1000) {
			/*
			 * Prevent counter from being wrapped after
			 * hanging years in that interrupt.
			 */
			plc->ebuf_cont++ ;	/* Ebuf continous error */
		}

#ifdef	SUPERNET_3
		if (plc->ebuf_cont == 1000 &&
			((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) ==
			PLC_REV_SN3)) {
			/*
			 * This interrupt remeained high for at least
			 * 1000 consecutive interrupt calls.
			 *
			 * This is caused by a hardware error of the
			 * ORION part of the Supernet III chipset.
			 *
			 * Disable this bit from the mask.
			 */
			corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ;
			outpw(PLC(np,PL_INTR_MASK),corr_mask);

			/*
			 * Disconnect from the ring.
			 * Call the driver with the reset indication.
			 */
			queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;

			/*
			 * Make an error log entry.
			 */
			SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ;

			/*
			 * Indicate the Reset.
			 */
			drv_reset_indication(smc) ;
		}
#endif	/* SUPERNET_3 */
	} else {
		/* Reset the continous error variable */
		plc->ebuf_cont = 0 ;	/* reset Ebuf continous error */
	}
	if (cmd & PL_PHYINV) {		/* physical layer invalid signal */
		plc->phyinv++ ;
	}
	if (cmd & PL_VSYM_CTR) {	/* violation symbol counter has incr.*/
		plc->vsym_ctr++ ;
	}
	if (cmd & PL_MINI_CTR) {	/* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
		plc->mini_ctr++ ;
	}
	if (cmd & PL_LE_CTR) {		/* link error event counter */
		int	j ;

		/*
		 * note: PL_LINK_ERR_CTR MUST be read to clear it
		 */
		j = inpw(PLC(np,PL_LE_THRESHOLD)) ;
		i = inpw(PLC(np,PL_LINK_ERR_CTR)) ;

		if (i < j) {
			/* wrapped around */
			i += 256 ;
		}

		if (phy->lem.lem_on) {
			/* Note: Lem errors shall only be counted when
			 * link is ACTIVE or LCT is active.
			 */
			phy->lem.lem_errors += i ;
			phy->mib->fddiPORTLem_Ct += i ;
		}
	}
	if (cmd & PL_TPC_EXPIRED) {	/* TPC timer reached zero */
		if (plc->p_state == PS_LCT) {
			/*
			 * end of LCT
			 */
			;
		}
		plc->tpc_exp++ ;
	}
	if (cmd & PL_LS_MATCH) {	/* LS == LS in PLC_CNTRL_B's MATCH_LS*/
		switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) {
		case PL_I_IDLE :	phy->curr_ls = PC_ILS ;		break ;
		case PL_I_HALT :	phy->curr_ls = PC_HLS ;		break ;
		case PL_I_MASTR :	phy->curr_ls = PC_MLS ;		break ;
		case PL_I_QUIET :	phy->curr_ls = PC_QLS ;		break ;
		}
	}
	if (cmd & PL_PCM_BREAK) {	/* PCM has entered the BREAK state */
		int	reason;

		reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ;

		switch (reason) {
		case PL_B_PCS :		plc->b_pcs++ ;	break ;
		case PL_B_TPC :		plc->b_tpc++ ;	break ;
		case PL_B_TNE :		plc->b_tne++ ;	break ;
		case PL_B_QLS :		plc->b_qls++ ;	break ;
		case PL_B_ILS :		plc->b_ils++ ;	break ;
		case PL_B_HLS :		plc->b_hls++ ;	break ;
		}

		/*jd 05-Aug-1999 changed: Bug #10419 */
		DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag);
		if (smc->e.DisconnectFlag == FALSE) {
			DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason);
			queue_event(smc,EVENT_PCM+np,PC_START) ;
		}
		else {
			DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason);
		}
		return ;
	}
	/*
	 * If both CODE & ENABLE are set ignore enable
	 */
	if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */
		queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ;
		n = inpw(PLC(np,PL_RCV_VECTOR)) ;
		for (i = 0 ; i < plc->p_bits ; i++) {
			phy->r_val[plc->p_start+i] = n & 1 ;
			n >>= 1 ;
		}
	}