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