| /****************************************************************************** | 
 |  * | 
 |  * Name:	skaddr.c | 
 |  * Project:	Gigabit Ethernet Adapters, ADDR-Module | 
 |  * Version:	$Revision: 1.52 $ | 
 |  * Date:	$Date: 2003/06/02 13:46:15 $ | 
 |  * Purpose:	Manage Addresses (Multicast and Unicast) and Promiscuous Mode. | 
 |  * | 
 |  ******************************************************************************/ | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	(C)Copyright 1998-2002 SysKonnect GmbH. | 
 |  *	(C)Copyright 2002-2003 Marvell. | 
 |  * | 
 |  *	This program is free software; you can redistribute it and/or modify | 
 |  *	it under the terms of the GNU General Public License as published by | 
 |  *	the Free Software Foundation; either version 2 of the License, or | 
 |  *	(at your option) any later version. | 
 |  * | 
 |  *	The information in this file is provided "AS IS" without warranty. | 
 |  * | 
 |  ******************************************************************************/ | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  * Description: | 
 |  * | 
 |  * This module is intended to manage multicast addresses, address override, | 
 |  * and promiscuous mode on GEnesis and Yukon adapters. | 
 |  * | 
 |  * Address Layout: | 
 |  *	port address:		physical MAC address | 
 |  *	1st exact match:	logical MAC address (GEnesis only) | 
 |  *	2nd exact match:	RLMT multicast (GEnesis only) | 
 |  *	exact match 3-13:	OS-specific multicasts (GEnesis only) | 
 |  * | 
 |  * Include File Hierarchy: | 
 |  * | 
 |  *	"skdrv1st.h" | 
 |  *	"skdrv2nd.h" | 
 |  * | 
 |  ******************************************************************************/ | 
 |  | 
 | #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM)))) | 
 | static const char SysKonnectFileId[] = | 
 | 	"@(#) $Id: skaddr.c,v 1.52 2003/06/02 13:46:15 tschilli Exp $ (C) Marvell."; | 
 | #endif /* DEBUG ||!LINT || !SK_SLIM */ | 
 |  | 
 | #define __SKADDR_C | 
 |  | 
 | #ifdef __cplusplus | 
 | extern "C" { | 
 | #endif	/* cplusplus */ | 
 |  | 
 | #include "h/skdrv1st.h" | 
 | #include "h/skdrv2nd.h" | 
 |  | 
 | /* defines ********************************************************************/ | 
 |  | 
 |  | 
 | #define XMAC_POLY	0xEDB88320UL	/* CRC32-Poly - XMAC: Little Endian */ | 
 | #define GMAC_POLY	0x04C11DB7L	/* CRC16-Poly - GMAC: Little Endian */ | 
 | #define HASH_BITS	6				/* #bits in hash */ | 
 | #define	SK_MC_BIT	0x01 | 
 |  | 
 | /* Error numbers and messages. */ | 
 |  | 
 | #define SKERR_ADDR_E001		(SK_ERRBASE_ADDR + 0) | 
 | #define SKERR_ADDR_E001MSG	"Bad Flags." | 
 | #define SKERR_ADDR_E002		(SKERR_ADDR_E001 + 1) | 
 | #define SKERR_ADDR_E002MSG	"New Error." | 
 |  | 
 | /* typedefs *******************************************************************/ | 
 |  | 
 | /* None. */ | 
 |  | 
 | /* global variables ***********************************************************/ | 
 |  | 
 | /* 64-bit hash values with all bits set. */ | 
 |  | 
 | static const SK_U16	OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; | 
 |  | 
 | /* local variables ************************************************************/ | 
 |  | 
 | #ifdef DEBUG | 
 | static int	Next0[SK_MAX_MACS] = {0}; | 
 | #endif	/* DEBUG */ | 
 |  | 
 | static int SkAddrGmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, | 
 | 			   SK_MAC_ADDR *pMc, int Flags); | 
 | static int SkAddrGmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, | 
 | 			     int Flags); | 
 | static int SkAddrGmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber); | 
 | static int SkAddrGmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC, | 
 | 				       SK_U32 PortNumber, int NewPromMode); | 
 | static int SkAddrXmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, | 
 | 			   SK_MAC_ADDR *pMc, int Flags); | 
 | static int SkAddrXmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, | 
 | 			     int Flags); | 
 | static int SkAddrXmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber); | 
 | static int SkAddrXmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC, | 
 | 				       SK_U32 PortNumber, int NewPromMode); | 
 |  | 
 | /* functions ******************************************************************/ | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrInit - initialize data, set state to init | 
 |  * | 
 |  * Description: | 
 |  * | 
 |  *	SK_INIT_DATA | 
 |  *	============ | 
 |  * | 
 |  *	This routine clears the multicast tables and resets promiscuous mode. | 
 |  *	Some entries are reserved for the "logical MAC address", the | 
 |  *	SK-RLMT multicast address, and the BPDU multicast address. | 
 |  * | 
 |  * | 
 |  *	SK_INIT_IO | 
 |  *	========== | 
 |  * | 
 |  *	All permanent MAC addresses are read from EPROM. | 
 |  *	If the current MAC addresses are not already set in software, | 
 |  *	they are set to the values of the permanent addresses. | 
 |  *	The current addresses are written to the corresponding MAC. | 
 |  * | 
 |  * | 
 |  *	SK_INIT_RUN | 
 |  *	=========== | 
 |  * | 
 |  *	Nothing. | 
 |  * | 
 |  * Context: | 
 |  *	init, pageable | 
 |  * | 
 |  * Returns: | 
 |  *	SK_ADDR_SUCCESS | 
 |  */ | 
 | int	SkAddrInit( | 
 | SK_AC	*pAC,	/* the adapter context */ | 
 | SK_IOC	IoC,	/* I/O context */ | 
 | int		Level)	/* initialization level */ | 
 | { | 
 | 	int			j; | 
 | 	SK_U32		i; | 
 | 	SK_U8		*InAddr; | 
 | 	SK_U16		*OutAddr; | 
 | 	SK_ADDR_PORT	*pAPort; | 
 |  | 
 | 	switch (Level) { | 
 | 	case SK_INIT_DATA: | 
 | 		SK_MEMSET((char *) &pAC->Addr, (SK_U8) 0, | 
 |             (SK_U16) sizeof(SK_ADDR)); | 
 |  | 
 | 		for (i = 0; i < SK_MAX_MACS; i++) { | 
 | 			pAPort = &pAC->Addr.Port[i]; | 
 | 			pAPort->PromMode = SK_PROM_MODE_NONE; | 
 | 			 | 
 | 			pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; | 
 | 			pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; | 
 | 			pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; | 
 | 			pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; | 
 | 		} | 
 | #ifdef xDEBUG | 
 | 		for (i = 0; i < SK_MAX_MACS; i++) { | 
 | 			if (pAC->Addr.Port[i].NextExactMatchRlmt < | 
 | 				SK_ADDR_FIRST_MATCH_RLMT) { | 
 | 				Next0[i] |= 4; | 
 | 			} | 
 | 		} | 
 | #endif	/* DEBUG */ | 
 | 		/* pAC->Addr.InitDone = SK_INIT_DATA; */ | 
 | 		break; | 
 |  | 
 |     case SK_INIT_IO: | 
 | #ifndef SK_NO_RLMT | 
 | 		for (i = 0; i < SK_MAX_NETS; i++) { | 
 | 			pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort; | 
 | 		} | 
 | #endif /* !SK_NO_RLMT */ | 
 | #ifdef xDEBUG | 
 | 		for (i = 0; i < SK_MAX_MACS; i++) { | 
 | 			if (pAC->Addr.Port[i].NextExactMatchRlmt < | 
 | 				SK_ADDR_FIRST_MATCH_RLMT) { | 
 | 				Next0[i] |= 8; | 
 | 			} | 
 | 		} | 
 | #endif	/* DEBUG */ | 
 | 		 | 
 | 		/* Read permanent logical MAC address from Control Register File. */ | 
 | 		for (j = 0; j < SK_MAC_ADDR_LEN; j++) { | 
 | 			InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j]; | 
 | 			SK_IN8(IoC, B2_MAC_1 + j, InAddr); | 
 | 		} | 
 |  | 
 | 		if (!pAC->Addr.Net[0].CurrentMacAddressSet) { | 
 | 			/* Set the current logical MAC address to the permanent one. */ | 
 | 			pAC->Addr.Net[0].CurrentMacAddress = | 
 | 				pAC->Addr.Net[0].PermanentMacAddress; | 
 | 			pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE; | 
 | 		} | 
 |  | 
 | 		/* Set the current logical MAC address. */ | 
 | 		pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] = | 
 | 			pAC->Addr.Net[0].CurrentMacAddress; | 
 | #if SK_MAX_NETS > 1 | 
 | 		/* Set logical MAC address for net 2 to (log | 3). */ | 
 | 		if (!pAC->Addr.Net[1].CurrentMacAddressSet) { | 
 | 			pAC->Addr.Net[1].PermanentMacAddress = | 
 | 				pAC->Addr.Net[0].PermanentMacAddress; | 
 | 			pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3; | 
 | 			/* Set the current logical MAC address to the permanent one. */ | 
 | 			pAC->Addr.Net[1].CurrentMacAddress = | 
 | 				pAC->Addr.Net[1].PermanentMacAddress; | 
 | 			pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE; | 
 | 		} | 
 | #endif	/* SK_MAX_NETS > 1 */ | 
 |  | 
 | #ifdef DEBUG | 
 | 		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { | 
 | 			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, | 
 | 				("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n", | 
 | 					i, | 
 | 					pAC->Addr.Net[i].PermanentMacAddress.a[0], | 
 | 					pAC->Addr.Net[i].PermanentMacAddress.a[1], | 
 | 					pAC->Addr.Net[i].PermanentMacAddress.a[2], | 
 | 					pAC->Addr.Net[i].PermanentMacAddress.a[3], | 
 | 					pAC->Addr.Net[i].PermanentMacAddress.a[4], | 
 | 					pAC->Addr.Net[i].PermanentMacAddress.a[5])) | 
 | 			 | 
 | 			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, | 
 | 				("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n", | 
 | 					i, | 
 | 					pAC->Addr.Net[i].CurrentMacAddress.a[0], | 
 | 					pAC->Addr.Net[i].CurrentMacAddress.a[1], | 
 | 					pAC->Addr.Net[i].CurrentMacAddress.a[2], | 
 | 					pAC->Addr.Net[i].CurrentMacAddress.a[3], | 
 | 					pAC->Addr.Net[i].CurrentMacAddress.a[4], | 
 | 					pAC->Addr.Net[i].CurrentMacAddress.a[5])) | 
 | 		} | 
 | #endif	/* DEBUG */ | 
 |  | 
 | 		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { | 
 | 			pAPort = &pAC->Addr.Port[i]; | 
 |  | 
 | 			/* Read permanent port addresses from Control Register File. */ | 
 | 			for (j = 0; j < SK_MAC_ADDR_LEN; j++) { | 
 | 				InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j]; | 
 | 				SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr); | 
 | 			} | 
 |  | 
 | 			if (!pAPort->CurrentMacAddressSet) { | 
 | 				/* | 
 | 				 * Set the current and previous physical MAC address | 
 | 				 * of this port to its permanent MAC address. | 
 | 				 */ | 
 | 				pAPort->CurrentMacAddress = pAPort->PermanentMacAddress; | 
 | 				pAPort->PreviousMacAddress = pAPort->PermanentMacAddress; | 
 | 				pAPort->CurrentMacAddressSet = SK_TRUE; | 
 | 			} | 
 |  | 
 | 			/* Set port's current physical MAC address. */ | 
 | 			OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0]; | 
 | #ifdef GENESIS | 
 | 			if (pAC->GIni.GIGenesis) { | 
 | 				XM_OUTADDR(IoC, i, XM_SA, OutAddr); | 
 | 			} | 
 | #endif /* GENESIS */ | 
 | #ifdef YUKON | 
 | 			if (!pAC->GIni.GIGenesis) { | 
 | 				GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr); | 
 | 			} | 
 | #endif /* YUKON */ | 
 | #ifdef DEBUG | 
 | 			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, | 
 | 				("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", | 
 | 					pAPort->PermanentMacAddress.a[0], | 
 | 					pAPort->PermanentMacAddress.a[1], | 
 | 					pAPort->PermanentMacAddress.a[2], | 
 | 					pAPort->PermanentMacAddress.a[3], | 
 | 					pAPort->PermanentMacAddress.a[4], | 
 | 					pAPort->PermanentMacAddress.a[5])) | 
 | 			 | 
 | 			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, | 
 | 				("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", | 
 | 					pAPort->CurrentMacAddress.a[0], | 
 | 					pAPort->CurrentMacAddress.a[1], | 
 | 					pAPort->CurrentMacAddress.a[2], | 
 | 					pAPort->CurrentMacAddress.a[3], | 
 | 					pAPort->CurrentMacAddress.a[4], | 
 | 					pAPort->CurrentMacAddress.a[5])) | 
 | #endif /* DEBUG */ | 
 | 		} | 
 | 		/* pAC->Addr.InitDone = SK_INIT_IO; */ | 
 | 		break; | 
 |  | 
 | 	case SK_INIT_RUN: | 
 | #ifdef xDEBUG | 
 | 		for (i = 0; i < SK_MAX_MACS; i++) { | 
 | 			if (pAC->Addr.Port[i].NextExactMatchRlmt < | 
 | 				SK_ADDR_FIRST_MATCH_RLMT) { | 
 | 				Next0[i] |= 16; | 
 | 			} | 
 | 		} | 
 | #endif	/* DEBUG */ | 
 |  | 
 | 		/* pAC->Addr.InitDone = SK_INIT_RUN; */ | 
 | 		break; | 
 |  | 
 | 	default:	/* error */ | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	return (SK_ADDR_SUCCESS); | 
 | 	 | 
 | }	/* SkAddrInit */ | 
 |  | 
 | #ifndef SK_SLIM | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrMcClear - clear the multicast table | 
 |  * | 
 |  * Description: | 
 |  *	This routine clears the multicast table. | 
 |  * | 
 |  *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated | 
 |  *	immediately. | 
 |  * | 
 |  *	It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according | 
 |  *	to the adapter in use. The real work is done there. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY | 
 |  *	may be called after SK_INIT_IO without limitation | 
 |  * | 
 |  * Returns: | 
 |  *	SK_ADDR_SUCCESS | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | int	SkAddrMcClear( | 
 | SK_AC	*pAC,		/* adapter context */ | 
 | SK_IOC	IoC,		/* I/O context */ | 
 | SK_U32	PortNumber,	/* Index of affected port */ | 
 | int		Flags)		/* permanent/non-perm, sw-only */ | 
 | { | 
 | 	int ReturnCode; | 
 | 	 | 
 | 	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { | 
 | 		return (SK_ADDR_ILLEGAL_PORT); | 
 | 	} | 
 | 	 | 
 | 	if (pAC->GIni.GIGenesis) { | 
 | 		ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags); | 
 | 	} | 
 | 	else { | 
 | 		ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags); | 
 | 	} | 
 |  | 
 | 	return (ReturnCode); | 
 |  | 
 | }	/* SkAddrMcClear */ | 
 |  | 
 | #endif /* !SK_SLIM */ | 
 |  | 
 | #ifndef SK_SLIM | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrXmacMcClear - clear the multicast table | 
 |  * | 
 |  * Description: | 
 |  *	This routine clears the multicast table | 
 |  *	(either entry 2 or entries 3-16 and InexactFilter) of the given port. | 
 |  *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated | 
 |  *	immediately. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY | 
 |  *	may be called after SK_INIT_IO without limitation | 
 |  * | 
 |  * Returns: | 
 |  *	SK_ADDR_SUCCESS | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | static int	SkAddrXmacMcClear( | 
 | SK_AC	*pAC,		/* adapter context */ | 
 | SK_IOC	IoC,		/* I/O context */ | 
 | SK_U32	PortNumber,	/* Index of affected port */ | 
 | int		Flags)		/* permanent/non-perm, sw-only */ | 
 | { | 
 | 	int i; | 
 |  | 
 | 	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */ | 
 |  | 
 | 		/* Clear RLMT multicast addresses. */ | 
 | 		pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; | 
 | 	} | 
 | 	else {	/* not permanent => DRV */ | 
 |  | 
 | 		/* Clear InexactFilter */ | 
 | 		for (i = 0; i < 8; i++) { | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; | 
 | 		} | 
 |  | 
 | 		/* Clear DRV multicast addresses. */ | 
 |  | 
 | 		pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; | 
 | 	} | 
 |  | 
 | 	if (!(Flags & SK_MC_SW_ONLY)) { | 
 | 		(void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber); | 
 | 	} | 
 |  | 
 | 	return (SK_ADDR_SUCCESS); | 
 | 	 | 
 | }	/* SkAddrXmacMcClear */ | 
 |  | 
 | #endif /* !SK_SLIM */ | 
 |  | 
 | #ifndef SK_SLIM | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrGmacMcClear - clear the multicast table | 
 |  * | 
 |  * Description: | 
 |  *	This routine clears the multicast hashing table (InexactFilter) | 
 |  *	(either the RLMT or the driver bits) of the given port. | 
 |  * | 
 |  *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated | 
 |  *	immediately. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY | 
 |  *	may be called after SK_INIT_IO without limitation | 
 |  * | 
 |  * Returns: | 
 |  *	SK_ADDR_SUCCESS | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | static int	SkAddrGmacMcClear( | 
 | SK_AC	*pAC,		/* adapter context */ | 
 | SK_IOC	IoC,		/* I/O context */ | 
 | SK_U32	PortNumber,	/* Index of affected port */ | 
 | int		Flags)		/* permanent/non-perm, sw-only */ | 
 | { | 
 | 	int i; | 
 |  | 
 | #ifdef DEBUG | 
 | 	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n", | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7])) | 
 | #endif	/* DEBUG */ | 
 |  | 
 | 	/* Clear InexactFilter */ | 
 | 	for (i = 0; i < 8; i++) { | 
 | 		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; | 
 | 	} | 
 | 	 | 
 | 	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */ | 
 | 		 | 
 | 		/* Copy DRV bits to InexactFilter. */ | 
 | 		for (i = 0; i < 8; i++) { | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= | 
 | 				pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i]; | 
 | 			 | 
 | 			/* Clear InexactRlmtFilter. */ | 
 | 			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0; | 
 |  | 
 | 		}		 | 
 | 	} | 
 | 	else {	/* not permanent => DRV */ | 
 | 		 | 
 | 		/* Copy RLMT bits to InexactFilter. */ | 
 | 		for (i = 0; i < 8; i++) { | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= | 
 | 				pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i]; | 
 | 			 | 
 | 			/* Clear InexactDrvFilter. */ | 
 | 			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0; | 
 | 		} | 
 | 	} | 
 | 	 | 
 | #ifdef DEBUG | 
 | 	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n", | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6], | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7])) | 
 | #endif	/* DEBUG */ | 
 | 	 | 
 | 	if (!(Flags & SK_MC_SW_ONLY)) { | 
 | 		(void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber); | 
 | 	} | 
 | 	 | 
 | 	return (SK_ADDR_SUCCESS); | 
 |  | 
 | }	/* SkAddrGmacMcClear */ | 
 |  | 
 | #ifndef SK_ADDR_CHEAT | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkXmacMcHash - hash multicast address | 
 |  * | 
 |  * Description: | 
 |  *	This routine computes the hash value for a multicast address. | 
 |  *	A CRC32 algorithm is used. | 
 |  * | 
 |  * Notes: | 
 |  *	The code was adapted from the XaQti data sheet. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  * | 
 |  * Returns: | 
 |  *	Hash value of multicast address. | 
 |  */ | 
 | static SK_U32 SkXmacMcHash( | 
 | unsigned char *pMc)	/* Multicast address */ | 
 | { | 
 | 	SK_U32 Idx; | 
 | 	SK_U32 Bit; | 
 | 	SK_U32 Data; | 
 | 	SK_U32 Crc; | 
 |  | 
 | 	Crc = 0xFFFFFFFFUL; | 
 | 	for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) { | 
 | 		Data = *pMc++; | 
 | 		for (Bit = 0; Bit < 8; Bit++, Data >>= 1) { | 
 | 			Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return (Crc & ((1 << HASH_BITS) - 1)); | 
 |  | 
 | }	/* SkXmacMcHash */ | 
 |  | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkGmacMcHash - hash multicast address | 
 |  * | 
 |  * Description: | 
 |  *	This routine computes the hash value for a multicast address. | 
 |  *	A CRC16 algorithm is used. | 
 |  * | 
 |  * Notes: | 
 |  * | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  * | 
 |  * Returns: | 
 |  *	Hash value of multicast address. | 
 |  */ | 
 | static SK_U32 SkGmacMcHash( | 
 | unsigned char *pMc)	/* Multicast address */ | 
 | { | 
 | 	SK_U32 Data; | 
 | 	SK_U32 TmpData; | 
 | 	SK_U32 Crc; | 
 | 	int Byte; | 
 | 	int Bit; | 
 |  | 
 | 	Crc = 0xFFFFFFFFUL; | 
 | 	for (Byte = 0; Byte < 6; Byte++) { | 
 | 		/* Get next byte. */ | 
 | 		Data = (SK_U32) pMc[Byte]; | 
 | 		 | 
 | 		/* Change bit order in byte. */ | 
 | 		TmpData = Data; | 
 | 		for (Bit = 0; Bit < 8; Bit++) { | 
 | 			if (TmpData & 1L) { | 
 | 				Data |=  1L << (7 - Bit); | 
 | 			} | 
 | 			else { | 
 | 				Data &= ~(1L << (7 - Bit)); | 
 | 			} | 
 | 			TmpData >>= 1; | 
 | 		} | 
 | 		 | 
 | 		Crc ^= (Data << 24); | 
 | 		for (Bit = 0; Bit < 8; Bit++) { | 
 | 			if (Crc & 0x80000000) { | 
 | 				Crc = (Crc << 1) ^ GMAC_POLY; | 
 | 			} | 
 | 			else { | 
 | 				Crc <<= 1; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	 | 
 | 	return (Crc & ((1 << HASH_BITS) - 1)); | 
 |  | 
 | }	/* SkGmacMcHash */ | 
 |  | 
 | #endif	/* !SK_ADDR_CHEAT */ | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrMcAdd - add a multicast address to a port | 
 |  * | 
 |  * Description: | 
 |  *	This routine enables reception for a given address on the given port. | 
 |  * | 
 |  *	It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the | 
 |  *	adapter in use. The real work is done there. | 
 |  * | 
 |  * Notes: | 
 |  *	The return code is only valid for SK_PROM_MODE_NONE. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_DATA | 
 |  * | 
 |  * Returns: | 
 |  *	SK_MC_FILTERING_EXACT | 
 |  *	SK_MC_FILTERING_INEXACT | 
 |  *	SK_MC_ILLEGAL_ADDRESS | 
 |  *	SK_MC_ILLEGAL_PORT | 
 |  *	SK_MC_RLMT_OVERFLOW | 
 |  */ | 
 | int	SkAddrMcAdd( | 
 | SK_AC		*pAC,		/* adapter context */ | 
 | SK_IOC		IoC,		/* I/O context */ | 
 | SK_U32		PortNumber,	/* Port Number */ | 
 | SK_MAC_ADDR	*pMc,		/* multicast address to be added */ | 
 | int			Flags)		/* permanent/non-permanent */ | 
 | { | 
 | 	int ReturnCode; | 
 | 	 | 
 | 	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { | 
 | 		return (SK_ADDR_ILLEGAL_PORT); | 
 | 	} | 
 | 	 | 
 | 	if (pAC->GIni.GIGenesis) { | 
 | 		ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags); | 
 | 	} | 
 | 	else { | 
 | 		ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags); | 
 | 	} | 
 |  | 
 | 	return (ReturnCode); | 
 |  | 
 | }	/* SkAddrMcAdd */ | 
 |  | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrXmacMcAdd - add a multicast address to a port | 
 |  * | 
 |  * Description: | 
 |  *	This routine enables reception for a given address on the given port. | 
 |  * | 
 |  * Notes: | 
 |  *	The return code is only valid for SK_PROM_MODE_NONE. | 
 |  * | 
 |  *	The multicast bit is only checked if there are no free exact match | 
 |  *	entries. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_DATA | 
 |  * | 
 |  * Returns: | 
 |  *	SK_MC_FILTERING_EXACT | 
 |  *	SK_MC_FILTERING_INEXACT | 
 |  *	SK_MC_ILLEGAL_ADDRESS | 
 |  *	SK_MC_RLMT_OVERFLOW | 
 |  */ | 
 | static int	SkAddrXmacMcAdd( | 
 | SK_AC		*pAC,		/* adapter context */ | 
 | SK_IOC		IoC,		/* I/O context */ | 
 | SK_U32		PortNumber,	/* Port Number */ | 
 | SK_MAC_ADDR	*pMc,		/* multicast address to be added */ | 
 | int		Flags)		/* permanent/non-permanent */ | 
 | { | 
 | 	int	i; | 
 | 	SK_U8	Inexact; | 
 | #ifndef SK_ADDR_CHEAT | 
 | 	SK_U32 HashBit; | 
 | #endif	/* !defined(SK_ADDR_CHEAT) */ | 
 |  | 
 | 	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */ | 
 | #ifdef xDEBUG | 
 | 		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt < | 
 | 			SK_ADDR_FIRST_MATCH_RLMT) { | 
 | 			Next0[PortNumber] |= 1; | 
 | 			return (SK_MC_RLMT_OVERFLOW); | 
 | 		} | 
 | #endif	/* DEBUG */ | 
 | 		 | 
 | 		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt > | 
 | 			SK_ADDR_LAST_MATCH_RLMT) { | 
 | 			return (SK_MC_RLMT_OVERFLOW); | 
 | 		} | 
 |  | 
 | 		/* Set a RLMT multicast address. */ | 
 |  | 
 | 		pAC->Addr.Port[PortNumber].Exact[ | 
 | 			pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc; | 
 |  | 
 | 		return (SK_MC_FILTERING_EXACT); | 
 | 	} | 
 |  | 
 | #ifdef xDEBUG | 
 | 	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv < | 
 | 		SK_ADDR_FIRST_MATCH_DRV) { | 
 | 			Next0[PortNumber] |= 2; | 
 | 		return (SK_MC_RLMT_OVERFLOW); | 
 | 	} | 
 | #endif	/* DEBUG */ | 
 | 	 | 
 | 	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { | 
 |  | 
 | 		/* Set exact match entry. */ | 
 | 		pAC->Addr.Port[PortNumber].Exact[ | 
 | 			pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc; | 
 |  | 
 | 		/* Clear InexactFilter */ | 
 | 		for (i = 0; i < 8; i++) { | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; | 
 | 		} | 
 | 	} | 
 | 	else { | 
 | 		if (!(pMc->a[0] & SK_MC_BIT)) { | 
 | 			/* Hashing only possible with multicast addresses */ | 
 | 			return (SK_MC_ILLEGAL_ADDRESS); | 
 | 		} | 
 | #ifndef SK_ADDR_CHEAT | 
 | 		/* Compute hash value of address. */ | 
 | 		HashBit = 63 - SkXmacMcHash(&pMc->a[0]); | 
 |  | 
 | 		/* Add bit to InexactFilter. */ | 
 | 		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |= | 
 | 			1 << (HashBit % 8); | 
 | #else	/* SK_ADDR_CHEAT */ | 
 | 		/* Set all bits in InexactFilter. */ | 
 | 		for (i = 0; i < 8; i++) { | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF; | 
 | 		} | 
 | #endif	/* SK_ADDR_CHEAT */ | 
 | 	} | 
 |  | 
 | 	for (Inexact = 0, i = 0; i < 8; i++) { | 
 | 		Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; | 
 | 	} | 
 |  | 
 | 	if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) { | 
 | 		return (SK_MC_FILTERING_EXACT); | 
 | 	} | 
 | 	else { | 
 | 		return (SK_MC_FILTERING_INEXACT); | 
 | 	} | 
 |  | 
 | }	/* SkAddrXmacMcAdd */ | 
 |  | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrGmacMcAdd - add a multicast address to a port | 
 |  * | 
 |  * Description: | 
 |  *	This routine enables reception for a given address on the given port. | 
 |  * | 
 |  * Notes: | 
 |  *	The return code is only valid for SK_PROM_MODE_NONE. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_DATA | 
 |  * | 
 |  * Returns: | 
 |  *	SK_MC_FILTERING_INEXACT | 
 |  *	SK_MC_ILLEGAL_ADDRESS | 
 |  */ | 
 | static int	SkAddrGmacMcAdd( | 
 | SK_AC		*pAC,		/* adapter context */ | 
 | SK_IOC		IoC,		/* I/O context */ | 
 | SK_U32		PortNumber,	/* Port Number */ | 
 | SK_MAC_ADDR	*pMc,		/* multicast address to be added */ | 
 | int		Flags)		/* permanent/non-permanent */ | 
 | { | 
 | 	int	i; | 
 | #ifndef SK_ADDR_CHEAT | 
 | 	SK_U32 HashBit; | 
 | #endif	/* !defined(SK_ADDR_CHEAT) */ | 
 | 		 | 
 | 	if (!(pMc->a[0] & SK_MC_BIT)) { | 
 | 		/* Hashing only possible with multicast addresses */ | 
 | 		return (SK_MC_ILLEGAL_ADDRESS); | 
 | 	} | 
 | 	 | 
 | #ifndef SK_ADDR_CHEAT | 
 | 	 | 
 | 	/* Compute hash value of address. */ | 
 | 	HashBit = SkGmacMcHash(&pMc->a[0]); | 
 | 	 | 
 | 	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */ | 
 | 		 | 
 | 		/* Add bit to InexactRlmtFilter. */ | 
 | 		pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |= | 
 | 			1 << (HashBit % 8); | 
 | 		 | 
 | 		/* Copy bit to InexactFilter. */ | 
 | 		for (i = 0; i < 8; i++) { | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= | 
 | 				pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i]; | 
 | 		} | 
 | #ifdef DEBUG | 
 | 		SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n", | 
 | 			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0], | 
 | 			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1], | 
 | 			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2], | 
 | 			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3], | 
 | 			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4], | 
 | 			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5], | 
 | 			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6], | 
 | 			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7])) | 
 | #endif	/* DEBUG */ | 
 | 	} | 
 | 	else {	/* not permanent => DRV */ | 
 | 		 | 
 | 		/* Add bit to InexactDrvFilter. */ | 
 | 		pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |= | 
 | 			1 << (HashBit % 8); | 
 | 		 | 
 | 		/* Copy bit to InexactFilter. */ | 
 | 		for (i = 0; i < 8; i++) { | 
 | 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |= | 
 | 				pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i]; | 
 | 		} | 
 | #ifdef DEBUG | 
 | 		SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n", | 
 | 			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0], | 
 | 			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1], | 
 | 			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2], | 
 | 			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3], | 
 | 			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4], | 
 | 			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5], | 
 | 			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6], | 
 | 			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7])) | 
 | #endif	/* DEBUG */ | 
 | 	} | 
 | 	 | 
 | #else	/* SK_ADDR_CHEAT */ | 
 | 	 | 
 | 	/* Set all bits in InexactFilter. */ | 
 | 	for (i = 0; i < 8; i++) { | 
 | 		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF; | 
 | 	} | 
 | #endif	/* SK_ADDR_CHEAT */ | 
 | 		 | 
 | 	return (SK_MC_FILTERING_INEXACT); | 
 | 	 | 
 | }	/* SkAddrGmacMcAdd */ | 
 |  | 
 | #endif /* !SK_SLIM */ | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrMcUpdate - update the HW MC address table and set the MAC address | 
 |  * | 
 |  * Description: | 
 |  *	This routine enables reception of the addresses contained in a local | 
 |  *	table for a given port. | 
 |  *	It also programs the port's current physical MAC address. | 
 |  * | 
 |  *	It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according | 
 |  *	to the adapter in use. The real work is done there. | 
 |  * | 
 |  * Notes: | 
 |  *	The return code is only valid for SK_PROM_MODE_NONE. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_IO | 
 |  * | 
 |  * Returns: | 
 |  *	SK_MC_FILTERING_EXACT | 
 |  *	SK_MC_FILTERING_INEXACT | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | int	SkAddrMcUpdate( | 
 | SK_AC	*pAC,		/* adapter context */ | 
 | SK_IOC	IoC,		/* I/O context */ | 
 | SK_U32	PortNumber)	/* Port Number */ | 
 | { | 
 | 	int ReturnCode = 0; | 
 | #if (!defined(SK_SLIM) || defined(DEBUG)) | 
 | 	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { | 
 | 		return (SK_ADDR_ILLEGAL_PORT); | 
 | 	} | 
 | #endif /* !SK_SLIM || DEBUG */ | 
 |  | 
 | #ifdef GENESIS | 
 | 	if (pAC->GIni.GIGenesis) { | 
 | 		ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber); | 
 | 	} | 
 | #endif /* GENESIS */ | 
 | #ifdef YUKON | 
 | 	if (!pAC->GIni.GIGenesis) { | 
 | 		ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber); | 
 | 	} | 
 | #endif /* YUKON */ | 
 | 	return (ReturnCode); | 
 |  | 
 | }	/* SkAddrMcUpdate */ | 
 |  | 
 |  | 
 | #ifdef GENESIS | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address | 
 |  * | 
 |  * Description: | 
 |  *	This routine enables reception of the addresses contained in a local | 
 |  *	table for a given port. | 
 |  *	It also programs the port's current physical MAC address. | 
 |  * | 
 |  * Notes: | 
 |  *	The return code is only valid for SK_PROM_MODE_NONE. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_IO | 
 |  * | 
 |  * Returns: | 
 |  *	SK_MC_FILTERING_EXACT | 
 |  *	SK_MC_FILTERING_INEXACT | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | static int	SkAddrXmacMcUpdate( | 
 | SK_AC	*pAC,		/* adapter context */ | 
 | SK_IOC	IoC,		/* I/O context */ | 
 | SK_U32	PortNumber)	/* Port Number */ | 
 | { | 
 | 	SK_U32		i; | 
 | 	SK_U8		Inexact; | 
 | 	SK_U16		*OutAddr; | 
 | 	SK_ADDR_PORT	*pAPort; | 
 |  | 
 | 	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("SkAddrXmacMcUpdate on Port %u.\n", PortNumber)) | 
 | 	 | 
 | 	pAPort = &pAC->Addr.Port[PortNumber]; | 
 |  | 
 | #ifdef DEBUG | 
 | 	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber])) | 
 | #endif /* DEBUG */ | 
 |  | 
 | 	/* Start with 0 to also program the logical MAC address. */ | 
 | 	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) { | 
 | 		/* Set exact match address i on XMAC */ | 
 | 		OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0]; | 
 | 		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr); | 
 | 	} | 
 |  | 
 | 	/* Clear other permanent exact match addresses on XMAC */ | 
 | 	if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) { | 
 | 		 | 
 | 		SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt, | 
 | 			SK_ADDR_LAST_MATCH_RLMT); | 
 | 	} | 
 |  | 
 | 	for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) { | 
 | 		OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0]; | 
 | 		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr); | 
 | 	} | 
 |  | 
 | 	/* Clear other non-permanent exact match addresses on XMAC */ | 
 | 	if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { | 
 | 		 | 
 | 		SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv, | 
 | 			SK_ADDR_LAST_MATCH_DRV); | 
 | 	} | 
 |  | 
 | 	for (Inexact = 0, i = 0; i < 8; i++) { | 
 | 		Inexact |= pAPort->InexactFilter.Bytes[i]; | 
 | 	} | 
 |  | 
 | 	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) { | 
 | 		 | 
 | 		/* Set all bits in 64-bit hash register. */ | 
 | 		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash); | 
 | 		 | 
 | 		/* Enable Hashing */ | 
 | 		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	} | 
 | 	else if (Inexact != 0) { | 
 | 		 | 
 | 		/* Set 64-bit hash register to InexactFilter. */ | 
 | 		XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]); | 
 | 		 | 
 | 		/* Enable Hashing */ | 
 | 		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	} | 
 | 	else { | 
 | 		/* Disable Hashing */ | 
 | 		SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE); | 
 | 	} | 
 |  | 
 | 	if (pAPort->PromMode != SK_PROM_MODE_NONE) { | 
 | 		(void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode); | 
 | 	} | 
 |  | 
 | 	/* Set port's current physical MAC address. */ | 
 | 	OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0]; | 
 | 	 | 
 | 	XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr); | 
 |  | 
 | #ifdef xDEBUG | 
 | 	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) { | 
 | 		SK_U8		InAddr8[6]; | 
 | 		SK_U16		*InAddr; | 
 |  | 
 | 		/* Get exact match address i from port PortNumber. */ | 
 | 		InAddr = (SK_U16 *) &InAddr8[0]; | 
 | 		 | 
 | 		XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr); | 
 | 		 | 
 | 		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 			("SkAddrXmacMcUpdate: MC address %d on Port %u: ", | 
 | 			 "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n", | 
 | 				i, | 
 | 				PortNumber, | 
 | 				InAddr8[0], | 
 | 				InAddr8[1], | 
 | 				InAddr8[2], | 
 | 				InAddr8[3], | 
 | 				InAddr8[4], | 
 | 				InAddr8[5], | 
 | 				pAPort->Exact[i].a[0], | 
 | 				pAPort->Exact[i].a[1], | 
 | 				pAPort->Exact[i].a[2], | 
 | 				pAPort->Exact[i].a[3], | 
 | 				pAPort->Exact[i].a[4], | 
 | 				pAPort->Exact[i].a[5])) | 
 | 	} | 
 | #endif /* DEBUG */ | 
 |  | 
 | 	/* Determine return value. */ | 
 | 	if (Inexact == 0 && pAPort->PromMode == 0) { | 
 | 		return (SK_MC_FILTERING_EXACT); | 
 | 	} | 
 | 	else { | 
 | 		return (SK_MC_FILTERING_INEXACT); | 
 | 	} | 
 | 	 | 
 | }	/* SkAddrXmacMcUpdate */ | 
 |  | 
 | #endif  /* GENESIS */ | 
 |  | 
 | #ifdef YUKON | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address | 
 |  * | 
 |  * Description: | 
 |  *	This routine enables reception of the addresses contained in a local | 
 |  *	table for a given port. | 
 |  *	It also programs the port's current physical MAC address. | 
 |  * | 
 |  * Notes: | 
 |  *	The return code is only valid for SK_PROM_MODE_NONE. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_IO | 
 |  * | 
 |  * Returns: | 
 |  *	SK_MC_FILTERING_EXACT | 
 |  *	SK_MC_FILTERING_INEXACT | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | static int	SkAddrGmacMcUpdate( | 
 | SK_AC	*pAC,		/* adapter context */ | 
 | SK_IOC	IoC,		/* I/O context */ | 
 | SK_U32	PortNumber)	/* Port Number */ | 
 | { | 
 | #ifndef SK_SLIM | 
 | 	SK_U32		i; | 
 | 	SK_U8		Inexact; | 
 | #endif	/* not SK_SLIM */ | 
 | 	SK_U16		*OutAddr; | 
 | 	SK_ADDR_PORT	*pAPort; | 
 |  | 
 | 	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("SkAddrGmacMcUpdate on Port %u.\n", PortNumber)) | 
 | 	 | 
 | 	pAPort = &pAC->Addr.Port[PortNumber]; | 
 |  | 
 | #ifdef DEBUG | 
 | 	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber])) | 
 | #endif /* DEBUG */ | 
 | 	 | 
 | #ifndef SK_SLIM | 
 | 	for (Inexact = 0, i = 0; i < 8; i++) { | 
 | 		Inexact |= pAPort->InexactFilter.Bytes[i]; | 
 | 	} | 
 | 	 | 
 | 	/* Set 64-bit hash register to InexactFilter. */ | 
 | 	GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, | 
 | 		&pAPort->InexactFilter.Bytes[0]); | 
 | 	 | 
 | 	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {				 | 
 | 		 | 
 | 		/* Set all bits in 64-bit hash register. */ | 
 | 		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash); | 
 | 		 | 
 | 		/* Enable Hashing */ | 
 | 		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	} | 
 | 	else {	 | 
 | 		/* Enable Hashing. */ | 
 | 		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	} | 
 | 	 | 
 | 	if (pAPort->PromMode != SK_PROM_MODE_NONE) { | 
 | 		(void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode); | 
 | 	} | 
 | #else /* SK_SLIM */ | 
 |  | 
 | 	/* Set all bits in 64-bit hash register. */ | 
 | 	GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash); | 
 |  | 
 | 	/* Enable Hashing */ | 
 | 	SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	 | 
 | 	(void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode); | 
 | 	 | 
 | #endif /* SK_SLIM */ | 
 | 	 | 
 | 	/* Set port's current physical MAC address. */ | 
 | 	OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0]; | 
 | 	GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr); | 
 | 	 | 
 | 	/* Set port's current logical MAC address. */ | 
 | 	OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0]; | 
 | 	GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr); | 
 | 	 | 
 | #ifdef DEBUG | 
 | 	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", | 
 | 			pAPort->Exact[0].a[0], | 
 | 			pAPort->Exact[0].a[1], | 
 | 			pAPort->Exact[0].a[2], | 
 | 			pAPort->Exact[0].a[3], | 
 | 			pAPort->Exact[0].a[4], | 
 | 			pAPort->Exact[0].a[5])) | 
 | 	 | 
 | 	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 		("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n", | 
 | 			pAPort->CurrentMacAddress.a[0], | 
 | 			pAPort->CurrentMacAddress.a[1], | 
 | 			pAPort->CurrentMacAddress.a[2], | 
 | 			pAPort->CurrentMacAddress.a[3], | 
 | 			pAPort->CurrentMacAddress.a[4], | 
 | 			pAPort->CurrentMacAddress.a[5])) | 
 | #endif /* DEBUG */ | 
 | 	 | 
 | #ifndef SK_SLIM | 
 | 	/* Determine return value. */ | 
 | 	if (Inexact == 0 && pAPort->PromMode == 0) { | 
 | 		return (SK_MC_FILTERING_EXACT); | 
 | 	} | 
 | 	else { | 
 | 		return (SK_MC_FILTERING_INEXACT); | 
 | 	} | 
 | #else /* SK_SLIM */ | 
 | 	return (SK_MC_FILTERING_INEXACT); | 
 | #endif /* SK_SLIM */ | 
 | 	 | 
 | }	/* SkAddrGmacMcUpdate */ | 
 |  | 
 | #endif /* YUKON */ | 
 |  | 
 | #ifndef SK_NO_MAO | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrOverride - override a port's MAC address | 
 |  * | 
 |  * Description: | 
 |  *	This routine overrides the MAC address of one port. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_IO | 
 |  * | 
 |  * Returns: | 
 |  *	SK_ADDR_SUCCESS if successful. | 
 |  *	SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address. | 
 |  *	SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address. | 
 |  *	SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before. | 
 |  */ | 
 | int	SkAddrOverride( | 
 | SK_AC		*pAC,				/* adapter context */ | 
 | SK_IOC		IoC,				/* I/O context */ | 
 | SK_U32		PortNumber,			/* Port Number */ | 
 | SK_MAC_ADDR	SK_FAR *pNewAddr,	/* new MAC address */ | 
 | int			Flags)				/* logical/physical MAC address */ | 
 | { | 
 | #ifndef SK_NO_RLMT | 
 | 	SK_EVPARA	Para; | 
 | #endif /* !SK_NO_RLMT */ | 
 | 	SK_U32		NetNumber; | 
 | 	SK_U32		i; | 
 | 	SK_U16		SK_FAR *OutAddr; | 
 |  | 
 | #ifndef SK_NO_RLMT | 
 | 	NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber; | 
 | #else | 
 | 	NetNumber = 0; | 
 | #endif /* SK_NO_RLMT */ | 
 | #if (!defined(SK_SLIM) || defined(DEBUG)) | 
 | 	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { | 
 | 		return (SK_ADDR_ILLEGAL_PORT); | 
 | 	} | 
 | #endif /* !SK_SLIM || DEBUG */ | 
 | 	if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) { | 
 | 		return (SK_ADDR_MULTICAST_ADDRESS); | 
 | 	} | 
 |  | 
 | 	if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) { | 
 | 		return (SK_ADDR_TOO_EARLY); | 
 | 	} | 
 |  | 
 | 	if (Flags & SK_ADDR_SET_LOGICAL) {	/* Activate logical MAC address. */ | 
 | 		/* Parameter *pNewAddr is ignored. */ | 
 | 		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { | 
 | 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) { | 
 | 				return (SK_ADDR_TOO_EARLY); | 
 | 			} | 
 | 		} | 
 | #ifndef SK_NO_RLMT | 
 | 		/* Set PortNumber to number of net's active port. */ | 
 | 		PortNumber = pAC->Rlmt.Net[NetNumber]. | 
 | 			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; | 
 | #endif /* !SK_NO_RLMT */ | 
 | 		pAC->Addr.Port[PortNumber].Exact[0] = | 
 | 			pAC->Addr.Net[NetNumber].CurrentMacAddress; | 
 |  | 
 | 		/* Write address to first exact match entry of active port. */ | 
 | 		(void) SkAddrMcUpdate(pAC, IoC, PortNumber); | 
 | 	} | 
 | 	else if (Flags & SK_ADDR_CLEAR_LOGICAL) { | 
 | 		/* Deactivate logical MAC address. */ | 
 | 		/* Parameter *pNewAddr is ignored. */ | 
 | 		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { | 
 | 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) { | 
 | 				return (SK_ADDR_TOO_EARLY); | 
 | 			} | 
 | 		} | 
 | #ifndef SK_NO_RLMT | 
 | 		/* Set PortNumber to number of net's active port. */ | 
 | 		PortNumber = pAC->Rlmt.Net[NetNumber]. | 
 | 			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; | 
 | #endif /* !SK_NO_RLMT */ | 
 | 		for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) { | 
 | 			pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0; | 
 | 		} | 
 |  | 
 | 		/* Write address to first exact match entry of active port. */ | 
 | 		(void) SkAddrMcUpdate(pAC, IoC, PortNumber); | 
 | 	} | 
 | 	else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical MAC address. */ | 
 | 		if (SK_ADDR_EQUAL(pNewAddr->a, | 
 | 			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) { | 
 | 			return (SK_ADDR_DUPLICATE_ADDRESS); | 
 | 		} | 
 |  | 
 | 		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { | 
 | 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) { | 
 | 				return (SK_ADDR_TOO_EARLY); | 
 | 			} | 
 |  | 
 | 			if (SK_ADDR_EQUAL(pNewAddr->a, | 
 | 				pAC->Addr.Port[i].CurrentMacAddress.a)) { | 
 | 				if (i == PortNumber) { | 
 | 					return (SK_ADDR_SUCCESS); | 
 | 				} | 
 | 				else { | 
 | 					return (SK_ADDR_DUPLICATE_ADDRESS); | 
 | 				} | 
 | 			} | 
 | 		} | 
 |  | 
 | 		pAC->Addr.Port[PortNumber].PreviousMacAddress = | 
 | 			pAC->Addr.Port[PortNumber].CurrentMacAddress; | 
 | 		pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr; | 
 |  | 
 | 		/* Change port's physical MAC address. */ | 
 | 		OutAddr = (SK_U16 SK_FAR *) pNewAddr; | 
 | #ifdef GENESIS | 
 | 		if (pAC->GIni.GIGenesis) { | 
 | 			XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr); | 
 | 		} | 
 | #endif /* GENESIS */ | 
 | #ifdef YUKON | 
 | 		if (!pAC->GIni.GIGenesis) { | 
 | 			GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr); | 
 | 		} | 
 | #endif /* YUKON */ | 
 |  | 
 | #ifndef SK_NO_RLMT | 
 | 		/* Report address change to RLMT. */ | 
 | 		Para.Para32[0] = PortNumber; | 
 | 		Para.Para32[0] = -1; | 
 | 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para); | 
 | #endif /* !SK_NO_RLMT */ | 
 | 	} | 
 | 	else {	/* Logical MAC address. */ | 
 | 		if (SK_ADDR_EQUAL(pNewAddr->a, | 
 | 			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) { | 
 | 			return (SK_ADDR_SUCCESS); | 
 | 		} | 
 | 		 | 
 | 		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) { | 
 | 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) { | 
 | 				return (SK_ADDR_TOO_EARLY); | 
 | 			} | 
 |  | 
 | 			if (SK_ADDR_EQUAL(pNewAddr->a, | 
 | 				pAC->Addr.Port[i].CurrentMacAddress.a)) { | 
 | 				return (SK_ADDR_DUPLICATE_ADDRESS); | 
 | 			} | 
 | 		} | 
 | 		 | 
 | 		/* | 
 | 		 * In case that the physical and the logical MAC addresses are equal | 
 | 		 * we must also change the physical MAC address here. | 
 | 		 * In this case we have an adapter which initially was programmed with | 
 | 		 * two identical MAC addresses. | 
 | 		 */ | 
 | 		if (SK_ADDR_EQUAL(pAC->Addr.Port[PortNumber].CurrentMacAddress.a, | 
 | 				pAC->Addr.Port[PortNumber].Exact[0].a)) { | 
 | 			 | 
 | 			pAC->Addr.Port[PortNumber].PreviousMacAddress = | 
 | 				pAC->Addr.Port[PortNumber].CurrentMacAddress; | 
 | 			pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr; | 
 | 			 | 
 | #ifndef SK_NO_RLMT | 
 | 			/* Report address change to RLMT. */ | 
 | 			Para.Para32[0] = PortNumber; | 
 | 			Para.Para32[0] = -1; | 
 | 			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para); | 
 | #endif /* !SK_NO_RLMT */ | 
 | 		} | 
 | 		 | 
 | #ifndef SK_NO_RLMT | 
 | 		/* Set PortNumber to number of net's active port. */ | 
 | 		PortNumber = pAC->Rlmt.Net[NetNumber]. | 
 | 			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; | 
 | #endif /* !SK_NO_RLMT */ | 
 | 		pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr; | 
 | 		pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr; | 
 | #ifdef DEBUG | 
 | 		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 			("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n", | 
 | 				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0], | 
 | 				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1], | 
 | 				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2], | 
 | 				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3], | 
 | 				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4], | 
 | 				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5])) | 
 | 		 | 
 | 		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, | 
 | 			("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n", | 
 | 				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0], | 
 | 				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1], | 
 | 				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2], | 
 | 				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3], | 
 | 				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4], | 
 | 				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5])) | 
 | #endif /* DEBUG */ | 
 |  | 
 |         /* Write address to first exact match entry of active port. */ | 
 | 		(void) SkAddrMcUpdate(pAC, IoC, PortNumber); | 
 | 	} | 
 |  | 
 | 	return (SK_ADDR_SUCCESS); | 
 | 	 | 
 | }	/* SkAddrOverride */ | 
 |  | 
 |  | 
 | #endif /* SK_NO_MAO */ | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrPromiscuousChange - set promiscuous mode for given port | 
 |  * | 
 |  * Description: | 
 |  *	This routine manages promiscuous mode: | 
 |  *	- none | 
 |  *	- all LLC frames | 
 |  *	- all MC frames | 
 |  * | 
 |  *	It calls either SkAddrXmacPromiscuousChange or | 
 |  *	SkAddrGmacPromiscuousChange, according to the adapter in use. | 
 |  *	The real work is done there. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_IO | 
 |  * | 
 |  * Returns: | 
 |  *	SK_ADDR_SUCCESS | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | int	SkAddrPromiscuousChange( | 
 | SK_AC	*pAC,			/* adapter context */ | 
 | SK_IOC	IoC,			/* I/O context */ | 
 | SK_U32	PortNumber,		/* port whose promiscuous mode changes */ | 
 | int		NewPromMode)	/* new promiscuous mode */ | 
 | { | 
 | 	int ReturnCode = 0; | 
 | #if (!defined(SK_SLIM) || defined(DEBUG)) | 
 | 	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { | 
 | 		return (SK_ADDR_ILLEGAL_PORT); | 
 | 	} | 
 | #endif /* !SK_SLIM || DEBUG */ | 
 |  | 
 | #ifdef GENESIS | 
 | 	if (pAC->GIni.GIGenesis) { | 
 | 		ReturnCode = | 
 | 			SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode); | 
 | 	} | 
 | #endif /* GENESIS */ | 
 | #ifdef YUKON | 
 | 	if (!pAC->GIni.GIGenesis) { | 
 | 		ReturnCode = | 
 | 			SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode); | 
 | 	} | 
 | #endif /* YUKON */ | 
 |  | 
 | 	return (ReturnCode); | 
 |  | 
 | }	/* SkAddrPromiscuousChange */ | 
 |  | 
 | #ifdef GENESIS | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrXmacPromiscuousChange - set promiscuous mode for given port | 
 |  * | 
 |  * Description: | 
 |  *	This routine manages promiscuous mode: | 
 |  *	- none | 
 |  *	- all LLC frames | 
 |  *	- all MC frames | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_IO | 
 |  * | 
 |  * Returns: | 
 |  *	SK_ADDR_SUCCESS | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | static int	SkAddrXmacPromiscuousChange( | 
 | SK_AC	*pAC,			/* adapter context */ | 
 | SK_IOC	IoC,			/* I/O context */ | 
 | SK_U32	PortNumber,		/* port whose promiscuous mode changes */ | 
 | int		NewPromMode)	/* new promiscuous mode */ | 
 | { | 
 | 	int			i; | 
 | 	SK_BOOL		InexactModeBit; | 
 | 	SK_U8		Inexact; | 
 | 	SK_U8		HwInexact; | 
 | 	SK_FILTER64	HwInexactFilter; | 
 | 	SK_U16		LoMode;		/* Lower 16 bits of XMAC Mode Register. */ | 
 | 	int			CurPromMode = SK_PROM_MODE_NONE; | 
 |  | 
 | 	/* Read CurPromMode from Hardware. */ | 
 | 	XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); | 
 |  | 
 | 	if ((LoMode & XM_MD_ENA_PROM) != 0) { | 
 | 		/* Promiscuous mode! */ | 
 | 		CurPromMode |= SK_PROM_MODE_LLC; | 
 | 	} | 
 | 	 | 
 | 	for (Inexact = 0xFF, i = 0; i < 8; i++) { | 
 | 		Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; | 
 | 	} | 
 | 	if (Inexact == 0xFF) { | 
 | 		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC); | 
 | 	} | 
 | 	else { | 
 | 		/* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */ | 
 | 		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); | 
 | 		 | 
 | 		InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0; | 
 |  | 
 | 		/* Read 64-bit hash register from XMAC */ | 
 | 		XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]); | 
 |  | 
 | 		for (HwInexact = 0xFF, i = 0; i < 8; i++) { | 
 | 			HwInexact &= HwInexactFilter.Bytes[i]; | 
 | 		} | 
 |  | 
 | 		if (InexactModeBit && (HwInexact == 0xFF)) { | 
 | 			CurPromMode |= SK_PROM_MODE_ALL_MC; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	pAC->Addr.Port[PortNumber].PromMode = NewPromMode; | 
 |  | 
 | 	if (NewPromMode == CurPromMode) { | 
 | 		return (SK_ADDR_SUCCESS); | 
 | 	} | 
 |  | 
 | 	if ((NewPromMode & SK_PROM_MODE_ALL_MC) && | 
 | 		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC. */ | 
 | 		 | 
 | 		/* Set all bits in 64-bit hash register. */ | 
 | 		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash); | 
 |  | 
 | 		/* Enable Hashing */ | 
 | 		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	} | 
 | 	else if ((CurPromMode & SK_PROM_MODE_ALL_MC) && | 
 | 		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm MC. */ | 
 | 		for (Inexact = 0, i = 0; i < 8; i++) { | 
 | 			Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; | 
 | 		} | 
 | 		if (Inexact == 0) { | 
 | 			/* Disable Hashing */ | 
 | 			SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE); | 
 | 		} | 
 | 		else { | 
 | 			/* Set 64-bit hash register to InexactFilter. */ | 
 | 			XM_OUTHASH(IoC, PortNumber, XM_HSM, | 
 | 				&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]); | 
 |  | 
 | 			/* Enable Hashing */ | 
 | 			SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if ((NewPromMode & SK_PROM_MODE_LLC) && | 
 | 		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */ | 
 | 		/* Set the MAC in Promiscuous Mode */ | 
 | 		SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	} | 
 | 	else if ((CurPromMode & SK_PROM_MODE_LLC) && | 
 | 		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC. */ | 
 | 		/* Clear Promiscuous Mode */ | 
 | 		SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE); | 
 | 	} | 
 | 	 | 
 | 	return (SK_ADDR_SUCCESS); | 
 | 	 | 
 | }	/* SkAddrXmacPromiscuousChange */ | 
 |  | 
 | #endif /* GENESIS */ | 
 |  | 
 | #ifdef YUKON | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrGmacPromiscuousChange - set promiscuous mode for given port | 
 |  * | 
 |  * Description: | 
 |  *	This routine manages promiscuous mode: | 
 |  *	- none | 
 |  *	- all LLC frames | 
 |  *	- all MC frames | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_IO | 
 |  * | 
 |  * Returns: | 
 |  *	SK_ADDR_SUCCESS | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | static int	SkAddrGmacPromiscuousChange( | 
 | SK_AC	*pAC,			/* adapter context */ | 
 | SK_IOC	IoC,			/* I/O context */ | 
 | SK_U32	PortNumber,		/* port whose promiscuous mode changes */ | 
 | int		NewPromMode)	/* new promiscuous mode */ | 
 | { | 
 | 	SK_U16		ReceiveControl;	/* GMAC Receive Control Register */ | 
 | 	int		CurPromMode = SK_PROM_MODE_NONE; | 
 |  | 
 | 	/* Read CurPromMode from Hardware. */ | 
 | 	GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl); | 
 |  | 
 | 	if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) { | 
 | 		/* Promiscuous mode! */ | 
 | 		CurPromMode |= SK_PROM_MODE_LLC; | 
 | 	} | 
 |  | 
 | 	if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) { | 
 | 		/* All Multicast mode! */ | 
 | 		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC); | 
 | 	} | 
 |  | 
 | 	pAC->Addr.Port[PortNumber].PromMode = NewPromMode; | 
 |  | 
 | 	if (NewPromMode == CurPromMode) { | 
 | 		return (SK_ADDR_SUCCESS); | 
 | 	} | 
 | 	 | 
 | 	if ((NewPromMode & SK_PROM_MODE_ALL_MC) && | 
 | 		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC */ | 
 | 		 | 
 | 		/* Set all bits in 64-bit hash register. */ | 
 | 		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash); | 
 | 		 | 
 | 		/* Enable Hashing */ | 
 | 		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	} | 
 | 	 | 
 | 	if ((CurPromMode & SK_PROM_MODE_ALL_MC) && | 
 | 		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm. MC */ | 
 |  | 
 | 		/* Set 64-bit hash register to InexactFilter. */ | 
 | 		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, | 
 | 			&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]); | 
 |  | 
 | 		/* Enable Hashing. */ | 
 | 		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	} | 
 |  | 
 | 	if ((NewPromMode & SK_PROM_MODE_LLC) && | 
 | 		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */ | 
 | 		 | 
 | 		/* Set the MAC to Promiscuous Mode. */ | 
 | 		SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE); | 
 | 	} | 
 | 	else if ((CurPromMode & SK_PROM_MODE_LLC) && | 
 | 		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC */ | 
 | 		 | 
 | 		/* Clear Promiscuous Mode. */ | 
 | 		SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE); | 
 | 	} | 
 |  | 
 | 	return (SK_ADDR_SUCCESS); | 
 | 	 | 
 | }	/* SkAddrGmacPromiscuousChange */ | 
 |  | 
 | #endif /* YUKON */ | 
 |  | 
 | #ifndef SK_SLIM | 
 |  | 
 | /****************************************************************************** | 
 |  * | 
 |  *	SkAddrSwap - swap address info | 
 |  * | 
 |  * Description: | 
 |  *	This routine swaps address info of two ports. | 
 |  * | 
 |  * Context: | 
 |  *	runtime, pageable | 
 |  *	may be called after SK_INIT_IO | 
 |  * | 
 |  * Returns: | 
 |  *	SK_ADDR_SUCCESS | 
 |  *	SK_ADDR_ILLEGAL_PORT | 
 |  */ | 
 | int	SkAddrSwap( | 
 | SK_AC	*pAC,			/* adapter context */ | 
 | SK_IOC	IoC,			/* I/O context */ | 
 | SK_U32	FromPortNumber,		/* Port1 Index */ | 
 | SK_U32	ToPortNumber)		/* Port2 Index */ | 
 | { | 
 | 	int			i; | 
 | 	SK_U8		Byte; | 
 | 	SK_MAC_ADDR	MacAddr; | 
 | 	SK_U32		DWord; | 
 |  | 
 | 	if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { | 
 | 		return (SK_ADDR_ILLEGAL_PORT); | 
 | 	} | 
 |  | 
 | 	if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { | 
 | 		return (SK_ADDR_ILLEGAL_PORT); | 
 | 	} | 
 |  | 
 | 	if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) { | 
 | 		return (SK_ADDR_ILLEGAL_PORT); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Swap: | 
 | 	 * - Exact Match Entries (GEnesis and Yukon) | 
 | 	 *   Yukon uses first entry for the logical MAC | 
 | 	 *   address (stored in the second GMAC register). | 
 | 	 * - FirstExactMatchRlmt (GEnesis only) | 
 | 	 * - NextExactMatchRlmt (GEnesis only) | 
 | 	 * - FirstExactMatchDrv (GEnesis only) | 
 | 	 * - NextExactMatchDrv (GEnesis only) | 
 | 	 * - 64-bit filter (InexactFilter) | 
 | 	 * - Promiscuous Mode | 
 | 	 * of ports. | 
 | 	 */ | 
 |  | 
 | 	for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) { | 
 | 		MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i]; | 
 | 		pAC->Addr.Port[FromPortNumber].Exact[i] = | 
 | 			pAC->Addr.Port[ToPortNumber].Exact[i]; | 
 | 		pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr; | 
 | 	} | 
 |  | 
 | 	for (i = 0; i < 8; i++) { | 
 | 		Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i]; | 
 | 		pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] = | 
 | 			pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i]; | 
 | 		pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte; | 
 | 	} | 
 | 	 | 
 | 	i = pAC->Addr.Port[FromPortNumber].PromMode; | 
 | 	pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode; | 
 | 	pAC->Addr.Port[ToPortNumber].PromMode = i; | 
 | 	 | 
 | 	if (pAC->GIni.GIGenesis) { | 
 | 		DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt; | 
 | 		pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt = | 
 | 			pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt; | 
 | 		pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord; | 
 | 		 | 
 | 		DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt; | 
 | 		pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt = | 
 | 			pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt; | 
 | 		pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord; | 
 | 		 | 
 | 		DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv; | 
 | 		pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv = | 
 | 			pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv; | 
 | 		pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord; | 
 | 		 | 
 | 		DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv; | 
 | 		pAC->Addr.Port[FromPortNumber].NextExactMatchDrv = | 
 | 			pAC->Addr.Port[ToPortNumber].NextExactMatchDrv; | 
 | 		pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord; | 
 | 	} | 
 | 	 | 
 | 	/* CAUTION: Solution works if only ports of one adapter are in use. */ | 
 | 	for (i = 0; (SK_U32) i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber]. | 
 | 		Net->NetNumber].NumPorts; i++) { | 
 | 		if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber]. | 
 | 			Port[i]->PortNumber == ToPortNumber) { | 
 | 			pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber]. | 
 | 				ActivePort = i; | 
 | 			/* 20001207 RA: Was "ToPortNumber;". */ | 
 | 		} | 
 | 	} | 
 | 	 | 
 | 	(void) SkAddrMcUpdate(pAC, IoC, FromPortNumber); | 
 | 	(void) SkAddrMcUpdate(pAC, IoC, ToPortNumber); | 
 |  | 
 | 	return (SK_ADDR_SUCCESS); | 
 | 	 | 
 | }	/* SkAddrSwap */ | 
 |  | 
 | #endif /* !SK_SLIM */ | 
 |  | 
 | #ifdef __cplusplus | 
 | } | 
 | #endif	/* __cplusplus */ | 
 |  |