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