diff options
Diffstat (limited to 'drivers/net/sk98lin/skrlmt.c')
| -rw-r--r-- | drivers/net/sk98lin/skrlmt.c | 3508 | 
1 files changed, 3508 insertions, 0 deletions
| diff --git a/drivers/net/sk98lin/skrlmt.c b/drivers/net/sk98lin/skrlmt.c new file mode 100644 index 000000000..f8a3b41f0 --- /dev/null +++ b/drivers/net/sk98lin/skrlmt.c @@ -0,0 +1,3508 @@ +/****************************************************************************** + * + * Name:	skrlmt.c + * Project:	GEnesis, PCI Gigabit Ethernet Adapter + * Version:	$Revision: 1.68 $ + * Date:	$Date: 2003/01/31 15:26:56 $ + * Purpose:	Manage links on SK-NET Adapters, esp. redundant ones. + * + ******************************************************************************/ + +/****************************************************************************** + * + *	(C)Copyright 1998-2001 SysKonnect GmbH. + * + *	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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + *	$Log: skrlmt.c,v $ + *	Revision 1.68  2003/01/31 15:26:56  rschmidt + *	Added init for local variables in RlmtInit(). + * + *	Revision 1.67  2003/01/31 14:12:41  mkunz + *	single port adapter runs now with two identical MAC addresses + * + *	Revision 1.66  2002/09/23 15:14:19  rwahl + *	- Reset broadcast timestamp on link down. + *	- Editorial corrections. + * + *	Revision 1.65  2002/07/22 14:29:48  rwahl + *	- Removed BRK statement from debug check. + * + *	Revision 1.64  2001/11/28 19:36:14  rwahl + *	- RLMT Packets sent to an invalid MAC address in CLP/CLPSS mode + *	  (#10650). + *	- Reworked fix for port switching in CLS mode (#10639) + *	 (no dependency to RLMT module). + *	- Enabled dbg output for entry/exit of event functions. + *	- Editorial changes. + * + *	Revision 1.63  2001/10/26 07:53:18  afischer + *	Port switching bug in `check local link` mode + * + *	Revision 1.62  2001/07/03 12:16:30  mkunz + *	New Flag ChgBcPrio (Change priority of last broadcast received) + * + *	Revision 1.61  2001/03/14 12:52:08  rassmann + *	Fixed reporting of active port up/down to PNMI. + * + *	Revision 1.60  2001/02/21 16:02:25  gklug + *	fix: when RLMT starts set Active Port for PNMI + * + *	Revision 1.59  2001/02/16 14:38:19  rassmann + *	Initializing some pointers earlier in the init phase. + *	Rx Mbufs are freed if the net which they belong to is stopped. + * + *	Revision 1.58  2001/02/14 14:06:31  rassmann + *	Editorial changes. + * + *	Revision 1.57  2001/02/05 14:25:26  rassmann + *	Prepared RLMT for transparent operation. + * + *	Revision 1.56  2001/01/30 10:29:09  rassmann + *	Not checking switching befor RlmtStart. + *	Editorial changes. + * + *	Revision 1.55  2001/01/22 13:41:38  rassmann + *	Supporting two nets on dual-port adapters. + * + *	Revision 1.54  2000/11/30 13:25:07  rassmann + *	Setting SK_TICK_INCR to 1 by default. + * + *	Revision 1.53  2000/11/30 10:48:07  cgoos + *	Changed definition of SK_RLMT_BC_DELTA. + * + *	Revision 1.52  2000/11/27 12:50:03  rassmann + *	Checking ports after receiving broadcasts. + * + *	Revision 1.51  2000/11/17 08:58:00  rassmann + *	Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event. + * + *	Revision 1.50  2000/11/09 12:24:34  rassmann + *	Indicating that segmentation check is not running anymore after + *	  SkRlmtCheckSeg(). + *	Restarting segmentation timer after segmentation log. + *	Editorial changes. + * + *	Revision 1.49  1999/11/22 13:38:02  cgoos + *	Changed license header to GPL. + *	Added initialization to some variables to avoid compiler warnings. + * + *	Revision 1.48  1999/10/04 14:01:17  rassmann + *	Corrected reaction to reception of BPDU frames (#10441). + * + *	Revision 1.47  1999/07/20 12:53:36  rassmann + *	Fixed documentation errors for lookahead macros. + * + *	Revision 1.46  1999/05/28 13:29:16  rassmann + *	Replaced C++-style comment. + * + *	Revision 1.45  1999/05/28 13:28:08  rassmann + *	Corrected syntax error (xxx). + * + *	Revision 1.44  1999/05/28 11:15:54  rassmann + *	Changed behaviour to reflect Design Spec v1.2. + *	Controlling Link LED(s). + *	Introduced RLMT Packet Version field in RLMT Packet. + *	Newstyle lookahead macros (checking meta-information before looking at + *	  the packet). + * + *	Revision 1.43  1999/01/28 13:12:43  rassmann + *	Corrected Lookahead (bug introduced in previous Rev.). + * + *	Revision 1.42  1999/01/28 12:50:41  rassmann + *	Not using broadcast time stamps in CheckLinkState mode. + * + *	Revision 1.41  1999/01/27 14:13:02  rassmann + *	Monitoring broadcast traffic. + *	Switching more reliably and not too early if switch is + *	 configured for spanning tree. + * + *	Revision 1.40  1999/01/22 13:17:30  rassmann + *	Informing PNMI of NET_UP. + *	Clearing RLMT multicast addresses before setting them for the first time. + *	Reporting segmentation earlier, setting a "quiet time" + *	 after a report. + * + *	Revision 1.39  1998/12/10 15:29:53  rassmann + *	Corrected SuspectStatus in SkRlmtBuildCheckChain(). + *	Corrected CHECK_SEG mode. + * + *	Revision 1.38  1998/12/08 13:11:23  rassmann + *	Stopping SegTimer at RlmtStop. + * + *	Revision 1.37  1998/12/07 16:51:42  rassmann + *	Corrected comments. + * + *	Revision 1.36  1998/12/04 10:58:56  rassmann + *	Setting next pointer to NULL when receiving. + * + *	Revision 1.35  1998/12/03 16:12:42  rassmann + *	Ignoring/correcting illegal PrefPort values. + * + *	Revision 1.34  1998/12/01 11:45:35  rassmann + *	Code cleanup. + * + *	Revision 1.33  1998/12/01 10:29:32  rassmann + *	Starting standby ports before getting the net up. + *	Checking if a port is started when the link comes up. + * + *	Revision 1.32  1998/11/30 16:19:50  rassmann + *	New default for PortNoRx. + * + *	Revision 1.31  1998/11/27 19:17:13  rassmann + *	Corrected handling of LINK_DOWN coming shortly after LINK_UP. + * + *	Revision 1.30  1998/11/24 12:37:31  rassmann + *	Implemented segmentation check. + * + *	Revision 1.29  1998/11/18 13:04:32  rassmann + *	Secured PortUpTimer event. + *	Waiting longer before starting standby port(s). + * + *	Revision 1.28  1998/11/17 13:43:04  rassmann + *	Handling (logical) tx failure. + *	Sending packet on logical address after PORT_SWITCH. + * + *	Revision 1.27  1998/11/13 17:09:50  rassmann + *	Secured some events against being called in wrong state. + * + *	Revision 1.26  1998/11/13 16:56:54  rassmann + *	Added macro version of SkRlmtLookaheadPacket. + * + *	Revision 1.25  1998/11/06 18:06:04  rassmann + *	Corrected timing when RLMT checks fail. + *	Clearing tx counter earlier in periodical checks. + * + *	Revision 1.24  1998/11/05 10:37:27  rassmann + *	Checking destination address in Lookahead. + * + *	Revision 1.23  1998/11/03 13:53:49  rassmann + *	RLMT should switch now (at least in mode 3). + * + *	Revision 1.22  1998/10/29 14:34:49  rassmann + *	Clearing SK_RLMT struct at startup. + *	Initializing PortsUp during SK_RLMT_START. + * + *	Revision 1.21  1998/10/28 11:30:17  rassmann + *	Default mode is now SK_RLMT_CHECK_LOC_LINK. + * + *	Revision 1.20  1998/10/26 16:02:03  rassmann + *	Ignoring LINK_DOWN for links that are down. + * + *	Revision 1.19  1998/10/22 15:54:01  rassmann + *	Corrected EtherLen. + *	Starting Link Check when second port comes up. + * + *	Revision 1.18  1998/10/22 11:39:50  rassmann + *	Corrected signed/unsigned mismatches. + *	Corrected receive list handling and address recognition. + * + *	Revision 1.17  1998/10/19 17:01:20  rassmann + *	More detailed checking of received packets. + * + *	Revision 1.16  1998/10/15 15:16:34  rassmann + *	Finished Spanning Tree checking. + *	Checked with lint. + * + *	Revision 1.15  1998/09/24 19:16:07  rassmann + *	Code cleanup. + *	Introduced Timer for PORT_DOWN due to no RX. + * + *	Revision 1.14  1998/09/18 20:27:14  rassmann + *	Added address override. + * + *	Revision 1.13  1998/09/16 11:31:48  rassmann + *	Including skdrv1st.h again. :( + * + *	Revision 1.12  1998/09/16 11:09:50  rassmann + *	Syntax corrections. + * + *	Revision 1.11  1998/09/15 12:32:03  rassmann + *	Syntax correction. + * + *	Revision 1.10  1998/09/15 11:28:49  rassmann + *	Syntax corrections. + * + *	Revision 1.9  1998/09/14 17:07:37  rassmann + *	Added code for port checking via LAN. + *	Changed Mbuf definition. + * + *	Revision 1.8  1998/09/07 11:14:14  rassmann + *	Syntax corrections. + * + *	Revision 1.7  1998/09/07 09:06:07  rassmann + *	Syntax corrections. + * + *	Revision 1.6  1998/09/04 19:41:33  rassmann + *	Syntax corrections. + *	Started entering code for checking local links. + * + *	Revision 1.5  1998/09/04 12:14:27  rassmann + *	Interface cleanup. + * + *	Revision 1.4  1998/09/02 16:55:28  rassmann + *	Updated to reflect new DRV/HWAC/RLMT interface. + * + *	Revision 1.3  1998/08/27 14:29:03  rassmann + *	Code cleanup. + * + *	Revision 1.2  1998/08/27 14:26:24  rassmann + *	Updated interface. + * + *	Revision 1.1  1998/08/21 08:26:49  rassmann + *	First public version. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Description: + * + * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters. + * It is mainly intended for adapters with more than one link. + * For such adapters, this module realizes Redundant Link ManagemenT (RLMT). + * + * Include File Hierarchy: + * + *	"skdrv1st.h" + *	"skdrv2nd.h" + * + ******************************************************************************/ + +#include <config.h> + +#ifdef CONFIG_SK98 + +#ifndef	lint +static const char SysKonnectFileId[] = +	"@(#) $Id: skrlmt.c,v 1.68 2003/01/31 15:26:56 rschmidt Exp $ (C) SysKonnect."; +#endif	/* !defined(lint) */ + +#define __SKRLMT_C + +#ifdef __cplusplus +#error C++ is not yet supported. +extern "C" { +#endif	/* cplusplus */ + +#include "h/skdrv1st.h" +#include "h/skdrv2nd.h" + +/* defines ********************************************************************/ + +#ifndef SK_HWAC_LINK_LED +#define SK_HWAC_LINK_LED(a,b,c,d) +#endif	/* !defined(SK_HWAC_LINK_LED) */ + +#ifndef DEBUG +#define RLMT_STATIC	static +#else	/* DEBUG */ +#define RLMT_STATIC + +#ifndef SK_LITTLE_ENDIAN +/* First 32 bits */ +#define OFFS_LO32	1 + +/* Second 32 bits */ +#define OFFS_HI32	0 +#else	/* SK_LITTLE_ENDIAN */ +/* First 32 bits */ +#define OFFS_LO32	0 + +/* Second 32 bits */ +#define OFFS_HI32	1 +#endif	/* SK_LITTLE_ENDIAN */ + +#endif	/* DEBUG */ + +/* ----- Private timeout values ----- */ + +#define SK_RLMT_MIN_TO_VAL			   125000	/* 1/8 sec. */ +#define SK_RLMT_DEF_TO_VAL			  1000000	/* 1 sec. */ +#define SK_RLMT_PORTDOWN_TIM_VAL	   900000	/* another 0.9 sec. */ +#define SK_RLMT_PORTSTART_TIM_VAL	   100000	/* 0.1 sec. */ +#define SK_RLMT_PORTUP_TIM_VAL		  2500000	/* 2.5 sec. */ +#define SK_RLMT_SEG_TO_VAL			900000000	/* 15 min. */ + +/* Assume tick counter increment is 1 - may be set OS-dependent. */ +#ifndef SK_TICK_INCR +#define SK_TICK_INCR	SK_CONSTU64(1) +#endif	/* !defined(SK_TICK_INCR) */ + +/* + * Amount that a time stamp must be later to be recognized as "substantially + * later". This is about 1/128 sec, but above 1 tick counter increment. + */ +#define SK_RLMT_BC_DELTA		(1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \ +									(SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR)) + +/* ----- Private RLMT defaults ----- */ + +#define SK_RLMT_DEF_PREF_PORT	0					/* "Lower" port. */ +#define SK_RLMT_DEF_MODE 		SK_RLMT_CHECK_LINK	/* Default RLMT Mode. */ + +/* ----- Private RLMT checking states ----- */ + +#define SK_RLMT_RCS_SEG			1		/* RLMT Check State: check seg. */ +#define SK_RLMT_RCS_START_SEG	2		/* RLMT Check State: start check seg. */ +#define SK_RLMT_RCS_SEND_SEG	4		/* RLMT Check State: send BPDU packet */ +#define SK_RLMT_RCS_REPORT_SEG	8		/* RLMT Check State: report seg. */ + +/* ----- Private PORT checking states ----- */ + +#define SK_RLMT_PCS_TX			1		/* Port Check State: check tx. */ +#define SK_RLMT_PCS_RX			2		/* Port Check State: check rx. */ + +/* ----- Private PORT events ----- */ + +/* Note: Update simulation when changing these. */ +#define SK_RLMT_PORTSTART_TIM	1100	/* Port start timeout. */ +#define SK_RLMT_PORTUP_TIM		1101	/* Port can now go up. */ +#define SK_RLMT_PORTDOWN_RX_TIM	1102	/* Port did not receive once ... */ +#define SK_RLMT_PORTDOWN		1103	/* Port went down. */ +#define SK_RLMT_PORTDOWN_TX_TIM	1104	/* Partner did not receive ... */ + +/* ----- Private RLMT events ----- */ + +/* Note: Update simulation when changing these. */ +#define SK_RLMT_TIM				2100	/* RLMT timeout. */ +#define SK_RLMT_SEG_TIM			2101	/* RLMT segmentation check timeout. */ + +#define TO_SHORTEN(tim)	((tim) / 2) + +/* Error numbers and messages. */ +#define SKERR_RLMT_E001		(SK_ERRBASE_RLMT + 0) +#define SKERR_RLMT_E001_MSG	"No Packet." +#define SKERR_RLMT_E002		(SKERR_RLMT_E001 + 1) +#define SKERR_RLMT_E002_MSG	"Short Packet." +#define SKERR_RLMT_E003		(SKERR_RLMT_E002 + 1) +#define SKERR_RLMT_E003_MSG	"Unknown RLMT event." +#define SKERR_RLMT_E004		(SKERR_RLMT_E003 + 1) +#define SKERR_RLMT_E004_MSG	"PortsUp incorrect." +#define SKERR_RLMT_E005		(SKERR_RLMT_E004 + 1) +#define SKERR_RLMT_E005_MSG	\ + "Net seems to be segmented (different root bridges are reported on the ports)." +#define SKERR_RLMT_E006		(SKERR_RLMT_E005 + 1) +#define SKERR_RLMT_E006_MSG	"Duplicate MAC Address detected." +#define SKERR_RLMT_E007		(SKERR_RLMT_E006 + 1) +#define SKERR_RLMT_E007_MSG	"LinksUp incorrect." +#define SKERR_RLMT_E008		(SKERR_RLMT_E007 + 1) +#define SKERR_RLMT_E008_MSG	"Port not started but link came up." +#define SKERR_RLMT_E009		(SKERR_RLMT_E008 + 1) +#define SKERR_RLMT_E009_MSG	"Corrected illegal setting of Preferred Port." +#define SKERR_RLMT_E010		(SKERR_RLMT_E009 + 1) +#define SKERR_RLMT_E010_MSG	"Ignored illegal Preferred Port." + +/* LLC field values. */ +#define LLC_COMMAND_RESPONSE_BIT		1 +#define LLC_TEST_COMMAND				0xE3 +#define LLC_UI							0x03 + +/* RLMT Packet fields. */ +#define	SK_RLMT_DSAP					0 +#define	SK_RLMT_SSAP					0 +#define SK_RLMT_CTRL					(LLC_TEST_COMMAND) +#define SK_RLMT_INDICATOR0				0x53	/* S */ +#define SK_RLMT_INDICATOR1				0x4B	/* K */ +#define SK_RLMT_INDICATOR2				0x2D	/* - */ +#define SK_RLMT_INDICATOR3				0x52	/* R */ +#define SK_RLMT_INDICATOR4				0x4C	/* L */ +#define SK_RLMT_INDICATOR5				0x4D	/* M */ +#define SK_RLMT_INDICATOR6				0x54	/* T */ +#define SK_RLMT_PACKET_VERSION			0 + +/* RLMT SPT Flag values. */ +#define	SK_RLMT_SPT_FLAG_CHANGE			0x01 +#define	SK_RLMT_SPT_FLAG_CHANGE_ACK		0x80 + +/* RLMT SPT Packet fields. */ +#define	SK_RLMT_SPT_DSAP				0x42 +#define	SK_RLMT_SPT_SSAP				0x42 +#define SK_RLMT_SPT_CTRL				(LLC_UI) +#define	SK_RLMT_SPT_PROTOCOL_ID0		0x00 +#define	SK_RLMT_SPT_PROTOCOL_ID1		0x00 +#define	SK_RLMT_SPT_PROTOCOL_VERSION_ID	0x00 +#define	SK_RLMT_SPT_BPDU_TYPE			0x00 +#define	SK_RLMT_SPT_FLAGS				0x00	/* ?? */ +#define	SK_RLMT_SPT_ROOT_ID0			0xFF	/* Lowest possible priority. */ +#define	SK_RLMT_SPT_ROOT_ID1			0xFF	/* Lowest possible priority. */ + +/* Remaining 6 bytes will be the current port address. */ +#define	SK_RLMT_SPT_ROOT_PATH_COST0		0x00 +#define	SK_RLMT_SPT_ROOT_PATH_COST1		0x00 +#define	SK_RLMT_SPT_ROOT_PATH_COST2		0x00 +#define	SK_RLMT_SPT_ROOT_PATH_COST3		0x00 +#define	SK_RLMT_SPT_BRIDGE_ID0			0xFF	/* Lowest possible priority. */ +#define	SK_RLMT_SPT_BRIDGE_ID1			0xFF	/* Lowest possible priority. */ + +/* Remaining 6 bytes will be the current port address. */ +#define	SK_RLMT_SPT_PORT_ID0			0xFF	/* Lowest possible priority. */ +#define	SK_RLMT_SPT_PORT_ID1			0xFF	/* Lowest possible priority. */ +#define	SK_RLMT_SPT_MSG_AGE0			0x00 +#define	SK_RLMT_SPT_MSG_AGE1			0x00 +#define	SK_RLMT_SPT_MAX_AGE0			0x00 +#define	SK_RLMT_SPT_MAX_AGE1			0xFF +#define	SK_RLMT_SPT_HELLO_TIME0			0x00 +#define	SK_RLMT_SPT_HELLO_TIME1			0xFF +#define	SK_RLMT_SPT_FWD_DELAY0			0x00 +#define	SK_RLMT_SPT_FWD_DELAY1			0x40 + +/* Size defines. */ +#define SK_RLMT_MIN_PACKET_SIZE			34 +#define SK_RLMT_MAX_PACKET_SIZE			(SK_RLMT_MAX_TX_BUF_SIZE) +#define SK_PACKET_DATA_LEN				(SK_RLMT_MAX_PACKET_SIZE - \ +										SK_RLMT_MIN_PACKET_SIZE) + +/* ----- RLMT packet types ----- */ +#define SK_PACKET_ANNOUNCE				1	/* Port announcement. */ +#define SK_PACKET_ALIVE					2	/* Alive packet to port. */ +#define SK_PACKET_ADDR_CHANGED			3	/* Port address changed. */ +#define SK_PACKET_CHECK_TX				4	/* Check your tx line. */ + +#ifdef SK_LITTLE_ENDIAN +#define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \ +	SK_U8	*_Addr = (SK_U8*)(Addr); \ +	SK_U16	_Val = (SK_U16)(Val); \ +	*_Addr++ = (SK_U8)(_Val >> 8); \ +	*_Addr = (SK_U8)(_Val & 0xFF); \ +} +#endif	/* SK_LITTLE_ENDIAN */ + +#ifdef SK_BIG_ENDIAN +#define SK_U16_TO_NETWORK_ORDER(Val,Addr) (*(SK_U16*)(Addr) = (SK_U16)(Val)) +#endif	/* SK_BIG_ENDIAN */ + +#define AUTONEG_FAILED	SK_FALSE +#define AUTONEG_SUCCESS	SK_TRUE + + +/* typedefs *******************************************************************/ + +/* RLMT packet.  Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */ +typedef struct s_RlmtPacket { +	SK_U8	DstAddr[SK_MAC_ADDR_LEN]; +	SK_U8	SrcAddr[SK_MAC_ADDR_LEN]; +	SK_U8	TypeLen[2]; +	SK_U8	DSap; +	SK_U8	SSap; +	SK_U8	Ctrl; +	SK_U8	Indicator[7]; +	SK_U8	RlmtPacketType[2]; +	SK_U8	Align1[2]; +	SK_U8	Random[4];				/* Random value of requesting(!) station. */ +	SK_U8	RlmtPacketVersion[2];	/* RLMT Packet version. */ +	SK_U8	Data[SK_PACKET_DATA_LEN]; +} SK_RLMT_PACKET; + +typedef struct s_SpTreeRlmtPacket { +	SK_U8	DstAddr[SK_MAC_ADDR_LEN]; +	SK_U8	SrcAddr[SK_MAC_ADDR_LEN]; +	SK_U8	TypeLen[2]; +	SK_U8	DSap; +	SK_U8	SSap; +	SK_U8	Ctrl; +	SK_U8	ProtocolId[2]; +	SK_U8	ProtocolVersionId; +	SK_U8	BpduType; +	SK_U8	Flags; +	SK_U8	RootId[8]; +	SK_U8	RootPathCost[4]; +	SK_U8	BridgeId[8]; +	SK_U8	PortId[2]; +	SK_U8	MessageAge[2]; +	SK_U8	MaxAge[2]; +	SK_U8	HelloTime[2]; +	SK_U8	ForwardDelay[2]; +} SK_SPTREE_PACKET; + +/* global variables ***********************************************************/ + +SK_MAC_ADDR	SkRlmtMcAddr =	{{0x01,  0x00,  0x5A,  0x52,  0x4C,  0x4D}}; +SK_MAC_ADDR	BridgeMcAddr =	{{0x01,  0x80,  0xC2,  0x00,  0x00,  0x00}}; +SK_MAC_ADDR	BcAddr = 		{{0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF}}; + +/* local variables ************************************************************/ + +/* None. */ + +/* functions ******************************************************************/ + +RLMT_STATIC void	SkRlmtCheckSwitch( +	SK_AC	*pAC, +	SK_IOC	IoC, +	SK_U32	NetIdx); +RLMT_STATIC void	SkRlmtCheckSeg( +	SK_AC	*pAC, +	SK_IOC	IoC, +	SK_U32	NetIdx); +RLMT_STATIC void	SkRlmtEvtSetNets( +	SK_AC		*pAC, +	SK_IOC		IoC, +	SK_EVPARA	Para); + +/****************************************************************************** + * + *	SkRlmtInit - initialize data, set state to init + * + * Description: + * + *	SK_INIT_DATA + *	============ + * + *	This routine initializes all RLMT-related variables to a known state. + *	The initial state is SK_RLMT_RS_INIT. + *	All ports are initialized to SK_RLMT_PS_INIT. + * + * + *	SK_INIT_IO + *	========== + * + *	Nothing. + * + * + *	SK_INIT_RUN + *	=========== + * + *	Determine the adapter's random value. + *	Set the hw registers, the "logical MAC address", the + *	RLMT multicast address, and eventually the BPDU multicast address. + * + * Context: + *	init, pageable + * + * Returns: + *	Nothing. + */ +void	SkRlmtInit( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC,	/* I/O Context */ +int		Level)	/* Initialization Level */ +{ +	SK_U32		i, j; +	SK_U64		Random; +	SK_EVPARA	Para; +    SK_MAC_ADDR		VirtualMacAddress; +    SK_MAC_ADDR		PhysicalAMacAddress; +    SK_BOOL		VirtualMacAddressSet; +    SK_BOOL		PhysicalAMacAddressSet; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT, +		("RLMT Init level %d.\n", Level)) + +	switch (Level) { +	case SK_INIT_DATA:	/* Initialize data structures. */ +		SK_MEMSET((char *)&pAC->Rlmt, 0, sizeof(SK_RLMT)); + +		for (i = 0; i < SK_MAX_MACS; i++) { +			pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT; +			pAC->Rlmt.Port[i].LinkDown = SK_TRUE; +			pAC->Rlmt.Port[i].PortDown = SK_TRUE; +			pAC->Rlmt.Port[i].PortStarted = SK_FALSE; +			pAC->Rlmt.Port[i].PortNoRx = SK_FALSE; +			pAC->Rlmt.Port[i].RootIdSet = SK_FALSE; +			pAC->Rlmt.Port[i].PortNumber = i; +			pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0]; +			pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i]; +		} + +		pAC->Rlmt.NumNets = 1; +		for (i = 0; i < SK_MAX_NETS; i++) { +			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; +			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; +			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; +			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* Automatic. */ +			/* Just assuming. */ +			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; +			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; +			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; +			pAC->Rlmt.Net[i].NetNumber = i; +		} + +		pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0]; +		pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1]; +#if SK_MAX_NETS > 1 +		pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1]; +#endif	/* SK_MAX_NETS > 1 */ +		break; + +	case SK_INIT_IO:	/* GIMacsFound first available here. */ +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT, +			("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound)) + +		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound; + +		/* Initialize HW registers? */ +		if (pAC->GIni.GIMacsFound == 1) { +			Para.Para32[0] = SK_RLMT_MODE_CLS; +			Para.Para32[1] = 0; +			(void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para); +		} +		break; + +	case SK_INIT_RUN: +		/* Ensure RLMT is set to one net. */ +		if (pAC->Rlmt.NumNets > 1) { +			Para.Para32[0] = 1; +			Para.Para32[1] = -1; +			SkRlmtEvtSetNets(pAC, IoC, Para); +		} + +		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { +			Random = SkOsGetTime(pAC); +			*(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random; + +			for (j = 0; j < 4; j++) { +				pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort-> +					CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j]; +			} + +			(void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY); + +			/* Add RLMT MC address. */ +			(void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT); + +			if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) { +				/* Add BPDU MC address. */ +				(void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT); +			} + +			(void)SkAddrMcUpdate(pAC, IoC, i); +		} + +	VirtualMacAddressSet = SK_FALSE; +		/* Read virtual MAC address from Control Register File. */ +		for (j = 0; j < SK_MAC_ADDR_LEN; j++) { + +	    SK_IN8(IoC, B2_MAC_1 + j, &VirtualMacAddress.a[j]); +	    VirtualMacAddressSet |= VirtualMacAddress.a[j]; +		} + +	PhysicalAMacAddressSet = SK_FALSE; +		/* Read physical MAC address for MAC A from Control Register File. */ +		for (j = 0; j < SK_MAC_ADDR_LEN; j++) { + +	    SK_IN8(IoC, B2_MAC_2 + j, &PhysicalAMacAddress.a[j]); +	    PhysicalAMacAddressSet |= PhysicalAMacAddress.a[j]; +		} + +	/* check if the two mac addresses contain reasonable values */ +	if (!VirtualMacAddressSet || !PhysicalAMacAddressSet) { + +	    pAC->Rlmt.RlmtOff = SK_TRUE; +	} + +	/* if the two mac addresses are equal switch off the RLMT_PRE_LOOKAHEAD +	   and the RLMT_LOOKAHEAD macros */ +	else if (SK_ADDR_EQUAL(PhysicalAMacAddress.a, VirtualMacAddress.a)) { + +	    pAC->Rlmt.RlmtOff = SK_TRUE; +	} +		else { +			pAC->Rlmt.RlmtOff = SK_FALSE; +		} +		break; + +	default:	/* error */ +		break; +	} +	return; +}	/* SkRlmtInit */ + + +/****************************************************************************** + * + *	SkRlmtBuildCheckChain - build the check chain + * + * Description: + *	This routine builds the local check chain: + *	- Each port that is up checks the next port. + *	- The last port that is up checks the first port that is up. + * + * Notes: + *	- Currently only local ports are considered when building the chain. + *	- Currently the SuspectState is just reset; + *	  it would be better to save it ... + * + * Context: + *	runtime, pageable? + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtBuildCheckChain( +SK_AC	*pAC,	/* Adapter Context */ +SK_U32	NetIdx)	/* Net Number */ +{ +	SK_U32			i; +	SK_U32			NumMacsUp; +	SK_RLMT_PORT *	FirstMacUp; +	SK_RLMT_PORT *	PrevMacUp; + +	FirstMacUp	= NULL; +	PrevMacUp	= NULL; + +	if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { +		for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) { +			pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0; +		} +		return;	/* Done. */ +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SkRlmtBuildCheckChain.\n")) + +	NumMacsUp = 0; + +	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { +		pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0; +		pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0; +		pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &= +			~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX); + +		/* +		 * If more than two links are detected we should consider +		 * checking at least two other ports: +		 * 1. the next port that is not LinkDown and +		 * 2. the next port that is not PortDown. +		 */ +		if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) { +			if (NumMacsUp == 0) { +				FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i]; +			} +			else { +				PrevMacUp->PortCheck[ +					pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr = +					pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress; +				PrevMacUp->PortCheck[ +					PrevMacUp->PortsChecked].SuspectTx = SK_FALSE; +				PrevMacUp->PortsChecked++; +			} +			PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i]; +			NumMacsUp++; +		} +	} + +	if (NumMacsUp > 1) { +		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr = +			FirstMacUp->AddrPort->CurrentMacAddress; +		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx = +			SK_FALSE; +		PrevMacUp->PortsChecked++; +	} + +#ifdef DEBUG +	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Port %d checks %d other ports: %2X.\n", i, +				pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked, +				pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5])) +	} +#endif	/* DEBUG */ + +	return; +}	/* SkRlmtBuildCheckChain */ + + +/****************************************************************************** + * + *	SkRlmtBuildPacket - build an RLMT packet + * + * Description: + *	This routine sets up an RLMT packet. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	NULL or pointer to RLMT mbuf + */ +RLMT_STATIC SK_MBUF	*SkRlmtBuildPacket( +SK_AC		*pAC,		/* Adapter Context */ +SK_IOC		IoC,		/* I/O Context */ +SK_U32		PortNumber,	/* Sending port */ +SK_U16		PacketType,	/* RLMT packet type */ +SK_MAC_ADDR	*SrcAddr,	/* Source address */ +SK_MAC_ADDR	*DestAddr)	/* Destination address */ +{ +	int		i; +	SK_U16		Length; +	SK_MBUF		*pMb; +	SK_RLMT_PACKET	*pPacket; + +#ifdef DEBUG +	SK_U8	CheckSrc  = 0; +	SK_U8	CheckDest = 0; + +	for (i = 0; i < SK_MAC_ADDR_LEN; ++i) { +		CheckSrc  |= SrcAddr->a[i]; +		CheckDest |= DestAddr->a[i]; +	} + +	if ((CheckSrc == 0) || (CheckDest == 0)) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_ERR, +			("SkRlmtBuildPacket: Invalid %s%saddr.\n", +			 (CheckSrc == 0 ? "Src" : ""), (CheckDest == 0 ? "Dest" : ""))) +	} +#endif + +	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) { +		pPacket = (SK_RLMT_PACKET*)pMb->pData; +		for (i = 0; i < SK_MAC_ADDR_LEN; i++) { +			pPacket->DstAddr[i] = DestAddr->a[i]; +			pPacket->SrcAddr[i] = SrcAddr->a[i]; +		} +		pPacket->DSap = SK_RLMT_DSAP; +		pPacket->SSap = SK_RLMT_SSAP; +		pPacket->Ctrl = SK_RLMT_CTRL; +		pPacket->Indicator[0] = SK_RLMT_INDICATOR0; +		pPacket->Indicator[1] = SK_RLMT_INDICATOR1; +		pPacket->Indicator[2] = SK_RLMT_INDICATOR2; +		pPacket->Indicator[3] = SK_RLMT_INDICATOR3; +		pPacket->Indicator[4] = SK_RLMT_INDICATOR4; +		pPacket->Indicator[5] = SK_RLMT_INDICATOR5; +		pPacket->Indicator[6] = SK_RLMT_INDICATOR6; + +		SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]); + +		for (i = 0; i < 4; i++) { +			pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i]; +		} + +		SK_U16_TO_NETWORK_ORDER( +			SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]); + +		for (i = 0; i < SK_PACKET_DATA_LEN; i++) { +			pPacket->Data[i] = 0x00; +		} + +		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */ +		pMb->Length = Length; +		pMb->PortIdx = PortNumber; +		Length -= 14; +		SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]); + +		if (PacketType == SK_PACKET_ALIVE) { +			pAC->Rlmt.Port[PortNumber].TxHelloCts++; +		} +	} + +	return (pMb); +}	/* SkRlmtBuildPacket */ + + +/****************************************************************************** + * + *	SkRlmtBuildSpanningTreePacket - build spanning tree check packet + * + * Description: + *	This routine sets up a BPDU packet for spanning tree check. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	NULL or pointer to RLMT mbuf + */ +RLMT_STATIC SK_MBUF	*SkRlmtBuildSpanningTreePacket( +SK_AC	*pAC,		/* Adapter Context */ +SK_IOC	IoC,		/* I/O Context */ +SK_U32	PortNumber)	/* Sending port */ +{ +	unsigned			i; +	SK_U16				Length; +	SK_MBUF				*pMb; +	SK_SPTREE_PACKET	*pSPacket; + +	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != +		NULL) { +		pSPacket = (SK_SPTREE_PACKET*)pMb->pData; +		for (i = 0; i < SK_MAC_ADDR_LEN; i++) { +			pSPacket->DstAddr[i] = BridgeMcAddr.a[i]; +			pSPacket->SrcAddr[i] = +				pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i]; +		} +		pSPacket->DSap = SK_RLMT_SPT_DSAP; +		pSPacket->SSap = SK_RLMT_SPT_SSAP; +		pSPacket->Ctrl = SK_RLMT_SPT_CTRL; + +		pSPacket->ProtocolId[0] = SK_RLMT_SPT_PROTOCOL_ID0; +		pSPacket->ProtocolId[1] = SK_RLMT_SPT_PROTOCOL_ID1; +		pSPacket->ProtocolVersionId = SK_RLMT_SPT_PROTOCOL_VERSION_ID; +		pSPacket->BpduType = SK_RLMT_SPT_BPDU_TYPE; +		pSPacket->Flags = SK_RLMT_SPT_FLAGS; +		pSPacket->RootId[0] = SK_RLMT_SPT_ROOT_ID0; +		pSPacket->RootId[1] = SK_RLMT_SPT_ROOT_ID1; +		pSPacket->RootPathCost[0] = SK_RLMT_SPT_ROOT_PATH_COST0; +		pSPacket->RootPathCost[1] = SK_RLMT_SPT_ROOT_PATH_COST1; +		pSPacket->RootPathCost[2] = SK_RLMT_SPT_ROOT_PATH_COST2; +		pSPacket->RootPathCost[3] = SK_RLMT_SPT_ROOT_PATH_COST3; +		pSPacket->BridgeId[0] = SK_RLMT_SPT_BRIDGE_ID0; +		pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1; + +		/* +		 * Use logical MAC address as bridge ID and filter these packets +		 * on receive. +		 */ +		for (i = 0; i < SK_MAC_ADDR_LEN; i++) { +			pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] = +				pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber]. +					CurrentMacAddress.a[i]; +		} +		pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0; +		pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1; +		pSPacket->MessageAge[0] = SK_RLMT_SPT_MSG_AGE0; +		pSPacket->MessageAge[1] = SK_RLMT_SPT_MSG_AGE1; +		pSPacket->MaxAge[0] = SK_RLMT_SPT_MAX_AGE0; +		pSPacket->MaxAge[1] = SK_RLMT_SPT_MAX_AGE1; +		pSPacket->HelloTime[0] = SK_RLMT_SPT_HELLO_TIME0; +		pSPacket->HelloTime[1] = SK_RLMT_SPT_HELLO_TIME1; +		pSPacket->ForwardDelay[0] = SK_RLMT_SPT_FWD_DELAY0; +		pSPacket->ForwardDelay[1] = SK_RLMT_SPT_FWD_DELAY1; + +		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */ +		pMb->Length = Length; +		pMb->PortIdx = PortNumber; +		Length -= 14; +		SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]); + +		pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++; +	} + +	return (pMb); +}	/* SkRlmtBuildSpanningTreePacket */ + + +/****************************************************************************** + * + *	SkRlmtSend - build and send check packets + * + * Description: + *	Depending on the RLMT state and the checking state, several packets + *	are sent through the indicated port. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	Nothing. + */ +RLMT_STATIC void	SkRlmtSend( +SK_AC	*pAC,		/* Adapter Context */ +SK_IOC	IoC,		/* I/O Context */ +SK_U32	PortNumber)	/* Sending port */ +{ +	unsigned	j; +	SK_EVPARA	Para; +	SK_RLMT_PORT	*pRPort; + +	pRPort = &pAC->Rlmt.Port[PortNumber]; +	if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) { +		if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) { +			/* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */ +			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, +				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, +				&SkRlmtMcAddr)) != NULL) { +				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); +			} +		} +		else { +			/* +			 * Send a directed RLMT packet to all ports that are +			 * checked by the indicated port. +			 */ +			for (j = 0; j < pRPort->PortsChecked; j++) { +				if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, +					SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, +					&pRPort->PortCheck[j].CheckAddr)) != NULL) { +					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); +				} +			} +		} +	} + +	if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) && +		(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) { +		/* +		 * Send a BPDU packet to make a connected switch tell us +		 * the correct root bridge. +		 */ +		if ((Para.pParaPtr = +			SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) { +			pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG; +			pRPort->RootIdSet = SK_FALSE; + +			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX, +				("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber)) +		} +	} +	return; +}	/* SkRlmtSend */ + + +/****************************************************************************** + * + *	SkRlmtPortReceives - check if port is (going) down and bring it up + * + * Description: + *	This routine checks if a port who received a non-BPDU packet + *	needs to go up or needs to be stopped going down. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	Nothing. + */ +RLMT_STATIC void	SkRlmtPortReceives( +SK_AC	*pAC,			/* Adapter Context */ +SK_IOC	IoC,			/* I/O Context */ +SK_U32	PortNumber)		/* Port to check */ +{ +	SK_RLMT_PORT	*pRPort; +	SK_EVPARA		Para; + +	pRPort = &pAC->Rlmt.Port[PortNumber]; +	pRPort->PortNoRx = SK_FALSE; + +	if ((pRPort->PortState == SK_RLMT_PS_DOWN) && +		!(pRPort->CheckingState & SK_RLMT_PCS_TX)) { +		/* +		 * Port is marked down (rx), but received a non-BPDU packet. +		 * Bring it up. +		 */ +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +			("SkRlmtPacketReceive: Received on PortDown.\n")) + +		pRPort->PortState = SK_RLMT_PS_GOING_UP; +		pRPort->GuTimeStamp = SkOsGetTime(pAC); +		Para.Para32[0] = PortNumber; +		Para.Para32[1] = (SK_U32)-1; +		SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL, +			SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para); +		pRPort->CheckingState &= ~SK_RLMT_PCS_RX; +		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */ +		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); +	}	/* PortDown && !SuspectTx */ +	else if (pRPort->CheckingState & SK_RLMT_PCS_RX) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +			("SkRlmtPacketReceive: Stop bringing port down.\n")) +		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); +		pRPort->CheckingState &= ~SK_RLMT_PCS_RX; +		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */ +		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); +	}	/* PortGoingDown */ + +	return; +}	/* SkRlmtPortReceives */ + + +/****************************************************************************** + * + *	SkRlmtPacketReceive - receive a packet for closer examination + * + * Description: + *	This routine examines a packet more closely than SK_RLMT_LOOKAHEAD. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	Nothing. + */ +RLMT_STATIC void	SkRlmtPacketReceive( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC,	/* I/O Context */ +SK_MBUF	*pMb)	/* Received packet */ +{ +#ifdef xDEBUG +	extern	void DumpData(char *p, int size); +#endif	/* DEBUG */ +	int					i; +	unsigned			j; +	SK_U16				PacketType; +	SK_U32				PortNumber; +	SK_ADDR_PORT		*pAPort; +	SK_RLMT_PORT		*pRPort; +	SK_RLMT_PACKET		*pRPacket; +	SK_SPTREE_PACKET	*pSPacket; +	SK_EVPARA			Para; + +	PortNumber	= pMb->PortIdx; +	pAPort = &pAC->Addr.Port[PortNumber]; +	pRPort = &pAC->Rlmt.Port[PortNumber]; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +		("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber)) + +	pRPacket = (SK_RLMT_PACKET*)pMb->pData; +	pSPacket = (SK_SPTREE_PACKET*)pRPacket; + +#ifdef xDEBUG +	DumpData((char *)pRPacket, 32); +#endif	/* DEBUG */ + +	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) { +		SkRlmtPortReceives(pAC, IoC, PortNumber); +	} + +	/* Check destination address. */ + +	if (!SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->DstAddr) && +		!SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) && +		!SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) { + +		/* Not sent to current MAC or registered MC address => Trash it. */ +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +			("SkRlmtPacketReceive: Not for me.\n")) + +		SkDrvFreeRlmtMbuf(pAC, IoC, pMb); +		return; +	} +	else if (SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->SrcAddr)) { + +		/* +		 * Was sent by same port (may happen during port switching +		 * or in case of duplicate MAC addresses). +		 */ + +		/* +		 * Check for duplicate address here: +		 * If Packet.Random != My.Random => DupAddr. +		 */ +		for (i = 3; i >= 0; i--) { +			if (pRPort->Random[i] != pRPacket->Random[i]) { +				break; +			} +		} + +		/* +		 * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply +		 * packets (they have the LLC_COMMAND_RESPONSE_BIT set in +		 * pRPacket->SSap). +		 */ +		if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP && +			pRPacket->Ctrl == SK_RLMT_CTRL && +			pRPacket->SSap == SK_RLMT_SSAP && +			pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 && +			pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 && +			pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 && +			pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 && +			pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 && +			pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 && +			pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) { +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +				("SkRlmtPacketReceive: Duplicate MAC Address.\n")) + +			/* Error Log entry. */ +			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG); +		} +		else { +			/* Simply trash it. */ +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +				("SkRlmtPacketReceive: Sent by me.\n")) +		} + +		SkDrvFreeRlmtMbuf(pAC, IoC, pMb); +		return; +	} + +	/* Check SuspectTx entries. */ +	if (pRPort->PortsSuspect > 0) { +		for (j = 0; j < pRPort->PortsChecked; j++) { +			if (pRPort->PortCheck[j].SuspectTx && +				SK_ADDR_EQUAL( +					pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) { +				pRPort->PortCheck[j].SuspectTx = SK_FALSE; +				pRPort->PortsSuspect--; +				break; +			} +		} +	} + +	/* Determine type of packet. */ +	if (pRPacket->DSap == SK_RLMT_DSAP && +		pRPacket->Ctrl == SK_RLMT_CTRL && +		(pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP && +		pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 && +		pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 && +		pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 && +		pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 && +		pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 && +		pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 && +		pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) { + +		/* It's an RLMT packet. */ +		PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) | +			pRPacket->RlmtPacketType[1]); + +		switch (PacketType) { +		case SK_PACKET_ANNOUNCE:	/* Not yet used. */ +#if 0 +			/* Build the check chain. */ +			SkRlmtBuildCheckChain(pAC); +#endif	/* 0 */ + +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +				("SkRlmtPacketReceive: Announce.\n")) + +			SkDrvFreeRlmtMbuf(pAC, IoC, pMb); +			break; + +		case SK_PACKET_ALIVE: +			if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) { +				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +					("SkRlmtPacketReceive: Alive Reply.\n")) + +				if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) || +					SK_ADDR_EQUAL( +						pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) { +					/* Obviously we could send something. */ +					if (pRPort->CheckingState & SK_RLMT_PCS_TX) { +						pRPort->CheckingState &=  ~SK_RLMT_PCS_TX; +						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); +					} + +					if ((pRPort->PortState == SK_RLMT_PS_DOWN) && +						!(pRPort->CheckingState & SK_RLMT_PCS_RX)) { +						pRPort->PortState = SK_RLMT_PS_GOING_UP; +						pRPort->GuTimeStamp = SkOsGetTime(pAC); + +						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + +						Para.Para32[0] = PortNumber; +						Para.Para32[1] = (SK_U32)-1; +						SkTimerStart(pAC, IoC, &pRPort->UpTimer, +							SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT, +							SK_RLMT_PORTUP_TIM, Para); +					} +				} + +				/* Mark sending port as alive? */ +				SkDrvFreeRlmtMbuf(pAC, IoC, pMb); +			} +			else {	/* Alive Request Packet. */ +				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +					("SkRlmtPacketReceive: Alive Request.\n")) + +				pRPort->RxHelloCts++; + +				/* Answer. */ +				for (i = 0; i < SK_MAC_ADDR_LEN; i++) { +					pRPacket->DstAddr[i] = pRPacket->SrcAddr[i]; +					pRPacket->SrcAddr[i] = +						pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i]; +				} +				pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT; + +				Para.pParaPtr = pMb; +				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); +			} +			break; + +		case SK_PACKET_CHECK_TX: +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +				("SkRlmtPacketReceive: Check your tx line.\n")) + +			/* A port checking us requests us to check our tx line. */ +			pRPort->CheckingState |= SK_RLMT_PCS_TX; + +			/* Start PortDownTx timer. */ +			Para.Para32[0] = PortNumber; +			Para.Para32[1] = (SK_U32)-1; +			SkTimerStart(pAC, IoC, &pRPort->DownTxTimer, +				SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT, +				SK_RLMT_PORTDOWN_TX_TIM, Para); + +			SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + +			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, +				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, +				&SkRlmtMcAddr)) != NULL) { +				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); +			} +			break; + +		case SK_PACKET_ADDR_CHANGED: +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +				("SkRlmtPacketReceive: Address Change.\n")) + +			/* Build the check chain. */ +			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); +			SkDrvFreeRlmtMbuf(pAC, IoC, pMb); +			break; + +		default: +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +				("SkRlmtPacketReceive: Unknown RLMT packet.\n")) + +			/* RA;:;: ??? */ +			SkDrvFreeRlmtMbuf(pAC, IoC, pMb); +		} +	} +	else if (pSPacket->DSap == SK_RLMT_SPT_DSAP && +		pSPacket->Ctrl == SK_RLMT_SPT_CTRL && +		(pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +			("SkRlmtPacketReceive: BPDU Packet.\n")) + +		/* Spanning Tree packet. */ +		pRPort->RxSpHelloCts++; + +		if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt. +			Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) { +			/* +			 * Check segmentation if a new root bridge is set and +			 * the segmentation check is not currently running. +			 */ +			if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) && +				(pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) && +				(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) +				!= 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState & +				SK_RLMT_RCS_SEG) == 0) { +				pAC->Rlmt.Port[PortNumber].Net->CheckingState |= +					SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG; +			} + +			/* Store tree view of this port. */ +			for (i = 0; i < 8; i++) { +				pRPort->Root.Id[i] = pSPacket->RootId[i]; +			} +			pRPort->RootIdSet = SK_TRUE; + +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP, +				("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", +					PortNumber, +					pRPort->Root.Id[0], pRPort->Root.Id[1], +					pRPort->Root.Id[2], pRPort->Root.Id[3], +					pRPort->Root.Id[4], pRPort->Root.Id[5], +					pRPort->Root.Id[6], pRPort->Root.Id[7])) +		} + +		SkDrvFreeRlmtMbuf(pAC, IoC, pMb); +		if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState & +			SK_RLMT_RCS_REPORT_SEG) != 0) { +			SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber); +		} +	} +	else { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, +			("SkRlmtPacketReceive: Unknown Packet Type.\n")) + +		/* Unknown packet. */ +		SkDrvFreeRlmtMbuf(pAC, IoC, pMb); +	} +	return; +}	/* SkRlmtPacketReceive */ + + +/****************************************************************************** + * + *	SkRlmtCheckPort - check if a port works + * + * Description: + *	This routine checks if a port whose link is up received something + *	and if it seems to transmit successfully. + * + *	# PortState: PsInit, PsLinkDown, PsDown, PsGoingUp, PsUp + *	# PortCheckingState (Bitfield): ChkTx, ChkRx, ChkSeg + *	# RlmtCheckingState (Bitfield): ChkSeg, StartChkSeg, ReportSeg + * + *	if (Rx - RxBpdu == 0) {	# No rx. + *		if (state == PsUp) { + *			PortCheckingState |= ChkRx + *		} + *		if (ModeCheckSeg && (Timeout == + *			TO_SHORTEN(RLMT_DEFAULT_TIMEOUT))) { + *			RlmtCheckingState |= ChkSeg) + *			PortCheckingState |= ChkSeg + *		} + *		NewTimeout = TO_SHORTEN(Timeout) + *		if (NewTimeout < RLMT_MIN_TIMEOUT) { + *			NewTimeout = RLMT_MIN_TIMEOUT + *			PortState = PsDown + *			... + *		} + *	} + *	else {	# something was received + *		# Set counter to 0 at LinkDown? + *		#   No - rx may be reported after LinkDown ??? + *		PortCheckingState &= ~ChkRx + *		NewTimeout = RLMT_DEFAULT_TIMEOUT + *		if (RxAck == 0) { + *			possible reasons: + *			is my tx line bad? -- + *				send RLMT multicast and report + *				back internally? (only possible + *				between ports on same adapter) + *		} + *		if (RxChk == 0) { + *			possible reasons: + *			- tx line of port set to check me + *			  maybe bad + *			- no other port/adapter available or set + *			  to check me + *			- adapter checking me has a longer + *			  timeout + *			??? anything that can be done here? + *		} + *	} + * + * Context: + *	runtime, pageable? + * + * Returns: + *	New timeout value. + */ +RLMT_STATIC SK_U32	SkRlmtCheckPort( +SK_AC	*pAC,		/* Adapter Context */ +SK_IOC	IoC,		/* I/O Context */ +SK_U32	PortNumber)	/* Port to check */ +{ +	unsigned		i; +	SK_U32			NewTimeout; +	SK_RLMT_PORT	*pRPort; +	SK_EVPARA		Para; + +	pRPort = &pAC->Rlmt.Port[PortNumber]; + +	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n", +				PortNumber, pRPort->PacketsPerTimeSlot)) + +		/* +		 * Check segmentation if there was no receive at least twice +		 * in a row (PortNoRx is already set) and the segmentation +		 * check is not currently running. +		 */ + +		if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) && +			(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) && +			!(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) { +			pAC->Rlmt.Port[PortNumber].Net->CheckingState |= +				SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG; +		} + +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n", +				pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX)) + +		if (pRPort->PortState != SK_RLMT_PS_DOWN) { +			NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue); +			if (NewTimeout < SK_RLMT_MIN_TO_VAL) { +				NewTimeout = SK_RLMT_MIN_TO_VAL; +			} + +			if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) { +				Para.Para32[0] = PortNumber; +				pRPort->CheckingState |= SK_RLMT_PCS_RX; + +				/* +				 * What shall we do if the port checked by this one receives +				 * our request frames?  What's bad - our rx line or his tx line? +				 */ +				Para.Para32[1] = (SK_U32)-1; +				SkTimerStart(pAC, IoC, &pRPort->DownRxTimer, +					SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT, +					SK_RLMT_PORTDOWN_RX_TIM, Para); + +				for (i = 0; i < pRPort->PortsChecked; i++) { +					if (pRPort->PortCheck[i].SuspectTx) { +						continue; +					} +					pRPort->PortCheck[i].SuspectTx = SK_TRUE; +					pRPort->PortsSuspect++; +					if ((Para.pParaPtr = +						SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX, +							&pAC->Addr.Port[PortNumber].CurrentMacAddress, +							&pRPort->PortCheck[i].CheckAddr)) != NULL) { +						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); +					} +				} +			} +		} +		else {	/* PortDown -- or all partners suspect. */ +			NewTimeout = SK_RLMT_DEF_TO_VAL; +		} +		pRPort->PortNoRx = SK_TRUE; +	} +	else {	/* A non-BPDU packet was received. */ +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n", +				PortNumber, +				pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot, +				pRPort->PacketsPerTimeSlot)) + +		SkRlmtPortReceives(pAC, IoC, PortNumber); +		if (pAC->Rlmt.CheckSwitch) { +			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); +		} + +		NewTimeout = SK_RLMT_DEF_TO_VAL; +	} + +	return (NewTimeout); +}	/* SkRlmtCheckPort */ + + +/****************************************************************************** + * + *	SkRlmtSelectBcRx - select new active port, criteria 1 (CLP) + * + * Description: + *	This routine selects the port that received a broadcast frame + *	substantially later than all other ports. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	SK_BOOL + */ +RLMT_STATIC SK_BOOL	SkRlmtSelectBcRx( +SK_AC	*pAC,		/* Adapter Context */ +SK_IOC	IoC,		/* I/O Context */ +SK_U32	Active,		/* Active port */ +SK_U32	PrefPort,	/* Preferred port */ +SK_U32	*pSelect)	/* New active port */ +{ +	SK_U64		BcTimeStamp; +	SK_U32		i; +	SK_BOOL		PortFound; + +	BcTimeStamp = 0;	/* Not totally necessary, but feeling better. */ +	PortFound = SK_FALSE; + +	/* Select port with the latest TimeStamp. */ +	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("TimeStamp Port %d (Down: %d, NoRx: %d): %08x %08x.\n", +				i, +				pAC->Rlmt.Port[i].PortDown, pAC->Rlmt.Port[i].PortNoRx, +				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32), +				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32))) + +		if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) { +			if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) { +				BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp; +				*pSelect = i; +				PortFound = SK_TRUE; +			} +		} +	} + +	if (PortFound) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Port %d received the last broadcast.\n", *pSelect)) + +		/* Look if another port's time stamp is similar. */ +		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { +			if (i == *pSelect) { +				continue; +			} +			if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx && +				(pAC->Rlmt.Port[i].BcTimeStamp > +				 BcTimeStamp - SK_RLMT_BC_DELTA || +				pAC->Rlmt.Port[i].BcTimeStamp + +				 SK_RLMT_BC_DELTA > BcTimeStamp)) { +				PortFound = SK_FALSE; + +				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +					("Port %d received a broadcast at a similar time.\n", i)) +				break; +			} +		} +	} + +#ifdef DEBUG +	if (PortFound) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_SELECT_BCRX found Port %d receiving the substantially " +			 "latest broadcast (%u).\n", +				*pSelect, +				BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp)) +	} +#endif	/* DEBUG */ + +	return (PortFound); +}	/* SkRlmtSelectBcRx */ + + +/****************************************************************************** + * + *	SkRlmtSelectNotSuspect - select new active port, criteria 2 (CLP) + * + * Description: + *	This routine selects a good port (it is PortUp && !SuspectRx). + * + * Context: + *	runtime, pageable? + * + * Returns: + *	SK_BOOL + */ +RLMT_STATIC SK_BOOL	SkRlmtSelectNotSuspect( +SK_AC	*pAC,		/* Adapter Context */ +SK_IOC	IoC,		/* I/O Context */ +SK_U32	Active,		/* Active port */ +SK_U32	PrefPort,	/* Preferred port */ +SK_U32	*pSelect)	/* New active port */ +{ +	SK_U32		i; +	SK_BOOL		PortFound; + +	PortFound = SK_FALSE; + +	/* Select first port that is PortUp && !SuspectRx. */ +	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { +		if (!pAC->Rlmt.Port[i].PortDown && +			!(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) { +			*pSelect = i; +			if (!pAC->Rlmt.Port[Active].PortDown && +				!(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) { +				*pSelect = Active; +			} +			if (!pAC->Rlmt.Port[PrefPort].PortDown && +				!(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) { +				*pSelect = PrefPort; +			} +			PortFound = SK_TRUE; +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +				("SK_RLMT_SELECT_NOTSUSPECT found Port %d up and not check RX.\n", +					*pSelect)) +			break; +		} +	} +	return (PortFound); +}	/* SkRlmtSelectNotSuspect */ + + +/****************************************************************************** + * + *	SkRlmtSelectUp - select new active port, criteria 3, 4 (CLP) + * + * Description: + *	This routine selects a port that is up. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	SK_BOOL + */ +RLMT_STATIC SK_BOOL	SkRlmtSelectUp( +SK_AC	*pAC,			/* Adapter Context */ +SK_IOC	IoC,			/* I/O Context */ +SK_U32	Active,			/* Active port */ +SK_U32	PrefPort,		/* Preferred port */ +SK_U32	*pSelect,		/* New active port */ +SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */ +{ +	SK_U32		i; +	SK_BOOL		PortFound; + +	PortFound = SK_FALSE; + +	/* Select first port that is PortUp. */ +	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { +		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP && +			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { +			*pSelect = i; +			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP && +				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) { +				*pSelect = Active; +			} +			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP && +				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) { +				*pSelect = PrefPort; +			} +			PortFound = SK_TRUE; +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +				("SK_RLMT_SELECT_UP found Port %d up.\n", *pSelect)) +			break; +		} +	} +	return (PortFound); +}	/* SkRlmtSelectUp */ + + +/****************************************************************************** + * + *	SkRlmtSelectGoingUp - select new active port, criteria 5, 6 (CLP) + * + * Description: + *	This routine selects the port that is going up for the longest time. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	SK_BOOL + */ +RLMT_STATIC SK_BOOL	SkRlmtSelectGoingUp( +SK_AC	*pAC,			/* Adapter Context */ +SK_IOC	IoC,			/* I/O Context */ +SK_U32	Active,			/* Active port */ +SK_U32	PrefPort,		/* Preferred port */ +SK_U32	*pSelect,		/* New active port */ +SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */ +{ +	SK_U64		GuTimeStamp; +	SK_U32		i; +	SK_BOOL		PortFound; + +	GuTimeStamp = 0; +	PortFound = SK_FALSE; + +	/* Select port that is PortGoingUp for the longest time. */ +	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { +		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP && +			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { +			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; +			*pSelect = i; +			PortFound = SK_TRUE; +			break; +		} +	} + +	if (!PortFound) { +		return (SK_FALSE); +	} + +	for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { +		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP && +			pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp && +			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { +			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; +			*pSelect = i; +		} +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_SELECT_GOINGUP found Port %d going up.\n", *pSelect)) +	return (SK_TRUE); +}	/* SkRlmtSelectGoingUp */ + + +/****************************************************************************** + * + *	SkRlmtSelectDown - select new active port, criteria 7, 8 (CLP) + * + * Description: + *	This routine selects a port that is down. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	SK_BOOL + */ +RLMT_STATIC SK_BOOL	SkRlmtSelectDown( +SK_AC	*pAC,			/* Adapter Context */ +SK_IOC	IoC,			/* I/O Context */ +SK_U32	Active,			/* Active port */ +SK_U32	PrefPort,		/* Preferred port */ +SK_U32	*pSelect,		/* New active port */ +SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */ +{ +	SK_U32		i; +	SK_BOOL		PortFound; + +	PortFound = SK_FALSE; + +	/* Select first port that is PortDown. */ +	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { +		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN && +			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { +			*pSelect = i; +			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN && +				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) { +				*pSelect = Active; +			} +			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN && +				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) { +				*pSelect = PrefPort; +			} +			PortFound = SK_TRUE; +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +				("SK_RLMT_SELECT_DOWN found Port %d down.\n", *pSelect)) +			break; +		} +	} +	return (PortFound); +}	/* SkRlmtSelectDown */ + + +/****************************************************************************** + * + *	SkRlmtCheckSwitch - select new active port and switch to it + * + * Description: + *	This routine decides which port should be the active one and queues + *	port switching if necessary. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	Nothing. + */ +RLMT_STATIC void	SkRlmtCheckSwitch( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC,	/* I/O Context */ +SK_U32	NetIdx)	/* Net index */ +{ +	SK_EVPARA	Para; +	SK_U32		Active; +	SK_U32		PrefPort; +	SK_U32		i; +	SK_BOOL		PortFound; + +	Active = pAC->Rlmt.Net[NetIdx].ActivePort;	/* Index of active port. */ +	PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort;	/* Index of preferred port. */ +	PortFound = SK_FALSE; +	pAC->Rlmt.CheckSwitch = SK_FALSE; + +#if 0	/* RW 2001/10/18 - active port becomes always prefered one */ +	if (pAC->Rlmt.Net[NetIdx].Preference == 0xFFFFFFFF) { /* Automatic */ +		/* disable auto-fail back */ +		PrefPort = Active; +	} +#endif + +	if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) { +		/* Last link went down - shut down the net. */ +		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN; +		Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP; +		Para.Para32[1] = NetIdx; +		SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para); + +		Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. +			Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber; +		Para.Para32[1] = NetIdx; +		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para); +		return; +	}	/* pAC->Rlmt.LinksUp == 0 */ +	else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 && +		pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) { +		/* First link came up - get the net up. */ +		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP; + +		/* +		 * If pAC->Rlmt.ActivePort != Para.Para32[0], +		 * the DRV switches to the port that came up. +		 */ +		for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { +			if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) { +				if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) { +					i = Active; +				} +				if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) { +					i = PrefPort; +				} +				PortFound = SK_TRUE; +				break; +			} +		} + +		if (PortFound) { +			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber; +			Para.Para32[1] = NetIdx; +			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para); + +			pAC->Rlmt.Net[NetIdx].ActivePort = i; +			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber; +			Para.Para32[1] = NetIdx; +			SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para); + +			if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 && +				(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, +				pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber, +				SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx]. +				CurrentMacAddress, &SkRlmtMcAddr)) != NULL) { +				/* +				 * Send announce packet to RLMT multicast address to force +				 * switches to learn the new location of the logical MAC address. +				 */ +				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); +			} +		} +		else { +			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG); +		} + +		return; +	}	/* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */ +	else {	/* Cannot be reached in dual-net mode. */ +		Para.Para32[0] = Active; + +		/* +		 * Preselection: +		 *	If RLMT Mode != CheckLinkState +		 *		select port that received a broadcast frame substantially later +		 *		than all other ports +		 *	else select first port that is not SuspectRx +		 *	else select first port that is PortUp +		 *	else select port that is PortGoingUp for the longest time +		 *	else select first port that is PortDown +		 *	else stop. +		 * +		 * For the preselected port: +		 *	If ActivePort is equal in quality, select ActivePort. +		 * +		 *	If PrefPort is equal in quality, select PrefPort. +		 * +		 *	If ActivePort != SelectedPort, +		 *		If old ActivePort is LinkDown, +		 *			SwitchHard +		 *		else +		 *			SwitchSoft +		 */ +		/* check of ChgBcPrio flag added */ +		if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) && +			(!pAC->Rlmt.Net[0].ChgBcPrio)) { + +			if (!PortFound) { +				PortFound = SkRlmtSelectBcRx( +					pAC, IoC, Active, PrefPort, &Para.Para32[1]); +			} + +			if (!PortFound) { +				PortFound = SkRlmtSelectNotSuspect( +					pAC, IoC, Active, PrefPort, &Para.Para32[1]); +			} +		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ + +		/* with changed priority for last broadcast received */ +		if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) && +			(pAC->Rlmt.Net[0].ChgBcPrio)) { +			if (!PortFound) { +				PortFound = SkRlmtSelectNotSuspect( +					pAC, IoC, Active, PrefPort, &Para.Para32[1]); +			} + +			if (!PortFound) { +				PortFound = SkRlmtSelectBcRx( +					pAC, IoC, Active, PrefPort, &Para.Para32[1]); +			} +		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ + +		if (!PortFound) { +			PortFound = SkRlmtSelectUp( +				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); +		} + +		if (!PortFound) { +			PortFound = SkRlmtSelectUp( +				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); +		} + +		if (!PortFound) { +			PortFound = SkRlmtSelectGoingUp( +				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); +		} + +		if (!PortFound) { +			PortFound = SkRlmtSelectGoingUp( +				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); +		} + +		if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) { +			if (!PortFound) { +				PortFound = SkRlmtSelectDown(pAC, IoC, +					Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); +			} + +			if (!PortFound) { +				PortFound = SkRlmtSelectDown(pAC, IoC, +					Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); +			} +		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ + +		if (PortFound) { + +			if (Para.Para32[1] != Active) { +				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +					("Active: %d, Para1: %d.\n", Active, Para.Para32[1])) +				pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1]; +				Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. +					Port[Para.Para32[0]]->PortNumber; +				Para.Para32[1] = pAC->Rlmt.Net[NetIdx]. +					Port[Para.Para32[1]]->PortNumber; +				SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE); +				if (pAC->Rlmt.Port[Active].LinkDown) { +					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para); +				} +				else { +					SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY); +					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para); +				} +				Para.Para32[1] = NetIdx; +				Para.Para32[0] = +					pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber; +				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para); +				Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. +					Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber; +				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para); +				if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 && +					(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], +					SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress, +					&SkRlmtMcAddr)) != NULL) { +					/* +					 * Send announce packet to RLMT multicast address to force +					 * switches to learn the new location of the logical +					 * MAC address. +					 */ +					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); +				}	/* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */ +			}	/* Para.Para32[1] != Active */ +		}	/* PortFound */ +		else { +			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG); +		} +	}	/* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */ +	return; +}	/* SkRlmtCheckSwitch */ + + +/****************************************************************************** + * + *	SkRlmtCheckSeg - Report if segmentation is detected + * + * Description: + *	This routine checks if the ports see different root bridges and reports + *	segmentation in such a case. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	Nothing. + */ +RLMT_STATIC void	SkRlmtCheckSeg( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC,	/* I/O Context */ +SK_U32	NetIdx)	/* Net number */ +{ +	SK_EVPARA	Para; +	SK_RLMT_NET	*pNet; +	SK_U32		i, j; +	SK_BOOL		Equal; + +	pNet = &pAC->Rlmt.Net[NetIdx]; +	pNet->RootIdSet = SK_FALSE; +	Equal = SK_TRUE; + +	for (i = 0; i < pNet->NumPorts; i++) { +		if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) { +			continue; +		} + +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP, +			("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i, +				pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1], +				pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3], +				pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5], +				pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7])) + +		if (!pNet->RootIdSet) { +			pNet->Root = pNet->Port[i]->Root; +			pNet->RootIdSet = SK_TRUE; +			continue; +		} + +		for (j = 0; j < 8; j ++) { +			Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j]; +			if (!Equal) { +				break; +			} +		} + +		if (!Equal) { +			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG); +			Para.Para32[0] = NetIdx; +			Para.Para32[1] = (SK_U32)-1; +			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para); + +			pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG; + +			/* 2000-03-06 RA: New. */ +			Para.Para32[0] = NetIdx; +			Para.Para32[1] = (SK_U32)-1; +			SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL, +				SKGE_RLMT, SK_RLMT_SEG_TIM, Para); +			break; +		} +	}	/* for (i = 0; i < pNet->NumPorts; i++) */ + +	/* 2000-03-06 RA: Moved here. */ +	/* Segmentation check not running anymore. */ +	pNet->CheckingState &= ~SK_RLMT_RCS_SEG; + +}	/* SkRlmtCheckSeg */ + + +/****************************************************************************** + * + *	SkRlmtPortStart - initialize port variables and start port + * + * Description: + *	This routine initializes a port's variables and issues a PORT_START + *	to the HWAC module.  This handles retries if the start fails or the + *	link eventually goes down. + * + * Context: + *	runtime, pageable? + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtPortStart( +SK_AC	*pAC,		/* Adapter Context */ +SK_IOC	IoC,		/* I/O Context */ +SK_U32	PortNumber)	/* Port number */ +{ +	SK_EVPARA	Para; + +	pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN; +	pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE; +	pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE; +	pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE; +	pAC->Rlmt.Port[PortNumber].CheckingState = 0; +	pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE; +	Para.Para32[0] = PortNumber; +	Para.Para32[1] = (SK_U32)-1; +	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para); +}	/* SkRlmtPortStart */ + + +/****************************************************************************** + * + *	SkRlmtEvtPortStartTim - PORT_START_TIM + * + * Description: + *	This routine handles PORT_START_TIM events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtPortStartTim( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */ +{ +	SK_U32			i; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0])) + +		if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n")) +		return; +	} + +	/* +	 * Used to start non-preferred ports if the preferred one +	 * does not come up. +	 * This timeout needs only be set when starting the first +	 * (preferred) port. +	 */ +	if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { +		/* PORT_START failed. */ +		for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) { +			if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) { +				SkRlmtPortStart(pAC, IoC, +					pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber); +			} +		} +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PORTSTART_TIMEOUT Event END.\n")) +}	/* SkRlmtEvtPortStartTim */ + + +/****************************************************************************** + * + *	SkRlmtEvtLinkUp - LINK_UP + * + * Description: + *	This routine handles LLINK_UP events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtLinkUp( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */ +{ +	SK_U32			i; +	SK_RLMT_PORT	*pRPort; +	SK_EVPARA		Para2; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0])) + +	pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; +	if (!pRPort->PortStarted) { +		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG); + +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +				("SK_RLMT_LINK_UP Event EMPTY.\n")) +		return; +	} + +	if (!pRPort->LinkDown) { +		/* RA;:;: Any better solution? */ +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_LINK_UP Event EMPTY.\n")) +		return; +	} + +	SkTimerStop(pAC, IoC, &pRPort->UpTimer); +	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); +	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + +	/* Do something if timer already fired? */ + +	pRPort->LinkDown = SK_FALSE; +	pRPort->PortState = SK_RLMT_PS_GOING_UP; +	pRPort->GuTimeStamp = SkOsGetTime(pAC); +	pRPort->BcTimeStamp = 0; +	pRPort->Net->LinksUp++; +	if (pRPort->Net->LinksUp == 1) { +		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE); +	} +	else { +		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY); +	} + +	for (i = 0; i < pRPort->Net->NumPorts; i++) { +		if (!pRPort->Net->Port[i]->PortStarted) { +			SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber); +		} +	} + +	SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + +	if (pRPort->Net->LinksUp >= 2) { +		if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) { +			/* Build the check chain. */ +			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); +		} +	} + +	/* If the first link comes up, start the periodical RLMT timeout. */ +	if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 && +		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) { +		Para2.Para32[0] = pRPort->Net->NetNumber; +		Para2.Para32[1] = (SK_U32)-1; +		SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer, +			pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2); +	} + +	Para2 = Para; +	Para2.Para32[1] = (SK_U32)-1; +	SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL, +		SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2); + +	/* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */ +	if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 && +		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 && +		(Para2.pParaPtr = +			SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE, +			&pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr) +		) != NULL) { +		/* Send "new" packet to RLMT multicast address. */ +		SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); +	} + +	if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) { +		if ((Para2.pParaPtr = +			SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) { +			pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE; +			pRPort->Net->CheckingState |= +				SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG; + +			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); + +			Para.Para32[1] = (SK_U32)-1; +			SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer, +				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para); +		} +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_LINK_UP Event END.\n")) +}	/* SkRlmtEvtLinkUp */ + + +/****************************************************************************** + * + *	SkRlmtEvtPortUpTim - PORT_UP_TIM + * + * Description: + *	This routine handles PORT_UP_TIM events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtPortUpTim( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */ +{ +	SK_RLMT_PORT	*pRPort; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0])) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_PORTUP_TIM Event EMPTY.\n")) +		return; +	} + +	pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; +	if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0])) +		return; +	} + +	pRPort->PortDown = SK_FALSE; +	pRPort->PortState = SK_RLMT_PS_UP; +	pRPort->Net->PortsUp++; +	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) { +		if (pAC->Rlmt.NumNets <= 1) { +			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); +		} +		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para); +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PORTUP_TIM Event END.\n")) +}	/* SkRlmtEvtPortUpTim */ + + +/****************************************************************************** + * + *	SkRlmtEvtPortDownTim - PORT_DOWN_* + * + * Description: + *	This routine handles PORT_DOWN_* events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtPortDownX( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_U32		Event,	/* Event code */ +SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */ +{ +	SK_RLMT_PORT	*pRPort; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n", +			Para.Para32[0], Event)) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_PORTDOWN* Event EMPTY.\n")) +		return; +	} + +	pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; +	if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM && +		!(pRPort->CheckingState & SK_RLMT_PCS_TX))) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event)) +		return; +	} + +	/* Stop port's timers. */ +	SkTimerStop(pAC, IoC, &pRPort->UpTimer); +	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); +	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + +	if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) { +		pRPort->PortState = SK_RLMT_PS_DOWN; +	} + +	if (!pRPort->PortDown) { +		pRPort->Net->PortsUp--; +		pRPort->PortDown = SK_TRUE; +		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para); +	} + +	pRPort->PacketsPerTimeSlot = 0; +	/* pRPort->DataPacketsPerTimeSlot = 0; */ +	pRPort->BpduPacketsPerTimeSlot = 0; +	pRPort->BcTimeStamp = 0; + +	/* +	 * RA;:;: To be checked: +	 * - actions at RLMT_STOP: We should not switch anymore. +	 */ +	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) { +		if (Para.Para32[0] == +			pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) { +			/* Active Port went down. */ +			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); +		} +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event)) +}	/* SkRlmtEvtPortDownX */ + + +/****************************************************************************** + * + *	SkRlmtEvtLinkDown - LINK_DOWN + * + * Description: + *	This routine handles LINK_DOWN events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtLinkDown( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */ +{ +	SK_RLMT_PORT	*pRPort; + +	pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0])) + +	if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { +		pRPort->Net->LinksUp--; +		pRPort->LinkDown = SK_TRUE; +		pRPort->PortState = SK_RLMT_PS_LINK_DOWN; +		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF); + +		if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) { +			/* Build the check chain. */ +			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); +		} + +		/* Ensure that port is marked down. */ +		Para.Para32[1] = -1; +		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para); +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_LINK_DOWN Event END.\n")) +}	/* SkRlmtEvtLinkDown */ + + +/****************************************************************************** + * + *	SkRlmtEvtPortAddr - PORT_ADDR + * + * Description: + *	This routine handles PORT_ADDR events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtPortAddr( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */ +{ +	SK_U32			i, j; +	SK_RLMT_PORT	*pRPort; +	SK_MAC_ADDR		*pOldMacAddr; +	SK_MAC_ADDR		*pNewMacAddr; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0])) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_PORT_ADDR Event EMPTY.\n")) +		return; +	} + +	/* Port's physical MAC address changed. */ +	pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress; +	pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress; + +	/* +	 * NOTE: This is not scalable for solutions where ports are +	 *	 checked remotely.  There, we need to send an RLMT +	 *	 address change packet - and how do we ensure delivery? +	 */ +	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { +		pRPort = &pAC->Rlmt.Port[i]; +		for (j = 0; j < pRPort->PortsChecked; j++) { +			if (SK_ADDR_EQUAL( +				pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) { +				pRPort->PortCheck[j].CheckAddr = *pNewMacAddr; +			} +		} +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_PORT_ADDR Event END.\n")) +}	/* SkRlmtEvtPortAddr */ + + +/****************************************************************************** + * + *	SkRlmtEvtStart - START + * + * Description: + *	This routine handles START events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtStart( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */ +{ +	SK_EVPARA	Para2; +	SK_U32		PortIdx; +	SK_U32		PortNumber; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0])) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_START Event EMPTY.\n")) +		return; +	} + +	if (Para.Para32[0] >= pAC->Rlmt.NumNets) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad NetNumber %d.\n", Para.Para32[0])) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_START Event EMPTY.\n")) +		return; +	} + +	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_START Event EMPTY.\n")) +		return; +	} + +	if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("All nets should have been started.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_START Event EMPTY.\n")) +		return; +	} + +	if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >= +		pAC->Rlmt.Net[Para.Para32[0]].NumPorts) { +		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG); + +		/* Change PrefPort to internal default. */ +		Para2.Para32[0] = 0xFFFFFFFF; +		Para2.Para32[1] = Para.Para32[0]; +		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2); +	} + +	PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort; +	PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber; + +	pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0; +	pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0; +	pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0; +	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN; + +	/* Start preferred port. */ +	SkRlmtPortStart(pAC, IoC, PortNumber); + +	/* Start Timer (for first port only). */ +	Para2.Para32[0] = PortNumber; +	Para2.Para32[1] = (SK_U32)-1; +	SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer, +		SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2); + +	pAC->Rlmt.NetsStarted++; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_START Event END.\n")) +}	/* SkRlmtEvtStart */ + + +/****************************************************************************** + * + *	SkRlmtEvtStop - STOP + * + * Description: + *	This routine handles STOP events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtStop( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */ +{ +	SK_EVPARA	Para2; +	SK_U32		PortNumber; +	SK_U32		i; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0])) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_STOP Event EMPTY.\n")) +		return; +	} + +	if (Para.Para32[0] >= pAC->Rlmt.NumNets) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad NetNumber %d.\n", Para.Para32[0])) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_STOP Event EMPTY.\n")) +		return; +	} + +	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_STOP Event EMPTY.\n")) +		return; +	} + +	if (pAC->Rlmt.NetsStarted == 0) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("All nets are stopped.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_STOP Event EMPTY.\n")) +		return; +	} + +	/* Stop RLMT timers. */ +	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer); +	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer); + +	/* Stop net. */ +	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT; +	pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE; +	Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL; +	Para2.Para32[1] = Para.Para32[0];			/* Net# */ +	SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2); + +	/* Stop ports. */ +	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { +		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber; +		if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) { +			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer); +			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer); +			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer); + +			pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT; +			pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE; +			pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE; +			Para2.Para32[0] = PortNumber; +			Para2.Para32[1] = (SK_U32)-1; +			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2); +		} +	} + +	pAC->Rlmt.NetsStarted--; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_STOP Event END.\n")) +}	/* SkRlmtEvtStop */ + + +/****************************************************************************** + * + *	SkRlmtEvtTim - TIM + * + * Description: + *	This routine handles TIM events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtTim( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */ +{ +	SK_RLMT_PORT	*pRPort; +	SK_U32			Timeout; +	SK_U32			NewTimeout; +	SK_U32			PortNumber; +	SK_U32			i; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_TIM Event BEGIN.\n")) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_TIM Event EMPTY.\n")) +		return; +	} + +	if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 || +		pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) { +		/* Mode changed or all links down: No more link checking. */ +		return; +	} + +#if 0 +	pAC->Rlmt.SwitchCheckCounter--; +	if (pAC->Rlmt.SwitchCheckCounter == 0) { +		pAC->Rlmt.SwitchCheckCounter; +	} +#endif	/* 0 */ + +	NewTimeout = SK_RLMT_DEF_TO_VAL; +	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { +		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber; +		pRPort = &pAC->Rlmt.Port[PortNumber]; +		if (!pRPort->LinkDown) { +			Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber); +			if (Timeout < NewTimeout) { +				NewTimeout = Timeout; +			} + +			/* +			 * These counters should be set to 0 for all ports before the +			 * first frame is sent in the next loop. +			 */ +			pRPort->PacketsPerTimeSlot = 0; +			/* pRPort->DataPacketsPerTimeSlot = 0; */ +			pRPort->BpduPacketsPerTimeSlot = 0; +		} +	} +	pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout; + +	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) { +		/* +		 * If checking remote ports, also send packets if +		 *   (LinksUp == 1) && +		 *   this port checks at least one (remote) port. +		 */ + +		/* +		 * Must be new loop, as SkRlmtCheckPort can request to +		 * check segmentation when e.g. checking the last port. +		 */ +		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { +			if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) { +				SkRlmtSend(pAC, IoC, +					pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber); +			} +		} +	} + +	SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer, +		pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, +		Para); + +	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 && +		(pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) && +		(pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) { +		SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer, +			SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para); +		pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG; +		pAC->Rlmt.Net[Para.Para32[0]].CheckingState |= +			SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG; +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_TIM Event END.\n")) +}	/* SkRlmtEvtTim */ + + +/****************************************************************************** + * + *	SkRlmtEvtSegTim - SEG_TIM + * + * Description: + *	This routine handles SEG_TIM events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtSegTim( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */ +{ +#ifdef xDEBUG +	int j; +#endif	/* DEBUG */ + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_SEG_TIM Event BEGIN.\n")) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_SEG_TIM Event EMPTY.\n")) +		return; +	} + +#ifdef xDEBUG +	for (j = 0; j < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) { +		SK_ADDR_PORT	*pAPort; +		SK_U32			k; +		SK_U16			*InAddr; +		SK_U8			InAddr8[6]; + +		InAddr = (SK_U16 *)&InAddr8[0]; +		pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort; +		for (k = 0; k < pAPort->NextExactMatchRlmt; k++) { +			/* Get exact match address k from port j. */ +			XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber, +				XM_EXM(k), InAddr); +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +				("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n", +					k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber, +					InAddr8[0], InAddr8[1], InAddr8[2], +					InAddr8[3], InAddr8[4], InAddr8[5], +					pAPort->Exact[k].a[0], pAPort->Exact[k].a[1], +					pAPort->Exact[k].a[2], pAPort->Exact[k].a[3], +					pAPort->Exact[k].a[4], pAPort->Exact[k].a[5])) +		} +	} +#endif	/* xDEBUG */ + +	SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]); + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_SEG_TIM Event END.\n")) +}	/* SkRlmtEvtSegTim */ + + +/****************************************************************************** + * + *	SkRlmtEvtPacketRx - PACKET_RECEIVED + * + * Description: + *	This routine handles PACKET_RECEIVED events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtPacketRx( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_MBUF *pMb */ +{ +	SK_MBUF	*pMb; +	SK_MBUF	*pNextMb; +	SK_U32	NetNumber; + + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n")) + +	/* Should we ignore frames during port switching? */ + +#ifdef DEBUG +	pMb = Para.pParaPtr; +	if (pMb == NULL) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n")) +	} +	else if (pMb->pNext != NULL) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("More than one mbuf or pMb->pNext not set.\n")) +	} +#endif	/* DEBUG */ + +	for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) { +		pNextMb = pMb->pNext; +		pMb->pNext = NULL; + +		NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber; +		if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) { +			SkDrvFreeRlmtMbuf(pAC, IoC, pMb); +		} +		else { +			SkRlmtPacketReceive(pAC, IoC, pMb); +		} +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PACKET_RECEIVED Event END.\n")) +}	/* SkRlmtEvtPacketRx */ + + +/****************************************************************************** + * + *	SkRlmtEvtStatsClear - STATS_CLEAR + * + * Description: + *	This routine handles STATS_CLEAR events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtStatsClear( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */ +{ +	SK_U32			i; +	SK_RLMT_PORT	*pRPort; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_STATS_CLEAR Event BEGIN.\n")) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_STATS_CLEAR Event EMPTY.\n")) +		return; +	} + +	if (Para.Para32[0] >= pAC->Rlmt.NumNets) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad NetNumber %d.\n", Para.Para32[0])) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_STATS_CLEAR Event EMPTY.\n")) +		return; +	} + +	/* Clear statistics for logical and physical ports. */ +	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { +		pRPort = +			&pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber]; +		pRPort->TxHelloCts = 0; +		pRPort->RxHelloCts = 0; +		pRPort->TxSpHelloReqCts = 0; +		pRPort->RxSpHelloCts = 0; +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_STATS_CLEAR Event END.\n")) +}	/* SkRlmtEvtStatsClear */ + + +/****************************************************************************** + * + *	SkRlmtEvtStatsUpdate - STATS_UPDATE + * + * Description: + *	This routine handles STATS_UPDATE events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtStatsUpdate( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */ +{ +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_STATS_UPDATE Event BEGIN.\n")) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_STATS_UPDATE Event EMPTY.\n")) +		return; +	} + +	if (Para.Para32[0] >= pAC->Rlmt.NumNets) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad NetNumber %d.\n", Para.Para32[0])) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_STATS_UPDATE Event EMPTY.\n")) +		return; +	} + +	/* Update statistics - currently always up-to-date. */ + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_STATS_UPDATE Event END.\n")) +}	/* SkRlmtEvtStatsUpdate */ + + +/****************************************************************************** + * + *	SkRlmtEvtPrefportChange - PREFPORT_CHANGE + * + * Description: + *	This routine handles PREFPORT_CHANGE events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtPrefportChange( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 PortIndex; SK_U32 NetNumber */ +{ +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0])) + +	if (Para.Para32[1] >= pAC->Rlmt.NumNets) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad NetNumber %d.\n", Para.Para32[1])) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n")) +		return; +	} + +	/* 0xFFFFFFFF == auto-mode. */ +	if (Para.Para32[0] == 0xFFFFFFFF) { +		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT; +	} +	else { +		if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) { +			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG); + +			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +				("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n")) +			return; +		} + +		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0]; +	} + +	pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0]; + +	if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) { +		SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]); +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_PREFPORT_CHANGE Event END.\n")) +}	/* SkRlmtEvtPrefportChange */ + + +/****************************************************************************** + * + *	SkRlmtEvtSetNets - SET_NETS + * + * Description: + *	This routine handles SET_NETS events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtSetNets( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 NumNets; SK_U32 -1 */ +{ +	int i; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_SET_NETS Event BEGIN.\n")) + +	if (Para.Para32[1] != (SK_U32)-1) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad Parameter.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_SET_NETS Event EMPTY.\n")) +		return; +	} + +	if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS || +		Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad number of nets: %d.\n", Para.Para32[0])) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_SET_NETS Event EMPTY.\n")) +		return; +	} + +	if (Para.Para32[0] == pAC->Rlmt.NumNets) {	/* No change. */ +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_SET_NETS Event EMPTY.\n")) +		return; +	} + +	/* Entering and leaving dual mode only allowed while nets are stopped. */ +	if (pAC->Rlmt.NetsStarted > 0) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Changing dual mode only allowed while all nets are stopped.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_SET_NETS Event EMPTY.\n")) +		return; +	} + +	if (Para.Para32[0] == 1) { +		if (pAC->Rlmt.NumNets > 1) { +			/* Clear logical MAC addr from second net's active port. */ +			(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr. +				Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL); +			pAC->Rlmt.Net[1].NumPorts = 0; +		} + +		pAC->Rlmt.NumNets = Para.Para32[0]; +		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) { +			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; +			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; +			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */ +			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; +			/* Just assuming. */ +			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; +			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; +			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; +			pAC->Rlmt.Net[i].NetNumber = i; +		} + +		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0]; +		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound; + +		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para); + +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("RLMT: Changed to one net with two ports.\n")) +	} +	else if (Para.Para32[0] == 2) { +		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1]; +		pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1; +		pAC->Rlmt.Net[0].NumPorts = +			pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts; + +		pAC->Rlmt.NumNets = Para.Para32[0]; +		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) { +			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; +			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; +			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */ +			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; +			/* Just assuming. */ +			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; +			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; +			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; + +			pAC->Rlmt.Net[i].NetNumber = i; +		} + +		/* Set logical MAC addr on second net's active port. */ +		(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr. +			Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL); + +		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para); + +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("RLMT: Changed to two nets with one port each.\n")) +	} +	else { +		/* Not implemented for more than two nets. */ +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SetNets not implemented for more than two nets.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_SET_NETS Event EMPTY.\n")) +		return; +	} + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_SET_NETS Event END.\n")) +}	/* SkRlmtSetNets */ + + +/****************************************************************************** + * + *	SkRlmtEvtModeChange - MODE_CHANGE + * + * Description: + *	This routine handles MODE_CHANGE events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	Nothing + */ +RLMT_STATIC void	SkRlmtEvtModeChange( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_EVPARA	Para)	/* SK_U32 NewMode; SK_U32 NetNumber */ +{ +	SK_EVPARA	Para2; +	SK_U32		i; +	SK_U32		PrevRlmtMode; + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +		("SK_RLMT_MODE_CHANGE Event BEGIN.\n")) + +	if (Para.Para32[1] >= pAC->Rlmt.NumNets) { +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Bad NetNumber %d.\n", Para.Para32[1])) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_MODE_CHANGE Event EMPTY.\n")) +		return; +	} + +	Para.Para32[0] |= SK_RLMT_CHECK_LINK; + +	if ((pAC->Rlmt.Net[Para.Para32[1]].NumPorts == 1) && +		Para.Para32[0] != SK_RLMT_MODE_CLS) { +		pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS; +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Forced RLMT mode to CLS on single port net.\n")) +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_MODE_CHANGE Event EMPTY.\n")) +		return; +	} + +	/* Update RLMT mode. */ +	PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode; +	pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0]; + +	if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) != +		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { +		/* SK_RLMT_CHECK_LOC_LINK bit changed. */ +		if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 && +			pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 && +			pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) { +			/* 20001207 RA: Was "PortsUp == 1". */ +			Para2.Para32[0] = Para.Para32[1]; +			Para2.Para32[1] = (SK_U32)-1; +			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer, +				pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue, +				SKGE_RLMT, SK_RLMT_TIM, Para2); +		} +	} + +	if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) != +		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) { +		/* SK_RLMT_CHECK_SEG bit changed. */ +		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) { +			(void)SkAddrMcClear(pAC, IoC, +				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, +				SK_ADDR_PERMANENT | SK_MC_SW_ONLY); + +			/* Add RLMT MC address. */ +			(void)SkAddrMcAdd(pAC, IoC, +				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, +				&SkRlmtMcAddr, SK_ADDR_PERMANENT); + +			if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & +				SK_RLMT_CHECK_SEG) != 0) { +				/* Add BPDU MC address. */ +				(void)SkAddrMcAdd(pAC, IoC, +					pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, +					&BridgeMcAddr, SK_ADDR_PERMANENT); + +				if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) { +					if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown && +						(Para2.pParaPtr = SkRlmtBuildSpanningTreePacket( +						pAC, IoC, i)) != NULL) { +						pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet = +							SK_FALSE; +						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); +					} +				} +			} +			(void)SkAddrMcUpdate(pAC, IoC, +				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber); +		}	/* for ... */ + +		if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) { +			Para2.Para32[0] = Para.Para32[1]; +			Para2.Para32[1] = (SK_U32)-1; +			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer, +				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2); +		} +	}	/* SK_RLMT_CHECK_SEG bit changed. */ + +	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("SK_RLMT_MODE_CHANGE Event END.\n")) +}	/* SkRlmtEvtModeChange */ + + +/****************************************************************************** + * + *	SkRlmtEvent - a PORT- or an RLMT-specific event happened + * + * Description: + *	This routine calls subroutines to handle PORT- and RLMT-specific events. + * + * Context: + *	runtime, pageable? + *	may be called after SK_INIT_IO + * + * Returns: + *	0 + */ +int	SkRlmtEvent( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_U32		Event,	/* Event code */ +SK_EVPARA	Para)	/* Event-specific parameter */ +{ +	switch (Event) { + +	/* ----- PORT events ----- */ + +	case SK_RLMT_PORTSTART_TIM:	/* From RLMT via TIME. */ +		SkRlmtEvtPortStartTim(pAC, IoC, Para); +		break; +	case SK_RLMT_LINK_UP:		/* From SIRQ. */ +		SkRlmtEvtLinkUp(pAC, IoC, Para); +		break; +	case SK_RLMT_PORTUP_TIM:	/* From RLMT via TIME. */ +		SkRlmtEvtPortUpTim(pAC, IoC, Para); +		break; +	case SK_RLMT_PORTDOWN:			/* From RLMT. */ +	case SK_RLMT_PORTDOWN_RX_TIM:	/* From RLMT via TIME. */ +	case SK_RLMT_PORTDOWN_TX_TIM:	/* From RLMT via TIME. */ +		SkRlmtEvtPortDownX(pAC, IoC, Event, Para); +		break; +	case SK_RLMT_LINK_DOWN:		/* From SIRQ. */ +		SkRlmtEvtLinkDown(pAC, IoC, Para); +		break; +	case SK_RLMT_PORT_ADDR:		/* From ADDR. */ +		SkRlmtEvtPortAddr(pAC, IoC, Para); +		break; + +	/* ----- RLMT events ----- */ + +	case SK_RLMT_START:		/* From DRV. */ +		SkRlmtEvtStart(pAC, IoC, Para); +		break; +	case SK_RLMT_STOP:		/* From DRV. */ +		SkRlmtEvtStop(pAC, IoC, Para); +		break; +	case SK_RLMT_TIM:		/* From RLMT via TIME. */ +		SkRlmtEvtTim(pAC, IoC, Para); +		break; +	case SK_RLMT_SEG_TIM: +		SkRlmtEvtSegTim(pAC, IoC, Para); +		break; +	case SK_RLMT_PACKET_RECEIVED:	/* From DRV. */ +		SkRlmtEvtPacketRx(pAC, IoC, Para); +		break; +	case SK_RLMT_STATS_CLEAR:	/* From PNMI. */ +		SkRlmtEvtStatsClear(pAC, IoC, Para); +		break; +	case SK_RLMT_STATS_UPDATE:	/* From PNMI. */ +		SkRlmtEvtStatsUpdate(pAC, IoC, Para); +		break; +	case SK_RLMT_PREFPORT_CHANGE:	/* From PNMI. */ +		SkRlmtEvtPrefportChange(pAC, IoC, Para); +		break; +	case SK_RLMT_MODE_CHANGE:	/* From PNMI. */ +		SkRlmtEvtModeChange(pAC, IoC, Para); +		break; +	case SK_RLMT_SET_NETS:	/* From DRV. */ +		SkRlmtEvtSetNets(pAC, IoC, Para); +		break; + +	/* ----- Unknown events ----- */ + +	default:	/* Create error log entry. */ +		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, +			("Unknown RLMT Event %d.\n", Event)) +		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG); +		break; +	}	/* switch() */ + +	return (0); +}	/* SkRlmtEvent */ + +#ifdef __cplusplus +} +#endif	/* __cplusplus */ + +#endif /* CONFIG_SK98 */ |