| /****************************************************************************** | 
 |  * | 
 |  * 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 */ |