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