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