10d63ce2bSvenki /*
20d63ce2bSvenki  * CDDL HEADER START
30d63ce2bSvenki  *
40d63ce2bSvenki  * The contents of this file are subject to the terms of the
50d63ce2bSvenki  * Common Development and Distribution License (the "License").
60d63ce2bSvenki  * You may not use this file except in compliance with the License.
70d63ce2bSvenki  *
80d63ce2bSvenki  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90d63ce2bSvenki  * or http://www.opensolaris.org/os/licensing.
100d63ce2bSvenki  * See the License for the specific language governing permissions
110d63ce2bSvenki  * and limitations under the License.
120d63ce2bSvenki  *
130d63ce2bSvenki  * When distributing Covered Code, include this CDDL HEADER in each
140d63ce2bSvenki  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150d63ce2bSvenki  * If applicable, add the following below this CDDL HEADER, with the
160d63ce2bSvenki  * fields enclosed by brackets "[]" replaced with your own identifying
170d63ce2bSvenki  * information: Portions Copyright [yyyy] [name of copyright owner]
180d63ce2bSvenki  *
190d63ce2bSvenki  * CDDL HEADER END
200d63ce2bSvenki  */
210d63ce2bSvenki 
220d63ce2bSvenki /*
2334f1a571SMichael Bergknoff  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240d63ce2bSvenki  * Use is subject to license terms.
250d63ce2bSvenki  */
260d63ce2bSvenki 
270d63ce2bSvenki /*
280d63ce2bSvenki  * The SNMP picl plugin connects to the agent on the SP and creates
290d63ce2bSvenki  * and populates the /physical-platform subtree in picl tree for use
300d63ce2bSvenki  * by picl consumers.
310d63ce2bSvenki  */
320d63ce2bSvenki 
330d63ce2bSvenki #include <stdio.h>
340d63ce2bSvenki #include <stdlib.h>
350d63ce2bSvenki #include <string.h>
360d63ce2bSvenki #include <syslog.h>
370d63ce2bSvenki #include <stdarg.h>
380d63ce2bSvenki #include <libgen.h>
390d63ce2bSvenki #include <libintl.h>
400d63ce2bSvenki #include <thread.h>
410d63ce2bSvenki #include <synch.h>
420d63ce2bSvenki #include <errno.h>
43817697f4SKelly Moyer #include <time.h>
4434f1a571SMichael Bergknoff #include <signal.h>
450d63ce2bSvenki 
460d63ce2bSvenki #include <picldefs.h>
470d63ce2bSvenki #include <picl.h>
480d63ce2bSvenki #include <picltree.h>
490d63ce2bSvenki 
500d63ce2bSvenki #include "picloids.h"
510d63ce2bSvenki #include "libpiclsnmp.h"
520d63ce2bSvenki #include "snmpplugin.h"
530d63ce2bSvenki 
540d63ce2bSvenki #pragma init(snmpplugin_register)	/* place in .init section */
550d63ce2bSvenki 
560d63ce2bSvenki picld_plugin_reg_t snmpplugin_reg = {
570d63ce2bSvenki 	PICLD_PLUGIN_VERSION_1,
580d63ce2bSvenki 	PICLD_PLUGIN_NON_CRITICAL,
590d63ce2bSvenki 	"snmp_plugin",
600d63ce2bSvenki 	snmpplugin_init,
610d63ce2bSvenki 	snmpplugin_fini
620d63ce2bSvenki };
630d63ce2bSvenki 
640d63ce2bSvenki static picl_snmphdl_t	hdl;
650d63ce2bSvenki 
660d63ce2bSvenki /*
670d63ce2bSvenki  * The stale_tree_rwlp protects the stale_xxx vars. The 'stale_tree' flag
680d63ce2bSvenki  * and the 'rebuild_tree' flag below are both initialized to B_TRUE to
690d63ce2bSvenki  * let the tree_builder() thread build the initial tree without blocking.
700d63ce2bSvenki  */
710d63ce2bSvenki static rwlock_t		stale_tree_rwlp;
720d63ce2bSvenki static boolean_t	stale_tree = B_TRUE;
730d63ce2bSvenki 
740d63ce2bSvenki /*
750d63ce2bSvenki  * vol_props, volprop_ndx and n_vol_props are protected by the stale_tree
760d63ce2bSvenki  * flag.  They are read only when the stale_tree flag is B_FALSE and written
770d63ce2bSvenki  * to only when the flag is B_TRUE.
780d63ce2bSvenki  *
790d63ce2bSvenki  * The change_time (last changed time) is read by only one thread at a
800d63ce2bSvenki  * time when stale_tree is B_FALSE (protected by stale_tree_rwlp).  It is
810d63ce2bSvenki  * written by only one thread (the tree builder) when stale_tree is B_TRUE.
820d63ce2bSvenki  *
830d63ce2bSvenki  * Note that strictly speaking, change_time should be uint_t (timeticks32).
840d63ce2bSvenki  * But keeping it as int is fine, since we don't do any arithmetic on it
850d63ce2bSvenki  * except equality check.
860d63ce2bSvenki  */
870d63ce2bSvenki static vol_prophdl_t	*vol_props = NULL;
880d63ce2bSvenki static int		volprop_ndx = 0, n_vol_props = 0;
890d63ce2bSvenki static int		change_time = 0;
901c60fca8Sfw static time_t		change_time_check;
910d63ce2bSvenki 
920d63ce2bSvenki /*
930d63ce2bSvenki  * The rebuild_tree_lock and cv are used by the tree builder thread.
940d63ce2bSvenki  * rebuild_tree has to be initialized to B_TRUE to let the tree_builder
950d63ce2bSvenki  * do the first build without blocking.
960d63ce2bSvenki  */
970d63ce2bSvenki static mutex_t		rebuild_tree_lock;
980d63ce2bSvenki static cond_t		rebuild_tree_cv;
990d63ce2bSvenki static boolean_t	rebuild_tree = B_TRUE;
100d2b9c676Sfw static boolean_t	tree_builder_thr_exit = B_FALSE;
101d2b9c676Sfw static thread_t		tree_builder_thr_id;
1020d63ce2bSvenki 
103817697f4SKelly Moyer /*
104817697f4SKelly Moyer  * The cache_refresh thread periodically queries the snmp cache refresh work
105817697f4SKelly Moyer  * queue and processes jobs from it to keep cache entries from expiring.  It
106817697f4SKelly Moyer  * attempts to run in cycles of CACHE_REFRESH_CYCLE seconds each, first
107817697f4SKelly Moyer  * processing cache refresh jobs and then sleeping for the remainder of the
108817697f4SKelly Moyer  * cycle once the next refresh job expiration is at least
109817697f4SKelly Moyer  * CACHE_REFRESH_MIN_WINDOW seconds in the future.
110817697f4SKelly Moyer  *
111817697f4SKelly Moyer  * NOTE: By using a thread to keep the SNMP cache refreshed in the background,
112817697f4SKelly Moyer  * we are both adding load to the system and reducing the system's ability to
113817697f4SKelly Moyer  * operate in power-saving mode when there is minimal load.  While these
114817697f4SKelly Moyer  * tradeoffs are acceptable at this time in light of customer concerns about
115817697f4SKelly Moyer  * performance, it may be desirable in the future to move this work into the
116817697f4SKelly Moyer  * firmware.  Also, while the current cycle times performed well on the largest
117817697f4SKelly Moyer  * sun4v config currently available (Batoka), they may need to be revisited for
118817697f4SKelly Moyer  * future systems if the number of sensors increases significantly.
119817697f4SKelly Moyer  */
120817697f4SKelly Moyer #define	CACHE_REFRESH_CYCLE		60
121817697f4SKelly Moyer #define	CACHE_REFRESH_MIN_WINDOW	75
122817697f4SKelly Moyer static mutex_t		cache_refresh_lock;
123817697f4SKelly Moyer static cond_t		cache_refresh_cv;
124817697f4SKelly Moyer static boolean_t	cache_refresh_thr_exit = B_FALSE;
125817697f4SKelly Moyer static thread_t		cache_refresh_thr_id;
126817697f4SKelly Moyer 
1270d63ce2bSvenki /*
1280d63ce2bSvenki  * These two should really not be global
1290d63ce2bSvenki  */
1300d63ce2bSvenki static picl_nodehdl_t	*physplat_nodes = NULL;
1310d63ce2bSvenki static int		n_physplat_nodes = 0;
1320d63ce2bSvenki 
1330d63ce2bSvenki static char *group1[] = {
1340d63ce2bSvenki 	OID_entPhysicalDescr,
1350d63ce2bSvenki 	OID_entPhysicalContainedIn,
1360d63ce2bSvenki 	OID_entPhysicalClass,
1370d63ce2bSvenki 	OID_entPhysicalName,
1380d63ce2bSvenki 	OID_entPhysicalHardwareRev,
1390d63ce2bSvenki 	OID_entPhysicalFirmwareRev,
1400d63ce2bSvenki 	OID_entPhysicalSerialNum,
1410d63ce2bSvenki 	OID_entPhysicalMfgName,
1420d63ce2bSvenki 	OID_entPhysicalModelName,
1430d63ce2bSvenki 	OID_entPhysicalIsFRU,
1440d63ce2bSvenki 	0
1450d63ce2bSvenki };
1460d63ce2bSvenki 
1470d63ce2bSvenki static char *group2[] = {
1480d63ce2bSvenki 	OID_sunPlatEquipmentHolderAcceptableTypes,
1490d63ce2bSvenki 	OID_sunPlatCircuitPackReplaceable,
1500d63ce2bSvenki 	OID_sunPlatCircuitPackHotSwappable,
1510d63ce2bSvenki 	OID_sunPlatPhysicalClass,
1520d63ce2bSvenki 	OID_sunPlatSensorClass,
1530d63ce2bSvenki 	OID_sunPlatSensorType,
1540d63ce2bSvenki 	OID_sunPlatAlarmType,
1550d63ce2bSvenki 	OID_sunPlatPowerSupplyClass,
1560d63ce2bSvenki 	0
1570d63ce2bSvenki };
1580d63ce2bSvenki 
1591c60fca8Sfw static char *group3[] = {
1601c60fca8Sfw 	OID_sunPlatNumericSensorEnabledThresholds,
1611c60fca8Sfw 	OID_sunPlatNumericSensorBaseUnits,
1621c60fca8Sfw 	OID_sunPlatNumericSensorRateUnits,
1631c60fca8Sfw 	0
1641c60fca8Sfw };
1651c60fca8Sfw 
1661c60fca8Sfw static char *group4[] = {
1671c60fca8Sfw 	OID_sunPlatBinarySensorInterpretTrue,
1681c60fca8Sfw 	OID_sunPlatBinarySensorInterpretFalse,
169c8268b2cSKelly Moyer 	0
1701c60fca8Sfw };
1711c60fca8Sfw 
1720d63ce2bSvenki static char *volgroup1[] = {
1730d63ce2bSvenki 	OID_sunPlatBinarySensorCurrent,
1740d63ce2bSvenki 	OID_sunPlatBinarySensorExpected,
1750d63ce2bSvenki 	0
1760d63ce2bSvenki };
1770d63ce2bSvenki 
1780d63ce2bSvenki static char *volgroup2[] = {
1790d63ce2bSvenki 	OID_sunPlatNumericSensorExponent,
1800d63ce2bSvenki 	OID_sunPlatNumericSensorCurrent,
1810d63ce2bSvenki 	OID_sunPlatNumericSensorLowerThresholdFatal,
1820d63ce2bSvenki 	OID_sunPlatNumericSensorLowerThresholdCritical,
1830d63ce2bSvenki 	OID_sunPlatNumericSensorLowerThresholdNonCritical,
1840d63ce2bSvenki 	OID_sunPlatNumericSensorUpperThresholdNonCritical,
1850d63ce2bSvenki 	OID_sunPlatNumericSensorUpperThresholdCritical,
1860d63ce2bSvenki 	OID_sunPlatNumericSensorUpperThresholdFatal,
1870d63ce2bSvenki 	0
1880d63ce2bSvenki };
1890d63ce2bSvenki 
1901c60fca8Sfw static char *volgroup3[] = {
1911c60fca8Sfw 	OID_sunPlatEquipmentOperationalState,
1921c60fca8Sfw 	0
1931c60fca8Sfw };
1941c60fca8Sfw 
1951c60fca8Sfw static char *volgroup4[] = {
1961c60fca8Sfw 	OID_sunPlatAlarmState,
1971c60fca8Sfw 	0
1981c60fca8Sfw };
1991c60fca8Sfw 
2001c60fca8Sfw static char *volgroup5[] = {
2011c60fca8Sfw 	OID_sunPlatBatteryStatus,
2021c60fca8Sfw 	0
2031c60fca8Sfw };
2041c60fca8Sfw 
2050d63ce2bSvenki /*
2060d63ce2bSvenki  * The following two items must match the Sun Platform MIB specification
2070d63ce2bSvenki  * in their indices and values.
2080d63ce2bSvenki  */
2090d63ce2bSvenki static char *sensor_baseunits[] = {
2100d63ce2bSvenki 	"", "other", "unknown", "degC", "degF", "degK", "volts", "amps",
2110d63ce2bSvenki 	"watts", "joules", "coulombs", "va", "nits", "lumens", "lux",
2120d63ce2bSvenki 	"candelas", "kPa", "psi", "newtons", "cfm", "rpm", "hertz",
2130d63ce2bSvenki 	"seconds", "minutes", "hours", "days", "weeks", "mils", "inches",
2140d63ce2bSvenki 	"feet", "cubicInches", "cubicFeet", "meters", "cubicCentimeters",
2150d63ce2bSvenki 	"cubicMeters", "liters", "fluidOunces", "radians", "steradians",
2160d63ce2bSvenki 	"revolutions", "cycles", "gravities", "ounces", "pounds", "footPounds",
2170d63ce2bSvenki 	"ounceInches", "gauss", "gilberts", "henries", "farads", "ohms",
2180d63ce2bSvenki 	"siemens", "moles", "becquerels", "ppm", "decibels", "dBA", "dbC",
2190d63ce2bSvenki 	"grays", "sieverts", "colorTemperatureDegK", "bits", "bytes", "words",
2200d63ce2bSvenki 	"doubleWords", "quadWords", "percentage"
2210d63ce2bSvenki };
2220d63ce2bSvenki static const int n_baseunits = sizeof (sensor_baseunits) / sizeof (char *);
2230d63ce2bSvenki 
2240d63ce2bSvenki static char *sensor_rateunits[] = {
2250d63ce2bSvenki 	"",
2260d63ce2bSvenki 	"none",
2270d63ce2bSvenki 	"perMicroSecond",
2280d63ce2bSvenki 	"perMilliSecond",
2290d63ce2bSvenki 	"perSecond",
2300d63ce2bSvenki 	"perMinute",
2310d63ce2bSvenki 	"perHour",
2320d63ce2bSvenki 	"perDay",
2330d63ce2bSvenki 	"perWeek",
2340d63ce2bSvenki 	"perMonth",
2350d63ce2bSvenki 	"perYear"
2360d63ce2bSvenki };
2370d63ce2bSvenki static const int n_rateunits = sizeof (sensor_rateunits) / sizeof (char *);
2380d63ce2bSvenki 
2390d63ce2bSvenki /*
2400d63ce2bSvenki  * Local declarations
2410d63ce2bSvenki  */
2420d63ce2bSvenki static void snmpplugin_register(void);
2430d63ce2bSvenki static void register_group(char **g, int is_volatile);
2440d63ce2bSvenki static void *tree_builder(void *arg);
2450d63ce2bSvenki static int build_physplat(picl_nodehdl_t *subtree_rootp);
2460d63ce2bSvenki static void free_resources(picl_nodehdl_t subtree_root);
2470d63ce2bSvenki 
2480d63ce2bSvenki static picl_nodehdl_t make_node(picl_nodehdl_t subtree_root, int row,
2490d63ce2bSvenki     int *snmp_syserr_p);
2500d63ce2bSvenki static void save_nodeh(picl_nodehdl_t nodeh, int row);
2510d63ce2bSvenki static picl_nodehdl_t lookup_nodeh(int row);
2520d63ce2bSvenki 
2530d63ce2bSvenki static void save_volprop(picl_prophdl_t prop, char *oidstr, int row,
2540d63ce2bSvenki     int proptype);
2551c60fca8Sfw static void check_for_stale_data(boolean_t nocache);
2560d63ce2bSvenki static int read_volprop(ptree_rarg_t *parg, void *buf);
2570d63ce2bSvenki 
2580d63ce2bSvenki static void threshold(picl_nodehdl_t node, char *oidstr, int row,
2590d63ce2bSvenki     char *propname, int *snmp_syserr_p);
2600d63ce2bSvenki static void add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p);
2610d63ce2bSvenki 
2620d63ce2bSvenki static char *get_slot_type(int row, int *snmp_syserr_p);
2630d63ce2bSvenki static int add_volatile_prop(picl_nodehdl_t nodeh, char *name,
2640d63ce2bSvenki     int type, int access, int size, int (*rdfunc)(ptree_rarg_t *, void *),
2650d63ce2bSvenki     int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp);
2660d63ce2bSvenki static int add_string_prop(picl_nodehdl_t node, char *propname, char *propval);
2670d63ce2bSvenki static int add_void_prop(picl_nodehdl_t node, char *propname);
2680d63ce2bSvenki static void add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
2690d63ce2bSvenki     int row, sp_propid_t pp, int *snmp_syserr_p);
2700d63ce2bSvenki 
271817697f4SKelly Moyer static void *cache_refresher(void *arg);
272817697f4SKelly Moyer static void cache_refresher_fini(void);
273817697f4SKelly Moyer 
2740d63ce2bSvenki static void log_msg(int pri, const char *fmt, ...);
2750d63ce2bSvenki 
2760d63ce2bSvenki #ifdef SNMPPLUGIN_DEBUG
2770d63ce2bSvenki static mutex_t	snmpplugin_dbuf_lock;
2780d63ce2bSvenki static char	*snmpplugin_dbuf = NULL;
2790d63ce2bSvenki static char	*snmpplugin_dbuf_curp = NULL;
2800d63ce2bSvenki static int	snmpplugin_dbuf_sz = 0;
2810d63ce2bSvenki static int	snmpplugin_dbuf_overflow = 0;
2820d63ce2bSvenki static char	snmpplugin_lbuf[SNMPPLUGIN_DMAX_LINE];
2830d63ce2bSvenki 
2840d63ce2bSvenki static void	snmpplugin_log_init(void);
2850d63ce2bSvenki static void	snmpplugin_log(const char *fmt, ...);
2860d63ce2bSvenki static void	snmpplugin_log_append(void);
2870d63ce2bSvenki static void	snmpplugin_dbuf_realloc(void);
2880d63ce2bSvenki #endif
2890d63ce2bSvenki 
2900d63ce2bSvenki static void
snmpplugin_register(void)2910d63ce2bSvenki snmpplugin_register(void)
2920d63ce2bSvenki {
2930d63ce2bSvenki 	(void) picld_plugin_register(&snmpplugin_reg);
2940d63ce2bSvenki }
2950d63ce2bSvenki 
2960d63ce2bSvenki static void
register_group(char ** g,int is_volatile)2970d63ce2bSvenki register_group(char **g, int is_volatile)
2980d63ce2bSvenki {
2990d63ce2bSvenki 	int	i, len = 0;
3000d63ce2bSvenki 	int	n_oids;
3010d63ce2bSvenki 	char	*p, *oidstrs;
3020d63ce2bSvenki 
3030d63ce2bSvenki 	for (i = 0; g[i]; i++)
3040d63ce2bSvenki 		len += strlen(g[i]) + 1;
3050d63ce2bSvenki 	n_oids = i;
3060d63ce2bSvenki 
3070d63ce2bSvenki 	if ((oidstrs = (char *)calloc(1, len)) == NULL)
3080d63ce2bSvenki 		return;
3090d63ce2bSvenki 
3100d63ce2bSvenki 	for (p = oidstrs, i = 0; g[i]; i++) {
3110d63ce2bSvenki 		(void) strcpy(p, g[i]);
3120d63ce2bSvenki 		p += strlen(g[i]) + 1;
3130d63ce2bSvenki 	}
3140d63ce2bSvenki 
3150d63ce2bSvenki 	snmp_register_group(hdl, oidstrs, n_oids, is_volatile);
3162ea390f3SMichael Bergknoff 	free(oidstrs);
3170d63ce2bSvenki }
3180d63ce2bSvenki 
3190d63ce2bSvenki void
snmpplugin_init(void)3200d63ce2bSvenki snmpplugin_init(void)
3210d63ce2bSvenki {
3220d63ce2bSvenki 	int		ret;
3230d63ce2bSvenki 
3240d63ce2bSvenki 	(void) mutex_init(&rebuild_tree_lock, USYNC_THREAD, NULL);
3250d63ce2bSvenki 	(void) cond_init(&rebuild_tree_cv, USYNC_THREAD, NULL);
3260d63ce2bSvenki 	(void) rwlock_init(&stale_tree_rwlp, USYNC_THREAD, NULL);
327d2b9c676Sfw 	tree_builder_thr_exit = B_FALSE;
328d2b9c676Sfw 
3290d63ce2bSvenki 	LOGINIT();
3300d63ce2bSvenki 
3310d63ce2bSvenki 	/*
3320d63ce2bSvenki 	 * Create the tree-builder thread and let it take over
3330d63ce2bSvenki 	 */
3340d63ce2bSvenki 	LOGPRINTF("Tree-builder thread being created.\n");
335*ada2da53SToomas Soome 	if ((ret = thr_create(NULL, 0, tree_builder, NULL,
336d2b9c676Sfw 	    THR_BOUND, &tree_builder_thr_id)) < 0) {
3370d63ce2bSvenki 		log_msg(LOG_ERR, SNMPP_CANT_CREATE_TREE_BUILDER, ret);
3380d63ce2bSvenki 		snmp_fini(hdl);
339d2b9c676Sfw 		hdl = NULL;
340d2b9c676Sfw 		(void) rwlock_destroy(&stale_tree_rwlp);
341d2b9c676Sfw 		(void) cond_destroy(&rebuild_tree_cv);
342d2b9c676Sfw 		(void) mutex_destroy(&rebuild_tree_lock);
343d2b9c676Sfw 		tree_builder_thr_exit = B_TRUE;
344817697f4SKelly Moyer 
345817697f4SKelly Moyer 		return;
346817697f4SKelly Moyer 	}
347817697f4SKelly Moyer 
348817697f4SKelly Moyer 	/*
349817697f4SKelly Moyer 	 * While the cache refresher thread does improve performance, it is not
350817697f4SKelly Moyer 	 * integral to the proper function of the plugin.  If we fail to create
351817697f4SKelly Moyer 	 * the thread for some reason, we will simply continue without
352817697f4SKelly Moyer 	 * refreshing.
353817697f4SKelly Moyer 	 */
354817697f4SKelly Moyer 	(void) mutex_init(&cache_refresh_lock, USYNC_THREAD, NULL);
355817697f4SKelly Moyer 	(void) cond_init(&cache_refresh_cv, USYNC_THREAD, NULL);
356817697f4SKelly Moyer 	cache_refresh_thr_exit = B_FALSE;
357817697f4SKelly Moyer 
358817697f4SKelly Moyer 	LOGPRINTF("Cache refresher thread being created.\n");
359*ada2da53SToomas Soome 	if (thr_create(NULL, 0, cache_refresher, NULL, THR_BOUND,
360817697f4SKelly Moyer 	    &cache_refresh_thr_id) < 0) {
361817697f4SKelly Moyer 		(void) cond_destroy(&cache_refresh_cv);
362817697f4SKelly Moyer 		(void) mutex_destroy(&cache_refresh_lock);
363817697f4SKelly Moyer 		cache_refresh_thr_exit = B_TRUE;
3640d63ce2bSvenki 	}
3650d63ce2bSvenki }
3660d63ce2bSvenki 
3670d63ce2bSvenki void
snmpplugin_fini(void)3680d63ce2bSvenki snmpplugin_fini(void)
3690d63ce2bSvenki {
3700d63ce2bSvenki 
371d2b9c676Sfw 	if (tree_builder_thr_exit == B_TRUE)
372d2b9c676Sfw 		return;
373d2b9c676Sfw 
374d2b9c676Sfw 	/*
375d2b9c676Sfw 	 * Make reads of volatile properties return PICL_PROPUNAVAILABLE
376d2b9c676Sfw 	 * since we're about to recycle the plug-in.  No need to worry
377d2b9c676Sfw 	 * about removing /physical-platform since tree_builder() will
378d2b9c676Sfw 	 * take care of recycling it for us.
379d2b9c676Sfw 	 */
380d2b9c676Sfw 	(void) rw_wrlock(&stale_tree_rwlp);
381d2b9c676Sfw 	stale_tree = B_TRUE;
382d2b9c676Sfw 	if (vol_props) {
383d2b9c676Sfw 		free(vol_props);
384d2b9c676Sfw 	}
385d2b9c676Sfw 	vol_props = NULL;
386d2b9c676Sfw 	volprop_ndx = 0;
387d2b9c676Sfw 	n_vol_props = 0;
388d2b9c676Sfw 	(void) rw_unlock(&stale_tree_rwlp);
389d2b9c676Sfw 
390817697f4SKelly Moyer 	/* clean up the cache_refresher thread and structures */
391817697f4SKelly Moyer 	cache_refresher_fini();
392817697f4SKelly Moyer 
393d2b9c676Sfw 	/* wake up the tree_builder thread, tell it to exit */
394d2b9c676Sfw 	(void) mutex_lock(&rebuild_tree_lock);
395d2b9c676Sfw 	rebuild_tree = B_TRUE;
396d2b9c676Sfw 	tree_builder_thr_exit = B_TRUE;
397dc6ca969Sfw 	(void) cond_signal(&rebuild_tree_cv);
398d2b9c676Sfw 	(void) mutex_unlock(&rebuild_tree_lock);
399d2b9c676Sfw 
40034f1a571SMichael Bergknoff 	/* send SIGUSR1 to get tree_builder out of a blocked system call */
40134f1a571SMichael Bergknoff 	(void) thr_kill(tree_builder_thr_id, SIGUSR1);
40234f1a571SMichael Bergknoff 
403d2b9c676Sfw 	/* reap the thread */
404d2b9c676Sfw 	(void) thr_join(tree_builder_thr_id, NULL, NULL);
405d2b9c676Sfw 
406d2b9c676Sfw 	/* close the channel */
407d2b9c676Sfw 	if (hdl != NULL) {
408d2b9c676Sfw 		snmp_fini(hdl);
409d2b9c676Sfw 		hdl = NULL;
410d2b9c676Sfw 	}
411d2b9c676Sfw 
412d2b9c676Sfw 	/* finish cleanup... */
4130d63ce2bSvenki 	(void) rwlock_destroy(&stale_tree_rwlp);
4140d63ce2bSvenki 	(void) cond_destroy(&rebuild_tree_cv);
4150d63ce2bSvenki 	(void) mutex_destroy(&rebuild_tree_lock);
4160d63ce2bSvenki }
4170d63ce2bSvenki 
41834f1a571SMichael Bergknoff /*ARGSUSED*/
41934f1a571SMichael Bergknoff static void
usr1_handler(int sig,siginfo_t * siginfo,void * sigctx)42034f1a571SMichael Bergknoff usr1_handler(int sig, siginfo_t *siginfo, void *sigctx)
42134f1a571SMichael Bergknoff {
42234f1a571SMichael Bergknoff 	/*
42334f1a571SMichael Bergknoff 	 * Nothing to do here.
42434f1a571SMichael Bergknoff 	 * The act of catching the signal causes any cond_wait() or blocked
42534f1a571SMichael Bergknoff 	 * system call to return EINTR. This is used to trigger early exit from
42634f1a571SMichael Bergknoff 	 * the tree builder thread which may be blocked in snmp_init. More work
42734f1a571SMichael Bergknoff 	 * would be required to allow early exit if the tree builder thread is
42834f1a571SMichael Bergknoff 	 * already in its main processing loop and not blocked in cond_wait.
42934f1a571SMichael Bergknoff 	 */
43034f1a571SMichael Bergknoff }
43134f1a571SMichael Bergknoff 
4320d63ce2bSvenki /*ARGSUSED*/
4330d63ce2bSvenki static void *
tree_builder(void * arg)4340d63ce2bSvenki tree_builder(void *arg)
4350d63ce2bSvenki {
4360d63ce2bSvenki 	int		ret, rv;
4370d63ce2bSvenki 	picl_nodehdl_t	root_node;
4380d63ce2bSvenki 	picl_nodehdl_t	physplat_root;
4390d63ce2bSvenki 	picl_nodehdl_t	old_physplat_root;
44034f1a571SMichael Bergknoff 	struct sigaction	act;
44134f1a571SMichael Bergknoff 
44234f1a571SMichael Bergknoff 	/*
44334f1a571SMichael Bergknoff 	 * catch SIGUSR1 to allow early exit from snmp_init which may block
44434f1a571SMichael Bergknoff 	 * indefinitely in a guest domain.
44534f1a571SMichael Bergknoff 	 */
44634f1a571SMichael Bergknoff 	act.sa_sigaction = usr1_handler;
44734f1a571SMichael Bergknoff 	(void) sigemptyset(&act.sa_mask);
44834f1a571SMichael Bergknoff 	act.sa_flags = 0;
44934f1a571SMichael Bergknoff 	if (sigaction(SIGUSR1, &act, NULL) == -1) {
45034f1a571SMichael Bergknoff 		syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGUSR1),
45134f1a571SMichael Bergknoff 		    strerror(errno));
45234f1a571SMichael Bergknoff 	}
4530d63ce2bSvenki 
4540d63ce2bSvenki 	/*
4550d63ce2bSvenki 	 * Initialize SNMP service
4560d63ce2bSvenki 	 */
4570d63ce2bSvenki 	LOGPRINTF("Initializing SNMP service.\n");
4580d63ce2bSvenki 	if ((hdl = snmp_init()) == NULL) {
4590d63ce2bSvenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT);
4600d63ce2bSvenki 		return ((void *)-1);
4610d63ce2bSvenki 	}
4620d63ce2bSvenki 
4630d63ce2bSvenki 	/*
4640d63ce2bSvenki 	 * Register OID groupings for BULKGET optimizations
4650d63ce2bSvenki 	 */
4660d63ce2bSvenki 	LOGPRINTF("Registering OID groups.\n");
4670d63ce2bSvenki 	register_group(group1, 0);
4680d63ce2bSvenki 	register_group(group2, 0);
4691c60fca8Sfw 	register_group(group3, 0);
4701c60fca8Sfw 	register_group(group4, 0);
4710d63ce2bSvenki 	register_group(volgroup1, 1);
4720d63ce2bSvenki 	register_group(volgroup2, 1);
4731c60fca8Sfw 	register_group(volgroup3, 1);
4741c60fca8Sfw 	register_group(volgroup4, 1);
4751c60fca8Sfw 	register_group(volgroup5, 1);
4760d63ce2bSvenki 
4770d63ce2bSvenki 	(void) mutex_lock(&rebuild_tree_lock);
4780d63ce2bSvenki 
4790d63ce2bSvenki 	for (;;) {
4800d63ce2bSvenki 		LOGPRINTF("tree_builder: check whether to rebuild subtree\n");
4810d63ce2bSvenki 		while (rebuild_tree == B_FALSE)
4820d63ce2bSvenki 			(void) cond_wait(&rebuild_tree_cv, &rebuild_tree_lock);
4830d63ce2bSvenki 
4840d63ce2bSvenki 		LOGPRINTF("tree_builder: woke up\n");
4850d63ce2bSvenki 
486d2b9c676Sfw 		if (tree_builder_thr_exit == B_TRUE) {
487d2b9c676Sfw 			(void) mutex_unlock(&rebuild_tree_lock);
488d2b9c676Sfw 			LOGPRINTF("tree_builder: time to exit\n");
489d2b9c676Sfw 			return (NULL);
490d2b9c676Sfw 		}
491d2b9c676Sfw 
492*ada2da53SToomas Soome 		old_physplat_root = 0;
493*ada2da53SToomas Soome 		physplat_root = 0;
4940d63ce2bSvenki 
4950d63ce2bSvenki 		LOGPRINTF("tree_builder: getting root node\n");
4960d63ce2bSvenki 		if ((ret = ptree_get_root(&root_node)) != PICL_SUCCESS) {
497d2b9c676Sfw 			(void) mutex_unlock(&rebuild_tree_lock);
4980d63ce2bSvenki 			log_msg(LOG_ERR, SNMPP_NO_ROOT, ret);
4990d63ce2bSvenki 			return ((void *)-2);
5000d63ce2bSvenki 		}
5010d63ce2bSvenki 
5020d63ce2bSvenki 		LOGPRINTF("tree_builder: getting existing physplat node\n");
5030d63ce2bSvenki 		rv = ptree_find_node(root_node, PICL_PROP_NAME,
5040d63ce2bSvenki 		    PICL_PTYPE_CHARSTRING, PICL_NODE_PHYSPLAT,
5050d63ce2bSvenki 		    sizeof (PICL_NODE_PHYSPLAT), &old_physplat_root);
5060d63ce2bSvenki 
5070d63ce2bSvenki 		LOGPRINTF("tree_builder: building physical-platform\n");
5080d63ce2bSvenki 		if ((ret = build_physplat(&physplat_root)) < 0) {
509d2b9c676Sfw 			(void) mutex_unlock(&rebuild_tree_lock);
5100d63ce2bSvenki 			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
511817697f4SKelly Moyer 			cache_refresher_fini();
5120d63ce2bSvenki 			snmp_fini(hdl);
513d2b9c676Sfw 			hdl = NULL;
5140d63ce2bSvenki 			return ((void *)-3);
5150d63ce2bSvenki 		}
5160d63ce2bSvenki 
517*ada2da53SToomas Soome 		if (rv == PICL_SUCCESS && old_physplat_root != 0) {
5180d63ce2bSvenki 			LOGPRINTF("tree_builder: destroying existing nodes\n");
5190d63ce2bSvenki 			ptree_delete_node(old_physplat_root);
5200d63ce2bSvenki 			ptree_destroy_node(old_physplat_root);
5210d63ce2bSvenki 		}
5220d63ce2bSvenki 
5230d63ce2bSvenki 		LOGPRINTF("tree_builder: attaching new subtree\n");
5240d63ce2bSvenki 		if ((ret = ptree_add_node(root_node, physplat_root)) < 0) {
525d2b9c676Sfw 			(void) mutex_unlock(&rebuild_tree_lock);
5260d63ce2bSvenki 			free_resources(physplat_root);
5270d63ce2bSvenki 			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
528817697f4SKelly Moyer 			cache_refresher_fini();
5290d63ce2bSvenki 			snmp_fini(hdl);
530d2b9c676Sfw 			hdl = NULL;
5310d63ce2bSvenki 			return ((void *)-4);
5320d63ce2bSvenki 		}
5330d63ce2bSvenki 
5340d63ce2bSvenki 		LOGPRINTF("tree_builder: setting stale_tree to FALSE\n");
5350d63ce2bSvenki 		(void) rw_wrlock(&stale_tree_rwlp);
5360d63ce2bSvenki 		stale_tree = B_FALSE;
5370d63ce2bSvenki 		(void) rw_unlock(&stale_tree_rwlp);
5380d63ce2bSvenki 
5390d63ce2bSvenki 		LOGPRINTF("tree_builder: setting rebuild_tree to FALSE\n");
5400d63ce2bSvenki 		rebuild_tree = B_FALSE;
5410d63ce2bSvenki 	}
5420d63ce2bSvenki 
5430d63ce2bSvenki 	/*NOTREACHED*/
5440d63ce2bSvenki 	return (NULL);
5450d63ce2bSvenki }
5460d63ce2bSvenki 
5470d63ce2bSvenki static int
build_physplat(picl_nodehdl_t * subtree_rootp)5480d63ce2bSvenki build_physplat(picl_nodehdl_t *subtree_rootp)
5490d63ce2bSvenki {
5500d63ce2bSvenki 	int	change_time1;
5510d63ce2bSvenki 	int	row, nxtrow;
5520d63ce2bSvenki 	int	clr_linkreset = 0;
5530d63ce2bSvenki 	int	ret = 0;
5540d63ce2bSvenki 	int	snmp_syserr = 0;
5550d63ce2bSvenki 
5560d63ce2bSvenki retry:
5570d63ce2bSvenki 	(void) snmp_reinit(hdl, clr_linkreset);
5580d63ce2bSvenki 	clr_linkreset = 0;
5590d63ce2bSvenki 
5600d63ce2bSvenki 	/*
5610d63ce2bSvenki 	 * Record LastChangeTime before we start building the tree
5620d63ce2bSvenki 	 */
5630d63ce2bSvenki 	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
5640d63ce2bSvenki 	    &change_time1, &snmp_syserr);
5650d63ce2bSvenki 	if (ret < 0) {
5660d63ce2bSvenki 		if (snmp_syserr == ECANCELED) {
567806db1d7Sfw 			LOGPRINTF(SNMPP_LINK_RESET);
5680d63ce2bSvenki 			clr_linkreset = 1;
5690d63ce2bSvenki 			goto retry;
5701c60fca8Sfw 		}
5711c60fca8Sfw 		log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
5721c60fca8Sfw 		    snmp_syserr ? snmp_syserr : ret, OID_entLastChangeTime, 0);
5730d63ce2bSvenki 	}
5740d63ce2bSvenki 
5750d63ce2bSvenki 	/*
5760d63ce2bSvenki 	 * Create the physical-platform node
5770d63ce2bSvenki 	 */
5780d63ce2bSvenki 	ret = ptree_create_node(PICL_NODE_PHYSPLAT, PICL_CLASS_PICL,
5790d63ce2bSvenki 	    subtree_rootp);
5800d63ce2bSvenki 	if (ret != PICL_SUCCESS)
5810d63ce2bSvenki 		return (-1);
5820d63ce2bSvenki 
5830d63ce2bSvenki 	/*
5840d63ce2bSvenki 	 * Scan entPhysicalTable and build the "physical-platform" subtree
5850d63ce2bSvenki 	 */
5860d63ce2bSvenki 	ret = 0;
5870d63ce2bSvenki 	for (row = -1; ret == 0; row = nxtrow) {
5880d63ce2bSvenki 		ret = snmp_get_nextrow(hdl, OID_entPhysicalDescr,
5890d63ce2bSvenki 		    row, &nxtrow, &snmp_syserr);
590a1c54725Sfw 		if (ret == 0)
5910d63ce2bSvenki 			(void) make_node(*subtree_rootp, nxtrow, &snmp_syserr);
592a1c54725Sfw 		switch (snmp_syserr) {
593a1c54725Sfw 		case ECANCELED:
5940d63ce2bSvenki 			/*
5950d63ce2bSvenki 			 * If we get this error, a link reset must've
5960d63ce2bSvenki 			 * happened and we need to throw away everything
5970d63ce2bSvenki 			 * we have now and rebuild the tree again.
5980d63ce2bSvenki 			 */
5990d63ce2bSvenki 			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
6000d63ce2bSvenki 			free_resources(*subtree_rootp);
6010d63ce2bSvenki 			clr_linkreset = 1;
6020d63ce2bSvenki 			goto retry;
603a1c54725Sfw 			/*NOTREACHED*/
604a1c54725Sfw 			break;
605a1c54725Sfw 		case ENOSPC:	/* end of MIB */
606a1c54725Sfw 			LOGPRINTF("build_physplat: end of MIB\n");
607a1c54725Sfw 			break;
608a1c54725Sfw 		case ENOENT:	/* end of table */
609a1c54725Sfw 			LOGPRINTF("build_physplat: end of table\n");
610a1c54725Sfw 			break;
611a1c54725Sfw 		default:
612a1c54725Sfw 			/*
613a1c54725Sfw 			 * make_node() will print messages so don't
614a1c54725Sfw 			 * repeat that exercise here.
615a1c54725Sfw 			 */
616a1c54725Sfw 			if (ret == -1) {
617a1c54725Sfw 				log_msg(LOG_WARNING,
618a1c54725Sfw 				    SNMPP_CANT_FETCH_OBJECT_VAL,
619a1c54725Sfw 				    snmp_syserr ? snmp_syserr : ret,
620a1c54725Sfw 				    OID_entPhysicalDescr, row);
621a1c54725Sfw 			}
6220d63ce2bSvenki 		}
6230d63ce2bSvenki 	}
6240d63ce2bSvenki 
6250d63ce2bSvenki 	/*
6260d63ce2bSvenki 	 * Record LastChangeTime after we're done building the tree
6270d63ce2bSvenki 	 */
6280d63ce2bSvenki 	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
6290d63ce2bSvenki 	    &change_time, &snmp_syserr);
6300d63ce2bSvenki 	if (ret < 0) {
6310d63ce2bSvenki 		if (snmp_syserr == ECANCELED) {
6320d63ce2bSvenki 			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
6330d63ce2bSvenki 			free_resources(*subtree_rootp);
6340d63ce2bSvenki 			clr_linkreset = 1;
6350d63ce2bSvenki 			goto retry;
6360d63ce2bSvenki 		} else
6371c60fca8Sfw 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
6381c60fca8Sfw 			    snmp_syserr ? snmp_syserr : ret,
6391c60fca8Sfw 			    OID_entLastChangeTime, row);
6400d63ce2bSvenki 	}
6410d63ce2bSvenki 
6420d63ce2bSvenki 	/*
6430d63ce2bSvenki 	 * If they don't match, some hotplugging must've happened,
6440d63ce2bSvenki 	 * free resources we've created and still holding, then go
6450d63ce2bSvenki 	 * back and retry
6460d63ce2bSvenki 	 */
6470d63ce2bSvenki 	if (change_time != change_time1) {
6480d63ce2bSvenki 		LOGPRINTF("build_physplat: entLastChangeTime has changed!\n");
6490d63ce2bSvenki 		free_resources(*subtree_rootp);
6500d63ce2bSvenki 		change_time1 = change_time;
6510d63ce2bSvenki 		goto retry;
6520d63ce2bSvenki 	}
6530d63ce2bSvenki 
6540d63ce2bSvenki 	/*
6550d63ce2bSvenki 	 * The physplat_nodes table is no longer needed, free it
6560d63ce2bSvenki 	 */
6570d63ce2bSvenki 	if (physplat_nodes) {
6580d63ce2bSvenki 		free(physplat_nodes);
6590d63ce2bSvenki 		physplat_nodes = NULL;
6600d63ce2bSvenki 		n_physplat_nodes = 0;
6610d63ce2bSvenki 	}
6620d63ce2bSvenki 
6630d63ce2bSvenki 	return (0);
6640d63ce2bSvenki }
6650d63ce2bSvenki 
6660d63ce2bSvenki /*
6670d63ce2bSvenki  * Destroy all resources that were created during the building
6680d63ce2bSvenki  * of the subtree
6690d63ce2bSvenki  */
6700d63ce2bSvenki static void
free_resources(picl_nodehdl_t subtree_root)6710d63ce2bSvenki free_resources(picl_nodehdl_t subtree_root)
6720d63ce2bSvenki {
6730d63ce2bSvenki 	if (physplat_nodes) {
6740d63ce2bSvenki 		free(physplat_nodes);
6750d63ce2bSvenki 		physplat_nodes = NULL;
6760d63ce2bSvenki 		n_physplat_nodes = 0;
6770d63ce2bSvenki 	}
6780d63ce2bSvenki 
6790d63ce2bSvenki 	if (subtree_root) {
6800d63ce2bSvenki 		(void) ptree_delete_node(subtree_root);
6810d63ce2bSvenki 		(void) ptree_destroy_node(subtree_root);
6820d63ce2bSvenki 	}
6830d63ce2bSvenki 
6840d63ce2bSvenki 	if (vol_props) {
6850d63ce2bSvenki 		free(vol_props);
6865413ab1bSMichael Bergknoff 		vol_props = NULL;
6870d63ce2bSvenki 		n_vol_props = 0;
6880d63ce2bSvenki 		volprop_ndx = 0;
6890d63ce2bSvenki 	}
6900d63ce2bSvenki }
6910d63ce2bSvenki 
6920d63ce2bSvenki static picl_nodehdl_t
make_node(picl_nodehdl_t subtree_root,int row,int * snmp_syserr_p)6930d63ce2bSvenki make_node(picl_nodehdl_t subtree_root, int row, int *snmp_syserr_p)
6940d63ce2bSvenki {
6950d63ce2bSvenki 	picl_nodehdl_t	nodeh, parenth;
6960d63ce2bSvenki 	picl_prophdl_t	proph;
6970d63ce2bSvenki 	char	*phys_name, *node_name;
6980d63ce2bSvenki 	int	parent_row;
6990d63ce2bSvenki 	int	ent_physclass, sunplat_physclass;
7000d63ce2bSvenki 	int	sensor_class, sensor_type;
7010d63ce2bSvenki 	int	alarm_type;
7020d63ce2bSvenki 	int	ps_class;
7030d63ce2bSvenki 	int	ret;
7040d63ce2bSvenki 
7050d63ce2bSvenki 	/*
7060d63ce2bSvenki 	 * If we've already created this picl node, just return it
7070d63ce2bSvenki 	 */
708*ada2da53SToomas Soome 	if ((nodeh = lookup_nodeh(row)) != 0)
7090d63ce2bSvenki 		return (nodeh);
7100d63ce2bSvenki 
7110d63ce2bSvenki 	/*
7120d63ce2bSvenki 	 * If we are creating it only now, make sure we have the parent
7130d63ce2bSvenki 	 * created first; if there's no parent, then parent it to the
7140d63ce2bSvenki 	 * subtree's root node
7150d63ce2bSvenki 	 */
7160d63ce2bSvenki 	ret = snmp_get_int(hdl, OID_entPhysicalContainedIn, row,
7170d63ce2bSvenki 	    &parent_row, snmp_syserr_p);
718*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
7190d63ce2bSvenki 	if (ret < 0 || parent_row <= 0)
7200d63ce2bSvenki 		parenth = subtree_root;
7210d63ce2bSvenki 	else {
7220d63ce2bSvenki 		parenth = make_node(subtree_root, parent_row, snmp_syserr_p);
723*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
724*ada2da53SToomas Soome 		if (parenth == 0)
7250d63ce2bSvenki 			parenth = subtree_root;
7260d63ce2bSvenki 	}
7270d63ce2bSvenki 
7280d63ce2bSvenki 	/*
7290d63ce2bSvenki 	 * Figure out the physical-platform node name from entPhysicalName;
7300d63ce2bSvenki 	 * all rows in the MIB that have a valid entPhysicalIndex should
7310d63ce2bSvenki 	 * have a physical name.
7320d63ce2bSvenki 	 */
7330d63ce2bSvenki 	ret = snmp_get_str(hdl, OID_entPhysicalName, row,
7340d63ce2bSvenki 	    &phys_name, snmp_syserr_p);
735*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
7360d63ce2bSvenki 	if (ret < 0 || phys_name == NULL) {
7370d63ce2bSvenki 		log_msg(LOG_WARNING, SNMPP_NO_ENTPHYSNAME, row);
738*ada2da53SToomas Soome 		return (0);
7390d63ce2bSvenki 	}
7400d63ce2bSvenki 
7410d63ce2bSvenki 	node_name = basename(phys_name);
7420d63ce2bSvenki 
7430d63ce2bSvenki 	ret = snmp_get_int(hdl, OID_entPhysicalClass, row,
7440d63ce2bSvenki 	    &ent_physclass, snmp_syserr_p);
745*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
7460d63ce2bSvenki 	if (ret < 0) {
7471c60fca8Sfw 		log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
7481c60fca8Sfw 		    *snmp_syserr_p ? *snmp_syserr_p : ret,
7491c60fca8Sfw 		    OID_entPhysicalClass, row);
7500d63ce2bSvenki 		free(phys_name);
751*ada2da53SToomas Soome 		return (0);
7520d63ce2bSvenki 	}
7530d63ce2bSvenki 
7540d63ce2bSvenki 	switch (ent_physclass) {
7550d63ce2bSvenki 	case SPC_OTHER:
7560d63ce2bSvenki 		ret = snmp_get_int(hdl, OID_sunPlatPhysicalClass, row,
7570d63ce2bSvenki 		    &sunplat_physclass, snmp_syserr_p);
758*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
7590d63ce2bSvenki 		if (ret < 0) {
7601c60fca8Sfw 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
7611c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
7621c60fca8Sfw 			    OID_sunPlatPhysicalClass, row);
7630d63ce2bSvenki 			free(phys_name);
764*ada2da53SToomas Soome 			return (0);
7650d63ce2bSvenki 		}
7660d63ce2bSvenki 
7670d63ce2bSvenki 		if (sunplat_physclass == SSPC_ALARM) {
7680d63ce2bSvenki 			ret = snmp_get_int(hdl, OID_sunPlatAlarmType,
7690d63ce2bSvenki 			    row, &alarm_type, snmp_syserr_p);
770*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
7710d63ce2bSvenki 			if (ret < 0) {
7720d63ce2bSvenki 				log_msg(LOG_WARNING,
7731c60fca8Sfw 				    SNMPP_CANT_FETCH_OBJECT_VAL,
7741c60fca8Sfw 				    *snmp_syserr_p ? *snmp_syserr_p : ret,
7751c60fca8Sfw 				    OID_sunPlatAlarmType, row);
7760d63ce2bSvenki 				free(phys_name);
777*ada2da53SToomas Soome 				return (0);
7780d63ce2bSvenki 			}
7790d63ce2bSvenki 
7800d63ce2bSvenki 			if (alarm_type == SSAT_VISIBLE) {
781aaba19e2Sfw 				ADD_NODE(PICL_CLASS_LED)
7820d63ce2bSvenki 			} else {
783aaba19e2Sfw 				ADD_NODE(PICL_CLASS_ALARM)
7840d63ce2bSvenki 			}
7850d63ce2bSvenki 
7860d63ce2bSvenki 			add_prop(nodeh, &proph, node_name, row, PP_STATE,
7870d63ce2bSvenki 			    snmp_syserr_p);
788*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
7890d63ce2bSvenki 		} else {
7900d63ce2bSvenki 			ADD_NODE(PICL_CLASS_OTHER)
7910d63ce2bSvenki 		}
7920d63ce2bSvenki 
7930d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
7940d63ce2bSvenki 		    snmp_syserr_p);
795*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
7960d63ce2bSvenki 		break;
7970d63ce2bSvenki 
7980d63ce2bSvenki 	case SPC_UNKNOWN:
7990d63ce2bSvenki 		ADD_NODE(PICL_CLASS_UNKNOWN)
8000d63ce2bSvenki 		break;
8010d63ce2bSvenki 
8020d63ce2bSvenki 	case SPC_CHASSIS:
8030d63ce2bSvenki 		ADD_NODE(PICL_CLASS_CHASSIS)
8040d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8050d63ce2bSvenki 		    snmp_syserr_p);
806*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
8070d63ce2bSvenki 		break;
8080d63ce2bSvenki 
8090d63ce2bSvenki 	case SPC_BACKPLANE:
8100d63ce2bSvenki 		ADD_NODE(PICL_CLASS_BACKPLANE)
8110d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8120d63ce2bSvenki 		    snmp_syserr_p);
813*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
8140d63ce2bSvenki 		break;
8150d63ce2bSvenki 
8160d63ce2bSvenki 	case SPC_CONTAINER:
8170d63ce2bSvenki 		ADD_NODE(PICL_CLASS_CONTAINER)
8180d63ce2bSvenki 
8190d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8200d63ce2bSvenki 		    snmp_syserr_p);
821*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
8220d63ce2bSvenki 
8230d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_SLOT_TYPE,
8240d63ce2bSvenki 		    snmp_syserr_p);
825*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
8260d63ce2bSvenki 		break;
8270d63ce2bSvenki 
8280d63ce2bSvenki 	case SPC_POWERSUPPLY:
8290d63ce2bSvenki 		ret = snmp_get_int(hdl, OID_sunPlatPowerSupplyClass,
8300d63ce2bSvenki 		    row, &ps_class, snmp_syserr_p);
831*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
8320d63ce2bSvenki 		if (ret < 0) {
8331c60fca8Sfw 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
8341c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
8351c60fca8Sfw 			    OID_sunPlatPowerSupplyClass, row);
8360d63ce2bSvenki 			free(phys_name);
837*ada2da53SToomas Soome 			return (0);
8380d63ce2bSvenki 		}
8390d63ce2bSvenki 
8400d63ce2bSvenki 		if (ps_class == SSPSC_BATTERY) {
8410d63ce2bSvenki 			ADD_NODE(PICL_CLASS_BATTERY)
8420d63ce2bSvenki 			add_prop(nodeh, &proph, node_name, row,
8430d63ce2bSvenki 			    PP_BATT_STATUS, snmp_syserr_p);
844*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
8450d63ce2bSvenki 		} else {
8460d63ce2bSvenki 			ADD_NODE(PICL_CLASS_POWERSUPPLY)
8470d63ce2bSvenki 		}
8480d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8490d63ce2bSvenki 		    snmp_syserr_p);
850*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
8510d63ce2bSvenki 		break;
8520d63ce2bSvenki 
8530d63ce2bSvenki 	case SPC_FAN:
8540d63ce2bSvenki 		ADD_NODE(PICL_CLASS_FAN)
8550d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8560d63ce2bSvenki 		    snmp_syserr_p);
857*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
8580d63ce2bSvenki 		break;
8590d63ce2bSvenki 
8600d63ce2bSvenki 	case SPC_SENSOR:
8610d63ce2bSvenki 		ret = snmp_get_int(hdl, OID_sunPlatSensorClass,
8620d63ce2bSvenki 		    row, &sensor_class, snmp_syserr_p);
863*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
8640d63ce2bSvenki 		if (ret < 0) {
8651c60fca8Sfw 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
8661c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
8671c60fca8Sfw 			    OID_sunPlatSensorClass, row);
8680d63ce2bSvenki 			free(phys_name);
869*ada2da53SToomas Soome 			return (0);
8700d63ce2bSvenki 		}
8710d63ce2bSvenki 
8720d63ce2bSvenki 		ret = snmp_get_int(hdl, OID_sunPlatSensorType,
8730d63ce2bSvenki 		    row, &sensor_type, snmp_syserr_p);
874*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
8750d63ce2bSvenki 		if (ret < 0) {
8761c60fca8Sfw 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
8771c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
8781c60fca8Sfw 			    OID_sunPlatSensorType, row);
8790d63ce2bSvenki 			free(phys_name);
880*ada2da53SToomas Soome 			return (0);
8810d63ce2bSvenki 		}
8820d63ce2bSvenki 
8830d63ce2bSvenki 		if (sensor_class == SSSC_NUMERIC) {
8840d63ce2bSvenki 			if (sensor_type == SSST_TEMPERATURE) {
8850d63ce2bSvenki 				ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR)
8860d63ce2bSvenki 				add_prop(nodeh, &proph, node_name, row,
8870d63ce2bSvenki 				    PP_TEMPERATURE, snmp_syserr_p);
8880d63ce2bSvenki 			} else if (sensor_type == SSST_VOLTAGE) {
8890d63ce2bSvenki 				ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR)
8900d63ce2bSvenki 				add_prop(nodeh, &proph, node_name, row,
8910d63ce2bSvenki 				    PP_VOLTAGE, snmp_syserr_p);
8920d63ce2bSvenki 			} else if (sensor_type == SSST_CURRENT) {
8930d63ce2bSvenki 				ADD_NODE(PICL_CLASS_CURRENT_SENSOR)
8940d63ce2bSvenki 				add_prop(nodeh, &proph, node_name, row,
8950d63ce2bSvenki 				    PP_CURRENT, snmp_syserr_p);
8960d63ce2bSvenki 			} else if (sensor_type == SSST_TACHOMETER) {
8970d63ce2bSvenki 				ADD_NODE(PICL_CLASS_RPM_SENSOR)
8980d63ce2bSvenki 				add_prop(nodeh, &proph, node_name, row,
8990d63ce2bSvenki 				    PP_SPEED, snmp_syserr_p);
9000d63ce2bSvenki 			} else {
9010d63ce2bSvenki 				ADD_NODE(PICL_CLASS_SENSOR)
9020d63ce2bSvenki 				add_prop(nodeh, &proph, node_name, row,
9030d63ce2bSvenki 				    PP_SENSOR_VALUE, snmp_syserr_p);
9040d63ce2bSvenki 			}
905*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
9060d63ce2bSvenki 
9070d63ce2bSvenki 			add_prop(nodeh, &proph, node_name, row,
9080d63ce2bSvenki 			    PP_OPSTATUS, snmp_syserr_p);
909*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
9100d63ce2bSvenki 
9110d63ce2bSvenki 			add_prop(nodeh, &proph, node_name, row,
9120d63ce2bSvenki 			    PP_BASE_UNITS, snmp_syserr_p);
913*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
9140d63ce2bSvenki 
9150d63ce2bSvenki 			add_prop(nodeh, &proph, node_name, row,
9160d63ce2bSvenki 			    PP_EXPONENT, snmp_syserr_p);
917*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
9180d63ce2bSvenki 
9190d63ce2bSvenki 			add_prop(nodeh, &proph, node_name, row,
9200d63ce2bSvenki 			    PP_RATE_UNITS, snmp_syserr_p);
921*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
9220d63ce2bSvenki 
9230d63ce2bSvenki 			add_thresholds(nodeh, row, snmp_syserr_p);
924*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
9250d63ce2bSvenki 
9260d63ce2bSvenki 		} else if (sensor_class == SSSC_BINARY) {
9270d63ce2bSvenki 			if (sensor_type == SSST_TEMPERATURE) {
9280d63ce2bSvenki 				ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR)
9290d63ce2bSvenki 			} else if (sensor_type == SSST_VOLTAGE) {
9300d63ce2bSvenki 				ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR)
9310d63ce2bSvenki 			} else if (sensor_type == SSST_CURRENT) {
9320d63ce2bSvenki 				ADD_NODE(PICL_CLASS_CURRENT_INDICATOR)
9330d63ce2bSvenki 			} else if (sensor_type == SSST_TACHOMETER) {
9340d63ce2bSvenki 				ADD_NODE(PICL_CLASS_RPM_INDICATOR)
9350d63ce2bSvenki 			} else if (sensor_type == SSST_PRESENCE) {
9360d63ce2bSvenki 				ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR)
9370d63ce2bSvenki 			} else {
9380d63ce2bSvenki 				ADD_NODE(PICL_CLASS_INDICATOR)
9390d63ce2bSvenki 			}
9400d63ce2bSvenki 
9410d63ce2bSvenki 			add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
9420d63ce2bSvenki 			    snmp_syserr_p);
943*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
9440d63ce2bSvenki 
9450d63ce2bSvenki 			add_prop(nodeh, &proph, node_name, row, PP_CONDITION,
9460d63ce2bSvenki 			    snmp_syserr_p);
947*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
9480d63ce2bSvenki 
9490d63ce2bSvenki 			add_prop(nodeh, &proph, node_name, row, PP_EXPECTED,
9500d63ce2bSvenki 			    snmp_syserr_p);
951*ada2da53SToomas Soome 			CHECK_LINKRESET(snmp_syserr_p, 0)
9520d63ce2bSvenki 		} else {
9530d63ce2bSvenki 			log_msg(LOG_ERR,
9540d63ce2bSvenki 			    SNMPP_UNSUPP_SENSOR_CLASS, sensor_class, row);
955*ada2da53SToomas Soome 			return (0);
9560d63ce2bSvenki 		}
9570d63ce2bSvenki 		break;
9580d63ce2bSvenki 
9590d63ce2bSvenki 	case SPC_MODULE:
9600d63ce2bSvenki 		ADD_NODE(PICL_CLASS_MODULE)
9610d63ce2bSvenki 
9620d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
9630d63ce2bSvenki 		    snmp_syserr_p);
964*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
9650d63ce2bSvenki 
9660d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_REPLACEABLE,
9670d63ce2bSvenki 		    snmp_syserr_p);
968*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
9690d63ce2bSvenki 
9700d63ce2bSvenki 		add_prop(nodeh, &proph, node_name, row, PP_HOTSWAPPABLE,
9710d63ce2bSvenki 		    snmp_syserr_p);
972*ada2da53SToomas Soome 		CHECK_LINKRESET(snmp_syserr_p, 0)
9730d63ce2bSvenki 		break;
9740d63ce2bSvenki 
9750d63ce2bSvenki 	case SPC_PORT:
9760d63ce2bSvenki 		ADD_NODE(PICL_CLASS_PORT)
9770d63ce2bSvenki 		break;
9780d63ce2bSvenki 
9790d63ce2bSvenki 	case SPC_STACK:
9800d63ce2bSvenki 		ADD_NODE(PICL_CLASS_STACK)
9810d63ce2bSvenki 		break;
9820d63ce2bSvenki 
9830d63ce2bSvenki 	default:
9840d63ce2bSvenki 		log_msg(LOG_WARNING,
9850d63ce2bSvenki 		    SNMPP_UNKNOWN_ENTPHYSCLASS, ent_physclass, row);
9860d63ce2bSvenki 		free(phys_name);
987*ada2da53SToomas Soome 		return (0);
9880d63ce2bSvenki 	}
9890d63ce2bSvenki 
9900d63ce2bSvenki 	add_prop(nodeh, &proph, node_name, row, PP_DESCRIPTION, snmp_syserr_p);
991*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
9920d63ce2bSvenki 
9930d63ce2bSvenki 	add_prop(nodeh, &proph, node_name, row, PP_LABEL, snmp_syserr_p);
994*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
9950d63ce2bSvenki 
9960d63ce2bSvenki 	add_prop(nodeh, &proph, node_name, row, PP_HW_REVISION, snmp_syserr_p);
997*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
9980d63ce2bSvenki 
9990d63ce2bSvenki 	add_prop(nodeh, &proph, node_name, row, PP_FW_REVISION, snmp_syserr_p);
1000*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
10010d63ce2bSvenki 
10020d63ce2bSvenki 	add_prop(nodeh, &proph, node_name, row, PP_SERIAL_NUM, snmp_syserr_p);
1003*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
10040d63ce2bSvenki 
10050d63ce2bSvenki 	add_prop(nodeh, &proph, node_name, row, PP_MFG_NAME, snmp_syserr_p);
1006*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
10070d63ce2bSvenki 
10080d63ce2bSvenki 	add_prop(nodeh, &proph, node_name, row, PP_MODEL_NAME, snmp_syserr_p);
1009*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
10100d63ce2bSvenki 
10110d63ce2bSvenki 	add_prop(nodeh, &proph, node_name, row, PP_IS_FRU, snmp_syserr_p);
1012*ada2da53SToomas Soome 	CHECK_LINKRESET(snmp_syserr_p, 0)
10130d63ce2bSvenki 
10140d63ce2bSvenki 	free(phys_name);
10150d63ce2bSvenki 	save_nodeh(nodeh, row);
10160d63ce2bSvenki 
10170d63ce2bSvenki 	return (nodeh);
10180d63ce2bSvenki }
10190d63ce2bSvenki 
10200d63ce2bSvenki /*
10210d63ce2bSvenki  * Saves the node handle and the row id into physplat_nodes[]. If we're
10220d63ce2bSvenki  * doing this in response to a hotplug event, we should've freed the
10230d63ce2bSvenki  * old physplat_nodes before entering here to save the first node of the
10240d63ce2bSvenki  * new physplat subtree.
10250d63ce2bSvenki  */
10260d63ce2bSvenki static void
save_nodeh(picl_nodehdl_t nodeh,int row)10270d63ce2bSvenki save_nodeh(picl_nodehdl_t nodeh, int row)
10280d63ce2bSvenki {
10290d63ce2bSvenki 	size_t		sz, count;
10300d63ce2bSvenki 	picl_nodehdl_t	*p;
10310d63ce2bSvenki 
10320d63ce2bSvenki 	if (row >= n_physplat_nodes) {
10330d63ce2bSvenki 		count = (((size_t)row >> NODE_BLOCK_SHIFT) + 1) *
10340d63ce2bSvenki 		    N_ELEMS_IN_NODE_BLOCK;
10350d63ce2bSvenki 		sz = count * sizeof (picl_nodehdl_t);
10360d63ce2bSvenki 
10370d63ce2bSvenki 		p = (picl_nodehdl_t *)calloc(count, sizeof (picl_nodehdl_t));
10380d63ce2bSvenki 		if (p == NULL) {
10390d63ce2bSvenki 			log_msg(LOG_ERR, SNMPP_NO_MEM, sz);
10400d63ce2bSvenki 			return;
10410d63ce2bSvenki 		}
10420d63ce2bSvenki 
10430d63ce2bSvenki 		if (physplat_nodes) {
10440d63ce2bSvenki 			(void) memcpy((void *) p, (void *) physplat_nodes,
10450d63ce2bSvenki 			    n_physplat_nodes * sizeof (picl_nodehdl_t));
10460d63ce2bSvenki 			free((void *) physplat_nodes);
10470d63ce2bSvenki 		}
10480d63ce2bSvenki 
10490d63ce2bSvenki 		physplat_nodes = p;
10500d63ce2bSvenki 		n_physplat_nodes = count;
10510d63ce2bSvenki 	}
10520d63ce2bSvenki 
10530d63ce2bSvenki 	physplat_nodes[row] = nodeh;
10540d63ce2bSvenki }
10550d63ce2bSvenki 
10560d63ce2bSvenki static picl_nodehdl_t
lookup_nodeh(int row)10570d63ce2bSvenki lookup_nodeh(int row)
10580d63ce2bSvenki {
10590d63ce2bSvenki 	if (row >= n_physplat_nodes)
1060*ada2da53SToomas Soome 		return (0);
10610d63ce2bSvenki 
10620d63ce2bSvenki 	return (physplat_nodes[row]);
10630d63ce2bSvenki }
10640d63ce2bSvenki 
10650d63ce2bSvenki /*
10660d63ce2bSvenki  * We enter this routine only when we are building the physical-platform
10670d63ce2bSvenki  * subtree, whether for the first time or in response to a hotplug event.
10680d63ce2bSvenki  * If we're here for rebuilding the tree, we have already set stale_tree
10690d63ce2bSvenki  * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props
10700d63ce2bSvenki  * or volprop_ndx. If we're here to build the tree for the first time,
10710d63ce2bSvenki  * picld hasn't yet created doors and is running single-threaded, so no
10720d63ce2bSvenki  * one else would be accessing them anyway.
10730d63ce2bSvenki  */
10740d63ce2bSvenki static void
save_volprop(picl_prophdl_t prop,char * oidstr,int row,int proptype)10750d63ce2bSvenki save_volprop(picl_prophdl_t prop, char *oidstr, int row, int proptype)
10760d63ce2bSvenki {
10770d63ce2bSvenki 	vol_prophdl_t	*p;
10780d63ce2bSvenki 	int		count;
10790d63ce2bSvenki 
10800d63ce2bSvenki 	if (volprop_ndx == n_vol_props) {
10810d63ce2bSvenki 		count = n_vol_props + N_ELEMS_IN_VOLPROP_BLOCK;
10820d63ce2bSvenki 		p = (vol_prophdl_t *)calloc(count, sizeof (vol_prophdl_t));
10830d63ce2bSvenki 		if (p == NULL) {
10840d63ce2bSvenki 			log_msg(LOG_ERR, SNMPP_NO_MEM,
10850d63ce2bSvenki 			    count * sizeof (vol_prophdl_t));
10860d63ce2bSvenki 			return;
10870d63ce2bSvenki 		}
10880d63ce2bSvenki 
10890d63ce2bSvenki 		if (vol_props) {
10900d63ce2bSvenki 			(void) memcpy((void *) p, (void *) vol_props,
10910d63ce2bSvenki 			    n_vol_props * sizeof (vol_prophdl_t));
10920d63ce2bSvenki 			free((void *) vol_props);
10930d63ce2bSvenki 		}
10940d63ce2bSvenki 
10950d63ce2bSvenki 		vol_props = p;
10960d63ce2bSvenki 		n_vol_props += N_ELEMS_IN_VOLPROP_BLOCK;
10970d63ce2bSvenki 	}
10980d63ce2bSvenki 
10990d63ce2bSvenki 	vol_props[volprop_ndx].prop = prop;
11000d63ce2bSvenki 	vol_props[volprop_ndx].oidstr = oidstr;
11010d63ce2bSvenki 	vol_props[volprop_ndx].row = row;
11020d63ce2bSvenki 	vol_props[volprop_ndx].proptype = proptype;
11030d63ce2bSvenki 
11040d63ce2bSvenki 	volprop_ndx++;
11050d63ce2bSvenki }
11060d63ce2bSvenki 
11070d63ce2bSvenki static void
check_for_stale_data(boolean_t nocache)11081c60fca8Sfw check_for_stale_data(boolean_t nocache)
11090d63ce2bSvenki {
11100d63ce2bSvenki 	int	cur_change_time;
11110d63ce2bSvenki 	int	ret;
11120d63ce2bSvenki 	int	snmp_syserr;
11130d63ce2bSvenki 
11140d63ce2bSvenki 	(void) rw_wrlock(&stale_tree_rwlp);
11150d63ce2bSvenki 
11160d63ce2bSvenki 	/*
11170d63ce2bSvenki 	 * Check if some other thread beat us to it
11180d63ce2bSvenki 	 */
11190d63ce2bSvenki 	if (stale_tree == B_TRUE) {
11200d63ce2bSvenki 		(void) rw_unlock(&stale_tree_rwlp);
11210d63ce2bSvenki 		return;
11220d63ce2bSvenki 	}
11230d63ce2bSvenki 
11241c60fca8Sfw 	/*
11251c60fca8Sfw 	 * Cache OID_entLastChangeTime for up to 10 seconds before
11261c60fca8Sfw 	 * fetching it from ILOM again.  This prevents us from fetching
11271c60fca8Sfw 	 * this value from ILOM when the we're filling or refreshing a
11281c60fca8Sfw 	 * whole bunch of items in the cache around the same time.
11291c60fca8Sfw 	 */
11301c60fca8Sfw 	if (nocache == B_FALSE && time(NULL) - change_time_check <= 10) {
11311c60fca8Sfw 		(void) rw_unlock(&stale_tree_rwlp);
11321c60fca8Sfw 		return;
11331c60fca8Sfw 	}
11341c60fca8Sfw 
11350d63ce2bSvenki 	/*
11360d63ce2bSvenki 	 * Check if mib data has changed (hotplug? link-reset?)
11370d63ce2bSvenki 	 */
1138af71cc4eSMichael Bergknoff 	do {
1139af71cc4eSMichael Bergknoff 		snmp_syserr = 0;
1140af71cc4eSMichael Bergknoff 		ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
1141af71cc4eSMichael Bergknoff 		    &cur_change_time, &snmp_syserr);
1142af71cc4eSMichael Bergknoff 		(void) time(&change_time_check);
1143af71cc4eSMichael Bergknoff 		if ((ret == 0) && (cur_change_time == change_time)) {
1144af71cc4eSMichael Bergknoff 			(void) rw_unlock(&stale_tree_rwlp);
1145af71cc4eSMichael Bergknoff 			return;
1146af71cc4eSMichael Bergknoff 		}
1147af71cc4eSMichael Bergknoff 	} while (ret != 0 && snmp_syserr == EINTR);
11480d63ce2bSvenki 
11490d63ce2bSvenki 	/*
11500d63ce2bSvenki 	 * If we can't read entLastChangeTime we assume we need to rebuild
11510d63ce2bSvenki 	 * the tree. This will also cover the case when we need to rebuild
11520d63ce2bSvenki 	 * the tree because a link reset had happened.
11530d63ce2bSvenki 	 */
11540d63ce2bSvenki 	LOGPRINTF2("check_for_stale_data: LastChange times have changed, "
11550d63ce2bSvenki 	    "(%#x != %#x)\n", change_time, cur_change_time);
11560d63ce2bSvenki 
11570d63ce2bSvenki 	/*
11580d63ce2bSvenki 	 * If the mib data has changed, we need to rebuild the physical-platform
11590d63ce2bSvenki 	 * subtree. To do this, we set a flag to mark the tree stale,
11600d63ce2bSvenki 	 * so that any future reads to get value of volatile properties will
11610d63ce2bSvenki 	 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag
11620d63ce2bSvenki 	 * is reset by the tree builder thread.
11630d63ce2bSvenki 	 */
11640d63ce2bSvenki 	stale_tree = B_TRUE;
11650d63ce2bSvenki 	if (vol_props) {
11660d63ce2bSvenki 		free(vol_props);
11670d63ce2bSvenki 	}
11680d63ce2bSvenki 	vol_props = NULL;
11690d63ce2bSvenki 	volprop_ndx = 0;
11700d63ce2bSvenki 	n_vol_props = 0;
11710d63ce2bSvenki 
11720d63ce2bSvenki 	(void) rw_unlock(&stale_tree_rwlp);
11730d63ce2bSvenki 
11740d63ce2bSvenki 	(void) mutex_lock(&rebuild_tree_lock);
11750d63ce2bSvenki 	rebuild_tree = B_TRUE;
11760d63ce2bSvenki 	(void) cond_signal(&rebuild_tree_cv);
11770d63ce2bSvenki 	LOGPRINTF("check_for_stale_data: signalled tree builder\n");
11780d63ce2bSvenki 	(void) mutex_unlock(&rebuild_tree_lock);
11790d63ce2bSvenki }
11800d63ce2bSvenki 
11810d63ce2bSvenki /*
11820d63ce2bSvenki  * This is the critical routine.  This callback is invoked by picl whenever
11830d63ce2bSvenki  * it needs to fetch the value of a volatile property. The first thing we
11840d63ce2bSvenki  * must do, however, is to see if there has been a hotplug or a link-reset
11850d63ce2bSvenki  * event since the last time we built the tree and whether we need to
11860d63ce2bSvenki  * rebuild the tree. If so, we do whatever is necessary to make that happen,
11870d63ce2bSvenki  * but return PICL_PROPVALUNAVAILABLE for now, without making any further
11880d63ce2bSvenki  * snmp requests or accessing any globals.
11890d63ce2bSvenki  */
11900d63ce2bSvenki static int
read_volprop(ptree_rarg_t * parg,void * buf)11910d63ce2bSvenki read_volprop(ptree_rarg_t *parg, void *buf)
11920d63ce2bSvenki {
11930d63ce2bSvenki 	char	*pstr;
11940d63ce2bSvenki 	int	propval;
11950d63ce2bSvenki 	int	i, ndx;
11960d63ce2bSvenki 	int	ret;
11970d63ce2bSvenki 	int	snmp_syserr = 0;
11980d63ce2bSvenki 
11990d63ce2bSvenki 	/*
12000d63ce2bSvenki 	 * First check for any event that would make us throw away
12010d63ce2bSvenki 	 * the existing /physical-platform subtree and rebuild
12020d63ce2bSvenki 	 * another one. If we are rebuilding the subtree, we just
12030d63ce2bSvenki 	 * return the stale value until the tree is fully built.
12040d63ce2bSvenki 	 */
12051c60fca8Sfw 	check_for_stale_data(B_FALSE);
12060d63ce2bSvenki 
12070d63ce2bSvenki 	(void) rw_rdlock(&stale_tree_rwlp);
12080d63ce2bSvenki 
12090d63ce2bSvenki 	if (stale_tree == B_TRUE) {
12100d63ce2bSvenki 		(void) rw_unlock(&stale_tree_rwlp);
12110d63ce2bSvenki 		return (PICL_PROPVALUNAVAILABLE);
12120d63ce2bSvenki 	}
12130d63ce2bSvenki 
12140d63ce2bSvenki 	for (i = 0; i < volprop_ndx; i++) {
12150d63ce2bSvenki 		if (vol_props[i].prop == parg->proph) {
12160d63ce2bSvenki 			ndx = i;
12170d63ce2bSvenki 			break;
12180d63ce2bSvenki 		}
12190d63ce2bSvenki 	}
12200d63ce2bSvenki 	if (i == volprop_ndx) {
12211c60fca8Sfw 		(void) rw_unlock(&stale_tree_rwlp);
12220d63ce2bSvenki 		log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph);
12230d63ce2bSvenki 		return (PICL_FAILURE);
12240d63ce2bSvenki 	}
12250d63ce2bSvenki 
12260d63ce2bSvenki 	/*
12270d63ce2bSvenki 	 * If we can't read the value, return failure. Even if this was
12280d63ce2bSvenki 	 * due to a link reset, between the check for stale data and now,
12290d63ce2bSvenki 	 * the next volatile callback by picl will initiate a tree-rebuild.
12300d63ce2bSvenki 	 */
12310d63ce2bSvenki 	ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row,
12320d63ce2bSvenki 	    &propval, &snmp_syserr);
12330d63ce2bSvenki 	if (ret < 0) {
12341c60fca8Sfw 		(void) rw_unlock(&stale_tree_rwlp);
12351c60fca8Sfw 		check_for_stale_data(B_TRUE);
12361c60fca8Sfw 		if (stale_tree == B_TRUE) {
12371c60fca8Sfw 			return (PICL_PROPVALUNAVAILABLE);
12381c60fca8Sfw 		}
12391c60fca8Sfw 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
12401c60fca8Sfw 		    snmp_syserr ? snmp_syserr : ret,
12411c60fca8Sfw 		    vol_props[ndx].oidstr, vol_props[ndx].row);
12420d63ce2bSvenki 		return (PICL_FAILURE);
12430d63ce2bSvenki 	}
12440d63ce2bSvenki 
12450d63ce2bSvenki 	switch (vol_props[ndx].proptype) {
12460d63ce2bSvenki 	case VPT_PLATOPSTATE:
12470d63ce2bSvenki 		if (propval == SSOS_DISABLED) {
12480d63ce2bSvenki 			(void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN);
12490d63ce2bSvenki 		} else if (propval == SSOS_ENABLED) {
12500d63ce2bSvenki 			(void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN);
12510d63ce2bSvenki 		} else {
12521c60fca8Sfw 			(void) rw_unlock(&stale_tree_rwlp);
12530d63ce2bSvenki 			log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE,
12540d63ce2bSvenki 			    propval, vol_props[ndx].row);
12550d63ce2bSvenki 			return (PICL_FAILURE);
12560d63ce2bSvenki 		}
12570d63ce2bSvenki 		break;
12580d63ce2bSvenki 
12590d63ce2bSvenki 	case VPT_NUMSENSOR:
12600d63ce2bSvenki 		(void) memcpy(buf, &propval, sizeof (propval));
12610d63ce2bSvenki 		break;
12620d63ce2bSvenki 
12630d63ce2bSvenki 	case VPT_BINSENSOR:
12640d63ce2bSvenki 		if (propval == ST_TRUE) {
12650d63ce2bSvenki 			ret = snmp_get_str(hdl,
12660d63ce2bSvenki 			    OID_sunPlatBinarySensorInterpretTrue,
12670d63ce2bSvenki 			    vol_props[ndx].row, &pstr, &snmp_syserr);
12681c60fca8Sfw 			if (snmp_syserr == ECANCELED) {
12691c60fca8Sfw 				(void) rw_unlock(&stale_tree_rwlp);
12701c60fca8Sfw 				if (pstr)
12711c60fca8Sfw 					free(pstr);
12720d63ce2bSvenki 				return (PICL_FAILURE);
12731c60fca8Sfw 			}
12740d63ce2bSvenki 			if (ret < 0 || pstr == NULL) {
12751c60fca8Sfw 				log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
12761c60fca8Sfw 				    snmp_syserr ? snmp_syserr : ret,
12771c60fca8Sfw 				    OID_sunPlatBinarySensorInterpretTrue,
12781c60fca8Sfw 				    vol_props[ndx].row);
12790d63ce2bSvenki 				(void) strlcpy(buf, STR_ST_TRUE,
12800d63ce2bSvenki 				    MAX_TRUTHVAL_LEN);
12810d63ce2bSvenki 			} else {
12820d63ce2bSvenki 				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
12830d63ce2bSvenki 			}
12841c60fca8Sfw 			if (pstr)
12851c60fca8Sfw 				free(pstr);
12860d63ce2bSvenki 		} else if (propval == ST_FALSE) {
12870d63ce2bSvenki 			ret = snmp_get_str(hdl,
12880d63ce2bSvenki 			    OID_sunPlatBinarySensorInterpretFalse,
12890d63ce2bSvenki 			    vol_props[ndx].row, &pstr, &snmp_syserr);
12901c60fca8Sfw 			if (snmp_syserr == ECANCELED) {
12911c60fca8Sfw 				(void) rw_unlock(&stale_tree_rwlp);
12921c60fca8Sfw 				if (pstr)
12931c60fca8Sfw 					free(pstr);
12940d63ce2bSvenki 				return (PICL_FAILURE);
12951c60fca8Sfw 			}
12960d63ce2bSvenki 			if (ret < 0 || pstr == NULL) {
12971c60fca8Sfw 				log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
12981c60fca8Sfw 				    snmp_syserr ? snmp_syserr : ret,
12991c60fca8Sfw 				    OID_sunPlatBinarySensorInterpretFalse,
13001c60fca8Sfw 				    vol_props[ndx].row);
13010d63ce2bSvenki 				(void) strlcpy(buf, STR_ST_FALSE,
13020d63ce2bSvenki 				    MAX_TRUTHVAL_LEN);
13030d63ce2bSvenki 			} else {
13040d63ce2bSvenki 				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
13050d63ce2bSvenki 			}
13061c60fca8Sfw 			if (pstr)
13071c60fca8Sfw 				free(pstr);
13080d63ce2bSvenki 		} else {
13091c60fca8Sfw 			(void) rw_unlock(&stale_tree_rwlp);
13100d63ce2bSvenki 			log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT,
13110d63ce2bSvenki 			    propval, vol_props[ndx].row);
13120d63ce2bSvenki 			return (PICL_FAILURE);
13130d63ce2bSvenki 		}
13140d63ce2bSvenki 		break;
13150d63ce2bSvenki 
13160d63ce2bSvenki 	case VPT_ALARMSTATE:
13170d63ce2bSvenki 		if (propval == SSAS_OFF) {
13180d63ce2bSvenki 			(void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN);
13190d63ce2bSvenki 		} else if (propval == SSAS_STEADY) {
13200d63ce2bSvenki 			(void) strlcpy(buf, STR_SSAS_STEADY,
13210d63ce2bSvenki 			    MAX_ALARMSTATE_LEN);
13220d63ce2bSvenki 		} else if (propval == SSAS_ALTERNATING) {
13230d63ce2bSvenki 			(void) strlcpy(buf, STR_SSAS_ALTERNATING,
13240d63ce2bSvenki 			    MAX_ALARMSTATE_LEN);
13250d63ce2bSvenki 		} else {
13260d63ce2bSvenki 			(void) strlcpy(buf, STR_SSAS_UNKNOWN,
13270d63ce2bSvenki 			    MAX_ALARMSTATE_LEN);
13280d63ce2bSvenki 		}
13290d63ce2bSvenki 		break;
13300d63ce2bSvenki 
13310d63ce2bSvenki 	case VPT_BATTERYSTATUS:
13320d63ce2bSvenki 		switch (propval) {
13330d63ce2bSvenki 		case SSBS_OTHER:
13340d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_OTHER,
13350d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13360d63ce2bSvenki 			break;
13370d63ce2bSvenki 		case SSBS_FULLYCHARGED:
13380d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_FULLYCHARGED,
13390d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13400d63ce2bSvenki 			break;
13410d63ce2bSvenki 		case SSBS_LOW:
13420d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_LOW,
13430d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13440d63ce2bSvenki 			break;
13450d63ce2bSvenki 		case SSBS_CRITICAL:
13460d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_CRITICAL,
13470d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13480d63ce2bSvenki 			break;
13490d63ce2bSvenki 		case SSBS_CHARGING:
13500d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_CHARGING,
13510d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13520d63ce2bSvenki 			break;
13530d63ce2bSvenki 		case SSBS_CHARGING_AND_LOW:
13540d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW,
13550d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13560d63ce2bSvenki 			break;
13570d63ce2bSvenki 		case SSBS_CHARGING_AND_HIGH:
13580d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH,
13590d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13600d63ce2bSvenki 			break;
13610d63ce2bSvenki 		case SSBS_CHARGING_AND_CRITICAL:
13620d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL,
13630d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13640d63ce2bSvenki 			break;
13650d63ce2bSvenki 		case SSBS_UNDEFINED:
13660d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_UNDEFINED,
13670d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13680d63ce2bSvenki 			break;
13690d63ce2bSvenki 		case SSBS_PARTIALLY_CHARGED:
13700d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED,
13710d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13720d63ce2bSvenki 			break;
13730d63ce2bSvenki 		case SSBS_UNKNOWN:
13740d63ce2bSvenki 		default:
13750d63ce2bSvenki 			(void) strlcpy(buf, STR_SSBS_UNKNOWN,
13760d63ce2bSvenki 			    MAX_BATTERYSTATUS_LEN);
13770d63ce2bSvenki 			break;
13780d63ce2bSvenki 		}
13790d63ce2bSvenki 		break;
13800d63ce2bSvenki 	}
13810d63ce2bSvenki 
13820d63ce2bSvenki 	(void) rw_unlock(&stale_tree_rwlp);
13830d63ce2bSvenki 
13840d63ce2bSvenki 	return (PICL_SUCCESS);
13850d63ce2bSvenki }
13860d63ce2bSvenki 
13870d63ce2bSvenki static void
threshold(picl_nodehdl_t node,char * oidstr,int row,char * propname,int * snmp_syserr_p)13880d63ce2bSvenki threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname,
13890d63ce2bSvenki     int *snmp_syserr_p)
13900d63ce2bSvenki {
13910d63ce2bSvenki 	picl_prophdl_t	prop;
13920d63ce2bSvenki 	int		err;
13930d63ce2bSvenki 	int		val;
13940d63ce2bSvenki 
13951c60fca8Sfw 	if ((err = snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p)) != -1) {
13960d63ce2bSvenki 		err = add_volatile_prop(node, propname, PICL_PTYPE_INT,
13970d63ce2bSvenki 		    PICL_READ, sizeof (int), read_volprop, NULL, &prop);
13980d63ce2bSvenki 		if (err == PICL_SUCCESS)
13990d63ce2bSvenki 			save_volprop(prop, oidstr, row, VPT_NUMSENSOR);
14001c60fca8Sfw 	} else
14011c60fca8Sfw 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
14021c60fca8Sfw 		    *snmp_syserr_p ? *snmp_syserr_p : err, oidstr, row);
14030d63ce2bSvenki }
14040d63ce2bSvenki 
14050d63ce2bSvenki static void
add_thresholds(picl_nodehdl_t node,int row,int * snmp_syserr_p)14060d63ce2bSvenki add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p)
14070d63ce2bSvenki {
14080d63ce2bSvenki 	uchar_t	*bitstr = NULL;
14090d63ce2bSvenki 	uchar_t	enabled;
14100d63ce2bSvenki 	uint_t	nbytes;
14110d63ce2bSvenki 	int	ret;
14120d63ce2bSvenki 
14131c60fca8Sfw 	ret = snmp_get_str(hdl,
14141c60fca8Sfw 	    OID_sunPlatNumericSensorEnabledThresholds,
14151c60fca8Sfw 	    row, (char **)&bitstr, snmp_syserr_p);
14161c60fca8Sfw 	if (ret == -1) {
14171c60fca8Sfw 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
14181c60fca8Sfw 		    *snmp_syserr_p ? *snmp_syserr_p : ret,
14191c60fca8Sfw 		    OID_sunPlatNumericSensorEnabledThresholds, row);
14201c60fca8Sfw 	} else {
14211c60fca8Sfw 		nbytes = strlen((const char *)bitstr);
14221c60fca8Sfw 	}
14231c60fca8Sfw 
14241c60fca8Sfw 	CHECK_LINKRESET_VOID(snmp_syserr_p);
14250d63ce2bSvenki 
14261c60fca8Sfw 	/*
14271c60fca8Sfw 	 * No bit string of threshold masks was returned, so we can't
14281c60fca8Sfw 	 * assume that any thresholds exist.
14291c60fca8Sfw 	 *
14301c60fca8Sfw 	 * This mask prevents us from attempting to fetch thresholds
14311c60fca8Sfw 	 * which don't apply to the sensor or that aren't there anyway,
14321c60fca8Sfw 	 * That speeds up the plug-in significantly since otherwise it
14331c60fca8Sfw 	 * takes several seconds to time out.
14341c60fca8Sfw 	 */
14351c60fca8Sfw 	if (ret < 0 || bitstr == NULL || nbytes == 0 || 2 < nbytes) {
14361c60fca8Sfw 		if (bitstr)
14371c60fca8Sfw 			free(bitstr);
14381c60fca8Sfw 		return;
14391c60fca8Sfw 	} else if (nbytes == 1) {
14400d63ce2bSvenki 		/*
14410d63ce2bSvenki 		 * The ALOM snmp agent doesn't adhere to the BER rules for
14420d63ce2bSvenki 		 * encoding bit strings. While the BER states that bitstrings
14430d63ce2bSvenki 		 * must begin from the second octet after length, and the
14440d63ce2bSvenki 		 * first octet after length must indicate the number of unused
14450d63ce2bSvenki 		 * bits in the last octet, the snmp agent simply sends the
14460d63ce2bSvenki 		 * bitstring data as if it were octet string -- that is, the
14470d63ce2bSvenki 		 * "unused bits" octet is missing.
14480d63ce2bSvenki 		 */
14490d63ce2bSvenki 		enabled = bitstr[0];
14500d63ce2bSvenki 	} else if (nbytes == 2)
14510d63ce2bSvenki 		enabled = bitstr[1];
14520d63ce2bSvenki 
14530d63ce2bSvenki 	if (bitstr) {
14540d63ce2bSvenki 		free(bitstr);
14550d63ce2bSvenki 	}
14560d63ce2bSvenki 
14570d63ce2bSvenki 	if (enabled & LOWER_FATAL) {
14580d63ce2bSvenki 		threshold(node,
14590d63ce2bSvenki 		    OID_sunPlatNumericSensorLowerThresholdFatal, row,
14600d63ce2bSvenki 		    PICL_PROP_LOW_POWER_OFF, snmp_syserr_p);
14610d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14620d63ce2bSvenki 	}
14630d63ce2bSvenki 	if (enabled & LOWER_CRITICAL) {
14640d63ce2bSvenki 		threshold(node,
14650d63ce2bSvenki 		    OID_sunPlatNumericSensorLowerThresholdCritical, row,
14660d63ce2bSvenki 		    PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p);
14670d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14680d63ce2bSvenki 	}
14690d63ce2bSvenki 	if (enabled & LOWER_NON_CRITICAL) {
14700d63ce2bSvenki 		threshold(node,
14710d63ce2bSvenki 		    OID_sunPlatNumericSensorLowerThresholdNonCritical, row,
14720d63ce2bSvenki 		    PICL_PROP_LOW_WARNING, snmp_syserr_p);
14730d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14740d63ce2bSvenki 	}
14750d63ce2bSvenki 	if (enabled & UPPER_NON_CRITICAL) {
14760d63ce2bSvenki 		threshold(node,
14770d63ce2bSvenki 		    OID_sunPlatNumericSensorUpperThresholdNonCritical, row,
1478aaba19e2Sfw 		    PICL_PROP_HIGH_WARNING, snmp_syserr_p);
14790d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14800d63ce2bSvenki 	}
14810d63ce2bSvenki 	if (enabled & UPPER_CRITICAL) {
14820d63ce2bSvenki 		threshold(node,
14830d63ce2bSvenki 		    OID_sunPlatNumericSensorUpperThresholdCritical, row,
14840d63ce2bSvenki 		    PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p);
14850d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14860d63ce2bSvenki 	}
14870d63ce2bSvenki 	if (enabled & UPPER_FATAL) {
14880d63ce2bSvenki 		threshold(node,
14890d63ce2bSvenki 		    OID_sunPlatNumericSensorUpperThresholdFatal, row,
1490aaba19e2Sfw 		    PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p);
14910d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14920d63ce2bSvenki 	}
14930d63ce2bSvenki }
14940d63ce2bSvenki 
14950d63ce2bSvenki static char *
get_slot_type(int row,int * snmp_syserr_p)14960d63ce2bSvenki get_slot_type(int row, int *snmp_syserr_p)
14970d63ce2bSvenki {
14980d63ce2bSvenki 	char	*p;
14990d63ce2bSvenki 	char	*slott = NULL;
15000d63ce2bSvenki 	int	ret;
15010d63ce2bSvenki 
15020d63ce2bSvenki 	ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes,
15030d63ce2bSvenki 	    row, &p, snmp_syserr_p);
15040d63ce2bSvenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
15050d63ce2bSvenki 
15060d63ce2bSvenki 	if ((ret == 0) && p && *p) {
15070d63ce2bSvenki 		slott = p;
15080d63ce2bSvenki 		if ((p = strchr(slott, '\n')) != NULL)
15090d63ce2bSvenki 			*p = 0;
15100d63ce2bSvenki 	} else {
15110d63ce2bSvenki 		log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row);
15120d63ce2bSvenki 		if (p) {
15130d63ce2bSvenki 			free(p);
15140d63ce2bSvenki 		}
15150d63ce2bSvenki 	}
15160d63ce2bSvenki 
15170d63ce2bSvenki 	return (slott);
15180d63ce2bSvenki }
15190d63ce2bSvenki 
15200d63ce2bSvenki /*
15210d63ce2bSvenki  * Create and add the specified volatile property
15220d63ce2bSvenki  */
15230d63ce2bSvenki 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)15240d63ce2bSvenki add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access,
15250d63ce2bSvenki     int size, int (*rdfunc)(ptree_rarg_t *, void *),
15260d63ce2bSvenki     int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp)
15270d63ce2bSvenki {
15280d63ce2bSvenki 	ptree_propinfo_t	propinfo;
15290d63ce2bSvenki 	picl_prophdl_t		prop;
15300d63ce2bSvenki 	int			err;
15310d63ce2bSvenki 
15320d63ce2bSvenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
15330d63ce2bSvenki 	    type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc);
15340d63ce2bSvenki 	if (err != PICL_SUCCESS) {
15350d63ce2bSvenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err);
15360d63ce2bSvenki 		return (err);
15370d63ce2bSvenki 	}
15380d63ce2bSvenki 
15390d63ce2bSvenki 	err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop);
15400d63ce2bSvenki 	if (err != PICL_SUCCESS) {
15410d63ce2bSvenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node);
15420d63ce2bSvenki 		return (err);
15430d63ce2bSvenki 	}
15440d63ce2bSvenki 
15450d63ce2bSvenki 	if (propp)
15460d63ce2bSvenki 		*propp = prop;
15470d63ce2bSvenki 
15480d63ce2bSvenki 	return (PICL_SUCCESS);
15490d63ce2bSvenki }
15500d63ce2bSvenki 
15510d63ce2bSvenki /*
15520d63ce2bSvenki  * Add the specified string property to the node
15530d63ce2bSvenki  */
15540d63ce2bSvenki static int
add_string_prop(picl_nodehdl_t node,char * propname,char * propval)15550d63ce2bSvenki add_string_prop(picl_nodehdl_t node, char *propname, char *propval)
15560d63ce2bSvenki {
15570d63ce2bSvenki 	ptree_propinfo_t	propinfo;
15580d63ce2bSvenki 	int			err;
15590d63ce2bSvenki 
15602ea390f3SMichael Bergknoff 	if (*propval == '\0')
15612ea390f3SMichael Bergknoff 		return (PICL_SUCCESS);
15622ea390f3SMichael Bergknoff 
15630d63ce2bSvenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
15640d63ce2bSvenki 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1,
15650d63ce2bSvenki 	    propname, NULL, NULL);
15660d63ce2bSvenki 	if (err != PICL_SUCCESS) {
15670d63ce2bSvenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err);
15680d63ce2bSvenki 		return (err);
15690d63ce2bSvenki 	}
15700d63ce2bSvenki 
15710d63ce2bSvenki 	err = ptree_create_and_add_prop(node, &propinfo, propval, NULL);
15720d63ce2bSvenki 	if (err != PICL_SUCCESS) {
15730d63ce2bSvenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node);
15740d63ce2bSvenki 		return (err);
15750d63ce2bSvenki 	}
15760d63ce2bSvenki 
15770d63ce2bSvenki 	return (PICL_SUCCESS);
15780d63ce2bSvenki }
15790d63ce2bSvenki 
15800d63ce2bSvenki /*
15810d63ce2bSvenki  * Add the specified void property to the node
15820d63ce2bSvenki  */
15830d63ce2bSvenki static int
add_void_prop(picl_nodehdl_t node,char * propname)15840d63ce2bSvenki add_void_prop(picl_nodehdl_t node, char *propname)
15850d63ce2bSvenki {
15860d63ce2bSvenki 	ptree_propinfo_t	propinfo;
15870d63ce2bSvenki 	int			err;
15880d63ce2bSvenki 
15890d63ce2bSvenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
15900d63ce2bSvenki 	    PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL);
15910d63ce2bSvenki 	if (err != PICL_SUCCESS) {
15920d63ce2bSvenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err);
15930d63ce2bSvenki 		return (err);
15940d63ce2bSvenki 	}
15950d63ce2bSvenki 
15960d63ce2bSvenki 	err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL);
15970d63ce2bSvenki 	if (err != PICL_SUCCESS) {
15980d63ce2bSvenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node);
15990d63ce2bSvenki 		return (err);
16000d63ce2bSvenki 	}
16010d63ce2bSvenki 
16020d63ce2bSvenki 	return (PICL_SUCCESS);
16030d63ce2bSvenki }
16040d63ce2bSvenki 
16050d63ce2bSvenki static void
add_prop(picl_nodehdl_t nodeh,picl_prophdl_t * php,char * label,int row,sp_propid_t pp,int * snmp_syserr_p)16060d63ce2bSvenki add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
16070d63ce2bSvenki     int row, sp_propid_t pp, int *snmp_syserr_p)
16080d63ce2bSvenki {
16090d63ce2bSvenki 	char	*serial_num;
16100d63ce2bSvenki 	char	*slot_type;
16110d63ce2bSvenki 	char	*fw_revision, *hw_revision;
16120d63ce2bSvenki 	char	*mfg_name, *model_name;
16130d63ce2bSvenki 	char	*phys_descr;
16140d63ce2bSvenki 	int	val;
16150d63ce2bSvenki 	int	ret;
16160d63ce2bSvenki 
16170d63ce2bSvenki 	switch (pp) {
16180d63ce2bSvenki 	case PP_SERIAL_NUM:
16190d63ce2bSvenki 		ret = snmp_get_str(hdl, OID_entPhysicalSerialNum,
16200d63ce2bSvenki 		    row, &serial_num, snmp_syserr_p);
16210d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
16222ea390f3SMichael Bergknoff 		if ((ret == 0) && serial_num) {
16230d63ce2bSvenki 			(void) add_string_prop(nodeh,
16240d63ce2bSvenki 			    PICL_PROP_SERIAL_NUMBER, serial_num);
16250d63ce2bSvenki 			free((void *) serial_num);
16260d63ce2bSvenki 		}
16271c60fca8Sfw 		if (ret == -1)
16281c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
16291c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
16301c60fca8Sfw 			    OID_entPhysicalSerialNum, row);
16310d63ce2bSvenki 		break;
16320d63ce2bSvenki 
16330d63ce2bSvenki 	case PP_SLOT_TYPE:
16340d63ce2bSvenki 		if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) {
16350d63ce2bSvenki 			CHECK_LINKRESET_VOID(snmp_syserr_p)
16360d63ce2bSvenki 			(void) add_string_prop(nodeh,
16370d63ce2bSvenki 			    PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE);
16380d63ce2bSvenki 		} else {
16390d63ce2bSvenki 			(void) add_string_prop(nodeh,
16400d63ce2bSvenki 			    PICL_PROP_SLOT_TYPE, slot_type);
16410d63ce2bSvenki 			free((void *) slot_type);
16420d63ce2bSvenki 		}
16430d63ce2bSvenki 		break;
16440d63ce2bSvenki 
16450d63ce2bSvenki 	case PP_STATE:
16460d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_STATE,
16470d63ce2bSvenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN,
16480d63ce2bSvenki 		    read_volprop, NULL, php);
16490d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
16500d63ce2bSvenki 			save_volprop(*php, OID_sunPlatAlarmState, row,
16510d63ce2bSvenki 			    VPT_ALARMSTATE);
16520d63ce2bSvenki 		}
16530d63ce2bSvenki 		break;
16540d63ce2bSvenki 
16550d63ce2bSvenki 	case PP_OPSTATUS:
16560d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS,
16570d63ce2bSvenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN,
16580d63ce2bSvenki 		    read_volprop, NULL, php);
16590d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
16600d63ce2bSvenki 			save_volprop(*php,
16610d63ce2bSvenki 			    OID_sunPlatEquipmentOperationalState, row,
16620d63ce2bSvenki 			    VPT_PLATOPSTATE);
16630d63ce2bSvenki 		}
16640d63ce2bSvenki 		break;
16650d63ce2bSvenki 
16660d63ce2bSvenki 	case PP_BATT_STATUS:
16670d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS,
1668aaba19e2Sfw 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN,
1669aaba19e2Sfw 		    read_volprop, NULL, php);
16700d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
16710d63ce2bSvenki 			save_volprop(*php, OID_sunPlatBatteryStatus, row,
16720d63ce2bSvenki 			    VPT_BATTERYSTATUS);
16730d63ce2bSvenki 		}
16740d63ce2bSvenki 		break;
16750d63ce2bSvenki 
16760d63ce2bSvenki 	case PP_TEMPERATURE:
16770d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE,
16780d63ce2bSvenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16790d63ce2bSvenki 		    NULL, php);
16800d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
16810d63ce2bSvenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
16820d63ce2bSvenki 			    row, VPT_NUMSENSOR);
16830d63ce2bSvenki 		}
16840d63ce2bSvenki 		break;
16850d63ce2bSvenki 
16860d63ce2bSvenki 	case PP_VOLTAGE:
16870d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE,
16880d63ce2bSvenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16890d63ce2bSvenki 		    NULL, php);
16900d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
16910d63ce2bSvenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
16920d63ce2bSvenki 			    row, VPT_NUMSENSOR);
16930d63ce2bSvenki 		}
16940d63ce2bSvenki 		break;
16950d63ce2bSvenki 
16960d63ce2bSvenki 	case PP_CURRENT:
16970d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT,
16980d63ce2bSvenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16990d63ce2bSvenki 		    NULL, php);
17000d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
17010d63ce2bSvenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
17020d63ce2bSvenki 			    row, VPT_NUMSENSOR);
17030d63ce2bSvenki 		}
17040d63ce2bSvenki 		break;
17050d63ce2bSvenki 
17060d63ce2bSvenki 	case PP_SPEED:
17070d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT,
17080d63ce2bSvenki 		    PICL_READ, sizeof (int), read_volprop, NULL, php);
17090d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
17100d63ce2bSvenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
17110d63ce2bSvenki 			    row, VPT_NUMSENSOR);
17120d63ce2bSvenki 		}
17130d63ce2bSvenki 		break;
17140d63ce2bSvenki 
17150d63ce2bSvenki 	case PP_SENSOR_VALUE:
17160d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE,
17170d63ce2bSvenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
17180d63ce2bSvenki 		    NULL, php);
17190d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
17200d63ce2bSvenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
17210d63ce2bSvenki 			    row, VPT_NUMSENSOR);
17220d63ce2bSvenki 		}
17230d63ce2bSvenki 		break;
17240d63ce2bSvenki 
17250d63ce2bSvenki 	case PP_CONDITION:
17260d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION,
17270d63ce2bSvenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
17280d63ce2bSvenki 		    read_volprop, NULL, php);
17290d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
17300d63ce2bSvenki 			save_volprop(*php, OID_sunPlatBinarySensorCurrent,
17310d63ce2bSvenki 			    row, VPT_BINSENSOR);
17320d63ce2bSvenki 		}
17330d63ce2bSvenki 		break;
17340d63ce2bSvenki 
17350d63ce2bSvenki 	case PP_EXPECTED:
17360d63ce2bSvenki 		ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED,
17370d63ce2bSvenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
17380d63ce2bSvenki 		    read_volprop, NULL, php);
17390d63ce2bSvenki 		if (ret == PICL_SUCCESS) {
17400d63ce2bSvenki 			save_volprop(*php, OID_sunPlatBinarySensorExpected,
17410d63ce2bSvenki 			    row, VPT_BINSENSOR);
17420d63ce2bSvenki 		}
17430d63ce2bSvenki 		break;
17440d63ce2bSvenki 
1745dc6ca969Sfw 	case PP_EXPONENT:
1746dc6ca969Sfw 		ret = add_volatile_prop(nodeh, PICL_PROP_EXPONENT,
1747dc6ca969Sfw 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
1748dc6ca969Sfw 		    NULL, php);
1749dc6ca969Sfw 		if (ret == PICL_SUCCESS) {
1750dc6ca969Sfw 			save_volprop(*php, OID_sunPlatNumericSensorExponent,
1751dc6ca969Sfw 			    row, VPT_NUMSENSOR);
1752dc6ca969Sfw 		}
1753dc6ca969Sfw 		break;
1754dc6ca969Sfw 
17550d63ce2bSvenki 	case PP_REPLACEABLE:
17560d63ce2bSvenki 		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable,
17570d63ce2bSvenki 		    row, &val, snmp_syserr_p);
17580d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17590d63ce2bSvenki 		if ((ret == 0) && (val == ST_TRUE))
17600d63ce2bSvenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE);
17611c60fca8Sfw 		if (ret == -1)
17621c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17631c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17641c60fca8Sfw 			    OID_sunPlatCircuitPackReplaceable, row);
17650d63ce2bSvenki 		break;
17660d63ce2bSvenki 
17670d63ce2bSvenki 	case PP_HOTSWAPPABLE:
17680d63ce2bSvenki 		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable,
17690d63ce2bSvenki 		    row, &val, snmp_syserr_p);
17700d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17710d63ce2bSvenki 		if ((ret == 0) && (val == ST_TRUE))
17720d63ce2bSvenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE);
17731c60fca8Sfw 		if (ret == -1)
17741c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17751c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17761c60fca8Sfw 			    OID_sunPlatCircuitPackHotSwappable, row);
17770d63ce2bSvenki 		break;
17780d63ce2bSvenki 
17790d63ce2bSvenki 	case PP_IS_FRU:
17800d63ce2bSvenki 		ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row,
17810d63ce2bSvenki 		    &val, snmp_syserr_p);
17820d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17830d63ce2bSvenki 		if ((ret == 0) && (val == ST_TRUE))
17840d63ce2bSvenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_FRU);
17851c60fca8Sfw 		if (ret == -1)
17861c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17871c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17881c60fca8Sfw 			    OID_entPhysicalIsFRU, row);
17890d63ce2bSvenki 		break;
17900d63ce2bSvenki 
17910d63ce2bSvenki 	case PP_HW_REVISION:
17920d63ce2bSvenki 		ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev,
17930d63ce2bSvenki 		    row, &hw_revision, snmp_syserr_p);
17940d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17952ea390f3SMichael Bergknoff 		if ((ret == 0) && hw_revision) {
17960d63ce2bSvenki 			(void) add_string_prop(nodeh,
17970d63ce2bSvenki 			    PICL_PROP_HW_REVISION, hw_revision);
17980d63ce2bSvenki 			free((void *) hw_revision);
17990d63ce2bSvenki 		}
18001c60fca8Sfw 		if (ret == -1)
18011c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18021c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18031c60fca8Sfw 			    OID_entPhysicalHardwareRev, row);
18040d63ce2bSvenki 		break;
18050d63ce2bSvenki 
18060d63ce2bSvenki 	case PP_FW_REVISION:
18070d63ce2bSvenki 		ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev,
18080d63ce2bSvenki 		    row, &fw_revision, snmp_syserr_p);
18090d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18102ea390f3SMichael Bergknoff 		if ((ret == 0) && fw_revision) {
18110d63ce2bSvenki 			(void) add_string_prop(nodeh,
18120d63ce2bSvenki 			    PICL_PROP_FW_REVISION, fw_revision);
18130d63ce2bSvenki 			free((void *) fw_revision);
18140d63ce2bSvenki 		}
18151c60fca8Sfw 		if (ret == -1)
18161c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18171c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18181c60fca8Sfw 			    OID_entPhysicalFirmwareRev, row);
18190d63ce2bSvenki 		break;
18200d63ce2bSvenki 
18210d63ce2bSvenki 	case PP_MFG_NAME:
18220d63ce2bSvenki 		ret = snmp_get_str(hdl, OID_entPhysicalMfgName,
18230d63ce2bSvenki 		    row, &mfg_name, snmp_syserr_p);
18240d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18252ea390f3SMichael Bergknoff 		if ((ret == 0) && mfg_name) {
18260d63ce2bSvenki 			(void) add_string_prop(nodeh,
18270d63ce2bSvenki 			    PICL_PROP_MFG_NAME, mfg_name);
18280d63ce2bSvenki 			free((void *) mfg_name);
18290d63ce2bSvenki 		}
18301c60fca8Sfw 		if (ret == -1)
18311c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18321c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18331c60fca8Sfw 			    OID_entPhysicalMfgName, row);
18340d63ce2bSvenki 		break;
18350d63ce2bSvenki 
18360d63ce2bSvenki 	case PP_MODEL_NAME:
18370d63ce2bSvenki 		ret = snmp_get_str(hdl, OID_entPhysicalModelName,
18380d63ce2bSvenki 		    row, &model_name, snmp_syserr_p);
18390d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18402ea390f3SMichael Bergknoff 		if ((ret == 0) && model_name) {
18410d63ce2bSvenki 			(void) add_string_prop(nodeh,
18420d63ce2bSvenki 			    PICL_PROP_MODEL_NAME, model_name);
18430d63ce2bSvenki 			free((void *) model_name);
18440d63ce2bSvenki 		}
18451c60fca8Sfw 		if (ret == -1)
18461c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18471c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18481c60fca8Sfw 			    OID_entPhysicalModelName, row);
18490d63ce2bSvenki 		break;
18500d63ce2bSvenki 
18510d63ce2bSvenki 	case PP_DESCRIPTION:
18520d63ce2bSvenki 		ret = snmp_get_str(hdl, OID_entPhysicalDescr,
18530d63ce2bSvenki 		    row, &phys_descr, snmp_syserr_p);
18540d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18552ea390f3SMichael Bergknoff 		if ((ret == 0) && phys_descr) {
1856aaba19e2Sfw 			(void) add_string_prop(nodeh,
1857aaba19e2Sfw 			    PICL_PROP_PHYS_DESCRIPTION, phys_descr);
1858aaba19e2Sfw 			free((void *) phys_descr);
18590d63ce2bSvenki 		}
18601c60fca8Sfw 		if (ret == -1)
18611c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18621c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18631c60fca8Sfw 			    OID_entPhysicalDescr, row);
18640d63ce2bSvenki 		break;
18650d63ce2bSvenki 
18660d63ce2bSvenki 	case PP_LABEL:
18670d63ce2bSvenki 		if (label && *label)
18680d63ce2bSvenki 			(void) add_string_prop(nodeh, PICL_PROP_LABEL, label);
18690d63ce2bSvenki 		break;
18700d63ce2bSvenki 
18710d63ce2bSvenki 	case PP_BASE_UNITS:
18720d63ce2bSvenki 		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits,
18730d63ce2bSvenki 		    row, &val, snmp_syserr_p);
18740d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18750d63ce2bSvenki 		if ((ret == 0) && (val > 0) && (val < n_baseunits)) {
18760d63ce2bSvenki 			(void) add_string_prop(nodeh,
18770d63ce2bSvenki 			    PICL_PROP_BASE_UNITS, sensor_baseunits[val]);
18780d63ce2bSvenki 		}
18791c60fca8Sfw 		if (ret == -1)
18801c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18811c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18821c60fca8Sfw 			    OID_sunPlatNumericSensorBaseUnits, row);
18830d63ce2bSvenki 		break;
18840d63ce2bSvenki 
18850d63ce2bSvenki 	case PP_RATE_UNITS:
18860d63ce2bSvenki 		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits,
18870d63ce2bSvenki 		    row, &val, snmp_syserr_p);
18880d63ce2bSvenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18890d63ce2bSvenki 		if ((ret == 0) && (val > 0) && (val < n_rateunits)) {
18900d63ce2bSvenki 			(void) add_string_prop(nodeh,
18910d63ce2bSvenki 			    PICL_PROP_RATE_UNITS, sensor_rateunits[val]);
18920d63ce2bSvenki 		}
18931c60fca8Sfw 		if (ret == -1)
18941c60fca8Sfw 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18951c60fca8Sfw 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18961c60fca8Sfw 			    OID_sunPlatNumericSensorRateUnits, row);
18970d63ce2bSvenki 		break;
18980d63ce2bSvenki 	}
18990d63ce2bSvenki }
19000d63ce2bSvenki 
1901817697f4SKelly Moyer /*
1902817697f4SKelly Moyer  * Initialize the SNMP library's cache refresh subsystem, then periodically
1903817697f4SKelly Moyer  * process refresh job to prevent cache entries from expiring.
1904817697f4SKelly Moyer  */
1905817697f4SKelly Moyer /*ARGSUSED*/
1906817697f4SKelly Moyer static void *
cache_refresher(void * arg)1907817697f4SKelly Moyer cache_refresher(void *arg)
1908817697f4SKelly Moyer {
1909817697f4SKelly Moyer 	int		jobs;
1910817697f4SKelly Moyer 	int		next_expiration;
1911817697f4SKelly Moyer 	timestruc_t	to;
1912817697f4SKelly Moyer 	hrtime_t	cycle_start, cycle_elapsed;
1913817697f4SKelly Moyer 
1914817697f4SKelly Moyer 	/*
1915817697f4SKelly Moyer 	 * Initialize refresh subsystem
1916817697f4SKelly Moyer 	 */
1917817697f4SKelly Moyer 	LOGPRINTF("Initializing SNMP refresh subsystem.\n");
1918817697f4SKelly Moyer 	if (snmp_refresh_init() < 0) {
1919817697f4SKelly Moyer 		return ((void *)-1);
1920817697f4SKelly Moyer 	}
1921817697f4SKelly Moyer 
1922817697f4SKelly Moyer 	(void) mutex_lock(&cache_refresh_lock);
1923817697f4SKelly Moyer 
1924817697f4SKelly Moyer 
1925817697f4SKelly Moyer 	for (;;) {
1926817697f4SKelly Moyer 		cycle_start = gethrtime();
1927817697f4SKelly Moyer 
1928817697f4SKelly Moyer 		/*
1929817697f4SKelly Moyer 		 * Process jobs from the snmp cache refresh work queue until one
1930817697f4SKelly Moyer 		 * of the following conditions is true:
1931817697f4SKelly Moyer 		 * 1) we are told to exit, or
1932817697f4SKelly Moyer 		 * 2) we have processed at least as many jobs as recommended by
1933817697f4SKelly Moyer 		 * the library, and the next job expiration is at least
1934817697f4SKelly Moyer 		 * CACHE_REFRESH_MIN_WINDOW * seconds away.
1935817697f4SKelly Moyer 		 */
1936817697f4SKelly Moyer 		jobs = snmp_refresh_get_cycle_hint(CACHE_REFRESH_CYCLE);
1937817697f4SKelly Moyer 		while ((cache_refresh_thr_exit == B_FALSE) && (jobs > 0)) {
1938817697f4SKelly Moyer 			(void) snmp_refresh_process_job();
1939817697f4SKelly Moyer 			jobs--;
1940817697f4SKelly Moyer 		}
1941817697f4SKelly Moyer 
1942817697f4SKelly Moyer 		next_expiration = snmp_refresh_get_next_expiration();
1943817697f4SKelly Moyer 		while ((cache_refresh_thr_exit == B_FALSE) &&
1944817697f4SKelly Moyer 		    ((next_expiration >= 0) &&
1945817697f4SKelly Moyer 		    (next_expiration < CACHE_REFRESH_MIN_WINDOW))) {
1946817697f4SKelly Moyer 			(void) snmp_refresh_process_job();
1947817697f4SKelly Moyer 			next_expiration = snmp_refresh_get_next_expiration();
1948817697f4SKelly Moyer 		}
1949817697f4SKelly Moyer 
1950817697f4SKelly Moyer 		/*
1951817697f4SKelly Moyer 		 * As long as we haven't been told to exit, sleep for
1952817697f4SKelly Moyer 		 * CACHE_REFRESH_CYCLE seconds minus the amount of time that has
1953817697f4SKelly Moyer 		 * elapsed since this cycle started.  If the elapsed time is
1954817697f4SKelly Moyer 		 * equal to or greater than 60 seconds, skip sleeping entirely.
1955817697f4SKelly Moyer 		 */
1956817697f4SKelly Moyer 		cycle_elapsed = (gethrtime() - cycle_start) / NANOSEC;
1957817697f4SKelly Moyer 		if ((cache_refresh_thr_exit == B_FALSE) &&
1958817697f4SKelly Moyer 		    (cycle_elapsed < CACHE_REFRESH_CYCLE)) {
1959817697f4SKelly Moyer 			to.tv_sec = CACHE_REFRESH_CYCLE - cycle_elapsed;
1960817697f4SKelly Moyer 			to.tv_nsec = 0;
1961817697f4SKelly Moyer 			(void) cond_reltimedwait(&cache_refresh_cv,
1962817697f4SKelly Moyer 			    &cache_refresh_lock, &to);
1963817697f4SKelly Moyer 		}
1964817697f4SKelly Moyer 
1965817697f4SKelly Moyer 		/*
1966817697f4SKelly Moyer 		 * If we have been told to exit, clean up and bail out.
1967817697f4SKelly Moyer 		 */
1968817697f4SKelly Moyer 		if (cache_refresh_thr_exit == B_TRUE) {
1969817697f4SKelly Moyer 			snmp_refresh_fini();
1970817697f4SKelly Moyer 			(void) mutex_unlock(&cache_refresh_lock);
1971817697f4SKelly Moyer 			LOGPRINTF("cache_refresher: time to exit\n");
1972817697f4SKelly Moyer 			return (NULL);
1973817697f4SKelly Moyer 		}
1974817697f4SKelly Moyer 
1975817697f4SKelly Moyer 	}
1976817697f4SKelly Moyer 
1977817697f4SKelly Moyer 	/*NOTREACHED*/
1978817697f4SKelly Moyer 	return (NULL);
1979817697f4SKelly Moyer }
1980817697f4SKelly Moyer 
1981817697f4SKelly Moyer /*
1982817697f4SKelly Moyer  * Check to see if the cache_refresher thread is running.  If it is, signal it
1983817697f4SKelly Moyer  * to terminate and clean up associated data structures.
1984817697f4SKelly Moyer  */
1985817697f4SKelly Moyer void
cache_refresher_fini(void)1986817697f4SKelly Moyer cache_refresher_fini(void)
1987817697f4SKelly Moyer {
1988817697f4SKelly Moyer 	/* if the thread isn't running, there is nothing to do */
1989817697f4SKelly Moyer 	if (cache_refresh_thr_exit == B_TRUE)
1990817697f4SKelly Moyer 		return;
1991817697f4SKelly Moyer 
1992817697f4SKelly Moyer 	/* wake up the cache_refresher thread, tell it to exit */
1993817697f4SKelly Moyer 	(void) mutex_lock(&cache_refresh_lock);
1994817697f4SKelly Moyer 	cache_refresh_thr_exit = B_TRUE;
1995817697f4SKelly Moyer 	(void) cond_signal(&cache_refresh_cv);
1996817697f4SKelly Moyer 	(void) mutex_unlock(&cache_refresh_lock);
1997817697f4SKelly Moyer 
1998817697f4SKelly Moyer 	/* reap the thread */
1999817697f4SKelly Moyer 	(void) thr_join(cache_refresh_thr_id, NULL, NULL);
2000817697f4SKelly Moyer 
2001817697f4SKelly Moyer 	/* finish cleanup... */
2002817697f4SKelly Moyer 	(void) cond_destroy(&cache_refresh_cv);
2003817697f4SKelly Moyer 	(void) mutex_destroy(&cache_refresh_lock);
2004817697f4SKelly Moyer }
2005817697f4SKelly Moyer 
20060d63ce2bSvenki /*VARARGS2*/
20070d63ce2bSvenki static void
log_msg(int pri,const char * fmt,...)20080d63ce2bSvenki log_msg(int pri, const char *fmt, ...)
20090d63ce2bSvenki {
20100d63ce2bSvenki 	va_list ap;
20110d63ce2bSvenki 
20120d63ce2bSvenki 	va_start(ap, fmt);
20130d63ce2bSvenki 	vsyslog(pri, fmt, ap);
20140d63ce2bSvenki 	va_end(ap);
20150d63ce2bSvenki }
20160d63ce2bSvenki 
20170d63ce2bSvenki #ifdef SNMPPLUGIN_DEBUG
20180d63ce2bSvenki 
20190d63ce2bSvenki static void
snmpplugin_log_init(void)20200d63ce2bSvenki snmpplugin_log_init(void)
20210d63ce2bSvenki {
20220d63ce2bSvenki 	(void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL);
20230d63ce2bSvenki }
20240d63ce2bSvenki 
20250d63ce2bSvenki static void
snmpplugin_log(const char * fmt,...)20260d63ce2bSvenki snmpplugin_log(const char *fmt, ...)
20270d63ce2bSvenki {
20280d63ce2bSvenki 	va_list	ap;
20290d63ce2bSvenki 
20300d63ce2bSvenki 	(void) mutex_lock(&snmpplugin_dbuf_lock);
20310d63ce2bSvenki 
20320d63ce2bSvenki 	va_start(ap, fmt);
20330d63ce2bSvenki 	(void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap);
20340d63ce2bSvenki 	snmpplugin_log_append();
20350d63ce2bSvenki 	va_end(ap);
20360d63ce2bSvenki 
20370d63ce2bSvenki 	(void) mutex_unlock(&snmpplugin_dbuf_lock);
20380d63ce2bSvenki }
20390d63ce2bSvenki 
20400d63ce2bSvenki static void
snmpplugin_log_append(void)20410d63ce2bSvenki snmpplugin_log_append(void)
20420d63ce2bSvenki {
20430d63ce2bSvenki 	int	len;
20440d63ce2bSvenki 
20450d63ce2bSvenki 	len = strlen(snmpplugin_lbuf);
20460d63ce2bSvenki 
20470d63ce2bSvenki 	if ((snmpplugin_dbuf_curp + len) >=
20480d63ce2bSvenki 	    (snmpplugin_dbuf + snmpplugin_dbuf_sz)) {
20490d63ce2bSvenki 		snmpplugin_dbuf_realloc();
20500d63ce2bSvenki 		if (snmpplugin_dbuf == NULL) {
20510d63ce2bSvenki 			return;
20520d63ce2bSvenki 		}
20530d63ce2bSvenki 	}
20540d63ce2bSvenki 
20550d63ce2bSvenki 	(void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf);
20560d63ce2bSvenki 	snmpplugin_dbuf_curp += len;
20570d63ce2bSvenki }
20580d63ce2bSvenki 
20590d63ce2bSvenki static void
snmpplugin_dbuf_realloc(void)20600d63ce2bSvenki snmpplugin_dbuf_realloc(void)
20610d63ce2bSvenki {
20620d63ce2bSvenki 	char	*p;
20630d63ce2bSvenki 	size_t	offset = 0;
20640d63ce2bSvenki 	size_t	count;
20650d63ce2bSvenki 
20660d63ce2bSvenki 	count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ;
20670d63ce2bSvenki 	if ((p = (char *)calloc(count, 1)) == NULL) {
20680d63ce2bSvenki 		snmpplugin_dbuf_overflow++;
20690d63ce2bSvenki 		snmpplugin_dbuf_curp = snmpplugin_dbuf;
20700d63ce2bSvenki 		return;
20710d63ce2bSvenki 	}
20720d63ce2bSvenki 
20730d63ce2bSvenki 	if (snmpplugin_dbuf) {
20740d63ce2bSvenki 		offset = snmpplugin_dbuf_curp - snmpplugin_dbuf;
20750d63ce2bSvenki 		(void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz);
20760d63ce2bSvenki 		free(snmpplugin_dbuf);
20770d63ce2bSvenki 	}
20780d63ce2bSvenki 
20790d63ce2bSvenki 	snmpplugin_dbuf = p;
20800d63ce2bSvenki 	snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ;
20810d63ce2bSvenki 
20820d63ce2bSvenki 	snmpplugin_dbuf_curp = snmpplugin_dbuf + offset;
20830d63ce2bSvenki }
20840d63ce2bSvenki #endif
2085