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