xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.c (revision 11471:d775393d483f)
13941Svenki /*
23941Svenki  * CDDL HEADER START
33941Svenki  *
43941Svenki  * The contents of this file are subject to the terms of the
53941Svenki  * Common Development and Distribution License (the "License").
63941Svenki  * You may not use this file except in compliance with the License.
73941Svenki  *
83941Svenki  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93941Svenki  * or http://www.opensolaris.org/os/licensing.
103941Svenki  * See the License for the specific language governing permissions
113941Svenki  * and limitations under the License.
123941Svenki  *
133941Svenki  * When distributing Covered Code, include this CDDL HEADER in each
143941Svenki  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153941Svenki  * If applicable, add the following below this CDDL HEADER, with the
163941Svenki  * fields enclosed by brackets "[]" replaced with your own identifying
173941Svenki  * information: Portions Copyright [yyyy] [name of copyright owner]
183941Svenki  *
193941Svenki  * CDDL HEADER END
203941Svenki  */
213941Svenki 
223941Svenki /*
23*11471SMichael.Bergknoff@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
243941Svenki  * Use is subject to license terms.
253941Svenki  */
263941Svenki 
273941Svenki /*
283941Svenki  * The SNMP picl plugin connects to the agent on the SP and creates
293941Svenki  * and populates the /physical-platform subtree in picl tree for use
303941Svenki  * by picl consumers.
313941Svenki  */
323941Svenki 
333941Svenki #include <stdio.h>
343941Svenki #include <stdlib.h>
353941Svenki #include <string.h>
363941Svenki #include <syslog.h>
373941Svenki #include <stdarg.h>
383941Svenki #include <libgen.h>
393941Svenki #include <libintl.h>
403941Svenki #include <thread.h>
413941Svenki #include <synch.h>
423941Svenki #include <errno.h>
437746SKelly.Moyer@Sun.COM #include <time.h>
44*11471SMichael.Bergknoff@Sun.COM #include <signal.h>
453941Svenki 
463941Svenki #include <picldefs.h>
473941Svenki #include <picl.h>
483941Svenki #include <picltree.h>
493941Svenki 
503941Svenki #include "picloids.h"
513941Svenki #include "libpiclsnmp.h"
523941Svenki #include "snmpplugin.h"
533941Svenki 
543941Svenki #pragma init(snmpplugin_register)	/* place in .init section */
553941Svenki 
563941Svenki picld_plugin_reg_t snmpplugin_reg = {
573941Svenki 	PICLD_PLUGIN_VERSION_1,
583941Svenki 	PICLD_PLUGIN_NON_CRITICAL,
593941Svenki 	"snmp_plugin",
603941Svenki 	snmpplugin_init,
613941Svenki 	snmpplugin_fini
623941Svenki };
633941Svenki 
643941Svenki static picl_snmphdl_t	hdl;
653941Svenki 
663941Svenki /*
673941Svenki  * The stale_tree_rwlp protects the stale_xxx vars. The 'stale_tree' flag
683941Svenki  * and the 'rebuild_tree' flag below are both initialized to B_TRUE to
693941Svenki  * let the tree_builder() thread build the initial tree without blocking.
703941Svenki  */
713941Svenki static rwlock_t		stale_tree_rwlp;
723941Svenki static boolean_t	stale_tree = B_TRUE;
733941Svenki 
743941Svenki /*
753941Svenki  * vol_props, volprop_ndx and n_vol_props are protected by the stale_tree
763941Svenki  * flag.  They are read only when the stale_tree flag is B_FALSE and written
773941Svenki  * to only when the flag is B_TRUE.
783941Svenki  *
793941Svenki  * The change_time (last changed time) is read by only one thread at a
803941Svenki  * time when stale_tree is B_FALSE (protected by stale_tree_rwlp).  It is
813941Svenki  * written by only one thread (the tree builder) when stale_tree is B_TRUE.
823941Svenki  *
833941Svenki  * Note that strictly speaking, change_time should be uint_t (timeticks32).
843941Svenki  * But keeping it as int is fine, since we don't do any arithmetic on it
853941Svenki  * except equality check.
863941Svenki  */
873941Svenki static vol_prophdl_t	*vol_props = NULL;
883941Svenki static int		volprop_ndx = 0, n_vol_props = 0;
893941Svenki static int		change_time = 0;
905723Sfw157321 static time_t		change_time_check;
913941Svenki 
923941Svenki /*
933941Svenki  * The rebuild_tree_lock and cv are used by the tree builder thread.
943941Svenki  * rebuild_tree has to be initialized to B_TRUE to let the tree_builder
953941Svenki  * do the first build without blocking.
963941Svenki  */
973941Svenki static mutex_t		rebuild_tree_lock;
983941Svenki static cond_t		rebuild_tree_cv;
993941Svenki static boolean_t	rebuild_tree = B_TRUE;
1005029Sfw157321 static boolean_t	tree_builder_thr_exit = B_FALSE;
1015029Sfw157321 static thread_t		tree_builder_thr_id;
1023941Svenki 
1033941Svenki /*
1047746SKelly.Moyer@Sun.COM  * The cache_refresh thread periodically queries the snmp cache refresh work
1057746SKelly.Moyer@Sun.COM  * queue and processes jobs from it to keep cache entries from expiring.  It
1067746SKelly.Moyer@Sun.COM  * attempts to run in cycles of CACHE_REFRESH_CYCLE seconds each, first
1077746SKelly.Moyer@Sun.COM  * processing cache refresh jobs and then sleeping for the remainder of the
1087746SKelly.Moyer@Sun.COM  * cycle once the next refresh job expiration is at least
1097746SKelly.Moyer@Sun.COM  * CACHE_REFRESH_MIN_WINDOW seconds in the future.
1107746SKelly.Moyer@Sun.COM  *
1117746SKelly.Moyer@Sun.COM  * NOTE: By using a thread to keep the SNMP cache refreshed in the background,
1127746SKelly.Moyer@Sun.COM  * we are both adding load to the system and reducing the system's ability to
1137746SKelly.Moyer@Sun.COM  * operate in power-saving mode when there is minimal load.  While these
1147746SKelly.Moyer@Sun.COM  * tradeoffs are acceptable at this time in light of customer concerns about
1157746SKelly.Moyer@Sun.COM  * performance, it may be desirable in the future to move this work into the
1167746SKelly.Moyer@Sun.COM  * firmware.  Also, while the current cycle times performed well on the largest
1177746SKelly.Moyer@Sun.COM  * sun4v config currently available (Batoka), they may need to be revisited for
1187746SKelly.Moyer@Sun.COM  * future systems if the number of sensors increases significantly.
1197746SKelly.Moyer@Sun.COM  */
1207746SKelly.Moyer@Sun.COM #define	CACHE_REFRESH_CYCLE		60
1217746SKelly.Moyer@Sun.COM #define	CACHE_REFRESH_MIN_WINDOW	75
1227746SKelly.Moyer@Sun.COM static mutex_t		cache_refresh_lock;
1237746SKelly.Moyer@Sun.COM static cond_t		cache_refresh_cv;
1247746SKelly.Moyer@Sun.COM static boolean_t	cache_refresh_thr_exit = B_FALSE;
1257746SKelly.Moyer@Sun.COM static thread_t		cache_refresh_thr_id;
1267746SKelly.Moyer@Sun.COM 
1277746SKelly.Moyer@Sun.COM /*
1283941Svenki  * These two should really not be global
1293941Svenki  */
1303941Svenki static picl_nodehdl_t	*physplat_nodes = NULL;
1313941Svenki static int		n_physplat_nodes = 0;
1323941Svenki 
1333941Svenki static char *group1[] = {
1343941Svenki 	OID_entPhysicalDescr,
1353941Svenki 	OID_entPhysicalContainedIn,
1363941Svenki 	OID_entPhysicalClass,
1373941Svenki 	OID_entPhysicalName,
1383941Svenki 	OID_entPhysicalHardwareRev,
1393941Svenki 	OID_entPhysicalFirmwareRev,
1403941Svenki 	OID_entPhysicalSerialNum,
1413941Svenki 	OID_entPhysicalMfgName,
1423941Svenki 	OID_entPhysicalModelName,
1433941Svenki 	OID_entPhysicalIsFRU,
1443941Svenki 	0
1453941Svenki };
1463941Svenki 
1473941Svenki static char *group2[] = {
1483941Svenki 	OID_sunPlatEquipmentHolderAcceptableTypes,
1493941Svenki 	OID_sunPlatCircuitPackReplaceable,
1503941Svenki 	OID_sunPlatCircuitPackHotSwappable,
1513941Svenki 	OID_sunPlatPhysicalClass,
1523941Svenki 	OID_sunPlatSensorClass,
1533941Svenki 	OID_sunPlatSensorType,
1543941Svenki 	OID_sunPlatAlarmType,
1553941Svenki 	OID_sunPlatPowerSupplyClass,
1563941Svenki 	0
1573941Svenki };
1583941Svenki 
1595723Sfw157321 static char *group3[] = {
1605723Sfw157321 	OID_sunPlatNumericSensorEnabledThresholds,
1615723Sfw157321 	OID_sunPlatNumericSensorBaseUnits,
1625723Sfw157321 	OID_sunPlatNumericSensorRateUnits,
1635723Sfw157321 	0
1645723Sfw157321 };
1655723Sfw157321 
1665723Sfw157321 static char *group4[] = {
1675723Sfw157321 	OID_sunPlatBinarySensorInterpretTrue,
1685723Sfw157321 	OID_sunPlatBinarySensorInterpretFalse,
1698411SKelly.Moyer@Sun.COM 	0
1705723Sfw157321 };
1715723Sfw157321 
1723941Svenki static char *volgroup1[] = {
1733941Svenki 	OID_sunPlatBinarySensorCurrent,
1743941Svenki 	OID_sunPlatBinarySensorExpected,
1753941Svenki 	0
1763941Svenki };
1773941Svenki 
1783941Svenki static char *volgroup2[] = {
1793941Svenki 	OID_sunPlatNumericSensorExponent,
1803941Svenki 	OID_sunPlatNumericSensorCurrent,
1813941Svenki 	OID_sunPlatNumericSensorLowerThresholdFatal,
1823941Svenki 	OID_sunPlatNumericSensorLowerThresholdCritical,
1833941Svenki 	OID_sunPlatNumericSensorLowerThresholdNonCritical,
1843941Svenki 	OID_sunPlatNumericSensorUpperThresholdNonCritical,
1853941Svenki 	OID_sunPlatNumericSensorUpperThresholdCritical,
1863941Svenki 	OID_sunPlatNumericSensorUpperThresholdFatal,
1873941Svenki 	0
1883941Svenki };
1893941Svenki 
1905723Sfw157321 static char *volgroup3[] = {
1915723Sfw157321 	OID_sunPlatEquipmentOperationalState,
1925723Sfw157321 	0
1935723Sfw157321 };
1945723Sfw157321 
1955723Sfw157321 static char *volgroup4[] = {
1965723Sfw157321 	OID_sunPlatAlarmState,
1975723Sfw157321 	0
1985723Sfw157321 };
1995723Sfw157321 
2005723Sfw157321 static char *volgroup5[] = {
2015723Sfw157321 	OID_sunPlatBatteryStatus,
2025723Sfw157321 	0
2035723Sfw157321 };
2045723Sfw157321 
2053941Svenki /*
2063941Svenki  * The following two items must match the Sun Platform MIB specification
2073941Svenki  * in their indices and values.
2083941Svenki  */
2093941Svenki static char *sensor_baseunits[] = {
2103941Svenki 	"", "other", "unknown", "degC", "degF", "degK", "volts", "amps",
2113941Svenki 	"watts", "joules", "coulombs", "va", "nits", "lumens", "lux",
2123941Svenki 	"candelas", "kPa", "psi", "newtons", "cfm", "rpm", "hertz",
2133941Svenki 	"seconds", "minutes", "hours", "days", "weeks", "mils", "inches",
2143941Svenki 	"feet", "cubicInches", "cubicFeet", "meters", "cubicCentimeters",
2153941Svenki 	"cubicMeters", "liters", "fluidOunces", "radians", "steradians",
2163941Svenki 	"revolutions", "cycles", "gravities", "ounces", "pounds", "footPounds",
2173941Svenki 	"ounceInches", "gauss", "gilberts", "henries", "farads", "ohms",
2183941Svenki 	"siemens", "moles", "becquerels", "ppm", "decibels", "dBA", "dbC",
2193941Svenki 	"grays", "sieverts", "colorTemperatureDegK", "bits", "bytes", "words",
2203941Svenki 	"doubleWords", "quadWords", "percentage"
2213941Svenki };
2223941Svenki static const int n_baseunits = sizeof (sensor_baseunits) / sizeof (char *);
2233941Svenki 
2243941Svenki static char *sensor_rateunits[] = {
2253941Svenki 	"",
2263941Svenki 	"none",
2273941Svenki 	"perMicroSecond",
2283941Svenki 	"perMilliSecond",
2293941Svenki 	"perSecond",
2303941Svenki 	"perMinute",
2313941Svenki 	"perHour",
2323941Svenki 	"perDay",
2333941Svenki 	"perWeek",
2343941Svenki 	"perMonth",
2353941Svenki 	"perYear"
2363941Svenki };
2373941Svenki static const int n_rateunits = sizeof (sensor_rateunits) / sizeof (char *);
2383941Svenki 
2393941Svenki /*
2403941Svenki  * Local declarations
2413941Svenki  */
2423941Svenki static void snmpplugin_register(void);
2433941Svenki static void register_group(char **g, int is_volatile);
2443941Svenki static void *tree_builder(void *arg);
2453941Svenki static int build_physplat(picl_nodehdl_t *subtree_rootp);
2463941Svenki static void free_resources(picl_nodehdl_t subtree_root);
2473941Svenki 
2483941Svenki static picl_nodehdl_t make_node(picl_nodehdl_t subtree_root, int row,
2493941Svenki     int *snmp_syserr_p);
2503941Svenki static void save_nodeh(picl_nodehdl_t nodeh, int row);
2513941Svenki static picl_nodehdl_t lookup_nodeh(int row);
2523941Svenki 
2533941Svenki static void save_volprop(picl_prophdl_t prop, char *oidstr, int row,
2543941Svenki     int proptype);
2555723Sfw157321 static void check_for_stale_data(boolean_t nocache);
2563941Svenki static int read_volprop(ptree_rarg_t *parg, void *buf);
2573941Svenki 
2583941Svenki static void threshold(picl_nodehdl_t node, char *oidstr, int row,
2593941Svenki     char *propname, int *snmp_syserr_p);
2603941Svenki static void add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p);
2613941Svenki 
2623941Svenki static char *get_slot_type(int row, int *snmp_syserr_p);
2633941Svenki static int add_volatile_prop(picl_nodehdl_t nodeh, char *name,
2643941Svenki     int type, int access, int size, int (*rdfunc)(ptree_rarg_t *, void *),
2653941Svenki     int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp);
2663941Svenki static int add_string_prop(picl_nodehdl_t node, char *propname, char *propval);
2673941Svenki static int add_void_prop(picl_nodehdl_t node, char *propname);
2683941Svenki static void add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
2693941Svenki     int row, sp_propid_t pp, int *snmp_syserr_p);
2703941Svenki 
2717746SKelly.Moyer@Sun.COM static void *cache_refresher(void *arg);
2727746SKelly.Moyer@Sun.COM static void cache_refresher_fini(void);
2737746SKelly.Moyer@Sun.COM 
2743941Svenki static void log_msg(int pri, const char *fmt, ...);
2753941Svenki 
2763941Svenki #ifdef SNMPPLUGIN_DEBUG
2773941Svenki static mutex_t	snmpplugin_dbuf_lock;
2783941Svenki static char	*snmpplugin_dbuf = NULL;
2793941Svenki static char	*snmpplugin_dbuf_curp = NULL;
2803941Svenki static int	snmpplugin_dbuf_sz = 0;
2813941Svenki static int	snmpplugin_dbuf_overflow = 0;
2823941Svenki static char	snmpplugin_lbuf[SNMPPLUGIN_DMAX_LINE];
2833941Svenki 
2843941Svenki static void	snmpplugin_log_init(void);
2853941Svenki static void	snmpplugin_log(const char *fmt, ...);
2863941Svenki static void	snmpplugin_log_append(void);
2873941Svenki static void	snmpplugin_dbuf_realloc(void);
2883941Svenki #endif
2893941Svenki 
2903941Svenki static void
snmpplugin_register(void)2913941Svenki snmpplugin_register(void)
2923941Svenki {
2933941Svenki 	(void) picld_plugin_register(&snmpplugin_reg);
2943941Svenki }
2953941Svenki 
2963941Svenki static void
register_group(char ** g,int is_volatile)2973941Svenki register_group(char **g, int is_volatile)
2983941Svenki {
2993941Svenki 	int	i, len = 0;
3003941Svenki 	int	n_oids;
3013941Svenki 	char	*p, *oidstrs;
3023941Svenki 
3033941Svenki 	for (i = 0; g[i]; i++)
3043941Svenki 		len += strlen(g[i]) + 1;
3053941Svenki 	n_oids = i;
3063941Svenki 
3073941Svenki 	if ((oidstrs = (char *)calloc(1, len)) == NULL)
3083941Svenki 		return;
3093941Svenki 
3103941Svenki 	for (p = oidstrs, i = 0; g[i]; i++) {
3113941Svenki 		(void) strcpy(p, g[i]);
3123941Svenki 		p += strlen(g[i]) + 1;
3133941Svenki 	}
3143941Svenki 
3153941Svenki 	snmp_register_group(hdl, oidstrs, n_oids, is_volatile);
3167382SMichael.Bergknoff@Sun.COM 	free(oidstrs);
3173941Svenki }
3183941Svenki 
3193941Svenki void
snmpplugin_init(void)3203941Svenki snmpplugin_init(void)
3213941Svenki {
3223941Svenki 	int		ret;
3233941Svenki 
3243941Svenki 	(void) mutex_init(&rebuild_tree_lock, USYNC_THREAD, NULL);
3253941Svenki 	(void) cond_init(&rebuild_tree_cv, USYNC_THREAD, NULL);
3263941Svenki 	(void) rwlock_init(&stale_tree_rwlp, USYNC_THREAD, NULL);
3275029Sfw157321 	tree_builder_thr_exit = B_FALSE;
3285029Sfw157321 
3293941Svenki 	LOGINIT();
3303941Svenki 
3313941Svenki 	/*
3323941Svenki 	 * Create the tree-builder thread and let it take over
3333941Svenki 	 */
3343941Svenki 	LOGPRINTF("Tree-builder thread being created.\n");
3353941Svenki 	if ((ret = thr_create(NULL, NULL, tree_builder, NULL,
3365029Sfw157321 	    THR_BOUND, &tree_builder_thr_id)) < 0) {
3373941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_CREATE_TREE_BUILDER, ret);
3383941Svenki 		snmp_fini(hdl);
3395029Sfw157321 		hdl = NULL;
3405029Sfw157321 		(void) rwlock_destroy(&stale_tree_rwlp);
3415029Sfw157321 		(void) cond_destroy(&rebuild_tree_cv);
3425029Sfw157321 		(void) mutex_destroy(&rebuild_tree_lock);
3435029Sfw157321 		tree_builder_thr_exit = B_TRUE;
3447746SKelly.Moyer@Sun.COM 
3457746SKelly.Moyer@Sun.COM 		return;
3467746SKelly.Moyer@Sun.COM 	}
3477746SKelly.Moyer@Sun.COM 
3487746SKelly.Moyer@Sun.COM 	/*
3497746SKelly.Moyer@Sun.COM 	 * While the cache refresher thread does improve performance, it is not
3507746SKelly.Moyer@Sun.COM 	 * integral to the proper function of the plugin.  If we fail to create
3517746SKelly.Moyer@Sun.COM 	 * the thread for some reason, we will simply continue without
3527746SKelly.Moyer@Sun.COM 	 * refreshing.
3537746SKelly.Moyer@Sun.COM 	 */
3547746SKelly.Moyer@Sun.COM 	(void) mutex_init(&cache_refresh_lock, USYNC_THREAD, NULL);
3557746SKelly.Moyer@Sun.COM 	(void) cond_init(&cache_refresh_cv, USYNC_THREAD, NULL);
3567746SKelly.Moyer@Sun.COM 	cache_refresh_thr_exit = B_FALSE;
3577746SKelly.Moyer@Sun.COM 
3587746SKelly.Moyer@Sun.COM 	LOGPRINTF("Cache refresher thread being created.\n");
3597746SKelly.Moyer@Sun.COM 	if (thr_create(NULL, NULL, cache_refresher, NULL, THR_BOUND,
3607746SKelly.Moyer@Sun.COM 	    &cache_refresh_thr_id) < 0) {
3617746SKelly.Moyer@Sun.COM 		(void) cond_destroy(&cache_refresh_cv);
3627746SKelly.Moyer@Sun.COM 		(void) mutex_destroy(&cache_refresh_lock);
3637746SKelly.Moyer@Sun.COM 		cache_refresh_thr_exit = B_TRUE;
3643941Svenki 	}
3653941Svenki }
3663941Svenki 
3673941Svenki void
snmpplugin_fini(void)3683941Svenki snmpplugin_fini(void)
3693941Svenki {
3705029Sfw157321 
3715029Sfw157321 	if (tree_builder_thr_exit == B_TRUE)
3725029Sfw157321 		return;
3733941Svenki 
3745029Sfw157321 	/*
3755029Sfw157321 	 * Make reads of volatile properties return PICL_PROPUNAVAILABLE
3765029Sfw157321 	 * since we're about to recycle the plug-in.  No need to worry
3775029Sfw157321 	 * about removing /physical-platform since tree_builder() will
3785029Sfw157321 	 * take care of recycling it for us.
3795029Sfw157321 	 */
3805029Sfw157321 	(void) rw_wrlock(&stale_tree_rwlp);
3815029Sfw157321 	stale_tree = B_TRUE;
3825029Sfw157321 	if (vol_props) {
3835029Sfw157321 		free(vol_props);
3845029Sfw157321 	}
3855029Sfw157321 	vol_props = NULL;
3865029Sfw157321 	volprop_ndx = 0;
3875029Sfw157321 	n_vol_props = 0;
3885029Sfw157321 	(void) rw_unlock(&stale_tree_rwlp);
3895029Sfw157321 
3907746SKelly.Moyer@Sun.COM 	/* clean up the cache_refresher thread and structures */
3917746SKelly.Moyer@Sun.COM 	cache_refresher_fini();
3927746SKelly.Moyer@Sun.COM 
3935029Sfw157321 	/* wake up the tree_builder thread, tell it to exit */
3945029Sfw157321 	(void) mutex_lock(&rebuild_tree_lock);
3955029Sfw157321 	rebuild_tree = B_TRUE;
3965029Sfw157321 	tree_builder_thr_exit = B_TRUE;
3975436Sfw157321 	(void) cond_signal(&rebuild_tree_cv);
3985029Sfw157321 	(void) mutex_unlock(&rebuild_tree_lock);
3995029Sfw157321 
400*11471SMichael.Bergknoff@Sun.COM 	/* send SIGUSR1 to get tree_builder out of a blocked system call */
401*11471SMichael.Bergknoff@Sun.COM 	(void) thr_kill(tree_builder_thr_id, SIGUSR1);
402*11471SMichael.Bergknoff@Sun.COM 
4035029Sfw157321 	/* reap the thread */
4045029Sfw157321 	(void) thr_join(tree_builder_thr_id, NULL, NULL);
4055029Sfw157321 
4065029Sfw157321 	/* close the channel */
4075029Sfw157321 	if (hdl != NULL) {
4085029Sfw157321 		snmp_fini(hdl);
4095029Sfw157321 		hdl = NULL;
4105029Sfw157321 	}
4115029Sfw157321 
4125029Sfw157321 	/* finish cleanup... */
4133941Svenki 	(void) rwlock_destroy(&stale_tree_rwlp);
4143941Svenki 	(void) cond_destroy(&rebuild_tree_cv);
4153941Svenki 	(void) mutex_destroy(&rebuild_tree_lock);
4163941Svenki }
4173941Svenki 
4183941Svenki /*ARGSUSED*/
419*11471SMichael.Bergknoff@Sun.COM static void
usr1_handler(int sig,siginfo_t * siginfo,void * sigctx)420*11471SMichael.Bergknoff@Sun.COM usr1_handler(int sig, siginfo_t *siginfo, void *sigctx)
421*11471SMichael.Bergknoff@Sun.COM {
422*11471SMichael.Bergknoff@Sun.COM 	/*
423*11471SMichael.Bergknoff@Sun.COM 	 * Nothing to do here.
424*11471SMichael.Bergknoff@Sun.COM 	 * The act of catching the signal causes any cond_wait() or blocked
425*11471SMichael.Bergknoff@Sun.COM 	 * system call to return EINTR. This is used to trigger early exit from
426*11471SMichael.Bergknoff@Sun.COM 	 * the tree builder thread which may be blocked in snmp_init. More work
427*11471SMichael.Bergknoff@Sun.COM 	 * would be required to allow early exit if the tree builder thread is
428*11471SMichael.Bergknoff@Sun.COM 	 * already in its main processing loop and not blocked in cond_wait.
429*11471SMichael.Bergknoff@Sun.COM 	 */
430*11471SMichael.Bergknoff@Sun.COM }
431*11471SMichael.Bergknoff@Sun.COM 
432*11471SMichael.Bergknoff@Sun.COM /*ARGSUSED*/
4333941Svenki static void *
tree_builder(void * arg)4343941Svenki tree_builder(void *arg)
4353941Svenki {
4363941Svenki 	int		ret, rv;
4373941Svenki 	picl_nodehdl_t	root_node;
4383941Svenki 	picl_nodehdl_t	physplat_root;
4393941Svenki 	picl_nodehdl_t	old_physplat_root;
440*11471SMichael.Bergknoff@Sun.COM 	struct sigaction	act;
441*11471SMichael.Bergknoff@Sun.COM 
442*11471SMichael.Bergknoff@Sun.COM 	/*
443*11471SMichael.Bergknoff@Sun.COM 	 * catch SIGUSR1 to allow early exit from snmp_init which may block
444*11471SMichael.Bergknoff@Sun.COM 	 * indefinitely in a guest domain.
445*11471SMichael.Bergknoff@Sun.COM 	 */
446*11471SMichael.Bergknoff@Sun.COM 	act.sa_sigaction = usr1_handler;
447*11471SMichael.Bergknoff@Sun.COM 	(void) sigemptyset(&act.sa_mask);
448*11471SMichael.Bergknoff@Sun.COM 	act.sa_flags = 0;
449*11471SMichael.Bergknoff@Sun.COM 	if (sigaction(SIGUSR1, &act, NULL) == -1) {
450*11471SMichael.Bergknoff@Sun.COM 		syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGUSR1),
451*11471SMichael.Bergknoff@Sun.COM 		    strerror(errno));
452*11471SMichael.Bergknoff@Sun.COM 	}
4533941Svenki 
4543941Svenki 	/*
4553941Svenki 	 * Initialize SNMP service
4563941Svenki 	 */
4573941Svenki 	LOGPRINTF("Initializing SNMP service.\n");
4583941Svenki 	if ((hdl = snmp_init()) == NULL) {
4593941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT);
4603941Svenki 		return ((void *)-1);
4613941Svenki 	}
4623941Svenki 
4633941Svenki 	/*
4643941Svenki 	 * Register OID groupings for BULKGET optimizations
4653941Svenki 	 */
4663941Svenki 	LOGPRINTF("Registering OID groups.\n");
4673941Svenki 	register_group(group1, 0);
4683941Svenki 	register_group(group2, 0);
4695723Sfw157321 	register_group(group3, 0);
4705723Sfw157321 	register_group(group4, 0);
4713941Svenki 	register_group(volgroup1, 1);
4723941Svenki 	register_group(volgroup2, 1);
4735723Sfw157321 	register_group(volgroup3, 1);
4745723Sfw157321 	register_group(volgroup4, 1);
4755723Sfw157321 	register_group(volgroup5, 1);
4763941Svenki 
4773941Svenki 	(void) mutex_lock(&rebuild_tree_lock);
4783941Svenki 
4793941Svenki 	for (;;) {
4803941Svenki 		LOGPRINTF("tree_builder: check whether to rebuild subtree\n");
4813941Svenki 		while (rebuild_tree == B_FALSE)
4823941Svenki 			(void) cond_wait(&rebuild_tree_cv, &rebuild_tree_lock);
4833941Svenki 
4843941Svenki 		LOGPRINTF("tree_builder: woke up\n");
4853941Svenki 
4865029Sfw157321 		if (tree_builder_thr_exit == B_TRUE) {
4875029Sfw157321 			(void) mutex_unlock(&rebuild_tree_lock);
4885029Sfw157321 			LOGPRINTF("tree_builder: time to exit\n");
4895029Sfw157321 			return (NULL);
4905029Sfw157321 		}
4915029Sfw157321 
4923941Svenki 		old_physplat_root = NULL;
4933941Svenki 		physplat_root = NULL;
4943941Svenki 
4953941Svenki 		LOGPRINTF("tree_builder: getting root node\n");
4963941Svenki 		if ((ret = ptree_get_root(&root_node)) != PICL_SUCCESS) {
4975029Sfw157321 			(void) mutex_unlock(&rebuild_tree_lock);
4983941Svenki 			log_msg(LOG_ERR, SNMPP_NO_ROOT, ret);
4993941Svenki 			return ((void *)-2);
5003941Svenki 		}
5013941Svenki 
5023941Svenki 		LOGPRINTF("tree_builder: getting existing physplat node\n");
5033941Svenki 		rv = ptree_find_node(root_node, PICL_PROP_NAME,
5043941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_NODE_PHYSPLAT,
5053941Svenki 		    sizeof (PICL_NODE_PHYSPLAT), &old_physplat_root);
5063941Svenki 
5073941Svenki 		LOGPRINTF("tree_builder: building physical-platform\n");
5083941Svenki 		if ((ret = build_physplat(&physplat_root)) < 0) {
5095029Sfw157321 			(void) mutex_unlock(&rebuild_tree_lock);
5103941Svenki 			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
5117746SKelly.Moyer@Sun.COM 			cache_refresher_fini();
5123941Svenki 			snmp_fini(hdl);
5135029Sfw157321 			hdl = NULL;
5143941Svenki 			return ((void *)-3);
5153941Svenki 		}
5163941Svenki 
5173941Svenki 		if (rv == PICL_SUCCESS && old_physplat_root != NULL) {
5183941Svenki 			LOGPRINTF("tree_builder: destroying existing nodes\n");
5193941Svenki 			ptree_delete_node(old_physplat_root);
5203941Svenki 			ptree_destroy_node(old_physplat_root);
5213941Svenki 		}
5223941Svenki 
5233941Svenki 		LOGPRINTF("tree_builder: attaching new subtree\n");
5243941Svenki 		if ((ret = ptree_add_node(root_node, physplat_root)) < 0) {
5255029Sfw157321 			(void) mutex_unlock(&rebuild_tree_lock);
5263941Svenki 			free_resources(physplat_root);
5273941Svenki 			log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret);
5287746SKelly.Moyer@Sun.COM 			cache_refresher_fini();
5293941Svenki 			snmp_fini(hdl);
5305029Sfw157321 			hdl = NULL;
5313941Svenki 			return ((void *)-4);
5323941Svenki 		}
5333941Svenki 
5343941Svenki 		LOGPRINTF("tree_builder: setting stale_tree to FALSE\n");
5353941Svenki 		(void) rw_wrlock(&stale_tree_rwlp);
5363941Svenki 		stale_tree = B_FALSE;
5373941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
5383941Svenki 
5393941Svenki 		LOGPRINTF("tree_builder: setting rebuild_tree to FALSE\n");
5403941Svenki 		rebuild_tree = B_FALSE;
5413941Svenki 	}
5423941Svenki 
5433941Svenki 	/*NOTREACHED*/
5443941Svenki 	return (NULL);
5453941Svenki }
5463941Svenki 
5473941Svenki static int
build_physplat(picl_nodehdl_t * subtree_rootp)5483941Svenki build_physplat(picl_nodehdl_t *subtree_rootp)
5493941Svenki {
5503941Svenki 	int	change_time1;
5513941Svenki 	int	row, nxtrow;
5523941Svenki 	int	clr_linkreset = 0;
5533941Svenki 	int	ret = 0;
5543941Svenki 	int	snmp_syserr = 0;
5553941Svenki 
5563941Svenki retry:
5573941Svenki 	(void) snmp_reinit(hdl, clr_linkreset);
5583941Svenki 	clr_linkreset = 0;
5593941Svenki 
5603941Svenki 	/*
5613941Svenki 	 * Record LastChangeTime before we start building the tree
5623941Svenki 	 */
5633941Svenki 	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
5643941Svenki 	    &change_time1, &snmp_syserr);
5653941Svenki 	if (ret < 0) {
5663941Svenki 		if (snmp_syserr == ECANCELED) {
5676751Sfw157321 			LOGPRINTF(SNMPP_LINK_RESET);
5683941Svenki 			clr_linkreset = 1;
5693941Svenki 			goto retry;
5705723Sfw157321 		}
5715723Sfw157321 		log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
5725723Sfw157321 		    snmp_syserr ? snmp_syserr : ret, OID_entLastChangeTime, 0);
5733941Svenki 	}
5743941Svenki 
5753941Svenki 	/*
5763941Svenki 	 * Create the physical-platform node
5773941Svenki 	 */
5783941Svenki 	ret = ptree_create_node(PICL_NODE_PHYSPLAT, PICL_CLASS_PICL,
5793941Svenki 	    subtree_rootp);
5803941Svenki 	if (ret != PICL_SUCCESS)
5813941Svenki 		return (-1);
5823941Svenki 
5833941Svenki 	/*
5843941Svenki 	 * Scan entPhysicalTable and build the "physical-platform" subtree
5853941Svenki 	 */
5863941Svenki 	ret = 0;
5873941Svenki 	for (row = -1; ret == 0; row = nxtrow) {
5883941Svenki 		ret = snmp_get_nextrow(hdl, OID_entPhysicalDescr,
5893941Svenki 		    row, &nxtrow, &snmp_syserr);
5905995Sfw157321 		if (ret == 0)
5913941Svenki 			(void) make_node(*subtree_rootp, nxtrow, &snmp_syserr);
5925995Sfw157321 		switch (snmp_syserr) {
5935995Sfw157321 		case ECANCELED:
5943941Svenki 			/*
5953941Svenki 			 * If we get this error, a link reset must've
5963941Svenki 			 * happened and we need to throw away everything
5973941Svenki 			 * we have now and rebuild the tree again.
5983941Svenki 			 */
5993941Svenki 			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
6003941Svenki 			free_resources(*subtree_rootp);
6013941Svenki 			clr_linkreset = 1;
6023941Svenki 			goto retry;
6035995Sfw157321 			/*NOTREACHED*/
6045995Sfw157321 			break;
6055995Sfw157321 		case ENOSPC:	/* end of MIB */
6065995Sfw157321 			LOGPRINTF("build_physplat: end of MIB\n");
6075995Sfw157321 			break;
6085995Sfw157321 		case ENOENT:	/* end of table */
6095995Sfw157321 			LOGPRINTF("build_physplat: end of table\n");
6105995Sfw157321 			break;
6115995Sfw157321 		default:
6125995Sfw157321 			/*
6135995Sfw157321 			 * make_node() will print messages so don't
6145995Sfw157321 			 * repeat that exercise here.
6155995Sfw157321 			 */
6165995Sfw157321 			if (ret == -1) {
6175995Sfw157321 				log_msg(LOG_WARNING,
6185995Sfw157321 				    SNMPP_CANT_FETCH_OBJECT_VAL,
6195995Sfw157321 				    snmp_syserr ? snmp_syserr : ret,
6205995Sfw157321 				    OID_entPhysicalDescr, row);
6215995Sfw157321 			}
6223941Svenki 		}
6233941Svenki 	}
6243941Svenki 
6253941Svenki 	/*
6263941Svenki 	 * Record LastChangeTime after we're done building the tree
6273941Svenki 	 */
6283941Svenki 	ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
6293941Svenki 	    &change_time, &snmp_syserr);
6303941Svenki 	if (ret < 0) {
6313941Svenki 		if (snmp_syserr == ECANCELED) {
6323941Svenki 			log_msg(LOG_WARNING, SNMPP_LINK_RESET);
6333941Svenki 			free_resources(*subtree_rootp);
6343941Svenki 			clr_linkreset = 1;
6353941Svenki 			goto retry;
6363941Svenki 		} else
6375723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
6385723Sfw157321 			    snmp_syserr ? snmp_syserr : ret,
6395723Sfw157321 			    OID_entLastChangeTime, row);
6403941Svenki 	}
6413941Svenki 
6423941Svenki 	/*
6433941Svenki 	 * If they don't match, some hotplugging must've happened,
6443941Svenki 	 * free resources we've created and still holding, then go
6453941Svenki 	 * back and retry
6463941Svenki 	 */
6473941Svenki 	if (change_time != change_time1) {
6483941Svenki 		LOGPRINTF("build_physplat: entLastChangeTime has changed!\n");
6493941Svenki 		free_resources(*subtree_rootp);
6503941Svenki 		change_time1 = change_time;
6513941Svenki 		goto retry;
6523941Svenki 	}
6533941Svenki 
6543941Svenki 	/*
6553941Svenki 	 * The physplat_nodes table is no longer needed, free it
6563941Svenki 	 */
6573941Svenki 	if (physplat_nodes) {
6583941Svenki 		free(physplat_nodes);
6593941Svenki 		physplat_nodes = NULL;
6603941Svenki 		n_physplat_nodes = 0;
6613941Svenki 	}
6623941Svenki 
6633941Svenki 	return (0);
6643941Svenki }
6653941Svenki 
6663941Svenki /*
6673941Svenki  * Destroy all resources that were created during the building
6683941Svenki  * of the subtree
6693941Svenki  */
6703941Svenki static void
free_resources(picl_nodehdl_t subtree_root)6713941Svenki free_resources(picl_nodehdl_t subtree_root)
6723941Svenki {
6733941Svenki 	if (physplat_nodes) {
6743941Svenki 		free(physplat_nodes);
6753941Svenki 		physplat_nodes = NULL;
6763941Svenki 		n_physplat_nodes = 0;
6773941Svenki 	}
6783941Svenki 
6793941Svenki 	if (subtree_root) {
6803941Svenki 		(void) ptree_delete_node(subtree_root);
6813941Svenki 		(void) ptree_destroy_node(subtree_root);
6823941Svenki 	}
6833941Svenki 
6843941Svenki 	if (vol_props) {
6853941Svenki 		free(vol_props);
68610406SMichael.Bergknoff@Sun.COM 		vol_props = NULL;
6873941Svenki 		n_vol_props = 0;
6883941Svenki 		volprop_ndx = 0;
6893941Svenki 	}
6903941Svenki }
6913941Svenki 
6923941Svenki static picl_nodehdl_t
make_node(picl_nodehdl_t subtree_root,int row,int * snmp_syserr_p)6933941Svenki make_node(picl_nodehdl_t subtree_root, int row, int *snmp_syserr_p)
6943941Svenki {
6953941Svenki 	picl_nodehdl_t	nodeh, parenth;
6963941Svenki 	picl_prophdl_t	proph;
6973941Svenki 	char	*phys_name, *node_name;
6983941Svenki 	int	parent_row;
6993941Svenki 	int	ent_physclass, sunplat_physclass;
7003941Svenki 	int	sensor_class, sensor_type;
7013941Svenki 	int	alarm_type;
7023941Svenki 	int	ps_class;
7033941Svenki 	int	ret;
7043941Svenki 
7053941Svenki 	/*
7063941Svenki 	 * If we've already created this picl node, just return it
7073941Svenki 	 */
7083941Svenki 	if ((nodeh = lookup_nodeh(row)) != NULL)
7093941Svenki 		return (nodeh);
7103941Svenki 
7113941Svenki 	/*
7123941Svenki 	 * If we are creating it only now, make sure we have the parent
7133941Svenki 	 * created first; if there's no parent, then parent it to the
7143941Svenki 	 * subtree's root node
7153941Svenki 	 */
7163941Svenki 	ret = snmp_get_int(hdl, OID_entPhysicalContainedIn, row,
7173941Svenki 	    &parent_row, snmp_syserr_p);
7183941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
7193941Svenki 	if (ret < 0 || parent_row <= 0)
7203941Svenki 		parenth = subtree_root;
7213941Svenki 	else {
7223941Svenki 		parenth = make_node(subtree_root, parent_row, snmp_syserr_p);
7233941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7243941Svenki 		if (parenth == NULL)
7253941Svenki 			parenth = subtree_root;
7263941Svenki 	}
7273941Svenki 
7283941Svenki 	/*
7293941Svenki 	 * Figure out the physical-platform node name from entPhysicalName;
7303941Svenki 	 * all rows in the MIB that have a valid entPhysicalIndex should
7313941Svenki 	 * have a physical name.
7323941Svenki 	 */
7333941Svenki 	ret = snmp_get_str(hdl, OID_entPhysicalName, row,
7343941Svenki 	    &phys_name, snmp_syserr_p);
7353941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
7363941Svenki 	if (ret < 0 || phys_name == NULL) {
7373941Svenki 		log_msg(LOG_WARNING, SNMPP_NO_ENTPHYSNAME, row);
7383941Svenki 		return (NULL);
7393941Svenki 	}
7403941Svenki 
7413941Svenki 	node_name = basename(phys_name);
7423941Svenki 
7433941Svenki 	ret = snmp_get_int(hdl, OID_entPhysicalClass, row,
7443941Svenki 	    &ent_physclass, snmp_syserr_p);
7453941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
7463941Svenki 	if (ret < 0) {
7475723Sfw157321 		log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
7485723Sfw157321 		    *snmp_syserr_p ? *snmp_syserr_p : ret,
7495723Sfw157321 		    OID_entPhysicalClass, row);
7503941Svenki 		free(phys_name);
7513941Svenki 		return (NULL);
7523941Svenki 	}
7533941Svenki 
7543941Svenki 	switch (ent_physclass) {
7553941Svenki 	case SPC_OTHER:
7563941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatPhysicalClass, row,
7573941Svenki 		    &sunplat_physclass, snmp_syserr_p);
7583941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7593941Svenki 		if (ret < 0) {
7605723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
7615723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
7625723Sfw157321 			    OID_sunPlatPhysicalClass, row);
7633941Svenki 			free(phys_name);
7643941Svenki 			return (NULL);
7653941Svenki 		}
7663941Svenki 
7673941Svenki 		if (sunplat_physclass == SSPC_ALARM) {
7683941Svenki 			ret = snmp_get_int(hdl, OID_sunPlatAlarmType,
7693941Svenki 			    row, &alarm_type, snmp_syserr_p);
7703941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
7713941Svenki 			if (ret < 0) {
7723941Svenki 				log_msg(LOG_WARNING,
7735723Sfw157321 				    SNMPP_CANT_FETCH_OBJECT_VAL,
7745723Sfw157321 				    *snmp_syserr_p ? *snmp_syserr_p : ret,
7755723Sfw157321 				    OID_sunPlatAlarmType, row);
7763941Svenki 				free(phys_name);
7773941Svenki 				return (NULL);
7783941Svenki 			}
7793941Svenki 
7803941Svenki 			if (alarm_type == SSAT_VISIBLE) {
7814802Sfw157321 				ADD_NODE(PICL_CLASS_LED)
7823941Svenki 			} else {
7834802Sfw157321 				ADD_NODE(PICL_CLASS_ALARM)
7843941Svenki 			}
7853941Svenki 
7863941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_STATE,
7873941Svenki 			    snmp_syserr_p);
7883941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
7893941Svenki 		} else {
7903941Svenki 			ADD_NODE(PICL_CLASS_OTHER)
7913941Svenki 		}
7923941Svenki 
7933941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
7943941Svenki 		    snmp_syserr_p);
7953941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
7963941Svenki 		break;
7973941Svenki 
7983941Svenki 	case SPC_UNKNOWN:
7993941Svenki 		ADD_NODE(PICL_CLASS_UNKNOWN)
8003941Svenki 		break;
8013941Svenki 
8023941Svenki 	case SPC_CHASSIS:
8033941Svenki 		ADD_NODE(PICL_CLASS_CHASSIS)
8043941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8053941Svenki 		    snmp_syserr_p);
8063941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8073941Svenki 		break;
8083941Svenki 
8093941Svenki 	case SPC_BACKPLANE:
8103941Svenki 		ADD_NODE(PICL_CLASS_BACKPLANE)
8113941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8123941Svenki 		    snmp_syserr_p);
8133941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8143941Svenki 		break;
8153941Svenki 
8163941Svenki 	case SPC_CONTAINER:
8173941Svenki 		ADD_NODE(PICL_CLASS_CONTAINER)
8183941Svenki 
8193941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8203941Svenki 		    snmp_syserr_p);
8213941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8223941Svenki 
8233941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_SLOT_TYPE,
8243941Svenki 		    snmp_syserr_p);
8253941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8263941Svenki 		break;
8273941Svenki 
8283941Svenki 	case SPC_POWERSUPPLY:
8293941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatPowerSupplyClass,
8303941Svenki 		    row, &ps_class, snmp_syserr_p);
8313941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8323941Svenki 		if (ret < 0) {
8335723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
8345723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
8355723Sfw157321 			    OID_sunPlatPowerSupplyClass, row);
8363941Svenki 			free(phys_name);
8373941Svenki 			return (NULL);
8383941Svenki 		}
8393941Svenki 
8403941Svenki 		if (ps_class == SSPSC_BATTERY) {
8413941Svenki 			ADD_NODE(PICL_CLASS_BATTERY)
8423941Svenki 			add_prop(nodeh, &proph, node_name, row,
8433941Svenki 			    PP_BATT_STATUS, snmp_syserr_p);
8443941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
8453941Svenki 		} else {
8463941Svenki 			ADD_NODE(PICL_CLASS_POWERSUPPLY)
8473941Svenki 		}
8483941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8493941Svenki 		    snmp_syserr_p);
8503941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8513941Svenki 		break;
8523941Svenki 
8533941Svenki 	case SPC_FAN:
8543941Svenki 		ADD_NODE(PICL_CLASS_FAN)
8553941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
8563941Svenki 		    snmp_syserr_p);
8573941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8583941Svenki 		break;
8593941Svenki 
8603941Svenki 	case SPC_SENSOR:
8613941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatSensorClass,
8623941Svenki 		    row, &sensor_class, snmp_syserr_p);
8633941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8643941Svenki 		if (ret < 0) {
8655723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
8665723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
8675723Sfw157321 			    OID_sunPlatSensorClass, row);
8683941Svenki 			free(phys_name);
8693941Svenki 			return (NULL);
8703941Svenki 		}
8713941Svenki 
8723941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatSensorType,
8733941Svenki 		    row, &sensor_type, snmp_syserr_p);
8743941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
8753941Svenki 		if (ret < 0) {
8765723Sfw157321 			log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL,
8775723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
8785723Sfw157321 			    OID_sunPlatSensorType, row);
8793941Svenki 			free(phys_name);
8803941Svenki 			return (NULL);
8813941Svenki 		}
8823941Svenki 
8833941Svenki 		if (sensor_class == SSSC_NUMERIC) {
8843941Svenki 			if (sensor_type == SSST_TEMPERATURE) {
8853941Svenki 				ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR)
8863941Svenki 				add_prop(nodeh, &proph, node_name, row,
8873941Svenki 				    PP_TEMPERATURE, snmp_syserr_p);
8883941Svenki 			} else if (sensor_type == SSST_VOLTAGE) {
8893941Svenki 				ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR)
8903941Svenki 				add_prop(nodeh, &proph, node_name, row,
8913941Svenki 				    PP_VOLTAGE, snmp_syserr_p);
8923941Svenki 			} else if (sensor_type == SSST_CURRENT) {
8933941Svenki 				ADD_NODE(PICL_CLASS_CURRENT_SENSOR)
8943941Svenki 				add_prop(nodeh, &proph, node_name, row,
8953941Svenki 				    PP_CURRENT, snmp_syserr_p);
8963941Svenki 			} else if (sensor_type == SSST_TACHOMETER) {
8973941Svenki 				ADD_NODE(PICL_CLASS_RPM_SENSOR)
8983941Svenki 				add_prop(nodeh, &proph, node_name, row,
8993941Svenki 				    PP_SPEED, snmp_syserr_p);
9003941Svenki 			} else {
9013941Svenki 				ADD_NODE(PICL_CLASS_SENSOR)
9023941Svenki 				add_prop(nodeh, &proph, node_name, row,
9033941Svenki 				    PP_SENSOR_VALUE, snmp_syserr_p);
9043941Svenki 			}
9053941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9063941Svenki 
9073941Svenki 			add_prop(nodeh, &proph, node_name, row,
9083941Svenki 			    PP_OPSTATUS, snmp_syserr_p);
9093941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9103941Svenki 
9113941Svenki 			add_prop(nodeh, &proph, node_name, row,
9123941Svenki 			    PP_BASE_UNITS, snmp_syserr_p);
9133941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9143941Svenki 
9153941Svenki 			add_prop(nodeh, &proph, node_name, row,
9163941Svenki 			    PP_EXPONENT, snmp_syserr_p);
9173941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9183941Svenki 
9193941Svenki 			add_prop(nodeh, &proph, node_name, row,
9203941Svenki 			    PP_RATE_UNITS, snmp_syserr_p);
9213941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9223941Svenki 
9233941Svenki 			add_thresholds(nodeh, row, snmp_syserr_p);
9243941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9253941Svenki 
9263941Svenki 		} else if (sensor_class == SSSC_BINARY) {
9273941Svenki 			if (sensor_type == SSST_TEMPERATURE) {
9283941Svenki 				ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR)
9293941Svenki 			} else if (sensor_type == SSST_VOLTAGE) {
9303941Svenki 				ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR)
9313941Svenki 			} else if (sensor_type == SSST_CURRENT) {
9323941Svenki 				ADD_NODE(PICL_CLASS_CURRENT_INDICATOR)
9333941Svenki 			} else if (sensor_type == SSST_TACHOMETER) {
9343941Svenki 				ADD_NODE(PICL_CLASS_RPM_INDICATOR)
9353941Svenki 			} else if (sensor_type == SSST_PRESENCE) {
9363941Svenki 				ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR)
9373941Svenki 			} else {
9383941Svenki 				ADD_NODE(PICL_CLASS_INDICATOR)
9393941Svenki 			}
9403941Svenki 
9413941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
9423941Svenki 			    snmp_syserr_p);
9433941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9443941Svenki 
9453941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_CONDITION,
9463941Svenki 			    snmp_syserr_p);
9473941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9483941Svenki 
9493941Svenki 			add_prop(nodeh, &proph, node_name, row, PP_EXPECTED,
9503941Svenki 			    snmp_syserr_p);
9513941Svenki 			CHECK_LINKRESET(snmp_syserr_p, NULL)
9523941Svenki 		} else {
9533941Svenki 			log_msg(LOG_ERR,
9543941Svenki 			    SNMPP_UNSUPP_SENSOR_CLASS, sensor_class, row);
9553941Svenki 			return (NULL);
9563941Svenki 		}
9573941Svenki 		break;
9583941Svenki 
9593941Svenki 	case SPC_MODULE:
9603941Svenki 		ADD_NODE(PICL_CLASS_MODULE)
9613941Svenki 
9623941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS,
9633941Svenki 		    snmp_syserr_p);
9643941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
9653941Svenki 
9663941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_REPLACEABLE,
9673941Svenki 		    snmp_syserr_p);
9683941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
9693941Svenki 
9703941Svenki 		add_prop(nodeh, &proph, node_name, row, PP_HOTSWAPPABLE,
9713941Svenki 		    snmp_syserr_p);
9723941Svenki 		CHECK_LINKRESET(snmp_syserr_p, NULL)
9733941Svenki 		break;
9743941Svenki 
9753941Svenki 	case SPC_PORT:
9763941Svenki 		ADD_NODE(PICL_CLASS_PORT)
9773941Svenki 		break;
9783941Svenki 
9793941Svenki 	case SPC_STACK:
9803941Svenki 		ADD_NODE(PICL_CLASS_STACK)
9813941Svenki 		break;
9823941Svenki 
9833941Svenki 	default:
9843941Svenki 		log_msg(LOG_WARNING,
9853941Svenki 		    SNMPP_UNKNOWN_ENTPHYSCLASS, ent_physclass, row);
9863941Svenki 		free(phys_name);
9873941Svenki 		return (NULL);
9883941Svenki 	}
9893941Svenki 
9903941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_DESCRIPTION, snmp_syserr_p);
9913941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9923941Svenki 
9933941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_LABEL, snmp_syserr_p);
9943941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9953941Svenki 
9963941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_HW_REVISION, snmp_syserr_p);
9973941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
9983941Svenki 
9993941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_FW_REVISION, snmp_syserr_p);
10003941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
10013941Svenki 
10023941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_SERIAL_NUM, snmp_syserr_p);
10033941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
10043941Svenki 
10053941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_MFG_NAME, snmp_syserr_p);
10063941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
10073941Svenki 
10083941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_MODEL_NAME, snmp_syserr_p);
10093941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
10103941Svenki 
10113941Svenki 	add_prop(nodeh, &proph, node_name, row, PP_IS_FRU, snmp_syserr_p);
10123941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
10133941Svenki 
10143941Svenki 	free(phys_name);
10153941Svenki 	save_nodeh(nodeh, row);
10163941Svenki 
10173941Svenki 	return (nodeh);
10183941Svenki }
10193941Svenki 
10203941Svenki /*
10213941Svenki  * Saves the node handle and the row id into physplat_nodes[]. If we're
10223941Svenki  * doing this in response to a hotplug event, we should've freed the
10233941Svenki  * old physplat_nodes before entering here to save the first node of the
10243941Svenki  * new physplat subtree.
10253941Svenki  */
10263941Svenki static void
save_nodeh(picl_nodehdl_t nodeh,int row)10273941Svenki save_nodeh(picl_nodehdl_t nodeh, int row)
10283941Svenki {
10293941Svenki 	size_t		sz, count;
10303941Svenki 	picl_nodehdl_t	*p;
10313941Svenki 
10323941Svenki 	if (row >= n_physplat_nodes) {
10333941Svenki 		count = (((size_t)row >> NODE_BLOCK_SHIFT) + 1) *
10343941Svenki 		    N_ELEMS_IN_NODE_BLOCK;
10353941Svenki 		sz = count * sizeof (picl_nodehdl_t);
10363941Svenki 
10373941Svenki 		p = (picl_nodehdl_t *)calloc(count, sizeof (picl_nodehdl_t));
10383941Svenki 		if (p == NULL) {
10393941Svenki 			log_msg(LOG_ERR, SNMPP_NO_MEM, sz);
10403941Svenki 			return;
10413941Svenki 		}
10423941Svenki 
10433941Svenki 		if (physplat_nodes) {
10443941Svenki 			(void) memcpy((void *) p, (void *) physplat_nodes,
10453941Svenki 			    n_physplat_nodes * sizeof (picl_nodehdl_t));
10463941Svenki 			free((void *) physplat_nodes);
10473941Svenki 		}
10483941Svenki 
10493941Svenki 		physplat_nodes = p;
10503941Svenki 		n_physplat_nodes = count;
10513941Svenki 	}
10523941Svenki 
10533941Svenki 	physplat_nodes[row] = nodeh;
10543941Svenki }
10553941Svenki 
10563941Svenki static picl_nodehdl_t
lookup_nodeh(int row)10573941Svenki lookup_nodeh(int row)
10583941Svenki {
10593941Svenki 	if (row >= n_physplat_nodes)
10603941Svenki 		return (NULL);
10613941Svenki 
10623941Svenki 	return (physplat_nodes[row]);
10633941Svenki }
10643941Svenki 
10653941Svenki /*
10663941Svenki  * We enter this routine only when we are building the physical-platform
10673941Svenki  * subtree, whether for the first time or in response to a hotplug event.
10683941Svenki  * If we're here for rebuilding the tree, we have already set stale_tree
10693941Svenki  * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props
10703941Svenki  * or volprop_ndx. If we're here to build the tree for the first time,
10713941Svenki  * picld hasn't yet created doors and is running single-threaded, so no
10723941Svenki  * one else would be accessing them anyway.
10733941Svenki  */
10743941Svenki static void
save_volprop(picl_prophdl_t prop,char * oidstr,int row,int proptype)10753941Svenki save_volprop(picl_prophdl_t prop, char *oidstr, int row, int proptype)
10763941Svenki {
10773941Svenki 	vol_prophdl_t	*p;
10783941Svenki 	int		count;
10793941Svenki 
10803941Svenki 	if (volprop_ndx == n_vol_props) {
10813941Svenki 		count = n_vol_props + N_ELEMS_IN_VOLPROP_BLOCK;
10823941Svenki 		p = (vol_prophdl_t *)calloc(count, sizeof (vol_prophdl_t));
10833941Svenki 		if (p == NULL) {
10843941Svenki 			log_msg(LOG_ERR, SNMPP_NO_MEM,
10853941Svenki 			    count * sizeof (vol_prophdl_t));
10863941Svenki 			return;
10873941Svenki 		}
10883941Svenki 
10893941Svenki 		if (vol_props) {
10903941Svenki 			(void) memcpy((void *) p, (void *) vol_props,
10913941Svenki 			    n_vol_props * sizeof (vol_prophdl_t));
10923941Svenki 			free((void *) vol_props);
10933941Svenki 		}
10943941Svenki 
10953941Svenki 		vol_props = p;
10963941Svenki 		n_vol_props += N_ELEMS_IN_VOLPROP_BLOCK;
10973941Svenki 	}
10983941Svenki 
10993941Svenki 	vol_props[volprop_ndx].prop = prop;
11003941Svenki 	vol_props[volprop_ndx].oidstr = oidstr;
11013941Svenki 	vol_props[volprop_ndx].row = row;
11023941Svenki 	vol_props[volprop_ndx].proptype = proptype;
11033941Svenki 
11043941Svenki 	volprop_ndx++;
11053941Svenki }
11063941Svenki 
11073941Svenki static void
check_for_stale_data(boolean_t nocache)11085723Sfw157321 check_for_stale_data(boolean_t nocache)
11093941Svenki {
11103941Svenki 	int	cur_change_time;
11113941Svenki 	int	ret;
11123941Svenki 	int	snmp_syserr;
11133941Svenki 
11143941Svenki 	(void) rw_wrlock(&stale_tree_rwlp);
11153941Svenki 
11163941Svenki 	/*
11173941Svenki 	 * Check if some other thread beat us to it
11183941Svenki 	 */
11193941Svenki 	if (stale_tree == B_TRUE) {
11203941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
11213941Svenki 		return;
11223941Svenki 	}
11233941Svenki 
11243941Svenki 	/*
11255723Sfw157321 	 * Cache OID_entLastChangeTime for up to 10 seconds before
11265723Sfw157321 	 * fetching it from ILOM again.  This prevents us from fetching
11275723Sfw157321 	 * this value from ILOM when the we're filling or refreshing a
11285723Sfw157321 	 * whole bunch of items in the cache around the same time.
11295723Sfw157321 	 */
11305723Sfw157321 	if (nocache == B_FALSE && time(NULL) - change_time_check <= 10) {
11315723Sfw157321 		(void) rw_unlock(&stale_tree_rwlp);
11325723Sfw157321 		return;
11335723Sfw157321 	}
11345723Sfw157321 
11355723Sfw157321 	/*
11363941Svenki 	 * Check if mib data has changed (hotplug? link-reset?)
11373941Svenki 	 */
11387935SMichael.Bergknoff@Sun.COM 	do {
11397935SMichael.Bergknoff@Sun.COM 		snmp_syserr = 0;
11407935SMichael.Bergknoff@Sun.COM 		ret = snmp_get_int(hdl, OID_entLastChangeTime, 0,
11417935SMichael.Bergknoff@Sun.COM 		    &cur_change_time, &snmp_syserr);
11427935SMichael.Bergknoff@Sun.COM 		(void) time(&change_time_check);
11437935SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && (cur_change_time == change_time)) {
11447935SMichael.Bergknoff@Sun.COM 			(void) rw_unlock(&stale_tree_rwlp);
11457935SMichael.Bergknoff@Sun.COM 			return;
11467935SMichael.Bergknoff@Sun.COM 		}
11477935SMichael.Bergknoff@Sun.COM 	} while (ret != 0 && snmp_syserr == EINTR);
11483941Svenki 
11493941Svenki 	/*
11503941Svenki 	 * If we can't read entLastChangeTime we assume we need to rebuild
11513941Svenki 	 * the tree. This will also cover the case when we need to rebuild
11523941Svenki 	 * the tree because a link reset had happened.
11533941Svenki 	 */
11543941Svenki 	LOGPRINTF2("check_for_stale_data: LastChange times have changed, "
11553941Svenki 	    "(%#x != %#x)\n", change_time, cur_change_time);
11563941Svenki 
11573941Svenki 	/*
11583941Svenki 	 * If the mib data has changed, we need to rebuild the physical-platform
11593941Svenki 	 * subtree. To do this, we set a flag to mark the tree stale,
11603941Svenki 	 * so that any future reads to get value of volatile properties will
11613941Svenki 	 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag
11623941Svenki 	 * is reset by the tree builder thread.
11633941Svenki 	 */
11643941Svenki 	stale_tree = B_TRUE;
11653941Svenki 	if (vol_props) {
11663941Svenki 		free(vol_props);
11673941Svenki 	}
11683941Svenki 	vol_props = NULL;
11693941Svenki 	volprop_ndx = 0;
11703941Svenki 	n_vol_props = 0;
11713941Svenki 
11723941Svenki 	(void) rw_unlock(&stale_tree_rwlp);
11733941Svenki 
11743941Svenki 	(void) mutex_lock(&rebuild_tree_lock);
11753941Svenki 	rebuild_tree = B_TRUE;
11763941Svenki 	(void) cond_signal(&rebuild_tree_cv);
11773941Svenki 	LOGPRINTF("check_for_stale_data: signalled tree builder\n");
11783941Svenki 	(void) mutex_unlock(&rebuild_tree_lock);
11793941Svenki }
11803941Svenki 
11813941Svenki /*
11823941Svenki  * This is the critical routine.  This callback is invoked by picl whenever
11833941Svenki  * it needs to fetch the value of a volatile property. The first thing we
11843941Svenki  * must do, however, is to see if there has been a hotplug or a link-reset
11853941Svenki  * event since the last time we built the tree and whether we need to
11863941Svenki  * rebuild the tree. If so, we do whatever is necessary to make that happen,
11873941Svenki  * but return PICL_PROPVALUNAVAILABLE for now, without making any further
11883941Svenki  * snmp requests or accessing any globals.
11893941Svenki  */
11903941Svenki static int
read_volprop(ptree_rarg_t * parg,void * buf)11913941Svenki read_volprop(ptree_rarg_t *parg, void *buf)
11923941Svenki {
11933941Svenki 	char	*pstr;
11943941Svenki 	int	propval;
11953941Svenki 	int	i, ndx;
11963941Svenki 	int	ret;
11973941Svenki 	int	snmp_syserr = 0;
11983941Svenki 
11993941Svenki 	/*
12003941Svenki 	 * First check for any event that would make us throw away
12013941Svenki 	 * the existing /physical-platform subtree and rebuild
12023941Svenki 	 * another one. If we are rebuilding the subtree, we just
12033941Svenki 	 * return the stale value until the tree is fully built.
12043941Svenki 	 */
12055723Sfw157321 	check_for_stale_data(B_FALSE);
12063941Svenki 
12073941Svenki 	(void) rw_rdlock(&stale_tree_rwlp);
12083941Svenki 
12093941Svenki 	if (stale_tree == B_TRUE) {
12103941Svenki 		(void) rw_unlock(&stale_tree_rwlp);
12113941Svenki 		return (PICL_PROPVALUNAVAILABLE);
12123941Svenki 	}
12133941Svenki 
12143941Svenki 	for (i = 0; i < volprop_ndx; i++) {
12153941Svenki 		if (vol_props[i].prop == parg->proph) {
12163941Svenki 			ndx = i;
12173941Svenki 			break;
12183941Svenki 		}
12193941Svenki 	}
12203941Svenki 	if (i == volprop_ndx) {
12215723Sfw157321 		(void) rw_unlock(&stale_tree_rwlp);
12223941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph);
12233941Svenki 		return (PICL_FAILURE);
12243941Svenki 	}
12253941Svenki 
12263941Svenki 	/*
12273941Svenki 	 * If we can't read the value, return failure. Even if this was
12283941Svenki 	 * due to a link reset, between the check for stale data and now,
12293941Svenki 	 * the next volatile callback by picl will initiate a tree-rebuild.
12303941Svenki 	 */
12313941Svenki 	ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row,
12323941Svenki 	    &propval, &snmp_syserr);
12333941Svenki 	if (ret < 0) {
12345723Sfw157321 		(void) rw_unlock(&stale_tree_rwlp);
12355723Sfw157321 		check_for_stale_data(B_TRUE);
12365723Sfw157321 		if (stale_tree == B_TRUE) {
12375723Sfw157321 			return (PICL_PROPVALUNAVAILABLE);
12385723Sfw157321 		}
12395723Sfw157321 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
12405723Sfw157321 		    snmp_syserr ? snmp_syserr : ret,
12415723Sfw157321 		    vol_props[ndx].oidstr, vol_props[ndx].row);
12423941Svenki 		return (PICL_FAILURE);
12433941Svenki 	}
12443941Svenki 
12453941Svenki 	switch (vol_props[ndx].proptype) {
12463941Svenki 	case VPT_PLATOPSTATE:
12473941Svenki 		if (propval == SSOS_DISABLED) {
12483941Svenki 			(void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN);
12493941Svenki 		} else if (propval == SSOS_ENABLED) {
12503941Svenki 			(void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN);
12513941Svenki 		} else {
12525723Sfw157321 			(void) rw_unlock(&stale_tree_rwlp);
12533941Svenki 			log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE,
12543941Svenki 			    propval, vol_props[ndx].row);
12553941Svenki 			return (PICL_FAILURE);
12563941Svenki 		}
12573941Svenki 		break;
12583941Svenki 
12593941Svenki 	case VPT_NUMSENSOR:
12603941Svenki 		(void) memcpy(buf, &propval, sizeof (propval));
12613941Svenki 		break;
12623941Svenki 
12633941Svenki 	case VPT_BINSENSOR:
12643941Svenki 		if (propval == ST_TRUE) {
12653941Svenki 			ret = snmp_get_str(hdl,
12663941Svenki 			    OID_sunPlatBinarySensorInterpretTrue,
12673941Svenki 			    vol_props[ndx].row, &pstr, &snmp_syserr);
12685723Sfw157321 			if (snmp_syserr == ECANCELED) {
12695723Sfw157321 				(void) rw_unlock(&stale_tree_rwlp);
12705723Sfw157321 				if (pstr)
12715723Sfw157321 					free(pstr);
12723941Svenki 				return (PICL_FAILURE);
12735723Sfw157321 			}
12743941Svenki 			if (ret < 0 || pstr == NULL) {
12755723Sfw157321 				log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
12765723Sfw157321 				    snmp_syserr ? snmp_syserr : ret,
12775723Sfw157321 				    OID_sunPlatBinarySensorInterpretTrue,
12785723Sfw157321 				    vol_props[ndx].row);
12793941Svenki 				(void) strlcpy(buf, STR_ST_TRUE,
12803941Svenki 				    MAX_TRUTHVAL_LEN);
12813941Svenki 			} else {
12823941Svenki 				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
12835723Sfw157321 			}
12845723Sfw157321 			if (pstr)
12853941Svenki 				free(pstr);
12863941Svenki 		} else if (propval == ST_FALSE) {
12873941Svenki 			ret = snmp_get_str(hdl,
12883941Svenki 			    OID_sunPlatBinarySensorInterpretFalse,
12893941Svenki 			    vol_props[ndx].row, &pstr, &snmp_syserr);
12905723Sfw157321 			if (snmp_syserr == ECANCELED) {
12915723Sfw157321 				(void) rw_unlock(&stale_tree_rwlp);
12925723Sfw157321 				if (pstr)
12935723Sfw157321 					free(pstr);
12943941Svenki 				return (PICL_FAILURE);
12955723Sfw157321 			}
12963941Svenki 			if (ret < 0 || pstr == NULL) {
12975723Sfw157321 				log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
12985723Sfw157321 				    snmp_syserr ? snmp_syserr : ret,
12995723Sfw157321 				    OID_sunPlatBinarySensorInterpretFalse,
13005723Sfw157321 				    vol_props[ndx].row);
13013941Svenki 				(void) strlcpy(buf, STR_ST_FALSE,
13023941Svenki 				    MAX_TRUTHVAL_LEN);
13033941Svenki 			} else {
13043941Svenki 				(void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN);
13055723Sfw157321 			}
13065723Sfw157321 			if (pstr)
13073941Svenki 				free(pstr);
13083941Svenki 		} else {
13095723Sfw157321 			(void) rw_unlock(&stale_tree_rwlp);
13103941Svenki 			log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT,
13113941Svenki 			    propval, vol_props[ndx].row);
13123941Svenki 			return (PICL_FAILURE);
13133941Svenki 		}
13143941Svenki 		break;
13153941Svenki 
13163941Svenki 	case VPT_ALARMSTATE:
13173941Svenki 		if (propval == SSAS_OFF) {
13183941Svenki 			(void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN);
13193941Svenki 		} else if (propval == SSAS_STEADY) {
13203941Svenki 			(void) strlcpy(buf, STR_SSAS_STEADY,
13213941Svenki 			    MAX_ALARMSTATE_LEN);
13223941Svenki 		} else if (propval == SSAS_ALTERNATING) {
13233941Svenki 			(void) strlcpy(buf, STR_SSAS_ALTERNATING,
13243941Svenki 			    MAX_ALARMSTATE_LEN);
13253941Svenki 		} else {
13263941Svenki 			(void) strlcpy(buf, STR_SSAS_UNKNOWN,
13273941Svenki 			    MAX_ALARMSTATE_LEN);
13283941Svenki 		}
13293941Svenki 		break;
13303941Svenki 
13313941Svenki 	case VPT_BATTERYSTATUS:
13323941Svenki 		switch (propval) {
13333941Svenki 		case SSBS_OTHER:
13343941Svenki 			(void) strlcpy(buf, STR_SSBS_OTHER,
13353941Svenki 			    MAX_BATTERYSTATUS_LEN);
13363941Svenki 			break;
13373941Svenki 		case SSBS_FULLYCHARGED:
13383941Svenki 			(void) strlcpy(buf, STR_SSBS_FULLYCHARGED,
13393941Svenki 			    MAX_BATTERYSTATUS_LEN);
13403941Svenki 			break;
13413941Svenki 		case SSBS_LOW:
13423941Svenki 			(void) strlcpy(buf, STR_SSBS_LOW,
13433941Svenki 			    MAX_BATTERYSTATUS_LEN);
13443941Svenki 			break;
13453941Svenki 		case SSBS_CRITICAL:
13463941Svenki 			(void) strlcpy(buf, STR_SSBS_CRITICAL,
13473941Svenki 			    MAX_BATTERYSTATUS_LEN);
13483941Svenki 			break;
13493941Svenki 		case SSBS_CHARGING:
13503941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING,
13513941Svenki 			    MAX_BATTERYSTATUS_LEN);
13523941Svenki 			break;
13533941Svenki 		case SSBS_CHARGING_AND_LOW:
13543941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW,
13553941Svenki 			    MAX_BATTERYSTATUS_LEN);
13563941Svenki 			break;
13573941Svenki 		case SSBS_CHARGING_AND_HIGH:
13583941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH,
13593941Svenki 			    MAX_BATTERYSTATUS_LEN);
13603941Svenki 			break;
13613941Svenki 		case SSBS_CHARGING_AND_CRITICAL:
13623941Svenki 			(void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL,
13633941Svenki 			    MAX_BATTERYSTATUS_LEN);
13643941Svenki 			break;
13653941Svenki 		case SSBS_UNDEFINED:
13663941Svenki 			(void) strlcpy(buf, STR_SSBS_UNDEFINED,
13673941Svenki 			    MAX_BATTERYSTATUS_LEN);
13683941Svenki 			break;
13693941Svenki 		case SSBS_PARTIALLY_CHARGED:
13703941Svenki 			(void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED,
13713941Svenki 			    MAX_BATTERYSTATUS_LEN);
13723941Svenki 			break;
13733941Svenki 		case SSBS_UNKNOWN:
13743941Svenki 		default:
13753941Svenki 			(void) strlcpy(buf, STR_SSBS_UNKNOWN,
13763941Svenki 			    MAX_BATTERYSTATUS_LEN);
13773941Svenki 			break;
13783941Svenki 		}
13793941Svenki 		break;
13803941Svenki 	}
13813941Svenki 
13823941Svenki 	(void) rw_unlock(&stale_tree_rwlp);
13833941Svenki 
13843941Svenki 	return (PICL_SUCCESS);
13853941Svenki }
13863941Svenki 
13873941Svenki static void
threshold(picl_nodehdl_t node,char * oidstr,int row,char * propname,int * snmp_syserr_p)13883941Svenki threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname,
13893941Svenki     int *snmp_syserr_p)
13903941Svenki {
13913941Svenki 	picl_prophdl_t	prop;
13923941Svenki 	int		err;
13933941Svenki 	int		val;
13943941Svenki 
13955723Sfw157321 	if ((err = snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p)) != -1) {
13963941Svenki 		err = add_volatile_prop(node, propname, PICL_PTYPE_INT,
13973941Svenki 		    PICL_READ, sizeof (int), read_volprop, NULL, &prop);
13983941Svenki 		if (err == PICL_SUCCESS)
13993941Svenki 			save_volprop(prop, oidstr, row, VPT_NUMSENSOR);
14005723Sfw157321 	} else
14015723Sfw157321 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
14025723Sfw157321 		    *snmp_syserr_p ? *snmp_syserr_p : err, oidstr, row);
14033941Svenki }
14043941Svenki 
14053941Svenki static void
add_thresholds(picl_nodehdl_t node,int row,int * snmp_syserr_p)14063941Svenki add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p)
14073941Svenki {
14083941Svenki 	uchar_t	*bitstr = NULL;
14093941Svenki 	uchar_t	enabled;
14103941Svenki 	uint_t	nbytes;
14113941Svenki 	int	ret;
14123941Svenki 
14135723Sfw157321 	ret = snmp_get_str(hdl,
14145723Sfw157321 	    OID_sunPlatNumericSensorEnabledThresholds,
14155723Sfw157321 	    row, (char **)&bitstr, snmp_syserr_p);
14165723Sfw157321 	if (ret == -1) {
14175723Sfw157321 		log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
14185723Sfw157321 		    *snmp_syserr_p ? *snmp_syserr_p : ret,
14195723Sfw157321 		    OID_sunPlatNumericSensorEnabledThresholds, row);
14205723Sfw157321 	} else {
14215723Sfw157321 		nbytes = strlen((const char *)bitstr);
14225723Sfw157321 	}
14235723Sfw157321 
14245723Sfw157321 	CHECK_LINKRESET_VOID(snmp_syserr_p);
14253941Svenki 
14265723Sfw157321 	/*
14275723Sfw157321 	 * No bit string of threshold masks was returned, so we can't
14285723Sfw157321 	 * assume that any thresholds exist.
14295723Sfw157321 	 *
14305723Sfw157321 	 * This mask prevents us from attempting to fetch thresholds
14315723Sfw157321 	 * which don't apply to the sensor or that aren't there anyway,
14325723Sfw157321 	 * That speeds up the plug-in significantly since otherwise it
14335723Sfw157321 	 * takes several seconds to time out.
14345723Sfw157321 	 */
14355723Sfw157321 	if (ret < 0 || bitstr == NULL || nbytes == 0 || 2 < nbytes) {
14365723Sfw157321 		if (bitstr)
14375723Sfw157321 			free(bitstr);
14385723Sfw157321 		return;
14395723Sfw157321 	} else if (nbytes == 1) {
14403941Svenki 		/*
14413941Svenki 		 * The ALOM snmp agent doesn't adhere to the BER rules for
14423941Svenki 		 * encoding bit strings. While the BER states that bitstrings
14433941Svenki 		 * must begin from the second octet after length, and the
14443941Svenki 		 * first octet after length must indicate the number of unused
14453941Svenki 		 * bits in the last octet, the snmp agent simply sends the
14463941Svenki 		 * bitstring data as if it were octet string -- that is, the
14473941Svenki 		 * "unused bits" octet is missing.
14483941Svenki 		 */
14493941Svenki 		enabled = bitstr[0];
14503941Svenki 	} else if (nbytes == 2)
14513941Svenki 		enabled = bitstr[1];
14523941Svenki 
14533941Svenki 	if (bitstr) {
14543941Svenki 		free(bitstr);
14553941Svenki 	}
14563941Svenki 
14573941Svenki 	if (enabled & LOWER_FATAL) {
14583941Svenki 		threshold(node,
14593941Svenki 		    OID_sunPlatNumericSensorLowerThresholdFatal, row,
14603941Svenki 		    PICL_PROP_LOW_POWER_OFF, snmp_syserr_p);
14613941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14623941Svenki 	}
14633941Svenki 	if (enabled & LOWER_CRITICAL) {
14643941Svenki 		threshold(node,
14653941Svenki 		    OID_sunPlatNumericSensorLowerThresholdCritical, row,
14663941Svenki 		    PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p);
14673941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14683941Svenki 	}
14693941Svenki 	if (enabled & LOWER_NON_CRITICAL) {
14703941Svenki 		threshold(node,
14713941Svenki 		    OID_sunPlatNumericSensorLowerThresholdNonCritical, row,
14723941Svenki 		    PICL_PROP_LOW_WARNING, snmp_syserr_p);
14733941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14743941Svenki 	}
14753941Svenki 	if (enabled & UPPER_NON_CRITICAL) {
14763941Svenki 		threshold(node,
14773941Svenki 		    OID_sunPlatNumericSensorUpperThresholdNonCritical, row,
14784802Sfw157321 		    PICL_PROP_HIGH_WARNING, snmp_syserr_p);
14793941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14803941Svenki 	}
14813941Svenki 	if (enabled & UPPER_CRITICAL) {
14823941Svenki 		threshold(node,
14833941Svenki 		    OID_sunPlatNumericSensorUpperThresholdCritical, row,
14843941Svenki 		    PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p);
14853941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14863941Svenki 	}
14873941Svenki 	if (enabled & UPPER_FATAL) {
14883941Svenki 		threshold(node,
14893941Svenki 		    OID_sunPlatNumericSensorUpperThresholdFatal, row,
14904802Sfw157321 		    PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p);
14913941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
14923941Svenki 	}
14933941Svenki }
14943941Svenki 
14953941Svenki static char *
get_slot_type(int row,int * snmp_syserr_p)14963941Svenki get_slot_type(int row, int *snmp_syserr_p)
14973941Svenki {
14983941Svenki 	char	*p;
14993941Svenki 	char	*slott = NULL;
15003941Svenki 	int	ret;
15013941Svenki 
15023941Svenki 	ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes,
15033941Svenki 	    row, &p, snmp_syserr_p);
15043941Svenki 	CHECK_LINKRESET(snmp_syserr_p, NULL)
15053941Svenki 
15063941Svenki 	if ((ret == 0) && p && *p) {
15073941Svenki 		slott = p;
15083941Svenki 		if ((p = strchr(slott, '\n')) != NULL)
15093941Svenki 			*p = 0;
15103941Svenki 	} else {
15113941Svenki 		log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row);
15123941Svenki 		if (p) {
15133941Svenki 			free(p);
15143941Svenki 		}
15153941Svenki 	}
15163941Svenki 
15173941Svenki 	return (slott);
15183941Svenki }
15193941Svenki 
15203941Svenki /*
15213941Svenki  * Create and add the specified volatile property
15223941Svenki  */
15233941Svenki 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)15243941Svenki add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access,
15253941Svenki     int size, int (*rdfunc)(ptree_rarg_t *, void *),
15263941Svenki     int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp)
15273941Svenki {
15283941Svenki 	ptree_propinfo_t	propinfo;
15293941Svenki 	picl_prophdl_t		prop;
15303941Svenki 	int			err;
15313941Svenki 
15323941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
15333941Svenki 	    type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc);
15343941Svenki 	if (err != PICL_SUCCESS) {
15353941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err);
15363941Svenki 		return (err);
15373941Svenki 	}
15383941Svenki 
15393941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop);
15403941Svenki 	if (err != PICL_SUCCESS) {
15413941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node);
15423941Svenki 		return (err);
15433941Svenki 	}
15443941Svenki 
15453941Svenki 	if (propp)
15463941Svenki 		*propp = prop;
15473941Svenki 
15483941Svenki 	return (PICL_SUCCESS);
15493941Svenki }
15503941Svenki 
15513941Svenki /*
15523941Svenki  * Add the specified string property to the node
15533941Svenki  */
15543941Svenki static int
add_string_prop(picl_nodehdl_t node,char * propname,char * propval)15553941Svenki add_string_prop(picl_nodehdl_t node, char *propname, char *propval)
15563941Svenki {
15573941Svenki 	ptree_propinfo_t	propinfo;
15583941Svenki 	int			err;
15593941Svenki 
15607382SMichael.Bergknoff@Sun.COM 	if (*propval == '\0')
15617382SMichael.Bergknoff@Sun.COM 		return (PICL_SUCCESS);
15627382SMichael.Bergknoff@Sun.COM 
15633941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
15643941Svenki 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1,
15653941Svenki 	    propname, NULL, NULL);
15663941Svenki 	if (err != PICL_SUCCESS) {
15673941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err);
15683941Svenki 		return (err);
15693941Svenki 	}
15703941Svenki 
15713941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, propval, NULL);
15723941Svenki 	if (err != PICL_SUCCESS) {
15733941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node);
15743941Svenki 		return (err);
15753941Svenki 	}
15763941Svenki 
15773941Svenki 	return (PICL_SUCCESS);
15783941Svenki }
15793941Svenki 
15803941Svenki /*
15813941Svenki  * Add the specified void property to the node
15823941Svenki  */
15833941Svenki static int
add_void_prop(picl_nodehdl_t node,char * propname)15843941Svenki add_void_prop(picl_nodehdl_t node, char *propname)
15853941Svenki {
15863941Svenki 	ptree_propinfo_t	propinfo;
15873941Svenki 	int			err;
15883941Svenki 
15893941Svenki 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
15903941Svenki 	    PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL);
15913941Svenki 	if (err != PICL_SUCCESS) {
15923941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err);
15933941Svenki 		return (err);
15943941Svenki 	}
15953941Svenki 
15963941Svenki 	err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL);
15973941Svenki 	if (err != PICL_SUCCESS) {
15983941Svenki 		log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node);
15993941Svenki 		return (err);
16003941Svenki 	}
16013941Svenki 
16023941Svenki 	return (PICL_SUCCESS);
16033941Svenki }
16043941Svenki 
16053941Svenki static void
add_prop(picl_nodehdl_t nodeh,picl_prophdl_t * php,char * label,int row,sp_propid_t pp,int * snmp_syserr_p)16063941Svenki add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label,
16073941Svenki     int row, sp_propid_t pp, int *snmp_syserr_p)
16083941Svenki {
16093941Svenki 	char	*serial_num;
16103941Svenki 	char	*slot_type;
16113941Svenki 	char	*fw_revision, *hw_revision;
16123941Svenki 	char	*mfg_name, *model_name;
16133941Svenki 	char	*phys_descr;
16143941Svenki 	int	val;
16153941Svenki 	int	ret;
16163941Svenki 
16173941Svenki 	switch (pp) {
16183941Svenki 	case PP_SERIAL_NUM:
16193941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalSerialNum,
16203941Svenki 		    row, &serial_num, snmp_syserr_p);
16213941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
16227382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && serial_num) {
16233941Svenki 			(void) add_string_prop(nodeh,
16243941Svenki 			    PICL_PROP_SERIAL_NUMBER, serial_num);
16253941Svenki 			free((void *) serial_num);
16263941Svenki 		}
16275723Sfw157321 		if (ret == -1)
16285723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
16295723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
16305723Sfw157321 			    OID_entPhysicalSerialNum, row);
16313941Svenki 		break;
16323941Svenki 
16333941Svenki 	case PP_SLOT_TYPE:
16343941Svenki 		if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) {
16353941Svenki 			CHECK_LINKRESET_VOID(snmp_syserr_p)
16363941Svenki 			(void) add_string_prop(nodeh,
16373941Svenki 			    PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE);
16383941Svenki 		} else {
16393941Svenki 			(void) add_string_prop(nodeh,
16403941Svenki 			    PICL_PROP_SLOT_TYPE, slot_type);
16413941Svenki 			free((void *) slot_type);
16423941Svenki 		}
16433941Svenki 		break;
16443941Svenki 
16453941Svenki 	case PP_STATE:
16463941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_STATE,
16473941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN,
16483941Svenki 		    read_volprop, NULL, php);
16493941Svenki 		if (ret == PICL_SUCCESS) {
16503941Svenki 			save_volprop(*php, OID_sunPlatAlarmState, row,
16513941Svenki 			    VPT_ALARMSTATE);
16523941Svenki 		}
16533941Svenki 		break;
16543941Svenki 
16553941Svenki 	case PP_OPSTATUS:
16563941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS,
16573941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN,
16583941Svenki 		    read_volprop, NULL, php);
16593941Svenki 		if (ret == PICL_SUCCESS) {
16603941Svenki 			save_volprop(*php,
16613941Svenki 			    OID_sunPlatEquipmentOperationalState, row,
16623941Svenki 			    VPT_PLATOPSTATE);
16633941Svenki 		}
16643941Svenki 		break;
16653941Svenki 
16663941Svenki 	case PP_BATT_STATUS:
16673941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS,
16684802Sfw157321 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN,
16694802Sfw157321 		    read_volprop, NULL, php);
16703941Svenki 		if (ret == PICL_SUCCESS) {
16713941Svenki 			save_volprop(*php, OID_sunPlatBatteryStatus, row,
16723941Svenki 			    VPT_BATTERYSTATUS);
16733941Svenki 		}
16743941Svenki 		break;
16753941Svenki 
16763941Svenki 	case PP_TEMPERATURE:
16773941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE,
16783941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16793941Svenki 		    NULL, php);
16803941Svenki 		if (ret == PICL_SUCCESS) {
16813941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
16823941Svenki 			    row, VPT_NUMSENSOR);
16833941Svenki 		}
16843941Svenki 		break;
16853941Svenki 
16863941Svenki 	case PP_VOLTAGE:
16873941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE,
16883941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16893941Svenki 		    NULL, php);
16903941Svenki 		if (ret == PICL_SUCCESS) {
16913941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
16923941Svenki 			    row, VPT_NUMSENSOR);
16933941Svenki 		}
16943941Svenki 		break;
16953941Svenki 
16963941Svenki 	case PP_CURRENT:
16973941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT,
16983941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
16993941Svenki 		    NULL, php);
17003941Svenki 		if (ret == PICL_SUCCESS) {
17013941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
17023941Svenki 			    row, VPT_NUMSENSOR);
17033941Svenki 		}
17043941Svenki 		break;
17053941Svenki 
17063941Svenki 	case PP_SPEED:
17073941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT,
17083941Svenki 		    PICL_READ, sizeof (int), read_volprop, NULL, php);
17093941Svenki 		if (ret == PICL_SUCCESS) {
17103941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
17113941Svenki 			    row, VPT_NUMSENSOR);
17123941Svenki 		}
17133941Svenki 		break;
17143941Svenki 
17153941Svenki 	case PP_SENSOR_VALUE:
17163941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE,
17173941Svenki 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
17183941Svenki 		    NULL, php);
17193941Svenki 		if (ret == PICL_SUCCESS) {
17203941Svenki 			save_volprop(*php, OID_sunPlatNumericSensorCurrent,
17213941Svenki 			    row, VPT_NUMSENSOR);
17223941Svenki 		}
17233941Svenki 		break;
17243941Svenki 
17253941Svenki 	case PP_CONDITION:
17263941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION,
17273941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
17283941Svenki 		    read_volprop, NULL, php);
17293941Svenki 		if (ret == PICL_SUCCESS) {
17303941Svenki 			save_volprop(*php, OID_sunPlatBinarySensorCurrent,
17313941Svenki 			    row, VPT_BINSENSOR);
17323941Svenki 		}
17333941Svenki 		break;
17343941Svenki 
17353941Svenki 	case PP_EXPECTED:
17363941Svenki 		ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED,
17373941Svenki 		    PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN,
17383941Svenki 		    read_volprop, NULL, php);
17393941Svenki 		if (ret == PICL_SUCCESS) {
17403941Svenki 			save_volprop(*php, OID_sunPlatBinarySensorExpected,
17413941Svenki 			    row, VPT_BINSENSOR);
17423941Svenki 		}
17433941Svenki 		break;
17443941Svenki 
17455436Sfw157321 	case PP_EXPONENT:
17465436Sfw157321 		ret = add_volatile_prop(nodeh, PICL_PROP_EXPONENT,
17475436Sfw157321 		    PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop,
17485436Sfw157321 		    NULL, php);
17495436Sfw157321 		if (ret == PICL_SUCCESS) {
17505436Sfw157321 			save_volprop(*php, OID_sunPlatNumericSensorExponent,
17515436Sfw157321 			    row, VPT_NUMSENSOR);
17525436Sfw157321 		}
17535436Sfw157321 		break;
17545436Sfw157321 
17553941Svenki 	case PP_REPLACEABLE:
17563941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable,
17573941Svenki 		    row, &val, snmp_syserr_p);
17583941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17593941Svenki 		if ((ret == 0) && (val == ST_TRUE))
17603941Svenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE);
17615723Sfw157321 		if (ret == -1)
17625723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17635723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17645723Sfw157321 			    OID_sunPlatCircuitPackReplaceable, row);
17653941Svenki 		break;
17663941Svenki 
17673941Svenki 	case PP_HOTSWAPPABLE:
17683941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable,
17693941Svenki 		    row, &val, snmp_syserr_p);
17703941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17713941Svenki 		if ((ret == 0) && (val == ST_TRUE))
17723941Svenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE);
17735723Sfw157321 		if (ret == -1)
17745723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17755723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17765723Sfw157321 			    OID_sunPlatCircuitPackHotSwappable, row);
17773941Svenki 		break;
17783941Svenki 
17793941Svenki 	case PP_IS_FRU:
17803941Svenki 		ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row,
17813941Svenki 		    &val, snmp_syserr_p);
17823941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17833941Svenki 		if ((ret == 0) && (val == ST_TRUE))
17843941Svenki 			(void) add_void_prop(nodeh, PICL_PROP_IS_FRU);
17855723Sfw157321 		if (ret == -1)
17865723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
17875723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
17885723Sfw157321 			    OID_entPhysicalIsFRU, row);
17893941Svenki 		break;
17903941Svenki 
17913941Svenki 	case PP_HW_REVISION:
17923941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev,
17933941Svenki 		    row, &hw_revision, snmp_syserr_p);
17943941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
17957382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && hw_revision) {
17963941Svenki 			(void) add_string_prop(nodeh,
17973941Svenki 			    PICL_PROP_HW_REVISION, hw_revision);
17983941Svenki 			free((void *) hw_revision);
17993941Svenki 		}
18005723Sfw157321 		if (ret == -1)
18015723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18025723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18035723Sfw157321 			    OID_entPhysicalHardwareRev, row);
18043941Svenki 		break;
18053941Svenki 
18063941Svenki 	case PP_FW_REVISION:
18073941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev,
18083941Svenki 		    row, &fw_revision, snmp_syserr_p);
18093941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18107382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && fw_revision) {
18113941Svenki 			(void) add_string_prop(nodeh,
18123941Svenki 			    PICL_PROP_FW_REVISION, fw_revision);
18133941Svenki 			free((void *) fw_revision);
18143941Svenki 		}
18155723Sfw157321 		if (ret == -1)
18165723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18175723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18185723Sfw157321 			    OID_entPhysicalFirmwareRev, row);
18193941Svenki 		break;
18203941Svenki 
18213941Svenki 	case PP_MFG_NAME:
18223941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalMfgName,
18233941Svenki 		    row, &mfg_name, snmp_syserr_p);
18243941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18257382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && mfg_name) {
18263941Svenki 			(void) add_string_prop(nodeh,
18273941Svenki 			    PICL_PROP_MFG_NAME, mfg_name);
18283941Svenki 			free((void *) mfg_name);
18293941Svenki 		}
18305723Sfw157321 		if (ret == -1)
18315723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18325723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18335723Sfw157321 			    OID_entPhysicalMfgName, row);
18343941Svenki 		break;
18353941Svenki 
18363941Svenki 	case PP_MODEL_NAME:
18373941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalModelName,
18383941Svenki 		    row, &model_name, snmp_syserr_p);
18393941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18407382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && model_name) {
18413941Svenki 			(void) add_string_prop(nodeh,
18423941Svenki 			    PICL_PROP_MODEL_NAME, model_name);
18433941Svenki 			free((void *) model_name);
18443941Svenki 		}
18455723Sfw157321 		if (ret == -1)
18465723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18475723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18485723Sfw157321 			    OID_entPhysicalModelName, row);
18493941Svenki 		break;
18503941Svenki 
18513941Svenki 	case PP_DESCRIPTION:
18523941Svenki 		ret = snmp_get_str(hdl, OID_entPhysicalDescr,
18533941Svenki 		    row, &phys_descr, snmp_syserr_p);
18543941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18557382SMichael.Bergknoff@Sun.COM 		if ((ret == 0) && phys_descr) {
18564802Sfw157321 			(void) add_string_prop(nodeh,
18574802Sfw157321 			    PICL_PROP_PHYS_DESCRIPTION, phys_descr);
18584802Sfw157321 			free((void *) phys_descr);
18593941Svenki 		}
18605723Sfw157321 		if (ret == -1)
18615723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18625723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18635723Sfw157321 			    OID_entPhysicalDescr, row);
18643941Svenki 		break;
18653941Svenki 
18663941Svenki 	case PP_LABEL:
18673941Svenki 		if (label && *label)
18683941Svenki 			(void) add_string_prop(nodeh, PICL_PROP_LABEL, label);
18693941Svenki 		break;
18703941Svenki 
18713941Svenki 	case PP_BASE_UNITS:
18723941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits,
18733941Svenki 		    row, &val, snmp_syserr_p);
18743941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18753941Svenki 		if ((ret == 0) && (val > 0) && (val < n_baseunits)) {
18763941Svenki 			(void) add_string_prop(nodeh,
18773941Svenki 			    PICL_PROP_BASE_UNITS, sensor_baseunits[val]);
18783941Svenki 		}
18795723Sfw157321 		if (ret == -1)
18805723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18815723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18825723Sfw157321 			    OID_sunPlatNumericSensorBaseUnits, row);
18833941Svenki 		break;
18843941Svenki 
18853941Svenki 	case PP_RATE_UNITS:
18863941Svenki 		ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits,
18873941Svenki 		    row, &val, snmp_syserr_p);
18883941Svenki 		CHECK_LINKRESET_VOID(snmp_syserr_p)
18893941Svenki 		if ((ret == 0) && (val > 0) && (val < n_rateunits)) {
18903941Svenki 			(void) add_string_prop(nodeh,
18913941Svenki 			    PICL_PROP_RATE_UNITS, sensor_rateunits[val]);
18923941Svenki 		}
18935723Sfw157321 		if (ret == -1)
18945723Sfw157321 			log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL,
18955723Sfw157321 			    *snmp_syserr_p ? *snmp_syserr_p : ret,
18965723Sfw157321 			    OID_sunPlatNumericSensorRateUnits, row);
18973941Svenki 		break;
18983941Svenki 	}
18993941Svenki }
19003941Svenki 
19017746SKelly.Moyer@Sun.COM /*
19027746SKelly.Moyer@Sun.COM  * Initialize the SNMP library's cache refresh subsystem, then periodically
19037746SKelly.Moyer@Sun.COM  * process refresh job to prevent cache entries from expiring.
19047746SKelly.Moyer@Sun.COM  */
19057746SKelly.Moyer@Sun.COM /*ARGSUSED*/
19067746SKelly.Moyer@Sun.COM static void *
cache_refresher(void * arg)19077746SKelly.Moyer@Sun.COM cache_refresher(void *arg)
19087746SKelly.Moyer@Sun.COM {
19097746SKelly.Moyer@Sun.COM 	int		jobs;
19107746SKelly.Moyer@Sun.COM 	int		next_expiration;
19117746SKelly.Moyer@Sun.COM 	timestruc_t	to;
19127746SKelly.Moyer@Sun.COM 	hrtime_t	cycle_start, cycle_elapsed;
19137746SKelly.Moyer@Sun.COM 
19147746SKelly.Moyer@Sun.COM 	/*
19157746SKelly.Moyer@Sun.COM 	 * Initialize refresh subsystem
19167746SKelly.Moyer@Sun.COM 	 */
19177746SKelly.Moyer@Sun.COM 	LOGPRINTF("Initializing SNMP refresh subsystem.\n");
19187746SKelly.Moyer@Sun.COM 	if (snmp_refresh_init() < 0) {
19197746SKelly.Moyer@Sun.COM 		return ((void *)-1);
19207746SKelly.Moyer@Sun.COM 	}
19217746SKelly.Moyer@Sun.COM 
19227746SKelly.Moyer@Sun.COM 	(void) mutex_lock(&cache_refresh_lock);
19237746SKelly.Moyer@Sun.COM 
19247746SKelly.Moyer@Sun.COM 
19257746SKelly.Moyer@Sun.COM 	for (;;) {
19267746SKelly.Moyer@Sun.COM 		cycle_start = gethrtime();
19277746SKelly.Moyer@Sun.COM 
19287746SKelly.Moyer@Sun.COM 		/*
19297746SKelly.Moyer@Sun.COM 		 * Process jobs from the snmp cache refresh work queue until one
19307746SKelly.Moyer@Sun.COM 		 * of the following conditions is true:
19317746SKelly.Moyer@Sun.COM 		 * 1) we are told to exit, or
19327746SKelly.Moyer@Sun.COM 		 * 2) we have processed at least as many jobs as recommended by
19337746SKelly.Moyer@Sun.COM 		 * the library, and the next job expiration is at least
19347746SKelly.Moyer@Sun.COM 		 * CACHE_REFRESH_MIN_WINDOW * seconds away.
19357746SKelly.Moyer@Sun.COM 		 */
19367746SKelly.Moyer@Sun.COM 		jobs = snmp_refresh_get_cycle_hint(CACHE_REFRESH_CYCLE);
19377746SKelly.Moyer@Sun.COM 		while ((cache_refresh_thr_exit == B_FALSE) && (jobs > 0)) {
19387746SKelly.Moyer@Sun.COM 			(void) snmp_refresh_process_job();
19397746SKelly.Moyer@Sun.COM 			jobs--;
19407746SKelly.Moyer@Sun.COM 		}
19417746SKelly.Moyer@Sun.COM 
19427746SKelly.Moyer@Sun.COM 		next_expiration = snmp_refresh_get_next_expiration();
19437746SKelly.Moyer@Sun.COM 		while ((cache_refresh_thr_exit == B_FALSE) &&
19447746SKelly.Moyer@Sun.COM 		    ((next_expiration >= 0) &&
19457746SKelly.Moyer@Sun.COM 		    (next_expiration < CACHE_REFRESH_MIN_WINDOW))) {
19467746SKelly.Moyer@Sun.COM 			(void) snmp_refresh_process_job();
19477746SKelly.Moyer@Sun.COM 			next_expiration = snmp_refresh_get_next_expiration();
19487746SKelly.Moyer@Sun.COM 		}
19497746SKelly.Moyer@Sun.COM 
19507746SKelly.Moyer@Sun.COM 		/*
19517746SKelly.Moyer@Sun.COM 		 * As long as we haven't been told to exit, sleep for
19527746SKelly.Moyer@Sun.COM 		 * CACHE_REFRESH_CYCLE seconds minus the amount of time that has
19537746SKelly.Moyer@Sun.COM 		 * elapsed since this cycle started.  If the elapsed time is
19547746SKelly.Moyer@Sun.COM 		 * equal to or greater than 60 seconds, skip sleeping entirely.
19557746SKelly.Moyer@Sun.COM 		 */
19567746SKelly.Moyer@Sun.COM 		cycle_elapsed = (gethrtime() - cycle_start) / NANOSEC;
19577746SKelly.Moyer@Sun.COM 		if ((cache_refresh_thr_exit == B_FALSE) &&
19587746SKelly.Moyer@Sun.COM 		    (cycle_elapsed < CACHE_REFRESH_CYCLE)) {
19597746SKelly.Moyer@Sun.COM 			to.tv_sec = CACHE_REFRESH_CYCLE - cycle_elapsed;
19607746SKelly.Moyer@Sun.COM 			to.tv_nsec = 0;
19617746SKelly.Moyer@Sun.COM 			(void) cond_reltimedwait(&cache_refresh_cv,
19627746SKelly.Moyer@Sun.COM 			    &cache_refresh_lock, &to);
19637746SKelly.Moyer@Sun.COM 		}
19647746SKelly.Moyer@Sun.COM 
19657746SKelly.Moyer@Sun.COM 		/*
19667746SKelly.Moyer@Sun.COM 		 * If we have been told to exit, clean up and bail out.
19677746SKelly.Moyer@Sun.COM 		 */
19687746SKelly.Moyer@Sun.COM 		if (cache_refresh_thr_exit == B_TRUE) {
19697746SKelly.Moyer@Sun.COM 			snmp_refresh_fini();
19707746SKelly.Moyer@Sun.COM 			(void) mutex_unlock(&cache_refresh_lock);
19717746SKelly.Moyer@Sun.COM 			LOGPRINTF("cache_refresher: time to exit\n");
19727746SKelly.Moyer@Sun.COM 			return (NULL);
19737746SKelly.Moyer@Sun.COM 		}
19747746SKelly.Moyer@Sun.COM 
19757746SKelly.Moyer@Sun.COM 	}
19767746SKelly.Moyer@Sun.COM 
19777746SKelly.Moyer@Sun.COM 	/*NOTREACHED*/
19787746SKelly.Moyer@Sun.COM 	return (NULL);
19797746SKelly.Moyer@Sun.COM }
19807746SKelly.Moyer@Sun.COM 
19817746SKelly.Moyer@Sun.COM /*
19827746SKelly.Moyer@Sun.COM  * Check to see if the cache_refresher thread is running.  If it is, signal it
19837746SKelly.Moyer@Sun.COM  * to terminate and clean up associated data structures.
19847746SKelly.Moyer@Sun.COM  */
19857746SKelly.Moyer@Sun.COM void
cache_refresher_fini(void)19867746SKelly.Moyer@Sun.COM cache_refresher_fini(void)
19877746SKelly.Moyer@Sun.COM {
19887746SKelly.Moyer@Sun.COM 	/* if the thread isn't running, there is nothing to do */
19897746SKelly.Moyer@Sun.COM 	if (cache_refresh_thr_exit == B_TRUE)
19907746SKelly.Moyer@Sun.COM 		return;
19917746SKelly.Moyer@Sun.COM 
19927746SKelly.Moyer@Sun.COM 	/* wake up the cache_refresher thread, tell it to exit */
19937746SKelly.Moyer@Sun.COM 	(void) mutex_lock(&cache_refresh_lock);
19947746SKelly.Moyer@Sun.COM 	cache_refresh_thr_exit = B_TRUE;
19957746SKelly.Moyer@Sun.COM 	(void) cond_signal(&cache_refresh_cv);
19967746SKelly.Moyer@Sun.COM 	(void) mutex_unlock(&cache_refresh_lock);
19977746SKelly.Moyer@Sun.COM 
19987746SKelly.Moyer@Sun.COM 	/* reap the thread */
19997746SKelly.Moyer@Sun.COM 	(void) thr_join(cache_refresh_thr_id, NULL, NULL);
20007746SKelly.Moyer@Sun.COM 
20017746SKelly.Moyer@Sun.COM 	/* finish cleanup... */
20027746SKelly.Moyer@Sun.COM 	(void) cond_destroy(&cache_refresh_cv);
20037746SKelly.Moyer@Sun.COM 	(void) mutex_destroy(&cache_refresh_lock);
20047746SKelly.Moyer@Sun.COM }
20057746SKelly.Moyer@Sun.COM 
20063941Svenki /*VARARGS2*/
20073941Svenki static void
log_msg(int pri,const char * fmt,...)20083941Svenki log_msg(int pri, const char *fmt, ...)
20093941Svenki {
20103941Svenki 	va_list ap;
20113941Svenki 
20123941Svenki 	va_start(ap, fmt);
20133941Svenki 	vsyslog(pri, fmt, ap);
20143941Svenki 	va_end(ap);
20153941Svenki }
20163941Svenki 
20173941Svenki #ifdef SNMPPLUGIN_DEBUG
20183941Svenki 
20193941Svenki static void
snmpplugin_log_init(void)20203941Svenki snmpplugin_log_init(void)
20213941Svenki {
20223941Svenki 	(void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL);
20233941Svenki }
20243941Svenki 
20253941Svenki static void
snmpplugin_log(const char * fmt,...)20263941Svenki snmpplugin_log(const char *fmt, ...)
20273941Svenki {
20283941Svenki 	va_list	ap;
20293941Svenki 
20303941Svenki 	(void) mutex_lock(&snmpplugin_dbuf_lock);
20313941Svenki 
20323941Svenki 	va_start(ap, fmt);
20333941Svenki 	(void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap);
20343941Svenki 	snmpplugin_log_append();
20353941Svenki 	va_end(ap);
20363941Svenki 
20373941Svenki 	(void) mutex_unlock(&snmpplugin_dbuf_lock);
20383941Svenki }
20393941Svenki 
20403941Svenki static void
snmpplugin_log_append(void)20413941Svenki snmpplugin_log_append(void)
20423941Svenki {
20433941Svenki 	int	len;
20443941Svenki 
20453941Svenki 	len = strlen(snmpplugin_lbuf);
20463941Svenki 
20473941Svenki 	if ((snmpplugin_dbuf_curp + len) >=
20483941Svenki 	    (snmpplugin_dbuf + snmpplugin_dbuf_sz)) {
20493941Svenki 		snmpplugin_dbuf_realloc();
20503941Svenki 		if (snmpplugin_dbuf == NULL) {
20513941Svenki 			return;
20523941Svenki 		}
20533941Svenki 	}
20543941Svenki 
20553941Svenki 	(void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf);
20563941Svenki 	snmpplugin_dbuf_curp += len;
20573941Svenki }
20583941Svenki 
20593941Svenki static void
snmpplugin_dbuf_realloc(void)20603941Svenki snmpplugin_dbuf_realloc(void)
20613941Svenki {
20623941Svenki 	char	*p;
20633941Svenki 	size_t	offset = 0;
20643941Svenki 	size_t	count;
20653941Svenki 
20663941Svenki 	count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ;
20673941Svenki 	if ((p = (char *)calloc(count, 1)) == NULL) {
20683941Svenki 		snmpplugin_dbuf_overflow++;
20693941Svenki 		snmpplugin_dbuf_curp = snmpplugin_dbuf;
20703941Svenki 		return;
20713941Svenki 	}
20723941Svenki 
20733941Svenki 	if (snmpplugin_dbuf) {
20743941Svenki 		offset = snmpplugin_dbuf_curp - snmpplugin_dbuf;
20753941Svenki 		(void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz);
20763941Svenki 		free(snmpplugin_dbuf);
20773941Svenki 	}
20783941Svenki 
20793941Svenki 	snmpplugin_dbuf = p;
20803941Svenki 	snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ;
20813941Svenki 
20823941Svenki 	snmpplugin_dbuf_curp = snmpplugin_dbuf + offset;
20833941Svenki }
20843941Svenki #endif
2085