xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.c (revision 7935:01d8effbe014)
13941Svenki /*
23941Svenki  * CDDL HEADER START
33941Svenki  *
43941Svenki  * The contents of this file are subject to the terms of the
53941Svenki  * Common Development and Distribution License (the "License").
63941Svenki  * You may not use this file except in compliance with the License.
73941Svenki  *
83941Svenki  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93941Svenki  * or http://www.opensolaris.org/os/licensing.
103941Svenki  * See the License for the specific language governing permissions
113941Svenki  * and limitations under the License.
123941Svenki  *
133941Svenki  * When distributing Covered Code, include this CDDL HEADER in each
143941Svenki  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153941Svenki  * If applicable, add the following below this CDDL HEADER, with the
163941Svenki  * fields enclosed by brackets "[]" replaced with your own identifying
173941Svenki  * information: Portions Copyright [yyyy] [name of copyright owner]
183941Svenki  *
193941Svenki  * CDDL HEADER END
203941Svenki  */
213941Svenki 
223941Svenki /*
235995Sfw157321  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
243941Svenki  * Use is subject to license terms.
253941Svenki  */
263941Svenki 
273941Svenki /*
283941Svenki  * The SNMP picl plugin connects to the agent on the SP and creates
293941Svenki  * and populates the /physical-platform subtree in picl tree for use
303941Svenki  * by picl consumers.
313941Svenki  */
323941Svenki 
333941Svenki #include <stdio.h>
343941Svenki #include <stdlib.h>
353941Svenki #include <string.h>
363941Svenki #include <syslog.h>
373941Svenki #include <stdarg.h>
383941Svenki #include <libgen.h>
393941Svenki #include <libintl.h>
403941Svenki #include <thread.h>
413941Svenki #include <synch.h>
423941Svenki #include <errno.h>
437746SKelly.Moyer@Sun.COM #include <time.h>
443941Svenki 
453941Svenki #include <picldefs.h>
463941Svenki #include <picl.h>
473941Svenki #include <picltree.h>
483941Svenki 
493941Svenki #include "picloids.h"
503941Svenki #include "libpiclsnmp.h"
513941Svenki #include "snmpplugin.h"
523941Svenki 
533941Svenki #pragma init(snmpplugin_register)	/* place in .init section */
543941Svenki 
553941Svenki picld_plugin_reg_t snmpplugin_reg = {
563941Svenki 	PICLD_PLUGIN_VERSION_1,
573941Svenki 	PICLD_PLUGIN_NON_CRITICAL,
583941Svenki 	"snmp_plugin",
593941Svenki 	snmpplugin_init,
603941Svenki 	snmpplugin_fini
613941Svenki };
623941Svenki 
633941Svenki static picl_snmphdl_t	hdl;
643941Svenki 
653941Svenki /*
663941Svenki  * The stale_tree_rwlp protects the stale_xxx vars. The 'stale_tree' flag
673941Svenki  * and the 'rebuild_tree' flag below are both initialized to B_TRUE to
683941Svenki  * let the tree_builder() thread build the initial tree without blocking.
693941Svenki  */
703941Svenki static rwlock_t		stale_tree_rwlp;
713941Svenki static boolean_t	stale_tree = B_TRUE;
723941Svenki 
733941Svenki /*
743941Svenki  * vol_props, volprop_ndx and n_vol_props are protected by the stale_tree
753941Svenki  * flag.  They are read only when the stale_tree flag is B_FALSE and written
763941Svenki  * to only when the flag is B_TRUE.
773941Svenki  *
783941Svenki  * The change_time (last changed time) is read by only one thread at a
793941Svenki  * time when stale_tree is B_FALSE (protected by stale_tree_rwlp).  It is
803941Svenki  * written by only one thread (the tree builder) when stale_tree is B_TRUE.
813941Svenki  *
823941Svenki  * Note that strictly speaking, change_time should be uint_t (timeticks32).
833941Svenki  * But keeping it as int is fine, since we don't do any arithmetic on it
843941Svenki  * except equality check.
853941Svenki  */
863941Svenki static vol_prophdl_t	*vol_props = NULL;
873941Svenki static int		volprop_ndx = 0, n_vol_props = 0;
883941Svenki static int		change_time = 0;
895723Sfw157321 static time_t		change_time_check;
903941Svenki 
913941Svenki /*
923941Svenki  * The rebuild_tree_lock and cv are used by the tree builder thread.
933941Svenki  * rebuild_tree has to be initialized to B_TRUE to let the tree_builder
943941Svenki  * do the first build without blocking.
953941Svenki  */
963941Svenki static mutex_t		rebuild_tree_lock;
973941Svenki static cond_t		rebuild_tree_cv;
983941Svenki static boolean_t	rebuild_tree = B_TRUE;
995029Sfw157321 static boolean_t	tree_builder_thr_exit = B_FALSE;
1005029Sfw157321 static thread_t		tree_builder_thr_id;
1013941Svenki 
1023941Svenki /*
1037746SKelly.Moyer@Sun.COM  * The cache_refresh thread periodically queries the snmp cache refresh work
1047746SKelly.Moyer@Sun.COM  * queue and processes jobs from it to keep cache entries from expiring.  It
1057746SKelly.Moyer@Sun.COM  * attempts to run in cycles of CACHE_REFRESH_CYCLE seconds each, first
1067746SKelly.Moyer@Sun.COM  * processing cache refresh jobs and then sleeping for the remainder of the
1077746SKelly.Moyer@Sun.COM  * cycle once the next refresh job expiration is at least
1087746SKelly.Moyer@Sun.COM  * CACHE_REFRESH_MIN_WINDOW seconds in the future.
1097746SKelly.Moyer@Sun.COM  *
1107746SKelly.Moyer@Sun.COM  * NOTE: By using a thread to keep the SNMP cache refreshed in the background,
1117746SKelly.Moyer@Sun.COM  * we are both adding load to the system and reducing the system's ability to
1127746SKelly.Moyer@Sun.COM  * operate in power-saving mode when there is minimal load.  While these
1137746SKelly.Moyer@Sun.COM  * tradeoffs are acceptable at this time in light of customer concerns about
1147746SKelly.Moyer@Sun.COM  * performance, it may be desirable in the future to move this work into the
1157746SKelly.Moyer@Sun.COM  * firmware.  Also, while the current cycle times performed well on the largest
1167746SKelly.Moyer@Sun.COM  * sun4v config currently available (Batoka), they may need to be revisited for
1177746SKelly.Moyer@Sun.COM  * future systems if the number of sensors increases significantly.
1187746SKelly.Moyer@Sun.COM  */
1197746SKelly.Moyer@Sun.COM #define	CACHE_REFRESH_CYCLE		60
1207746SKelly.Moyer@Sun.COM #define	CACHE_REFRESH_MIN_WINDOW	75
1217746SKelly.Moyer@Sun.COM static mutex_t		cache_refresh_lock;
1227746SKelly.Moyer@Sun.COM static cond_t		cache_refresh_cv;
1237746SKelly.Moyer@Sun.COM static boolean_t	cache_refresh_thr_exit = B_FALSE;
1247746SKelly.Moyer@Sun.COM static thread_t		cache_refresh_thr_id;
1257746SKelly.Moyer@Sun.COM 
1267746SKelly.Moyer@Sun.COM /*
1273941Svenki  * These two should really not be global
1283941Svenki  */
1293941Svenki static picl_nodehdl_t	*physplat_nodes = NULL;
1303941Svenki static int		n_physplat_nodes = 0;
1313941Svenki 
1323941Svenki static char *group1[] = {
1333941Svenki 	OID_entPhysicalDescr,
1343941Svenki 	OID_entPhysicalContainedIn,
1353941Svenki 	OID_entPhysicalClass,
1363941Svenki 	OID_entPhysicalName,
1373941Svenki 	OID_entPhysicalHardwareRev,
1383941Svenki 	OID_entPhysicalFirmwareRev,
1393941Svenki 	OID_entPhysicalSerialNum,
1403941Svenki 	OID_entPhysicalMfgName,
1413941Svenki 	OID_entPhysicalModelName,
1423941Svenki 	OID_entPhysicalIsFRU,
1433941Svenki 	0
1443941Svenki };
1453941Svenki 
1463941Svenki static char *group2[] = {
1473941Svenki 	OID_sunPlatEquipmentHolderAcceptableTypes,
1483941Svenki 	OID_sunPlatCircuitPackReplaceable,
1493941Svenki 	OID_sunPlatCircuitPackHotSwappable,
1503941Svenki 	OID_sunPlatPhysicalClass,
1513941Svenki 	OID_sunPlatSensorClass,
1523941Svenki 	OID_sunPlatSensorType,
1533941Svenki 	OID_sunPlatAlarmType,
1543941Svenki 	OID_sunPlatPowerSupplyClass,
1553941Svenki 	0
1563941Svenki };
1573941Svenki 
1585723Sfw157321 static char *group3[] = {
1595723Sfw157321 	OID_sunPlatNumericSensorEnabledThresholds,
1605723Sfw157321 	OID_sunPlatNumericSensorBaseUnits,
1615723Sfw157321 	OID_sunPlatNumericSensorRateUnits,
1625723Sfw157321 	0
1635723Sfw157321 };
1645723Sfw157321 
1655723Sfw157321 static char *group4[] = {
1665723Sfw157321 	OID_sunPlatBinarySensorInterpretTrue,
1675723Sfw157321 	OID_sunPlatBinarySensorInterpretFalse,
1685723Sfw157321 };
1695723Sfw157321 
1703941Svenki static char *volgroup1[] = {
1713941Svenki 	OID_sunPlatBinarySensorCurrent,
1723941Svenki 	OID_sunPlatBinarySensorExpected,
1733941Svenki 	0
1743941Svenki };
1753941Svenki 
1763941Svenki static char *volgroup2[] = {
1773941Svenki 	OID_sunPlatNumericSensorExponent,
1783941Svenki 	OID_sunPlatNumericSensorCurrent,
1793941Svenki 	OID_sunPlatNumericSensorLowerThresholdFatal,
1803941Svenki 	OID_sunPlatNumericSensorLowerThresholdCritical,
1813941Svenki 	OID_sunPlatNumericSensorLowerThresholdNonCritical,
1823941Svenki 	OID_sunPlatNumericSensorUpperThresholdNonCritical,
1833941Svenki 	OID_sunPlatNumericSensorUpperThresholdCritical,
1843941Svenki 	OID_sunPlatNumericSensorUpperThresholdFatal,
1853941Svenki 	0
1863941Svenki };
1873941Svenki 
1885723Sfw157321 static char *volgroup3[] = {
1895723Sfw157321 	OID_sunPlatEquipmentOperationalState,
1905723Sfw157321 	0
1915723Sfw157321 };
1925723Sfw157321 
1935723Sfw157321 static char *volgroup4[] = {
1945723Sfw157321 	OID_sunPlatAlarmState,
1955723Sfw157321 	0
1965723Sfw157321 };
1975723Sfw157321 
1985723Sfw157321 static char *volgroup5[] = {
1995723Sfw157321 	OID_sunPlatBatteryStatus,
2005723Sfw157321 	0
2015723Sfw157321 };
2025723Sfw157321 
2033941Svenki /*
2043941Svenki  * The following two items must match the Sun Platform MIB specification
2053941Svenki  * in their indices and values.
2063941Svenki  */
2073941Svenki static char *sensor_baseunits[] = {
2083941Svenki 	"", "other", "unknown", "degC", "degF", "degK", "volts", "amps",
2093941Svenki 	"watts", "joules", "coulombs", "va", "nits", "lumens", "lux",
2103941Svenki 	"candelas", "kPa", "psi", "newtons", "cfm", "rpm", "hertz",
2113941Svenki 	"seconds", "minutes", "hours", "days", "weeks", "mils", "inches",
2123941Svenki 	"feet", "cubicInches", "cubicFeet", "meters", "cubicCentimeters",
2133941Svenki 	"cubicMeters", "liters", "fluidOunces", "radians", "steradians",
2143941Svenki 	"revolutions", "cycles", "gravities", "ounces", "pounds", "footPounds",
2153941Svenki 	"ounceInches", "gauss", "gilberts", "henries", "farads", "ohms",
2163941Svenki 	"siemens", "moles", "becquerels", "ppm", "decibels", "dBA", "dbC",
2173941Svenki 	"grays", "sieverts", "colorTemperatureDegK", "bits", "bytes", "words",
2183941Svenki 	"doubleWords", "quadWords", "percentage"
2193941Svenki };
2203941Svenki static const int n_baseunits = sizeof (sensor_baseunits) / sizeof (char *);
2213941Svenki 
2223941Svenki static char *sensor_rateunits[] = {
2233941Svenki 	"",
2243941Svenki 	"none",
2253941Svenki 	"perMicroSecond",
2263941Svenki 	"perMilliSecond",
2273941Svenki 	"perSecond",
2283941Svenki 	"perMinute",
2293941Svenki 	"perHour",
2303941Svenki 	"perDay",
2313941Svenki 	"perWeek",
2323941Svenki 	"perMonth",
2333941Svenki 	"perYear"
2343941Svenki };
2353941Svenki static const int n_rateunits = sizeof (sensor_rateunits) / sizeof (char *);
2363941Svenki 
2373941Svenki /*
2383941Svenki  * Local declarations
2393941Svenki  */
2403941Svenki static void snmpplugin_register(void);
2413941Svenki static void register_group(char **g, int is_volatile);
2423941Svenki static void *tree_builder(void *arg);
2433941Svenki static int build_physplat(picl_nodehdl_t *subtree_rootp);
2443941Svenki static void free_resources(picl_nodehdl_t subtree_root);
2453941Svenki 
2463941Svenki static picl_nodehdl_t make_node(picl_nodehdl_t subtree_root, int row,
2473941Svenki     int *snmp_syserr_p);
2483941Svenki static void save_nodeh(picl_nodehdl_t nodeh, int row);
2493941Svenki static picl_nodehdl_t lookup_nodeh(int row);
2503941Svenki 
2513941Svenki static void save_volprop(picl_prophdl_t prop, char *oidstr, int row,
2523941Svenki     int proptype);
2535723Sfw157321 static void check_for_stale_data(boolean_t nocache);
2543941Svenki static int read_volprop(ptree_rarg_t *parg, void *buf);
2553941Svenki 
2563941Svenki static void threshold(picl_nodehdl_t node, char *oidstr, int row,
2573941Svenki     char *propname, int *snmp_syserr_p);
2583941Svenki static void add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p);
2593941Svenki 
2603941Svenki static char *get_slot_type(int row, int *snmp_syserr_p);
2613941Svenki static int add_volatile_prop(picl_nodehdl_t nodeh, char *name,
2623941Svenki     int type, int access, int size, int (*rdfunc)(ptree_rarg_t *, void *),
2633941Svenki     int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp);
2643941Svenki static int add_string_prop(picl_nodehdl_t node, char *propname, char *propval);
2653941Svenki static int add_void_prop(picl_nodehdl_t node, char *propname);
2663941Svenki static void add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
2673941Svenki     int row, sp_propid_t pp, int *snmp_syserr_p);
2683941Svenki 
2697746SKelly.Moyer@Sun.COM static void *cache_refresher(void *arg);
2707746SKelly.Moyer@Sun.COM static void cache_refresher_fini(void);
2717746SKelly.Moyer@Sun.COM 
2723941Svenki static void log_msg(int pri, const char *fmt, ...);
2733941Svenki 
2743941Svenki #ifdef SNMPPLUGIN_DEBUG
2753941Svenki static mutex_t	snmpplugin_dbuf_lock;
2763941Svenki static char	*snmpplugin_dbuf = NULL;
2773941Svenki static char	*snmpplugin_dbuf_curp = NULL;
2783941Svenki static int	snmpplugin_dbuf_sz = 0;
2793941Svenki static int	snmpplugin_dbuf_overflow = 0;
2803941Svenki static char	snmpplugin_lbuf[SNMPPLUGIN_DMAX_LINE];
2813941Svenki 
2823941Svenki static void	snmpplugin_log_init(void);
2833941Svenki static void	snmpplugin_log(const char *fmt, ...);
2843941Svenki static void	snmpplugin_log_append(void);
2853941Svenki static void	snmpplugin_dbuf_realloc(void);
2863941Svenki #endif
2873941Svenki 
2883941Svenki static void
2893941Svenki snmpplugin_register(void)
2903941Svenki {
2913941Svenki 	(void) picld_plugin_register(&snmpplugin_reg);
2923941Svenki }
2933941Svenki 
2943941Svenki static void
2953941Svenki register_group(char **g, int is_volatile)
2963941Svenki {
2973941Svenki 	int	i, len = 0;
2983941Svenki 	int	n_oids;
2993941Svenki 	char	*p, *oidstrs;
3003941Svenki 
3013941Svenki 	for (i = 0; g[i]; i++)
3023941Svenki 		len += strlen(g[i]) + 1;
3033941Svenki 	n_oids = i;
3043941Svenki 
3053941Svenki 	if ((oidstrs = (char *)calloc(1, len)) == NULL)
3063941Svenki 		return;
3073941Svenki 
3083941Svenki 	for (p = oidstrs, i = 0; g[i]; i++) {
3093941Svenki 		(void) strcpy(p, g[i]);
3103941Svenki 		p += strlen(g[i]) + 1;
3113941Svenki 	}
3123941Svenki 
3133941Svenki 	snmp_register_group(hdl, oidstrs, n_oids, is_volatile);
3147382SMichael.Bergknoff@Sun.COM 	free(oidstrs);
3153941Svenki }
3163941Svenki 
3173941Svenki void
3183941Svenki snmpplugin_init(void)
3193941Svenki {
3203941Svenki 	int		ret;
3213941Svenki 
3223941Svenki 	(void) mutex_init(&rebuild_tree_lock, USYNC_THREAD, NULL);
3233941Svenki 	(void) cond_init(&rebuild_tree_cv, USYNC_THREAD, NULL);
3243941Svenki 	(void) rwlock_init(&stale_tree_rwlp, USYNC_THREAD, NULL);
3255029Sfw157321 	tree_builder_thr_exit = B_FALSE;
3265029Sfw157321 
3273941Svenki 	LOGINIT();
3283941Svenki 
3293941Svenki 	/*
3303941Svenki 	 * Create the tree-builder thread and let it take over
3313941Svenki 	 */
3323941Svenki 	LOGPRINTF("Tree-builder thread being created.\n");
3333941Svenki 	if ((ret = thr_create(NULL, NULL, tree_builder, NULL,
3345029Sfw157321 	    THR_BOUND, &tree_builder_thr_id)) < 0) {
3353941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_CREATE_TREE_BUILDER, ret);
3363941Svenki 		snmp_fini(hdl);
3375029Sfw157321 		hdl = NULL;
3385029Sfw157321 		(void) rwlock_destroy(&stale_tree_rwlp);
3395029Sfw157321 		(void) cond_destroy(&rebuild_tree_cv);
3405029Sfw157321 		(void) mutex_destroy(&rebuild_tree_lock);
3415029Sfw157321 		tree_builder_thr_exit = B_TRUE;
3427746SKelly.Moyer@Sun.COM 
3437746SKelly.Moyer@Sun.COM 		return;
3447746SKelly.Moyer@Sun.COM 	}
3457746SKelly.Moyer@Sun.COM 
3467746SKelly.Moyer@Sun.COM 	/*
3477746SKelly.Moyer@Sun.COM 	 * While the cache refresher thread does improve performance, it is not
3487746SKelly.Moyer@Sun.COM 	 * integral to the proper function of the plugin.  If we fail to create
3497746SKelly.Moyer@Sun.COM 	 * the thread for some reason, we will simply continue without
3507746SKelly.Moyer@Sun.COM 	 * refreshing.
3517746SKelly.Moyer@Sun.COM 	 */
3527746SKelly.Moyer@Sun.COM 	(void) mutex_init(&cache_refresh_lock, USYNC_THREAD, NULL);
3537746SKelly.Moyer@Sun.COM 	(void) cond_init(&cache_refresh_cv, USYNC_THREAD, NULL);
3547746SKelly.Moyer@Sun.COM 	cache_refresh_thr_exit = B_FALSE;
3557746SKelly.Moyer@Sun.COM 
3567746SKelly.Moyer@Sun.COM 	LOGPRINTF("Cache refresher thread being created.\n");
3577746SKelly.Moyer@Sun.COM 	if (thr_create(NULL, NULL, cache_refresher, NULL, THR_BOUND,
3587746SKelly.Moyer@Sun.COM 	    &cache_refresh_thr_id) < 0) {
3597746SKelly.Moyer@Sun.COM 		(void) cond_destroy(&cache_refresh_cv);
3607746SKelly.Moyer@Sun.COM 		(void) mutex_destroy(&cache_refresh_lock);
3617746SKelly.Moyer@Sun.COM 		cache_refresh_thr_exit = B_TRUE;
3623941Svenki 	}
3633941Svenki }
3643941Svenki 
3653941Svenki void
3663941Svenki snmpplugin_fini(void)
3673941Svenki {
3685029Sfw157321 
3695029Sfw157321 	if (tree_builder_thr_exit == B_TRUE)
3705029Sfw157321 		return;
3713941Svenki 
3725029Sfw157321 	/*
3735029Sfw157321 	 * Make reads of volatile properties return PICL_PROPUNAVAILABLE
3745029Sfw157321 	 * since we're about to recycle the plug-in.  No need to worry
3755029Sfw157321 	 * about removing /physical-platform since tree_builder() will
3765029Sfw157321 	 * take care of recycling it for us.
3775029Sfw157321 	 */
3785029Sfw157321 	(void) rw_wrlock(&stale_tree_rwlp);
3795029Sfw157321 	stale_tree = B_TRUE;
3805029Sfw157321 	if (vol_props) {
3815029Sfw157321 		free(vol_props);
3825029Sfw157321 	}
3835029Sfw157321 	vol_props = NULL;
3845029Sfw157321 	volprop_ndx = 0;
3855029Sfw157321 	n_vol_props = 0;
3865029Sfw157321 	(void) rw_unlock(&stale_tree_rwlp);
3875029Sfw157321 
3887746SKelly.Moyer@Sun.COM 	/* clean up the cache_refresher thread and structures */
3897746SKelly.Moyer@Sun.COM 	cache_refresher_fini();
3907746SKelly.Moyer@Sun.COM 
3915029Sfw157321 	/* wake up the tree_builder thread, tell it to exit */
3925029Sfw157321 	(void) mutex_lock(&rebuild_tree_lock);
3935029Sfw157321 	rebuild_tree = B_TRUE;
3945029Sfw157321 	tree_builder_thr_exit = B_TRUE;
3955436Sfw157321 	(void) cond_signal(&rebuild_tree_cv);
3965029Sfw157321 	(void) mutex_unlock(&rebuild_tree_lock);
3975029Sfw157321 
3985029Sfw157321 	/* reap the thread */
3995029Sfw157321 	(void) thr_join(tree_builder_thr_id, NULL, NULL);
4005029Sfw157321 
4015029Sfw157321 	/* close the channel */
4025029Sfw157321 	if (hdl != NULL) {
4035029Sfw157321 		snmp_fini(hdl);
4045029Sfw157321 		hdl = NULL;
4055029Sfw157321 	}
4065029Sfw157321 
4075029Sfw157321 	/* finish cleanup... */
4083941Svenki 	(void) rwlock_destroy(&stale_tree_rwlp);
4093941Svenki 	(void) cond_destroy(&rebuild_tree_cv);
4103941Svenki 	(void) mutex_destroy(&rebuild_tree_lock);
4113941Svenki }
4123941Svenki 
4133941Svenki /*ARGSUSED*/
4143941Svenki static void *
4153941Svenki tree_builder(void *arg)
4163941Svenki {
4173941Svenki 	int		ret, rv;
4183941Svenki 	picl_nodehdl_t	root_node;
4193941Svenki 	picl_nodehdl_t	physplat_root;
4203941Svenki 	picl_nodehdl_t	old_physplat_root;
4213941Svenki 
4223941Svenki 	/*
4233941Svenki 	 * Initialize SNMP service
4243941Svenki 	 */
4253941Svenki 	LOGPRINTF("Initializing SNMP service.\n");
4263941Svenki 	if ((hdl = snmp_init()) == NULL) {
4273941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT);
4283941Svenki 		return ((void *)-1);
4293941Svenki 	}
4303941Svenki 
4313941Svenki 	/*
4323941Svenki 	 * Register OID groupings for BULKGET optimizations
4333941Svenki 	 */
4343941Svenki 	LOGPRINTF("Registering OID groups.\n");
4353941Svenki 	register_group(group1, 0);
4363941Svenki 	register_group(group2, 0);
4375723Sfw157321 	register_group(group3, 0);
4385723Sfw157321 	register_group(group4, 0);
4393941Svenki 	register_group(volgroup1, 1);
4403941Svenki 	register_group(volgroup2, 1);
4415723Sfw157321 	register_group(volgroup3, 1);
4425723Sfw157321 	register_group(volgroup4, 1);
4435723Sfw157321 	register_group(volgroup5, 1);
4443941Svenki 
4453941Svenki 	(void) mutex_lock(&rebuild_tree_lock);
4463941Svenki 
4473941Svenki 	for (;;) {
4483941Svenki 		LOGPRINTF("tree_builder: check whether to rebuild subtree\n");
4493941Svenki 		while (rebuild_tree == B_FALSE)
4503941Svenki 			(void) cond_wait(&rebuild_tree_cv, &rebuild_tree_lock);
4513941Svenki 
4523941Svenki 		LOGPRINTF("tree_builder: woke up\n");
4533941Svenki 
4545029Sfw157321 		if (tree_builder_thr_exit == B_TRUE) {
4555029Sfw157321 			(void) mutex_unlock(&rebuild_tree_lock);
4565029Sfw157321 			LOGPRINTF("tree_builder: time to exit\n");
4575029Sfw157321 			return (NULL);
4585029Sfw157321 		}
4595029Sfw157321 
4603941Svenki 		old_physplat_root = NULL;
4613941Svenki 		physplat_root = NULL;
4623941Svenki 
4633941Svenki 		LOGPRINTF("tree_builder: getting root node\n");
4643941Svenki 		if ((ret = ptree_get_root(&root_node)) != PICL_SUCCESS) {
4655029Sfw157321 			(void) mutex_unlock(&rebuild_tree_lock);
4663941Svenki 			log_msg(LOG_ERR, SNMPP_NO_ROOT, ret);
4673941Svenki 			return ((void *)-2);
4683941Svenki 		}
4693941Svenki 
4703941Svenki 		LOGPRINTF("tree_builder: getting existing physplat node\n");
4713941Svenki 		rv = ptree_find_node(root_node, PICL_PROP_NAME,
4723941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_NODE_PHYSPLAT,
4733941Svenki 		    sizeof (PICL_NODE_PHYSPLAT), &old_physplat_root);
4743941Svenki 
4753941Svenki 		LOGPRINTF("tree_builder: building physical-platform\n");
4763941Svenki 		if ((ret = build_physplat(&physplat_root)) < 0) {
4775029Sfw157321 			(void) mutex_unlock(&rebuild_tree_lock);
4783941Svenki 			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
4797746SKelly.Moyer@Sun.COM 			cache_refresher_fini();
4803941Svenki 			snmp_fini(hdl);
4815029Sfw157321 			hdl = NULL;
4823941Svenki 			return ((void *)-3);
4833941Svenki 		}
4843941Svenki 
4853941Svenki 		if (rv == PICL_SUCCESS && old_physplat_root != NULL) {
4863941Svenki 			LOGPRINTF("tree_builder: destroying existing nodes\n");
4873941Svenki 			ptree_delete_node(old_physplat_root);
4883941Svenki 			ptree_destroy_node(old_physplat_root);
4893941Svenki 		}
4903941Svenki 
4913941Svenki 		LOGPRINTF("tree_builder: attaching new subtree\n");
4923941Svenki 		if ((ret = ptree_add_node(root_node, physplat_root)) < 0) {
4935029Sfw157321 			(void) mutex_unlock(&rebuild_tree_lock);
4943941Svenki 			free_resources(physplat_root);
4953941Svenki 			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
4967746SKelly.Moyer@Sun.COM 			cache_refresher_fini();
4973941Svenki 			snmp_fini(hdl);
4985029Sfw157321 			hdl = NULL;
4993941Svenki 			return ((void *)-4);
5003941Svenki 		}
5013941Svenki 
5023941Svenki 		LOGPRINTF("tree_builder: setting stale_tree to FALSE\n");
5033941Svenki 		(void) rw_wrlock(&stale_tree_rwlp);
5043941Svenki 		stale_tree = B_FALSE;
5053941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
5063941Svenki 
5073941Svenki 		LOGPRINTF("tree_builder: setting rebuild_tree to FALSE\n");
5083941Svenki 		rebuild_tree = B_FALSE;
5093941Svenki 	}
5103941Svenki 
5113941Svenki 	/*NOTREACHED*/
5123941Svenki 	return (NULL);
5133941Svenki }
5143941Svenki 
5153941Svenki static int
5163941Svenki build_physplat(picl_nodehdl_t *subtree_rootp)
5173941Svenki {
5183941Svenki 	int	change_time1;
5193941Svenki 	int	row, nxtrow;
5203941Svenki 	int	clr_linkreset = 0;
5213941Svenki 	int	ret = 0;
5223941Svenki 	int	snmp_syserr = 0;
5233941Svenki 
5243941Svenki retry:
5253941Svenki 	(void) snmp_reinit(hdl, clr_linkreset);
5263941Svenki 	clr_linkreset = 0;
5273941Svenki 
5283941Svenki 	/*
5293941Svenki 	 * Record LastChangeTime before we start building the tree
5303941Svenki 	 */
5313941Svenki 	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
5323941Svenki 	    &change_time1, &snmp_syserr);
5333941Svenki 	if (ret < 0) {
5343941Svenki 		if (snmp_syserr == ECANCELED) {
5356751Sfw157321 			LOGPRINTF(SNMPP_LINK_RESET);
5363941Svenki 			clr_linkreset = 1;
5373941Svenki 			goto retry;
5385723Sfw157321 		}
5395723Sfw157321 		log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
5405723Sfw157321 		    snmp_syserr ? snmp_syserr : ret, OID_entLastChangeTime, 0);
5413941Svenki 	}
5423941Svenki 
5433941Svenki 	/*
5443941Svenki 	 * Create the physical-platform node
5453941Svenki 	 */
5463941Svenki 	ret = ptree_create_node(PICL_NODE_PHYSPLAT, PICL_CLASS_PICL,
5473941Svenki 	    subtree_rootp);
5483941Svenki 	if (ret != PICL_SUCCESS)
5493941Svenki 		return (-1);
5503941Svenki 
5513941Svenki 	/*
5523941Svenki 	 * Scan entPhysicalTable and build the "physical-platform" subtree
5533941Svenki 	 */
5543941Svenki 	ret = 0;
5553941Svenki 	for (row = -1; ret == 0; row = nxtrow) {
5563941Svenki 		ret = snmp_get_nextrow(hdl, OID_entPhysicalDescr,
5573941Svenki 		    row, &nxtrow, &snmp_syserr);
5585995Sfw157321 		if (ret == 0)
5593941Svenki 			(void) make_node(*subtree_rootp, nxtrow, &snmp_syserr);
5605995Sfw157321 		switch (snmp_syserr) {
5615995Sfw157321 		case ECANCELED:
5623941Svenki 			/*
5633941Svenki 			 * If we get this error, a link reset must've
5643941Svenki 			 * happened and we need to throw away everything
5653941Svenki 			 * we have now and rebuild the tree again.
5663941Svenki 			 */
5673941Svenki 			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
5683941Svenki 			free_resources(*subtree_rootp);
5693941Svenki 			clr_linkreset = 1;
5703941Svenki 			goto retry;
5715995Sfw157321 			/*NOTREACHED*/
5725995Sfw157321 			break;
5735995Sfw157321 		case ENOSPC:	/* end of MIB */
5745995Sfw157321 			LOGPRINTF("build_physplat: end of MIB\n");
5755995Sfw157321 			break;
5765995Sfw157321 		case ENOENT:	/* end of table */
5775995Sfw157321 			LOGPRINTF("build_physplat: end of table\n");
5785995Sfw157321 			break;
5795995Sfw157321 		default:
5805995Sfw157321 			/*
5815995Sfw157321 			 * make_node() will print messages so don't
5825995Sfw157321 			 * repeat that exercise here.
5835995Sfw157321 			 */
5845995Sfw157321 			if (ret == -1) {
5855995Sfw157321 				log_msg(LOG_WARNING,
5865995Sfw157321 				    SNMPP_CANT_FETCH_OBJECT_VAL,
5875995Sfw157321 				    snmp_syserr ? snmp_syserr : ret,
5885995Sfw157321 				    OID_entPhysicalDescr, row);
5895995Sfw157321 			}
5903941Svenki 		}
5913941Svenki 	}
5923941Svenki 
5933941Svenki 	/*
5943941Svenki 	 * Record LastChangeTime after we're done building the tree
5953941Svenki 	 */
5963941Svenki 	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
5973941Svenki 	    &change_time, &snmp_syserr);
5983941Svenki 	if (ret < 0) {
5993941Svenki 		if (snmp_syserr == ECANCELED) {
6003941Svenki 			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
6013941Svenki 			free_resources(*subtree_rootp);
6023941Svenki 			clr_linkreset = 1;
6033941Svenki 			goto retry;
6043941Svenki 		} else
6055723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
6065723Sfw157321 			    snmp_syserr ? snmp_syserr : ret,
6075723Sfw157321 			    OID_entLastChangeTime, row);
6083941Svenki 	}
6093941Svenki 
6103941Svenki 	/*
6113941Svenki 	 * If they don't match, some hotplugging must've happened,
6123941Svenki 	 * free resources we've created and still holding, then go
6133941Svenki 	 * back and retry
6143941Svenki 	 */
6153941Svenki 	if (change_time != change_time1) {
6163941Svenki 		LOGPRINTF("build_physplat: entLastChangeTime has changed!\n");
6173941Svenki 		free_resources(*subtree_rootp);
6183941Svenki 		change_time1 = change_time;
6193941Svenki 		goto retry;
6203941Svenki 	}
6213941Svenki 
6223941Svenki 	/*
6233941Svenki 	 * The physplat_nodes table is no longer needed, free it
6243941Svenki 	 */
6253941Svenki 	if (physplat_nodes) {
6263941Svenki 		free(physplat_nodes);
6273941Svenki 		physplat_nodes = NULL;
6283941Svenki 		n_physplat_nodes = 0;
6293941Svenki 	}
6303941Svenki 
6313941Svenki 	return (0);
6323941Svenki }
6333941Svenki 
6343941Svenki /*
6353941Svenki  * Destroy all resources that were created during the building
6363941Svenki  * of the subtree
6373941Svenki  */
6383941Svenki static void
6393941Svenki free_resources(picl_nodehdl_t subtree_root)
6403941Svenki {
6413941Svenki 	if (physplat_nodes) {
6423941Svenki 		free(physplat_nodes);
6433941Svenki 		physplat_nodes = NULL;
6443941Svenki 		n_physplat_nodes = 0;
6453941Svenki 	}
6463941Svenki 
6473941Svenki 	if (subtree_root) {
6483941Svenki 		(void) ptree_delete_node(subtree_root);
6493941Svenki 		(void) ptree_destroy_node(subtree_root);
6503941Svenki 	}
6513941Svenki 
6523941Svenki 	if (vol_props) {
6533941Svenki 		free(vol_props);
6543941Svenki 		n_vol_props = 0;
6553941Svenki 		volprop_ndx = 0;
6563941Svenki 	}
6573941Svenki }
6583941Svenki 
6593941Svenki static picl_nodehdl_t
6603941Svenki make_node(picl_nodehdl_t subtree_root, int row, int *snmp_syserr_p)
6613941Svenki {
6623941Svenki 	picl_nodehdl_t	nodeh, parenth;
6633941Svenki 	picl_prophdl_t	proph;
6643941Svenki 	char	*phys_name, *node_name;
6653941Svenki 	int	parent_row;
6663941Svenki 	int	ent_physclass, sunplat_physclass;
6673941Svenki 	int	sensor_class, sensor_type;
6683941Svenki 	int	alarm_type;
6693941Svenki 	int	ps_class;
6703941Svenki 	int	ret;
6713941Svenki 
6723941Svenki 	/*
6733941Svenki 	 * If we've already created this picl node, just return it
6743941Svenki 	 */
6753941Svenki 	if ((nodeh = lookup_nodeh(row)) != NULL)
6763941Svenki 		return (nodeh);
6773941Svenki 
6783941Svenki 	/*
6793941Svenki 	 * If we are creating it only now, make sure we have the parent
6803941Svenki 	 * created first; if there's no parent, then parent it to the
6813941Svenki 	 * subtree's root node
6823941Svenki 	 */
6833941Svenki 	ret = snmp_get_int(hdl, OID_entPhysicalContainedIn, row,
6843941Svenki 	    &parent_row, snmp_syserr_p);
6853941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
6863941Svenki 	if (ret < 0 || parent_row <= 0)
6873941Svenki 		parenth = subtree_root;
6883941Svenki 	else {
6893941Svenki 		parenth = make_node(subtree_root, parent_row, snmp_syserr_p);
6903941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
6913941Svenki 		if (parenth == NULL)
6923941Svenki 			parenth = subtree_root;
6933941Svenki 	}
6943941Svenki 
6953941Svenki 	/*
6963941Svenki 	 * Figure out the physical-platform node name from entPhysicalName;
6973941Svenki 	 * all rows in the MIB that have a valid entPhysicalIndex should
6983941Svenki 	 * have a physical name.
6993941Svenki 	 */
7003941Svenki 	ret = snmp_get_str(hdl, OID_entPhysicalName, row,
7013941Svenki 	    &phys_name, snmp_syserr_p);
7023941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
7033941Svenki 	if (ret < 0 || phys_name == NULL) {
7043941Svenki 		log_msg(LOG_WARNING, SNMPP_NO_ENTPHYSNAME, row);
7053941Svenki 		return (NULL);
7063941Svenki 	}
7073941Svenki 
7083941Svenki 	node_name = basename(phys_name);
7093941Svenki 
7103941Svenki 	ret = snmp_get_int(hdl, OID_entPhysicalClass, row,
7113941Svenki 	    &ent_physclass, snmp_syserr_p);
7123941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
7133941Svenki 	if (ret < 0) {
7145723Sfw157321 		log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
7155723Sfw157321 		    *snmp_syserr_p ? *snmp_syserr_p : ret,
7165723Sfw157321 		    OID_entPhysicalClass, row);
7173941Svenki 		free(phys_name);
7183941Svenki 		return (NULL);
7193941Svenki 	}
7203941Svenki 
7213941Svenki 	switch (ent_physclass) {
7223941Svenki 	case SPC_OTHER:
7233941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatPhysicalClass, row,
7243941Svenki 		    &sunplat_physclass, snmp_syserr_p);
7253941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7263941Svenki 		if (ret < 0) {
7275723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
7285723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
7295723Sfw157321 			    OID_sunPlatPhysicalClass, row);
7303941Svenki 			free(phys_name);
7313941Svenki 			return (NULL);
7323941Svenki 		}
7333941Svenki 
7343941Svenki 		if (sunplat_physclass == SSPC_ALARM) {
7353941Svenki 			ret = snmp_get_int(hdl, OID_sunPlatAlarmType,
7363941Svenki 			    row, &alarm_type, snmp_syserr_p);
7373941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
7383941Svenki 			if (ret < 0) {
7393941Svenki 				log_msg(LOG_WARNING,
7405723Sfw157321 				    SNMPP_CANT_FETCH_OBJECT_VAL,
7415723Sfw157321 				    *snmp_syserr_p ? *snmp_syserr_p : ret,
7425723Sfw157321 				    OID_sunPlatAlarmType, row);
7433941Svenki 				free(phys_name);
7443941Svenki 				return (NULL);
7453941Svenki 			}
7463941Svenki 
7473941Svenki 			if (alarm_type == SSAT_VISIBLE) {
7484802Sfw157321 				ADD_NODE(PICL_CLASS_LED)
7493941Svenki 			} else {
7504802Sfw157321 				ADD_NODE(PICL_CLASS_ALARM)
7513941Svenki 			}
7523941Svenki 
7533941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_STATE,
7543941Svenki 			    snmp_syserr_p);
7553941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
7563941Svenki 		} else {
7573941Svenki 			ADD_NODE(PICL_CLASS_OTHER)
7583941Svenki 		}
7593941Svenki 
7603941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
7613941Svenki 		    snmp_syserr_p);
7623941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7633941Svenki 		break;
7643941Svenki 
7653941Svenki 	case SPC_UNKNOWN:
7663941Svenki 		ADD_NODE(PICL_CLASS_UNKNOWN)
7673941Svenki 		break;
7683941Svenki 
7693941Svenki 	case SPC_CHASSIS:
7703941Svenki 		ADD_NODE(PICL_CLASS_CHASSIS)
7713941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
7723941Svenki 		    snmp_syserr_p);
7733941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7743941Svenki 		break;
7753941Svenki 
7763941Svenki 	case SPC_BACKPLANE:
7773941Svenki 		ADD_NODE(PICL_CLASS_BACKPLANE)
7783941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
7793941Svenki 		    snmp_syserr_p);
7803941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7813941Svenki 		break;
7823941Svenki 
7833941Svenki 	case SPC_CONTAINER:
7843941Svenki 		ADD_NODE(PICL_CLASS_CONTAINER)
7853941Svenki 
7863941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
7873941Svenki 		    snmp_syserr_p);
7883941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7893941Svenki 
7903941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_SLOT_TYPE,
7913941Svenki 		    snmp_syserr_p);
7923941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7933941Svenki 		break;
7943941Svenki 
7953941Svenki 	case SPC_POWERSUPPLY:
7963941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatPowerSupplyClass,
7973941Svenki 		    row, &ps_class, snmp_syserr_p);
7983941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7993941Svenki 		if (ret < 0) {
8005723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
8015723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
8025723Sfw157321 			    OID_sunPlatPowerSupplyClass, row);
8033941Svenki 			free(phys_name);
8043941Svenki 			return (NULL);
8053941Svenki 		}
8063941Svenki 
8073941Svenki 		if (ps_class == SSPSC_BATTERY) {
8083941Svenki 			ADD_NODE(PICL_CLASS_BATTERY)
8093941Svenki 			add_prop(nodeh, &proph, node_name, row,
8103941Svenki 			    PP_BATT_STATUS, snmp_syserr_p);
8113941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
8123941Svenki 		} else {
8133941Svenki 			ADD_NODE(PICL_CLASS_POWERSUPPLY)
8143941Svenki 		}
8153941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8163941Svenki 		    snmp_syserr_p);
8173941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8183941Svenki 		break;
8193941Svenki 
8203941Svenki 	case SPC_FAN:
8213941Svenki 		ADD_NODE(PICL_CLASS_FAN)
8223941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8233941Svenki 		    snmp_syserr_p);
8243941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8253941Svenki 		break;
8263941Svenki 
8273941Svenki 	case SPC_SENSOR:
8283941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatSensorClass,
8293941Svenki 		    row, &sensor_class, snmp_syserr_p);
8303941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8313941Svenki 		if (ret < 0) {
8325723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
8335723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
8345723Sfw157321 			    OID_sunPlatSensorClass, row);
8353941Svenki 			free(phys_name);
8363941Svenki 			return (NULL);
8373941Svenki 		}
8383941Svenki 
8393941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatSensorType,
8403941Svenki 		    row, &sensor_type, snmp_syserr_p);
8413941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8423941Svenki 		if (ret < 0) {
8435723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
8445723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
8455723Sfw157321 			    OID_sunPlatSensorType, row);
8463941Svenki 			free(phys_name);
8473941Svenki 			return (NULL);
8483941Svenki 		}
8493941Svenki 
8503941Svenki 		if (sensor_class == SSSC_NUMERIC) {
8513941Svenki 			if (sensor_type == SSST_TEMPERATURE) {
8523941Svenki 				ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR)
8533941Svenki 				add_prop(nodeh, &proph, node_name, row,
8543941Svenki 				    PP_TEMPERATURE, snmp_syserr_p);
8553941Svenki 			} else if (sensor_type == SSST_VOLTAGE) {
8563941Svenki 				ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR)
8573941Svenki 				add_prop(nodeh, &proph, node_name, row,
8583941Svenki 				    PP_VOLTAGE, snmp_syserr_p);
8593941Svenki 			} else if (sensor_type == SSST_CURRENT) {
8603941Svenki 				ADD_NODE(PICL_CLASS_CURRENT_SENSOR)
8613941Svenki 				add_prop(nodeh, &proph, node_name, row,
8623941Svenki 				    PP_CURRENT, snmp_syserr_p);
8633941Svenki 			} else if (sensor_type == SSST_TACHOMETER) {
8643941Svenki 				ADD_NODE(PICL_CLASS_RPM_SENSOR)
8653941Svenki 				add_prop(nodeh, &proph, node_name, row,
8663941Svenki 				    PP_SPEED, snmp_syserr_p);
8673941Svenki 			} else {
8683941Svenki 				ADD_NODE(PICL_CLASS_SENSOR)
8693941Svenki 				add_prop(nodeh, &proph, node_name, row,
8703941Svenki 				    PP_SENSOR_VALUE, snmp_syserr_p);
8713941Svenki 			}
8723941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
8733941Svenki 
8743941Svenki 			add_prop(nodeh, &proph, node_name, row,
8753941Svenki 			    PP_OPSTATUS, snmp_syserr_p);
8763941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
8773941Svenki 
8783941Svenki 			add_prop(nodeh, &proph, node_name, row,
8793941Svenki 			    PP_BASE_UNITS, snmp_syserr_p);
8803941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
8813941Svenki 
8823941Svenki 			add_prop(nodeh, &proph, node_name, row,
8833941Svenki 			    PP_EXPONENT, snmp_syserr_p);
8843941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
8853941Svenki 
8863941Svenki 			add_prop(nodeh, &proph, node_name, row,
8873941Svenki 			    PP_RATE_UNITS, snmp_syserr_p);
8883941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
8893941Svenki 
8903941Svenki 			add_thresholds(nodeh, row, snmp_syserr_p);
8913941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
8923941Svenki 
8933941Svenki 		} else if (sensor_class == SSSC_BINARY) {
8943941Svenki 			if (sensor_type == SSST_TEMPERATURE) {
8953941Svenki 				ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR)
8963941Svenki 			} else if (sensor_type == SSST_VOLTAGE) {
8973941Svenki 				ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR)
8983941Svenki 			} else if (sensor_type == SSST_CURRENT) {
8993941Svenki 				ADD_NODE(PICL_CLASS_CURRENT_INDICATOR)
9003941Svenki 			} else if (sensor_type == SSST_TACHOMETER) {
9013941Svenki 				ADD_NODE(PICL_CLASS_RPM_INDICATOR)
9023941Svenki 			} else if (sensor_type == SSST_PRESENCE) {
9033941Svenki 				ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR)
9043941Svenki 			} else {
9053941Svenki 				ADD_NODE(PICL_CLASS_INDICATOR)
9063941Svenki 			}
9073941Svenki 
9083941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
9093941Svenki 			    snmp_syserr_p);
9103941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9113941Svenki 
9123941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_CONDITION,
9133941Svenki 			    snmp_syserr_p);
9143941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9153941Svenki 
9163941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_EXPECTED,
9173941Svenki 			    snmp_syserr_p);
9183941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9193941Svenki 		} else {
9203941Svenki 			log_msg(LOG_ERR,
9213941Svenki 			    SNMPP_UNSUPP_SENSOR_CLASS, sensor_class, row);
9223941Svenki 			return (NULL);
9233941Svenki 		}
9243941Svenki 		break;
9253941Svenki 
9263941Svenki 	case SPC_MODULE:
9273941Svenki 		ADD_NODE(PICL_CLASS_MODULE)
9283941Svenki 
9293941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
9303941Svenki 		    snmp_syserr_p);
9313941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
9323941Svenki 
9333941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_REPLACEABLE,
9343941Svenki 		    snmp_syserr_p);
9353941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
9363941Svenki 
9373941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_HOTSWAPPABLE,
9383941Svenki 		    snmp_syserr_p);
9393941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
9403941Svenki 		break;
9413941Svenki 
9423941Svenki 	case SPC_PORT:
9433941Svenki 		ADD_NODE(PICL_CLASS_PORT)
9443941Svenki 		break;
9453941Svenki 
9463941Svenki 	case SPC_STACK:
9473941Svenki 		ADD_NODE(PICL_CLASS_STACK)
9483941Svenki 		break;
9493941Svenki 
9503941Svenki 	default:
9513941Svenki 		log_msg(LOG_WARNING,
9523941Svenki 		    SNMPP_UNKNOWN_ENTPHYSCLASS, ent_physclass, row);
9533941Svenki 		free(phys_name);
9543941Svenki 		return (NULL);
9553941Svenki 	}
9563941Svenki 
9573941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_DESCRIPTION, snmp_syserr_p);
9583941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9593941Svenki 
9603941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_LABEL, snmp_syserr_p);
9613941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9623941Svenki 
9633941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_HW_REVISION, snmp_syserr_p);
9643941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9653941Svenki 
9663941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_FW_REVISION, snmp_syserr_p);
9673941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9683941Svenki 
9693941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_SERIAL_NUM, snmp_syserr_p);
9703941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9713941Svenki 
9723941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_MFG_NAME, snmp_syserr_p);
9733941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9743941Svenki 
9753941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_MODEL_NAME, snmp_syserr_p);
9763941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9773941Svenki 
9783941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_IS_FRU, snmp_syserr_p);
9793941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9803941Svenki 
9813941Svenki 	free(phys_name);
9823941Svenki 	save_nodeh(nodeh, row);
9833941Svenki 
9843941Svenki 	return (nodeh);
9853941Svenki }
9863941Svenki 
9873941Svenki /*
9883941Svenki  * Saves the node handle and the row id into physplat_nodes[]. If we're
9893941Svenki  * doing this in response to a hotplug event, we should've freed the
9903941Svenki  * old physplat_nodes before entering here to save the first node of the
9913941Svenki  * new physplat subtree.
9923941Svenki  */
9933941Svenki static void
9943941Svenki save_nodeh(picl_nodehdl_t nodeh, int row)
9953941Svenki {
9963941Svenki 	size_t		sz, count;
9973941Svenki 	picl_nodehdl_t	*p;
9983941Svenki 
9993941Svenki 	if (row >= n_physplat_nodes) {
10003941Svenki 		count = (((size_t)row >> NODE_BLOCK_SHIFT) + 1) *
10013941Svenki 		    N_ELEMS_IN_NODE_BLOCK;
10023941Svenki 		sz = count * sizeof (picl_nodehdl_t);
10033941Svenki 
10043941Svenki 		p = (picl_nodehdl_t *)calloc(count, sizeof (picl_nodehdl_t));
10053941Svenki 		if (p == NULL) {
10063941Svenki 			log_msg(LOG_ERR, SNMPP_NO_MEM, sz);
10073941Svenki 			return;
10083941Svenki 		}
10093941Svenki 
10103941Svenki 		if (physplat_nodes) {
10113941Svenki 			(void) memcpy((void *) p, (void *) physplat_nodes,
10123941Svenki 			    n_physplat_nodes * sizeof (picl_nodehdl_t));
10133941Svenki 			free((void *) physplat_nodes);
10143941Svenki 		}
10153941Svenki 
10163941Svenki 		physplat_nodes = p;
10173941Svenki 		n_physplat_nodes = count;
10183941Svenki 	}
10193941Svenki 
10203941Svenki 	physplat_nodes[row] = nodeh;
10213941Svenki }
10223941Svenki 
10233941Svenki static picl_nodehdl_t
10243941Svenki lookup_nodeh(int row)
10253941Svenki {
10263941Svenki 	if (row >= n_physplat_nodes)
10273941Svenki 		return (NULL);
10283941Svenki 
10293941Svenki 	return (physplat_nodes[row]);
10303941Svenki }
10313941Svenki 
10323941Svenki /*
10333941Svenki  * We enter this routine only when we are building the physical-platform
10343941Svenki  * subtree, whether for the first time or in response to a hotplug event.
10353941Svenki  * If we're here for rebuilding the tree, we have already set stale_tree
10363941Svenki  * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props
10373941Svenki  * or volprop_ndx. If we're here to build the tree for the first time,
10383941Svenki  * picld hasn't yet created doors and is running single-threaded, so no
10393941Svenki  * one else would be accessing them anyway.
10403941Svenki  */
10413941Svenki static void
10423941Svenki save_volprop(picl_prophdl_t prop, char *oidstr, int row, int proptype)
10433941Svenki {
10443941Svenki 	vol_prophdl_t	*p;
10453941Svenki 	int		count;
10463941Svenki 
10473941Svenki 	if (volprop_ndx == n_vol_props) {
10483941Svenki 		count = n_vol_props + N_ELEMS_IN_VOLPROP_BLOCK;
10493941Svenki 		p = (vol_prophdl_t *)calloc(count, sizeof (vol_prophdl_t));
10503941Svenki 		if (p == NULL) {
10513941Svenki 			log_msg(LOG_ERR, SNMPP_NO_MEM,
10523941Svenki 			    count * sizeof (vol_prophdl_t));
10533941Svenki 			return;
10543941Svenki 		}
10553941Svenki 
10563941Svenki 		if (vol_props) {
10573941Svenki 			(void) memcpy((void *) p, (void *) vol_props,
10583941Svenki 			    n_vol_props * sizeof (vol_prophdl_t));
10593941Svenki 			free((void *) vol_props);
10603941Svenki 		}
10613941Svenki 
10623941Svenki 		vol_props = p;
10633941Svenki 		n_vol_props += N_ELEMS_IN_VOLPROP_BLOCK;
10643941Svenki 	}
10653941Svenki 
10663941Svenki 	vol_props[volprop_ndx].prop = prop;
10673941Svenki 	vol_props[volprop_ndx].oidstr = oidstr;
10683941Svenki 	vol_props[volprop_ndx].row = row;
10693941Svenki 	vol_props[volprop_ndx].proptype = proptype;
10703941Svenki 
10713941Svenki 	volprop_ndx++;
10723941Svenki }
10733941Svenki 
10743941Svenki static void
10755723Sfw157321 check_for_stale_data(boolean_t nocache)
10763941Svenki {
10773941Svenki 	int	cur_change_time;
10783941Svenki 	int	ret;
10793941Svenki 	int	snmp_syserr;
10803941Svenki 
10813941Svenki 	(void) rw_wrlock(&stale_tree_rwlp);
10823941Svenki 
10833941Svenki 	/*
10843941Svenki 	 * Check if some other thread beat us to it
10853941Svenki 	 */
10863941Svenki 	if (stale_tree == B_TRUE) {
10873941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
10883941Svenki 		return;
10893941Svenki 	}
10903941Svenki 
10913941Svenki 	/*
10925723Sfw157321 	 * Cache OID_entLastChangeTime for up to 10 seconds before
10935723Sfw157321 	 * fetching it from ILOM again.  This prevents us from fetching
10945723Sfw157321 	 * this value from ILOM when the we're filling or refreshing a
10955723Sfw157321 	 * whole bunch of items in the cache around the same time.
10965723Sfw157321 	 */
10975723Sfw157321 	if (nocache == B_FALSE && time(NULL) - change_time_check <= 10) {
10985723Sfw157321 		(void) rw_unlock(&stale_tree_rwlp);
10995723Sfw157321 		return;
11005723Sfw157321 	}
11015723Sfw157321 
11025723Sfw157321 	/*
11033941Svenki 	 * Check if mib data has changed (hotplug? link-reset?)
11043941Svenki 	 */
1105*7935SMichael.Bergknoff@Sun.COM 	do {
1106*7935SMichael.Bergknoff@Sun.COM 		snmp_syserr = 0;
1107*7935SMichael.Bergknoff@Sun.COM 		ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
1108*7935SMichael.Bergknoff@Sun.COM 		    &cur_change_time, &snmp_syserr);
1109*7935SMichael.Bergknoff@Sun.COM 		(void) time(&change_time_check);
1110*7935SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && (cur_change_time == change_time)) {
1111*7935SMichael.Bergknoff@Sun.COM 			(void) rw_unlock(&stale_tree_rwlp);
1112*7935SMichael.Bergknoff@Sun.COM 			return;
1113*7935SMichael.Bergknoff@Sun.COM 		}
1114*7935SMichael.Bergknoff@Sun.COM 	} while (ret != 0 && snmp_syserr == EINTR);
11153941Svenki 
11163941Svenki 	/*
11173941Svenki 	 * If we can't read entLastChangeTime we assume we need to rebuild
11183941Svenki 	 * the tree. This will also cover the case when we need to rebuild
11193941Svenki 	 * the tree because a link reset had happened.
11203941Svenki 	 */
11213941Svenki 	LOGPRINTF2("check_for_stale_data: LastChange times have changed, "
11223941Svenki 	    "(%#x != %#x)\n", change_time, cur_change_time);
11233941Svenki 
11243941Svenki 	/*
11253941Svenki 	 * If the mib data has changed, we need to rebuild the physical-platform
11263941Svenki 	 * subtree. To do this, we set a flag to mark the tree stale,
11273941Svenki 	 * so that any future reads to get value of volatile properties will
11283941Svenki 	 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag
11293941Svenki 	 * is reset by the tree builder thread.
11303941Svenki 	 */
11313941Svenki 	stale_tree = B_TRUE;
11323941Svenki 	if (vol_props) {
11333941Svenki 		free(vol_props);
11343941Svenki 	}
11353941Svenki 	vol_props = NULL;
11363941Svenki 	volprop_ndx = 0;
11373941Svenki 	n_vol_props = 0;
11383941Svenki 
11393941Svenki 	(void) rw_unlock(&stale_tree_rwlp);
11403941Svenki 
11413941Svenki 	(void) mutex_lock(&rebuild_tree_lock);
11423941Svenki 	rebuild_tree = B_TRUE;
11433941Svenki 	(void) cond_signal(&rebuild_tree_cv);
11443941Svenki 	LOGPRINTF("check_for_stale_data: signalled tree builder\n");
11453941Svenki 	(void) mutex_unlock(&rebuild_tree_lock);
11463941Svenki }
11473941Svenki 
11483941Svenki /*
11493941Svenki  * This is the critical routine.  This callback is invoked by picl whenever
11503941Svenki  * it needs to fetch the value of a volatile property. The first thing we
11513941Svenki  * must do, however, is to see if there has been a hotplug or a link-reset
11523941Svenki  * event since the last time we built the tree and whether we need to
11533941Svenki  * rebuild the tree. If so, we do whatever is necessary to make that happen,
11543941Svenki  * but return PICL_PROPVALUNAVAILABLE for now, without making any further
11553941Svenki  * snmp requests or accessing any globals.
11563941Svenki  */
11573941Svenki static int
11583941Svenki read_volprop(ptree_rarg_t *parg, void *buf)
11593941Svenki {
11603941Svenki 	char	*pstr;
11613941Svenki 	int	propval;
11623941Svenki 	int	i, ndx;
11633941Svenki 	int	ret;
11643941Svenki 	int	snmp_syserr = 0;
11653941Svenki 
11663941Svenki 	/*
11673941Svenki 	 * First check for any event that would make us throw away
11683941Svenki 	 * the existing /physical-platform subtree and rebuild
11693941Svenki 	 * another one. If we are rebuilding the subtree, we just
11703941Svenki 	 * return the stale value until the tree is fully built.
11713941Svenki 	 */
11725723Sfw157321 	check_for_stale_data(B_FALSE);
11733941Svenki 
11743941Svenki 	(void) rw_rdlock(&stale_tree_rwlp);
11753941Svenki 
11763941Svenki 	if (stale_tree == B_TRUE) {
11773941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
11783941Svenki 		return (PICL_PROPVALUNAVAILABLE);
11793941Svenki 	}
11803941Svenki 
11813941Svenki 	for (i = 0; i < volprop_ndx; i++) {
11823941Svenki 		if (vol_props[i].prop == parg->proph) {
11833941Svenki 			ndx = i;
11843941Svenki 			break;
11853941Svenki 		}
11863941Svenki 	}
11873941Svenki 	if (i == volprop_ndx) {
11885723Sfw157321 		(void) rw_unlock(&stale_tree_rwlp);
11893941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph);
11903941Svenki 		return (PICL_FAILURE);
11913941Svenki 	}
11923941Svenki 
11933941Svenki 	/*
11943941Svenki 	 * If we can't read the value, return failure. Even if this was
11953941Svenki 	 * due to a link reset, between the check for stale data and now,
11963941Svenki 	 * the next volatile callback by picl will initiate a tree-rebuild.
11973941Svenki 	 */
11983941Svenki 	ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row,
11993941Svenki 	    &propval, &snmp_syserr);
12003941Svenki 	if (ret < 0) {
12015723Sfw157321 		(void) rw_unlock(&stale_tree_rwlp);
12025723Sfw157321 		check_for_stale_data(B_TRUE);
12035723Sfw157321 		if (stale_tree == B_TRUE) {
12045723Sfw157321 			return (PICL_PROPVALUNAVAILABLE);
12055723Sfw157321 		}
12065723Sfw157321 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
12075723Sfw157321 		    snmp_syserr ? snmp_syserr : ret,
12085723Sfw157321 		    vol_props[ndx].oidstr, vol_props[ndx].row);
12093941Svenki 		return (PICL_FAILURE);
12103941Svenki 	}
12113941Svenki 
12123941Svenki 	switch (vol_props[ndx].proptype) {
12133941Svenki 	case VPT_PLATOPSTATE:
12143941Svenki 		if (propval == SSOS_DISABLED) {
12153941Svenki 			(void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN);
12163941Svenki 		} else if (propval == SSOS_ENABLED) {
12173941Svenki 			(void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN);
12183941Svenki 		} else {
12195723Sfw157321 			(void) rw_unlock(&stale_tree_rwlp);
12203941Svenki 			log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE,
12213941Svenki 			    propval, vol_props[ndx].row);
12223941Svenki 			return (PICL_FAILURE);
12233941Svenki 		}
12243941Svenki 		break;
12253941Svenki 
12263941Svenki 	case VPT_NUMSENSOR:
12273941Svenki 		(void) memcpy(buf, &propval, sizeof (propval));
12283941Svenki 		break;
12293941Svenki 
12303941Svenki 	case VPT_BINSENSOR:
12313941Svenki 		if (propval == ST_TRUE) {
12323941Svenki 			ret = snmp_get_str(hdl,
12333941Svenki 			    OID_sunPlatBinarySensorInterpretTrue,
12343941Svenki 			    vol_props[ndx].row, &pstr, &snmp_syserr);
12355723Sfw157321 			if (snmp_syserr == ECANCELED) {
12365723Sfw157321 				(void) rw_unlock(&stale_tree_rwlp);
12375723Sfw157321 				if (pstr)
12385723Sfw157321 					free(pstr);
12393941Svenki 				return (PICL_FAILURE);
12405723Sfw157321 			}
12413941Svenki 			if (ret < 0 || pstr == NULL) {
12425723Sfw157321 				log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
12435723Sfw157321 				    snmp_syserr ? snmp_syserr : ret,
12445723Sfw157321 				    OID_sunPlatBinarySensorInterpretTrue,
12455723Sfw157321 				    vol_props[ndx].row);
12463941Svenki 				(void) strlcpy(buf, STR_ST_TRUE,
12473941Svenki 				    MAX_TRUTHVAL_LEN);
12483941Svenki 			} else {
12493941Svenki 				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
12505723Sfw157321 			}
12515723Sfw157321 			if (pstr)
12523941Svenki 				free(pstr);
12533941Svenki 		} else if (propval == ST_FALSE) {
12543941Svenki 			ret = snmp_get_str(hdl,
12553941Svenki 			    OID_sunPlatBinarySensorInterpretFalse,
12563941Svenki 			    vol_props[ndx].row, &pstr, &snmp_syserr);
12575723Sfw157321 			if (snmp_syserr == ECANCELED) {
12585723Sfw157321 				(void) rw_unlock(&stale_tree_rwlp);
12595723Sfw157321 				if (pstr)
12605723Sfw157321 					free(pstr);
12613941Svenki 				return (PICL_FAILURE);
12625723Sfw157321 			}
12633941Svenki 			if (ret < 0 || pstr == NULL) {
12645723Sfw157321 				log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
12655723Sfw157321 				    snmp_syserr ? snmp_syserr : ret,
12665723Sfw157321 				    OID_sunPlatBinarySensorInterpretFalse,
12675723Sfw157321 				    vol_props[ndx].row);
12683941Svenki 				(void) strlcpy(buf, STR_ST_FALSE,
12693941Svenki 				    MAX_TRUTHVAL_LEN);
12703941Svenki 			} else {
12713941Svenki 				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
12725723Sfw157321 			}
12735723Sfw157321 			if (pstr)
12743941Svenki 				free(pstr);
12753941Svenki 		} else {
12765723Sfw157321 			(void) rw_unlock(&stale_tree_rwlp);
12773941Svenki 			log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT,
12783941Svenki 			    propval, vol_props[ndx].row);
12793941Svenki 			return (PICL_FAILURE);
12803941Svenki 		}
12813941Svenki 		break;
12823941Svenki 
12833941Svenki 	case VPT_ALARMSTATE:
12843941Svenki 		if (propval == SSAS_OFF) {
12853941Svenki 			(void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN);
12863941Svenki 		} else if (propval == SSAS_STEADY) {
12873941Svenki 			(void) strlcpy(buf, STR_SSAS_STEADY,
12883941Svenki 			    MAX_ALARMSTATE_LEN);
12893941Svenki 		} else if (propval == SSAS_ALTERNATING) {
12903941Svenki 			(void) strlcpy(buf, STR_SSAS_ALTERNATING,
12913941Svenki 			    MAX_ALARMSTATE_LEN);
12923941Svenki 		} else {
12933941Svenki 			(void) strlcpy(buf, STR_SSAS_UNKNOWN,
12943941Svenki 			    MAX_ALARMSTATE_LEN);
12953941Svenki 		}
12963941Svenki 		break;
12973941Svenki 
12983941Svenki 	case VPT_BATTERYSTATUS:
12993941Svenki 		switch (propval) {
13003941Svenki 		case SSBS_OTHER:
13013941Svenki 			(void) strlcpy(buf, STR_SSBS_OTHER,
13023941Svenki 			    MAX_BATTERYSTATUS_LEN);
13033941Svenki 			break;
13043941Svenki 		case SSBS_FULLYCHARGED:
13053941Svenki 			(void) strlcpy(buf, STR_SSBS_FULLYCHARGED,
13063941Svenki 			    MAX_BATTERYSTATUS_LEN);
13073941Svenki 			break;
13083941Svenki 		case SSBS_LOW:
13093941Svenki 			(void) strlcpy(buf, STR_SSBS_LOW,
13103941Svenki 			    MAX_BATTERYSTATUS_LEN);
13113941Svenki 			break;
13123941Svenki 		case SSBS_CRITICAL:
13133941Svenki 			(void) strlcpy(buf, STR_SSBS_CRITICAL,
13143941Svenki 			    MAX_BATTERYSTATUS_LEN);
13153941Svenki 			break;
13163941Svenki 		case SSBS_CHARGING:
13173941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING,
13183941Svenki 			    MAX_BATTERYSTATUS_LEN);
13193941Svenki 			break;
13203941Svenki 		case SSBS_CHARGING_AND_LOW:
13213941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW,
13223941Svenki 			    MAX_BATTERYSTATUS_LEN);
13233941Svenki 			break;
13243941Svenki 		case SSBS_CHARGING_AND_HIGH:
13253941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH,
13263941Svenki 			    MAX_BATTERYSTATUS_LEN);
13273941Svenki 			break;
13283941Svenki 		case SSBS_CHARGING_AND_CRITICAL:
13293941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL,
13303941Svenki 			    MAX_BATTERYSTATUS_LEN);
13313941Svenki 			break;
13323941Svenki 		case SSBS_UNDEFINED:
13333941Svenki 			(void) strlcpy(buf, STR_SSBS_UNDEFINED,
13343941Svenki 			    MAX_BATTERYSTATUS_LEN);
13353941Svenki 			break;
13363941Svenki 		case SSBS_PARTIALLY_CHARGED:
13373941Svenki 			(void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED,
13383941Svenki 			    MAX_BATTERYSTATUS_LEN);
13393941Svenki 			break;
13403941Svenki 		case SSBS_UNKNOWN:
13413941Svenki 		default:
13423941Svenki 			(void) strlcpy(buf, STR_SSBS_UNKNOWN,
13433941Svenki 			    MAX_BATTERYSTATUS_LEN);
13443941Svenki 			break;
13453941Svenki 		}
13463941Svenki 		break;
13473941Svenki 	}
13483941Svenki 
13493941Svenki 	(void) rw_unlock(&stale_tree_rwlp);
13503941Svenki 
13513941Svenki 	return (PICL_SUCCESS);
13523941Svenki }
13533941Svenki 
13543941Svenki static void
13553941Svenki threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname,
13563941Svenki     int *snmp_syserr_p)
13573941Svenki {
13583941Svenki 	picl_prophdl_t	prop;
13593941Svenki 	int		err;
13603941Svenki 	int		val;
13613941Svenki 
13625723Sfw157321 	if ((err = snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p)) != -1) {
13633941Svenki 		err = add_volatile_prop(node, propname, PICL_PTYPE_INT,
13643941Svenki 		    PICL_READ, sizeof (int), read_volprop, NULL, &prop);
13653941Svenki 		if (err == PICL_SUCCESS)
13663941Svenki 			save_volprop(prop, oidstr, row, VPT_NUMSENSOR);
13675723Sfw157321 	} else
13685723Sfw157321 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
13695723Sfw157321 		    *snmp_syserr_p ? *snmp_syserr_p : err, oidstr, row);
13703941Svenki }
13713941Svenki 
13723941Svenki static void
13733941Svenki add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p)
13743941Svenki {
13753941Svenki 	uchar_t	*bitstr = NULL;
13763941Svenki 	uchar_t	enabled;
13773941Svenki 	uint_t	nbytes;
13783941Svenki 	int	ret;
13793941Svenki 
13805723Sfw157321 	ret = snmp_get_str(hdl,
13815723Sfw157321 	    OID_sunPlatNumericSensorEnabledThresholds,
13825723Sfw157321 	    row, (char **)&bitstr, snmp_syserr_p);
13835723Sfw157321 	if (ret == -1) {
13845723Sfw157321 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
13855723Sfw157321 		    *snmp_syserr_p ? *snmp_syserr_p : ret,
13865723Sfw157321 		    OID_sunPlatNumericSensorEnabledThresholds, row);
13875723Sfw157321 	} else {
13885723Sfw157321 		nbytes = strlen((const char *)bitstr);
13895723Sfw157321 	}
13905723Sfw157321 
13915723Sfw157321 	CHECK_LINKRESET_VOID(snmp_syserr_p);
13923941Svenki 
13935723Sfw157321 	/*
13945723Sfw157321 	 * No bit string of threshold masks was returned, so we can't
13955723Sfw157321 	 * assume that any thresholds exist.
13965723Sfw157321 	 *
13975723Sfw157321 	 * This mask prevents us from attempting to fetch thresholds
13985723Sfw157321 	 * which don't apply to the sensor or that aren't there anyway,
13995723Sfw157321 	 * That speeds up the plug-in significantly since otherwise it
14005723Sfw157321 	 * takes several seconds to time out.
14015723Sfw157321 	 */
14025723Sfw157321 	if (ret < 0 || bitstr == NULL || nbytes == 0 || 2 < nbytes) {
14035723Sfw157321 		if (bitstr)
14045723Sfw157321 			free(bitstr);
14055723Sfw157321 		return;
14065723Sfw157321 	} else if (nbytes == 1) {
14073941Svenki 		/*
14083941Svenki 		 * The ALOM snmp agent doesn't adhere to the BER rules for
14093941Svenki 		 * encoding bit strings. While the BER states that bitstrings
14103941Svenki 		 * must begin from the second octet after length, and the
14113941Svenki 		 * first octet after length must indicate the number of unused
14123941Svenki 		 * bits in the last octet, the snmp agent simply sends the
14133941Svenki 		 * bitstring data as if it were octet string -- that is, the
14143941Svenki 		 * "unused bits" octet is missing.
14153941Svenki 		 */
14163941Svenki 		enabled = bitstr[0];
14173941Svenki 	} else if (nbytes == 2)
14183941Svenki 		enabled = bitstr[1];
14193941Svenki 
14203941Svenki 	if (bitstr) {
14213941Svenki 		free(bitstr);
14223941Svenki 	}
14233941Svenki 
14243941Svenki 	if (enabled & LOWER_FATAL) {
14253941Svenki 		threshold(node,
14263941Svenki 		    OID_sunPlatNumericSensorLowerThresholdFatal, row,
14273941Svenki 		    PICL_PROP_LOW_POWER_OFF, snmp_syserr_p);
14283941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14293941Svenki 	}
14303941Svenki 	if (enabled & LOWER_CRITICAL) {
14313941Svenki 		threshold(node,
14323941Svenki 		    OID_sunPlatNumericSensorLowerThresholdCritical, row,
14333941Svenki 		    PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p);
14343941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14353941Svenki 	}
14363941Svenki 	if (enabled & LOWER_NON_CRITICAL) {
14373941Svenki 		threshold(node,
14383941Svenki 		    OID_sunPlatNumericSensorLowerThresholdNonCritical, row,
14393941Svenki 		    PICL_PROP_LOW_WARNING, snmp_syserr_p);
14403941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14413941Svenki 	}
14423941Svenki 	if (enabled & UPPER_NON_CRITICAL) {
14433941Svenki 		threshold(node,
14443941Svenki 		    OID_sunPlatNumericSensorUpperThresholdNonCritical, row,
14454802Sfw157321 		    PICL_PROP_HIGH_WARNING, snmp_syserr_p);
14463941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14473941Svenki 	}
14483941Svenki 	if (enabled & UPPER_CRITICAL) {
14493941Svenki 		threshold(node,
14503941Svenki 		    OID_sunPlatNumericSensorUpperThresholdCritical, row,
14513941Svenki 		    PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p);
14523941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14533941Svenki 	}
14543941Svenki 	if (enabled & UPPER_FATAL) {
14553941Svenki 		threshold(node,
14563941Svenki 		    OID_sunPlatNumericSensorUpperThresholdFatal, row,
14574802Sfw157321 		    PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p);
14583941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14593941Svenki 	}
14603941Svenki }
14613941Svenki 
14623941Svenki static char *
14633941Svenki get_slot_type(int row, int *snmp_syserr_p)
14643941Svenki {
14653941Svenki 	char	*p;
14663941Svenki 	char	*slott = NULL;
14673941Svenki 	int	ret;
14683941Svenki 
14693941Svenki 	ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes,
14703941Svenki 	    row, &p, snmp_syserr_p);
14713941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
14723941Svenki 
14733941Svenki 	if ((ret == 0) && p && *p) {
14743941Svenki 		slott = p;
14753941Svenki 		if ((p = strchr(slott, '\n')) != NULL)
14763941Svenki 			*p = 0;
14773941Svenki 	} else {
14783941Svenki 		log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row);
14793941Svenki 		if (p) {
14803941Svenki 			free(p);
14813941Svenki 		}
14823941Svenki 	}
14833941Svenki 
14843941Svenki 	return (slott);
14853941Svenki }
14863941Svenki 
14873941Svenki /*
14883941Svenki  * Create and add the specified volatile property
14893941Svenki  */
14903941Svenki static int
14913941Svenki add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access,
14923941Svenki     int size, int (*rdfunc)(ptree_rarg_t *, void *),
14933941Svenki     int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp)
14943941Svenki {
14953941Svenki 	ptree_propinfo_t	propinfo;
14963941Svenki 	picl_prophdl_t		prop;
14973941Svenki 	int			err;
14983941Svenki 
14993941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
15003941Svenki 	    type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc);
15013941Svenki 	if (err != PICL_SUCCESS) {
15023941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err);
15033941Svenki 		return (err);
15043941Svenki 	}
15053941Svenki 
15063941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop);
15073941Svenki 	if (err != PICL_SUCCESS) {
15083941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node);
15093941Svenki 		return (err);
15103941Svenki 	}
15113941Svenki 
15123941Svenki 	if (propp)
15133941Svenki 		*propp = prop;
15143941Svenki 
15153941Svenki 	return (PICL_SUCCESS);
15163941Svenki }
15173941Svenki 
15183941Svenki /*
15193941Svenki  * Add the specified string property to the node
15203941Svenki  */
15213941Svenki static int
15223941Svenki add_string_prop(picl_nodehdl_t node, char *propname, char *propval)
15233941Svenki {
15243941Svenki 	ptree_propinfo_t	propinfo;
15253941Svenki 	int			err;
15263941Svenki 
15277382SMichael.Bergknoff@Sun.COM 	if (*propval == '\0')
15287382SMichael.Bergknoff@Sun.COM 		return (PICL_SUCCESS);
15297382SMichael.Bergknoff@Sun.COM 
15303941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
15313941Svenki 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1,
15323941Svenki 	    propname, NULL, NULL);
15333941Svenki 	if (err != PICL_SUCCESS) {
15343941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err);
15353941Svenki 		return (err);
15363941Svenki 	}
15373941Svenki 
15383941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, propval, NULL);
15393941Svenki 	if (err != PICL_SUCCESS) {
15403941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node);
15413941Svenki 		return (err);
15423941Svenki 	}
15433941Svenki 
15443941Svenki 	return (PICL_SUCCESS);
15453941Svenki }
15463941Svenki 
15473941Svenki /*
15483941Svenki  * Add the specified void property to the node
15493941Svenki  */
15503941Svenki static int
15513941Svenki add_void_prop(picl_nodehdl_t node, char *propname)
15523941Svenki {
15533941Svenki 	ptree_propinfo_t	propinfo;
15543941Svenki 	int			err;
15553941Svenki 
15563941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
15573941Svenki 	    PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL);
15583941Svenki 	if (err != PICL_SUCCESS) {
15593941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err);
15603941Svenki 		return (err);
15613941Svenki 	}
15623941Svenki 
15633941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL);
15643941Svenki 	if (err != PICL_SUCCESS) {
15653941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node);
15663941Svenki 		return (err);
15673941Svenki 	}
15683941Svenki 
15693941Svenki 	return (PICL_SUCCESS);
15703941Svenki }
15713941Svenki 
15723941Svenki static void
15733941Svenki add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
15743941Svenki     int row, sp_propid_t pp, int *snmp_syserr_p)
15753941Svenki {
15763941Svenki 	char	*serial_num;
15773941Svenki 	char	*slot_type;
15783941Svenki 	char	*fw_revision, *hw_revision;
15793941Svenki 	char	*mfg_name, *model_name;
15803941Svenki 	char	*phys_descr;
15813941Svenki 	int	val;
15823941Svenki 	int	ret;
15833941Svenki 
15843941Svenki 	switch (pp) {
15853941Svenki 	case PP_SERIAL_NUM:
15863941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalSerialNum,
15873941Svenki 		    row, &serial_num, snmp_syserr_p);
15883941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
15897382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && serial_num) {
15903941Svenki 			(void) add_string_prop(nodeh,
15913941Svenki 			    PICL_PROP_SERIAL_NUMBER, serial_num);
15923941Svenki 			free((void *) serial_num);
15933941Svenki 		}
15945723Sfw157321 		if (ret == -1)
15955723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
15965723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
15975723Sfw157321 			    OID_entPhysicalSerialNum, row);
15983941Svenki 		break;
15993941Svenki 
16003941Svenki 	case PP_SLOT_TYPE:
16013941Svenki 		if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) {
16023941Svenki 			CHECK_LINKRESET_VOID(snmp_syserr_p)
16033941Svenki 			(void) add_string_prop(nodeh,
16043941Svenki 			    PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE);
16053941Svenki 		} else {
16063941Svenki 			(void) add_string_prop(nodeh,
16073941Svenki 			    PICL_PROP_SLOT_TYPE, slot_type);
16083941Svenki 			free((void *) slot_type);
16093941Svenki 		}
16103941Svenki 		break;
16113941Svenki 
16123941Svenki 	case PP_STATE:
16133941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_STATE,
16143941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN,
16153941Svenki 		    read_volprop, NULL, php);
16163941Svenki 		if (ret == PICL_SUCCESS) {
16173941Svenki 			save_volprop(*php, OID_sunPlatAlarmState, row,
16183941Svenki 			    VPT_ALARMSTATE);
16193941Svenki 		}
16203941Svenki 		break;
16213941Svenki 
16223941Svenki 	case PP_OPSTATUS:
16233941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS,
16243941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN,
16253941Svenki 		    read_volprop, NULL, php);
16263941Svenki 		if (ret == PICL_SUCCESS) {
16273941Svenki 			save_volprop(*php,
16283941Svenki 			    OID_sunPlatEquipmentOperationalState, row,
16293941Svenki 			    VPT_PLATOPSTATE);
16303941Svenki 		}
16313941Svenki 		break;
16323941Svenki 
16333941Svenki 	case PP_BATT_STATUS:
16343941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS,
16354802Sfw157321 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN,
16364802Sfw157321 		    read_volprop, NULL, php);
16373941Svenki 		if (ret == PICL_SUCCESS) {
16383941Svenki 			save_volprop(*php, OID_sunPlatBatteryStatus, row,
16393941Svenki 			    VPT_BATTERYSTATUS);
16403941Svenki 		}
16413941Svenki 		break;
16423941Svenki 
16433941Svenki 	case PP_TEMPERATURE:
16443941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE,
16453941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16463941Svenki 		    NULL, php);
16473941Svenki 		if (ret == PICL_SUCCESS) {
16483941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
16493941Svenki 			    row, VPT_NUMSENSOR);
16503941Svenki 		}
16513941Svenki 		break;
16523941Svenki 
16533941Svenki 	case PP_VOLTAGE:
16543941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE,
16553941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16563941Svenki 		    NULL, php);
16573941Svenki 		if (ret == PICL_SUCCESS) {
16583941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
16593941Svenki 			    row, VPT_NUMSENSOR);
16603941Svenki 		}
16613941Svenki 		break;
16623941Svenki 
16633941Svenki 	case PP_CURRENT:
16643941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT,
16653941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16663941Svenki 		    NULL, php);
16673941Svenki 		if (ret == PICL_SUCCESS) {
16683941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
16693941Svenki 			    row, VPT_NUMSENSOR);
16703941Svenki 		}
16713941Svenki 		break;
16723941Svenki 
16733941Svenki 	case PP_SPEED:
16743941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT,
16753941Svenki 		    PICL_READ, sizeof (int), read_volprop, NULL, php);
16763941Svenki 		if (ret == PICL_SUCCESS) {
16773941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
16783941Svenki 			    row, VPT_NUMSENSOR);
16793941Svenki 		}
16803941Svenki 		break;
16813941Svenki 
16823941Svenki 	case PP_SENSOR_VALUE:
16833941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE,
16843941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16853941Svenki 		    NULL, php);
16863941Svenki 		if (ret == PICL_SUCCESS) {
16873941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
16883941Svenki 			    row, VPT_NUMSENSOR);
16893941Svenki 		}
16903941Svenki 		break;
16913941Svenki 
16923941Svenki 	case PP_CONDITION:
16933941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION,
16943941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
16953941Svenki 		    read_volprop, NULL, php);
16963941Svenki 		if (ret == PICL_SUCCESS) {
16973941Svenki 			save_volprop(*php, OID_sunPlatBinarySensorCurrent,
16983941Svenki 			    row, VPT_BINSENSOR);
16993941Svenki 		}
17003941Svenki 		break;
17013941Svenki 
17023941Svenki 	case PP_EXPECTED:
17033941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED,
17043941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
17053941Svenki 		    read_volprop, NULL, php);
17063941Svenki 		if (ret == PICL_SUCCESS) {
17073941Svenki 			save_volprop(*php, OID_sunPlatBinarySensorExpected,
17083941Svenki 			    row, VPT_BINSENSOR);
17093941Svenki 		}
17103941Svenki 		break;
17113941Svenki 
17125436Sfw157321 	case PP_EXPONENT:
17135436Sfw157321 		ret = add_volatile_prop(nodeh, PICL_PROP_EXPONENT,
17145436Sfw157321 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
17155436Sfw157321 		    NULL, php);
17165436Sfw157321 		if (ret == PICL_SUCCESS) {
17175436Sfw157321 			save_volprop(*php, OID_sunPlatNumericSensorExponent,
17185436Sfw157321 			    row, VPT_NUMSENSOR);
17195436Sfw157321 		}
17205436Sfw157321 		break;
17215436Sfw157321 
17223941Svenki 	case PP_REPLACEABLE:
17233941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable,
17243941Svenki 		    row, &val, snmp_syserr_p);
17253941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17263941Svenki 		if ((ret == 0) && (val == ST_TRUE))
17273941Svenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE);
17285723Sfw157321 		if (ret == -1)
17295723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17305723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17315723Sfw157321 			    OID_sunPlatCircuitPackReplaceable, row);
17323941Svenki 		break;
17333941Svenki 
17343941Svenki 	case PP_HOTSWAPPABLE:
17353941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable,
17363941Svenki 		    row, &val, snmp_syserr_p);
17373941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17383941Svenki 		if ((ret == 0) && (val == ST_TRUE))
17393941Svenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE);
17405723Sfw157321 		if (ret == -1)
17415723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17425723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17435723Sfw157321 			    OID_sunPlatCircuitPackHotSwappable, row);
17443941Svenki 		break;
17453941Svenki 
17463941Svenki 	case PP_IS_FRU:
17473941Svenki 		ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row,
17483941Svenki 		    &val, snmp_syserr_p);
17493941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17503941Svenki 		if ((ret == 0) && (val == ST_TRUE))
17513941Svenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_FRU);
17525723Sfw157321 		if (ret == -1)
17535723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17545723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17555723Sfw157321 			    OID_entPhysicalIsFRU, row);
17563941Svenki 		break;
17573941Svenki 
17583941Svenki 	case PP_HW_REVISION:
17593941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev,
17603941Svenki 		    row, &hw_revision, snmp_syserr_p);
17613941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17627382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && hw_revision) {
17633941Svenki 			(void) add_string_prop(nodeh,
17643941Svenki 			    PICL_PROP_HW_REVISION, hw_revision);
17653941Svenki 			free((void *) hw_revision);
17663941Svenki 		}
17675723Sfw157321 		if (ret == -1)
17685723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17695723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17705723Sfw157321 			    OID_entPhysicalHardwareRev, row);
17713941Svenki 		break;
17723941Svenki 
17733941Svenki 	case PP_FW_REVISION:
17743941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev,
17753941Svenki 		    row, &fw_revision, snmp_syserr_p);
17763941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17777382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && fw_revision) {
17783941Svenki 			(void) add_string_prop(nodeh,
17793941Svenki 			    PICL_PROP_FW_REVISION, fw_revision);
17803941Svenki 			free((void *) fw_revision);
17813941Svenki 		}
17825723Sfw157321 		if (ret == -1)
17835723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17845723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17855723Sfw157321 			    OID_entPhysicalFirmwareRev, row);
17863941Svenki 		break;
17873941Svenki 
17883941Svenki 	case PP_MFG_NAME:
17893941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalMfgName,
17903941Svenki 		    row, &mfg_name, snmp_syserr_p);
17913941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17927382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && mfg_name) {
17933941Svenki 			(void) add_string_prop(nodeh,
17943941Svenki 			    PICL_PROP_MFG_NAME, mfg_name);
17953941Svenki 			free((void *) mfg_name);
17963941Svenki 		}
17975723Sfw157321 		if (ret == -1)
17985723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17995723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18005723Sfw157321 			    OID_entPhysicalMfgName, row);
18013941Svenki 		break;
18023941Svenki 
18033941Svenki 	case PP_MODEL_NAME:
18043941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalModelName,
18053941Svenki 		    row, &model_name, snmp_syserr_p);
18063941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18077382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && model_name) {
18083941Svenki 			(void) add_string_prop(nodeh,
18093941Svenki 			    PICL_PROP_MODEL_NAME, model_name);
18103941Svenki 			free((void *) model_name);
18113941Svenki 		}
18125723Sfw157321 		if (ret == -1)
18135723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18145723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18155723Sfw157321 			    OID_entPhysicalModelName, row);
18163941Svenki 		break;
18173941Svenki 
18183941Svenki 	case PP_DESCRIPTION:
18193941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalDescr,
18203941Svenki 		    row, &phys_descr, snmp_syserr_p);
18213941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18227382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && phys_descr) {
18234802Sfw157321 			(void) add_string_prop(nodeh,
18244802Sfw157321 			    PICL_PROP_PHYS_DESCRIPTION, phys_descr);
18254802Sfw157321 			free((void *) phys_descr);
18263941Svenki 		}
18275723Sfw157321 		if (ret == -1)
18285723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18295723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18305723Sfw157321 			    OID_entPhysicalDescr, row);
18313941Svenki 		break;
18323941Svenki 
18333941Svenki 	case PP_LABEL:
18343941Svenki 		if (label && *label)
18353941Svenki 			(void) add_string_prop(nodeh, PICL_PROP_LABEL, label);
18363941Svenki 		break;
18373941Svenki 
18383941Svenki 	case PP_BASE_UNITS:
18393941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits,
18403941Svenki 		    row, &val, snmp_syserr_p);
18413941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18423941Svenki 		if ((ret == 0) && (val > 0) && (val < n_baseunits)) {
18433941Svenki 			(void) add_string_prop(nodeh,
18443941Svenki 			    PICL_PROP_BASE_UNITS, sensor_baseunits[val]);
18453941Svenki 		}
18465723Sfw157321 		if (ret == -1)
18475723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18485723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18495723Sfw157321 			    OID_sunPlatNumericSensorBaseUnits, row);
18503941Svenki 		break;
18513941Svenki 
18523941Svenki 	case PP_RATE_UNITS:
18533941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits,
18543941Svenki 		    row, &val, snmp_syserr_p);
18553941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18563941Svenki 		if ((ret == 0) && (val > 0) && (val < n_rateunits)) {
18573941Svenki 			(void) add_string_prop(nodeh,
18583941Svenki 			    PICL_PROP_RATE_UNITS, sensor_rateunits[val]);
18593941Svenki 		}
18605723Sfw157321 		if (ret == -1)
18615723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18625723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18635723Sfw157321 			    OID_sunPlatNumericSensorRateUnits, row);
18643941Svenki 		break;
18653941Svenki 	}
18663941Svenki }
18673941Svenki 
18687746SKelly.Moyer@Sun.COM /*
18697746SKelly.Moyer@Sun.COM  * Initialize the SNMP library's cache refresh subsystem, then periodically
18707746SKelly.Moyer@Sun.COM  * process refresh job to prevent cache entries from expiring.
18717746SKelly.Moyer@Sun.COM  */
18727746SKelly.Moyer@Sun.COM /*ARGSUSED*/
18737746SKelly.Moyer@Sun.COM static void *
18747746SKelly.Moyer@Sun.COM cache_refresher(void *arg)
18757746SKelly.Moyer@Sun.COM {
18767746SKelly.Moyer@Sun.COM 	int		jobs;
18777746SKelly.Moyer@Sun.COM 	int		next_expiration;
18787746SKelly.Moyer@Sun.COM 	timestruc_t	to;
18797746SKelly.Moyer@Sun.COM 	hrtime_t	cycle_start, cycle_elapsed;
18807746SKelly.Moyer@Sun.COM 
18817746SKelly.Moyer@Sun.COM 	/*
18827746SKelly.Moyer@Sun.COM 	 * Initialize refresh subsystem
18837746SKelly.Moyer@Sun.COM 	 */
18847746SKelly.Moyer@Sun.COM 	LOGPRINTF("Initializing SNMP refresh subsystem.\n");
18857746SKelly.Moyer@Sun.COM 	if (snmp_refresh_init() < 0) {
18867746SKelly.Moyer@Sun.COM 		return ((void *)-1);
18877746SKelly.Moyer@Sun.COM 	}
18887746SKelly.Moyer@Sun.COM 
18897746SKelly.Moyer@Sun.COM 	(void) mutex_lock(&cache_refresh_lock);
18907746SKelly.Moyer@Sun.COM 
18917746SKelly.Moyer@Sun.COM 
18927746SKelly.Moyer@Sun.COM 	for (;;) {
18937746SKelly.Moyer@Sun.COM 		cycle_start = gethrtime();
18947746SKelly.Moyer@Sun.COM 
18957746SKelly.Moyer@Sun.COM 		/*
18967746SKelly.Moyer@Sun.COM 		 * Process jobs from the snmp cache refresh work queue until one
18977746SKelly.Moyer@Sun.COM 		 * of the following conditions is true:
18987746SKelly.Moyer@Sun.COM 		 * 1) we are told to exit, or
18997746SKelly.Moyer@Sun.COM 		 * 2) we have processed at least as many jobs as recommended by
19007746SKelly.Moyer@Sun.COM 		 * the library, and the next job expiration is at least
19017746SKelly.Moyer@Sun.COM 		 * CACHE_REFRESH_MIN_WINDOW * seconds away.
19027746SKelly.Moyer@Sun.COM 		 */
19037746SKelly.Moyer@Sun.COM 		jobs = snmp_refresh_get_cycle_hint(CACHE_REFRESH_CYCLE);
19047746SKelly.Moyer@Sun.COM 		while ((cache_refresh_thr_exit == B_FALSE) && (jobs > 0)) {
19057746SKelly.Moyer@Sun.COM 			(void) snmp_refresh_process_job();
19067746SKelly.Moyer@Sun.COM 			jobs--;
19077746SKelly.Moyer@Sun.COM 		}
19087746SKelly.Moyer@Sun.COM 
19097746SKelly.Moyer@Sun.COM 		next_expiration = snmp_refresh_get_next_expiration();
19107746SKelly.Moyer@Sun.COM 		while ((cache_refresh_thr_exit == B_FALSE) &&
19117746SKelly.Moyer@Sun.COM 		    ((next_expiration >= 0) &&
19127746SKelly.Moyer@Sun.COM 		    (next_expiration < CACHE_REFRESH_MIN_WINDOW))) {
19137746SKelly.Moyer@Sun.COM 			(void) snmp_refresh_process_job();
19147746SKelly.Moyer@Sun.COM 			next_expiration = snmp_refresh_get_next_expiration();
19157746SKelly.Moyer@Sun.COM 		}
19167746SKelly.Moyer@Sun.COM 
19177746SKelly.Moyer@Sun.COM 		/*
19187746SKelly.Moyer@Sun.COM 		 * As long as we haven't been told to exit, sleep for
19197746SKelly.Moyer@Sun.COM 		 * CACHE_REFRESH_CYCLE seconds minus the amount of time that has
19207746SKelly.Moyer@Sun.COM 		 * elapsed since this cycle started.  If the elapsed time is
19217746SKelly.Moyer@Sun.COM 		 * equal to or greater than 60 seconds, skip sleeping entirely.
19227746SKelly.Moyer@Sun.COM 		 */
19237746SKelly.Moyer@Sun.COM 		cycle_elapsed = (gethrtime() - cycle_start) / NANOSEC;
19247746SKelly.Moyer@Sun.COM 		if ((cache_refresh_thr_exit == B_FALSE) &&
19257746SKelly.Moyer@Sun.COM 		    (cycle_elapsed < CACHE_REFRESH_CYCLE)) {
19267746SKelly.Moyer@Sun.COM 			to.tv_sec = CACHE_REFRESH_CYCLE - cycle_elapsed;
19277746SKelly.Moyer@Sun.COM 			to.tv_nsec = 0;
19287746SKelly.Moyer@Sun.COM 			(void) cond_reltimedwait(&cache_refresh_cv,
19297746SKelly.Moyer@Sun.COM 			    &cache_refresh_lock, &to);
19307746SKelly.Moyer@Sun.COM 		}
19317746SKelly.Moyer@Sun.COM 
19327746SKelly.Moyer@Sun.COM 		/*
19337746SKelly.Moyer@Sun.COM 		 * If we have been told to exit, clean up and bail out.
19347746SKelly.Moyer@Sun.COM 		 */
19357746SKelly.Moyer@Sun.COM 		if (cache_refresh_thr_exit == B_TRUE) {
19367746SKelly.Moyer@Sun.COM 			snmp_refresh_fini();
19377746SKelly.Moyer@Sun.COM 			(void) mutex_unlock(&cache_refresh_lock);
19387746SKelly.Moyer@Sun.COM 			LOGPRINTF("cache_refresher: time to exit\n");
19397746SKelly.Moyer@Sun.COM 			return (NULL);
19407746SKelly.Moyer@Sun.COM 		}
19417746SKelly.Moyer@Sun.COM 
19427746SKelly.Moyer@Sun.COM 	}
19437746SKelly.Moyer@Sun.COM 
19447746SKelly.Moyer@Sun.COM 	/*NOTREACHED*/
19457746SKelly.Moyer@Sun.COM 	return (NULL);
19467746SKelly.Moyer@Sun.COM }
19477746SKelly.Moyer@Sun.COM 
19487746SKelly.Moyer@Sun.COM /*
19497746SKelly.Moyer@Sun.COM  * Check to see if the cache_refresher thread is running.  If it is, signal it
19507746SKelly.Moyer@Sun.COM  * to terminate and clean up associated data structures.
19517746SKelly.Moyer@Sun.COM  */
19527746SKelly.Moyer@Sun.COM void
19537746SKelly.Moyer@Sun.COM cache_refresher_fini(void)
19547746SKelly.Moyer@Sun.COM {
19557746SKelly.Moyer@Sun.COM 	/* if the thread isn't running, there is nothing to do */
19567746SKelly.Moyer@Sun.COM 	if (cache_refresh_thr_exit == B_TRUE)
19577746SKelly.Moyer@Sun.COM 		return;
19587746SKelly.Moyer@Sun.COM 
19597746SKelly.Moyer@Sun.COM 	/* wake up the cache_refresher thread, tell it to exit */
19607746SKelly.Moyer@Sun.COM 	(void) mutex_lock(&cache_refresh_lock);
19617746SKelly.Moyer@Sun.COM 	cache_refresh_thr_exit = B_TRUE;
19627746SKelly.Moyer@Sun.COM 	(void) cond_signal(&cache_refresh_cv);
19637746SKelly.Moyer@Sun.COM 	(void) mutex_unlock(&cache_refresh_lock);
19647746SKelly.Moyer@Sun.COM 
19657746SKelly.Moyer@Sun.COM 	/* reap the thread */
19667746SKelly.Moyer@Sun.COM 	(void) thr_join(cache_refresh_thr_id, NULL, NULL);
19677746SKelly.Moyer@Sun.COM 
19687746SKelly.Moyer@Sun.COM 	/* finish cleanup... */
19697746SKelly.Moyer@Sun.COM 	(void) cond_destroy(&cache_refresh_cv);
19707746SKelly.Moyer@Sun.COM 	(void) mutex_destroy(&cache_refresh_lock);
19717746SKelly.Moyer@Sun.COM }
19727746SKelly.Moyer@Sun.COM 
19733941Svenki /*VARARGS2*/
19743941Svenki static void
19753941Svenki log_msg(int pri, const char *fmt, ...)
19763941Svenki {
19773941Svenki 	va_list ap;
19783941Svenki 
19793941Svenki 	va_start(ap, fmt);
19803941Svenki 	vsyslog(pri, fmt, ap);
19813941Svenki 	va_end(ap);
19823941Svenki }
19833941Svenki 
19843941Svenki #ifdef SNMPPLUGIN_DEBUG
19853941Svenki 
19863941Svenki static void
19873941Svenki snmpplugin_log_init(void)
19883941Svenki {
19893941Svenki 	(void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL);
19903941Svenki }
19913941Svenki 
19923941Svenki static void
19933941Svenki snmpplugin_log(const char *fmt, ...)
19943941Svenki {
19953941Svenki 	va_list	ap;
19963941Svenki 
19973941Svenki 	(void) mutex_lock(&snmpplugin_dbuf_lock);
19983941Svenki 
19993941Svenki 	va_start(ap, fmt);
20003941Svenki 	(void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap);
20013941Svenki 	snmpplugin_log_append();
20023941Svenki 	va_end(ap);
20033941Svenki 
20043941Svenki 	(void) mutex_unlock(&snmpplugin_dbuf_lock);
20053941Svenki }
20063941Svenki 
20073941Svenki static void
20083941Svenki snmpplugin_log_append(void)
20093941Svenki {
20103941Svenki 	int	len;
20113941Svenki 
20123941Svenki 	len = strlen(snmpplugin_lbuf);
20133941Svenki 
20143941Svenki 	if ((snmpplugin_dbuf_curp + len) >=
20153941Svenki 	    (snmpplugin_dbuf + snmpplugin_dbuf_sz)) {
20163941Svenki 		snmpplugin_dbuf_realloc();
20173941Svenki 		if (snmpplugin_dbuf == NULL) {
20183941Svenki 			return;
20193941Svenki 		}
20203941Svenki 	}
20213941Svenki 
20223941Svenki 	(void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf);
20233941Svenki 	snmpplugin_dbuf_curp += len;
20243941Svenki }
20253941Svenki 
20263941Svenki static void
20273941Svenki snmpplugin_dbuf_realloc(void)
20283941Svenki {
20293941Svenki 	char	*p;
20303941Svenki 	size_t	offset = 0;
20313941Svenki 	size_t	count;
20323941Svenki 
20333941Svenki 	count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ;
20343941Svenki 	if ((p = (char *)calloc(count, 1)) == NULL) {
20353941Svenki 		snmpplugin_dbuf_overflow++;
20363941Svenki 		snmpplugin_dbuf_curp = snmpplugin_dbuf;
20373941Svenki 		return;
20383941Svenki 	}
20393941Svenki 
20403941Svenki 	if (snmpplugin_dbuf) {
20413941Svenki 		offset = snmpplugin_dbuf_curp - snmpplugin_dbuf;
20423941Svenki 		(void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz);
20433941Svenki 		free(snmpplugin_dbuf);
20443941Svenki 	}
20453941Svenki 
20463941Svenki 	snmpplugin_dbuf = p;
20473941Svenki 	snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ;
20483941Svenki 
20493941Svenki 	snmpplugin_dbuf_curp = snmpplugin_dbuf + offset;
20503941Svenki }
20513941Svenki #endif
2052