diff options
Diffstat (limited to 'drivers/net/sk98lin/skgepnmi.c')
| -rw-r--r-- | drivers/net/sk98lin/skgepnmi.c | 8310 | 
1 files changed, 8310 insertions, 0 deletions
| diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c new file mode 100644 index 000000000..b5d32b04c --- /dev/null +++ b/drivers/net/sk98lin/skgepnmi.c @@ -0,0 +1,8310 @@ +/***************************************************************************** + * + * Name:	skgepnmi.c + * Project:	GEnesis, PCI Gigabit Ethernet Adapter + * Version:	$Revision: 1.102 $ + * Date:	$Date: 2002/12/16 14:03:24 $ + * Purpose:	Private Network Management Interface + * + ****************************************************************************/ + +/****************************************************************************** + * + *	(C)Copyright 1998-2002 SysKonnect GmbH. + * + *	This program is free software; you can redistribute it and/or modify + *	it under the terms of the GNU General Public License as published by + *	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. + * + ******************************************************************************/ + +/***************************************************************************** + * + * History: + * + *	$Log: skgepnmi.c,v $ + *	Revision 1.102  2002/12/16 14:03:24  tschilli + *	VCT code in Vct() changed. + * + *	Revision 1.101  2002/12/16 09:04:10  tschilli + *	Code for VCT handling added. + * + *	Revision 1.100  2002/09/26 14:28:13  tschilli + *	For XMAC the values in the SK_PNMI_PORT Port struct are copied to + *	the new SK_PNMI_PORT BufPort struct during a MacUpdate() call. + *	These values are used when GetPhysStatVal() is called. With this + *	mechanism you get the best results when software corrections for + *	counters are needed. Example: RX_LONGFRAMES. + * + *	Revision 1.99  2002/09/17 12:31:19  tschilli + *	OID_SKGE_TX_HW_ERROR_CTS, OID_SKGE_OUT_ERROR_CTS, OID_GEN_XMIT_ERROR: + *	Double count of SK_PNMI_HTX_EXCESS_COL in function General() removed. + *	OID_PNP_CAPABILITIES: sizeof(SK_PM_WAKE_UP_CAPABILITIES) changed to + *	sizeof(SK_PNP_CAPABILITIES) in function PowerManagement(). + * + *	Revision 1.98  2002/09/10 09:00:03  rwahl + *	Adapted boolean definitions according sktypes. + * + *	Revision 1.97  2002/09/05 15:07:03  rwahl + *	Editorial changes. + * + *	Revision 1.96  2002/09/05 11:04:14  rwahl + *	- Rx/Tx packets statistics of virtual port were zero on link down (#10750) + *	- For GMAC the overflow IRQ for Rx longframe counter was not counted. + *	- Incorrect calculation for oids OID_SKGE_RX_HW_ERROR_CTS, + *	  OID_SKGE_IN_ERRORS_CTS,  OID_GEN_RCV_ERROR. + *	- Moved correction for OID_SKGE_STAT_RX_TOO_LONG to GetPhysStatVal(). + *	- Editorial changes. + * + *	Revision 1.95  2002/09/04 08:53:37  rwahl + *	- Incorrect statistics for Rx_too_long counter with jumbo frame (#10751) + *	- StatRxFrameTooLong & StatRxPMaccErr counters were not reset. + *	- Fixed compiler warning for debug msg arg types. + * + *	Revision 1.94  2002/08/09 15:42:14  rwahl + *	- Fixed StatAddr table for GMAC. + *	- VirtualConf(): returned indeterminated status for speed oids if no + *	  active port. + * + *	Revision 1.93  2002/08/09 11:04:59  rwahl + *	Added handler for link speed caps. + * + *	Revision 1.92  2002/08/09 09:43:03  rwahl + *	- Added handler for NDIS OID_PNP_xxx ids. + * + *	Revision 1.91  2002/07/17 19:53:03  rwahl + *	- Added StatOvrflwBit table for XMAC & GMAC. + *	- Extended StatAddr table for GMAC. Added check of number of counters + *	  in enumeration and size of StatAddr table on init level. + *	- Added use of GIFunc table. + *	- ChipSet is not static anymore, + *	- Extended SIRQ event handler for both mac types. + *	- Fixed rx short counter bug (#10620) + *	- Added handler for oids SKGE_SPEED_MODE & SKGE_SPEED_STATUS. + *	- Extendet GetPhysStatVal() for GMAC. + *	- Editorial changes. + * + *	Revision 1.90  2002/05/22 08:56:25  rwahl + *	- Moved OID table to separate source file. + *	- Fix: TX_DEFFERAL counter incremented in full-duplex mode. + *	- Use string definitions for error msgs. + * + *	Revision 1.89  2001/09/18 10:01:30  mkunz + *	some OID's fixed for dualnetmode + * + *	Revision 1.88  2001/08/02 07:58:08  rwahl + *	- Fixed NetIndex to csum module at ResetCounter(). + * + *	Revision 1.87  2001/04/06 13:35:09  mkunz + *	-Bugs fixed in handling of OID_SKGE_MTU and the VPD OID's + * + *	Revision 1.86  2001/03/09 09:18:03  mkunz + *	Changes in SK_DBG_MSG + * + *	Revision 1.85  2001/03/08 09:37:31  mkunz + *	Bugfix in ResetCounter for Pnmi.Port structure + * + *	Revision 1.84  2001/03/06 09:04:55  mkunz + *	Made some changes in instance calculation + * + *	Revision 1.83  2001/02/15 09:15:32  mkunz + *	Necessary changes for dual net mode added + * + *	Revision 1.82  2001/02/07 08:24:19  mkunz + *	-Made changes in handling of OID_SKGE_MTU + * + *	Revision 1.81  2001/02/06 09:58:00  mkunz + *	-Vpd bug fixed + *	-OID_SKGE_MTU added + *	-pnmi support for dual net mode. Interface function and macros extended + * + *	Revision 1.80  2001/01/22 13:41:35  rassmann + *	Supporting two nets on dual-port adapters. + * + *	Revision 1.79  2000/12/05 14:57:40  cgoos + *	SetStruct failed before first Link Up (link mode of virtual + *	port "INDETERMINATED"). + * + *	Revision 1.78  2000/09/12 10:44:58  cgoos + *	Fixed SK_PNMI_STORE_U32 calls with typecasted argument. + * + *	Revision 1.77  2000/09/07 08:10:19  rwahl + *	- Modified algorithm for 64bit NDIS statistic counters; + *	  returns 64bit or 32bit value depending on passed buffer + *	  size. Indicate capability for 64bit NDIS counter, if passed + *	  buffer size is zero. OID_GEN_XMIT_ERROR, OID_GEN_RCV_ERROR, + *	  and OID_GEN_RCV_NO_BUFFER handled as 64bit counter, too. + *	- corrected OID_SKGE_RLMT_PORT_PREFERRED. + * + *	Revision 1.76  2000/08/03 15:23:39  rwahl + *	- Correction for FrameTooLong counter has to be moved to OID handling + *	  routines (instead of statistic counter routine). + *	- Fix in XMAC Reset Event handling: Only offset counter for hardware + *	  statistic registers are updated. + * + *	Revision 1.75  2000/08/01 16:46:05  rwahl + *	- Added StatRxLongFrames counter and correction of FrameTooLong counter. + *	- Added directive to control width (default = 32bit) of NDIS statistic + *	  counters (SK_NDIS_64BIT_CTR). + * + *	Revision 1.74  2000/07/04 11:41:53  rwahl + *	- Added volition connector type. + * + *	Revision 1.73  2000/03/15 16:33:10  rwahl + *	Fixed bug 10510; wrong reset of virtual port statistic counters. + * + *	Revision 1.72  1999/12/06 16:15:53  rwahl + *	Fixed problem of instance range for current and factory MAC address. + * + *	Revision 1.71  1999/12/06 10:14:20  rwahl + *	Fixed bug 10476; set operation for PHY_OPERATION_MODE. + * + *	Revision 1.70  1999/11/22 13:33:34  cgoos + *	Changed license header to GPL. + * + *	Revision 1.69  1999/10/18 11:42:15  rwahl + *	Added typecasts for checking event dependent param (debug only). + * + *	Revision 1.68  1999/10/06 09:35:59  cgoos + *	Added state check to PHY_READ call (hanged if called during startup). + * + *	Revision 1.67  1999/09/22 09:53:20  rwahl + *	- Read Broadcom register for updating fcs error counter (1000Base-T). + * + *	Revision 1.66  1999/08/26 13:47:56  rwahl + *	Added SK_DRIVER_SENDEVENT when queueing RLMT_CHANGE_THRES trap. + * + *	Revision 1.65  1999/07/26 07:49:35  cgoos + *	Added two typecasts to avoid compiler warnings. + * + *	Revision 1.64  1999/05/20 09:24:12  cgoos + *	Changes for 1000Base-T (sensors, Master/Slave). + * + *	Revision 1.63  1999/04/13 15:11:58  mhaveman + *	Moved include of rlmt.h to header skgepnmi.h because some macros + *	are needed there. + * + *	Revision 1.62  1999/04/13 15:08:07  mhaveman + *	Replaced again SK_RLMT_CHECK_LINK with SK_PNMI_RLMT_MODE_CHK_LINK + *	to grant unified interface by only using the PNMI header file. + *	SK_PNMI_RLMT_MODE_CHK_LINK is defined the same as SK_RLMT_CHECK_LINK. + * + *	Revision 1.61  1999/04/13 15:02:48  mhaveman + *	Changes caused by review: + *	-Changed some comments + *	-Removed redundant check for OID_SKGE_PHYS_FAC_ADDR + *	-Optimized PRESET check. + *	-Meaning of error SK_ADDR_DUPLICATE_ADDRESS changed. Set of same + *	 address will now not cause this error. Removed corresponding check. + * + *	Revision 1.60  1999/03/23 10:41:23  mhaveman + *	Added comments. + * + *	Revision 1.59  1999/02/19 08:01:28  mhaveman + *	Fixed bug 10372 that after counter reset all ports were displayed + *	as inactive. + * + *	Revision 1.58  1999/02/16 18:04:47  mhaveman + *	Fixed problem of twisted OIDs SENSOR_WAR_TIME and SENSOR_ERR_TIME. + * + *	Revision 1.56  1999/01/27 12:29:11  mhaveman + *	SkTimerStart was called with time value in milli seconds but needs + *	micro seconds. + * + *	Revision 1.55  1999/01/25 15:00:38  mhaveman + *	Added support to allow multiple ports to be active. If this feature in + *	future will be used, the Management Data Base variables PORT_ACTIVE + *	and PORT_PREFERED should be moved to the port specific part of RLMT. + *	Currently they return the values of the first active physical port + *	found. A set to the virtual port will actually change all active + *	physical ports. A get returns the melted values of all active physical + *	ports. If the port values differ a return value INDETERMINATED will + *	be returned. This effects especially the CONF group. + * + *	Revision 1.54  1999/01/19 10:10:22  mhaveman + *	-Fixed bug 10354: Counter values of virtual port were wrong after port + *	 switches + *	-Added check if a switch to the same port is notified. + * + *	Revision 1.53  1999/01/07 09:25:21  mhaveman + *	Forgot to initialize a variable. + * + *	Revision 1.52  1999/01/05 10:34:33  mhaveman + *	Fixed little error in RlmtChangeEstimate calculation. + * + *	Revision 1.51  1999/01/05 09:59:07  mhaveman + *	-Moved timer start to init level 2 + *	-Redesigned port switch average calculation to avoid 64bit + *	 arithmetic. + * + *	Revision 1.50  1998/12/10 15:13:59  mhaveman + *	-Fixed: PHYS_CUR_ADDR returned wrong addresses + *	-Fixed: RLMT_PORT_PREFERED and RLMT_CHANGE_THRES preset returned + *	        always BAD_VALUE. + *	-Fixed: TRAP buffer seemed to sometimes suddenly empty + * + *	Revision 1.49  1998/12/09 16:17:07  mhaveman + *	Fixed: Couldnot delete VPD keys on UNIX. + * + *	Revision 1.48  1998/12/09 14:11:10  mhaveman + *	-Add: Debugmessage for XMAC_RESET supressed to minimize output. + *	-Fixed: RlmtChangeThreshold will now be initialized. + *	-Fixed: VPD_ENTRIES_LIST extended value with unnecessary space char. + *	-Fixed: On VPD key creation an invalid key name could be created + *	        (e.g. A5) + *	-Some minor changes in comments and code. + * + *	Revision 1.47  1998/12/08 16:00:31  mhaveman + *	-Fixed: For RLMT_PORT_ACTIVE will now be returned a 0 if no port + *		is active. + *	-Fixed: For the RLMT statistics group only the last value was + *		returned and the rest of the buffer was filled with 0xff + *	-Fixed: Mysteriously the preset on RLMT_MODE still returned + *		BAD_VALUE. + *	Revision 1.46  1998/12/08 10:04:56  mhaveman + *	-Fixed: Preset on RLMT_MODE returned always BAD_VALUE error. + *	-Fixed: Alignment error in GetStruct + *	-Fixed: If for Get/Preset/SetStruct the buffer size is equal or + *	        larger than SK_PNMI_MIN_STRUCT_SIZE the return value is stored + *		to the buffer. In this case the caller should always return + *	        ok to its upper routines. Only if the buffer size is less + *	        than SK_PNMI_MIN_STRUCT_SIZE and the return value is unequal + *	        to 0, an error should be returned by the caller. + *	-Fixed: Wrong number of instances with RLMT statistic. + *	-Fixed: Return now SK_LMODE_STAT_UNKNOWN if the LinkModeStatus is 0. + * + *	Revision 1.45  1998/12/03 17:17:24  mhaveman + *	-Removed for VPD create action the buffer size limitation to 4 bytes. + *	-Pass now physical/active physical port to ADDR for CUR_ADDR set + * + *	Revision 1.44  1998/12/03 15:14:35  mhaveman + *	Another change to Vpd instance evaluation. + * + *	Revision 1.43  1998/12/03 14:18:10  mhaveman + *	-Fixed problem in PnmiSetStruct. It was impossible to set any value. + *	-Removed VPD key evaluation for VPD_FREE_BYTES and VPD_ACTION. + * + *	Revision 1.42  1998/12/03 11:31:47  mhaveman + *	Inserted cast to satisfy lint. + * + *	Revision 1.41  1998/12/03 11:28:16  mhaveman + *	Removed SK_PNMI_CHECKPTR + * + *	Revision 1.40  1998/12/03 11:19:07  mhaveman + *	Fixed problems + *	-A set to virtual port will now be ignored. A set with broadcast + *	 address to any port will be ignored. + *	-GetStruct function made VPD instance calculation wrong. + *	-Prefered port returned -1 instead of 0. + * + *	Revision 1.39  1998/11/26 15:30:29  mhaveman + *	Added sense mode to link mode. + * + *	Revision 1.38  1998/11/23 15:34:00  mhaveman + *	-Fixed bug for RX counters. On an RX overflow interrupt the high + *	 words of all RX counters were incremented. + *	-SET operations on FLOWCTRL_MODE and LINK_MODE accept now the + *	 value 0, which has no effect. It is usefull for multiple instance + *	 SETs. + * + *	Revision 1.37  1998/11/20 08:02:04  mhaveman + *	-Fixed: Ports were compared with MAX_SENSORS + *	-Fixed: Crash in GetTrapEntry with MEMSET macro + *	-Fixed: Conversions between physical, logical port index and instance + * + *	Revision 1.36  1998/11/16 07:48:53  mhaveman + *	Casted SK_DRIVER_SENDEVENT with (void) to eleminate compiler warnings + *	on Solaris. + * + *	Revision 1.35  1998/11/16 07:45:34  mhaveman + *	SkAddrOverride now returns value and will be checked. + * + *	Revision 1.34  1998/11/10 13:40:37  mhaveman + *	Needed to change interface, because NT driver needs a return value + *	of needed buffer space on TOO_SHORT errors. Therefore all + *	SkPnmiGet/Preset/Set functions now have a pointer to the length + *	parameter, where the needed space on error is returned. + * + *	Revision 1.33  1998/11/03 13:52:46  mhaveman + *	Made file lint conform. + * + *	Revision 1.32  1998/11/03 13:19:07  mhaveman + *	The events SK_HWEV_SET_LMODE and SK_HWEV_SET_FLOWMODE pass now in + *	Para32[0] the physical MAC index and in Para32[1] the new mode. + * + *	Revision 1.31  1998/11/03 12:30:40  gklug + *	fix: compiler warning memset + * + *	Revision 1.30  1998/11/03 12:04:46  mhaveman + *	Fixed problem in SENSOR_VALUE, which wrote beyond the buffer end + *	Fixed alignment problem with CHIPSET. + * + *	Revision 1.29  1998/11/02 11:23:54  mhaveman + *	Corrected SK_ERROR_LOG to SK_ERR_LOG. Sorry. + * + *	Revision 1.28  1998/11/02 10:47:16  mhaveman + *	Added syslog messages for internal errors. + * + *	Revision 1.27  1998/10/30 15:48:06  mhaveman + *	Fixed problems after simulation of SK_PNMI_EVT_CHG_EST_TIMER and + *	RlmtChangeThreshold calculation. + * + *	Revision 1.26  1998/10/29 15:36:55  mhaveman + *	-Fixed bug in trap buffer handling. + *	-OID_SKGE_DRIVER_DESCR, OID_SKGE_DRIVER_VERSION, OID_SKGE_HW_DESCR, + *	 OID_SKGE_HW_VERSION, OID_SKGE_VPD_ENTRIES_LIST, OID_SKGE_VPD_KEY, + *	 OID_SKGE_VPD_VALUE, and OID_SKGE_SENSOR_DESCR return values with + *	 a leading octet before each string storing the string length. + *	-Perform a RlmtUpdate during SK_PNMI_EVT_XMAC_RESET to minimize + *	 RlmtUpdate calls in GetStatVal. + *	-Inserted SK_PNMI_CHECKFLAGS macro increase readability. + * + *	Revision 1.25  1998/10/29 08:50:36  mhaveman + *	Fixed problems after second event simulation. + * + *	Revision 1.24  1998/10/28 08:44:37  mhaveman + *	-Fixed alignment problem + *	-Fixed problems during event simulation + *	-Fixed sequence of error return code (INSTANCE -> ACCESS -> SHORT) + *	-Changed type of parameter Instance back to SK_U32 because of VPD + *	-Updated new VPD function calls + * + *	Revision 1.23  1998/10/23 10:16:37  mhaveman + *	Fixed bugs after buffer test simulation. + * + *	Revision 1.22  1998/10/21 13:23:52  mhaveman + *	-Call syntax of SkOsGetTime() changed to SkOsGetTime(pAc). + *	-Changed calculation of hundrets of seconds. + * + *	Revision 1.20  1998/10/20 07:30:45  mhaveman + *	Made type changes to unsigned integer where possible. + * + *	Revision 1.19  1998/10/19 10:51:30  mhaveman + *	-Made Bug fixes after simulation run + *	-Renamed RlmtMAC... to RlmtPort... + *	-Marked workarounds with Errata comments + * + *	Revision 1.18  1998/10/14 07:50:08  mhaveman + *	-For OID_SKGE_LINK_STATUS the link down detection has moved from RLMT + *	 to HWACCESS. + *	-Provided all MEMCPY/MEMSET macros with (char *) pointers, because + *	 Solaris throwed warnings when mapping to bcopy/bset. + * + *	Revision 1.17  1998/10/13 07:42:01  mhaveman + *	-Added OIDs OID_SKGE_TRAP_NUMBER and OID_SKGE_ALL_DATA + *	-Removed old cvs history entries + *	-Renamed MacNumber to PortNumber + * + *	Revision 1.16  1998/10/07 10:52:49  mhaveman + *	-Inserted handling of some OID_GEN_ Ids for windows + *	-Fixed problem with 803.2 statistic. + * + *	Revision 1.15  1998/10/01 09:16:29  mhaveman + *	Added Debug messages for function call and UpdateFlag tracing. + * + *	Revision 1.14  1998/09/30 13:39:09  mhaveman + *	-Reduced namings of 'MAC' by replacing them with 'PORT'. + *	-Completed counting of OID_SKGE_RX_HW_ERROR_CTS, + *       OID_SKGE_TX_HW_ERROR_CTS, + *	 OID_SKGE_IN_ERRORS_CTS, and OID_SKGE_OUT_ERROR_CTS. + *	-SET check for RlmtMode + * + *	Revision 1.13  1998/09/28 13:13:08  mhaveman + *	Hide strcmp, strlen, and strncpy behind macros SK_STRCMP, SK_STRLEN, + *	and SK_STRNCPY. (Same reasons as for mem.. and MEM..) + * + *	Revision 1.12  1998/09/16 08:18:36  cgoos + *	Fix: XM_INxx and XM_OUTxx called with different parameter order: + *      sometimes IoC,Mac,...  sometimes Mac,IoC,... Now always first variant. + *	Fix: inserted "Pnmi." into some pAC->pDriverDescription / Version. + *	Change: memset, memcpy to makros SK_MEMSET, SK_MEMCPY + * + *	Revision 1.11  1998/09/04 17:01:45  mhaveman + *	Added SyncCounter as macro and OID_SKGE_.._NO_DESCR_CTS to + *	OID_SKGE_RX_NO_BUF_CTS. + * + *	Revision 1.10  1998/09/04 14:35:35  mhaveman + *	Added macro counters, that are counted by driver. + * + ****************************************************************************/ + + +#include <config.h> + +#ifdef CONFIG_SK98 + +static const char SysKonnectFileId[] = +	"@(#) $Id: skgepnmi.c,v 1.102 2002/12/16 14:03:24 tschilli Exp $" +	" (C) SysKonnect."; + +#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); + + +/* + * 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_GEPORT	*pPrt; +	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)); +			BRK; +		} + +		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)); +			BRK; +		} +#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 ++) { +			pPrt = &pAC->GIni.GP[PortIndex]; +			pPrt->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 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 */ +SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways 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 as instance a -1 is passed, an array of values is supposed and + *	all instance 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 which stores the mgmt data to be set */ +unsigned int *pLen,	/* Total length of mgmt data */ +SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */ +SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways 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 as instance a -1 is passed, an array of values is supposed and + *	all instance 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 which stores the mgmt data to be set */ +unsigned int *pLen,	/* Total length of mgmt data */ +SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */ +SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways 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 which will store the retrieved data */ +unsigned int *pLen,	/* Length of buffer */ +SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways 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 allways 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 allways 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 +	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 +		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: +				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: +				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 +		/* +		 * 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 +		/* +		 * 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 +		/* +		 * 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 +		/* +		 * 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 initilization 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 + +		/* +		 * Set all counters and timestamps to zero +		 */ +		ResetCounter(pAC, IoC, NetIndex); /* the according NetIndex is required +												as a Parameter of the Event */ +		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 +		/* +		 * 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 (pAC->GIni.GIMacType == 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 +		/* +		 * 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 ((pAC->GIni.GIMacType == 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 +		/* +		 * 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 +		/* +		 * 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->PMdiPairLen[i] > 35) { +				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 to 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 which stores the mgmt data to be set */ +unsigned int *pLen,	/* Total length of mgmt data */ +SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */ +SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways 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,		/* Set action to be performed */ +char *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 allways 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 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 */ +{ +	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 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 */ +{ +	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 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 */ +{ +	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 XMAC 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 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 */ +{ +	unsigned int	LogPortMax; +	unsigned int	LogPortIndex; +	unsigned int	PhysPortMax; +	unsigned int	Limit; +	unsigned int	Offset; +	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); + +	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 XMAC 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: +		case OID_SKGE_STAT_TX: +			switch (pAC->GIni.GIMacType) { +			case SK_MAC_XMAC: +				StatVal = GetStatVal(pAC, IoC, LogPortIndex, +					IdTable[TableIndex].Param, NetIndex); +				break; + +			case SK_MAC_GMAC: +				if (Id == OID_SKGE_STAT_TX) { + +					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, +								   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); +				} +				break; + +			default: +				StatVal = 0; +				break; +			} + +			SK_PNMI_STORE_U64(pBuf + Offset, StatVal); +			break; + +		default: +			StatVal = GetStatVal(pAC, IoC, LogPortIndex, +				IdTable[TableIndex].Param, NetIndex); +			SK_PNMI_STORE_U64(pBuf + Offset, StatVal); +			break; +		} + +		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 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 */ +{ +	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 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 */ +{ +	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 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 */ +{ +	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 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_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 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 */ +{ +	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: +		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: +		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_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_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_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 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 */ +{ +	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 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 */ +{ +	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 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 */ +{ +	unsigned int	PhysPortMax; +	unsigned int	PhysPortIndex; +	unsigned int	LogPortMax; +	unsigned int	LogPortIndex; +	unsigned int	Limit; +	unsigned int	Offset; +	char		Val8; +	int		Ret; +	SK_EVPARA	EventParam; +	SK_U32		Val32; + + +	/* +	 * Calculate instance if wished. MAC index 0 is the virtual +	 * MAC. +	 */ +	PhysPortMax = pAC->GIni.GIMacsFound; +	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax); + +	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */ +		LogPortMax--; +	} + +	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */ +		/* Check instance range */ +		if ((Instance < 1) || (Instance > LogPortMax)) { + +			*pLen = 0; +			return (SK_PNMI_ERR_UNKNOWN_INST); +		} +		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance); +		Limit = LogPortIndex + 1; +	} + +	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */ + +		LogPortIndex = 0; +		Limit = LogPortMax; +	} + +	/* +	 * Perform action +	 */ +	if (Action == SK_PNMI_GET) { + +		/* +		 * Check length +		 */ +		switch (Id) { + +		case OID_SKGE_PMD: +		case OID_SKGE_CONNECTOR: +		case OID_SKGE_LINK_CAP: +		case OID_SKGE_LINK_MODE: +		case OID_SKGE_LINK_MODE_STATUS: +		case OID_SKGE_LINK_STATUS: +		case OID_SKGE_FLOWCTRL_CAP: +		case OID_SKGE_FLOWCTRL_MODE: +		case OID_SKGE_FLOWCTRL_STATUS: +		case OID_SKGE_PHY_OPERATION_CAP: +		case OID_SKGE_PHY_OPERATION_MODE: +		case OID_SKGE_PHY_OPERATION_STATUS: +		case OID_SKGE_SPEED_CAP: +		case OID_SKGE_SPEED_MODE: +		case OID_SKGE_SPEED_STATUS: +			if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) { + +				*pLen = (Limit - LogPortIndex) * +					sizeof(SK_U8); +				return (SK_PNMI_ERR_TOO_SHORT); +			} +			break; + +	case OID_SKGE_MTU: +			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_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 ++) { + +			switch (Id) { + +			case OID_SKGE_PMD: +				*(pBuf + Offset) = pAC->Pnmi.PMD; +				Offset += sizeof(char); +				break; + +			case OID_SKGE_CONNECTOR: +				*(pBuf + Offset) = pAC->Pnmi.Connector; +				Offset += sizeof(char); +				break; + +			case OID_SKGE_LINK_CAP: +				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ +					if (LogPortIndex == 0) { + +						/* Get value for virtual port */ +						VirtualConf(pAC, IoC, Id, pBuf + +							Offset); +					} +					else { +						/* Get value for physical ports */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PLinkCap; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + +						Offset); +					} +					else { +						/* Get value for physical ports */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PLinkModeConf; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + +							Offset); +					} +					else { +						/* Get value for physical port */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = +							CalculateLinkModeStatus(pAC, +								IoC, PhysPortIndex); +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ +					*(pBuf + Offset) = 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, pBuf + +							Offset); +					} +					else { +						/* Get value for physical ports */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = +							CalculateLinkStatus(pAC, +								IoC, PhysPortIndex); +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + +							Offset); +					} +					else { +						/* Get value for physical ports */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PFlowCtrlCap; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + +							Offset); +					} +					else { +						/* Get value for physical port */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PFlowCtrlMode; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + +							Offset); +					} +					else { +						/* Get value for physical port */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PFlowCtrlStatus; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + +							Offset); +					} +					else { +						/* Get value for physical ports */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PMSCap; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + Offset); +					} +					else { +						/* Get value for physical port */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PMSMode; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + Offset); +					} +					else { +						/* Get value for physical port */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PMSStatus; +					} +					Offset += sizeof(char); +				} +				else { + +					*(pBuf + Offset) = 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, pBuf + +							Offset); +					} +					else { +						/* Get value for physical ports */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PLinkSpeedCap; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + Offset); +					} +					else { +						/* Get value for physical port */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PLinkSpeed; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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, pBuf + Offset); +					} +					else { +						/* Get value for physical port */ +						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( +							pAC, LogPortIndex); + +						*(pBuf + Offset) = pAC->GIni.GP[ +							PhysPortIndex].PLinkSpeedUsed; +					} +					Offset += sizeof(char); +				} +				else { /* DualNetMode */ + +					*(pBuf + Offset) = 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(pBuf + Offset, Val32); +				Offset += sizeof(SK_U32); +				break; + +			default: +				SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, +					("MacPrivateConf: Unknown OID should be handled before")); + +				pAC->Pnmi.SirqUpdatedFlag --; +				return (SK_PNMI_ERR_GENERAL); +			} +		} +		*pLen = Offset; +		pAC->Pnmi.SirqUpdatedFlag --; + +		return (SK_PNMI_ERR_OK); +	} + +	/* +	 * From here SET or PRESET action. Check if the passed +	 * buffer length is plausible. +	 */ +	switch (Id) { + +	case OID_SKGE_LINK_MODE: +	case OID_SKGE_FLOWCTRL_MODE: +	case OID_SKGE_PHY_OPERATION_MODE: +	case OID_SKGE_SPEED_MODE: +		if (*pLen < Limit - LogPortIndex) { + +			*pLen = Limit - LogPortIndex; +			return (SK_PNMI_ERR_TOO_SHORT); +		} +		if (*pLen != Limit - LogPortIndex) { + +			*pLen = 0; +			return (SK_PNMI_ERR_BAD_VALUE); +		} +		break; + +	case OID_SKGE_MTU: +		if (*pLen < sizeof(SK_U32)) { + +			*pLen = sizeof(SK_U32); +			return (SK_PNMI_ERR_TOO_SHORT); +		} +		if (*pLen != sizeof(SK_U32)) { + +			*pLen = 0; +			return (SK_PNMI_ERR_BAD_VALUE); +		} +		break; + +    default: +		*pLen = 0; +		return (SK_PNMI_ERR_READ_ONLY); +	} + +	/* +	 * Perform preset or set +	 */ +	Offset = 0; +	for (; LogPortIndex < Limit; LogPortIndex ++) { + +		switch (Id) { + +		case OID_SKGE_LINK_MODE: +			/* Check the value range */ +			Val8 = *(pBuf + Offset); +			if (Val8 == 0) { + +				Offset += sizeof(char); +				break; +			} +			if (Val8 < SK_LMODE_HALF || +				(LogPortIndex != 0 && Val8 > SK_LMODE_AUTOSENSE) || +				(LogPortIndex == 0 && Val8 > SK_LMODE_INDETERMINATED)) { + +				*pLen = 0; +				return (SK_PNMI_ERR_BAD_VALUE); +			} + +			/* The preset ends here */ +			if (Action == SK_PNMI_PRESET) { + +				return (SK_PNMI_ERR_OK); +			} + +			if (LogPortIndex == 0) { + +				/* +				 * The virtual port consists of all currently +				 * active ports. Find them and send an event +				 * with the new link mode to SIRQ. +				 */ +				for (PhysPortIndex = 0; +					PhysPortIndex < PhysPortMax; +					PhysPortIndex ++) { + +					if (!pAC->Pnmi.Port[PhysPortIndex]. +						ActiveFlag) { + +						continue; +					} + +					EventParam.Para32[0] = PhysPortIndex; +					EventParam.Para32[1] = (SK_U32)Val8; +					if (SkGeSirqEvent(pAC, IoC, +						SK_HWEV_SET_LMODE, +						EventParam) > 0) { + +						SK_ERR_LOG(pAC, SK_ERRCL_SW, +							SK_PNMI_ERR043, +							SK_PNMI_ERR043MSG); + +						*pLen = 0; +						return (SK_PNMI_ERR_GENERAL); +					} +				} +			} +			else { +				/* +				 * Send an event with the new link mode to +				 * the SIRQ module. +				 */ +				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS( +					pAC, LogPortIndex); +				EventParam.Para32[1] = (SK_U32)Val8; +				if (SkGeSirqEvent(pAC, IoC, SK_HWEV_SET_LMODE, +					EventParam) > 0) { + +					SK_ERR_LOG(pAC, SK_ERRCL_SW, +						SK_PNMI_ERR043, +						SK_PNMI_ERR043MSG); + +					*pLen = 0; +					return (SK_PNMI_ERR_GENERAL); +				} +			} +			Offset += sizeof(char); +			break; + +		case OID_SKGE_FLOWCTRL_MODE: +			/* Check the value range */ +			Val8 = *(pBuf + Offset); +			if (Val8 == 0) { + +				Offset += sizeof(char); +				break; +			} +			if (Val8 < SK_FLOW_MODE_NONE || +				(LogPortIndex != 0 && Val8 > SK_FLOW_MODE_SYM_OR_REM) || +				(LogPortIndex == 0 && Val8 > SK_FLOW_MODE_INDETERMINATED)) { + +				*pLen = 0; +				return (SK_PNMI_ERR_BAD_VALUE); +			} + +			/* The preset ends here */ +			if (Action == SK_PNMI_PRESET) { + +				return (SK_PNMI_ERR_OK); +			} + +			if (LogPortIndex == 0) { + +				/* +				 * The virtual port consists of all currently +				 * active ports. Find them and send an event +				 * with the new flow control mode to SIRQ. +				 */ +				for (PhysPortIndex = 0; +					PhysPortIndex < PhysPortMax; +					PhysPortIndex ++) { + +					if (!pAC->Pnmi.Port[PhysPortIndex]. +						ActiveFlag) { + +						continue; +					} + +					EventParam.Para32[0] = PhysPortIndex; +					EventParam.Para32[1] = (SK_U32)Val8; +					if (SkGeSirqEvent(pAC, IoC, +						SK_HWEV_SET_FLOWMODE, +						EventParam) > 0) { + +						SK_ERR_LOG(pAC, SK_ERRCL_SW, +							SK_PNMI_ERR044, +							SK_PNMI_ERR044MSG); + +						*pLen = 0; +						return (SK_PNMI_ERR_GENERAL); +					} +				} +			} +			else { +				/* +				 * Send an event with the new flow control +				 * mode to the SIRQ module. +				 */ +				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS( +					pAC, LogPortIndex); +				EventParam.Para32[1] = (SK_U32)Val8; +				if (SkGeSirqEvent(pAC, IoC, +					SK_HWEV_SET_FLOWMODE, EventParam) +					> 0) { + +					SK_ERR_LOG(pAC, SK_ERRCL_SW, +						SK_PNMI_ERR044, +						SK_PNMI_ERR044MSG); + +					*pLen = 0; +					return (SK_PNMI_ERR_GENERAL); +				} +			} +			Offset += sizeof(char); +			break; + +		case OID_SKGE_PHY_OPERATION_MODE : +			/* Check the value range */ +			Val8 = *(pBuf + Offset); +			if (Val8 == 0) { +				/* mode of this port remains unchanged */ +				Offset += sizeof(char); +				break; +			} +			if (Val8 < SK_MS_MODE_AUTO || +				(LogPortIndex != 0 && Val8 > SK_MS_MODE_SLAVE) || +				(LogPortIndex == 0 && Val8 > SK_MS_MODE_INDETERMINATED)) { + +				*pLen = 0; +				return (SK_PNMI_ERR_BAD_VALUE); +			} + +			/* The preset ends here */ +			if (Action == SK_PNMI_PRESET) { + +				return (SK_PNMI_ERR_OK); +			} + +			if (LogPortIndex == 0) { + +				/* +				 * The virtual port consists of all currently +				 * active ports. Find them and send an event +				 * with new master/slave (role) mode to SIRQ. +				 */ +				for (PhysPortIndex = 0; +					PhysPortIndex < PhysPortMax; +					PhysPortIndex ++) { + +					if (!pAC->Pnmi.Port[PhysPortIndex]. +						ActiveFlag) { + +						continue; +					} + +					EventParam.Para32[0] = PhysPortIndex; +					EventParam.Para32[1] = (SK_U32)Val8; +					if (SkGeSirqEvent(pAC, IoC, +						SK_HWEV_SET_ROLE, +						EventParam) > 0) { + +						SK_ERR_LOG(pAC, SK_ERRCL_SW, +							SK_PNMI_ERR042, +							SK_PNMI_ERR042MSG); + +						*pLen = 0; +						return (SK_PNMI_ERR_GENERAL); +					} +				} +			} +			else { +				/* +				 * Send an event with the new master/slave +				 * (role) mode to the SIRQ module. +				 */ +				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS( +					pAC, LogPortIndex); +				EventParam.Para32[1] = (SK_U32)Val8; +				if (SkGeSirqEvent(pAC, IoC, +					SK_HWEV_SET_ROLE, EventParam) > 0) { + +					SK_ERR_LOG(pAC, SK_ERRCL_SW, +						SK_PNMI_ERR042, +						SK_PNMI_ERR042MSG); + +					*pLen = 0; +					return (SK_PNMI_ERR_GENERAL); +				} +			} + +			Offset += sizeof(char); +			break; + +		case OID_SKGE_SPEED_MODE: +			/* Check the value range */ +			Val8 = *(pBuf + Offset); +			if (Val8 == 0) { + +				Offset += sizeof(char); +				break; +			} +			if (Val8 < (SK_LSPEED_AUTO) || +				(LogPortIndex != 0 && Val8 > (SK_LSPEED_1000MBPS)) || +				(LogPortIndex == 0 && Val8 > (SK_LSPEED_INDETERMINATED))) { + +				*pLen = 0; +				return (SK_PNMI_ERR_BAD_VALUE); +			} + +			/* The preset ends here */ +			if (Action == SK_PNMI_PRESET) { + +				return (SK_PNMI_ERR_OK); +			} + +			if (LogPortIndex == 0) { + +				/* +				 * The virtual port consists of all currently +				 * active ports. Find them and send an event +				 * with the new flow control mode to SIRQ. +				 */ +				for (PhysPortIndex = 0; +					PhysPortIndex < PhysPortMax; +					PhysPortIndex ++) { + +					if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + +						continue; +					} + +					EventParam.Para32[0] = PhysPortIndex; +					EventParam.Para32[1] = (SK_U32)Val8; +					if (SkGeSirqEvent(pAC, IoC, +						SK_HWEV_SET_SPEED, +						EventParam) > 0) { + +						SK_ERR_LOG(pAC, SK_ERRCL_SW, +							SK_PNMI_ERR045, +							SK_PNMI_ERR045MSG); + +						*pLen = 0; +						return (SK_PNMI_ERR_GENERAL); +					} +				} +			} +			else { +				/* +				 * Send an event with the new flow control +				 * mode to the SIRQ module. +				 */ +				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS( +					pAC, LogPortIndex); +				EventParam.Para32[1] = (SK_U32)Val8; +				if (SkGeSirqEvent(pAC, IoC, +					SK_HWEV_SET_SPEED, +					EventParam) > 0) { + +					SK_ERR_LOG(pAC, SK_ERRCL_SW, +						SK_PNMI_ERR045, +						SK_PNMI_ERR045MSG); + +					*pLen = 0; +					return (SK_PNMI_ERR_GENERAL); +				} +			} +			Offset += sizeof(char); +			break; + +		case OID_SKGE_MTU : +			/* Check the value range */ +			Val32 = *(SK_U32*)(pBuf + Offset); +			if (Val32 == 0) { +				/* mtu of this port remains unchanged */ +				Offset += sizeof(SK_U32); +				break; +			} +			if (SK_DRIVER_PRESET_MTU(pAC, IoC, NetIndex, Val32) != 0) { +				*pLen = 0; +				return (SK_PNMI_ERR_BAD_VALUE); +			} + +			/* The preset ends here */ +			if (Action == SK_PNMI_PRESET) { +				return (SK_PNMI_ERR_OK); +			} + +			if (SK_DRIVER_SET_MTU(pAC, IoC, NetIndex, Val32) != 0) { +				return (SK_PNMI_ERR_GENERAL); +			} + +			Offset += sizeof(SK_U32); +			break; + +		default: +	    SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, +		("MacPrivateConf: Unknown OID should be handled before set")); + +			*pLen = 0; +			return (SK_PNMI_ERR_GENERAL); +		} +	} + +	return (SK_PNMI_ERR_OK); +} + +/***************************************************************************** + * + * Monitor - OID handler function for RLMT_MONITOR_XXX + * + * Description: + *	Because RLMT currently does not support the monitoring of + *	remote adapter cards, we return always an empty table. + * + * Returns: + *	SK_PNMI_ERR_OK           The request was successfully performed. + *	SK_PNMI_ERR_GENERAL      A general severe internal error occured. + *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain + *	                         the correct data (e.g. a 32bit value is + *	                         needed, but a 16 bit value was passed). + *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid + *	                         value range. + *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set. + *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't + *                               exist (e.g. port instance 3 on a two port + *	                         adapter. + */ +PNMI_STATIC int Monitor( +SK_AC *pAC,		/* Pointer to adapter context */ +SK_IOC IoC,		/* IO context handle */ +int Action,		/* Get/PreSet/Set action */ +SK_U32 Id,		/* Object ID that is to be processed */ +char *pBuf,		/* Buffer 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 */ +{ +	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 to which to mgmt data will be retrieved */ +{ +	unsigned int	PhysPortMax; +	unsigned int	PhysPortIndex; +	SK_U8		Val8; +	SK_BOOL		PortActiveFlag; + + +	*pBuf = 0; +	PortActiveFlag = SK_FALSE; +	PhysPortMax = pAC->GIni.GIMacsFound; + +	for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax; +		PhysPortIndex ++) { + +		/* Check if the physical port is active */ +		if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + +			continue; +		} + +		PortActiveFlag = SK_TRUE; + +		switch (Id) { + +		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 |= pAC->GIni.GP[PhysPortIndex].PLinkCap; +			break; + +		case OID_SKGE_LINK_MODE: +			/* Check if it is the first active port */ +			if (*pBuf == 0) { + +				*pBuf = pAC->GIni.GP[PhysPortIndex].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 != pAC->GIni.GP[PhysPortIndex].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 = pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap; +				continue; +			} + +			/* +			 * From a curious point of view the virtual port +			 * is capable of all found capabilities. +			 */ +			*pBuf |= pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap; +			break; + +		case OID_SKGE_FLOWCTRL_MODE: +			/* Check if it is the first active port */ +			if (*pBuf == 0) { + +				*pBuf = pAC->GIni.GP[PhysPortIndex].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 != pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode) { + +				*pBuf = SK_FLOW_MODE_INDETERMINATED; +			} +			break; + +		case OID_SKGE_FLOWCTRL_STATUS: +			/* Check if it is the first active port */ +			if (*pBuf == 0) { + +				*pBuf = pAC->GIni.GP[PhysPortIndex].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 != pAC->GIni.GP[PhysPortIndex].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 = pAC->GIni.GP[PhysPortIndex].PMSCap; +				continue; +			} + +			/* +			 * From a curious point of view the virtual port +			 * is capable of all found capabilities. +			 */ +			*pBuf |= pAC->GIni.GP[PhysPortIndex].PMSCap; +			break; + +		case OID_SKGE_PHY_OPERATION_MODE: +			/* Check if it is the first active port */ +			if (*pBuf == 0) { + +				*pBuf = pAC->GIni.GP[PhysPortIndex].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 != pAC->GIni.GP[PhysPortIndex].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 = pAC->GIni.GP[PhysPortIndex].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 != pAC->GIni.GP[PhysPortIndex].PMSStatus) { + +				*pBuf = SK_MS_STAT_INDETERMINATED; +			} +			break; + +		case OID_SKGE_SPEED_MODE: +			/* Check if it is the first active port */ +			if (*pBuf == 0) { + +				*pBuf = pAC->GIni.GP[PhysPortIndex].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 != pAC->GIni.GP[PhysPortIndex].PLinkSpeed) { + +				*pBuf = SK_LSPEED_INDETERMINATED; +			} +			break; + +		case OID_SKGE_SPEED_STATUS: +			/* Check if it is the first active port */ +			if (*pBuf == 0) { + +				*pBuf = pAC->GIni.GP[PhysPortIndex].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 != pAC->GIni.GP[PhysPortIndex].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 send a command so that the statistic data will + *	be written to apredefined 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; + +	SK_PNMI_PORT	*pPnmiPrt; +	SK_GEMACFUNC	*pFnMac; + +	MacType = pAC->GIni.GIMacType; + +	/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */ +	if (pAC->GIni.GIMacType == SK_MAC_XMAC) { +		pPnmiPrt = &pAC->Pnmi.BufPort[PhysPortIndex]; +	} +	else { +		pPnmiPrt = &pAC->Pnmi.Port[PhysPortIndex]; +	} + +	pFnMac   = &pAC->GIni.GIFunc; + +	switch (StatIndex) { +	case SK_PNMI_HTX: +	case SK_PNMI_HRX: +		/* 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_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) { +			Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, SK_PNMI_HTX_PMACC); + +			return (Val); +		} + +		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, +									  StatAddr[StatIndex][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 ((pAC->GIni.GP[PhysPortIndex].PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) || +			(pAC->GIni.GP[PhysPortIndex].PLinkModeStatus == SK_LMODE_STAT_FULL)) { + +			LowVal = 0; +			HighVal = 0; +		} +		else { +			/* Otherwise get contents of hardware register. */ +			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex, +										  StatAddr[SK_PNMI_HTX_DEFFERAL][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); + +		switch (MacType) { +		case SK_MAC_GMAC: +			/* For GMAC the SW counter is additionally managed by PNMI */ +			Val += pPnmiPrt->StatRxFrameTooLongCts; +			break; + +		case SK_MAC_XMAC: +			/* +			 * 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; +			break; + +		default: +			break; +		} + +		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 (pAC->GIni.GP[PhysPortIndex].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) { +			/* GM_RXE_FRAG?? */ +			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 (pAC->GIni.GP[PhysPortIndex].PhyType == SK_PHY_BCOM) { +			/* do not read while not initialized (PHY_READ hangs!)*/ +			if (pAC->GIni.GP[PhysPortIndex].PState) { +				PHY_READ(IoC, &pAC->GIni.GP[PhysPortIndex], +						 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 + +	/* 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 +		if (End == BufPad) { +#ifdef DEBUG +			SK_MEMSET(pBuf, (char)(-1), End); +#endif +			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); +	} + +	/* +	 * Perform action +	 */ +	if (Action == SK_PNMI_GET) { + +		/* +		 * 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_QUERY_POWER: +		case OID_PNP_ENABLE_WAKE_UP: +			if (*pLen < sizeof(SK_U32)) { + +				*pLen = sizeof(SK_U32); +				return (SK_PNMI_ERR_TOO_SHORT); +			} +			break; + +		case OID_PNP_SET_POWER: +		case OID_PNP_ADD_WAKE_UP_PATTERN: +		case OID_PNP_REMOVE_WAKE_UP_PATTERN: +			break; + +		default: +			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040, +				SK_PNMI_ERR040MSG); +			*pLen = 0; +			return (SK_PNMI_ERR_GENERAL); +		} + +		/* +		 * 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. */ +			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_OK; +			break; + +		case OID_PNP_ENABLE_WAKE_UP: +			RetCode = SkPowerGetEnableWakeUp(pAC, IoC, pBuf, pLen); +			break; + +		default: +			RetCode = SK_PNMI_ERR_GENERAL; +			break; +		} + +		return (RetCode); +	} + +	/* +	 * From here SET or PRESET action. Check if the passed +	 * buffer length is plausible. +	 */ +	switch (Id) { +	case OID_PNP_SET_POWER: +	case OID_PNP_ENABLE_WAKE_UP: +		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; + +	case OID_PNP_ADD_WAKE_UP_PATTERN: +	case OID_PNP_REMOVE_WAKE_UP_PATTERN: +		if (*pLen < sizeof(SK_PM_PACKET_PATTERN)) { + +			*pLen = 0; +			return (SK_PNMI_ERR_BAD_VALUE); +		} +		break; + +    default: +		*pLen = 0; +		return (SK_PNMI_ERR_READ_ONLY); +	} + +	/* +	 * 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_GENERAL; +	} + +	return (RetCode); +} +#endif /* SK_POWER_MGMT */ + + +/***************************************************************************** + * + * 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 to which the mgmt data will be copied */ +unsigned int *pLen,	/* On call: 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; +	SK_U8		LinkSpeedUsed; + +	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. */ +		LinkSpeedUsed = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed; +		if (LinkSpeedUsed != SK_LSPEED_STAT_10MBPS) { +			pVctData->VctStatus |= SK_PNMI_VCT_NEW_DSP_DATA; +		} +	} + +} /* CheckVctStatus */ + +#endif /* CONFIG_SK98 */ |