changeset 3941:328be6a20f20

FWARC/2007/133 SNMP Domain Service FWARC/2007/138 Updates to PRI structures 6438074 customer requests ability to query power/fan status info from OS 6526169 prtdiag output doesn't have Memory Configuration Information 6531453 sun4v picl needs device labels in the devtree 6534449 Unable to send a domain services message larger than 4K
author venki
date Sat, 31 Mar 2007 18:24:05 -0700
parents 5517729c4306
children c202da1d3c1c
files usr/src/cmd/picl/plugins/common/devtree/picldevtree.c usr/src/cmd/picl/plugins/inc/picldefs.h usr/src/cmd/picl/plugins/sun4v/Makefile usr/src/cmd/picl/plugins/sun4v/include/libpiclsnmp.h usr/src/cmd/picl/plugins/sun4v/include/picloids.h usr/src/cmd/picl/plugins/sun4v/lib/Makefile usr/src/cmd/picl/plugins/sun4v/lib/snmp/Makefile usr/src/cmd/picl/plugins/sun4v/lib/snmp/asn1.c usr/src/cmd/picl/plugins/sun4v/lib/snmp/asn1.h usr/src/cmd/picl/plugins/sun4v/lib/snmp/debug.c usr/src/cmd/picl/plugins/sun4v/lib/snmp/debug.h usr/src/cmd/picl/plugins/sun4v/lib/snmp/pdu.c usr/src/cmd/picl/plugins/sun4v/lib/snmp/pdu.h usr/src/cmd/picl/plugins/sun4v/lib/snmp/snmplib.c usr/src/cmd/picl/plugins/sun4v/lib/snmp/snmplib.h usr/src/cmd/picl/plugins/sun4v/mdesc/init.c usr/src/cmd/picl/plugins/sun4v/pri/Makefile usr/src/cmd/picl/plugins/sun4v/pri/init.c usr/src/cmd/picl/plugins/sun4v/pri/io_dev_label.c usr/src/cmd/picl/plugins/sun4v/pri/mem_prop_update.c usr/src/cmd/picl/plugins/sun4v/pri/priplugin.c usr/src/cmd/picl/plugins/sun4v/pri/priplugin.h usr/src/cmd/picl/plugins/sun4v/snmp/Makefile usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.c usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.h usr/src/lib/libprtdiag/Makefile.com usr/src/lib/libprtdiag/common/display_sun4v.c usr/src/lib/libprtdiag/common/pdevinfo_sun4v.c usr/src/pkgdefs/SUNWhea/prototype_sparc usr/src/pkgdefs/SUNWldomr.v/prototype_sparc usr/src/pkgdefs/SUNWpiclu/prototype_sparc usr/src/uts/sparc/os/name_to_major usr/src/uts/sun4v/Makefile.files usr/src/uts/sun4v/Makefile.sun4v.shared usr/src/uts/sun4v/ds_snmp/Makefile usr/src/uts/sun4v/io/ds.c usr/src/uts/sun4v/io/ds_pri.c usr/src/uts/sun4v/io/ds_snmp.c usr/src/uts/sun4v/io/ds_snmp.conf usr/src/uts/sun4v/sys/Makefile usr/src/uts/sun4v/sys/ds_snmp.h
diffstat 41 files changed, 10218 insertions(+), 201 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/picl/plugins/common/devtree/picldevtree.c	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/cmd/picl/plugins/common/devtree/picldevtree.c	Sat Mar 31 18:24:05 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -3212,6 +3212,9 @@
 	if (strcmp(mach_name, "sun4u") == 0) {
 		builtin_map_ptr = sun4u_map;
 		builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t);
+	} else if (strcmp(mach_name, "sun4v") == 0) {
+		builtin_map_ptr = sun4u_map;
+		builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t);
 	} else if (strcmp(mach_name, "i86pc") == 0) {
 		builtin_map_ptr = i86pc_map;
 		builtin_map_size = sizeof (i86pc_map) / sizeof (builtin_map_t);
--- a/usr/src/cmd/picl/plugins/inc/picldefs.h	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/cmd/picl/plugins/inc/picldefs.h	Sat Mar 31 18:24:05 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -110,6 +110,27 @@
 #define	PICL_CLASS_CHASSIS_SERIAL_NUM	"chassis-serial-number"
 
 /*
+ * Sun4v platforms do not create /frutree; instead they create
+ * the /physical-platform subtree. The following is the list of
+ * additional PICL classes that may be present in /physical-platform
+ */
+#define	PICL_CLASS_ALARM		"alarm"
+#define	PICL_CLASS_BACKPLANE		"backplane"
+#define	PICL_CLASS_BATTERY		"battery"
+#define	PICL_CLASS_CHASSIS		"chassis"
+#define	PICL_CLASS_CONTAINER		"container"
+#define	PICL_CLASS_MODULE		"module"
+#define	PICL_CLASS_OTHER		"other"
+#define	PICL_CLASS_POWERSUPPLY		"power-supply"
+#define	PICL_CLASS_RPM_INDICATOR	"rpm-indicator"
+#define	PICL_CLASS_RPM_SENSOR		"rpm-sensor"
+#define	PICL_CLASS_PRESENCE_INDICATOR	"presence-indicator"
+#define	PICL_CLASS_INDICATOR		"indicator"
+#define	PICL_CLASS_SENSOR		"sensor"
+#define	PICL_CLASS_STACK		"stack"
+#define	PICL_CLASS_UNKNOWN		"unknown"
+
+/*
  * Solaris driver property names
  */
 #define	PICL_PROP_INSTANCE		"instance"
@@ -203,6 +224,25 @@
 #define	PICL_UNITADDR_LEN_MAX		256
 
 /*
+ * Additional PICL properties for Sun4v platforms
+ */
+#define	PICL_PROP_BATTERY_STATUS		"BatteryStatus"
+#define	PICL_PROP_EXPECTED			"Expected"
+#define	PICL_PROP_FW_REVISION			"FW-version"
+#define	PICL_PROP_HW_REVISION			"HW-version"
+#define	PICL_PROP_IS_REPLACEABLE		"Replaceable"
+#define	PICL_PROP_IS_HOT_SWAPPABLE		"HotSwappable"
+#define	PICL_PROP_IS_FRU			"FRU"
+#define	PICL_PROP_PHYS_DESCRIPTION		"Description"
+#define	PICL_PROP_SPEED				"Speed"
+#define	PICL_PROP_MFG_NAME			"MfgName"
+#define	PICL_PROP_MODEL_NAME			"ModelName"
+#define	PICL_PROP_SENSOR_VALUE			"SensorValue"
+#define	PICL_PROP_BASE_UNITS			"BaseUnits"
+#define	PICL_PROP_EXPONENT			"Exponent"
+#define	PICL_PROP_RATE_UNITS			"RateUnits"
+
+/*
  * Various threshold property names
  */
 #define	PICL_PROP_LOW_POWER_OFF			"LowPowerOffThreshold"
--- a/usr/src/cmd/picl/plugins/sun4v/Makefile	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/cmd/picl/plugins/sun4v/Makefile	Sat Mar 31 18:24:05 2007 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -19,27 +18,35 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
 #
 # cmd/picl/plugins/sun4v/Makefile
 #
 
-SUBDIRS= mdesc ontario
+SUBDIRS= lib .WAIT snmp .WAIT mdesc pri ontario
+
+MSGSUBDIRS=	snmp
 
 all :=		TARGET= all
 install :=	TARGET= install
 clean :=	TARGET= clean
 clobber :=	TARGET= clobber
 lint :=		TARGET= lint
+_msg :=		TARGET= _msg
 
 .KEEP_STATE:
 
 all install clean clobber lint : $(SUBDIRS)
 
+_msg:	$(MSGSUBDIRS)
+
 $(SUBDIRS): FRC
 	@cd $@; pwd; $(MAKE) $(TARGET)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/include/libpiclsnmp.h	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,60 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_LIBPICLSNMP_H
+#define	_LIBPICLSNMP_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Opaque picl snmp handle
+ */
+typedef void	*picl_snmphdl_t;
+
+/*
+ * Exported interfaces
+ */
+extern picl_snmphdl_t snmp_init(void);
+extern void snmp_fini(picl_snmphdl_t);
+
+extern int snmp_reinit(picl_snmphdl_t hdl, int clr_linkreset);
+extern void snmp_register_group(picl_snmphdl_t, char *, int, int);
+
+extern int snmp_get_int(picl_snmphdl_t, char *, int, int *, int *);
+extern int snmp_get_str(picl_snmphdl_t, char *, int, char **, int *);
+extern int snmp_get_bitstr(picl_snmphdl_t, char *, int, uchar_t **,
+	    uint_t *, int *);
+extern int snmp_get_nextrow(picl_snmphdl_t, char *, int, int *, int *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBPICLSNMP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/include/picloids.h	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,355 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_PICLOIDS_H
+#define	_PICLOIDS_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * IETF OIDs (not all are used by PICL)
+ */
+#define	OID_ISO				"1"
+#define	OID_ORG				OID_ISO ".3"
+#define	OID_DOD				OID_ORG ".6"
+#define	OID_INTERNET			OID_DOD ".1"
+
+#define	OID_PRIVATE			OID_INTERNET ".4"
+#define	OID_ENTERPRISES			OID_PRIVATE ".1"
+#define	OID_SUN				OID_ENTERPRISES ".42"
+
+#define	OID_MGMT			OID_INTERNET ".2"
+#define	OID_MIB2			OID_MGMT ".1"
+#define	OID_entityMIB			OID_MIB2 ".47"
+#define	OID_entityMIBObjects		OID_entityMIB ".1"
+
+#define	OID_entityPhysical		OID_entityMIBObjects ".1"
+#define	OID_entPhysicalTable		OID_entityPhysical ".1"
+#define	OID_entPhysicalEntry		OID_entPhysicalTable ".1"
+
+#define	OID_entPhysicalIndex		OID_entPhysicalEntry ".1"
+#define	OID_entPhysicalDescr		OID_entPhysicalEntry ".2"
+#define	OID_entPhysicalVendorType	OID_entPhysicalEntry ".3"
+#define	OID_entPhysicalContainedIn	OID_entPhysicalEntry ".4"
+#define	OID_entPhysicalClass		OID_entPhysicalEntry ".5"
+#define	OID_entPhysicalParentRelPos	OID_entPhysicalEntry ".6"
+#define	OID_entPhysicalName		OID_entPhysicalEntry ".7"
+#define	OID_entPhysicalHardwareRev	OID_entPhysicalEntry ".8"
+#define	OID_entPhysicalFirmwareRev	OID_entPhysicalEntry ".9"
+#define	OID_entPhysicalSoftwareRev	OID_entPhysicalEntry ".10"
+#define	OID_entPhysicalSerialNum	OID_entPhysicalEntry ".11"
+#define	OID_entPhysicalMfgName		OID_entPhysicalEntry ".12"
+#define	OID_entPhysicalModelName	OID_entPhysicalEntry ".13"
+#define	OID_entPhysicalAlias		OID_entPhysicalEntry ".14"
+#define	OID_entPhysicalAssetID		OID_entPhysicalEntry ".15"
+#define	OID_entPhysicalIsFRU		OID_entPhysicalEntry ".16"
+
+/*
+ * Conceptual row change time for handling hotplug/hotswap events
+ */
+#define	OID_entityGeneral		OID_entityMIBObjects ".4"
+#define	OID_entLastChangeTime		OID_entityGeneral ".1"
+
+/*
+ * Sun Platform MIB OIDs used by PICL
+ */
+#define	OID_products			OID_SUN ".2"
+#define	OID_sunFire			OID_products ".70"
+#define	OID_sunPlatMIB			OID_sunFire ".101"
+#define	OID_sunPlatMIBObjects		OID_sunPlatMIB ".1"
+#define	OID_sunPlatMIBPhysicalObjects	OID_sunPlatMIBObjects ".1"
+
+/*
+ * Equipment Table
+ */
+#define	OID_sunPlatEquipmentTable	OID_sunPlatMIBPhysicalObjects ".2"
+#define	OID_sunPlatEquipmentEntry	OID_sunPlatEquipmentTable ".1"
+#define	OID_sunPlatEquipmentOperationalState	\
+					OID_sunPlatEquipmentEntry ".2"
+
+/*
+ * Equipment Holder Table
+ */
+#define	OID_sunPlatEquipmentHolderTable	OID_sunPlatMIBPhysicalObjects ".3"
+#define	OID_sunPlatEquipmentHolderEntry	OID_sunPlatEquipmentHolderTable ".1"
+#define	OID_sunPlatEquipmentHolderAcceptableTypes	\
+					OID_sunPlatEquipmentHolderEntry ".2"
+
+/*
+ * Circuit Pack Table
+ */
+#define	OID_sunPlatCircuitPackTable	OID_sunPlatMIBPhysicalObjects ".4"
+#define	OID_sunPlatCircuitPackEntry	OID_sunPlatCircuitPackTable ".1"
+#define	OID_sunPlatCircuitPackReplaceable	\
+					OID_sunPlatCircuitPackEntry ".3"
+#define	OID_sunPlatCircuitPackHotSwappable	\
+					OID_sunPlatCircuitPackEntry ".4"
+
+/*
+ * Physical Class Table
+ */
+#define	OID_sunPlatPhysicalTable	OID_sunPlatMIBPhysicalObjects ".5"
+#define	OID_sunPlatPhysicalEntry	OID_sunPlatPhysicalTable ".1"
+#define	OID_sunPlatPhysicalClass	OID_sunPlatPhysicalEntry ".1"
+
+/*
+ * Sensor Table
+ */
+#define	OID_sunPlatSensorTable		OID_sunPlatMIBPhysicalObjects ".6"
+#define	OID_sunPlatSensorEntry		OID_sunPlatSensorTable ".1"
+#define	OID_sunPlatSensorClass		OID_sunPlatSensorEntry ".1"
+#define	OID_sunPlatSensorType		OID_sunPlatSensorEntry ".2"
+
+/*
+ * Binary Sensor Table
+ */
+#define	OID_sunPlatBinarySensorTable	OID_sunPlatMIBPhysicalObjects ".7"
+#define	OID_sunPlatBinarySensorEntry	OID_sunPlatBinarySensorTable ".1"
+
+#define	OID_sunPlatBinarySensorCurrent	OID_sunPlatBinarySensorEntry ".1"
+#define	OID_sunPlatBinarySensorExpected	OID_sunPlatBinarySensorEntry ".2"
+#define	OID_sunPlatBinarySensorInterpretTrue	\
+					OID_sunPlatBinarySensorEntry ".3"
+#define	OID_sunPlatBinarySensorInterpretFalse	\
+					OID_sunPlatBinarySensorEntry ".4"
+
+/*
+ * Numeric Sensor Table
+ */
+#define	OID_sunPlatNumericSensorTable	OID_sunPlatMIBPhysicalObjects ".8"
+#define	OID_sunPlatNumericSensorEntry	OID_sunPlatNumericSensorTable ".1"
+#define	OID_sunPlatNumericSensorCurrent	OID_sunPlatNumericSensorEntry ".4"
+#define	OID_sunPlatNumericSensorBaseUnits	\
+					OID_sunPlatNumericSensorEntry ".1"
+#define	OID_sunPlatNumericSensorExponent	\
+					OID_sunPlatNumericSensorEntry ".2"
+#define	OID_sunPlatNumericSensorRateUnits	\
+					OID_sunPlatNumericSensorEntry ".3"
+#define	OID_sunPlatNumericSensorLowerThresholdNonCritical	\
+					OID_sunPlatNumericSensorEntry ".8"
+#define	OID_sunPlatNumericSensorUpperThresholdNonCritical	\
+					OID_sunPlatNumericSensorEntry ".9"
+#define	OID_sunPlatNumericSensorLowerThresholdCritical	\
+					OID_sunPlatNumericSensorEntry ".10"
+#define	OID_sunPlatNumericSensorUpperThresholdCritical	\
+					OID_sunPlatNumericSensorEntry ".11"
+#define	OID_sunPlatNumericSensorLowerThresholdFatal	\
+					OID_sunPlatNumericSensorEntry ".12"
+#define	OID_sunPlatNumericSensorUpperThresholdFatal	\
+					OID_sunPlatNumericSensorEntry ".13"
+#define	OID_sunPlatNumericSensorEnabledThresholds	\
+					OID_sunPlatNumericSensorEntry ".15"
+
+/*
+ * Alarm Table
+ */
+#define	OID_sunPlatAlarmTable		OID_sunPlatMIBPhysicalObjects ".12"
+#define	OID_sunPlatAlarmEntry		OID_sunPlatAlarmTable ".1"
+#define	OID_sunPlatAlarmType		OID_sunPlatAlarmEntry ".1"
+#define	OID_sunPlatAlarmState		OID_sunPlatAlarmEntry ".2"
+
+/*
+ * Power Supply Table
+ */
+#define	OID_sunPlatPowerSupplyTable	OID_sunPlatMIBPhysicalObjects ".14"
+#define	OID_sunPlatPowerSupplyEntry	OID_sunPlatPowerSupplyTable ".1"
+#define	OID_sunPlatPowerSupplyClass	OID_sunPlatPowerSupplyEntry ".1"
+
+/*
+ * Battery Table
+ */
+#define	OID_sunPlatBatteryTable		OID_sunPlatMIBPhysicalObjects ".15"
+#define	OID_sunPlatBatteryEntry		OID_sunPlatBatteryTable ".1"
+#define	OID_sunPlatBatteryStatus	OID_sunPlatBatteryEntry ".1"
+
+/*
+ * Integer enumeration classes used by PICL
+ */
+typedef enum {
+	ST_TRUE = 1,
+	ST_FALSE = 2
+} snmp_truthval_t;
+
+/*
+ * Note that the truth values could be much longer than the length
+ * of the strings "true" or "false", since we actuallly interpret them
+ * using InterpretTrue and InterpretFalse values in the MIB. Currently
+ * we limit them to be 32 (see MAX_TRUTHVAL_LEN definition below)
+ */
+#define	STR_ST_TRUE	"true"
+#define	STR_ST_FALSE	"false"
+
+/* entPhysicalClass */
+typedef enum {
+	SPC_OTHER = 1,
+	SPC_UNKNOWN = 2,
+	SPC_CHASSIS = 3,
+	SPC_BACKPLANE = 4,
+	SPC_CONTAINER = 5,
+	SPC_POWERSUPPLY = 6,
+	SPC_FAN = 7,
+	SPC_SENSOR = 8,
+	SPC_MODULE = 9,
+	SPC_PORT = 10,
+	SPC_STACK = 11
+} snmp_physical_class_t;
+
+/* sunPlatEquipmentOperationalState */
+typedef enum {
+	SSOS_DISABLED = 1,
+	SSOS_ENABLED = 2
+} snmp_sunplat_op_state_t;
+
+/*
+ * Update MAX_OPSTATE_LEN below if these strings are changed
+ */
+#define	STR_SSOS_DISABLED	"disabled"
+#define	STR_SSOS_ENABLED	"enabled"
+
+/* sunPlatPhysicalClass */
+typedef enum {
+	SSPC_OTHER = 1,
+	SSPC_ALARM = 2,
+	SSPC_WATCHDOG = 3
+} snmp_sunplat_phys_class_t;
+
+/* sunPlatSensorClass */
+typedef enum {
+	SSSC_BINARY = 1,
+	SSSC_NUMERIC = 2,
+	SSSC_DISCRETE = 3
+} snmp_sunplat_sensor_class_t;
+
+/* sunPlatSensorType */
+typedef enum {
+	SSST_OTHER = 1,
+	SSST_UNKNOWN = 2,
+	SSST_TEMPERATURE = 3,
+	SSST_VOLTAGE = 4,
+	SSST_CURRENT = 5,
+	SSST_TACHOMETER = 6,
+	SSST_COUNTER = 7,
+	SSST_SWITCH = 8,
+	SSST_LOCK = 9,
+	SSST_HUMIDITY = 10,
+	SSST_SMOKE_DETECTION = 11,
+	SSST_PRESENCE = 12,
+	SSST_AIRFLOW = 13
+} snmp_sunplat_sensor_type_t;
+
+/* sunPlatAlarmType */
+typedef enum {
+	SSAT_OTHER = 1,
+	SSAT_AUDIBLE = 2,
+	SSAT_VISIBLE = 3,
+	SSAT_MOTION = 4,
+	SSAT_SWITCH = 5
+} snmp_sunplat_alarm_type_t;
+
+/* sunPlatAlarmState */
+typedef enum {
+	SSAS_UNKNOWN = 1,
+	SSAS_OFF = 2,
+	SSAS_STEADY = 3,
+	SSAS_ALTERNATING = 4
+} snmp_sunplat_alarm_state_t;
+
+/*
+ * Update MAX_ALARMSTATE_LEN below if these strings are changed
+ */
+#define	STR_SSAS_UNKNOWN	"unknown"
+#define	STR_SSAS_OFF		"off"
+#define	STR_SSAS_STEADY		"steady"
+#define	STR_SSAS_ALTERNATING	"alternating"
+
+/*
+ * Bit masks for the sunPlatNumericSensorEnabledThresholds
+ */
+#define	LOWER_NON_CRITICAL	0x80
+#define	UPPER_NON_CRITICAL	0x40
+#define	LOWER_CRITICAL		0x20
+#define	UPPER_CRITICAL		0x10
+#define	LOWER_FATAL		0x08
+#define	UPPER_FATAL		0x04
+
+/*
+ * sunPlatPowerSupplyClass
+ */
+typedef enum {
+	SSPSC_OTHER = 1,
+	SSPSC_POWERSUPPLY = 2,
+	SSPSC_BATTERY = 3
+} snmp_sunplat_power_supply_class_t;
+
+/*
+ * sunPlatBatteryStatus
+ */
+typedef enum {
+	SSBS_OTHER = 1,
+	SSBS_UNKNOWN = 2,
+	SSBS_FULLYCHARGED = 3,
+	SSBS_LOW = 4,
+	SSBS_CRITICAL = 5,
+	SSBS_CHARGING = 6,
+	SSBS_CHARGING_AND_LOW = 7,
+	SSBS_CHARGING_AND_HIGH = 8,
+	SSBS_CHARGING_AND_CRITICAL = 9,
+	SSBS_UNDEFINED = 10,
+	SSBS_PARTIALLY_CHARGED = 11
+} snmp_sunplat_battery_status_t;
+
+/*
+ * Update MAX_BATTERYSTATUS_LEN below if these strings are changed
+ */
+#define	STR_SSBS_OTHER			"Other"
+#define	STR_SSBS_UNKNOWN		"Unknown"
+#define	STR_SSBS_FULLYCHARGED		"Fully Charged"
+#define	STR_SSBS_LOW			"Low"
+#define	STR_SSBS_CRITICAL		"Critical"
+#define	STR_SSBS_CHARGING		"Charging"
+#define	STR_SSBS_CHARGING_AND_LOW	"Charging and Low"
+#define	STR_SSBS_CHARGING_AND_HIGH	"Charging and High"
+#define	STR_SSBS_CHARGING_AND_CRITICAL	"Charging and Critical"
+#define	STR_SSBS_UNDEFINED		"Undefined"
+#define	STR_SSBS_PARTIALLY_CHARGED	"Partially Charged"
+
+/*
+ * Max limits of all volatiles
+ */
+#define	MAX_OPSTATE_LEN			10
+#define	MAX_ALARMSTATE_LEN		12
+#define	MAX_TRUTHVAL_LEN		32
+#define	MAX_BATTERYSTATUS_LEN		32
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _PICLOIDS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/Makefile	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+# cmd/picl/plugins/sun4v/lib/Makefile
+#
+
+SUBDIRS=	snmp .WAIT
+
+all :=		TARGET= all
+install :=	TARGET= install
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+lint :=		TARGET= lint
+
+.KEEP_STATE:
+
+all install clean clobber lint : $(SUBDIRS)
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/snmp/Makefile	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,108 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+# cmd/picl/plugins/sun4v/lib/snmp/Makefile
+#
+
+LIBRARY=	libpiclsnmp.a
+VERS=		.1
+OBJECTS=	snmplib.o pdu.o asn1.o debug.o
+
+# include library definitions
+include $(SRC)/Makefile.psm
+include $(SRC)/lib/Makefile.lib
+
+ROOT_PLATFORM = $(USR_PLAT_DIR)/sun4v
+
+include $(SRC)/cmd/picl/plugins/Makefile.com
+
+SRCS=		$(OBJECTS:%.o=%.c)
+
+LIBS=		$(DYNLIB)
+
+ROOTLIBDIR      = $(ROOT_PLATFORM)/lib
+ROOTLIBDIR      := OWNER = root
+ROOTLIBDIR      := GROUP = sys
+
+CLEANFILES=	$(LINTOUT) $(LINTLIB)
+CLOBBERFILES += $(LIBLINKS)
+
+CPPFLAGS +=	-I. -I../../include -I$(SRC)/uts/sun4v
+CPPFLAGS +=	-D_REENTRANT
+
+#
+# Be careful when enabling SNMP_DEBUG; the debug log can quickly grow
+# very very large. Never run cycle stress test with SNMP_DEBUG enabled!
+#
+#CPPFLAGS +=	-DSNMP_DEBUG
+
+#
+# Do NOT uncomment the following two lines, unless you want to test
+# the behavior of the library with an SNMP agent over network.
+#
+#CPPFLAGS +=	-DUSE_SOCKETS
+#LDLIBS +=	-lsocket -lnsl
+
+CFLAGS +=	$(CCVERBOSE) -DBIG_ENDIAN
+LDLIBS +=	-lc -lnvpair
+
+# It's OK not to build debug.c except when SNMP_DEBUG is enabled.
+# Don't let lint complain about it.
+#
+ALWAYS_LINT_DEFS +=	-erroff=E_EMPTY_TRANSLATION_UNIT
+
+.KEEP_STATE:
+
+
+SUBDIRS=
+
+all :=		TARGET= all
+install :=	TARGET= install
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+lint :=		TARGET= lint
+
+all:  $(DYNLIB) $(LIBLINKS)
+
+install:	$(ROOTLIBDIR) all $(ROOTLIBS) $(ROOTLINKS)
+
+$(LIBLINKS):	FRC
+	$(RM) $@; $(SYMLINK) $(DYNLIB) $@
+
+# include library targets
+include $(SRC)/cmd/picl/plugins/Makefile.targ
+include $(SRC)/lib/Makefile.targ
+
+lint :
+	$(LINT.c) -m $(SRCS)
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/snmp/asn1.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,760 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * ASN.1 encoding related routines
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "asn1.h"
+#include "pdu.h"
+#include "debug.h"
+
+/*
+ * This routine builds a 'SEQUENCE OF' ASN.1 object in the buffer
+ * using the 'id' and 'length' supplied. This is probably the place
+ * where using "reverse" asn encoding will help.
+ */
+uchar_t *
+asn_build_sequence(uchar_t *buf, size_t *bufsz_p, uchar_t id, size_t length)
+{
+	/*
+	 * When rebuilding sequence (which we do many times), we'll
+	 * simply pass NULL to bufsz_p to skip the error check.
+	 */
+	if ((bufsz_p) && (*bufsz_p < 4))
+		return (NULL);
+
+	buf[0] = id;
+	buf[1] = (uchar_t)(ASN_LONG_LEN | 0x02);	/* following 2 octets */
+	buf[2] = (uchar_t)((length >> 8) & 0xff);
+	buf[3] = (uchar_t)(length & 0xff);
+
+	if (bufsz_p)
+		*bufsz_p -= 4;
+
+	LOGASNSEQ(buf, 4);
+
+	return (buf + 4);
+}
+
+/*
+ * The next two routines, asn_build_header() and asn_build_length(), build
+ * the header and length for an arbitrary object type into the buffer. The
+ * length of the object is encoded using as few length octets as possible.
+ */
+uchar_t *
+asn_build_header(uchar_t *buf, size_t *bufsz_p, uchar_t id, size_t length)
+{
+	if (*bufsz_p < 1)
+		return (NULL);
+
+	buf[0] = id;
+	(*bufsz_p)--;
+
+	return (asn_build_length(buf + 1, bufsz_p, length));
+}
+uchar_t *
+asn_build_length(uchar_t *buf, size_t *bufsz_p, size_t length)
+{
+	if (length < 0x80) {
+		if (*bufsz_p < 1)
+			return (NULL);
+		buf[0] = (uchar_t)length;
+		(*bufsz_p)--;
+
+		LOGASNLENGTH(buf, 1);
+
+		return (buf + 1);
+
+	} else if (length <= 0xFF) {
+		if (*bufsz_p < 2)
+			return (NULL);
+		buf[0] = (uchar_t)(ASN_LONG_LEN | 0x01);
+		buf[1] = (uchar_t)length;
+		*bufsz_p -= 2;
+
+		LOGASNLENGTH(buf, 2);
+
+		return (buf + 2);
+
+	} else {
+		if (*bufsz_p < 3)
+			return (NULL);
+
+		buf[0] = (uchar_t)(ASN_LONG_LEN | 0x02);
+		buf[1] = (uchar_t)((length >> 8) & 0xff);
+		buf[2] = (uchar_t)(length & 0xff);
+		*bufsz_p -= 3;
+
+		LOGASNLENGTH(buf, 3);
+
+		return (buf + 3);
+	}
+}
+/*
+ * Builds an ASN.1 encoded integer in the buffer using as few octets
+ * as possible.
+ */
+uchar_t *
+asn_build_int(uchar_t *buf, size_t *bufsz_p, uchar_t id, int val)
+{
+	uint_t	uival;
+	int	ival, i;
+	short	sval;
+	char	cval;
+
+	size_t	valsz;
+	uchar_t	*p, *valp;
+
+	/*
+	 * We need to "pack" the integer before sending it, so determine
+	 * the minimum number of bytes in which we can pack the integer
+	 */
+	uival = ((uint_t)val >> BUILD_INT_SHIFT) & BUILD_INT_MASK;
+	ival = val;
+	sval = (short)val;	/* yes, loss of data intended */
+	cval = (char)val;	/* yes, loss of data intended */
+
+	if (val == (int)cval)
+		valsz = 1;
+	else if (val == (int)sval)
+		valsz = 2;
+	else if (uival == BUILD_INT_MASK || uival == 0)
+		valsz = 3;
+	else
+		valsz = 4;
+
+	/*
+	 * Prepare the ASN.1 header for the integer
+	 */
+	if ((p = asn_build_header(buf, bufsz_p, id, valsz)) == NULL)
+		return (NULL);
+
+	/*
+	 * If we have enough space left, encode the integer
+	 */
+	if (*bufsz_p < valsz)
+		return (NULL);
+	else {
+		valp = (uchar_t *)&ival;
+		for (i = 0; i < valsz; i++)
+			p[i] = valp[sizeof (int) - valsz + i];
+
+		*bufsz_p -= valsz;
+
+		LOGASNINT(buf, p + valsz - buf);
+
+		return (p + valsz);
+	}
+}
+/*
+ * Builds an ASN.1 encoded octet string in the buffer. The source string
+ * need not be null-terminated.
+ */
+uchar_t *
+asn_build_string(uchar_t *buf, size_t *bufsz_p, uchar_t id, uchar_t *str,
+    size_t slen)
+{
+	uchar_t	*p;
+
+	if ((p = asn_build_header(buf, bufsz_p, id, slen)) == NULL)
+		return (NULL);
+
+	if (*bufsz_p < slen)
+		return (NULL);
+	else {
+	    if (str) {
+		    (void) memcpy(p, str, slen);
+	    } else {
+		    (void) memset(p, 0, slen);
+	    }
+
+	    *bufsz_p -= slen;
+
+	    LOGASNOCTSTR(buf, p + slen - buf);
+
+	    return (p + slen);
+	}
+}
+
+/*
+ * Builds an Object Identifier into the buffer according to the OID
+ * packing and encoding rules.
+ */
+uchar_t *
+asn_build_objid(uchar_t *buf, size_t *bufsz_p, uchar_t id, void *oidp,
+    size_t n_subids)
+{
+	oid	*objid = oidp;
+	size_t	oid_asnlen;
+	oid	subid, first_subid;
+	uchar_t	subid_len[MAX_SUBIDS_IN_OID];
+	uchar_t	*p;
+	int	i, ndx;
+
+	/*
+	 * Eliminate invalid cases
+	 */
+	if (n_subids < MIN_SUBIDS_IN_OID || n_subids > MAX_SUBIDS_IN_OID)
+		return (NULL);
+	if ((objid[0] > 2) || (objid[0] < 2 && objid[1] >= 40))
+		return (NULL);
+
+	/*
+	 * The BER encoding rule for the ASN.1 Object Identifier states
+	 * that after packing the first two subids into one, each subsequent
+	 * component is considered as the next subid. Each subidentifier is
+	 * then encoded as a non-negative integer using as few 7-bit blocks
+	 * as possible. The blocks are packed in octets with the first bit of
+	 * each octet equal to 1, except for the last octet of each subid.
+	 */
+	oid_asnlen = 0;
+	for (i = 0, ndx = 0; i < n_subids; i++, ndx++) {
+		if (i == 0) {
+			/*
+			 * The packing formula for the first two subids
+			 * of an OID is given by Z = (X * 40) + Y
+			 */
+			subid = objid[0] * 40 + objid[1];
+			first_subid = subid;
+			i++;	/* done with both subids 0 and 1 */
+		} else {
+			subid = objid[i];
+		}
+
+		if (subid < (oid) 0x80)
+			subid_len[ndx] = 1;
+		else if (subid < (oid) 0x4000)
+			subid_len[ndx] = 2;
+		else if (subid < (oid) 0x200000)
+			subid_len[ndx] = 3;
+		else if (subid < (oid) 0x10000000)
+			subid_len[ndx] = 4;
+		else {
+			subid_len[ndx] = 5;
+		}
+
+		oid_asnlen += subid_len[ndx];
+	}
+
+	if ((p = asn_build_header(buf, bufsz_p, id, oid_asnlen)) == NULL)
+		return (NULL);
+
+	if (*bufsz_p < oid_asnlen)
+		return (NULL);
+
+	/*
+	 * Store the encoded OID
+	 */
+	for (i = 0, ndx = 0; i < n_subids; i++, ndx++) {
+		if (i == 0) {
+			subid = first_subid;
+			i++;
+		} else {
+			subid = objid[i];
+		}
+
+		switch (subid_len[ndx]) {
+		case 1:
+			*p++ = (uchar_t)subid;
+			break;
+
+		case 2:
+			*p++ = (uchar_t)((subid >> 7) | 0x80);
+			*p++ = (uchar_t)(subid & 0x7f);
+			break;
+
+		case 3:
+			*p++ = (uchar_t)((subid >> 14) | 0x80);
+			*p++ = (uchar_t)(((subid >> 7) & 0x7f) | 0x80);
+			*p++ = (uchar_t)(subid & 0x7f);
+			break;
+
+		case 4:
+			*p++ = (uchar_t)((subid >> 21) | 0x80);
+			*p++ = (uchar_t)(((subid >> 14) & 0x7f) | 0x80);
+			*p++ = (uchar_t)(((subid >> 7) & 0x7f) | 0x80);
+			*p++ = (uchar_t)(subid & 0x7f);
+			break;
+
+		case 5:
+			*p++ = (uchar_t)((subid >> 28) | 0x80);
+			*p++ = (uchar_t)(((subid >> 21) & 0x7f) | 0x80);
+			*p++ = (uchar_t)(((subid >> 14) & 0x7f) | 0x80);
+			*p++ = (uchar_t)(((subid >> 7) & 0x7f) | 0x80);
+			*p++ = (uchar_t)(subid & 0x7f);
+			break;
+		}
+	}
+
+	*bufsz_p -= oid_asnlen;
+
+	LOGASNOID(buf, p - buf);
+
+	return (p);
+}
+/*
+ * Build an ASN_NULL object val into the request packet
+ */
+uchar_t *
+asn_build_null(uchar_t *buf, size_t *bufsz_p, uchar_t id)
+{
+	uchar_t	*p;
+
+	p = asn_build_header(buf, bufsz_p, id, 0);
+
+	LOGASNNULL(buf, p - buf);
+
+	return (p);
+}
+
+
+
+/*
+ * This routine parses a 'SEQUENCE OF' object header from the input
+ * buffer stream. If the identifier tag (made up of class, constructed
+ * type and data type tag) does not match the expected identifier tag,
+ * returns failure.
+ */
+uchar_t *
+asn_parse_sequence(uchar_t *buf, size_t *bufsz_p, uchar_t exp_id)
+{
+	uchar_t	*p;
+	uchar_t	id;
+
+	if ((p = asn_parse_header(buf, bufsz_p, &id)) == NULL)
+		return (NULL);
+
+	if (id != exp_id)
+		return (NULL);
+
+	return (p);
+}
+/*
+ * Return the type identifier of the ASN object via 'id'
+ */
+uchar_t *
+asn_parse_header(uchar_t *buf, size_t *bufsz_p, uchar_t *id)
+{
+	uchar_t	*p;
+	size_t	asnobj_len, hdrlen;
+
+	/*
+	 * Objects with extension tag type are not supported
+	 */
+	if ((buf[0] & ASN_EXT_TAG) == ASN_EXT_TAG)
+		return (NULL);
+
+	/*
+	 * Parse the length field of the ASN object in the header
+	 */
+	if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL)
+		return (NULL);
+
+	/*
+	 * Check if the rest of the msg packet is big enough for the
+	 * full length of the object
+	 */
+	hdrlen = p - buf;
+	if (*bufsz_p < (asnobj_len + hdrlen))
+		return (NULL);
+
+	*id = buf[0];
+	*bufsz_p -= hdrlen;
+
+	return (p);
+}
+/*
+ * This routine parses the length of the object as specified in its
+ * header. The 'Indefinite' form of representing length is not supported.
+ */
+uchar_t *
+asn_parse_length(uchar_t *buf, size_t *asnobj_len_p)
+{
+	uchar_t	*p;
+	int	n_length_octets;
+
+	/*
+	 * First, check for the short-definite form. Length of
+	 * the object is simply the least significant 7-bits of
+	 * the first byte.
+	 */
+	if ((buf[0] & ASN_LONG_LEN) == 0) {
+		*asnobj_len_p = (size_t)buf[0];
+		return (buf + 1);
+	}
+
+	/*
+	 * Then, eliminate the indefinite form. The ASN_LONG_LEN
+	 * bit of the first byte will be set and the least significant
+	 * 7-bites of that byte will be zeros.
+	 */
+	if (buf[0] == (uchar_t)ASN_LONG_LEN)
+		return (NULL);
+
+	/*
+	 * Then, eliminate the long-definite case when the number of
+	 * follow-up octets is more than what the size var can hold.
+	 */
+	n_length_octets = buf[0] & ~ASN_LONG_LEN;
+	if (n_length_octets > sizeof (*asnobj_len_p))
+		return (NULL);
+
+	/*
+	 * Finally gather the length
+	 */
+	p = buf + 1;
+	*asnobj_len_p = 0;
+	while (n_length_octets--) {
+		*asnobj_len_p <<= 8;
+		*asnobj_len_p |= *p++;
+	}
+
+	return (p);
+}
+/*
+ * Parses an integer out of the input buffer
+ */
+uchar_t *
+asn_parse_int(uchar_t *buf, size_t *bufsz_p, int *ival)
+{
+	size_t	asnobj_len, hdrlen;
+	uchar_t	int_id;
+	uchar_t	*p;
+
+	int_id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
+	if (buf[0] != int_id)
+		return (NULL);
+
+	/*
+	 * Read in the length of the object; Note that integers are
+	 * "packed" when sent from agent to manager and vice-versa,
+	 * so the size of the object could be less than sizeof (int).
+	 */
+	if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL)
+		return (NULL);
+
+	/*
+	 * Is there sufficient space left in the packet to read the integer ?
+	 */
+	hdrlen = p - buf;
+	if (*bufsz_p < (hdrlen + asnobj_len))
+		return (NULL);
+
+	/*
+	 * Update space left in the buffer after the integer is read
+	 */
+	*bufsz_p -= (hdrlen + asnobj_len);
+
+	/*
+	 * Read in the integer value
+	 */
+	*ival = (*p & ASN_BIT8) ? -1 : 0;
+	while (asnobj_len--) {
+		*ival <<= 8;
+		*ival |= *p++;
+	}
+
+	return (p);
+}
+/*
+ * Parses an unsigned integer out of the input buffer
+ */
+uchar_t *
+asn_parse_uint(uchar_t *buf, size_t *bufsz_p, uint_t *uival)
+{
+	size_t	asnobj_len, hdrlen;
+	uchar_t	*p;
+
+	if ((buf[0] != ASN_COUNTER) && (buf[0] != ASN_TIMETICKS))
+		return (NULL);
+
+	/*
+	 * Read in the length of the object. Integers are sent the same
+	 * way unsigned integers are sent.  Except that, if the MSB was 1
+	 * in the unsigned int value, a null-byte is attached to the front.
+	 * Otherwise, packing rules are the same as for integer values.
+	 */
+	if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL)
+		return (NULL);
+
+	/*
+	 * Is there sufficient space left in the packet to read in the value ?
+	 */
+	hdrlen = p - buf;
+	if (*bufsz_p < (hdrlen + asnobj_len))
+		return (NULL);
+
+	/*
+	 * Update space left in the buffer after the uint is read
+	 */
+	*bufsz_p -= (hdrlen + asnobj_len);
+
+	/*
+	 * Read in the unsigned integer (this should never get
+	 * initialized to ~0 if it was sent right)
+	 */
+	*uival = (*p & ASN_BIT8) ? ~0 : 0;
+	while (asnobj_len--) {
+		*uival <<= 8;
+		*uival |= *p++;
+	}
+
+	return (p);
+}
+/*
+ * Parses a string (ASN_OCTET_STR or ASN_BIT_STR) out of the input buffer.
+ * The memory for the string is allocated inside the routine and must be
+ * freed by the caller when it is no longer needed. If the string type is
+ * ASN_OCTET_STR, the returned string is null-terminated, and the returned
+ * length indicates the strlen value. If the string type is ASN_BIT_STR,
+ * the returned string is not null-terminated, and the returned length
+ * indicates the number of bytes.
+ */
+uchar_t *
+asn_parse_string(uchar_t *buf, size_t *bufsz_p, uchar_t **str_p, size_t *slen)
+{
+	uchar_t	*p;
+	uchar_t	id1, id2;
+	size_t	asnobj_len, hdrlen;
+
+	/*
+	 * Octet and bit strings are supported
+	 */
+	id1 = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR;
+	id2 = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_BIT_STR;
+	if ((buf[0] != id1) && (buf[0] != id2))
+		return (NULL);
+
+	/*
+	 * Parse out the length of the object and verify source buf sz
+	 */
+	if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL)
+		return (NULL);
+
+	hdrlen = p - buf;
+	if (*bufsz_p < (hdrlen + asnobj_len))
+		return (NULL);
+
+	/*
+	 * Allocate for and copy out the string
+	 */
+	if ((*str_p = (uchar_t *)calloc(1, asnobj_len + 1)) == NULL)
+		return (NULL);
+
+	(void) memcpy(*str_p, p, asnobj_len);
+
+	/*
+	 * Terminate the octet string with a null
+	 */
+	if (buf[0] == id1) {
+		(*str_p)[asnobj_len] = 0;
+	}
+
+	/*
+	 * Update pointers and return
+	 */
+	*slen = asnobj_len;
+	*bufsz_p -= (hdrlen + asnobj_len);
+
+	return (p + asnobj_len);
+}
+/*
+ * Parses an object identifier out of the input packet buffer. Space for
+ * the oid object is allocated within this routine and must be freed by the
+ * caller when no longer needed.
+ */
+uchar_t *
+asn_parse_objid(uchar_t *msg, size_t *varsz_p, void *oidp, size_t *n_subids)
+{
+	oid	**objid_p = oidp;
+	oid	*objid;
+	uchar_t	*p;
+	size_t	hdrlen, asnobj_len;
+	oid	subid;
+	int	i, ndx;
+	uchar_t	exp_id;
+
+	/*
+	 * Check id
+	 */
+	exp_id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID;
+	if (msg[0] != exp_id)
+		return (NULL);
+
+	/*
+	 * Read object length
+	 */
+	if ((p = asn_parse_length(msg + 1, &asnobj_len)) == NULL)
+		return (NULL);
+
+	/*
+	 * Check space in input message
+	 */
+	hdrlen = p - msg;
+	if (*varsz_p < (hdrlen + asnobj_len))
+		return (NULL);
+
+	/*
+	 * Since the OID subidentifiers are packed in 7-bit blocks with
+	 * MSB set to 1 for all but the last octet, the number of subids
+	 * is simply the number of octets with MSB equal to 0, plus 1
+	 * (since the first two subids were packed into one subid and have
+	 * to be expanded back to two).
+	 */
+	*n_subids = 1;
+	for (i = 0; i < asnobj_len; i++) {
+		if ((p[i] & ASN_BIT8) == 0)
+			(*n_subids)++;
+	}
+
+	/*
+	 * Now allocate for the oid and parse the OID into it
+	 */
+	if ((objid = (oid *) calloc(1, (*n_subids) * sizeof (oid))) == NULL)
+		return (NULL);
+
+	ndx = 1;	/* start from 1 to allow for unpacking later */
+	subid = 0;
+	for (i = 0; i < asnobj_len; i++) {
+		subid = subid << 7;
+		subid |= (p[i] & ~ASN_BIT8);
+
+		if ((p[i] & ASN_BIT8) == 0) {
+			objid[ndx] = subid;
+			ndx++;
+			subid = 0;
+		}
+	}
+
+	/*
+	 * Now unpack the first two subids from the subid at index 1.
+	 */
+	if (objid[1] < 40) {
+		objid[0] = 0;
+	} else if (objid[1] < 80) {
+		objid[0] = 1;
+		objid[1] -= 40;
+	} else {
+		objid[0] = 2;
+		objid[1] -= 80;
+	}
+
+	*objid_p = objid;
+	*varsz_p -= (hdrlen + asnobj_len);
+
+	return (msg + hdrlen + asnobj_len);
+}
+/*
+ * Parses the value of an OID object out of the input message buffer.
+ * Only type tags less than ASN_EXT_TAG (0x1f) are supported.
+ */
+uchar_t *
+asn_parse_objval(uchar_t *msg, size_t *varsz_p, void *varlistp)
+{
+	pdu_varlist_t	*vp = varlistp;
+	uchar_t	*p;
+	size_t	n_subids;
+	size_t	hdrlen, asnobj_len;
+
+	vp->type = msg[0] & ASN_EXT_TAG;
+	if (vp->type == ASN_EXT_TAG)
+		return (NULL);
+
+	/*
+	 * Currently we handle ASN_INTEGER, ASN_OCTET_STR, ASN_BIT_STR
+	 * and ASN_TIMETICKS types.
+	 */
+	switch (msg[0]) {
+	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER:
+		vp->val.iptr = (int *)calloc(1, sizeof (int));
+		if (vp->val.iptr == NULL)
+			return (NULL);
+
+		if ((p = asn_parse_int(msg, varsz_p, vp->val.iptr)) == NULL) {
+			free(vp->val.iptr);
+			return (NULL);
+		}
+		vp->val_len = sizeof (int);
+		break;
+
+	case ASN_COUNTER:
+	case ASN_TIMETICKS:
+		vp->val.uiptr = (uint_t *)calloc(1, sizeof (uint_t));
+		if (vp->val.uiptr == NULL)
+			return (NULL);
+
+		if ((p = asn_parse_uint(msg, varsz_p, vp->val.uiptr)) == NULL) {
+			free(vp->val.uiptr);
+			return (NULL);
+		}
+		vp->val_len = sizeof (uint_t);
+		vp->type = msg[0];
+		break;
+
+	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR:
+	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_BIT_STR:
+		p = asn_parse_string(msg, varsz_p, &vp->val.str, &vp->val_len);
+		if (p == NULL)
+			return (NULL);
+		break;
+
+	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID:
+		p = asn_parse_objid(msg, varsz_p, &vp->val.objid, &n_subids);
+		if (p == NULL)
+			return (NULL);
+		vp->val_len = n_subids * sizeof (oid);
+		break;
+
+	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_NULL:
+	case SNMP_NOSUCHOBJECT:
+	case SNMP_NOSUCHINSTANCE:
+	case SNMP_ENDOFMIBVIEW:
+	default:
+		p = asn_parse_length(msg + 1, &asnobj_len);
+		if (p == NULL)
+			return (NULL);
+
+		hdrlen = p - msg;
+		if (*varsz_p < (hdrlen + asnobj_len))
+			return (NULL);
+
+		vp->type = msg[0];
+		vp->val_len = asnobj_len;
+
+		*varsz_p -= (hdrlen + asnobj_len);
+		p += asnobj_len;
+		break;
+	}
+
+	return (p);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/snmp/asn1.h	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,154 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_ASN1_H
+#define	_ASN1_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * ASN.1 values are encoded as octet strings based on the use of a
+ * Type-Length-Value (TLV) structure. The Type indicates the ASN.1
+ * type, the class of the type, and whether the encoding is primitive
+ * or constructed. The Length indicates the length of the actual value
+ * representation and the Value represents the value as a string
+ * of octets.
+ *
+ *              +------------+--------+----------+
+ *              | Identifier | Length | Contents |
+ *              +------------+--------+----------+
+ *
+ * The encoding of the Identifier field is shown below (for tags less than 31):
+ *
+ *              +-------+-----+------------+
+ *              | Class | P/C | Tag number |
+ *              +-------+-----+------------+
+ *          Bit   7   6    5   4  3  2  1  0
+ *
+ * The class field specifies one of four classes, the P/C bit specifies
+ * whether this is a primitive/constructed encoding and the tag number
+ * distinguishes one data type from another within the class.
+ */
+
+/*
+ * Identifier classes
+ */
+#define	ASN_UNIVERSAL		((uchar_t)0x00)
+#define	ASN_APPLICATION		((uchar_t)0x40)
+#define	ASN_CONTEXT		((uchar_t)0x80)
+#define	ASN_PRIVATE		((uchar_t)0xc0)
+
+/*
+ * Encoding type
+ */
+#define	ASN_PRIMITIVE		((uchar_t)0x00)
+#define	ASN_CONSTRUCTOR		((uchar_t)0x20)
+
+/*
+ * Tag numbers for the Universal class of ASN.1 values
+ */
+#define	ASN_BOOLEAN		((uchar_t)0x01)
+#define	ASN_INTEGER		((uchar_t)0x02)
+#define	ASN_BIT_STR		((uchar_t)0x03)
+#define	ASN_OCTET_STR		((uchar_t)0x04)
+#define	ASN_NULL		((uchar_t)0x05)
+#define	ASN_OBJECT_ID		((uchar_t)0x06)
+#define	ASN_SEQUENCE		((uchar_t)0x10)
+#define	ASN_SET			((uchar_t)0x11)
+
+/*
+ * ASN Extension Tag in the identifier
+ */
+#define	ASN_EXT_TAG		((uchar_t)0x1f)
+
+/*
+ * Application class ASN.1 identifiers
+ */
+#define	ASN_COUNTER	(ASN_APPLICATION | ASN_PRIMITIVE | (uchar_t)0x01)
+#define	ASN_TIMETICKS	(ASN_APPLICATION | ASN_PRIMITIVE | (uchar_t)0x03)
+
+/*
+ * The Length field in the TLV structure described above is represented
+ * in many ways depending on the value.
+ *
+ * If the length is less than 128, the length field consists of a
+ * single octet beginning with a zero.
+ *
+ *                        +---+-----------+
+ *                        | 0 | Length(L) |
+ *                        +---+-----------+
+ *
+ * If the length is greater than 127, the first octet of the length field
+ * contains a seven-bit integer that specifies the number of additional
+ * length octets and the additional octets specify the actual length.
+ *
+ *              <-- one octet --><----- K octets ----->
+ *              +---------------+---------------------+
+ *              |  1  |    K    |      Length(L)      |
+ *              +---------------+---------------------+
+ *
+ */
+#define	ASN_LONG_LEN	((uchar_t)0x80)
+#define	ASN_BIT8	((uchar_t)0x80)
+
+/*
+ * Some parts of the code assumes a few things -- big-endian ordering,
+ * sizeof int, etc. to simplify things.
+ */
+#define	BUILD_INT_SHIFT	23
+#define	BUILD_INT_MASK	0x1ff
+
+/*
+ * Exported ASN.1 encoding related interfaces (only exported within
+ * snmplib, we need to do ld versioning to limit the scope of these to
+ * within snmplib).
+ */
+uchar_t	*asn_build_sequence(uchar_t *, size_t *, uchar_t, size_t);
+uchar_t	*asn_build_header(uchar_t *, size_t *, uchar_t, size_t);
+uchar_t	*asn_build_length(uchar_t *, size_t *, size_t);
+uchar_t	*asn_build_int(uchar_t *, size_t *, uchar_t, int);
+uchar_t	*asn_build_string(uchar_t *, size_t *, uchar_t, uchar_t *, size_t);
+uchar_t	*asn_build_objid(uchar_t *, size_t *, uchar_t, void *, size_t);
+uchar_t	*asn_build_null(uchar_t *, size_t *, uchar_t);
+
+uchar_t	*asn_parse_sequence(uchar_t *, size_t *, uchar_t);
+uchar_t	*asn_parse_header(uchar_t *, size_t *, uchar_t *);
+uchar_t	*asn_parse_length(uchar_t *, size_t *);
+uchar_t	*asn_parse_int(uchar_t *, size_t *, int *);
+uchar_t *asn_parse_uint(uchar_t *, size_t *, uint_t *);
+uchar_t	*asn_parse_string(uchar_t *, size_t *, uchar_t **, size_t *);
+uchar_t	*asn_parse_objid(uchar_t *, size_t *, void *, size_t *);
+uchar_t	*asn_parse_objval(uchar_t *, size_t *, void *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _ASN1_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/snmp/debug.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,616 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef SNMP_DEBUG
+
+/*
+ * Debug routines
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <thread.h>
+#include <synch.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "asn1.h"
+#include "pdu.h"
+#include "snmplib.h"
+#include "debug.h"
+
+/*
+ * Buffer and line limits
+ */
+#define	SNMP_DBLOCK_SZ		4096
+#define	SNMP_DMAX_LINE		80
+#define	SNMP_NCHARS_IN_A_ROW	16
+
+/*
+ * Debug flags
+ */
+#define	SNMP_DEBUG_CMD		0x01
+#define	SNMP_DEBUG_VAR		0x02
+#define	SNMP_DEBUG_PDU		0x04
+#define	SNMP_DEBUG_ASN		0x08
+#define	SNMP_DEBUG_PKT		0x10
+#define	SNMP_DEBUG_IO		0x20
+
+#define	SNMP_DEBUG_DEFAULT	0x15	/* cmd, pdu, pkt */
+#define	SNMP_DEBUG_EXTENDED	0x35	/* cmd, pdu, pkt, io */
+#define	SNMP_DEBUG_ALL		0x3f
+
+/*
+ * Formatting aids
+ */
+#define	SNMP_DCMD_INDENT	2
+#define	SNMP_DVAR_INDENT	4
+#define	SNMP_DPDU_INDENT	6
+#define	SNMP_DASN_INDENT	8
+#define	SNMP_DPKT_INDENT	10
+#define	SNMP_DIO_INDENT		12
+
+#define	SNMP_DHDR_PREFIX	(const char *)" ___ "
+#define	SNMP_DHDR_SUFFIX	(const char *)" ___"
+#define	SNMP_DTEXT_PREFIX	(const char *)"| "
+
+/*
+ * All debug vars are protected by a single lock
+ */
+static mutex_t	snmp_dbuf_lock;				/* debug lock */
+static uint16_t	snmp_debug_flag = SNMP_DEBUG_EXTENDED;	/* debug flags */
+static char	*snmp_dbuf = NULL;			/* the debug buffer */
+static char	*snmp_dbuf_curp = NULL;			/* current dbuf index */
+static char	*snmp_dbuf_tail = NULL;			/* current dbuf tail */
+static int	snmp_dbuf_sz = 0;			/* current dbuf size */
+static int	snmp_dbuf_overflow = 0;			/* no more memory */
+static char	snmp_lbuf[SNMP_DMAX_LINE];		/* scratch space */
+
+/*
+ * Key-to-string
+ */
+typedef struct {
+	int	key;
+	char	*str;
+} snmp_key_to_str_t;
+
+static snmp_key_to_str_t snmp_cmds[] = {
+	{ SNMP_MSG_GET, "SNMP_MSG_GET" },
+	{ SNMP_MSG_GETNEXT, "SNMP_MSG_GETNEXT" },
+	{ SNMP_MSG_RESPONSE, "SNMP_MSG_RESPONSE" },
+	{ SNMP_MSG_SET, "SNMP_MSG_SET" },
+	{ SNMP_MSG_TRAP, "SNMP_MSG_TRAP" },
+	{ SNMP_MSG_GETBULK, "SNMP_MSG_GETBULK" },
+	{ SNMP_MSG_INFORM, "SNMP_MSG_INFORM" },
+	{ SNMP_MSG_TRAP2, "SNMP_MSG_TRAP2" },
+	{ SNMP_MSG_REPORT, "SNMP_MSG_REPORT" }
+};
+
+static snmp_key_to_str_t snmp_vartypes[] = {
+	{ ASN_BOOLEAN, "ASN_BOOLEAN" },
+	{ ASN_INTEGER, "ASN_INTEGER" },
+	{ ASN_BIT_STR, "ASN_BIT_STR" },
+	{ ASN_OCTET_STR, "ASN_OCTET_STR" },
+	{ ASN_NULL, "ASN_NULL" },
+	{ ASN_OBJECT_ID, "ASN_OBJECT_ID" },
+	{ ASN_SEQUENCE, "ASN_SEQUENCE" }
+};
+
+static snmp_key_to_str_t snmp_asnencodings[] = {
+	{ SNMP_DASN_SEQUENCE, "ASN SEQUENCE" },
+	{ SNMP_DASN_LENGTH, "ASN LENGTH" },
+	{ SNMP_DASN_INT, "ASN INT" },
+	{ SNMP_DASN_OCTET_STR, "ASN OCTET STR" },
+	{ SNMP_DASN_OID, "ASN OBJECT ID" },
+	{ SNMP_DASN_NULL, "ASN NULL" }
+};
+
+static char *debug_tags[] = {
+	"SNMP Command Request",
+	"Null Var",
+	"Response Var",
+	"Request PDU",
+	"Response PDU",
+	"Request Packet",
+	"Response Packet",
+	"WRITE",
+	"IOCTL",
+	"READ",
+	"SENDTO",
+	"RECVFROM"
+};
+static const int n_tags = sizeof (debug_tags) / sizeof (char *);
+
+/*
+ * Helpers
+ */
+static char	*snmp_cmdstr_lookup(int cmd);
+static char	*snmp_vtypestr_lookup(int vtype);
+static char	*snmp_asnencoding_lookup(int asnkey);
+static void	snmp_get_dumpchars(uchar_t *abuf, uchar_t *p, int nchars);
+static void	snmp_log_append(char *bufp);
+static void	snmp_dbuf_realloc(void);
+
+void
+snmp_debug_init(void)
+{
+	(void) mutex_init(&snmp_dbuf_lock, USYNC_THREAD, NULL);
+
+	(void) mutex_lock(&snmp_dbuf_lock);
+	snmp_dbuf_realloc();
+	if (snmp_dbuf == NULL)
+		snmp_debug_flag = 0;	/* really tragic */
+	(void) mutex_unlock(&snmp_dbuf_lock);
+}
+
+void
+snmp_log_cmd(uint_t tag, int cmd, int n_oids, char *oidstr, int row)
+{
+	char	*cmdstr;
+	int	i;
+
+	if (oidstr == NULL)
+		return;
+
+	(void) mutex_lock(&snmp_dbuf_lock);
+
+	if ((snmp_debug_flag & SNMP_DEBUG_CMD) == 0) {
+		(void) mutex_unlock(&snmp_dbuf_lock);
+		return;
+	}
+
+	snmp_log_append("\n");
+
+	if (tag < n_tags) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s%s%s\n",
+		    SNMP_DCMD_INDENT, ' ', SNMP_DHDR_PREFIX,
+		    debug_tags[tag], SNMP_DHDR_SUFFIX);
+		snmp_log_append(snmp_lbuf);
+	}
+
+	if ((cmdstr = snmp_cmdstr_lookup(cmd)) == NULL) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sCMD=%#x\n",
+		    SNMP_DCMD_INDENT, ' ', SNMP_DTEXT_PREFIX, cmd);
+	} else {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s%s\n",
+		    SNMP_DCMD_INDENT, ' ', SNMP_DTEXT_PREFIX, cmdstr);
+	}
+	snmp_log_append(snmp_lbuf);
+
+	for (i = 0; i < n_oids; i++) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s  %s.%d\n",
+		    SNMP_DCMD_INDENT, ' ', SNMP_DTEXT_PREFIX,
+		    oidstr, row);
+		snmp_log_append(snmp_lbuf);
+
+		oidstr += strlen(oidstr) + 1;
+	}
+
+	(void) mutex_unlock(&snmp_dbuf_lock);
+}
+
+void
+snmp_log_var(uint_t tag, pdu_varlist_t *vp)
+{
+	char	*vts;
+
+	if (vp == NULL)
+		return;
+
+	(void) mutex_lock(&snmp_dbuf_lock);
+
+	if ((snmp_debug_flag & SNMP_DEBUG_VAR) == 0) {
+		(void) mutex_unlock(&snmp_dbuf_lock);
+		return;
+	}
+
+	snmp_log_append("\n");
+
+	if (tag < n_tags) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s%s%s\n",
+		    SNMP_DVAR_INDENT, ' ', SNMP_DHDR_PREFIX,
+		    debug_tags[tag], SNMP_DHDR_SUFFIX);
+		snmp_log_append(snmp_lbuf);
+	}
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%snextvar = %#x\n",
+	    SNMP_DVAR_INDENT, ' ', SNMP_DTEXT_PREFIX, vp->nextvar);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sname = %#x\n",
+	    SNMP_DVAR_INDENT, ' ', SNMP_DTEXT_PREFIX, vp->name);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sname_len = %u\n",
+	    SNMP_DVAR_INDENT, ' ', SNMP_DTEXT_PREFIX, vp->name_len);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sval.ptr = %#x\n",
+	    SNMP_DVAR_INDENT, ' ', SNMP_DTEXT_PREFIX, vp->val.str);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sval_len = %u\n",
+	    SNMP_DVAR_INDENT, ' ', SNMP_DTEXT_PREFIX, vp->val_len);
+	snmp_log_append(snmp_lbuf);
+
+	if ((vts = snmp_vtypestr_lookup(vp->type)) == NULL) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%stype = %#x\n",
+		    SNMP_DVAR_INDENT, ' ', SNMP_DTEXT_PREFIX, vp->type);
+	} else {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%stype = %s\n",
+		    SNMP_DVAR_INDENT, ' ', SNMP_DTEXT_PREFIX, vts);
+	}
+	snmp_log_append(snmp_lbuf);
+
+	(void) mutex_unlock(&snmp_dbuf_lock);
+}
+
+void
+snmp_log_pdu(uint_t tag, snmp_pdu_t *pdu)
+{
+	char	*cmdstr;
+
+	if (pdu == NULL)
+		return;
+
+	(void) mutex_lock(&snmp_dbuf_lock);
+
+	if ((snmp_debug_flag & SNMP_DEBUG_PDU) == 0) {
+		(void) mutex_unlock(&snmp_dbuf_lock);
+		return;
+	}
+
+	snmp_log_append("\n");
+
+	if (tag < n_tags) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s%s%s\n",
+		    SNMP_DPDU_INDENT, ' ', SNMP_DHDR_PREFIX,
+		    debug_tags[tag], SNMP_DHDR_SUFFIX);
+		snmp_log_append(snmp_lbuf);
+	}
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sversion = %d\n",
+	    SNMP_DPDU_INDENT, ' ', SNMP_DTEXT_PREFIX, pdu->version);
+	snmp_log_append(snmp_lbuf);
+
+	if (pdu->community) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE,
+		    "%*c%scommunity = %s\n", SNMP_DPDU_INDENT, ' ',
+		    SNMP_DTEXT_PREFIX, pdu->community);
+	} else {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE,
+		    "%*c%scommunity = %#x\n", SNMP_DPDU_INDENT, ' ',
+		    SNMP_DTEXT_PREFIX, pdu->community);
+	}
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%scommunity_len = %u\n",
+	    SNMP_DPDU_INDENT, ' ', SNMP_DTEXT_PREFIX, pdu->community_len);
+	snmp_log_append(snmp_lbuf);
+
+	if ((cmdstr = snmp_cmdstr_lookup(pdu->command)) == NULL) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE,
+		    "%*c%scommand = %#x\n", SNMP_DPDU_INDENT, ' ',
+		    SNMP_DTEXT_PREFIX, pdu->command);
+	} else {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE,
+		    "%*c%scommand = %s\n", SNMP_DPDU_INDENT, ' ',
+		    SNMP_DTEXT_PREFIX, cmdstr);
+	}
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sreqid = %d\n",
+	    SNMP_DPDU_INDENT, ' ', SNMP_DTEXT_PREFIX, pdu->reqid);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE,
+	    "%*c%serrstat = %#x (non-repeaters)\n", SNMP_DPDU_INDENT, ' ',
+	    SNMP_DTEXT_PREFIX, pdu->errstat);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE,
+	    "%*c%serrindex = %u (max-reps)\n", SNMP_DPDU_INDENT, ' ',
+	    SNMP_DTEXT_PREFIX, pdu->errindex);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%svars = %#x\n",
+	    SNMP_DPDU_INDENT, ' ', SNMP_DTEXT_PREFIX, pdu->vars);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sreq_pkt = %#x\n",
+	    SNMP_DPDU_INDENT, ' ', SNMP_DTEXT_PREFIX, pdu->req_pkt);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sreq_pktsz = %u\n",
+	    SNMP_DPDU_INDENT, ' ', SNMP_DTEXT_PREFIX, pdu->req_pktsz);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sreply_pkt = %#x\n",
+	    SNMP_DPDU_INDENT, ' ', SNMP_DTEXT_PREFIX, pdu->reply_pkt);
+	snmp_log_append(snmp_lbuf);
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sreply_pktsz = %u\n",
+	    SNMP_DPDU_INDENT, ' ', SNMP_DTEXT_PREFIX, pdu->reply_pktsz);
+	snmp_log_append(snmp_lbuf);
+
+	snmp_log_append("\n");
+
+	(void) mutex_unlock(&snmp_dbuf_lock);
+}
+
+void
+snmp_log_asn(int key, uchar_t *pkt, size_t pktsz)
+{
+	char	*p, *asnstr;
+	int	i, len;
+	size_t	nrows, nrem;
+
+	if (pkt == NULL)
+		return;
+
+	(void) mutex_lock(&snmp_dbuf_lock);
+
+	if ((snmp_debug_flag & SNMP_DEBUG_ASN) == 0) {
+		(void) mutex_unlock(&snmp_dbuf_lock);
+		return;
+	}
+
+	if ((asnstr = snmp_asnencoding_lookup(key)) == NULL) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%sASNKEY=%#x\n",
+		    SNMP_DASN_INDENT, ' ', SNMP_DTEXT_PREFIX, key);
+	} else {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s%s\n",
+		    SNMP_DASN_INDENT, ' ', SNMP_DTEXT_PREFIX, asnstr);
+	}
+	snmp_log_append(snmp_lbuf);
+
+	nrows = pktsz / 16;
+	for (i = 0; i < nrows; i++) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s  "
+		    "%02x %02x %02x %02x %02x %02x %02x %02x "
+		    "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+		    SNMP_DASN_INDENT, ' ', SNMP_DTEXT_PREFIX,
+		    pkt[0], pkt[1], pkt[2], pkt[3], pkt[4], pkt[5],
+		    pkt[6], pkt[7], pkt[8], pkt[9], pkt[10], pkt[11],
+		    pkt[12], pkt[13], pkt[14], pkt[15]);
+
+		pkt += 16;
+		snmp_log_append(snmp_lbuf);
+	}
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s ",
+	    SNMP_DASN_INDENT, ' ', SNMP_DTEXT_PREFIX);
+
+	p = snmp_lbuf + SNMP_DASN_INDENT + strlen(SNMP_DTEXT_PREFIX) + 1;
+	len = SNMP_DMAX_LINE - SNMP_DASN_INDENT - strlen(SNMP_DTEXT_PREFIX) - 1;
+
+	nrem = pktsz % 16;
+	for (i = 0; i < nrem; i++) {
+		(void) snprintf(p, len, " %02x", pkt[i]);
+
+		p += 3;
+		len -= 3;
+	}
+	(void) snprintf(p, len, "\n");
+	snmp_log_append(snmp_lbuf);
+
+	(void) mutex_unlock(&snmp_dbuf_lock);
+}
+
+void
+snmp_log_pkt(uint_t tag, uchar_t *pkt, size_t pktsz)
+{
+	uchar_t	ascii[SNMP_NCHARS_IN_A_ROW + 1];
+	uchar_t	*p = pkt;
+	char	*bufp;
+	int	nrows, nrem;
+	int	i, len;
+
+	if (pkt == NULL)
+		return;
+
+	(void) mutex_lock(&snmp_dbuf_lock);
+
+	if ((snmp_debug_flag & SNMP_DEBUG_PKT) == 0) {
+		(void) mutex_unlock(&snmp_dbuf_lock);
+		return;
+	}
+
+	snmp_log_append("\n");
+
+	if (tag < n_tags) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s%s%s\n",
+		    SNMP_DPKT_INDENT, ' ',
+		    SNMP_DHDR_PREFIX, debug_tags[tag], SNMP_DHDR_SUFFIX);
+		snmp_log_append(snmp_lbuf);
+	}
+
+	nrows = pktsz / SNMP_NCHARS_IN_A_ROW;
+	nrem = pktsz % SNMP_NCHARS_IN_A_ROW;
+
+	for (i = 0; i < nrows; i++) {
+		snmp_get_dumpchars(ascii, p, SNMP_NCHARS_IN_A_ROW);
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s"
+		    "%02x %02x %02x %02x %02x %02x %02x %02x "
+		    "%02x %02x %02x %02x %02x %02x %02x %02x "
+		    "%s\n",
+		    SNMP_DPKT_INDENT, ' ', SNMP_DTEXT_PREFIX,
+		    p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
+		    p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15],
+		    ascii);
+		p += 16;
+
+		snmp_log_append(snmp_lbuf);
+	}
+
+	(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE, "%*c%s",
+	    SNMP_DPKT_INDENT, ' ', SNMP_DTEXT_PREFIX);
+
+	snmp_get_dumpchars(ascii, p, nrem);
+
+	bufp = snmp_lbuf + SNMP_DPKT_INDENT + strlen(SNMP_DTEXT_PREFIX);
+	len = SNMP_DMAX_LINE - SNMP_DPKT_INDENT + strlen(SNMP_DTEXT_PREFIX);
+	for (i = 0; i < 16; i++) {
+		if (i < nrem)
+			(void) snprintf(bufp, len, "%02x ", p[i]);
+		else
+			(void) snprintf(bufp, len, "   ");
+
+		bufp += 3;
+		len -= 3;
+	}
+	(void) snprintf(bufp, len, "%s\n", ascii);
+	snmp_log_append(snmp_lbuf);
+
+	(void) mutex_unlock(&snmp_dbuf_lock);
+}
+
+void
+snmp_log_io(uint_t tag, int a1, uint_t a2, uint_t a3)
+{
+	(void) mutex_lock(&snmp_dbuf_lock);
+
+	if ((snmp_debug_flag & SNMP_DEBUG_IO) == 0) {
+		(void) mutex_unlock(&snmp_dbuf_lock);
+		return;
+	}
+
+	snmp_log_append("\n");
+
+	if (tag < n_tags) {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE,
+		    "%*c%s%s(%d, %#x, %#x)\n", SNMP_DIO_INDENT, ' ',
+		    SNMP_DTEXT_PREFIX, debug_tags[tag], a1, a2, a3);
+	} else {
+		(void) snprintf(snmp_lbuf, SNMP_DMAX_LINE,
+		    "%*c%s%#x(%d, %#x, %#x)\n", SNMP_DIO_INDENT, ' ',
+		    SNMP_DTEXT_PREFIX, tag, a1, a2, a3);
+	}
+
+	snmp_log_append(snmp_lbuf);
+
+	(void) mutex_unlock(&snmp_dbuf_lock);
+}
+
+static char *
+snmp_cmdstr_lookup(int cmd)
+{
+	int	nelem = sizeof (snmp_cmds) / sizeof (snmp_key_to_str_t);
+	int	i;
+
+	for (i = 0; i < nelem; i++) {
+		if (snmp_cmds[i].key == cmd)
+			return (snmp_cmds[i].str);
+	}
+
+	return (NULL);
+}
+
+static char *
+snmp_vtypestr_lookup(int vtype)
+{
+	int	nelem = sizeof (snmp_vartypes) / sizeof (snmp_key_to_str_t);
+	int	i;
+
+	for (i = 0; i < nelem; i++) {
+		if (snmp_vartypes[i].key == vtype)
+			return (snmp_vartypes[i].str);
+	}
+
+	return (NULL);
+}
+
+static char *
+snmp_asnencoding_lookup(int asnkey)
+{
+	int	nelem = sizeof (snmp_asnencodings) / sizeof (snmp_key_to_str_t);
+	int	i;
+
+	for (i = 0; i < nelem; i++) {
+		if (snmp_asnencodings[i].key == asnkey)
+			return (snmp_asnencodings[i].str);
+	}
+
+	return (NULL);
+}
+
+static void
+snmp_get_dumpchars(uchar_t *abuf, uchar_t *p, int nchars)
+{
+	int	i;
+
+	if (nchars > SNMP_NCHARS_IN_A_ROW)
+		nchars = SNMP_NCHARS_IN_A_ROW;
+
+	abuf[nchars] = 0;
+	for (i = 0; i < nchars; i++)
+		abuf[i] = isprint(p[i]) ? p[i] : '.';
+}
+
+static void
+snmp_log_append(char *bufp)
+{
+	int	len;
+
+	len = strlen(bufp);
+	if ((snmp_dbuf_curp + len) >= snmp_dbuf_tail)
+		snmp_dbuf_realloc();
+
+	(void) strcpy(snmp_dbuf_curp, bufp);
+
+	snmp_dbuf_curp += len;
+}
+
+static void
+snmp_dbuf_realloc(void)
+{
+	char	*p;
+	size_t	offset = 0;
+	size_t	count;
+
+	count = snmp_dbuf_sz + SNMP_DBLOCK_SZ;
+	if ((p = (char *)calloc(count, 1)) == NULL) {
+		snmp_dbuf_overflow++;
+		snmp_dbuf_curp = snmp_dbuf;
+		return;
+	}
+
+	if (snmp_dbuf) {
+		offset = snmp_dbuf_curp - snmp_dbuf;
+		(void) memcpy(p, snmp_dbuf, snmp_dbuf_sz);
+		free(snmp_dbuf);
+	}
+
+	snmp_dbuf = p;
+	snmp_dbuf_sz += SNMP_DBLOCK_SZ;
+
+	snmp_dbuf_curp = snmp_dbuf + offset;
+	snmp_dbuf_tail = snmp_dbuf + snmp_dbuf_sz;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/snmp/debug.h	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,144 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_DEBUG_H
+#define	_DEBUG_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifdef SNMP_DEBUG
+
+/*
+ * ASN Debugging keys
+ */
+#define	SNMP_DASN_SEQUENCE	1
+#define	SNMP_DASN_LENGTH	2
+#define	SNMP_DASN_INT		3
+#define	SNMP_DASN_OCTET_STR	4
+#define	SNMP_DASN_OID		5
+#define	SNMP_DASN_NULL		6
+
+/*
+ * Debug tags
+ */
+#define	TAG_CMD_REQUEST		0
+#define	TAG_NULL_VAR		1
+#define	TAG_RESPONSE_VAR	2
+#define	TAG_REQUEST_PDU		3
+#define	TAG_RESPONSE_PDU	4
+#define	TAG_REQUEST_PKT		5
+#define	TAG_RESPONSE_PKT	6
+#define	TAG_WRITE		7
+#define	TAG_IOCTL		8
+#define	TAG_READ		9
+#define	TAG_SENDTO		10
+#define	TAG_RECVFROM		11
+
+/*
+ * Debug macros
+ */
+#define	LOGINIT() \
+	snmp_debug_init()
+
+#define	LOGGET(tag, prefix, row) \
+	snmp_log_cmd(tag, SNMP_MSG_GET, 1, prefix, row)
+
+#define	LOGBULK(tag, n_oids, oidstrs, row) \
+	snmp_log_cmd(tag, SNMP_MSG_GETBULK, n_oids, oidstrs, row)
+
+#define	LOGNEXT(tag, prefix, row) \
+	snmp_log_cmd(tag, SNMP_MSG_GETNEXT, 1, prefix, row)
+
+#define	LOGVAR(tag, vp) \
+	snmp_log_var(tag, vp)
+
+#define	LOGPDU(tag, pdu) \
+	snmp_log_pdu(tag, pdu)
+
+#define	LOGASNSEQ(pkt, pktsz) \
+	snmp_log_asn(SNMP_DASN_SEQUENCE, pkt, pktsz)
+
+#define	LOGASNLENGTH(pkt, pktsz) \
+	snmp_log_asn(SNMP_DASN_LENGTH, pkt, pktsz)
+
+#define	LOGASNINT(pkt, pktsz) \
+	snmp_log_asn(SNMP_DASN_INT, pkt, pktsz)
+
+#define	LOGASNOCTSTR(pkt, pktsz) \
+	snmp_log_asn(SNMP_DASN_OCTET_STR, pkt, pktsz)
+
+#define	LOGASNOID(pkt, pktsz) \
+	snmp_log_asn(SNMP_DASN_OID, pkt, pktsz)
+
+#define	LOGASNNULL(pkt, pktsz) \
+	snmp_log_asn(SNMP_DASN_NULL, pkt, pktsz)
+
+#define	LOGPKT(tag, pkt, sz) \
+	snmp_log_pkt(tag, pkt, sz)
+
+#define	LOGIO(tag, a1, a2, a3) \
+	snmp_log_io(tag, (int)a1, (uint_t)a2, (uint_t)a3)
+
+/*
+ * Exported debug interfaces
+ */
+extern void	snmp_debug_init(void);
+extern void	snmp_log_cmd(uint_t tag, int cmd, int n_oids,
+		    char *oidstr, int row);
+extern void	snmp_log_var(uint_t tag, pdu_varlist_t *vp);
+extern void	snmp_log_pdu(uint_t tag, snmp_pdu_t *pdu);
+extern void	snmp_log_asn(int key, uchar_t *pkt, size_t pktsz);
+extern void	snmp_log_pkt(uint_t tag, uchar_t *pkt, size_t pktsz);
+extern void	snmp_log_io(uint_t tag, int a1, uint_t a2, uint_t a3);
+
+#else /* SNMP_DEBUG */
+
+#define	LOGINIT()
+#define	LOGGET(tag, prefix, row)
+#define	LOGBULK(tag, n_oids, oidstrs, row)
+#define	LOGNEXT(tag, prefix, row)
+#define	LOGVAR(tag, vp)
+#define	LOGPDU(tag, pdu)
+#define	LOGASNSEQ(pkt, pktsz)
+#define	LOGASNLENGTH(pkt, pktsz)
+#define	LOGASNINT(pkt, pktsz)
+#define	LOGASNOCTSTR(pkt, pktsz)
+#define	LOGASNOID(pkt, pktsz)
+#define	LOGASNNULL(pkt, pktsz)
+#define	LOGPKT(tag, pkt, sz)
+#define	LOGIO(tag, a1, a2, a3)
+
+#endif /* SNMP_DEBUG */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _DEBUG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/snmp/pdu.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,668 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * SNMP PDU and packet transport related routines
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "asn1.h"
+#include "pdu.h"
+#include "debug.h"
+
+/*
+ * Static declarations
+ */
+static int	snmp_add_null_vars(snmp_pdu_t *, char *, int, int);
+static oid	*snmp_oidstr_to_oid(int, char *, int, size_t *);
+static uchar_t	*snmp_build_pdu(snmp_pdu_t *, uchar_t *, size_t *);
+static uchar_t	*snmp_build_variable(uchar_t *, size_t *, oid *, size_t,
+		    uchar_t, void *, size_t);
+static uchar_t	*snmp_parse_pdu(int, uchar_t *, size_t *, snmp_pdu_t *);
+static uchar_t	*snmp_parse_variable(uchar_t *, size_t *, pdu_varlist_t *);
+
+/*
+ * Allocates and creates a PDU for the specified SNMP command. Currently
+ * only SNMP_MSG_GET, SNMP_MSG_GETNEXT and SNMP_MSG_GETBULK are supported
+ */
+snmp_pdu_t *
+snmp_create_pdu(int cmd, int max_reps, char *oidstrs, int n_oids, int row)
+{
+	snmp_pdu_t	*pdu;
+
+	if ((cmd != SNMP_MSG_GET) && (cmd != SNMP_MSG_GETNEXT) &&
+	    (cmd != SNMP_MSG_GETBULK)) {
+		return (NULL);
+	}
+
+	pdu = (snmp_pdu_t *)calloc(1, sizeof (snmp_pdu_t));
+	if (pdu == NULL)
+		return (NULL);
+
+	if (cmd == SNMP_MSG_GET || cmd == SNMP_MSG_GETNEXT) {
+		pdu->version = SNMP_VERSION_1;
+		pdu->errstat = 0;
+		pdu->errindex = 0;
+	} else if (cmd == SNMP_MSG_GETBULK) {
+		pdu->version = SNMP_VERSION_2c;
+		pdu->non_repeaters = 0;
+		pdu->max_repetitions = max_reps ?
+		    max_reps : SNMP_DEF_MAX_REPETITIONS;
+	}
+
+	pdu->command = cmd;
+	pdu->reqid = snmp_get_reqid();
+	pdu->community = (uchar_t *)SNMP_DEF_COMMUNITY;
+	pdu->community_len = SNMP_DEF_COMMUNITY_LEN;
+
+	if (snmp_add_null_vars(pdu, oidstrs, n_oids, row) < 0) {
+		free((void *) pdu);
+		return (NULL);
+	}
+
+	pdu->req_pkt = NULL;
+	pdu->req_pktsz = 0;
+	pdu->reply_pkt = NULL;
+	pdu->reply_pktsz = 0;
+
+	return (pdu);
+}
+
+/*
+ * Builds a complete ASN.1 encoded snmp message packet out of the PDU.
+ * Currently the maximum request packet is limited to SNMP_DEF_PKTBUF_SZ.
+ * Since we only send SNMP_MSG_GET, SNMP_MSG_GETNEXT and SNMP_MSG_GETBULK,
+ * as long as the number of bulk oids are not *too* many, we're safe with
+ * this limit (the typical packet size of a bulk request of 10 vars is
+ * around 250 bytes).
+ */
+int
+snmp_make_packet(snmp_pdu_t *pdu)
+{
+	uchar_t	*buf, *p;
+	uchar_t	*msg_seq_end;
+	uchar_t id;
+	size_t	bufsz = SNMP_DEF_PKTBUF_SZ;
+	size_t	seqlen;
+
+	if ((buf = (uchar_t *)calloc(1, SNMP_DEF_PKTBUF_SZ)) == NULL)
+		return (-1);
+
+	/*
+	 * Let's start with the ASN sequence tag. Set the length
+	 * to 0 initially and fill it up once the message packetizing
+	 * is complete.
+	 */
+	id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
+	if ((p = asn_build_sequence(buf, &bufsz, id, 0)) == NULL) {
+		free((void *) buf);
+		return (-1);
+	}
+	msg_seq_end = p;
+
+	/*
+	 * Store the version
+	 */
+	id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
+	if ((p = asn_build_int(p, &bufsz, id, pdu->version)) == NULL) {
+		free((void *) buf);
+		return (-1);
+	}
+
+	/*
+	 * Store the community string
+	 */
+	id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR;
+	p = asn_build_string(p, &bufsz, id, pdu->community, pdu->community_len);
+	if (p == NULL) {
+		free((void *) buf);
+		return (-1);
+	}
+
+	/*
+	 * Build the PDU
+	 */
+	if ((p = snmp_build_pdu(pdu, p, &bufsz)) == NULL) {
+		free((void *) buf);
+		return (-1);
+	}
+
+	/*
+	 * Complete the message pkt by updating the message sequence length
+	 */
+	seqlen = p - msg_seq_end;
+	id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
+	(void) asn_build_sequence(buf, NULL, id, seqlen);
+
+	/*
+	 * Calculate packet size and return
+	 */
+	pdu->req_pkt = buf;
+	pdu->req_pktsz = p - buf;
+
+	return (0);
+}
+
+/*
+ * Makes a PDU out of a reply packet. The reply message is parsed
+ * and if the reqid of the incoming packet does not match the reqid
+ * we're waiting for, an error is returned. The PDU is allocated
+ * inside this routine and must be freed by the caller once it is no
+ * longer needed.
+ */
+snmp_pdu_t *
+snmp_parse_reply(int reqid, uchar_t *reply_pkt, size_t reply_pktsz)
+{
+	snmp_pdu_t	*reply_pdu;
+	uchar_t		*p;
+	size_t		msgsz = reply_pktsz;
+	uchar_t		exp_id;
+
+	reply_pdu = (snmp_pdu_t *)calloc(1, sizeof (snmp_pdu_t));
+	if (reply_pdu == NULL)
+		return (NULL);
+
+	/*
+	 * Try to parse the ASN sequence out of the beginning of the reply
+	 * packet. If we don't find a sequence at the beginning, something's
+	 * wrong.
+	 */
+	exp_id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
+	if ((p = asn_parse_sequence(reply_pkt, &msgsz, exp_id)) == NULL) {
+		snmp_free_pdu(reply_pdu);
+		return (NULL);
+	}
+
+	/*
+	 * Now try to parse the version out of the packet
+	 */
+	if ((p = asn_parse_int(p, &msgsz, &reply_pdu->version)) == NULL) {
+		snmp_free_pdu(reply_pdu);
+		return (NULL);
+	}
+	if ((reply_pdu->version != SNMP_VERSION_1) &&
+	    (reply_pdu->version != SNMP_VERSION_2c)) {
+		snmp_free_pdu(reply_pdu);
+		return (NULL);
+	}
+
+	/*
+	 * Parse the community string (space allocated by asn_parse_string)
+	 */
+	p = asn_parse_string(p, &msgsz, &reply_pdu->community,
+	    &reply_pdu->community_len);
+	if (p == NULL) {
+		snmp_free_pdu(reply_pdu);
+		return (NULL);
+	}
+
+	/*
+	 * Parse the PDU part of the message
+	 */
+	if ((p = snmp_parse_pdu(reqid, p, &msgsz, reply_pdu)) == NULL) {
+		snmp_free_pdu(reply_pdu);
+		return (NULL);
+	}
+
+	return (reply_pdu);
+}
+
+
+/*
+ * Convert the OID strings into the standard PDU oid form (sequence of
+ * integer subids) and add them to the PDU's variable list. Note that
+ * this is used only for preparing the request messages (GET, GETNEXT
+ * and GETBULK), so the values of the variables are always null.
+ */
+static int
+snmp_add_null_vars(snmp_pdu_t *pdu, char *oidstrs, int n_oids, int row)
+{
+	pdu_varlist_t	*vp, *prev;
+	pdu_varlist_t	*varblock_p;
+	char	*p;
+	int	i;
+
+	/*
+	 * It's much easier to allocate for all variables in one go,
+	 * so we can release it quickly if there's any failure.
+	 */
+	varblock_p = (pdu_varlist_t *)calloc(n_oids, sizeof (pdu_varlist_t));
+	if (varblock_p == NULL)
+		return (-1);
+
+	prev = NULL;
+	p = oidstrs;
+	vp = varblock_p;
+	for (i = 0; i < n_oids; i++) {
+		vp->name = snmp_oidstr_to_oid(pdu->command,
+		    p, row, &vp->name_len);
+		if (vp->name == NULL) {
+			free((void *) varblock_p);
+			return (-1);
+		}
+		vp->val.str = NULL;
+		vp->val_len = 0;
+		vp->type = ASN_NULL;
+		vp->nextvar = vp + 1;
+
+		LOGVAR(TAG_NULL_VAR, vp);
+
+		prev = vp;
+		p += strlen(p) + 1;
+		vp++;
+	}
+	prev->nextvar = NULL;
+
+	/*
+	 * append the varlist to the PDU
+	 */
+	if (pdu->vars == NULL)
+		pdu->vars = varblock_p;
+	else {
+		for (vp = pdu->vars; vp->nextvar; vp = vp->nextvar)
+			;
+		vp->nextvar = varblock_p;
+	}
+
+	return (0);
+}
+/*
+ * Some assumptions are in place here to eliminate unnecessary complexity.
+ * All OID strings passed are assumed to be in the numeric string form, have
+ * no leading/trailing '.' or spaces. Since PICL plugin is currently the
+ * only customer, this is quite reasonable.
+ */
+static oid *
+snmp_oidstr_to_oid(int cmd, char *oidstr, int row, size_t *n_subids)
+{
+	int	i, count;
+	char	*p, *q;
+	char	*oidstr_dup;
+	oid	*objid;
+
+	if ((oidstr == NULL) || (n_subids == NULL))
+		return (NULL);
+
+	for (count = 1, p = oidstr; p; count++, p++) {
+		if ((p = strchr(p, '.')) == NULL)
+			break;
+	}
+
+	/*
+	 * Add one more to count for 'row'. Need special processing
+	 * for SNMP_MSG_GETNEXT and SNMP_MSG_GETBULK requests; see
+	 * comment below.
+	 */
+	if ((cmd == SNMP_MSG_GET) || (cmd == SNMP_MSG_GETBULK && row > 0) ||
+	    (cmd == SNMP_MSG_GETNEXT && row >= 0)) {
+		count++;
+	}
+
+	if ((oidstr_dup = strdup(oidstr)) == NULL)
+		return (NULL);
+
+	objid = (oid *) calloc(count, sizeof (oid));
+	if (objid == NULL) {
+		free((void *) p);
+		return (NULL);
+	}
+
+	p = oidstr_dup;
+	for (i = 0; i < count - 1; i++) {
+		if (q = strchr(p, '.'))
+			*q = 0;
+		objid[i] = (oid) strtoul(p, NULL, 10);
+		p = q + 1;
+	}
+
+	/*
+	 * For SNMP_MSG_GET, the leaf subid will simply be the row#.
+	 *
+	 * For SNMP_MSG_GETBULK, if the row# passed is greater than 0,
+	 * we pass 'row-1' as the leaf subid, to include the item that
+	 * is of interest to us. If the row# is less than or equal to 0,
+	 * we will simply ignore it and pass only the prefix part of the
+	 * oidstr. For this case, our count would have been 1 less than
+	 * usual, and we are yet to save the last subid.
+	 *
+	 * For SNMP_MSG_GETNEXT, if the row# passed is less than 0,
+	 * we'll simply ignore it and pass only the prefix part of the
+	 * oidstr. For this case, our count would have been 1 less than
+	 * usual, and we are yet to save the last subid. If the row#
+	 * passed is greater than or equal to 0, we'll simply pass it
+	 * verbatim, as the leaf subid.
+	 */
+	switch (cmd) {
+	case SNMP_MSG_GET:
+		objid[i] = (oid) row;
+		break;
+
+	case SNMP_MSG_GETBULK:
+		if (row > 0)
+			objid[i] = (oid) (row - 1);
+		else
+			objid[i] = (oid) strtoul(p, NULL, 10);
+		break;
+
+	case SNMP_MSG_GETNEXT:
+		if (row < 0)
+			objid[i] = (oid) strtoul(p, NULL, 10);
+		else
+			objid[i] = (oid) row;
+		break;
+	}
+
+	*n_subids = count;
+
+	free((void *) oidstr_dup);
+
+	return (objid);
+}
+
+/*
+ * Builds the PDU part of the snmp message packet.
+ */
+static uchar_t *
+snmp_build_pdu(snmp_pdu_t *pdu, uchar_t *buf, size_t *bufsz_p)
+{
+	uchar_t	*p;
+	uchar_t	*pdu_seq_begin, *pdu_seq_end;
+	uchar_t	*varlist_seq_begin, *varlist_seq_end;
+	uchar_t	id;
+	size_t	seqlen;
+	pdu_varlist_t	*vp;
+
+	/*
+	 * Build ASN sequence for the PDU command (length will be
+	 * updated later once the entire command is completely formed)
+	 */
+	pdu_seq_begin = buf;
+	p = asn_build_sequence(buf, bufsz_p, (uchar_t)pdu->command, 0);
+	if (p == NULL)
+		return (NULL);
+	pdu_seq_end = p;
+
+	/*
+	 * Build the request id
+	 */
+	id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
+	if ((p = asn_build_int(p, bufsz_p, id, pdu->reqid)) == NULL)
+		return (NULL);
+
+	/*
+	 * Build the non-repeaters and max-repetitions for SNMP_MSG_GETBULK
+	 * (same as error status and error index for other message types)
+	 */
+	id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
+	if ((p = asn_build_int(p, bufsz_p, id, pdu->non_repeaters)) == NULL)
+		return (NULL);
+
+	id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
+	if ((p = asn_build_int(p, bufsz_p, id, pdu->max_repetitions)) == NULL)
+		return (NULL);
+
+	/*
+	 * Build ASN sequence for the variables list (update length
+	 * after building the varlist)
+	 */
+	varlist_seq_begin = p;
+	id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
+	if ((p = asn_build_sequence(p, bufsz_p, id, 0)) == NULL)
+		return (NULL);
+	varlist_seq_end = p;
+
+	/*
+	 * Build the variables list
+	 */
+	for (vp = pdu->vars; vp; vp = vp->nextvar) {
+		p = snmp_build_variable(p, bufsz_p, vp->name, vp->name_len,
+		    vp->type, vp->val.str, vp->val_len);
+		if (p == NULL)
+			return (NULL);
+	}
+
+	/*
+	 * Now update the varlist sequence length
+	 */
+	seqlen = p - varlist_seq_end;
+	id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
+	(void) asn_build_sequence(varlist_seq_begin, NULL, id, seqlen);
+
+	/*
+	 * And finally, update the length for the PDU sequence
+	 */
+	seqlen = p - pdu_seq_end;
+	(void) asn_build_sequence(pdu_seq_begin, NULL, (uchar_t)pdu->command,
+	    seqlen);
+
+	return (p);
+}
+
+/*
+ * Builds an object variable into the snmp message packet. Although the
+ * code is here to build variables of basic types such as integer, object id
+ * and strings, the only type of variable we ever send via snmp request
+ * messages is the ASN_NULL type.
+ */
+static uchar_t *
+snmp_build_variable(uchar_t *buf, size_t *bufsz_p, oid *name, size_t name_len,
+    uchar_t val_type, void *val, size_t val_len)
+{
+	uchar_t	*p, *varseq_end;
+	size_t	seqlen;
+	uchar_t	id;
+
+	/*
+	 * Each variable binding is in turn defined as a 'SEQUENCE of' by
+	 * the SNMP PDU format, so we'll prepare the sequence and fill up
+	 * the length later. Sigh!
+	 */
+	id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
+	if ((p = asn_build_sequence(buf, bufsz_p, id, 0)) == NULL)
+		return (NULL);
+	varseq_end = p;
+
+	/*
+	 * Build the object id
+	 */
+	id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID;
+	if ((p = asn_build_objid(p, bufsz_p, id, name, name_len)) == NULL)
+		return (NULL);
+
+	/*
+	 * Currently we only ever build ASN_NULL vars while sending requests,
+	 * since we support only SNMP_MSG_GET, SNMP_MSG_GETNEXT and
+	 * SNMP_MSG_GETBULK.
+	 */
+	id = ASN_UNIVERSAL | ASN_PRIMITIVE | val_type;
+	switch (val_type) {
+	case ASN_INTEGER:
+		p = asn_build_int(p, bufsz_p, id, *((int *)val));
+		if (p == NULL)
+			return (NULL);
+		break;
+
+	case ASN_OBJECT_ID:
+		p = asn_build_objid(p, bufsz_p, id, val,
+		    val_len / sizeof (oid));
+		if (p == NULL)
+			return (NULL);
+		break;
+
+	case ASN_OCTET_STR:
+		p = asn_build_string(p, bufsz_p, id, (uchar_t *)val, val_len);
+		if (p == NULL)
+			return (NULL);
+		break;
+
+	case ASN_NULL:
+		if ((p = asn_build_null(p, bufsz_p, id)) == NULL)
+			return (NULL);
+		break;
+
+	default:
+		return (NULL);
+	}
+
+	/*
+	 * Rebuild the variable sequence length
+	 */
+	seqlen = p - varseq_end;
+	id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
+	(void) asn_build_sequence(buf, NULL, id, seqlen);
+
+	return (p);
+}
+
+/*
+ * Parse the PDU portion of the incoming snmp message into the reply_pdu.
+ * Space for all structure members are allocated as needed and must be freed
+ * by the caller when these are no longer needed.
+ */
+static uchar_t *
+snmp_parse_pdu(int reqid, uchar_t *msg, size_t *msgsz_p, snmp_pdu_t *reply_pdu)
+{
+	uchar_t	*p;
+	uchar_t	id, exp_id;
+	pdu_varlist_t	*newvp, *vp = NULL;
+
+	/*
+	 * Parse the PDU header out of the message
+	 */
+	if ((p = asn_parse_header(msg, msgsz_p, &id)) == NULL)
+		return (NULL);
+	if (id != SNMP_MSG_RESPONSE && id != SNMP_MSG_REPORT)
+		return (NULL);
+	reply_pdu->command = (int)id;
+
+	/*
+	 * Parse the request id and verify that this is the response
+	 * we're expecting.
+	 */
+	if ((p = asn_parse_int(p, msgsz_p, &reply_pdu->reqid)) == NULL)
+		return (NULL);
+	if (reply_pdu->reqid != reqid)
+		return (NULL);
+
+	/*
+	 * Parse the error-status and error-index values
+	 */
+	if ((p = asn_parse_int(p, msgsz_p, &reply_pdu->errstat)) == NULL)
+		return (NULL);
+	if ((p = asn_parse_int(p, msgsz_p, &reply_pdu->errindex)) == NULL)
+		return (NULL);
+
+	/*
+	 * Parse the header for the variables list sequence.
+	 */
+	exp_id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
+	if ((p = asn_parse_sequence(p, msgsz_p, exp_id)) == NULL)
+		return (NULL);
+
+	while (((int)*msgsz_p) > 0) {
+		if ((newvp = calloc(1, sizeof (pdu_varlist_t))) == NULL)
+			return (NULL);
+
+		if (vp == NULL)
+			reply_pdu->vars = newvp;
+		else
+			vp->nextvar = newvp;
+
+		vp = newvp;
+		if ((p = snmp_parse_variable(p, msgsz_p, vp)) == NULL)
+			return (NULL);
+
+		LOGVAR(TAG_RESPONSE_VAR, vp);
+	}
+
+	return (p);
+}
+
+/*
+ * Allocate and parse the next variable into the varlist
+ */
+static uchar_t *
+snmp_parse_variable(uchar_t *msg, size_t *msgsz_p, pdu_varlist_t *vp)
+{
+	uchar_t	*p;
+	uchar_t	exp_id;
+
+	/*
+	 * Parse this variable's sequence
+	 */
+	exp_id = ASN_UNIVERSAL | ASN_CONSTRUCTOR | ASN_SEQUENCE;
+	if ((p = asn_parse_sequence(msg, msgsz_p, exp_id)) == NULL)
+		return (NULL);
+
+	/*
+	 * Parse the variable's object identifier
+	 */
+	p = asn_parse_objid(p, msgsz_p, &vp->name, &vp->name_len);
+	if (p == NULL)
+		return (NULL);
+
+	/*
+	 * Parse the object's value
+	 */
+	if ((p = asn_parse_objval(p, msgsz_p, vp)) == NULL)
+		return (NULL);
+
+	return (p);
+}
+
+void
+snmp_free_pdu(snmp_pdu_t *pdu)
+{
+	pdu_varlist_t *vp, *nxt;
+
+	if (pdu) {
+		if (pdu->community)
+			free((void *) pdu->community);
+
+		for (vp = pdu->vars; vp; vp = nxt) {
+			nxt = vp->nextvar;
+
+			if (vp->name)
+				free((void *) vp->name);
+			if (vp->val.str)
+				free((void *) vp->val.str);
+			free((void *) vp);
+		}
+
+		if (pdu->req_pkt)
+			free((void *) pdu->req_pkt);
+
+		if (pdu->reply_pkt)
+			free((void *) pdu->reply_pkt);
+
+		free((void *) pdu);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/snmp/pdu.h	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,159 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_PDU_H
+#define	_PDU_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef uint_t	oid;
+
+/*
+ * SNMP PDU variable list
+ */
+typedef struct pdu_varlist {
+	struct pdu_varlist *nextvar;
+	oid	*name;
+	size_t	name_len;		/* number of subids in the name */
+	union {
+		uint_t	*uiptr;		/* unused except while parsing */
+		int	*iptr;
+		uchar_t	*str;
+		oid	*objid;
+	} val;
+	size_t	val_len;		/* in bytes even if val is objid */
+	uchar_t	type;
+} pdu_varlist_t;
+
+/*
+ * Essential snmp message/PDU fields
+ */
+typedef struct snmp_pdu {
+	int	version;
+	uchar_t	*community;
+	size_t	community_len;
+	int	command;
+	int	reqid;
+	int	errstat;	/* shared with non-repeaters for GETBULK */
+	int	errindex;	/* shared with max-repetitions for GETBULK */
+	pdu_varlist_t	*vars;
+
+	uchar_t	*req_pkt;	/* not really part of PDU */
+	size_t	req_pktsz;	/* not really part of PDU */
+	uchar_t	*reply_pkt;	/* not really part of PDU */
+	size_t	reply_pktsz;	/* not really part of PDU */
+} snmp_pdu_t;
+#define	non_repeaters	errstat
+#define	max_repetitions	errindex
+
+/*
+ * Supported SNMP versions
+ */
+#define	SNMP_VERSION_1		0
+#define	SNMP_VERSION_2c		1
+
+/*
+ * Community strings for supported PDUs
+ */
+#define	SNMP_DEF_COMMUNITY	"public"
+#define	SNMP_DEF_COMMUNITY_LEN	6
+
+/*
+ * PDU types (not all are supported)
+ */
+#define	SNMP_MSG_GET		(ASN_CONTEXT | ASN_CONSTRUCTOR | (uchar_t)0x0)
+#define	SNMP_MSG_GETNEXT	(ASN_CONTEXT | ASN_CONSTRUCTOR | (uchar_t)0x1)
+#define	SNMP_MSG_RESPONSE	(ASN_CONTEXT | ASN_CONSTRUCTOR | (uchar_t)0x2)
+#define	SNMP_MSG_SET		(ASN_CONTEXT | ASN_CONSTRUCTOR | (uchar_t)0x3)
+#define	SNMP_MSG_TRAP		(ASN_CONTEXT | ASN_CONSTRUCTOR | (uchar_t)0x4)
+#define	SNMP_MSG_GETBULK	(ASN_CONTEXT | ASN_CONSTRUCTOR | (uchar_t)0x5)
+#define	SNMP_MSG_INFORM		(ASN_CONTEXT | ASN_CONSTRUCTOR | (uchar_t)0x6)
+#define	SNMP_MSG_TRAP2		(ASN_CONTEXT | ASN_CONSTRUCTOR | (uchar_t)0x7)
+#define	SNMP_MSG_REPORT		(ASN_CONTEXT | ASN_CONSTRUCTOR | (uchar_t)0x8)
+
+/*
+ * Exception values (not all are supported)
+ */
+#define	SNMP_NOSUCHOBJECT	(ASN_CONTEXT | ASN_PRIMITIVE | (uchar_t)0x0)
+#define	SNMP_NOSUCHINSTANCE	(ASN_CONTEXT | ASN_PRIMITIVE | (uchar_t)0x1)
+#define	SNMP_ENDOFMIBVIEW	(ASN_CONTEXT | ASN_PRIMITIVE | (uchar_t)0x2)
+
+/*
+ * Error codes (not all are supported)
+ */
+#define	SNMP_ERR_NOERROR		(0)
+#define	SNMP_ERR_TOOBIG			(1)
+#define	SNMP_ERR_NOSUCHNAME		(2)
+#define	SNMP_ERR_BADVALUE		(3)
+#define	SNMP_ERR_READONLY		(4)
+#define	SNMP_ERR_GENERR			(5)
+#define	SNMP_ERR_NOACCESS		(6)
+#define	SNMP_ERR_WRONGTYPE		(7)
+#define	SNMP_ERR_WRONGLENGTH		(8)
+#define	SNMP_ERR_WRONGENCODING		(9)
+#define	SNMP_ERR_WRONGVALUE		(10)
+#define	SNMP_ERR_NOCREATION		(11)
+#define	SNMP_ERR_INCONSISTENTVALUE	(12)
+#define	SNMP_ERR_RESOURCEUNAVAILABLE	(13)
+#define	SNMP_ERR_COMMITFAILED		(14)
+#define	SNMP_ERR_UNDOFAILED		(15)
+#define	SNMP_ERR_AUTHORIZATIONERROR	(16)
+#define	SNMP_ERR_NOTWRITABLE		(17)
+#define	SNMP_ERR_INCONSISTENTNAME	(18)
+
+/*
+ * Default values
+ */
+#define	SNMP_DEF_NON_REPEATERS		0
+#define	SNMP_DEF_MAX_REPETITIONS	25
+#define	SNMP_DEF_PKTBUF_SZ		2048
+#define	SNMP_PKTBUF_BLKSZ		1024
+#define	SNMP_MAX_ERR    		18
+#define	MIN_SUBIDS_IN_OID		2
+#define	MAX_SUBIDS_IN_OID		128
+
+/*
+ * Exported interfaces used by other parts of snmplib
+ */
+snmp_pdu_t	*snmp_create_pdu(int, int, char *, int, int);
+int		snmp_make_packet(snmp_pdu_t *);
+snmp_pdu_t	*snmp_parse_reply(int, uchar_t *, size_t);
+void		snmp_free_pdu(snmp_pdu_t *);
+
+/*
+ * Imported from elsewhere
+ */
+int		snmp_get_reqid(void);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _PDU_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/snmp/snmplib.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,1245 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * The snmp library helps to prepare the PDUs and communicate with
+ * the snmp agent on the SP side via the ds_snmp driver.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <thread.h>
+#include <synch.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libnvpair.h>
+#include <sys/ds_snmp.h>
+
+#include "libpiclsnmp.h"
+#include "snmplib.h"
+#include "asn1.h"
+#include "pdu.h"
+#include "debug.h"
+
+#pragma init(libpiclsnmp_init)		/* need this in .init */
+
+/*
+ * Data from the MIB is fetched based on the hints about object
+ * groups received from (possibly many threads in) the application.
+ * However, the fetched data is kept in a common cache for use across
+ * all threads, so even a GETBULK is issued only when absolutely
+ * necessary.
+ *
+ * Note that locking is not fine grained (there's no locking per row)
+ * since we don't expect too many MT consumers right away.
+ *
+ */
+static mutex_t	mibcache_lock;
+static nvlist_t	**mibcache = NULL;
+static uint_t	n_mibcache_rows = 0;
+
+static mutex_t snmp_reqid_lock;
+static int snmp_reqid = 1;
+
+#ifdef SNMP_DEBUG
+uint_t snmp_nsends = 0;
+uint_t snmp_sentbytes = 0;
+uint_t snmp_nrecvs = 0;
+uint_t snmp_rcvdbytes = 0;
+#endif
+
+#ifdef USE_SOCKETS
+#define	SNMP_DEFAULT_PORT	161
+#define	SNMP_MAX_RECV_PKTSZ	(64 * 1024)
+#endif
+
+/*
+ * Static function declarations
+ */
+static void	libpiclsnmp_init(void);
+
+static int	lookup_int(char *, int, int *, int);
+static int	lookup_str(char *, int, char **, int);
+static int	lookup_bitstr(char *, int, uchar_t **, uint_t *, int);
+
+static oidgroup_t *locate_oid_group(struct picl_snmphdl *, char *);
+static int	search_oid_in_group(char *, char *, int);
+
+static snmp_pdu_t *fetch_single(struct picl_snmphdl *, char *, int, int *);
+static snmp_pdu_t *fetch_next(struct picl_snmphdl *, char *, int, int *);
+static void	fetch_bulk(struct picl_snmphdl *, char *, int, int, int, int *);
+static int	fetch_single_str(struct picl_snmphdl *, char *, int,
+		    char **, int *);
+static int	fetch_single_int(struct picl_snmphdl *, char *, int,
+		    int *, int *);
+static int	fetch_single_bitstr(struct picl_snmphdl *, char *, int,
+		    uchar_t **, uint_t *, int *);
+
+static int	snmp_send_request(struct picl_snmphdl *, snmp_pdu_t *, int *);
+static int	snmp_recv_reply(struct picl_snmphdl *, snmp_pdu_t *, int *);
+
+static int	mibcache_realloc(int);
+static void	mibcache_populate(snmp_pdu_t *, int);
+static char	*oid_to_oidstr(oid *, size_t);
+
+
+static void
+libpiclsnmp_init(void)
+{
+	(void) mutex_init(&mibcache_lock, USYNC_THREAD, NULL);
+	if (mibcache_realloc(0) < 0)
+		(void) mutex_destroy(&mibcache_lock);
+
+	(void) mutex_init(&snmp_reqid_lock, USYNC_THREAD, NULL);
+
+	LOGINIT();
+}
+
+picl_snmphdl_t
+snmp_init()
+{
+	struct picl_snmphdl	*smd;
+#ifdef USE_SOCKETS
+	int	sbuf = (1 << 15);	/* 16K */
+	int	rbuf = (1 << 17);	/* 64K */
+	char	*snmp_agent_addr;
+#endif
+
+	smd = (struct picl_snmphdl *)calloc(1, sizeof (struct picl_snmphdl));
+	if (smd == NULL)
+		return (NULL);
+
+#ifdef USE_SOCKETS
+	if ((snmp_agent_addr = getenv("SNMP_AGENT_IPADDR")) == NULL)
+		return (NULL);
+
+	if ((smd->fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
+		return (NULL);
+
+	(void) setsockopt(smd->fd, SOL_SOCKET, SO_SNDBUF, &sbuf, sizeof (int));
+	(void) setsockopt(smd->fd, SOL_SOCKET, SO_RCVBUF, &rbuf, sizeof (int));
+
+	memset(&smd->agent_addr, 0, sizeof (struct sockaddr_in));
+	smd->agent_addr.sin_family = AF_INET;
+	smd->agent_addr.sin_port = htons(SNMP_DEFAULT_PORT);
+	smd->agent_addr.sin_addr.s_addr = inet_addr(snmp_agent_addr);
+#else
+	smd->fd = open(DS_SNMP_DRIVER, O_RDWR);
+	if (smd->fd < 0) {
+		free(smd);
+		return (NULL);
+	}
+#endif
+
+	return ((picl_snmphdl_t)smd);
+}
+
+void
+snmp_fini(picl_snmphdl_t hdl)
+{
+	struct picl_snmphdl	*smd = (struct picl_snmphdl *)hdl;
+
+	if (smd) {
+		if (smd->fd >= 0) {
+			(void) close(smd->fd);
+		}
+		free(smd);
+	}
+}
+
+int
+snmp_reinit(picl_snmphdl_t hdl, int clr_linkreset)
+{
+	struct picl_snmphdl *smd = (struct picl_snmphdl *)hdl;
+	nvlist_t *nvl;
+	int i;
+
+	(void) mutex_lock(&mibcache_lock);
+
+	for (i = 0; i < n_mibcache_rows; i++) {
+		if ((nvl = mibcache[i]) != NULL)
+			nvlist_free(nvl);
+	}
+
+	n_mibcache_rows = 0;
+	if (mibcache) {
+		free(mibcache);
+		mibcache = NULL;
+	}
+
+	(void) mutex_unlock(&mibcache_lock);
+
+	if (clr_linkreset) {
+		if (smd == NULL || smd->fd < 0)
+			return (-1);
+		else
+			return (ioctl(smd->fd, DSSNMP_CLRLNKRESET, NULL));
+	}
+
+	return (0);
+}
+
+void
+snmp_register_group(picl_snmphdl_t hdl, char *oidstrs, int n_oids, int is_vol)
+{
+	struct picl_snmphdl *smd = (struct picl_snmphdl *)hdl;
+	oidgroup_t	*oidg;
+	oidgroup_t	*curr, *prev;
+	char		*p;
+	int		i, sz;
+
+	/*
+	 * Allocate a new oidgroup_t
+	 */
+	oidg = (oidgroup_t *)calloc(1, sizeof (struct oidgroup));
+	if (oidg == NULL)
+		return;
+
+	/*
+	 * Determine how much space is required to register this group
+	 */
+	sz = 0;
+	p = oidstrs;
+	for (i = 0; i < n_oids; i++) {
+		sz += strlen(p) + 1;
+		p = oidstrs + sz;
+	}
+
+	/*
+	 * Create this oid group
+	 */
+	if ((p = (char *)malloc(sz)) == NULL) {
+		free((void *) oidg);
+		return;
+	}
+
+	(void) memcpy(p, oidstrs, sz);
+
+	oidg->next = NULL;
+	oidg->oidstrs = p;
+	oidg->n_oids = n_oids;
+	oidg->is_volatile = is_vol;
+
+	/*
+	 * Link it to the tail of the list of oid groups
+	 */
+	for (prev = NULL, curr = smd->group; curr; curr = curr->next)
+		prev = curr;
+
+	if (prev == NULL)
+		smd->group = oidg;
+	else
+		prev->next = oidg;
+}
+
+/*
+ * snmp_get_int() takes in an OID and returns the integer value
+ * of the object referenced in the passed arg. It returns 0 on
+ * success and -1 on failure.
+ */
+int
+snmp_get_int(picl_snmphdl_t hdl, char *prefix, int row, int *val,
+    int *snmp_syserr)
+{
+	struct picl_snmphdl *smd = (struct picl_snmphdl *)hdl;
+	oidgroup_t	*grp;
+	int	ret;
+	int	err = 0;
+
+	if (smd == NULL || prefix == NULL || val == NULL)
+		return (-1);
+
+	/*
+	 * If this item should not be cached, fetch it directly from
+	 * the agent using fetch_single_xxx()
+	 */
+	if ((grp = locate_oid_group(smd, prefix)) == NULL) {
+		ret = fetch_single_int(smd, prefix, row, val, &err);
+
+		if (snmp_syserr)
+			*snmp_syserr = err;
+
+		return (ret);
+	}
+
+	/*
+	 * is it in the cache ?
+	 */
+	if (lookup_int(prefix, row, val, grp->is_volatile) == 0)
+		return (0);
+
+	/*
+	 * fetch it from the agent and populate the cache
+	 */
+	fetch_bulk(smd, grp->oidstrs, grp->n_oids, row, grp->is_volatile, &err);
+	if (snmp_syserr)
+		*snmp_syserr = err;
+
+	/*
+	 * look it up again and return it
+	 */
+	if (lookup_int(prefix, row, val, grp->is_volatile) < 0)
+		return (-1);
+
+	return (0);
+}
+
+/*
+ * snmp_get_str() takes in an OID and returns the string value
+ * of the object referenced in the passed arg. Memory for the string
+ * is allocated within snmp_get_str() and is expected to be freed by
+ * the caller when it is no longer needed. The function returns 0
+ * on success and -1 on failure.
+ */
+int
+snmp_get_str(picl_snmphdl_t hdl, char *prefix, int row, char **strp,
+    int *snmp_syserr)
+{
+	struct picl_snmphdl *smd = (struct picl_snmphdl *)hdl;
+	oidgroup_t	*grp;
+	char	*val;
+	int	ret;
+	int	err = 0;
+
+	if (smd == NULL || prefix == NULL || strp == NULL)
+		return (-1);
+
+	/*
+	 * Check if this item is cacheable or not. If not, call
+	 * fetch_single_* to get it directly from the agent
+	 */
+	if ((grp = locate_oid_group(smd, prefix)) == NULL) {
+		ret = fetch_single_str(smd, prefix, row, strp, &err);
+
+		if (snmp_syserr)
+			*snmp_syserr = err;
+
+		return (ret);
+	}
+
+	/*
+	 * See if it's in the cache already
+	 */
+	if (lookup_str(prefix, row, &val, grp->is_volatile) == 0) {
+		if ((*strp = strdup(val)) == NULL)
+			return (-1);
+		else
+			return (0);
+	}
+
+	/*
+	 * Fetch it from the agent and populate cache
+	 */
+	fetch_bulk(smd, grp->oidstrs, grp->n_oids, row, grp->is_volatile, &err);
+	if (snmp_syserr)
+		*snmp_syserr = err;
+
+	/*
+	 * Retry lookup
+	 */
+	if (lookup_str(prefix, row, &val, grp->is_volatile) < 0)
+		return (-1);
+
+
+	if ((*strp = strdup(val)) == NULL)
+		return (-1);
+	else
+		return (0);
+}
+
+/*
+ * snmp_get_bitstr() takes in an OID and returns the bit string value
+ * of the object referenced in the passed args. Memory for the bitstring
+ * is allocated within the function and is expected to be freed by
+ * the caller when it is no longer needed. The function returns 0
+ * on success and -1 on failure.
+ */
+int
+snmp_get_bitstr(picl_snmphdl_t hdl, char *prefix, int row, uchar_t **bitstrp,
+    uint_t *nbytes, int *snmp_syserr)
+{
+	struct picl_snmphdl *smd = (struct picl_snmphdl *)hdl;
+	oidgroup_t	*grp;
+	uchar_t	*val;
+	int	ret;
+	int	err = 0;
+
+	if (smd == NULL || prefix == NULL || bitstrp == NULL || nbytes == NULL)
+		return (-1);
+
+	/*
+	 * Check if this item is cacheable or not. If not, call
+	 * fetch_single_* to get it directly from the agent
+	 */
+	if ((grp = locate_oid_group(smd, prefix)) == NULL) {
+		ret = fetch_single_bitstr(smd, prefix, row, bitstrp,
+		    nbytes, &err);
+
+		if (snmp_syserr)
+			*snmp_syserr = err;
+
+		return (ret);
+	}
+
+	/*
+	 * See if it's in the cache already
+	 */
+	if (lookup_bitstr(prefix, row, &val, nbytes, grp->is_volatile) == 0) {
+		if ((*bitstrp = (uchar_t *)calloc(*nbytes, 1)) == NULL)
+			return (-1);
+		(void) memcpy(*bitstrp, (const void *)val, *nbytes);
+		return (0);
+	}
+
+	/*
+	 * Fetch it from the agent and populate cache
+	 */
+	fetch_bulk(smd, grp->oidstrs, grp->n_oids, row, grp->is_volatile, &err);
+	if (snmp_syserr)
+		*snmp_syserr = err;
+
+	/*
+	 * Retry lookup
+	 */
+	if (lookup_bitstr(prefix, row, &val, nbytes, grp->is_volatile) < 0)
+		return (-1);
+
+	if ((*bitstrp = (uchar_t *)calloc(*nbytes, 1)) == NULL)
+		return (-1);
+	(void) memcpy(*bitstrp, (const void *)val, *nbytes);
+
+	return (0);
+}
+
+/*
+ * snmp_get_nextrow() is similar in operation to SNMP_GETNEXT, but
+ * only just. In particular, this is only expected to return the next
+ * valid row number for the same object, not its value. Since we don't
+ * have any other means, we use this to determine the number of rows
+ * in the table (and the valid ones). This function returns 0 on success
+ * and -1 on failure.
+ */
+int
+snmp_get_nextrow(picl_snmphdl_t hdl, char *prefix, int row, int *nextrow,
+    int *snmp_syserr)
+{
+	struct picl_snmphdl *smd = (struct picl_snmphdl *)hdl;
+	snmp_pdu_t *reply_pdu;
+	pdu_varlist_t *vp;
+	char	*nxt_oidstr;
+	int	err = 0;
+
+	if (smd == NULL || prefix == NULL || nextrow == NULL)
+		return (-1);
+
+	/*
+	 * The get_nextrow results should *never* go into any cache,
+	 * since these relationships are dynamically discovered each time.
+	 */
+	if ((reply_pdu = fetch_next(smd, prefix, row, &err)) == NULL) {
+		if (snmp_syserr)
+			*snmp_syserr = err;
+
+		return (-1);
+	}
+
+	/*
+	 * We are not concerned about the "value" of the lexicographically
+	 * next object; we only care about the name of that object and
+	 * its row number (and whether such an object exists or not).
+	 */
+	vp = reply_pdu->vars;
+	if (vp == NULL || vp->name == NULL || vp->type == SNMP_NOSUCHOBJECT ||
+	    vp->type == SNMP_NOSUCHINSTANCE || vp->type == SNMP_ENDOFMIBVIEW) {
+		snmp_free_pdu(reply_pdu);
+		return (-1);
+	}
+	if ((nxt_oidstr = oid_to_oidstr(vp->name, vp->name_len - 1)) == NULL) {
+		snmp_free_pdu(reply_pdu);
+		return (-1);
+	}
+	if (strcmp(nxt_oidstr, prefix) != 0) {
+		free(nxt_oidstr);
+		snmp_free_pdu(reply_pdu);
+		return (-1);
+	}
+
+	/*
+	 * Ok, so we've got an oid that's simply the next valid row of the
+	 * passed on object, return this row number.
+	 */
+	*nextrow = (vp->name)[vp->name_len-1];
+
+	free(nxt_oidstr);
+	snmp_free_pdu(reply_pdu);
+
+	return (0);
+}
+
+/*
+ * Request ids for snmp messages to the agent are sequenced here.
+ */
+int
+snmp_get_reqid(void)
+{
+	int	ret;
+
+	(void) mutex_lock(&snmp_reqid_lock);
+
+	ret = snmp_reqid++;
+
+	(void) mutex_unlock(&snmp_reqid_lock);
+
+	return (ret);
+}
+
+static int
+lookup_int(char *prefix, int row, int *valp, int is_vol)
+{
+	int32_t	*val_arr;
+	uint_t	nelem;
+	struct timeval tv;
+	int	elapsed;
+
+	(void) mutex_lock(&mibcache_lock);
+
+	if (row >= n_mibcache_rows) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (-1);
+	}
+
+	if (mibcache[row] == NULL) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (-1);
+	}
+
+	/*
+	 * If this is a volatile property, we should be searching
+	 * for an integer-timestamp pair
+	 */
+	if (is_vol) {
+		if (nvlist_lookup_int32_array(mibcache[row], prefix,
+		    &val_arr, &nelem) != 0) {
+			(void) mutex_unlock(&mibcache_lock);
+			return (-1);
+		}
+		if (nelem != 2 || val_arr[1] < 0) {
+			(void) mutex_unlock(&mibcache_lock);
+			return (-1);
+		}
+		if (gettimeofday(&tv, NULL) < 0) {
+			(void) mutex_unlock(&mibcache_lock);
+			return (-1);
+		}
+		elapsed = tv.tv_sec - val_arr[1];
+		if (elapsed < 0 || elapsed > MAX_INCACHE_TIME) {
+			(void) mutex_unlock(&mibcache_lock);
+			return (-1);
+		}
+
+		*valp = (int)val_arr[0];
+	} else {
+		if (nvlist_lookup_int32(mibcache[row], prefix, valp) != 0) {
+			(void) mutex_unlock(&mibcache_lock);
+			return (-1);
+		}
+	}
+
+	(void) mutex_unlock(&mibcache_lock);
+
+	return (0);
+}
+
+static int
+lookup_str(char *prefix, int row, char **valp, int is_vol)
+{
+	char	**val_arr;
+	uint_t	nelem;
+	struct timeval tv;
+	int	elapsed;
+
+	(void) mutex_lock(&mibcache_lock);
+
+	if (row >= n_mibcache_rows) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (-1);
+	}
+
+	if (mibcache[row] == NULL) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (-1);
+	}
+
+	/*
+	 * If this is a volatile property, we should be searching
+	 * for a string-timestamp pair
+	 */
+	if (is_vol) {
+		if (nvlist_lookup_string_array(mibcache[row], prefix,
+		    &val_arr, &nelem) != 0) {
+			(void) mutex_unlock(&mibcache_lock);
+			return (-1);
+		}
+		if (nelem != 2 || atoi(val_arr[1]) <= 0) {
+			(void) mutex_unlock(&mibcache_lock);
+			return (-1);
+		}
+		if (gettimeofday(&tv, NULL) < 0) {
+			(void) mutex_unlock(&mibcache_lock);
+			return (-1);
+		}
+		elapsed = tv.tv_sec - atoi(val_arr[1]);
+		if (elapsed < 0 || elapsed > MAX_INCACHE_TIME) {
+			(void) mutex_unlock(&mibcache_lock);
+			return (-1);
+		}
+
+		*valp = val_arr[0];
+	} else {
+	    if (nvlist_lookup_string(mibcache[row], prefix, valp) != 0) {
+		    (void) mutex_unlock(&mibcache_lock);
+		    return (-1);
+	    }
+	}
+
+	(void) mutex_unlock(&mibcache_lock);
+
+	return (0);
+}
+
+static int
+lookup_bitstr(char *prefix, int row, uchar_t **valp, uint_t *nelem, int is_vol)
+{
+	(void) mutex_lock(&mibcache_lock);
+
+	if (row >= n_mibcache_rows) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (-1);
+	}
+
+	if (mibcache[row] == NULL) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (-1);
+	}
+
+	/*
+	 * We don't support volatile bit string values yet. The nvlist
+	 * functions don't support bitstring arrays like they do charstring
+	 * arrays, so we would need to do things in a convoluted way,
+	 * probably by attaching the timestamp as part of the byte array
+	 * itself. However, the need for volatile bitstrings isn't there
+	 * yet, to justify the effort.
+	 */
+	if (is_vol) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (-1);
+	}
+
+	if (nvlist_lookup_byte_array(mibcache[row], prefix, valp, nelem) != 0) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (-1);
+	}
+
+	(void) mutex_unlock(&mibcache_lock);
+
+	return (0);
+}
+
+static int
+search_oid_in_group(char *prefix, char *oidstrs, int n_oids)
+{
+	char	*p;
+	int	i;
+
+	p = oidstrs;
+	for (i = 0; i < n_oids; i++) {
+		if (strcmp(p, prefix) == 0)
+			return (0);
+
+		p += strlen(p) + 1;
+	}
+
+	return (-1);
+}
+
+static oidgroup_t *
+locate_oid_group(struct picl_snmphdl *smd, char *prefix)
+{
+	oidgroup_t	*grp;
+
+	if (smd == NULL)
+		return (NULL);
+
+	if (smd->group == NULL)
+		return (NULL);
+
+	for (grp = smd->group; grp; grp = grp->next) {
+		if (search_oid_in_group(prefix, grp->oidstrs,
+		    grp->n_oids) == 0) {
+			return (grp);
+		}
+	}
+
+	return (NULL);
+}
+
+static int
+fetch_single_int(struct picl_snmphdl *smd, char *prefix, int row, int *ival,
+    int *snmp_syserr)
+{
+	snmp_pdu_t *reply_pdu;
+	pdu_varlist_t *vp;
+
+	if ((reply_pdu = fetch_single(smd, prefix, row, snmp_syserr)) == NULL)
+		return (-1);
+
+	/*
+	 * Note that we don't make any distinction between unsigned int
+	 * value and signed int value at this point, since we provide
+	 * only snmp_get_int() at the higher level. While it is possible
+	 * to provide an entirely separate interface such as snmp_get_uint(),
+	 * that's quite unnecessary, because we don't do any interpretation
+	 * of the received value. Besides, the sizes of int and uint are
+	 * the same and the sizes of all pointers are the same (so val.iptr
+	 * would be the same as val.uiptr in pdu_varlist_t). If/when we
+	 * violate any of these assumptions, it will be time to add
+	 * snmp_get_uint().
+	 */
+	vp = reply_pdu->vars;
+	if (vp == NULL || vp->val.iptr == NULL) {
+		snmp_free_pdu(reply_pdu);
+		return (-1);
+	}
+
+	*ival = *(vp->val.iptr);
+
+	snmp_free_pdu(reply_pdu);
+
+	return (0);
+}
+
+static int
+fetch_single_str(struct picl_snmphdl *smd, char *prefix, int row, char **valp,
+    int *snmp_syserr)
+{
+	snmp_pdu_t *reply_pdu;
+	pdu_varlist_t *vp;
+
+	if ((reply_pdu = fetch_single(smd, prefix, row, snmp_syserr)) == NULL)
+		return (-1);
+
+	vp = reply_pdu->vars;
+	if (vp == NULL || vp->val.str == NULL) {
+		snmp_free_pdu(reply_pdu);
+		return (-1);
+	}
+
+	*valp = strdup((const char *)(vp->val.str));
+
+	snmp_free_pdu(reply_pdu);
+
+	return (0);
+}
+
+static int
+fetch_single_bitstr(struct picl_snmphdl *smd, char *prefix, int row,
+    uchar_t **valp, uint_t *nelem, int *snmp_syserr)
+{
+	snmp_pdu_t *reply_pdu;
+	pdu_varlist_t *vp;
+
+	if ((reply_pdu = fetch_single(smd, prefix, row, snmp_syserr)) == NULL)
+		return (-1);
+
+	vp = reply_pdu->vars;
+	if (vp == NULL || vp->val.str == NULL) {
+		snmp_free_pdu(reply_pdu);
+		return (-1);
+	}
+
+	if ((*valp = (uchar_t *)calloc(vp->val_len, 1)) == NULL) {
+		snmp_free_pdu(reply_pdu);
+		return (-1);
+	}
+
+	*nelem = vp->val_len;
+	(void) memcpy(*valp, (const void *)(vp->val.str),
+	    (size_t)(vp->val_len));
+
+	snmp_free_pdu(reply_pdu);
+
+	return (0);
+}
+
+static snmp_pdu_t *
+fetch_single(struct picl_snmphdl *smd, char *prefix, int row, int *snmp_syserr)
+{
+	snmp_pdu_t	*pdu, *reply_pdu;
+
+	LOGGET(TAG_CMD_REQUEST, prefix, row);
+
+	if ((pdu = snmp_create_pdu(SNMP_MSG_GET, 0, prefix, 1, row)) == NULL)
+		return (NULL);
+
+	LOGPDU(TAG_REQUEST_PDU, pdu);
+
+	if (snmp_make_packet(pdu) < 0) {
+		snmp_free_pdu(pdu);
+		return (NULL);
+	}
+
+	LOGPKT(TAG_REQUEST_PKT, pdu->req_pkt, pdu->req_pktsz);
+
+	if (snmp_send_request(smd, pdu, snmp_syserr) < 0) {
+		snmp_free_pdu(pdu);
+		return (NULL);
+	}
+
+	if (snmp_recv_reply(smd, pdu, snmp_syserr) < 0) {
+		snmp_free_pdu(pdu);
+		return (NULL);
+	}
+
+	LOGPKT(TAG_RESPONSE_PKT, pdu->reply_pkt, pdu->reply_pktsz);
+
+	reply_pdu = snmp_parse_reply(pdu->reqid, pdu->reply_pkt,
+	    pdu->reply_pktsz);
+
+	LOGPDU(TAG_RESPONSE_PDU, reply_pdu);
+
+	snmp_free_pdu(pdu);
+
+	return (reply_pdu);
+}
+
+static void
+fetch_bulk(struct picl_snmphdl *smd, char *oidstrs, int n_oids,
+    int row, int is_vol, int *snmp_syserr)
+{
+	snmp_pdu_t	*pdu, *reply_pdu;
+	int		max_reps;
+
+	LOGBULK(TAG_CMD_REQUEST, n_oids, oidstrs, row);
+
+	/*
+	 * If we're fetching volatile properties using BULKGET, don't
+	 * venture to get multiple rows (passing max_reps=0 will make
+	 * snmp_create_pdu() fetch SNMP_DEF_MAX_REPETITIONS rows)
+	 */
+	max_reps = is_vol ? 1 : 0;
+
+	pdu = snmp_create_pdu(SNMP_MSG_GETBULK, max_reps, oidstrs, n_oids, row);
+	if (pdu == NULL)
+		return;
+
+	LOGPDU(TAG_REQUEST_PDU, pdu);
+
+	/*
+	 * Make an ASN.1 encoded packet from the PDU information
+	 */
+	if (snmp_make_packet(pdu) < 0) {
+		snmp_free_pdu(pdu);
+		return;
+	}
+
+	LOGPKT(TAG_REQUEST_PKT, pdu->req_pkt, pdu->req_pktsz);
+
+	/*
+	 * Send the request packet to the agent
+	 */
+	if (snmp_send_request(smd, pdu, snmp_syserr) < 0) {
+		snmp_free_pdu(pdu);
+		return;
+	}
+
+	/*
+	 * Receive response from the agent into the reply packet buffer
+	 * in the request PDU
+	 */
+	if (snmp_recv_reply(smd, pdu, snmp_syserr) < 0) {
+		snmp_free_pdu(pdu);
+		return;
+	}
+
+	LOGPKT(TAG_RESPONSE_PKT, pdu->reply_pkt, pdu->reply_pktsz);
+
+	/*
+	 * Parse the reply, validate the response and create a
+	 * reply-PDU out of the information. Populate the mibcache
+	 * with the received values.
+	 */
+	reply_pdu = snmp_parse_reply(pdu->reqid, pdu->reply_pkt,
+	    pdu->reply_pktsz);
+	if (reply_pdu) {
+		LOGPDU(TAG_RESPONSE_PDU, reply_pdu);
+
+		if (reply_pdu->errstat == SNMP_ERR_NOERROR)
+			mibcache_populate(reply_pdu, is_vol);
+
+		snmp_free_pdu(reply_pdu);
+	}
+
+	snmp_free_pdu(pdu);
+}
+
+static snmp_pdu_t *
+fetch_next(struct picl_snmphdl *smd, char *prefix, int row, int *snmp_syserr)
+{
+	snmp_pdu_t	*pdu, *reply_pdu;
+
+	LOGNEXT(TAG_CMD_REQUEST, prefix, row);
+
+	pdu = snmp_create_pdu(SNMP_MSG_GETNEXT, 0, prefix, 1, row);
+	if (pdu == NULL)
+		return (NULL);
+
+	LOGPDU(TAG_REQUEST_PDU, pdu);
+
+	if (snmp_make_packet(pdu) < 0) {
+		snmp_free_pdu(pdu);
+		return (NULL);
+	}
+
+	LOGPKT(TAG_REQUEST_PKT, pdu->req_pkt, pdu->req_pktsz);
+
+	if (snmp_send_request(smd, pdu, snmp_syserr) < 0) {
+		snmp_free_pdu(pdu);
+		return (NULL);
+	}
+
+	if (snmp_recv_reply(smd, pdu, snmp_syserr) < 0) {
+		snmp_free_pdu(pdu);
+		return (NULL);
+	}
+
+	LOGPKT(TAG_RESPONSE_PKT, pdu->reply_pkt, pdu->reply_pktsz);
+
+	reply_pdu = snmp_parse_reply(pdu->reqid, pdu->reply_pkt,
+	    pdu->reply_pktsz);
+
+	LOGPDU(TAG_RESPONSE_PDU, reply_pdu);
+
+	snmp_free_pdu(pdu);
+
+	return (reply_pdu);
+}
+
+static int
+snmp_send_request(struct picl_snmphdl *smd, snmp_pdu_t *pdu, int *snmp_syserr)
+{
+	extern int	errno;
+#ifdef USE_SOCKETS
+	int		ret;
+#endif
+
+	if (smd->fd < 0)
+		return (-1);
+
+	if (pdu == NULL || pdu->req_pkt == NULL)
+		return (-1);
+
+#ifdef USE_SOCKETS
+	ret = -1;
+	while (ret < 0) {
+		LOGIO(TAG_SENDTO, smd->fd, pdu->req_pkt, pdu->req_pktsz);
+
+		ret = sendto(smd->fd, pdu->req_pkt, pdu->req_pktsz, 0,
+		    (struct sockaddr *)&smd->agent_addr,
+		    sizeof (struct sockaddr));
+		if (ret < 0 && errno != EINTR) {
+			return (-1);
+		}
+	}
+#else
+	LOGIO(TAG_WRITE, smd->fd, pdu->req_pkt, pdu->req_pktsz);
+
+	if (write(smd->fd, pdu->req_pkt, pdu->req_pktsz) < 0) {
+		if (snmp_syserr)
+			*snmp_syserr = errno;
+		return (-1);
+	}
+#endif
+
+#ifdef SNMP_DEBUG
+	snmp_nsends++;
+	snmp_sentbytes += pdu->req_pktsz;
+#endif
+
+	return (0);
+}
+
+static int
+snmp_recv_reply(struct picl_snmphdl *smd, snmp_pdu_t *pdu, int *snmp_syserr)
+{
+	struct dssnmp_info	snmp_info;
+	size_t	pktsz;
+	uchar_t	*pkt;
+	extern int errno;
+#ifdef USE_SOCKETS
+	struct sockaddr_in 	from;
+	int	fromlen;
+	ssize_t	msgsz;
+#endif
+
+	if (smd->fd < 0 || pdu == NULL)
+		return (-1);
+
+#ifdef USE_SOCKETS
+	if ((pkt = (uchar_t *)calloc(1, SNMP_MAX_RECV_PKTSZ)) == NULL)
+		return (-1);
+
+	fromlen = sizeof (struct sockaddr_in);
+
+	LOGIO(TAG_RECVFROM, smd->fd, pkt, SNMP_MAX_RECV_PKTSZ);
+
+	msgsz = recvfrom(smd->fd, pkt, SNMP_MAX_RECV_PKTSZ, 0,
+	    (struct sockaddr *)&from, &fromlen);
+	if (msgsz  < 0 || msgsz >= SNMP_MAX_RECV_PKTSZ) {
+		free(pkt);
+		return (-1);
+	}
+
+	pktsz = (size_t)msgsz;
+#else
+	LOGIO(TAG_IOCTL, smd->fd, DSSNMP_GETINFO, &snmp_info);
+
+	/*
+	 * The ioctl will block until we have snmp data available
+	 */
+	if (ioctl(smd->fd, DSSNMP_GETINFO, &snmp_info) < 0) {
+		if (snmp_syserr)
+			*snmp_syserr = errno;
+		return (-1);
+	}
+
+	pktsz = snmp_info.size;
+	if ((pkt = (uchar_t *)calloc(1, pktsz)) == NULL)
+		return (-1);
+
+	LOGIO(TAG_READ, smd->fd, pkt, pktsz);
+
+	if (read(smd->fd, pkt, pktsz) < 0) {
+		free(pkt);
+		if (snmp_syserr)
+			*snmp_syserr = errno;
+		return (-1);
+	}
+#endif
+
+	pdu->reply_pkt = pkt;
+	pdu->reply_pktsz = pktsz;
+
+#ifdef SNMP_DEBUG
+	snmp_nrecvs++;
+	snmp_rcvdbytes += pktsz;
+#endif
+
+	return (0);
+}
+
+static int
+mibcache_realloc(int hint)
+{
+	uint_t		count = (uint_t)hint;
+	nvlist_t	**p;
+
+	if (hint < 0)
+		return (-1);
+
+	(void) mutex_lock(&mibcache_lock);
+
+	if (hint < n_mibcache_rows) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (0);
+	}
+
+	count =  ((count >> MIBCACHE_BLK_SHIFT) + 1) << MIBCACHE_BLK_SHIFT;
+
+	p = (nvlist_t **)calloc(count, sizeof (nvlist_t *));
+	if (p == NULL) {
+		(void) mutex_unlock(&mibcache_lock);
+		return (-1);
+	}
+
+	if (mibcache) {
+		(void) memcpy((void *) p, (void *) mibcache,
+		    n_mibcache_rows * sizeof (nvlist_t *));
+		free((void *) mibcache);
+	}
+
+	mibcache = p;
+	n_mibcache_rows = count;
+
+	(void) mutex_unlock(&mibcache_lock);
+
+	return (0);
+}
+
+
+/*
+ * Scan each variable in the returned PDU's bindings and populate
+ * the cache appropriately
+ */
+static void
+mibcache_populate(snmp_pdu_t *pdu, int is_vol)
+{
+	pdu_varlist_t	*vp;
+	int		row, ret;
+	char		*oidstr;
+	struct timeval	tv;
+	int		tod;	/* in secs */
+	char		tod_str[MAX_INT_LEN];
+	int		ival_arr[2];
+	char		*sval_arr[2];
+
+	/*
+	 * If we're populating volatile properties, we also store a
+	 * timestamp with each property value. When we lookup, we
+	 * check the current time against this timestamp to determine
+	 * if we need to refetch the value or not (refetch if it has
+	 * been in for far too long).
+	 */
+	if (is_vol) {
+		if (gettimeofday(&tv, NULL) < 0)
+			tod = -1;
+		else
+			tod = (int)tv.tv_sec;
+
+		tod_str[0] = 0;
+		(void) snprintf(tod_str, MAX_INT_LEN, "%d", tod);
+
+		ival_arr[1] = tod;
+		sval_arr[1] = (char *)tod_str;
+	}
+
+	for (vp = pdu->vars; vp; vp = vp->nextvar) {
+		if (vp->type != ASN_INTEGER && vp->type != ASN_OCTET_STR &&
+		    vp->type != ASN_BIT_STR) {
+			continue;
+		}
+
+		if (vp->name == NULL || vp->val.str == NULL)
+			continue;
+
+		row = (vp->name)[vp->name_len-1];
+
+		(void) mutex_lock(&mibcache_lock);
+
+		if (row >= n_mibcache_rows) {
+			(void) mutex_unlock(&mibcache_lock);
+			if (mibcache_realloc(row) < 0)
+				continue;
+			(void) mutex_lock(&mibcache_lock);
+		}
+		ret = 0;
+		if (mibcache[row] == NULL)
+			ret = nvlist_alloc(&mibcache[row], NV_UNIQUE_NAME, 0);
+
+		(void) mutex_unlock(&mibcache_lock);
+
+		if (ret != 0)
+			continue;
+
+		/*
+		 * Convert the standard OID form into an oid string that
+		 * we can use as the key to lookup. Since we only search
+		 * by the prefix (mibcache is really an array of nvlist_t
+		 * pointers), ignore the leaf subid.
+		 */
+		oidstr = oid_to_oidstr(vp->name, vp->name_len - 1);
+		if (oidstr == NULL)
+			continue;
+
+		(void) mutex_lock(&mibcache_lock);
+
+		if (vp->type == ASN_INTEGER) {
+			if (is_vol) {
+				ival_arr[0] = *(vp->val.iptr);
+				(void) nvlist_add_int32_array(mibcache[row],
+				    oidstr, ival_arr, 2);
+			} else {
+				nvlist_add_int32(mibcache[row],
+				    oidstr, *(vp->val.iptr));
+			}
+
+		} else if (vp->type == ASN_OCTET_STR) {
+			if (is_vol) {
+				sval_arr[0] = (char *)vp->val.str;
+				(void) nvlist_add_string_array(mibcache[row],
+				    oidstr, sval_arr, 2);
+			} else {
+				(void) nvlist_add_string(mibcache[row],
+				    oidstr, (const char *)(vp->val.str));
+			}
+		} else if (vp->type == ASN_BIT_STR) {
+			/*
+			 * We don't support yet bit string objects that are
+			 * volatile values.
+			 */
+			if (!is_vol) {
+				(void) nvlist_add_byte_array(mibcache[row],
+				    oidstr, (uchar_t *)(vp->val.str),
+				    (uint_t)vp->val_len);
+			}
+		}
+		(void) mutex_unlock(&mibcache_lock);
+
+		free(oidstr);
+	}
+}
+
+static char *
+oid_to_oidstr(oid *objid, size_t n_subids)
+{
+	char	*oidstr;
+	char	subid_str[MAX_INT_LEN];
+	int	i, isize;
+
+	/*
+	 * ugly, but for now this will have to do.
+	 */
+	oidstr = (char *)calloc(1, MAX_INT_LEN * n_subids);
+
+	for (i = 0; i < n_subids; i++) {
+		(void) memset(subid_str, 0, MAX_INT_LEN);
+		isize = snprintf(subid_str, MAX_INT_LEN, "%d", objid[i]);
+		if (isize >= MAX_INT_LEN)
+			return (NULL);
+
+		(void) strcat(oidstr, subid_str);
+		if (i < (n_subids - 1))
+			(void) strcat(oidstr, ".");
+	}
+
+	return (oidstr);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/lib/snmp/snmplib.h	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,76 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SNMPLIB_H
+#define	_SNMPLIB_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifdef USE_SOCKETS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+/*
+ * Groups of OIDs are registered with the picl snmp library to provide
+ * the library with a hint as to the set of OIDs to do GETBULK requests
+ */
+typedef struct oidgroup {
+	struct oidgroup *next;
+	char		*oidstrs;
+	int		n_oids;
+	int		is_volatile;
+} oidgroup_t;
+
+/*
+ * Private (opaque to clients) handle to manage per-client snmp data
+ */
+struct picl_snmphdl {
+	oidgroup_t	*group;
+#ifdef USE_SOCKETS
+	struct sockaddr_in	agent_addr;
+#endif
+	int		fd;
+};
+
+#define	MIBCACHE_BLK_SZ		256
+#define	MIBCACHE_BLK_SHIFT	8
+#define	MAX_INCACHE_TIME	300	/* in secs */
+#define	MAX_INT_LEN		16	/* #chars to print */
+
+#define	DS_SNMP_DRIVER   	"/devices/pseudo/ds_snmp@0:ds_snmp"
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SNMPLIB_H */
--- a/usr/src/cmd/picl/plugins/sun4v/mdesc/init.c	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/cmd/picl/plugins/sun4v/mdesc/init.c	Sat Mar 31 18:24:05 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -40,74 +40,54 @@
 #include <errno.h>
 
 #define	MDESC_PATH	"/devices/pseudo/mdesc@0:mdesc"
-#define	SIZE	8192
 
 static void mdesc_free(void *bufp, size_t size);
-uint8_t *md_bufp;
+uint64_t *md_bufp;
 
 md_t *
 mdesc_devinit(void)
 {
-	int fh;
-	int res;
-	int size;
-	int offset;
+	int fd;
 	md_t *mdp;
+	size_t size;
 
+	/*
+	 * We haven't finished using the previous MD/PRI info.
+	 */
 	if (md_bufp != NULL)
 		return (NULL);
 
-	fh = open(MDESC_PATH, O_RDONLY, 0);
-	if (fh < 0) {
-		return (NULL);
-	}
-
-	size = SIZE;	/* initial size */
-	offset = 0;
-
-	md_bufp = malloc(size);
-	if (NULL == md_bufp) {
-		return (NULL);
-	}
+	do {
+		if ((fd = open(MDESC_PATH, O_RDONLY, 0)) < 0)
+			break;
 
-		/* OK read until we get a EOF */
-
-	do {
-		int len;
-
-		len = size - offset;
-
-		while (len < SIZE) {
-			size += SIZE;
-			md_bufp = realloc(md_bufp, size);
-			if (NULL == md_bufp)
-				return (NULL);
-			len = size - offset;
+		if (ioctl(fd, MDESCIOCGSZ, &size) < 0)
+			break;
+		if ((md_bufp = (uint64_t *)malloc(size)) == NULL) {
+			(void) close(fd);
+			break;
 		}
 
-		do {
-			res = read(fh, md_bufp + offset, len);
-		} while ((res < 0) && (errno == EAGAIN));
-
-		if (res < 0) {
+		/*
+		 * A partial read is as bad as a failed read.
+		 */
+		if (read(fd, md_bufp, size) != size) {
 			free(md_bufp);
-			return (NULL);
+			md_bufp = NULL;
 		}
 
-		offset += res;
-	} while (res > 0);
-
-	(void) close(fh);
+		(void) close(fd);
+	/*LINTED: E_CONSTANT_CONDITION */
+	} while (0);
 
-	md_bufp = realloc(md_bufp, offset);
-	if (NULL == md_bufp)
-		return (NULL);
-
-	mdp = md_init_intern((uint64_t *)md_bufp, malloc, mdesc_free);
-	if (NULL == mdp) {
-		free(md_bufp);
-		return (NULL);
-	}
+	if (md_bufp) {
+		mdp = md_init_intern(md_bufp, malloc, mdesc_free);
+		if (mdp == NULL) {
+			free(md_bufp);
+			md_bufp = NULL;
+		}
+	} else
+		mdp = NULL;
 
 	return (mdp);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/pri/Makefile	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,120 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# cmd/picl/plugins/sun4v/pri/Makefile
+#
+LIBRARY=	libpriplugin.a
+VERS=		.1
+
+OBJS_DIR=	pics
+
+OBJECTS=	priplugin.o init.o \
+		mem_prop_update.o io_dev_label.o \
+		mdesc_findname.o mdesc_findnodeprop.o \
+		mdesc_fini.o mdesc_getpropstr.o \
+		mdesc_getpropval.o mdesc_init_intern.o \
+		mdesc_nodecount.o mdesc_rootnode.o \
+		mdesc_scandag.o mdesc_getpropdata.o
+
+# include library definitions
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/Makefile.psm
+
+include $(SRC)/cmd/picl/plugins/Makefile.com
+
+SRCS=		$(OBJECTS:%.o=%.c)
+
+LINT_SRC=	./priplugin.c ./init.c \
+		./mem_prop_update.c io_dev_label.c \
+		$(SRC)/common/mdesc/mdesc_findname.c \
+		$(SRC)/common/mdesc/mdesc_findnodeprop.c \
+		$(SRC)/common/mdesc/mdesc_fini.c \
+		$(SRC)/common/mdesc/mdesc_getpropdata.c \
+		$(SRC)/common/mdesc/mdesc_getpropstr.c \
+		$(SRC)/common/mdesc/mdesc_getpropval.c \
+		$(SRC)/common/mdesc/mdesc_init_intern.c \
+		$(SRC)/common/mdesc/mdesc_nodecount.c \
+		$(SRC)/common/mdesc/mdesc_rootnode.c \
+		$(SRC)/common/mdesc/mdesc_scandag.c
+
+$(OBJS_DIR)/%.o:		$(SRC)/common/mdesc/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
+LIBS =		$(DYNLIB)
+
+ROOT_PLATFORM =		$(USR_PLAT_DIR)/sun4v
+DYNFLAGS_PLAT =		/usr/platform/\$$PLATFORM/lib/picl/plugins
+DYNFLAGS_SUN4V =	/usr/platform/sun4v/lib/picl/plugins
+DYNFLAGS_COM =		/usr/lib/picl/plugins
+
+ROOTLIBDIR =	$(ROOT_PLAT_PLUGINDIR)
+
+CLEANFILES =	$(LINTOUT) $(LINTLIB)
+
+CPPFLAGS +=	-I$(SRC)/common/mdesc
+CPPFLAGS +=	-I$(SRC)/uts/common/sys
+CPPFLAGS +=	-I$(SRC)/lib/libpri/common
+CPPFLAGS +=	-D_REENTRANT
+
+CFLAGS +=	$(CCVERBOSE)
+LDLIBS +=	-L$(SRC)/lib/libpicl/$(MACH) -L$(SRC)/lib/libpicltree/$(MACH)
+LDLIBS +=	-L$(ROOT)/usr/lib/picl/plugins -L$(ROOT)/usr/lib/sparcv9
+LDLIBS +=	-L$(ROOT)/usr/lib/libpri
+LDLIBS +=	-L$(ROOT_PLATFORM)/lib -L$(ROOT_PLATFORM)/lib/picl/plugins
+
+LDLIBS +=	-lc -lpicl -lpicltree -lpicldevtree -lpri
+
+# No interfaces from libsnmpplugin.so directly used here, but we need the
+# snmp plugin to load and init before libpriplugin.so.
+#
+LDLIBS +=	-lsnmpplugin
+
+#DYNFLAGS +=	-R$(DYNFLAGS_COM)
+$(SPARC_BLD)LDLIBS +=	-R$(DYNFLAGS_PLAT) \
+			-R$(DYNFLAGS_SUN4V)
+LDLIBS +=	-R$(DYNFLAGS_COM)
+
+LINTFLAGS +=	-erroff=E_BAD_PTR_CAST_ALIGN -v
+
+.KEEP_STATE:
+
+all: $(LIBS) $(LIBLINKS)
+
+install:	all $(ROOTLIBDIR) $(ROOTLIBS) $(ROOTLINKS)
+
+$(LIBLINKS):	FRC
+	$(RM) $(LIBLINKS); $(SYMLINK) $(DYNLIB) $(LIBLINKS)
+
+# include library targets
+include $(SRC)/cmd/picl/plugins/Makefile.targ
+include $(SRC)/lib/Makefile.targ
+
+lint :
+	$(LINT.c) $(LINT_SRC)
+
+FRC:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/pri/init.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,105 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <errno.h>
+#include <malloc.h>
+#include <mdesc.h>
+#include <pri.h>
+#include "priplugin.h"
+
+static void pri_free(void *bufp, size_t size);
+uint64_t *md_bufp;
+
+md_t *
+pri_devinit(void)
+{
+	md_t *mdp;
+	uint64_t tok;
+
+	md_bufp = NULL;
+	tok = 0;
+
+	if (pri_init() != -1) {
+		if (pri_get(PRI_GET, &tok, &md_bufp, malloc, pri_free) ==
+		    (ssize_t)-1) {
+			pri_debug(LOG_NOTICE, "pri_devinit: can'r read from "
+			    "the PRI: %d\n", errno);
+		}
+		if (md_bufp == NULL) {
+			pri_debug(LOG_NOTICE, "pri_devinit: pri_get returned"
+			    "NULL buffer!\n");
+		}
+	} else {
+		pri_debug(LOG_NOTICE, "pri_devinit: pri_init failed!\n");
+	}
+	pri_fini();
+
+	pri_debug(LOG_NOTICE, "pri_devinit: done reading PRI\n");
+
+	/*
+	 * The PRI and the MD use the same data format so they can be
+	 * parsed by the same functions.
+	 */
+	if (md_bufp) {
+		mdp = md_init_intern(md_bufp, malloc, pri_free);
+		if (mdp == NULL) {
+			pri_debug(LOG_NOTICE, "pri_devinit: md_init_intern "
+			"failed\n");
+			free(md_bufp);
+			md_bufp = NULL;
+		} else {
+			pri_debug(LOG_NOTICE, "pri_devinit: mdi_init_intern "
+			    "completed successfully\n");
+		}
+	} else
+		mdp = NULL;
+
+	pri_debug(LOG_NOTICE, "pri_devinit: returning\n");
+
+	return (mdp);
+}
+
+/*ARGSUSED*/
+static void
+pri_free(void *bufp, size_t size)
+{
+	if (bufp)
+		free(bufp);
+}
+
+void
+pri_devfini(md_t *mdp)
+{
+	if (mdp)
+		(void) md_fini(mdp);
+
+	if (md_bufp)
+		free(md_bufp);
+	md_bufp = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/pri/io_dev_label.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,305 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include "priplugin.h"
+
+/*
+ * These 3 variable are defined and set in mdescplugin.c
+ */
+extern picl_nodehdl_t	root_node;
+extern md_t		*mdp;
+extern mde_cookie_t	rootnode;
+
+static int
+find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
+    const char *pval, picl_nodehdl_t *nodeh);
+static int
+compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
+    const char *pval);
+
+/*
+ * Gather IO device nodes from the PRI and use the info to
+ * find the corresponding nodes in PICL's device tree, insert
+ * a Label into the devtree containing the "nac" from the PRI,
+ * and add a reference property to the corresponding fru tree node.
+ */
+void
+io_dev_addlabel(void)
+{
+	int status, substatus, i, node_count, component_count, busaddr_match;
+	int type_size, nac_size;
+	picl_nodehdl_t platnode, tpn;
+	char busaddr[PICL_PROPNAMELEN_MAX], *p, *q;
+	mde_cookie_t *components;
+	char *type, *nac, *path, *saved_path;
+
+	/*
+	 * Find and remember the roots of the /frutree and /platform trees.
+	 */
+	if ((status = ptree_get_node_by_path(PLATFORM_PATH, &platnode)) !=
+	    PICL_SUCCESS) {
+		pri_debug(LOG_NOTICE,
+		    "io_dev_label: can't find platform node: %s\n",
+		    picl_strerror(status));
+		return;
+	}
+
+	node_count = md_node_count(mdp);
+	if (node_count == 0) {
+		pri_debug(LOG_NOTICE, "io_dev_addlabel: no nodes to process\n");
+		return;
+	}
+	components = (mde_cookie_t *)malloc(node_count * sizeof (mde_cookie_t));
+	if (components == NULL) {
+		pri_debug(LOG_NOTICE,
+		    "io_dev_addlabel: can't get memory for IO nodes\n");
+		return;
+	}
+
+	component_count = md_scan_dag(mdp, rootnode,
+	    md_find_name(mdp, "component"),
+	    md_find_name(mdp, "fwd"), components);
+
+	for (i = 0; i < component_count; ++i) {
+		tpn = platnode;
+
+		/*
+		 * Try to fetch the "type" as a string or as "data" until we
+		 * can agree on what its tag type should be.
+		 */
+		if (md_get_prop_str(mdp, components[i], "type", &type) == -1) {
+			if (md_get_prop_data(mdp, components[i], "type",
+			    (uint8_t **)&type, &type_size)) {
+				pri_debug(LOG_NOTICE, "io_add_devlabel: can't "
+				    "get type for component %d\n", i);
+			continue;
+			}
+		}
+
+		/*
+		 * Isolate components of type "io".
+		 */
+		if (strcmp((const char *)type, "io")) {
+			pri_debug(LOG_NOTICE,
+			    "io_add_devlabel: skipping component %d with "
+			    "type %s\n", i, type);
+			continue;
+		}
+
+		/*
+		 * Now get the nac and raw path from the PRI.
+		 */
+		if (md_get_prop_str(mdp, components[i], "nac", &nac) == -1) {
+			pri_debug(LOG_NOTICE,
+			    "io_add_devlabel: can't get nac value for device "
+			    "<%s>\n", type);
+			continue;
+		} else
+			nac_size = strlen(nac) + 1;
+
+		if (md_get_prop_str(mdp, components[i], "path", &path) == -1) {
+			pri_debug(LOG_NOTICE,
+			    "io_add_devlabel: can't get path value for "
+			    "device <%s>\n", type);
+			continue;
+		}
+
+		pri_debug(LOG_NOTICE, "io_add_devlabel: processing component "
+		    "%d, type <%s>, nac <%s>, path <%s>\n", i, type, nac,
+		    path);
+
+		/*
+		 * This loop visits each path component where those
+		 * components are delimited with '/' and '@' characters.
+		 * Each path component is a search key into the /platform
+		 * tree; we're looking to match the bus-addr field of
+		 * a node if that field is defined.  If each path component
+		 * matches up then we now have the corresponding device
+		 * path for that IO device.  Add a Label property to the
+		 * leaf node.
+		 */
+		for (busaddr_match = 1, p = q = (char *)path; q; p = q + 1) {
+
+			/*
+			 * Isolate the bus address for this node by skipping
+			 * over the first delimiter if present and writing
+			 * a NUL character over the next '/'.
+			 */
+			if (*p == '/')
+				++p;
+			if (*p == '@')
+				++p;
+			if ((q = strchr((const char *)p, '/')) != NULL)
+				*q = '\0';
+
+			/*
+			 * See if there's a match, at this level only, in the
+			 * device tree.  We cannot skip generations in the
+			 * device tree, which is why we're not doing a
+			 * recursive search for bus-addr.  bus-addr must
+			 * be found at each node along the way.  By doing
+			 * this we'll stay in sync with the path components
+			 * in the PRI.
+			 */
+			if ((status = find_node_by_string_prop(tpn,
+			    PICL_PROP_BUS_ADDR, (const char *)p, &tpn)) !=
+			    PICL_SUCCESS) {
+				pri_debug(LOG_NOTICE,
+				    "can't find %s property of <%s> "
+				    "for nac %s: %s\n",
+				    PICL_PROP_BUS_ADDR, p, nac,
+				    picl_strerror(status));
+				busaddr_match = 0;
+				break;
+			}
+
+			/*
+			 * Note path component for the leaf so we can use
+			 * it below.
+			 */
+			saved_path = p;
+		}
+
+		/*
+		 * We could not drill down through the bus-addrs, so skip this
+		 * device and move on to the next.
+		 */
+		if (busaddr_match == 0) {
+			pri_debug(LOG_NOTICE, "io_add_devlabel: no matching "
+			    "bus-addr path for this nac - skipping\n");
+			continue;
+		}
+
+		nac_size = strlen((const char *)nac) + 1;
+
+		/*
+		 * This loop adds a Label property to all the functions
+		 * on the device we matched from the PRI path.
+		 */
+		for (status = PICL_SUCCESS; status == PICL_SUCCESS;
+			status = ptree_get_propval_by_name(tpn, PICL_PROP_PEER,
+			    &tpn, sizeof (picl_nodehdl_t))) {
+			/*
+			 * Add Labels to peers that have the same bus-addr
+			 * value (ignoring the function numbers.)
+			 */
+			if ((substatus = ptree_get_propval_by_name(tpn,
+			    PICL_PROP_BUS_ADDR,
+			    busaddr, sizeof (busaddr))) != PICL_SUCCESS) {
+				pri_debug(LOG_NOTICE,
+				    "io_add_device: can't get %s "
+				    "property from picl devtree: %s\n",
+				    PICL_PROP_BUS_ADDR,
+				    picl_strerror(substatus));
+			} else {
+				/*
+				 * If the nac doesn't include a specific
+				 * function number then don't look for one
+				 * in the bus-addr.  Devices on PCI-X bridges
+				 * may have a function number in the path,
+				 * so don't ignore that.
+				 */
+				if (strchr(nac, ',') == NULL) {
+					if ((q = strchr(busaddr, ',')) !=
+					    NULL) {
+						*q = '\0';
+					}
+				}
+				if (strncmp(busaddr, saved_path,
+				    PICL_PROPNAMELEN_MAX) == 0) {
+					add_md_prop(tpn, nac_size,
+					    PICL_PROP_LABEL, nac,
+					    PICL_PTYPE_CHARSTRING);
+				}
+			}
+		}
+	}
+}
+
+/*
+ * These two functions shamelessly stolen from picldevtree.c
+ */
+
+/*
+ * Return 1 if this node has this property with the given value.
+ */
+static int
+compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
+    const char *pval)
+{
+	char *pvalbuf;
+	int err;
+	int len;
+	ptree_propinfo_t pinfo;
+	picl_prophdl_t proph;
+
+	err = ptree_get_prop_by_name(nodeh, pname, &proph);
+	if (err != PICL_SUCCESS)	/* prop doesn't exist */
+		return (0);
+
+	err = ptree_get_propinfo(proph, &pinfo);
+	if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING)
+		return (0);	/* not string prop */
+
+	len = strlen(pval) + 1;
+
+	pvalbuf = alloca(len);
+	if (pvalbuf == NULL)
+		return (0);
+
+	err = ptree_get_propval(proph, pvalbuf, len);
+	if ((err == PICL_SUCCESS) && (strcmp(pvalbuf, pval) == 0))
+		return (1);	/* prop match */
+
+	return (0);
+}
+
+/*
+ * Search this node's children for the given property.
+ */
+static int
+find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
+    const char *pval, picl_nodehdl_t *nodeh)
+{
+	picl_nodehdl_t childh;
+	int err;
+
+	for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
+	    sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
+		err = ptree_get_propval_by_name(childh, PICL_PROP_PEER, &childh,
+		    sizeof (picl_nodehdl_t))) {
+		if (err != PICL_SUCCESS)
+			return (err);
+
+		if (compare_string_propval(childh, pname, pval)) {
+			*nodeh = childh;
+			return (PICL_SUCCESS);
+		}
+	}
+	return (PICL_ENDOFLIST);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/pri/mem_prop_update.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,316 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * The PRI plug-in picks up memory configuration data from the PRI
+ * and injects this into PICL's /platform tree.  It only populates
+ * the logical view of memory: memory, memory-segment, memory-bank.
+ * It does not populate the /device tree since there are no memory
+ * controller devices on sun4v.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include "priplugin.h"
+#include "../../common/memcfg/piclmemcfg.h"
+
+/*
+ * These 3 variable are defined and set in mdescplugin.c
+ */
+extern picl_nodehdl_t	root_node;
+extern md_t		*mdp;
+extern mde_cookie_t	rootnode;
+
+static void
+add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, uint64_t size);
+
+static void
+add_bank_props(picl_nodehdl_t node, mde_cookie_t banklistp,
+	uint64_t *size, uint64_t *mask, unsigned int id);
+static uint64_t countbits(uint64_t v);
+
+static void
+add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp,
+	uint64_t interleave, uint64_t *size, uint64_t base);
+
+/*
+ * Callback function for picl_walk_tree_by_class().
+ * NOTE: picl_walk_tree_by_class() maps the return codes PICL_WALK_CONTINUE
+ * and PICL_WALK_TERMINATE to PICL_SUCCESS.
+ */
+int
+add_mem_prop(picl_nodehdl_t node, void *args)
+{
+	mde_cookie_t *memorylistp, *segmentlistp, *banklistp;
+	picl_prophdl_t memh, segmenth, bankh;
+	mde_cookie_t *buf;
+	int j, k, num_nodes, interleave, err;
+	int nsegments, nbanks, nmemory;
+	uint64_t memsize, segsize, segbase;
+	uint64_t size, mask;
+
+	/*
+	 * An absence of nodes or failure to obtain memory for searches
+	 * or absence of the /memory node will cause this to fail.
+	 * Return PICL_WALK_SUCCESS to allow the plug-in to continue.
+	 */
+	num_nodes = md_node_count(mdp);
+	if (num_nodes == 0) {
+		pri_debug(LOG_NOTICE, "add_mem_prop: no nodes to walk\n");
+		return (PICL_SUCCESS);
+	}
+	buf = (mde_cookie_t *)malloc(sizeof (mde_cookie_t) * num_nodes * 3);
+	if (buf == NULL) {
+		pri_debug(LOG_NOTICE, "add_mem_prop: can't allocate memory\n");
+		return (PICL_SUCCESS);
+	}
+
+	memorylistp = &buf[0];
+	segmentlistp = &buf[num_nodes];
+	banklistp = &buf[num_nodes * 2];
+
+	if ((ptree_get_node_by_path(MEMORY_PATH, &memh)) != PICL_SUCCESS) {
+		pri_debug(LOG_NOTICE,
+		    "add_mem_prop: can't find /memory node in platform tree\n");
+		free(buf);
+		return (PICL_SUCCESS);
+	}
+
+	/*
+	 * There should be only one memory node.
+	 * If we can't find what we're looking for in the DAG then
+	 * return PICL_PROPNOTFOUND to get the caller to re-try with
+	 * a different property name.
+	 */
+	nmemory = md_scan_dag(mdp, rootnode, md_find_name(mdp, args),
+	    md_find_name(mdp, "fwd"), memorylistp);
+	if (nmemory != 1) {
+		pri_debug(LOG_NOTICE,
+		    "add_mem_prop: wrong number of memory dags: expected "
+		    "1, got %d\n", nmemory);
+		free(buf);
+		return (PICL_PROPNOTFOUND);
+	}
+
+	nsegments = md_scan_dag(mdp, memorylistp[0],
+	    md_find_name(mdp, "memory-segment"),
+	    md_find_name(mdp, "fwd"),
+	    segmentlistp);
+
+	if (nsegments == 0) {
+		pri_debug(LOG_NOTICE, "add_mem_prop: wrong number of memory "
+		    "segments: expected >0, got %d\n", nsegments);
+		free(buf);
+		return (PICL_PROPNOTFOUND);
+	}
+
+	/*
+	 * Add memory segments, keep running total of system memory.
+	 */
+	for (memsize = 0, segsize = 0, j = 0; j < nsegments;
+	    ++j, memsize += segsize) {
+		nbanks = 0;
+		err = ptree_create_and_add_node(memh,
+		    PICL_NAME_MEMORY_SEGMENT,
+		    PICL_CLASS_MEMORY_SEGMENT, &segmenth);
+		if (err == PICL_SUCCESS) {
+			size = 0;
+			mask = 0;
+
+			/*
+			 * Need to pull this out here since it's used for
+			 * the ID.
+			 */
+			if (md_get_prop_val(mdp, segmentlistp[j], "base",
+			    &segbase))
+				segbase = 0ULL;
+
+			/*
+			 * Add banks under each segment.
+			 */
+			nbanks = md_scan_dag(mdp, segmentlistp[j],
+			    md_find_name(mdp, "memory-bank"),
+			    md_find_name(mdp, "fwd"),
+			    banklistp);
+
+			if (nbanks <= 0) {
+				pri_debug(LOG_NOTICE, "add_mem_prop: no banks "
+				    "found for segment %d\n", j);
+			} else {
+				for (k = 0; k < nbanks; ++k) {
+					err =
+					    ptree_create_and_add_node(segmenth,
+					    PICL_NAME_MEMORY_BANK,
+					    PICL_CLASS_MEMORY_BANK, &bankh);
+					if (err == PICL_SUCCESS) {
+						/*
+						 * Add AddressMatch,
+						 * AddressMask, Size, and
+						 * ID to each bank.
+						 */
+						add_bank_props(bankh,
+						    banklistp[k],
+						    &size, &mask,
+						    (segbase >> 32) * j + k);
+					}
+				}
+			}
+		}
+
+		/*
+		 * Add Interleave, BaseAddress, and Size to each segment.
+		 */
+		interleave = 2 << (countbits(mask & (size - 1)) - 1);
+		add_segment_props(segmenth, segmentlistp[j],
+			interleave, &segsize, segbase);
+	}
+
+	/*
+	 * Add TransferSize and Size (total memory) to this node.
+	 */
+	add_memory_props(memh, memorylistp[0], memsize);
+
+	free(buf);
+	return (PICL_WALK_CONTINUE);
+}
+
+static void
+add_bank_props(picl_nodehdl_t node, mde_cookie_t banklistp,
+	uint64_t *size, uint64_t *mask, unsigned int id)
+{
+	uint64_t int_value;
+	mde_cookie_t *dimmlistp;
+	int node_count, i, type_size, nac_size, status;
+	uint8_t *type;
+	char *pc, *nac;
+
+	*size = 0ULL;
+	*mask = 0ULL;
+
+	node_count = md_node_count(mdp);
+	dimmlistp = (mde_cookie_t *)malloc(node_count * sizeof (mde_cookie_t));
+
+	if (!md_get_prop_val(mdp, banklistp, "size", &int_value)) {
+		add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE,
+		    &int_value, PICL_PTYPE_UNSIGNED_INT);
+		*size = int_value;
+	}
+	if (!md_get_prop_val(mdp, banklistp, "mask",
+	    &int_value)) {
+		add_md_prop(node, sizeof (int_value),
+		    PICL_PROP_ADDRESSMASK,
+		    &int_value, PICL_PTYPE_UNSIGNED_INT);
+		*mask = int_value;
+	}
+	if (!md_get_prop_val(mdp, banklistp, "match",
+	    &int_value)) {
+		add_md_prop(node, sizeof (int_value),
+		    PICL_PROP_ADDRESSMATCH,
+		    &int_value, PICL_PTYPE_UNSIGNED_INT);
+	}
+
+	add_md_prop(node, sizeof (id), PICL_PROP_ID, &id,
+	    PICL_PTYPE_INT);
+
+	node_count = md_scan_dag(mdp, banklistp, md_find_name(mdp, "component"),
+	    md_find_name(mdp, "fwd"), dimmlistp);
+
+	for (i = 0; i < node_count; ++i) {
+		if ((status = md_get_prop_str(mdp, dimmlistp[i], "type",
+		    (char **)&type)) == -1) {
+			status = md_get_prop_data(mdp, dimmlistp[i],
+			    "type", &type, &type_size);
+		}
+		if (status == 0) {
+			if (strcmp((const char *)type, "dimm") == 0) {
+				if (!md_get_prop_str(mdp, dimmlistp[i], "nac",
+				    (char **)&nac)) {
+					nac_size = strlen(nac) + 1;
+					add_md_prop(node, nac_size,
+					    "nac", nac,
+					    PICL_PTYPE_CHARSTRING);
+					if ((pc = strrchr(nac, '/')) != NULL)
+						nac = ++pc;
+					nac_size = strlen(nac) + 1;
+					add_md_prop(node, nac_size,
+					    PICL_PROP_LABEL, nac,
+					    PICL_PTYPE_CHARSTRING);
+				}
+			}
+		}
+	}
+}
+
+static uint64_t
+countbits(uint64_t v)
+{
+	uint64_t c;	/* c accumulates the total bits set in v */
+
+	for (c = 0; v; c++)
+		v &= v - 1;	/* clear the least significant bit set */
+	return (c);
+}
+
+static void
+add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp,
+    uint64_t interleave, uint64_t *size, uint64_t base)
+{
+	uint64_t int_value;
+
+	*size = 0;
+	if (!md_get_prop_val(mdp, segmentlistp, "size", &int_value)) {
+		add_md_prop(node, sizeof (int_value),
+		    PICL_PROP_SIZE, &int_value,
+		    PICL_PTYPE_UNSIGNED_INT);
+		*size = int_value;
+	}
+	add_md_prop(node, sizeof (base), PICL_PROP_BASEADDRESS,
+		&base, PICL_PTYPE_UNSIGNED_INT);
+
+	add_md_prop(node, sizeof (interleave), PICL_PROP_INTERLEAVE_FACTOR,
+		&interleave, PICL_PTYPE_UNSIGNED_INT);
+}
+
+static void
+add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, uint64_t size)
+{
+	uint64_t int_value;
+
+	/*
+	 * If the top-level node has a size property then use that,
+	 * otherwise use the size that was calculated by the caller
+	 * and passed in.
+	 */
+	if (md_get_prop_val(mdp, memorylistp, "size", &int_value))
+		int_value = size;
+	add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE, &int_value,
+		PICL_PTYPE_UNSIGNED_INT);
+	if (!md_get_prop_val(mdp, memorylistp, "transfer_size",
+	    &int_value)) {
+		add_md_prop(node, sizeof (int_value),
+		    PICL_PROP_TRANSFER_SIZE,
+		    &int_value, PICL_PTYPE_UNSIGNED_INT);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/pri/priplugin.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,145 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include "priplugin.h"
+
+#pragma init(priplugin_register)	/* place in .init section */
+
+picl_nodehdl_t	root_node;
+md_t		*mdp;
+mde_cookie_t	rootnode;
+
+void priplugin_init(void);
+void priplugin_fini(void);
+
+picld_plugin_reg_t priplugin_reg = {
+	PICLD_PLUGIN_VERSION_1,
+	PICLD_PLUGIN_CRITICAL,
+	"pri_plugin",
+	priplugin_init,
+	priplugin_fini
+};
+
+void
+set_prop_info(ptree_propinfo_t *propinfo, int size, char *name, int type)
+{
+	propinfo->version = PICLD_PLUGIN_VERSION_1;
+	propinfo->read = NULL;
+	propinfo->write = NULL;
+	propinfo->piclinfo.type = type;
+	propinfo->piclinfo.accessmode = PICL_READ;
+	propinfo->piclinfo.size = size;
+	(void) strncpy(propinfo->piclinfo.name, name,
+	    sizeof (propinfo->piclinfo.name));
+}
+
+boolean_t
+prop_exists(picl_nodehdl_t node, char *name)
+{
+	int status;
+	picl_prophdl_t proph;
+
+	status = ptree_get_prop_by_name(node, name, &proph);
+	if (status == PICL_SUCCESS)
+		return (B_TRUE);
+	else
+		return (B_FALSE);
+}
+
+void
+add_md_prop(picl_nodehdl_t node, int size, char *name, void* value, int type)
+{
+	ptree_propinfo_t propinfo;
+	picl_prophdl_t proph;
+
+	if (!prop_exists(node, name)) {
+		set_prop_info(&propinfo, size, name, type);
+
+		(void) ptree_create_and_add_prop(node, &propinfo,
+		    value, &proph);
+	}
+}
+
+void
+priplugin_init(void)
+{
+	int status;
+
+	pri_debug(LOG_NOTICE, "priplugin: entered\n");
+	status = ptree_get_root(&root_node);
+	if (status != PICL_SUCCESS) {
+		pri_debug(LOG_NOTICE, "priplugin: can't get picl root node\n");
+		return;
+	}
+
+	mdp = pri_devinit();
+	if (mdp == NULL) {
+		pri_debug(LOG_NOTICE, "priplugin: cannot init pri: %d\n",
+		    errno);
+		return;
+	}
+
+	rootnode = md_root_node(mdp);
+
+	pri_debug(LOG_NOTICE, "priplugin: have root picl and PRI nodes\n");
+
+	status = ptree_walk_tree_by_class(root_node, "memory",
+	    "memory-segments", add_mem_prop);
+	if (status != PICL_SUCCESS) {
+		pri_debug(LOG_NOTICE, "pri: memory-segments walk failed\n");
+	} else
+		pri_debug(LOG_NOTICE, "pri: success walking memory node\n");
+
+	io_dev_addlabel();
+
+	pri_devfini(mdp);
+}
+
+void
+priplugin_fini(void)
+{
+}
+
+void
+priplugin_register(void)
+{
+	picld_plugin_register(&priplugin_reg);
+}
+
+/*VARARGS2*/
+void
+pri_debug(int level, char *fmt, ...)
+{
+#if (PRI_DEBUG != 0)
+	va_list	ap;
+
+	va_start(ap, fmt);
+	vsyslog(level, fmt, ap);
+	va_end(ap);
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/pri/priplugin.h	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,86 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_PRIPLUGIN_H
+#define	_PRIPLUGIN_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <picl.h>
+#include <picltree.h>
+#include <picldefs.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <alloca.h>
+#include <sys/stat.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <mdesc.h>
+#include <string.h>
+#include <errno.h>
+#include <libnvpair.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <config_admin.h>
+#include <sys/param.h>
+#include <libdevinfo.h>
+#include <sys/systeminfo.h>
+#include <sys/sysevent/dr.h>
+#include <syslog.h>
+#include <stdarg.h>
+
+#define	MAXSTRLEN 256
+
+#ifndef PRI_DEBUG
+#define	PRI_DEBUG 0
+#endif
+
+/* These 3 variable are defined and set in mdescplugin.c */
+extern picl_nodehdl_t	root_node;
+extern md_t		*mdp;
+extern mde_cookie_t	rootnode;
+
+int add_mem_prop(picl_nodehdl_t node, void *args);
+md_t *pri_devinit(void);
+void pri_devfini(md_t *mdp);
+void pri_debug(int level, char *fmt, ...);
+void add_md_prop(picl_nodehdl_t node, int size, char *name, void* value,
+    int type);
+void io_dev_addlabel(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _PRIPLUGIN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/snmp/Makefile	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,97 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# cmd/picl/plugins/sun4v/snmp/Makefile
+#
+
+LIBRARY=	libsnmpplugin.a
+VERS=		.1
+
+OBJS_DIR=	pics
+OBJECTS=	snmpplugin.o
+
+# Include library definitions
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/Makefile.psm
+include $(SRC)/cmd/picl/plugins/Makefile.com
+
+SRCS=		$(OBJECTS:%.o=%.c)
+LIBS =		$(DYNLIB)
+
+ROOT_PLATFORM =	$(USR_PLAT_DIR)/sun4v
+ROOTLIBDIR =	$(ROOT_PLAT_PLUGINDIR)
+
+CLEANFILES=	$(LINTOUT) $(LINTLIB)
+
+CPPFLAGS +=	-I. -I../include -I$(SRC)/uts/common/sys
+CPPFLAGS +=	-D_REENTRANT
+
+#
+# Be careful when enabling SNMPPLUGIN_DEBUG. The debug log can quickly
+# grow too large. NEVER stress/cycle test picl with SNMPPLUGIN_DEBUG
+# enabled
+#
+#CPPFLAGS +=	-DSNMPPLUGIN_DEBUG
+
+CFLAGS +=	$(CCVERBOSE)
+LDLIBS +=	-L$(SRC)/lib/libpicltree/$(MACH)
+LDLIBS +=	-L$(SRC)/cmd/picl/plugins/sun4v/lib/snmp
+LDLIBS +=	-L$(ROOT)/usr/lib/sparcv9
+LDLIBS +=	-lc -lpicltree -lpiclsnmp
+DYNFLAGS +=	-R/usr/platform/sun4v/lib
+
+POFILE =	snmpplugin_sun4v.po
+POFILES =	$(SRCS:%.c=%.po)
+
+.KEEP_STATE:
+
+all: $(LIBS) $(LIBLINKS)
+
+install:	all $(ROOTLIBDIR) $(ROOTLIBS) $(ROOTLINKS)
+
+$(LIBLINKS):	FRC
+	$(RM) $(LIBLINKS); $(SYMLINK) $(DYNLIB) $(LIBLINKS)
+
+# Messages
+_msg:	$(MSGDOMAIN) $(POFILE)
+	$(RM) $(MSGDOMAIN)/$(POFILE)
+	$(CP) $(POFILE) $(MSGDOMAIN)/$(POFILE)
+
+$(MSGDOMAIN):
+	$(INS.dir)
+
+$(POFILE):	$(POFILES)
+	$(CAT) $(POFILES) > $(POFILE)
+
+# Include library targets
+include $(SRC)/cmd/picl/plugins/Makefile.targ
+include $(SRC)/lib/Makefile.targ
+
+lint :
+	$(LINT.c) $(SRCS)
+
+FRC:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,1690 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * The SNMP picl plugin connects to the agent on the SP and creates
+ * and populates the /physical-platform subtree in picl tree for use
+ * by picl consumers.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <thread.h>
+#include <synch.h>
+#include <errno.h>
+
+#include <picldefs.h>
+#include <picl.h>
+#include <picltree.h>
+
+#include "picloids.h"
+#include "libpiclsnmp.h"
+#include "snmpplugin.h"
+
+#pragma init(snmpplugin_register)	/* place in .init section */
+
+picld_plugin_reg_t snmpplugin_reg = {
+	PICLD_PLUGIN_VERSION_1,
+	PICLD_PLUGIN_NON_CRITICAL,
+	"snmp_plugin",
+	snmpplugin_init,
+	snmpplugin_fini
+};
+
+static picl_snmphdl_t	hdl;
+
+/*
+ * The stale_tree_rwlp protects the stale_xxx vars. The 'stale_tree' flag
+ * and the 'rebuild_tree' flag below are both initialized to B_TRUE to
+ * let the tree_builder() thread build the initial tree without blocking.
+ */
+static rwlock_t		stale_tree_rwlp;
+static boolean_t	stale_tree = B_TRUE;
+
+/*
+ * vol_props, volprop_ndx and n_vol_props are protected by the stale_tree
+ * flag.  They are read only when the stale_tree flag is B_FALSE and written
+ * to only when the flag is B_TRUE.
+ *
+ * The change_time (last changed time) is read by only one thread at a
+ * time when stale_tree is B_FALSE (protected by stale_tree_rwlp).  It is
+ * written by only one thread (the tree builder) when stale_tree is B_TRUE.
+ *
+ * Note that strictly speaking, change_time should be uint_t (timeticks32).
+ * But keeping it as int is fine, since we don't do any arithmetic on it
+ * except equality check.
+ */
+static vol_prophdl_t	*vol_props = NULL;
+static int		volprop_ndx = 0, n_vol_props = 0;
+static int		change_time = 0;
+
+/*
+ * The rebuild_tree_lock and cv are used by the tree builder thread.
+ * rebuild_tree has to be initialized to B_TRUE to let the tree_builder
+ * do the first build without blocking.
+ */
+static mutex_t		rebuild_tree_lock;
+static cond_t		rebuild_tree_cv;
+static boolean_t	rebuild_tree = B_TRUE;
+
+/*
+ * These two should really not be global
+ */
+static picl_nodehdl_t	*physplat_nodes = NULL;
+static int		n_physplat_nodes = 0;
+
+static char *group1[] = {
+	OID_entPhysicalDescr,
+	OID_entPhysicalContainedIn,
+	OID_entPhysicalClass,
+	OID_entPhysicalName,
+	OID_entPhysicalHardwareRev,
+	OID_entPhysicalFirmwareRev,
+	OID_entPhysicalSerialNum,
+	OID_entPhysicalMfgName,
+	OID_entPhysicalModelName,
+	OID_entPhysicalIsFRU,
+	0
+};
+
+static char *group2[] = {
+	OID_sunPlatEquipmentHolderAcceptableTypes,
+	OID_sunPlatCircuitPackReplaceable,
+	OID_sunPlatCircuitPackHotSwappable,
+	OID_sunPlatPhysicalClass,
+	OID_sunPlatSensorClass,
+	OID_sunPlatSensorType,
+	OID_sunPlatAlarmType,
+	OID_sunPlatPowerSupplyClass,
+	0
+};
+
+static char *volgroup1[] = {
+	OID_sunPlatBinarySensorCurrent,
+	OID_sunPlatBinarySensorExpected,
+	OID_sunPlatBinarySensorInterpretTrue,
+	OID_sunPlatBinarySensorInterpretFalse,
+	0
+};
+
+static char *volgroup2[] = {
+	OID_sunPlatNumericSensorBaseUnits,
+	OID_sunPlatNumericSensorExponent,
+	OID_sunPlatNumericSensorRateUnits,
+	OID_sunPlatNumericSensorCurrent,
+	OID_sunPlatNumericSensorLowerThresholdFatal,
+	OID_sunPlatNumericSensorLowerThresholdCritical,
+	OID_sunPlatNumericSensorLowerThresholdNonCritical,
+	OID_sunPlatNumericSensorUpperThresholdNonCritical,
+	OID_sunPlatNumericSensorUpperThresholdCritical,
+	OID_sunPlatNumericSensorUpperThresholdFatal,
+	0
+};
+
+/*
+ * The following two items must match the Sun Platform MIB specification
+ * in their indices and values.
+ */
+static char *sensor_baseunits[] = {
+	"", "other", "unknown", "degC", "degF", "degK", "volts", "amps",
+	"watts", "joules", "coulombs", "va", "nits", "lumens", "lux",
+	"candelas", "kPa", "psi", "newtons", "cfm", "rpm", "hertz",
+	"seconds", "minutes", "hours", "days", "weeks", "mils", "inches",
+	"feet", "cubicInches", "cubicFeet", "meters", "cubicCentimeters",
+	"cubicMeters", "liters", "fluidOunces", "radians", "steradians",
+	"revolutions", "cycles", "gravities", "ounces", "pounds", "footPounds",
+	"ounceInches", "gauss", "gilberts", "henries", "farads", "ohms",
+	"siemens", "moles", "becquerels", "ppm", "decibels", "dBA", "dbC",
+	"grays", "sieverts", "colorTemperatureDegK", "bits", "bytes", "words",
+	"doubleWords", "quadWords", "percentage"
+};
+static const int n_baseunits = sizeof (sensor_baseunits) / sizeof (char *);
+
+static char *sensor_rateunits[] = {
+	"",
+	"none",
+	"perMicroSecond",
+	"perMilliSecond",
+	"perSecond",
+	"perMinute",
+	"perHour",
+	"perDay",
+	"perWeek",
+	"perMonth",
+	"perYear"
+};
+static const int n_rateunits = sizeof (sensor_rateunits) / sizeof (char *);
+
+/*
+ * Local declarations
+ */
+static void snmpplugin_register(void);
+static void register_group(char **g, int is_volatile);
+static void *tree_builder(void *arg);
+static int build_physplat(picl_nodehdl_t *subtree_rootp);
+static void free_resources(picl_nodehdl_t subtree_root);
+
+static picl_nodehdl_t make_node(picl_nodehdl_t subtree_root, int row,
+    int *snmp_syserr_p);
+static void save_nodeh(picl_nodehdl_t nodeh, int row);
+static picl_nodehdl_t lookup_nodeh(int row);
+
+static void save_volprop(picl_prophdl_t prop, char *oidstr, int row,
+    int proptype);
+static void check_for_stale_data(void);
+static int read_volprop(ptree_rarg_t *parg, void *buf);
+
+static void threshold(picl_nodehdl_t node, char *oidstr, int row,
+    char *propname, int *snmp_syserr_p);
+static void add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p);
+
+static char *get_slot_type(int row, int *snmp_syserr_p);
+static int add_volatile_prop(picl_nodehdl_t nodeh, char *name,
+    int type, int access, int size, int (*rdfunc)(ptree_rarg_t *, void *),
+    int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp);
+static int add_string_prop(picl_nodehdl_t node, char *propname, char *propval);
+static int add_void_prop(picl_nodehdl_t node, char *propname);
+static int add_int_prop(picl_nodehdl_t node, char *propname, int val);
+static void add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
+    int row, sp_propid_t pp, int *snmp_syserr_p);
+
+static void log_msg(int pri, const char *fmt, ...);
+
+#ifdef SNMPPLUGIN_DEBUG
+static mutex_t	snmpplugin_dbuf_lock;
+static char	*snmpplugin_dbuf = NULL;
+static char	*snmpplugin_dbuf_curp = NULL;
+static int	snmpplugin_dbuf_sz = 0;
+static int	snmpplugin_dbuf_overflow = 0;
+static char	snmpplugin_lbuf[SNMPPLUGIN_DMAX_LINE];
+
+static void	snmpplugin_log_init(void);
+static void	snmpplugin_log(const char *fmt, ...);
+static void	snmpplugin_log_append(void);
+static void	snmpplugin_dbuf_realloc(void);
+#endif
+
+static void
+snmpplugin_register(void)
+{
+	(void) picld_plugin_register(&snmpplugin_reg);
+}
+
+static void
+register_group(char **g, int is_volatile)
+{
+	int	i, len = 0;
+	int	n_oids;
+	char	*p, *oidstrs;
+
+	for (i = 0; g[i]; i++)
+		len += strlen(g[i]) + 1;
+	n_oids = i;
+
+	if ((oidstrs = (char *)calloc(1, len)) == NULL)
+		return;
+
+	for (p = oidstrs, i = 0; g[i]; i++) {
+		(void) strcpy(p, g[i]);
+		p += strlen(g[i]) + 1;
+	}
+
+	snmp_register_group(hdl, oidstrs, n_oids, is_volatile);
+}
+
+void
+snmpplugin_init(void)
+{
+	int		ret;
+
+	(void) mutex_init(&rebuild_tree_lock, USYNC_THREAD, NULL);
+	(void) cond_init(&rebuild_tree_cv, USYNC_THREAD, NULL);
+	(void) rwlock_init(&stale_tree_rwlp, USYNC_THREAD, NULL);
+	LOGINIT();
+
+	/*
+	 * Create the tree-builder thread and let it take over
+	 */
+	LOGPRINTF("Tree-builder thread being created.\n");
+	if ((ret = thr_create(NULL, NULL, tree_builder, NULL,
+	    THR_BOUND, NULL)) < 0) {
+		log_msg(LOG_ERR, SNMPP_CANT_CREATE_TREE_BUILDER, ret);
+		snmp_fini(hdl);
+		return;
+	}
+}
+
+void
+snmpplugin_fini(void)
+{
+	snmp_fini(hdl);
+
+	(void) rwlock_destroy(&stale_tree_rwlp);
+	(void) cond_destroy(&rebuild_tree_cv);
+	(void) mutex_destroy(&rebuild_tree_lock);
+}
+
+/*ARGSUSED*/
+static void *
+tree_builder(void *arg)
+{
+	int		ret, rv;
+	picl_nodehdl_t	root_node;
+	picl_nodehdl_t	physplat_root;
+	picl_nodehdl_t	old_physplat_root;
+
+	/*
+	 * Initialize SNMP service
+	 */
+	LOGPRINTF("Initializing SNMP service.\n");
+	if ((hdl = snmp_init()) == NULL) {
+		log_msg(LOG_ERR, SNMPP_CANT_INIT);
+		return ((void *)-1);
+	}
+
+	/*
+	 * Register OID groupings for BULKGET optimizations
+	 */
+	LOGPRINTF("Registering OID groups.\n");
+	register_group(group1, 0);
+	register_group(group2, 0);
+	register_group(volgroup1, 1);
+	register_group(volgroup2, 1);
+
+	(void) mutex_lock(&rebuild_tree_lock);
+
+	for (;;) {
+		LOGPRINTF("tree_builder: check whether to rebuild subtree\n");
+		while (rebuild_tree == B_FALSE)
+			(void) cond_wait(&rebuild_tree_cv, &rebuild_tree_lock);
+
+		LOGPRINTF("tree_builder: woke up\n");
+
+		old_physplat_root = NULL;
+		physplat_root = NULL;
+
+		LOGPRINTF("tree_builder: getting root node\n");
+		if ((ret = ptree_get_root(&root_node)) != PICL_SUCCESS) {
+			log_msg(LOG_ERR, SNMPP_NO_ROOT, ret);
+			return ((void *)-2);
+		}
+
+		LOGPRINTF("tree_builder: getting existing physplat node\n");
+		rv = ptree_find_node(root_node, PICL_PROP_NAME,
+		    PICL_PTYPE_CHARSTRING, PICL_NODE_PHYSPLAT,
+		    sizeof (PICL_NODE_PHYSPLAT), &old_physplat_root);
+
+		LOGPRINTF("tree_builder: building physical-platform\n");
+		if ((ret = build_physplat(&physplat_root)) < 0) {
+			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
+			snmp_fini(hdl);
+			return ((void *)-3);
+		}
+
+		if (rv == PICL_SUCCESS && old_physplat_root != NULL) {
+			LOGPRINTF("tree_builder: destroying existing nodes\n");
+			ptree_delete_node(old_physplat_root);
+			ptree_destroy_node(old_physplat_root);
+		}
+
+		LOGPRINTF("tree_builder: attaching new subtree\n");
+		if ((ret = ptree_add_node(root_node, physplat_root)) < 0) {
+			free_resources(physplat_root);
+			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
+			snmp_fini(hdl);
+			return ((void *)-4);
+		}
+
+		LOGPRINTF("tree_builder: setting stale_tree to FALSE\n");
+		(void) rw_wrlock(&stale_tree_rwlp);
+		stale_tree = B_FALSE;
+		(void) rw_unlock(&stale_tree_rwlp);
+
+		LOGPRINTF("tree_builder: setting rebuild_tree to FALSE\n");
+		rebuild_tree = B_FALSE;
+	}
+
+	/*NOTREACHED*/
+	return (NULL);
+}
+
+static int
+build_physplat(picl_nodehdl_t *subtree_rootp)
+{
+	int	change_time1;
+	int	row, nxtrow;
+	int	clr_linkreset = 0;
+	int	ret = 0;
+	int	snmp_syserr = 0;
+
+retry:
+	(void) snmp_reinit(hdl, clr_linkreset);
+	clr_linkreset = 0;
+
+	/*
+	 * Record LastChangeTime before we start building the tree
+	 */
+	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
+	    &change_time1, &snmp_syserr);
+	if (ret < 0) {
+		if (snmp_syserr == ECANCELED) {
+			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
+			clr_linkreset = 1;
+			goto retry;
+		} else
+			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
+	}
+
+	/*
+	 * Create the physical-platform node
+	 */
+	ret = ptree_create_node(PICL_NODE_PHYSPLAT, PICL_CLASS_PICL,
+	    subtree_rootp);
+	if (ret != PICL_SUCCESS)
+		return (-1);
+
+	/*
+	 * Scan entPhysicalTable and build the "physical-platform" subtree
+	 */
+	ret = 0;
+	for (row = -1; ret == 0; row = nxtrow) {
+		ret = snmp_get_nextrow(hdl, OID_entPhysicalDescr,
+		    row, &nxtrow, &snmp_syserr);
+		if (ret == 0) {
+			(void) make_node(*subtree_rootp, nxtrow, &snmp_syserr);
+		}
+
+		if (snmp_syserr == ECANCELED) {
+			/*
+			 * If we get this error, a link reset must've
+			 * happened and we need to throw away everything
+			 * we have now and rebuild the tree again.
+			 */
+			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
+			free_resources(*subtree_rootp);
+			clr_linkreset = 1;
+			goto retry;
+		}
+	}
+
+	/*
+	 * Record LastChangeTime after we're done building the tree
+	 */
+	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
+	    &change_time, &snmp_syserr);
+	if (ret < 0) {
+		if (snmp_syserr == ECANCELED) {
+			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
+			free_resources(*subtree_rootp);
+			clr_linkreset = 1;
+			goto retry;
+		} else
+			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
+	}
+
+	/*
+	 * If they don't match, some hotplugging must've happened,
+	 * free resources we've created and still holding, then go
+	 * back and retry
+	 */
+	if (change_time != change_time1) {
+		LOGPRINTF("build_physplat: entLastChangeTime has changed!\n");
+		free_resources(*subtree_rootp);
+		change_time1 = change_time;
+		goto retry;
+	}
+
+	/*
+	 * The physplat_nodes table is no longer needed, free it
+	 */
+	if (physplat_nodes) {
+		free(physplat_nodes);
+		physplat_nodes = NULL;
+		n_physplat_nodes = 0;
+	}
+
+	return (0);
+}
+
+/*
+ * Destroy all resources that were created during the building
+ * of the subtree
+ */
+static void
+free_resources(picl_nodehdl_t subtree_root)
+{
+	if (physplat_nodes) {
+		free(physplat_nodes);
+		physplat_nodes = NULL;
+		n_physplat_nodes = 0;
+	}
+
+	if (subtree_root) {
+		(void) ptree_delete_node(subtree_root);
+		(void) ptree_destroy_node(subtree_root);
+	}
+
+	if (vol_props) {
+		free(vol_props);
+		n_vol_props = 0;
+		volprop_ndx = 0;
+	}
+}
+
+static picl_nodehdl_t
+make_node(picl_nodehdl_t subtree_root, int row, int *snmp_syserr_p)
+{
+	picl_nodehdl_t	nodeh, parenth;
+	picl_prophdl_t	proph;
+	char	*phys_name, *node_name;
+	int	parent_row;
+	int	ent_physclass, sunplat_physclass;
+	int	sensor_class, sensor_type;
+	int	alarm_type;
+	int	ps_class;
+	int	ret;
+
+	/*
+	 * If we've already created this picl node, just return it
+	 */
+	if ((nodeh = lookup_nodeh(row)) != NULL)
+		return (nodeh);
+
+	/*
+	 * If we are creating it only now, make sure we have the parent
+	 * created first; if there's no parent, then parent it to the
+	 * subtree's root node
+	 */
+	ret = snmp_get_int(hdl, OID_entPhysicalContainedIn, row,
+	    &parent_row, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+	if (ret < 0 || parent_row <= 0)
+		parenth = subtree_root;
+	else {
+		parenth = make_node(subtree_root, parent_row, snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		if (parenth == NULL)
+			parenth = subtree_root;
+	}
+
+	/*
+	 * Figure out the physical-platform node name from entPhysicalName;
+	 * all rows in the MIB that have a valid entPhysicalIndex should
+	 * have a physical name.
+	 */
+	ret = snmp_get_str(hdl, OID_entPhysicalName, row,
+	    &phys_name, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+	if (ret < 0 || phys_name == NULL) {
+		log_msg(LOG_WARNING, SNMPP_NO_ENTPHYSNAME, row);
+		return (NULL);
+	}
+
+	node_name = basename(phys_name);
+
+	ret = snmp_get_int(hdl, OID_entPhysicalClass, row,
+	    &ent_physclass, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+	if (ret < 0) {
+		log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
+		free(phys_name);
+		return (NULL);
+	}
+
+	switch (ent_physclass) {
+	case SPC_OTHER:
+		ret = snmp_get_int(hdl, OID_sunPlatPhysicalClass, row,
+		    &sunplat_physclass, snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		if (ret < 0) {
+			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
+			free(phys_name);
+			return (NULL);
+		}
+
+		if (sunplat_physclass == SSPC_ALARM) {
+			ret = snmp_get_int(hdl, OID_sunPlatAlarmType,
+			    row, &alarm_type, snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+			if (ret < 0) {
+				log_msg(LOG_WARNING,
+				    SNMPP_CANT_FETCH_OBJECT_VAL, ret);
+				free(phys_name);
+				return (NULL);
+			}
+
+			if (alarm_type == SSAT_VISIBLE) {
+			    ADD_NODE(PICL_CLASS_LED)
+			} else {
+			    ADD_NODE(PICL_CLASS_ALARM)
+			}
+
+			add_prop(nodeh, &proph, node_name, row, PP_STATE,
+			    snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+		} else {
+			ADD_NODE(PICL_CLASS_OTHER)
+		}
+
+		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		break;
+
+	case SPC_UNKNOWN:
+		ADD_NODE(PICL_CLASS_UNKNOWN)
+		break;
+
+	case SPC_CHASSIS:
+		ADD_NODE(PICL_CLASS_CHASSIS)
+		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		break;
+
+	case SPC_BACKPLANE:
+		ADD_NODE(PICL_CLASS_BACKPLANE)
+		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		break;
+
+	case SPC_CONTAINER:
+		ADD_NODE(PICL_CLASS_CONTAINER)
+
+		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+		add_prop(nodeh, &proph, node_name, row, PP_SLOT_TYPE,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		break;
+
+	case SPC_POWERSUPPLY:
+		ret = snmp_get_int(hdl, OID_sunPlatPowerSupplyClass,
+		    row, &ps_class, snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		if (ret < 0) {
+			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
+			free(phys_name);
+			return (NULL);
+		}
+
+		if (ps_class == SSPSC_BATTERY) {
+			ADD_NODE(PICL_CLASS_BATTERY)
+			add_prop(nodeh, &proph, node_name, row,
+			    PP_BATT_STATUS, snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+		} else {
+			ADD_NODE(PICL_CLASS_POWERSUPPLY)
+		}
+		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		break;
+
+	case SPC_FAN:
+		ADD_NODE(PICL_CLASS_FAN)
+		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		break;
+
+	case SPC_SENSOR:
+		ret = snmp_get_int(hdl, OID_sunPlatSensorClass,
+		    row, &sensor_class, snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		if (ret < 0) {
+			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
+			free(phys_name);
+			return (NULL);
+		}
+
+		ret = snmp_get_int(hdl, OID_sunPlatSensorType,
+		    row, &sensor_type, snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		if (ret < 0) {
+			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
+			free(phys_name);
+			return (NULL);
+		}
+
+		if (sensor_class == SSSC_NUMERIC) {
+			if (sensor_type == SSST_TEMPERATURE) {
+				ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR)
+				add_prop(nodeh, &proph, node_name, row,
+				    PP_TEMPERATURE, snmp_syserr_p);
+			} else if (sensor_type == SSST_VOLTAGE) {
+				ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR)
+				add_prop(nodeh, &proph, node_name, row,
+				    PP_VOLTAGE, snmp_syserr_p);
+			} else if (sensor_type == SSST_CURRENT) {
+				ADD_NODE(PICL_CLASS_CURRENT_SENSOR)
+				add_prop(nodeh, &proph, node_name, row,
+				    PP_CURRENT, snmp_syserr_p);
+			} else if (sensor_type == SSST_TACHOMETER) {
+				ADD_NODE(PICL_CLASS_RPM_SENSOR)
+				add_prop(nodeh, &proph, node_name, row,
+				    PP_SPEED, snmp_syserr_p);
+			} else {
+				ADD_NODE(PICL_CLASS_SENSOR)
+				add_prop(nodeh, &proph, node_name, row,
+				    PP_SENSOR_VALUE, snmp_syserr_p);
+			}
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+			add_prop(nodeh, &proph, node_name, row,
+			    PP_OPSTATUS, snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+			add_prop(nodeh, &proph, node_name, row,
+			    PP_BASE_UNITS, snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+			add_prop(nodeh, &proph, node_name, row,
+			    PP_EXPONENT, snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+			add_prop(nodeh, &proph, node_name, row,
+			    PP_RATE_UNITS, snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+			add_thresholds(nodeh, row, snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+		} else if (sensor_class == SSSC_BINARY) {
+			if (sensor_type == SSST_TEMPERATURE) {
+				ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR)
+			} else if (sensor_type == SSST_VOLTAGE) {
+				ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR)
+			} else if (sensor_type == SSST_CURRENT) {
+				ADD_NODE(PICL_CLASS_CURRENT_INDICATOR)
+			} else if (sensor_type == SSST_TACHOMETER) {
+				ADD_NODE(PICL_CLASS_RPM_INDICATOR)
+			} else if (sensor_type == SSST_PRESENCE) {
+				ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR)
+			} else {
+				ADD_NODE(PICL_CLASS_INDICATOR)
+			}
+
+			add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
+			    snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+			add_prop(nodeh, &proph, node_name, row, PP_CONDITION,
+			    snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+			add_prop(nodeh, &proph, node_name, row, PP_EXPECTED,
+			    snmp_syserr_p);
+			CHECK_LINKRESET(snmp_syserr_p, NULL)
+		} else {
+			log_msg(LOG_ERR,
+			    SNMPP_UNSUPP_SENSOR_CLASS, sensor_class, row);
+			return (NULL);
+		}
+		break;
+
+	case SPC_MODULE:
+		ADD_NODE(PICL_CLASS_MODULE)
+
+		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+		add_prop(nodeh, &proph, node_name, row, PP_REPLACEABLE,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+		add_prop(nodeh, &proph, node_name, row, PP_HOTSWAPPABLE,
+		    snmp_syserr_p);
+		CHECK_LINKRESET(snmp_syserr_p, NULL)
+		break;
+
+	case SPC_PORT:
+		ADD_NODE(PICL_CLASS_PORT)
+		break;
+
+	case SPC_STACK:
+		ADD_NODE(PICL_CLASS_STACK)
+		break;
+
+	default:
+		log_msg(LOG_WARNING,
+		    SNMPP_UNKNOWN_ENTPHYSCLASS, ent_physclass, row);
+		free(phys_name);
+		return (NULL);
+	}
+
+	add_prop(nodeh, &proph, node_name, row, PP_DESCRIPTION, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+	add_prop(nodeh, &proph, node_name, row, PP_LABEL, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+	add_prop(nodeh, &proph, node_name, row, PP_HW_REVISION, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+	add_prop(nodeh, &proph, node_name, row, PP_FW_REVISION, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+	add_prop(nodeh, &proph, node_name, row, PP_SERIAL_NUM, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+	add_prop(nodeh, &proph, node_name, row, PP_MFG_NAME, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+	add_prop(nodeh, &proph, node_name, row, PP_MODEL_NAME, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+	add_prop(nodeh, &proph, node_name, row, PP_IS_FRU, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+	free(phys_name);
+	save_nodeh(nodeh, row);
+
+	return (nodeh);
+}
+
+/*
+ * Saves the node handle and the row id into physplat_nodes[]. If we're
+ * doing this in response to a hotplug event, we should've freed the
+ * old physplat_nodes before entering here to save the first node of the
+ * new physplat subtree.
+ */
+static void
+save_nodeh(picl_nodehdl_t nodeh, int row)
+{
+	size_t		sz, count;
+	picl_nodehdl_t	*p;
+
+	if (row >= n_physplat_nodes) {
+		count = (((size_t)row >> NODE_BLOCK_SHIFT) + 1) *
+		    N_ELEMS_IN_NODE_BLOCK;
+		sz = count * sizeof (picl_nodehdl_t);
+
+		p = (picl_nodehdl_t *)calloc(count, sizeof (picl_nodehdl_t));
+		if (p == NULL) {
+			log_msg(LOG_ERR, SNMPP_NO_MEM, sz);
+			return;
+		}
+
+		if (physplat_nodes) {
+			(void) memcpy((void *) p, (void *) physplat_nodes,
+			    n_physplat_nodes * sizeof (picl_nodehdl_t));
+			free((void *) physplat_nodes);
+		}
+
+		physplat_nodes = p;
+		n_physplat_nodes = count;
+	}
+
+	physplat_nodes[row] = nodeh;
+}
+
+static picl_nodehdl_t
+lookup_nodeh(int row)
+{
+	if (row >= n_physplat_nodes)
+		return (NULL);
+
+	return (physplat_nodes[row]);
+}
+
+/*
+ * We enter this routine only when we are building the physical-platform
+ * subtree, whether for the first time or in response to a hotplug event.
+ * If we're here for rebuilding the tree, we have already set stale_tree
+ * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props
+ * or volprop_ndx. If we're here to build the tree for the first time,
+ * picld hasn't yet created doors and is running single-threaded, so no
+ * one else would be accessing them anyway.
+ */
+static void
+save_volprop(picl_prophdl_t prop, char *oidstr, int row, int proptype)
+{
+	vol_prophdl_t	*p;
+	int		count;
+
+	if (volprop_ndx == n_vol_props) {
+		count = n_vol_props + N_ELEMS_IN_VOLPROP_BLOCK;
+		p = (vol_prophdl_t *)calloc(count, sizeof (vol_prophdl_t));
+		if (p == NULL) {
+			log_msg(LOG_ERR, SNMPP_NO_MEM,
+			    count * sizeof (vol_prophdl_t));
+			return;
+		}
+
+		if (vol_props) {
+			(void) memcpy((void *) p, (void *) vol_props,
+			    n_vol_props * sizeof (vol_prophdl_t));
+			free((void *) vol_props);
+		}
+
+		vol_props = p;
+		n_vol_props += N_ELEMS_IN_VOLPROP_BLOCK;
+	}
+
+	vol_props[volprop_ndx].prop = prop;
+	vol_props[volprop_ndx].oidstr = oidstr;
+	vol_props[volprop_ndx].row = row;
+	vol_props[volprop_ndx].proptype = proptype;
+
+	volprop_ndx++;
+}
+
+static void
+check_for_stale_data(void)
+{
+	int	cur_change_time;
+	int	ret;
+	int	snmp_syserr;
+
+	(void) rw_wrlock(&stale_tree_rwlp);
+
+	/*
+	 * Check if some other thread beat us to it
+	 */
+	if (stale_tree == B_TRUE) {
+		(void) rw_unlock(&stale_tree_rwlp);
+		return;
+	}
+
+	/*
+	 * Check if mib data has changed (hotplug? link-reset?)
+	 */
+	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, &cur_change_time,
+	    &snmp_syserr);
+	if ((ret == 0) && (cur_change_time == change_time)) {
+		(void) rw_unlock(&stale_tree_rwlp);
+		return;
+	}
+
+	/*
+	 * If we can't read entLastChangeTime we assume we need to rebuild
+	 * the tree. This will also cover the case when we need to rebuild
+	 * the tree because a link reset had happened.
+	 */
+	LOGPRINTF2("check_for_stale_data: LastChange times have changed, "
+	    "(%#x != %#x)\n", change_time, cur_change_time);
+
+	/*
+	 * If the mib data has changed, we need to rebuild the physical-platform
+	 * subtree. To do this, we set a flag to mark the tree stale,
+	 * so that any future reads to get value of volatile properties will
+	 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag
+	 * is reset by the tree builder thread.
+	 */
+	stale_tree = B_TRUE;
+	if (vol_props) {
+		free(vol_props);
+	}
+	vol_props = NULL;
+	volprop_ndx = 0;
+	n_vol_props = 0;
+
+	(void) rw_unlock(&stale_tree_rwlp);
+
+	(void) mutex_lock(&rebuild_tree_lock);
+	rebuild_tree = B_TRUE;
+	(void) cond_signal(&rebuild_tree_cv);
+	LOGPRINTF("check_for_stale_data: signalled tree builder\n");
+	(void) mutex_unlock(&rebuild_tree_lock);
+}
+
+/*
+ * This is the critical routine.  This callback is invoked by picl whenever
+ * it needs to fetch the value of a volatile property. The first thing we
+ * must do, however, is to see if there has been a hotplug or a link-reset
+ * event since the last time we built the tree and whether we need to
+ * rebuild the tree. If so, we do whatever is necessary to make that happen,
+ * but return PICL_PROPVALUNAVAILABLE for now, without making any further
+ * snmp requests or accessing any globals.
+ */
+static int
+read_volprop(ptree_rarg_t *parg, void *buf)
+{
+	char	*pstr;
+	int	propval;
+	int	i, ndx;
+	int	ret;
+	int	snmp_syserr = 0;
+
+	/*
+	 * First check for any event that would make us throw away
+	 * the existing /physical-platform subtree and rebuild
+	 * another one. If we are rebuilding the subtree, we just
+	 * return the stale value until the tree is fully built.
+	 */
+	check_for_stale_data();
+
+	(void) rw_rdlock(&stale_tree_rwlp);
+
+	if (stale_tree == B_TRUE) {
+		(void) rw_unlock(&stale_tree_rwlp);
+		return (PICL_PROPVALUNAVAILABLE);
+	}
+
+	for (i = 0; i < volprop_ndx; i++) {
+		if (vol_props[i].prop == parg->proph) {
+			ndx = i;
+			break;
+		}
+	}
+	if (i == volprop_ndx) {
+		log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph);
+		return (PICL_FAILURE);
+	}
+
+	/*
+	 * If we can't read the value, return failure. Even if this was
+	 * due to a link reset, between the check for stale data and now,
+	 * the next volatile callback by picl will initiate a tree-rebuild.
+	 */
+	ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row,
+	    &propval, &snmp_syserr);
+	if (ret < 0) {
+		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, ret);
+		return (PICL_FAILURE);
+	}
+
+	switch (vol_props[ndx].proptype) {
+	case VPT_PLATOPSTATE:
+		if (propval == SSOS_DISABLED) {
+			(void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN);
+		} else if (propval == SSOS_ENABLED) {
+			(void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN);
+		} else {
+			log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE,
+			    propval, vol_props[ndx].row);
+			return (PICL_FAILURE);
+		}
+		break;
+
+	case VPT_NUMSENSOR:
+		(void) memcpy(buf, &propval, sizeof (propval));
+		break;
+
+	case VPT_BINSENSOR:
+		if (propval == ST_TRUE) {
+			ret = snmp_get_str(hdl,
+			    OID_sunPlatBinarySensorInterpretTrue,
+			    vol_props[ndx].row, &pstr, &snmp_syserr);
+			if (snmp_syserr == ECANCELED)
+				return (PICL_FAILURE);
+			if (ret < 0 || pstr == NULL) {
+				(void) strlcpy(buf, STR_ST_TRUE,
+				    MAX_TRUTHVAL_LEN);
+			} else {
+				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
+				free(pstr);
+			}
+		} else if (propval == ST_FALSE) {
+			ret = snmp_get_str(hdl,
+			    OID_sunPlatBinarySensorInterpretFalse,
+			    vol_props[ndx].row, &pstr, &snmp_syserr);
+			if (snmp_syserr == ECANCELED)
+				return (PICL_FAILURE);
+			if (ret < 0 || pstr == NULL) {
+				(void) strlcpy(buf, STR_ST_FALSE,
+				    MAX_TRUTHVAL_LEN);
+			} else {
+				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
+				free(pstr);
+			}
+		} else {
+			log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT,
+			    propval, vol_props[ndx].row);
+			return (PICL_FAILURE);
+		}
+		break;
+
+	case VPT_ALARMSTATE:
+		if (propval == SSAS_OFF) {
+			(void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN);
+		} else if (propval == SSAS_STEADY) {
+			(void) strlcpy(buf, STR_SSAS_STEADY,
+			    MAX_ALARMSTATE_LEN);
+		} else if (propval == SSAS_ALTERNATING) {
+			(void) strlcpy(buf, STR_SSAS_ALTERNATING,
+			    MAX_ALARMSTATE_LEN);
+		} else {
+			(void) strlcpy(buf, STR_SSAS_UNKNOWN,
+			    MAX_ALARMSTATE_LEN);
+		}
+		break;
+
+	case VPT_BATTERYSTATUS:
+		switch (propval) {
+		case SSBS_OTHER:
+			(void) strlcpy(buf, STR_SSBS_OTHER,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_FULLYCHARGED:
+			(void) strlcpy(buf, STR_SSBS_FULLYCHARGED,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_LOW:
+			(void) strlcpy(buf, STR_SSBS_LOW,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_CRITICAL:
+			(void) strlcpy(buf, STR_SSBS_CRITICAL,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_CHARGING:
+			(void) strlcpy(buf, STR_SSBS_CHARGING,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_CHARGING_AND_LOW:
+			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_CHARGING_AND_HIGH:
+			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_CHARGING_AND_CRITICAL:
+			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_UNDEFINED:
+			(void) strlcpy(buf, STR_SSBS_UNDEFINED,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_PARTIALLY_CHARGED:
+			(void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		case SSBS_UNKNOWN:
+		default:
+			(void) strlcpy(buf, STR_SSBS_UNKNOWN,
+			    MAX_BATTERYSTATUS_LEN);
+			break;
+		}
+		break;
+	}
+
+	(void) rw_unlock(&stale_tree_rwlp);
+
+	return (PICL_SUCCESS);
+}
+
+static void
+threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname,
+    int *snmp_syserr_p)
+{
+	picl_prophdl_t	prop;
+	int		err;
+	int		val;
+
+	if (snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p) != -1) {
+		err = add_volatile_prop(node, propname, PICL_PTYPE_INT,
+		    PICL_READ, sizeof (int), read_volprop, NULL, &prop);
+		if (err == PICL_SUCCESS)
+			save_volprop(prop, oidstr, row, VPT_NUMSENSOR);
+	}
+}
+
+static void
+add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p)
+{
+	uchar_t	*bitstr = NULL;
+	uchar_t	enabled;
+	uint_t	nbytes;
+	int	ret;
+
+	ret = snmp_get_bitstr(hdl, OID_sunPlatNumericSensorEnabledThresholds,
+	    row, &bitstr, &nbytes, snmp_syserr_p);
+	CHECK_LINKRESET_VOID(snmp_syserr_p)
+
+	if (ret < 0 || bitstr == NULL || nbytes > 2)
+		enabled = 0xff;
+	else if (nbytes == 1) {
+		/*
+		 * The ALOM snmp agent doesn't adhere to the BER rules for
+		 * encoding bit strings. While the BER states that bitstrings
+		 * must begin from the second octet after length, and the
+		 * first octet after length must indicate the number of unused
+		 * bits in the last octet, the snmp agent simply sends the
+		 * bitstring data as if it were octet string -- that is, the
+		 * "unused bits" octet is missing.
+		 */
+		enabled = bitstr[0];
+	} else if (nbytes == 2)
+		enabled = bitstr[1];
+
+	if (bitstr) {
+		free(bitstr);
+	}
+
+	if (enabled & LOWER_FATAL) {
+		threshold(node,
+		    OID_sunPlatNumericSensorLowerThresholdFatal, row,
+		    PICL_PROP_LOW_POWER_OFF, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+	}
+	if (enabled & LOWER_CRITICAL) {
+		threshold(node,
+		    OID_sunPlatNumericSensorLowerThresholdCritical, row,
+		    PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+	}
+	if (enabled & LOWER_NON_CRITICAL) {
+		threshold(node,
+		    OID_sunPlatNumericSensorLowerThresholdNonCritical, row,
+		    PICL_PROP_LOW_WARNING, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+	}
+	if (enabled & UPPER_NON_CRITICAL) {
+		threshold(node,
+		    OID_sunPlatNumericSensorUpperThresholdNonCritical, row,
+		    PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+	}
+	if (enabled & UPPER_CRITICAL) {
+		threshold(node,
+		    OID_sunPlatNumericSensorUpperThresholdCritical, row,
+		    PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+	}
+	if (enabled & UPPER_FATAL) {
+		threshold(node,
+		    OID_sunPlatNumericSensorUpperThresholdFatal, row,
+		    PICL_PROP_HIGH_WARNING, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+	}
+}
+
+static char *
+get_slot_type(int row, int *snmp_syserr_p)
+{
+	char	*p;
+	char	*slott = NULL;
+	int	ret;
+
+	ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes,
+	    row, &p, snmp_syserr_p);
+	CHECK_LINKRESET(snmp_syserr_p, NULL)
+
+	if ((ret == 0) && p && *p) {
+		slott = p;
+		if ((p = strchr(slott, '\n')) != NULL)
+			*p = 0;
+	} else {
+		log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row);
+		if (p) {
+			free(p);
+		}
+	}
+
+	return (slott);
+}
+
+/*
+ * Create and add the specified volatile property
+ */
+static int
+add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access,
+    int size, int (*rdfunc)(ptree_rarg_t *, void *),
+    int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp)
+{
+	ptree_propinfo_t	propinfo;
+	picl_prophdl_t		prop;
+	int			err;
+
+	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
+	    type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc);
+	if (err != PICL_SUCCESS) {
+		log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err);
+		return (err);
+	}
+
+	err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop);
+	if (err != PICL_SUCCESS) {
+		log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node);
+		return (err);
+	}
+
+	if (propp)
+		*propp = prop;
+
+	return (PICL_SUCCESS);
+}
+
+/*
+ * Add the specified string property to the node
+ */
+static int
+add_string_prop(picl_nodehdl_t node, char *propname, char *propval)
+{
+	ptree_propinfo_t	propinfo;
+	int			err;
+
+	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
+	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1,
+	    propname, NULL, NULL);
+	if (err != PICL_SUCCESS) {
+		log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err);
+		return (err);
+	}
+
+	err = ptree_create_and_add_prop(node, &propinfo, propval, NULL);
+	if (err != PICL_SUCCESS) {
+		log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node);
+		return (err);
+	}
+
+	return (PICL_SUCCESS);
+}
+
+/*
+ * Add the specified void property to the node
+ */
+static int
+add_void_prop(picl_nodehdl_t node, char *propname)
+{
+	ptree_propinfo_t	propinfo;
+	int			err;
+
+	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
+	    PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL);
+	if (err != PICL_SUCCESS) {
+		log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err);
+		return (err);
+	}
+
+	err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL);
+	if (err != PICL_SUCCESS) {
+		log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node);
+		return (err);
+	}
+
+	return (PICL_SUCCESS);
+}
+
+static int
+add_int_prop(picl_nodehdl_t node, char *propname, int val)
+{
+	ptree_propinfo_t	propinfo;
+	int			propval = val;
+	int			err;
+
+	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
+	    PICL_PTYPE_INT, PICL_READ, sizeof (int),
+	    propname, NULL, NULL);
+	if (err != PICL_SUCCESS) {
+		log_msg(LOG_ERR, SNMPP_CANT_INIT_INT_PROPINFO, err);
+		return (err);
+	}
+
+	err = ptree_create_and_add_prop(node, &propinfo, &propval, NULL);
+	if (err != PICL_SUCCESS) {
+		log_msg(LOG_ERR, SNMPP_CANT_ADD_INT_PROP, err, node);
+		return (err);
+	}
+
+	return (PICL_SUCCESS);
+}
+
+static void
+add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
+    int row, sp_propid_t pp, int *snmp_syserr_p)
+{
+	char	*serial_num;
+	char	*slot_type;
+	char	*fw_revision, *hw_revision;
+	char	*mfg_name, *model_name;
+	char	*phys_descr;
+	int	val;
+	int	ret;
+
+	switch (pp) {
+	case PP_SERIAL_NUM:
+		ret = snmp_get_str(hdl, OID_entPhysicalSerialNum,
+		    row, &serial_num, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && serial_num && *serial_num) {
+			(void) add_string_prop(nodeh,
+			    PICL_PROP_SERIAL_NUMBER, serial_num);
+			free((void *) serial_num);
+		}
+		break;
+
+	case PP_SLOT_TYPE:
+		if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) {
+			CHECK_LINKRESET_VOID(snmp_syserr_p)
+			(void) add_string_prop(nodeh,
+			    PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE);
+		} else {
+			(void) add_string_prop(nodeh,
+			    PICL_PROP_SLOT_TYPE, slot_type);
+			free((void *) slot_type);
+		}
+		break;
+
+	case PP_STATE:
+		ret = add_volatile_prop(nodeh, PICL_PROP_STATE,
+		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN,
+		    read_volprop, NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php, OID_sunPlatAlarmState, row,
+			    VPT_ALARMSTATE);
+		}
+		break;
+
+	case PP_OPSTATUS:
+		ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS,
+		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN,
+		    read_volprop, NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php,
+			    OID_sunPlatEquipmentOperationalState, row,
+			    VPT_PLATOPSTATE);
+		}
+		break;
+
+	case PP_BATT_STATUS:
+		ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS,
+			PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN,
+			read_volprop, NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php, OID_sunPlatBatteryStatus, row,
+			    VPT_BATTERYSTATUS);
+		}
+		break;
+
+	case PP_TEMPERATURE:
+		ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE,
+		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
+		    NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
+			    row, VPT_NUMSENSOR);
+		}
+		break;
+
+	case PP_VOLTAGE:
+		ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE,
+		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
+		    NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
+			    row, VPT_NUMSENSOR);
+		}
+		break;
+
+	case PP_CURRENT:
+		ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT,
+		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
+		    NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
+			    row, VPT_NUMSENSOR);
+		}
+		break;
+
+	case PP_SPEED:
+		ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT,
+		    PICL_READ, sizeof (int), read_volprop, NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
+			    row, VPT_NUMSENSOR);
+		}
+		break;
+
+	case PP_SENSOR_VALUE:
+		ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE,
+		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
+		    NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
+			    row, VPT_NUMSENSOR);
+		}
+		break;
+
+	case PP_CONDITION:
+		ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION,
+		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
+		    read_volprop, NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php, OID_sunPlatBinarySensorCurrent,
+			    row, VPT_BINSENSOR);
+		}
+		break;
+
+	case PP_EXPECTED:
+		ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED,
+		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
+		    read_volprop, NULL, php);
+		if (ret == PICL_SUCCESS) {
+			save_volprop(*php, OID_sunPlatBinarySensorExpected,
+			    row, VPT_BINSENSOR);
+		}
+		break;
+
+	case PP_REPLACEABLE:
+		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable,
+		    row, &val, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && (val == ST_TRUE))
+			(void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE);
+		break;
+
+	case PP_HOTSWAPPABLE:
+		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable,
+		    row, &val, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && (val == ST_TRUE))
+			(void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE);
+		break;
+
+	case PP_IS_FRU:
+		ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row,
+		    &val, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && (val == ST_TRUE))
+			(void) add_void_prop(nodeh, PICL_PROP_IS_FRU);
+		break;
+
+	case PP_HW_REVISION:
+		ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev,
+		    row, &hw_revision, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && hw_revision && *hw_revision) {
+			(void) add_string_prop(nodeh,
+			    PICL_PROP_HW_REVISION, hw_revision);
+			free((void *) hw_revision);
+		}
+		break;
+
+	case PP_FW_REVISION:
+		ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev,
+		    row, &fw_revision, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && fw_revision && *fw_revision) {
+			(void) add_string_prop(nodeh,
+			    PICL_PROP_FW_REVISION, fw_revision);
+			free((void *) fw_revision);
+		}
+		break;
+
+	case PP_MFG_NAME:
+		ret = snmp_get_str(hdl, OID_entPhysicalMfgName,
+		    row, &mfg_name, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && mfg_name && *mfg_name) {
+			(void) add_string_prop(nodeh,
+			    PICL_PROP_MFG_NAME, mfg_name);
+			free((void *) mfg_name);
+		}
+		break;
+
+	case PP_MODEL_NAME:
+		ret = snmp_get_str(hdl, OID_entPhysicalModelName,
+		    row, &model_name, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && model_name && *model_name) {
+			(void) add_string_prop(nodeh,
+			    PICL_PROP_MODEL_NAME, model_name);
+			free((void *) model_name);
+		}
+		break;
+
+	case PP_DESCRIPTION:
+		ret = snmp_get_str(hdl, OID_entPhysicalDescr,
+		    row, &phys_descr, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && phys_descr && *phys_descr) {
+		    (void) add_string_prop(nodeh,
+			PICL_PROP_PHYS_DESCRIPTION, phys_descr);
+		    free((void *) phys_descr);
+		}
+		break;
+
+	case PP_LABEL:
+		if (label && *label)
+			(void) add_string_prop(nodeh, PICL_PROP_LABEL, label);
+		break;
+
+	case PP_BASE_UNITS:
+		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits,
+		    row, &val, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && (val > 0) && (val < n_baseunits)) {
+			(void) add_string_prop(nodeh,
+			    PICL_PROP_BASE_UNITS, sensor_baseunits[val]);
+		}
+		break;
+
+	case PP_RATE_UNITS:
+		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits,
+		    row, &val, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if ((ret == 0) && (val > 0) && (val < n_rateunits)) {
+			(void) add_string_prop(nodeh,
+			    PICL_PROP_RATE_UNITS, sensor_rateunits[val]);
+		}
+		break;
+
+	case PP_EXPONENT:
+		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorExponent,
+		    row, &val, snmp_syserr_p);
+		CHECK_LINKRESET_VOID(snmp_syserr_p)
+		if (ret == 0)
+			(void) add_int_prop(nodeh, PICL_PROP_EXPONENT, val);
+		break;
+	}
+}
+
+/*VARARGS2*/
+static void
+log_msg(int pri, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsyslog(pri, fmt, ap);
+	va_end(ap);
+}
+
+#ifdef SNMPPLUGIN_DEBUG
+
+static void
+snmpplugin_log_init(void)
+{
+	(void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL);
+}
+
+static void
+snmpplugin_log(const char *fmt, ...)
+{
+	va_list	ap;
+
+	(void) mutex_lock(&snmpplugin_dbuf_lock);
+
+	va_start(ap, fmt);
+	(void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap);
+	snmpplugin_log_append();
+	va_end(ap);
+
+	(void) mutex_unlock(&snmpplugin_dbuf_lock);
+}
+
+static void
+snmpplugin_log_append(void)
+{
+	int	len;
+
+	len = strlen(snmpplugin_lbuf);
+
+	if ((snmpplugin_dbuf_curp + len) >=
+	    (snmpplugin_dbuf + snmpplugin_dbuf_sz)) {
+		snmpplugin_dbuf_realloc();
+		if (snmpplugin_dbuf == NULL) {
+			(void) mutex_unlock(&snmpplugin_dbuf_lock);
+			return;
+		}
+	}
+
+	(void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf);
+	snmpplugin_dbuf_curp += len;
+}
+
+static void
+snmpplugin_dbuf_realloc(void)
+{
+	char	*p;
+	size_t	offset = 0;
+	size_t	count;
+
+	count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ;
+	if ((p = (char *)calloc(count, 1)) == NULL) {
+		snmpplugin_dbuf_overflow++;
+		snmpplugin_dbuf_curp = snmpplugin_dbuf;
+		return;
+	}
+
+	if (snmpplugin_dbuf) {
+		offset = snmpplugin_dbuf_curp - snmpplugin_dbuf;
+		(void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz);
+		free(snmpplugin_dbuf);
+	}
+
+	snmpplugin_dbuf = p;
+	snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ;
+
+	snmpplugin_dbuf_curp = snmpplugin_dbuf + offset;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.h	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,215 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SNMPPLUGIN_H
+#define	_SNMPPLUGIN_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * The /physical-platform node
+ */
+#define	PICL_NODE_PHYSPLAT		"physical-platform"
+
+/*
+ * List of volatile property OIDs to lookup and update when needed
+ */
+typedef struct {
+	picl_prophdl_t  prop;
+	char		*oidstr;
+	int		row;
+	int		proptype;
+} vol_prophdl_t;
+
+/*
+ * Types of volatile properties (proptype values)
+ */
+#define	VPT_PLATOPSTATE		1
+#define	VPT_NUMSENSOR		2
+#define	VPT_BINSENSOR		3
+#define	VPT_ALARMSTATE		4
+#define	VPT_BATTERYSTATUS	5
+
+/*
+ * Storage related and miscellaneous definitions
+ */
+#define	N_ELEMS_IN_VOLPROP_BLOCK	512
+#define	N_ELEMS_IN_NODE_BLOCK		256
+#define	NODE_BLOCK_SHIFT		8
+#define	DEFAULT_SLOT_TYPE		"slot"
+
+/*
+ * Local macros and property ids
+ */
+#define	ADD_NODE(cl)							\
+{									\
+	if (ptree_create_and_add_node(parenth, node_name, cl,		\
+	    &nodeh) != PICL_SUCCESS) {					\
+		log_msg(LOG_ERR, SNMPP_ADD_NODE_FAIL, node_name, cl);	\
+		return (NULL);						\
+	}								\
+}
+
+#define	CHECK_LINKRESET(errp, retval)		\
+	if ((errp) && (*errp == ECANCELED)) {	\
+		return (retval);		\
+	}
+
+#define	CHECK_LINKRESET_VOID(errp)		\
+	if ((errp) && (*errp == ECANCELED)) {	\
+		return;				\
+	}
+
+#define	min(x, y)	((x) < (y) ? (x) : (y))
+
+typedef enum {
+	PP_SERIAL_NUM = 1,
+	PP_SLOT_TYPE,
+	PP_STATE,
+	PP_OPSTATUS,
+	PP_BATT_STATUS,
+	PP_TEMPERATURE,
+	PP_VOLTAGE,
+	PP_CURRENT,
+	PP_SPEED,
+	PP_SENSOR_VALUE,
+	PP_BASE_UNITS,
+	PP_EXPONENT,
+	PP_RATE_UNITS,
+	PP_CONDITION,
+	PP_EXPECTED,
+	PP_REPLACEABLE,
+	PP_HOTSWAPPABLE,
+	PP_IS_FRU,
+	PP_HW_REVISION,
+	PP_FW_REVISION,
+	PP_MFG_NAME,
+	PP_MODEL_NAME,
+	PP_DESCRIPTION,
+	PP_LABEL
+} sp_propid_t;
+
+/*
+ * Plugin global routines
+ */
+void snmpplugin_init(void);
+void snmpplugin_fini(void);
+
+/*
+ * Plugin messages
+ */
+#define	SNMPP_NO_ROOT			\
+    gettext("PICL snmpplugin: cannot get picl tree root (ret=%d)\n")
+
+#define	SNMPP_CANT_INIT			\
+    gettext("PICL snmpplugin: cannot initialize snmp service\n")
+
+#define	SNMPP_CANT_CREATE_PHYSPLAT	\
+    gettext("PICL snmpplugin: cannot create physical-platform root (ret=%d)\n")
+
+#define	SNMPP_CANT_CREATE_TREE_BUILDER	\
+    gettext("PICL snmpplugin: cannot create thr to handle hotplugs (ret=%d)\n")
+
+#define	SNMPP_NO_ENTPHYSNAME		\
+    gettext("PICL snmpplugin: cannot get entPhysicalName (row=%d)\n")
+
+#define	SNMPP_ADD_NODE_FAIL		\
+    gettext("PICL snmpplugin: couldn't add node %s (class=%d)\n")
+
+#define	SNMPP_UNSUPP_SENSOR_CLASS	\
+    gettext("PICL snmpplugin: sunPlatSensorClass %d unsupported (row=%d)\n")
+
+#define	SNMPP_UNKNOWN_ENTPHYSCLASS	\
+    gettext("PICL snmpplugin: entPhysicalClass %d unknown (row=%d)\n")
+
+#define	SNMPP_NO_MEM			\
+    gettext("PICL snmpplugin: failed to allocate %d bytes\n")
+
+#define	SNMPP_CANT_FIND_VOLPROP		\
+    gettext("PICL snmpplugin: cannot find volatile property (proph=%lx)\n")
+
+#define	SNMPP_INV_PLAT_EQUIP_OPSTATE	\
+    gettext("PICL snmpplugin: invalid sunPlatEquipmentOpState %d (row=%d)\n")
+
+#define	SNMPP_INV_PLAT_BINSNSR_CURRENT	\
+    gettext("PICL snmpplugin: invalid sunPlatBinarySensorCurrent %d (row=%d)\n")
+
+#define	SNMPP_NO_SLOT_TYPE		\
+    gettext("PICL snmpplugin: no acceptable slot types (row=%d)\n")
+
+#define	SNMPP_CANT_INIT_PROPINFO	\
+    gettext("PICL snmpplugin: cannot init picl propinfo (err=%d)\n")
+
+#define	SNMPP_CANT_ADD_PROP		\
+    gettext("PICL snmpplugin: cannot add property, err=%d (node=%lx)\n")
+
+#define	SNMPP_CANT_INIT_STR_PROPINFO	\
+    gettext("PICL snmpplugin: cannot init picl str propinfo (err=%d)\n")
+
+#define	SNMPP_CANT_ADD_STR_PROP		\
+    gettext("PICL snmpplugin: cannot add string property (err=%d, node=%lx)\n")
+
+#define	SNMPP_CANT_INIT_VOID_PROPINFO	\
+    gettext("PICL snmpplugin: cannot init picl void propinfo (err=%d)\n")
+
+#define	SNMPP_CANT_ADD_VOID_PROP	\
+    gettext("PICL snmpplugin: cannot add void property (err=%d, node=%lx)\n")
+
+#define	SNMPP_CANT_INIT_INT_PROPINFO	\
+    gettext("PICL snmpplugin: cannot init picl int propinfo (err=%d)\n")
+
+#define	SNMPP_CANT_ADD_INT_PROP	\
+    gettext("PICL snmpplugin: cannot add int property (err=%d, node=%lx)\n")
+
+#define	SNMPP_CANT_FETCH_OBJECT_VAL	\
+    gettext("PICL snmpplugin: cannot fetch object value (err=%d)\n")
+
+#define	SNMPP_LINK_RESET	\
+    gettext("PICL snmpplugin: snmp ds reset happened, rebuilding tree\n")
+
+#ifdef SNMPPLUGIN_DEBUG
+#define	SNMPPLUGIN_DBLOCK_SZ		4096
+#define	SNMPPLUGIN_DMAX_LINE		80
+#define	LOGINIT()			snmpplugin_log_init()
+#define	LOGPRINTF(s)			snmpplugin_log(s)
+#define	LOGPRINTF1(s, a1)		snmpplugin_log(s, a1)
+#define	LOGPRINTF2(s, a1, a2)		snmpplugin_log(s, a1, a2)
+#else
+#define	LOGINIT()
+#define	LOGPRINTF(s)
+#define	LOGPRINTF1(s, a1)
+#define	LOGPRINTF2(s, a1, a2)
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SNMPPLUGIN_H */
--- a/usr/src/lib/libprtdiag/Makefile.com	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/lib/libprtdiag/Makefile.com	Sat Mar 31 18:24:05 2007 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -40,6 +40,7 @@
 
 LIBS		= $(DYNLIB) $(LINTLIB)
 IFLAGS		= -I ../../inc -I $(USR_PSM_INCL_DIR)
+IFLAGS		+= -I $(SRC)/cmd/picl/plugins/inc
 IFLAGS		+= -I $(UTSBASE)/sun4u 
 IFLAGS		+= -I $(UTSBASE)/sun4u/sunfire
 IFLAGS		+= -I $(UTSBASE)/sun4u/serengeti
--- a/usr/src/lib/libprtdiag/common/display_sun4v.c	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/lib/libprtdiag/common/display_sun4v.c	Sat Mar 31 18:24:05 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,26 +43,87 @@
 #include <libintl.h>
 #include <syslog.h>
 #include <sys/dkio.h>
+#include <sys/systeminfo.h>
+#include <picldefs.h>
 #include "pdevinfo.h"
 #include "display.h"
 #include "display_sun4v.h"
 #include "libprtdiag.h"
 
-
 #if !defined(TEXT_DOMAIN)
 #define	TEXT_DOMAIN	"SYS_TEST"
 #endif
 
-extern	int sys_clk;
+#define	IOBOARD				"IOBD"
+#define	NETWORK				"network"
+#define	PCIE_COMPATIBLE_STR		"pciex"
+#define	PCIX_COMPATIBLE_STR		"pci"
+#define	SUN4V_MACHINE			"sun4v"
+#define	PARENT_NAMES			10
+
+/*
+ * Additional OBP properties
+ */
+#define	OBP_PROP_COMPATIBLE		"compatible"
+#define	OBP_PROP_MODEL			"model"
+#define	OBP_PROP_SLOT_NAMES		"slot-names"
+
+#define	PICL_NODE_PHYSICAL_PLATFORM	"physical-platform"
+#define	PICL_NODE_CHASSIS		"chassis"
+#define	MEMORY_SIZE_FIELD		11
+#define	INVALID_THRESHOLD		1000000
+
+/*
+ * Additional picl classes
+ */
+#ifndef	PICL_CLASS_SUN4V
+#define	PICL_CLASS_SUN4V		"sun4v"
+#endif
+
+#ifndef	PICL_PROP_NAC
+#define	PICL_PROP_NAC			"nac"
+#endif
+
+extern int sys_clk;
+extern picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *,
+	picl_nodehdl_t *);
+
+static picl_nodehdl_t rooth = 0, phyplatformh = 0;
+static picl_nodehdl_t chassish = 0;
+static int class_node_found;
+static int syserrlog;
+static int all_status_ok;
+
+/* local functions */
+static int sun4v_get_first_compatible_value(picl_nodehdl_t, char **);
+static void sun4v_display_memory_conf(picl_nodehdl_t);
+static void sun4v_disp_env_status();
+static void sun4v_env_print_fan_sensors();
+static void sun4v_env_print_fan_indicators();
+static void sun4v_env_print_temp_sensors();
+static void sun4v_env_print_temp_indicators();
+static void sun4v_env_print_current_sensors();
+static void sun4v_env_print_current_indicators();
+static void sun4v_env_print_voltage_sensors();
+static void sun4v_env_print_voltage_indicators();
+static void sun4v_env_print_LEDs();
+static void sun4v_print_fru_status();
+static void sun4v_print_fw_rev();
+static void sun4v_print_chassis_serial_no();
 
 int
-sun4v_display(Sys_tree *tree, Prom_node *root, int syserrlog,
-    picl_nodehdl_t plafh)
+sun4v_display(Sys_tree *tree, Prom_node *root, int log,
+	picl_nodehdl_t plafh)
 {
-	int exit_code = 0;	/* init to all OK */
 	void *value;		/* used for opaque PROM data */
 	struct mem_total memory_total;	/* Total memory in system */
 	struct grp_info grps;	/* Info on all groups in system */
+	char machine[MAXSTRLEN];
+
+	if (sysinfo(SI_MACHINE, machine, sizeof (machine)) == -1)
+		return (1);
+	if (strncmp(machine, SUN4V_MACHINE, strlen(SUN4V_MACHINE)) != 0)
+		return (1);
 
 	sys_clk = -1;  /* System clock freq. (in MHz) */
 
@@ -79,11 +139,9 @@
 		 */
 		(void) uname(&uts_buf);
 
-		log_printf(
-			dgettext(TEXT_DOMAIN, "System Configuration:  "
-				"Sun Microsystems  %s %s\n"), uts_buf.machine,
-					get_prop_val(find_prop(root,
-					"banner-name")), 0);
+		log_printf(dgettext(TEXT_DOMAIN, "System Configuration:  "
+			"Sun Microsystems  %s %s\n"), uts_buf.machine,
+			get_prop_val(find_prop(root, "banner-name")), 0);
 
 		/* display system clock frequency */
 		value = get_prop_val(find_prop(root, "clock-frequency"));
@@ -100,15 +158,286 @@
 		sun4v_display_cpu_devices(plafh);
 
 		/* Display the Memory configuration */
-		sun4v_display_memoryconf(plafh);
+		class_node_found = 0;
+		sun4v_display_memory_conf(plafh);
 
 		/* Display all the IO cards. */
 		(void) sun4v_display_pci(plafh);
+		sun4v_display_diaginfo((log || (logging)), root, plafh);
 
-		sun4v_display_diaginfo((syserrlog || (logging)), root, plafh);
+		if (picl_get_root(&rooth) != PICL_SUCCESS)
+			return (1);
+		if (sun4v_get_node_by_name(rooth, PICL_NODE_PHYSICAL_PLATFORM,
+			&phyplatformh) != PICL_SUCCESS)
+			return (1);
+
+		if (picl_find_node(phyplatformh, PICL_PROP_CLASSNAME,
+			PICL_PTYPE_CHARSTRING, (void *)PICL_CLASS_CHASSIS,
+			strlen(PICL_CLASS_CHASSIS), &chassish) != PICL_SUCCESS)
+			return (1);
+
+		syserrlog = log;
+		sun4v_disp_env_status();
+	}
+	return (0);
+}
+
+static void
+get_bus_type(picl_nodehdl_t nodeh, struct io_card *card)
+{
+	char *compatible;
+
+	(void) strcpy(card->bus_type, "PCIX");
+	if (sun4v_get_first_compatible_value(nodeh, &compatible)
+		== PICL_SUCCESS) {
+		if (strncmp(compatible, PCIE_COMPATIBLE_STR,
+			strlen(PCIE_COMPATIBLE_STR)) == 0)
+			(void) strcpy(card->bus_type, "PCIE");
+		free(compatible);
+	}
+}
+
+static picl_errno_t
+get_slot_label(picl_nodehdl_t nodeh, struct io_card *card)
+{
+	char val[PICL_PROPNAMELEN_MAX];
+	picl_errno_t err;
+
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
+		sizeof (val));
+	if (err != PICL_SUCCESS)
+		return (err);
+
+	(void) strcpy(card->slot_str, val);
+	card->slot = -1;
+	return (PICL_SUCCESS);
+}
+
+static void
+get_slot_number(picl_nodehdl_t nodeh, struct io_card *card)
+{
+	picl_errno_t err;
+	picl_prophdl_t proph;
+	picl_propinfo_t pinfo;
+	picl_nodehdl_t pnodeh;
+	uint8_t *pval;
+	uint32_t dev_mask;
+	char uaddr[MAXSTRLEN];
+	int i;
+
+	if (get_slot_label(nodeh, card) == PICL_SUCCESS)
+		return;
+	err = PICL_SUCCESS;
+	while (err == PICL_SUCCESS) {
+		if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
+			sizeof (pnodeh)) != PICL_SUCCESS) {
+			(void) strcpy(card->slot_str, IOBOARD);
+			card->slot = -1;
+			return;
+		}
+		if (picl_get_propinfo_by_name(pnodeh, OBP_PROP_SLOT_NAMES,
+			&pinfo, &proph) == PICL_SUCCESS) {
+			break;
+		}
+		nodeh = pnodeh;
+	}
+	if (picl_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, uaddr,
+		sizeof (uaddr)) != PICL_SUCCESS) {
+		(void) strcpy(card->slot_str, IOBOARD);
+		card->slot = -1;
+		return;
+	}
+	pval = (uint8_t *)malloc(pinfo.size);
+	if (!pval) {
+		(void) strcpy(card->slot_str, IOBOARD);
+		card->slot = -1;
+		return;
+	}
+	if (picl_get_propval(proph, pval, pinfo.size) != PICL_SUCCESS) {
+		(void) strcpy(card->slot_str, IOBOARD);
+		card->slot = -1;
+		free(pval);
+		return;
 	}
 
-	return (exit_code);
+	dev_mask = 0;
+	for (i = 0; i < sizeof (dev_mask); i++)
+		dev_mask |= (*(pval+i) << 8*(sizeof (dev_mask)-1-i));
+	for (i = 0; i < sizeof (uaddr) && uaddr[i] != '\0'; i++) {
+		if (uaddr[i] == ',') {
+			uaddr[i] = '\0';
+			break;
+		}
+	}
+	card->slot = atol(uaddr);
+	if (((1 << card->slot) & dev_mask) == 0) {
+		(void) strcpy(card->slot_str, IOBOARD);
+		card->slot = -1;
+	} else {
+		char *p = (char *)(pval+sizeof (dev_mask));
+		int shift = sizeof (uint32_t)*8-1-card->slot;
+		uint32_t x = (dev_mask << shift) >> shift;
+		int count = 0;	/* count # of 1's in x */
+		int i = 0;
+		while (x != 0) {
+			count++;
+			x &= x-1;
+		}
+		while (count > 1) {
+			while (p[i++] != '\0');
+			count--;
+		}
+		(void) strcpy(card->slot_str, (char *)(p+i));
+	}
+	free(pval);
+}
+
+/*
+ * add all io devices under pci in io list
+ */
+/* ARGSUSED */
+static int
+sun4v_pci_callback(picl_nodehdl_t pcih, void *args)
+{
+	char path[PICL_PROPNAMELEN_MAX];
+	char class[PICL_CLASSNAMELEN_MAX];
+	char name[PICL_PROPNAMELEN_MAX];
+	char model[PICL_PROPNAMELEN_MAX];
+	char binding_name[PICL_PROPNAMELEN_MAX];
+	char val[PICL_PROPNAMELEN_MAX];
+	char *compatible;
+	picl_errno_t err;
+	picl_nodehdl_t nodeh;
+	struct io_card pci_card;
+
+	/* Walk through the children */
+
+	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
+		sizeof (picl_nodehdl_t));
+
+	while (err == PICL_SUCCESS) {
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+			class, sizeof (class));
+		if (err !=  PICL_SUCCESS)
+			return (err);
+
+		if (args) {
+			char *val = args;
+			if (strcmp(class, val) == 0) {
+				err = picl_get_propval_by_name(nodeh,
+					PICL_PROP_PEER, &nodeh,
+					sizeof (picl_nodehdl_t));
+				continue;
+			} else if (strcmp(val, PICL_CLASS_PCIEX) == 0 &&
+				strcmp(class, PICL_CLASS_PCI) == 0) {
+				err = picl_get_propval_by_name(nodeh,
+					PICL_PROP_PEER, &nodeh,
+					sizeof (picl_nodehdl_t));
+				continue;
+			} else if (strcmp(val, PICL_CLASS_PCI) == 0 &&
+				strcmp(class, PICL_CLASS_PCIEX) == 0) {
+				err = picl_get_propval_by_name(nodeh,
+					PICL_PROP_PEER, &nodeh,
+					sizeof (picl_nodehdl_t));
+				continue;
+			}
+		}
+
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
+			path, sizeof (path));
+		if (err != PICL_SUCCESS)
+			return (err);
+
+		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
+
+		get_bus_type(nodeh, &pci_card);
+		get_slot_number(nodeh, &pci_card);
+
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, name,
+			sizeof (name));
+		if (err == PICL_PROPNOTFOUND)
+			(void) strcpy(name, "");
+		else if (err != PICL_SUCCESS)
+			return (err);
+
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_STATUS, val,
+			sizeof (val));
+		if (err == PICL_PROPNOTFOUND)
+			(void) strcpy(val, "");
+		else if (err != PICL_SUCCESS)
+			return (err);
+
+		/* Figure NAC name */
+		if (pci_card.slot != -1)
+			(void) snprintf(pci_card.status,
+					sizeof (pci_card.status),
+					"%s%d", pci_card.slot_str,
+					pci_card.slot);
+		else
+			(void) snprintf(pci_card.status,
+					sizeof (pci_card.status),
+					"%s", pci_card.slot_str);
+
+		/*
+		 * Get the name of this card. If binding_name is found,
+		 * name will be <nodename>-<binding_name>.
+		 */
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
+			binding_name, sizeof (binding_name));
+		if (err == PICL_SUCCESS) {
+			if (strcmp(name, binding_name) != 0) {
+				(void) strlcat(name, "-", sizeof (name));
+				(void) strlcat(name, binding_name,
+					sizeof (name));
+			}
+		} else if (err == PICL_PROPNOTFOUND) {
+			/*
+			 * if compatible prop is not found, name will be
+			 * <nodename>-<compatible>
+			 */
+			err = sun4v_get_first_compatible_value(nodeh,
+				&compatible);
+			if (err == PICL_SUCCESS) {
+				(void) strlcat(name, "-", sizeof (name));
+				(void) strlcat(name, compatible, sizeof (name));
+				free(compatible);
+			}
+		} else
+			return (err);
+
+		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
+
+		/* Get the model of this card */
+
+		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
+			model, sizeof (model));
+		if (err == PICL_PROPNOTFOUND)
+			(void) strcpy(model, "");
+		else if (err != PICL_SUCCESS)
+			return (err);
+		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
+
+		/* Print NAC name */
+		log_printf("%-12s", pci_card.status);
+		/* Print IO Type */
+		log_printf("%-6s", pci_card.bus_type);
+		/* Printf Card Name */
+		log_printf("%-46s", pci_card.name);
+		/* Print Card Model */
+		log_printf("%-8s", pci_card.model);
+		log_printf("\n");
+		/* Print Status */
+		log_printf("%-12s", val);
+		/* Print IO Type */
+		log_printf("%-6s", "");
+		/* Print Parent Path */
+		log_printf("%-46s", pci_card.notes);
+		log_printf("\n");
+
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+			sizeof (picl_nodehdl_t));
+	}
+	return (PICL_WALK_CONTINUE);
 }
 
 /*
@@ -118,29 +447,229 @@
 void
 sun4v_display_pci(picl_nodehdl_t plafh)
 {
-#ifdef	lint
-	plafh = plafh;
-#endif
-	/*
-	 * This function is intentionally empty
-	 */
+	char *fmt = "%-11s %-5s %-45s %-8s";
+	/* Have we printed the column headings? */
+	static int banner = FALSE;
+
+	if (banner == FALSE) {
+		log_printf("\n");
+		log_printf("============================");
+		log_printf(" IO Devices ");
+		log_printf("============================");
+		log_printf("\n");
+		log_printf(fmt, "Slot +", "Bus", "Name +", "Model", 0);
+		log_printf("\n");
+		log_printf(fmt, "Status", "Type", "Path", "", 0);
+		log_printf("\n");
+		log_printf("---------------------------------"
+			"------------------------------------\n");
+		banner = TRUE;
+	}
+
+	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX,
+		PICL_CLASS_PCIEX, sun4v_pci_callback);
+	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
+		PICL_CLASS_PCI, sun4v_pci_callback);
+	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_SUN4V,
+		PICL_CLASS_SUN4V, sun4v_pci_callback);
+}
+
+/*
+ * return the first compatible value
+ */
+static int
+sun4v_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
+{
+	picl_errno_t err;
+	picl_prophdl_t proph;
+	picl_propinfo_t pinfo;
+	picl_prophdl_t tblh;
+	picl_prophdl_t rowproph;
+	char *pval;
+
+	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
+		&pinfo, &proph);
+	if (err != PICL_SUCCESS)
+		return (err);
+
+	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+		pval = malloc(pinfo.size);
+		if (pval == NULL)
+			return (PICL_FAILURE);
+		err = picl_get_propval(proph, pval, pinfo.size);
+		if (err != PICL_SUCCESS) {
+			free(pval);
+			return (err);
+		}
+		*outbuf = pval;
+		return (PICL_SUCCESS);
+	}
+
+	if (pinfo.type != PICL_PTYPE_TABLE)
+		return (PICL_FAILURE);
+
+	/* get first string from table */
+	err = picl_get_propval(proph, &tblh, pinfo.size);
+	if (err != PICL_SUCCESS)
+		return (err);
+
+	err = picl_get_next_by_row(tblh, &rowproph);
+	if (err != PICL_SUCCESS)
+		return (err);
+
+	err = picl_get_propinfo(rowproph, &pinfo);
+	if (err != PICL_SUCCESS)
+		return (err);
+
+	pval = malloc(pinfo.size);
+	if (pval == NULL)
+		return (PICL_FAILURE);
+
+	err = picl_get_propval(rowproph, pval, pinfo.size);
+	if (err != PICL_SUCCESS) {
+		free(pval);
+		return (err);
+	}
+
+	*outbuf = pval;
+	return (PICL_SUCCESS);
 }
 
-void
-sun4v_display_memoryconf(picl_nodehdl_t plafh)
+/*
+ * print size of a memory segment
+ */
+static void
+print_memory_segment_size(uint64_t size)
+{
+	uint64_t kbyte = 1024;
+	uint64_t mbyte = kbyte * kbyte;
+	uint64_t gbyte = kbyte * mbyte;
+	char buf[MEMORY_SIZE_FIELD];
+
+	if (size >= gbyte) {
+		if (size % gbyte == 0)
+			(void) snprintf(buf, sizeof (buf), "%d GB",
+				(int)(size / gbyte));
+		else
+			(void) snprintf(buf, sizeof (buf), "%.2f GB",
+				(float)size / gbyte);
+	} else if (size >= mbyte) {
+		if (size % mbyte == 0)
+			(void) snprintf(buf, sizeof (buf), "%d MB",
+				(int)(size / mbyte));
+		else
+			(void) snprintf(buf, sizeof (buf), "%.2f MB",
+				(float)size / mbyte);
+	} else {
+		if (size % kbyte == 0)
+			(void) snprintf(buf, sizeof (buf), "%d KB",
+				(int)(size / kbyte));
+		else
+			(void) snprintf(buf, sizeof (buf), "%.2f KB",
+				(float)size / kbyte);
+	}
+	log_printf("%-7s ", buf);
+}
+
+/*
+ * print bank IDs of a memory segment
+ */
+static void
+print_memory_segment_contain(picl_nodehdl_t nodeh)
 {
-#ifdef	lint
-	plafh = plafh;
-#endif
-	/*
-	 * This function is intentionally empty
-	 */
+	char val[PICL_PROPNAMELEN_MAX];
+	picl_errno_t err = picl_get_propval_by_name(nodeh,
+		PICL_PROP_NAC, val, sizeof (val));
+	if (err != PICL_SUCCESS)
+		return;
+	log_printf("%-30s", val);
+	while ((err = picl_get_propval_by_name(nodeh,
+			PICL_PROP_PEER, &nodeh,
+			sizeof (nodeh))) == PICL_SUCCESS) {
+		err = picl_get_propval_by_name(nodeh,
+			PICL_PROP_NAC, val, sizeof (val));
+		if (err == PICL_SUCCESS) {
+			log_printf("\n");
+			log_printf("%-30s", val);
+		}
+	}
+}
+
+/*
+ * Search node where _class=="memory-segment"
+ * print "Base Address", "Size", etc
+ */
+/*ARGSUSED*/
+static int
+sun4v_memory_conf_callback(picl_nodehdl_t nodeh, void *args)
+{
+	uint64_t base;
+	uint64_t size;
+	uint64_t ifactor;
+	picl_errno_t err = PICL_SUCCESS;
+
+	if (class_node_found == 0) {
+		class_node_found = 1;
+		return (PICL_WALK_TERMINATE);
+	}
+	while (err == PICL_SUCCESS) {
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_BASEADDRESS,
+			&base, sizeof (base));
+		if (err !=  PICL_SUCCESS)
+			break;
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_SIZE,
+			&size, sizeof (size));
+		if (err !=  PICL_SUCCESS)
+			break;
+		err = picl_get_propval_by_name(nodeh,
+			PICL_PROP_INTERLEAVE_FACTOR, &ifactor,
+			sizeof (ifactor));
+		if (err !=  PICL_SUCCESS)
+			break;
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
+			&nodeh, sizeof (nodeh));
+		if (err !=  PICL_SUCCESS)
+			break;
+		log_printf("%-13llx", base);
+		print_memory_segment_size(size);
+		log_printf("%-18d", ifactor);
+		print_memory_segment_contain(nodeh);
+		log_printf("\n");
+		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+			sizeof (picl_nodehdl_t));
+	}
+
+	return (PICL_WALK_CONTINUE);
+}
+
+/*ARGSUSED*/
+void
+sun4v_display_memory_conf(picl_nodehdl_t plafh)
+{
+	char *fmt = "%-12s %-7s %-9s %-20s";
+	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
+		NULL, sun4v_memory_conf_callback);
+	if (class_node_found == 0)
+		return;
+	log_printf("\n");
+	log_printf("============================");
+	log_printf(" Memory Configuration ");
+	log_printf("============================");
+	log_printf("\n");
+	log_printf("Segment Table:\n");
+	log_printf("-----------------------------------------------\n");
+	log_printf(fmt, "Base Address", "Size", "Interleave Factor",
+		"Contains", 0);
+	log_printf("\n");
+	log_printf("-----------------------------------------------\n");
+	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
+		NULL, sun4v_memory_conf_callback);
 }
 
 void
 sun4v_display_cpu_devices(picl_nodehdl_t plafh)
 {
-	char	*fmt = "%-12s %-5s %-8s %-19s %-5s";
+	char *fmt = "%-12s %-5s %-8s %-19s %-5s";
 
 	/*
 	 * Display the table header for CPUs . Then display the CPU
@@ -156,15 +685,13 @@
 	log_printf(fmt, "", "", "", "CPU", "CPU", 0);
 	log_printf("\n");
 	log_printf(fmt, "Location", "CPU", "Freq",
-	    "Implementation", "Mask", 0);
+		"Implementation", "Mask", 0);
 	log_printf("\n");
 	log_printf(fmt, "------------", "-----", "--------",
-	    "-------------------", "-----", 0);
+		"-------------------", "-----", 0);
 	log_printf("\n");
 
 	(void) picl_walk_tree_by_class(plafh, "cpu", "cpu", sun4v_display_cpus);
-
-	log_printf("\n");
 }
 
 /*
@@ -175,16 +702,16 @@
 sun4v_display_cpus(picl_nodehdl_t cpuh, void* args)
 {
 	int status;
-	picl_prophdl_t	proph;
-	picl_prophdl_t	tblh;
-	picl_prophdl_t	rowproph;
+	picl_prophdl_t proph;
+	picl_prophdl_t tblh;
+	picl_prophdl_t rowproph;
 	picl_propinfo_t propinfo;
-	int		*int_value;
-	uint64_t	cpuid, mask_no;
-	char		*comp_value;
-	char		*no_prop_value = "   ";
-	char		freq_str[MAXSTRLEN];
-	char		fru_name[MAXSTRLEN];
+	int *int_value;
+	uint64_t cpuid, mask_no;
+	char *comp_value;
+	char *no_prop_value = "   ";
+	char freq_str[MAXSTRLEN];
+	char fru_name[MAXSTRLEN];
 
 	/*
 	 * Get cpuid property and print it and the NAC name
@@ -193,44 +720,44 @@
 	if (status == PICL_SUCCESS) {
 		status = picl_get_propval(proph, &cpuid, sizeof (cpuid));
 		if (status != PICL_SUCCESS) {
-			log_printf("%-12s", no_prop_value);
-			log_printf("%6s", no_prop_value);
+			log_printf("%-13s", no_prop_value);
+			log_printf("%-6s", no_prop_value);
 		} else {
 			(void) snprintf(fru_name, sizeof (fru_name), "%s%d",
 			    CPU_STRAND_NAC, (int)cpuid);
-			log_printf("%-12s", fru_name);
-			log_printf("%6d", (int)cpuid);
+			log_printf("%-13s", fru_name);
+			log_printf("%-6d", (int)cpuid);
 		}
 	} else {
-		log_printf("%-12s", no_prop_value);
-		log_printf("%6s", no_prop_value);
+		log_printf("%-13s", no_prop_value);
+		log_printf("%-6s", no_prop_value);
 	}
 
 clock_freq:
 	status = picl_get_propinfo_by_name(cpuh, "clock-frequency", &propinfo,
-	    &proph);
+		&proph);
 	if (status == PICL_SUCCESS) {
 		int_value = malloc(propinfo.size);
 		if (int_value == NULL) {
-			log_printf("%9s", no_prop_value);
+			log_printf("%-9s", no_prop_value);
 			goto compatible;
 		}
 		status = picl_get_propval(proph, int_value, propinfo.size);
 		if (status != PICL_SUCCESS) {
-			log_printf("%9s", no_prop_value);
+			log_printf("%-9s", no_prop_value);
 		} else {
 			/* Running frequency */
 			(void) snprintf(freq_str, sizeof (freq_str), "%d MHz",
 			    CLK_FREQ_TO_MHZ(*int_value));
-			log_printf("%9s", freq_str);
+			log_printf("%-9s", freq_str);
 		}
 		free(int_value);
 	} else
-		log_printf("%9s", no_prop_value);
+		log_printf("%-9s", no_prop_value);
 
 compatible:
 	status = picl_get_propinfo_by_name(cpuh, "compatible", &propinfo,
-	    &proph);
+		&proph);
 	if (status == PICL_SUCCESS) {
 		if (propinfo.type == PICL_PTYPE_CHARSTRING) {
 			/*
@@ -238,72 +765,65 @@
 			 */
 			comp_value = malloc(propinfo.size);
 			if (comp_value == NULL) {
-				log_printf("%20s", no_prop_value, 0);
+				log_printf("%-20s", no_prop_value, 0);
 				goto mask;
 			}
 			status = picl_get_propval(proph, comp_value,
-			    propinfo.size);
-			if (status == PICL_SUCCESS) {
-				log_printf("%20s", no_prop_value, 0);
-				free(comp_value);
-			}
+				propinfo.size);
+			if (status != PICL_SUCCESS)
+				log_printf("%-20s", no_prop_value, 0);
+			else
+				log_printf("%-20s", comp_value, 0);
+			free(comp_value);
 		} else if (propinfo.type == PICL_PTYPE_TABLE) {
 			/*
 			 * Compatible Property has multiple values
 			 */
 			status = picl_get_propval(proph, &tblh, propinfo.size);
 			if (status != PICL_SUCCESS) {
-				printf("Failed getting tblh\n");
-				log_printf("%20s", no_prop_value, 0);
+				log_printf("%-20s", no_prop_value, 0);
 				goto mask;
 			}
 			status = picl_get_next_by_row(tblh, &rowproph);
 			if (status != PICL_SUCCESS) {
-				printf("Failed getting next by row\n");
-				log_printf("%20s", no_prop_value, 0);
+				log_printf("%-20s", no_prop_value, 0);
 				goto mask;
 			}
 
 			status = picl_get_propinfo(rowproph, &propinfo);
 			if (status != PICL_SUCCESS) {
-				printf("Failed getting prop for rowproph\n");
-				log_printf("%20s", no_prop_value, 0);
+				log_printf("%-20s", no_prop_value, 0);
 				goto mask;
 			}
 
 			comp_value = malloc(propinfo.size);
 			if (comp_value == NULL) {
-				printf("Failed to get malloc value?\n");
-				log_printf("%20s", no_prop_value, 0);
+				log_printf("%-20s", no_prop_value, 0);
 				goto mask;
 			}
-
 			status = picl_get_propval(rowproph, comp_value,
-			    propinfo.size);
-			if (status != PICL_SUCCESS) {
-				printf("Failed geting rowproph\n");
-				log_printf("%20s", no_prop_value, 0);
-				free(comp_value);
-				goto mask;
-			} else
-				log_printf("%20s", comp_value, 0);
+				propinfo.size);
+			if (status != PICL_SUCCESS)
+				log_printf("%-20s", no_prop_value, 0);
+			else
+				log_printf("%-20s", comp_value, 0);
 			free(comp_value);
 		}
 	} else
-		log_printf("%20s", no_prop_value, 0);
+		log_printf("%-20s", no_prop_value, 0);
 
 mask:
 	status = picl_get_propinfo_by_name(cpuh, "mask#", &propinfo, &proph);
 	if (status == PICL_SUCCESS) {
 		status = picl_get_propval(proph, &mask_no, sizeof (mask_no));
 		if (status != PICL_SUCCESS) {
-			log_printf("%9s", no_prop_value);
+			log_printf("%-9s", no_prop_value);
 		} else {
 			log_printf(dgettext(TEXT_DOMAIN, " %2d.%d"),
-			    (mask_no>> 4) & 0xf, mask_no & 0xf);
+				(mask_no>> 4) & 0xf, mask_no & 0xf);
 		}
 	} else
-		log_printf("%9s", no_prop_value);
+		log_printf("%-9s", no_prop_value);
 
 done:
 	log_printf("\n");
@@ -328,3 +848,701 @@
 {
 	log_printf("%2d   ", num, 0);
 }
+
+static void
+sun4v_disp_env_status()
+{
+	if (phyplatformh == 0)
+		return;
+	log_printf("\n");
+	log_printf("============================");
+	log_printf(" Environmental Status ");
+	log_printf("============================");
+	log_printf("\n");
+
+	class_node_found = 0;
+	all_status_ok = 1;
+	sun4v_env_print_fan_sensors();
+
+	class_node_found = 0;
+	all_status_ok = 1;
+	sun4v_env_print_fan_indicators();
+
+	class_node_found = 0;
+	all_status_ok = 1;
+	sun4v_env_print_temp_sensors();
+
+	class_node_found = 0;
+	all_status_ok = 1;
+	sun4v_env_print_temp_indicators();
+
+	class_node_found = 0;
+	all_status_ok = 1;
+	sun4v_env_print_current_sensors();
+
+	class_node_found = 0;
+	all_status_ok = 1;
+	sun4v_env_print_current_indicators();
+
+	class_node_found = 0;
+	all_status_ok = 1;
+	sun4v_env_print_voltage_sensors();
+
+	class_node_found = 0;
+	all_status_ok = 1;
+	sun4v_env_print_voltage_indicators();
+
+	class_node_found = 0;
+	sun4v_env_print_LEDs();
+
+	class_node_found = 0;
+	all_status_ok = 1;
+	sun4v_print_fru_status();
+
+	class_node_found = 0;
+	sun4v_print_fw_rev();
+
+	sun4v_print_chassis_serial_no();
+}
+
+/*ARGSUSED*/
+static int
+sun4v_env_print_sensor_callback(picl_nodehdl_t nodeh, void *args)
+{
+	char val[PICL_PROPNAMELEN_MAX];
+	picl_nodehdl_t parenth;
+	char *names[PARENT_NAMES];
+	char *loc;
+	int i;
+	char *prop;
+	picl_errno_t err;
+	int32_t lo_warning, lo_shutdown;
+	int32_t hi_warning, hi_shutdown;
+	int32_t current_val;
+
+	if (class_node_found == 0) {
+		class_node_found = 1;
+		return (PICL_WALK_TERMINATE);
+	}
+
+	if (syserrlog == 0) {
+		err = picl_get_propval_by_name(nodeh,
+			PICL_PROP_OPERATIONAL_STATUS, val,
+			sizeof (val));
+		if (err == PICL_SUCCESS) {
+			if (strcmp(val, "disabled") == 0) {
+				if (all_status_ok) {
+					all_status_ok = 0;
+					return (PICL_WALK_TERMINATE);
+				}
+			} else
+				return (PICL_WALK_CONTINUE);
+		} else {
+			all_status_ok = 0;
+			return (PICL_WALK_TERMINATE);
+		}
+	}
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
+		sizeof (parenth));
+	if (err != PICL_SUCCESS) {
+		log_printf("\n");
+		return (PICL_WALK_CONTINUE);
+	}
+	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL)
+		return (PICL_WALK_TERMINATE);
+	for (i = 0; i < PARENT_NAMES; i++)
+		if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) {
+			while (--i > -1)
+				free(names[i]);
+			free(loc);
+			return (PICL_WALK_TERMINATE);
+		}
+	i = 0;
+	while (err == PICL_SUCCESS) {
+		if (parenth == chassish || parenth == phyplatformh)
+			break;
+		err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
+			names[i++], PICL_PROPNAMELEN_MAX);
+		if (err != PICL_SUCCESS) {
+			i--;
+			break;
+		}
+		if (i == PARENT_NAMES)
+			break;
+		err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
+			&parenth, sizeof (parenth));
+	}
+	loc[0] = '\0';
+	if (--i > -1)
+		loc = strncat(loc, names[i], strlen(names[i]));
+	while (--i > -1) {
+		loc = strncat(loc, "/", 1);
+		loc = strncat(loc, names[i], strlen(names[i]));
+	}
+	log_printf("%-12s", loc);
+	for (i = 0; i < PARENT_NAMES; i++)
+		free(names[i]);
+	free(loc);
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
+		sizeof (val));
+	if (err == PICL_SUCCESS)
+		log_printf("%-15s", val);
+
+	prop = (char *)args;
+	if (!prop) {
+		log_printf("\n");
+		return (PICL_WALK_CONTINUE);
+	}
+	if (picl_get_propval_by_name(nodeh, prop, &current_val,
+		sizeof (current_val)) != PICL_SUCCESS) {
+		log_printf("\n");
+		return (PICL_WALK_CONTINUE);
+	}
+	if (picl_get_propval_by_name(nodeh, PICL_PROP_LOW_WARNING,
+		&lo_warning, sizeof (lo_warning)) != PICL_SUCCESS)
+		lo_warning = INVALID_THRESHOLD;
+	if (picl_get_propval_by_name(nodeh, PICL_PROP_LOW_SHUTDOWN,
+		&lo_shutdown, sizeof (lo_shutdown)) != PICL_SUCCESS)
+		lo_shutdown = INVALID_THRESHOLD;
+	if (picl_get_propval_by_name(nodeh, PICL_PROP_HIGH_WARNING,
+		&hi_warning, sizeof (hi_warning)) != PICL_SUCCESS)
+		hi_warning = INVALID_THRESHOLD;
+	if (picl_get_propval_by_name(nodeh, PICL_PROP_HIGH_SHUTDOWN,
+		&hi_shutdown, sizeof (hi_shutdown)) != PICL_SUCCESS)
+		hi_shutdown = INVALID_THRESHOLD;
+
+	if ((lo_shutdown != INVALID_THRESHOLD &&
+		current_val <= lo_shutdown) ||
+		(hi_shutdown != INVALID_THRESHOLD &&
+		current_val >= hi_shutdown)) {
+		log_printf("%-s", "failed (");
+		log_printf("%-d", current_val);
+		log_printf("%-s", ")");
+	} else if ((lo_warning != INVALID_THRESHOLD &&
+		current_val <= lo_warning) ||
+		(hi_warning != INVALID_THRESHOLD &&
+		current_val >= hi_warning)) {
+		log_printf("%-s", "warning (");
+		log_printf("%-d", current_val);
+		log_printf("%-s", ")");
+	} else
+		log_printf("%-s", "ok");
+
+	log_printf("\n");
+	return (PICL_WALK_CONTINUE);
+}
+
+/*ARGSUSED*/
+static int
+sun4v_env_print_indicator_callback(picl_nodehdl_t nodeh, void *args)
+{
+	char val[PICL_PROPNAMELEN_MAX];
+	char status[PICL_PROPNAMELEN_MAX];
+	picl_nodehdl_t parenth;
+	char *names[PARENT_NAMES];
+	char *loc;
+	int i = 0;
+	char *prop = (char *)args;
+	picl_errno_t err = PICL_SUCCESS;
+
+	if (class_node_found == 0) {
+		class_node_found = 1;
+		return (PICL_WALK_TERMINATE);
+	}
+	if (syserrlog == 0) {
+		err = picl_get_propval_by_name(nodeh,
+			PICL_PROP_OPERATIONAL_STATUS, status,
+			sizeof (status));
+		if (err == PICL_SUCCESS) {
+			if (strcmp(status, "disabled") == 0) {
+				if (all_status_ok) {
+					all_status_ok = 0;
+					return (PICL_WALK_TERMINATE);
+				}
+			} else
+				return (PICL_WALK_CONTINUE);
+		} else {
+			all_status_ok = 0;
+			return (PICL_WALK_TERMINATE);
+		}
+	}
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
+		sizeof (parenth));
+	if (err != PICL_SUCCESS) {
+		log_printf("\n");
+		return (PICL_WALK_CONTINUE);
+	}
+	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL)
+		return (PICL_WALK_TERMINATE);
+	for (i = 0; i < PARENT_NAMES; i++)
+		if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) {
+			while (--i > -1)
+				free(names[i]);
+			free(loc);
+			return (PICL_WALK_TERMINATE);
+		}
+	i = 0;
+	while (err == PICL_SUCCESS) {
+		if (parenth == chassish || parenth == phyplatformh)
+			break;
+		err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
+			names[i++], PICL_PROPNAMELEN_MAX);
+		if (err != PICL_SUCCESS) {
+			i--;
+			break;
+		}
+		if (i == PARENT_NAMES)
+			break;
+		err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
+			&parenth, sizeof (parenth));
+	}
+	loc[0] = '\0';
+	if (--i > -1)
+		loc = strncat(loc, names[i], strlen(names[i]));
+	while (--i > -1) {
+		loc = strncat(loc, "/", 1);
+		loc = strncat(loc, names[i], strlen(names[i]));
+	}
+	log_printf("%-12s", loc);
+	for (i = 0; i < PARENT_NAMES; i++)
+		free(names[i]);
+	free(loc);
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
+		sizeof (val));
+	if (err == PICL_SUCCESS)
+		log_printf("%-15s", val);
+	if (syserrlog == 0) {
+		log_printf("%-8s", status);
+		return (PICL_WALK_CONTINUE);
+	}
+	err = picl_get_propval_by_name(nodeh, prop, val,
+		sizeof (val));
+	if (err == PICL_SUCCESS)
+		log_printf("%-8s", val);
+	log_printf("\n");
+	return (PICL_WALK_CONTINUE);
+}
+
+static void
+sun4v_env_print_fan_sensors()
+{
+	char *fmt = "%-11s %-14s %-10s\n";
+	/*
+	 * If there isn't any fan sensor node, return now.
+	 */
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_RPM_SENSOR, (void *)PICL_CLASS_RPM_SENSOR,
+		sun4v_env_print_sensor_callback);
+	if (!class_node_found)
+		return;
+	log_printf("Fan sensors:\n");
+	if (syserrlog == 0) {
+		(void) picl_walk_tree_by_class(phyplatformh,
+			PICL_CLASS_RPM_SENSOR,
+			NULL, sun4v_env_print_sensor_callback);
+		if (all_status_ok) {
+			log_printf("All fan sensors are OK.\n");
+			return;
+		}
+	}
+	log_printf("---------------------------------\n");
+	log_printf(fmt, "Location", "Sensor", "Status", 0);
+	log_printf("---------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_SENSOR,
+		PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
+}
+
+static void
+sun4v_env_print_fan_indicators()
+{
+	char *fmt = "%-11s %-14s %-10s\n";
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_RPM_INDICATOR, (void *)PICL_CLASS_RPM_INDICATOR,
+		sun4v_env_print_indicator_callback);
+	if (!class_node_found)
+		return;
+	log_printf("\nFan indicators:\n");
+	if (syserrlog == 0) {
+		(void) picl_walk_tree_by_class(phyplatformh,
+			PICL_CLASS_RPM_INDICATOR,
+			NULL, sun4v_env_print_indicator_callback);
+		if (all_status_ok) {
+			log_printf("All fan indicators are OK.\n");
+			return;
+		}
+	}
+	log_printf("------------------------------------\n");
+	log_printf(fmt, "Location", "Sensor", "Condition", 0);
+	log_printf("------------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_INDICATOR,
+		PICL_CLASS_RPM_INDICATOR, sun4v_env_print_indicator_callback);
+}
+
+static void
+sun4v_env_print_temp_sensors()
+{
+	char *fmt = "%-11s %-14s %-10s\n";
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_TEMPERATURE_SENSOR,
+		(void *)PICL_PROP_TEMPERATURE,
+		sun4v_env_print_sensor_callback);
+	if (!class_node_found)
+		return;
+
+	log_printf("\nTemperature sensors:\n");
+	if (syserrlog == 0) {
+		(void) picl_walk_tree_by_class(phyplatformh,
+			PICL_CLASS_TEMPERATURE_SENSOR,
+			NULL, sun4v_env_print_sensor_callback);
+		if (all_status_ok) {
+			log_printf("All temperature sensors are OK.\n");
+			return;
+		}
+	}
+	log_printf("---------------------------------\n");
+	log_printf(fmt, "Location", "Sensor", "Status", 0);
+	log_printf("---------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_TEMPERATURE_SENSOR,
+		(void *)PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
+}
+
+static void
+sun4v_env_print_temp_indicators()
+{
+	char *fmt = "%-11s %-14s %-8s\n";
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_TEMPERATURE_INDICATOR, (void *)PICL_PROP_CONDITION,
+		sun4v_env_print_indicator_callback);
+	if (!class_node_found)
+		return;
+	log_printf("\nTemperature indicators:\n");
+	if (syserrlog == 0) {
+		(void) picl_walk_tree_by_class(phyplatformh,
+			PICL_CLASS_TEMPERATURE_INDICATOR, NULL,
+			sun4v_env_print_indicator_callback);
+		if (all_status_ok) {
+			log_printf("All temperature indicators are OK.\n");
+			return;
+		}
+	}
+	log_printf("------------------------------\n");
+	log_printf(fmt, "Location", "Indicator", "Condition", 0);
+	log_printf("------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_TEMPERATURE_INDICATOR,
+		(void *)PICL_PROP_CONDITION,
+		sun4v_env_print_indicator_callback);
+}
+
+static void
+sun4v_env_print_current_sensors()
+{
+	char *fmt = "%-11s %-14s %-10s\n";
+	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_CURRENT_SENSOR,
+		(void *)PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
+	if (!class_node_found)
+		return;
+	log_printf("\nCurrent sensors:\n");
+	if (syserrlog == 0) {
+		(void) picl_walk_tree_by_class(phyplatformh,
+			PICL_CLASS_CURRENT_SENSOR,
+			NULL, sun4v_env_print_sensor_callback);
+		if (all_status_ok) {
+			log_printf("All current sensors are OK.\n");
+			return;
+		}
+	}
+	log_printf("---------------------------------\n");
+	log_printf(fmt, "Location", "Sensor", "Status", 0);
+	log_printf("---------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_CURRENT_SENSOR, (void *)PICL_PROP_CURRENT,
+		sun4v_env_print_sensor_callback);
+}
+
+static void
+sun4v_env_print_current_indicators()
+{
+	char *fmt = "%-11s %-14s %-8s\n";
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_CURRENT_INDICATOR,
+		(void *)PICL_PROP_CONDITION,
+		sun4v_env_print_indicator_callback);
+	if (!class_node_found)
+		return;
+	log_printf("\nCurrent indicators:\n");
+	if (syserrlog == 0) {
+		(void) picl_walk_tree_by_class(phyplatformh,
+			PICL_CLASS_CURRENT_INDICATOR, NULL,
+			sun4v_env_print_indicator_callback);
+		if (all_status_ok) {
+			log_printf("All current indicators are OK.\n");
+			return;
+		}
+	}
+	log_printf("------------------------------------\n");
+	log_printf(fmt, "Location", "Indicator", "Condition", 0);
+	log_printf("------------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_CURRENT_INDICATOR,
+		(void *)PICL_PROP_CONDITION,
+		sun4v_env_print_indicator_callback);
+}
+
+static void
+sun4v_env_print_voltage_sensors()
+{
+	char *fmt = "%-11s %-14s %-10s\n";
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_VOLTAGE_SENSOR,
+		PICL_PROP_VOLTAGE,
+		sun4v_env_print_sensor_callback);
+	if (!class_node_found)
+		return;
+	log_printf("\nVoltage sensors:\n");
+	if (syserrlog == 0) {
+		(void) picl_walk_tree_by_class(phyplatformh,
+			PICL_CLASS_VOLTAGE_SENSOR,
+			NULL, sun4v_env_print_sensor_callback);
+		if (all_status_ok) {
+			log_printf("All voltage sensors are OK.\n");
+			return;
+		}
+	}
+	log_printf("---------------------------------\n");
+	log_printf(fmt, "Location", "Sensor", "Status", 0);
+	log_printf("---------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_VOLTAGE_SENSOR,
+		(void *)PICL_PROP_VOLTAGE,
+		sun4v_env_print_sensor_callback);
+}
+
+static void
+sun4v_env_print_voltage_indicators()
+{
+	char *fmt = "%-11s %-14s %-8s\n";
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_VOLTAGE_INDICATOR,
+		(void *)PICL_PROP_CONDITION,
+		sun4v_env_print_indicator_callback);
+	if (!class_node_found)
+		return;
+	log_printf("\nVoltage indicators:\n");
+	if (syserrlog == 0) {
+		(void) picl_walk_tree_by_class(phyplatformh,
+			PICL_CLASS_VOLTAGE_INDICATOR, NULL,
+			sun4v_env_print_indicator_callback);
+		if (all_status_ok) {
+			log_printf("All voltage indicators are OK.\n");
+			return;
+		}
+	}
+	log_printf("------------------------------------\n");
+	log_printf(fmt, "Location", "Indicator", "Condition", 0);
+	log_printf("------------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh,
+		PICL_CLASS_VOLTAGE_INDICATOR,
+		(void *)PICL_PROP_CONDITION,
+		sun4v_env_print_indicator_callback);
+}
+
+static void
+sun4v_env_print_LEDs()
+{
+	char *fmt = "%-11s %-14s %-8s\n";
+	if (syserrlog == 0)
+		return;
+	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
+		(void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
+	if (!class_node_found)
+		return;
+	log_printf("\nLEDs:\n");
+	log_printf("--------------------------------\n");
+	log_printf(fmt, "Location", "LED", "State", 0);
+	log_printf("--------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
+		(void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
+}
+
+/*ARGSUSED*/
+static int
+sun4v_print_fru_status_callback(picl_nodehdl_t nodeh, void *args)
+{
+	char label[PICL_PROPNAMELEN_MAX];
+	char status[PICL_PROPNAMELEN_MAX];
+	picl_errno_t err;
+	picl_prophdl_t proph;
+	picl_nodehdl_t parenth;
+	char *names[PARENT_NAMES];
+	char *loc;
+	int i;
+
+	if (!class_node_found) {
+		class_node_found = 1;
+		return (PICL_WALK_TERMINATE);
+	}
+	err = picl_get_prop_by_name(nodeh, PICL_PROP_IS_FRU, &proph);
+	if (err != PICL_SUCCESS)
+		return (PICL_WALK_CONTINUE);
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
+		sizeof (label));
+	if (err != PICL_SUCCESS)
+		return (PICL_WALK_CONTINUE);
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
+		status, sizeof (status));
+	if (err != PICL_SUCCESS)
+		return (PICL_WALK_CONTINUE);
+	if (syserrlog == 0) {
+		if (strcmp(status, "disabled") == 0) {
+			if (all_status_ok) {
+				all_status_ok = 0;
+				return (PICL_WALK_TERMINATE);
+			}
+		} else
+			return (PICL_WALK_CONTINUE);
+	}
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
+		sizeof (parenth));
+	if (err != PICL_SUCCESS) {
+		log_printf("\n");
+		return (PICL_WALK_CONTINUE);
+	}
+	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL)
+		return (PICL_WALK_TERMINATE);
+	for (i = 0; i < PARENT_NAMES; i++)
+		if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) {
+			while (--i > -1)
+				free(names[i]);
+			free(loc);
+			return (PICL_WALK_TERMINATE);
+		}
+	i = 0;
+	while (err == PICL_SUCCESS) {
+		if (parenth == chassish || parenth == phyplatformh)
+			break;
+		err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
+			names[i++], PICL_PROPNAMELEN_MAX);
+		if (err != PICL_SUCCESS) {
+			i--;
+			break;
+		}
+		if (i == PARENT_NAMES)
+			break;
+		err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
+			&parenth, sizeof (parenth));
+	}
+	loc[0] = '\0';
+	if (--i > -1)
+		loc = strncat(loc, names[i], strlen(names[i]));
+	while (--i > -1) {
+		loc = strncat(loc, "/", 1);
+		loc = strncat(loc, names[i], strlen(names[i]));
+	}
+	log_printf("%-21s", loc);
+	for (i = 0; i < PARENT_NAMES; i++)
+		free(names[i]);
+	free(loc);
+	log_printf("%-10s", label);
+	log_printf("%-9s", status);
+	log_printf("\n");
+	return (PICL_WALK_CONTINUE);
+}
+
+static void
+sun4v_print_fru_status()
+{
+	char *fmt = "%-20s %-9s %-8s\n";
+	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
+		sun4v_print_fru_status_callback);
+	if (!class_node_found)
+		return;
+	log_printf("\n");
+	log_printf("============================");
+	log_printf(" FRU Status ");
+	log_printf("============================");
+	log_printf("\n");
+
+	if (syserrlog == 0) {
+		(void) picl_walk_tree_by_class(phyplatformh,
+			PICL_CLASS_MODULE, NULL,
+			sun4v_print_fru_status_callback);
+		if (all_status_ok) {
+			log_printf("All FRUs are enabled.\n");
+			return;
+		}
+	}
+	log_printf(fmt, "Location", "Name", "Status", 0);
+	log_printf("-------------------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_MODULE, NULL,
+		sun4v_print_fru_status_callback);
+}
+
+/*ARGSUSED*/
+static int
+sun4v_print_fw_rev_callback(picl_nodehdl_t nodeh, void *args)
+{
+	char label[PICL_PROPNAMELEN_MAX];
+	char rev[PICL_PROPNAMELEN_MAX];
+	picl_errno_t err;
+
+	if (!class_node_found) {
+		class_node_found = 1;
+		return (PICL_WALK_TERMINATE);
+	}
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
+		sizeof (label));
+	if (err != PICL_SUCCESS)
+		return (PICL_WALK_CONTINUE);
+	err = picl_get_propval_by_name(nodeh, PICL_PROP_FW_REVISION, rev,
+		sizeof (rev));
+	if (err != PICL_SUCCESS)
+		return (PICL_WALK_CONTINUE);
+	if (strlen(rev) == 0)
+		return (PICL_WALK_CONTINUE);
+	log_printf("%-21s", label);
+	log_printf("%-40s", rev);
+	log_printf("\n");
+	return (PICL_WALK_CONTINUE);
+}
+
+static void
+sun4v_print_fw_rev()
+{
+	char *fmt = "%-20s %-10s\n";
+	if (syserrlog == 0)
+		return;
+	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
+		sun4v_print_fw_rev_callback);
+	if (!class_node_found)
+		return;
+	log_printf("\n");
+	log_printf("============================");
+	log_printf(" FW Version ");
+	log_printf("============================");
+	log_printf("\n");
+	log_printf(fmt, "Name", "Version", 0);
+	log_printf("----------------------------\n");
+	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
+		sun4v_print_fw_rev_callback);
+}
+
+static void
+sun4v_print_chassis_serial_no()
+{
+	char val[PICL_PROPNAMELEN_MAX];
+	picl_errno_t err;
+	if (syserrlog == 0 || chassish == 0)
+		return;
+
+	log_printf("\n");
+	log_printf("Chassis Serial Number");
+	log_printf("\n");
+	log_printf("---------------------\n");
+	err = picl_get_propval_by_name(chassish, PICL_PROP_SERIAL_NUMBER,
+		val, sizeof (val));
+	if (err == PICL_SUCCESS)
+		log_printf("%s", val);
+	log_printf("\n");
+}
--- a/usr/src/lib/libprtdiag/common/pdevinfo_sun4v.c	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/lib/libprtdiag/common/pdevinfo_sun4v.c	Sat Mar 31 18:24:05 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -68,8 +67,8 @@
 
 /* Function prototypes */
 Prom_node *sun4v_walk(Sys_tree *, Prom_node *, int);
-int sun4v_get_node_by_name(picl_nodehdl_t rooth, char *name,
-    picl_nodehdl_t *nodeh);
+picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *, picl_nodehdl_t *);
+
 /*
  * do_prominfo() is called from main() in usr/src/cmd/prtdiag/main.c
  *
@@ -86,7 +85,7 @@
 	picl_nodehdl_t	rooth;		/* root PICL node for IO display */
 	picl_nodehdl_t plafh;		/* Platform PICL node for IO display */
 
-	int err;
+	picl_errno_t err;
 
 	err = picl_initialize();
 	if (err != PICL_SUCCESS) {
@@ -238,7 +237,7 @@
 /*
  * search children to get the node by the nodename
  */
-int
+picl_errno_t
 sun4v_get_node_by_name(picl_nodehdl_t rooth, char *name,
     picl_nodehdl_t *nodeh)
 {
--- a/usr/src/pkgdefs/SUNWhea/prototype_sparc	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/pkgdefs/SUNWhea/prototype_sparc	Sat Mar 31 18:24:05 2007 -0700
@@ -278,6 +278,7 @@
 f none usr/platform/sun4v/include/sys/cpu_sgnblk_defs.h 644 root bin
 f none usr/platform/sun4v/include/sys/ddi_subrdefs.h 644 root bin
 f none usr/platform/sun4v/include/sys/ds_pri.h 644 root bin
+f none usr/platform/sun4v/include/sys/ds_snmp.h 644 root bin
 f none usr/platform/sun4v/include/sys/dvma.h 644 root bin
 f none usr/platform/sun4v/include/sys/eeprom.h 644 root bin
 f none usr/platform/sun4v/include/sys/fcode.h 644 root bin
--- a/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/pkgdefs/SUNWldomr.v/prototype_sparc	Sat Mar 31 18:24:05 2007 -0700
@@ -59,10 +59,12 @@
 d none platform/sun4v/kernel/drv 755 root sys
 f none platform/sun4v/kernel/drv/drctl.conf 0644 root sys
 f none platform/sun4v/kernel/drv/ds_pri.conf 644 root sys
+f none platform/sun4v/kernel/drv/ds_snmp.conf 644 root sys
 d none platform/sun4v/kernel/drv/sparcv9 755 root sys
 f none platform/sun4v/kernel/drv/sparcv9/cnex 755 root sys
 f none platform/sun4v/kernel/drv/sparcv9/drctl 755 root sys
 f none platform/sun4v/kernel/drv/sparcv9/ds_pri 755 root sys
+f none platform/sun4v/kernel/drv/sparcv9/ds_snmp 755 root sys
 f none platform/sun4v/kernel/drv/sparcv9/vcc 755 root sys
 f none platform/sun4v/kernel/drv/sparcv9/vdc 755 root sys
 f none platform/sun4v/kernel/drv/sparcv9/vds 755 root sys
--- a/usr/src/pkgdefs/SUNWpiclu/prototype_sparc	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/pkgdefs/SUNWpiclu/prototype_sparc	Sat Mar 31 18:24:05 2007 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -62,10 +62,16 @@
 s none usr/platform/sun4u/lib/picl/plugins/libpiclenvmon.so=./libpiclenvmon.so.1
 d none usr/platform/sun4v 755 root sys
 d none usr/platform/sun4v/lib 755 root bin
+f none usr/platform/sun4v/lib/libpiclsnmp.so.1 755 root sys
+s none usr/platform/sun4v/lib/libpiclsnmp.so=./libpiclsnmp.so.1 755 root sys
 d none usr/platform/sun4v/lib/picl 755 root sys
 d none usr/platform/sun4v/lib/picl/plugins 755 root sys
 f none usr/platform/sun4v/lib/picl/plugins/libmdescplugin.so.1 755 root sys
 s none usr/platform/sun4v/lib/picl/plugins/libmdescplugin.so=./libmdescplugin.so.1
+f none usr/platform/sun4v/lib/picl/plugins/libpriplugin.so.1 755 root sys
+s none usr/platform/sun4v/lib/picl/plugins/libpriplugin.so=./libpriplugin.so.1
+f none usr/platform/sun4v/lib/picl/plugins/libsnmpplugin.so.1 755 root sys
+s none usr/platform/sun4v/lib/picl/plugins/libsnmpplugin.so=./libsnmpplugin.so.1
 d none usr/platform/SUNW,Sun-Blade-100 755 root sys
 d none usr/platform/SUNW,Sun-Blade-100/lib 755 root bin
 d none usr/platform/SUNW,Sun-Blade-100/lib/picl 755 root sys
--- a/usr/src/uts/sparc/os/name_to_major	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/uts/sparc/os/name_to_major	Sat Mar 31 18:24:05 2007 -0700
@@ -216,3 +216,5 @@
 pxb_plx 268
 n2rng 269
 physmem 270
+ds_snmp 271
+ds_pri 272
--- a/usr/src/uts/sun4v/Makefile.files	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/uts/sun4v/Makefile.files	Sat Mar 31 18:24:05 2007 -0700
@@ -147,6 +147,7 @@
 VDC_OBJS	= vdc.o
 VDS_OBJS	= vds.o
 DS_PRI_OBJS	= ds_pri.o
+DS_SNMP_OBJS	= ds_snmp.o
 
 #
 #			Misc modules
--- a/usr/src/uts/sun4v/Makefile.sun4v.shared	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/uts/sun4v/Makefile.sun4v.shared	Sat Mar 31 18:24:05 2007 -0700
@@ -327,6 +327,7 @@
 DRV_KMODS	+= dma
 DRV_KMODS	+= drctl
 DRV_KMODS	+= ds_pri
+DRV_KMODS	+= ds_snmp
 DRV_KMODS	+= ebus
 DRV_KMODS	+= fpc
 DRV_KMODS	+= glvc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/ds_snmp/Makefile	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,99 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the pseudo device
+#	to access the sun4v SNMP
+#
+#	sun4v implementation architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= ds_snmp
+OBJECTS		= $(DS_SNMP_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(DS_SNMP_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_PSM_DRV_DIR)/$(MODULE)
+CONF_SRCDIR     = $(UTSBASE)/sun4v/io
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sun4v/Makefile.sun4v
+
+#
+#	Override defaults to build a unique, local modstubs.o.
+#
+MODSTUBS_DIR	= $(OBJS_DIR)
+
+CLEANFILES	+= $(MODSTUBS_O)
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# lint pass one enforcement
+#
+CFLAGS += -v
+
+#
+# Module Dependencies
+LDFLAGS		+= -dy -Nmisc/ds
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/$(PLATFORM)/Makefile.targ
--- a/usr/src/uts/sun4v/io/ds.c	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/uts/sun4v/io/ds.c	Sat Mar 31 18:24:05 2007 -0700
@@ -121,6 +121,15 @@
 #define	DS_DISPATCH(fn, arg)	taskq_dispatch(ds_taskq, fn, arg, TQ_SLEEP)
 
 /*
+ * Retry count and delay for LDC reads and writes
+ */
+#define	DS_DEFAULT_RETRIES	10000	/* number of times to retry */
+#define	DS_DEFAULT_DELAY	1000	/* usecs to wait between retries */
+
+static int ds_retries = DS_DEFAULT_RETRIES;
+static clock_t ds_delay = DS_DEFAULT_DELAY;
+
+/*
  * Supported versions of the DS message protocol
  *
  * The version array must be sorted in order from the highest
@@ -205,22 +214,24 @@
 
 #define	DS_DBG_FLAG_LDC			0x1
 #define	DS_DBG_FLAG_LOG			0x2
+#define	DS_DBG_FLAG_MSG			0x4
 #define	DS_DBG_FLAG_ALL			0xf
 
 #define	DS_DBG				if (ds_debug) printf
 #define	DS_DBG_LDC			if (ds_debug & DS_DBG_FLAG_LDC) printf
 #define	DS_DBG_LOG			if (ds_debug & DS_DBG_FLAG_LOG) printf
-#define	DS_DUMP_LDC_MSG(buf, len)	ds_dump_ldc_msg(buf, len)
+#define	DS_DBG_MSG			if (ds_debug & DS_DBG_FLAG_MSG) printf
+#define	DS_DUMP_MSG(buf, len)		ds_dump_msg(buf, len)
 
 uint_t ds_debug = 0;
-static void ds_dump_ldc_msg(void *buf, size_t len);
+static void ds_dump_msg(void *buf, size_t len);
 
 #else /* DEBUG */
 
 #define	DS_DBG				_NOTE(CONSTCOND) if (0) printf
 #define	DS_DBG_LDC			DS_DBG
 #define	DS_DBG_LOG			DS_DBG
-#define	DS_DUMP_LDC_MSG(buf, len)
+#define	DS_DUMP_MSG(buf, len)
 
 #endif /* DEBUG */
 
@@ -236,7 +247,7 @@
 /* event processing functions */
 static uint_t ds_ldc_cb(uint64_t event, caddr_t arg);
 static void ds_dispatch_event(void *arg);
-static int ds_recv_msg(ldc_handle_t ldc_hdl, caddr_t msgp, size_t *sizep);
+static int ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep);
 static void ds_handle_recv(void *arg);
 
 /* message sending functions */
@@ -764,42 +775,64 @@
  * in the size parameter.
  */
 static int
-ds_recv_msg(ldc_handle_t ldc_hdl, caddr_t msgp, size_t *sizep)
+ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep)
 {
 	int	rv = 0;
-	size_t	msglen = *sizep;
-	size_t	amt_left = msglen;
-	int	loopcnt = 0;
+	size_t	bytes_req = *sizep;
+	size_t	bytes_left = bytes_req;
+	size_t	nbytes;
+	int	retry_count = 0;
 
 	*sizep = 0;
 
-	while (msglen > 0) {
-		if ((rv = ldc_read(ldc_hdl, msgp, &amt_left)) != 0) {
-			if ((rv == EAGAIN) && (loopcnt++ < 1000)) {
-				/*
-				 * Try again, but don't try for more than
-				 * one second.  Something is wrong with
-				 * the channel.
-				 */
-				delay(drv_usectohz(10000)); /* 1/1000 sec */
-			} else {
-				/* fail */
-				return (rv);
-			}
+	DS_DBG_LDC("ds@%lx: attempting to read %ld bytes\n", port->id,
+	    bytes_req);
+
+	while (bytes_left > 0) {
+
+		nbytes = bytes_left;
+
+		if ((rv = ldc_read(port->ldc.hdl, msgp, &nbytes)) != 0) {
+			if (rv != EAGAIN)
+				break;
 		} else {
+			if (nbytes != 0) {
+				DS_DBG_LDC("ds@%lx: read %ld bytes, %d "
+				    "retries\n", port->id, nbytes, retry_count);
+
+				*sizep += nbytes;
+				msgp += nbytes;
+				bytes_left -= nbytes;
+
+				/* reset counter on a successful read */
+				retry_count = 0;
+				continue;
+			}
+
 			/*
-			 * Check for a zero length read. This
-			 * indicates that there is no more data
-			 * to read from the channel.
+			 * No data was read. Check if this is the
+			 * first attempt. If so, just return since
+			 * nothing has been read yet.
 			 */
-			if (amt_left == 0)
+			if (bytes_left == bytes_req) {
+				DS_DBG_LDC("ds@%lx: read zero bytes, no data "
+				    "available\n", port->id);
 				break;
-
-			*sizep += amt_left;
-			msgp += amt_left;
-			msglen -= amt_left;
-			amt_left = msglen;
+			}
 		}
+
+		/*
+		 * A retry is necessary because the read returned
+		 * EAGAIN, or a zero length read occurred after
+		 * reading a partial message.
+		 */
+		if (retry_count++ >= ds_retries) {
+			DS_DBG_LDC("ds@%lx: timed out waiting for "
+			    "message\n", port->id);
+			break;
+		}
+
+		drv_usecwait(ds_delay);
 	}
 
 	return (rv);
@@ -845,7 +878,7 @@
 		currp = hbuf;
 
 		/* read in the message header */
-		if ((rv = ds_recv_msg(ldc_hdl, currp, &read_size)) != 0) {
+		if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) {
 			cmn_err(CE_NOTE, "ds@%lx: ldc_read returned %d",
 			    port->id, rv);
 			continue;
@@ -874,7 +907,7 @@
 		currp = (char *)(msg) + DS_HDR_SZ;
 
 		/* read in the message body */
-		if ((rv = ds_recv_msg(ldc_hdl, currp, &read_size)) != 0) {
+		if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) {
 			cmn_err(CE_NOTE, "ds@%lx: ldc_read returned %d",
 			    port->id, rv);
 			kmem_free(msg, msglen);
@@ -890,7 +923,7 @@
 			continue;
 		}
 
-		DS_DUMP_LDC_MSG(msg, msglen);
+		DS_DUMP_MSG(msg, msglen);
 
 		/*
 		 * Send the message for processing, and store it
@@ -1555,7 +1588,8 @@
 	size_t	amt_left = msglen;
 	int	loopcnt = 0;
 
-	DS_DUMP_LDC_MSG(msg, msglen);
+	DS_DUMP_MSG(msg, msglen);
+
 	(void) ds_log_add_msg(DS_LOG_OUT(port->id), (uint8_t *)msg, msglen);
 
 	/*
@@ -1568,12 +1602,8 @@
 	/* send the message */
 	do {
 		if ((rv = ldc_write(port->ldc.hdl, currp, &msglen)) != 0) {
-			if ((rv == EWOULDBLOCK) && (loopcnt++ < 1000)) {
-				/*
-				 * don't try for more than a sec.  Something
-				 * is wrong with the channel.
-				 */
-				delay(drv_usectohz(10000)); /* 1/1000 sec */
+			if ((rv == EWOULDBLOCK) && (loopcnt++ < ds_retries)) {
+				drv_usecwait(ds_delay);
 			} else {
 				cmn_err(CE_WARN,
 				    "ds@%lx: send_msg: ldc_write failed (%d)",
@@ -1879,7 +1909,7 @@
  * and '.' otherwise.
  */
 static void
-ds_dump_ldc_msg(void *vbuf, size_t len)
+ds_dump_msg(void *vbuf, size_t len)
 {
 	int	i, j;
 	char	*curr;
@@ -1888,7 +1918,7 @@
 	uint8_t	*buf = vbuf;
 
 	/* abort if not debugging ldc */
-	if (!(ds_debug & DS_DBG_FLAG_LDC)) {
+	if (!(ds_debug & DS_DBG_FLAG_MSG)) {
 		return;
 	}
 
@@ -1923,7 +1953,7 @@
 		while (curr != (line + ASCIIOFFSET))
 			*curr++ = ' ';
 
-		DS_DBG_LDC("%s\n", line);
+		DS_DBG_MSG("%s\n", line);
 	}
 }
 #endif /* DEBUG */
--- a/usr/src/uts/sun4v/io/ds_pri.c	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/uts/sun4v/io/ds_pri.c	Sat Mar 31 18:24:05 2007 -0700
@@ -110,6 +110,7 @@
 	size_t		ds_pri_len;
 	uint64_t	req_id;
 	uint64_t	last_req_id;
+	int		num_opens;
 };
 
 typedef struct ds_pri_state ds_pri_state_t;
@@ -329,6 +330,7 @@
 	sp->ds_pri = NULL;
 	sp->ds_pri_len = 0;
 	sp->req_id = 0;
+	sp->num_opens = 0;
 
 	if ((rv = ds_cap_init(&ds_pri_cap, &ds_pri_ops)) != 0) {
 		cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
@@ -403,6 +405,25 @@
 	if (sp == NULL)
 		return (ENXIO);
 
+	mutex_enter(&sp->lock);
+
+	/*
+	 * If we're here and the state is DS_PRI_NO_SERVICE then this
+	 * means that ds hasn't yet called the registration callback.
+	 * Wait here and the callback will signal us when it has completed
+	 * its work.
+	 */
+	if (sp->state == DS_PRI_NO_SERVICE) {
+		if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
+			mutex_exit(&sp->lock);
+			return (EINTR);
+		}
+	}
+
+	sp->num_opens++;
+
+	mutex_exit(&sp->lock);
+
 	/*
 	 * On open we dont fetch the PRI even if we have a valid service
 	 * handle. PRI fetch is essentially lazy and on-demand.
@@ -419,6 +440,7 @@
 ds_pri_close(dev_t dev, int flag, int otyp, cred_t *credp)
 {
 	int instance;
+	ds_pri_state_t *sp;
 
 	if (otyp != OTYP_CHR)
 		return (EINVAL);
@@ -426,9 +448,35 @@
 	DS_PRI_DBG("ds_pri_close\n");
 
 	instance = getminor(dev);
-	if (ddi_get_soft_state(ds_pri_statep, instance) == NULL)
+	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
 		return (ENXIO);
 
+	mutex_enter(&sp->lock);
+	if (!(sp->state & DS_PRI_HAS_SERVICE)) {
+		mutex_exit(&sp->lock);
+		return (0);
+	}
+
+	if (--sp->num_opens > 0) {
+		mutex_exit(&sp->lock);
+		return (0);
+	}
+
+	/* If we have an old PRI - remove it */
+	if (sp->state & DS_PRI_HAS_PRI) {
+		if (sp->ds_pri != NULL && sp->ds_pri_len > 0) {
+			/*
+			 * remove the old data if we have an
+			 * outstanding request
+			 */
+			kmem_free(sp->ds_pri, sp->ds_pri_len);
+			sp->ds_pri_len = 0;
+			sp->ds_pri = NULL;
+		}
+		sp->state &= ~DS_PRI_HAS_PRI;
+	}
+	sp->state &= ~DS_PRI_REQUESTED;
+	mutex_exit(&sp->lock);
 	return (0);
 }
 
@@ -674,10 +722,14 @@
 	/* have service, but no PRI */
 	sp->state |= DS_PRI_HAS_SERVICE;
 
-		/*
-		 * Cannot request a PRI here, because the reg handler cannot
-		 * do a DS send operation - we take care of this later.
-		 */
+	/*
+	 * Cannot request a PRI here, because the reg handler cannot
+	 * do a DS send operation - we take care of this later.
+	 */
+
+	/* Wake up anyone waiting in open() */
+	cv_broadcast(&sp->cv);
+
 	mutex_exit(&sp->lock);
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/io/ds_snmp.c	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,1014 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * sun4v domain services SNMP driver
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <sys/open.h>
+#include <sys/cred.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/ksynch.h>
+#include <sys/modctl.h>
+#include <sys/conf.h>
+#include <sys/devops.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/ds.h>
+#include <sys/ds_snmp.h>
+
+#define	DS_SNMP_NAME		"ds_snmp"
+#define	DS_SNMP_MAX_OPENS	256
+#define	DS_BITS_IN_UINT64	64
+#define	DS_MINOR_POOL_SZ	(DS_SNMP_MAX_OPENS / DS_BITS_IN_UINT64)
+#define	DS_SNMP_MINOR_SHIFT	56
+#define	DS_SNMP_DBG		if (ds_snmp_debug) printf
+
+typedef	struct {
+	uint64_t	seq_num;
+	uint64_t	type;
+} ds_snmp_msg_t;
+
+typedef	enum {
+	DS_SNMP_REQUEST	= 0,
+	DS_SNMP_REPLY	= 1,
+	DS_SNMP_ERROR = 2
+} ds_snmp_msg_type_t;
+
+typedef enum {
+	DS_SNMP_READY = 0x0,
+	DS_SNMP_REQUESTED = 0x1,
+	DS_SNMP_DATA_AVL = 0x2,
+	DS_SNMP_DATA_ERR = 0x3
+} ds_snmp_flags_t;
+
+/*
+ * The single mutex 'lock' protects all the SNMP/DS variables in the state
+ * structure.
+ *
+ * The condition variable 'state_cv' helps serialize write() calls for a
+ * single descriptor. When write() is called, it sets a flag to indicate
+ * that an SNMP request has been made to the agent. No more write()'s on
+ * the same open descriptor will be allowed until this flag is cleared via
+ * a matching read(), where the requested packet is consumed on arrival.
+ * Read() then wakes up any waiters blocked in write() for sending the next
+ * SNMP request to the agent.
+ */
+typedef struct ds_snmp_state {
+	dev_info_t	*dip;
+	int		instance;
+	dev_t		dev;
+
+	/* SNMP/DS */
+	kmutex_t	lock;
+	kcondvar_t	state_cv;
+	ds_snmp_flags_t	state;
+	void		*data;
+	size_t		data_len;
+	uint64_t	req_id;
+	uint64_t	last_req_id;
+	uint64_t	gencount;
+	boolean_t	sc_reset;
+} ds_snmp_state_t;
+
+
+static uint_t		ds_snmp_debug = 0;
+static void		*ds_snmp_statep = NULL;
+static int		ds_snmp_instance = -1;
+static dev_info_t	*ds_snmp_devi = NULL;
+
+/*
+ * The ds_snmp_lock mutex protects the following data global to the
+ * driver.
+ *
+ * The ds_snmp_service_cv condition variable is used to resolve the
+ * potential race between the registration of snmp service via a
+ * ds_cap_init() in attach(), the acknowledgement of this registration
+ * at a later time in ds_snmp_reg_handler(), and a possible open() at
+ * a time inbetween. The ds_snmp_has_service and ds_snmp_handle are
+ * used to indicate whether the registration acknowledgement has happened
+ * or not.
+ *
+ * The ds_snmp_minor_pool[] is a bitmask to allocate and keep track of
+ * minor numbers dynamically.
+ */
+static kmutex_t		ds_snmp_lock;
+static kcondvar_t	ds_snmp_service_cv;
+static int		ds_snmp_has_service = B_FALSE;
+static ds_svc_hdl_t	ds_snmp_handle = DS_INVALID_HDL;
+static uint64_t		ds_snmp_minor_pool[DS_MINOR_POOL_SZ];	/* bitmask */
+static int		ds_snmp_num_opens = 0;
+
+static int ds_snmp_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int ds_snmp_attach(dev_info_t *, ddi_attach_cmd_t);
+static int ds_snmp_detach(dev_info_t *, ddi_detach_cmd_t);
+static int ds_snmp_open(dev_t *, int, int, cred_t *);
+static int ds_snmp_close(dev_t, int, int, cred_t *);
+static int ds_snmp_read(dev_t, struct uio *, cred_t *);
+static int ds_snmp_write(dev_t, struct uio *, cred_t *);
+static int ds_snmp_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+
+/*
+ * DS Callbacks
+ */
+static void ds_snmp_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
+static void ds_snmp_unreg_handler(ds_cb_arg_t arg);
+static void ds_snmp_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
+
+/*
+ * SNMP DS capability registration
+ */
+static ds_ver_t ds_snmp_ver_1_0 = { 1, 0 };
+static ds_capability_t ds_snmp_cap = {
+	"snmp",
+	&ds_snmp_ver_1_0,
+	1
+};
+
+/*
+ * SNMP DS Client callback vector
+ */
+static ds_clnt_ops_t ds_snmp_ops = {
+	ds_snmp_reg_handler,	/* ds_reg_cb */
+	ds_snmp_unreg_handler,	/* ds_unreg_cb */
+	ds_snmp_data_handler,	/* ds_data_cb */
+	NULL			/* cb_arg */
+};
+
+/*
+ * DS SNMP driver Ops Vector
+ */
+static struct cb_ops ds_snmp_cb_ops = {
+	ds_snmp_open,		/* cb_open */
+	ds_snmp_close,		/* cb_close */
+	nodev,			/* cb_strategy */
+	nodev,			/* cb_print */
+	nodev,			/* cb_dump */
+	ds_snmp_read,		/* cb_read */
+	ds_snmp_write,		/* cb_write */
+	ds_snmp_ioctl,		/* cb_ioctl */
+	nodev,			/* cb_devmap */
+	nodev,			/* cb_mmap */
+	nodev,			/* cb_segmap */
+	nochpoll,		/* cb_chpoll */
+	ddi_prop_op,		/* cb_prop_op */
+	(struct streamtab *)NULL, /* cb_str */
+	D_MP | D_64BIT,		/* cb_flag */
+	CB_REV,			/* cb_rev */
+	nodev,			/* cb_aread */
+	nodev			/* cb_awrite */
+};
+
+static struct dev_ops ds_snmp_dev_ops = {
+	DEVO_REV,		/* devo_rev */
+	0,			/* devo_refcnt */
+	ds_snmp_getinfo,	/* devo_getinfo */
+	nulldev,		/* devo_identify */
+	nulldev,		/* devo_probe */
+	ds_snmp_attach,		/* devo_attach */
+	ds_snmp_detach,		/* devo_detach */
+	nodev,			/* devo_reset */
+	&ds_snmp_cb_ops,	/* devo_cb_ops */
+	(struct bus_ops *)NULL,	/* devo_bus_ops */
+	nulldev			/* devo_power */
+};
+
+static struct modldrv modldrv = {
+	&mod_driverops,
+	"Domain Services SNMP Driver 1.0",
+	&ds_snmp_dev_ops
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	(void *)&modldrv,
+	NULL
+};
+
+int
+_init(void)
+{
+	int retval;
+
+	mutex_init(&ds_snmp_lock, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&ds_snmp_service_cv, NULL, CV_DRIVER, NULL);
+
+	retval = ddi_soft_state_init(&ds_snmp_statep,
+	    sizeof (ds_snmp_state_t), DS_SNMP_MAX_OPENS);
+	if (retval != 0) {
+		cv_destroy(&ds_snmp_service_cv);
+		mutex_destroy(&ds_snmp_lock);
+		return (retval);
+	}
+
+	retval = mod_install(&modlinkage);
+	if (retval != 0) {
+		ddi_soft_state_fini(&ds_snmp_statep);
+		cv_destroy(&ds_snmp_service_cv);
+		mutex_destroy(&ds_snmp_lock);
+	}
+
+	return (retval);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+	int retval;
+
+	if ((retval = mod_remove(&modlinkage)) != 0)
+		return (retval);
+
+	ddi_soft_state_fini(&ds_snmp_statep);
+
+	cv_destroy(&ds_snmp_service_cv);
+	mutex_destroy(&ds_snmp_lock);
+
+	return (retval);
+}
+
+/*ARGSUSED*/
+static int
+ds_snmp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
+{
+	ds_snmp_state_t *sp;
+	int retval = DDI_FAILURE;
+
+	ASSERT(resultp != NULL);
+
+	switch (cmd) {
+	case DDI_INFO_DEVT2DEVINFO:
+		sp = ddi_get_soft_state(ds_snmp_statep, getminor((dev_t)arg));
+		if (sp != NULL) {
+			*resultp = sp->dip;
+			retval = DDI_SUCCESS;
+		} else
+			*resultp = NULL;
+		break;
+
+	case DDI_INFO_DEVT2INSTANCE:
+		*resultp = (void *)(uintptr_t)getminor((dev_t)arg);
+		retval = DDI_SUCCESS;
+		break;
+	}
+
+	return (retval);
+}
+
+static int
+ds_snmp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	int	rv;
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		if (ds_snmp_instance != -1)
+			return (DDI_FAILURE);
+		break;
+
+	case DDI_RESUME:
+		return (DDI_SUCCESS);
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	ds_snmp_instance = ddi_get_instance(dip);
+	if (ddi_create_minor_node(dip, DS_SNMP_NAME, S_IFCHR, ds_snmp_instance,
+		DDI_PSEUDO, 0) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "%s@%d: Unable to create minor node",
+		    DS_SNMP_NAME, ds_snmp_instance);
+		return (DDI_FAILURE);
+	}
+
+	bzero(ds_snmp_minor_pool, DS_MINOR_POOL_SZ * sizeof (uint64_t));
+
+	ds_snmp_ops.cb_arg = dip;
+	if ((rv = ds_cap_init(&ds_snmp_cap, &ds_snmp_ops)) != 0) {
+		cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
+		ddi_remove_minor_node(dip, NULL);
+		ds_snmp_instance = -1;
+		return (DDI_FAILURE);
+	}
+
+	ds_snmp_devi = dip;
+	ddi_report_dev(dip);
+
+	return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+static int
+ds_snmp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	switch (cmd) {
+	case DDI_DETACH:
+		if (ds_snmp_instance == -1)
+			return (DDI_FAILURE);
+		break;
+
+	case DDI_SUSPEND:
+		return (DDI_SUCCESS);
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	(void) ds_cap_fini(&ds_snmp_cap);
+
+	ddi_remove_minor_node(ds_snmp_devi, NULL);
+	bzero(ds_snmp_minor_pool, DS_MINOR_POOL_SZ * sizeof (uint64_t));
+
+	ds_snmp_instance = -1;
+	ds_snmp_devi = NULL;
+
+	return (DDI_SUCCESS);
+}
+
+static minor_t
+ds_snmp_get_minor(void)
+{
+	uint64_t	val;
+	int		i, ndx;
+	minor_t		minor;
+
+	mutex_enter(&ds_snmp_lock);
+	for (ndx = 0; ndx < DS_MINOR_POOL_SZ; ndx++) {
+		val = ds_snmp_minor_pool[ndx];
+		for (i = 0; i < DS_BITS_IN_UINT64; i++) {
+			if ((val & 0x1) == 0) {
+				ds_snmp_minor_pool[ndx] |= ((uint64_t)1 << i);
+				ds_snmp_num_opens++;
+				mutex_exit(&ds_snmp_lock);
+
+				minor = ndx * DS_BITS_IN_UINT64 + i + 1;
+
+				return (minor);
+			}
+			val >>= 1;
+		}
+	}
+	mutex_exit(&ds_snmp_lock);
+
+	return (0);
+}
+
+static void
+ds_snmp_rel_minor(minor_t minor)
+{
+	int	i, ndx;
+
+	ndx = (minor - 1) / DS_BITS_IN_UINT64;
+	i = (minor - 1) % DS_BITS_IN_UINT64;
+
+	ASSERT(ndx < DS_MINOR_POOL_SZ);
+
+	mutex_enter(&ds_snmp_lock);
+
+	ds_snmp_num_opens--;
+	ds_snmp_minor_pool[ndx] &= ~((uint64_t)1 << i);
+
+	mutex_exit(&ds_snmp_lock);
+}
+
+static boolean_t
+ds_snmp_is_open(minor_t minor)
+{
+	uint64_t	val;
+	int		i, ndx;
+
+	ndx = (minor - 1) / DS_BITS_IN_UINT64;
+	i = (minor - 1) % DS_BITS_IN_UINT64;
+
+	val = ((uint64_t)1 << i);
+	if (ds_snmp_minor_pool[ndx] & val)
+		return (B_TRUE);
+	else
+		return (B_FALSE);
+}
+
+static int
+ds_snmp_create_state(dev_t *devp)
+{
+	major_t	major;
+	minor_t	minor;
+	ds_snmp_state_t	*sp;
+
+	if ((minor = ds_snmp_get_minor()) == 0)
+		return (EMFILE);
+
+	if (ddi_soft_state_zalloc(ds_snmp_statep, minor) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "%s@%d: Unable to allocate state",
+		    DS_SNMP_NAME, minor);
+		ds_snmp_rel_minor(minor);
+		return (ENOMEM);
+	}
+
+	sp = ddi_get_soft_state(ds_snmp_statep, minor);
+	if (devp != NULL)
+		major = getemajor(*devp);
+	else
+		major = ddi_driver_major(ds_snmp_devi);
+
+	sp->dev = makedevice(major, minor);
+	if (devp != NULL)
+		*devp = sp->dev;
+
+	sp->instance = minor;
+	sp->data = NULL;
+	sp->data_len = 0;
+	sp->req_id = 0;
+	sp->last_req_id = 0;
+	sp->state = DS_SNMP_READY;
+	sp->sc_reset = B_FALSE;
+
+	mutex_init(&sp->lock, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&sp->state_cv, NULL, CV_DRIVER, NULL);
+
+	return (0);
+}
+
+static int
+ds_snmp_destroy_state(dev_t dev)
+{
+	ds_snmp_state_t	*sp;
+	minor_t	minor;
+
+	minor = getminor(dev);
+
+	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
+		return (ENXIO);
+
+	ASSERT(sp->instance == minor);
+
+	/*
+	 * If the app has not exited cleanly, the data may not have been
+	 * read/memory freed, hence take care of that here
+	 */
+	if (sp->data) {
+		kmem_free(sp->data, sp->data_len);
+	}
+	cv_destroy(&sp->state_cv);
+	mutex_destroy(&sp->lock);
+
+	ddi_soft_state_free(ds_snmp_statep, minor);
+	ds_snmp_rel_minor(minor);
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+ds_snmp_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+
+	if (otyp != OTYP_CHR)
+		return (EINVAL);
+
+	if (ds_snmp_instance == -1)
+		return (ENXIO);
+
+	/*
+	 * Avoid possible race condition - ds service may not be there yet
+	 */
+	mutex_enter(&ds_snmp_lock);
+	while (ds_snmp_has_service == B_FALSE) {
+		if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
+			mutex_exit(&ds_snmp_lock);
+			return (EINTR);
+		}
+	}
+	mutex_exit(&ds_snmp_lock);
+
+	return (ds_snmp_create_state(devp));
+}
+
+
+/*ARGSUSED*/
+static int
+ds_snmp_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+	if (otyp != OTYP_CHR)
+		return (EINVAL);
+
+	if (ds_snmp_instance == -1)
+		return (ENXIO);
+
+	if (ds_snmp_handle == DS_INVALID_HDL)
+		return (EIO);
+
+	return (ds_snmp_destroy_state(dev));
+}
+
+/*ARGSUSED*/
+static int
+ds_snmp_read(dev_t dev, struct uio *uiop, cred_t *credp)
+{
+	ds_snmp_state_t *sp;
+	minor_t	minor;
+	size_t len;
+	int retval;
+	caddr_t tmpbufp = (caddr_t)NULL;
+
+	/*
+	 * Given that now we can have sc resets happening at any
+	 * time, it is possible that it happened since the last time
+	 * we issued a read, write or ioctl.  If so, we need to wait
+	 * for the unreg-reg pair to complete before we can do
+	 * anything.
+	 */
+	mutex_enter(&ds_snmp_lock);
+	while (ds_snmp_has_service == B_FALSE) {
+		DS_SNMP_DBG("ds_snmp_read: waiting for service\n");
+		if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
+			mutex_exit(&ds_snmp_lock);
+			return (EINTR);
+		}
+	}
+	mutex_exit(&ds_snmp_lock);
+
+	if ((len = uiop->uio_resid) == 0)
+		return (0);
+
+	minor = getminor(dev);
+	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
+		return (ENXIO);
+
+	mutex_enter(&sp->lock);
+
+	if (sp->sc_reset == B_TRUE) {
+		mutex_exit(&sp->lock);
+		return (ECANCELED);
+	}
+
+	/*
+	 * Block or bail if there is no SNMP data
+	 */
+	if (sp->state != DS_SNMP_DATA_AVL && sp->state != DS_SNMP_DATA_ERR) {
+		DS_SNMP_DBG("ds_snmp_read: no SNMP data\n");
+		if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) {
+			mutex_exit(&sp->lock);
+			return (EAGAIN);
+		}
+		while (sp->state != DS_SNMP_DATA_AVL &&
+			sp->state != DS_SNMP_DATA_ERR) {
+			if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) {
+				mutex_exit(&sp->lock);
+				return (EINTR);
+			}
+		}
+	}
+
+	/*
+	 * If there has been an error, it could be because the agent
+	 * returned failure and there is no data to read, or an ldc-reset
+	 * has happened.  Figure out which and return appropriate
+	 * error to the caller.
+	 */
+	if (sp->state == DS_SNMP_DATA_ERR) {
+		if (sp->sc_reset == B_TRUE) {
+			mutex_exit(&sp->lock);
+			DS_SNMP_DBG("ds_snmp_read: sc got reset, "
+			    "returning ECANCELED\n");
+			return (ECANCELED);
+		} else {
+			sp->state = DS_SNMP_READY;
+			cv_broadcast(&sp->state_cv);
+			mutex_exit(&sp->lock);
+			DS_SNMP_DBG("ds_snmp_read: data error, "
+			    "returning EIO\n");
+			return (EIO);
+		}
+	}
+
+	if (len > sp->data_len)
+		len = sp->data_len;
+
+	tmpbufp = kmem_alloc(len, KM_SLEEP);
+
+	bcopy(sp->data, (void *)tmpbufp, len);
+	kmem_free(sp->data, sp->data_len);
+	sp->data = (caddr_t)NULL;
+	sp->data_len = 0;
+
+	/*
+	 * SNMP data has been consumed, wake up anyone waiting to send
+	 */
+	sp->state = DS_SNMP_READY;
+	cv_broadcast(&sp->state_cv);
+
+	mutex_exit(&sp->lock);
+
+	retval = uiomove(tmpbufp, len, UIO_READ, uiop);
+	kmem_free(tmpbufp, len);
+
+	return (retval);
+}
+
+/*ARGSUSED*/
+static int
+ds_snmp_write(dev_t dev, struct uio *uiop, cred_t *credp)
+{
+	ds_snmp_state_t *sp;
+	ds_snmp_msg_t hdr;
+	minor_t minor;
+	size_t len;
+	caddr_t tmpbufp;
+
+	/*
+	 * Check if there was an sc reset; if yes, wait until we have the
+	 * service back again.
+	 */
+	mutex_enter(&ds_snmp_lock);
+	while (ds_snmp_has_service == B_FALSE) {
+		DS_SNMP_DBG("ds_snmp_write: waiting for service\n");
+		if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
+			mutex_exit(&ds_snmp_lock);
+			return (EINTR);
+		}
+	}
+	mutex_exit(&ds_snmp_lock);
+
+	minor = getminor(dev);
+	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
+		return (ENXIO);
+
+	len = uiop->uio_resid + sizeof (ds_snmp_msg_t);
+	tmpbufp = kmem_alloc(len, KM_SLEEP);
+
+	if (uiomove(tmpbufp + sizeof (ds_snmp_msg_t),
+	    len - sizeof (ds_snmp_msg_t), UIO_WRITE, uiop) != 0) {
+		kmem_free(tmpbufp, len);
+		return (EIO);
+	}
+
+	mutex_enter(&sp->lock);
+
+	if (sp->sc_reset == B_TRUE) {
+		mutex_exit(&sp->lock);
+		kmem_free(tmpbufp, len);
+		DS_SNMP_DBG("ds_snmp_write: sc_reset is TRUE, "
+		    "returning ECANCELD\n");
+		return (ECANCELED);
+	}
+
+	/*
+	 * wait if earlier transaction is not yet completed
+	 */
+	while (sp->state != DS_SNMP_READY) {
+		if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) {
+			mutex_exit(&sp->lock);
+			kmem_free(tmpbufp, len);
+			return (EINTR);
+		}
+		/*
+		 * Normally, only a reader would ever wake us up. But if we
+		 * did get signalled with an ERROR, it could only mean there
+		 * was an sc reset and there's no point waiting; we need to
+		 * fail this write().
+		 */
+		if (sp->state == DS_SNMP_DATA_ERR && sp->sc_reset == B_TRUE) {
+			DS_SNMP_DBG("ds_snmp_write: woke up with an sc_reset, "
+			    "returning ECANCELED\n");
+			mutex_exit(&sp->lock);
+			kmem_free(tmpbufp, len);
+			return (ECANCELED);
+		}
+	}
+
+	if (sp->req_id == (((uint64_t)1 << DS_SNMP_MINOR_SHIFT) - 1))
+		sp->req_id = 0; /* Reset */
+
+	hdr.seq_num = ((uint64_t)minor << DS_SNMP_MINOR_SHIFT) | sp->req_id;
+	sp->last_req_id = hdr.seq_num;
+	(sp->req_id)++;
+
+	/*
+	 * Set state to SNMP_REQUESTED, but don't wakeup anyone yet
+	 */
+	sp->state = DS_SNMP_REQUESTED;
+
+	mutex_exit(&sp->lock);
+
+	hdr.type = DS_SNMP_REQUEST;
+	bcopy((void *)&hdr, (void *)tmpbufp, sizeof (hdr));
+
+	/*
+	 * If the service went away since the time we entered this
+	 * routine and now, tough luck. Just ignore the current
+	 * write() and return.
+	 */
+	mutex_enter(&ds_snmp_lock);
+	if (ds_snmp_has_service == B_FALSE) {
+		DS_SNMP_DBG("ds_snmp_write: service went away, aborting "
+		    "write, returning ECANCELED\n");
+		mutex_exit(&ds_snmp_lock);
+		kmem_free(tmpbufp, len);
+		return (ECANCELED);
+	}
+	DS_SNMP_DBG("ds_snmp_write: ds_cap_send(0x%lx, %lu) called.\n",
+	    ds_snmp_handle, len);
+	(void) ds_cap_send(ds_snmp_handle, tmpbufp, len);
+	mutex_exit(&ds_snmp_lock);
+
+	kmem_free(tmpbufp, len);
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+ds_snmp_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+    int *rvalp)
+{
+	ds_snmp_state_t *sp;
+	struct dssnmp_info info;
+	minor_t	minor;
+
+	/*
+	 * Check if there was an sc reset; if yes, wait until we have the
+	 * service back again.
+	 */
+	mutex_enter(&ds_snmp_lock);
+	while (ds_snmp_has_service == B_FALSE) {
+		DS_SNMP_DBG("ds_snmp_ioctl: waiting for service\n");
+		if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
+			mutex_exit(&ds_snmp_lock);
+			return (EINTR);
+		}
+	}
+	mutex_exit(&ds_snmp_lock);
+
+	DS_SNMP_DBG("ds_snmp_ioctl: hdl=0x%lx\n", ds_snmp_handle);
+
+	minor = getminor(dev);
+	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
+		return (ENXIO);
+
+	if (!(mode & FREAD))
+		return (EACCES);
+
+	switch (cmd) {
+	case DSSNMP_GETINFO:
+		mutex_enter(&sp->lock);
+
+		if (sp->sc_reset == B_TRUE) {
+			mutex_exit(&sp->lock);
+			DS_SNMP_DBG("ds_snmp_ioctl: returning ECANCELED\n");
+			return (ECANCELED);
+		}
+
+		while (sp->state != DS_SNMP_DATA_AVL &&
+		    sp->state != DS_SNMP_DATA_ERR) {
+			DS_SNMP_DBG("ds_snmp_ioctl: state=%d, sc_reset=%d, "
+			    "waiting for data\n", sp->state, sp->sc_reset);
+			if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) {
+				mutex_exit(&sp->lock);
+				return (EINTR);
+			}
+		}
+		DS_SNMP_DBG("ds_snmp_ioctl: state=%d, sc_reset=%d, "
+		    "out of wait!\n", sp->state, sp->sc_reset);
+
+		/*
+		 * If there has been an error, it could be because the
+		 * agent returned failure and there is no data to read,
+		 * or an ldc-reset has happened.  Figure out which and
+		 * return appropriate error to the caller.
+		 */
+		if (sp->state == DS_SNMP_DATA_ERR) {
+			if (sp->sc_reset == B_TRUE) {
+				mutex_exit(&sp->lock);
+				DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=TRUE "
+				    "returning ECANCELED\n");
+				return (ECANCELED);
+			} else {
+				sp->state = DS_SNMP_READY;
+				cv_broadcast(&sp->state_cv);
+				mutex_exit(&sp->lock);
+				DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=FALSE "
+				    "returning EIO\n");
+				return (EIO);
+			}
+		}
+
+		info.size = sp->data_len;
+		info.token = sp->gencount;
+
+		mutex_exit(&sp->lock);
+
+		if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0)
+			return (EFAULT);
+		break;
+
+	case DSSNMP_CLRLNKRESET:
+		mutex_enter(&sp->lock);
+
+		DS_SNMP_DBG("ds_snmp_ioctl: DSSNMP_CLRLNKRESET\n");
+		DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=%d\n", sp->sc_reset);
+
+		if (sp->sc_reset == B_TRUE) {
+			if (sp->data) {
+				DS_SNMP_DBG("ds_snmp_ioctl: data=%p, len=%lu\n",
+				    sp->data, sp->data_len);
+				kmem_free(sp->data, sp->data_len);
+			}
+			sp->data = NULL;
+			sp->data_len = 0;
+			sp->state = DS_SNMP_READY;
+			sp->req_id = 0;
+			sp->last_req_id = 0;
+			sp->sc_reset = B_FALSE;
+		}
+		mutex_exit(&sp->lock);
+		break;
+
+	default:
+		return (ENOTTY);
+	}
+
+	return (0);
+}
+
+/*
+ * DS Callbacks
+ */
+/*ARGSUSED*/
+static void
+ds_snmp_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
+{
+	DS_SNMP_DBG("ds_snmp_reg_handler: registering handle 0x%lx for version "
+	    "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor);
+
+	mutex_enter(&ds_snmp_lock);
+
+	ASSERT(ds_snmp_handle == DS_INVALID_HDL);
+
+	ds_snmp_handle = hdl;
+	ds_snmp_has_service = B_TRUE;
+
+	cv_broadcast(&ds_snmp_service_cv);
+
+	mutex_exit(&ds_snmp_lock);
+
+}
+
+/*ARGSUSED*/
+static void
+ds_snmp_unreg_handler(ds_cb_arg_t arg)
+{
+	minor_t minor;
+	ds_snmp_state_t *sp;
+
+	DS_SNMP_DBG("ds_snmp_unreg_handler: un-registering ds_snmp service\n");
+
+	mutex_enter(&ds_snmp_lock);
+
+	if (ds_snmp_num_opens) {
+		DS_SNMP_DBG("ds_snmp_unreg_handler: %d opens, sc reset!\n",
+		    ds_snmp_num_opens);
+		for (minor = 1; minor <= DS_SNMP_MAX_OPENS; minor++) {
+			if (ds_snmp_is_open(minor)) {
+				DS_SNMP_DBG("ds_snmp_unreg_handler: minor %d "
+				    "open\n", minor);
+				sp = ddi_get_soft_state(ds_snmp_statep, minor);
+				if (sp == NULL)
+					continue;
+
+				/*
+				 * Set the sc_reset flag and break any waiters
+				 * out of their existing reads/writes/ioctls.
+				 */
+				DS_SNMP_DBG("ds_snmp_unreg_hdlr: about to "
+				    "signal waiters\n");
+				mutex_enter(&sp->lock);
+				sp->sc_reset = B_TRUE;
+				sp->state = DS_SNMP_DATA_ERR;
+				cv_broadcast(&sp->state_cv);
+				mutex_exit(&sp->lock);
+			}
+		}
+	}
+
+	ds_snmp_handle = DS_INVALID_HDL;
+	ds_snmp_has_service = B_FALSE;
+
+	DS_SNMP_DBG("ds_snmp_unreg_handler: handle invalidated\n");
+
+	mutex_exit(&ds_snmp_lock);
+}
+
+/*ARGSUSED*/
+static void
+ds_snmp_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
+{
+	ds_snmp_state_t *sp;
+	ds_snmp_msg_t   hdr;
+	size_t  	snmp_size;
+	minor_t 	minor;
+
+	/*
+	 * Make sure the header is at least valid
+	 */
+	if (buflen < sizeof (hdr)) {
+		cmn_err(CE_WARN,
+		"ds_snmp_data_handler: buflen <%lu> too small", buflen);
+		return;
+	}
+
+	ASSERT(buf != NULL);
+	bcopy(buf, (void *)&hdr, sizeof (hdr));
+
+	DS_SNMP_DBG("ds_snmp_data_handler: msg buf len 0x%lx : type 0x%lx, "
+	    "seqn 0x%lx\n", buflen, hdr.type, hdr.seq_num);
+
+	minor = (int)(hdr.seq_num >> DS_SNMP_MINOR_SHIFT);
+	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
+		return;
+
+	mutex_enter(&sp->lock);
+
+	/*
+	 * If there is no pending SNMP request, then we've received
+	 * bogus data or an SNMP trap. Since we don't yet support SNMP
+	 * traps, ignore it.
+	 */
+	if (sp->state != DS_SNMP_REQUESTED) {
+		cmn_err(CE_WARN, "Received SNMP data without request");
+		mutex_exit(&sp->lock);
+		return;
+	}
+
+	/*
+	 * Response to a request therefore old SNMP must've been consumed
+	 */
+	ASSERT(sp->data_len == 0);
+	ASSERT(sp->data == NULL);
+
+	/*
+	 * Response seq_num should match our request seq_num
+	 */
+	if (hdr.seq_num != sp->last_req_id) {
+		cmn_err(CE_WARN, "Received DS snmp data out of sequence with "
+		    "request");
+		mutex_exit(&sp->lock);
+		return;
+	}
+
+	if (hdr.type == DS_SNMP_ERROR) {
+		sp->state = DS_SNMP_DATA_ERR;
+		DS_SNMP_DBG("ds_snmp_data_handler: hdr.type = DS_SNMP_ERROR\n");
+	} else {
+		snmp_size = buflen - sizeof (ds_snmp_msg_t);
+		sp->data = kmem_alloc(snmp_size, KM_SLEEP);
+		sp->data_len = snmp_size;
+		sp->state = DS_SNMP_DATA_AVL;
+
+		bcopy((caddr_t)buf + sizeof (ds_snmp_msg_t),
+		    sp->data, sp->data_len);
+	}
+
+	sp->gencount++;
+
+	/*
+	 * Wake up any readers waiting for data
+	 */
+	cv_broadcast(&sp->state_cv);
+	mutex_exit(&sp->lock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/io/ds_snmp.conf	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+name="ds_snmp" parent="pseudo" instance=0;
--- a/usr/src/uts/sun4v/sys/Makefile	Sat Mar 31 14:17:25 2007 -0700
+++ b/usr/src/uts/sun4v/sys/Makefile	Sat Mar 31 18:24:05 2007 -0700
@@ -72,6 +72,7 @@
 
 HDRS=	\
 	ds_pri.h		\
+	ds_snmp.h		\
 	hypervisor_api.h	\
 	hsvc.h			\
 	machasi.h		\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/sys/ds_snmp.h	Sat Mar 31 18:24:05 2007 -0700
@@ -0,0 +1,60 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SYS_DS_SNMP_H_
+#define	_SYS_DS_SNMP_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * ioctl info for ds_snmp device
+ */
+
+#define	DSSNMPIOC		('d' << 24 | 's' << 16 | 'p' << 8)
+
+#define	DSSNMP_GETINFO		(DSSNMPIOC | 1)	/* Get SNMP size */
+#define	DSSNMP_CLRLNKRESET	(DSSNMPIOC | 2)	/* Clear link reset flag */
+
+/*
+ * DSSNMP_GETINFO
+ * Datamodel invariant.
+ */
+struct dssnmp_info {
+	uint64_t size;
+	uint64_t token;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DS_SNMP_H_ */