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