File: /usr/src/linux/drivers/net/sk98lin/skaddr.c

1     /******************************************************************************
2      *
3      * Name:	skaddr.c
4      * Project:	GEnesis, PCI Gigabit Ethernet Adapter
5      * Version:	$Revision: 1.40 $
6      * Date:	$Date: 2001/02/14 14:04:59 $
7      * Purpose:	Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
8      *
9      ******************************************************************************/
10     
11     /******************************************************************************
12      *
13      *	(C)Copyright 1998-2001 SysKonnect GmbH.
14      *
15      *	This program is free software; you can redistribute it and/or modify
16      *	it under the terms of the GNU General Public License as published by
17      *	the Free Software Foundation; either version 2 of the License, or
18      *	(at your option) any later version.
19      *
20      *	The information in this file is provided "AS IS" without warranty.
21      *
22      ******************************************************************************/
23     
24     /******************************************************************************
25      *
26      * History:
27      *
28      *	$Log: skaddr.c,v $
29      *	Revision 1.40  2001/02/14 14:04:59  rassmann
30      *	Editorial changes.
31      *	
32      *	Revision 1.39  2001/01/30 10:30:04  rassmann
33      *	Editorial changes.
34      *	
35      *	Revision 1.38  2001/01/25 16:26:52  rassmann
36      *	Ensured that logical address overrides are done on net's active port.
37      *	
38      *	Revision 1.37  2001/01/22 13:41:34  rassmann
39      *	Supporting two nets on dual-port adapters.
40      *	
41      *	Revision 1.36  2000/08/07 11:10:39  rassmann
42      *	Editorial changes.
43      *	
44      *	Revision 1.35  2000/05/04 09:38:41  rassmann
45      *	Editorial changes.
46      *	Corrected multicast address hashing.
47      *	
48      *	Revision 1.34  1999/11/22 13:23:44  cgoos
49      *	Changed license header to GPL.
50      *	
51      *	Revision 1.33  1999/05/28 10:56:06  rassmann
52      *	Editorial changes.
53      *	
54      *	Revision 1.32  1999/03/31 10:59:20  rassmann
55      *	Returning Success instead of DupAddr if address shall be overridden
56      *	with same value.
57      *	
58      *	Revision 1.31  1999/01/14 16:18:17  rassmann
59      *	Corrected multicast initialization.
60      *	
61      *	Revision 1.30  1999/01/04 10:30:35  rassmann
62      *	SkAddrOverride only possible after SK_INIT_IO phase.
63      *	
64      *	Revision 1.29  1998/12/29 13:13:10  rassmann
65      *	An address override is now preserved in the SK_INIT_IO phase.
66      *	All functions return an int now.
67      *	Extended parameter checking.
68      *	
69      *	Revision 1.28  1998/12/01 11:45:53  rassmann
70      *	Code cleanup.
71      *	
72      *	Revision 1.27  1998/12/01 09:22:49  rassmann
73      *	SkAddrMcAdd and SkAddrMcUpdate returned SK_MC_FILTERING_INEXACT
74      *	too often.
75      *	
76      *	Revision 1.26  1998/11/24 12:39:44  rassmann
77      *	Reserved multicast entry for BPDU address.
78      *	13 multicast entries left for protocol.
79      *	
80      *	Revision 1.25  1998/11/17 16:54:23  rassmann
81      *	Using exact match for up to 14 multicast addresses.
82      *	Still receiving all multicasts if more addresses are added.
83      *	
84      *	Revision 1.24  1998/11/13 17:24:31  rassmann
85      *	Changed return value of SkAddrOverride to int.
86      *	
87      *	Revision 1.23  1998/11/13 16:56:18  rassmann
88      *	Added macro SK_ADDR_COMPARE.
89      *	Changed return type of SkAddrOverride to SK_BOOL.
90      *	
91      *	Revision 1.22  1998/11/04 17:06:17  rassmann
92      *	Corrected McUpdate and PromiscuousChange functions.
93      *	
94      *	Revision 1.21  1998/10/29 14:34:04  rassmann
95      *	Clearing SK_ADDR struct at startup.
96      *	
97      *	Revision 1.20  1998/10/28 18:16:34  rassmann
98      *	Avoiding I/Os before SK_INIT_RUN level.
99      *	Aligning InexactFilter.
100      *	
101      *	Revision 1.19  1998/10/28 11:29:28  rassmann
102      *	Programming physical address in SkAddrMcUpdate.
103      *	Corrected programming of exact match entries.
104      *	
105      *	Revision 1.18  1998/10/28 10:34:48  rassmann
106      *	Corrected reading of physical addresses.
107      *	
108      *	Revision 1.17  1998/10/28 10:26:13  rassmann
109      *	Getting ports' current MAC addresses from EPROM now.
110      *	Added debug output.
111      *	
112      *	Revision 1.16  1998/10/27 16:20:12  rassmann
113      *	Reading MAC address byte by byte.
114      *	
115      *	Revision 1.15  1998/10/22 11:39:09  rassmann
116      *	Corrected signed/unsigned mismatches.
117      *	
118      *	Revision 1.14  1998/10/19 17:12:35  rassmann
119      *	Syntax corrections.
120      *	
121      *	Revision 1.13  1998/10/19 17:02:19  rassmann
122      *	Now reading permanent MAC addresses from CRF.
123      *	
124      *	Revision 1.12  1998/10/15 15:15:48  rassmann
125      *	Changed Flags Parameters from SK_U8 to int.
126      *	Checked with lint.
127      *	
128      *	Revision 1.11  1998/09/24 19:15:12  rassmann
129      *	Code cleanup.
130      *	
131      *	Revision 1.10  1998/09/18 20:18:54  rassmann
132      *	Added HW access.
133      *	Implemented swapping.
134      *	
135      *	Revision 1.9  1998/09/16 11:32:00  rassmann
136      *	Including skdrv1st.h again. :(
137      *	
138      *	Revision 1.8  1998/09/16 11:09:34  rassmann
139      *	Syntax corrections.
140      *	
141      *	Revision 1.7  1998/09/14 17:06:34  rassmann
142      *	Minor changes.
143      *	
144      *	Revision 1.6  1998/09/07 08:45:41  rassmann
145      *	Syntax corrections.
146      *	
147      *	Revision 1.5  1998/09/04 19:40:19  rassmann
148      *	Interface enhancements.
149      *	
150      *	Revision 1.4  1998/09/04 12:14:12  rassmann
151      *	Interface cleanup.
152      *	
153      *	Revision 1.3  1998/09/02 16:56:40  rassmann
154      *	Updated interface.
155      *	
156      *	Revision 1.2  1998/08/27 14:26:09  rassmann
157      *	Updated interface.
158      *	
159      *	Revision 1.1  1998/08/21 08:30:22  rassmann
160      *	First public version.
161      *
162      ******************************************************************************/
163     
164     /******************************************************************************
165      *
166      * Description:
167      *
168      * This module is intended to manage multicast addresses, address override,
169      * and promiscuous mode on GEnesis adapters.
170      *
171      * Address Layout:
172      *	port address:		physical MAC address
173      *	1st exact match:	logical MAC address
174      *	2nd exact match:	RLMT multicast
175      *	exact match 3-13:	OS-specific multicasts
176      *
177      * Include File Hierarchy:
178      *
179      *	"skdrv1st.h"
180      *	"skdrv2nd.h"
181      *
182      ******************************************************************************/
183     
184     #ifndef	lint
185     static const char SysKonnectFileId[] =
186     	"@(#) $Id: skaddr.c,v 1.40 2001/02/14 14:04:59 rassmann Exp $ (C) SysKonnect.";
187     #endif	/* !defined(lint) */
188     
189     #define __SKADDR_C
190     
191     #ifdef __cplusplus
192     #error C++ is not yet supported.
193     extern "C" {
194     #endif	/* cplusplus */
195     
196     #include "h/skdrv1st.h"
197     #include "h/skdrv2nd.h"
198     
199     /* defines ********************************************************************/
200     
201     
202     #define CRC32_POLY	0xEDB88320UL	/* CRC32-Poly - XMAC: Little Endian */
203     #define HASH_BITS	6				/* #bits in hash */
204     #define	SK_MC_BIT	0x01
205     
206     /* Error numbers and messages. */
207     
208     #define SKERR_ADDR_E001		(SK_ERRBASE_ADDR + 0)
209     #define SKERR_ADDR_E001MSG	"Bad Flags."
210     #define SKERR_ADDR_E002		(SKERR_ADDR_E001 + 1)
211     #define SKERR_ADDR_E002MSG	"New Error."
212     
213     /* typedefs *******************************************************************/
214     
215     /* None. */
216     
217     /* global variables ***********************************************************/
218     
219     /* 64-bit hash values with all bits set. */
220     
221     SK_U16	OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
222     
223     /* local variables ************************************************************/
224     
225     #ifdef DEBUG
226     static int	Next0[SK_MAX_MACS] = {0, 0};
227     #endif	/* DEBUG */
228     
229     /* functions ******************************************************************/
230     
231     /******************************************************************************
232      *
233      *	SkAddrInit - initialize data, set state to init
234      *
235      * Description:
236      *
237      *	SK_INIT_DATA
238      *	============
239      *
240      *	This routine clears the multicast tables and resets promiscuous mode.
241      *	Some entries are reserved for the "logical MAC address", the
242      *	SK-RLMT multicast address, and the BPDU multicast address.
243      *
244      *
245      *	SK_INIT_IO
246      *	==========
247      *
248      *	All permanent MAC addresses are read from EPROM.
249      *	If the current MAC addresses are not already set in software,
250      *	they are set to the values of the permanent addresses.
251      *	The current addresses are written to the corresponding XMAC.
252      *
253      *
254      *	SK_INIT_RUN
255      *	===========
256      *
257      *	Nothing.
258      *
259      * Context:
260      *	init, pageable
261      *
262      * Returns:
263      *	SK_ADDR_SUCCESS
264      */
265     int	SkAddrInit(
266     SK_AC	*pAC,	/* the adapter context */
267     SK_IOC	IoC,	/* I/O context */
268     int		Level)	/* initialization level */
269     {
270     	int				j;
271     	SK_U32			i;
272     	SK_U8			*InAddr;
273     	SK_U16			*OutAddr;
274     	SK_ADDR_PORT	*pAPort;
275     
276     	switch (Level) {
277     	case SK_INIT_DATA:
278     		SK_MEMSET((char *)&pAC->Addr, 0, sizeof(SK_ADDR));
279     
280     		for (i = 0; i < SK_MAX_MACS; i++) {
281     			pAPort = &pAC->Addr.Port[i];
282     			pAPort->PromMode = SK_PROM_MODE_NONE;
283     
284     			pAPort->FirstExactMatchRlmt	= SK_ADDR_FIRST_MATCH_RLMT;
285     			pAPort->FirstExactMatchDrv	= SK_ADDR_FIRST_MATCH_DRV;
286     			pAPort->NextExactMatchRlmt	= SK_ADDR_FIRST_MATCH_RLMT;
287     			pAPort->NextExactMatchDrv	= SK_ADDR_FIRST_MATCH_DRV;
288     
289     #if 0
290     			/* Don't do this here ... */
291     
292     			/* Reset Promiscuous mode. */
293     			(void)SkAddrPromiscuousChange(
294     				pAC,
295     				IoC,
296     				i,
297     				SK_PROM_MODE_NONE);
298     #endif	/* 0 */
299     		}
300     		
301     #ifdef DEBUG
302     		for (i = 0; i < SK_MAX_MACS; i++) {
303     			if (pAC->Addr.Port[i].NextExactMatchRlmt <
304     				SK_ADDR_FIRST_MATCH_RLMT) {
305     				Next0[i] |= 4;
306     			}
307     		}
308     #endif	/* DEBUG */
309     
310     		/* pAC->Addr.InitDone = SK_INIT_DATA; */
311     		break;
312     
313     	case SK_INIT_IO:
314     		for (i = 0; i < SK_MAX_NETS; i++) {
315     			pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
316     		}
317     		
318     #ifdef DEBUG
319     		for (i = 0; i < SK_MAX_MACS; i++) {
320     			if (pAC->Addr.Port[i].NextExactMatchRlmt <
321     				SK_ADDR_FIRST_MATCH_RLMT) {
322     				Next0[i] |= 8;
323     			}
324     		}
325     #endif	/* DEBUG */
326     
327     		/* Read permanent logical MAC address from Control Register File. */
328     		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
329     			InAddr = (SK_U8 *)&pAC->Addr.Net[0].PermanentMacAddress.a[j];
330     			SK_IN8(IoC, B2_MAC_1 + j, InAddr);
331     		}
332     
333     		if (!pAC->Addr.Net[0].CurrentMacAddressSet) {
334     			/* Set the current logical MAC address to the permanent one. */
335     			pAC->Addr.Net[0].CurrentMacAddress =
336     				pAC->Addr.Net[0].PermanentMacAddress;
337     			pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE;
338     		}
339     
340     		/* Set the current logical MAC address. */
341     		pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] =
342     			pAC->Addr.Net[0].CurrentMacAddress;
343     
344     #if SK_MAX_NETS > 1
345     		/* Set logical MAC address for net 2 to (log | 3). */
346     		if (!pAC->Addr.Net[1].CurrentMacAddressSet) {
347     			pAC->Addr.Net[1].PermanentMacAddress =
348     				pAC->Addr.Net[0].PermanentMacAddress;
349     			pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3;
350     			/* Set the current logical MAC address to the permanent one. */
351     			pAC->Addr.Net[1].CurrentMacAddress =
352     				pAC->Addr.Net[1].PermanentMacAddress;
353     			pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE;
354     		}
355     #endif	/* SK_MAX_NETS > 1 */
356     
357     #ifdef xDEBUG
358     		SK_DBG_MSG(
359     			pAC,
360     			SK_DBGMOD_ADDR,
361     			SK_DBGCAT_INIT,
362     			("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
363     				pAC->Addr.PermanentMacAddress.a[0],
364     				pAC->Addr.PermanentMacAddress.a[1],
365     				pAC->Addr.PermanentMacAddress.a[2],
366     				pAC->Addr.PermanentMacAddress.a[3],
367     				pAC->Addr.PermanentMacAddress.a[4],
368     				pAC->Addr.PermanentMacAddress.a[5]))
369     		SK_DBG_MSG(
370     			pAC,
371     			SK_DBGMOD_ADDR,
372     			SK_DBGCAT_INIT,
373     			("Logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
374     				pAC->Addr.CurrentMacAddress.a[0],
375     				pAC->Addr.CurrentMacAddress.a[1],
376     				pAC->Addr.CurrentMacAddress.a[2],
377     				pAC->Addr.CurrentMacAddress.a[3],
378     				pAC->Addr.CurrentMacAddress.a[4],
379     				pAC->Addr.CurrentMacAddress.a[5]))
380     #endif	/* DEBUG */
381     
382     #if 0
383     		/* Don't do this here ... */
384     
385     		(void)SkAddrMcUpdate(pAC, IoC, pAC->Addr.ActivePort);
386     #endif	/* 0 */
387     
388     		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
389     			pAPort = &pAC->Addr.Port[i];
390     
391     			/* Read permanent port addresses from Control Register File. */
392     			for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
393     				InAddr = (SK_U8 *)&pAPort->PermanentMacAddress.a[j];
394     				SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
395     			}
396     
397     			if (!pAPort->CurrentMacAddressSet) {
398     				/*
399     				 * Set the current and previous physical MAC address
400     				 * of this port to its permanent MAC address.
401     				 */
402     				pAPort->CurrentMacAddress = pAPort->PermanentMacAddress;
403     				pAPort->PreviousMacAddress = pAPort->PermanentMacAddress;
404     				pAPort->CurrentMacAddressSet = SK_TRUE;
405     			}
406     
407     			/* Set port's current MAC addresses. */
408     			OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
409     			XM_OUTADDR(IoC, i, XM_SA, OutAddr);
410     
411     #ifdef xDEBUG
412     			SK_DBG_MSG(
413     				pAC,
414     				SK_DBGMOD_ADDR,
415     				SK_DBGCAT_INIT,
416     				("Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
417     					pAPort->PermanentMacAddress.a[0],
418     					pAPort->PermanentMacAddress.a[1],
419     					pAPort->PermanentMacAddress.a[2],
420     					pAPort->PermanentMacAddress.a[3],
421     					pAPort->PermanentMacAddress.a[4],
422     					pAPort->PermanentMacAddress.a[5]))
423     			SK_DBG_MSG(
424     				pAC,
425     				SK_DBGMOD_ADDR,
426     				SK_DBGCAT_INIT,
427     				("Phsical MAC Address: %02X %02X %02X %02X %02X %02X\n",
428     					pAPort->CurrentMacAddress.a[0],
429     					pAPort->CurrentMacAddress.a[1],
430     					pAPort->CurrentMacAddress.a[2],
431     					pAPort->CurrentMacAddress.a[3],
432     					pAPort->CurrentMacAddress.a[4],
433     					pAPort->CurrentMacAddress.a[5]))
434     #endif	/* DEBUG */
435     		}
436     		/* pAC->Addr.InitDone = SK_INIT_IO; */
437     		break;
438     
439     	case SK_INIT_RUN:
440     #ifdef DEBUG
441     		for (i = 0; i < SK_MAX_MACS; i++) {
442     			if (pAC->Addr.Port[i].NextExactMatchRlmt <
443     				SK_ADDR_FIRST_MATCH_RLMT) {
444     				Next0[i] |= 16;
445     			}
446     		}
447     #endif	/* DEBUG */
448     
449     		/* pAC->Addr.InitDone = SK_INIT_RUN; */
450     		break;
451     
452     	default:	/* error */
453     		break;
454     	}
455     
456     	return (SK_ADDR_SUCCESS);
457     }	/* SkAddrInit */
458     
459     
460     /******************************************************************************
461      *
462      *	SkAddrMcClear - clear the multicast table
463      *
464      * Description:
465      *	This routine clears the multicast table
466      *	(either entry 2 or entries 3-16 and InexactFilter) of the given port.
467      *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
468      *	immediately.
469      *
470      * Context:
471      *	runtime, pageable
472      *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
473      *	may be called after SK_INIT_IO without limitation
474      *
475      * Returns:
476      *	SK_ADDR_SUCCESS
477      *	SK_ADDR_ILLEGAL_PORT
478      */
479     int	SkAddrMcClear(
480     SK_AC	*pAC,		/* adapter context */
481     SK_IOC	IoC,		/* I/O context */
482     SK_U32	PortNumber,	/* Index of affected port */
483     int		Flags)		/* permanent/non-perm, sw-only */
484     {
485     	int i;
486     
487     	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
488     		return (SK_ADDR_ILLEGAL_PORT);
489     	}
490     
491     	if (Flags & SK_ADDR_PERMANENT) {
492     
493     		/* Clear RLMT multicast addresses. */
494     		pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
495     	}
496     	else {	/* not permanent => DRV */
497     
498     		/* Clear InexactFilter. */
499     
500     		for (i = 0; i < 8; i++) {
501     			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
502     		}
503     
504     		/* Clear DRV multicast addresses. */
505     
506     		pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
507     	}
508     
509     	if (!(Flags & SK_MC_SW_ONLY)) {
510     		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
511     	}
512     
513     	return (SK_ADDR_SUCCESS);
514     }	/* SkAddrMcClear */
515     
516     #ifndef SK_ADDR_CHEAT
517     
518     /******************************************************************************
519      *
520      *	SkCrc32McHash - hash multicast address
521      *
522      * Description:
523      *	This routine computes the hash value for a multicast address.
524      *
525      * Notes:
526      *	The code was adapted from the XaQti data sheet.
527      *
528      * Context:
529      *	runtime, pageable
530      *
531      * Returns:
532      *	Hash value of multicast address.
533      */
534     unsigned SkCrc32McHash(
535     unsigned char *pMc)	/* Multicast address */
536     {
537     	unsigned Idx;
538     	unsigned Bit;
539     	unsigned Data;
540     	unsigned Crc;
541     
542     	Crc = 0xFFFFFFFFUL;
543     	for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
544     		Data = *pMc++;
545     		for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
546     			Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? CRC32_POLY : 0);
547     		}
548     	}
549     
550     	return (Crc & ((1 << HASH_BITS) - 1));
551     }	/* SkCrc32McHash */
552     
553     #endif	/* not SK_ADDR_CHEAT */
554     
555     /******************************************************************************
556      *
557      *	SkAddrMcAdd - add a multicast address to a port
558      *
559      * Description:
560      *	This routine enables reception for a given address on the given port.
561      *
562      * Notes:
563      *	The return code is only valid for SK_PROM_MODE_NONE.
564      *
565      *	In the current version, only RLMT may add addresses to the non-active
566      *	port.
567      *
568      *	The multicast bit is only checked if there are no free exact match
569      *	entries.
570      *
571      * Context:
572      *	runtime, pageable
573      *	may be called after SK_INIT_DATA
574      *
575      * Returns:
576      *	SK_MC_FILTERING_EXACT
577      *	SK_MC_FILTERING_INEXACT
578      *	SK_MC_ILLEGAL_ADDRESS
579      *	SK_MC_ILLEGAL_PORT
580      *	SK_MC_RLMT_OVERFLOW
581      */
582     int	SkAddrMcAdd(
583     SK_AC		*pAC,		/* adapter context */
584     SK_IOC		IoC,		/* I/O context */
585     SK_U32		PortNumber,	/* Port Number */
586     SK_MAC_ADDR	*pMc,		/* multicast address to be added */
587     int			Flags)		/* permanent/non-permanent */
588     {
589     	int	i;
590     	SK_U8	Inexact;
591     #ifndef SK_ADDR_CHEAT
592     	unsigned HashBit;
593     #endif	/* !defined(SK_ADDR_CHEAT) */
594     
595     	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
596     		return (SK_ADDR_ILLEGAL_PORT);
597     	}
598     
599     	if (Flags & SK_ADDR_PERMANENT) {
600     #ifdef DEBUG
601     		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
602     			SK_ADDR_FIRST_MATCH_RLMT) {
603     			Next0[PortNumber] |= 1;
604     			return (SK_MC_RLMT_OVERFLOW);
605     		}
606     #endif	/* DEBUG */
607     		
608     		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt >
609     			SK_ADDR_LAST_MATCH_RLMT) {
610     			return (SK_MC_RLMT_OVERFLOW);
611     		}
612     
613     		/* Set an RLMT multicast address. */
614     
615     		pAC->Addr.Port[PortNumber].Exact[
616     			pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
617     
618     		return (SK_MC_FILTERING_EXACT);
619     	}
620     
621     #if 0
622     	/* Not PERMANENT => DRV */
623     	if (PortNumber != pAC->Addr.ActivePort) {
624     		/* Only RLMT is allowed to do this. */
625     		return (SK_MC_ILLEGAL_PORT);
626     	}
627     #endif	/* 0 */
628     
629     #ifdef DEBUG
630     	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
631     		SK_ADDR_FIRST_MATCH_DRV) {
632     			Next0[PortNumber] |= 2;
633     		return (SK_MC_RLMT_OVERFLOW);
634     	}
635     #endif	/* DEBUG */
636     	
637     	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
638     
639     		/* Set exact match entry. */
640     		pAC->Addr.Port[PortNumber].Exact[
641     			pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
642     
643     		/* Clear InexactFilter. */
644     		for (i = 0; i < 8; i++) {
645     			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
646     		}
647     	}
648     	else {
649     		if (!(pMc->a[0] & SK_MC_BIT)) {
650     			/*
651     			 * Hashing only possible with
652     			 * multicast addresses.
653     			 */
654     			return (SK_MC_ILLEGAL_ADDRESS);
655     		}
656     #ifndef SK_ADDR_CHEAT
657     		/* Compute hash value of address. */
658     		HashBit = 63 - SkCrc32McHash(&pMc->a[0]);
659     
660     		/* Add bit to InexactFilter. */
661     		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
662     			1 << (HashBit % 8);
663     #else	/* SK_ADDR_CHEAT */
664     		/* Set all bits in InexactFilter. */
665     		for (i = 0; i < 8; i++) {
666     			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
667     		}
668     #endif	/* SK_ADDR_CHEAT */
669     	}
670     
671     	for (Inexact = 0, i = 0; i < 8; i++) {
672     		Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
673     	}
674     
675     	if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) {
676     		return (SK_MC_FILTERING_EXACT);
677     	}
678     	else {
679     		return (SK_MC_FILTERING_INEXACT);
680     	}
681     }	/* SkAddrMcAdd */
682     
683     
684     /******************************************************************************
685      *
686      *	SkAddrMcUpdate - update the HW MC address table and set the MAC address
687      *
688      * Description:
689      *	This routine enables reception of the addresses contained in a local
690      *	table for a given port.
691      *	It also programs the port's current physical MAC address.
692      *
693      * Notes:
694      *	The return code is only valid for SK_PROM_MODE_NONE.
695      *
696      * Context:
697      *	runtime, pageable
698      *	may be called after SK_INIT_IO
699      *
700      * Returns:
701      *	SK_MC_FILTERING_EXACT
702      *	SK_MC_FILTERING_INEXACT
703      *	SK_ADDR_ILLEGAL_PORT
704      */
705     int	SkAddrMcUpdate(
706     SK_AC	*pAC,		/* adapter context */
707     SK_IOC	IoC,		/* I/O context */
708     SK_U32	PortNumber)	/* Port Number */
709     {
710     	SK_U32			i;
711     	SK_U8			Inexact;
712     	SK_U16			*OutAddr;
713     	SK_U16			LoMode;		/* Lower 16 bits of XMAC Mode Reg. */
714     	SK_ADDR_PORT	*pAPort;
715     
716     	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
717     		return (SK_ADDR_ILLEGAL_PORT);
718     	}
719     
720     	SK_DBG_MSG(
721     		pAC,
722     		SK_DBGMOD_ADDR,
723     		SK_DBGCAT_CTRL,
724     		("SkAddrMcUpdate on Port %u.\n", PortNumber))
725     	
726     	pAPort = &pAC->Addr.Port[PortNumber];
727     
728     #ifdef DEBUG
729     		SK_DBG_MSG(
730     			pAC,
731     			SK_DBGMOD_ADDR,
732     			SK_DBGCAT_CTRL,
733     			("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
734     #endif	/* DEBUG */
735     
736     	/* Start with 0 to also program the logical MAC address. */
737     	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
738     		/* Set exact match address i on HW. */
739     		OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
740     		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
741     	}
742     
743     	/* Clear other permanent exact match addresses on HW. */
744     	if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
745     		SkXmClrExactAddr(
746     			pAC,
747     			IoC,
748     			PortNumber,
749     			pAPort->NextExactMatchRlmt,
750     			SK_ADDR_LAST_MATCH_RLMT);
751     	}
752     
753     	for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
754     		OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
755     		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
756     	}
757     
758     	/* Clear other non-permanent exact match addresses on HW. */
759     	if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
760     		SkXmClrExactAddr(
761     			pAC,
762     			IoC,
763     			PortNumber,
764     			pAPort->NextExactMatchDrv,
765     			SK_ADDR_LAST_MATCH_DRV);
766     	}
767     
768     	for (Inexact = 0, i = 0; i < 8; i++) {
769     		Inexact |= pAPort->InexactFilter.Bytes[i];
770     	}
771     
772     	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
773     		/* Set all bits in 64-bit hash register. */
774     		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
775     
776     		/* Set bit 15 in mode register. */
777     		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
778     		LoMode |= XM_MD_ENA_HSH;
779     		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
780     	}
781     	else if (Inexact != 0) {
782     		/* Set 64-bit hash register to InexactFilter. */
783     		XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
784     
785     		/* Set bit 15 in mode register. */
786     		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
787     		LoMode |= XM_MD_ENA_HSH;
788     		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
789     	}
790     	else {
791     		/* Clear bit 15 in mode register. */
792     		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
793     		LoMode &= ~XM_MD_ENA_HSH;
794     		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
795     	}
796     
797     	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
798     		(void)SkAddrPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
799     	}
800     
801     	/* Set port's current MAC address. */
802     	OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
803     	XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
804     
805     #ifdef xDEBUG
806     	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
807     		SK_U8		InAddr8[6];
808     		SK_U16		*InAddr;
809     
810     		/* Get exact match address i from port PortNumber. */
811     		InAddr = (SK_U16 *)&InAddr8[0];
812     		XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
813     		SK_DBG_MSG(
814     			pAC,
815     			SK_DBGMOD_ADDR,
816     			SK_DBGCAT_CTRL,
817     			("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
818     				i,
819     				PortNumber,
820     				InAddr8[0],
821     				InAddr8[1],
822     				InAddr8[2],
823     				InAddr8[3],
824     				InAddr8[4],
825     				InAddr8[5],
826     				pAPort->Exact[i].a[0],
827     				pAPort->Exact[i].a[1],
828     				pAPort->Exact[i].a[2],
829     				pAPort->Exact[i].a[3],
830     				pAPort->Exact[i].a[4],
831     				pAPort->Exact[i].a[5]))
832     	}
833     #endif	/* DEBUG */		
834     
835     	/* Determine return value. */
836     	if (Inexact == 0 && pAPort->PromMode == 0) {
837     		return (SK_MC_FILTERING_EXACT);
838     	}
839     	else {
840     		return (SK_MC_FILTERING_INEXACT);
841     	}
842     }	/* SkAddrMcUpdate */
843     
844     
845     /******************************************************************************
846      *
847      *	SkAddrOverride - override a port's MAC address
848      *
849      * Description:
850      *	This routine overrides the MAC address of one port.
851      *
852      * Context:
853      *	runtime, pageable
854      *	may be called after SK_INIT_IO
855      *
856      * Returns:
857      *	SK_ADDR_SUCCESS if successful.
858      *	SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address.
859      *	SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address.
860      *	SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before.
861      */
862     int	SkAddrOverride(
863     SK_AC		*pAC,		/* adapter context */
864     SK_IOC		IoC,		/* I/O context */
865     SK_U32		PortNumber,	/* Port Number */
866     SK_MAC_ADDR	*pNewAddr,	/* new MAC address */
867     int			Flags)		/* logical/physical MAC address */
868     {
869     	SK_EVPARA	Para;
870     	SK_U32		NetNumber;
871     	SK_U32		i;
872     	SK_U16		*OutAddr;
873     
874     	NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
875     
876     	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
877     		return (SK_ADDR_ILLEGAL_PORT);
878     	}
879     
880     	if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) {
881     		return (SK_ADDR_MULTICAST_ADDRESS);
882     	}
883     
884     	if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) {
885     		return (SK_ADDR_TOO_EARLY);
886     	}
887     
888     	if (Flags & SK_ADDR_SET_LOGICAL) {	/* Activate logical MAC address. */
889     		/* Parameter *pNewAddr is ignored. */
890     		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
891     			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
892     				return (SK_ADDR_TOO_EARLY);
893     			}
894     		}
895     
896     		/* Set PortNumber to number of net's active port. */
897     		PortNumber = pAC->Rlmt.Net[NetNumber].
898     			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
899     
900     		pAC->Addr.Port[PortNumber].Exact[0] =
901     			pAC->Addr.Net[NetNumber].CurrentMacAddress;
902     
903     		/* Write address to first exact match entry of active port. */
904     		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
905     	}
906     	else if (Flags & SK_ADDR_CLEAR_LOGICAL) {
907     		/* Deactivate logical MAC address. */
908     		/* Parameter *pNewAddr is ignored. */
909     		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
910     			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
911     				return (SK_ADDR_TOO_EARLY);
912     			}
913     		}
914     
915     		/* Set PortNumber to number of net's active port. */
916     		PortNumber = pAC->Rlmt.Net[NetNumber].
917     			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
918     
919     		for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) {
920     			pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0;
921     		}
922     
923     		/* Write address to first exact match entry of active port. */
924     		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
925     	}
926     	else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical MAC address. */
927     		if (SK_ADDR_EQUAL(pNewAddr->a,
928     			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
929     			return (SK_ADDR_DUPLICATE_ADDRESS);
930     		}
931     
932     		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
933     			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
934     				return (SK_ADDR_TOO_EARLY);
935     			}
936     
937     			if (SK_ADDR_EQUAL(pNewAddr->a,
938     				pAC->Addr.Port[i].CurrentMacAddress.a)) {
939     				if (i == PortNumber) {
940     					return (SK_ADDR_SUCCESS);
941     				}
942     				else {
943     					return (SK_ADDR_DUPLICATE_ADDRESS);
944     				}
945     			}
946     		}
947     
948     		pAC->Addr.Port[PortNumber].PreviousMacAddress =
949     			pAC->Addr.Port[PortNumber].CurrentMacAddress;
950     		pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
951     
952     		/* Change port's address. */
953     		OutAddr = (SK_U16 *)pNewAddr;
954     		XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
955     
956     		/* Report address change to RLMT. */
957     		Para.Para32[0] = PortNumber;
958     		Para.Para32[0] = -1;
959     		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
960     	}
961     	else {	/* Logical MAC address. */
962     		if (SK_ADDR_EQUAL(pNewAddr->a,
963     			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
964     			return (SK_ADDR_SUCCESS);
965     		}
966     		
967     		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
968     			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
969     				return (SK_ADDR_TOO_EARLY);
970     			}
971     
972     			if (SK_ADDR_EQUAL(pNewAddr->a,
973     				pAC->Addr.Port[i].CurrentMacAddress.a)) {
974     				return (SK_ADDR_DUPLICATE_ADDRESS);
975     			}
976     		}
977     
978     		/* Set PortNumber to number of net's active port. */
979     		PortNumber = pAC->Rlmt.Net[NetNumber].
980     			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
981     
982     		pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
983     		pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
984     
985     #ifdef DEBUG
986     		SK_DBG_MSG(
987     			pAC,
988     			SK_DBGMOD_ADDR,
989     			SK_DBGCAT_CTRL,
990     			("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
991     				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0],
992     				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1],
993     				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2],
994     				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3],
995     				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4],
996     				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5]))
997     		SK_DBG_MSG(
998     			pAC,
999     			SK_DBGMOD_ADDR,
1000     			SK_DBGCAT_CTRL,
1001     			("New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
1002     				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
1003     				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
1004     				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
1005     				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3],
1006     				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4],
1007     				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5]))
1008     #endif	/* DEBUG */
1009     
1010     		/* Write address to first exact match entry of active port. */
1011     		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
1012     	}
1013     
1014     	return (SK_ADDR_SUCCESS);
1015     }	/* SkAddrOverride */
1016     
1017     
1018     /******************************************************************************
1019      *
1020      *	SkAddrPromiscuousChange - set promiscuous mode for given port
1021      *
1022      * Description:
1023      *	This routine manages promiscuous mode:
1024      *	- none
1025      *	- all LLC frames
1026      *	- all MC frames
1027      *
1028      * Context:
1029      *	runtime, pageable
1030      *	may be called after SK_INIT_IO
1031      *
1032      * Returns:
1033      *	SK_ADDR_SUCCESS
1034      *	SK_ADDR_ILLEGAL_PORT
1035      */
1036     int	SkAddrPromiscuousChange(
1037     SK_AC	*pAC,			/* adapter context */
1038     SK_IOC	IoC,			/* I/O context */
1039     SK_U32	PortNumber,		/* port whose promiscuous mode changes */
1040     int		NewPromMode)	/* new promiscuous mode */
1041     {
1042     	int			i;
1043     	SK_BOOL		InexactModeBit;
1044     	SK_U8		Inexact;
1045     	SK_U8		HwInexact;
1046     	SK_FILTER64	HwInexactFilter;
1047     	SK_U16		LoMode;		/* Lower 16 bits of XMAC Mode Register. */
1048     	int			CurPromMode = SK_PROM_MODE_NONE;
1049     
1050     	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
1051     		return (SK_ADDR_ILLEGAL_PORT);
1052     	}
1053     
1054     	/* Read CurPromMode from Hardware. */
1055     	XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1056     
1057     	if (LoMode & XM_MD_ENA_PROM) {
1058     		CurPromMode |= SK_PROM_MODE_LLC;
1059     	}
1060     	
1061     	for (Inexact = 0xFF, i = 0; i < 8; i++) {
1062     		Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
1063     	}
1064     	if (Inexact == 0xFF) {
1065     		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
1066     	}
1067     	else {
1068     		/* Read InexactModeBit (bit 15 in mode register). */
1069     		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1070     		
1071     		InexactModeBit = (LoMode & XM_MD_ENA_HSH) != 0;
1072     
1073     		/* Read 64-bit hash register from HW. */
1074     		XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
1075     
1076     		for (HwInexact = 0xFF, i = 0; i < 8; i++) {
1077     			HwInexact &= HwInexactFilter.Bytes[i];
1078     		}
1079     
1080     		if (InexactModeBit && (HwInexact == 0xFF)) {
1081     			CurPromMode |= SK_PROM_MODE_ALL_MC;
1082     		}
1083     	}
1084     
1085     	pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
1086     
1087     	if (NewPromMode == CurPromMode) {
1088     		return (SK_ADDR_SUCCESS);
1089     	}
1090     
1091     	if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
1092     		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC. */
1093     		/* Set all bits in 64-bit hash register. */
1094     		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
1095     
1096     		/* Set bit 15 in mode register. */
1097     		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1098     		LoMode |= XM_MD_ENA_HSH;
1099     		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1100     	}
1101     	else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
1102     		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm MC. */
1103     		for (Inexact = 0, i = 0; i < 8; i++) {
1104     			Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
1105     		}
1106     		if (Inexact == 0) {
1107     			/* Clear bit 15 in mode register. */
1108     			XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1109     			LoMode &= ~XM_MD_ENA_HSH;
1110     			XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1111     		}
1112     		else {
1113     			/* Set 64-bit hash register to InexactFilter. */
1114     			XM_OUTHASH(
1115     				IoC,
1116     				PortNumber,
1117     				XM_HSM,
1118     				&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
1119     
1120     			/* Set bit 15 in mode register. */
1121     			XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1122     			LoMode |= XM_MD_ENA_HSH;
1123     			XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1124     		}
1125     	}
1126     
1127     	if ((NewPromMode & SK_PROM_MODE_LLC) &&
1128     		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
1129     		/* Set promiscuous bit in mode register. */
1130     		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1131     
1132     #if 0
1133     		/* Receive MAC frames. */
1134     		LoMode |= XM_MD_RX_MCTRL;
1135     #endif	/* 0 */
1136     
1137     		LoMode |= XM_MD_ENA_PROM;
1138     		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1139     	}
1140     	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
1141     		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC. */
1142     		/* Clear promiscuous bit in mode register. */
1143     		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
1144     
1145     #if 0
1146     		/* Don't receive MAC frames. */
1147     		LoMode &= ~XM_MD_RX_MCTRL;
1148     #endif	/* 0 */
1149     		
1150     		LoMode &= ~XM_MD_ENA_PROM;
1151     		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
1152     	}
1153     	
1154     	return (SK_ADDR_SUCCESS);
1155     }	/* SkAddrPromiscuousChange */
1156     
1157     
1158     /******************************************************************************
1159      *
1160      *	SkAddrSwap - swap address info
1161      *
1162      * Description:
1163      *	This routine swaps address info of two ports.
1164      *
1165      * Context:
1166      *	runtime, pageable
1167      *	may be called after SK_INIT_IO
1168      *
1169      * Returns:
1170      *	SK_ADDR_SUCCESS
1171      *	SK_ADDR_ILLEGAL_PORT
1172      */
1173     int	SkAddrSwap(
1174     SK_AC	*pAC,			/* adapter context */
1175     SK_IOC	IoC,			/* I/O context */
1176     SK_U32	FromPortNumber,	/* Port1 Index */
1177     SK_U32	ToPortNumber)		/* Port2 Index */
1178     {
1179     	int			i;
1180     	SK_U8		Byte;
1181     	SK_MAC_ADDR	MacAddr;
1182     	SK_U32		DWord;
1183     
1184     	if (FromPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
1185     		return (SK_ADDR_ILLEGAL_PORT);
1186     	}
1187     
1188     	if (ToPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
1189     		return (SK_ADDR_ILLEGAL_PORT);
1190     	}
1191     
1192     	if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) {
1193     		return (SK_ADDR_ILLEGAL_PORT);
1194     	}
1195     
1196     	/*
1197     	 * Swap
1198     	 * - Exact Match Entries
1199     	 * - FirstExactMatchRlmt;
1200     	 * - NextExactMatchRlmt;
1201     	 * - FirstExactMatchDrv;
1202     	 * - NextExactMatchDrv;
1203     	 * - 64-bit filter
1204     	 * - Promiscuous Mode
1205     	 * of ports.
1206     	 */
1207     
1208     	for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
1209     		MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i];
1210     		pAC->Addr.Port[FromPortNumber].Exact[i] =
1211     			pAC->Addr.Port[ToPortNumber].Exact[i];
1212     		pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr;
1213     	}
1214     
1215     	for (i = 0; i < 8; i++) {
1216     		Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i];
1217     		pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] =
1218     			pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i];
1219     		pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte;
1220     	}
1221     
1222     	i = pAC->Addr.Port[FromPortNumber].PromMode;
1223     	pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode;
1224     	pAC->Addr.Port[ToPortNumber].PromMode = i;
1225     
1226     	DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt;
1227     	pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt =
1228     		pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt;
1229     	pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord;
1230     
1231     	DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt;
1232     	pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt =
1233     		pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt;
1234     	pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord;
1235     
1236     	DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv;
1237     	pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv =
1238     		pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv;
1239     	pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord;
1240     
1241     	DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv;
1242     	pAC->Addr.Port[FromPortNumber].NextExactMatchDrv =
1243     		pAC->Addr.Port[ToPortNumber].NextExactMatchDrv;
1244     	pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord;
1245     
1246     	/* CAUTION: Solution works if only ports of one adapter are in use. */
1247     	for (i = 0; (SK_U32)i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].
1248     		Net->NetNumber].NumPorts; i++) {
1249     		if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
1250     			Port[i]->PortNumber == ToPortNumber) {
1251     			pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
1252     				ActivePort = i;
1253     			/* 20001207 RA: Was "ToPortNumber;". */
1254     
1255     		}
1256     	}
1257     	(void)SkAddrMcUpdate(pAC, IoC, FromPortNumber);
1258     	(void)SkAddrMcUpdate(pAC, IoC, ToPortNumber);
1259     
1260     	return (SK_ADDR_SUCCESS);
1261     }	/* SkAddrSwap */
1262     
1263     #ifdef __cplusplus
1264     }
1265     #endif	/* __cplusplus */
1266     
1267