628 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			628 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/******************************************************************************
 | 
						|
 *
 | 
						|
 *	(C)Copyright 1998,1999 SysKonnect,
 | 
						|
 *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
 | 
						|
 *
 | 
						|
 *	See the file "skfddi.c" for further information.
 | 
						|
 *
 | 
						|
 *	This program is free software; you can redistribute it and/or modify
 | 
						|
 *	it under the terms of the GNU General Public License as published by
 | 
						|
 *	the Free Software Foundation; either version 2 of the License, or
 | 
						|
 *	(at your option) any later version.
 | 
						|
 *
 | 
						|
 *	The information in this file is provided "AS IS" without warranty.
 | 
						|
 *
 | 
						|
 ******************************************************************************/
 | 
						|
 | 
						|
/*
 | 
						|
	SMT CFM
 | 
						|
	Configuration Management
 | 
						|
	DAS with single MAC
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
 *	Hardware independent state machine implemantation
 | 
						|
 *	The following external SMT functions are referenced :
 | 
						|
 *
 | 
						|
 *		queue_event()
 | 
						|
 *
 | 
						|
 *	The following external HW dependent functions are referenced :
 | 
						|
 *		config_mux()
 | 
						|
 *
 | 
						|
 *	The following HW dependent events are required :
 | 
						|
 *		NONE 
 | 
						|
 */
 | 
						|
 | 
						|
#include "h/types.h"
 | 
						|
#include "h/fddi.h"
 | 
						|
#include "h/smc.h"
 | 
						|
 | 
						|
#define KERNEL
 | 
						|
#include "h/smtstate.h"
 | 
						|
 | 
						|
#ifndef	lint
 | 
						|
static const char ID_sccs[] = "@(#)cfm.c	2.18 98/10/06 (C) SK " ;
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * FSM Macros
 | 
						|
 */
 | 
						|
#define AFLAG	0x10
 | 
						|
#define GO_STATE(x)	(smc->mib.fddiSMTCF_State = (x)|AFLAG)
 | 
						|
#define ACTIONS_DONE()	(smc->mib.fddiSMTCF_State &= ~AFLAG)
 | 
						|
#define ACTIONS(x)	(x|AFLAG)
 | 
						|
 | 
						|
#ifdef	DEBUG
 | 
						|
/*
 | 
						|
 * symbolic state names
 | 
						|
 */
 | 
						|
static const char * const cfm_states[] = {
 | 
						|
	"SC0_ISOLATED","CF1","CF2","CF3","CF4",
 | 
						|
	"SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S",
 | 
						|
	"SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A"
 | 
						|
} ;
 | 
						|
 | 
						|
/*
 | 
						|
 * symbolic event names
 | 
						|
 */
 | 
						|
static const char * const cfm_events[] = {
 | 
						|
	"NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
 | 
						|
} ;
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * map from state to downstream port type
 | 
						|
 */
 | 
						|
static const unsigned char cf_to_ptype[] = {
 | 
						|
	TNONE,TNONE,TNONE,TNONE,TNONE,
 | 
						|
	TNONE,TB,TB,TS,
 | 
						|
	TA,TB,TS,TB
 | 
						|
} ;
 | 
						|
 | 
						|
/*
 | 
						|
 * CEM port states
 | 
						|
 */
 | 
						|
#define	CEM_PST_DOWN	0
 | 
						|
#define	CEM_PST_UP	1
 | 
						|
#define	CEM_PST_HOLD	2
 | 
						|
/* define portstate array only for A and B port */
 | 
						|
/* Do this within the smc structure (use in multiple cards) */
 | 
						|
 | 
						|
/*
 | 
						|
 * all Globals  are defined in smc.h
 | 
						|
 * struct s_cfm
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * function declarations
 | 
						|
 */
 | 
						|
static void cfm_fsm(struct s_smc *smc, int cmd);
 | 
						|
 | 
						|
/*
 | 
						|
	init CFM state machine
 | 
						|
	clear all CFM vars and flags
 | 
						|
*/
 | 
						|
void cfm_init(struct s_smc *smc)
 | 
						|
{
 | 
						|
	smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ;
 | 
						|
	smc->r.rm_join = 0 ;
 | 
						|
	smc->r.rm_loop = 0 ;
 | 
						|
	smc->y[PA].scrub = 0 ;
 | 
						|
	smc->y[PB].scrub = 0 ;
 | 
						|
	smc->y[PA].cem_pst = CEM_PST_DOWN ;
 | 
						|
	smc->y[PB].cem_pst = CEM_PST_DOWN ;
 | 
						|
}
 | 
						|
 | 
						|
/* Some terms conditions used by the selection criteria */
 | 
						|
#define THRU_ENABLED(smc)	(smc->y[PA].pc_mode != PM_TREE && \
 | 
						|
				 smc->y[PB].pc_mode != PM_TREE)
 | 
						|
/* Selection criteria for the ports */
 | 
						|
static void selection_criteria (struct s_smc *smc, struct s_phy *phy)
 | 
						|
{
 | 
						|
 | 
						|
	switch (phy->mib->fddiPORTMy_Type) {
 | 
						|
	case TA:
 | 
						|
		if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) {
 | 
						|
			phy->wc_flag = TRUE ;
 | 
						|
		} else {
 | 
						|
			phy->wc_flag = FALSE ;
 | 
						|
		}
 | 
						|
 | 
						|
		break;
 | 
						|
	case TB:
 | 
						|
		/* take precedence over PA */
 | 
						|
		phy->wc_flag = FALSE ;
 | 
						|
		break;
 | 
						|
	case TS:
 | 
						|
		phy->wc_flag = FALSE ;
 | 
						|
		break;
 | 
						|
	case TM:
 | 
						|
		phy->wc_flag = FALSE ;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void all_selection_criteria(struct s_smc *smc)
 | 
						|
{
 | 
						|
	struct s_phy	*phy ;
 | 
						|
	int		p ;
 | 
						|
 | 
						|
	for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) {
 | 
						|
		/* Do the selection criteria */
 | 
						|
		selection_criteria (smc,phy);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void cem_priv_state(struct s_smc *smc, int event)
 | 
						|
/* State machine for private PORT states: used to optimize dual homing */
 | 
						|
{
 | 
						|
	int	np;	/* Number of the port */
 | 
						|
	int	i;
 | 
						|
 | 
						|
	/* Do this only in a DAS */
 | 
						|
	if (smc->s.sas != SMT_DAS )
 | 
						|
		return ;
 | 
						|
 | 
						|
	np = event - CF_JOIN;
 | 
						|
 | 
						|
	if (np != PA && np != PB) {
 | 
						|
		return ;
 | 
						|
	}
 | 
						|
	/* Change the port state according to the event (portnumber) */
 | 
						|
	if (smc->y[np].cf_join) {
 | 
						|
		smc->y[np].cem_pst = CEM_PST_UP ;
 | 
						|
	} else if (!smc->y[np].wc_flag) {
 | 
						|
		/* set the port to done only if it is not withheld */
 | 
						|
		smc->y[np].cem_pst = CEM_PST_DOWN ;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Don't set an hold port to down */
 | 
						|
 | 
						|
	/* Check all ports of restart conditions */
 | 
						|
	for (i = 0 ; i < 2 ; i ++ ) {
 | 
						|
		/* Check all port for PORT is on hold and no withhold is done */
 | 
						|
		if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) {
 | 
						|
			smc->y[i].cem_pst = CEM_PST_DOWN;
 | 
						|
			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
 | 
						|
		}
 | 
						|
		if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) {
 | 
						|
			smc->y[i].cem_pst = CEM_PST_HOLD;
 | 
						|
			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
 | 
						|
		}
 | 
						|
		if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) {
 | 
						|
			/*
 | 
						|
			 * The port must be restarted when the wc_flag
 | 
						|
			 * will be reset. So set the port on hold.
 | 
						|
			 */
 | 
						|
			smc->y[i].cem_pst = CEM_PST_HOLD;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return ;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	CFM state machine
 | 
						|
	called by dispatcher
 | 
						|
 | 
						|
	do
 | 
						|
		display state change
 | 
						|
		process event
 | 
						|
	until SM is stable
 | 
						|
*/
 | 
						|
void cfm(struct s_smc *smc, int event)
 | 
						|
{
 | 
						|
	int	state ;		/* remember last state */
 | 
						|
	int	cond ;
 | 
						|
	int	oldstate ;
 | 
						|
 | 
						|
	/* We will do the following: */
 | 
						|
	/*  - compute the variable WC_Flag for every port (This is where */
 | 
						|
	/*    we can extend the requested path checking !!) */
 | 
						|
	/*  - do the old (SMT 6.2 like) state machine */
 | 
						|
	/*  - do the resulting station states */
 | 
						|
 | 
						|
	all_selection_criteria (smc);
 | 
						|
 | 
						|
	/* We will check now whether a state transition is allowed or not */
 | 
						|
	/*  - change the portstates */
 | 
						|
	cem_priv_state (smc, event);
 | 
						|
 | 
						|
	oldstate = smc->mib.fddiSMTCF_State ;
 | 
						|
	do {
 | 
						|
		DB_CFM("CFM : state %s%s",
 | 
						|
			(smc->mib.fddiSMTCF_State & AFLAG) ? "ACTIONS " : "",
 | 
						|
			cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG]) ;
 | 
						|
		DB_CFM(" event %s\n",cfm_events[event],0) ;
 | 
						|
		state = smc->mib.fddiSMTCF_State ;
 | 
						|
		cfm_fsm(smc,event) ;
 | 
						|
		event = 0 ;
 | 
						|
	} while (state != smc->mib.fddiSMTCF_State) ;
 | 
						|
 | 
						|
#ifndef	SLIM_SMT
 | 
						|
	/*
 | 
						|
	 * check peer wrap condition
 | 
						|
	 */
 | 
						|
	cond = FALSE ;
 | 
						|
	if (	(smc->mib.fddiSMTCF_State == SC9_C_WRAP_A &&
 | 
						|
		smc->y[PA].pc_mode == PM_PEER) 	||
 | 
						|
		(smc->mib.fddiSMTCF_State == SC10_C_WRAP_B &&
 | 
						|
		smc->y[PB].pc_mode == PM_PEER) 	||
 | 
						|
		(smc->mib.fddiSMTCF_State == SC11_C_WRAP_S &&
 | 
						|
		smc->y[PS].pc_mode == PM_PEER &&
 | 
						|
		smc->y[PS].mib->fddiPORTNeighborType != TS ) ) {
 | 
						|
			cond = TRUE ;
 | 
						|
	}
 | 
						|
	if (cond != smc->mib.fddiSMTPeerWrapFlag)
 | 
						|
		smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ;
 | 
						|
 | 
						|
#if	0
 | 
						|
	/*
 | 
						|
	 * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired
 | 
						|
	 * to the primary path.
 | 
						|
	 */
 | 
						|
	/*
 | 
						|
	 * path change
 | 
						|
	 */
 | 
						|
	if (smc->mib.fddiSMTCF_State != oldstate) {
 | 
						|
		smt_srf_event(smc,SMT_EVENT_MAC_PATH_CHANGE,INDEX_MAC,0) ;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
#endif	/* no SLIM_SMT */
 | 
						|
 | 
						|
	/*
 | 
						|
	 * set MAC port type
 | 
						|
	 */
 | 
						|
	smc->mib.m[MAC0].fddiMACDownstreamPORTType =
 | 
						|
		cf_to_ptype[smc->mib.fddiSMTCF_State] ;
 | 
						|
	cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
	process CFM event
 | 
						|
*/
 | 
						|
/*ARGSUSED1*/
 | 
						|
static void cfm_fsm(struct s_smc *smc, int cmd)
 | 
						|
{
 | 
						|
	switch(smc->mib.fddiSMTCF_State) {
 | 
						|
	case ACTIONS(SC0_ISOLATED) :
 | 
						|
		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
 | 
						|
		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
 | 
						|
		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
 | 
						|
		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
 | 
						|
		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;
 | 
						|
		config_mux(smc,MUX_ISOLATE) ;	/* configure PHY Mux */
 | 
						|
		smc->r.rm_loop = FALSE ;
 | 
						|
		smc->r.rm_join = FALSE ;
 | 
						|
		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
 | 
						|
		/* Don't do the WC-Flag changing here */
 | 
						|
		ACTIONS_DONE() ;
 | 
						|
		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
 | 
						|
		break;
 | 
						|
	case SC0_ISOLATED :
 | 
						|
		/*SC07*/
 | 
						|
		/*SAS port can be PA or PB ! */
 | 
						|
		if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop ||
 | 
						|
				smc->y[PB].cf_join || smc->y[PB].cf_loop)) {
 | 
						|
			GO_STATE(SC11_C_WRAP_S) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC01*/
 | 
						|
		if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join &&
 | 
						|
		     !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) {
 | 
						|
			GO_STATE(SC9_C_WRAP_A) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC02*/
 | 
						|
		if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join &&
 | 
						|
		     !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) {
 | 
						|
			GO_STATE(SC10_C_WRAP_B) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		break ;
 | 
						|
	case ACTIONS(SC9_C_WRAP_A) :
 | 
						|
		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
 | 
						|
		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
 | 
						|
		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
 | 
						|
		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
 | 
						|
		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
 | 
						|
		config_mux(smc,MUX_WRAPA) ;		/* configure PHY mux */
 | 
						|
		if (smc->y[PA].cf_loop) {
 | 
						|
			smc->r.rm_join = FALSE ;
 | 
						|
			smc->r.rm_loop = TRUE ;
 | 
						|
			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
 | 
						|
		}
 | 
						|
		if (smc->y[PA].cf_join) {
 | 
						|
			smc->r.rm_loop = FALSE ;
 | 
						|
			smc->r.rm_join = TRUE ;
 | 
						|
			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
 | 
						|
		}
 | 
						|
		ACTIONS_DONE() ;
 | 
						|
		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
 | 
						|
		break ;
 | 
						|
	case SC9_C_WRAP_A :
 | 
						|
		/*SC10*/
 | 
						|
		if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) &&
 | 
						|
		      !smc->y[PA].cf_loop ) {
 | 
						|
			GO_STATE(SC0_ISOLATED) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC12*/
 | 
						|
		else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join &&
 | 
						|
			   smc->y[PA].cem_pst == CEM_PST_UP) ||
 | 
						|
			  ((smc->y[PB].cf_loop ||
 | 
						|
			   (smc->y[PB].cf_join &&
 | 
						|
			    smc->y[PB].cem_pst == CEM_PST_UP)) &&
 | 
						|
			    (smc->y[PA].pc_mode == PM_TREE ||
 | 
						|
			     smc->y[PB].pc_mode == PM_TREE))) {
 | 
						|
			smc->y[PA].scrub = TRUE ;
 | 
						|
			GO_STATE(SC10_C_WRAP_B) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC14*/
 | 
						|
		else if (!smc->s.attach_s &&
 | 
						|
			  smc->y[PA].cf_join &&
 | 
						|
			  smc->y[PA].cem_pst == CEM_PST_UP &&
 | 
						|
			  smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join &&
 | 
						|
			  smc->y[PB].cem_pst == CEM_PST_UP &&
 | 
						|
			  smc->y[PB].pc_mode == PM_PEER) {
 | 
						|
			smc->y[PA].scrub = TRUE ;
 | 
						|
			smc->y[PB].scrub = TRUE ;
 | 
						|
			GO_STATE(SC4_THRU_A) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC15*/
 | 
						|
		else if ( smc->s.attach_s &&
 | 
						|
			  smc->y[PA].cf_join &&
 | 
						|
			  smc->y[PA].cem_pst == CEM_PST_UP &&
 | 
						|
			  smc->y[PA].pc_mode == PM_PEER &&
 | 
						|
			  smc->y[PB].cf_join &&
 | 
						|
			  smc->y[PB].cem_pst == CEM_PST_UP &&
 | 
						|
			  smc->y[PB].pc_mode == PM_PEER) {
 | 
						|
			smc->y[PA].scrub = TRUE ;
 | 
						|
			smc->y[PB].scrub = TRUE ;
 | 
						|
			GO_STATE(SC5_THRU_B) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		break ;
 | 
						|
	case ACTIONS(SC10_C_WRAP_B) :
 | 
						|
		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
 | 
						|
		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
 | 
						|
		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
 | 
						|
		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
 | 
						|
		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
 | 
						|
		config_mux(smc,MUX_WRAPB) ;		/* configure PHY mux */
 | 
						|
		if (smc->y[PB].cf_loop) {
 | 
						|
			smc->r.rm_join = FALSE ;
 | 
						|
			smc->r.rm_loop = TRUE ;
 | 
						|
			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
 | 
						|
		}
 | 
						|
		if (smc->y[PB].cf_join) {
 | 
						|
			smc->r.rm_loop = FALSE ;
 | 
						|
			smc->r.rm_join = TRUE ;
 | 
						|
			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
 | 
						|
		}
 | 
						|
		ACTIONS_DONE() ;
 | 
						|
		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
 | 
						|
		break ;
 | 
						|
	case SC10_C_WRAP_B :
 | 
						|
		/*SC20*/
 | 
						|
		if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) {
 | 
						|
			GO_STATE(SC0_ISOLATED) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC21*/
 | 
						|
		else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER &&
 | 
						|
			  smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
 | 
						|
			smc->y[PB].scrub = TRUE ;
 | 
						|
			GO_STATE(SC9_C_WRAP_A) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC24*/
 | 
						|
		else if (!smc->s.attach_s &&
 | 
						|
			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
 | 
						|
			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
 | 
						|
			smc->y[PA].scrub = TRUE ;
 | 
						|
			smc->y[PB].scrub = TRUE ;
 | 
						|
			GO_STATE(SC4_THRU_A) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC25*/
 | 
						|
		else if ( smc->s.attach_s &&
 | 
						|
			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
 | 
						|
			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
 | 
						|
			smc->y[PA].scrub = TRUE ;
 | 
						|
			smc->y[PB].scrub = TRUE ;
 | 
						|
			GO_STATE(SC5_THRU_B) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		break ;
 | 
						|
	case ACTIONS(SC4_THRU_A) :
 | 
						|
		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
 | 
						|
		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
 | 
						|
		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
 | 
						|
		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
 | 
						|
		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
 | 
						|
		config_mux(smc,MUX_THRUA) ;		/* configure PHY mux */
 | 
						|
		smc->r.rm_loop = FALSE ;
 | 
						|
		smc->r.rm_join = TRUE ;
 | 
						|
		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
 | 
						|
		ACTIONS_DONE() ;
 | 
						|
		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
 | 
						|
		break ;
 | 
						|
	case SC4_THRU_A :
 | 
						|
		/*SC41*/
 | 
						|
		if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) {
 | 
						|
			smc->y[PA].scrub = TRUE ;
 | 
						|
			GO_STATE(SC9_C_WRAP_A) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC42*/
 | 
						|
		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
 | 
						|
			smc->y[PB].scrub = TRUE ;
 | 
						|
			GO_STATE(SC10_C_WRAP_B) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC45*/
 | 
						|
		else if (smc->s.attach_s) {
 | 
						|
			smc->y[PB].scrub = TRUE ;
 | 
						|
			GO_STATE(SC5_THRU_B) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		break ;
 | 
						|
	case ACTIONS(SC5_THRU_B) :
 | 
						|
		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
 | 
						|
		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
 | 
						|
		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
 | 
						|
		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
 | 
						|
		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
 | 
						|
		config_mux(smc,MUX_THRUB) ;		/* configure PHY mux */
 | 
						|
		smc->r.rm_loop = FALSE ;
 | 
						|
		smc->r.rm_join = TRUE ;
 | 
						|
		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
 | 
						|
		ACTIONS_DONE() ;
 | 
						|
		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
 | 
						|
		break ;
 | 
						|
	case SC5_THRU_B :
 | 
						|
		/*SC51*/
 | 
						|
		if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) {
 | 
						|
			smc->y[PA].scrub = TRUE ;
 | 
						|
			GO_STATE(SC9_C_WRAP_A) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC52*/
 | 
						|
		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
 | 
						|
			smc->y[PB].scrub = TRUE ;
 | 
						|
			GO_STATE(SC10_C_WRAP_B) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		/*SC54*/
 | 
						|
		else if (!smc->s.attach_s) {
 | 
						|
			smc->y[PA].scrub = TRUE ;
 | 
						|
			GO_STATE(SC4_THRU_A) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		break ;
 | 
						|
	case ACTIONS(SC11_C_WRAP_S) :
 | 
						|
		smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
 | 
						|
		smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ;
 | 
						|
		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
 | 
						|
		config_mux(smc,MUX_WRAPS) ;		/* configure PHY mux */
 | 
						|
		if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) {
 | 
						|
			smc->r.rm_join = FALSE ;
 | 
						|
			smc->r.rm_loop = TRUE ;
 | 
						|
			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
 | 
						|
		}
 | 
						|
		if (smc->y[PA].cf_join || smc->y[PB].cf_join) {
 | 
						|
			smc->r.rm_loop = FALSE ;
 | 
						|
			smc->r.rm_join = TRUE ;
 | 
						|
			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
 | 
						|
		}
 | 
						|
		ACTIONS_DONE() ;
 | 
						|
		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
 | 
						|
		break ;
 | 
						|
	case SC11_C_WRAP_S :
 | 
						|
		/*SC70*/
 | 
						|
		if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop &&
 | 
						|
		     !smc->y[PB].cf_join && !smc->y[PB].cf_loop) {
 | 
						|
			GO_STATE(SC0_ISOLATED) ;
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
		break ;
 | 
						|
	default:
 | 
						|
		SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * get MAC's input Port
 | 
						|
 *	return :
 | 
						|
 *		PA or PB
 | 
						|
 */
 | 
						|
int cfm_get_mac_input(struct s_smc *smc)
 | 
						|
{
 | 
						|
	return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
 | 
						|
		smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA) ;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * get MAC's output Port
 | 
						|
 *	return :
 | 
						|
 *		PA or PB
 | 
						|
 */
 | 
						|
int cfm_get_mac_output(struct s_smc *smc)
 | 
						|
{
 | 
						|
	return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
 | 
						|
		smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA) ;
 | 
						|
}
 | 
						|
 | 
						|
static char path_iso[] = {
 | 
						|
	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO,
 | 
						|
	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
 | 
						|
	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
 | 
						|
} ;
 | 
						|
 | 
						|
static char path_wrap_a[] = {
 | 
						|
	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
 | 
						|
	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
 | 
						|
	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
 | 
						|
} ;
 | 
						|
 | 
						|
static char path_wrap_b[] = {
 | 
						|
	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM,
 | 
						|
	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
 | 
						|
	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO
 | 
						|
} ;
 | 
						|
 | 
						|
static char path_thru[] = {
 | 
						|
	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
 | 
						|
	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
 | 
						|
	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM
 | 
						|
} ;
 | 
						|
 | 
						|
static char path_wrap_s[] = {
 | 
						|
	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_PRIM,
 | 
						|
	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
 | 
						|
} ;
 | 
						|
 | 
						|
static char path_iso_s[] = {
 | 
						|
	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_ISO,
 | 
						|
	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
 | 
						|
} ;
 | 
						|
 | 
						|
int cem_build_path(struct s_smc *smc, char *to, int path_index)
 | 
						|
{
 | 
						|
	char	*path ;
 | 
						|
	int	len ;
 | 
						|
 | 
						|
	switch (smc->mib.fddiSMTCF_State) {
 | 
						|
	default :
 | 
						|
	case SC0_ISOLATED :
 | 
						|
		path = smc->s.sas ? path_iso_s : path_iso ;
 | 
						|
		len = smc->s.sas ? sizeof(path_iso_s) :  sizeof(path_iso) ;
 | 
						|
		break ;
 | 
						|
	case SC9_C_WRAP_A :
 | 
						|
		path = path_wrap_a ;
 | 
						|
		len = sizeof(path_wrap_a) ;
 | 
						|
		break ;
 | 
						|
	case SC10_C_WRAP_B :
 | 
						|
		path = path_wrap_b ;
 | 
						|
		len = sizeof(path_wrap_b) ;
 | 
						|
		break ;
 | 
						|
	case SC4_THRU_A :
 | 
						|
		path = path_thru ;
 | 
						|
		len = sizeof(path_thru) ;
 | 
						|
		break ;
 | 
						|
	case SC11_C_WRAP_S :
 | 
						|
		path = path_wrap_s ;
 | 
						|
		len = sizeof(path_wrap_s) ;
 | 
						|
		break ;
 | 
						|
	}
 | 
						|
	memcpy(to,path,len) ;
 | 
						|
 | 
						|
	LINT_USE(path_index);
 | 
						|
 | 
						|
	return(len) ;
 | 
						|
}
 |