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