Logo Search packages:      
Sourcecode: linux version File versions  Download package

skaddr.c

/******************************************************************************
 *
 * 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 */


Generated by  Doxygen 1.6.0   Back to index