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

skgepnmi.c

/*****************************************************************************
 *
 * Name:    skgepnmi.c
 * Project: GEnesis, PCI Gigabit Ethernet Adapter
 * Version: $Revision: 1.111 $
 * Date:    $Date: 2003/09/15 13:35:35 $
 * Purpose: Private Network Management Interface
 *
 ****************************************************************************/

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


#ifndef _lint
static const char SysKonnectFileId[] =
      "@(#) $Id: skgepnmi.c,v 1.111 2003/09/15 13:35:35 tschilli Exp $ (C) Marvell.";
#endif /* !_lint */

#include "h/skdrv1st.h"
#include "h/sktypes.h"
#include "h/xmac_ii.h"
#include "h/skdebug.h"
#include "h/skqueue.h"
#include "h/skgepnmi.h"
#include "h/skgesirq.h"
#include "h/skcsum.h"
#include "h/skvpd.h"
#include "h/skgehw.h"
#include "h/skgeinit.h"
#include "h/skdrv2nd.h"
#include "h/skgepnm2.h"
#ifdef SK_POWER_MGMT
#include "h/skgepmgt.h"
#endif
/* defines *******************************************************************/

#ifndef DEBUG
#define PNMI_STATIC     static
#else /* DEBUG */
#define PNMI_STATIC
#endif /* DEBUG */

/*
 * Public Function prototypes
 */
int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level);
int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
      unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
      unsigned int *pLen, SK_U32 NetIndex);
int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
      unsigned int *pLen, SK_U32 NetIndex);
int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
      unsigned int *pLen, SK_U32 NetIndex);
int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param);
int SkPnmiGenIoctl(SK_AC *pAC, SK_IOC IoC, void * pBuf,
      unsigned int * pLen, SK_U32 NetIndex);


/*
 * Private Function prototypes
 */

PNMI_STATIC SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
      PhysPortIndex);
PNMI_STATIC SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
      PhysPortIndex);
PNMI_STATIC void CopyMac(char *pDst, SK_MAC_ADDR *pMac);
PNMI_STATIC void CopyTrapQueue(SK_AC *pAC, char *pDstBuf);
PNMI_STATIC SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC,
      unsigned int PhysPortIndex, unsigned int StatIndex);
PNMI_STATIC SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex,
      unsigned int StatIndex, SK_U32 NetIndex);
PNMI_STATIC char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size);
PNMI_STATIC void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen,
      unsigned int *pEntries);
PNMI_STATIC int GetVpdKeyArr(SK_AC *pAC, SK_IOC IoC, char *pKeyArr,
      unsigned int KeyArrLen, unsigned int *pKeyNo);
PNMI_STATIC int LookupId(SK_U32 Id);
PNMI_STATIC int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac,
      unsigned int LastMac);
PNMI_STATIC int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf,
      unsigned int *pLen, SK_U32 NetIndex);
PNMI_STATIC int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id,
      char *pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
PNMI_STATIC void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac);
PNMI_STATIC void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId,
      unsigned int PortIndex);
PNMI_STATIC void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId,
      unsigned int SensorIndex);
PNMI_STATIC void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId);
PNMI_STATIC void ResetCounter(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
PNMI_STATIC int RlmtUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
PNMI_STATIC int SirqUpdate(SK_AC *pAC, SK_IOC IoC);
PNMI_STATIC void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf);
PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id, char *pBuf,
      unsigned int *pLen, SK_U32 Instance, unsigned int TableIndex, SK_U32 NetIndex);
PNMI_STATIC void CheckVctStatus(SK_AC *, SK_IOC, char *, SK_U32, SK_U32);

/*
 * Table to correlate OID with handler function and index to
 * hardware register stored in StatAddress if applicable.
 */
#include "skgemib.c"

/* global variables **********************************************************/

/*
 * Overflow status register bit table and corresponding counter
 * dependent on MAC type - the number relates to the size of overflow
 * mask returned by the pFnMacOverflow function
 */
PNMI_STATIC const SK_U16 StatOvrflwBit[][SK_PNMI_MAC_TYPES] = {
/* Bit0  */ { SK_PNMI_HTX,                      SK_PNMI_HTX_UNICAST},
/* Bit1  */ { SK_PNMI_HTX_OCTETHIGH,      SK_PNMI_HTX_BROADCAST},
/* Bit2  */ { SK_PNMI_HTX_OCTETLOW,       SK_PNMI_HTX_PMACC},
/* Bit3  */ { SK_PNMI_HTX_BROADCAST,      SK_PNMI_HTX_MULTICAST},
/* Bit4  */ { SK_PNMI_HTX_MULTICAST,      SK_PNMI_HTX_OCTETLOW},
/* Bit5  */ { SK_PNMI_HTX_UNICAST,        SK_PNMI_HTX_OCTETHIGH},
/* Bit6  */ { SK_PNMI_HTX_LONGFRAMES,     SK_PNMI_HTX_64},
/* Bit7  */ { SK_PNMI_HTX_BURST,          SK_PNMI_HTX_127},
/* Bit8  */ { SK_PNMI_HTX_PMACC,          SK_PNMI_HTX_255},
/* Bit9  */ { SK_PNMI_HTX_MACC,           SK_PNMI_HTX_511},
/* Bit10 */ { SK_PNMI_HTX_SINGLE_COL,     SK_PNMI_HTX_1023},
/* Bit11 */ { SK_PNMI_HTX_MULTI_COL,      SK_PNMI_HTX_MAX},
/* Bit12 */ { SK_PNMI_HTX_EXCESS_COL,     SK_PNMI_HTX_LONGFRAMES},
/* Bit13 */ { SK_PNMI_HTX_LATE_COL,       SK_PNMI_HTX_RESERVED},
/* Bit14 */ { SK_PNMI_HTX_DEFFERAL,       SK_PNMI_HTX_COL},
/* Bit15 */ { SK_PNMI_HTX_EXCESS_DEF,     SK_PNMI_HTX_LATE_COL},
/* Bit16 */ { SK_PNMI_HTX_UNDERRUN,       SK_PNMI_HTX_EXCESS_COL},
/* Bit17 */ { SK_PNMI_HTX_CARRIER,        SK_PNMI_HTX_MULTI_COL},
/* Bit18 */ { SK_PNMI_HTX_UTILUNDER,      SK_PNMI_HTX_SINGLE_COL},
/* Bit19 */ { SK_PNMI_HTX_UTILOVER,       SK_PNMI_HTX_UNDERRUN},
/* Bit20 */ { SK_PNMI_HTX_64,                   SK_PNMI_HTX_RESERVED},
/* Bit21 */ { SK_PNMI_HTX_127,                  SK_PNMI_HTX_RESERVED},
/* Bit22 */ { SK_PNMI_HTX_255,                  SK_PNMI_HTX_RESERVED},
/* Bit23 */ { SK_PNMI_HTX_511,                  SK_PNMI_HTX_RESERVED},
/* Bit24 */ { SK_PNMI_HTX_1023,           SK_PNMI_HTX_RESERVED},
/* Bit25 */ { SK_PNMI_HTX_MAX,                  SK_PNMI_HTX_RESERVED},
/* Bit26 */ { SK_PNMI_HTX_RESERVED,       SK_PNMI_HTX_RESERVED},
/* Bit27 */ { SK_PNMI_HTX_RESERVED,       SK_PNMI_HTX_RESERVED},
/* Bit28 */ { SK_PNMI_HTX_RESERVED,       SK_PNMI_HTX_RESERVED},
/* Bit29 */ { SK_PNMI_HTX_RESERVED,       SK_PNMI_HTX_RESERVED},
/* Bit30 */ { SK_PNMI_HTX_RESERVED,       SK_PNMI_HTX_RESERVED},
/* Bit31 */ { SK_PNMI_HTX_RESERVED,       SK_PNMI_HTX_RESERVED},
/* Bit32 */ { SK_PNMI_HRX,                      SK_PNMI_HRX_UNICAST},
/* Bit33 */ { SK_PNMI_HRX_OCTETHIGH,      SK_PNMI_HRX_BROADCAST},
/* Bit34 */ { SK_PNMI_HRX_OCTETLOW,       SK_PNMI_HRX_PMACC},
/* Bit35 */ { SK_PNMI_HRX_BROADCAST,      SK_PNMI_HRX_MULTICAST},
/* Bit36 */ { SK_PNMI_HRX_MULTICAST,      SK_PNMI_HRX_FCS},
/* Bit37 */ { SK_PNMI_HRX_UNICAST,        SK_PNMI_HRX_RESERVED},
/* Bit38 */ { SK_PNMI_HRX_PMACC,          SK_PNMI_HRX_OCTETLOW},
/* Bit39 */ { SK_PNMI_HRX_MACC,           SK_PNMI_HRX_OCTETHIGH},
/* Bit40 */ { SK_PNMI_HRX_PMACC_ERR,      SK_PNMI_HRX_BADOCTETLOW},
/* Bit41 */ { SK_PNMI_HRX_MACC_UNKWN,     SK_PNMI_HRX_BADOCTETHIGH},
/* Bit42 */ { SK_PNMI_HRX_BURST,          SK_PNMI_HRX_UNDERSIZE},
/* Bit43 */ { SK_PNMI_HRX_MISSED,         SK_PNMI_HRX_RUNT},
/* Bit44 */ { SK_PNMI_HRX_FRAMING,        SK_PNMI_HRX_64},
/* Bit45 */ { SK_PNMI_HRX_OVERFLOW,       SK_PNMI_HRX_127},
/* Bit46 */ { SK_PNMI_HRX_JABBER,         SK_PNMI_HRX_255},
/* Bit47 */ { SK_PNMI_HRX_CARRIER,        SK_PNMI_HRX_511},
/* Bit48 */ { SK_PNMI_HRX_IRLENGTH,       SK_PNMI_HRX_1023},
/* Bit49 */ { SK_PNMI_HRX_SYMBOL,         SK_PNMI_HRX_MAX},
/* Bit50 */ { SK_PNMI_HRX_SHORTS,         SK_PNMI_HRX_LONGFRAMES},
/* Bit51 */ { SK_PNMI_HRX_RUNT,           SK_PNMI_HRX_TOO_LONG},
/* Bit52 */ { SK_PNMI_HRX_TOO_LONG,       SK_PNMI_HRX_JABBER},
/* Bit53 */ { SK_PNMI_HRX_FCS,                  SK_PNMI_HRX_RESERVED},
/* Bit54 */ { SK_PNMI_HRX_RESERVED,       SK_PNMI_HRX_OVERFLOW},
/* Bit55 */ { SK_PNMI_HRX_CEXT,           SK_PNMI_HRX_RESERVED},
/* Bit56 */ { SK_PNMI_HRX_UTILUNDER,      SK_PNMI_HRX_RESERVED},
/* Bit57 */ { SK_PNMI_HRX_UTILOVER,       SK_PNMI_HRX_RESERVED},
/* Bit58 */ { SK_PNMI_HRX_64,                   SK_PNMI_HRX_RESERVED},
/* Bit59 */ { SK_PNMI_HRX_127,                  SK_PNMI_HRX_RESERVED},
/* Bit60 */ { SK_PNMI_HRX_255,                  SK_PNMI_HRX_RESERVED},
/* Bit61 */ { SK_PNMI_HRX_511,                  SK_PNMI_HRX_RESERVED},
/* Bit62 */ { SK_PNMI_HRX_1023,           SK_PNMI_HRX_RESERVED},
/* Bit63 */ { SK_PNMI_HRX_MAX,                  SK_PNMI_HRX_RESERVED}
};

/*
 * Table for hardware register saving on resets and port switches
 */
PNMI_STATIC const SK_PNMI_STATADDR StatAddr[SK_PNMI_MAX_IDX][SK_PNMI_MAC_TYPES] = {
      /* SK_PNMI_HTX */
      {{XM_TXF_OK, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_OCTETHIGH */
      {{XM_TXO_OK_HI, SK_TRUE}, {GM_TXO_OK_HI, SK_TRUE}},
      /* SK_PNMI_HTX_OCTETLOW */
      {{XM_TXO_OK_LO, SK_FALSE}, {GM_TXO_OK_LO, SK_FALSE}},
      /* SK_PNMI_HTX_BROADCAST */
      {{XM_TXF_BC_OK, SK_TRUE}, {GM_TXF_BC_OK, SK_TRUE}},
      /* SK_PNMI_HTX_MULTICAST */
      {{XM_TXF_MC_OK, SK_TRUE}, {GM_TXF_MC_OK, SK_TRUE}},
      /* SK_PNMI_HTX_UNICAST */
      {{XM_TXF_UC_OK, SK_TRUE}, {GM_TXF_UC_OK, SK_TRUE}},
      /* SK_PNMI_HTX_BURST */
      {{XM_TXE_BURST, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_PMACC */
      {{XM_TXF_MPAUSE, SK_TRUE}, {GM_TXF_MPAUSE, SK_TRUE}},
      /* SK_PNMI_HTX_MACC */
      {{XM_TXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_COL */
      {{0, SK_FALSE}, {GM_TXF_COL, SK_TRUE}},
      /* SK_PNMI_HTX_SINGLE_COL */
      {{XM_TXF_SNG_COL, SK_TRUE}, {GM_TXF_SNG_COL, SK_TRUE}},
      /* SK_PNMI_HTX_MULTI_COL */
      {{XM_TXF_MUL_COL, SK_TRUE}, {GM_TXF_MUL_COL, SK_TRUE}},
      /* SK_PNMI_HTX_EXCESS_COL */
      {{XM_TXF_ABO_COL, SK_TRUE}, {GM_TXF_ABO_COL, SK_TRUE}},
      /* SK_PNMI_HTX_LATE_COL */
      {{XM_TXF_LAT_COL, SK_TRUE}, {GM_TXF_LAT_COL, SK_TRUE}},
      /* SK_PNMI_HTX_DEFFERAL */
      {{XM_TXF_DEF, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_EXCESS_DEF */
      {{XM_TXF_EX_DEF, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_UNDERRUN */
      {{XM_TXE_FIFO_UR, SK_TRUE}, {GM_TXE_FIFO_UR, SK_TRUE}},
      /* SK_PNMI_HTX_CARRIER */
      {{XM_TXE_CS_ERR, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_UTILUNDER */
      {{0, SK_FALSE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_UTILOVER */
      {{0, SK_FALSE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_64 */
      {{XM_TXF_64B, SK_TRUE}, {GM_TXF_64B, SK_TRUE}},
      /* SK_PNMI_HTX_127 */
      {{XM_TXF_127B, SK_TRUE}, {GM_TXF_127B, SK_TRUE}},
      /* SK_PNMI_HTX_255 */
      {{XM_TXF_255B, SK_TRUE}, {GM_TXF_255B, SK_TRUE}},
      /* SK_PNMI_HTX_511 */
      {{XM_TXF_511B, SK_TRUE}, {GM_TXF_511B, SK_TRUE}},
      /* SK_PNMI_HTX_1023 */
      {{XM_TXF_1023B, SK_TRUE}, {GM_TXF_1023B, SK_TRUE}},
      /* SK_PNMI_HTX_MAX */
      {{XM_TXF_MAX_SZ, SK_TRUE}, {GM_TXF_1518B, SK_TRUE}},
      /* SK_PNMI_HTX_LONGFRAMES  */
      {{XM_TXF_LONG, SK_TRUE}, {GM_TXF_MAX_SZ, SK_TRUE}},
      /* SK_PNMI_HTX_SYNC */
      {{0, SK_FALSE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_SYNC_OCTET */
      {{0, SK_FALSE}, {0, SK_FALSE}},
      /* SK_PNMI_HTX_RESERVED */
      {{0, SK_FALSE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX */
      {{XM_RXF_OK, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_OCTETHIGH */
      {{XM_RXO_OK_HI, SK_TRUE}, {GM_RXO_OK_HI, SK_TRUE}},
      /* SK_PNMI_HRX_OCTETLOW */
      {{XM_RXO_OK_LO, SK_FALSE}, {GM_RXO_OK_LO, SK_FALSE}},
      /* SK_PNMI_HRX_BADOCTETHIGH */
      {{0, SK_FALSE}, {GM_RXO_ERR_HI, SK_TRUE}},
      /* SK_PNMI_HRX_BADOCTETLOW */
      {{0, SK_FALSE}, {GM_RXO_ERR_LO, SK_TRUE}},
      /* SK_PNMI_HRX_BROADCAST */
      {{XM_RXF_BC_OK, SK_TRUE}, {GM_RXF_BC_OK, SK_TRUE}},
      /* SK_PNMI_HRX_MULTICAST */
      {{XM_RXF_MC_OK, SK_TRUE}, {GM_RXF_MC_OK, SK_TRUE}},
      /* SK_PNMI_HRX_UNICAST */
      {{XM_RXF_UC_OK, SK_TRUE}, {GM_RXF_UC_OK, SK_TRUE}},
      /* SK_PNMI_HRX_PMACC */
      {{XM_RXF_MPAUSE, SK_TRUE}, {GM_RXF_MPAUSE, SK_TRUE}},
      /* SK_PNMI_HRX_MACC */
      {{XM_RXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_PMACC_ERR */
      {{XM_RXF_INV_MP, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_MACC_UNKWN */
      {{XM_RXF_INV_MOC, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_BURST */
      {{XM_RXE_BURST, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_MISSED */
      {{XM_RXE_FMISS, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_FRAMING */
      {{XM_RXF_FRA_ERR, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_UNDERSIZE */
      {{0, SK_FALSE}, {GM_RXF_SHT, SK_TRUE}},
      /* SK_PNMI_HRX_OVERFLOW */
      {{XM_RXE_FIFO_OV, SK_TRUE}, {GM_RXE_FIFO_OV, SK_TRUE}},
      /* SK_PNMI_HRX_JABBER */
      {{XM_RXF_JAB_PKT, SK_TRUE}, {GM_RXF_JAB_PKT, SK_TRUE}},
      /* SK_PNMI_HRX_CARRIER */
      {{XM_RXE_CAR_ERR, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_IRLENGTH */
      {{XM_RXF_LEN_ERR, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_SYMBOL */
      {{XM_RXE_SYM_ERR, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_SHORTS */
      {{XM_RXE_SHT_ERR, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_RUNT */
      {{XM_RXE_RUNT, SK_TRUE}, {GM_RXE_FRAG, SK_TRUE}},
      /* SK_PNMI_HRX_TOO_LONG */
      {{XM_RXF_LNG_ERR, SK_TRUE}, {GM_RXF_LNG_ERR, SK_TRUE}},
      /* SK_PNMI_HRX_FCS */
      {{XM_RXF_FCS_ERR, SK_TRUE}, {GM_RXF_FCS_ERR, SK_TRUE}},
      /* SK_PNMI_HRX_CEXT */
      {{XM_RXF_CEX_ERR, SK_TRUE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_UTILUNDER */
      {{0, SK_FALSE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_UTILOVER */
      {{0, SK_FALSE}, {0, SK_FALSE}},
      /* SK_PNMI_HRX_64 */
      {{XM_RXF_64B, SK_TRUE}, {GM_RXF_64B, SK_TRUE}},
      /* SK_PNMI_HRX_127 */
      {{XM_RXF_127B, SK_TRUE}, {GM_RXF_127B, SK_TRUE}},
      /* SK_PNMI_HRX_255 */
      {{XM_RXF_255B, SK_TRUE}, {GM_RXF_255B, SK_TRUE}},
      /* SK_PNMI_HRX_511 */
      {{XM_RXF_511B, SK_TRUE}, {GM_RXF_511B, SK_TRUE}},
      /* SK_PNMI_HRX_1023 */
      {{XM_RXF_1023B, SK_TRUE}, {GM_RXF_1023B, SK_TRUE}},
      /* SK_PNMI_HRX_MAX */
      {{XM_RXF_MAX_SZ, SK_TRUE}, {GM_RXF_1518B, SK_TRUE}},
      /* SK_PNMI_HRX_LONGFRAMES */
      {{0, SK_FALSE}, {GM_RXF_MAX_SZ, SK_TRUE}},
      /* SK_PNMI_HRX_RESERVED */
      {{0, SK_FALSE}, {0, SK_FALSE}}
};


/*****************************************************************************
 *
 * Public functions
 *
 */

/*****************************************************************************
 *
 * SkPnmiInit - Init function of PNMI
 *
 * Description:
 *    SK_INIT_DATA: Initialises the data structures
 *    SK_INIT_IO:   Resets the XMAC statistics, determines the device and
 *                  connector type.
 *    SK_INIT_RUN:  Starts a timer event for port switch per hour
 *                  calculation.
 *
 * Returns:
 *    Always 0
 */
int SkPnmiInit(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Level)        /* Initialization level */
{
      unsigned int      PortMax;    /* Number of ports */
      unsigned int      PortIndex;  /* Current port index in loop */
      SK_U16            Val16;            /* Multiple purpose 16 bit variable */
      SK_U8       Val8;       /* Mulitple purpose 8 bit variable */
      SK_EVPARA   EventParam; /* Event struct for timer event */
      SK_PNMI_VCT *pVctBackupData;


      SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
            ("PNMI: SkPnmiInit: Called, level=%d\n", Level));

      switch (Level) {

      case SK_INIT_DATA:
            SK_MEMSET((char *)&pAC->Pnmi, 0, sizeof(pAC->Pnmi));
            pAC->Pnmi.TrapBufFree = SK_PNMI_TRAP_QUEUE_LEN;
            pAC->Pnmi.StartUpTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
            pAC->Pnmi.RlmtChangeThreshold = SK_PNMI_DEF_RLMT_CHG_THRES;
            for (PortIndex = 0; PortIndex < SK_MAX_MACS; PortIndex ++) {

                  pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE;
                  pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
            }

#ifdef SK_PNMI_CHECK
            if (SK_PNMI_MAX_IDX != SK_PNMI_CNT_NO) {
                  
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR049, SK_PNMI_ERR049MSG);

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
                                 ("CounterOffset struct size (%d) differs from"
                                    "SK_PNMI_MAX_IDX (%d)\n",
                                    SK_PNMI_CNT_NO, SK_PNMI_MAX_IDX));
            }

            if (SK_PNMI_MAX_IDX !=
                  (sizeof(StatAddr) / (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES))) {
                  
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR050, SK_PNMI_ERR050MSG);

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
                                 ("StatAddr table size (%d) differs from "
                                    "SK_PNMI_MAX_IDX (%d)\n",
                                    (sizeof(StatAddr) /
                                     (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES)),
                                     SK_PNMI_MAX_IDX));
            }
#endif /* SK_PNMI_CHECK */
            break;

      case SK_INIT_IO:
            /*
             * Reset MAC counters
             */
            PortMax = pAC->GIni.GIMacsFound;

            for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {

                  pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PortIndex);
            }
            
            /* Initialize DSP variables for Vct() to 0xff => Never written! */            
            for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
                  pAC->GIni.GP[PortIndex].PCableLen = 0xff;
                  pVctBackupData = &pAC->Pnmi.VctBackup[PortIndex];
                  pVctBackupData->PCableLen = 0xff;
            }
            
            /*
             * Get pci bus speed
             */
            SK_IN16(IoC, B0_CTST, &Val16);
            if ((Val16 & CS_BUS_CLOCK) == 0) {

                  pAC->Pnmi.PciBusSpeed = 33;
            }
            else {
                  pAC->Pnmi.PciBusSpeed = 66;
            }

            /*
             * Get pci bus width
             */
            SK_IN16(IoC, B0_CTST, &Val16);
            if ((Val16 & CS_BUS_SLOT_SZ) == 0) {

                  pAC->Pnmi.PciBusWidth = 32;
            }
            else {
                  pAC->Pnmi.PciBusWidth = 64;
            }

            /*
             * Get chipset
             */
            switch (pAC->GIni.GIChipId) {
            case CHIP_ID_GENESIS:
                  pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_XMAC;
                  break;

            case CHIP_ID_YUKON:
                  pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_YUKON;
                  break;

            default:
                  break;
            }

            /*
             * Get PMD and DeviceType
             */
            SK_IN8(IoC, B2_PMD_TYP, &Val8);
            switch (Val8) {
            case 'S':
                  pAC->Pnmi.PMD = 3;
                  if (pAC->GIni.GIMacsFound > 1) {

                        pAC->Pnmi.DeviceType = 0x00020002;
                  }
                  else {
                        pAC->Pnmi.DeviceType = 0x00020001;
                  }
                  break;

            case 'L':
                  pAC->Pnmi.PMD = 2;
                  if (pAC->GIni.GIMacsFound > 1) {

                        pAC->Pnmi.DeviceType = 0x00020004;
                  }
                  else {
                        pAC->Pnmi.DeviceType = 0x00020003;
                  }
                  break;

            case 'C':
                  pAC->Pnmi.PMD = 4;
                  if (pAC->GIni.GIMacsFound > 1) {

                        pAC->Pnmi.DeviceType = 0x00020006;
                  }
                  else {
                        pAC->Pnmi.DeviceType = 0x00020005;
                  }
                  break;

            case 'T':
                  pAC->Pnmi.PMD = 5;
                  if (pAC->GIni.GIMacsFound > 1) {

                        pAC->Pnmi.DeviceType = 0x00020008;
                  }
                  else {
                        pAC->Pnmi.DeviceType = 0x00020007;
                  }
                  break;

            default :
                  pAC->Pnmi.PMD = 1;
                  pAC->Pnmi.DeviceType = 0;
                  break;
            }

            /*
             * Get connector
             */
            SK_IN8(IoC, B2_CONN_TYP, &Val8);
            switch (Val8) {
            case 'C':
                  pAC->Pnmi.Connector = 2;
                  break;

            case 'D':
                  pAC->Pnmi.Connector = 3;
                  break;

            case 'F':
                  pAC->Pnmi.Connector = 4;
                  break;

            case 'J':
                  pAC->Pnmi.Connector = 5;
                  break;

            case 'V':
                  pAC->Pnmi.Connector = 6;
                  break;

            default:
                  pAC->Pnmi.Connector = 1;
                  break;
            }
            break;

      case SK_INIT_RUN:
            /*
             * Start timer for RLMT change counter
             */
            SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
            SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
                  28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
                  EventParam);
            break;

      default:
            break; /* Nothing todo */
      }

      return (0);
}

/*****************************************************************************
 *
 * SkPnmiGetVar - Retrieves the value of a single OID
 *
 * Description:
 *    Calls a general sub-function for all this stuff. If the instance
 *    -1 is passed, the values of all instances are returned in an
 *    array of values.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
 *                             the data.
 *    SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
static int SkPnmiGetVar(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
SK_U32 Id,        /* Object ID that is to be processed */
void *pBuf,       /* Buffer to which the management data will be copied */
unsigned int *pLen,     /* On call: buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
            ("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
                  Id, *pLen, Instance, NetIndex));

      return (PnmiVar(pAC, IoC, SK_PNMI_GET, Id, (char *)pBuf, pLen,
            Instance, NetIndex));
}

/*****************************************************************************
 *
 * SkPnmiPreSetVar - Presets the value of a single OID
 *
 * Description:
 *    Calls a general sub-function for all this stuff. The preset does
 *    the same as a set, but returns just before finally setting the
 *    new value. This is useful to check if a set might be successfull.
 *    If the instance -1 is passed, an array of values is supposed and
 *    all instances of the OID will be set.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 *    SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
 *    SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
static int SkPnmiPreSetVar(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
SK_U32 Id,        /* Object ID that is to be processed */
void *pBuf,       /* Buffer to which the management data will be copied */
unsigned int *pLen,     /* Total length of management data */
SK_U32 Instance,  /* Instance (1..n) that is to be set or -1 */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
            ("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
                  Id, *pLen, Instance, NetIndex));


      return (PnmiVar(pAC, IoC, SK_PNMI_PRESET, Id, (char *)pBuf, pLen,
            Instance, NetIndex));
}

/*****************************************************************************
 *
 * SkPnmiSetVar - Sets the value of a single OID
 *
 * Description:
 *    Calls a general sub-function for all this stuff. The preset does
 *    the same as a set, but returns just before finally setting the
 *    new value. This is useful to check if a set might be successfull.
 *    If the instance -1 is passed, an array of values is supposed and
 *    all instances of the OID will be set.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 *    SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
 *    SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
int SkPnmiSetVar(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
SK_U32 Id,        /* Object ID that is to be processed */
void *pBuf,       /* Buffer to which the management data will be copied */
unsigned int *pLen,     /* Total length of management data */
SK_U32 Instance,  /* Instance (1..n) that is to be set or -1 */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
            ("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
                  Id, *pLen, Instance, NetIndex));

      return (PnmiVar(pAC, IoC, SK_PNMI_SET, Id, (char *)pBuf, pLen,
            Instance, NetIndex));
}

/*****************************************************************************
 *
 * SkPnmiGetStruct - Retrieves the management database in SK_PNMI_STRUCT_DATA
 *
 * Description:
 *    Runs through the IdTable, queries the single OIDs and stores the
 *    returned data into the management database structure
 *    SK_PNMI_STRUCT_DATA. The offset of the OID in the structure
 *    is stored in the IdTable. The return value of the function will also
 *    be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
 *    minimum size of SK_PNMI_MIN_STRUCT_SIZE.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
 *                             the data.
 *    SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
 */
int SkPnmiGetStruct(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
void *pBuf,       /* Buffer to which the management data will be copied. */
unsigned int *pLen,     /* Length of buffer */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      int         Ret;
      unsigned int      TableIndex;
      unsigned int      DstOffset;
      unsigned int      InstanceNo;
      unsigned int      InstanceCnt;
      SK_U32            Instance;
      unsigned int      TmpLen;
      char        KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];


      SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
            ("PNMI: SkPnmiGetStruct: Called, BufLen=%d, NetIndex=%d\n",
                  *pLen, NetIndex));

      if (*pLen < SK_PNMI_STRUCT_SIZE) {

            if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {

                  SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
                        (SK_U32)(-1));
            }

            *pLen = SK_PNMI_STRUCT_SIZE;
            return (SK_PNMI_ERR_TOO_SHORT);
      }

    /*
     * Check NetIndex
     */
      if (NetIndex >= pAC->Rlmt.NumNets) {
            return (SK_PNMI_ERR_UNKNOWN_NET);
      }

      /* Update statistic */
      SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On call");

      if ((Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1)) !=
            SK_PNMI_ERR_OK) {

            SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
            *pLen = SK_PNMI_MIN_STRUCT_SIZE;
            return (Ret);
      }

      if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {

            SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
            *pLen = SK_PNMI_MIN_STRUCT_SIZE;
            return (Ret);
      }

      if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {

            SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
            *pLen = SK_PNMI_MIN_STRUCT_SIZE;
            return (Ret);
      }

      /*
       * Increment semaphores to indicate that an update was
       * already done
       */
      pAC->Pnmi.MacUpdatedFlag ++;
      pAC->Pnmi.RlmtUpdatedFlag ++;
      pAC->Pnmi.SirqUpdatedFlag ++;

      /* Get vpd keys for instance calculation */
      Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &TmpLen);
      if (Ret != SK_PNMI_ERR_OK) {

            pAC->Pnmi.MacUpdatedFlag --;
            pAC->Pnmi.RlmtUpdatedFlag --;
            pAC->Pnmi.SirqUpdatedFlag --;

            SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
            SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
            *pLen = SK_PNMI_MIN_STRUCT_SIZE;
            return (SK_PNMI_ERR_GENERAL);
      }

      /* Retrieve values */
      SK_MEMSET((char *)pBuf, 0, SK_PNMI_STRUCT_SIZE);
      for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {

            InstanceNo = IdTable[TableIndex].InstanceNo;
            for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
                  InstanceCnt ++) {

                  DstOffset = IdTable[TableIndex].Offset +
                        (InstanceCnt - 1) *
                        IdTable[TableIndex].StructSize;

                  /*
                   * For the VPD the instance is not an index number
                   * but the key itself. Determin with the instance
                   * counter the VPD key to be used.
                   */
                  if (IdTable[TableIndex].Id == OID_SKGE_VPD_KEY ||
                        IdTable[TableIndex].Id == OID_SKGE_VPD_VALUE ||
                        IdTable[TableIndex].Id == OID_SKGE_VPD_ACCESS ||
                        IdTable[TableIndex].Id == OID_SKGE_VPD_ACTION) {

                        SK_STRNCPY((char *)&Instance, KeyArr[InstanceCnt - 1], 4);
                  }
                  else {
                        Instance = (SK_U32)InstanceCnt;
                  }

                  TmpLen = *pLen - DstOffset;
                  Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET,
                        IdTable[TableIndex].Id, (char *)pBuf +
                        DstOffset, &TmpLen, Instance, TableIndex, NetIndex);

                  /*
                   * An unknown instance error means that we reached
                   * the last instance of that variable. Proceed with
                   * the next OID in the table and ignore the return
                   * code.
                   */
                  if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {

                break;
                  }

                  if (Ret != SK_PNMI_ERR_OK) {

                        pAC->Pnmi.MacUpdatedFlag --;
                        pAC->Pnmi.RlmtUpdatedFlag --;
                        pAC->Pnmi.SirqUpdatedFlag --;

                        SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
                        SK_PNMI_SET_STAT(pBuf, Ret, DstOffset);
                        *pLen = SK_PNMI_MIN_STRUCT_SIZE;
                        return (Ret);
                  }
            }
      }

      pAC->Pnmi.MacUpdatedFlag --;
      pAC->Pnmi.RlmtUpdatedFlag --;
      pAC->Pnmi.SirqUpdatedFlag --;

      *pLen = SK_PNMI_STRUCT_SIZE;
      SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
      SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * SkPnmiPreSetStruct - Presets the management database in SK_PNMI_STRUCT_DATA
 *
 * Description:
 *    Calls a general sub-function for all this set stuff. The preset does
 *    the same as a set, but returns just before finally setting the
 *    new value. This is useful to check if a set might be successfull.
 *    The sub-function runs through the IdTable, checks which OIDs are able
 *    to set, and calls the handler function of the OID to perform the
 *    preset. The return value of the function will also be stored in
 *    SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
 *    SK_PNMI_MIN_STRUCT_SIZE.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 */
int SkPnmiPreSetStruct(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
void *pBuf,       /* Buffer which contains the data to be set */
unsigned int *pLen,     /* Length of buffer */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
            ("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d, NetIndex=%d\n",
                  *pLen, NetIndex));

      return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf,
                              pLen, NetIndex));
}

/*****************************************************************************
 *
 * SkPnmiSetStruct - Sets the management database in SK_PNMI_STRUCT_DATA
 *
 * Description:
 *    Calls a general sub-function for all this set stuff. The return value
 *    of the function will also be stored in SK_PNMI_STRUCT_DATA if the
 *    passed buffer has the minimum size of SK_PNMI_MIN_STRUCT_SIZE.
 *    The sub-function runs through the IdTable, checks which OIDs are able
 *    to set, and calls the handler function of the OID to perform the
 *    set. The return value of the function will also be stored in
 *    SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
 *    SK_PNMI_MIN_STRUCT_SIZE.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 */
int SkPnmiSetStruct(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
void *pBuf,       /* Buffer which contains the data to be set */
unsigned int *pLen,     /* Length of buffer */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
            ("PNMI: SkPnmiSetStruct: Called, BufLen=%d, NetIndex=%d\n",
                  *pLen, NetIndex));

      return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf,
                              pLen, NetIndex));
}

/*****************************************************************************
 *
 * SkPnmiEvent - Event handler
 *
 * Description:
 *    Handles the following events:
 *    SK_PNMI_EVT_SIRQ_OVERFLOW     When a hardware counter overflows an
 *                                  interrupt will be generated which is
 *                                  first handled by SIRQ which generates a
 *                                  this event. The event increments the
 *                                  upper 32 bit of the 64 bit counter.
 *    SK_PNMI_EVT_SEN_XXX           The event is generated by the I2C module
 *                                  when a sensor reports a warning or
 *                                  error. The event will store a trap
 *                                  message in the trap buffer.
 *    SK_PNMI_EVT_CHG_EST_TIMER     The timer event was initiated by this
 *                                  module and is used to calculate the
 *                                  port switches per hour.
 *    SK_PNMI_EVT_CLEAR_COUNTER     The event clears all counters and
 *                                  timestamps.
 *    SK_PNMI_EVT_XMAC_RESET        The event is generated by the driver
 *                                  before a hard reset of the XMAC is
 *                                  performed. All counters will be saved
 *                                  and added to the hardware counter
 *                                  values after reset to grant continuous
 *                                  counter values.
 *    SK_PNMI_EVT_RLMT_PORT_UP      Generated by RLMT to notify that a port
 *                                  went logically up. A trap message will
 *                                  be stored to the trap buffer.
 *    SK_PNMI_EVT_RLMT_PORT_DOWN    Generated by RLMT to notify that a port
 *                                  went logically down. A trap message will
 *                                  be stored to the trap buffer.
 *    SK_PNMI_EVT_RLMT_SEGMENTATION Generated by RLMT to notify that two
 *                                  spanning tree root bridges were
 *                                  detected. A trap message will be stored
 *                                  to the trap buffer.
 *    SK_PNMI_EVT_RLMT_ACTIVE_DOWN  Notifies PNMI that an active port went
 *                                  down. PNMI will not further add the
 *                                  statistic values to the virtual port.
 *    SK_PNMI_EVT_RLMT_ACTIVE_UP    Notifies PNMI that a port went up and
 *                                  is now an active port. PNMI will now
 *                                  add the statistic data of this port to
 *                                  the virtual port.
 *    SK_PNMI_EVT_RLMT_SET_NETS     Notifies PNMI about the net mode. The first parameter
 *                                  contains the number of nets. 1 means single net, 2 means
 *                                  dual net. The second parameter is -1
 *
 * Returns:
 *    Always 0
 */
int SkPnmiEvent(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
SK_U32 Event,           /* Event-Id */
SK_EVPARA Param)  /* Event dependent parameter */
{
      unsigned int      PhysPortIndex;
    unsigned int  MaxNetNumber;
      int               CounterIndex;
      int               Ret;
      SK_U16            MacStatus;
      SK_U64            OverflowStatus;
      SK_U64            Mask;
      int               MacType;
      SK_U64            Value;
      SK_U32            Val32;
      SK_U16            Register;
      SK_EVPARA   EventParam;
      SK_U64            NewestValue;
      SK_U64            OldestValue;
      SK_U64            Delta;
      SK_PNMI_ESTIMATE *pEst;
      SK_U32            NetIndex;
      SK_GEPORT   *pPrt;
      SK_PNMI_VCT *pVctBackupData;
      SK_U32            RetCode;
      int         i;
      SK_U32            CableLength;


#ifdef DEBUG
      if (Event != SK_PNMI_EVT_XMAC_RESET) {

            SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                  ("PNMI: SkPnmiEvent: Called, Event=0x%x, Param=0x%x\n",
                  (unsigned int)Event, (unsigned int)Param.Para64));
      }
#endif /* DEBUG */
      SK_PNMI_CHECKFLAGS("SkPnmiEvent: On call");

      MacType = pAC->GIni.GIMacType;
      
      switch (Event) {

      case SK_PNMI_EVT_SIRQ_OVERFLOW:
            PhysPortIndex = (int)Param.Para32[0];
            MacStatus = (SK_U16)Param.Para32[1];
#ifdef DEBUG
            if (PhysPortIndex >= SK_MAX_MACS) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SIRQ_OVERFLOW parameter"
                         " wrong, PhysPortIndex=0x%x\n",
                        PhysPortIndex));
                  return (0);
            }
#endif /* DEBUG */
            OverflowStatus = 0;

            /*
             * Check which source caused an overflow interrupt.
             */
            if ((pAC->GIni.GIFunc.pFnMacOverflow(pAC, IoC, PhysPortIndex,
                        MacStatus, &OverflowStatus) != 0) ||
                  (OverflowStatus == 0)) {

                  SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
                  return (0);
            }

            /*
             * Check the overflow status register and increment
             * the upper dword of corresponding counter.
             */
            for (CounterIndex = 0; CounterIndex < sizeof(Mask) * 8;
                  CounterIndex ++) {

                  Mask = (SK_U64)1 << CounterIndex;
                  if ((OverflowStatus & Mask) == 0) {

                        continue;
                  }

                  switch (StatOvrflwBit[CounterIndex][MacType]) {

                  case SK_PNMI_HTX_UTILUNDER:
                  case SK_PNMI_HTX_UTILOVER:
                        if (MacType == SK_MAC_XMAC) {
                              XM_IN16(IoC, PhysPortIndex, XM_TX_CMD, &Register);
                              Register |= XM_TX_SAM_LINE;
                              XM_OUT16(IoC, PhysPortIndex, XM_TX_CMD, Register);
                        }
                        break;

                  case SK_PNMI_HRX_UTILUNDER:
                  case SK_PNMI_HRX_UTILOVER:
                        if (MacType == SK_MAC_XMAC) {
                              XM_IN16(IoC, PhysPortIndex, XM_RX_CMD, &Register);
                              Register |= XM_RX_SAM_LINE;
                              XM_OUT16(IoC, PhysPortIndex, XM_RX_CMD, Register);
                        }
                        break;

                  case SK_PNMI_HTX_OCTETHIGH:
                  case SK_PNMI_HTX_OCTETLOW:
                  case SK_PNMI_HTX_RESERVED:
                  case SK_PNMI_HRX_OCTETHIGH:
                  case SK_PNMI_HRX_OCTETLOW:
                  case SK_PNMI_HRX_IRLENGTH:
                  case SK_PNMI_HRX_RESERVED:
                  
                  /*
                   * the following counters aren't be handled (id > 63)
                   */
                  case SK_PNMI_HTX_SYNC:
                  case SK_PNMI_HTX_SYNC_OCTET:
                        break;

                  case SK_PNMI_HRX_LONGFRAMES:
                        if (MacType == SK_MAC_GMAC) {
                              pAC->Pnmi.Port[PhysPortIndex].
                                    CounterHigh[CounterIndex] ++;
                        }
                        break;

                  default:
                        pAC->Pnmi.Port[PhysPortIndex].
                              CounterHigh[CounterIndex] ++;
                  }
            }
            break;

      case SK_PNMI_EVT_SEN_WAR_LOW:
#ifdef DEBUG
            if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_LOW parameter wrong, SensorIndex=%d\n",
                        (unsigned int)Param.Para64));
                  return (0);
            }
#endif /* DEBUG */

            /*
             * Store a trap message in the trap buffer and generate
             * an event for user space applications with the
             * SK_DRIVER_SENDEVENT macro.
             */
            QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_LOW,
                  (unsigned int)Param.Para64);
            (void)SK_DRIVER_SENDEVENT(pAC, IoC);
            break;

      case SK_PNMI_EVT_SEN_WAR_UPP:
#ifdef DEBUG
            if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_UPP parameter wrong, SensorIndex=%d\n",
                        (unsigned int)Param.Para64));
                  return (0);
            }
#endif /* DEBUG */

            /*
             * Store a trap message in the trap buffer and generate
             * an event for user space applications with the
             * SK_DRIVER_SENDEVENT macro.
             */
            QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_UPP,
                  (unsigned int)Param.Para64);
            (void)SK_DRIVER_SENDEVENT(pAC, IoC);
            break;

      case SK_PNMI_EVT_SEN_ERR_LOW:
#ifdef DEBUG
            if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_LOW parameter wrong, SensorIndex=%d\n",
                        (unsigned int)Param.Para64));
                  return (0);
            }
#endif /* DEBUG */

            /*
             * Store a trap message in the trap buffer and generate
             * an event for user space applications with the
             * SK_DRIVER_SENDEVENT macro.
             */
            QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_LOW,
                  (unsigned int)Param.Para64);
            (void)SK_DRIVER_SENDEVENT(pAC, IoC);
            break;
      
      case SK_PNMI_EVT_SEN_ERR_UPP:
#ifdef DEBUG
            if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_UPP parameter wrong, SensorIndex=%d\n",
                        (unsigned int)Param.Para64));
                  return (0);
            }
#endif /* DEBUG */

            /*
             * Store a trap message in the trap buffer and generate
             * an event for user space applications with the
             * SK_DRIVER_SENDEVENT macro.
             */
            QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_UPP,
                  (unsigned int)Param.Para64);
            (void)SK_DRIVER_SENDEVENT(pAC, IoC);
            break;

      case SK_PNMI_EVT_CHG_EST_TIMER:
            /*
             * Calculate port switch average on a per hour basis
             *   Time interval for check       : 28125 ms
             *   Number of values for average  : 8
             *
             * Be careful in changing these values, on change check
             *   - typedef of SK_PNMI_ESTIMATE (Size of EstValue
             *     array one less than value number)
             *   - Timer initialization SkTimerStart() in SkPnmiInit
             *   - Delta value below must be multiplicated with
             *     power of 2
             *
             */
            pEst = &pAC->Pnmi.RlmtChangeEstimate;
            CounterIndex = pEst->EstValueIndex + 1;
            if (CounterIndex == 7) {

                  CounterIndex = 0;
            }
            pEst->EstValueIndex = CounterIndex;

            NewestValue = pAC->Pnmi.RlmtChangeCts;
            OldestValue = pEst->EstValue[CounterIndex];
            pEst->EstValue[CounterIndex] = NewestValue;

            /*
             * Calculate average. Delta stores the number of
             * port switches per 28125 * 8 = 225000 ms
             */
            if (NewestValue >= OldestValue) {

                  Delta = NewestValue - OldestValue;
            }
            else {
                  /* Overflow situation */
                  Delta = (SK_U64)(0 - OldestValue) + NewestValue;
            }

            /*
             * Extrapolate delta to port switches per hour.
             *     Estimate = Delta * (3600000 / 225000)
             *              = Delta * 16
             *              = Delta << 4
             */
            pAC->Pnmi.RlmtChangeEstimate.Estimate = Delta << 4;

            /*
             * Check if threshold is exceeded. If the threshold is
             * permanently exceeded every 28125 ms an event will be
             * generated to remind the user of this condition.
             */
            if ((pAC->Pnmi.RlmtChangeThreshold != 0) &&
                  (pAC->Pnmi.RlmtChangeEstimate.Estimate >=
                  pAC->Pnmi.RlmtChangeThreshold)) {

                  QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_CHANGE_THRES);
                  (void)SK_DRIVER_SENDEVENT(pAC, IoC);
            }

            SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
            SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
                  28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
                  EventParam);
            break;

      case SK_PNMI_EVT_CLEAR_COUNTER:
            /*
             *  Param.Para32[0] contains the NetIndex (0 ..1).
             *  Param.Para32[1] is reserved, contains -1.
             */
            NetIndex = (SK_U32)Param.Para32[0];

#ifdef DEBUG
            if (NetIndex >= pAC->Rlmt.NumNets) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_CLEAR_COUNTER parameter wrong, NetIndex=%d\n",
                        NetIndex));

                  return (0);
            }
#endif /* DEBUG */

            /*
             * Set all counters and timestamps to zero.
             * The according NetIndex is required as a
             * parameter of the event.
             */
            ResetCounter(pAC, IoC, NetIndex);
            break;

      case SK_PNMI_EVT_XMAC_RESET:
            /*
             * To grant continuous counter values store the current
             * XMAC statistic values to the entries 1..n of the
             * CounterOffset array. XMAC Errata #2
             */
#ifdef DEBUG
            if ((unsigned int)Param.Para64 >= SK_MAX_MACS) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_XMAC_RESET parameter wrong, PhysPortIndex=%d\n",
                        (unsigned int)Param.Para64));
                  return (0);
            }
#endif
            PhysPortIndex = (unsigned int)Param.Para64;

            /*
             * Update XMAC statistic to get fresh values
             */
            Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
            if (Ret != SK_PNMI_ERR_OK) {

                  SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
                  return (0);
            }
            /*
             * Increment semaphore to indicate that an update was
             * already done
             */
            pAC->Pnmi.MacUpdatedFlag ++;

            for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
                  CounterIndex ++) {

                  if (!StatAddr[CounterIndex][MacType].GetOffset) {

                        continue;
                  }

                  pAC->Pnmi.Port[PhysPortIndex].CounterOffset[CounterIndex] =
                        GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
                  
                  pAC->Pnmi.Port[PhysPortIndex].CounterHigh[CounterIndex] = 0;
            }

            pAC->Pnmi.MacUpdatedFlag --;
            break;

      case SK_PNMI_EVT_RLMT_PORT_UP:
            PhysPortIndex = (unsigned int)Param.Para32[0];
#ifdef DEBUG
            if (PhysPortIndex >= SK_MAX_MACS) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_UP parameter"
                 " wrong, PhysPortIndex=%d\n", PhysPortIndex));

                  return (0);
            }
#endif /* DEBUG */

            /*
             * Store a trap message in the trap buffer and generate an event for
             * user space applications with the SK_DRIVER_SENDEVENT macro.
             */
            QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP, PhysPortIndex);
            (void)SK_DRIVER_SENDEVENT(pAC, IoC);

            /* Bugfix for XMAC errata (#10620)*/
            if (MacType == SK_MAC_XMAC) {
                  /* Add incremental difference to offset (#10620)*/
                  (void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
                        XM_RXE_SHT_ERR, &Val32);
                  
                  Value = (((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
                         CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
                  pAC->Pnmi.Port[PhysPortIndex].CounterOffset[SK_PNMI_HRX_SHORTS] +=
                        Value - pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark;
            }
            
            /* Tell VctStatus() that a link was up meanwhile. */
            pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_LINK;           
            break;

    case SK_PNMI_EVT_RLMT_PORT_DOWN:
            PhysPortIndex = (unsigned int)Param.Para32[0];

#ifdef DEBUG
            if (PhysPortIndex >= SK_MAX_MACS) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_DOWN parameter"
                 " wrong, PhysPortIndex=%d\n", PhysPortIndex));

                  return (0);
            }
#endif /* DEBUG */

            /*
             * Store a trap message in the trap buffer and generate an event for
             * user space applications with the SK_DRIVER_SENDEVENT macro.
             */
            QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN, PhysPortIndex);
            (void)SK_DRIVER_SENDEVENT(pAC, IoC);

            /* Bugfix #10620 - get zero level for incremental difference */
            if (MacType == SK_MAC_XMAC) {

                  (void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
                        XM_RXE_SHT_ERR, &Val32);
                  
                  pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark =
                        (((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
                         CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
            }
            break;

      case SK_PNMI_EVT_RLMT_ACTIVE_DOWN:
            PhysPortIndex = (unsigned int)Param.Para32[0];
            NetIndex = (SK_U32)Param.Para32[1];

#ifdef DEBUG
            if (PhysPortIndex >= SK_MAX_MACS) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, PhysPort=%d\n",
                        PhysPortIndex));
            }

            if (NetIndex >= pAC->Rlmt.NumNets) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, NetIndex=%d\n",
                        NetIndex));
            }
#endif /* DEBUG */

            /*
             * For now, ignore event if NetIndex != 0.
             */
            if (Param.Para32[1] != 0) {

                  return (0);
            }

            /*
             * Nothing to do if port is already inactive
             */
            if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {

                  return (0);
            }

            /*
             * Update statistic counters to calculate new offset for the virtual
             * port and increment semaphore to indicate that an update was already
             * done.
             */
            if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
                  SK_PNMI_ERR_OK) {

                  SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
                  return (0);
            }
            pAC->Pnmi.MacUpdatedFlag ++;

            /*
             * Calculate new counter offset for virtual port to grant continous
             * counting on port switches. The virtual port consists of all currently
             * active ports. The port down event indicates that a port is removed
             * from the virtual port. Therefore add the counter value of the removed
             * port to the CounterOffset for the virtual port to grant the same
             * counter value.
             */
            for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
                  CounterIndex ++) {

                  if (!StatAddr[CounterIndex][MacType].GetOffset) {

                        continue;
                  }

                  Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);

                  pAC->Pnmi.VirtualCounterOffset[CounterIndex] += Value;
            }

            /*
             * Set port to inactive
             */
            pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_FALSE;

            pAC->Pnmi.MacUpdatedFlag --;
            break;

      case SK_PNMI_EVT_RLMT_ACTIVE_UP:
            PhysPortIndex = (unsigned int)Param.Para32[0];
            NetIndex = (SK_U32)Param.Para32[1];

#ifdef DEBUG
            if (PhysPortIndex >= SK_MAX_MACS) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, PhysPort=%d\n",
                        PhysPortIndex));
            }

            if (NetIndex >= pAC->Rlmt.NumNets) {

                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
                        ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, NetIndex=%d\n",
                        NetIndex));
            }
#endif /* DEBUG */

            /*
             * For now, ignore event if NetIndex != 0.
             */
            if (Param.Para32[1] != 0) {

                  return (0);
            }

            /*
             * Nothing to do if port is already active
             */
            if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {

                  return (0);
            }

            /*
             * Statistic maintenance
             */
            pAC->Pnmi.RlmtChangeCts ++;
            pAC->Pnmi.RlmtChangeTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));

            /*
             * Store a trap message in the trap buffer and generate an event for
             * user space applications with the SK_DRIVER_SENDEVENT macro.
             */
            QueueRlmtNewMacTrap(pAC, PhysPortIndex);
            (void)SK_DRIVER_SENDEVENT(pAC, IoC);

            /*
             * Update statistic counters to calculate new offset for the virtual
             * port and increment semaphore to indicate that an update was
             * already done.
             */
            if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
                  SK_PNMI_ERR_OK) {

                  SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
                  return (0);
            }
            pAC->Pnmi.MacUpdatedFlag ++;

            /*
             * Calculate new counter offset for virtual port to grant continous
             * counting on port switches. A new port is added to the virtual port.
             * Therefore substract the counter value of the new port from the
             * CounterOffset for the virtual port to grant the same value.
             */
            for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
                  CounterIndex ++) {

                  if (!StatAddr[CounterIndex][MacType].GetOffset) {

                        continue;
                  }

                  Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);

                  pAC->Pnmi.VirtualCounterOffset[CounterIndex] -= Value;
            }

            /* Set port to active */
            pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_TRUE;

            pAC->Pnmi.MacUpdatedFlag --;
            break;

      case SK_PNMI_EVT_RLMT_SEGMENTATION:
            /*
             * Para.Para32[0] contains the NetIndex.
             */

            /*
             * Store a trap message in the trap buffer and generate an event for
             * user space applications with the SK_DRIVER_SENDEVENT macro.
             */
            QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_SEGMENTATION);
            (void)SK_DRIVER_SENDEVENT(pAC, IoC);
            break;

    case SK_PNMI_EVT_RLMT_SET_NETS:
            /*
             *  Param.Para32[0] contains the number of Nets.
             *  Param.Para32[1] is reserved, contains -1.
             */
          /*
       * Check number of nets
             */
            MaxNetNumber = pAC->GIni.GIMacsFound;
            if (((unsigned int)Param.Para32[0] < 1)
                  || ((unsigned int)Param.Para32[0] > MaxNetNumber)) {
                  return (SK_PNMI_ERR_UNKNOWN_NET);
            }

        if ((unsigned int)Param.Para32[0] == 1) { /* single net mode */
            pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
        }
        else { /* dual net mode */
            pAC->Pnmi.DualNetActiveFlag = SK_TRUE;
        }
        break;

    case SK_PNMI_EVT_VCT_RESET:
            PhysPortIndex = Param.Para32[0];
            pPrt = &pAC->GIni.GP[PhysPortIndex];
            pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
            
            if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
                  RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
                  if (RetCode == 2) {
                        /*
                         * VCT test is still running.
                         * Start VCT timer counter again.
                         */
                        SK_MEMSET((char *) &Param, 0, sizeof(Param));
                        Param.Para32[0] = PhysPortIndex;
                        Param.Para32[1] = -1;
                        SkTimerStart(pAC, IoC,
                              &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
                        4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Param);
                        break;
                  }
                  pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
                  pAC->Pnmi.VctStatus[PhysPortIndex] |=
                        (SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
                  
                  /* Copy results for later use to PNMI struct. */
                  for (i = 0; i < 4; i++)  {
                        if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
                              if ((pPrt->PMdiPairLen[i] > 35) &&
                                    (pPrt->PMdiPairLen[i] < 0xff)) {
                                    pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
                              }
                        }
                        if ((pPrt->PMdiPairLen[i] > 35) &&
                              (pPrt->PMdiPairLen[i] != 0xff)) {
                              CableLength = 1000 *
                                    (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
                        }
                        else {
                              CableLength = 0;
                        }
                        pVctBackupData->PMdiPairLen[i] = CableLength;
                        pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
                  }
                  
                  Param.Para32[0] = PhysPortIndex;
                  Param.Para32[1] = -1;
                  SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Param);
                  SkEventDispatcher(pAC, IoC);
            }
            
            break;

      default:
            break;
      }

      SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
      return (0);
}


/******************************************************************************
 *
 * Private functions
 *
 */

/*****************************************************************************
 *
 * PnmiVar - Gets, presets, and sets single OIDs
 *
 * Description:
 *    Looks up the requested OID, calls the corresponding handler
 *    function, and passes the parameters with the get, preset, or
 *    set command. The function is called by SkGePnmiGetVar,
 *    SkGePnmiPreSetVar, or SkGePnmiSetVar.
 *
 * Returns:
 *    SK_PNMI_ERR_XXX. For details have a look at the description of the
 *    calling functions.
 *    SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
 */
PNMI_STATIC int PnmiVar(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* Total length of pBuf management data  */
SK_U32 Instance,  /* Instance (1..n) that is to be set or -1 */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      unsigned int      TableIndex;
      int         Ret;


      if ((TableIndex = LookupId(Id)) == (unsigned int)(-1)) {

            *pLen = 0;
            return (SK_PNMI_ERR_UNKNOWN_OID);
      }
      
    /* Check NetIndex */
      if (NetIndex >= pAC->Rlmt.NumNets) {
            return (SK_PNMI_ERR_UNKNOWN_NET);
      }

      SK_PNMI_CHECKFLAGS("PnmiVar: On call");

      Ret = IdTable[TableIndex].Func(pAC, IoC, Action, Id, pBuf, pLen,
            Instance, TableIndex, NetIndex);

      SK_PNMI_CHECKFLAGS("PnmiVar: On return");

      return (Ret);
}

/*****************************************************************************
 *
 * PnmiStruct - Presets and Sets data in structure SK_PNMI_STRUCT_DATA
 *
 * Description:
 *    The return value of the function will also be stored in
 *    SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
 *    SK_PNMI_MIN_STRUCT_SIZE. The sub-function runs through the IdTable,
 *    checks which OIDs are able to set, and calls the handler function of
 *    the OID to perform the set. The return value of the function will
 *    also be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
 *    minimum size of SK_PNMI_MIN_STRUCT_SIZE. The function is called
 *    by SkGePnmiPreSetStruct and SkGePnmiSetStruct.
 *
 * Returns:
 *    SK_PNMI_ERR_XXX. The codes are described in the calling functions.
 *    SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
 */
PNMI_STATIC int PnmiStruct(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int  Action,      /* PRESET/SET action to be performed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* Length of pBuf management data buffer */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      int         Ret;
      unsigned int      TableIndex;
      unsigned int      DstOffset;
      unsigned int      Len;
      unsigned int      InstanceNo;
      unsigned int      InstanceCnt;
      SK_U32            Instance;
      SK_U32            Id;


      /* Check if the passed buffer has the right size */
      if (*pLen < SK_PNMI_STRUCT_SIZE) {

            /* Check if we can return the error within the buffer */
            if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {

                  SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
                        (SK_U32)(-1));
            }

            *pLen = SK_PNMI_STRUCT_SIZE;
            return (SK_PNMI_ERR_TOO_SHORT);
      }
      
    /* Check NetIndex */
      if (NetIndex >= pAC->Rlmt.NumNets) {
            return (SK_PNMI_ERR_UNKNOWN_NET);
      }
      
      SK_PNMI_CHECKFLAGS("PnmiStruct: On call");

      /*
       * Update the values of RLMT and SIRQ and increment semaphores to
       * indicate that an update was already done.
       */
      if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {

            SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
            *pLen = SK_PNMI_MIN_STRUCT_SIZE;
            return (Ret);
      }

      if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {

            SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
            *pLen = SK_PNMI_MIN_STRUCT_SIZE;
            return (Ret);
      }

      pAC->Pnmi.RlmtUpdatedFlag ++;
      pAC->Pnmi.SirqUpdatedFlag ++;

      /* Preset/Set values */
      for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {

            if ((IdTable[TableIndex].Access != SK_PNMI_RW) &&
                  (IdTable[TableIndex].Access != SK_PNMI_WO)) {

                  continue;
            }

            InstanceNo = IdTable[TableIndex].InstanceNo;
            Id = IdTable[TableIndex].Id;

            for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
                  InstanceCnt ++) {

                  DstOffset = IdTable[TableIndex].Offset +
                        (InstanceCnt - 1) *
                        IdTable[TableIndex].StructSize;

                  /*
                   * Because VPD multiple instance variables are
                   * not setable we do not need to evaluate VPD
                   * instances. Have a look to VPD instance
                   * calculation in SkPnmiGetStruct().
                   */
                  Instance = (SK_U32)InstanceCnt;

                  /*
                   * Evaluate needed buffer length
                   */
                  Len = 0;
                  Ret = IdTable[TableIndex].Func(pAC, IoC,
                        SK_PNMI_GET, IdTable[TableIndex].Id,
                        NULL, &Len, Instance, TableIndex, NetIndex);

                  if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {

                        break;
                  }
                  if (Ret != SK_PNMI_ERR_TOO_SHORT) {

                        pAC->Pnmi.RlmtUpdatedFlag --;
                        pAC->Pnmi.SirqUpdatedFlag --;

                        SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
                        SK_PNMI_SET_STAT(pBuf,
                              SK_PNMI_ERR_GENERAL, DstOffset);
                        *pLen = SK_PNMI_MIN_STRUCT_SIZE;
                        return (SK_PNMI_ERR_GENERAL);
                  }
                  if (Id == OID_SKGE_VPD_ACTION) {

                        switch (*(pBuf + DstOffset)) {

                        case SK_PNMI_VPD_CREATE:
                              Len = 3 + *(pBuf + DstOffset + 3);
                              break;

                        case SK_PNMI_VPD_DELETE:
                              Len = 3;
                              break;

                        default:
                              Len = 1;
                              break;
                        }
                  }

                  /* Call the OID handler function */
                  Ret = IdTable[TableIndex].Func(pAC, IoC, Action,
                        IdTable[TableIndex].Id, pBuf + DstOffset,
                        &Len, Instance, TableIndex, NetIndex);

                  if (Ret != SK_PNMI_ERR_OK) {

                        pAC->Pnmi.RlmtUpdatedFlag --;
                        pAC->Pnmi.SirqUpdatedFlag --;

                        SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
                        SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_BAD_VALUE,
                              DstOffset);
                        *pLen = SK_PNMI_MIN_STRUCT_SIZE;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }
            }
      }

      pAC->Pnmi.RlmtUpdatedFlag --;
      pAC->Pnmi.SirqUpdatedFlag --;

      SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
      SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * LookupId - Lookup an OID in the IdTable
 *
 * Description:
 *    Scans the IdTable to find the table entry of an OID.
 *
 * Returns:
 *    The table index or -1 if not found.
 */
PNMI_STATIC int LookupId(
SK_U32 Id)        /* Object identifier to be searched */
{
      int i;

      for (i = 0; i < ID_TABLE_SIZE; i++) {

            if (IdTable[i].Id == Id) {

                  return i;
            }
      }

      return (-1);
}

/*****************************************************************************
 *
 * OidStruct - Handler of OID_SKGE_ALL_DATA
 *
 * Description:
 *    This OID performs a Get/Preset/SetStruct call and returns all data
 *    in a SK_PNMI_STRUCT_DATA structure.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 *    SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int OidStruct(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      if (Id != OID_SKGE_ALL_DATA) {

            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR003,
                  SK_PNMI_ERR003MSG);

            *pLen = 0;
            return (SK_PNMI_ERR_GENERAL);
      }

      /*
       * Check instance. We only handle single instance variables
       */
      if (Instance != (SK_U32)(-1) && Instance != 1) {

            *pLen = 0;
            return (SK_PNMI_ERR_UNKNOWN_INST);
      }

      switch (Action) {

      case SK_PNMI_GET:
            return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex));

      case SK_PNMI_PRESET:
            return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex));

      case SK_PNMI_SET:
            return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
      }

      SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR004, SK_PNMI_ERR004MSG);

      *pLen = 0;
      return (SK_PNMI_ERR_GENERAL);
}

/*****************************************************************************
 *
 * Perform - OID handler of OID_SKGE_ACTION
 *
 * Description:
 *    None.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 *    SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int Perform(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      int   Ret;
      SK_U32      ActionOp;


      /*
       * Check instance. We only handle single instance variables
       */
      if (Instance != (SK_U32)(-1) && Instance != 1) {

            *pLen = 0;
            return (SK_PNMI_ERR_UNKNOWN_INST);
      }

      if (*pLen < sizeof(SK_U32)) {

            *pLen = sizeof(SK_U32);
            return (SK_PNMI_ERR_TOO_SHORT);
      }

      /* Check if a get should be performed */
      if (Action == SK_PNMI_GET) {

            /* A get is easy. We always return the same value */
            ActionOp = (SK_U32)SK_PNMI_ACT_IDLE;
            SK_PNMI_STORE_U32(pBuf, ActionOp);
            *pLen = sizeof(SK_U32);

            return (SK_PNMI_ERR_OK);
      }

      /* Continue with PRESET/SET action */
      if (*pLen > sizeof(SK_U32)) {

            return (SK_PNMI_ERR_BAD_VALUE);
      }

      /* Check if the command is a known one */
      SK_PNMI_READ_U32(pBuf, ActionOp);
      if (*pLen > sizeof(SK_U32) ||
            (ActionOp != SK_PNMI_ACT_IDLE &&
            ActionOp != SK_PNMI_ACT_RESET &&
            ActionOp != SK_PNMI_ACT_SELFTEST &&
            ActionOp != SK_PNMI_ACT_RESETCNT)) {

            *pLen = 0;
            return (SK_PNMI_ERR_BAD_VALUE);
      }

      /* A preset ends here */
      if (Action == SK_PNMI_PRESET) {

            return (SK_PNMI_ERR_OK);
      }

      switch (ActionOp) {

      case SK_PNMI_ACT_IDLE:
            /* Nothing to do */
            break;

      case SK_PNMI_ACT_RESET:
            /*
             * Perform a driver reset or something that comes near
             * to this.
             */
            Ret = SK_DRIVER_RESET(pAC, IoC);
            if (Ret != 0) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR005,
                        SK_PNMI_ERR005MSG);

                  return (SK_PNMI_ERR_GENERAL);
            }
            break;

      case SK_PNMI_ACT_SELFTEST:
            /*
             * Perform a driver selftest or something similar to this.
             * Currently this feature is not used and will probably
             * implemented in another way.
             */
            Ret = SK_DRIVER_SELFTEST(pAC, IoC);
            pAC->Pnmi.TestResult = Ret;
            break;

      case SK_PNMI_ACT_RESETCNT:
            /* Set all counters and timestamps to zero */
            ResetCounter(pAC, IoC, NetIndex);
            break;

      default:
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR006,
                  SK_PNMI_ERR006MSG);

            return (SK_PNMI_ERR_GENERAL);
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * Mac8023Stat - OID handler of OID_GEN_XXX and OID_802_3_XXX
 *
 * Description:
 *    Retrieves the statistic values of the virtual port (logical
 *    index 0). Only special OIDs of NDIS are handled which consist
 *    of a 32 bit instead of a 64 bit value. The OIDs are public
 *    because perhaps some other platform can use them too.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int Mac8023Stat(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex,      /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      int     Ret;
      SK_U64  StatVal;
      SK_U32  StatVal32;
      SK_BOOL Is64BitReq = SK_FALSE;

      /*
       * Only the active Mac is returned
       */
      if (Instance != (SK_U32)(-1) && Instance != 1) {

            *pLen = 0;
            return (SK_PNMI_ERR_UNKNOWN_INST);
      }

      /*
       * Check action type
       */
      if (Action != SK_PNMI_GET) {

            *pLen = 0;
            return (SK_PNMI_ERR_READ_ONLY);
      }

      /* Check length */
      switch (Id) {

      case OID_802_3_PERMANENT_ADDRESS:
      case OID_802_3_CURRENT_ADDRESS:
            if (*pLen < sizeof(SK_MAC_ADDR)) {

                  *pLen = sizeof(SK_MAC_ADDR);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      default:
#ifndef SK_NDIS_64BIT_CTR
            if (*pLen < sizeof(SK_U32)) {
                  *pLen = sizeof(SK_U32);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }

#else /* SK_NDIS_64BIT_CTR */

            /* for compatibility, at least 32bit are required for OID */
            if (*pLen < sizeof(SK_U32)) {
                  /*
                  * but indicate handling for 64bit values,
                  * if insufficient space is provided
                  */
                  *pLen = sizeof(SK_U64);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }

            Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
#endif /* SK_NDIS_64BIT_CTR */
            break;
      }

      /*
       * Update all statistics, because we retrieve virtual MAC, which
       * consists of multiple physical statistics and increment semaphore
       * to indicate that an update was already done.
       */
      Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
      if ( Ret != SK_PNMI_ERR_OK) {

            *pLen = 0;
            return (Ret);
      }
      pAC->Pnmi.MacUpdatedFlag ++;

      /*
       * Get value (MAC Index 0 identifies the virtual MAC)
       */
      switch (Id) {

      case OID_802_3_PERMANENT_ADDRESS:
            CopyMac(pBuf, &pAC->Addr.Net[NetIndex].PermanentMacAddress);
            *pLen = sizeof(SK_MAC_ADDR);
            break;

      case OID_802_3_CURRENT_ADDRESS:
            CopyMac(pBuf, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
            *pLen = sizeof(SK_MAC_ADDR);
            break;

      default:
            StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param, NetIndex);

            /* by default 32bit values are evaluated */
            if (!Is64BitReq) {
                  StatVal32 = (SK_U32)StatVal;
                  SK_PNMI_STORE_U32(pBuf, StatVal32);
                  *pLen = sizeof(SK_U32);
            }
            else {
                  SK_PNMI_STORE_U64(pBuf, StatVal);
                  *pLen = sizeof(SK_U64);
            }
            break;
      }

      pAC->Pnmi.MacUpdatedFlag --;

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * MacPrivateStat - OID handler function of OID_SKGE_STAT_XXX
 *
 * Description:
 *    Retrieves the MAC statistic data.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int MacPrivateStat(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      unsigned int      LogPortMax;
      unsigned int      LogPortIndex;
      unsigned int      PhysPortMax;
      unsigned int      Limit;
      unsigned int      Offset;
      int                     MacType;
      int                     Ret;
      SK_U64                  StatVal;
      
      

      /* Calculate instance if wished. MAC index 0 is the virtual MAC */
      PhysPortMax = pAC->GIni.GIMacsFound;
      LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
      
      MacType = pAC->GIni.GIMacType;

      if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
            LogPortMax--;
      }

      if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
            /* Check instance range */
            if ((Instance < 1) || (Instance > LogPortMax)) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_UNKNOWN_INST);
            }
            LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
            Limit = LogPortIndex + 1;
      }

      else { /* Instance == (SK_U32)(-1), get all Instances of that OID */

            LogPortIndex = 0;
            Limit = LogPortMax;
      }

      /* Check action */
      if (Action != SK_PNMI_GET) {

            *pLen = 0;
            return (SK_PNMI_ERR_READ_ONLY);
      }

      /* Check length */
      if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U64)) {

            *pLen = (Limit - LogPortIndex) * sizeof(SK_U64);
            return (SK_PNMI_ERR_TOO_SHORT);
      }

      /*
       * Update MAC statistic and increment semaphore to indicate that
       * an update was already done.
       */
      Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
      if (Ret != SK_PNMI_ERR_OK) {

            *pLen = 0;
            return (Ret);
      }
      pAC->Pnmi.MacUpdatedFlag ++;

      /* Get value */
      Offset = 0;
      for (; LogPortIndex < Limit; LogPortIndex ++) {

            switch (Id) {

/* XXX not yet implemented due to XMAC problems
            case OID_SKGE_STAT_TX_UTIL:
                  return (SK_PNMI_ERR_GENERAL);
*/
/* XXX not yet implemented due to XMAC problems
            case OID_SKGE_STAT_RX_UTIL:
                  return (SK_PNMI_ERR_GENERAL);
*/
            case OID_SKGE_STAT_RX:
                  if (MacType == SK_MAC_GMAC) {
                        StatVal =
                              GetStatVal(pAC, IoC, LogPortIndex,
                                             SK_PNMI_HRX_BROADCAST, NetIndex) +
                              GetStatVal(pAC, IoC, LogPortIndex,
                                             SK_PNMI_HRX_MULTICAST, NetIndex) +
                              GetStatVal(pAC, IoC, LogPortIndex,
                                             SK_PNMI_HRX_UNICAST, NetIndex) +
                              GetStatVal(pAC, IoC, LogPortIndex,
                                             SK_PNMI_HRX_UNDERSIZE, NetIndex);
                  }
                  else {
                        StatVal = GetStatVal(pAC, IoC, LogPortIndex,
                              IdTable[TableIndex].Param, NetIndex);
                  }
                  break;

            case OID_SKGE_STAT_TX:
                  if (MacType == SK_MAC_GMAC) {
                        StatVal =
                              GetStatVal(pAC, IoC, LogPortIndex,
                                             SK_PNMI_HTX_BROADCAST, NetIndex) +
                              GetStatVal(pAC, IoC, LogPortIndex,
                                             SK_PNMI_HTX_MULTICAST, NetIndex) +
                              GetStatVal(pAC, IoC, LogPortIndex,
                                             SK_PNMI_HTX_UNICAST, NetIndex);
                  }
                  else {
                        StatVal = GetStatVal(pAC, IoC, LogPortIndex,
                              IdTable[TableIndex].Param, NetIndex);
                  }
                  break;

            default:
                  StatVal = GetStatVal(pAC, IoC, LogPortIndex,
                        IdTable[TableIndex].Param, NetIndex);
            }
            SK_PNMI_STORE_U64(pBuf + Offset, StatVal);

            Offset += sizeof(SK_U64);
      }
      *pLen = Offset;

      pAC->Pnmi.MacUpdatedFlag --;

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * Addr - OID handler function of OID_SKGE_PHYS_CUR_ADDR and _FAC_ADDR
 *
 * Description:
 *    Get/Presets/Sets the current and factory MAC address. The MAC
 *    address of the virtual port, which is reported to the OS, may
 *    not be changed, but the physical ones. A set to the virtual port
 *    will be ignored. No error should be reported because otherwise
 *    a multiple instance set (-1) would always fail.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 *    SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int Addr(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      int         Ret;
      unsigned int      LogPortMax;
      unsigned int      PhysPortMax;
      unsigned int      LogPortIndex;
      unsigned int      PhysPortIndex;
      unsigned int      Limit;
      unsigned int      Offset = 0;

      /*
       * Calculate instance if wished. MAC index 0 is the virtual
       * MAC.
       */
      PhysPortMax = pAC->GIni.GIMacsFound;
      LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);

      if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
            LogPortMax--;
      }

      if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
            /* Check instance range */
            if ((Instance < 1) || (Instance > LogPortMax)) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_UNKNOWN_INST);
            }
            LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
            Limit = LogPortIndex + 1;
      }
      else { /* Instance == (SK_U32)(-1), get all Instances of that OID */

            LogPortIndex = 0;
            Limit = LogPortMax;
      }

      /*
       * Perform Action
       */
      if (Action == SK_PNMI_GET) {

            /* Check length */
            if (*pLen < (Limit - LogPortIndex) * 6) {

                  *pLen = (Limit - LogPortIndex) * 6;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }

            /*
             * Get value
             */
            for (; LogPortIndex < Limit; LogPortIndex ++) {

                  switch (Id) {

                  case OID_SKGE_PHYS_CUR_ADDR:
                        if (LogPortIndex == 0) {
                              CopyMac(pBuf + Offset, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
                        }
                        else {
                              PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);

                              CopyMac(pBuf + Offset,
                                    &pAC->Addr.Port[PhysPortIndex].CurrentMacAddress);
                        }
                        Offset += 6;
                        break;

                  case OID_SKGE_PHYS_FAC_ADDR:
                        if (LogPortIndex == 0) {
                              CopyMac(pBuf + Offset,
                                    &pAC->Addr.Net[NetIndex].PermanentMacAddress);
                        }
                        else {
                              PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                    pAC, LogPortIndex);

                              CopyMac(pBuf + Offset,
                                    &pAC->Addr.Port[PhysPortIndex].PermanentMacAddress);
                        }
                        Offset += 6;
                        break;

                  default:
                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR008,
                              SK_PNMI_ERR008MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
            }

            *pLen = Offset;
      }
      else {
            /*
             * The logical MAC address may not be changed only
             * the physical ones
             */
            if (Id == OID_SKGE_PHYS_FAC_ADDR) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_READ_ONLY);
            }

            /*
             * Only the current address may be changed
             */
            if (Id != OID_SKGE_PHYS_CUR_ADDR) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR009,
                        SK_PNMI_ERR009MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            /* Check length */
            if (*pLen < (Limit - LogPortIndex) * 6) {

                  *pLen = (Limit - LogPortIndex) * 6;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            if (*pLen > (Limit - LogPortIndex) * 6) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_BAD_VALUE);
            }

            /*
             * Check Action
             */
            if (Action == SK_PNMI_PRESET) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_OK);
            }

            /*
             * Set OID_SKGE_MAC_CUR_ADDR
             */
            for (; LogPortIndex < Limit; LogPortIndex ++, Offset += 6) {

                  /*
                   * A set to virtual port and set of broadcast
                   * address will be ignored
                   */
                  if (LogPortIndex == 0 || SK_MEMCMP(pBuf + Offset,
                        "\xff\xff\xff\xff\xff\xff", 6) == 0) {

                        continue;
                  }

                  PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC,
                        LogPortIndex);

                  Ret = SkAddrOverride(pAC, IoC, PhysPortIndex,
                        (SK_MAC_ADDR *)(pBuf + Offset),
                        (LogPortIndex == 0 ? SK_ADDR_VIRTUAL_ADDRESS :
                        SK_ADDR_PHYSICAL_ADDRESS));
                  if (Ret != SK_ADDR_OVERRIDE_SUCCESS) {

                        return (SK_PNMI_ERR_GENERAL);
                  }
            }
            *pLen = Offset;
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * CsumStat - OID handler function of OID_SKGE_CHKSM_XXX
 *
 * Description:
 *    Retrieves the statistic values of the CSUM module. The CSUM data
 *    structure must be available in the SK_AC even if the CSUM module
 *    is not included, because PNMI reads the statistic data from the
 *    CSUM part of SK_AC directly.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int CsumStat(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      unsigned int      Index;
      unsigned int      Limit;
      unsigned int      Offset = 0;
      SK_U64            StatVal;


      /*
       * Calculate instance if wished
       */
      if (Instance != (SK_U32)(-1)) {

            if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_UNKNOWN_INST);
            }
            Index = (unsigned int)Instance - 1;
            Limit = Index + 1;
      }
      else {
            Index = 0;
            Limit = SKCS_NUM_PROTOCOLS;
      }

      /*
       * Check action
       */
      if (Action != SK_PNMI_GET) {

            *pLen = 0;
            return (SK_PNMI_ERR_READ_ONLY);
      }

      /* Check length */
      if (*pLen < (Limit - Index) * sizeof(SK_U64)) {

            *pLen = (Limit - Index) * sizeof(SK_U64);
            return (SK_PNMI_ERR_TOO_SHORT);
      }

      /*
       * Get value
       */
      for (; Index < Limit; Index ++) {

            switch (Id) {

            case OID_SKGE_CHKSM_RX_OK_CTS:
                  StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxOkCts;
                  break;

            case OID_SKGE_CHKSM_RX_UNABLE_CTS:
                  StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxUnableCts;
                  break;

            case OID_SKGE_CHKSM_RX_ERR_CTS:
                  StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxErrCts;
                  break;

            case OID_SKGE_CHKSM_TX_OK_CTS:
                  StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxOkCts;
                  break;

            case OID_SKGE_CHKSM_TX_UNABLE_CTS:
                  StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxUnableCts;
                  break;

            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR010,
                        SK_PNMI_ERR010MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
            Offset += sizeof(SK_U64);
      }

      /*
       * Store used buffer space
       */
      *pLen = Offset;

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * SensorStat - OID handler function of OID_SKGE_SENSOR_XXX
 *
 * Description:
 *    Retrieves the statistic values of the I2C module, which handles
 *    the temperature and voltage sensors.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int SensorStat(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      unsigned int      i;
      unsigned int      Index;
      unsigned int      Limit;
      unsigned int      Offset;
      unsigned int      Len;
      SK_U32            Val32;
      SK_U64            Val64;


      /*
       * Calculate instance if wished
       */
      if ((Instance != (SK_U32)(-1))) {

            if ((Instance < 1) || (Instance > (SK_U32)pAC->I2c.MaxSens)) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_UNKNOWN_INST);
            }

            Index = (unsigned int)Instance -1;
            Limit = (unsigned int)Instance;
      }
      else {
            Index = 0;
            Limit = (unsigned int) pAC->I2c.MaxSens;
      }

      /*
       * Check action
       */
      if (Action != SK_PNMI_GET) {

            *pLen = 0;
            return (SK_PNMI_ERR_READ_ONLY);
      }

      /* Check length */
      switch (Id) {

      case OID_SKGE_SENSOR_VALUE:
      case OID_SKGE_SENSOR_WAR_THRES_LOW:
      case OID_SKGE_SENSOR_WAR_THRES_UPP:
      case OID_SKGE_SENSOR_ERR_THRES_LOW:
      case OID_SKGE_SENSOR_ERR_THRES_UPP:
            if (*pLen < (Limit - Index) * sizeof(SK_U32)) {

                  *pLen = (Limit - Index) * sizeof(SK_U32);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      case OID_SKGE_SENSOR_DESCR:
            for (Offset = 0, i = Index; i < Limit; i ++) {

                  Len = (unsigned int)
                        SK_STRLEN(pAC->I2c.SenTable[i].SenDesc) + 1;
                  if (Len >= SK_PNMI_STRINGLEN2) {

                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR011,
                              SK_PNMI_ERR011MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
                  Offset += Len;
            }
            if (*pLen < Offset) {

                  *pLen = Offset;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      case OID_SKGE_SENSOR_INDEX:
      case OID_SKGE_SENSOR_TYPE:
      case OID_SKGE_SENSOR_STATUS:
            if (*pLen < Limit - Index) {

                  *pLen = Limit - Index;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      case OID_SKGE_SENSOR_WAR_CTS:
      case OID_SKGE_SENSOR_WAR_TIME:
      case OID_SKGE_SENSOR_ERR_CTS:
      case OID_SKGE_SENSOR_ERR_TIME:
            if (*pLen < (Limit - Index) * sizeof(SK_U64)) {

                  *pLen = (Limit - Index) * sizeof(SK_U64);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      default:
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR012,
                  SK_PNMI_ERR012MSG);

            *pLen = 0;
            return (SK_PNMI_ERR_GENERAL);

      }

      /*
       * Get value
       */
      for (Offset = 0; Index < Limit; Index ++) {

            switch (Id) {

            case OID_SKGE_SENSOR_INDEX:
                  *(pBuf + Offset) = (char)Index;
                  Offset += sizeof(char);
                  break;

            case OID_SKGE_SENSOR_DESCR:
                  Len = SK_STRLEN(pAC->I2c.SenTable[Index].SenDesc);
                  SK_MEMCPY(pBuf + Offset + 1,
                        pAC->I2c.SenTable[Index].SenDesc, Len);
                  *(pBuf + Offset) = (char)Len;
                  Offset += Len + 1;
                  break;

            case OID_SKGE_SENSOR_TYPE:
                  *(pBuf + Offset) =
                        (char)pAC->I2c.SenTable[Index].SenType;
                  Offset += sizeof(char);
                  break;

            case OID_SKGE_SENSOR_VALUE:
                  Val32 = (SK_U32)pAC->I2c.SenTable[Index].SenValue;
                  SK_PNMI_STORE_U32(pBuf + Offset, Val32);
                  Offset += sizeof(SK_U32);
                  break;

            case OID_SKGE_SENSOR_WAR_THRES_LOW:
                  Val32 = (SK_U32)pAC->I2c.SenTable[Index].
                        SenThreWarnLow;
                  SK_PNMI_STORE_U32(pBuf + Offset, Val32);
                  Offset += sizeof(SK_U32);
                  break;

            case OID_SKGE_SENSOR_WAR_THRES_UPP:
                  Val32 = (SK_U32)pAC->I2c.SenTable[Index].
                        SenThreWarnHigh;
                  SK_PNMI_STORE_U32(pBuf + Offset, Val32);
                  Offset += sizeof(SK_U32);
                  break;

            case OID_SKGE_SENSOR_ERR_THRES_LOW:
                  Val32 = (SK_U32)pAC->I2c.SenTable[Index].
                        SenThreErrLow;
                  SK_PNMI_STORE_U32(pBuf + Offset, Val32);
                  Offset += sizeof(SK_U32);
                  break;

            case OID_SKGE_SENSOR_ERR_THRES_UPP:
                  Val32 = pAC->I2c.SenTable[Index].SenThreErrHigh;
                  SK_PNMI_STORE_U32(pBuf + Offset, Val32);
                  Offset += sizeof(SK_U32);
                  break;

            case OID_SKGE_SENSOR_STATUS:
                  *(pBuf + Offset) =
                        (char)pAC->I2c.SenTable[Index].SenErrFlag;
                  Offset += sizeof(char);
                  break;

            case OID_SKGE_SENSOR_WAR_CTS:
                  Val64 = pAC->I2c.SenTable[Index].SenWarnCts;
                  SK_PNMI_STORE_U64(pBuf + Offset, Val64);
                  Offset += sizeof(SK_U64);
                  break;

            case OID_SKGE_SENSOR_ERR_CTS:
                  Val64 = pAC->I2c.SenTable[Index].SenErrCts;
                  SK_PNMI_STORE_U64(pBuf + Offset, Val64);
                  Offset += sizeof(SK_U64);
                  break;

            case OID_SKGE_SENSOR_WAR_TIME:
                  Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
                        SenBegWarnTS);
                  SK_PNMI_STORE_U64(pBuf + Offset, Val64);
                  Offset += sizeof(SK_U64);
                  break;

            case OID_SKGE_SENSOR_ERR_TIME:
                  Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
                        SenBegErrTS);
                  SK_PNMI_STORE_U64(pBuf + Offset, Val64);
                  Offset += sizeof(SK_U64);
                  break;

            default:
                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
                        ("SensorStat: Unknown OID should be handled before"));

                  return (SK_PNMI_ERR_GENERAL);
            }
      }

      /*
       * Store used buffer space
       */
      *pLen = Offset;

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * Vpd - OID handler function of OID_SKGE_VPD_XXX
 *
 * Description:
 *    Get/preset/set of VPD data. As instance the name of a VPD key
 *    can be passed. The Instance parameter is a SK_U32 and can be
 *    used as a string buffer for the VPD key, because their maximum
 *    length is 4 byte.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 *    SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int Vpd(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      SK_VPD_STATUS     *pVpdStatus;
      unsigned int      BufLen;
      char        Buf[256];
      char        KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
      char        KeyStr[SK_PNMI_VPD_KEY_SIZE];
      unsigned int      KeyNo;
      unsigned int      Offset;
      unsigned int      Index;
      unsigned int      FirstIndex;
      unsigned int      LastIndex;
      unsigned int      Len;
      int         Ret;
      SK_U32            Val32;

      /*
       * Get array of all currently stored VPD keys
       */
      Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &KeyNo);
      if (Ret != SK_PNMI_ERR_OK) {
            *pLen = 0;
            return (Ret);
      }

      /*
       * If instance is not -1, try to find the requested VPD key for
       * the multiple instance variables. The other OIDs as for example
       * OID VPD_ACTION are single instance variables and must be
       * handled separatly.
       */
      FirstIndex = 0;
      LastIndex = KeyNo;

      if ((Instance != (SK_U32)(-1))) {

            if (Id == OID_SKGE_VPD_KEY || Id == OID_SKGE_VPD_VALUE ||
                  Id == OID_SKGE_VPD_ACCESS) {

                  SK_STRNCPY(KeyStr, (char *)&Instance, 4);
                  KeyStr[4] = 0;

                  for (Index = 0; Index < KeyNo; Index ++) {

                        if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
                              FirstIndex = Index;
                              LastIndex = Index+1;
                              break;
                        }
                  }
                  if (Index == KeyNo) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_UNKNOWN_INST);
                  }
            }
            else if (Instance != 1) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_UNKNOWN_INST);
            }
      }

      /*
       * Get value, if a query should be performed
       */
      if (Action == SK_PNMI_GET) {

            switch (Id) {

            case OID_SKGE_VPD_FREE_BYTES:
                  /* Check length of buffer */
                  if (*pLen < sizeof(SK_U32)) {

                        *pLen = sizeof(SK_U32);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  /* Get number of free bytes */
                  pVpdStatus = VpdStat(pAC, IoC);
                  if (pVpdStatus == NULL) {

                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR017,
                              SK_PNMI_ERR017MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
                  if ((pVpdStatus->vpd_status & VPD_VALID) == 0) {

                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR018,
                              SK_PNMI_ERR018MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
                  
                  Val32 = (SK_U32)pVpdStatus->vpd_free_rw;
                  SK_PNMI_STORE_U32(pBuf, Val32);
                  *pLen = sizeof(SK_U32);
                  break;

            case OID_SKGE_VPD_ENTRIES_LIST:
                  /* Check length */
                  for (Len = 0, Index = 0; Index < KeyNo; Index ++) {

                        Len += SK_STRLEN(KeyArr[Index]) + 1;
                  }
                  if (*pLen < Len) {

                        *pLen = Len;
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }

                  /* Get value */
                  *(pBuf) = (char)Len - 1;
                  for (Offset = 1, Index = 0; Index < KeyNo; Index ++) {

                        Len = SK_STRLEN(KeyArr[Index]);
                        SK_MEMCPY(pBuf + Offset, KeyArr[Index], Len);

                        Offset += Len;

                        if (Index < KeyNo - 1) {

                              *(pBuf + Offset) = ' ';
                              Offset ++;
                        }
                  }
                  *pLen = Offset;
                  break;

            case OID_SKGE_VPD_ENTRIES_NUMBER:
                  /* Check length */
                  if (*pLen < sizeof(SK_U32)) {

                        *pLen = sizeof(SK_U32);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }

                  Val32 = (SK_U32)KeyNo;
                  SK_PNMI_STORE_U32(pBuf, Val32);
                  *pLen = sizeof(SK_U32);
                  break;

            case OID_SKGE_VPD_KEY:
                  /* Check buffer length, if it is large enough */
                  for (Len = 0, Index = FirstIndex;
                        Index < LastIndex; Index ++) {

                        Len += SK_STRLEN(KeyArr[Index]) + 1;
                  }
                  if (*pLen < Len) {

                        *pLen = Len;
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }

                  /*
                   * Get the key to an intermediate buffer, because
                   * we have to prepend a length byte.
                   */
                  for (Offset = 0, Index = FirstIndex;
                        Index < LastIndex; Index ++) {

                        Len = SK_STRLEN(KeyArr[Index]);

                        *(pBuf + Offset) = (char)Len;
                        SK_MEMCPY(pBuf + Offset + 1, KeyArr[Index],
                              Len);
                        Offset += Len + 1;
                  }
                  *pLen = Offset;
                  break;

            case OID_SKGE_VPD_VALUE:
                  /* Check the buffer length if it is large enough */
                  for (Offset = 0, Index = FirstIndex;
                        Index < LastIndex; Index ++) {

                        BufLen = 256;
                        if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
                              (int *)&BufLen) > 0 ||
                              BufLen >= SK_PNMI_VPD_DATALEN) {

                              SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                    SK_PNMI_ERR021,
                                    SK_PNMI_ERR021MSG);

                              return (SK_PNMI_ERR_GENERAL);
                        }
                        Offset += BufLen + 1;
                  }
                  if (*pLen < Offset) {

                        *pLen = Offset;
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }

                  /*
                   * Get the value to an intermediate buffer, because
                   * we have to prepend a length byte.
                   */
                  for (Offset = 0, Index = FirstIndex;
                        Index < LastIndex; Index ++) {

                        BufLen = 256;
                        if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
                              (int *)&BufLen) > 0 ||
                              BufLen >= SK_PNMI_VPD_DATALEN) {

                              SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                    SK_PNMI_ERR022,
                                    SK_PNMI_ERR022MSG);

                              *pLen = 0;
                              return (SK_PNMI_ERR_GENERAL);
                        }

                        *(pBuf + Offset) = (char)BufLen;
                        SK_MEMCPY(pBuf + Offset + 1, Buf, BufLen);
                        Offset += BufLen + 1;
                  }
                  *pLen = Offset;
                  break;

            case OID_SKGE_VPD_ACCESS:
                  if (*pLen < LastIndex - FirstIndex) {

                        *pLen = LastIndex - FirstIndex;
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }

                  for (Offset = 0, Index = FirstIndex;
                        Index < LastIndex; Index ++) {

                        if (VpdMayWrite(KeyArr[Index])) {

                              *(pBuf + Offset) = SK_PNMI_VPD_RW;
                        }
                        else {
                              *(pBuf + Offset) = SK_PNMI_VPD_RO;
                        }
                        Offset ++;
                  }
                  *pLen = Offset;
                  break;

            case OID_SKGE_VPD_ACTION:
                  Offset = LastIndex - FirstIndex;
                  if (*pLen < Offset) {

                        *pLen = Offset;
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  SK_MEMSET(pBuf, 0, Offset);
                  *pLen = Offset;
                  break;

            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR023,
                        SK_PNMI_ERR023MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }
      }
      else {
            /* The only OID which can be set is VPD_ACTION */
            if (Id != OID_SKGE_VPD_ACTION) {

                  if (Id == OID_SKGE_VPD_FREE_BYTES ||
                        Id == OID_SKGE_VPD_ENTRIES_LIST ||
                        Id == OID_SKGE_VPD_ENTRIES_NUMBER ||
                        Id == OID_SKGE_VPD_KEY ||
                        Id == OID_SKGE_VPD_VALUE ||
                        Id == OID_SKGE_VPD_ACCESS) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_READ_ONLY);
                  }

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR024,
                        SK_PNMI_ERR024MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            /*
             * From this point we handle VPD_ACTION. Check the buffer
             * length. It should at least have the size of one byte.
             */
            if (*pLen < 1) {

                  *pLen = 1;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }

            /*
             * The first byte contains the VPD action type we should
             * perform.
             */
            switch (*pBuf) {

            case SK_PNMI_VPD_IGNORE:
                  /* Nothing to do */
                  break;

            case SK_PNMI_VPD_CREATE:
                  /*
                   * We have to create a new VPD entry or we modify
                   * an existing one. Check first the buffer length.
                   */
                  if (*pLen < 4) {

                        *pLen = 4;
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  KeyStr[0] = pBuf[1];
                  KeyStr[1] = pBuf[2];
                  KeyStr[2] = 0;

                  /*
                   * Is the entry writable or does it belong to the
                   * read-only area?
                   */
                  if (!VpdMayWrite(KeyStr)) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }

                  Offset = (int)pBuf[3] & 0xFF;

                  SK_MEMCPY(Buf, pBuf + 4, Offset);
                  Buf[Offset] = 0;

                  /* A preset ends here */
                  if (Action == SK_PNMI_PRESET) {

                        return (SK_PNMI_ERR_OK);
                  }

                  /* Write the new entry or modify an existing one */
                  Ret = VpdWrite(pAC, IoC, KeyStr, Buf);
                  if (Ret == SK_PNMI_VPD_NOWRITE ) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }
                  else if (Ret != SK_PNMI_VPD_OK) {

                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR025,
                              SK_PNMI_ERR025MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }

                  /*
                   * Perform an update of the VPD data. This is
                   * not mandantory, but just to be sure.
                   */
                  Ret = VpdUpdate(pAC, IoC);
                  if (Ret != SK_PNMI_VPD_OK) {

                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR026,
                              SK_PNMI_ERR026MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
                  break;

            case SK_PNMI_VPD_DELETE:
                  /* Check if the buffer size is plausible */
                  if (*pLen < 3) {

                        *pLen = 3;
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  if (*pLen > 3) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }
                  KeyStr[0] = pBuf[1];
                  KeyStr[1] = pBuf[2];
                  KeyStr[2] = 0;

                  /* Find the passed key in the array */
                  for (Index = 0; Index < KeyNo; Index ++) {

                        if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {

                              break;
                        }
                  }
                  /*
                   * If we cannot find the key it is wrong, so we
                   * return an appropriate error value.
                   */
                  if (Index == KeyNo) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }

                  if (Action == SK_PNMI_PRESET) {

                        return (SK_PNMI_ERR_OK);
                  }

                  /* Ok, you wanted it and you will get it */
                  Ret = VpdDelete(pAC, IoC, KeyStr);
                  if (Ret != SK_PNMI_VPD_OK) {

                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR027,
                              SK_PNMI_ERR027MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }

                  /*
                   * Perform an update of the VPD data. This is
                   * not mandantory, but just to be sure.
                   */
                  Ret = VpdUpdate(pAC, IoC);
                  if (Ret != SK_PNMI_VPD_OK) {

                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR028,
                              SK_PNMI_ERR028MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
                  break;

            default:
                  *pLen = 0;
                  return (SK_PNMI_ERR_BAD_VALUE);
            }
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * General - OID handler function of various single instance OIDs
 *
 * Description:
 *    The code is simple. No description necessary.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int General(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      int         Ret;
      unsigned int      Index;
      unsigned int      Len;
      unsigned int      Offset;
      unsigned int      Val;
      SK_U8       Val8;
      SK_U16            Val16;
      SK_U32            Val32;
      SK_U64            Val64;
      SK_U64            Val64RxHwErrs = 0;
      SK_U64            Val64TxHwErrs = 0;
      SK_BOOL           Is64BitReq = SK_FALSE;
      char        Buf[256];
      int               MacType;

      /*
       * Check instance. We only handle single instance variables.
       */
      if (Instance != (SK_U32)(-1) && Instance != 1) {

            *pLen = 0;
            return (SK_PNMI_ERR_UNKNOWN_INST);
      }

      /*
       * Check action. We only allow get requests.
       */
      if (Action != SK_PNMI_GET) {

            *pLen = 0;
            return (SK_PNMI_ERR_READ_ONLY);
      }
      
      MacType = pAC->GIni.GIMacType;
      
      /*
       * Check length for the various supported OIDs
       */
      switch (Id) {

      case OID_GEN_XMIT_ERROR:
      case OID_GEN_RCV_ERROR:
      case OID_GEN_RCV_NO_BUFFER:
#ifndef SK_NDIS_64BIT_CTR
            if (*pLen < sizeof(SK_U32)) {
                  *pLen = sizeof(SK_U32);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }

#else /* SK_NDIS_64BIT_CTR */

            /*
             * for compatibility, at least 32bit are required for oid
             */
            if (*pLen < sizeof(SK_U32)) {
                  /*
                  * but indicate handling for 64bit values,
                  * if insufficient space is provided
                  */
                  *pLen = sizeof(SK_U64);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }

            Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
#endif /* SK_NDIS_64BIT_CTR */
            break;

      case OID_SKGE_PORT_NUMBER:
      case OID_SKGE_DEVICE_TYPE:
      case OID_SKGE_RESULT:
      case OID_SKGE_RLMT_MONITOR_NUMBER:
      case OID_GEN_TRANSMIT_QUEUE_LENGTH:
      case OID_SKGE_TRAP_NUMBER:
      case OID_SKGE_MDB_VERSION:
      case OID_SKGE_BOARDLEVEL:
      case OID_SKGE_CHIPID:
      case OID_SKGE_RAMSIZE:
            if (*pLen < sizeof(SK_U32)) {

                  *pLen = sizeof(SK_U32);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      case OID_SKGE_CHIPSET:
            if (*pLen < sizeof(SK_U16)) {

                  *pLen = sizeof(SK_U16);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      case OID_SKGE_BUS_TYPE:
      case OID_SKGE_BUS_SPEED:
      case OID_SKGE_BUS_WIDTH:
      case OID_SKGE_SENSOR_NUMBER:
      case OID_SKGE_CHKSM_NUMBER:
      case OID_SKGE_VAUXAVAIL:
            if (*pLen < sizeof(SK_U8)) {

                  *pLen = sizeof(SK_U8);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      case OID_SKGE_TX_SW_QUEUE_LEN:
      case OID_SKGE_TX_SW_QUEUE_MAX:
      case OID_SKGE_TX_RETRY:
      case OID_SKGE_RX_INTR_CTS:
      case OID_SKGE_TX_INTR_CTS:
      case OID_SKGE_RX_NO_BUF_CTS:
      case OID_SKGE_TX_NO_BUF_CTS:
      case OID_SKGE_TX_USED_DESCR_NO:
      case OID_SKGE_RX_DELIVERED_CTS:
      case OID_SKGE_RX_OCTETS_DELIV_CTS:
      case OID_SKGE_RX_HW_ERROR_CTS:
      case OID_SKGE_TX_HW_ERROR_CTS:
      case OID_SKGE_IN_ERRORS_CTS:
      case OID_SKGE_OUT_ERROR_CTS:
      case OID_SKGE_ERR_RECOVERY_CTS:
      case OID_SKGE_SYSUPTIME:
            if (*pLen < sizeof(SK_U64)) {

                  *pLen = sizeof(SK_U64);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      default:
            /* Checked later */
            break;
      }

      /* Update statistic */
      if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
            Id == OID_SKGE_TX_HW_ERROR_CTS ||
            Id == OID_SKGE_IN_ERRORS_CTS ||
            Id == OID_SKGE_OUT_ERROR_CTS ||
            Id == OID_GEN_XMIT_ERROR ||
            Id == OID_GEN_RCV_ERROR) {

            /* Force the XMAC to update its statistic counters and
             * Increment semaphore to indicate that an update was
             * already done.
             */
            Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
            if (Ret != SK_PNMI_ERR_OK) {

                  *pLen = 0;
                  return (Ret);
            }
            pAC->Pnmi.MacUpdatedFlag ++;

            /*
             * Some OIDs consist of multiple hardware counters. Those
             * values which are contained in all of them will be added
             * now.
             */
            switch (Id) {

            case OID_SKGE_RX_HW_ERROR_CTS:
            case OID_SKGE_IN_ERRORS_CTS:
            case OID_GEN_RCV_ERROR:
                  Val64RxHwErrs =
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT, NetIndex);
              break;

            case OID_SKGE_TX_HW_ERROR_CTS:
            case OID_SKGE_OUT_ERROR_CTS:
            case OID_GEN_XMIT_ERROR:
                  Val64TxHwErrs =
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN, NetIndex) +
                        GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER, NetIndex);
                  break;
            }
      }

      /*
       * Retrieve value
       */
      switch (Id) {

      case OID_SKGE_SUPPORTED_LIST:
            Len = ID_TABLE_SIZE * sizeof(SK_U32);
            if (*pLen < Len) {

                  *pLen = Len;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            for (Offset = 0, Index = 0; Offset < Len;
                  Offset += sizeof(SK_U32), Index ++) {

                  Val32 = (SK_U32)IdTable[Index].Id;
                  SK_PNMI_STORE_U32(pBuf + Offset, Val32);
            }
            *pLen = Len;
            break;

      case OID_SKGE_BOARDLEVEL:
            Val32 = (SK_U32)pAC->GIni.GILevel;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      case OID_SKGE_PORT_NUMBER:
            Val32 = (SK_U32)pAC->GIni.GIMacsFound;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      case OID_SKGE_DEVICE_TYPE:
            Val32 = (SK_U32)pAC->Pnmi.DeviceType;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      case OID_SKGE_DRIVER_DESCR:
            if (pAC->Pnmi.pDriverDescription == NULL) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR007,
                        SK_PNMI_ERR007MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            Len = SK_STRLEN(pAC->Pnmi.pDriverDescription) + 1;
            if (Len > SK_PNMI_STRINGLEN1) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR029,
                        SK_PNMI_ERR029MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            if (*pLen < Len) {

                  *pLen = Len;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            *pBuf = (char)(Len - 1);
            SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverDescription, Len - 1);
            *pLen = Len;
            break;

      case OID_SKGE_DRIVER_VERSION:
            if (pAC->Pnmi.pDriverVersion == NULL) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
                        SK_PNMI_ERR030MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            Len = SK_STRLEN(pAC->Pnmi.pDriverVersion) + 1;
            if (Len > SK_PNMI_STRINGLEN1) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
                        SK_PNMI_ERR031MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            if (*pLen < Len) {

                  *pLen = Len;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            *pBuf = (char)(Len - 1);
            SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverVersion, Len - 1);
            *pLen = Len;
            break;

      case OID_SKGE_DRIVER_RELDATE:
            if (pAC->Pnmi.pDriverReleaseDate == NULL) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
                        SK_PNMI_ERR053MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            Len = SK_STRLEN(pAC->Pnmi.pDriverReleaseDate) + 1;
            if (Len > SK_PNMI_STRINGLEN1) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
                        SK_PNMI_ERR054MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            if (*pLen < Len) {

                  *pLen = Len;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            *pBuf = (char)(Len - 1);
            SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverReleaseDate, Len - 1);
            *pLen = Len;
            break;

      case OID_SKGE_DRIVER_FILENAME:
            if (pAC->Pnmi.pDriverFileName == NULL) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
                        SK_PNMI_ERR055MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            Len = SK_STRLEN(pAC->Pnmi.pDriverFileName) + 1;
            if (Len > SK_PNMI_STRINGLEN1) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
                        SK_PNMI_ERR056MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            if (*pLen < Len) {

                  *pLen = Len;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            *pBuf = (char)(Len - 1);
            SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverFileName, Len - 1);
            *pLen = Len;
            break;

      case OID_SKGE_HW_DESCR:
            /*
             * The hardware description is located in the VPD. This
             * query may move to the initialisation routine. But
             * the VPD data is cached and therefore a call here
             * will not make much difference.
             */
            Len = 256;
            if (VpdRead(pAC, IoC, VPD_NAME, Buf, (int *)&Len) > 0) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR032,
                        SK_PNMI_ERR032MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }
            Len ++;
            if (Len > SK_PNMI_STRINGLEN1) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR033,
                        SK_PNMI_ERR033MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }
            if (*pLen < Len) {

                  *pLen = Len;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            *pBuf = (char)(Len - 1);
            SK_MEMCPY(pBuf + 1, Buf, Len - 1);
            *pLen = Len;
            break;

      case OID_SKGE_HW_VERSION:
            /* Oh, I love to do some string manipulation */
            if (*pLen < 5) {

                  *pLen = 5;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            Val8 = (SK_U8)pAC->GIni.GIPciHwRev;
            pBuf[0] = 4;
            pBuf[1] = 'v';
            pBuf[2] = (char)(0x30 | ((Val8 >> 4) & 0x0F));
            pBuf[3] = '.';
            pBuf[4] = (char)(0x30 | (Val8 & 0x0F));
            *pLen = 5;
            break;

      case OID_SKGE_CHIPSET:
            Val16 = pAC->Pnmi.Chipset;
            SK_PNMI_STORE_U16(pBuf, Val16);
            *pLen = sizeof(SK_U16);
            break;

      case OID_SKGE_CHIPID:
            Val32 = pAC->GIni.GIChipId;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      case OID_SKGE_RAMSIZE:
            Val32 = pAC->GIni.GIRamSize;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      case OID_SKGE_VAUXAVAIL:
            *pBuf = (char) pAC->GIni.GIVauxAvail;
            *pLen = sizeof(char);
            break;

      case OID_SKGE_BUS_TYPE:
            *pBuf = (char) SK_PNMI_BUS_PCI;
            *pLen = sizeof(char);
            break;

      case OID_SKGE_BUS_SPEED:
            *pBuf = pAC->Pnmi.PciBusSpeed;
            *pLen = sizeof(char);
            break;

      case OID_SKGE_BUS_WIDTH:
            *pBuf = pAC->Pnmi.PciBusWidth;
            *pLen = sizeof(char);
            break;

      case OID_SKGE_RESULT:
            Val32 = pAC->Pnmi.TestResult;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      case OID_SKGE_SENSOR_NUMBER:
            *pBuf = (char)pAC->I2c.MaxSens;
            *pLen = sizeof(char);
            break;

      case OID_SKGE_CHKSM_NUMBER:
            *pBuf = SKCS_NUM_PROTOCOLS;
            *pLen = sizeof(char);
            break;

      case OID_SKGE_TRAP_NUMBER:
            GetTrapQueueLen(pAC, &Len, &Val);
            Val32 = (SK_U32)Val;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      case OID_SKGE_TRAP:
            GetTrapQueueLen(pAC, &Len, &Val);
            if (*pLen < Len) {

                  *pLen = Len;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            CopyTrapQueue(pAC, pBuf);
            *pLen = Len;
            break;

      case OID_SKGE_RLMT_MONITOR_NUMBER:
/* XXX Not yet implemented by RLMT therefore we return zero elements */
            Val32 = 0;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      case OID_SKGE_TX_SW_QUEUE_LEN:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueLen;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].TxSwQueueLen +
                              pAC->Pnmi.BufPort[1].TxSwQueueLen;
                  }                 
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].TxSwQueueLen +
                              pAC->Pnmi.Port[1].TxSwQueueLen;
                  }                 
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;


      case OID_SKGE_TX_SW_QUEUE_MAX:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueMax;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].TxSwQueueMax +
                              pAC->Pnmi.BufPort[1].TxSwQueueMax;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueMax;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].TxSwQueueMax +
                              pAC->Pnmi.Port[1].TxSwQueueMax;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_TX_RETRY:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].TxRetryCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].TxRetryCts +
                              pAC->Pnmi.BufPort[1].TxRetryCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].TxRetryCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].TxRetryCts +
                              pAC->Pnmi.Port[1].TxRetryCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_RX_INTR_CTS:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].RxIntrCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].RxIntrCts +
                              pAC->Pnmi.BufPort[1].RxIntrCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].RxIntrCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].RxIntrCts +
                              pAC->Pnmi.Port[1].RxIntrCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_TX_INTR_CTS:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].TxIntrCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].TxIntrCts +
                              pAC->Pnmi.BufPort[1].TxIntrCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].TxIntrCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].TxIntrCts +
                              pAC->Pnmi.Port[1].TxIntrCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_RX_NO_BUF_CTS:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].RxNoBufCts +
                              pAC->Pnmi.BufPort[1].RxNoBufCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].RxNoBufCts +
                              pAC->Pnmi.Port[1].RxNoBufCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_TX_NO_BUF_CTS:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].TxNoBufCts +
                              pAC->Pnmi.BufPort[1].TxNoBufCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].TxNoBufCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].TxNoBufCts +
                              pAC->Pnmi.Port[1].TxNoBufCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_TX_USED_DESCR_NO:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].TxUsedDescrNo;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].TxUsedDescrNo +
                              pAC->Pnmi.BufPort[1].TxUsedDescrNo;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].TxUsedDescrNo;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].TxUsedDescrNo +
                              pAC->Pnmi.Port[1].TxUsedDescrNo;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_RX_DELIVERED_CTS:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].RxDeliveredCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].RxDeliveredCts +
                              pAC->Pnmi.BufPort[1].RxDeliveredCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].RxDeliveredCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].RxDeliveredCts +
                              pAC->Pnmi.Port[1].RxDeliveredCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_RX_OCTETS_DELIV_CTS:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].RxOctetsDeliveredCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].RxOctetsDeliveredCts +
                              pAC->Pnmi.BufPort[1].RxOctetsDeliveredCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].RxOctetsDeliveredCts +
                              pAC->Pnmi.Port[1].RxOctetsDeliveredCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_RX_HW_ERROR_CTS:
            SK_PNMI_STORE_U64(pBuf, Val64RxHwErrs);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_TX_HW_ERROR_CTS:
            SK_PNMI_STORE_U64(pBuf, Val64TxHwErrs);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_IN_ERRORS_CTS:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = Val64RxHwErrs +
                              pAC->Pnmi.BufPort[0].RxNoBufCts +
                              pAC->Pnmi.BufPort[1].RxNoBufCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = Val64RxHwErrs +
                              pAC->Pnmi.Port[0].RxNoBufCts +
                              pAC->Pnmi.Port[1].RxNoBufCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_OUT_ERROR_CTS:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = Val64TxHwErrs +
                              pAC->Pnmi.BufPort[0].TxNoBufCts +
                              pAC->Pnmi.BufPort[1].TxNoBufCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = Val64TxHwErrs +
                              pAC->Pnmi.Port[0].TxNoBufCts +
                              pAC->Pnmi.Port[1].TxNoBufCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_ERR_RECOVERY_CTS:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.BufPort[NetIndex].ErrRecoveryCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.BufPort[0].ErrRecoveryCts +
                              pAC->Pnmi.BufPort[1].ErrRecoveryCts;
                  }
            }
            else {
                  /* Dual net mode */
                  if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                        Val64 = pAC->Pnmi.Port[NetIndex].ErrRecoveryCts;
                  }
                  /* Single net mode */
                  else {
                        Val64 = pAC->Pnmi.Port[0].ErrRecoveryCts +
                              pAC->Pnmi.Port[1].ErrRecoveryCts;
                  }
            }
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_SYSUPTIME:
            Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
            Val64 -= pAC->Pnmi.StartUpTime;
            SK_PNMI_STORE_U64(pBuf, Val64);
            *pLen = sizeof(SK_U64);
            break;

      case OID_SKGE_MDB_VERSION:
            Val32 = SK_PNMI_MDB_VERSION;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      case OID_GEN_RCV_ERROR:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
            }
            else {
                  Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
            }

            /*
             * by default 32bit values are evaluated
             */
            if (!Is64BitReq) {
                  Val32 = (SK_U32)Val64;
                  SK_PNMI_STORE_U32(pBuf, Val32);
                  *pLen = sizeof(SK_U32);
            }
            else {
                  SK_PNMI_STORE_U64(pBuf, Val64);
                  *pLen = sizeof(SK_U64);
            }
            break;

      case OID_GEN_XMIT_ERROR:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
            }
            else {
                  Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
            }

            /*
             * by default 32bit values are evaluated
             */
            if (!Is64BitReq) {
                  Val32 = (SK_U32)Val64;
                  SK_PNMI_STORE_U32(pBuf, Val32);
                  *pLen = sizeof(SK_U32);
            }
            else {
                  SK_PNMI_STORE_U64(pBuf, Val64);
                  *pLen = sizeof(SK_U64);
            }
            break;

      case OID_GEN_RCV_NO_BUFFER:
            /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
            if (MacType == SK_MAC_XMAC) {
                  Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
            }
            else {
                  Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
            }

            /*
             * by default 32bit values are evaluated
             */
            if (!Is64BitReq) {
                  Val32 = (SK_U32)Val64;
                  SK_PNMI_STORE_U32(pBuf, Val32);
                  *pLen = sizeof(SK_U32);
            }
            else {
                  SK_PNMI_STORE_U64(pBuf, Val64);
                  *pLen = sizeof(SK_U64);
            }
            break;

      case OID_GEN_TRANSMIT_QUEUE_LENGTH:
            Val32 = (SK_U32)pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
            SK_PNMI_STORE_U32(pBuf, Val32);
            *pLen = sizeof(SK_U32);
            break;

      default:
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR034,
                  SK_PNMI_ERR034MSG);

            *pLen = 0;
            return (SK_PNMI_ERR_GENERAL);
      }

      if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
            Id == OID_SKGE_TX_HW_ERROR_CTS ||
            Id == OID_SKGE_IN_ERRORS_CTS ||
            Id == OID_SKGE_OUT_ERROR_CTS ||
            Id == OID_GEN_XMIT_ERROR ||
            Id == OID_GEN_RCV_ERROR) {

            pAC->Pnmi.MacUpdatedFlag --;
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * Rlmt - OID handler function of OID_SKGE_RLMT_XXX single instance.
 *
 * Description:
 *    Get/Presets/Sets the RLMT OIDs.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 *    SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int Rlmt(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      int         Ret;
      unsigned int      PhysPortIndex;
      unsigned int      PhysPortMax;
      SK_EVPARA   EventParam;
      SK_U32            Val32;
      SK_U64            Val64;


      /*
       * Check instance. Only single instance OIDs are allowed here.
       */
      if (Instance != (SK_U32)(-1) && Instance != 1) {

            *pLen = 0;
            return (SK_PNMI_ERR_UNKNOWN_INST);
      }

      /*
       * Perform the requested action.
       */
      if (Action == SK_PNMI_GET) {

            /*
             * Check if the buffer length is large enough.
             */

            switch (Id) {

            case OID_SKGE_RLMT_MODE:
            case OID_SKGE_RLMT_PORT_ACTIVE:
            case OID_SKGE_RLMT_PORT_PREFERRED:
                  if (*pLen < sizeof(SK_U8)) {

                        *pLen = sizeof(SK_U8);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  break;

            case OID_SKGE_RLMT_PORT_NUMBER:
                  if (*pLen < sizeof(SK_U32)) {

                        *pLen = sizeof(SK_U32);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  break;

            case OID_SKGE_RLMT_CHANGE_CTS:
            case OID_SKGE_RLMT_CHANGE_TIME:
            case OID_SKGE_RLMT_CHANGE_ESTIM:
            case OID_SKGE_RLMT_CHANGE_THRES:
                  if (*pLen < sizeof(SK_U64)) {

                        *pLen = sizeof(SK_U64);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  break;

            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR035,
                        SK_PNMI_ERR035MSG);

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            /*
             * Update RLMT statistic and increment semaphores to indicate
             * that an update was already done. Maybe RLMT will hold its
             * statistic always up to date some time. Then we can
             * remove this type of call.
             */
            if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {

                  *pLen = 0;
                  return (Ret);
            }
            pAC->Pnmi.RlmtUpdatedFlag ++;

            /*
             * Retrieve Value
            */
            switch (Id) {

            case OID_SKGE_RLMT_MODE:
                  *pBuf = (char)pAC->Rlmt.Net[0].RlmtMode;
                  *pLen = sizeof(char);
                  break;

            case OID_SKGE_RLMT_PORT_NUMBER:
                  Val32 = (SK_U32)pAC->GIni.GIMacsFound;
                  SK_PNMI_STORE_U32(pBuf, Val32);
                  *pLen = sizeof(SK_U32);
                  break;

            case OID_SKGE_RLMT_PORT_ACTIVE:
                  *pBuf = 0;
                  /*
                   * If multiple ports may become active this OID
                   * doesn't make sense any more. A new variable in
                   * the port structure should be created. However,
                   * for this variable the first active port is
                   * returned.
                   */
                  PhysPortMax = pAC->GIni.GIMacsFound;

                  for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
                        PhysPortIndex ++) {

                        if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {

                              *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(PhysPortIndex);
                              break;
                        }
                  }
                  *pLen = sizeof(char);
                  break;

            case OID_SKGE_RLMT_PORT_PREFERRED:
                  *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(pAC->Rlmt.Net[NetIndex].Preference);
                  *pLen = sizeof(char);
                  break;

            case OID_SKGE_RLMT_CHANGE_CTS:
                  Val64 = pAC->Pnmi.RlmtChangeCts;
                  SK_PNMI_STORE_U64(pBuf, Val64);
                  *pLen = sizeof(SK_U64);
                  break;

            case OID_SKGE_RLMT_CHANGE_TIME:
                  Val64 = pAC->Pnmi.RlmtChangeTime;
                  SK_PNMI_STORE_U64(pBuf, Val64);
                  *pLen = sizeof(SK_U64);
                  break;

            case OID_SKGE_RLMT_CHANGE_ESTIM:
                  Val64 = pAC->Pnmi.RlmtChangeEstimate.Estimate;
                  SK_PNMI_STORE_U64(pBuf, Val64);
                  *pLen = sizeof(SK_U64);
                  break;

            case OID_SKGE_RLMT_CHANGE_THRES:
                  Val64 = pAC->Pnmi.RlmtChangeThreshold;
                  SK_PNMI_STORE_U64(pBuf, Val64);
                  *pLen = sizeof(SK_U64);
                  break;

            default:
                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
                        ("Rlmt: Unknown OID should be handled before"));

                  pAC->Pnmi.RlmtUpdatedFlag --;
                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            pAC->Pnmi.RlmtUpdatedFlag --;
      }
      else {
            /* Perform a preset or set */
            switch (Id) {

            case OID_SKGE_RLMT_MODE:
                  /* Check if the buffer length is plausible */
                  if (*pLen < sizeof(char)) {

                        *pLen = sizeof(char);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  /* Check if the value range is correct */
                  if (*pLen != sizeof(char) ||
                        (*pBuf & SK_PNMI_RLMT_MODE_CHK_LINK) == 0 ||
                        *(SK_U8 *)pBuf > 15) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }
                  /* The preset ends here */
                  if (Action == SK_PNMI_PRESET) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_OK);
                  }
                  /* Send an event to RLMT to change the mode */
                  SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
                  EventParam.Para32[0] |= (SK_U32)(*pBuf);
                  EventParam.Para32[1] = 0;
                  if (SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE,
                        EventParam) > 0) {

                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR037,
                              SK_PNMI_ERR037MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
                  break;

            case OID_SKGE_RLMT_PORT_PREFERRED:
                  /* Check if the buffer length is plausible */
                  if (*pLen < sizeof(char)) {

                        *pLen = sizeof(char);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  /* Check if the value range is correct */
                  if (*pLen != sizeof(char) || *(SK_U8 *)pBuf >
                        (SK_U8)pAC->GIni.GIMacsFound) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }
                  /* The preset ends here */
                  if (Action == SK_PNMI_PRESET) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_OK);
                  }

                  /*
                   * Send an event to RLMT change the preferred port.
                   * A param of -1 means automatic mode. RLMT will
                   * make the decision which is the preferred port.
                   */
                  SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
                  EventParam.Para32[0] = (SK_U32)(*pBuf) - 1;
                  EventParam.Para32[1] = NetIndex;
                  if (SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE,
                        EventParam) > 0) {

                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR038,
                              SK_PNMI_ERR038MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
                  break;

            case OID_SKGE_RLMT_CHANGE_THRES:
                  /* Check if the buffer length is plausible */
                  if (*pLen < sizeof(SK_U64)) {

                        *pLen = sizeof(SK_U64);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  /*
                   * There are not many restrictions to the
                   * value range.
                   */
                  if (*pLen != sizeof(SK_U64)) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }
                  /* A preset ends here */
                  if (Action == SK_PNMI_PRESET) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_OK);
                  }
                  /*
                   * Store the new threshold, which will be taken
                   * on the next timer event.
                   */
                  SK_PNMI_READ_U64(pBuf, Val64);
                  pAC->Pnmi.RlmtChangeThreshold = Val64;
                  break;

            default:
                  /* The other OIDs are not be able for set */
                  *pLen = 0;
                  return (SK_PNMI_ERR_READ_ONLY);
            }
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * RlmtStat - OID handler function of OID_SKGE_RLMT_XXX multiple instance.
 *
 * Description:
 *    Performs get requests on multiple instance variables.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int RlmtStat(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      unsigned int      PhysPortMax;
      unsigned int      PhysPortIndex;
      unsigned int      Limit;
      unsigned int      Offset;
      int         Ret;
      SK_U32            Val32;
      SK_U64            Val64;

      /*
       * Calculate the port indexes from the instance.
       */
      PhysPortMax = pAC->GIni.GIMacsFound;

      if ((Instance != (SK_U32)(-1))) {
            /* Check instance range */
            if ((Instance < 1) || (Instance > PhysPortMax)) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_UNKNOWN_INST);
            }

            /* Single net mode */
            PhysPortIndex = Instance - 1;

            /* Dual net mode */
            if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                  PhysPortIndex = NetIndex;
            }

            /* Both net modes */
            Limit = PhysPortIndex + 1;
      }
      else {
            /* Single net mode */
            PhysPortIndex = 0;
            Limit = PhysPortMax;

            /* Dual net mode */
            if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                  PhysPortIndex = NetIndex;
                  Limit = PhysPortIndex + 1;
            }
      }

      /*
       * Currently only get requests are allowed.
       */
      if (Action != SK_PNMI_GET) {

            *pLen = 0;
            return (SK_PNMI_ERR_READ_ONLY);
      }

      /*
       * Check if the buffer length is large enough.
       */
      switch (Id) {

      case OID_SKGE_RLMT_PORT_INDEX:
      case OID_SKGE_RLMT_STATUS:
            if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {

                  *pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      case OID_SKGE_RLMT_TX_HELLO_CTS:
      case OID_SKGE_RLMT_RX_HELLO_CTS:
      case OID_SKGE_RLMT_TX_SP_REQ_CTS:
      case OID_SKGE_RLMT_RX_SP_CTS:
            if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U64)) {

                  *pLen = (Limit - PhysPortIndex) * sizeof(SK_U64);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      default:
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR039,
                  SK_PNMI_ERR039MSG);

            *pLen = 0;
            return (SK_PNMI_ERR_GENERAL);

      }

      /*
       * Update statistic and increment semaphores to indicate that
       * an update was already done.
       */
      if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {

            *pLen = 0;
            return (Ret);
      }
      pAC->Pnmi.RlmtUpdatedFlag ++;

      /*
       * Get value
       */
      Offset = 0;
      for (; PhysPortIndex < Limit; PhysPortIndex ++) {

            switch (Id) {

            case OID_SKGE_RLMT_PORT_INDEX:
                  Val32 = PhysPortIndex;
                  SK_PNMI_STORE_U32(pBuf + Offset, Val32);
                  Offset += sizeof(SK_U32);
                  break;

            case OID_SKGE_RLMT_STATUS:
                  if (pAC->Rlmt.Port[PhysPortIndex].PortState ==
                        SK_RLMT_PS_INIT ||
                        pAC->Rlmt.Port[PhysPortIndex].PortState ==
                        SK_RLMT_PS_DOWN) {

                        Val32 = SK_PNMI_RLMT_STATUS_ERROR;
                  }
                  else if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {

                        Val32 = SK_PNMI_RLMT_STATUS_ACTIVE;
                  }
                  else {
                        Val32 = SK_PNMI_RLMT_STATUS_STANDBY;
                  }
                  SK_PNMI_STORE_U32(pBuf + Offset, Val32);
                  Offset += sizeof(SK_U32);
                  break;

            case OID_SKGE_RLMT_TX_HELLO_CTS:
                  Val64 = pAC->Rlmt.Port[PhysPortIndex].TxHelloCts;
                  SK_PNMI_STORE_U64(pBuf + Offset, Val64);
                  Offset += sizeof(SK_U64);
                  break;

            case OID_SKGE_RLMT_RX_HELLO_CTS:
                  Val64 = pAC->Rlmt.Port[PhysPortIndex].RxHelloCts;
                  SK_PNMI_STORE_U64(pBuf + Offset, Val64);
                  Offset += sizeof(SK_U64);
                  break;

            case OID_SKGE_RLMT_TX_SP_REQ_CTS:
                  Val64 = pAC->Rlmt.Port[PhysPortIndex].TxSpHelloReqCts;
                  SK_PNMI_STORE_U64(pBuf + Offset, Val64);
                  Offset += sizeof(SK_U64);
                  break;

            case OID_SKGE_RLMT_RX_SP_CTS:
                  Val64 = pAC->Rlmt.Port[PhysPortIndex].RxSpHelloCts;
                  SK_PNMI_STORE_U64(pBuf + Offset, Val64);
                  Offset += sizeof(SK_U64);
                  break;

            default:
                  SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
                        ("RlmtStat: Unknown OID should be errored before"));

                  pAC->Pnmi.RlmtUpdatedFlag --;
                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }
      }
      *pLen = Offset;

      pAC->Pnmi.RlmtUpdatedFlag --;

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * MacPrivateConf - OID handler function of OIDs concerning the configuration
 *
 * Description:
 *    Get/Presets/Sets the OIDs concerning the configuration.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 *    SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int MacPrivateConf(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      unsigned int      PhysPortMax;
      unsigned int      PhysPortIndex;
      unsigned int      LogPortMax;
      unsigned int      LogPortIndex;
      unsigned int      Limit;
      unsigned int      Offset;
      char        Val8;
      char        *pBufPtr;
      int               Ret;
      SK_EVPARA   EventParam;
      SK_U32            Val32;

      /*
       * Calculate instance if wished. MAC index 0 is the virtual MAC.
       */
      PhysPortMax = pAC->GIni.GIMacsFound;
      LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);

      if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
            LogPortMax--;
      }

      if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
            /* Check instance range */
            if ((Instance < 1) || (Instance > LogPortMax)) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_UNKNOWN_INST);
            }
            LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
            Limit = LogPortIndex + 1;
      }

      else { /* Instance == (SK_U32)(-1), get all Instances of that OID */

            LogPortIndex = 0;
            Limit = LogPortMax;
      }

      /*
       * Perform action
       */
      if (Action == SK_PNMI_GET) {

            /* Check length */
            switch (Id) {

            case OID_SKGE_PMD:
            case OID_SKGE_CONNECTOR:
            case OID_SKGE_LINK_CAP:
            case OID_SKGE_LINK_MODE:
            case OID_SKGE_LINK_MODE_STATUS:
            case OID_SKGE_LINK_STATUS:
            case OID_SKGE_FLOWCTRL_CAP:
            case OID_SKGE_FLOWCTRL_MODE:
            case OID_SKGE_FLOWCTRL_STATUS:
            case OID_SKGE_PHY_OPERATION_CAP:
            case OID_SKGE_PHY_OPERATION_MODE:
            case OID_SKGE_PHY_OPERATION_STATUS:
            case OID_SKGE_SPEED_CAP:
            case OID_SKGE_SPEED_MODE:
            case OID_SKGE_SPEED_STATUS:
                  if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) {

                        *pLen = (Limit - LogPortIndex) * sizeof(SK_U8);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  break;

        case OID_SKGE_MTU:
        case OID_SKGE_PHY_TYPE:
                  if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U32)) {

                        *pLen = (Limit - LogPortIndex) * sizeof(SK_U32);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  break;

            default:
                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR041,
                        SK_PNMI_ERR041MSG);
                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }

            /*
             * Update statistic and increment semaphore to indicate
             * that an update was already done.
             */
            if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {

                  *pLen = 0;
                  return (Ret);
            }
            pAC->Pnmi.SirqUpdatedFlag ++;

            /*
             * Get value
             */
            Offset = 0;
            for (; LogPortIndex < Limit; LogPortIndex ++) {

                  pBufPtr = pBuf + Offset;
                  
                  switch (Id) {

                  case OID_SKGE_PMD:
                        *pBufPtr = pAC->Pnmi.PMD;
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_CONNECTOR:
                        *pBufPtr = pAC->Pnmi.Connector;
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_PHY_TYPE:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    continue;
                              }
                              else {
                                    /* Get value for physical ports */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
                                    Val32 = pAC->GIni.GP[PhysPortIndex].PhyType;
                                    SK_PNMI_STORE_U32(pBufPtr, Val32);
                              }
                        }
                        else { /* DualNetMode */
                              
                              Val32 = pAC->GIni.GP[NetIndex].PhyType;
                              SK_PNMI_STORE_U32(pBufPtr, Val32);
                        }
                        Offset += sizeof(SK_U32);
                        break;

                  case OID_SKGE_LINK_CAP:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical ports */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);

                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkCap;
                              }
                        }
                        else { /* DualNetMode */
                              
                              *pBufPtr = pAC->GIni.GP[NetIndex].PLinkCap;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_LINK_MODE:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical ports */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);

                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkModeConf;
                              }
                        }
                        else { /* DualNetMode */
                        
                              *pBufPtr = pAC->GIni.GP[NetIndex].PLinkModeConf;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_LINK_MODE_STATUS:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical port */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);

                                    *pBufPtr =
                                          CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);
                              }
                        }
                        else { /* DualNetMode */
                              
                              *pBufPtr = CalculateLinkModeStatus(pAC, IoC, NetIndex);
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_LINK_STATUS:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical ports */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
      
                                    *pBufPtr = CalculateLinkStatus(pAC, IoC, PhysPortIndex);
                              }
                        }
                        else { /* DualNetMode */

                              *pBufPtr = CalculateLinkStatus(pAC, IoC, NetIndex);
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_FLOWCTRL_CAP:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical ports */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
      
                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap;
                              }
                        }
                        else { /* DualNetMode */
                        
                              *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlCap;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_FLOWCTRL_MODE:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical port */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
      
                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode;
                              }
                        }
                        else { /* DualNetMode */

                              *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlMode;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_FLOWCTRL_STATUS:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical port */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
      
                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlStatus;
                              }
                        }
                        else { /* DualNetMode */

                              *pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlStatus;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_PHY_OPERATION_CAP:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical ports */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
      
                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSCap;
                              }
                        }
                        else { /* DualNetMode */
                        
                              *pBufPtr = pAC->GIni.GP[NetIndex].PMSCap;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_PHY_OPERATION_MODE:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical port */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);

                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSMode;
                              }
                        }
                        else { /* DualNetMode */
                        
                              *pBufPtr = pAC->GIni.GP[NetIndex].PMSMode;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_PHY_OPERATION_STATUS:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical port */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
      
                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSStatus;
                              }
                        }
                        else {
                        
                              *pBufPtr = pAC->GIni.GP[NetIndex].PMSStatus;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_SPEED_CAP:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical ports */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
      
                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedCap;
                              }
                        }
                        else { /* DualNetMode */
                        
                              *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedCap;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_SPEED_MODE:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical port */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
      
                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeed;
                              }
                        }
                        else { /* DualNetMode */

                              *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeed;
                        }
                        Offset += sizeof(char);
                        break;

                  case OID_SKGE_SPEED_STATUS:
                        if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
                              if (LogPortIndex == 0) {
                                    /* Get value for virtual port */
                                    VirtualConf(pAC, IoC, Id, pBufPtr);
                              }
                              else {
                                    /* Get value for physical port */
                                    PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
                                          pAC, LogPortIndex);
      
                                    *pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed;
                              }
                        }
                        else { /* DualNetMode */

                              *pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedUsed;
                        }
                        Offset += sizeof(char);
                        break;
                  
                  case OID_SKGE_MTU:
                        Val32 = SK_DRIVER_GET_MTU(pAC, IoC, NetIndex);
                        SK_PNMI_STORE_U32(pBufPtr, Val32);
                        Offset += sizeof(SK_U32);
                        break;

                  default:
                        SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
                              ("MacPrivateConf: Unknown OID should be handled before"));

                        pAC->Pnmi.SirqUpdatedFlag --;
                        return (SK_PNMI_ERR_GENERAL);
                  }
            }
            *pLen = Offset;
            pAC->Pnmi.SirqUpdatedFlag --;

            return (SK_PNMI_ERR_OK);
      }

      /*
       * From here SET or PRESET action. Check if the passed
       * buffer length is plausible.
       */
      switch (Id) {

      case OID_SKGE_LINK_MODE:
      case OID_SKGE_FLOWCTRL_MODE:
      case OID_SKGE_PHY_OPERATION_MODE:
      case OID_SKGE_SPEED_MODE:
            if (*pLen < Limit - LogPortIndex) {

                  *pLen = Limit - LogPortIndex;
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            if (*pLen != Limit - LogPortIndex) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_BAD_VALUE);
            }
            break;

      case OID_SKGE_MTU:
            if (*pLen < sizeof(SK_U32)) {

                  *pLen = sizeof(SK_U32);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            if (*pLen != sizeof(SK_U32)) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_BAD_VALUE);
            }
            break;

    default:
            *pLen = 0;
            return (SK_PNMI_ERR_READ_ONLY);
      }

      /*
       * Perform preset or set
       */
      Offset = 0;
      for (; LogPortIndex < Limit; LogPortIndex ++) {

            switch (Id) {

            case OID_SKGE_LINK_MODE:
                  /* Check the value range */
                  Val8 = *(pBuf + Offset);
                  if (Val8 == 0) {

                        Offset += sizeof(char);
                        break;
                  }
                  if (Val8 < SK_LMODE_HALF ||
                        (LogPortIndex != 0 && Val8 > SK_LMODE_AUTOSENSE) ||
                        (LogPortIndex == 0 && Val8 > SK_LMODE_INDETERMINATED)) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }

                  /* The preset ends here */
                  if (Action == SK_PNMI_PRESET) {

                        return (SK_PNMI_ERR_OK);
                  }

                  if (LogPortIndex == 0) {

                        /*
                         * The virtual port consists of all currently
                         * active ports. Find them and send an event
                         * with the new link mode to SIRQ.
                         */
                        for (PhysPortIndex = 0;
                              PhysPortIndex < PhysPortMax;
                              PhysPortIndex ++) {

                              if (!pAC->Pnmi.Port[PhysPortIndex].
                                    ActiveFlag) {

                                    continue;
                              }

                              EventParam.Para32[0] = PhysPortIndex;
                              EventParam.Para32[1] = (SK_U32)Val8;
                              if (SkGeSirqEvent(pAC, IoC,
                                    SK_HWEV_SET_LMODE,
                                    EventParam) > 0) {

                                    SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                          SK_PNMI_ERR043,
                                          SK_PNMI_ERR043MSG);

                                    *pLen = 0;
                                    return (SK_PNMI_ERR_GENERAL);
                              }
                        }
                  }
                  else {
                        /*
                         * Send an event with the new link mode to
                         * the SIRQ module.
                         */
                        EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
                              pAC, LogPortIndex);
                        EventParam.Para32[1] = (SK_U32)Val8;
                        if (SkGeSirqEvent(pAC, IoC, SK_HWEV_SET_LMODE,
                              EventParam) > 0) {

                              SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                    SK_PNMI_ERR043,
                                    SK_PNMI_ERR043MSG);

                              *pLen = 0;
                              return (SK_PNMI_ERR_GENERAL);
                        }
                  }
                  Offset += sizeof(char);
                  break;

            case OID_SKGE_FLOWCTRL_MODE:
                  /* Check the value range */
                  Val8 = *(pBuf + Offset);
                  if (Val8 == 0) {

                        Offset += sizeof(char);
                        break;
                  }
                  if (Val8 < SK_FLOW_MODE_NONE ||
                        (LogPortIndex != 0 && Val8 > SK_FLOW_MODE_SYM_OR_REM) ||
                        (LogPortIndex == 0 && Val8 > SK_FLOW_MODE_INDETERMINATED)) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }

                  /* The preset ends here */
                  if (Action == SK_PNMI_PRESET) {

                        return (SK_PNMI_ERR_OK);
                  }

                  if (LogPortIndex == 0) {

                        /*
                         * The virtual port consists of all currently
                         * active ports. Find them and send an event
                         * with the new flow control mode to SIRQ.
                         */
                        for (PhysPortIndex = 0;
                              PhysPortIndex < PhysPortMax;
                              PhysPortIndex ++) {

                              if (!pAC->Pnmi.Port[PhysPortIndex].
                                    ActiveFlag) {

                                    continue;
                              }

                              EventParam.Para32[0] = PhysPortIndex;
                              EventParam.Para32[1] = (SK_U32)Val8;
                              if (SkGeSirqEvent(pAC, IoC,
                                    SK_HWEV_SET_FLOWMODE,
                                    EventParam) > 0) {

                                    SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                          SK_PNMI_ERR044,
                                          SK_PNMI_ERR044MSG);

                                    *pLen = 0;
                                    return (SK_PNMI_ERR_GENERAL);
                              }
                        }
                  }
                  else {
                        /*
                         * Send an event with the new flow control
                         * mode to the SIRQ module.
                         */
                        EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
                              pAC, LogPortIndex);
                        EventParam.Para32[1] = (SK_U32)Val8;
                        if (SkGeSirqEvent(pAC, IoC,
                              SK_HWEV_SET_FLOWMODE, EventParam)
                              > 0) {

                              SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                    SK_PNMI_ERR044,
                                    SK_PNMI_ERR044MSG);

                              *pLen = 0;
                              return (SK_PNMI_ERR_GENERAL);
                        }
                  }
                  Offset += sizeof(char);
                  break;

            case OID_SKGE_PHY_OPERATION_MODE :
                  /* Check the value range */
                  Val8 = *(pBuf + Offset);
                  if (Val8 == 0) {
                        /* mode of this port remains unchanged */
                        Offset += sizeof(char);
                        break;
                  }
                  if (Val8 < SK_MS_MODE_AUTO ||
                        (LogPortIndex != 0 && Val8 > SK_MS_MODE_SLAVE) ||
                        (LogPortIndex == 0 && Val8 > SK_MS_MODE_INDETERMINATED)) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }

                  /* The preset ends here */
                  if (Action == SK_PNMI_PRESET) {

                        return (SK_PNMI_ERR_OK);
                  }

                  if (LogPortIndex == 0) {

                        /*
                         * The virtual port consists of all currently
                         * active ports. Find them and send an event
                         * with new master/slave (role) mode to SIRQ.
                         */
                        for (PhysPortIndex = 0;
                              PhysPortIndex < PhysPortMax;
                              PhysPortIndex ++) {

                              if (!pAC->Pnmi.Port[PhysPortIndex].
                                    ActiveFlag) {

                                    continue;
                              }

                              EventParam.Para32[0] = PhysPortIndex;
                              EventParam.Para32[1] = (SK_U32)Val8;
                              if (SkGeSirqEvent(pAC, IoC,
                                    SK_HWEV_SET_ROLE,
                                    EventParam) > 0) {

                                    SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                          SK_PNMI_ERR042,
                                          SK_PNMI_ERR042MSG);

                                    *pLen = 0;
                                    return (SK_PNMI_ERR_GENERAL);
                              }
                        }
                  }
                  else {
                        /*
                         * Send an event with the new master/slave
                         * (role) mode to the SIRQ module.
                         */
                        EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
                              pAC, LogPortIndex);
                        EventParam.Para32[1] = (SK_U32)Val8;
                        if (SkGeSirqEvent(pAC, IoC,
                              SK_HWEV_SET_ROLE, EventParam) > 0) {

                              SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                    SK_PNMI_ERR042,
                                    SK_PNMI_ERR042MSG);

                              *pLen = 0;
                              return (SK_PNMI_ERR_GENERAL);
                        }
                  }

                  Offset += sizeof(char);
                  break;

            case OID_SKGE_SPEED_MODE:
                  /* Check the value range */
                  Val8 = *(pBuf + Offset);
                  if (Val8 == 0) {

                        Offset += sizeof(char);
                        break;
                  }
                  if (Val8 < (SK_LSPEED_AUTO) ||
                        (LogPortIndex != 0 && Val8 > (SK_LSPEED_1000MBPS)) ||
                        (LogPortIndex == 0 && Val8 > (SK_LSPEED_INDETERMINATED))) {

                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }

                  /* The preset ends here */
                  if (Action == SK_PNMI_PRESET) {

                        return (SK_PNMI_ERR_OK);
                  }

                  if (LogPortIndex == 0) {

                        /*
                         * The virtual port consists of all currently
                         * active ports. Find them and send an event
                         * with the new flow control mode to SIRQ.
                         */
                        for (PhysPortIndex = 0;
                              PhysPortIndex < PhysPortMax;
                              PhysPortIndex ++) {

                              if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {

                                    continue;
                              }

                              EventParam.Para32[0] = PhysPortIndex;
                              EventParam.Para32[1] = (SK_U32)Val8;
                              if (SkGeSirqEvent(pAC, IoC,
                                    SK_HWEV_SET_SPEED,
                                    EventParam) > 0) {

                                    SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                          SK_PNMI_ERR045,
                                          SK_PNMI_ERR045MSG);

                                    *pLen = 0;
                                    return (SK_PNMI_ERR_GENERAL);
                              }
                        }
                  }
                  else {
                        /*
                         * Send an event with the new flow control
                         * mode to the SIRQ module.
                         */
                        EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
                              pAC, LogPortIndex);
                        EventParam.Para32[1] = (SK_U32)Val8;
                        if (SkGeSirqEvent(pAC, IoC,
                              SK_HWEV_SET_SPEED,
                              EventParam) > 0) {

                              SK_ERR_LOG(pAC, SK_ERRCL_SW,
                                    SK_PNMI_ERR045,
                                    SK_PNMI_ERR045MSG);

                              *pLen = 0;
                              return (SK_PNMI_ERR_GENERAL);
                        }
                  }
                  Offset += sizeof(char);
                  break;

            case OID_SKGE_MTU :
                  /* Check the value range */
                  Val32 = *(SK_U32*)(pBuf + Offset);
                  if (Val32 == 0) {
                        /* mtu of this port remains unchanged */
                        Offset += sizeof(SK_U32);
                        break;
                  }
                  if (SK_DRIVER_PRESET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
                        *pLen = 0;
                        return (SK_PNMI_ERR_BAD_VALUE);
                  }

                  /* The preset ends here */
                  if (Action == SK_PNMI_PRESET) {
                        return (SK_PNMI_ERR_OK);
                  }

                  if (SK_DRIVER_SET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
                        return (SK_PNMI_ERR_GENERAL);
                  }

                  Offset += sizeof(SK_U32);
                  break;
            
            default:
            SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
                ("MacPrivateConf: Unknown OID should be handled before set"));

                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * Monitor - OID handler function for RLMT_MONITOR_XXX
 *
 * Description:
 *    Because RLMT currently does not support the monitoring of
 *    remote adapter cards, we return always an empty table.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
 *                             value range.
 *    SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
PNMI_STATIC int Monitor(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      unsigned int      Index;
      unsigned int      Limit;
      unsigned int      Offset;
      unsigned int      Entries;

      
      /*
       * Calculate instance if wished.
       */
      /* XXX Not yet implemented. Return always an empty table. */
      Entries = 0;

      if ((Instance != (SK_U32)(-1))) {

            if ((Instance < 1) || (Instance > Entries)) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_UNKNOWN_INST);
            }

            Index = (unsigned int)Instance - 1;
            Limit = (unsigned int)Instance;
      }
      else {
            Index = 0;
            Limit = Entries;
      }

      /*
       * Get/Set value
      */
      if (Action == SK_PNMI_GET) {

            for (Offset=0; Index < Limit; Index ++) {

                  switch (Id) {

                  case OID_SKGE_RLMT_MONITOR_INDEX:
                  case OID_SKGE_RLMT_MONITOR_ADDR:
                  case OID_SKGE_RLMT_MONITOR_ERRS:
                  case OID_SKGE_RLMT_MONITOR_TIMESTAMP:
                  case OID_SKGE_RLMT_MONITOR_ADMIN:
                        break;

                  default:
                        SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR046,
                              SK_PNMI_ERR046MSG);

                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
            }
            *pLen = Offset;
      }
      else {
            /* Only MONITOR_ADMIN can be set */
            if (Id != OID_SKGE_RLMT_MONITOR_ADMIN) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_READ_ONLY);
            }

            /* Check if the length is plausible */
            if (*pLen < (Limit - Index)) {

                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            /* Okay, we have a wide value range */
            if (*pLen != (Limit - Index)) {

                  *pLen = 0;
                  return (SK_PNMI_ERR_BAD_VALUE);
            }
/*
            for (Offset=0; Index < Limit; Index ++) {
            }
*/
/*
 * XXX Not yet implemented. Return always BAD_VALUE, because the table
 * is empty.
 */
            *pLen = 0;
            return (SK_PNMI_ERR_BAD_VALUE);
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * VirtualConf - Calculates the values of configuration OIDs for virtual port
 *
 * Description:
 *    We handle here the get of the configuration group OIDs, which are
 *    a little bit complicated. The virtual port consists of all currently
 *    active physical ports. If multiple ports are active and configured
 *    differently we get in some trouble to return a single value. So we
 *    get the value of the first active port and compare it with that of
 *    the other active ports. If they are not the same, we return a value
 *    that indicates that the state is indeterminated.
 *
 * Returns:
 *    Nothing
 */
PNMI_STATIC void VirtualConf(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf)       /* Buffer used for the management data transfer */
{
      unsigned int      PhysPortMax;
      unsigned int      PhysPortIndex;
      SK_U8       Val8;
      SK_U32            Val32;
      SK_BOOL           PortActiveFlag;
      SK_GEPORT   *pPrt;

      *pBuf = 0;
      PortActiveFlag = SK_FALSE;
      PhysPortMax = pAC->GIni.GIMacsFound;
      
      for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
            PhysPortIndex ++) {

            pPrt = &pAC->GIni.GP[PhysPortIndex];

            /* Check if the physical port is active */
            if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {

                  continue;
            }

            PortActiveFlag = SK_TRUE;

            switch (Id) {

            case OID_SKGE_PHY_TYPE:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {
                        Val32 = pPrt->PhyType;
                        SK_PNMI_STORE_U32(pBuf, Val32);
                        continue;
                  }

            case OID_SKGE_LINK_CAP:

                  /*
                   * Different capabilities should not happen, but
                   * in the case of the cases OR them all together.
                   * From a curious point of view the virtual port
                   * is capable of all found capabilities.
                   */
                  *pBuf |= pPrt->PLinkCap;
                  break;

            case OID_SKGE_LINK_MODE:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = pPrt->PLinkModeConf;
                        continue;
                  }

                  /*
                   * If we find an active port with a different link
                   * mode than the first one we return a value that
                   * indicates that the link mode is indeterminated.
                   */
                  if (*pBuf != pPrt->PLinkModeConf) {

                        *pBuf = SK_LMODE_INDETERMINATED;
                  }
                  break;

            case OID_SKGE_LINK_MODE_STATUS:
                  /* Get the link mode of the physical port */
                  Val8 = CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);

                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = Val8;
                        continue;
                  }

                  /*
                   * If we find an active port with a different link
                   * mode status than the first one we return a value
                   * that indicates that the link mode status is
                   * indeterminated.
                   */
                  if (*pBuf != Val8) {

                        *pBuf = SK_LMODE_STAT_INDETERMINATED;
                  }
                  break;

            case OID_SKGE_LINK_STATUS:
                  /* Get the link status of the physical port */
                  Val8 = CalculateLinkStatus(pAC, IoC, PhysPortIndex);

                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = Val8;
                        continue;
                  }

                  /*
                   * If we find an active port with a different link
                   * status than the first one, we return a value
                   * that indicates that the link status is
                   * indeterminated.
                   */
                  if (*pBuf != Val8) {

                        *pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
                  }
                  break;

            case OID_SKGE_FLOWCTRL_CAP:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = pPrt->PFlowCtrlCap;
                        continue;
                  }

                  /*
                   * From a curious point of view the virtual port
                   * is capable of all found capabilities.
                   */
                  *pBuf |= pPrt->PFlowCtrlCap;
                  break;

            case OID_SKGE_FLOWCTRL_MODE:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = pPrt->PFlowCtrlMode;
                        continue;
                  }

                  /*
                   * If we find an active port with a different flow
                   * control mode than the first one, we return a value
                   * that indicates that the mode is indeterminated.
                   */
                  if (*pBuf != pPrt->PFlowCtrlMode) {

                        *pBuf = SK_FLOW_MODE_INDETERMINATED;
                  }
                  break;

            case OID_SKGE_FLOWCTRL_STATUS:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = pPrt->PFlowCtrlStatus;
                        continue;
                  }

                  /*
                   * If we find an active port with a different flow
                   * control status than the first one, we return a
                   * value that indicates that the status is
                   * indeterminated.
                   */
                  if (*pBuf != pPrt->PFlowCtrlStatus) {

                        *pBuf = SK_FLOW_STAT_INDETERMINATED;
                  }
                  break;
            
            case OID_SKGE_PHY_OPERATION_CAP:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = pPrt->PMSCap;
                        continue;
                  }

                  /*
                   * From a curious point of view the virtual port
                   * is capable of all found capabilities.
                   */
                  *pBuf |= pPrt->PMSCap;
                  break;

            case OID_SKGE_PHY_OPERATION_MODE:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = pPrt->PMSMode;
                        continue;
                  }

                  /*
                   * If we find an active port with a different master/
                   * slave mode than the first one, we return a value
                   * that indicates that the mode is indeterminated.
                   */
                  if (*pBuf != pPrt->PMSMode) {

                        *pBuf = SK_MS_MODE_INDETERMINATED;
                  }
                  break;

            case OID_SKGE_PHY_OPERATION_STATUS:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = pPrt->PMSStatus;
                        continue;
                  }

                  /*
                   * If we find an active port with a different master/
                   * slave status than the first one, we return a
                   * value that indicates that the status is
                   * indeterminated.
                   */
                  if (*pBuf != pPrt->PMSStatus) {

                        *pBuf = SK_MS_STAT_INDETERMINATED;
                  }
                  break;
            
            case OID_SKGE_SPEED_MODE:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = pPrt->PLinkSpeed;
                        continue;
                  }

                  /*
                   * If we find an active port with a different flow
                   * control mode than the first one, we return a value
                   * that indicates that the mode is indeterminated.
                   */
                  if (*pBuf != pPrt->PLinkSpeed) {

                        *pBuf = SK_LSPEED_INDETERMINATED;
                  }
                  break;
            
            case OID_SKGE_SPEED_STATUS:
                  /* Check if it is the first active port */
                  if (*pBuf == 0) {

                        *pBuf = pPrt->PLinkSpeedUsed;
                        continue;
                  }

                  /*
                   * If we find an active port with a different flow
                   * control status than the first one, we return a
                   * value that indicates that the status is
                   * indeterminated.
                   */
                  if (*pBuf != pPrt->PLinkSpeedUsed) {

                        *pBuf = SK_LSPEED_STAT_INDETERMINATED;
                  }
                  break;
            }
      }

      /*
       * If no port is active return an indeterminated answer
       */
      if (!PortActiveFlag) {

            switch (Id) {

            case OID_SKGE_LINK_CAP:
                  *pBuf = SK_LMODE_CAP_INDETERMINATED;
                  break;

            case OID_SKGE_LINK_MODE:
                  *pBuf = SK_LMODE_INDETERMINATED;
                  break;

            case OID_SKGE_LINK_MODE_STATUS:
                  *pBuf = SK_LMODE_STAT_INDETERMINATED;
                  break;

            case OID_SKGE_LINK_STATUS:
                  *pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
                  break;

            case OID_SKGE_FLOWCTRL_CAP:
            case OID_SKGE_FLOWCTRL_MODE:
                  *pBuf = SK_FLOW_MODE_INDETERMINATED;
                  break;

            case OID_SKGE_FLOWCTRL_STATUS:
                  *pBuf = SK_FLOW_STAT_INDETERMINATED;
                  break;
                  
            case OID_SKGE_PHY_OPERATION_CAP:
                  *pBuf = SK_MS_CAP_INDETERMINATED;
                  break;

            case OID_SKGE_PHY_OPERATION_MODE:
                  *pBuf = SK_MS_MODE_INDETERMINATED;
                  break;

            case OID_SKGE_PHY_OPERATION_STATUS:
                  *pBuf = SK_MS_STAT_INDETERMINATED;
                  break;
            case OID_SKGE_SPEED_CAP:
                  *pBuf = SK_LSPEED_CAP_INDETERMINATED;
                  break;

            case OID_SKGE_SPEED_MODE:
                  *pBuf = SK_LSPEED_INDETERMINATED;
                  break;

            case OID_SKGE_SPEED_STATUS:
                  *pBuf = SK_LSPEED_STAT_INDETERMINATED;
                  break;
            }
      }
}

/*****************************************************************************
 *
 * CalculateLinkStatus - Determins the link status of a physical port
 *
 * Description:
 *    Determins the link status the following way:
 *      LSTAT_PHY_DOWN:  Link is down
 *      LSTAT_AUTONEG:   Auto-negotiation failed
 *      LSTAT_LOG_DOWN:  Link is up but RLMT did not yet put the port
 *                       logically up.
 *      LSTAT_LOG_UP:    RLMT marked the port as up
 *
 * Returns:
 *    Link status of physical port
 */
PNMI_STATIC SK_U8 CalculateLinkStatus(
SK_AC *pAC,             /* Pointer to adapter context */
SK_IOC IoC,             /* IO context handle */
unsigned int PhysPortIndex)   /* Physical port index */
{
      SK_U8 Result;

      if (!pAC->GIni.GP[PhysPortIndex].PHWLinkUp) {

            Result = SK_PNMI_RLMT_LSTAT_PHY_DOWN;
      }
      else if (pAC->GIni.GP[PhysPortIndex].PAutoNegFail > 0) {

            Result = SK_PNMI_RLMT_LSTAT_AUTONEG;
                        }
      else if (!pAC->Rlmt.Port[PhysPortIndex].PortDown) {

            Result = SK_PNMI_RLMT_LSTAT_LOG_UP;
      }
      else {
            Result = SK_PNMI_RLMT_LSTAT_LOG_DOWN;
      }

      return (Result);
}

/*****************************************************************************
 *
 * CalculateLinkModeStatus - Determins the link mode status of a phys. port
 *
 * Description:
 *    The COMMON module only tells us if the mode is half or full duplex.
 *    But in the decade of auto sensing it is useful for the user to
 *    know if the mode was negotiated or forced. Therefore we have a
 *    look to the mode, which was last used by the negotiation process.
 *
 * Returns:
 *    The link mode status
 */
PNMI_STATIC SK_U8 CalculateLinkModeStatus(
SK_AC *pAC,             /* Pointer to adapter context */
SK_IOC IoC,             /* IO context handle */
unsigned int PhysPortIndex)   /* Physical port index */
{
      SK_U8 Result;

      /* Get the current mode, which can be full or half duplex */
      Result = pAC->GIni.GP[PhysPortIndex].PLinkModeStatus;

      /* Check if no valid mode could be found (link is down) */
      if (Result < SK_LMODE_STAT_HALF) {

            Result = SK_LMODE_STAT_UNKNOWN;
      }
      else if (pAC->GIni.GP[PhysPortIndex].PLinkMode >= SK_LMODE_AUTOHALF) {

            /*
             * Auto-negotiation was used to bring up the link. Change
             * the already found duplex status that it indicates
             * auto-negotiation was involved.
             */
            if (Result == SK_LMODE_STAT_HALF) {

                  Result = SK_LMODE_STAT_AUTOHALF;
            }
            else if (Result == SK_LMODE_STAT_FULL) {

                  Result = SK_LMODE_STAT_AUTOFULL;
            }
      }

      return (Result);
}

/*****************************************************************************
 *
 * GetVpdKeyArr - Obtain an array of VPD keys
 *
 * Description:
 *    Read the VPD keys and build an array of VPD keys, which are
 *    easy to access.
 *
 * Returns:
 *    SK_PNMI_ERR_OK         Task successfully performed.
 *    SK_PNMI_ERR_GENERAL  Something went wrong.
 */
PNMI_STATIC int GetVpdKeyArr(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
char *pKeyArr,          /* Ptr KeyArray */
unsigned int KeyArrLen, /* Length of array in bytes */
unsigned int *pKeyNo)   /* Number of keys */
{
      unsigned int            BufKeysLen = SK_PNMI_VPD_BUFSIZE;
      char              BufKeys[SK_PNMI_VPD_BUFSIZE];
      unsigned int            StartOffset;
      unsigned int            Offset;
      int               Index;
      int               Ret;


      SK_MEMSET(pKeyArr, 0, KeyArrLen);

      /*
       * Get VPD key list
       */
      Ret = VpdKeys(pAC, IoC, (char *)&BufKeys, (int *)&BufKeysLen,
            (int *)pKeyNo);
      if (Ret > 0) {

            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR014,
                  SK_PNMI_ERR014MSG);

            return (SK_PNMI_ERR_GENERAL);
      }
      /* If no keys are available return now */
      if (*pKeyNo == 0 || BufKeysLen == 0) {

            return (SK_PNMI_ERR_OK);
      }
      /*
       * If the key list is too long for us trunc it and give a
       * errorlog notification. This case should not happen because
       * the maximum number of keys is limited due to RAM limitations
       */
      if (*pKeyNo > SK_PNMI_VPD_ENTRIES) {

            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR015,
                  SK_PNMI_ERR015MSG);

            *pKeyNo = SK_PNMI_VPD_ENTRIES;
      }

      /*
       * Now build an array of fixed string length size and copy
       * the keys together.
       */
      for (Index = 0, StartOffset = 0, Offset = 0; Offset < BufKeysLen;
            Offset ++) {

            if (BufKeys[Offset] != 0) {

                  continue;
            }

            if (Offset - StartOffset > SK_PNMI_VPD_KEY_SIZE) {

                  SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR016,
                        SK_PNMI_ERR016MSG);
                  return (SK_PNMI_ERR_GENERAL);
            }

            SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
                  &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);

            Index ++;
            StartOffset = Offset + 1;
      }

      /* Last key not zero terminated? Get it anyway */
      if (StartOffset < Offset) {

            SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
                  &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * SirqUpdate - Let the SIRQ update its internal values
 *
 * Description:
 *    Just to be sure that the SIRQ module holds its internal data
 *    structures up to date, we send an update event before we make
 *    any access.
 *
 * Returns:
 *    SK_PNMI_ERR_OK         Task successfully performed.
 *    SK_PNMI_ERR_GENERAL  Something went wrong.
 */
PNMI_STATIC int SirqUpdate(
SK_AC *pAC, /* Pointer to adapter context */
SK_IOC IoC) /* IO context handle */
{
      SK_EVPARA   EventParam;


      /* Was the module already updated during the current PNMI call? */
      if (pAC->Pnmi.SirqUpdatedFlag > 0) {

            return (SK_PNMI_ERR_OK);
      }

      /* Send an synchronuous update event to the module */
      SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
      if (SkGeSirqEvent(pAC, IoC, SK_HWEV_UPDATE_STAT, EventParam) > 0) {

            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR047,
                  SK_PNMI_ERR047MSG);

            return (SK_PNMI_ERR_GENERAL);
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * RlmtUpdate - Let the RLMT update its internal values
 *
 * Description:
 *    Just to be sure that the RLMT module holds its internal data
 *    structures up to date, we send an update event before we make
 *    any access.
 *
 * Returns:
 *    SK_PNMI_ERR_OK         Task successfully performed.
 *    SK_PNMI_ERR_GENERAL  Something went wrong.
 */
PNMI_STATIC int RlmtUpdate(
SK_AC *pAC, /* Pointer to adapter context */
SK_IOC IoC, /* IO context handle */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode allways zero */
{
      SK_EVPARA   EventParam;


      /* Was the module already updated during the current PNMI call? */
      if (pAC->Pnmi.RlmtUpdatedFlag > 0) {

            return (SK_PNMI_ERR_OK);
      }

      /* Send an synchronuous update event to the module */
      SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
      EventParam.Para32[0] = NetIndex;
      EventParam.Para32[1] = (SK_U32)-1;
      if (SkRlmtEvent(pAC, IoC, SK_RLMT_STATS_UPDATE, EventParam) > 0) {

            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR048,
                  SK_PNMI_ERR048MSG);

            return (SK_PNMI_ERR_GENERAL);
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * MacUpdate - Force the XMAC to output the current statistic
 *
 * Description:
 *    The XMAC holds its statistic internally. To obtain the current
 *    values we must send a command so that the statistic data will
 *    be written to a predefined memory area on the adapter.
 *
 * Returns:
 *    SK_PNMI_ERR_OK         Task successfully performed.
 *    SK_PNMI_ERR_GENERAL  Something went wrong.
 */
PNMI_STATIC int MacUpdate(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
unsigned int FirstMac,  /* Index of the first Mac to be updated */
unsigned int LastMac)   /* Index of the last Mac to be updated */
{
      unsigned int      MacIndex;

      /*
       * Were the statistics already updated during the
       * current PNMI call?
       */
      if (pAC->Pnmi.MacUpdatedFlag > 0) {

            return (SK_PNMI_ERR_OK);
      }

      /* Send an update command to all MACs specified */
      for (MacIndex = FirstMac; MacIndex <= LastMac; MacIndex ++) {

            /*
             * 2002-09-13 pweber:   Freeze the current SW counters.
             *                      (That should be done as close as
             *                      possible to the update of the
             *                      HW counters)
             */
            if (pAC->GIni.GIMacType == SK_MAC_XMAC) {
                  pAC->Pnmi.BufPort[MacIndex] = pAC->Pnmi.Port[MacIndex];
            }
                  
            /* 2002-09-13 pweber:  Update the HW counter  */
            if (pAC->GIni.GIFunc.pFnMacUpdateStats(pAC, IoC, MacIndex) != 0) {

                  return (SK_PNMI_ERR_GENERAL);
            }
      }

      return (SK_PNMI_ERR_OK);
}

/*****************************************************************************
 *
 * GetStatVal - Retrieve an XMAC statistic counter
 *
 * Description:
 *    Retrieves the statistic counter of a virtual or physical port. The
 *    virtual port is identified by the index 0. It consists of all
 *    currently active ports. To obtain the counter value for this port
 *    we must add the statistic counter of all active ports. To grant
 *    continuous counter values for the virtual port even when port
 *    switches occur we must additionally add a delta value, which was
 *    calculated during a SK_PNMI_EVT_RLMT_ACTIVE_UP event.
 *
 * Returns:
 *    Requested statistic value
 */
PNMI_STATIC SK_U64 GetStatVal(
SK_AC *pAC,                         /* Pointer to adapter context */
SK_IOC IoC,                         /* IO context handle */
unsigned int LogPortIndex,    /* Index of the logical Port to be processed */
unsigned int StatIndex,       /* Index to statistic value */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode allways zero */
{
      unsigned int      PhysPortIndex;
      unsigned int      PhysPortMax;
      SK_U64                  Val = 0;


      if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {   /* Dual net mode */

            PhysPortIndex = NetIndex;
            
            Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
      }
      else {      /* Single Net mode */

            if (LogPortIndex == 0) {

                  PhysPortMax = pAC->GIni.GIMacsFound;

                  /* Add counter of all active ports */
                  for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
                        PhysPortIndex ++) {

                        if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {

                              Val += GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
                        }
                  }

                  /* Correct value because of port switches */
                  Val += pAC->Pnmi.VirtualCounterOffset[StatIndex];
            }
            else {
                  /* Get counter value of physical port */
                  PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
                  
                  Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
            }
      }
      return (Val);
}

/*****************************************************************************
 *
 * GetPhysStatVal - Get counter value for physical port
 *
 * Description:
 *    Builds a 64bit counter value. Except for the octet counters
 *    the lower 32bit are counted in hardware and the upper 32bit
 *    in software by monitoring counter overflow interrupts in the
 *    event handler. To grant continous counter values during XMAC
 *    resets (caused by a workaround) we must add a delta value.
 *    The delta was calculated in the event handler when a
 *    SK_PNMI_EVT_XMAC_RESET was received.
 *
 * Returns:
 *    Counter value
 */
PNMI_STATIC SK_U64 GetPhysStatVal(
SK_AC *pAC,                         /* Pointer to adapter context */
SK_IOC IoC,                         /* IO context handle */
unsigned int PhysPortIndex,   /* Index of the logical Port to be processed */
unsigned int StatIndex)       /* Index to statistic value */
{
      SK_U64      Val = 0;
      SK_U32      LowVal = 0;
      SK_U32      HighVal = 0;
      SK_U16      Word;
      int         MacType;
      unsigned int HelpIndex;
      SK_GEPORT   *pPrt;
      
      SK_PNMI_PORT      *pPnmiPrt;
      SK_GEMACFUNC      *pFnMac;
      
      pPrt = &pAC->GIni.GP[PhysPortIndex];
      
      MacType = pAC->GIni.GIMacType;
      
      /* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
      if (MacType == SK_MAC_XMAC) {
            pPnmiPrt = &pAC->Pnmi.BufPort[PhysPortIndex];
      }
      else {
            pPnmiPrt = &pAC->Pnmi.Port[PhysPortIndex];
      }
      
      pFnMac   = &pAC->GIni.GIFunc;

      switch (StatIndex) {
      case SK_PNMI_HTX:
            if (MacType == SK_MAC_GMAC) {
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                          StatAddr[SK_PNMI_HTX_BROADCAST][MacType].Reg,
                                          &LowVal);
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                          StatAddr[SK_PNMI_HTX_MULTICAST][MacType].Reg,
                                          &HighVal);
                  LowVal += HighVal;
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                          StatAddr[SK_PNMI_HTX_UNICAST][MacType].Reg,
                                          &HighVal);
                  LowVal += HighVal;
            }
            else {
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                              StatAddr[StatIndex][MacType].Reg,
                                                              &LowVal);
            }
            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            break;
      
      case SK_PNMI_HRX:
            if (MacType == SK_MAC_GMAC) {
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                          StatAddr[SK_PNMI_HRX_BROADCAST][MacType].Reg,
                                          &LowVal);
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                          StatAddr[SK_PNMI_HRX_MULTICAST][MacType].Reg,
                                          &HighVal);
                  LowVal += HighVal;
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                          StatAddr[SK_PNMI_HRX_UNICAST][MacType].Reg,
                                          &HighVal);
                  LowVal += HighVal;
            }
            else {
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                              StatAddr[StatIndex][MacType].Reg,
                                                              &LowVal);
            }
            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            break;

      case SK_PNMI_HTX_OCTET:
      case SK_PNMI_HRX_OCTET:
            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex][MacType].Reg,
                                                        &HighVal);
            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex + 1][MacType].Reg,
                                                        &LowVal);
            break;

      case SK_PNMI_HTX_BURST:
      case SK_PNMI_HTX_EXCESS_DEF:
      case SK_PNMI_HTX_CARRIER:
            /* Not supported by GMAC */
            if (MacType == SK_MAC_GMAC) {
                  return (Val);
            }

            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex][MacType].Reg,
                                                        &LowVal);
            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            break;

      case SK_PNMI_HTX_MACC:
            /* GMAC only supports PAUSE MAC control frames */
            if (MacType == SK_MAC_GMAC) {
                  HelpIndex = SK_PNMI_HTX_PMACC;
            }
            else {
                  HelpIndex = StatIndex;
            }
            
            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                StatAddr[HelpIndex][MacType].Reg,
                                                &LowVal);

            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            break;

      case SK_PNMI_HTX_COL:
      case SK_PNMI_HRX_UNDERSIZE:
            /* Not supported by XMAC */
            if (MacType == SK_MAC_XMAC) {
                  return (Val);
            }

            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex][MacType].Reg,
                                                        &LowVal);
            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            break;

      case SK_PNMI_HTX_DEFFERAL:
            /* Not supported by GMAC */
            if (MacType == SK_MAC_GMAC) {
                  return (Val);
            }
            
            /*
             * XMAC counts frames with deferred transmission
             * even in full-duplex mode.
             *
             * In full-duplex mode the counter remains constant!
             */
            if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) ||
                  (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL)) {

                  LowVal = 0;
                  HighVal = 0;
            }
            else {
                  /* Otherwise get contents of hardware register */
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                              StatAddr[StatIndex][MacType].Reg,
                                                              &LowVal);
                  HighVal = pPnmiPrt->CounterHigh[StatIndex];
            }
            break;

      case SK_PNMI_HRX_BADOCTET:
            /* Not supported by XMAC */
            if (MacType == SK_MAC_XMAC) {
                  return (Val);
            }

            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex][MacType].Reg,
                                                        &HighVal);
            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex + 1][MacType].Reg,
                                      &LowVal);
            break;

      case SK_PNMI_HTX_OCTETLOW:
      case SK_PNMI_HRX_OCTETLOW:
      case SK_PNMI_HRX_BADOCTETLOW:
            return (Val);

      case SK_PNMI_HRX_LONGFRAMES:
            /* For XMAC the SW counter is managed by PNMI */
            if (MacType == SK_MAC_XMAC) {
                  return (pPnmiPrt->StatRxLongFrameCts);
            }
            
            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex][MacType].Reg,
                                                        &LowVal);
            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            break;
            
      case SK_PNMI_HRX_TOO_LONG:
            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                StatAddr[StatIndex][MacType].Reg,
                                                &LowVal);
            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            
            Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);

            if (MacType == SK_MAC_GMAC) {
                  /* For GMAC the SW counter is additionally managed by PNMI */
                  Val += pPnmiPrt->StatRxFrameTooLongCts;
            }
            else {
                  /*
                   * Frames longer than IEEE 802.3 frame max size are counted
                   * by XMAC in frame_too_long counter even reception of long
                   * frames was enabled and the frame was correct.
                   * So correct the value by subtracting RxLongFrame counter.
                   */
                  Val -= pPnmiPrt->StatRxLongFrameCts;
            }

            LowVal = (SK_U32)Val;
            HighVal = (SK_U32)(Val >> 32);
            break;
            
      case SK_PNMI_HRX_SHORTS:
            /* Not supported by GMAC */
            if (MacType == SK_MAC_GMAC) {
                  /* GM_RXE_FRAG?? */
                  return (Val);
            }
            
            /*
             * XMAC counts short frame errors even if link down (#10620)
             *
             * If link-down the counter remains constant
             */
            if (pPrt->PLinkModeStatus != SK_LMODE_STAT_UNKNOWN) {

                  /* Otherwise get incremental difference */
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                              StatAddr[StatIndex][MacType].Reg,
                                                              &LowVal);
                  HighVal = pPnmiPrt->CounterHigh[StatIndex];

                  Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
                  Val -= pPnmiPrt->RxShortZeroMark;

                  LowVal = (SK_U32)Val;
                  HighVal = (SK_U32)(Val >> 32);
            }
            break;

      case SK_PNMI_HRX_MACC:
      case SK_PNMI_HRX_MACC_UNKWN:
      case SK_PNMI_HRX_BURST:
      case SK_PNMI_HRX_MISSED:
      case SK_PNMI_HRX_FRAMING:
      case SK_PNMI_HRX_CARRIER:
      case SK_PNMI_HRX_IRLENGTH:
      case SK_PNMI_HRX_SYMBOL:
      case SK_PNMI_HRX_CEXT:
            /* Not supported by GMAC */
            if (MacType == SK_MAC_GMAC) {
                  return (Val);
            }

            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex][MacType].Reg,
                                                        &LowVal);
            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            break;

      case SK_PNMI_HRX_PMACC_ERR:
            /* For GMAC the SW counter is managed by PNMI */
            if (MacType == SK_MAC_GMAC) {
                  return (pPnmiPrt->StatRxPMaccErr);
            }
            
            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex][MacType].Reg,
                                                        &LowVal);
            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            break;

      /* SW counter managed by PNMI */
      case SK_PNMI_HTX_SYNC:
            LowVal = (SK_U32)pPnmiPrt->StatSyncCts;
            HighVal = (SK_U32)(pPnmiPrt->StatSyncCts >> 32);
            break;

      /* SW counter managed by PNMI */
      case SK_PNMI_HTX_SYNC_OCTET:
            LowVal = (SK_U32)pPnmiPrt->StatSyncOctetsCts;
            HighVal = (SK_U32)(pPnmiPrt->StatSyncOctetsCts >> 32);
            break;

      case SK_PNMI_HRX_FCS:
            /*
             * Broadcom filters FCS errors and counts it in
             * Receive Error Counter register
             */
            if (pPrt->PhyType == SK_PHY_BCOM) {
                  /* do not read while not initialized (PHY_READ hangs!)*/
                  if (pPrt->PState != SK_PRT_RESET) {
                        SkXmPhyRead(pAC, IoC, PhysPortIndex, PHY_BCOM_RE_CTR, &Word);
                        
                        LowVal = Word;
                  }
                  HighVal = pPnmiPrt->CounterHigh[StatIndex];
            }
            else {
                  (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                              StatAddr[StatIndex][MacType].Reg,
                                                              &LowVal);
                  HighVal = pPnmiPrt->CounterHigh[StatIndex];
            }
            break;

      default:
            (void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
                                                        StatAddr[StatIndex][MacType].Reg,
                                                        &LowVal);
            HighVal = pPnmiPrt->CounterHigh[StatIndex];
            break;
      }

      Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);

      /* Correct value because of possible XMAC reset. XMAC Errata #2 */
      Val += pPnmiPrt->CounterOffset[StatIndex];

      return (Val);
}

/*****************************************************************************
 *
 * ResetCounter - Set all counters and timestamps to zero
 *
 * Description:
 *    Notifies other common modules which store statistic data to
 *    reset their counters and finally reset our own counters.
 *
 * Returns:
 *    Nothing
 */
PNMI_STATIC void ResetCounter(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
SK_U32 NetIndex)
{
      unsigned int      PhysPortIndex;
      SK_EVPARA   EventParam;


      SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));

      /* Notify sensor module */
      SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_CLEAR, EventParam);

      /* Notify RLMT module */
      EventParam.Para32[0] = NetIndex;
      EventParam.Para32[1] = (SK_U32)-1;
      SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STATS_CLEAR, EventParam);
      EventParam.Para32[1] = 0;

      /* Notify SIRQ module */
      SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_CLEAR_STAT, EventParam);

      /* Notify CSUM module */
#ifdef SK_USE_CSUM
      EventParam.Para32[0] = NetIndex;
      EventParam.Para32[1] = (SK_U32)-1;
      SkEventQueue(pAC, SKGE_CSUM, SK_CSUM_EVENT_CLEAR_PROTO_STATS,
            EventParam);
#endif /* SK_USE_CSUM */
      
      /* Clear XMAC statistic */
      for (PhysPortIndex = 0; PhysPortIndex <
            (unsigned int)pAC->GIni.GIMacsFound; PhysPortIndex ++) {

            (void)pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PhysPortIndex);

            SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].CounterHigh,
                  0, sizeof(pAC->Pnmi.Port[PhysPortIndex].CounterHigh));
            SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
                  CounterOffset, 0, sizeof(pAC->Pnmi.Port[
                  PhysPortIndex].CounterOffset));
            SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].StatSyncCts,
                  0, sizeof(pAC->Pnmi.Port[PhysPortIndex].StatSyncCts));
            SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
                  StatSyncOctetsCts, 0, sizeof(pAC->Pnmi.Port[
                  PhysPortIndex].StatSyncOctetsCts));
            SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
                  StatRxLongFrameCts, 0, sizeof(pAC->Pnmi.Port[
                  PhysPortIndex].StatRxLongFrameCts));
            SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
                          StatRxFrameTooLongCts, 0, sizeof(pAC->Pnmi.Port[
                  PhysPortIndex].StatRxFrameTooLongCts));
            SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
                          StatRxPMaccErr, 0, sizeof(pAC->Pnmi.Port[
                  PhysPortIndex].StatRxPMaccErr));
      }

      /*
       * Clear local statistics
       */
      SK_MEMSET((char *)&pAC->Pnmi.VirtualCounterOffset, 0,
              sizeof(pAC->Pnmi.VirtualCounterOffset));
      pAC->Pnmi.RlmtChangeCts = 0;
      pAC->Pnmi.RlmtChangeTime = 0;
      SK_MEMSET((char *)&pAC->Pnmi.RlmtChangeEstimate.EstValue[0], 0,
            sizeof(pAC->Pnmi.RlmtChangeEstimate.EstValue));
      pAC->Pnmi.RlmtChangeEstimate.EstValueIndex = 0;
      pAC->Pnmi.RlmtChangeEstimate.Estimate = 0;
      pAC->Pnmi.Port[NetIndex].TxSwQueueMax = 0;
      pAC->Pnmi.Port[NetIndex].TxRetryCts = 0;
      pAC->Pnmi.Port[NetIndex].RxIntrCts = 0;
      pAC->Pnmi.Port[NetIndex].TxIntrCts = 0;
      pAC->Pnmi.Port[NetIndex].RxNoBufCts = 0;
      pAC->Pnmi.Port[NetIndex].TxNoBufCts = 0;
      pAC->Pnmi.Port[NetIndex].TxUsedDescrNo = 0;
      pAC->Pnmi.Port[NetIndex].RxDeliveredCts = 0;
      pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts = 0;
      pAC->Pnmi.Port[NetIndex].ErrRecoveryCts = 0;
}

/*****************************************************************************
 *
 * GetTrapEntry - Get an entry in the trap buffer
 *
 * Description:
 *    The trap buffer stores various events. A user application somehow
 *    gets notified that an event occured and retrieves the trap buffer
 *    contens (or simply polls the buffer). The buffer is organized as
 *    a ring which stores the newest traps at the beginning. The oldest
 *    traps are overwritten by the newest ones. Each trap entry has a
 *    unique number, so that applications may detect new trap entries.
 *
 * Returns:
 *    A pointer to the trap entry
 */
PNMI_STATIC char* GetTrapEntry(
SK_AC *pAC,       /* Pointer to adapter context */
SK_U32 TrapId,          /* SNMP ID of the trap */
unsigned int Size)      /* Space needed for trap entry */
{
      unsigned int            BufPad = pAC->Pnmi.TrapBufPad;
      unsigned int            BufFree = pAC->Pnmi.TrapBufFree;
      unsigned int            Beg = pAC->Pnmi.TrapQueueBeg;
      unsigned int            End = pAC->Pnmi.TrapQueueEnd;
      char              *pBuf = &pAC->Pnmi.TrapBuf[0];
      int               Wrap;
      unsigned int            NeededSpace;
      unsigned int            EntrySize;
      SK_U32                  Val32;
      SK_U64                  Val64;


      /* Last byte of entry will get a copy of the entry length */
      Size ++;

      /*
       * Calculate needed buffer space */
      if (Beg >= Size) {

            NeededSpace = Size;
            Wrap = SK_FALSE;
      }
      else {
            NeededSpace = Beg + Size;
            Wrap = SK_TRUE;
      }

      /*
       * Check if enough buffer space is provided. Otherwise
       * free some entries. Leave one byte space between begin
       * and end of buffer to make it possible to detect whether
       * the buffer is full or empty
       */
      while (BufFree < NeededSpace + 1) {

            if (End == 0) {

                  End = SK_PNMI_TRAP_QUEUE_LEN;
            }

            EntrySize = (unsigned int)*((unsigned char *)pBuf + End - 1);
            BufFree += EntrySize;
            End -= EntrySize;
#ifdef DEBUG
            SK_MEMSET(pBuf + End, (char)(-1), EntrySize);
#endif /* DEBUG */
            if (End == BufPad) {
#ifdef DEBUG
                  SK_MEMSET(pBuf, (char)(-1), End);
#endif /* DEBUG */
                  BufFree += End;
                  End = 0;
                  BufPad = 0;
            }
      }

      /*
       * Insert new entry as first entry. Newest entries are
       * stored at the beginning of the queue.
       */
      if (Wrap) {

            BufPad = Beg;
            Beg = SK_PNMI_TRAP_QUEUE_LEN - Size;
      }
      else {
            Beg = Beg - Size;
      }
      BufFree -= NeededSpace;

      /* Save the current offsets */
      pAC->Pnmi.TrapQueueBeg = Beg;
      pAC->Pnmi.TrapQueueEnd = End;
      pAC->Pnmi.TrapBufPad = BufPad;
      pAC->Pnmi.TrapBufFree = BufFree;

      /* Initialize the trap entry */
      *(pBuf + Beg + Size - 1) = (char)Size;
      *(pBuf + Beg) = (char)Size;
      Val32 = (pAC->Pnmi.TrapUnique) ++;
      SK_PNMI_STORE_U32(pBuf + Beg + 1, Val32);
      SK_PNMI_STORE_U32(pBuf + Beg + 1 + sizeof(SK_U32), TrapId);
      Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
      SK_PNMI_STORE_U64(pBuf + Beg + 1 + 2 * sizeof(SK_U32), Val64);

      return (pBuf + Beg);
}

/*****************************************************************************
 *
 * CopyTrapQueue - Copies the trap buffer for the TRAP OID
 *
 * Description:
 *    On a query of the TRAP OID the trap buffer contents will be
 *    copied continuously to the request buffer, which must be large
 *    enough. No length check is performed.
 *
 * Returns:
 *    Nothing
 */
PNMI_STATIC void CopyTrapQueue(
SK_AC *pAC,       /* Pointer to adapter context */
char *pDstBuf)          /* Buffer to which the queued traps will be copied */
{
      unsigned int      BufPad = pAC->Pnmi.TrapBufPad;
      unsigned int      Trap = pAC->Pnmi.TrapQueueBeg;
      unsigned int      End = pAC->Pnmi.TrapQueueEnd;
      char        *pBuf = &pAC->Pnmi.TrapBuf[0];
      unsigned int      Len;
      unsigned int      DstOff = 0;


      while (Trap != End) {

            Len = (unsigned int)*(pBuf + Trap);

            /*
             * Last byte containing a copy of the length will
             * not be copied.
             */
            *(pDstBuf + DstOff) = (char)(Len - 1);
            SK_MEMCPY(pDstBuf + DstOff + 1, pBuf + Trap + 1, Len - 2);
            DstOff += Len - 1;

            Trap += Len;
            if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {

                  Trap = BufPad;
            }
      }
}

/*****************************************************************************
 *
 * GetTrapQueueLen - Get the length of the trap buffer
 *
 * Description:
 *    Evaluates the number of currently stored traps and the needed
 *    buffer size to retrieve them.
 *
 * Returns:
 *    Nothing
 */
PNMI_STATIC void GetTrapQueueLen(
SK_AC *pAC,       /* Pointer to adapter context */
unsigned int *pLen,     /* Length in Bytes of all queued traps */
unsigned int *pEntries) /* Returns number of trapes stored in queue */
{
      unsigned int      BufPad = pAC->Pnmi.TrapBufPad;
      unsigned int      Trap = pAC->Pnmi.TrapQueueBeg;
      unsigned int      End = pAC->Pnmi.TrapQueueEnd;
      char        *pBuf = &pAC->Pnmi.TrapBuf[0];
      unsigned int      Len;
      unsigned int      Entries = 0;
      unsigned int      TotalLen = 0;


      while (Trap != End) {

            Len = (unsigned int)*(pBuf + Trap);
            TotalLen += Len - 1;
            Entries ++;

            Trap += Len;
            if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {

                  Trap = BufPad;
            }
      }

      *pEntries = Entries;
      *pLen = TotalLen;
}

/*****************************************************************************
 *
 * QueueSimpleTrap - Store a simple trap to the trap buffer
 *
 * Description:
 *    A simple trap is a trap with now additional data. It consists
 *    simply of a trap code.
 *
 * Returns:
 *    Nothing
 */
PNMI_STATIC void QueueSimpleTrap(
SK_AC *pAC,       /* Pointer to adapter context */
SK_U32 TrapId)          /* Type of sensor trap */
{
      GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_SIMPLE_LEN);
}

/*****************************************************************************
 *
 * QueueSensorTrap - Stores a sensor trap in the trap buffer
 *
 * Description:
 *    Gets an entry in the trap buffer and fills it with sensor related
 *    data.
 *
 * Returns:
 *    Nothing
 */
PNMI_STATIC void QueueSensorTrap(
SK_AC *pAC,             /* Pointer to adapter context */
SK_U32 TrapId,                /* Type of sensor trap */
unsigned int SensorIndex)     /* Index of sensor which caused the trap */
{
      char        *pBuf;
      unsigned int      Offset;
      unsigned int      DescrLen;
      SK_U32            Val32;


      /* Get trap buffer entry */
      DescrLen = SK_STRLEN(pAC->I2c.SenTable[SensorIndex].SenDesc);
      pBuf = GetTrapEntry(pAC, TrapId,
            SK_PNMI_TRAP_SENSOR_LEN_BASE + DescrLen);
      Offset = SK_PNMI_TRAP_SIMPLE_LEN;

      /* Store additionally sensor trap related data */
      Val32 = OID_SKGE_SENSOR_INDEX;
      SK_PNMI_STORE_U32(pBuf + Offset, Val32);
      *(pBuf + Offset + 4) = 4;
      Val32 = (SK_U32)SensorIndex;
      SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
      Offset += 9;
      
      Val32 = (SK_U32)OID_SKGE_SENSOR_DESCR;
      SK_PNMI_STORE_U32(pBuf + Offset, Val32);
      *(pBuf + Offset + 4) = (char)DescrLen;
      SK_MEMCPY(pBuf + Offset + 5, pAC->I2c.SenTable[SensorIndex].SenDesc,
            DescrLen);
      Offset += DescrLen + 5;

      Val32 = OID_SKGE_SENSOR_TYPE;
      SK_PNMI_STORE_U32(pBuf + Offset, Val32);
      *(pBuf + Offset + 4) = 1;
      *(pBuf + Offset + 5) = (char)pAC->I2c.SenTable[SensorIndex].SenType;
      Offset += 6;

      Val32 = OID_SKGE_SENSOR_VALUE;
      SK_PNMI_STORE_U32(pBuf + Offset, Val32);
      *(pBuf + Offset + 4) = 4;
      Val32 = (SK_U32)pAC->I2c.SenTable[SensorIndex].SenValue;
      SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
}

/*****************************************************************************
 *
 * QueueRlmtNewMacTrap - Store a port switch trap in the trap buffer
 *
 * Description:
 *    Nothing further to explain.
 *
 * Returns:
 *    Nothing
 */
PNMI_STATIC void QueueRlmtNewMacTrap(
SK_AC *pAC,       /* Pointer to adapter context */
unsigned int ActiveMac) /* Index (0..n) of the currently active port */
{
      char  *pBuf;
      SK_U32      Val32;


      pBuf = GetTrapEntry(pAC, OID_SKGE_TRAP_RLMT_CHANGE_PORT,
            SK_PNMI_TRAP_RLMT_CHANGE_LEN);

      Val32 = OID_SKGE_RLMT_PORT_ACTIVE;
      SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
      *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
      *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)ActiveMac;
}

/*****************************************************************************
 *
 * QueueRlmtPortTrap - Store port related RLMT trap to trap buffer
 *
 * Description:
 *    Nothing further to explain.
 *
 * Returns:
 *    Nothing
 */
PNMI_STATIC void QueueRlmtPortTrap(
SK_AC *pAC,       /* Pointer to adapter context */
SK_U32 TrapId,          /* Type of RLMT port trap */
unsigned int PortIndex) /* Index of the port, which changed its state */
{
      char  *pBuf;
      SK_U32      Val32;


      pBuf = GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_RLMT_PORT_LEN);

      Val32 = OID_SKGE_RLMT_PORT_INDEX;
      SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
      *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
      *(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)PortIndex;
}

/*****************************************************************************
 *
 * CopyMac - Copies a MAC address
 *
 * Description:
 *    Nothing further to explain.
 *
 * Returns:
 *    Nothing
 */
PNMI_STATIC void CopyMac(
char *pDst,       /* Pointer to destination buffer */
SK_MAC_ADDR *pMac)      /* Pointer of Source */
{
      int   i;


      for (i = 0; i < sizeof(SK_MAC_ADDR); i ++) {

            *(pDst + i) = pMac->a[i];
      }
}

#ifdef SK_POWER_MGMT
/*****************************************************************************
 *
 * PowerManagement - OID handler function of PowerManagement OIDs
 *
 * Description:
 *    The code is simple. No description necessary.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                               exist (e.g. port instance 3 on a two port
 *                             adapter.
 */

PNMI_STATIC int PowerManagement(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* Get/PreSet/Set action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer to which to mgmt data will be retrieved */
unsigned int *pLen,     /* On call: buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode allways zero */
{
      
      SK_U32      RetCode = SK_PNMI_ERR_GENERAL;

      /*
       * Check instance. We only handle single instance variables
       */
      if (Instance != (SK_U32)(-1) && Instance != 1) {

            *pLen = 0;
            return (SK_PNMI_ERR_UNKNOWN_INST);
      }
      
    
    /* Check length */
    switch (Id) {

    case OID_PNP_CAPABILITIES:
        if (*pLen < sizeof(SK_PNP_CAPABILITIES)) {

            *pLen = sizeof(SK_PNP_CAPABILITIES);
            return (SK_PNMI_ERR_TOO_SHORT);
        }
        break;

      case OID_PNP_SET_POWER:
    case OID_PNP_QUERY_POWER:
      if (*pLen < sizeof(SK_DEVICE_POWER_STATE))
      {
            *pLen = sizeof(SK_DEVICE_POWER_STATE);
            return (SK_PNMI_ERR_TOO_SHORT);
      }
        break;

    case OID_PNP_ADD_WAKE_UP_PATTERN:
    case OID_PNP_REMOVE_WAKE_UP_PATTERN:
            if (*pLen < sizeof(SK_PM_PACKET_PATTERN)) {

                  *pLen = sizeof(SK_PM_PACKET_PATTERN);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

    case OID_PNP_ENABLE_WAKE_UP:
        if (*pLen < sizeof(SK_U32)) {

            *pLen = sizeof(SK_U32);
            return (SK_PNMI_ERR_TOO_SHORT);
        }
        break;
    }
      
    /*
       * Perform action
       */
      if (Action == SK_PNMI_GET) {

            /*
             * Get value
             */
            switch (Id) {

            case OID_PNP_CAPABILITIES:
                  RetCode = SkPowerQueryPnPCapabilities(pAC, IoC, pBuf, pLen);
                  break;

            case OID_PNP_QUERY_POWER:
                  /* The Windows DDK describes: An OID_PNP_QUERY_POWER requests
                   the miniport to indicate whether it can transition its NIC
                   to the low-power state.
                   A miniport driver must always return NDIS_STATUS_SUCCESS
                   to a query of OID_PNP_QUERY_POWER. */
                  *pLen = sizeof(SK_DEVICE_POWER_STATE);
            RetCode = SK_PNMI_ERR_OK;
                  break;

                  /* NDIS handles these OIDs as write-only.
                   * So in case of get action the buffer with written length = 0
                   * is returned
                   */
            case OID_PNP_SET_POWER:
            case OID_PNP_ADD_WAKE_UP_PATTERN:
            case OID_PNP_REMOVE_WAKE_UP_PATTERN:
                  *pLen = 0;  
            RetCode = SK_PNMI_ERR_NOT_SUPPORTED;
                  break;

            case OID_PNP_ENABLE_WAKE_UP:
                  RetCode = SkPowerGetEnableWakeUp(pAC, IoC, pBuf, pLen);
                  break;

            default:
                  RetCode = SK_PNMI_ERR_GENERAL;
                  break;
            }

            return (RetCode);
      }
      

      /*
       * Perform preset or set
       */
      
      /* POWER module does not support PRESET action */
      if (Action == SK_PNMI_PRESET) {
            return (SK_PNMI_ERR_OK);
      }

      switch (Id) {
      case OID_PNP_SET_POWER:
            RetCode = SkPowerSetPower(pAC, IoC, pBuf, pLen);      
            break;

      case OID_PNP_ADD_WAKE_UP_PATTERN:
            RetCode = SkPowerAddWakeUpPattern(pAC, IoC, pBuf, pLen);    
            break;
            
      case OID_PNP_REMOVE_WAKE_UP_PATTERN:
            RetCode = SkPowerRemoveWakeUpPattern(pAC, IoC, pBuf, pLen); 
            break;
            
      case OID_PNP_ENABLE_WAKE_UP:
            RetCode = SkPowerSetEnableWakeUp(pAC, IoC, pBuf, pLen);
            break;
            
      default:
            RetCode = SK_PNMI_ERR_READ_ONLY;
      }
      
      return (RetCode);
}
#endif /* SK_POWER_MGMT */

#ifdef SK_DIAG_SUPPORT
/*****************************************************************************
 *
 * DiagActions - OID handler function of Diagnostic driver 
 *
 * Description:
 *    The code is simple. No description necessary.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */

PNMI_STATIC int DiagActions(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (1..n) that is to be queried or -1 */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{

      SK_U32      DiagStatus;
      SK_U32      RetCode = SK_PNMI_ERR_GENERAL;

      /*
       * Check instance. We only handle single instance variables.
       */
      if (Instance != (SK_U32)(-1) && Instance != 1) {

            *pLen = 0;
            return (SK_PNMI_ERR_UNKNOWN_INST);
      }

      /*
       * Check length.
       */
      switch (Id) {

      case OID_SKGE_DIAG_MODE:
            if (*pLen < sizeof(SK_U32)) {

                  *pLen = sizeof(SK_U32);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;

      default:
            SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040, SK_PNMI_ERR040MSG);
            *pLen = 0;
            return (SK_PNMI_ERR_GENERAL);
      }

      /* Perform action. */

      /* GET value. */
      if (Action == SK_PNMI_GET) {

            switch (Id) {

            case OID_SKGE_DIAG_MODE:
                  DiagStatus = pAC->Pnmi.DiagAttached;
                  SK_PNMI_STORE_U32(pBuf, DiagStatus);
                  *pLen = sizeof(SK_U32); 
                  RetCode = SK_PNMI_ERR_OK;
                  break;

            default:
                  *pLen = 0;  
                  RetCode = SK_PNMI_ERR_GENERAL;
                  break;
            }
            return (RetCode); 
      }

      /* From here SET or PRESET value. */
      
      /* PRESET value is not supported. */
      if (Action == SK_PNMI_PRESET) {
            return (SK_PNMI_ERR_OK); 
      }

      /* SET value. */
      switch (Id) {
            case OID_SKGE_DIAG_MODE:

                  /* Handle the SET. */
                  switch (*pBuf) {

                        /* Attach the DIAG to this adapter. */
                        case SK_DIAG_ATTACHED:
                              /* Check if we come from running */
                              if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {

                                    RetCode = SkDrvLeaveDiagMode(pAC);

                              }
                              else if (pAC->Pnmi.DiagAttached == SK_DIAG_IDLE) {

                                    RetCode = SK_PNMI_ERR_OK;
                              }     
                              
                              else {

                                    RetCode = SK_PNMI_ERR_GENERAL;

                              }
                              
                              if (RetCode == SK_PNMI_ERR_OK) {

                                    pAC->Pnmi.DiagAttached = SK_DIAG_ATTACHED;
                              }
                              break;

                        /* Enter the DIAG mode in the driver. */
                        case SK_DIAG_RUNNING:
                              RetCode = SK_PNMI_ERR_OK;
                              
                              /*
                               * If DiagAttached is set, we can tell the driver
                               * to enter the DIAG mode.
                               */
                              if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) {
                                    /* If DiagMode is not active, we can enter it. */
                                    if (!pAC->DiagModeActive) {

                                          RetCode = SkDrvEnterDiagMode(pAC); 
                                    }
                                    else {

                                          RetCode = SK_PNMI_ERR_GENERAL;
                                    }
                              }
                              else {

                                    RetCode = SK_PNMI_ERR_GENERAL;
                              }
                              
                              if (RetCode == SK_PNMI_ERR_OK) {

                                    pAC->Pnmi.DiagAttached = SK_DIAG_RUNNING;
                              }
                              break;

                        case SK_DIAG_IDLE:
                              /* Check if we come from running */
                              if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {

                                    RetCode = SkDrvLeaveDiagMode(pAC);

                              }
                              else if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) {

                                    RetCode = SK_PNMI_ERR_OK;
                              }     
                              
                              else {

                                    RetCode = SK_PNMI_ERR_GENERAL;

                              }

                              if (RetCode == SK_PNMI_ERR_OK) {

                                    pAC->Pnmi.DiagAttached = SK_DIAG_IDLE;
                              }
                              break;

                        default:
                              RetCode = SK_PNMI_ERR_BAD_VALUE;
                              break;
                  }
                  break;

            default:
                  RetCode = SK_PNMI_ERR_GENERAL;
      }

      if (RetCode == SK_PNMI_ERR_OK) {
            *pLen = sizeof(SK_U32);
      }
      else {

            *pLen = 0;
      }
      return (RetCode);
}
#endif /* SK_DIAG_SUPPORT */

/*****************************************************************************
 *
 * Vct - OID handler function of  OIDs
 *
 * Description:
 *    The code is simple. No description necessary.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was performed successfully.
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured.
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
 *                             the correct data (e.g. a 32bit value is
 *                             needed, but a 16 bit value was passed).
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter).
 *    SK_PNMI_ERR_READ_ONLY    Only the Get action is allowed.
 *
 */

PNMI_STATIC int Vct(
SK_AC *pAC,       /* Pointer to adapter context */
SK_IOC IoC,       /* IO context handle */
int Action,       /* GET/PRESET/SET action */
SK_U32 Id,        /* Object ID that is to be processed */
char *pBuf,       /* Buffer used for the management data transfer */
unsigned int *pLen,     /* On call: pBuf buffer length. On return: used buffer */
SK_U32 Instance,  /* Instance (-1,2..n) that is to be queried */
unsigned int TableIndex, /* Index to the Id table */
SK_U32 NetIndex)  /* NetIndex (0..n), in single net mode always zero */
{
      SK_GEPORT   *pPrt;
      SK_PNMI_VCT *pVctBackupData;
      SK_U32            LogPortMax;
      SK_U32            PhysPortMax;
      SK_U32            PhysPortIndex;
      SK_U32            Limit;
      SK_U32            Offset;
      SK_BOOL           Link;
      SK_U32            RetCode = SK_PNMI_ERR_GENERAL;
      int         i;
      SK_EVPARA   Para;
      SK_U32            CableLength;
      
      /*
       * Calculate the port indexes from the instance.
       */
      PhysPortMax = pAC->GIni.GIMacsFound;
      LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
      
      /* Dual net mode? */
      if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
            LogPortMax--;
      }
      
      if ((Instance != (SK_U32) (-1))) {
            /* Check instance range. */
            if ((Instance < 2) || (Instance > LogPortMax)) {
                  *pLen = 0;
                  return (SK_PNMI_ERR_UNKNOWN_INST);
            }
            
            if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
                  PhysPortIndex = NetIndex;
            }
            else {
                  PhysPortIndex = Instance - 2;
            }
            Limit = PhysPortIndex + 1;
      }
      else {
            /*
             * Instance == (SK_U32) (-1), get all Instances of that OID.
             *
             * Not implemented yet. May be used in future releases.
             */
            PhysPortIndex = 0;
            Limit = PhysPortMax;
      }
      
      pPrt = &pAC->GIni.GP[PhysPortIndex];
      if (pPrt->PHWLinkUp) {
            Link = SK_TRUE;
      }
      else {
            Link = SK_FALSE;
      }
      
      /* Check MAC type */
      if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
            *pLen = 0;
            return (SK_PNMI_ERR_GENERAL);
      }
      
      /* Initialize backup data pointer. */
      pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
      
      /* Check action type */
      if (Action == SK_PNMI_GET) {
            /* Check length */
            switch (Id) {
            
            case OID_SKGE_VCT_GET:
                  if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT)) {
                        *pLen = (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  break;
            
            case OID_SKGE_VCT_STATUS:
                  if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U8)) {
                        *pLen = (Limit - PhysPortIndex) * sizeof(SK_U8);
                        return (SK_PNMI_ERR_TOO_SHORT);
                  }
                  break;
            
            default:
                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }     
            
            /* Get value */
            Offset = 0;
            for (; PhysPortIndex < Limit; PhysPortIndex++) {
                  switch (Id) {
                  
                  case OID_SKGE_VCT_GET:
                        if ((Link == SK_FALSE) &&
                              (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING)) {
                              RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
                              if (RetCode == 0) {
                                    pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
                                    pAC->Pnmi.VctStatus[PhysPortIndex] |=
                                          (SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
                                    
                                    /* Copy results for later use to PNMI struct. */
                                    for (i = 0; i < 4; i++)  {
                                          if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
                                                if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] < 0xff)) {
                                                      pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
                                                }
                                          }
                                          if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] != 0xff)) {
                                                CableLength = 1000 * (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
                                          }
                                          else {
                                                CableLength = 0;
                                          }
                                          pVctBackupData->PMdiPairLen[i] = CableLength;
                                          pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
                                    }

                                    Para.Para32[0] = PhysPortIndex;
                                    Para.Para32[1] = -1;
                                    SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
                                    SkEventDispatcher(pAC, IoC);
                              }
                              else {
                                    ; /* VCT test is running. */
                              }
                        }
                        
                        /* Get all results. */
                        CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
                        Offset += sizeof(SK_U8);
                        *(pBuf + Offset) = pPrt->PCableLen;
                        Offset += sizeof(SK_U8);
                        for (i = 0; i < 4; i++)  {
                              SK_PNMI_STORE_U32((pBuf + Offset), pVctBackupData->PMdiPairLen[i]);
                              Offset += sizeof(SK_U32);
                        }
                        for (i = 0; i < 4; i++)  {
                              *(pBuf + Offset) = pVctBackupData->PMdiPairSts[i];
                              Offset += sizeof(SK_U8);
                        }
                        
                        RetCode = SK_PNMI_ERR_OK;
                        break;
            
                  case OID_SKGE_VCT_STATUS:
                        CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
                        Offset += sizeof(SK_U8);
                        RetCode = SK_PNMI_ERR_OK;
                        break;
                  
                  default:
                        *pLen = 0;
                        return (SK_PNMI_ERR_GENERAL);
                  }
            } /* for */
            *pLen = Offset;
            return (RetCode);
      
      } /* if SK_PNMI_GET */
      
      /*
       * From here SET or PRESET action. Check if the passed
       * buffer length is plausible.
       */
      
      /* Check length */
      switch (Id) {
      case OID_SKGE_VCT_SET:
            if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
                  *pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
                  return (SK_PNMI_ERR_TOO_SHORT);
            }
            break;
      
      default:
            *pLen = 0;
            return (SK_PNMI_ERR_GENERAL);
      }
      
      /*
       * Perform preset or set.
       */
      
      /* VCT does not support PRESET action. */
      if (Action == SK_PNMI_PRESET) {
            return (SK_PNMI_ERR_OK);
      }
      
      Offset = 0;
      for (; PhysPortIndex < Limit; PhysPortIndex++) {
            switch (Id) {
            case OID_SKGE_VCT_SET: /* Start VCT test. */
                  if (Link == SK_FALSE) {
                        SkGeStopPort(pAC, IoC, PhysPortIndex, SK_STOP_ALL, SK_SOFT_RST);
                        
                        RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_TRUE);
                        if (RetCode == 0) { /* RetCode: 0 => Start! */
                              pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_PENDING;
                              pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_NEW_VCT_DATA;
                              pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_LINK;
                              
                              /*
                               * Start VCT timer counter.
                               */
                              SK_MEMSET((char *) &Para, 0, sizeof(Para));
                              Para.Para32[0] = PhysPortIndex;
                              Para.Para32[1] = -1;
                              SkTimerStart(pAC, IoC, &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
                                    4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Para);
                              SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
                              RetCode = SK_PNMI_ERR_OK;
                        }
                        else { /* RetCode: 2 => Running! */
                              SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
                              RetCode = SK_PNMI_ERR_OK;
                        }
                  }
                  else { /* RetCode: 4 => Link! */
                        RetCode = 4;
                        SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
                        RetCode = SK_PNMI_ERR_OK;
                  }
                  Offset += sizeof(SK_U32);
                  break;
      
            default:
                  *pLen = 0;
                  return (SK_PNMI_ERR_GENERAL);
            }
      } /* for */
      *pLen = Offset;
      return (RetCode);

} /* Vct */


PNMI_STATIC void CheckVctStatus(
SK_AC       *pAC,
SK_IOC            IoC,
char        *pBuf,
SK_U32            Offset,
SK_U32            PhysPortIndex)
{
      SK_GEPORT   *pPrt;
      SK_PNMI_VCT *pVctData;
      SK_U32            RetCode;
      
      pPrt = &pAC->GIni.GP[PhysPortIndex];
      
      pVctData = (SK_PNMI_VCT *) (pBuf + Offset);
      pVctData->VctStatus = SK_PNMI_VCT_NONE;
      
      if (!pPrt->PHWLinkUp) {
            
            /* Was a VCT test ever made before? */
            if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
                  if ((pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_LINK)) {
                        pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
                  }
                  else {
                        pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
                  }
            }
            
            /* Check VCT test status. */
            RetCode = SkGmCableDiagStatus(pAC,IoC, PhysPortIndex, SK_FALSE);
            if (RetCode == 2) { /* VCT test is running. */
                  pVctData->VctStatus |= SK_PNMI_VCT_RUNNING;
            }
            else { /* VCT data was copied to pAC here. Check PENDING state. */
                  if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
                        pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
                  }
            }
            
            if (pPrt->PCableLen != 0xff) { /* Old DSP value. */
                  pVctData->VctStatus |= SK_PNMI_VCT_OLD_DSP_DATA;
            }
      }
      else {
            
            /* Was a VCT test ever made before? */
            if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
                  pVctData->VctStatus &= ~SK_PNMI_VCT_NEW_VCT_DATA;
                  pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
            }
            
            /* DSP only valid in 100/1000 modes. */
            if (pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed !=
                  SK_LSPEED_STAT_10MBPS) {      
                  pVctData->VctStatus |= SK_PNMI_VCT_NEW_DSP_DATA;
            }
      }
} /* CheckVctStatus */


/*****************************************************************************
 *
 *      SkPnmiGenIoctl - Handles new generic PNMI IOCTL, calls the needed
 *                       PNMI function depending on the subcommand and
 *                       returns all data belonging to the complete database
 *                       or OID request.
 *
 * Description:
 *    Looks up the requested subcommand, calls the corresponding handler
 *    function and passes all required parameters to it.
 *    The function is called by the driver. It is needed to handle the new
 *  generic PNMI IOCTL. This IOCTL is given to the driver and contains both
 *  the OID and a subcommand to decide what kind of request has to be done.
 *
 * Returns:
 *    SK_PNMI_ERR_OK           The request was successfully performed
 *    SK_PNMI_ERR_GENERAL      A general severe internal error occured
 *    SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
 *                             the data.
 *    SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
 *    SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
 *                           exist (e.g. port instance 3 on a two port
 *                             adapter.
 */
int SkPnmiGenIoctl(
SK_AC       *pAC,       /* Pointer to adapter context struct */
SK_IOC            IoC,        /* I/O context */
void        *pBuf,            /* Buffer used for the management data transfer */
unsigned int *pLen,           /* Length of buffer */
SK_U32            NetIndex)   /* NetIndex (0..n), in single net mode always zero */
{
SK_I32      Mode;             /* Store value of subcommand. */
SK_U32      Oid;              /* Store value of OID. */
int         ReturnCode;       /* Store return value to show status of PNMI action. */
int   HeaderLength;     /* Length of desired action plus OID. */

      ReturnCode = SK_PNMI_ERR_GENERAL;
      
      SK_MEMCPY(&Mode, pBuf, sizeof(SK_I32));
      SK_MEMCPY(&Oid, (char *) pBuf + sizeof(SK_I32), sizeof(SK_U32));
      HeaderLength = sizeof(SK_I32) + sizeof(SK_U32);
      *pLen = *pLen - HeaderLength;
      SK_MEMCPY((char *) pBuf + sizeof(SK_I32), (char *) pBuf + HeaderLength, *pLen);
      
      switch(Mode) {
      case SK_GET_SINGLE_VAR:
            ReturnCode = SkPnmiGetVar(pAC, IoC, Oid, 
                        (char *) pBuf + sizeof(SK_I32), pLen,
                        ((SK_U32) (-1)), NetIndex);
            SK_PNMI_STORE_U32(pBuf, ReturnCode);
            *pLen = *pLen + sizeof(SK_I32);
            break;
      case SK_PRESET_SINGLE_VAR:
            ReturnCode = SkPnmiPreSetVar(pAC, IoC, Oid, 
                        (char *) pBuf + sizeof(SK_I32), pLen,
                        ((SK_U32) (-1)), NetIndex);
            SK_PNMI_STORE_U32(pBuf, ReturnCode);
            *pLen = *pLen + sizeof(SK_I32);
            break;
      case SK_SET_SINGLE_VAR:
            ReturnCode = SkPnmiSetVar(pAC, IoC, Oid, 
                        (char *) pBuf + sizeof(SK_I32), pLen,
                        ((SK_U32) (-1)), NetIndex);
            SK_PNMI_STORE_U32(pBuf, ReturnCode);
            *pLen = *pLen + sizeof(SK_I32);
            break;
      case SK_GET_FULL_MIB:
            ReturnCode = SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex);
            break;
      case SK_PRESET_FULL_MIB:
            ReturnCode = SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex);
            break;
      case SK_SET_FULL_MIB:
            ReturnCode = SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex);
            break;
      default:
            break;
      }
      
      return (ReturnCode);

} /* SkGeIocGen */

Generated by  Doxygen 1.6.0   Back to index