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