patch-2.4.21 linux-2.4.21/drivers/net/sk98lin/skaddr.c

Next file: linux-2.4.21/drivers/net/sk98lin/skcsum.c
Previous file: linux-2.4.21/drivers/net/sk98lin/h/xmac_ii.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/net/sk98lin/skaddr.c linux-2.4.21/drivers/net/sk98lin/skaddr.c
@@ -2,15 +2,15 @@
  *
  * Name:	skaddr.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.40 $
- * Date:	$Date: 2001/02/14 14:04:59 $
+ * Version:	$Revision: 1.47 $
+ * Date:	$Date: 2002/09/17 06:31:10 $
  * Purpose:	Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
  *
  *	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
@@ -26,6 +26,39 @@
  * History:
  *
  *	$Log: skaddr.c,v $
+ *	Revision 1.47  2002/09/17 06:31:10  tschilli
+ *	Handling of SK_PROM_MODE_ALL_MC flag in SkAddrGmacMcUpdate()
+ *	and SkAddrGmacPromiscuousChange() fixed.
+ *	Editorial changes.
+ *	
+ *	Revision 1.46  2002/08/22 07:55:41  tschilli
+ *	New function SkGmacMcHash() for GMAC multicast hashing algorithm added.
+ *	Editorial changes.
+ *	
+ *	Revision 1.45  2002/08/15 12:29:35  tschilli
+ *	SkAddrGmacMcUpdate() and SkAddrGmacPromiscuousChange() changed.
+ *	
+ *	Revision 1.44  2002/08/14 12:18:03  rschmidt
+ *	Replaced direct handling of MAC Hashing (XMAC and GMAC)
+ *	with routine SkMacHashing().
+ *	Replaced wrong 3rd para 'i' with 'PortNumber' in SkMacPromiscMode().
+ *	
+ *	Revision 1.43  2002/08/13 09:37:43  rschmidt
+ *	Corrected some SK_DBG_MSG outputs.
+ *	Replaced wrong 2nd para pAC with IoC in SkMacPromiscMode().
+ *	Editorial changes.
+ *	
+ *	Revision 1.42  2002/08/12 11:24:36  rschmidt
+ *	Remove setting of logical MAC address GM_SRC_ADDR_2 in SkAddrInit().
+ *	Replaced direct handling of MAC Promiscuous Mode (XMAC and GMAC)
+ *	with routine SkMacPromiscMode().
+ *	Editorial changes.
+ *	
+ *	Revision 1.41  2002/06/10 13:52:18  tschilli
+ *	Changes for handling YUKON.
+ *	All changes are internally and not visible to the programmer
+ *	using this module.
+ *	
  *	Revision 1.40  2001/02/14 14:04:59  rassmann
  *	Editorial changes.
  *	
@@ -166,13 +199,13 @@
  * Description:
  *
  * This module is intended to manage multicast addresses, address override,
- * and promiscuous mode on GEnesis adapters.
+ * and promiscuous mode on GEnesis and Yukon adapters.
  *
  * Address Layout:
  *	port address:		physical MAC address
- *	1st exact match:	logical MAC address
- *	2nd exact match:	RLMT multicast
- *	exact match 3-13:	OS-specific multicasts
+ *	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:
  *
@@ -183,7 +216,7 @@
 
 #ifndef	lint
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skaddr.c,v 1.40 2001/02/14 14:04:59 rassmann Exp $ (C) SysKonnect.";
+	"@(#) $Id: skaddr.c,v 1.47 2002/09/17 06:31:10 tschilli Exp $ (C) SysKonnect.";
 #endif	/* !defined(lint) */
 
 #define __SKADDR_C
@@ -199,6 +232,8 @@
 /* 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
 
@@ -247,7 +282,7 @@
  *	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 XMAC.
+ *	The current addresses are written to the corresponding MAC.
  *
  *
  *	SK_INIT_RUN
@@ -266,38 +301,26 @@
 SK_IOC	IoC,	/* I/O context */
 int		Level)	/* initialization level */
 {
-	int				j;
-	SK_U32			i;
-	SK_U8			*InAddr;
-	SK_U16			*OutAddr;
+	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, 0, sizeof(SK_ADDR));
+		SK_MEMSET((char *) &pAC->Addr, 0, 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;
-
-#if 0
-			/* Don't do this here ... */
-
-			/* Reset Promiscuous mode. */
-			(void)SkAddrPromiscuousChange(
-				pAC,
-				IoC,
-				i,
-				SK_PROM_MODE_NONE);
-#endif	/* 0 */
+			
+			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 DEBUG
+#ifdef xDEBUG
 		for (i = 0; i < SK_MAX_MACS; i++) {
 			if (pAC->Addr.Port[i].NextExactMatchRlmt <
 				SK_ADDR_FIRST_MATCH_RLMT) {
@@ -305,7 +328,6 @@
 			}
 		}
 #endif	/* DEBUG */
-
 		/* pAC->Addr.InitDone = SK_INIT_DATA; */
 		break;
 
@@ -313,8 +335,7 @@
 		for (i = 0; i < SK_MAX_NETS; i++) {
 			pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
 		}
-		
-#ifdef DEBUG
+#ifdef xDEBUG
 		for (i = 0; i < SK_MAX_MACS; i++) {
 			if (pAC->Addr.Port[i].NextExactMatchRlmt <
 				SK_ADDR_FIRST_MATCH_RLMT) {
@@ -322,10 +343,10 @@
 			}
 		}
 #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];
+			InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j];
 			SK_IN8(IoC, B2_MAC_1 + j, InAddr);
 		}
 
@@ -339,7 +360,6 @@
 		/* 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) {
@@ -353,43 +373,36 @@
 		}
 #endif	/* SK_MAX_NETS > 1 */
 
-#ifdef xDEBUG
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_ADDR,
-			SK_DBGCAT_INIT,
-			("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
-				pAC->Addr.PermanentMacAddress.a[0],
-				pAC->Addr.PermanentMacAddress.a[1],
-				pAC->Addr.PermanentMacAddress.a[2],
-				pAC->Addr.PermanentMacAddress.a[3],
-				pAC->Addr.PermanentMacAddress.a[4],
-				pAC->Addr.PermanentMacAddress.a[5]))
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_ADDR,
-			SK_DBGCAT_INIT,
-			("Logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
-				pAC->Addr.CurrentMacAddress.a[0],
-				pAC->Addr.CurrentMacAddress.a[1],
-				pAC->Addr.CurrentMacAddress.a[2],
-				pAC->Addr.CurrentMacAddress.a[3],
-				pAC->Addr.CurrentMacAddress.a[4],
-				pAC->Addr.CurrentMacAddress.a[5]))
+#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 */
 
-#if 0
-		/* Don't do this here ... */
-
-		(void)SkAddrMcUpdate(pAC, IoC, pAC->Addr.ActivePort);
-#endif	/* 0 */
-
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		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];
+				InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j];
 				SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
 			}
 
@@ -403,27 +416,27 @@
 				pAPort->CurrentMacAddressSet = SK_TRUE;
 			}
 
-			/* Set port's current MAC addresses. */
-			OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
-			XM_OUTADDR(IoC, i, XM_SA, OutAddr);
-
-#ifdef xDEBUG
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_ADDR,
-				SK_DBGCAT_INIT,
-				("Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			/* Set port's current physical MAC address. */
+			OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+			
+			if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+				XM_OUTADDR(IoC, i, XM_SA, OutAddr);
+			}
+			else {
+				GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr);
+			}
+#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,
-				("Phsical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			
+			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],
@@ -436,7 +449,7 @@
 		break;
 
 	case SK_INIT_RUN:
-#ifdef DEBUG
+#ifdef xDEBUG
 		for (i = 0; i < SK_MAX_MACS; i++) {
 			if (pAC->Addr.Port[i].NextExactMatchRlmt <
 				SK_ADDR_FIRST_MATCH_RLMT) {
@@ -453,6 +466,7 @@
 	}
 
 	return (SK_ADDR_SUCCESS);
+	
 }	/* SkAddrInit */
 
 
@@ -461,11 +475,14 @@
  *	SkAddrMcClear - clear the multicast table
  *
  * Description:
- *	This routine clears the multicast table
- *	(either entry 2 or entries 3-16 and InexactFilter) of the given port.
+ *	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
@@ -481,21 +498,59 @@
 SK_U32	PortNumber,	/* Index of affected port */
 int		Flags)		/* permanent/non-perm, sw-only */
 {
-	int i;
-
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
+	int ReturnCode;
+	
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrMcClear */
+
+
+/******************************************************************************
+ *
+ *	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
+ */
+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) {
+	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. */
-
+		/* Clear InexactFilter */
 		for (i = 0; i < 8; i++) {
 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
 		}
@@ -506,20 +561,114 @@
 	}
 
 	if (!(Flags & SK_MC_SW_ONLY)) {
-		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
+		(void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
 	}
 
 	return (SK_ADDR_SUCCESS);
-}	/* SkAddrMcClear */
+	
+}	/* SkAddrXmacMcClear */
+
+
+/******************************************************************************
+ *
+ *	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
+ */
+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
 
 /******************************************************************************
  *
- *	SkCrc32McHash - hash multicast address
+ *	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.
@@ -530,15 +679,84 @@
  * Returns:
  *	Hash value of multicast address.
  */
-unsigned SkCrc32McHash(
+SK_U32 SkXmacMcHash(
 unsigned char *pMc)	/* Multicast address */
 {
-	u32 Crc;
+	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);
+		}
+	}
 
-	Crc = ether_crc_le(SK_MAC_ADDR_LEN, pMc);
+	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.
+ */
+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));
-}	/* SkCrc32McHash */
+
+}	/* SkGmacMcHash */
 
 #endif	/* not SK_ADDR_CHEAT */
 
@@ -549,11 +767,57 @@
  * 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.
  *
- *	In the current version, only RLMT may add addresses to the non-active
- *	port.
+ * 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.GIChipId == CHIP_ID_GENESIS) {
+		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.
@@ -566,28 +830,23 @@
  *	SK_MC_FILTERING_EXACT
  *	SK_MC_FILTERING_INEXACT
  *	SK_MC_ILLEGAL_ADDRESS
- *	SK_MC_ILLEGAL_PORT
  *	SK_MC_RLMT_OVERFLOW
  */
-int	SkAddrMcAdd(
+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		Flags)		/* permanent/non-permanent */
 {
 	int	i;
 	SK_U8	Inexact;
 #ifndef SK_ADDR_CHEAT
-	unsigned HashBit;
+	SK_U32 HashBit;
 #endif	/* !defined(SK_ADDR_CHEAT) */
 
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
-		return (SK_ADDR_ILLEGAL_PORT);
-	}
-
-	if (Flags & SK_ADDR_PERMANENT) {
-#ifdef DEBUG
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+#ifdef xDEBUG
 		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
 			SK_ADDR_FIRST_MATCH_RLMT) {
 			Next0[PortNumber] |= 1;
@@ -600,7 +859,7 @@
 			return (SK_MC_RLMT_OVERFLOW);
 		}
 
-		/* Set an RLMT multicast address. */
+		/* Set a RLMT multicast address. */
 
 		pAC->Addr.Port[PortNumber].Exact[
 			pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
@@ -608,15 +867,7 @@
 		return (SK_MC_FILTERING_EXACT);
 	}
 
-#if 0
-	/* Not PERMANENT => DRV */
-	if (PortNumber != pAC->Addr.ActivePort) {
-		/* Only RLMT is allowed to do this. */
-		return (SK_MC_ILLEGAL_PORT);
-	}
-#endif	/* 0 */
-
-#ifdef DEBUG
+#ifdef xDEBUG
 	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
 		SK_ADDR_FIRST_MATCH_DRV) {
 			Next0[PortNumber] |= 2;
@@ -630,22 +881,19 @@
 		pAC->Addr.Port[PortNumber].Exact[
 			pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
 
-		/* Clear InexactFilter. */
+		/* 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.
-			 */
+			/* Hashing only possible with multicast addresses. */
 			return (SK_MC_ILLEGAL_ADDRESS);
 		}
 #ifndef SK_ADDR_CHEAT
 		/* Compute hash value of address. */
-		HashBit = 63 - SkCrc32McHash(&pMc->a[0]);
+		HashBit = 63 - SkXmacMcHash(&pMc->a[0]);
 
 		/* Add bit to InexactFilter. */
 		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
@@ -668,90 +916,223 @@
 	else {
 		return (SK_MC_FILTERING_INEXACT);
 	}
-}	/* SkAddrMcAdd */
+
+}	/* SkAddrXmacMcAdd */
 
 
 /******************************************************************************
  *
- *	SkAddrMcUpdate - update the HW MC address table and set the MAC address
+ *	SkAddrGmacMcAdd - add a multicast address to a port
  *
  * 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.
+ *	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_IO
+ *	may be called after SK_INIT_DATA
  *
  * Returns:
- *	SK_MC_FILTERING_EXACT
  *	SK_MC_FILTERING_INEXACT
- *	SK_ADDR_ILLEGAL_PORT
+ *	SK_MC_ILLEGAL_ADDRESS
  */
-int	SkAddrMcUpdate(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* I/O context */
-SK_U32	PortNumber)	/* Port Number */
+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 */
 {
-	SK_U32			i;
-	SK_U8			Inexact;
-	SK_U16			*OutAddr;
-	SK_U16			LoMode;		/* Lower 16 bits of XMAC Mode Reg. */
-	SK_ADDR_PORT	*pAPort;
-
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
-		return (SK_ADDR_ILLEGAL_PORT);
+	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);
 	}
-
-	SK_DBG_MSG(
-		pAC,
-		SK_DBGMOD_ADDR,
-		SK_DBGCAT_CTRL,
-		("SkAddrMcUpdate on Port %u.\n", PortNumber))
 	
-	pAPort = &pAC->Addr.Port[PortNumber];
-
+#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,
-			("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+		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 */
-
-	/* Start with 0 to also program the logical MAC address. */
-	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
-		/* Set exact match address i on HW. */
-		OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
-		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
+	}
+	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 */
+
+
+/******************************************************************************
+ *
+ *	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;
+	
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+	}
+	
+	return (ReturnCode);
+
+}	/* SkAddrMcUpdate */
+
+
+/******************************************************************************
+ *
+ *	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
+ */
+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 HW. */
+	/* Clear other permanent exact match addresses on XMAC */
 	if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
-		SkXmClrExactAddr(
-			pAC,
-			IoC,
-			PortNumber,
-			pAPort->NextExactMatchRlmt,
+		
+		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];
+		OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
 		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
 	}
 
-	/* Clear other non-permanent exact match addresses on HW. */
+	/* Clear other non-permanent exact match addresses on XMAC */
 	if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
-		SkXmClrExactAddr(
-			pAC,
-			IoC,
-			PortNumber,
-			pAPort->NextExactMatchDrv,
+		
+		SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv,
 			SK_ADDR_LAST_MATCH_DRV);
 	}
 
@@ -760,36 +1141,33 @@
 	}
 
 	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
+		
 		/* Set all bits in 64-bit hash register. */
 		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
-
-		/* Set bit 15 in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-		LoMode |= XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
 	}
 	else if (Inexact != 0) {
+		
 		/* Set 64-bit hash register to InexactFilter. */
 		XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
-
-		/* Set bit 15 in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-		LoMode |= XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
 	}
 	else {
-		/* Clear bit 15 in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-		LoMode &= ~XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		/* Disable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_FALSE);
 	}
 
 	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
-		(void)SkAddrPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+		(void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
 	}
 
-	/* Set port's current MAC address. */
-	OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
+	/* Set port's current physical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+	
 	XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
 
 #ifdef xDEBUG
@@ -798,13 +1176,13 @@
 		SK_U16		*InAddr;
 
 		/* Get exact match address i from port PortNumber. */
-		InAddr = (SK_U16 *)&InAddr8[0];
+		InAddr = (SK_U16 *) &InAddr8[0];
+		
 		XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_ADDR,
-			SK_DBGCAT_CTRL,
-			("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
+		
+		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],
@@ -829,7 +1207,113 @@
 	else {
 		return (SK_MC_FILTERING_INEXACT);
 	}
-}	/* SkAddrMcUpdate */
+	
+}	/* SkAddrXmacMcUpdate */
+
+
+/******************************************************************************
+ *
+ *	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
+ */
+int	SkAddrGmacMcUpdate(
+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,
+		("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 */
+	
+	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, PortNumber, SK_TRUE);
+	}
+	else {	
+		/* Enable Hashing. */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	
+	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+		(void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+	}
+	
+	/* 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 */
+	
+	/* Determine return value. */
+	if (Inexact == 0 && pAPort->PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+	
+}	/* SkAddrGmacMcUpdate */
 
 
 /******************************************************************************
@@ -863,7 +1347,7 @@
 
 	NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
 
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
@@ -877,7 +1361,7 @@
 
 	if (Flags & SK_ADDR_SET_LOGICAL) {	/* Activate logical MAC address. */
 		/* Parameter *pNewAddr is ignored. */
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
 				return (SK_ADDR_TOO_EARLY);
 			}
@@ -891,12 +1375,12 @@
 			pAC->Addr.Net[NetNumber].CurrentMacAddress;
 
 		/* Write address to first exact match entry of active port. */
-		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
+		(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++) {
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
 				return (SK_ADDR_TOO_EARLY);
 			}
@@ -911,7 +1395,7 @@
 		}
 
 		/* Write address to first exact match entry of active port. */
-		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
 	}
 	else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical MAC address. */
 		if (SK_ADDR_EQUAL(pNewAddr->a,
@@ -919,7 +1403,7 @@
 			return (SK_ADDR_DUPLICATE_ADDRESS);
 		}
 
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
 				return (SK_ADDR_TOO_EARLY);
 			}
@@ -939,9 +1423,15 @@
 			pAC->Addr.Port[PortNumber].CurrentMacAddress;
 		pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
 
-		/* Change port's address. */
-		OutAddr = (SK_U16 *)pNewAddr;
-		XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+		/* Change port's physical MAC address. */
+		OutAddr = (SK_U16 *) pNewAddr;
+		
+		if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+			XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+		}
+		else {
+			GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+		}
 
 		/* Report address change to RLMT. */
 		Para.Para32[0] = PortNumber;
@@ -954,7 +1444,7 @@
 			return (SK_ADDR_SUCCESS);
 		}
 		
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
 				return (SK_ADDR_TOO_EARLY);
 			}
@@ -971,24 +1461,18 @@
 
 		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,
-			("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
+		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,
-			("New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+		
+		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],
@@ -998,10 +1482,11 @@
 #endif	/* DEBUG */
 
 		/* Write address to first exact match entry of active port. */
-		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
 	}
 
 	return (SK_ADDR_SUCCESS);
+	
 }	/* SkAddrOverride */
 
 
@@ -1015,6 +1500,10 @@
  *	- 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
@@ -1029,6 +1518,48 @@
 SK_U32	PortNumber,		/* port whose promiscuous mode changes */
 int		NewPromMode)	/* new promiscuous mode */
 {
+	int ReturnCode;
+	
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+	}
+	else {
+		ReturnCode = SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrPromiscuousChange */
+
+
+/******************************************************************************
+ *
+ *	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
+ */
+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;
@@ -1037,14 +1568,11 @@
 	SK_U16		LoMode;		/* Lower 16 bits of XMAC Mode Register. */
 	int			CurPromMode = SK_PROM_MODE_NONE;
 
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
-		return (SK_ADDR_ILLEGAL_PORT);
-	}
-
 	/* Read CurPromMode from Hardware. */
 	XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 
-	if (LoMode & XM_MD_ENA_PROM) {
+	if ((LoMode & XM_MD_ENA_PROM) != 0) {
+		/* Promiscuous mode! */
 		CurPromMode |= SK_PROM_MODE_LLC;
 	}
 	
@@ -1055,12 +1583,12 @@
 		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
 	}
 	else {
-		/* Read InexactModeBit (bit 15 in mode register). */
+		/* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */
 		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 		
-		InexactModeBit = (LoMode & XM_MD_ENA_HSH) != 0;
+		InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0;
 
-		/* Read 64-bit hash register from HW. */
+		/* Read 64-bit hash register from XMAC */
 		XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
 
 		for (HwInexact = 0xFF, i = 0; i < 8; i++) {
@@ -1080,13 +1608,12 @@
 
 	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);
 
-		/* Set bit 15 in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-		LoMode |= XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
 	}
 	else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
 		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm MC. */
@@ -1094,55 +1621,118 @@
 			Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
 		}
 		if (Inexact == 0) {
-			/* Clear bit 15 in mode register. */
-			XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-			LoMode &= ~XM_MD_ENA_HSH;
-			XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+			/* Disable Hashing */
+			SkMacHashing(pAC, IoC, PortNumber, SK_FALSE);
 		}
 		else {
 			/* Set 64-bit hash register to InexactFilter. */
-			XM_OUTHASH(
-				IoC,
-				PortNumber,
-				XM_HSM,
+			XM_OUTHASH(IoC, PortNumber, XM_HSM,
 				&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
 
-			/* Set bit 15 in mode register. */
-			XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-			LoMode |= XM_MD_ENA_HSH;
-			XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+			/* Enable Hashing */
+			SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
 		}
 	}
 
 	if ((NewPromMode & SK_PROM_MODE_LLC) &&
 		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
-		/* Set promiscuous bit in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-
-#if 0
-		/* Receive MAC frames. */
-		LoMode |= XM_MD_RX_MCTRL;
-#endif	/* 0 */
-
-		LoMode |= XM_MD_ENA_PROM;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		/* Set the MAC in Promiscuous Mode */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_TRUE);
 	}
 	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
 		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC. */
-		/* Clear promiscuous bit in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+		/* Clear Promiscuous Mode */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE);
+	}
+	
+	return (SK_ADDR_SUCCESS);
+	
+}	/* SkAddrXmacPromiscuousChange */
+
+
+/******************************************************************************
+ *
+ *	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
+ */
+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);
+	}
 
-#if 0
-		/* Don't receive MAC frames. */
-		LoMode &= ~XM_MD_RX_MCTRL;
-#endif	/* 0 */
+	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 */
 		
-		LoMode &= ~XM_MD_ENA_PROM;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		/* Set all bits in 64-bit hash register. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, 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, 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, PortNumber, SK_TRUE);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC */
+		
+		/* Clear Promiscuous Mode. */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE);
+	}
+
 	return (SK_ADDR_SUCCESS);
-}	/* SkAddrPromiscuousChange */
+	
+}	/* SkAddrGmacPromiscuousChange */
 
 
 /******************************************************************************
@@ -1163,7 +1753,7 @@
 int	SkAddrSwap(
 SK_AC	*pAC,			/* adapter context */
 SK_IOC	IoC,			/* I/O context */
-SK_U32	FromPortNumber,	/* Port1 Index */
+SK_U32	FromPortNumber,		/* Port1 Index */
 SK_U32	ToPortNumber)		/* Port2 Index */
 {
 	int			i;
@@ -1171,11 +1761,11 @@
 	SK_MAC_ADDR	MacAddr;
 	SK_U32		DWord;
 
-	if (FromPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
-	if (ToPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
@@ -1184,13 +1774,15 @@
 	}
 
 	/*
-	 * Swap
-	 * - Exact Match Entries
-	 * - FirstExactMatchRlmt;
-	 * - NextExactMatchRlmt;
-	 * - FirstExactMatchDrv;
-	 * - NextExactMatchDrv;
-	 * - 64-bit filter
+	 * 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.
 	 */
@@ -1208,46 +1800,49 @@
 			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;
-
-	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;
-
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		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].
+	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);
+	
+	(void) SkAddrMcUpdate(pAC, IoC, FromPortNumber);
+	(void) SkAddrMcUpdate(pAC, IoC, ToPortNumber);
 
 	return (SK_ADDR_SUCCESS);
+	
 }	/* SkAddrSwap */
 
 #ifdef __cplusplus

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)