text: /*****************************************************************************
   *
   * Name:	skgepnmi.c
   * Project:	GEnesis, PCI Gigabit Ethernet Adapter
   * 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 SkPnmiGetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
  	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
  int SkPnmiPreSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
  	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
  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.
   */
  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 usefull 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 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 usefull 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 usefull 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:
  #ifdef SK_PHY_LP_MODE
  		case OID_SKGE_PHY_LP_MODE:
  #endif
  			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;
  
  #ifdef SK_PHY_LP_MODE
  			case OID_SKGE_PHY_LP_MODE:
  				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
  					if (LogPortIndex == 0) {
  						continue;
  					}
  					else {
  						/* Get value for physical ports */
  						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
  						Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState;
  						*pBufPtr = Val8;
  					}
  				}
  				else { /* DualNetMode */
  					
  					Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState;
  					*pBufPtr = Val8;
  				}
  				Offset += sizeof(SK_U8);
  				break;
  #endif
  
  			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;
  
  #ifdef SK_PHY_LP_MODE
  	case OID_SKGE_PHY_LP_MODE:
  		if (*pLen < Limit - LogPortIndex) {
  
  			*pLen = Limit - LogPortIndex;
  			return (SK_PNMI_ERR_TOO_SHORT);
  		}
  		break;
  #endif
  
  	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;
  		
  #ifdef SK_PHY_LP_MODE
  		case OID_SKGE_PHY_LP_MODE:
  			/* The preset ends here */
  			if (Action == SK_PNMI_PRESET) {
  
  				return (SK_PNMI_ERR_OK);
  			}
  
  			if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
  				if (LogPortIndex == 0) {
  					Offset = 0;
  					continue;
  				}
  				else {
  					/* Set value for physical ports */
  					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
  
  					switch (*(pBuf + Offset)) {
  						case 0:
  							/* If LowPowerMode is active, we can leave it. */
  							if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) {
  
  								Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex);
  								
  								if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3)	{
  									
  									SkDrvInitAdapter(pAC);
  								}
  								break;
  							}
  							else {
  								*pLen = 0;
  								return (SK_PNMI_ERR_GENERAL);
  							}
  						case 1:
  						case 2:
  						case 3:
  						case 4:
  							/* If no LowPowerMode is active, we can enter it. */
  							if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) {
  
  								if ((*(pBuf + Offset)) < 3)	{
  								
  									SkDrvDeInitAdapter(pAC);
  								}
  
  								Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf);
  								break;
  							}
  							else {
  								*pLen = 0;
  								return (SK_PNMI_ERR_GENERAL);
  							}
  						default:
  							*pLen = 0;
  							return (SK_PNMI_ERR_BAD_VALUE);
  					}
  				}
  			}
  			else { /* DualNetMode */
  				
  				switch (*(pBuf + Offset)) {
  					case 0:
  						/* If we are in a LowPowerMode, we can leave it. */
  						if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) {
  
  							Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex);
  							
  							if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3)	{
  
  								SkDrvInitAdapter(pAC);
  							}
  							break;
  						}
  						else {
  							*pLen = 0;
  							return (SK_PNMI_ERR_GENERAL);
  						}
  					
  					case 1:
  					case 2:
  					case 3:
  					case 4:
  						/* If we are not already in LowPowerMode, we can enter it. */
  						if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) {
  
  							if ((*(pBuf + Offset)) < 3)	{
  
  								SkDrvDeInitAdapter(pAC);
  							}
  							else {
  
  								Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf);
  							}
  							break;
  						}
  						else {
  							*pLen = 0;
  							return (SK_PNMI_ERR_GENERAL);
  						}
  					
  					default:
  						*pLen = 0;
  						return (SK_PNMI_ERR_BAD_VALUE);
  				}
  			}
  			Offset += sizeof(SK_U8);
  			break;
  #endif
  
  		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 usefull 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 */
  