Merge branch 'from-linus'
[linux-2.6] / drivers / net / sk98lin / skaddr.c
1 /******************************************************************************
2  *
3  * Name:        skaddr.c
4  * Project:     Gigabit Ethernet Adapters, ADDR-Module
5  * Version:     $Revision: 1.52 $
6  * Date:        $Date: 2003/06/02 13:46:15 $
7  * Purpose:     Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
8  *
9  ******************************************************************************/
10
11 /******************************************************************************
12  *
13  *      (C)Copyright 1998-2002 SysKonnect GmbH.
14  *      (C)Copyright 2002-2003 Marvell.
15  *
16  *      This program is free software; you can redistribute it and/or modify
17  *      it under the terms of the GNU General Public License as published by
18  *      the Free Software Foundation; either version 2 of the License, or
19  *      (at your option) any later version.
20  *
21  *      The information in this file is provided "AS IS" without warranty.
22  *
23  ******************************************************************************/
24
25 /******************************************************************************
26  *
27  * Description:
28  *
29  * This module is intended to manage multicast addresses, address override,
30  * and promiscuous mode on GEnesis and Yukon adapters.
31  *
32  * Address Layout:
33  *      port address:           physical MAC address
34  *      1st exact match:        logical MAC address (GEnesis only)
35  *      2nd exact match:        RLMT multicast (GEnesis only)
36  *      exact match 3-13:       OS-specific multicasts (GEnesis only)
37  *
38  * Include File Hierarchy:
39  *
40  *      "skdrv1st.h"
41  *      "skdrv2nd.h"
42  *
43  ******************************************************************************/
44
45 #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
46 static const char SysKonnectFileId[] =
47         "@(#) $Id: skaddr.c,v 1.52 2003/06/02 13:46:15 tschilli Exp $ (C) Marvell.";
48 #endif /* DEBUG ||!LINT || !SK_SLIM */
49
50 #define __SKADDR_C
51
52 #ifdef __cplusplus
53 extern "C" {
54 #endif  /* cplusplus */
55
56 #include "h/skdrv1st.h"
57 #include "h/skdrv2nd.h"
58
59 /* defines ********************************************************************/
60
61
62 #define XMAC_POLY       0xEDB88320UL    /* CRC32-Poly - XMAC: Little Endian */
63 #define GMAC_POLY       0x04C11DB7L     /* CRC16-Poly - GMAC: Little Endian */
64 #define HASH_BITS       6                               /* #bits in hash */
65 #define SK_MC_BIT       0x01
66
67 /* Error numbers and messages. */
68
69 #define SKERR_ADDR_E001         (SK_ERRBASE_ADDR + 0)
70 #define SKERR_ADDR_E001MSG      "Bad Flags."
71 #define SKERR_ADDR_E002         (SKERR_ADDR_E001 + 1)
72 #define SKERR_ADDR_E002MSG      "New Error."
73
74 /* typedefs *******************************************************************/
75
76 /* None. */
77
78 /* global variables ***********************************************************/
79
80 /* 64-bit hash values with all bits set. */
81
82 static const SK_U16     OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
83
84 /* local variables ************************************************************/
85
86 #ifdef DEBUG
87 static int      Next0[SK_MAX_MACS] = {0};
88 #endif  /* DEBUG */
89
90 static int SkAddrGmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
91                            SK_MAC_ADDR *pMc, int Flags);
92 static int SkAddrGmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
93                              int Flags);
94 static int SkAddrGmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
95 static int SkAddrGmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
96                                        SK_U32 PortNumber, int NewPromMode);
97 static int SkAddrXmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
98                            SK_MAC_ADDR *pMc, int Flags);
99 static int SkAddrXmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
100                              int Flags);
101 static int SkAddrXmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
102 static int SkAddrXmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
103                                        SK_U32 PortNumber, int NewPromMode);
104
105 /* functions ******************************************************************/
106
107 /******************************************************************************
108  *
109  *      SkAddrInit - initialize data, set state to init
110  *
111  * Description:
112  *
113  *      SK_INIT_DATA
114  *      ============
115  *
116  *      This routine clears the multicast tables and resets promiscuous mode.
117  *      Some entries are reserved for the "logical MAC address", the
118  *      SK-RLMT multicast address, and the BPDU multicast address.
119  *
120  *
121  *      SK_INIT_IO
122  *      ==========
123  *
124  *      All permanent MAC addresses are read from EPROM.
125  *      If the current MAC addresses are not already set in software,
126  *      they are set to the values of the permanent addresses.
127  *      The current addresses are written to the corresponding MAC.
128  *
129  *
130  *      SK_INIT_RUN
131  *      ===========
132  *
133  *      Nothing.
134  *
135  * Context:
136  *      init, pageable
137  *
138  * Returns:
139  *      SK_ADDR_SUCCESS
140  */
141 int     SkAddrInit(
142 SK_AC   *pAC,   /* the adapter context */
143 SK_IOC  IoC,    /* I/O context */
144 int             Level)  /* initialization level */
145 {
146         int                     j;
147         SK_U32          i;
148         SK_U8           *InAddr;
149         SK_U16          *OutAddr;
150         SK_ADDR_PORT    *pAPort;
151
152         switch (Level) {
153         case SK_INIT_DATA:
154                 SK_MEMSET((char *) &pAC->Addr, (SK_U8) 0,
155             (SK_U16) sizeof(SK_ADDR));
156
157                 for (i = 0; i < SK_MAX_MACS; i++) {
158                         pAPort = &pAC->Addr.Port[i];
159                         pAPort->PromMode = SK_PROM_MODE_NONE;
160                         
161                         pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
162                         pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
163                         pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
164                         pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
165                 }
166 #ifdef xDEBUG
167                 for (i = 0; i < SK_MAX_MACS; i++) {
168                         if (pAC->Addr.Port[i].NextExactMatchRlmt <
169                                 SK_ADDR_FIRST_MATCH_RLMT) {
170                                 Next0[i] |= 4;
171                         }
172                 }
173 #endif  /* DEBUG */
174                 /* pAC->Addr.InitDone = SK_INIT_DATA; */
175                 break;
176
177     case SK_INIT_IO:
178 #ifndef SK_NO_RLMT
179                 for (i = 0; i < SK_MAX_NETS; i++) {
180                         pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
181                 }
182 #endif /* !SK_NO_RLMT */
183 #ifdef xDEBUG
184                 for (i = 0; i < SK_MAX_MACS; i++) {
185                         if (pAC->Addr.Port[i].NextExactMatchRlmt <
186                                 SK_ADDR_FIRST_MATCH_RLMT) {
187                                 Next0[i] |= 8;
188                         }
189                 }
190 #endif  /* DEBUG */
191                 
192                 /* Read permanent logical MAC address from Control Register File. */
193                 for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
194                         InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j];
195                         SK_IN8(IoC, B2_MAC_1 + j, InAddr);
196                 }
197
198                 if (!pAC->Addr.Net[0].CurrentMacAddressSet) {
199                         /* Set the current logical MAC address to the permanent one. */
200                         pAC->Addr.Net[0].CurrentMacAddress =
201                                 pAC->Addr.Net[0].PermanentMacAddress;
202                         pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE;
203                 }
204
205                 /* Set the current logical MAC address. */
206                 pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] =
207                         pAC->Addr.Net[0].CurrentMacAddress;
208 #if SK_MAX_NETS > 1
209                 /* Set logical MAC address for net 2 to (log | 3). */
210                 if (!pAC->Addr.Net[1].CurrentMacAddressSet) {
211                         pAC->Addr.Net[1].PermanentMacAddress =
212                                 pAC->Addr.Net[0].PermanentMacAddress;
213                         pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3;
214                         /* Set the current logical MAC address to the permanent one. */
215                         pAC->Addr.Net[1].CurrentMacAddress =
216                                 pAC->Addr.Net[1].PermanentMacAddress;
217                         pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE;
218                 }
219 #endif  /* SK_MAX_NETS > 1 */
220
221 #ifdef DEBUG
222                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
223                         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
224                                 ("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
225                                         i,
226                                         pAC->Addr.Net[i].PermanentMacAddress.a[0],
227                                         pAC->Addr.Net[i].PermanentMacAddress.a[1],
228                                         pAC->Addr.Net[i].PermanentMacAddress.a[2],
229                                         pAC->Addr.Net[i].PermanentMacAddress.a[3],
230                                         pAC->Addr.Net[i].PermanentMacAddress.a[4],
231                                         pAC->Addr.Net[i].PermanentMacAddress.a[5]))
232                         
233                         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
234                                 ("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
235                                         i,
236                                         pAC->Addr.Net[i].CurrentMacAddress.a[0],
237                                         pAC->Addr.Net[i].CurrentMacAddress.a[1],
238                                         pAC->Addr.Net[i].CurrentMacAddress.a[2],
239                                         pAC->Addr.Net[i].CurrentMacAddress.a[3],
240                                         pAC->Addr.Net[i].CurrentMacAddress.a[4],
241                                         pAC->Addr.Net[i].CurrentMacAddress.a[5]))
242                 }
243 #endif  /* DEBUG */
244
245                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
246                         pAPort = &pAC->Addr.Port[i];
247
248                         /* Read permanent port addresses from Control Register File. */
249                         for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
250                                 InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j];
251                                 SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
252                         }
253
254                         if (!pAPort->CurrentMacAddressSet) {
255                                 /*
256                                  * Set the current and previous physical MAC address
257                                  * of this port to its permanent MAC address.
258                                  */
259                                 pAPort->CurrentMacAddress = pAPort->PermanentMacAddress;
260                                 pAPort->PreviousMacAddress = pAPort->PermanentMacAddress;
261                                 pAPort->CurrentMacAddressSet = SK_TRUE;
262                         }
263
264                         /* Set port's current physical MAC address. */
265                         OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
266 #ifdef GENESIS
267                         if (pAC->GIni.GIGenesis) {
268                                 XM_OUTADDR(IoC, i, XM_SA, OutAddr);
269                         }
270 #endif /* GENESIS */
271 #ifdef YUKON
272                         if (!pAC->GIni.GIGenesis) {
273                                 GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr);
274                         }
275 #endif /* YUKON */
276 #ifdef DEBUG
277                         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
278                                 ("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
279                                         pAPort->PermanentMacAddress.a[0],
280                                         pAPort->PermanentMacAddress.a[1],
281                                         pAPort->PermanentMacAddress.a[2],
282                                         pAPort->PermanentMacAddress.a[3],
283                                         pAPort->PermanentMacAddress.a[4],
284                                         pAPort->PermanentMacAddress.a[5]))
285                         
286                         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
287                                 ("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
288                                         pAPort->CurrentMacAddress.a[0],
289                                         pAPort->CurrentMacAddress.a[1],
290                                         pAPort->CurrentMacAddress.a[2],
291                                         pAPort->CurrentMacAddress.a[3],
292                                         pAPort->CurrentMacAddress.a[4],
293                                         pAPort->CurrentMacAddress.a[5]))
294 #endif /* DEBUG */
295                 }
296                 /* pAC->Addr.InitDone = SK_INIT_IO; */
297                 break;
298
299         case SK_INIT_RUN:
300 #ifdef xDEBUG
301                 for (i = 0; i < SK_MAX_MACS; i++) {
302                         if (pAC->Addr.Port[i].NextExactMatchRlmt <
303                                 SK_ADDR_FIRST_MATCH_RLMT) {
304                                 Next0[i] |= 16;
305                         }
306                 }
307 #endif  /* DEBUG */
308
309                 /* pAC->Addr.InitDone = SK_INIT_RUN; */
310                 break;
311
312         default:        /* error */
313                 break;
314         }
315
316         return (SK_ADDR_SUCCESS);
317         
318 }       /* SkAddrInit */
319
320 #ifndef SK_SLIM
321
322 /******************************************************************************
323  *
324  *      SkAddrMcClear - clear the multicast table
325  *
326  * Description:
327  *      This routine clears the multicast table.
328  *
329  *      If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
330  *      immediately.
331  *
332  *      It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according
333  *      to the adapter in use. The real work is done there.
334  *
335  * Context:
336  *      runtime, pageable
337  *      may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
338  *      may be called after SK_INIT_IO without limitation
339  *
340  * Returns:
341  *      SK_ADDR_SUCCESS
342  *      SK_ADDR_ILLEGAL_PORT
343  */
344 int     SkAddrMcClear(
345 SK_AC   *pAC,           /* adapter context */
346 SK_IOC  IoC,            /* I/O context */
347 SK_U32  PortNumber,     /* Index of affected port */
348 int             Flags)          /* permanent/non-perm, sw-only */
349 {
350         int ReturnCode;
351         
352         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
353                 return (SK_ADDR_ILLEGAL_PORT);
354         }
355         
356         if (pAC->GIni.GIGenesis) {
357                 ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags);
358         }
359         else {
360                 ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags);
361         }
362
363         return (ReturnCode);
364
365 }       /* SkAddrMcClear */
366
367 #endif /* !SK_SLIM */
368
369 #ifndef SK_SLIM
370
371 /******************************************************************************
372  *
373  *      SkAddrXmacMcClear - clear the multicast table
374  *
375  * Description:
376  *      This routine clears the multicast table
377  *      (either entry 2 or entries 3-16 and InexactFilter) of the given port.
378  *      If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
379  *      immediately.
380  *
381  * Context:
382  *      runtime, pageable
383  *      may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
384  *      may be called after SK_INIT_IO without limitation
385  *
386  * Returns:
387  *      SK_ADDR_SUCCESS
388  *      SK_ADDR_ILLEGAL_PORT
389  */
390 static int      SkAddrXmacMcClear(
391 SK_AC   *pAC,           /* adapter context */
392 SK_IOC  IoC,            /* I/O context */
393 SK_U32  PortNumber,     /* Index of affected port */
394 int             Flags)          /* permanent/non-perm, sw-only */
395 {
396         int i;
397
398         if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
399
400                 /* Clear RLMT multicast addresses. */
401                 pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
402         }
403         else {  /* not permanent => DRV */
404
405                 /* Clear InexactFilter */
406                 for (i = 0; i < 8; i++) {
407                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
408                 }
409
410                 /* Clear DRV multicast addresses. */
411
412                 pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
413         }
414
415         if (!(Flags & SK_MC_SW_ONLY)) {
416                 (void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
417         }
418
419         return (SK_ADDR_SUCCESS);
420         
421 }       /* SkAddrXmacMcClear */
422
423 #endif /* !SK_SLIM */
424
425 #ifndef SK_SLIM
426
427 /******************************************************************************
428  *
429  *      SkAddrGmacMcClear - clear the multicast table
430  *
431  * Description:
432  *      This routine clears the multicast hashing table (InexactFilter)
433  *      (either the RLMT or the driver bits) of the given port.
434  *
435  *      If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
436  *      immediately.
437  *
438  * Context:
439  *      runtime, pageable
440  *      may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
441  *      may be called after SK_INIT_IO without limitation
442  *
443  * Returns:
444  *      SK_ADDR_SUCCESS
445  *      SK_ADDR_ILLEGAL_PORT
446  */
447 static int      SkAddrGmacMcClear(
448 SK_AC   *pAC,           /* adapter context */
449 SK_IOC  IoC,            /* I/O context */
450 SK_U32  PortNumber,     /* Index of affected port */
451 int             Flags)          /* permanent/non-perm, sw-only */
452 {
453         int i;
454
455 #ifdef DEBUG
456         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
457                 ("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
458                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
459                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
460                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
461                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
462                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
463                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
464                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
465                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
466 #endif  /* DEBUG */
467
468         /* Clear InexactFilter */
469         for (i = 0; i < 8; i++) {
470                 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
471         }
472         
473         if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
474                 
475                 /* Copy DRV bits to InexactFilter. */
476                 for (i = 0; i < 8; i++) {
477                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
478                                 pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
479                         
480                         /* Clear InexactRlmtFilter. */
481                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0;
482
483                 }               
484         }
485         else {  /* not permanent => DRV */
486                 
487                 /* Copy RLMT bits to InexactFilter. */
488                 for (i = 0; i < 8; i++) {
489                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
490                                 pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
491                         
492                         /* Clear InexactDrvFilter. */
493                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0;
494                 }
495         }
496         
497 #ifdef DEBUG
498         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
499                 ("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
500                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
501                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
502                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
503                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
504                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
505                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
506                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
507                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
508 #endif  /* DEBUG */
509         
510         if (!(Flags & SK_MC_SW_ONLY)) {
511                 (void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
512         }
513         
514         return (SK_ADDR_SUCCESS);
515
516 }       /* SkAddrGmacMcClear */
517
518 #ifndef SK_ADDR_CHEAT
519
520 /******************************************************************************
521  *
522  *      SkXmacMcHash - hash multicast address
523  *
524  * Description:
525  *      This routine computes the hash value for a multicast address.
526  *      A CRC32 algorithm is used.
527  *
528  * Notes:
529  *      The code was adapted from the XaQti data sheet.
530  *
531  * Context:
532  *      runtime, pageable
533  *
534  * Returns:
535  *      Hash value of multicast address.
536  */
537 static SK_U32 SkXmacMcHash(
538 unsigned char *pMc)     /* Multicast address */
539 {
540         SK_U32 Idx;
541         SK_U32 Bit;
542         SK_U32 Data;
543         SK_U32 Crc;
544
545         Crc = 0xFFFFFFFFUL;
546         for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
547                 Data = *pMc++;
548                 for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
549                         Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0);
550                 }
551         }
552
553         return (Crc & ((1 << HASH_BITS) - 1));
554
555 }       /* SkXmacMcHash */
556
557
558 /******************************************************************************
559  *
560  *      SkGmacMcHash - hash multicast address
561  *
562  * Description:
563  *      This routine computes the hash value for a multicast address.
564  *      A CRC16 algorithm is used.
565  *
566  * Notes:
567  *
568  *
569  * Context:
570  *      runtime, pageable
571  *
572  * Returns:
573  *      Hash value of multicast address.
574  */
575 static SK_U32 SkGmacMcHash(
576 unsigned char *pMc)     /* Multicast address */
577 {
578         SK_U32 Data;
579         SK_U32 TmpData;
580         SK_U32 Crc;
581         int Byte;
582         int Bit;
583
584         Crc = 0xFFFFFFFFUL;
585         for (Byte = 0; Byte < 6; Byte++) {
586                 /* Get next byte. */
587                 Data = (SK_U32) pMc[Byte];
588                 
589                 /* Change bit order in byte. */
590                 TmpData = Data;
591                 for (Bit = 0; Bit < 8; Bit++) {
592                         if (TmpData & 1L) {
593                                 Data |=  1L << (7 - Bit);
594                         }
595                         else {
596                                 Data &= ~(1L << (7 - Bit));
597                         }
598                         TmpData >>= 1;
599                 }
600                 
601                 Crc ^= (Data << 24);
602                 for (Bit = 0; Bit < 8; Bit++) {
603                         if (Crc & 0x80000000) {
604                                 Crc = (Crc << 1) ^ GMAC_POLY;
605                         }
606                         else {
607                                 Crc <<= 1;
608                         }
609                 }
610         }
611         
612         return (Crc & ((1 << HASH_BITS) - 1));
613
614 }       /* SkGmacMcHash */
615
616 #endif  /* !SK_ADDR_CHEAT */
617
618 /******************************************************************************
619  *
620  *      SkAddrMcAdd - add a multicast address to a port
621  *
622  * Description:
623  *      This routine enables reception for a given address on the given port.
624  *
625  *      It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the
626  *      adapter in use. The real work is done there.
627  *
628  * Notes:
629  *      The return code is only valid for SK_PROM_MODE_NONE.
630  *
631  * Context:
632  *      runtime, pageable
633  *      may be called after SK_INIT_DATA
634  *
635  * Returns:
636  *      SK_MC_FILTERING_EXACT
637  *      SK_MC_FILTERING_INEXACT
638  *      SK_MC_ILLEGAL_ADDRESS
639  *      SK_MC_ILLEGAL_PORT
640  *      SK_MC_RLMT_OVERFLOW
641  */
642 int     SkAddrMcAdd(
643 SK_AC           *pAC,           /* adapter context */
644 SK_IOC          IoC,            /* I/O context */
645 SK_U32          PortNumber,     /* Port Number */
646 SK_MAC_ADDR     *pMc,           /* multicast address to be added */
647 int                     Flags)          /* permanent/non-permanent */
648 {
649         int ReturnCode;
650         
651         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
652                 return (SK_ADDR_ILLEGAL_PORT);
653         }
654         
655         if (pAC->GIni.GIGenesis) {
656                 ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
657         }
658         else {
659                 ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
660         }
661
662         return (ReturnCode);
663
664 }       /* SkAddrMcAdd */
665
666
667 /******************************************************************************
668  *
669  *      SkAddrXmacMcAdd - add a multicast address to a port
670  *
671  * Description:
672  *      This routine enables reception for a given address on the given port.
673  *
674  * Notes:
675  *      The return code is only valid for SK_PROM_MODE_NONE.
676  *
677  *      The multicast bit is only checked if there are no free exact match
678  *      entries.
679  *
680  * Context:
681  *      runtime, pageable
682  *      may be called after SK_INIT_DATA
683  *
684  * Returns:
685  *      SK_MC_FILTERING_EXACT
686  *      SK_MC_FILTERING_INEXACT
687  *      SK_MC_ILLEGAL_ADDRESS
688  *      SK_MC_RLMT_OVERFLOW
689  */
690 static int      SkAddrXmacMcAdd(
691 SK_AC           *pAC,           /* adapter context */
692 SK_IOC          IoC,            /* I/O context */
693 SK_U32          PortNumber,     /* Port Number */
694 SK_MAC_ADDR     *pMc,           /* multicast address to be added */
695 int             Flags)          /* permanent/non-permanent */
696 {
697         int     i;
698         SK_U8   Inexact;
699 #ifndef SK_ADDR_CHEAT
700         SK_U32 HashBit;
701 #endif  /* !defined(SK_ADDR_CHEAT) */
702
703         if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
704 #ifdef xDEBUG
705                 if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
706                         SK_ADDR_FIRST_MATCH_RLMT) {
707                         Next0[PortNumber] |= 1;
708                         return (SK_MC_RLMT_OVERFLOW);
709                 }
710 #endif  /* DEBUG */
711                 
712                 if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt >
713                         SK_ADDR_LAST_MATCH_RLMT) {
714                         return (SK_MC_RLMT_OVERFLOW);
715                 }
716
717                 /* Set a RLMT multicast address. */
718
719                 pAC->Addr.Port[PortNumber].Exact[
720                         pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
721
722                 return (SK_MC_FILTERING_EXACT);
723         }
724
725 #ifdef xDEBUG
726         if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
727                 SK_ADDR_FIRST_MATCH_DRV) {
728                         Next0[PortNumber] |= 2;
729                 return (SK_MC_RLMT_OVERFLOW);
730         }
731 #endif  /* DEBUG */
732         
733         if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
734
735                 /* Set exact match entry. */
736                 pAC->Addr.Port[PortNumber].Exact[
737                         pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
738
739                 /* Clear InexactFilter */
740                 for (i = 0; i < 8; i++) {
741                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
742                 }
743         }
744         else {
745                 if (!(pMc->a[0] & SK_MC_BIT)) {
746                         /* Hashing only possible with multicast addresses */
747                         return (SK_MC_ILLEGAL_ADDRESS);
748                 }
749 #ifndef SK_ADDR_CHEAT
750                 /* Compute hash value of address. */
751                 HashBit = 63 - SkXmacMcHash(&pMc->a[0]);
752
753                 /* Add bit to InexactFilter. */
754                 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
755                         1 << (HashBit % 8);
756 #else   /* SK_ADDR_CHEAT */
757                 /* Set all bits in InexactFilter. */
758                 for (i = 0; i < 8; i++) {
759                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
760                 }
761 #endif  /* SK_ADDR_CHEAT */
762         }
763
764         for (Inexact = 0, i = 0; i < 8; i++) {
765                 Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
766         }
767
768         if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) {
769                 return (SK_MC_FILTERING_EXACT);
770         }
771         else {
772                 return (SK_MC_FILTERING_INEXACT);
773         }
774
775 }       /* SkAddrXmacMcAdd */
776
777
778 /******************************************************************************
779  *
780  *      SkAddrGmacMcAdd - add a multicast address to a port
781  *
782  * Description:
783  *      This routine enables reception for a given address on the given port.
784  *
785  * Notes:
786  *      The return code is only valid for SK_PROM_MODE_NONE.
787  *
788  * Context:
789  *      runtime, pageable
790  *      may be called after SK_INIT_DATA
791  *
792  * Returns:
793  *      SK_MC_FILTERING_INEXACT
794  *      SK_MC_ILLEGAL_ADDRESS
795  */
796 static int      SkAddrGmacMcAdd(
797 SK_AC           *pAC,           /* adapter context */
798 SK_IOC          IoC,            /* I/O context */
799 SK_U32          PortNumber,     /* Port Number */
800 SK_MAC_ADDR     *pMc,           /* multicast address to be added */
801 int             Flags)          /* permanent/non-permanent */
802 {
803         int     i;
804 #ifndef SK_ADDR_CHEAT
805         SK_U32 HashBit;
806 #endif  /* !defined(SK_ADDR_CHEAT) */
807                 
808         if (!(pMc->a[0] & SK_MC_BIT)) {
809                 /* Hashing only possible with multicast addresses */
810                 return (SK_MC_ILLEGAL_ADDRESS);
811         }
812         
813 #ifndef SK_ADDR_CHEAT
814         
815         /* Compute hash value of address. */
816         HashBit = SkGmacMcHash(&pMc->a[0]);
817         
818         if (Flags & SK_ADDR_PERMANENT) {        /* permanent => RLMT */
819                 
820                 /* Add bit to InexactRlmtFilter. */
821                 pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |=
822                         1 << (HashBit % 8);
823                 
824                 /* Copy bit to InexactFilter. */
825                 for (i = 0; i < 8; i++) {
826                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
827                                 pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
828                 }
829 #ifdef DEBUG
830                 SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
831                 ("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
832                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0],
833                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1],
834                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2],
835                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3],
836                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4],
837                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5],
838                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6],
839                         pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7]))
840 #endif  /* DEBUG */
841         }
842         else {  /* not permanent => DRV */
843                 
844                 /* Add bit to InexactDrvFilter. */
845                 pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |=
846                         1 << (HashBit % 8);
847                 
848                 /* Copy bit to InexactFilter. */
849                 for (i = 0; i < 8; i++) {
850                         pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
851                                 pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
852                 }
853 #ifdef DEBUG
854                 SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
855                 ("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
856                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0],
857                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1],
858                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2],
859                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3],
860                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4],
861                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5],
862                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6],
863                         pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7]))
864 #endif  /* DEBUG */
865         }
866         
867 #else   /* SK_ADDR_CHEAT */
868         
869         /* Set all bits in InexactFilter. */
870         for (i = 0; i < 8; i++) {
871                 pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
872         }
873 #endif  /* SK_ADDR_CHEAT */
874                 
875         return (SK_MC_FILTERING_INEXACT);
876         
877 }       /* SkAddrGmacMcAdd */
878
879 #endif /* !SK_SLIM */
880
881 /******************************************************************************
882  *
883  *      SkAddrMcUpdate - update the HW MC address table and set the MAC address
884  *
885  * Description:
886  *      This routine enables reception of the addresses contained in a local
887  *      table for a given port.
888  *      It also programs the port's current physical MAC address.
889  *
890  *      It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according
891  *      to the adapter in use. The real work is done there.
892  *
893  * Notes:
894  *      The return code is only valid for SK_PROM_MODE_NONE.
895  *
896  * Context:
897  *      runtime, pageable
898  *      may be called after SK_INIT_IO
899  *
900  * Returns:
901  *      SK_MC_FILTERING_EXACT
902  *      SK_MC_FILTERING_INEXACT
903  *      SK_ADDR_ILLEGAL_PORT
904  */
905 int     SkAddrMcUpdate(
906 SK_AC   *pAC,           /* adapter context */
907 SK_IOC  IoC,            /* I/O context */
908 SK_U32  PortNumber)     /* Port Number */
909 {
910         int ReturnCode = 0;
911 #if (!defined(SK_SLIM) || defined(DEBUG))
912         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
913                 return (SK_ADDR_ILLEGAL_PORT);
914         }
915 #endif /* !SK_SLIM || DEBUG */
916
917 #ifdef GENESIS
918         if (pAC->GIni.GIGenesis) {
919                 ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
920         }
921 #endif /* GENESIS */
922 #ifdef YUKON
923         if (!pAC->GIni.GIGenesis) {
924                 ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
925         }
926 #endif /* YUKON */
927         return (ReturnCode);
928
929 }       /* SkAddrMcUpdate */
930
931
932 #ifdef GENESIS
933
934 /******************************************************************************
935  *
936  *      SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address
937  *
938  * Description:
939  *      This routine enables reception of the addresses contained in a local
940  *      table for a given port.
941  *      It also programs the port's current physical MAC address.
942  *
943  * Notes:
944  *      The return code is only valid for SK_PROM_MODE_NONE.
945  *
946  * Context:
947  *      runtime, pageable
948  *      may be called after SK_INIT_IO
949  *
950  * Returns:
951  *      SK_MC_FILTERING_EXACT
952  *      SK_MC_FILTERING_INEXACT
953  *      SK_ADDR_ILLEGAL_PORT
954  */
955 static int      SkAddrXmacMcUpdate(
956 SK_AC   *pAC,           /* adapter context */
957 SK_IOC  IoC,            /* I/O context */
958 SK_U32  PortNumber)     /* Port Number */
959 {
960         SK_U32          i;
961         SK_U8           Inexact;
962         SK_U16          *OutAddr;
963         SK_ADDR_PORT    *pAPort;
964
965         SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
966                 ("SkAddrXmacMcUpdate on Port %u.\n", PortNumber))
967         
968         pAPort = &pAC->Addr.Port[PortNumber];
969
970 #ifdef DEBUG
971         SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
972                 ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
973 #endif /* DEBUG */
974
975         /* Start with 0 to also program the logical MAC address. */
976         for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
977                 /* Set exact match address i on XMAC */
978                 OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
979                 XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
980         }
981
982         /* Clear other permanent exact match addresses on XMAC */
983         if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
984                 
985                 SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt,
986                         SK_ADDR_LAST_MATCH_RLMT);
987         }
988
989         for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
990                 OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
991                 XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
992         }
993
994         /* Clear other non-permanent exact match addresses on XMAC */
995         if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
996                 
997                 SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv,
998                         SK_ADDR_LAST_MATCH_DRV);
999         }
1000
1001         for (Inexact = 0, i = 0; i < 8; i++) {
1002                 Inexact |= pAPort->InexactFilter.Bytes[i];
1003         }
1004
1005         if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
1006                 
1007                 /* Set all bits in 64-bit hash register. */
1008                 XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
1009                 
1010                 /* Enable Hashing */
1011                 SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
1012         }
1013         else if (Inexact != 0) {
1014                 
1015                 /* Set 64-bit hash register to InexactFilter. */
1016                 XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
1017                 
1018                 /* Enable Hashing */
1019                 SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
1020         }
1021         else {
1022                 /* Disable Hashing */
1023                 SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE);
1024         }
1025
1026         if (pAPort->PromMode != SK_PROM_MODE_NONE) {
1027                 (void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
1028         }
1029
1030         /* Set port's current physical MAC address. */
1031         OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
1032         
1033         XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
1034
1035 #ifdef xDEBUG
1036         for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
1037                 SK_U8           InAddr8[6];
1038                 SK_U16          *InAddr;
1039
1040                 /* Get exact match address i from port PortNumber. */
1041                 InAddr = (SK_U16 *) &InAddr8[0];
1042                 
1043                 XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
1044                 
1045                 SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1046                         ("SkAddrXmacMcUpdate: MC address %d on Port %u: ",
1047                          "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n",
1048                                 i,
1049                                 PortNumber,
1050                                 InAddr8[0],
1051                                 InAddr8[1],
1052                                 InAddr8[2],
1053                                 InAddr8[3],
1054                                 InAddr8[4],
1055                                 InAddr8[5],
1056                                 pAPort->Exact[i].a[0],
1057                                 pAPort->Exact[i].a[1],
1058                                 pAPort->Exact[i].a[2],
1059                                 pAPort->Exact[i].a[3],
1060                                 pAPort->Exact[i].a[4],
1061                                 pAPort->Exact[i].a[5]))
1062         }
1063 #endif /* DEBUG */
1064
1065         /* Determine return value. */
1066         if (Inexact == 0 && pAPort->PromMode == 0) {
1067                 return (SK_MC_FILTERING_EXACT);
1068         }
1069         else {
1070                 return (SK_MC_FILTERING_INEXACT);
1071         }
1072         
1073 }       /* SkAddrXmacMcUpdate */
1074
1075 #endif  /* GENESIS */
1076
1077 #ifdef YUKON
1078
1079 /******************************************************************************
1080  *
1081  *      SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address
1082  *
1083  * Description:
1084  *      This routine enables reception of the addresses contained in a local
1085  *      table for a given port.
1086  *      It also programs the port's current physical MAC address.
1087  *
1088  * Notes:
1089  *      The return code is only valid for SK_PROM_MODE_NONE.
1090  *
1091  * Context:
1092  *      runtime, pageable
1093  *      may be called after SK_INIT_IO
1094  *
1095  * Returns:
1096  *      SK_MC_FILTERING_EXACT
1097  *      SK_MC_FILTERING_INEXACT
1098  *      SK_ADDR_ILLEGAL_PORT
1099  */
1100 static int      SkAddrGmacMcUpdate(
1101 SK_AC   *pAC,           /* adapter context */
1102 SK_IOC  IoC,            /* I/O context */
1103 SK_U32  PortNumber)     /* Port Number */
1104 {
1105 #ifndef SK_SLIM
1106         SK_U32          i;
1107         SK_U8           Inexact;
1108 #endif  /* not SK_SLIM */
1109         SK_U16          *OutAddr;
1110         SK_ADDR_PORT    *pAPort;
1111
1112         SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1113                 ("SkAddrGmacMcUpdate on Port %u.\n", PortNumber))
1114         
1115         pAPort = &pAC->Addr.Port[PortNumber];
1116
1117 #ifdef DEBUG
1118         SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1119                 ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
1120 #endif /* DEBUG */
1121         
1122 #ifndef SK_SLIM
1123         for (Inexact = 0, i = 0; i < 8; i++) {
1124                 Inexact |= pAPort->InexactFilter.Bytes[i];
1125         }
1126         
1127         /* Set 64-bit hash register to InexactFilter. */
1128         GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
1129                 &pAPort->InexactFilter.Bytes[0]);
1130         
1131         if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {                           
1132                 
1133                 /* Set all bits in 64-bit hash register. */
1134                 GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
1135                 
1136                 /* Enable Hashing */
1137                 SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
1138         }
1139         else {  
1140                 /* Enable Hashing. */
1141                 SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
1142         }
1143         
1144         if (pAPort->PromMode != SK_PROM_MODE_NONE) {
1145                 (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
1146         }
1147 #else /* SK_SLIM */
1148
1149         /* Set all bits in 64-bit hash register. */
1150         GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
1151
1152         /* Enable Hashing */
1153         SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
1154         
1155         (void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
1156         
1157 #endif /* SK_SLIM */
1158         
1159         /* Set port's current physical MAC address. */
1160         OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
1161         GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
1162         
1163         /* Set port's current logical MAC address. */
1164         OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0];
1165         GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr);
1166         
1167 #ifdef DEBUG
1168         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1169                 ("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
1170                         pAPort->Exact[0].a[0],
1171                         pAPort->Exact[0].a[1],
1172                         pAPort->Exact[0].a[2],
1173                         pAPort->Exact[0].a[3],
1174                         pAPort->Exact[0].a[4],
1175                         pAPort->Exact[0].a[5]))
1176         
1177         SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1178                 ("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
1179                         pAPort->CurrentMacAddress.a[0],
1180                         pAPort->CurrentMacAddress.a[1],
1181                         pAPort->CurrentMacAddress.a[2],
1182                         pAPort->CurrentMacAddress.a[3],
1183                         pAPort->CurrentMacAddress.a[4],
1184                         pAPort->CurrentMacAddress.a[5]))
1185 #endif /* DEBUG */
1186         
1187 #ifndef SK_SLIM
1188         /* Determine return value. */
1189         if (Inexact == 0 && pAPort->PromMode == 0) {
1190                 return (SK_MC_FILTERING_EXACT);
1191         }
1192         else {
1193                 return (SK_MC_FILTERING_INEXACT);
1194         }
1195 #else /* SK_SLIM */
1196         return (SK_MC_FILTERING_INEXACT);
1197 #endif /* SK_SLIM */
1198         
1199 }       /* SkAddrGmacMcUpdate */
1200
1201 #endif /* YUKON */
1202
1203 #ifndef SK_NO_MAO
1204
1205 /******************************************************************************
1206  *
1207  *      SkAddrOverride - override a port's MAC address
1208  *
1209  * Description:
1210  *      This routine overrides the MAC address of one port.
1211  *
1212  * Context:
1213  *      runtime, pageable
1214  *      may be called after SK_INIT_IO
1215  *
1216  * Returns:
1217  *      SK_ADDR_SUCCESS if successful.
1218  *      SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address.
1219  *      SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address.
1220  *      SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before.
1221  */
1222 int     SkAddrOverride(
1223 SK_AC           *pAC,                           /* adapter context */
1224 SK_IOC          IoC,                            /* I/O context */
1225 SK_U32          PortNumber,                     /* Port Number */
1226 SK_MAC_ADDR     SK_FAR *pNewAddr,       /* new MAC address */
1227 int                     Flags)                          /* logical/physical MAC address */
1228 {
1229 #ifndef SK_NO_RLMT
1230         SK_EVPARA       Para;
1231 #endif /* !SK_NO_RLMT */
1232         SK_U32          NetNumber;
1233         SK_U32          i;
1234         SK_U16          SK_FAR *OutAddr;
1235
1236 #ifndef SK_NO_RLMT
1237         NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
1238 #else
1239         NetNumber = 0;
1240 #endif /* SK_NO_RLMT */
1241 #if (!defined(SK_SLIM) || defined(DEBUG))
1242         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
1243                 return (SK_ADDR_ILLEGAL_PORT);
1244         }
1245 #endif /* !SK_SLIM || DEBUG */
1246         if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) {
1247                 return (SK_ADDR_MULTICAST_ADDRESS);
1248         }
1249
1250         if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) {
1251                 return (SK_ADDR_TOO_EARLY);
1252         }
1253
1254         if (Flags & SK_ADDR_SET_LOGICAL) {      /* Activate logical MAC address. */
1255                 /* Parameter *pNewAddr is ignored. */
1256                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
1257                         if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
1258                                 return (SK_ADDR_TOO_EARLY);
1259                         }
1260                 }
1261 #ifndef SK_NO_RLMT
1262                 /* Set PortNumber to number of net's active port. */
1263                 PortNumber = pAC->Rlmt.Net[NetNumber].
1264                         Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
1265 #endif /* !SK_NO_RLMT */
1266                 pAC->Addr.Port[PortNumber].Exact[0] =
1267                         pAC->Addr.Net[NetNumber].CurrentMacAddress;
1268
1269                 /* Write address to first exact match entry of active port. */
1270                 (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
1271         }
1272         else if (Flags & SK_ADDR_CLEAR_LOGICAL) {
1273                 /* Deactivate logical MAC address. */
1274                 /* Parameter *pNewAddr is ignored. */
1275                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
1276                         if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
1277                                 return (SK_ADDR_TOO_EARLY);
1278                         }
1279                 }
1280 #ifndef SK_NO_RLMT
1281                 /* Set PortNumber to number of net's active port. */
1282                 PortNumber = pAC->Rlmt.Net[NetNumber].
1283                         Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
1284 #endif /* !SK_NO_RLMT */
1285                 for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) {
1286                         pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0;
1287                 }
1288
1289                 /* Write address to first exact match entry of active port. */
1290                 (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
1291         }
1292         else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {    /* Physical MAC address. */
1293                 if (SK_ADDR_EQUAL(pNewAddr->a,
1294                         pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
1295                         return (SK_ADDR_DUPLICATE_ADDRESS);
1296                 }
1297
1298                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
1299                         if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
1300                                 return (SK_ADDR_TOO_EARLY);
1301                         }
1302
1303                         if (SK_ADDR_EQUAL(pNewAddr->a,
1304                                 pAC->Addr.Port[i].CurrentMacAddress.a)) {
1305                                 if (i == PortNumber) {
1306                                         return (SK_ADDR_SUCCESS);
1307                                 }
1308                                 else {
1309                                         return (SK_ADDR_DUPLICATE_ADDRESS);
1310                                 }
1311                         }
1312                 }
1313
1314                 pAC->Addr.Port[PortNumber].PreviousMacAddress =
1315                         pAC->Addr.Port[PortNumber].CurrentMacAddress;
1316                 pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
1317
1318                 /* Change port's physical MAC address. */
1319                 OutAddr = (SK_U16 SK_FAR *) pNewAddr;
1320 #ifdef GENESIS
1321                 if (pAC->GIni.GIGenesis) {
1322                         XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
1323                 }
1324 #endif /* GENESIS */
1325 #ifdef YUKON
1326                 if (!pAC->GIni.GIGenesis) {
1327                         GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
1328                 }
1329 #endif /* YUKON */
1330
1331 #ifndef SK_NO_RLMT
1332                 /* Report address change to RLMT. */
1333                 Para.Para32[0] = PortNumber;
1334                 Para.Para32[0] = -1;
1335                 SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
1336 #endif /* !SK_NO_RLMT */
1337         }
1338         else {  /* Logical MAC address. */
1339                 if (SK_ADDR_EQUAL(pNewAddr->a,
1340                         pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
1341                         return (SK_ADDR_SUCCESS);
1342                 }
1343                 
1344                 for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
1345                         if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
1346                                 return (SK_ADDR_TOO_EARLY);
1347                         }
1348
1349                         if (SK_ADDR_EQUAL(pNewAddr->a,
1350                                 pAC->Addr.Port[i].CurrentMacAddress.a)) {
1351                                 return (SK_ADDR_DUPLICATE_ADDRESS);
1352                         }
1353                 }
1354                 
1355                 /*
1356                  * In case that the physical and the logical MAC addresses are equal
1357                  * we must also change the physical MAC address here.
1358                  * In this case we have an adapter which initially was programmed with
1359                  * two identical MAC addresses.
1360                  */
1361                 if (SK_ADDR_EQUAL(pAC->Addr.Port[PortNumber].CurrentMacAddress.a,
1362                                 pAC->Addr.Port[PortNumber].Exact[0].a)) {
1363                         
1364                         pAC->Addr.Port[PortNumber].PreviousMacAddress =
1365                                 pAC->Addr.Port[PortNumber].CurrentMacAddress;
1366                         pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
1367                         
1368 #ifndef SK_NO_RLMT
1369                         /* Report address change to RLMT. */
1370                         Para.Para32[0] = PortNumber;
1371                         Para.Para32[0] = -1;
1372                         SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
1373 #endif /* !SK_NO_RLMT */
1374                 }
1375                 
1376 #ifndef SK_NO_RLMT
1377                 /* Set PortNumber to number of net's active port. */
1378                 PortNumber = pAC->Rlmt.Net[NetNumber].
1379                         Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
1380 #endif /* !SK_NO_RLMT */
1381                 pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
1382                 pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
1383 #ifdef DEBUG
1384                 SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1385                         ("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
1386                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0],
1387                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1],
1388                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2],
1389                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3],
1390                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4],
1391                                 pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5]))
1392                 
1393                 SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
1394                         ("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
1395                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
1396                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
1397                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
1398                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3],
1399                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4],
1400                                 pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5]))
1401 #endif /* DEBUG */
1402
1403         /* Write address to first exact match entry of active port. */
1404                 (void) SkAddrMcUpdate(pAC, IoC, PortNumber);
1405         }
1406
1407         return (SK_ADDR_SUCCESS);
1408         
1409 }       /* SkAddrOverride */
1410
1411
1412 #endif /* SK_NO_MAO */
1413
1414 /******************************************************************************
1415  *
1416  *      SkAddrPromiscuousChange - set promiscuous mode for given port
1417  *
1418  * Description:
1419  *      This routine manages promiscuous mode:
1420  *      - none
1421  *      - all LLC frames
1422  *      - all MC frames
1423  *
1424  *      It calls either SkAddrXmacPromiscuousChange or
1425  *      SkAddrGmacPromiscuousChange, according to the adapter in use.
1426  *      The real work is done there.
1427  *
1428  * Context:
1429  *      runtime, pageable
1430  *      may be called after SK_INIT_IO
1431  *
1432  * Returns:
1433  *      SK_ADDR_SUCCESS
1434  *      SK_ADDR_ILLEGAL_PORT
1435  */
1436 int     SkAddrPromiscuousChange(
1437 SK_AC   *pAC,                   /* adapter context */
1438 SK_IOC  IoC,                    /* I/O context */
1439 SK_U32  PortNumber,             /* port whose promiscuous mode changes */
1440 int             NewPromMode)    /* new promiscuous mode */
1441 {
1442         int ReturnCode = 0;
1443 #if (!defined(SK_SLIM) || defined(DEBUG))
1444         if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
1445                 return (SK_ADDR_ILLEGAL_PORT);
1446         }
1447 #endif /* !SK_SLIM || DEBUG */
1448
1449 #ifdef GENESIS
1450         if (pAC->GIni.GIGenesis) {
1451                 ReturnCode =
1452                         SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
1453         }
1454 #endif /* GENESIS */
1455 #ifdef YUKON
1456         if (!pAC->GIni.GIGenesis) {
1457                 ReturnCode =
1458                         SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
1459         }
1460 #endif /* YUKON */
1461
1462         return (ReturnCode);
1463
1464 }       /* SkAddrPromiscuousChange */
1465
1466 #ifdef GENESIS
1467
1468 /******************************************************************************
1469  *
1470  *      SkAddrXmacPromiscuousChange - set promiscuous mode for given port
1471  *
1472  * Description:
1473  *      This routine manages promiscuous mode:
1474  *      - none
1475  *      - all LLC frames
1476  *      - all MC frames
1477  *
1478  * Context:
1479  *      runtime, pageable
1480  *      may be called after SK_INIT_IO
1481  *
1482  * Returns:
1483  *      SK_ADDR_SUCCESS
1484  *      SK_ADDR_ILLEGAL_PORT
1485  */
1486 static int      SkAddrXmacPromiscuousChange(
1487 SK_AC   *pAC,                   /* adapter context */
1488 SK_IOC  IoC,                    /* I/O context */
1489 SK_U32  PortNumber,             /* port whose promiscuous mode changes */
1490 int             NewPromMode)    /* new promiscuous mode */
1491 {
1492         int                     i;
1493         SK_BOOL         InexactModeBit;
1494         SK_U8           Inexact;
1495         SK_U8           HwInexact;
1496         SK_FILTER64     HwInexactFilter;
1497         SK_U16          LoMode;         /* Lower 16 bits of XMAC Mode Register. */
1498         int                     CurPromMode = SK_PROM_MODE_NONE;
1499
1500         /* Read CurPromMode from Hardware. */
1501         XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1502
1503         if ((LoMode & XM_MD_ENA_PROM) != 0) {
1504                 /* Promiscuous mode! */
1505                 CurPromMode |= SK_PROM_MODE_LLC;
1506         }
1507         
1508         for (Inexact = 0xFF, i = 0; i < 8; i++) {
1509                 Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
1510         }
1511         if (Inexact == 0xFF) {
1512                 CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
1513         }
1514         else {
1515                 /* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */
1516                 XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1517                 
1518                 InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0;
1519
1520                 /* Read 64-bit hash register from XMAC */
1521                 XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
1522
1523                 for (HwInexact = 0xFF, i = 0; i < 8; i++) {
1524                         HwInexact &= HwInexactFilter.Bytes[i];
1525                 }
1526
1527                 if (InexactModeBit && (HwInexact == 0xFF)) {
1528                         CurPromMode |= SK_PROM_MODE_ALL_MC;
1529                 }
1530         }
1531
1532         pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
1533
1534         if (NewPromMode == CurPromMode) {
1535                 return (SK_ADDR_SUCCESS);
1536         }
1537
1538         if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
1539                 !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC. */
1540                 
1541                 /* Set all bits in 64-bit hash register. */
1542                 XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
1543
1544                 /* Enable Hashing */
1545                 SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
1546         }
1547         else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
1548                 !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm MC. */
1549                 for (Inexact = 0, i = 0; i < 8; i++) {
1550                         Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
1551                 }
1552                 if (Inexact == 0) {
1553                         /* Disable Hashing */
1554                         SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE);
1555                 }
1556                 else {
1557                         /* Set 64-bit hash register to InexactFilter. */
1558                         XM_OUTHASH(IoC, PortNumber, XM_HSM,
1559                                 &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
1560
1561                         /* Enable Hashing */
1562                         SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
1563                 }
1564         }
1565
1566         if ((NewPromMode & SK_PROM_MODE_LLC) &&
1567                 !(CurPromMode & SK_PROM_MODE_LLC)) {    /* Prom. LLC */
1568                 /* Set the MAC in Promiscuous Mode */
1569                 SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE);
1570         }
1571         else if ((CurPromMode & SK_PROM_MODE_LLC) &&
1572                 !(NewPromMode & SK_PROM_MODE_LLC)) {    /* Norm. LLC. */
1573                 /* Clear Promiscuous Mode */
1574                 SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE);
1575         }
1576         
1577         return (SK_ADDR_SUCCESS);
1578         
1579 }       /* SkAddrXmacPromiscuousChange */
1580
1581 #endif /* GENESIS */
1582
1583 #ifdef YUKON
1584
1585 /******************************************************************************
1586  *
1587  *      SkAddrGmacPromiscuousChange - set promiscuous mode for given port
1588  *
1589  * Description:
1590  *      This routine manages promiscuous mode:
1591  *      - none
1592  *      - all LLC frames
1593  *      - all MC frames
1594  *
1595  * Context:
1596  *      runtime, pageable
1597  *      may be called after SK_INIT_IO
1598  *
1599  * Returns:
1600  *      SK_ADDR_SUCCESS
1601  *      SK_ADDR_ILLEGAL_PORT
1602  */
1603 static int      SkAddrGmacPromiscuousChange(
1604 SK_AC   *pAC,                   /* adapter context */
1605 SK_IOC  IoC,                    /* I/O context */
1606 SK_U32  PortNumber,             /* port whose promiscuous mode changes */
1607 int             NewPromMode)    /* new promiscuous mode */
1608 {
1609         SK_U16          ReceiveControl; /* GMAC Receive Control Register */
1610         int             CurPromMode = SK_PROM_MODE_NONE;
1611
1612         /* Read CurPromMode from Hardware. */
1613         GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl);
1614
1615         if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) {
1616                 /* Promiscuous mode! */
1617                 CurPromMode |= SK_PROM_MODE_LLC;
1618         }
1619
1620         if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) {
1621                 /* All Multicast mode! */
1622                 CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
1623         }
1624
1625         pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
1626
1627         if (NewPromMode == CurPromMode) {
1628                 return (SK_ADDR_SUCCESS);
1629         }
1630         
1631         if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
1632                 !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC */
1633                 
1634                 /* Set all bits in 64-bit hash register. */
1635                 GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
1636                 
1637                 /* Enable Hashing */
1638                 SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
1639         }
1640         
1641         if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
1642                 !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm. MC */
1643
1644                 /* Set 64-bit hash register to InexactFilter. */
1645                 GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
1646                         &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
1647
1648                 /* Enable Hashing. */
1649                 SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
1650         }
1651
1652         if ((NewPromMode & SK_PROM_MODE_LLC) &&
1653                 !(CurPromMode & SK_PROM_MODE_LLC)) {    /* Prom. LLC */
1654                 
1655                 /* Set the MAC to Promiscuous Mode. */
1656                 SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE);
1657         }
1658         else if ((CurPromMode & SK_PROM_MODE_LLC) &&
1659                 !(NewPromMode & SK_PROM_MODE_LLC)) {    /* Norm. LLC */
1660                 
1661                 /* Clear Promiscuous Mode. */
1662                 SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE);
1663         }
1664
1665         return (SK_ADDR_SUCCESS);
1666         
1667 }       /* SkAddrGmacPromiscuousChange */
1668
1669 #endif /* YUKON */
1670
1671 #ifndef SK_SLIM
1672
1673 /******************************************************************************
1674  *
1675  *      SkAddrSwap - swap address info
1676  *
1677  * Description:
1678  *      This routine swaps address info of two ports.
1679  *
1680  * Context:
1681  *      runtime, pageable
1682  *      may be called after SK_INIT_IO
1683  *
1684  * Returns:
1685  *      SK_ADDR_SUCCESS
1686  *      SK_ADDR_ILLEGAL_PORT
1687  */
1688 int     SkAddrSwap(
1689 SK_AC   *pAC,                   /* adapter context */
1690 SK_IOC  IoC,                    /* I/O context */
1691 SK_U32  FromPortNumber,         /* Port1 Index */
1692 SK_U32  ToPortNumber)           /* Port2 Index */
1693 {
1694         int                     i;
1695         SK_U8           Byte;
1696         SK_MAC_ADDR     MacAddr;
1697         SK_U32          DWord;
1698
1699         if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
1700                 return (SK_ADDR_ILLEGAL_PORT);
1701         }
1702
1703         if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
1704                 return (SK_ADDR_ILLEGAL_PORT);
1705         }
1706
1707         if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) {
1708                 return (SK_ADDR_ILLEGAL_PORT);
1709         }
1710
1711         /*
1712          * Swap:
1713          * - Exact Match Entries (GEnesis and Yukon)
1714          *   Yukon uses first entry for the logical MAC
1715          *   address (stored in the second GMAC register).
1716          * - FirstExactMatchRlmt (GEnesis only)
1717          * - NextExactMatchRlmt (GEnesis only)
1718          * - FirstExactMatchDrv (GEnesis only)
1719          * - NextExactMatchDrv (GEnesis only)
1720          * - 64-bit filter (InexactFilter)
1721          * - Promiscuous Mode
1722          * of ports.
1723          */
1724
1725         for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
1726                 MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i];
1727                 pAC->Addr.Port[FromPortNumber].Exact[i] =
1728                         pAC->Addr.Port[ToPortNumber].Exact[i];
1729                 pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr;
1730         }
1731
1732         for (i = 0; i < 8; i++) {
1733                 Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i];
1734                 pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] =
1735                         pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i];
1736                 pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte;
1737         }
1738         
1739         i = pAC->Addr.Port[FromPortNumber].PromMode;
1740         pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode;
1741         pAC->Addr.Port[ToPortNumber].PromMode = i;
1742         
1743         if (pAC->GIni.GIGenesis) {
1744                 DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt;
1745                 pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt =
1746                         pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt;
1747                 pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord;
1748                 
1749                 DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt;
1750                 pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt =
1751                         pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt;
1752                 pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord;
1753                 
1754                 DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv;
1755                 pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv =
1756                         pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv;
1757                 pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord;
1758                 
1759                 DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv;
1760                 pAC->Addr.Port[FromPortNumber].NextExactMatchDrv =
1761                         pAC->Addr.Port[ToPortNumber].NextExactMatchDrv;
1762                 pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord;
1763         }
1764         
1765         /* CAUTION: Solution works if only ports of one adapter are in use. */
1766         for (i = 0; (SK_U32) i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].
1767                 Net->NetNumber].NumPorts; i++) {
1768                 if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
1769                         Port[i]->PortNumber == ToPortNumber) {
1770                         pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
1771                                 ActivePort = i;
1772                         /* 20001207 RA: Was "ToPortNumber;". */
1773                 }
1774         }
1775         
1776         (void) SkAddrMcUpdate(pAC, IoC, FromPortNumber);
1777         (void) SkAddrMcUpdate(pAC, IoC, ToPortNumber);
1778
1779         return (SK_ADDR_SUCCESS);
1780         
1781 }       /* SkAddrSwap */
1782
1783 #endif /* !SK_SLIM */
1784
1785 #ifdef __cplusplus
1786 }
1787 #endif  /* __cplusplus */
1788