File: /usr/src/linux/drivers/net/sk98lin/skrlmt.c

1     /******************************************************************************
2      *
3      * Name:	skrlmt.c
4      * Project:	GEnesis, PCI Gigabit Ethernet Adapter
5      * Version:	$Revision: 1.61 $
6      * Date:	$Date: 2001/03/14 12:52:08 $
7      * Purpose:	Manage links on SK-NET Adapters, esp. redundant ones.
8      *
9      ******************************************************************************/
10     
11     /******************************************************************************
12      *
13      *	(C)Copyright 1998-2001 SysKonnect GmbH.
14      *
15      *	This program is free software; you can redistribute it and/or modify
16      *	it under the terms of the GNU General Public License as published by
17      *	the Free Software Foundation; either version 2 of the License, or
18      *	(at your option) any later version.
19      *
20      *	The information in this file is provided "AS IS" without warranty.
21      *
22      ******************************************************************************/
23     
24     /******************************************************************************
25      *
26      * History:
27      *
28      *	$Log: skrlmt.c,v $
29      *	Revision 1.61  2001/03/14 12:52:08  rassmann
30      *	Fixed reporting of active port up/down to PNMI.
31      *	
32      *	Revision 1.60  2001/02/21 16:02:25  gklug
33      *	fix: when RLMT starts set Active Port for PNMI
34      *	
35      *	Revision 1.59  2001/02/16 14:38:19  rassmann
36      *	Initializing some pointers earlier in the init phase.
37      *	Rx Mbufs are freed if the net which they belong to is stopped.
38      *	
39      *	Revision 1.58  2001/02/14 14:06:31  rassmann
40      *	Editorial changes.
41      *	
42      *	Revision 1.57  2001/02/05 14:25:26  rassmann
43      *	Prepared RLMT for transparent operation.
44      *	
45      *	Revision 1.56  2001/01/30 10:29:09  rassmann
46      *	Not checking switching befor RlmtStart.
47      *	Editorial changes.
48      *	
49      *	Revision 1.55  2001/01/22 13:41:38  rassmann
50      *	Supporting two nets on dual-port adapters.
51      *	
52      *	Revision 1.54  2000/11/30 13:25:07  rassmann
53      *	Setting SK_TICK_INCR to 1 by default.
54      *	
55      *	Revision 1.53  2000/11/30 10:48:07  cgoos
56      *	Changed definition of SK_RLMT_BC_DELTA.
57      *	
58      *	Revision 1.52  2000/11/27 12:50:03  rassmann
59      *	Checking ports after receiving broadcasts.
60      *	
61      *	Revision 1.51  2000/11/17 08:58:00  rassmann
62      *	Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event.
63      *	
64      *	Revision 1.50  2000/11/09 12:24:34  rassmann
65      *	Indicating that segmentation check is not running anymore after
66      *	  SkRlmtCheckSeg().
67      *	Restarting segmentation timer after segmentation log.
68      *	Editorial changes.
69      *	
70      *	Revision 1.49  1999/11/22 13:38:02  cgoos
71      *	Changed license header to GPL.
72      *	Added initialization to some variables to avoid compiler warnings.
73      *	
74      *	Revision 1.48  1999/10/04 14:01:17  rassmann
75      *	Corrected reaction to reception of BPDU frames (#10441).
76      *	
77      *	Revision 1.47  1999/07/20 12:53:36  rassmann
78      *	Fixed documentation errors for lookahead macros.
79      *	
80      *	Revision 1.46  1999/05/28 13:29:16  rassmann
81      *	Replaced C++-style comment.
82      *	
83      *	Revision 1.45  1999/05/28 13:28:08  rassmann
84      *	Corrected syntax error (xxx).
85      *	
86      *	Revision 1.44  1999/05/28 11:15:54  rassmann
87      *	Changed behaviour to reflect Design Spec v1.2.
88      *	Controlling Link LED(s).
89      *	Introduced RLMT Packet Version field in RLMT Packet.
90      *	Newstyle lookahead macros (checking meta-information before looking at
91      *	  the packet).
92      *	
93      *	Revision 1.43  1999/01/28 13:12:43  rassmann
94      *	Corrected Lookahead (bug introduced in previous Rev.).
95      *	
96      *	Revision 1.42  1999/01/28 12:50:41  rassmann
97      *	Not using broadcast time stamps in CheckLinkState mode.
98      *	
99      *	Revision 1.41  1999/01/27 14:13:02  rassmann
100      *	Monitoring broadcast traffic.
101      *	Switching more reliably and not too early if switch is
102      *	 configured for spanning tree.
103      *	
104      *	Revision 1.40  1999/01/22 13:17:30  rassmann
105      *	Informing PNMI of NET_UP.
106      *	Clearing RLMT multicast addresses before setting them for the first time.
107      *	Reporting segmentation earlier, setting a "quiet time"
108      *	 after a report.
109      *	
110      *	Revision 1.39  1998/12/10 15:29:53  rassmann
111      *	Corrected SuspectStatus in SkRlmtBuildCheckChain().
112      *	Corrected CHECK_SEG mode.
113      *	
114      *	Revision 1.38  1998/12/08 13:11:23  rassmann
115      *	Stopping SegTimer at RlmtStop.
116      *	
117      *	Revision 1.37  1998/12/07 16:51:42  rassmann
118      *	Corrected comments.
119      *	
120      *	Revision 1.36  1998/12/04 10:58:56  rassmann
121      *	Setting next pointer to NULL when receiving.
122      *	
123      *	Revision 1.35  1998/12/03 16:12:42  rassmann
124      *	Ignoring/correcting illegal PrefPort values.
125      *	
126      *	Revision 1.34  1998/12/01 11:45:35  rassmann
127      *	Code cleanup.
128      *	
129      *	Revision 1.33  1998/12/01 10:29:32  rassmann
130      *	Starting standby ports before getting the net up.
131      *	Checking if a port is started when the link comes up.
132      *	
133      *	Revision 1.32  1998/11/30 16:19:50  rassmann
134      *	New default for PortNoRx.
135      *	
136      *	Revision 1.31  1998/11/27 19:17:13  rassmann
137      *	Corrected handling of LINK_DOWN coming shortly after LINK_UP.
138      *	
139      *	Revision 1.30  1998/11/24 12:37:31  rassmann
140      *	Implemented segmentation check.
141      *	
142      *	Revision 1.29  1998/11/18 13:04:32  rassmann
143      *	Secured PortUpTimer event.
144      *	Waiting longer before starting standby port(s).
145      *	
146      *	Revision 1.28  1998/11/17 13:43:04  rassmann
147      *	Handling (logical) tx failure.
148      *	Sending packet on logical address after PORT_SWITCH.
149      *	
150      *	Revision 1.27  1998/11/13 17:09:50  rassmann
151      *	Secured some events against being called in wrong state.
152      *	
153      *	Revision 1.26  1998/11/13 16:56:54  rassmann
154      *	Added macro version of SkRlmtLookaheadPacket.
155      *	
156      *	Revision 1.25  1998/11/06 18:06:04  rassmann
157      *	Corrected timing when RLMT checks fail.
158      *	Clearing tx counter earlier in periodical checks.
159      *	
160      *	Revision 1.24  1998/11/05 10:37:27  rassmann
161      *	Checking destination address in Lookahead.
162      *	
163      *	Revision 1.23  1998/11/03 13:53:49  rassmann
164      *	RLMT should switch now (at least in mode 3).
165      *	
166      *	Revision 1.22  1998/10/29 14:34:49  rassmann
167      *	Clearing SK_RLMT struct at startup.
168      *	Initializing PortsUp during SK_RLMT_START.
169      *	
170      *	Revision 1.21  1998/10/28 11:30:17  rassmann
171      *	Default mode is now SK_RLMT_CHECK_LOC_LINK.
172      *	
173      *	Revision 1.20  1998/10/26 16:02:03  rassmann
174      *	Ignoring LINK_DOWN for links that are down.
175      *	
176      *	Revision 1.19  1998/10/22 15:54:01  rassmann
177      *	Corrected EtherLen.
178      *	Starting Link Check when second port comes up.
179      *	
180      *	Revision 1.18  1998/10/22 11:39:50  rassmann
181      *	Corrected signed/unsigned mismatches.
182      *	Corrected receive list handling and address recognition.
183      *	
184      *	Revision 1.17  1998/10/19 17:01:20  rassmann
185      *	More detailed checking of received packets.
186      *	
187      *	Revision 1.16  1998/10/15 15:16:34  rassmann
188      *	Finished Spanning Tree checking.
189      *	Checked with lint.
190      *	
191      *	Revision 1.15  1998/09/24 19:16:07  rassmann
192      *	Code cleanup.
193      *	Introduced Timer for PORT_DOWN due to no RX.
194      *	
195      *	Revision 1.14  1998/09/18 20:27:14  rassmann
196      *	Added address override.
197      *	
198      *	Revision 1.13  1998/09/16 11:31:48  rassmann
199      *	Including skdrv1st.h again. :(
200      *	
201      *	Revision 1.12  1998/09/16 11:09:50  rassmann
202      *	Syntax corrections.
203      *	
204      *	Revision 1.11  1998/09/15 12:32:03  rassmann
205      *	Syntax correction.
206      *	
207      *	Revision 1.10  1998/09/15 11:28:49  rassmann
208      *	Syntax corrections.
209      *	
210      *	Revision 1.9  1998/09/14 17:07:37  rassmann
211      *	Added code for port checking via LAN.
212      *	Changed Mbuf definition.
213      *	
214      *	Revision 1.8  1998/09/07 11:14:14  rassmann
215      *	Syntax corrections.
216      *	
217      *	Revision 1.7  1998/09/07 09:06:07  rassmann
218      *	Syntax corrections.
219      *	
220      *	Revision 1.6  1998/09/04 19:41:33  rassmann
221      *	Syntax corrections.
222      *	Started entering code for checking local links.
223      *	
224      *	Revision 1.5  1998/09/04 12:14:27  rassmann
225      *	Interface cleanup.
226      *	
227      *	Revision 1.4  1998/09/02 16:55:28  rassmann
228      *	Updated to reflect new DRV/HWAC/RLMT interface.
229      *	
230      *	Revision 1.3  1998/08/27 14:29:03  rassmann
231      *	Code cleanup.
232      *	
233      *	Revision 1.2  1998/08/27 14:26:24  rassmann
234      *	Updated interface.
235      *	
236      *	Revision 1.1  1998/08/21 08:26:49  rassmann
237      *	First public version.
238      *
239      ******************************************************************************/
240     
241     /******************************************************************************
242      *
243      * Description:
244      *
245      * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters.
246      * It is mainly intended for adapters with more than one link.
247      * For such adapters, this module realizes Redundant Link ManagemenT (RLMT).
248      *
249      * Include File Hierarchy:
250      *
251      *	"skdrv1st.h"
252      *	"skdrv2nd.h"
253      *
254      ******************************************************************************/
255     
256     #ifndef	lint
257     static const char SysKonnectFileId[] =
258     	"@(#) $Id: skrlmt.c,v 1.61 2001/03/14 12:52:08 rassmann Exp $ (C) SysKonnect.";
259     #endif	/* !defined(lint) */
260     
261     #define __SKRLMT_C
262     
263     #ifdef __cplusplus
264     #error C++ is not yet supported.
265     extern "C" {
266     #endif	/* cplusplus */
267     
268     #include "h/skdrv1st.h"
269     #include "h/skdrv2nd.h"
270     
271     /* defines ********************************************************************/
272     
273     #ifndef SK_HWAC_LINK_LED
274     #define SK_HWAC_LINK_LED(a,b,c,d)
275     #endif	/* !defined(SK_HWAC_LINK_LED) */
276     
277     #ifndef DEBUG
278     #define RLMT_STATIC	static
279     #else	/* DEBUG */
280     #define RLMT_STATIC
281     
282     #ifndef SK_LITTLE_ENDIAN
283     /* First 32 bits */
284     #define OFFS_LO32	1
285     
286     /* Second 32 bits */
287     #define OFFS_HI32	0
288     #else	/* SK_LITTLE_ENDIAN */
289     /* First 32 bits */
290     #define OFFS_LO32	0
291     
292     /* Second 32 bits */
293     #define OFFS_HI32	1
294     #endif	/* SK_LITTLE_ENDIAN */
295     
296     #endif	/* DEBUG */
297     
298     /* ----- Private timeout values ----- */
299     
300     #define SK_RLMT_MIN_TO_VAL			   125000	/* 1/8 sec. */
301     #define SK_RLMT_DEF_TO_VAL			  1000000	/* 1 sec. */
302     #define SK_RLMT_PORTDOWN_TIM_VAL	   900000	/* another 0.9 sec. */
303     #define SK_RLMT_PORTSTART_TIM_VAL	   100000	/* 0.1 sec. */
304     #define SK_RLMT_PORTUP_TIM_VAL		  2500000	/* 2.5 sec. */
305     #define SK_RLMT_SEG_TO_VAL			900000000	/* 15 min. */
306     
307     /* Assume tick counter increment is 1 - may be set OS-dependent. */
308     #ifndef SK_TICK_INCR
309     #define SK_TICK_INCR	SK_CONSTU64(1)
310     #endif	/* !defined(SK_TICK_INCR) */
311     
312     /*
313      * Amount that a time stamp must be later to be recognized as "substantially
314      * later". This is about 1/128 sec, but above 1 tick counter increment.
315      */
316     #define SK_RLMT_BC_DELTA		(1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \
317     									(SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR))
318     
319     /* ----- Private RLMT defaults ----- */
320     
321     #define SK_RLMT_DEF_PREF_PORT	0					/* "Lower" port. */
322     #define SK_RLMT_DEF_MODE 		SK_RLMT_CHECK_LINK	/* Default RLMT Mode. */
323     
324     /* ----- Private RLMT checking states ----- */
325     
326     #define SK_RLMT_RCS_SEG			1		/* RLMT Check State: check seg. */
327     #define SK_RLMT_RCS_START_SEG	2		/* RLMT Check State: start check seg. */
328     #define SK_RLMT_RCS_SEND_SEG	4		/* RLMT Check State: send BPDU packet */
329     #define SK_RLMT_RCS_REPORT_SEG	8		/* RLMT Check State: report seg. */
330     
331     /* ----- Private PORT checking states ----- */
332     
333     #define SK_RLMT_PCS_TX			1		/* Port Check State: check tx. */
334     #define SK_RLMT_PCS_RX			2		/* Port Check State: check rx. */
335     
336     /* ----- Private PORT events ----- */
337     
338     /* Note: Update simulation when changing these. */
339     #define SK_RLMT_PORTSTART_TIM	1100	/* Port start timeout. */
340     #define SK_RLMT_PORTUP_TIM		1101	/* Port can now go up. */
341     #define SK_RLMT_PORTDOWN_RX_TIM	1102	/* Port did not receive once ... */
342     #define SK_RLMT_PORTDOWN		1103	/* Port went down. */
343     #define SK_RLMT_PORTDOWN_TX_TIM	1104	/* Partner did not receive ... */
344     
345     /* ----- Private RLMT events ----- */
346     
347     /* Note: Update simulation when changing these. */
348     #define SK_RLMT_TIM				2100	/* RLMT timeout. */
349     #define SK_RLMT_SEG_TIM			2101	/* RLMT segmentation check timeout. */
350     
351     #define TO_SHORTEN(tim)	((tim) / 2)
352     
353     /* Error numbers and messages. */
354     #define SKERR_RLMT_E001		(SK_ERRBASE_RLMT + 0)
355     #define SKERR_RLMT_E001_MSG	"No Packet."
356     #define SKERR_RLMT_E002		(SKERR_RLMT_E001 + 1)
357     #define SKERR_RLMT_E002_MSG	"Short Packet."
358     #define SKERR_RLMT_E003		(SKERR_RLMT_E002 + 1)
359     #define SKERR_RLMT_E003_MSG	"Unknown RLMT event."
360     #define SKERR_RLMT_E004		(SKERR_RLMT_E003 + 1)
361     #define SKERR_RLMT_E004_MSG	"PortsUp incorrect."
362     #define SKERR_RLMT_E005		(SKERR_RLMT_E004 + 1)
363     #define SKERR_RLMT_E005_MSG	\
364      "Net seems to be segmented (different root bridges are reported on the ports)."
365     #define SKERR_RLMT_E006		(SKERR_RLMT_E005 + 1)
366     #define SKERR_RLMT_E006_MSG	"Duplicate MAC Address detected."
367     #define SKERR_RLMT_E007		(SKERR_RLMT_E006 + 1)
368     #define SKERR_RLMT_E007_MSG	"LinksUp incorrect."
369     #define SKERR_RLMT_E008		(SKERR_RLMT_E007 + 1)
370     #define SKERR_RLMT_E008_MSG	"Port not started but link came up."
371     #define SKERR_RLMT_E009		(SKERR_RLMT_E008 + 1)
372     #define SKERR_RLMT_E009_MSG	"Corrected illegal setting of Preferred Port."
373     #define SKERR_RLMT_E010		(SKERR_RLMT_E009 + 1)
374     #define SKERR_RLMT_E010_MSG	"Ignored illegal Preferred Port."
375     
376     /* LLC field values. */
377     #define LLC_COMMAND_RESPONSE_BIT		1
378     #define LLC_TEST_COMMAND				0xE3
379     #define LLC_UI							0x03
380     
381     /* RLMT Packet fields. */
382     #define	SK_RLMT_DSAP					0
383     #define	SK_RLMT_SSAP					0
384     #define SK_RLMT_CTRL					(LLC_TEST_COMMAND)
385     #define SK_RLMT_INDICATOR0				0x53	/* S */
386     #define SK_RLMT_INDICATOR1				0x4B	/* K */
387     #define SK_RLMT_INDICATOR2				0x2D	/* - */
388     #define SK_RLMT_INDICATOR3				0x52	/* R */
389     #define SK_RLMT_INDICATOR4				0x4C	/* L */
390     #define SK_RLMT_INDICATOR5				0x4D	/* M */
391     #define SK_RLMT_INDICATOR6				0x54	/* T */
392     #define SK_RLMT_PACKET_VERSION			0
393     
394     /* RLMT SPT Flag values. */
395     #define	SK_RLMT_SPT_FLAG_CHANGE			0x01
396     #define	SK_RLMT_SPT_FLAG_CHANGE_ACK		0x80
397     
398     /* RLMT SPT Packet fields. */
399     #define	SK_RLMT_SPT_DSAP				0x42
400     #define	SK_RLMT_SPT_SSAP				0x42
401     #define SK_RLMT_SPT_CTRL				(LLC_UI)
402     #define	SK_RLMT_SPT_PROTOCOL_ID0		0x00
403     #define	SK_RLMT_SPT_PROTOCOL_ID1		0x00
404     #define	SK_RLMT_SPT_PROTOCOL_VERSION_ID	0x00
405     #define	SK_RLMT_SPT_BPDU_TYPE			0x00
406     #define	SK_RLMT_SPT_FLAGS				0x00	/* ?? */
407     #define	SK_RLMT_SPT_ROOT_ID0			0xFF	/* Lowest possible priority. */
408     #define	SK_RLMT_SPT_ROOT_ID1			0xFF	/* Lowest possible priority. */
409     
410     /* Remaining 6 bytes will be the current port address. */
411     #define	SK_RLMT_SPT_ROOT_PATH_COST0		0x00
412     #define	SK_RLMT_SPT_ROOT_PATH_COST1		0x00
413     #define	SK_RLMT_SPT_ROOT_PATH_COST2		0x00
414     #define	SK_RLMT_SPT_ROOT_PATH_COST3		0x00
415     #define	SK_RLMT_SPT_BRIDGE_ID0			0xFF	/* Lowest possible priority. */
416     #define	SK_RLMT_SPT_BRIDGE_ID1			0xFF	/* Lowest possible priority. */
417     
418     /* Remaining 6 bytes will be the current port address. */
419     #define	SK_RLMT_SPT_PORT_ID0			0xFF	/* Lowest possible priority. */
420     #define	SK_RLMT_SPT_PORT_ID1			0xFF	/* Lowest possible priority. */
421     #define	SK_RLMT_SPT_MSG_AGE0			0x00
422     #define	SK_RLMT_SPT_MSG_AGE1			0x00
423     #define	SK_RLMT_SPT_MAX_AGE0			0x00
424     #define	SK_RLMT_SPT_MAX_AGE1			0xFF
425     #define	SK_RLMT_SPT_HELLO_TIME0			0x00
426     #define	SK_RLMT_SPT_HELLO_TIME1			0xFF
427     #define	SK_RLMT_SPT_FWD_DELAY0			0x00
428     #define	SK_RLMT_SPT_FWD_DELAY1			0x40
429     
430     /* Size defines. */
431     #define SK_RLMT_MIN_PACKET_SIZE			34
432     #define SK_RLMT_MAX_PACKET_SIZE			(SK_RLMT_MAX_TX_BUF_SIZE)
433     #define SK_PACKET_DATA_LEN				(SK_RLMT_MAX_PACKET_SIZE - \
434     										SK_RLMT_MIN_PACKET_SIZE)
435     
436     /* ----- RLMT packet types ----- */
437     #define SK_PACKET_ANNOUNCE				1	/* Port announcement. */
438     #define SK_PACKET_ALIVE					2	/* Alive packet to port. */
439     #define SK_PACKET_ADDR_CHANGED			3	/* Port address changed. */
440     #define SK_PACKET_CHECK_TX				4	/* Check your tx line. */
441     
442     #ifdef SK_LITTLE_ENDIAN
443     #define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \
444     	SK_U8	*_Addr = (SK_U8*)(Addr); \
445     	SK_U16	_Val = (SK_U16)(Val); \
446     	*_Addr++ = (SK_U8)(_Val >> 8); \
447     	*_Addr = (SK_U8)(_Val & 0xFF); \
448     }
449     #endif	/* SK_LITTLE_ENDIAN */
450     
451     #ifdef SK_BIG_ENDIAN
452     #define SK_U16_TO_NETWORK_ORDER(Val,Addr) (*(SK_U16*)(Addr) = (SK_U16)(Val))
453     #endif	/* SK_BIG_ENDIAN */
454     
455     #define AUTONEG_FAILED	SK_FALSE
456     #define AUTONEG_SUCCESS	SK_TRUE
457     
458     
459     /* typedefs *******************************************************************/
460     
461     /* RLMT packet.  Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */
462     typedef struct s_RlmtPacket {
463     	SK_U8	DstAddr[SK_MAC_ADDR_LEN];
464     	SK_U8	SrcAddr[SK_MAC_ADDR_LEN];
465     	SK_U8	TypeLen[2];
466     	SK_U8	DSap;
467     	SK_U8	SSap;
468     	SK_U8	Ctrl;
469     	SK_U8	Indicator[7];
470     	SK_U8	RlmtPacketType[2];
471     	SK_U8	Align1[2];
472     	SK_U8	Random[4];				/* Random value of requesting(!) station. */
473     	SK_U8	RlmtPacketVersion[2];	/* RLMT Packet version. */
474     	SK_U8	Data[SK_PACKET_DATA_LEN];
475     } SK_RLMT_PACKET;
476     
477     typedef struct s_SpTreeRlmtPacket {
478     	SK_U8	DstAddr[SK_MAC_ADDR_LEN];
479     	SK_U8	SrcAddr[SK_MAC_ADDR_LEN];
480     	SK_U8	TypeLen[2];
481     	SK_U8	DSap;
482     	SK_U8	SSap;
483     	SK_U8	Ctrl;
484     	SK_U8	ProtocolId[2];
485     	SK_U8	ProtocolVersionId;
486     	SK_U8	BpduType;
487     	SK_U8	Flags;
488     	SK_U8	RootId[8];
489     	SK_U8	RootPathCost[4];
490     	SK_U8	BridgeId[8];
491     	SK_U8	PortId[2];
492     	SK_U8	MessageAge[2];
493     	SK_U8	MaxAge[2];
494     	SK_U8	HelloTime[2];
495     	SK_U8	ForwardDelay[2];
496     } SK_SPTREE_PACKET;
497     
498     /* global variables ***********************************************************/
499     
500     SK_MAC_ADDR	SkRlmtMcAddr =	{{0x01,  0x00,  0x5A,  0x52,  0x4C,  0x4D}};
501     SK_MAC_ADDR	BridgeMcAddr =	{{0x01,  0x80,  0xC2,  0x00,  0x00,  0x00}};
502     SK_MAC_ADDR	BcAddr = 		{{0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF}};
503     
504     /* local variables ************************************************************/
505     
506     /* None. */
507     
508     /* functions ******************************************************************/
509     
510     RLMT_STATIC void	SkRlmtCheckSwitch(
511     	SK_AC	*pAC,
512     	SK_IOC	IoC,
513     	SK_U32	NetIdx);
514     RLMT_STATIC void	SkRlmtCheckSeg(
515     	SK_AC	*pAC,
516     	SK_IOC	IoC,
517     	SK_U32	NetIdx);
518     RLMT_STATIC void	SkRlmtEvtSetNets(
519     	SK_AC		*pAC,
520     	SK_IOC		IoC,
521     	SK_EVPARA	Para);
522     
523     /******************************************************************************
524      *
525      *	SkRlmtInit - initialize data, set state to init
526      *
527      * Description:
528      *
529      *	SK_INIT_DATA
530      *	============
531      *
532      *	This routine initializes all RLMT-related variables to a known state.
533      *	The initial state is SK_RLMT_RS_INIT.
534      *	All ports are initialized to SK_RLMT_PS_INIT.
535      *
536      *
537      *	SK_INIT_IO
538      *	==========
539      *
540      *	Nothing.
541      *
542      *
543      *	SK_INIT_RUN
544      *	===========
545      *
546      *	Determine the adapter's random value.
547      *	Set the hw registers, the "logical MAC address", the
548      *	RLMT multicast address, and eventually the BPDU multicast address.
549      *
550      * Context:
551      *	init, pageable
552      *
553      * Returns:
554      *	Nothing.
555      */
556     void	SkRlmtInit(
557     SK_AC	*pAC,	/* Adapter Context */
558     SK_IOC	IoC,	/* I/O Context */
559     int		Level)	/* Initialization Level */
560     {
561     	SK_U32		i, j;
562     	SK_U64		Random;
563     	SK_EVPARA	Para;
564     
565     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
566     		("RLMT Init level %d.\n", Level))
567     
568     	switch (Level) {
569     	case SK_INIT_DATA:	/* Initialize data structures. */
570     		SK_MEMSET((char *)&pAC->Rlmt, 0, sizeof(SK_RLMT));
571     
572     		for (i = 0; i < SK_MAX_MACS; i++) {
573     			pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT;
574     			pAC->Rlmt.Port[i].LinkDown = SK_TRUE;
575     			pAC->Rlmt.Port[i].PortDown = SK_TRUE;
576     			pAC->Rlmt.Port[i].PortStarted = SK_FALSE;
577     			pAC->Rlmt.Port[i].PortNoRx = SK_FALSE;
578     			pAC->Rlmt.Port[i].RootIdSet = SK_FALSE;
579     			pAC->Rlmt.Port[i].PortNumber = i;
580     			pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0];
581     			pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i];
582     		}
583     
584     		pAC->Rlmt.NumNets = 1;
585     		for (i = 0; i < SK_MAX_NETS; i++) {
586     			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
587     			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
588     			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* Automatic. */
589     			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
590     			/* Just assuming. */
591     			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
592     			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
593     			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
594     			pAC->Rlmt.Net[i].NetNumber = i;
595     		}
596     
597     		pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0];
598     		pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1];
599     #if SK_MAX_NETS > 1
600     		pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1];
601     #endif	/* SK_MAX_NETS > 1 */
602     		break;
603     
604     	case SK_INIT_IO:	/* GIMacsFound first available here. */
605     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
606     			("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound))
607     
608     		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
609     
610     		/* Initialize HW registers? */
611     		if (pAC->GIni.GIMacsFound < 2) {
612     			Para.Para32[0] = SK_RLMT_MODE_CLS;
613     			Para.Para32[1] = 0;
614     			(void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para);
615     		}
616     		break;
617     
618     	case SK_INIT_RUN:
619     		/* Ensure RLMT is set to one net. */
620     		if (pAC->Rlmt.NumNets > 1) {
621     			Para.Para32[0] = 1;
622     			Para.Para32[1] = -1;
623     			SkRlmtEvtSetNets(pAC, IoC, Para);
624     		}
625     
626     		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
627     			Random = SkOsGetTime(pAC);
628     			*(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random;
629     
630     			for (j = 0; j < 4; j++) {
631     				pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort->
632     					CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j];
633     			}
634     
635     			(void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
636     			
637     			/* Add RLMT MC address. */
638     			(void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT);
639     
640     			if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) {
641     				/* Add BPDU MC address. */
642     				(void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT);
643     			}
644     
645     			(void)SkAddrMcUpdate(pAC, IoC, i);
646     		}
647     		break;
648     
649     	default:	/* error */
650     		break;
651     	}
652     	return;
653     }	/* SkRlmtInit */
654     
655     
656     /******************************************************************************
657      *
658      *	SkRlmtBuildCheckChain - build the check chain
659      *
660      * Description:
661      *	This routine builds the local check chain:
662      *	- Each port that is up checks the next port.
663      *	- The last port that is up checks the first port that is up.
664      *
665      * Notes:
666      *	- Currently only local ports are considered when building the chain.
667      *	- Currently the SuspectState is just reset;
668      *	  it would be better to save it ...
669      *
670      * Context:
671      *	runtime, pageable?
672      *
673      * Returns:
674      *	Nothing
675      */
676     RLMT_STATIC void	SkRlmtBuildCheckChain(
677     SK_AC	*pAC,	/* Adapter Context */
678     SK_U32	NetIdx)	/* Net Number */
679     {
680     	SK_U32			i;
681     	SK_U32			NumMacsUp;
682     	SK_RLMT_PORT *	FirstMacUp;
683     	SK_RLMT_PORT *	PrevMacUp;
684     
685     	FirstMacUp	= NULL;
686     	PrevMacUp	= NULL;
687     	
688     	if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
689     		for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) {
690     			pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
691     		}
692     		return;	/* Done. */
693     	}
694     			
695     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
696     		("SkRlmtBuildCheckChain.\n"))
697     
698     	NumMacsUp = 0;
699     
700     	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
701     		pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
702     		pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0;
703     		pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &=
704     			~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX);
705     
706     		/*
707     		 * If more than two links are detected we should consider
708     		 * checking at least two other ports:
709     		 * 1. the next port that is not LinkDown and
710     		 * 2. the next port that is not PortDown.
711     		 */
712     		if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
713     			if (NumMacsUp == 0) {
714     				FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
715     			}
716     			else {
717     				pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[
718     					pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr =
719     					pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress;
720     				PrevMacUp->PortCheck[
721     					PrevMacUp->PortsChecked].SuspectTx = SK_FALSE;
722     				PrevMacUp->PortsChecked++;
723     			}
724     			PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
725     			NumMacsUp++;
726     		}
727     	}
728     
729     	if (NumMacsUp > 1) {
730     		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr =
731     			FirstMacUp->AddrPort->CurrentMacAddress;
732     		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx =
733     			SK_FALSE;
734     		PrevMacUp->PortsChecked++;
735     	}
736     
737     #ifdef DEBUG
738     	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
739     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
740     			("Port %d checks %d other ports: %2X.\n", NetIdx,
741     				pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked,
742     				pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5]))
743     	}
744     #endif	/* DEBUG */
745     
746     	return;       
747     }	/* SkRlmtBuildCheckChain */
748     
749     
750     /******************************************************************************
751      *
752      *	SkRlmtBuildPacket - build an RLMT packet
753      *
754      * Description:
755      *	This routine sets up an RLMT packet.
756      *
757      * Context:
758      *	runtime, pageable?
759      *
760      * Returns:
761      *	NULL or pointer to RLMT mbuf
762      */
763     RLMT_STATIC SK_MBUF	*SkRlmtBuildPacket(
764     SK_AC		*pAC,		/* Adapter Context */
765     SK_IOC		IoC,		/* I/O Context */
766     SK_U32		PortNumber,	/* Sending port */
767     SK_U16		PacketType,	/* RLMT packet type */
768     SK_MAC_ADDR	*SrcAddr,	/* Source address */
769     SK_MAC_ADDR	*DestAddr)	/* Destination address */
770     {
771     	int		i;
772     	SK_U16		Length;
773     	SK_MBUF		*pMb;
774     	SK_RLMT_PACKET	*pPacket;
775     
776     	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) {
777     		pPacket = (SK_RLMT_PACKET*)pMb->pData;
778     		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
779     			pPacket->DstAddr[i] = DestAddr->a[i];
780     			pPacket->SrcAddr[i] = SrcAddr->a[i];
781     		}
782     		pPacket->DSap = SK_RLMT_DSAP;
783     		pPacket->SSap = SK_RLMT_SSAP;
784     		pPacket->Ctrl = SK_RLMT_CTRL;
785     		pPacket->Indicator[0] = SK_RLMT_INDICATOR0;
786     		pPacket->Indicator[1] = SK_RLMT_INDICATOR1;
787     		pPacket->Indicator[2] = SK_RLMT_INDICATOR2;
788     		pPacket->Indicator[3] = SK_RLMT_INDICATOR3;
789     		pPacket->Indicator[4] = SK_RLMT_INDICATOR4;
790     		pPacket->Indicator[5] = SK_RLMT_INDICATOR5;
791     		pPacket->Indicator[6] = SK_RLMT_INDICATOR6;
792     
793     		SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]);
794     
795     		for (i = 0; i < 4; i++) {
796     			pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i];
797     		}
798     		
799     		SK_U16_TO_NETWORK_ORDER(
800     			SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]);
801     
802     		for (i = 0; i < SK_PACKET_DATA_LEN; i++) {
803     			pPacket->Data[i] = 0x00;
804     		}
805     
806     		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
807     		pMb->Length = Length;
808     		pMb->PortIdx = PortNumber;
809     		Length -= 14;
810     		SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]);
811     
812     		if (PacketType == SK_PACKET_ALIVE) {
813     			pAC->Rlmt.Port[PortNumber].TxHelloCts++;
814     		}
815     	}
816     
817     	return (pMb);       
818     }	/* SkRlmtBuildPacket */
819     
820     
821     /******************************************************************************
822      *
823      *	SkRlmtBuildSpanningTreePacket - build spanning tree check packet
824      *
825      * Description:
826      *	This routine sets up a BPDU packet for spanning tree check.
827      *
828      * Context:
829      *	runtime, pageable?
830      *
831      * Returns:
832      *	NULL or pointer to RLMT mbuf
833      */
834     RLMT_STATIC SK_MBUF	*SkRlmtBuildSpanningTreePacket(
835     SK_AC	*pAC,		/* Adapter Context */
836     SK_IOC	IoC,		/* I/O Context */
837     SK_U32	PortNumber)	/* Sending port */
838     {
839     	unsigned			i;
840     	SK_U16				Length;
841     	SK_MBUF				*pMb;
842     	SK_SPTREE_PACKET	*pSPacket;
843     
844     	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) !=
845     		NULL) {
846     		pSPacket = (SK_SPTREE_PACKET*)pMb->pData;
847     		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
848     			pSPacket->DstAddr[i] = BridgeMcAddr.a[i];
849     			pSPacket->SrcAddr[i] =
850     				pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
851     		}
852     		pSPacket->DSap = SK_RLMT_SPT_DSAP;
853     		pSPacket->SSap = SK_RLMT_SPT_SSAP;
854     		pSPacket->Ctrl = SK_RLMT_SPT_CTRL;
855     
856     		pSPacket->ProtocolId[0] = SK_RLMT_SPT_PROTOCOL_ID0;
857     		pSPacket->ProtocolId[1] = SK_RLMT_SPT_PROTOCOL_ID1;
858     		pSPacket->ProtocolVersionId = SK_RLMT_SPT_PROTOCOL_VERSION_ID;
859     		pSPacket->BpduType = SK_RLMT_SPT_BPDU_TYPE;
860     		pSPacket->Flags = SK_RLMT_SPT_FLAGS;
861     		pSPacket->RootId[0] = SK_RLMT_SPT_ROOT_ID0;
862     		pSPacket->RootId[1] = SK_RLMT_SPT_ROOT_ID1;
863     		pSPacket->RootPathCost[0] = SK_RLMT_SPT_ROOT_PATH_COST0;
864     		pSPacket->RootPathCost[1] = SK_RLMT_SPT_ROOT_PATH_COST1;
865     		pSPacket->RootPathCost[2] = SK_RLMT_SPT_ROOT_PATH_COST2;
866     		pSPacket->RootPathCost[3] = SK_RLMT_SPT_ROOT_PATH_COST3;
867     		pSPacket->BridgeId[0] = SK_RLMT_SPT_BRIDGE_ID0;
868     		pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1;
869     
870     		/*
871     		 * Use logical MAC address as bridge ID and filter these packets
872     		 * on receive.
873     		 */
874     		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
875     			pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] =
876     				pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber].
877     					CurrentMacAddress.a[i];
878     		}
879     		pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0;
880     		pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1;
881     		pSPacket->MessageAge[0] = SK_RLMT_SPT_MSG_AGE0;
882     		pSPacket->MessageAge[1] = SK_RLMT_SPT_MSG_AGE1;
883     		pSPacket->MaxAge[0] = SK_RLMT_SPT_MAX_AGE0;
884     		pSPacket->MaxAge[1] = SK_RLMT_SPT_MAX_AGE1;
885     		pSPacket->HelloTime[0] = SK_RLMT_SPT_HELLO_TIME0;
886     		pSPacket->HelloTime[1] = SK_RLMT_SPT_HELLO_TIME1;
887     		pSPacket->ForwardDelay[0] = SK_RLMT_SPT_FWD_DELAY0;
888     		pSPacket->ForwardDelay[1] = SK_RLMT_SPT_FWD_DELAY1;
889     
890     		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
891     		pMb->Length = Length;
892     		pMb->PortIdx = PortNumber;
893     		Length -= 14;
894     		SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]);
895     
896     		pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++;
897     	}
898     
899     	return (pMb);       
900     }	/* SkRlmtBuildSpanningTreePacket */
901     
902     
903     /******************************************************************************
904      *
905      *	SkRlmtSend - build and send check packets
906      *
907      * Description:
908      *	Depending on the RLMT state and the checking state, several packets
909      *	are sent through the indicated port.
910      *
911      * Context:
912      *	runtime, pageable?
913      *
914      * Returns:
915      *	Nothing.
916      */
917     RLMT_STATIC void	SkRlmtSend(
918     SK_AC	*pAC,		/* Adapter Context */
919     SK_IOC	IoC,		/* I/O Context */
920     SK_U32	PortNumber)	/* Sending port */
921     {
922     	unsigned	j;
923     	SK_EVPARA	Para;
924     	SK_RLMT_PORT	*pRPort;
925     
926     	pRPort = &pAC->Rlmt.Port[PortNumber];
927     	if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
928     		if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) {
929     			/* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */
930     			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
931     				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
932     				&SkRlmtMcAddr)) != NULL) {
933     				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
934     			}
935     		}
936     		else {
937     			/*
938     			 * Send a directed RLMT packet to all ports that are
939     			 * checked by the indicated port.
940     			 */
941     			for (j = 0; j < pRPort->PortsChecked; j++) {
942     				if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
943     					SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
944     					&pRPort->PortCheck[j].CheckAddr)) != NULL) {
945     					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
946     				}
947     			}
948     		}
949     	}
950     
951     	if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
952     		(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) {
953     		/*
954     		 * Send a BPDU packet to make a connected switch tell us
955     		 * the correct root bridge.
956     		 */
957     		if ((Para.pParaPtr =
958     			SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) {
959     			pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG;
960     			pRPort->RootIdSet = SK_FALSE;
961     
962     			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
963     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX,
964     				("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber))
965     		}
966     	}   
967     	return;   
968     }	/* SkRlmtSend */
969     
970     
971     /******************************************************************************
972      *
973      *	SkRlmtPortReceives - check if port is (going) down and bring it up
974      *
975      * Description:
976      *	This routine checks if a port who received a non-BPDU packet
977      *	needs to go up or needs to be stopped going down.
978      *
979      * Context:
980      *	runtime, pageable?
981      *
982      * Returns:
983      *	Nothing.
984      */
985     RLMT_STATIC void	SkRlmtPortReceives(
986     SK_AC	*pAC,			/* Adapter Context */
987     SK_IOC	IoC,			/* I/O Context */
988     SK_U32	PortNumber)		/* Port to check */
989     {
990     	SK_RLMT_PORT	*pRPort;
991     	SK_EVPARA		Para;
992     
993     	pRPort = &pAC->Rlmt.Port[PortNumber];
994     	pRPort->PortNoRx = SK_FALSE;
995     
996     	if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
997     		!(pRPort->CheckingState & SK_RLMT_PCS_TX)) {
998     		/*
999     		 * Port is marked down (rx), but received a non-BPDU packet.
1000     		 * Bring it up.
1001     		 */
1002     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1003     			("SkRlmtPacketReceive: Received on PortDown.\n"))
1004     
1005     		pRPort->PortState = SK_RLMT_PS_GOING_UP;
1006     		pRPort->GuTimeStamp = SkOsGetTime(pAC);
1007     		Para.Para32[0] = PortNumber;
1008     		Para.Para32[1] = (SK_U32)-1;
1009     		SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
1010     			SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para);
1011     		pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
1012     		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */
1013     		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
1014     	}	/* PortDown && !SuspectTx */
1015     	else if (pRPort->CheckingState & SK_RLMT_PCS_RX) {
1016     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1017     			("SkRlmtPacketReceive: Stop bringing port down.\n"))
1018     		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
1019     		pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
1020     		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */
1021     		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
1022     	}	/* PortGoingDown */
1023     
1024     	return;
1025     }	/* SkRlmtPortReceives */
1026     
1027     
1028     /******************************************************************************
1029      *
1030      *	SkRlmtPacketReceive - receive a packet for closer examination
1031      *
1032      * Description:
1033      *	This routine examines a packet more closely than SK_RLMT_LOOKAHEAD.
1034      *
1035      * Context:
1036      *	runtime, pageable?
1037      *
1038      * Returns:
1039      *	Nothing.
1040      */
1041     RLMT_STATIC void	SkRlmtPacketReceive(
1042     SK_AC	*pAC,	/* Adapter Context */
1043     SK_IOC	IoC,	/* I/O Context */
1044     SK_MBUF	*pMb)	/* Received packet */
1045     {
1046     #ifdef xDEBUG
1047     	extern	void DumpData(char *p, int size);
1048     #endif	/* DEBUG */
1049     	int					i;
1050     	unsigned			j;
1051     	SK_U16				PacketType;
1052     	SK_U32				PortNumber;
1053     	SK_ADDR_PORT		*pAPort;
1054     	SK_RLMT_PORT		*pRPort;
1055     	SK_RLMT_PACKET		*pRPacket;
1056     	SK_SPTREE_PACKET	*pSPacket;
1057     	SK_EVPARA			Para;
1058     
1059     	PortNumber	= pMb->PortIdx;
1060     	pAPort = &pAC->Addr.Port[PortNumber];
1061     	pRPort = &pAC->Rlmt.Port[PortNumber];
1062     
1063     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1064     		("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber))
1065     
1066     	pRPacket = (SK_RLMT_PACKET*)pMb->pData;
1067     	pSPacket = (SK_SPTREE_PACKET*)pRPacket;
1068     
1069     #ifdef xDEBUG
1070     	DumpData((char *)pRPacket, 32);
1071     #endif	/* DEBUG */
1072     
1073     	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) {
1074     		SkRlmtPortReceives(pAC, IoC, PortNumber);
1075     	}
1076     	
1077     	/* Check destination address. */
1078     
1079     	if (!SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->DstAddr) &&
1080     		!SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) &&
1081     		!SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) {
1082     
1083     		/* Not sent to current MAC or registered MC address => Trash it. */
1084     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1085     			("SkRlmtPacketReceive: Not for me.\n"))
1086     
1087     		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
1088     		return;
1089     	}
1090     	else if (SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->SrcAddr)) {
1091     
1092     		/*
1093     		 * Was sent by same port (may happen during port switching
1094     		 * or in case of duplicate MAC addresses).
1095     		 */
1096     
1097     		/*
1098     		 * Check for duplicate address here:
1099     		 * If Packet.Random != My.Random => DupAddr.
1100     		 */
1101     		for (i = 3; i >= 0; i--) {
1102     			if (pRPort->Random[i] != pRPacket->Random[i]) {
1103     				break;
1104     			}
1105     		}
1106     
1107     		/*
1108     		 * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply
1109     		 * packets (they have the LLC_COMMAND_RESPONSE_BIT set in
1110     		 * pRPacket->SSap).
1111     		 */
1112     		if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP &&
1113     			pRPacket->Ctrl == SK_RLMT_CTRL &&
1114     			pRPacket->SSap == SK_RLMT_SSAP &&
1115     			pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
1116     			pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
1117     			pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
1118     			pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
1119     			pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
1120     			pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
1121     			pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
1122     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1123     				("SkRlmtPacketReceive: Duplicate MAC Address.\n"))
1124     
1125     			/* Error Log entry. */
1126     			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG);
1127     		}
1128     		else {
1129     			/* Simply trash it. */
1130     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1131     				("SkRlmtPacketReceive: Sent by me.\n"))
1132     		}
1133     
1134     		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
1135     		return;
1136     	}
1137     
1138     	/* Check SuspectTx entries. */
1139     	if (pRPort->PortsSuspect > 0) {
1140     		for (j = 0; j < pRPort->PortsChecked; j++) {
1141     			if (pRPort->PortCheck[j].SuspectTx &&
1142     				SK_ADDR_EQUAL(
1143     					pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) {
1144     				pRPort->PortCheck[j].SuspectTx = SK_FALSE;
1145     				pRPort->PortsSuspect--;
1146     				break;
1147     			}
1148     		}
1149     	}
1150     
1151     	/* Determine type of packet. */
1152     	if (pRPacket->DSap == SK_RLMT_DSAP &&
1153     		pRPacket->Ctrl == SK_RLMT_CTRL &&
1154     		(pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP &&
1155     		pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
1156     		pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
1157     		pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
1158     		pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
1159     		pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
1160     		pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
1161     		pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
1162     
1163     		/* It's an RLMT packet. */
1164     		PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) |
1165     			pRPacket->RlmtPacketType[1]);
1166     
1167     		switch (PacketType) {
1168     		case SK_PACKET_ANNOUNCE:	/* Not yet used. */
1169     #if 0
1170     			/* Build the check chain. */
1171     			SkRlmtBuildCheckChain(pAC);
1172     #endif	/* 0 */
1173     
1174     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1175     				("SkRlmtPacketReceive: Announce.\n"))
1176     
1177     			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
1178     			break;
1179     
1180     		case SK_PACKET_ALIVE:
1181     			if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) {
1182     				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1183     					("SkRlmtPacketReceive: Alive Reply.\n"))
1184     
1185     				if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) ||
1186     					SK_ADDR_EQUAL(
1187     						pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) {
1188     					/* Obviously we could send something. */
1189     					if (pRPort->CheckingState & SK_RLMT_PCS_TX) {
1190     						pRPort->CheckingState &=  ~SK_RLMT_PCS_TX;
1191     						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
1192     					}
1193     
1194     					if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
1195     						!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
1196     						pRPort->PortState = SK_RLMT_PS_GOING_UP;
1197     						pRPort->GuTimeStamp = SkOsGetTime(pAC);
1198     
1199     						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
1200     
1201     						Para.Para32[0] = PortNumber;
1202     						Para.Para32[1] = (SK_U32)-1;
1203     						SkTimerStart(pAC, IoC, &pRPort->UpTimer,
1204     							SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT,
1205     							SK_RLMT_PORTUP_TIM, Para);
1206     					}
1207     				}
1208     
1209     				/* Mark sending port as alive? */
1210     				SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
1211     			}
1212     			else {	/* Alive Request Packet. */
1213     				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1214     					("SkRlmtPacketReceive: Alive Request.\n"))
1215     
1216     				pRPort->RxHelloCts++;
1217     
1218     				/* Answer. */
1219     				for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
1220     					pRPacket->DstAddr[i] = pRPacket->SrcAddr[i];
1221     					pRPacket->SrcAddr[i] =
1222     						pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
1223     				}
1224     				pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT;
1225     
1226     				Para.pParaPtr = pMb;
1227     				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
1228     			}
1229     			break;
1230     
1231     		case SK_PACKET_CHECK_TX:
1232     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1233     				("SkRlmtPacketReceive: Check your tx line.\n"))
1234     
1235     			/* A port checking us requests us to check our tx line. */
1236     			pRPort->CheckingState |= SK_RLMT_PCS_TX;
1237     
1238     			/* Start PortDownTx timer. */
1239     			Para.Para32[0] = PortNumber;
1240     			Para.Para32[1] = (SK_U32)-1;
1241     			SkTimerStart(pAC, IoC, &pRPort->DownTxTimer,
1242     				SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
1243     				SK_RLMT_PORTDOWN_TX_TIM, Para);
1244     
1245     			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
1246     
1247     			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
1248     				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
1249     				&SkRlmtMcAddr)) != NULL) {
1250     				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
1251     			}
1252     			break;
1253     
1254     		case SK_PACKET_ADDR_CHANGED:
1255     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1256     				("SkRlmtPacketReceive: Address Change.\n"))
1257     
1258     			/* Build the check chain. */
1259     			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
1260     			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
1261     			break;
1262     
1263     		default:
1264     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1265     				("SkRlmtPacketReceive: Unknown RLMT packet.\n"))
1266     
1267     			/* RA;:;: ??? */
1268     			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
1269     		}
1270     	}
1271     	else if (pSPacket->DSap == SK_RLMT_SPT_DSAP &&
1272     		pSPacket->Ctrl == SK_RLMT_SPT_CTRL &&
1273     		(pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) {
1274     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1275     			("SkRlmtPacketReceive: BPDU Packet.\n"))
1276     
1277     		/* Spanning Tree packet. */
1278     		pRPort->RxSpHelloCts++;
1279     
1280     		if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt.
1281     			Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) {
1282     			/*
1283     			 * Check segmentation if a new root bridge is set and
1284     			 * the segmentation check is not currently running.
1285     			 */
1286     			if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) &&
1287     				(pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
1288     				(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG)
1289     				!= 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState &
1290     				SK_RLMT_RCS_SEG) == 0) {
1291     				pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
1292     					SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
1293     			}
1294     
1295     			/* Store tree view of this port. */
1296     			for (i = 0; i < 8; i++) {
1297     				pRPort->Root.Id[i] = pSPacket->RootId[i];
1298     			}
1299     			pRPort->RootIdSet = SK_TRUE;
1300     
1301     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
1302     				("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
1303     					PortNumber,
1304     					pRPort->Root.Id[0], pRPort->Root.Id[1],
1305     					pRPort->Root.Id[2], pRPort->Root.Id[3],
1306     					pRPort->Root.Id[4], pRPort->Root.Id[5],
1307     					pRPort->Root.Id[6], pRPort->Root.Id[7]))      
1308     		}
1309     
1310     		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
1311     		if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState &
1312     			SK_RLMT_RCS_REPORT_SEG) != 0) {
1313     			SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber);
1314     		}
1315     	}
1316     	else {
1317     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
1318     			("SkRlmtPacketReceive: Unknown Packet Type.\n"))
1319     
1320     		/* Unknown packet. */
1321     		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
1322     	}
1323     	return;
1324     }	/* SkRlmtPacketReceive */
1325     
1326     
1327     /******************************************************************************
1328      *
1329      *	SkRlmtCheckPort - check if a port works
1330      *
1331      * Description:
1332      *	This routine checks if a port whose link is up received something
1333      *	and if it seems to transmit successfully.
1334      *
1335      *	# PortState: PsInit, PsLinkDown, PsDown, PsGoingUp, PsUp
1336      *	# PortCheckingState (Bitfield): ChkTx, ChkRx, ChkSeg
1337      *	# RlmtCheckingState (Bitfield): ChkSeg, StartChkSeg, ReportSeg
1338      *
1339      *	if (Rx - RxBpdu == 0) {	# No rx.
1340      *		if (state == PsUp) {
1341      *			PortCheckingState |= ChkRx
1342      *		}
1343      *		if (ModeCheckSeg && (Timeout ==
1344      *			TO_SHORTEN(RLMT_DEFAULT_TIMEOUT))) {
1345      *			RlmtCheckingState |= ChkSeg)
1346      *			PortCheckingState |= ChkSeg
1347      *		}
1348      *		NewTimeout = TO_SHORTEN(Timeout)
1349      *		if (NewTimeout < RLMT_MIN_TIMEOUT) {
1350      *			NewTimeout = RLMT_MIN_TIMEOUT
1351      *			PortState = PsDown
1352      *			...
1353      *		}
1354      *	}
1355      *	else {	# something was received
1356      *		# Set counter to 0 at LinkDown?
1357      *		#   No - rx may be reported after LinkDown ???
1358      *		PortCheckingState &= ~ChkRx
1359      *		NewTimeout = RLMT_DEFAULT_TIMEOUT
1360      *		if (RxAck == 0) {
1361      *			possible reasons:
1362      *			is my tx line bad? --
1363      *				send RLMT multicast and report
1364      *				back internally? (only possible
1365      *				between ports on same adapter)
1366      *		}
1367      *		if (RxChk == 0) {
1368      *			possible reasons:
1369      *			- tx line of port set to check me
1370      *			  maybe bad
1371      *			- no other port/adapter available or set
1372      *			  to check me
1373      *			- adapter checking me has a longer
1374      *			  timeout
1375      *			??? anything that can be done here?
1376      *		}
1377      *	}
1378      *
1379      * Context:
1380      *	runtime, pageable?
1381      *
1382      * Returns:
1383      *	New timeout value.
1384      */
1385     RLMT_STATIC SK_U32	SkRlmtCheckPort(
1386     SK_AC	*pAC,		/* Adapter Context */
1387     SK_IOC	IoC,		/* I/O Context */
1388     SK_U32	PortNumber)	/* Port to check */
1389     {
1390     	unsigned		i;
1391     	SK_U32			NewTimeout;
1392     	SK_RLMT_PORT	*pRPort;
1393     	SK_EVPARA		Para;
1394     
1395     	pRPort = &pAC->Rlmt.Port[PortNumber];
1396     
1397     	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) {
1398     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1399     			("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n",
1400     				PortNumber, pRPort->PacketsPerTimeSlot))
1401     
1402     		/*
1403     		 * Check segmentation if there was no receive at least twice
1404     		 * in a row (PortNoRx is already set) and the segmentation
1405     		 * check is not currently running.
1406     		 */
1407     
1408     		if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
1409     			(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
1410     			!(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) {
1411     			pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
1412     				SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
1413     		}
1414     
1415     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1416     			("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n",
1417     				pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX))
1418     
1419     		if (pRPort->PortState != SK_RLMT_PS_DOWN) {
1420     			NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue);
1421     			if (NewTimeout < SK_RLMT_MIN_TO_VAL) {
1422     				NewTimeout = SK_RLMT_MIN_TO_VAL;
1423     			}
1424     
1425     			if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
1426     				Para.Para32[0] = PortNumber;
1427     				pRPort->CheckingState |= SK_RLMT_PCS_RX;
1428     
1429     				/*
1430     				 * What shall we do if the port checked by this one receives
1431     				 * our request frames?  What's bad - our rx line or his tx line?
1432     				 */
1433     				Para.Para32[1] = (SK_U32)-1;
1434     				SkTimerStart(pAC, IoC, &pRPort->DownRxTimer,
1435     					SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
1436     					SK_RLMT_PORTDOWN_RX_TIM, Para);
1437     
1438     				for (i = 0; i < pRPort->PortsChecked; i++) {
1439     					if (pRPort->PortCheck[i].SuspectTx) {
1440     						continue;
1441     					}
1442     					pRPort->PortCheck[i].SuspectTx = SK_TRUE;
1443     					pRPort->PortsSuspect++;
1444     					if ((Para.pParaPtr =
1445     						SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX,
1446     							&pAC->Addr.Port[PortNumber].CurrentMacAddress,
1447     							&pRPort->PortCheck[i].CheckAddr)) != NULL) {
1448     						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
1449     					}
1450     				}
1451     			}
1452     		}
1453     		else {	/* PortDown -- or all partners suspect. */
1454     			NewTimeout = SK_RLMT_DEF_TO_VAL;
1455     		}
1456     		pRPort->PortNoRx = SK_TRUE;
1457     	}
1458     	else {	/* A non-BPDU packet was received. */
1459     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1460     			("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n",
1461     				PortNumber,
1462     				pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot,
1463     				pRPort->PacketsPerTimeSlot))
1464     		
1465     		SkRlmtPortReceives(pAC, IoC, PortNumber);
1466     		if (pAC->Rlmt.CheckSwitch) {
1467     			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
1468     		}
1469     
1470     		NewTimeout = SK_RLMT_DEF_TO_VAL;              
1471     	}
1472     
1473     	return (NewTimeout);       
1474     }	/* SkRlmtCheckPort */
1475     
1476     
1477     /******************************************************************************
1478      *
1479      *	SkRlmtSelectBcRx - select new active port, criteria 1 (CLP)
1480      *
1481      * Description:
1482      *	This routine selects the port that received a broadcast frame
1483      *	substantially later than all other ports.
1484      *
1485      * Context:
1486      *	runtime, pageable?
1487      *
1488      * Returns:
1489      *	SK_BOOL
1490      */
1491     RLMT_STATIC SK_BOOL	SkRlmtSelectBcRx(
1492     SK_AC	*pAC,		/* Adapter Context */
1493     SK_IOC	IoC,		/* I/O Context */
1494     SK_U32	Active,		/* Active port */
1495     SK_U32	PrefPort,	/* Preferred port */
1496     SK_U32	*pSelect)	/* New active port */
1497     {
1498     	SK_U64		BcTimeStamp;
1499     	SK_U32		i;
1500     	SK_BOOL		PortFound;
1501     
1502     	BcTimeStamp = 0;	/* Not totally necessary, but feeling better. */
1503     	PortFound = SK_FALSE;
1504     	
1505     	/* Select port with the latest TimeStamp. */
1506     	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
1507     #ifdef xDEBUG
1508     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1509     			("TimeStamp Port %d: %08x %08x.\n",
1510     				i,
1511     				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32),
1512     				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32)))
1513     #endif	/* DEBUG */
1514     		if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) {
1515     			if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) {
1516     				BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp;
1517     				*pSelect = i;
1518     				PortFound = SK_TRUE;
1519     			}
1520     		}
1521     	}
1522     
1523     	if (PortFound) {
1524     #if 0
1525     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1526     			("Port %d received the last broadcast.\n", *pSelect))
1527     #endif	/* 0 */
1528     
1529     		/* Look if another port's time stamp is similar. */
1530     		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
1531     			if (i == *pSelect) {
1532     				continue;
1533     			}
1534     			if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx &&
1535     				(pAC->Rlmt.Port[i].BcTimeStamp >
1536     				 BcTimeStamp - SK_RLMT_BC_DELTA ||
1537     				pAC->Rlmt.Port[i].BcTimeStamp +
1538     				 SK_RLMT_BC_DELTA > BcTimeStamp)) {
1539     				PortFound = SK_FALSE;
1540     #ifdef xDEBUG
1541     				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1542     					("Port %d received a broadcast at a similar time.\n", i))
1543     #endif	/* DEBUG */
1544     				break;
1545     			}
1546     		}
1547     	}
1548     
1549     #ifdef xDEBUG
1550     	if (PortFound) {
1551     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1552     			("SK_RLMT_CHECK_SWITCH found Port %d receiving the substantially latest broadcast (%d).\n",
1553     				*pSelect,
1554     				BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp))
1555     	}
1556     #endif	/* DEBUG */
1557     
1558     	return (PortFound);
1559     }	/* SkRlmtSelectBcRx */
1560     
1561     
1562     /******************************************************************************
1563      *
1564      *	SkRlmtSelectNotSuspect - select new active port, criteria 2 (CLP)
1565      *
1566      * Description:
1567      *	This routine selects a good port (it is PortUp && !SuspectRx).
1568      *
1569      * Context:
1570      *	runtime, pageable?
1571      *
1572      * Returns:
1573      *	SK_BOOL
1574      */
1575     RLMT_STATIC SK_BOOL	SkRlmtSelectNotSuspect(
1576     SK_AC	*pAC,		/* Adapter Context */
1577     SK_IOC	IoC,		/* I/O Context */
1578     SK_U32	Active,		/* Active port */
1579     SK_U32	PrefPort,	/* Preferred port */
1580     SK_U32	*pSelect)	/* New active port */
1581     {
1582     	SK_U32		i;
1583     	SK_BOOL		PortFound;
1584     
1585     	PortFound = SK_FALSE;
1586     
1587     	/* Select first port that is PortUp && !SuspectRx. */
1588     	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
1589     		if (!pAC->Rlmt.Port[i].PortDown &&
1590     			!(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) {
1591     			*pSelect = i;
1592     			if (!pAC->Rlmt.Port[Active].PortDown &&
1593     				!(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) {
1594     				*pSelect = Active;
1595     			}
1596     			if (!pAC->Rlmt.Port[PrefPort].PortDown &&
1597     				!(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) {
1598     				*pSelect = PrefPort;
1599     			}
1600     			PortFound = SK_TRUE;
1601     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1602     				("SK_RLMT_CHECK_SWITCH found Port %d up and not check RX.\n",
1603     					*pSelect))
1604     			break;
1605     		}
1606     	}
1607     	return (PortFound);
1608     }	/* SkRlmtSelectNotSuspect */
1609     
1610     
1611     /******************************************************************************
1612      *
1613      *	SkRlmtSelectUp - select new active port, criteria 3, 4 (CLP)
1614      *
1615      * Description:
1616      *	This routine selects a port that is up.
1617      *
1618      * Context:
1619      *	runtime, pageable?
1620      *
1621      * Returns:
1622      *	SK_BOOL
1623      */
1624     RLMT_STATIC SK_BOOL	SkRlmtSelectUp(
1625     SK_AC	*pAC,			/* Adapter Context */
1626     SK_IOC	IoC,			/* I/O Context */
1627     SK_U32	Active,			/* Active port */
1628     SK_U32	PrefPort,		/* Preferred port */
1629     SK_U32	*pSelect,		/* New active port */
1630     SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
1631     {
1632     	SK_U32		i;
1633     	SK_BOOL		PortFound;
1634     
1635     	PortFound = SK_FALSE;
1636     
1637     	/* Select first port that is PortUp. */
1638     	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
1639     		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP &&
1640     			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
1641     			*pSelect = i;
1642     			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP &&
1643     				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
1644     				*pSelect = Active;
1645     			}
1646     			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP &&
1647     				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
1648     				*pSelect = PrefPort;
1649     			}
1650     			PortFound = SK_TRUE;
1651     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1652     				("SK_RLMT_CHECK_SWITCH found Port %d up.\n", *pSelect))
1653     			break;
1654     		}
1655     	}
1656     	return (PortFound);
1657     }	/* SkRlmtSelectUp */
1658     
1659     
1660     /******************************************************************************
1661      *
1662      *	SkRlmtSelectGoingUp - select new active port, criteria 5, 6 (CLP)
1663      *
1664      * Description:
1665      *	This routine selects the port that is going up for the longest time.
1666      *
1667      * Context:
1668      *	runtime, pageable?
1669      *
1670      * Returns:
1671      *	SK_BOOL
1672      */
1673     RLMT_STATIC SK_BOOL	SkRlmtSelectGoingUp(
1674     SK_AC	*pAC,			/* Adapter Context */
1675     SK_IOC	IoC,			/* I/O Context */
1676     SK_U32	Active,			/* Active port */
1677     SK_U32	PrefPort,		/* Preferred port */
1678     SK_U32	*pSelect,		/* New active port */
1679     SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
1680     {
1681     	SK_U64		GuTimeStamp;
1682     	SK_U32		i;
1683     	SK_BOOL		PortFound;
1684     
1685     	GuTimeStamp = 0;
1686     	PortFound = SK_FALSE;
1687     
1688     	/* Select port that is PortGoingUp for the longest time. */
1689     	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
1690     		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
1691     			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
1692     			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
1693     			*pSelect = i;
1694     			PortFound = SK_TRUE;
1695     			break;
1696     		}
1697     	}
1698     
1699     	if (!PortFound) {
1700     		return (SK_FALSE);
1701     	}
1702     
1703     	for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
1704     		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
1705     			pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp &&
1706     			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
1707     			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
1708     			*pSelect = i;
1709     		}
1710     	}
1711     
1712     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1713     		("SK_RLMT_CHECK_SWITCH found Port %d going up.\n", *pSelect))
1714     	return (SK_TRUE);
1715     }	/* SkRlmtSelectGoingUp */
1716     
1717     
1718     /******************************************************************************
1719      *
1720      *	SkRlmtSelectDown - select new active port, criteria 7, 8 (CLP)
1721      *
1722      * Description:
1723      *	This routine selects a port that is down.
1724      *
1725      * Context:
1726      *	runtime, pageable?
1727      *
1728      * Returns:
1729      *	SK_BOOL
1730      */
1731     RLMT_STATIC SK_BOOL	SkRlmtSelectDown(
1732     SK_AC	*pAC,			/* Adapter Context */
1733     SK_IOC	IoC,			/* I/O Context */
1734     SK_U32	Active,			/* Active port */
1735     SK_U32	PrefPort,		/* Preferred port */
1736     SK_U32	*pSelect,		/* New active port */
1737     SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
1738     {
1739     	SK_U32		i;
1740     	SK_BOOL		PortFound;
1741     
1742     	PortFound = SK_FALSE;
1743     
1744     	/* Select first port that is PortDown. */
1745     	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
1746     		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN &&
1747     			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
1748     			*pSelect = i;
1749     			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN &&
1750     				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
1751     				*pSelect = Active;
1752     			}
1753     			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN &&
1754     				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
1755     				*pSelect = PrefPort;
1756     			}
1757     			PortFound = SK_TRUE;
1758     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1759     				("SK_RLMT_CHECK_SWITCH found Port %d down.\n", *pSelect))
1760     			break;
1761     		}
1762     	}
1763     	return (PortFound);
1764     }	/* SkRlmtSelectDown */
1765     
1766     
1767     /******************************************************************************
1768      *
1769      *	SkRlmtCheckSwitch - select new active port and switch to it
1770      *
1771      * Description:
1772      *	This routine decides which port should be the active one and queues
1773      *	port switching if necessary.
1774      *
1775      * Context:
1776      *	runtime, pageable?
1777      *
1778      * Returns:
1779      *	Nothing.
1780      */
1781     RLMT_STATIC void	SkRlmtCheckSwitch(
1782     SK_AC	*pAC,	/* Adapter Context */
1783     SK_IOC	IoC,	/* I/O Context */
1784     SK_U32	NetIdx)	/* Net index */
1785     {
1786     	SK_EVPARA	Para;
1787     	SK_U32		Active;
1788     	SK_U32		PrefPort;
1789     	SK_U32		i;
1790     	SK_BOOL		PortFound;
1791     
1792     	Active = pAC->Rlmt.Net[NetIdx].ActivePort;	/* Index of active port. */
1793     	PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort;	/* Index of preferred port. */
1794     	PortFound = SK_FALSE;
1795     	pAC->Rlmt.CheckSwitch = SK_FALSE;
1796     
1797     	if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) {
1798     		/* Last link went down - shut down the net. */
1799     		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN;
1800     		Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP;
1801     		Para.Para32[1] = NetIdx;
1802     		SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para);
1803     
1804     		Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
1805     			Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
1806     		Para.Para32[1] = NetIdx;
1807     		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
1808     		return;
1809     	}	/* pAC->Rlmt.LinksUp == 0 */
1810     	else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 &&
1811     		pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) {
1812     		/* First link came up - get the net up. */
1813     		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP;
1814     
1815     		/*
1816     		 * If pAC->Rlmt.ActivePort != Para.Para32[0],
1817     		 * the DRV switches to the port that came up.
1818     		 */
1819     		for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
1820     			if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
1821     				if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) {
1822     					i = Active;
1823     				}
1824     				if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) {
1825     					i = PrefPort;
1826     				}
1827     				PortFound = SK_TRUE;
1828     				break;
1829     			}
1830     		}
1831     
1832     		if (PortFound) {
1833     			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
1834     			Para.Para32[1] = NetIdx;
1835     			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
1836     
1837     			pAC->Rlmt.Net[NetIdx].ActivePort = i;
1838     			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
1839     			Para.Para32[1] = NetIdx;
1840     			SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para);
1841     
1842     			if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
1843     				(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC,
1844     				pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber,
1845     				SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].
1846     				CurrentMacAddress, &SkRlmtMcAddr)) != NULL) {
1847     				/*
1848     				 * Send announce packet to RLMT multicast address to force
1849     				 * switches to learn the new location of the logical MAC address.
1850     				 */
1851     				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
1852     			}
1853     		}
1854     		else {
1855     			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG);
1856     		}
1857     
1858     		return;
1859     	}	/* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */
1860     	else {	/* Cannot be reached in dual-net mode. */
1861     		Para.Para32[0] = Active;
1862     
1863     		/*
1864     		 * Preselection:
1865     		 *	If RLMT Mode != CheckLinkState
1866     		 *		select port that received a broadcast frame substantially later
1867     		 *		than all other ports
1868     		 *	else select first port that is not SuspectRx
1869     		 *	else select first port that is PortUp
1870     		 *	else select port that is PortGoingUp for the longest time
1871     		 *	else select first port that is PortDown
1872     		 *	else stop.
1873     		 *
1874     		 * For the preselected port:
1875     		 *	If ActivePort is equal in quality, select ActivePort.
1876     		 *
1877     		 *	If PrefPort is equal in quality, select PrefPort.
1878     		 *
1879     		 *	If ActivePort != SelectedPort,
1880     		 *		If old ActivePort is LinkDown,
1881     		 *			SwitchHard
1882     		 *		else
1883     		 *			SwitchSoft
1884     		 */
1885     		if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) {
1886     			if (!PortFound) {
1887     				PortFound = SkRlmtSelectBcRx(
1888     					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
1889     			}
1890     
1891     			if (!PortFound) {
1892     				PortFound = SkRlmtSelectNotSuspect(
1893     					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
1894     			}
1895     		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
1896     
1897     		if (!PortFound) {
1898     			PortFound = SkRlmtSelectUp(
1899     				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
1900     		}
1901     
1902     		if (!PortFound) {
1903     			PortFound = SkRlmtSelectUp(
1904     				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
1905     		}
1906     
1907     		if (!PortFound) {
1908     			PortFound = SkRlmtSelectGoingUp(
1909     				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
1910     		}
1911     
1912     		if (!PortFound) {
1913     			PortFound = SkRlmtSelectGoingUp(
1914     				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
1915     		}
1916     
1917     		if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) {
1918     			if (!PortFound) {
1919     				PortFound = SkRlmtSelectDown(pAC, IoC,
1920     					Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
1921     			}
1922     
1923     			if (!PortFound) {
1924     				PortFound = SkRlmtSelectDown(pAC, IoC,
1925     					Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
1926     			}
1927     		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
1928     
1929     		if (PortFound) {
1930     			if (Para.Para32[1] != Active) {
1931     				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
1932     					("Active: %d, Para1: %d.\n", Active, Para.Para32[1]))
1933     				pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1];
1934     				Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
1935     					Port[Para.Para32[0]]->PortNumber;
1936     				Para.Para32[1] = pAC->Rlmt.Net[NetIdx].
1937     					Port[Para.Para32[1]]->PortNumber;
1938     				SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE);
1939     				if (pAC->Rlmt.Port[Active].LinkDown) {
1940     					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para);
1941     				}
1942     				else {
1943     					SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
1944     					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para);
1945     				}
1946     				Para.Para32[1] = NetIdx;
1947     				Para.Para32[0] =
1948     					pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber;
1949     				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
1950     				Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
1951     					Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
1952     				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
1953     				if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
1954     					(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0],
1955     					SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress,
1956     					&SkRlmtMcAddr)) != NULL) {
1957     					/*
1958     					 * Send announce packet to RLMT multicast address to force
1959     					 * switches to learn the new location of the logical
1960     					 * MAC address.
1961     					 */
1962     					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
1963     				}	/* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */
1964     			}	/* Para.Para32[1] != Active */
1965     		}	/* PortFound */
1966     		else {
1967     			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG);
1968     		}
1969     	}	/* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */
1970     	return;
1971     }	/* SkRlmtCheckSwitch */
1972     
1973     
1974     /******************************************************************************
1975      *
1976      *	SkRlmtCheckSeg - Report if segmentation is detected
1977      *
1978      * Description:
1979      *	This routine checks if the ports see different root bridges and reports
1980      *	segmentation in such a case.
1981      *
1982      * Context:
1983      *	runtime, pageable?
1984      *
1985      * Returns:
1986      *	Nothing.
1987      */
1988     RLMT_STATIC void	SkRlmtCheckSeg(
1989     SK_AC	*pAC,	/* Adapter Context */
1990     SK_IOC	IoC,	/* I/O Context */
1991     SK_U32	NetIdx)	/* Net number */
1992     {
1993     	SK_EVPARA	Para;
1994     	SK_RLMT_NET	*pNet;
1995     	SK_U32		i, j;
1996     	SK_BOOL		Equal;
1997     
1998     	pNet = &pAC->Rlmt.Net[NetIdx];
1999     	pNet->RootIdSet = SK_FALSE;
2000     	Equal = SK_TRUE;
2001     
2002     	for (i = 0; i < pNet->NumPorts; i++) {
2003     		if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) {
2004     			continue;
2005     		}
2006     
2007     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
2008     			("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i,
2009     				pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1],
2010     				pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3],
2011     				pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5],
2012     				pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7]))
2013     
2014     		if (!pNet->RootIdSet) {
2015     			pNet->Root = pNet->Port[i]->Root;
2016     			pNet->RootIdSet = SK_TRUE;
2017     			continue;
2018     		}
2019     
2020     		for (j = 0; j < 8; j ++) {
2021     			Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j];
2022     			if (!Equal) {
2023     				break;
2024     			}
2025     		}
2026     		
2027     		if (!Equal) {
2028     			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG);
2029     			Para.Para32[0] = NetIdx;
2030     			Para.Para32[1] = (SK_U32)-1;
2031     			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para);
2032     
2033     			pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG;
2034     
2035     			/* 2000-03-06 RA: New. */
2036     			Para.Para32[0] = NetIdx;
2037     			Para.Para32[1] = (SK_U32)-1;
2038     			SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL,
2039     				SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
2040     			break;
2041     		}
2042     	}	/* for (i = 0; i < pNet->NumPorts; i++) */
2043     
2044     	/* 2000-03-06 RA: Moved here. */
2045     	/* Segmentation check not running anymore. */
2046     	pNet->CheckingState &= ~SK_RLMT_RCS_SEG;
2047     
2048     }	/* SkRlmtCheckSeg */
2049     
2050     
2051     /******************************************************************************
2052      *
2053      *	SkRlmtPortStart - initialize port variables and start port
2054      *
2055      * Description:
2056      *	This routine initializes a port's variables and issues a PORT_START
2057      *	to the HWAC module.  This handles retries if the start fails or the
2058      *	link eventually goes down.
2059      *
2060      * Context:
2061      *	runtime, pageable?
2062      *
2063      * Returns:
2064      *	Nothing
2065      */
2066     RLMT_STATIC void	SkRlmtPortStart(
2067     SK_AC	*pAC,		/* Adapter Context */
2068     SK_IOC	IoC,		/* I/O Context */
2069     SK_U32	PortNumber)	/* Port number */
2070     {
2071     	SK_EVPARA	Para;
2072     
2073     	pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN;
2074     	pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE;
2075     	pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE;
2076     	pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE;
2077     	pAC->Rlmt.Port[PortNumber].CheckingState = 0;
2078     	pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
2079     	Para.Para32[0] = PortNumber;
2080     	Para.Para32[1] = (SK_U32)-1;
2081     	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
2082     }	/* SkRlmtPortStart */
2083     
2084     
2085     /******************************************************************************
2086      *
2087      *	SkRlmtEvtPortStartTim - PORT_START_TIM
2088      *
2089      * Description:
2090      *	This routine handles PORT_START_TIM events.
2091      *
2092      * Context:
2093      *	runtime, pageable?
2094      *	may be called after SK_INIT_IO
2095      *
2096      * Returns:
2097      *	Nothing
2098      */
2099     RLMT_STATIC void	SkRlmtEvtPortStartTim(
2100     SK_AC		*pAC,	/* Adapter Context */
2101     SK_IOC		IoC,	/* I/O Context */
2102     SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
2103     {
2104     	SK_U32			i;
2105     
2106     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2107     		("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0]))
2108     
2109     		if (Para.Para32[1] != (SK_U32)-1) {
2110     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2111     			("Bad Parameter.\n"))
2112     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2113     			("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n"))
2114     		return;
2115     	}
2116     
2117     	/*
2118     	 * Used to start non-preferred ports if the preferred one
2119     	 * does not come up.
2120     	 * This timeout needs only be set when starting the first
2121     	 * (preferred) port.
2122     	 */
2123     	if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
2124     		/* PORT_START failed. */
2125     		for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) {
2126     			if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) {
2127     				SkRlmtPortStart(pAC, IoC,
2128     					pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber);
2129     			}
2130     		}
2131     	}
2132     
2133     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2134     		("SK_RLMT_PORTSTART_TIMEOUT Event END.\n"))
2135     }	/* SkRlmtEvtPortStartTim */
2136     
2137     
2138     /******************************************************************************
2139      *
2140      *	SkRlmtEvtLinkUp - LINK_UP
2141      *
2142      * Description:
2143      *	This routine handles LLINK_UP events.
2144      *
2145      * Context:
2146      *	runtime, pageable?
2147      *	may be called after SK_INIT_IO
2148      *
2149      * Returns:
2150      *	Nothing
2151      */
2152     RLMT_STATIC void	SkRlmtEvtLinkUp(
2153     SK_AC		*pAC,	/* Adapter Context */
2154     SK_IOC		IoC,	/* I/O Context */
2155     SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */
2156     {
2157     	SK_U32			i;
2158     	SK_RLMT_PORT	*pRPort;
2159     	SK_EVPARA		Para2;
2160     
2161     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2162     		("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0]))
2163     
2164     	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
2165     	if (!pRPort->PortStarted) {
2166     		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG);
2167     
2168     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2169     				("SK_RLMT_LINK_UP Event EMPTY.\n"))
2170     		return;
2171     	}
2172     
2173     	if (!pRPort->LinkDown) {
2174     		/* RA;:;: Any better solution? */
2175     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2176     			("SK_RLMT_LINK_UP Event EMPTY.\n"))
2177     		return;
2178     	}
2179     
2180     	SkTimerStop(pAC, IoC, &pRPort->UpTimer);
2181     	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
2182     	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
2183     
2184     	/* Do something if timer already fired? */
2185     
2186     	pRPort->LinkDown = SK_FALSE;
2187     	pRPort->PortState = SK_RLMT_PS_GOING_UP;
2188     	pRPort->GuTimeStamp = SkOsGetTime(pAC);
2189     	pRPort->BcTimeStamp = 0;
2190     	pRPort->Net->LinksUp++;
2191     	if (pRPort->Net->LinksUp == 1) {
2192     		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE);
2193     	}
2194     	else {
2195     		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
2196     	}
2197     
2198     	for (i = 0; i < pRPort->Net->NumPorts; i++) {
2199     		if (!pRPort->Net->Port[i]->PortStarted) {
2200     			SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber);
2201     		}
2202     	}
2203     
2204     	SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
2205     
2206     	if (pRPort->Net->LinksUp >= 2) {
2207     		if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
2208     			/* Build the check chain. */
2209     			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
2210     		}
2211     	}
2212     
2213     	/* If the first link comes up, start the periodical RLMT timeout. */
2214     	if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 &&
2215     		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) {
2216     		Para2.Para32[0] = pRPort->Net->NetNumber;
2217     		Para2.Para32[1] = (SK_U32)-1;
2218     		SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer,
2219     			pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2);
2220     	}
2221     
2222     	Para2 = Para;
2223     	Para2.Para32[1] = (SK_U32)-1;
2224     	SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
2225     		SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2);
2226     	
2227     	/* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */
2228     	if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
2229     		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 &&
2230     		(Para2.pParaPtr =
2231     			SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE,
2232     			&pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr)
2233     		) != NULL) {
2234     		/* Send "new" packet to RLMT multicast address. */
2235     		SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
2236     	}
2237     
2238     	if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) {
2239     		if ((Para2.pParaPtr =
2240     			SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) {
2241     			pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE;
2242     			pRPort->Net->CheckingState |=
2243     				SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
2244     
2245     			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
2246     
2247     			Para.Para32[1] = (SK_U32)-1;
2248     			SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer,
2249     				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
2250     		}
2251     	}
2252     
2253     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2254     		("SK_RLMT_LINK_UP Event END.\n"))
2255     }	/* SkRlmtEvtLinkUp */
2256     
2257     
2258     /******************************************************************************
2259      *
2260      *	SkRlmtEvtPortUpTim - PORT_UP_TIM
2261      *
2262      * Description:
2263      *	This routine handles PORT_UP_TIM events.
2264      *
2265      * Context:
2266      *	runtime, pageable?
2267      *	may be called after SK_INIT_IO
2268      *
2269      * Returns:
2270      *	Nothing
2271      */
2272     RLMT_STATIC void	SkRlmtEvtPortUpTim(
2273     SK_AC		*pAC,	/* Adapter Context */
2274     SK_IOC		IoC,	/* I/O Context */
2275     SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
2276     {
2277     	SK_RLMT_PORT	*pRPort;
2278     
2279     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2280     		("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0]))
2281     
2282     	if (Para.Para32[1] != (SK_U32)-1) {
2283     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2284     			("Bad Parameter.\n"))
2285     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2286     			("SK_RLMT_PORTUP_TIM Event EMPTY.\n"))
2287     		return;
2288     	}
2289     
2290     	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
2291     	if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) {
2292     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2293     			("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0]))
2294     		return;
2295     	}
2296     
2297     	pRPort->PortDown = SK_FALSE;
2298     	pRPort->PortState = SK_RLMT_PS_UP;
2299     	pRPort->Net->PortsUp++;
2300     	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
2301     		if (pAC->Rlmt.NumNets <= 1) {
2302     			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
2303     		}
2304     		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para);
2305     	}
2306     
2307     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2308     		("SK_RLMT_PORTUP_TIM Event END.\n"))
2309     }	/* SkRlmtEvtPortUpTim */
2310     
2311     
2312     /******************************************************************************
2313      *
2314      *	SkRlmtEvtPortDownTim - PORT_DOWN_*
2315      *
2316      * Description:
2317      *	This routine handles PORT_DOWN_* events.
2318      *
2319      * Context:
2320      *	runtime, pageable?
2321      *	may be called after SK_INIT_IO
2322      *
2323      * Returns:
2324      *	Nothing
2325      */
2326     RLMT_STATIC void	SkRlmtEvtPortDownX(
2327     SK_AC		*pAC,	/* Adapter Context */
2328     SK_IOC		IoC,	/* I/O Context */
2329     SK_U32		Event,	/* Event code */
2330     SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
2331     {
2332     	SK_RLMT_PORT	*pRPort;
2333     
2334     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2335     		("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n",
2336     			Para.Para32[0], Event))
2337     
2338     	if (Para.Para32[1] != (SK_U32)-1) {
2339     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2340     			("Bad Parameter.\n"))
2341     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2342     			("SK_RLMT_PORTDOWN* Event EMPTY.\n"))
2343     		return;
2344     	}
2345     
2346     	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
2347     	if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM &&
2348     		!(pRPort->CheckingState & SK_RLMT_PCS_TX))) {
2349     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2350     			("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event))
2351     		return;
2352     	}
2353     	
2354     	/* Stop port's timers. */
2355     	SkTimerStop(pAC, IoC, &pRPort->UpTimer);
2356     	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
2357     	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
2358     
2359     	if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) {
2360     		pRPort->PortState = SK_RLMT_PS_DOWN;
2361     	}
2362     
2363     	if (!pRPort->PortDown) {
2364     		pRPort->Net->PortsUp--;
2365     		pRPort->PortDown = SK_TRUE;
2366     		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para);
2367     	}
2368     
2369     	pRPort->PacketsPerTimeSlot = 0;
2370     	/* pRPort->DataPacketsPerTimeSlot = 0; */
2371     	pRPort->BpduPacketsPerTimeSlot = 0;
2372     
2373     	/*
2374     	 * RA;:;: To be checked:
2375     	 * - actions at RLMT_STOP: We should not switch anymore.
2376     	 */
2377     	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
2378     		if (Para.Para32[0] ==
2379     			pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) {
2380     			/* Active Port went down. */
2381     			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
2382     		}
2383     	}
2384     
2385     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2386     		("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event))
2387     }	/* SkRlmtEvtPortDownX */
2388     
2389     
2390     /******************************************************************************
2391      *
2392      *	SkRlmtEvtLinkDown - LINK_DOWN
2393      *
2394      * Description:
2395      *	This routine handles LINK_DOWN events.
2396      *
2397      * Context:
2398      *	runtime, pageable?
2399      *	may be called after SK_INIT_IO
2400      *
2401      * Returns:
2402      *	Nothing
2403      */
2404     RLMT_STATIC void	SkRlmtEvtLinkDown(
2405     SK_AC		*pAC,	/* Adapter Context */
2406     SK_IOC		IoC,	/* I/O Context */
2407     SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */
2408     {
2409     	SK_RLMT_PORT	*pRPort;
2410     
2411     	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
2412     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2413     		("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0]))
2414     
2415     	if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
2416     		pRPort->Net->LinksUp--;
2417     		pRPort->LinkDown = SK_TRUE;
2418     		pRPort->PortState = SK_RLMT_PS_LINK_DOWN;
2419     		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF);
2420     
2421     		if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) {
2422     			/* Build the check chain. */
2423     			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
2424     		}
2425     
2426     		/* Ensure that port is marked down. */
2427     		Para.Para32[1] = -1;
2428     		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para);
2429     	}
2430     
2431     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2432     		("SK_RLMT_LINK_DOWN Event END.\n"))
2433     }	/* SkRlmtEvtLinkDown */
2434     
2435     
2436     /******************************************************************************
2437      *
2438      *	SkRlmtEvtPortAddr - PORT_ADDR
2439      *
2440      * Description:
2441      *	This routine handles PORT_ADDR events.
2442      *
2443      * Context:
2444      *	runtime, pageable?
2445      *	may be called after SK_INIT_IO
2446      *
2447      * Returns:
2448      *	Nothing
2449      */
2450     RLMT_STATIC void	SkRlmtEvtPortAddr(
2451     SK_AC		*pAC,	/* Adapter Context */
2452     SK_IOC		IoC,	/* I/O Context */
2453     SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
2454     {
2455     	SK_U32			i, j;
2456     	SK_RLMT_PORT	*pRPort;
2457     	SK_MAC_ADDR		*pOldMacAddr;
2458     	SK_MAC_ADDR		*pNewMacAddr;
2459     
2460     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2461     		("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0]))
2462     
2463     	if (Para.Para32[1] != (SK_U32)-1) {
2464     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2465     			("Bad Parameter.\n"))
2466     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2467     			("SK_RLMT_PORT_ADDR Event EMPTY.\n"))
2468     		return;
2469     	}
2470     
2471     	/* Port's physical MAC address changed. */
2472     	pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress;
2473     	pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress;
2474     
2475     	/*
2476     	 * NOTE: This is not scalable for solutions where ports are
2477     	 *	 checked remotely.  There, we need to send an RLMT
2478     	 *	 address change packet - and how do we ensure delivery?
2479     	 */
2480     	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
2481     		pRPort = &pAC->Rlmt.Port[i];
2482     		for (j = 0; j < pRPort->PortsChecked; j++) {
2483     			if (SK_ADDR_EQUAL(
2484     				pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) {
2485     				pRPort->PortCheck[j].CheckAddr = *pNewMacAddr;
2486     			}
2487     		}
2488     	}
2489     
2490     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2491     			("SK_RLMT_PORT_ADDR Event END.\n"))
2492     }	/* SkRlmtEvtPortAddr */
2493     
2494     
2495     /******************************************************************************
2496      *
2497      *	SkRlmtEvtStart - START
2498      *
2499      * Description:
2500      *	This routine handles START events.
2501      *
2502      * Context:
2503      *	runtime, pageable?
2504      *	may be called after SK_INIT_IO
2505      *
2506      * Returns:
2507      *	Nothing
2508      */
2509     RLMT_STATIC void	SkRlmtEvtStart(
2510     SK_AC		*pAC,	/* Adapter Context */
2511     SK_IOC		IoC,	/* I/O Context */
2512     SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
2513     {
2514     	SK_EVPARA	Para2;
2515     	SK_U32		PortIdx;
2516     	SK_U32		PortNumber;
2517     
2518     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2519     		("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0]))
2520     
2521     	if (Para.Para32[1] != (SK_U32)-1) {
2522     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2523     			("Bad Parameter.\n"))
2524     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2525     			("SK_RLMT_START Event EMPTY.\n"))
2526     		return;
2527     	}
2528     
2529     	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
2530     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2531     			("Bad NetNumber %d.\n", Para.Para32[0]))
2532     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2533     			("SK_RLMT_START Event EMPTY.\n"))
2534     		return;
2535     	}
2536     
2537     	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) {
2538     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2539     			("SK_RLMT_START Event EMPTY.\n"))
2540     		return;
2541     	}
2542     
2543     	if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) {
2544     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2545     			("All nets should have been started.\n"))
2546     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2547     			("SK_RLMT_START Event EMPTY.\n"))
2548     		return;
2549     	}
2550     
2551     	if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >=
2552     		pAC->Rlmt.Net[Para.Para32[0]].NumPorts) {
2553     		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG);
2554     
2555     		/* Change PrefPort to internal default. */
2556     		Para2.Para32[0] = 0xFFFFFFFF;
2557     		Para2.Para32[1] = Para.Para32[0];
2558     		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2);
2559     	}
2560     
2561     	PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort;
2562     	PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber;
2563     
2564     	pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0;
2565     	pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0;
2566     	pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0;
2567     	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN;
2568     
2569     	/* Start preferred port. */
2570     	SkRlmtPortStart(pAC, IoC, PortNumber);
2571     
2572     	/* Start Timer (for first port only). */
2573     	Para2.Para32[0] = PortNumber;
2574     	Para2.Para32[1] = (SK_U32)-1;
2575     	SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer,
2576     		SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2);
2577     
2578     	pAC->Rlmt.NetsStarted++;
2579     
2580     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2581     			("SK_RLMT_START Event END.\n"))
2582     }	/* SkRlmtEvtStart */
2583     
2584     
2585     /******************************************************************************
2586      *
2587      *	SkRlmtEvtStop - STOP
2588      *
2589      * Description:
2590      *	This routine handles STOP events.
2591      *
2592      * Context:
2593      *	runtime, pageable?
2594      *	may be called after SK_INIT_IO
2595      *
2596      * Returns:
2597      *	Nothing
2598      */
2599     RLMT_STATIC void	SkRlmtEvtStop(
2600     SK_AC		*pAC,	/* Adapter Context */
2601     SK_IOC		IoC,	/* I/O Context */
2602     SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
2603     {
2604     	SK_EVPARA	Para2;
2605     	SK_U32		PortNumber;
2606     	SK_U32		i;
2607     
2608     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2609     		("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0]))
2610     
2611     	if (Para.Para32[1] != (SK_U32)-1) {
2612     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2613     			("Bad Parameter.\n"))
2614     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2615     			("SK_RLMT_STOP Event EMPTY.\n"))
2616     		return;
2617     	}
2618     
2619     	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
2620     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2621     			("Bad NetNumber %d.\n", Para.Para32[0]))
2622     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2623     			("SK_RLMT_STOP Event EMPTY.\n"))
2624     		return;
2625     	}
2626     
2627     	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) {
2628     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2629     			("SK_RLMT_STOP Event EMPTY.\n"))
2630     		return;
2631     	}
2632     
2633     	if (pAC->Rlmt.NetsStarted == 0) {
2634     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2635     			("All nets are stopped.\n"))
2636     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2637     			("SK_RLMT_STOP Event EMPTY.\n"))
2638     		return;
2639     	}
2640     
2641     	/* Stop RLMT timers. */
2642     	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer); 
2643     	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer);
2644     
2645     	/* Stop net. */
2646     	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT;
2647     	pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE;
2648     	Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL;
2649     	Para2.Para32[1] = Para.Para32[0];			/* Net# */
2650     	SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2);
2651     
2652     	/* Stop ports. */
2653     	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
2654     		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
2655     		if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) {
2656     			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer);
2657     			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer);
2658     			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer);
2659     
2660     			pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT;
2661     			pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
2662     			pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE;
2663     			Para2.Para32[0] = PortNumber;
2664     			Para2.Para32[1] = (SK_U32)-1;
2665     			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2);
2666     		}
2667     	}
2668     
2669     	pAC->Rlmt.NetsStarted--;
2670     
2671     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2672     		("SK_RLMT_STOP Event END.\n"))
2673     }	/* SkRlmtEvtStop */
2674     
2675     
2676     /******************************************************************************
2677      *
2678      *	SkRlmtEvtTim - TIM
2679      *
2680      * Description:
2681      *	This routine handles TIM events.
2682      *
2683      * Context:
2684      *	runtime, pageable?
2685      *	may be called after SK_INIT_IO
2686      *
2687      * Returns:
2688      *	Nothing
2689      */
2690     RLMT_STATIC void	SkRlmtEvtTim(
2691     SK_AC		*pAC,	/* Adapter Context */
2692     SK_IOC		IoC,	/* I/O Context */
2693     SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
2694     {
2695     	SK_RLMT_PORT	*pRPort;
2696     	SK_U32			Timeout;
2697     	SK_U32			NewTimeout;
2698     	SK_U32			PortNumber;
2699     	SK_U32			i;
2700     
2701     #if 0
2702     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2703     		("SK_RLMT_TIM Event BEGIN.\n"))
2704     #endif	/* 0 */
2705     
2706     	if (Para.Para32[1] != (SK_U32)-1) {
2707     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2708     			("Bad Parameter.\n"))
2709     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2710     			("SK_RLMT_TIM Event EMPTY.\n"))
2711     		return;
2712     	}
2713     
2714     	if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 ||
2715     		pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) {
2716     		/* Mode changed or all links down: No more link checking. */
2717     		return;
2718     	}
2719     
2720     #if 0
2721     	pAC->Rlmt.SwitchCheckCounter--;
2722     	if (pAC->Rlmt.SwitchCheckCounter == 0) {
2723     		pAC->Rlmt.SwitchCheckCounter;
2724     	}
2725     #endif	/* 0 */
2726     
2727     	NewTimeout = SK_RLMT_DEF_TO_VAL;
2728     	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
2729     		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
2730     		pRPort = &pAC->Rlmt.Port[PortNumber];
2731     		if (!pRPort->LinkDown) {
2732     			Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber);
2733     			if (Timeout < NewTimeout) {
2734     				NewTimeout = Timeout;
2735     			}
2736     
2737     			/*
2738     			 * These counters should be set to 0 for all ports before the
2739     			 * first frame is sent in the next loop.
2740     			 */
2741     			pRPort->PacketsPerTimeSlot = 0;
2742     			/* pRPort->DataPacketsPerTimeSlot = 0; */
2743     			pRPort->BpduPacketsPerTimeSlot = 0;
2744     		}
2745     	}
2746     	pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout;
2747     
2748     	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) {
2749     		/*
2750     		 * If checking remote ports, also send packets if
2751     		 *   (LinksUp == 1) &&
2752     		 *   this port checks at least one (remote) port.
2753     		 */
2754     
2755     		/*
2756     		 * Must be new loop, as SkRlmtCheckPort can request to
2757     		 * check segmentation when e.g. checking the last port.
2758     		 */
2759     		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
2760     			if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) {
2761     				SkRlmtSend(pAC, IoC,
2762     					pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber);
2763     			}
2764     		}
2765     	}
2766     
2767     	SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer,
2768     		pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM,
2769     		Para);
2770     
2771     	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 &&
2772     		(pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) &&
2773     		(pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) {
2774     		SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer,
2775     			SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
2776     		pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG;
2777     		pAC->Rlmt.Net[Para.Para32[0]].CheckingState |=
2778     			SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
2779     	}
2780     
2781     #if 0
2782     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2783     			("SK_RLMT_TIM Event END.\n"))
2784     #endif	/* 0 */
2785     }	/* SkRlmtEvtTim */
2786     
2787     
2788     /******************************************************************************
2789      *
2790      *	SkRlmtEvtSegTim - SEG_TIM
2791      *
2792      * Description:
2793      *	This routine handles SEG_TIM events.
2794      *
2795      * Context:
2796      *	runtime, pageable?
2797      *	may be called after SK_INIT_IO
2798      *
2799      * Returns:
2800      *	Nothing
2801      */
2802     RLMT_STATIC void	SkRlmtEvtSegTim(
2803     SK_AC		*pAC,	/* Adapter Context */
2804     SK_IOC		IoC,	/* I/O Context */
2805     SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
2806     {
2807     #ifdef XDEBUG
2808     	int j;
2809     #endif	/* DEBUG */
2810     
2811     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2812     		("SK_RLMT_SEG_TIM Event BEGIN.\n"))
2813     
2814     	if (Para.Para32[1] != (SK_U32)-1) {
2815     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2816     			("Bad Parameter.\n"))
2817     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2818     			("SK_RLMT_SEG_TIM Event EMPTY.\n"))
2819     		return;
2820     	}
2821     
2822     #ifdef xDEBUG
2823     	for (j = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) {
2824     		SK_ADDR_PORT	*pAPort;
2825     		SK_U32			k;
2826     		SK_U16			*InAddr;
2827     		SK_U8			InAddr8[6];
2828     
2829     		InAddr = (SK_U16 *)&InAddr8[0];
2830     		pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort;
2831     		for (k = 0; k < pAPort->NextExactMatchRlmt; k++) {
2832     			/* Get exact match address k from port j. */
2833     			XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
2834     				XM_EXM(k), InAddr);
2835     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2836     				("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
2837     					k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
2838     					InAddr8[0], InAddr8[1], InAddr8[2],
2839     					InAddr8[3], InAddr8[4], InAddr8[5],
2840     					pAPort->Exact[k].a[0], pAPort->Exact[k].a[1],
2841     					pAPort->Exact[k].a[2], pAPort->Exact[k].a[3],
2842     					pAPort->Exact[k].a[4], pAPort->Exact[k].a[5]))
2843     		}
2844     	}
2845     #endif	/* DEBUG */
2846     				   
2847     	SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]);
2848     
2849     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2850     			("SK_RLMT_SEG_TIM Event END.\n"))
2851     }	/* SkRlmtEvtSegTim */
2852     
2853     
2854     /******************************************************************************
2855      *
2856      *	SkRlmtEvtPacketRx - PACKET_RECEIVED
2857      *
2858      * Description:
2859      *	This routine handles PACKET_RECEIVED events.
2860      *
2861      * Context:
2862      *	runtime, pageable?
2863      *	may be called after SK_INIT_IO
2864      *
2865      * Returns:
2866      *	Nothing
2867      */
2868     RLMT_STATIC void	SkRlmtEvtPacketRx(
2869     SK_AC		*pAC,	/* Adapter Context */
2870     SK_IOC		IoC,	/* I/O Context */
2871     SK_EVPARA	Para)	/* SK_MBUF *pMb */
2872     {
2873     	SK_MBUF	*pMb;
2874     	SK_MBUF	*pNextMb;
2875     	SK_U32	NetNumber;
2876     
2877     #if 0
2878     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2879     		("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n"))
2880     #endif	/* 0 */
2881     
2882     	/* Should we ignore frames during port switching? */
2883     
2884     #ifdef DEBUG
2885     	pMb = Para.pParaPtr;
2886     	if (pMb == NULL) {
2887     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n"))
2888     	}
2889     	else if (pMb->pNext != NULL) {
2890     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2891     			("More than one mbuf or pMb->pNext not set.\n"))
2892     	}
2893     #endif	/* DEBUG */
2894     
2895     	for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) {
2896     		pNextMb = pMb->pNext;
2897     		pMb->pNext = NULL;
2898     
2899     		NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber;
2900     		if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) {
2901     			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
2902     		}
2903     		else {
2904     			SkRlmtPacketReceive(pAC, IoC, pMb);
2905     		}
2906     	}
2907     
2908     #if 0
2909     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2910     		("SK_RLMT_PACKET_RECEIVED Event END.\n"))
2911     #endif	/* 0 */
2912     }	/* SkRlmtEvtPacketRx */
2913     
2914     
2915     /******************************************************************************
2916      *
2917      *	SkRlmtEvtStatsClear - STATS_CLEAR
2918      *
2919      * Description:
2920      *	This routine handles STATS_CLEAR events.
2921      *
2922      * Context:
2923      *	runtime, pageable?
2924      *	may be called after SK_INIT_IO
2925      *
2926      * Returns:
2927      *	Nothing
2928      */
2929     RLMT_STATIC void	SkRlmtEvtStatsClear(
2930     SK_AC		*pAC,	/* Adapter Context */
2931     SK_IOC		IoC,	/* I/O Context */
2932     SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
2933     {
2934     	SK_U32			i;
2935     	SK_RLMT_PORT	*pRPort;
2936     
2937     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2938     		("SK_RLMT_STATS_CLEAR Event BEGIN.\n"))
2939     
2940     	if (Para.Para32[1] != (SK_U32)-1) {
2941     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2942     			("Bad Parameter.\n"))
2943     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2944     			("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
2945     		return;
2946     	}
2947     
2948     	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
2949     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2950     			("Bad NetNumber %d.\n", Para.Para32[0]))
2951     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2952     			("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
2953     		return;
2954     	}
2955     
2956     	/* Clear statistics for logical and physical ports. */
2957     	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
2958     		pRPort =
2959     			&pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber];
2960     		pRPort->TxHelloCts = 0;
2961     		pRPort->RxHelloCts = 0;
2962     		pRPort->TxSpHelloReqCts = 0;
2963     		pRPort->RxSpHelloCts = 0;
2964     	}
2965     
2966     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2967     		("SK_RLMT_STATS_CLEAR Event END.\n"))
2968     }	/* SkRlmtEvtStatsClear */
2969     
2970     
2971     /******************************************************************************
2972      *
2973      *	SkRlmtEvtStatsUpdate - STATS_UPDATE
2974      *
2975      * Description:
2976      *	This routine handles STATS_UPDATE events.
2977      *
2978      * Context:
2979      *	runtime, pageable?
2980      *	may be called after SK_INIT_IO
2981      *
2982      * Returns:
2983      *	Nothing
2984      */
2985     RLMT_STATIC void	SkRlmtEvtStatsUpdate(
2986     SK_AC		*pAC,	/* Adapter Context */
2987     SK_IOC		IoC,	/* I/O Context */
2988     SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
2989     {
2990     	if (Para.Para32[1] != (SK_U32)-1) {
2991     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2992     			("Bad Parameter.\n"))
2993     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
2994     			("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
2995     		return;
2996     	}
2997     
2998     	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
2999     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3000     			("Bad NetNumber %d.\n", Para.Para32[0]))
3001     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3002     			("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
3003     		return;
3004     	}
3005     
3006     #if 0
3007     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3008     		("SK_RLMT_STATS_UPDATE Event BEGIN.\n"))
3009     
3010     	/* Update statistics - currently always up-to-date. */
3011     
3012     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3013     		("SK_RLMT_STATS_UPDATE Event END.\n"))
3014     #endif	/* 0 */
3015     }	/* SkRlmtEvtStatsUpdate */
3016     
3017     
3018     /******************************************************************************
3019      *
3020      *	SkRlmtEvtPrefportChange - PREFPORT_CHANGE
3021      *
3022      * Description:
3023      *	This routine handles PREFPORT_CHANGE events.
3024      *
3025      * Context:
3026      *	runtime, pageable?
3027      *	may be called after SK_INIT_IO
3028      *
3029      * Returns:
3030      *	Nothing
3031      */
3032     RLMT_STATIC void	SkRlmtEvtPrefportChange(
3033     SK_AC		*pAC,	/* Adapter Context */
3034     SK_IOC		IoC,	/* I/O Context */
3035     SK_EVPARA	Para)	/* SK_U32 PortIndex; SK_U32 NetNumber */
3036     {
3037     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3038     		("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0]))
3039     
3040     	if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
3041     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3042     			("Bad NetNumber %d.\n", Para.Para32[1]))
3043     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3044     			("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
3045     		return;
3046     	}
3047     
3048     	/* 0xFFFFFFFF == auto-mode. */
3049     	if (Para.Para32[0] == 0xFFFFFFFF) {
3050     		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT;
3051     	}
3052     	else {
3053     		if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) {
3054     			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG);
3055     
3056     			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3057     				("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
3058     			return;
3059     		}
3060     
3061     		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0];
3062     	}
3063     
3064     	pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0];
3065     
3066     	if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
3067     		SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]);
3068     	}
3069     
3070     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3071     		("SK_RLMT_PREFPORT_CHANGE Event END.\n"))
3072     }	/* SkRlmtEvtPrefportChange */
3073     
3074     
3075     /******************************************************************************
3076      *
3077      *	SkRlmtEvtSetNets - SET_NETS
3078      *
3079      * Description:
3080      *	This routine handles SET_NETS events.
3081      *
3082      * Context:
3083      *	runtime, pageable?
3084      *	may be called after SK_INIT_IO
3085      *
3086      * Returns:
3087      *	Nothing
3088      */
3089     RLMT_STATIC void	SkRlmtEvtSetNets(
3090     SK_AC		*pAC,	/* Adapter Context */
3091     SK_IOC		IoC,	/* I/O Context */
3092     SK_EVPARA	Para)	/* SK_U32 NumNets; SK_U32 -1 */
3093     {
3094     	int i;
3095     
3096     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3097     		("SK_RLMT_SET_NETS Event BEGIN.\n"))
3098     
3099     	if (Para.Para32[1] != (SK_U32)-1) {
3100     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3101     			("Bad Parameter.\n"))
3102     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3103     			("SK_RLMT_SET_NETS Event EMPTY.\n"))
3104     		return;
3105     	}
3106     
3107     	if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS ||
3108     		Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) {
3109     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3110     			("Bad number of nets: %d.\n", Para.Para32[0]))
3111     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3112     			("SK_RLMT_SET_NETS Event EMPTY.\n"))
3113     		return;
3114     	}
3115     
3116     	if (Para.Para32[0] == pAC->Rlmt.NumNets) {	/* No change. */
3117     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3118     			("SK_RLMT_SET_NETS Event EMPTY.\n"))
3119     		return;
3120     	}
3121     
3122     	/* Entering and leaving dual mode only allowed while nets are stopped. */
3123     	if (pAC->Rlmt.NetsStarted > 0) {
3124     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3125     			("Changing dual mode only allowed while all nets are stopped.\n"))
3126     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3127     			("SK_RLMT_SET_NETS Event EMPTY.\n"))
3128     		return;
3129     	}
3130     
3131     	if (Para.Para32[0] == 1) {
3132     		if (pAC->Rlmt.NumNets > 1) {
3133     			/* Clear logical MAC addr from second net's active port. */
3134     			(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
3135     				Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL);
3136     			pAC->Rlmt.Net[1].NumPorts = 0;
3137     		}
3138     
3139     		pAC->Rlmt.NumNets = Para.Para32[0];
3140     		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
3141     			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
3142     			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
3143     			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */
3144     			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
3145     			/* Just assuming. */
3146     			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
3147     			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
3148     			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
3149     			pAC->Rlmt.Net[i].NetNumber = i;
3150     		}
3151     
3152     		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0];
3153     		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
3154     
3155     		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
3156     
3157     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3158     			("RLMT: Changed to one net with two ports.\n"))
3159     	}
3160     	else if (Para.Para32[0] == 2) {
3161     		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1];
3162     		pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1;
3163     		pAC->Rlmt.Net[0].NumPorts =
3164     			pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts;
3165     		
3166     		pAC->Rlmt.NumNets = Para.Para32[0];
3167     		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
3168     			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
3169     			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
3170     			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */
3171     			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
3172     			/* Just assuming. */
3173     			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
3174     			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
3175     			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
3176     
3177     			pAC->Rlmt.Net[i].NetNumber = i;
3178     		}
3179     
3180     		/* Set logical MAC addr on second net's active port. */
3181     		(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
3182     			Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL);
3183     
3184     		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
3185     
3186     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3187     			("RLMT: Changed to two nets with one port each.\n"))
3188     	}
3189     	else {
3190     		/* Not implemented for more than two nets. */
3191     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3192     			("SetNets not implemented for more than two nets.\n"))
3193     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3194     			("SK_RLMT_SET_NETS Event EMPTY.\n"))
3195     		return;
3196     	}
3197     
3198     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3199     		("SK_RLMT_SET_NETS Event END.\n"))
3200     }	/* SkRlmtSetNets */
3201     
3202     
3203     /******************************************************************************
3204      *
3205      *	SkRlmtEvtModeChange - MODE_CHANGE
3206      *
3207      * Description:
3208      *	This routine handles MODE_CHANGE events.
3209      *
3210      * Context:
3211      *	runtime, pageable?
3212      *	may be called after SK_INIT_IO
3213      *
3214      * Returns:
3215      *	Nothing
3216      */
3217     RLMT_STATIC void	SkRlmtEvtModeChange(
3218     SK_AC		*pAC,	/* Adapter Context */
3219     SK_IOC		IoC,	/* I/O Context */
3220     SK_EVPARA	Para)	/* SK_U32 NewMode; SK_U32 NetNumber */
3221     {
3222     	SK_EVPARA	Para2;
3223     	SK_U32		i;
3224     	SK_U32		PrevRlmtMode;
3225     
3226     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3227     		("SK_RLMT_MODE_CHANGE Event BEGIN.\n"))
3228     
3229     	if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
3230     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3231     			("Bad NetNumber %d.\n", Para.Para32[1]))
3232     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3233     			("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
3234     		return;
3235     	}
3236     
3237     	Para.Para32[0] |= SK_RLMT_CHECK_LINK;
3238     
3239     	if (pAC->Rlmt.Net[Para.Para32[1]].NumPorts < 2 &&
3240     		Para.Para32[0] != SK_RLMT_MODE_CLS) {
3241     		pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS;
3242     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3243     			("Forced RLMT mode to CLS on single port net.\n"))
3244     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3245     			("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
3246     		return;
3247     	}
3248     
3249     	/* Update RLMT mode. */
3250     	PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode;
3251     	pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0];
3252     
3253     	if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) !=
3254     		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
3255     		/* SK_RLMT_CHECK_LOC_LINK bit changed. */
3256     		if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 &&
3257     			pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 &&
3258     			pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) {
3259     			/* 20001207 RA: Was "PortsUp == 1". */
3260     			Para2.Para32[0] = Para.Para32[1];
3261     			Para2.Para32[1] = (SK_U32)-1;
3262     			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer,
3263     				pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue,
3264     				SKGE_RLMT, SK_RLMT_TIM, Para2);
3265     		}
3266     	}
3267     
3268     	if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) !=
3269     		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) {
3270     		/* SK_RLMT_CHECK_SEG bit changed. */
3271     		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) {
3272     			(void)SkAddrMcClear(pAC, IoC,
3273     				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
3274     				SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
3275     
3276     			/* Add RLMT MC address. */
3277     			(void)SkAddrMcAdd(pAC, IoC,
3278     				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
3279     				&SkRlmtMcAddr, SK_ADDR_PERMANENT);
3280     
3281     			if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode &
3282     				SK_RLMT_CHECK_SEG) != 0) {
3283     				/* Add BPDU MC address. */
3284     				(void)SkAddrMcAdd(pAC, IoC,
3285     					pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
3286     					&BridgeMcAddr, SK_ADDR_PERMANENT);
3287     
3288     				if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
3289     					if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown &&
3290     						(Para2.pParaPtr = SkRlmtBuildSpanningTreePacket(
3291     						pAC, IoC, i)) != NULL) {
3292     						pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet =
3293     							SK_FALSE;
3294     						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
3295     					}
3296     				}
3297     			}
3298     			(void)SkAddrMcUpdate(pAC, IoC,
3299     				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber);
3300     		}	/* for ... */
3301     
3302     		if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) {
3303     			Para2.Para32[0] = Para.Para32[1];
3304     			Para2.Para32[1] = (SK_U32)-1;
3305     			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer,
3306     				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2);
3307     		}
3308     	}	/* SK_RLMT_CHECK_SEG bit changed. */
3309     
3310     	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3311     			("SK_RLMT_MODE_CHANGE Event END.\n"))
3312     }	/* SkRlmtEvtModeChange */
3313     
3314     
3315     /******************************************************************************
3316      *
3317      *	SkRlmtEvent - a PORT- or an RLMT-specific event happened
3318      *
3319      * Description:
3320      *	This routine calls subroutines to handle PORT- and RLMT-specific events.
3321      *
3322      * Context:
3323      *	runtime, pageable?
3324      *	may be called after SK_INIT_IO
3325      *
3326      * Returns:
3327      *	0
3328      */
3329     int	SkRlmtEvent(
3330     SK_AC		*pAC,	/* Adapter Context */
3331     SK_IOC		IoC,	/* I/O Context */
3332     SK_U32		Event,	/* Event code */
3333     SK_EVPARA	Para)	/* Event-specific parameter */
3334     {
3335     	switch (Event) {
3336     	
3337     	/* ----- PORT events ----- */
3338     
3339     	case SK_RLMT_PORTSTART_TIM:	/* From RLMT via TIME. */
3340     		SkRlmtEvtPortStartTim(pAC, IoC, Para);
3341     		break;
3342     	case SK_RLMT_LINK_UP:		/* From SIRQ. */
3343     		SkRlmtEvtLinkUp(pAC, IoC, Para);
3344     		break;
3345     	case SK_RLMT_PORTUP_TIM:	/* From RLMT via TIME. */
3346     		SkRlmtEvtPortUpTim(pAC, IoC, Para);
3347     		break;
3348     	case SK_RLMT_PORTDOWN:			/* From RLMT. */
3349     	case SK_RLMT_PORTDOWN_RX_TIM:	/* From RLMT via TIME. */
3350     	case SK_RLMT_PORTDOWN_TX_TIM:	/* From RLMT via TIME. */
3351     		SkRlmtEvtPortDownX(pAC, IoC, Event, Para);
3352     		break;
3353     	case SK_RLMT_LINK_DOWN:		/* From SIRQ. */
3354     		SkRlmtEvtLinkDown(pAC, IoC, Para);
3355     		break;
3356     	case SK_RLMT_PORT_ADDR:		/* From ADDR. */
3357     		SkRlmtEvtPortAddr(pAC, IoC, Para);
3358     		break;
3359     
3360     	/* ----- RLMT events ----- */
3361     
3362     	case SK_RLMT_START:		/* From DRV. */
3363     		SkRlmtEvtStart(pAC, IoC, Para);
3364     		break;
3365     	case SK_RLMT_STOP:		/* From DRV. */
3366     		SkRlmtEvtStop(pAC, IoC, Para);
3367     		break;
3368     	case SK_RLMT_TIM:		/* From RLMT via TIME. */
3369     		SkRlmtEvtTim(pAC, IoC, Para);
3370     		break;
3371     	case SK_RLMT_SEG_TIM:
3372     		SkRlmtEvtSegTim(pAC, IoC, Para);
3373     		break;
3374     	case SK_RLMT_PACKET_RECEIVED:	/* From DRV. */
3375     		SkRlmtEvtPacketRx(pAC, IoC, Para);
3376     		break;
3377     	case SK_RLMT_STATS_CLEAR:	/* From PNMI. */
3378     		SkRlmtEvtStatsClear(pAC, IoC, Para);
3379     		break;
3380     	case SK_RLMT_STATS_UPDATE:	/* From PNMI. */
3381     		SkRlmtEvtStatsUpdate(pAC, IoC, Para);
3382     		break;
3383     	case SK_RLMT_PREFPORT_CHANGE:	/* From PNMI. */
3384     		SkRlmtEvtPrefportChange(pAC, IoC, Para);
3385     		break;
3386     	case SK_RLMT_MODE_CHANGE:	/* From PNMI. */
3387     		SkRlmtEvtModeChange(pAC, IoC, Para);
3388     		break;
3389     	case SK_RLMT_SET_NETS:	/* From DRV. */
3390     		SkRlmtEvtSetNets(pAC, IoC, Para);
3391     		break;
3392     
3393     	/* ----- Unknown events ----- */
3394     
3395     	default:	/* Create error log entry. */
3396     		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
3397     			("Unknown RLMT Event %d.\n", Event))
3398     		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG);
3399     		break;
3400     	}	/* switch() */
3401     
3402     	return (0);       
3403     }	/* SkRlmtEvent */
3404     
3405     #ifdef __cplusplus
3406     }
3407     #endif	/* __cplusplus */
3408