xref: /onnv-gate/usr/src/uts/sun4u/lw8/io/sgenv.c (revision 11311:639e7bc0b42f)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel 
281708Sstevel /*
291708Sstevel  * Serengeti Environmental Information driver (sgenv)
301708Sstevel  *
311708Sstevel  * This driver requests the environmental properties from the SC. These
321708Sstevel  * request-response transactions are transferred through the SBBC mailbox,
331708Sstevel  * between the Domain and the SC.
341708Sstevel  *
351708Sstevel  * All sensors have the same sort of properties: Low and high limits, warning
361708Sstevel  * thresholds, last measured value, time of measurement, units (e.g., degrees
371708Sstevel  * Celsius, volts, etc.), and so on.
381708Sstevel  *
391708Sstevel  * Each sensor is named by a unique Tag. The Tag identifies the geographical
401708Sstevel  * location of the sensor in the Serengeti, and what it is the sensor measures.
411708Sstevel  *
421708Sstevel  * Requestable sensor properties are broken into two types:  Those which are
431708Sstevel  * quasi-constant (infrequently change) - e.g., tolerance-defining low and high
441708Sstevel  * limits; and those which are volatile (typically change) - e.g., the current
451708Sstevel  * measurement.
461708Sstevel  *
471708Sstevel  * Unfortunately, property sets are too large to comprise a single mailbox
481708Sstevel  * message, so the sets are further subdivided into notionally arbitrary
491708Sstevel  * collections. NOTE: The SC-mailbox framework now supports fragmented messages
501708Sstevel  * which could allow us to request the data in larger chunks in the future.
511708Sstevel  *
521708Sstevel  * Each collection is fetched by a separate transaction.
531708Sstevel  *
541708Sstevel  * Firstly there is a transaction to obtain a list of all collections. Each non-
551708Sstevel  * zero key in this list is associated whith one of the collections of sensors.
561708Sstevel  * (This sparse list of keys is then used as an index to obtain all the sensor
571708Sstevel  * data for each collection).
581708Sstevel  *
591708Sstevel  * For each collection, there is one request-reply transaction to obtain a list
601708Sstevel  * of all sensors in that collection and the limits that apply to each; and a
611708Sstevel  * separate request-reply transaction to obtain the measurements from the
621708Sstevel  * sensors in the collection.
631708Sstevel  *
641708Sstevel  * The sgenv driver assembles each property set from the constituent
651708Sstevel  * collections, and caches the assembled property sets into the appropriate
661708Sstevel  * cache (env_cache, board_cache). The caches are created at startup and are
671708Sstevel  * updated on receipt of events from the SC. These events (which include DR
681708Sstevel  * events and ENV events) notify sgenv of configuration changes and
691708Sstevel  * environmental state changes (such as a sensor state change, Fan speed
701708Sstevel  * change).
711708Sstevel  *
721708Sstevel  * The SC-APP maintains a pseudo-sensor in each collection "measuring" changes
731708Sstevel  * to the quasi-constants in that collection. By monitoring these pseudo-sensor
741708Sstevel  * measurements, the kstat driver avoids redundant or speculative re-fetches of
751708Sstevel  * the quasi-constant properties.
761708Sstevel  */
771708Sstevel 
781708Sstevel #include <sys/time.h>
791708Sstevel #include <sys/errno.h>
801708Sstevel #include <sys/kmem.h>
811708Sstevel #include <sys/stat.h>
821708Sstevel #include <sys/cmn_err.h>
831708Sstevel #include <sys/disp.h>
841708Sstevel 
851708Sstevel #include <sys/conf.h>
861708Sstevel #include <sys/modctl.h>
871708Sstevel #include <sys/devops.h>
881708Sstevel #include <sys/ddi.h>
891708Sstevel #include <sys/sunddi.h>
901708Sstevel 
911708Sstevel #include <sys/sgevents.h>
921708Sstevel #include <sys/sysevent.h>
931708Sstevel #include <sys/sysevent/eventdefs.h>
941708Sstevel #include <sys/sysevent/domain.h>
951708Sstevel #include <sys/sysevent/env.h>
961708Sstevel 
971708Sstevel #include <sys/serengeti.h>
981708Sstevel #include <sys/sgfrutypes.h>
991708Sstevel 
1001708Sstevel #include <sys/sgsbbc.h>
1011708Sstevel #include <sys/sgsbbc_iosram.h>
1021708Sstevel #include <sys/sgsbbc_mailbox.h>
1031708Sstevel 
1041708Sstevel #include <sys/sbd_ioctl.h>	/* sbd header files needed for board support */
1051708Sstevel #include <sys/sbdp_priv.h>
1061708Sstevel #include <sys/sbd.h>
1071708Sstevel 
1081708Sstevel #include <sys/sgenv_impl.h>
1091708Sstevel 
1101708Sstevel 
1111708Sstevel /*
1121708Sstevel  * Global Variables - can be patched from Solaris
1131708Sstevel  * ==============================================
1141708Sstevel  */
1151708Sstevel 
1161708Sstevel /*
1171708Sstevel  * the maximum amount of time this driver is prepared to wait for the mailbox
1181708Sstevel  * to reply before it decides to timeout. The value is initially set in the
1191708Sstevel  * _init() routine to the global Serengeti variable <sbbc_mbox_default_timeout>
1201708Sstevel  * but could be tuned specifically for SGENV after booting up the system.
1211708Sstevel  */
1221708Sstevel int	sgenv_max_mbox_wait_time = 0;
1231708Sstevel 
1241708Sstevel #ifdef DEBUG
1251708Sstevel /*
1261708Sstevel  * This variable controls the level of debug output
1271708Sstevel  */
1281708Sstevel uint_t		sgenv_debug = SGENV_DEBUG_NONE;
1291708Sstevel #endif
1301708Sstevel 
1311708Sstevel 
1321708Sstevel /*
1331708Sstevel  * Module Variables
1341708Sstevel  * ================
1351708Sstevel  */
1361708Sstevel 
1371708Sstevel /*
1381708Sstevel  * Driver entry points
1391708Sstevel  */
1401708Sstevel static struct cb_ops sgenv_cb_ops = {
1411708Sstevel 	nodev,		/* open() */
1421708Sstevel 	nodev,		/* close() */
1431708Sstevel 	nodev,		/* strategy() */
1441708Sstevel 	nodev,		/* print() */
1451708Sstevel 	nodev,		/* dump() */
1461708Sstevel 	nodev,		/* read() */
1471708Sstevel 	nodev,		/* write() */
1481708Sstevel 	nodev,		/* ioctl() */
1491708Sstevel 	nodev,		/* devmap() */
1501708Sstevel 	nodev,		/* mmap() */
1511708Sstevel 	ddi_segmap,	/* segmap() */
1521708Sstevel 	nochpoll,	/* poll() */
1531708Sstevel 	ddi_prop_op,    /* prop_op() */
1541708Sstevel 	NULL,		/* cb_str */
1551708Sstevel 	D_NEW | D_MP	/* cb_flag */
1561708Sstevel };
1571708Sstevel 
1581708Sstevel 
1591708Sstevel static struct dev_ops sgenv_ops = {
1601708Sstevel 	DEVO_REV,
1611708Sstevel 	0,			/* ref count */
1621708Sstevel 	ddi_getinfo_1to1,	/* getinfo() */
1631708Sstevel 	nulldev,		/* identify() */
1641708Sstevel 	nulldev,		/* probe() */
1651708Sstevel 	sgenv_attach,		/* attach() */
1661708Sstevel 	sgenv_detach,		/* detach */
1671708Sstevel 	nodev,			/* reset */
1681708Sstevel 	&sgenv_cb_ops,		/* pointer to cb_ops structure */
1691708Sstevel 	(struct bus_ops *)NULL,
1707656SSherry.Moore@Sun.COM 	nulldev,		/* power() */
1717656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce() */
1721708Sstevel };
1731708Sstevel 
1741708Sstevel /*
1751708Sstevel  * Loadable module support.
1761708Sstevel  */
1771708Sstevel extern struct mod_ops mod_driverops;
1781708Sstevel 
1791708Sstevel static struct modldrv modldrv = {
1801708Sstevel 	&mod_driverops,			/* Type of module. This is a driver */
1817656SSherry.Moore@Sun.COM 	"Environmental Driver",		/* Name of the module */
1821708Sstevel 	&sgenv_ops			/* pointer to the dev_ops structure */
1831708Sstevel };
1841708Sstevel 
1851708Sstevel static struct modlinkage modlinkage = {
1861708Sstevel 	MODREV_1,
1871708Sstevel 	&modldrv,
1881708Sstevel 	NULL
1891708Sstevel };
1901708Sstevel 
1911708Sstevel /* Opaque state structure pointer */
1921708Sstevel static void		*sgenv_statep;
1931708Sstevel 
1941708Sstevel /*
1951708Sstevel  * <env_cache> is a cache of all the sensor readings which is persistent
1961708Sstevel  * between kstat reads. It is created at init and gets updated upon receipt
1971708Sstevel  * of events from the SC.
1981708Sstevel  *
1991708Sstevel  * The kstat_update function takes a copy of the non-zero entries in this
2001708Sstevel  * cache and creates a temp buffer called env_cache_snapshot. The
2011708Sstevel  * kstat_snapshot function then bcopies the env_cache_snapshot into the
2021708Sstevel  * kstat buffer. This is done because there is no way to ensure that the
2031708Sstevel  * env_cache won't change between the kstat_update and the kstat_snapshot
2041708Sstevel  * which will cause problems as the update sets the ks_data_size.
2051708Sstevel  */
2061708Sstevel static env_sensor_t	*env_cache[SGENV_MAX_HPU_KEYS] = {NULL};
2071708Sstevel static void		*env_cache_snapshot = NULL;
2081708Sstevel static size_t		env_cache_snapshot_size = 0;
2091708Sstevel 
2101708Sstevel /*
2111708Sstevel  * This is set to TRUE the first time env data is stored in the cache
2121708Sstevel  * so that at least from then on, old data can be returned if a call to
2131708Sstevel  * the mailbox fails.
2141708Sstevel  */
2151708Sstevel static int		env_cache_updated = FALSE;
2161708Sstevel 
2171708Sstevel /*
2181708Sstevel  * This lock is needed by the variable-sized kstat which returns
2191708Sstevel  * environmental info. It prevents data-size races with kstat clients.
2201708Sstevel  */
2211708Sstevel static kmutex_t		env_kstat_lock;
2221708Sstevel 
2231708Sstevel /*
2241708Sstevel  * The <env_cache> can be accessed asynchronously by the polling function
2251708Sstevel  * and the kstat_read framework. This mutex ensures that access to the data
2261708Sstevel  * is controlled correctly.
2271708Sstevel  */
2281708Sstevel static kmutex_t		env_cache_lock;
2291708Sstevel 
2301708Sstevel /*
2311708Sstevel  * We need to store the last time we asked the SC for environmental information
2321708Sstevel  * so that we do not send too many requests in a short period of time.
2331708Sstevel  */
2341708Sstevel static hrtime_t		last_env_read_time = 0;
2351708Sstevel 
2361708Sstevel /*
2371708Sstevel  * Variables to coordinate between the handlers which are triggered when
2381708Sstevel  * the env cache needs to be updated and the thread which does the work.
2391708Sstevel  */
2401708Sstevel static volatile int	env_thread_run = 0;
2411708Sstevel static kthread_t	*env_thread = NULL;
2421708Sstevel static kt_did_t		env_thread_tid;
2431708Sstevel 
2441708Sstevel static kcondvar_t	env_flag_cond;
2451708Sstevel static kmutex_t		env_flag_lock;
2461708Sstevel static boolean_t	env_cache_updating = B_FALSE;
2471708Sstevel static boolean_t	env_cache_update_needed = B_TRUE;
2481708Sstevel 
2491708Sstevel /*
2501708Sstevel  * <board_cache> is a cache of all the board status info and it is persistent
2511708Sstevel  * between kstat reads.
2521708Sstevel  *
2531708Sstevel  * The kstat_update function takes a copy of the non-zero entries in this
2541708Sstevel  * cache and copies them into the board_cache_snapshot buffer. The
2551708Sstevel  * kstat_snapshot function then bcopies the board_cache_snapshot into the
2561708Sstevel  * kstat buffer. This is done because there is no way to ensure that the
2571708Sstevel  * board_cache won't change between the kstat_update and the kstat_snapshot
2581708Sstevel  * which will cause problems as the update sets the ks_data_size.
2591708Sstevel  */
2601708Sstevel static sg_board_info_t	board_cache[SG_MAX_BDS] = {NULL};
2611708Sstevel static sg_board_info_t	board_cache_snapshot[SG_MAX_BDS] = {NULL};
2621708Sstevel static int		board_cache_updated = FALSE;
2631708Sstevel 
2641708Sstevel /*
2651708Sstevel  * This mutex ensures the <board_cache> is not destroyed while the board data
2661708Sstevel  * is being collected.
2671708Sstevel  */
2681708Sstevel static kmutex_t		board_cache_lock;
2691708Sstevel 
2701708Sstevel /*
2711708Sstevel  * This lock is needed by the variable-sized kstat which returns
2721708Sstevel  * board status info. It prevents data-size races with kstat clients.
2731708Sstevel  */
2741708Sstevel static kmutex_t		board_kstat_lock;
2751708Sstevel 
2761708Sstevel /*
2771708Sstevel  * This is a count of the number of board readings were stored by
2781708Sstevel  * the kstat_update routine - this is needed by the kstat_snapshot routine.
2791708Sstevel  */
2801708Sstevel static int		board_count = 0;
2811708Sstevel static int		board_count_snapshot = 0;
2821708Sstevel 
2831708Sstevel /*
2841708Sstevel  * We need to store the last time we asked the SC for board information
2851708Sstevel  * so that we do not send too many requests in a short period of time.
2861708Sstevel  */
2871708Sstevel static hrtime_t		last_board_read_time = 0;
2881708Sstevel 
2891708Sstevel /*
2901708Sstevel  * Variables to coordinate between the handlers which are triggered when
2911708Sstevel  * the board cache needs to be updated and the thread which does the work.
2921708Sstevel  */
2931708Sstevel static volatile int	board_thread_run = 0;
2941708Sstevel static kthread_t	*board_thread = NULL;
2951708Sstevel static kt_did_t		board_thread_tid;
2961708Sstevel static kcondvar_t	board_flag_cond;
2971708Sstevel 
2981708Sstevel static kmutex_t		board_flag_lock;
2991708Sstevel static boolean_t	board_cache_updating = B_FALSE;
3001708Sstevel static boolean_t	board_cache_update_needed = B_TRUE;
3011708Sstevel 
3021708Sstevel /*
3031708Sstevel  * Used to keep track of the number of sensors associated with each key.
3041708Sstevel  * The sum of all the values in this array is used to set ks_data_size.
3051708Sstevel  */
3061708Sstevel static int		vol_sensor_count[SGENV_MAX_HPU_KEYS] = {0};
3071708Sstevel 
3081708Sstevel /*
3091708Sstevel  * This variable keeps a count of the number of errors that have occurred
3101708Sstevel  * when we make calls to the mailbox for Env or Board data.
3111708Sstevel  */
3121708Sstevel static int		sgenv_mbox_error_count = 0;
3131708Sstevel 
3141708Sstevel /*
3151708Sstevel  * mutex which protects the keyswitch interrupt handler.
3161708Sstevel  */
3171708Sstevel static kmutex_t		keysw_hdlr_lock;
3181708Sstevel 
3191708Sstevel /*
3201708Sstevel  * mutex which protects the env interrupt handler.
3211708Sstevel  */
3221708Sstevel static kmutex_t		env_hdlr_lock;
3231708Sstevel 
3241708Sstevel /*
3251708Sstevel  * mutex which protects the DR handler interrupt handler.
3261708Sstevel  */
3271708Sstevel static kmutex_t		dr_hdlr_lock;
3281708Sstevel 
3291708Sstevel /*
3301708Sstevel  * Payloads of the event handlers.
3311708Sstevel  */
3321708Sstevel static sg_event_key_position_t	keysw_payload;
3331708Sstevel static sbbc_msg_t		keysw_payload_msg;
3341708Sstevel 
3351708Sstevel static sg_event_env_changed_t	env_payload;
3361708Sstevel static sbbc_msg_t		env_payload_msg;
3371708Sstevel 
3381708Sstevel static sg_event_fan_status_t	fan_payload;
3391708Sstevel static sbbc_msg_t		fan_payload_msg;
3401708Sstevel 
3411708Sstevel static sg_system_fru_descriptor_t	dr_payload;
3421708Sstevel static sbbc_msg_t			dr_payload_msg;
3431708Sstevel 
3441708Sstevel /*
3451708Sstevel  * The following 3 arrays list all possible HPUs, Parts and Device types
3461708Sstevel  */
3471708Sstevel 
3481708Sstevel /*
3491708Sstevel  * ensure that all possible HPUs exported, as described in the main comment
3501708Sstevel  * in <sys/sensor_tag.h>, are accounted for here.
3511708Sstevel  */
3521708Sstevel static const hpu_value_t hpus[] = {
3531708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_UNKNOWN),
3541708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_CPU_BOARD),
3551708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_PCI_IO_BOARD),
3561708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_CPCI_IO_BOARD),
3571708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_SP_CPCI_IO_BOARD),
3581708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_REPEATER_BOARD),
3591708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_L2_REPEATER_BOARD),
3601708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_SYSTEM_CONTROLLER_BOARD),
3611708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_SP_SYSTEM_CONTROLLER_BOARD),
3621708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A123_POWER_SUPPLY),
3631708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A138_POWER_SUPPLY),
3641708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A145_POWER_SUPPLY),
3651708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A152_POWER_SUPPLY),
3661708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A153_POWER_SUPPLY),
3671708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_RACK_FAN_TRAY),
3681708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_SP_FAN_TRAY),
3691708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_MD_TOP_IO_FAN_TRAY),
3701708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_MD_BOTTOM_IO_FAN_TRAY),
3711708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_R12_THREE_FAN_TRAY),
3721708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_K12_IO_ONE_FAN_TRAY),
3731708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_K12_CPU_THREE_FAN_TRAY),
3741708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_R24_IO_FOUR_FAN_TRAY),
3751708Sstevel 	HPU_ENTRY(SG_HPU_TYPE_R24_CPU_SIX_FAN_TRAY),
3761708Sstevel 	0,	(char *)NULL
3771708Sstevel };
3781708Sstevel 
3791708Sstevel static const struct part_value parts[] = {
3801708Sstevel 	PART_VALUE(SG_SENSOR_PART_SBBC),
3811708Sstevel 	PART_VALUE(SG_SENSOR_PART_SDC),
3821708Sstevel 	PART_VALUE(SG_SENSOR_PART_AR),
3831708Sstevel 	PART_VALUE(SG_SENSOR_PART_CBH),
3841708Sstevel 	PART_VALUE(SG_SENSOR_PART_DX),
3851708Sstevel 	PART_VALUE(SG_SENSOR_PART_CHEETAH),
3861708Sstevel 	PART_VALUE(SG_SENSOR_PART_1_5_VDC),
3871708Sstevel 	PART_VALUE(SG_SENSOR_PART_3_3_VDC),
3881708Sstevel 	PART_VALUE(SG_SENSOR_PART_5_VDC),
3891708Sstevel 	PART_VALUE(SG_SENSOR_PART_12_VDC),
3901708Sstevel 	PART_VALUE(SG_SENSOR_PART_48_VDC),
3911708Sstevel 	PART_VALUE(SG_SENSOR_PART_CURRENT),
3921708Sstevel 	PART_VALUE(SG_SENSOR_PART_BOARD),
3931708Sstevel 	PART_VALUE(SG_SENSOR_PART_SCAPP),
3941708Sstevel 	PART_VALUE(SG_SENSOR_PART_SCHIZO),
3951708Sstevel 	PART_VALUE(SG_SENSOR_PART_FAN),
3961708Sstevel 	0,	(char *)NULL
3971708Sstevel };
3981708Sstevel 
3991708Sstevel static const struct type_value types[] = {
4001708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_CURRENT, SG_CURRENT_SCALE),
4011708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_TEMPERATURE, SG_TEMPERATURE_SCALE),
4021708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_1_5_VDC, SG_1_5_VDC_SCALE),
4031708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_1_8_VDC, SG_1_8_VDC_SCALE),
4041708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_3_3_VDC, SG_3_3_VDC_SCALE),
4051708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_5_VDC, SG_5_VDC_SCALE),
4061708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_12_VDC, SG_12_VDC_SCALE),
4071708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_48_VDC, SG_48_VDC_SCALE),
4081708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_ENVDB, 1),
4091708Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_COOLING, 1),
4101708Sstevel 	0,	(char *)NULL
4111708Sstevel };
4121708Sstevel 
4131708Sstevel int
_init(void)4141708Sstevel _init(void)
4151708Sstevel {
4161708Sstevel 	int	error = 0;
4171708Sstevel 
4181708Sstevel 	error = ddi_soft_state_init(&sgenv_statep,
4197656SSherry.Moore@Sun.COM 	    sizeof (sgenv_soft_state_t), 1);
4201708Sstevel 
4211708Sstevel 	if (error)
4221708Sstevel 		return (error);
4231708Sstevel 
4241708Sstevel 	error = mod_install(&modlinkage);
4251708Sstevel 	if (error) {
4261708Sstevel 		ddi_soft_state_fini(&sgenv_statep);
4271708Sstevel 		return (error);
4281708Sstevel 	}
4291708Sstevel 
4301708Sstevel 	mutex_init(&env_kstat_lock, NULL, MUTEX_DEFAULT, NULL);
4311708Sstevel 	mutex_init(&env_cache_lock, NULL, MUTEX_DEFAULT, NULL);
4321708Sstevel 	mutex_init(&env_flag_lock, NULL, MUTEX_DEFAULT, NULL);
4331708Sstevel 	cv_init(&env_flag_cond, NULL, CV_DEFAULT, NULL);
4341708Sstevel 
4351708Sstevel 	mutex_init(&board_cache_lock, NULL, MUTEX_DEFAULT, NULL);
4361708Sstevel 	mutex_init(&board_kstat_lock, NULL, MUTEX_DEFAULT, NULL);
4371708Sstevel 	mutex_init(&board_flag_lock, NULL, MUTEX_DEFAULT, NULL);
4381708Sstevel 	cv_init(&board_flag_cond, NULL, CV_DEFAULT, NULL);
4391708Sstevel 
4401708Sstevel 	mutex_init(&keysw_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
4411708Sstevel 	mutex_init(&env_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
4421708Sstevel 	mutex_init(&dr_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
4431708Sstevel 
4441708Sstevel 	/* set the default timeout value */
4451708Sstevel 	sgenv_max_mbox_wait_time = sbbc_mbox_default_timeout;
4461708Sstevel 
4471708Sstevel 	return (error);
4481708Sstevel }
4491708Sstevel 
4501708Sstevel 
4511708Sstevel int
_info(struct modinfo * modinfop)4521708Sstevel _info(struct modinfo *modinfop)
4531708Sstevel {
4541708Sstevel 	return (mod_info(&modlinkage, modinfop));
4551708Sstevel }
4561708Sstevel 
4571708Sstevel 
4581708Sstevel int
_fini(void)4591708Sstevel _fini(void)
4601708Sstevel {
4611708Sstevel 	int	error = 0;
4621708Sstevel 
4631708Sstevel 	error = mod_remove(&modlinkage);
4641708Sstevel 	if (error)
4651708Sstevel 		return (error);
4661708Sstevel 
4671708Sstevel 	mutex_destroy(&env_kstat_lock);
4681708Sstevel 	mutex_destroy(&env_cache_lock);
4691708Sstevel 
4701708Sstevel 	mutex_destroy(&board_cache_lock);
4711708Sstevel 	mutex_destroy(&board_kstat_lock);
4721708Sstevel 
4731708Sstevel 	mutex_destroy(&keysw_hdlr_lock);
4741708Sstevel 	mutex_destroy(&env_hdlr_lock);
4751708Sstevel 	mutex_destroy(&dr_hdlr_lock);
4761708Sstevel 
4771708Sstevel 	ddi_soft_state_fini(&sgenv_statep);
4781708Sstevel 
4791708Sstevel 	return (error);
4801708Sstevel }
4811708Sstevel 
4821708Sstevel 
4831708Sstevel static int
sgenv_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)4841708Sstevel sgenv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4851708Sstevel {
4861708Sstevel 	sgenv_soft_state_t	*softsp;
4871708Sstevel 
4881708Sstevel 	int			instance;
4891708Sstevel 	int			err;
4901708Sstevel 
4911708Sstevel 	switch (cmd) {
4921708Sstevel 	case DDI_ATTACH:
4931708Sstevel 
4941708Sstevel 		instance = ddi_get_instance(dip);
4951708Sstevel 
4961708Sstevel 		/* allocate a global sgenv_soft_state structure */
4971708Sstevel 		err = ddi_soft_state_zalloc(sgenv_statep, instance);
4981708Sstevel 		if (err != DDI_SUCCESS) {
4991708Sstevel 			cmn_err(CE_WARN, "attach: could not allocate state "
5007656SSherry.Moore@Sun.COM 			    "structure for inst %d.", instance);
5011708Sstevel 			return (DDI_FAILURE);
5021708Sstevel 		}
5031708Sstevel 
5041708Sstevel 		softsp = ddi_get_soft_state(sgenv_statep, instance);
5051708Sstevel 		if (softsp == NULL) {
5061708Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
5071708Sstevel 			cmn_err(CE_WARN, "attach: could not get state "
5087656SSherry.Moore@Sun.COM 			    "structure for inst %d.", instance);
5091708Sstevel 			return (DDI_FAILURE);
5101708Sstevel 		}
5111708Sstevel 
5121708Sstevel 		softsp->dip = dip;
5131708Sstevel 		softsp->instance = instance;
5141708Sstevel 
5151708Sstevel 		err = sgenv_add_kstats(softsp);
5161708Sstevel 		if (err != 0) {
5171708Sstevel 			/*
5181708Sstevel 			 * Some of the kstats may have been created before the
5191708Sstevel 			 * error occurred in sgenv_add_kstats(), so we call
5201708Sstevel 			 * sgenv_remove_kstats() which removes any kstats
5211708Sstevel 			 * already created.
5221708Sstevel 			 */
5231708Sstevel 			sgenv_remove_kstats(softsp);
5241708Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
5251708Sstevel 			return (DDI_FAILURE);
5261708Sstevel 		}
5271708Sstevel 
5281708Sstevel 		/*
5291708Sstevel 		 * Before we setup the framework to read the data from the SC
5301708Sstevel 		 * we need to ensure the caches are initialized correctly.
5311708Sstevel 		 */
5321708Sstevel 		sgenv_init_board_cache();
5331708Sstevel 		sgenv_init_env_cache();
5341708Sstevel 
5351708Sstevel 		/*
5361708Sstevel 		 * Add the threads which will update the env and board caches
5371708Sstevel 		 * and post events to Sysevent Framework in the background
5381708Sstevel 		 * when the interrupt handlers watching for ENV/DR events
5391708Sstevel 		 * indicate to the threads that they need to do so.
5401708Sstevel 		 */
5411708Sstevel 		err = sgenv_create_cache_update_threads();
5421708Sstevel 		if (err != DDI_SUCCESS) {
5431708Sstevel 			sgenv_remove_kstats(softsp);
5441708Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
5451708Sstevel 			return (DDI_FAILURE);
5461708Sstevel 		}
5471708Sstevel 
5481708Sstevel 		err = ddi_create_minor_node(dip, SGENV_DRV_NAME, S_IFCHR,
5497656SSherry.Moore@Sun.COM 		    instance, DDI_PSEUDO, NULL);
5501708Sstevel 		if (err != DDI_SUCCESS) {
5511708Sstevel 			sgenv_remove_kstats(softsp);
552*11311SSurya.Prakki@Sun.COM 			(void) sgenv_remove_cache_update_threads();
5531708Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
5541708Sstevel 			return (DDI_FAILURE);
5551708Sstevel 		}
5561708Sstevel 
5571708Sstevel 		/*
5581708Sstevel 		 * Add the handlers which watch for unsolicited messages
5591708Sstevel 		 * and post event to Sysevent Framework.
5601708Sstevel 		 */
5611708Sstevel 		err = sgenv_add_intr_handlers();
5621708Sstevel 		if (err != DDI_SUCCESS) {
5631708Sstevel 			cmn_err(CE_WARN, "Failed to add event handlers");
564*11311SSurya.Prakki@Sun.COM 			(void) sgenv_remove_intr_handlers();
5651708Sstevel 			sgenv_remove_kstats(softsp);
566*11311SSurya.Prakki@Sun.COM 			(void) sgenv_remove_cache_update_threads();
5671708Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
5681708Sstevel 			return (DDI_FAILURE);
5691708Sstevel 		}
5701708Sstevel 
5711708Sstevel 		ddi_report_dev(dip);
5721708Sstevel 
5731708Sstevel 		return (DDI_SUCCESS);
5741708Sstevel 
5751708Sstevel 	case DDI_RESUME:
5761708Sstevel 		return (DDI_SUCCESS);
5771708Sstevel 
5781708Sstevel 	default:
5791708Sstevel 		return (DDI_FAILURE);
5801708Sstevel 	}
5811708Sstevel }
5821708Sstevel 
5831708Sstevel 
5841708Sstevel static int
sgenv_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)5851708Sstevel sgenv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
5861708Sstevel {
5871708Sstevel 	sgenv_soft_state_t	*softsp;
5881708Sstevel 
5891708Sstevel 	int	instance;
5901708Sstevel 	int	err;
5911708Sstevel 
5921708Sstevel 	switch (cmd) {
5931708Sstevel 	case DDI_DETACH:
5941708Sstevel 
5951708Sstevel 		instance = ddi_get_instance(dip);
5961708Sstevel 
5971708Sstevel 		softsp = ddi_get_soft_state(sgenv_statep, instance);
5981708Sstevel 		if (softsp == NULL) {
5991708Sstevel 			cmn_err(CE_WARN, "detach: could not get state "
6007656SSherry.Moore@Sun.COM 			    "structure for inst %d.", instance);
6011708Sstevel 			return (DDI_FAILURE);
6021708Sstevel 		}
6031708Sstevel 
6041708Sstevel 		err = sgenv_remove_cache_update_threads();
6051708Sstevel 		if (err != DDI_SUCCESS) {
6061708Sstevel 			cmn_err(CE_WARN, "Failed to remove update threads");
6071708Sstevel 		}
6081708Sstevel 
6091708Sstevel 		/*
6101708Sstevel 		 * Remove the handlers which watch for unsolicited messages
6111708Sstevel 		 * and post event to Sysevent Framework.
6121708Sstevel 		 */
6131708Sstevel 		err = sgenv_remove_intr_handlers();
6141708Sstevel 		if (err != DDI_SUCCESS) {
6151708Sstevel 			cmn_err(CE_WARN, "Failed to remove event handlers");
6161708Sstevel 		}
6171708Sstevel 
6181708Sstevel 		sgenv_remove_kstats(softsp);
6191708Sstevel 
6201708Sstevel 		ddi_soft_state_free(sgenv_statep, instance);
6211708Sstevel 
6221708Sstevel 		ddi_remove_minor_node(dip, NULL);
6231708Sstevel 
6241708Sstevel 		return (DDI_SUCCESS);
6251708Sstevel 
6261708Sstevel 	case DDI_SUSPEND:
6271708Sstevel 		return (DDI_SUCCESS);
6281708Sstevel 
6291708Sstevel 	default:
6301708Sstevel 		return (DDI_FAILURE);
6311708Sstevel 	}
6321708Sstevel }
6331708Sstevel 
6341708Sstevel 
6351708Sstevel static int
sgenv_add_kstats(sgenv_soft_state_t * softsp)6361708Sstevel sgenv_add_kstats(sgenv_soft_state_t *softsp)
6371708Sstevel {
6381708Sstevel 	kstat_t		*ksp;
6391708Sstevel 	kstat_named_t	*keyswitch_named_data;
6401708Sstevel 
6411708Sstevel 	int		inst = softsp->instance;
6421708Sstevel 
6431708Sstevel 	/*
6441708Sstevel 	 * Create the 'keyswitch position' named kstat.
6451708Sstevel 	 */
6461708Sstevel 	ksp = kstat_create(SGENV_DRV_NAME, inst, SG_KEYSWITCH_KSTAT_NAME,
6477656SSherry.Moore@Sun.COM 	    "misc", KSTAT_TYPE_NAMED, 1, NULL);
6481708Sstevel 
6491708Sstevel 	if (ksp != NULL) {
6501708Sstevel 		/* initialize the named kstat */
6511708Sstevel 		keyswitch_named_data = (struct kstat_named *)(ksp->ks_data);
6521708Sstevel 
6531708Sstevel 		kstat_named_init(&keyswitch_named_data[0],
6547656SSherry.Moore@Sun.COM 		    POSITION_KSTAT_NAME,
6557656SSherry.Moore@Sun.COM 		    KSTAT_DATA_INT32);
6561708Sstevel 
6571708Sstevel 		ksp->ks_update = sgenv_keyswitch_kstat_update;
6581708Sstevel 		kstat_install(ksp);
6591708Sstevel 
6601708Sstevel 		/* update the soft state */
6611708Sstevel 		softsp->keyswitch_ksp = ksp;
6621708Sstevel 
6631708Sstevel 	} else {
6641708Sstevel 		cmn_err(CE_WARN, "Keyswitch: kstat_create failed");
6651708Sstevel 		return (-1);
6661708Sstevel 	}
6671708Sstevel 
6681708Sstevel 
6691708Sstevel 	/*
6701708Sstevel 	 * Environmental Information.
6711708Sstevel 	 */
6721708Sstevel 	ksp = kstat_create(SGENV_DRV_NAME, inst, SG_ENV_INFO_KSTAT_NAME,
6737656SSherry.Moore@Sun.COM 	    "misc", KSTAT_TYPE_RAW, 0,
6747656SSherry.Moore@Sun.COM 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE);
6751708Sstevel 
6761708Sstevel 	if (ksp != NULL) {
6771708Sstevel 		ksp->ks_data = NULL;
6781708Sstevel 		ksp->ks_data_size = 0;
6791708Sstevel 		ksp->ks_snaptime = 0;
6801708Sstevel 		ksp->ks_update = sgenv_env_info_kstat_update;
6811708Sstevel 		ksp->ks_snapshot = sgenv_env_info_kstat_snapshot;
6821708Sstevel 		ksp->ks_lock = &env_kstat_lock;
6831708Sstevel 		kstat_install(ksp);
6841708Sstevel 
6851708Sstevel 		/* update the soft state */
6861708Sstevel 		softsp->env_info_ksp = ksp;
6871708Sstevel 
6881708Sstevel 	} else {
6891708Sstevel 		cmn_err(CE_WARN, "Environmental Info: kstat_create failed");
6901708Sstevel 		return (-1);
6911708Sstevel 	}
6921708Sstevel 
6931708Sstevel 
6941708Sstevel 	/*
6951708Sstevel 	 * Board Status Information.
6961708Sstevel 	 */
6971708Sstevel 	ksp = kstat_create(SGENV_DRV_NAME, inst, SG_BOARD_STATUS_KSTAT_NAME,
6987656SSherry.Moore@Sun.COM 	    "misc", KSTAT_TYPE_RAW, 0,
6997656SSherry.Moore@Sun.COM 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE);
7001708Sstevel 
7011708Sstevel 	if (ksp != NULL) {
7021708Sstevel 		ksp->ks_data = NULL;
7031708Sstevel 		ksp->ks_data_size = 0;
7041708Sstevel 		ksp->ks_snaptime = 0;
7051708Sstevel 		ksp->ks_update = sgenv_board_info_kstat_update;
7061708Sstevel 		ksp->ks_snapshot = sgenv_board_info_kstat_snapshot;
7071708Sstevel 		ksp->ks_lock = &board_kstat_lock;
7081708Sstevel 		kstat_install(ksp);
7091708Sstevel 
7101708Sstevel 		/* update the soft state */
7111708Sstevel 		softsp->board_info_ksp = ksp;
7121708Sstevel 
7131708Sstevel 	} else {
7141708Sstevel 		cmn_err(CE_WARN, "Board Status Info: kstat_create failed");
7151708Sstevel 		return (-1);
7161708Sstevel 	}
7171708Sstevel 
7181708Sstevel 	return (0);
7191708Sstevel }
7201708Sstevel 
7211708Sstevel 
7221708Sstevel static void
sgenv_remove_kstats(sgenv_soft_state_t * softsp)7231708Sstevel sgenv_remove_kstats(sgenv_soft_state_t *softsp)
7241708Sstevel {
7251708Sstevel 	kstat_t	*ksp;
7261708Sstevel 
7271708Sstevel 	ksp = softsp->keyswitch_ksp;
7281708Sstevel 	if (ksp != NULL) {
7291708Sstevel 		softsp->keyswitch_ksp = NULL;
7301708Sstevel 		kstat_delete(ksp);
7311708Sstevel 	}
7321708Sstevel 
7331708Sstevel 	ksp = softsp->env_info_ksp;
7341708Sstevel 	if (ksp != NULL) {
7351708Sstevel 		sgenv_destroy_env_cache();
7361708Sstevel 		softsp->env_info_ksp = NULL;
7371708Sstevel 		ksp->ks_lock = NULL;
7381708Sstevel 		kstat_delete(ksp);
7391708Sstevel 	}
7401708Sstevel 
7411708Sstevel 	ksp = softsp->board_info_ksp;
7421708Sstevel 	if (ksp != NULL) {
7431708Sstevel 		softsp->board_info_ksp = NULL;
7441708Sstevel 		ksp->ks_lock = NULL;
7451708Sstevel 		kstat_delete(ksp);
7461708Sstevel 	}
7471708Sstevel }
7481708Sstevel 
7491708Sstevel 
7501708Sstevel /*
7511708Sstevel  * This function registers mailbox interrupt handlers to watch for certain
7521708Sstevel  * unsolicited mailbox messages, which indicate that some event has occurred.
7531708Sstevel  *
7541708Sstevel  * Currently only the following events are handled:
7551708Sstevel  *	MBOX_EVENT_KEY_SWITCH
7561708Sstevel  *	MBOX_EVENT_ENV
7571708Sstevel  *		- Thresholds/Limits Exceeded
7581708Sstevel  *		- Fan Status changed
7591708Sstevel  *
7601708Sstevel  * ERRORS:
7611708Sstevel  *	We return DDI_FAILURE if we fail to register any one of the
7621708Sstevel  *	interrupt handlers.
7631708Sstevel  */
7641708Sstevel static int
sgenv_add_intr_handlers(void)7651708Sstevel sgenv_add_intr_handlers(void)
7661708Sstevel {
7671708Sstevel 	int	err;
7681708Sstevel 
7691708Sstevel 	/*
7701708Sstevel 	 * Register an interrupt handler with the sgsbbc driver for the
7711708Sstevel 	 * MBOX_EVENT_KEY_SWITCH events.
7721708Sstevel 	 *	- The virtual keyswitch has changed, we generate a sysevent.
7731708Sstevel 	 */
7741708Sstevel 	keysw_payload_msg.msg_buf = (caddr_t)&keysw_payload;
7751708Sstevel 	keysw_payload_msg.msg_len = sizeof (keysw_payload);
7761708Sstevel 
7771708Sstevel 	err = sbbc_mbox_reg_intr(MBOX_EVENT_KEY_SWITCH, sgenv_keyswitch_handler,
7787656SSherry.Moore@Sun.COM 	    &keysw_payload_msg, NULL, &keysw_hdlr_lock);
7791708Sstevel 	if (err != 0) {
7801708Sstevel 		cmn_err(CE_WARN, "Failed to register MBOX_EVENT_KEY_SWITCH "
7817656SSherry.Moore@Sun.COM 		    "handler. Err=%d", err);
7821708Sstevel 		return (DDI_FAILURE);
7831708Sstevel 	}
7841708Sstevel 
7851708Sstevel 	/*
7861708Sstevel 	 * Register an interrupt handler with the sgsbbc driver for the
7871708Sstevel 	 * MBOX_EVENT_ENV events.
7881708Sstevel 	 *	- Thresholds/Limits Exceeded, we generate a sysevent
7891708Sstevel 	 *	and we update our caches.
7901708Sstevel 	 */
7911708Sstevel 	env_payload_msg.msg_buf = (caddr_t)&env_payload;
7921708Sstevel 	env_payload_msg.msg_len = sizeof (env_payload);
7931708Sstevel 
7941708Sstevel 	err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, sgenv_env_data_handler,
7957656SSherry.Moore@Sun.COM 	    &env_payload_msg, NULL, &env_hdlr_lock);
7961708Sstevel 	if (err != 0) {
7971708Sstevel 		cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV "
7987656SSherry.Moore@Sun.COM 		    "(env) handler. Err=%d", err);
7991708Sstevel 		return (DDI_FAILURE);
8001708Sstevel 	}
8011708Sstevel 
8021708Sstevel 	/*
8031708Sstevel 	 * Register an interrupt handler with the sgsbbc driver for the
8041708Sstevel 	 * MBOX_EVENT_ENV events.
8051708Sstevel 	 *	- Fan Status changed, we generate a sysevent, and
8061708Sstevel 	 *	we update the env cache only.
8071708Sstevel 	 */
8081708Sstevel 	fan_payload_msg.msg_buf = (caddr_t)&fan_payload;
8091708Sstevel 	fan_payload_msg.msg_len = sizeof (fan_payload);
8101708Sstevel 
8111708Sstevel 	err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, sgenv_fan_status_handler,
8127656SSherry.Moore@Sun.COM 	    &fan_payload_msg, NULL, &env_hdlr_lock);
8131708Sstevel 	if (err != 0) {
8141708Sstevel 		cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV (fan)"
8157656SSherry.Moore@Sun.COM 		    "handler. Err=%d", err);
8161708Sstevel 		return (DDI_FAILURE);
8171708Sstevel 	}
8181708Sstevel 
8191708Sstevel 	/*
8201708Sstevel 	 * Register an interrupt handler with the sgsbbc driver for the
8211708Sstevel 	 * MBOX_EVENT_GENERIC events.
8221708Sstevel 	 *	- DR state change, we update our caches.
8231708Sstevel 	 */
8241708Sstevel 	dr_payload_msg.msg_buf = (caddr_t)&dr_payload;
8251708Sstevel 	dr_payload_msg.msg_len = sizeof (dr_payload);
8261708Sstevel 
8271708Sstevel 	err = sbbc_mbox_reg_intr(MBOX_EVENT_GENERIC, sgenv_dr_event_handler,
8287656SSherry.Moore@Sun.COM 	    &dr_payload_msg, NULL, &dr_hdlr_lock);
8291708Sstevel 	if (err != 0) {
8301708Sstevel 		cmn_err(CE_WARN, "Failed to register MBOX_EVENT_GENERIC (DR)"
8317656SSherry.Moore@Sun.COM 		    "handler. Err=%d", err);
8321708Sstevel 		return (DDI_FAILURE);
8331708Sstevel 	}
8341708Sstevel 
8351708Sstevel 	return (DDI_SUCCESS);
8361708Sstevel }
8371708Sstevel 
8381708Sstevel /*
8391708Sstevel  * This function unregisters the mailbox interrupt handlers.
8401708Sstevel  *
8411708Sstevel  * ERRORS:
8421708Sstevel  *	We return DDI_FAILURE if we fail to register any one of the
8431708Sstevel  *	interrupt handlers.
8441708Sstevel  */
8451708Sstevel static int
sgenv_remove_intr_handlers(void)8461708Sstevel sgenv_remove_intr_handlers(void)
8471708Sstevel {
8481708Sstevel 	int	rv = DDI_SUCCESS;
8491708Sstevel 	int	err;
8501708Sstevel 
8511708Sstevel 	err = sbbc_mbox_unreg_intr(MBOX_EVENT_KEY_SWITCH,
8527656SSherry.Moore@Sun.COM 	    sgenv_keyswitch_handler);
8531708Sstevel 	if (err != 0) {
8541708Sstevel 		cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_KEY_SWITCH "
8557656SSherry.Moore@Sun.COM 		    "handler. Err=%d", err);
8561708Sstevel 		rv = DDI_FAILURE;
8571708Sstevel 	}
8581708Sstevel 
8591708Sstevel 	err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, sgenv_env_data_handler);
8601708Sstevel 	if (err != 0) {
8611708Sstevel 		cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV (env)"
8627656SSherry.Moore@Sun.COM 		    "handler. Err=%d", err);
8631708Sstevel 		rv = DDI_FAILURE;
8641708Sstevel 	}
8651708Sstevel 
8661708Sstevel 	err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, sgenv_fan_status_handler);
8671708Sstevel 	if (err != 0) {
8681708Sstevel 		cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV (fan)"
8697656SSherry.Moore@Sun.COM 		    "handler. Err=%d", err);
8701708Sstevel 		rv = DDI_FAILURE;
8711708Sstevel 	}
8721708Sstevel 
8731708Sstevel 	err = sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, sgenv_dr_event_handler);
8741708Sstevel 	if (err != 0) {
8751708Sstevel 		cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_GENERIC (DR) "
8767656SSherry.Moore@Sun.COM 		    "handler. Err=%d", err);
8771708Sstevel 		rv = DDI_FAILURE;
8781708Sstevel 	}
8791708Sstevel 
8801708Sstevel 	return (rv);
8811708Sstevel }
8821708Sstevel 
8831708Sstevel 
8841708Sstevel static int
sgenv_create_cache_update_threads(void)8851708Sstevel sgenv_create_cache_update_threads(void)
8861708Sstevel {
8871979Sarutz 	DCMN_ERR_S(f, "sgenv_create_cache_update_threads()");
8881708Sstevel 
8891708Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "Entering %s", f);
8901708Sstevel 
8911708Sstevel 	/* Create thread to ensure env_cache is updated */
8921708Sstevel 	env_thread_run = 1;
8931708Sstevel 
8941708Sstevel 	env_thread = thread_create(NULL, 0, sgenv_update_env_cache,
8951708Sstevel 	    NULL, 0, &p0, TS_RUN, minclsyspri);
8961708Sstevel 	env_thread_tid = env_thread->t_did;
8971708Sstevel 
8981708Sstevel 	/* Create thread to ensure board_cache is updated */
8991708Sstevel 	board_thread_run = 1;
9001708Sstevel 
9011708Sstevel 	board_thread = thread_create(NULL, 0, sgenv_update_board_cache,
9021708Sstevel 	    NULL, 0, &p0, TS_RUN, minclsyspri);
9031708Sstevel 	board_thread_tid = board_thread->t_did;
9041708Sstevel 
9051708Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "Exiting %s", f);
9061708Sstevel 
9071708Sstevel 	return (DDI_SUCCESS);
9081708Sstevel }
9091708Sstevel 
9101708Sstevel 
9111708Sstevel static int
sgenv_remove_cache_update_threads(void)9121708Sstevel sgenv_remove_cache_update_threads(void)
9131708Sstevel {
9141979Sarutz 	DCMN_ERR_S(f, "sgenv_remove_cache_update_threads()");
9151708Sstevel 
9161708Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "%s: Waiting for cache update threads", f);
9171708Sstevel 
9181708Sstevel 	/* Cause the env_cache thread to terminate. */
9191708Sstevel 	mutex_enter(&env_flag_lock);
9201708Sstevel 	env_thread_run = 0;
9211708Sstevel 	cv_signal(&env_flag_cond);
9221708Sstevel 	mutex_exit(&env_flag_lock);
9231708Sstevel 
9241708Sstevel 	thread_join(env_thread_tid);
9251708Sstevel 
9261708Sstevel 	/* Cause the board_cache thread to terminate. */
9271708Sstevel 	mutex_enter(&board_flag_lock);
9281708Sstevel 	board_thread_run = 0;
9291708Sstevel 	cv_signal(&board_flag_cond);
9301708Sstevel 	mutex_exit(&board_flag_lock);
9311708Sstevel 
9321708Sstevel 	thread_join(board_thread_tid);
9331708Sstevel 
9341708Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "%s: cache update threads finished", f);
9351708Sstevel 
9361708Sstevel 	return (DDI_SUCCESS);
9371708Sstevel }
9381708Sstevel 
9391708Sstevel 
9401708Sstevel static int
sgenv_keyswitch_kstat_update(kstat_t * ksp,int rw)9411708Sstevel sgenv_keyswitch_kstat_update(kstat_t *ksp, int rw)
9421708Sstevel {
9431708Sstevel 	sg_keyswitch_kstat_t	*keysw_data;
9441708Sstevel 
9451708Sstevel 	int8_t	posn;	/* keysw posn read from IO-SRAM */
9461708Sstevel 	int	size;	/* size of IO-SRAM chunk */
9471708Sstevel 	int	rv = 0;	/* return value of iosram_read() */
9481708Sstevel 
9491708Sstevel 	keysw_data	= (sg_keyswitch_kstat_t *)ksp->ks_data;
9501708Sstevel 
9511708Sstevel 	switch (rw) {
9521708Sstevel 	case KSTAT_WRITE:
9531708Sstevel 		/*
9541708Sstevel 		 * Write not permitted
9551708Sstevel 		 */
9561708Sstevel 		return (EACCES);
9571708Sstevel 
9581708Sstevel 	case KSTAT_READ:
9591708Sstevel 		/*
9601708Sstevel 		 * Get the size of the keyswitch IO-SRAM chunk.
9611708Sstevel 		 * This should be one byte.
9621708Sstevel 		 *
9631708Sstevel 		 * If the size is not 1 byte we set the position to UNKNOWN
9641708Sstevel 		 *
9651708Sstevel 		 * Otherwise we read the keyswitch position from IO-SRAM.
9661708Sstevel 		 * Then check that this is a valid keyswitch position.
9671708Sstevel 		 * If it is not valid then something is corrupt and set
9681708Sstevel 		 * the position to UNKNOWN.
9691708Sstevel 		 */
9701708Sstevel 		size = iosram_size(SBBC_KEYSWITCH_KEY);
9711708Sstevel 		if (size != 1) {
9721708Sstevel 			posn = SG_KEYSWITCH_POSN_UNKNOWN;
9731708Sstevel 			rv = -1;
9741708Sstevel 
9751708Sstevel 		} else if ((rv = iosram_read(SBBC_KEYSWITCH_KEY, 0,
9767656SSherry.Moore@Sun.COM 		    (char *)&posn, size)) != 0) {
9771708Sstevel 			posn = SG_KEYSWITCH_POSN_UNKNOWN;
9781708Sstevel 
9791708Sstevel 		} else {
9801708Sstevel 			/* Check posn is not corrupt */
9811708Sstevel 			switch (posn) {
9821708Sstevel 				case SG_KEYSWITCH_POSN_ON:
9831708Sstevel 				case SG_KEYSWITCH_POSN_DIAG:
9841708Sstevel 				case SG_KEYSWITCH_POSN_SECURE:
9851708Sstevel 					/* value read from kstat is OK */
9861708Sstevel 					break;
9871708Sstevel 
9881708Sstevel 				default:
9891708Sstevel 					/* value read from kstat is corrupt */
9901708Sstevel 					posn = SG_KEYSWITCH_POSN_UNKNOWN;
9911708Sstevel 					break;
9921708Sstevel 			}
9931708Sstevel 		}
9941708Sstevel 
9951708Sstevel 		/* Write position to kstat. */
9961708Sstevel 		keysw_data->keyswitch_position.value.i32 = posn;
9971708Sstevel 
9981708Sstevel 		return (rv);
9991708Sstevel 
10001708Sstevel 	default:
10011708Sstevel 		return (EINVAL);
10021708Sstevel 	}
10031708Sstevel }
10041708Sstevel 
10051708Sstevel static void
sgenv_init_env_cache(void)10061708Sstevel sgenv_init_env_cache(void)
10071708Sstevel {
10081708Sstevel 	ASSERT(env_thread_run == 0);
10091708Sstevel 	ASSERT(env_thread == NULL);
10101708Sstevel }
10111708Sstevel 
10121708Sstevel 
10131708Sstevel /*
10141708Sstevel  * This thread runs in the background and waits for an interrupt handler
10151708Sstevel  * registered to wait for ENV/DR events from the SC to signal/flag that we
10161708Sstevel  * need to update our Env Cache.
10171708Sstevel  */
10181708Sstevel static void
sgenv_update_env_cache(void)10191708Sstevel sgenv_update_env_cache(void)
10201708Sstevel {
10211979Sarutz 	DCMN_ERR_S(f, "sgenv_update_env_cache()");
10221708Sstevel 
10231708Sstevel 	mutex_enter(&env_flag_lock);
10241708Sstevel 
10251708Sstevel 	while (env_thread_run == 1) {
10261708Sstevel 
10271708Sstevel 		/*
10281708Sstevel 		 * We check to see if the update needed flag is set.
10291708Sstevel 		 * If it is then this means that:
10301708Sstevel 		 *	1) This is the first time through the while loop
10311708Sstevel 		 *	   and we need to initialize the cache.
10321708Sstevel 		 *	2) An interrupt handler was triggered while we
10331708Sstevel 		 *	   we were updating the env cache during the previous
10341708Sstevel 		 *	   iteration of the while loop and we need to refresh
10351708Sstevel 		 *	   the env data to ensure we are completely up to date.
10361708Sstevel 		 *
10371708Sstevel 		 * Otherwise we wait until we get a signal from one of the
10381708Sstevel 		 * interrupt handlers.
10391708Sstevel 		 */
10401708Sstevel 		if (env_cache_update_needed) {
10411708Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: update needed", f);
10421708Sstevel 
10431708Sstevel 			env_cache_update_needed = B_FALSE;
10441708Sstevel 
10451708Sstevel 		} else {
10461708Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Waiting for signal", f);
10471708Sstevel 
10481708Sstevel 			cv_wait(&env_flag_cond, &env_flag_lock);
10491708Sstevel 
10501708Sstevel 			/* Check if we are being asked to terminate */
10511708Sstevel 			if (env_thread_run == 0) {
10521708Sstevel 				break;
10531708Sstevel 			}
10541708Sstevel 
10551708Sstevel 			env_cache_updating = B_TRUE;
10561708Sstevel 		}
10571708Sstevel 
10581708Sstevel 		mutex_exit(&env_flag_lock);
1059*11311SSurya.Prakki@Sun.COM 		(void) sgenv_get_env_info_data();
1060*11311SSurya.Prakki@Sun.COM 
1061*11311SSurya.Prakki@Sun.COM 		(void) sgenv_check_sensor_thresholds();
10621708Sstevel 		mutex_enter(&env_flag_lock);
10631708Sstevel 
10641708Sstevel 		if (env_cache_update_needed == B_FALSE)
10651708Sstevel 			env_cache_updating = B_FALSE;
10661708Sstevel 	}
10671708Sstevel 
10681708Sstevel 	mutex_exit(&env_flag_lock);
10691708Sstevel 
10701708Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "Exiting %s", f);
10711708Sstevel 
10721708Sstevel 	env_thread_run = -1;
10731708Sstevel 	thread_exit();
10741708Sstevel }
10751708Sstevel 
10761708Sstevel 
10771708Sstevel /*
10781708Sstevel  * We always return what is in the env_cache. It is up to the SC to ensure
10791708Sstevel  * that the env_cache is current by sending events to us when something
10801708Sstevel  * changes. The cache will then be updated by going to the SC to get the
10811708Sstevel  * new data. That way the kstat_update code can always be sure that it gets
10821708Sstevel  * current data without having to wait while the SC responds (slowly) to our
10831708Sstevel  * request for data.
10841708Sstevel  *
10851708Sstevel  * The way the update and snapshot code works, we cannot be guaranteed that
10861708Sstevel  * someone won't grab the env_cache_lock between the update and snapshot
10871708Sstevel  * calls so we use a temporary snapshot of the env_cache. We cannot hold
10881708Sstevel  * any locks across the calls from the update to the snapshot as we are
10891708Sstevel  * not guaranteed that the snapshot function will be called. So we create
10901708Sstevel  * the snapshot of the env_cache in the update routine and dump this to the
10911708Sstevel  * kstat user buffer in the snapshot routine. (There are error conditions in
10921708Sstevel  * which the snapshot will not be called by the kstat framework so we need
10931708Sstevel  * to handle these appropriately.)
10941708Sstevel  */
10951708Sstevel static int
sgenv_env_info_kstat_update(kstat_t * ksp,int rw)10961708Sstevel sgenv_env_info_kstat_update(kstat_t *ksp, int rw)
10971708Sstevel {
10981979Sarutz 	DCMN_ERR_S(f, "sgenv_env_info_kstat_update()");
10991708Sstevel 
11001708Sstevel 	int		err = 0;
11011708Sstevel 	int		key_posn;
11021708Sstevel 	env_sensor_t	*ptr;
11031708Sstevel 
11041708Sstevel 	switch (rw) {
11051708Sstevel 	case KSTAT_WRITE:
11061708Sstevel 		/*
11071708Sstevel 		 * Write not permitted
11081708Sstevel 		 */
11091708Sstevel 		return (EACCES);
11101708Sstevel 
11111708Sstevel 	case KSTAT_READ:
11121708Sstevel 
11131708Sstevel 		mutex_enter(&env_cache_lock);
11141708Sstevel 		/*
11151708Sstevel 		 * We now need to ensure that there is enough room allocated
11161708Sstevel 		 * by the kstat framework to return the data via ks_data.
11171708Sstevel 		 * It is possible there may be no data in the cache but
11181708Sstevel 		 * we still return zero sized kstats to ensure no client breaks
11191708Sstevel 		 */
11201708Sstevel 		sgenv_update_env_kstat_size(ksp);
11211708Sstevel 
11221708Sstevel 		/*
11231708Sstevel 		 * If the snapshot still has data (this could be because the
11241708Sstevel 		 * kstat framework discovered an error and did not call the
11251708Sstevel 		 * snapshot code which should have freed this buffer) we free
11261708Sstevel 		 * it here.
11271708Sstevel 		 */
11281708Sstevel 		if ((env_cache_snapshot != NULL) &&
11297656SSherry.Moore@Sun.COM 		    (env_cache_snapshot_size > 0)) {
11301708Sstevel 			DCMN_ERR_CACHE(CE_NOTE, "%s freeing "
11317656SSherry.Moore@Sun.COM 			    "env_cache_snapshot buf", f);
11321708Sstevel 			kmem_free(env_cache_snapshot, env_cache_snapshot_size);
11331708Sstevel 		}
11341708Sstevel 
11351708Sstevel 		/*
11361708Sstevel 		 * Create a new snapshot buffer based on ks_data_size
11371708Sstevel 		 */
11381708Sstevel 		env_cache_snapshot_size = ksp->ks_data_size;
11391708Sstevel 		env_cache_snapshot = kmem_zalloc(
11407656SSherry.Moore@Sun.COM 		    env_cache_snapshot_size, KM_SLEEP);
11411708Sstevel 
11421708Sstevel 		/*
11431708Sstevel 		 * We need to take a fresh snapshot of the env_cache here.
11441708Sstevel 		 * For each sensor collection, we check to see if there is
11451708Sstevel 		 * data in the cache (ie. != NULL). If there is, we copy it
11461708Sstevel 		 * into the snapshot.
11471708Sstevel 		 */
11481708Sstevel 		ptr = env_cache_snapshot;
11491708Sstevel 		for (key_posn = 0; key_posn < SGENV_MAX_HPU_KEYS; key_posn++) {
11501708Sstevel 			if (vol_sensor_count[key_posn] <= 0)
11511708Sstevel 				continue;
11521708Sstevel 
11531708Sstevel 			ASSERT(vol_sensor_count[key_posn] <=
11547656SSherry.Moore@Sun.COM 			    SGENV_MAX_SENSORS_PER_KEY);
11551708Sstevel 
11561708Sstevel 			/*
11571708Sstevel 			 * <env_cache> entry should have been allocated
11581708Sstevel 			 * in the kstat_update function already.
11591708Sstevel 			 *
11601708Sstevel 			 * If this <env_cache> entry is NULL, then
11611708Sstevel 			 * it has already been destroyed or cleared
11621708Sstevel 			 * and the sensor readings have disappeared.
11631708Sstevel 			 */
11641708Sstevel 			if (env_cache[key_posn] == NULL) {
11651708Sstevel 				DCMN_ERR(CE_NOTE, "!Cache entry %d has "
11667656SSherry.Moore@Sun.COM 				    "disappeared", key_posn);
11671708Sstevel 				vol_sensor_count[key_posn] = 0;
11681708Sstevel 				continue;
11691708Sstevel 			}
11701708Sstevel 
11711708Sstevel 			bcopy(&env_cache[key_posn][0], ptr,
11721708Sstevel 			    sizeof (env_sensor_t) *
11731708Sstevel 			    vol_sensor_count[key_posn]);
11741708Sstevel 			ptr += vol_sensor_count[key_posn];
11751708Sstevel 		}
11761708Sstevel 		mutex_exit(&env_cache_lock);
11771708Sstevel 
11781708Sstevel 		return (err);
11791708Sstevel 
11801708Sstevel 	default:
11811708Sstevel 		return (EINVAL);
11821708Sstevel 	}
11831708Sstevel }
11841708Sstevel 
11851708Sstevel static int
sgenv_env_info_kstat_snapshot(kstat_t * ksp,void * buf,int rw)11861708Sstevel sgenv_env_info_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
11871708Sstevel {
11881979Sarutz 	DCMN_ERR_S(f, "sgenv_env_info_kstat_snapshot()");
11891708Sstevel 
11901708Sstevel 	switch (rw) {
11911708Sstevel 	case KSTAT_WRITE:
11921708Sstevel 		/*
11931708Sstevel 		 * Write not permitted
11941708Sstevel 		 */
11951708Sstevel 		return (EACCES);
11961708Sstevel 
11971708Sstevel 	case KSTAT_READ:
11981708Sstevel 
11991708Sstevel 		/*
12001708Sstevel 		 * We have taken a snapshot of the env_cache in the
12011708Sstevel 		 * update routine so we simply bcopy this into the
12021708Sstevel 		 * kstat buf. No locks needed here.
12031708Sstevel 		 */
12041708Sstevel 		if (env_cache_snapshot_size > 0)
12051708Sstevel 			bcopy(env_cache_snapshot, buf, env_cache_snapshot_size);
12061708Sstevel 
12071708Sstevel 		ksp->ks_snaptime = last_env_read_time;
12081708Sstevel 
12091708Sstevel 		/*
12101708Sstevel 		 * Free the memory used by the snapshot. If for some reason
12111708Sstevel 		 * the kstat framework does not call this snapshot routine,
12121708Sstevel 		 * we also have a check in the update routine so the next
12131708Sstevel 		 * time it is called it checks for this condition and frees
12141708Sstevel 		 * the snapshot buffer there.
12151708Sstevel 		 */
12161708Sstevel 		DCMN_ERR_CACHE(CE_NOTE, "%s freeing env_cache_snapshot buf", f);
12171708Sstevel 		kmem_free(env_cache_snapshot, env_cache_snapshot_size);
12181708Sstevel 		env_cache_snapshot = NULL;
12191708Sstevel 		env_cache_snapshot_size = 0;
12201708Sstevel 
12211708Sstevel 		return (0);
12221708Sstevel 
12231708Sstevel 	default:
12241708Sstevel 		return (EINVAL);
12251708Sstevel 	}
12261708Sstevel }
12271708Sstevel 
12281708Sstevel static void
sgenv_init_board_cache(void)12291708Sstevel sgenv_init_board_cache(void)
12301708Sstevel {
12311708Sstevel 	int	i;
12321708Sstevel 
12331708Sstevel 	ASSERT(board_thread_run == 0);
12341708Sstevel 	ASSERT(board_thread == NULL);
12351708Sstevel 
12361708Sstevel 	/*
12371708Sstevel 	 * Init all node-ids to be -1.
12381708Sstevel 	 */
12391708Sstevel 	mutex_enter(&board_cache_lock);
12401708Sstevel 	for (i = 0; i < SG_MAX_BDS; i++)
12411708Sstevel 		board_cache[i].node_id = (-1);
12421708Sstevel 	mutex_exit(&board_cache_lock);
12431708Sstevel }
12441708Sstevel 
12451708Sstevel 
12461708Sstevel /*
12471708Sstevel  * This thread runs in the background and waits for an interrupt handler
12481708Sstevel  * registered to wait for DR events from the SC to signal/flag that we
12491708Sstevel  * need to update our Board Cache.
12501708Sstevel  */
12511708Sstevel static void
sgenv_update_board_cache(void)12521708Sstevel sgenv_update_board_cache(void)
12531708Sstevel {
12541979Sarutz 	DCMN_ERR_S(f, "sgenv_update_board_cache()");
12551708Sstevel 
12561708Sstevel 	mutex_enter(&board_flag_lock);
12571708Sstevel 
12581708Sstevel 	while (board_thread_run == 1) {
12591708Sstevel 
12601708Sstevel 		/*
12611708Sstevel 		 * We check to see if the update needed flag is set.
12621708Sstevel 		 * If it is then this means that:
12631708Sstevel 		 *	1) This is the first time through the while loop
12641708Sstevel 		 *	   and we need to initialize the cache.
12651708Sstevel 		 *	2) An interrupt handler was triggered while we
12661708Sstevel 		 *	   we were updating the cache during the previous
12671708Sstevel 		 *	   iteration of the while loop and we need to refresh
12681708Sstevel 		 *	   the env data to ensure we are completely up to date.
12691708Sstevel 		 *
12701708Sstevel 		 * Otherwise we wait until we get a signal from one of the
12711708Sstevel 		 * interrupt handlers.
12721708Sstevel 		 */
12731708Sstevel 		if (board_cache_update_needed) {
12741708Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: update needed", f);
12751708Sstevel 			board_cache_update_needed = B_FALSE;
12761708Sstevel 
12771708Sstevel 		} else {
12781708Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Waiting for signal", f);
12791708Sstevel 
12801708Sstevel 			cv_wait(&board_flag_cond, &board_flag_lock);
12811708Sstevel 
12821708Sstevel 			/* Check if we are being asked to terminate */
12831708Sstevel 			if (board_thread_run == 0) {
12841708Sstevel 				break;
12851708Sstevel 			}
12861708Sstevel 
12871708Sstevel 			board_cache_updating = B_TRUE;
12881708Sstevel 		}
12891708Sstevel 
12901708Sstevel 		mutex_exit(&board_flag_lock);
1291*11311SSurya.Prakki@Sun.COM 		(void) sgenv_get_board_info_data();
12921708Sstevel 		mutex_enter(&board_flag_lock);
12931708Sstevel 
12941708Sstevel 		if (board_cache_update_needed == B_FALSE)
12951708Sstevel 			board_cache_updating = B_FALSE;
12961708Sstevel 	}
12971708Sstevel 
12981708Sstevel 	mutex_exit(&board_flag_lock);
12991708Sstevel 
13001708Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "Exiting %s", f);
13011708Sstevel 
13021708Sstevel 	board_thread_run = -1;
13031708Sstevel 	thread_exit();
13041708Sstevel }
13051708Sstevel 
13061708Sstevel 
13071708Sstevel /*
13081708Sstevel  * We always return what is in the board_cache. It is up to the SC to ensure
13091708Sstevel  * that the board_cache is current by sending events to us when something
13101708Sstevel  * changes. The cache will then be updated by going to the SC to get the
13111708Sstevel  * new data. That way the kstat_update code can always be sure that it gets
13121708Sstevel  * current data without having to wait while the SC responds (slowly) to our
13131708Sstevel  * request for data.
13141708Sstevel  *
13151708Sstevel  * The way the update and snapshot code works, we cannot be guaranteed that
13161708Sstevel  * someone won't grab the board_cache_lock between the update and snapshot
13171708Sstevel  * calls so we use a snapshot buffer of the board_cache. We cannot hold
13181708Sstevel  * any locks across the calls from the update to the snapshot as we are
13191708Sstevel  * not guaranteed that the snapshot function will be called. So we create
13201708Sstevel  * the snapshot of the board_cache in the update routine and dump this to the
13211708Sstevel  * kstat user buffer in the snapshot routine. (There are error conditions in
13221708Sstevel  * which the snapshot will not be called by the kstat framework so we need
13231708Sstevel  * to handle these appropriately.)
13241708Sstevel  */
13251708Sstevel static int
sgenv_board_info_kstat_update(kstat_t * ksp,int rw)13261708Sstevel sgenv_board_info_kstat_update(kstat_t *ksp, int rw)
13271708Sstevel {
13281708Sstevel 	int		i;
13291708Sstevel 
13301708Sstevel 	switch (rw) {
13311708Sstevel 	case KSTAT_WRITE:
13321708Sstevel 		/*
13331708Sstevel 		 * Write not permitted
13341708Sstevel 		 */
13351708Sstevel 		return (EACCES);
13361708Sstevel 
13371708Sstevel 	case KSTAT_READ:
13381708Sstevel 		/*
13391708Sstevel 		 * The board_cache is created during startup, and so should be
13401708Sstevel 		 * available before a user can log in and trigger a kstat read,
13411708Sstevel 		 * but we check just in case.
13421708Sstevel 		 */
13431708Sstevel 		if (board_cache_updated == FALSE)
13441708Sstevel 			return (ENXIO);
13451708Sstevel 
13461708Sstevel 		mutex_enter(&board_cache_lock);
13471708Sstevel 
13481708Sstevel 		/*
13491708Sstevel 		 * Set <ks_data_size> to the new number of board readings so
13501708Sstevel 		 * that the snapshot routine can allocate the correctly sized
13511708Sstevel 		 * kstat.
13521708Sstevel 		 */
13531708Sstevel 		ksp->ks_data_size = board_count * sizeof (sg_board_info_t);
13541708Sstevel 
13551708Sstevel 		board_count_snapshot = board_count;
13561708Sstevel 
13571708Sstevel 		/*
13581708Sstevel 		 * We are now guaranteed that that board_cache is not in flux
13591708Sstevel 		 * (as we have the lock) so we take a copy of the board_cache
13601708Sstevel 		 * into the board_cache_snapshot so that the snapshot routine
13611708Sstevel 		 * can copy it from the board_cache_snapshot into the user kstat
13621708Sstevel 		 * buffer.
13631708Sstevel 		 */
13641708Sstevel 		for (i = 0; i < SG_MAX_BDS; i++) {
13651708Sstevel 			board_cache_snapshot[i] = board_cache[i];
13661708Sstevel 		}
13671708Sstevel 
13681708Sstevel 		mutex_exit(&board_cache_lock);
13691708Sstevel 
13701708Sstevel 		return (0);
13711708Sstevel 
13721708Sstevel 	default:
13731708Sstevel 		return (EINVAL);
13741708Sstevel 	}
13751708Sstevel }
13761708Sstevel 
13771708Sstevel static int
sgenv_board_info_kstat_snapshot(kstat_t * ksp,void * buf,int rw)13781708Sstevel sgenv_board_info_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
13791708Sstevel {
13801979Sarutz 	DCMN_ERR_S(f, "sgenv_board_info_kstat_snapshot()");
13811708Sstevel 
13821708Sstevel 	sg_board_info_t	*bdp;
13831708Sstevel 	int		i, num_bds = 0;
13841708Sstevel 
13851708Sstevel 	switch (rw) {
13861708Sstevel 	case KSTAT_WRITE:
13871708Sstevel 		/*
13881708Sstevel 		 * Write not permitted
13891708Sstevel 		 */
13901708Sstevel 		return (EACCES);
13911708Sstevel 
13921708Sstevel 	case KSTAT_READ:
13931708Sstevel 
13941708Sstevel 		if (board_cache_updated == FALSE) {
13951708Sstevel 			ksp->ks_data_size = 0;
13961708Sstevel 			ksp->ks_data = NULL;
13971708Sstevel 			return (ENOMEM);
13981708Sstevel 		}
13991708Sstevel 
14001708Sstevel 		/*
14011708Sstevel 		 * Update the snap_time with the last time we got fresh data
14021708Sstevel 		 * from the SC.
14031708Sstevel 		 */
14041708Sstevel 		ksp->ks_snaptime = last_board_read_time;
14051708Sstevel 
14061708Sstevel 		ASSERT(board_count_snapshot <= SG_MAX_BDS);
14071708Sstevel 		/*
14081708Sstevel 		 * For each entry in the board_cache_snapshot we check to see
14091708Sstevel 		 * if the node_id is != NULL before we copy it into
14101708Sstevel 		 * the kstat buf.
14111708Sstevel 		 */
14121708Sstevel 		for (i = 0; i < SG_MAX_BDS; i++) {
14131708Sstevel 			bdp = &board_cache_snapshot[i];
14141708Sstevel 			DCMN_ERR_CACHE(CE_NOTE, "%s: looking at "
14157656SSherry.Moore@Sun.COM 			    "cache_snapshot entry[%d], node=%d",
14167656SSherry.Moore@Sun.COM 			    f, i, bdp->node_id);
14171708Sstevel 			if (bdp->node_id >= 0) {
14181708Sstevel 				/*
14191708Sstevel 				 * Need a check to ensure that the buf
14201708Sstevel 				 * is still within the allocated size.
14211708Sstevel 				 * We check how many boards are already
14221708Sstevel 				 * in the user buf before adding one.
14231708Sstevel 				 */
14241708Sstevel 				num_bds++;
14251708Sstevel 				if (num_bds > board_count_snapshot) {
14261708Sstevel 					ksp->ks_data_size = 0;
14271708Sstevel 					ksp->ks_data = NULL;
14281708Sstevel 					DCMN_ERR(CE_WARN, "%s: buf overflow."
14291708Sstevel 					    " %d >= %d.",
14301708Sstevel 					    f, num_bds, board_count_snapshot);
14311708Sstevel 					return (EIO);
14321708Sstevel 				}
14331708Sstevel 
14341708Sstevel 				DCMN_ERR_CACHE(CE_NOTE, "%s: about to bcopy"
14357656SSherry.Moore@Sun.COM 				    " cache_snapshot entry[%d], node=%d,"
14367656SSherry.Moore@Sun.COM 				    " board=%d", f, i, bdp->node_id,
14377656SSherry.Moore@Sun.COM 				    bdp->board_num);
14381708Sstevel 				bcopy(bdp, buf, sizeof (sg_board_info_t));
14391708Sstevel 				buf = ((sg_board_info_t *)buf) + 1;
14401708Sstevel 			}
14411708Sstevel 		}
14421708Sstevel 		return (0);
14431708Sstevel 
14441708Sstevel 	default:
14451708Sstevel 		return (EINVAL);
14461708Sstevel 	}
14471708Sstevel }
14481708Sstevel 
14491708Sstevel 
14501708Sstevel /*
14511708Sstevel  * This function coordinates reading the env data from the SC.
14521708Sstevel  *
14531708Sstevel  * ERROR:
14541708Sstevel  * 	If an error occurs while making a call to the mailbox and we have data
14551708Sstevel  *	in the cache from a previous call to the SC, we return an error of 0.
14561708Sstevel  *	That way the kstat framework will return the old data instead of
14571708Sstevel  *	returning an error and an empty kstat.
14581708Sstevel  */
14591708Sstevel static int
sgenv_get_env_info_data(void)14601708Sstevel sgenv_get_env_info_data(void)
14611708Sstevel {
14621979Sarutz 	DCMN_ERR_S(f, "sgenv_get_env_info_data()");
14631708Sstevel 
14641708Sstevel 	envresp_key_t	new_keys[SGENV_MAX_HPU_KEYS] = {0};
14651708Sstevel 	envresp_key_t	old_key;
14661708Sstevel 	envresp_key_t	key;
14671708Sstevel 
14681708Sstevel 	int	i;
14691708Sstevel 
14701708Sstevel 	int	err = 0;	/* return value of func's which get env data */
14711708Sstevel 	int	status = 0;	/* reason why env data func returned an error */
14721708Sstevel 
14731708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: entered.", f);
14741708Sstevel 
14751708Sstevel 	err = sgenv_get_hpu_keys(new_keys, &status);
14761708Sstevel 
14771708Sstevel 	if (err != 0) {
14781708Sstevel 		/*
14791708Sstevel 		 * If we get an error getting the key values, then we return
14801708Sstevel 		 * as we cannot proceed any farther. If there is old env data
14811708Sstevel 		 * in the cache, then we return zero so that the kstat
14821708Sstevel 		 * framework will export the old data.
14831708Sstevel 		 */
14841708Sstevel 		if (env_cache_updated == FALSE) {
14851708Sstevel 			sgenv_mbox_error_msg("HPU Keys", err, status);
14861708Sstevel 			return (err);
14871708Sstevel 		} else {
14881708Sstevel 			sgenv_mbox_error_msg("HPU Keys", err, status);
14891708Sstevel 			return (0);
14901708Sstevel 		}
14911708Sstevel 	}
14921708Sstevel 
14931708Sstevel 
14941708Sstevel 	for (i = 0; i < SGENV_MAX_HPU_KEYS; i++) {
14951708Sstevel 
14961708Sstevel 		if (vol_sensor_count[i] == 0) {
14971708Sstevel 			/* empty collection */
14981708Sstevel 			old_key = 0;
14991708Sstevel 		} else {
15001708Sstevel 			/*
15011708Sstevel 			 * populated collection:
15021708Sstevel 			 * (assert size is OK, and 1st sensor is pseudo-sensor)
15031708Sstevel 			 */
15041708Sstevel 			ASSERT(env_cache[i] != NULL);
15051708Sstevel 			ASSERT(env_cache[i][0].sd_id.id.sensor_part ==
15067656SSherry.Moore@Sun.COM 			    SG_SENSOR_PART_SCAPP);
15071708Sstevel 			ASSERT(env_cache[i][0].sd_id.id.sensor_type ==
15087656SSherry.Moore@Sun.COM 			    SG_SENSOR_TYPE_ENVDB);
15091708Sstevel 			ASSERT(SG_INFO_VALUESTATUS(env_cache[i][0].sd_infostamp)
15107656SSherry.Moore@Sun.COM 			    == SG_INFO_VALUE_OK);
15111708Sstevel 
15121708Sstevel 			old_key = env_cache[i][0].sd_value;
15131708Sstevel 		}
15141708Sstevel 
15151708Sstevel 		key = new_keys[i];
15161708Sstevel 
15171708Sstevel 		/*
15181708Sstevel 		 * No data is associated with this key position and there was
15191708Sstevel 		 * no data on the previous read either so we simply continue
15201708Sstevel 		 * to the next key position.
15211708Sstevel 		 */
15221708Sstevel 		if ((key == 0) && (old_key == 0)) {
15231708Sstevel 			ASSERT(env_cache[i] == NULL);
15241708Sstevel 			continue;
15251708Sstevel 		}
15261708Sstevel 
15271708Sstevel 
15281708Sstevel 		/*
15291708Sstevel 		 * We need to grab this lock every time we are going to
15301708Sstevel 		 * update a HPU. However, a kstat_read can grab
15311708Sstevel 		 * the env_cache_lock when it wants to get a snapshot of
15321708Sstevel 		 * the env_cache. This has the affect of stopping the
15331708Sstevel 		 * active env_cache writer after they have updated the
15341708Sstevel 		 * active HPU, allowing the kstat_read to get a dump of
15351708Sstevel 		 * the env_cache, then the env_cache writer can resume
15361708Sstevel 		 * updating the cache. For performance it is more important
15371708Sstevel 		 * that the kstat_read completes quickly so we allow the
15381708Sstevel 		 * kstat_read to interrupt the updating of the env_cache.
15391708Sstevel 		 * The updating can take anything from a few seconds to
15401708Sstevel 		 * several minutes to complete.
15411708Sstevel 		 */
15421708Sstevel 		mutex_enter(&env_cache_lock);
15431708Sstevel 
15441708Sstevel 		/*
15451708Sstevel 		 * If the key just read is zero, then the
15461708Sstevel 		 * group of sensors have been removed by
15471708Sstevel 		 * some means and we need to zero out
15481708Sstevel 		 * the env_cache. (this ensures that data
15491708Sstevel 		 * belonging to a removed board is not
15501708Sstevel 		 * returned)
15511708Sstevel 		 */
15521708Sstevel 		if (key == 0) {
15531708Sstevel 			ASSERT(old_key != 0);
15541708Sstevel 			(void) sgenv_clear_env_cache_entry(i);
15551708Sstevel 			mutex_exit(&env_cache_lock);
15561708Sstevel 			continue;
15571708Sstevel 		}
15581708Sstevel 
15591708Sstevel 		/*
15601708Sstevel 		 * Check to see if this key has changed since
15611708Sstevel 		 * the last read.
15621708Sstevel 		 *
15631708Sstevel 		 * If it has changed, we need to update everything.
15641708Sstevel 		 *
15651708Sstevel 		 * If it hasn't we simply read the volatiles
15661708Sstevel 		 * and check to see if the constants have changed.
15671708Sstevel 		 */
15681708Sstevel 		if (key != old_key) {
15691708Sstevel 			/*
15701708Sstevel 			 * If the key is non-zero, then a new HPU has
15711708Sstevel 			 * been added to the system or it has changed
15721708Sstevel 			 * somehow and we need to re-read everything.
15731708Sstevel 			 * (we also need to zero out the env_cache as
15741708Sstevel 			 * there may be less sensors returned now and
15751708Sstevel 			 * the old ones may not be overwritten)
15761708Sstevel 			 */
15771708Sstevel 
15781708Sstevel 			/*
15791708Sstevel 			 * If the <env_cache> has not already been
15801708Sstevel 			 * allocated for this key position then we
15811708Sstevel 			 * go ahead and allocate it.
15821708Sstevel 			 */
15831708Sstevel 			if (env_cache[i] == NULL) {
15841708Sstevel 				err = sgenv_create_env_cache_entry(i);
15851708Sstevel 				if (err == DDI_FAILURE) {
15861708Sstevel 					mutex_exit(&env_cache_lock);
15871708Sstevel 					continue;
15881708Sstevel 				}
15891708Sstevel 			}
15901708Sstevel 
15911708Sstevel 			err = sgenv_get_env_data(new_keys[i], i,
15927656SSherry.Moore@Sun.COM 			    SG_GET_ENV_CONSTANTS, &status);
15931708Sstevel 			if (err) {
15941708Sstevel 				err = sgenv_handle_env_data_error(err, status,
15957656SSherry.Moore@Sun.COM 				    i, old_key, "Constant Data");
15961708Sstevel 				mutex_exit(&env_cache_lock);
15971708Sstevel 				if (err != DDI_FAILURE) {
15981708Sstevel 					continue;
15991708Sstevel 				} else if (env_cache_updated == TRUE) {
16001708Sstevel 					return (0);
16011708Sstevel 				} else {
16021708Sstevel 					return (DDI_FAILURE);
16031708Sstevel 				}
16041708Sstevel 			}
16051708Sstevel 
16061708Sstevel 			err = sgenv_get_env_data(new_keys[i], i,
16077656SSherry.Moore@Sun.COM 			    SG_GET_ENV_THRESHOLDS, &status);
16081708Sstevel 			if (err) {
16091708Sstevel 				err = sgenv_handle_env_data_error(err, status,
16107656SSherry.Moore@Sun.COM 				    i, old_key, "Threshold Data");
16111708Sstevel 				mutex_exit(&env_cache_lock);
16121708Sstevel 				if (err != DDI_FAILURE) {
16131708Sstevel 					continue;
16141708Sstevel 				} else if (env_cache_updated == TRUE) {
16151708Sstevel 					return (0);
16161708Sstevel 				} else {
16171708Sstevel 					return (DDI_FAILURE);
16181708Sstevel 				}
16191708Sstevel 			}
16201708Sstevel 
16211708Sstevel 			err = sgenv_get_env_data(new_keys[i], i,
16227656SSherry.Moore@Sun.COM 			    SG_GET_ENV_VOLATILES, &status);
16231708Sstevel 			if (err) {
16241708Sstevel 				err = sgenv_handle_env_data_error(err, status,
16257656SSherry.Moore@Sun.COM 				    i, old_key, "Volatile Data (fresh)");
16261708Sstevel 				mutex_exit(&env_cache_lock);
16271708Sstevel 				if (err != DDI_FAILURE) {
16281708Sstevel 					continue;
16291708Sstevel 				} else if (env_cache_updated == TRUE) {
16301708Sstevel 					return (0);
16311708Sstevel 				} else {
16321708Sstevel 					return (DDI_FAILURE);
16331708Sstevel 				}
16341708Sstevel 			}
16351708Sstevel 
16361708Sstevel 			/*
16371708Sstevel 			 * As we have successfully got env data for a HPU,
16381708Sstevel 			 * we ensure <env_cache_updated> is set to TRUE so that
16391708Sstevel 			 * in the future, if an error occurs during the mailbox
16401708Sstevel 			 * transfer, we know that there is old data for at
16411708Sstevel 			 * least one HPU in the <env_cache> which could be
16421708Sstevel 			 * returned instead of returning an error to the kstat
16431708Sstevel 			 * framework indicating that we have no data to return.
16441708Sstevel 			 */
16451708Sstevel 			env_cache_updated = TRUE;
16461708Sstevel 			last_env_read_time = gethrtime();
16471708Sstevel 
16481708Sstevel 		} else {
16491708Sstevel 			/*
16501708Sstevel 			 * key == old_key
16511708Sstevel 			 *
16521708Sstevel 			 * Handle the case when the value of the old key and
16531708Sstevel 			 * the new key are identical.
16541708Sstevel 			 */
16551708Sstevel 			ASSERT(env_cache[i] != NULL);
16561708Sstevel 
16571708Sstevel 			/*
16581708Sstevel 			 * If the keys are identical, then the quasi-constants
16591708Sstevel 			 * should not have changed (and so don't need updating).
16601708Sstevel 			 * Similarly for the threshold readings.
16611708Sstevel 			 */
16621708Sstevel 
16631708Sstevel 			/* Update the volatile data */
16641708Sstevel 			err = sgenv_get_env_data(new_keys[i], i,
16657656SSherry.Moore@Sun.COM 			    SG_GET_ENV_VOLATILES, &status);
16661708Sstevel 			if (err) {
16671708Sstevel 				err = sgenv_handle_env_data_error(err, status,
16687656SSherry.Moore@Sun.COM 				    i, old_key, "Volatile Data (update)");
16691708Sstevel 				mutex_exit(&env_cache_lock);
16701708Sstevel 				if (err == DDI_FAILURE) {
16711708Sstevel 					return (0);
16721708Sstevel 				} else {
16731708Sstevel 					continue;
16741708Sstevel 				}
16751708Sstevel 			}
16761708Sstevel 
16771708Sstevel 		}
16781708Sstevel 		mutex_exit(&env_cache_lock);
16791708Sstevel 	}
16801708Sstevel 
16811708Sstevel 	return (0);
16821708Sstevel }
16831708Sstevel 
16841708Sstevel 
16851708Sstevel static int
sgenv_get_board_info_data(void)16861708Sstevel sgenv_get_board_info_data(void)
16871708Sstevel {
16881708Sstevel 	/*
16891708Sstevel 	 * This array keeps track of the valid nodes in a system. A call is
16901708Sstevel 	 * made to OBP to get the "nodeid" property from all the ssm nodes,
16911708Sstevel 	 * and for each nodeid found, that position in the array is set to
16921708Sstevel 	 * TRUE. For a Serengeti only one position in the array will be TRUE.
16931708Sstevel 	 */
16941708Sstevel 	static uint_t node_present[SSM_MAX_INSTANCES] = {SGENV_NO_NODE_EXISTS};
16951708Sstevel 
16961708Sstevel 	static fn_t	f = "sgenv_get_board_info_data()";
16971708Sstevel 	static int	first_time = TRUE;
16981708Sstevel 
16991708Sstevel 	sbbc_msg_t	req;
17001708Sstevel 	sbbc_msg_t	resp;
17011708Sstevel 	int		node;	/* loop index */
17021708Sstevel 	int		board;	/* loop index */
17031708Sstevel 	show_board_t	show_bd, *shbp = &show_bd;
17041708Sstevel 	info_t		inform;
17051708Sstevel 	int		status;	/* msg_status returned by response */
17061708Sstevel 	int		rv = 0;	/* return value of call to mailbox */
17071708Sstevel 	sg_board_info_t	*ptr;
17081708Sstevel 
17091708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: entered.", f);
17101708Sstevel 
17111708Sstevel 	ASSERT(board_cache != NULL);
17121708Sstevel 
17131708Sstevel 	if (first_time) {
17141708Sstevel 		sgenv_set_valid_node_positions(node_present);
17151708Sstevel 		first_time = FALSE;
17161708Sstevel 	}
17171708Sstevel 
17181708Sstevel 	for (node = 0; node < SSM_MAX_INSTANCES; node++) {
17191708Sstevel 
17201708Sstevel 		if (node_present[node] == SGENV_NO_NODE_EXISTS)
17211708Sstevel 			continue;
17221708Sstevel 
17231708Sstevel 		for (board = 0; board < SG_MAX_BDS; board++) {
17241708Sstevel 
17251708Sstevel 			/*
17261708Sstevel 			 * If we have discovered in a previous call to the SC
17271708Sstevel 			 * that there is no board in this slot on this type of
17281708Sstevel 			 * chassis then we don't waste resources asking the SC
17291708Sstevel 			 * for nonexistent data.
17301708Sstevel 			 */
17311708Sstevel 			if ((node_present[node] & (1 << board)) == 0)
17321708Sstevel 				continue;
17331708Sstevel 
17341708Sstevel 			inform.board = board;
17351708Sstevel 			inform.node = node;
17361708Sstevel 			inform.revision = 0xdead;
17371708Sstevel 
17381708Sstevel 			req.msg_type.type = DR_MBOX;
17391708Sstevel 			req.msg_type.sub_type = DR_MBOX_SHOW_BOARD;
17401708Sstevel 			req.msg_status = SG_MBOX_STATUS_SUCCESS;
17411708Sstevel 			req.msg_len = sizeof (info_t);
17421708Sstevel 			req.msg_bytes = sizeof (info_t);
17431708Sstevel 			req.msg_buf = (caddr_t)&inform;
17441708Sstevel 
17451708Sstevel 			bzero(shbp, sizeof (show_board_t));
17461708Sstevel 			shbp->s_cond = -1;
17471708Sstevel 			shbp->s_power = -1;
17481708Sstevel 			shbp->s_assigned = -1;
17491708Sstevel 			shbp->s_claimed = -1;
17501708Sstevel 			shbp->s_present = -1;
17511708Sstevel 
17521708Sstevel 			resp.msg_type.type = DR_MBOX;
17531708Sstevel 			resp.msg_type.sub_type = DR_MBOX_SHOW_BOARD;
17541708Sstevel 			resp.msg_bytes = sizeof (show_board_t);
17551708Sstevel 			resp.msg_status = SG_MBOX_STATUS_SUCCESS;
17561708Sstevel 			resp.msg_len = sizeof (show_board_t);
17571708Sstevel 			resp.msg_buf = (caddr_t)shbp;
17581708Sstevel 
17591708Sstevel 
17601708Sstevel 			/*
17611708Sstevel 			 * We want to avoid the case where an invalid time
17621708Sstevel 			 * is specified by a user (by patching the
17631708Sstevel 			 * global variable <sgenv_max_mbox_wait_time>).
17641708Sstevel 			 *
17651708Sstevel 			 * Any incorrect values are reset to the default time.
17661708Sstevel 			 */
17671708Sstevel 			if (sgenv_max_mbox_wait_time <=
17687656SSherry.Moore@Sun.COM 			    max(sbbc_mbox_min_timeout, 0))
17691708Sstevel 				sgenv_max_mbox_wait_time =
17707656SSherry.Moore@Sun.COM 				    sbbc_mbox_default_timeout;
17711708Sstevel 
17721708Sstevel 			rv = sbbc_mbox_request_response(&req, &resp,
17737656SSherry.Moore@Sun.COM 			    sgenv_max_mbox_wait_time);
17741708Sstevel 			status = resp.msg_status;
17751708Sstevel 
17761708Sstevel 			if ((rv) || (status != SG_MBOX_STATUS_SUCCESS)) {
17771708Sstevel 				/*
17781708Sstevel 				 * errors from Solaris sgsbbc driver
17791708Sstevel 				 */
17801708Sstevel 				if (status > SG_MBOX_STATUS_SUCCESS) {
17811708Sstevel 					sgenv_mbox_error_msg("Board Info", rv,
17827656SSherry.Moore@Sun.COM 					    resp.msg_status);
17831708Sstevel 					return (rv);
17841708Sstevel 				}
17851708Sstevel 
17861708Sstevel 				/*
17871708Sstevel 				 * errors from SCAPP
17881708Sstevel 				 */
17891708Sstevel 				if (status == SG_MBOX_STATUS_ILLEGAL_NODE) {
17901708Sstevel 					sgenv_mbox_error_msg("Board Info", rv,
17917656SSherry.Moore@Sun.COM 					    resp.msg_status);
17921708Sstevel 					node_present[node] =
17937656SSherry.Moore@Sun.COM 					    SGENV_NO_NODE_EXISTS;
17941708Sstevel 
17951708Sstevel 					/*
17961708Sstevel 					 * No point looping through the rest of
17971708Sstevel 					 * the boards associated with this node.
17981708Sstevel 					 */
17991708Sstevel 					break;
18001708Sstevel 
18011708Sstevel 				} else if (status ==
18027656SSherry.Moore@Sun.COM 				    SG_MBOX_STATUS_ILLEGAL_SLOT) {
18031708Sstevel 
18041708Sstevel 					/*
18051708Sstevel 					 * We clear the bit representing <board>
18061708Sstevel 					 * in <node> to indicate that this slot
18071708Sstevel 					 * cannot exist on this chassis.
18081708Sstevel 					 */
18091708Sstevel 					node_present[node] &= (~(1 << board) &
18107656SSherry.Moore@Sun.COM 					    SGENV_NODE_TYPE_DS);
18111708Sstevel 					continue;
18121708Sstevel 
18131708Sstevel 				} else if (status ==
18147656SSherry.Moore@Sun.COM 				    SG_MBOX_STATUS_BOARD_ACCESS_DENIED) {
18151708Sstevel 					/*
18161708Sstevel 					 * We cannot access data for this slot,
18171708Sstevel 					 * however we may be able to do so in
18181708Sstevel 					 * the future. We do nothing.
18191708Sstevel 					 */
18201708Sstevel 					rv = rv;
18211708Sstevel 				} else {
18221708Sstevel 					char	err_msg[40];
18231708Sstevel 
1824*11311SSurya.Prakki@Sun.COM 					(void) sprintf(err_msg,
1825*11311SSurya.Prakki@Sun.COM 					    "Board data for "
18267656SSherry.Moore@Sun.COM 					    "Node%d/Slot%d", node, board);
18271708Sstevel 					sgenv_mbox_error_msg(err_msg, rv,
18287656SSherry.Moore@Sun.COM 					    resp.msg_status);
18291708Sstevel 
18301708Sstevel 					if (rv == 0)
18311708Sstevel 						rv = status;
18321708Sstevel 
18331708Sstevel 					continue;
18341708Sstevel 				}
18351708Sstevel 			}
18361708Sstevel 
18371708Sstevel 			mutex_enter(&board_cache_lock);
18381708Sstevel 			ptr = &board_cache[board];
18391708Sstevel 
18401708Sstevel 			/*
18411708Sstevel 			 * Check if the SC returns data for this board.
18421708Sstevel 			 */
18431708Sstevel 			if (shbp->s_assigned == -1) {
18441708Sstevel 				/*
18451708Sstevel 				 * If this cache entry used to have data and
18461708Sstevel 				 * now doesn't we decrement the board_count
18471708Sstevel 				 * clear the env_cache. The board must have
18481708Sstevel 				 * been removed.
18491708Sstevel 				 */
18501708Sstevel 				if (ptr->node_id != -1) {
18511708Sstevel 					board_count--;
18521708Sstevel 
18531708Sstevel 					/*
18541708Sstevel 					 * clear board_cache entry by
18551708Sstevel 					 * setting node_id to -1;
18561708Sstevel 					 */
18571708Sstevel 					ptr->node_id = -1;
18581708Sstevel 					DCMN_ERR_CACHE(CE_NOTE, "%s: "
18597656SSherry.Moore@Sun.COM 					    "Clearing cache line %d [%p]",
1860*11311SSurya.Prakki@Sun.COM 					    f, board, (void *)ptr);
18611708Sstevel 				}
18621708Sstevel 			} else {
18631708Sstevel 				/*
18641708Sstevel 				 * If this cache entry was previously empty
18651708Sstevel 				 * and we now have data for it we increment
18661708Sstevel 				 * the board_count. A new board must have
18671708Sstevel 				 * been added.
18681708Sstevel 				 */
18691708Sstevel 				if (ptr->node_id == -1)
18701708Sstevel 					board_count++;
18711708Sstevel 				/*
18721708Sstevel 				 * update the board_cache entry
18731708Sstevel 				 */
18741708Sstevel 				DCMN_ERR_CACHE(CE_NOTE, "%s: "
18757656SSherry.Moore@Sun.COM 				    "Writing data for bd=%d into "
18767656SSherry.Moore@Sun.COM 				    " the board_cache at [%p]",
1877*11311SSurya.Prakki@Sun.COM 				    f, board, (void *)ptr);
18781708Sstevel 				ptr->node_id = node;
18791708Sstevel 				ptr->board_num = board;
18801708Sstevel 				ptr->condition = shbp->s_cond;
18811708Sstevel 				ptr->assigned = shbp->s_assigned;
18821708Sstevel 				ptr->claimed = shbp->s_claimed;
18831708Sstevel 				ptr->present = shbp->s_present;
18841708Sstevel 				ptr->led.led_status =
18857656SSherry.Moore@Sun.COM 				    shbp->s_ledstatus;
18861708Sstevel 				last_board_read_time = gethrtime();
18871708Sstevel 			}
18881708Sstevel 			mutex_exit(&board_cache_lock);
18891708Sstevel 		} /* board */
18901708Sstevel 	} /* node */
18911708Sstevel 
18921708Sstevel 	/*
18931708Sstevel 	 * Indicate that have managed to store valid data in the <board_cache>
18941708Sstevel 	 * at least once.
18951708Sstevel 	 */
18961708Sstevel 	if (board_count > 0)
18971708Sstevel 		board_cache_updated = TRUE;
18981708Sstevel 
18991708Sstevel 
19001708Sstevel 	return (rv);
19011708Sstevel }
19021708Sstevel 
19031708Sstevel 
19041708Sstevel static int
sgenv_get_hpu_keys(envresp_key_t * new,int * status)19051708Sstevel sgenv_get_hpu_keys(envresp_key_t *new, int *status)
19061708Sstevel {
19071708Sstevel 	sbbc_msg_t	req;	/* request */
19081708Sstevel 	sbbc_msg_t	resp;	/* response */
19091708Sstevel 
19101708Sstevel 	int	rv;	/* return value from call to mbox */
19111708Sstevel 
19121708Sstevel 	req.msg_type.type = SG_ENV;
19131708Sstevel 	req.msg_type.sub_type = SG_GET_ENV_HPU_KEYS;
19141708Sstevel 	req.msg_status = SG_MBOX_STATUS_SUCCESS;
19151708Sstevel 	req.msg_len = 0;
19161708Sstevel 	req.msg_bytes = 0;
19171708Sstevel 
19181708Sstevel 	resp.msg_type.type = SG_ENV;
19191708Sstevel 	resp.msg_type.sub_type = SG_GET_ENV_HPU_KEYS;
19201708Sstevel 	resp.msg_status = SG_MBOX_STATUS_SUCCESS;
19211708Sstevel 	resp.msg_len = sizeof (envresp_key_t) * SGENV_MAX_HPU_KEYS;
19221708Sstevel 	resp.msg_bytes = 0;
19231708Sstevel 	resp.msg_buf = (caddr_t)new;
19241708Sstevel 
19251708Sstevel 	/*
19261708Sstevel 	 * We want to avoid the case where an invalid time
19271708Sstevel 	 * is specified by a user (by patching the
19281708Sstevel 	 * global variable <sgenv_max_mbox_wait_time>).
19291708Sstevel 	 *
19301708Sstevel 	 * Any incorrect values are reset to the default time.
19311708Sstevel 	 */
19321708Sstevel 	if (sgenv_max_mbox_wait_time <= max(sbbc_mbox_min_timeout, 0))
19331708Sstevel 		sgenv_max_mbox_wait_time = sbbc_mbox_default_timeout;
19341708Sstevel 
19351708Sstevel 	rv = sbbc_mbox_request_response(&req, &resp, sgenv_max_mbox_wait_time);
19361708Sstevel 
19371708Sstevel 	*status = resp.msg_status;
19381708Sstevel 
19391708Sstevel 	return (rv);
19401708Sstevel }
19411708Sstevel 
19421708Sstevel 
19431708Sstevel static int
sgenv_get_env_data(envresp_key_t key,int key_posn,uint16_t flag,int * status)19441708Sstevel sgenv_get_env_data(envresp_key_t key, int key_posn, uint16_t flag, int *status)
19451708Sstevel {
19461708Sstevel 	/*
19471708Sstevel 	 * Only one of these buffers is ever going to be used in a call
19481708Sstevel 	 * so to save kernel stack space we use a union.
19491708Sstevel 	 */
19501708Sstevel 	union {
19511708Sstevel 		envresp_constants_t	con[SGENV_MAX_SENSORS_PER_KEY];
19521708Sstevel 		envresp_volatiles_t	vol[SGENV_MAX_SENSORS_PER_KEY];
19531708Sstevel 		envresp_thresholds_t	thr[SGENV_MAX_SENSORS_PER_KEY];
19541708Sstevel 	} buf;
19551708Sstevel 
19561708Sstevel 	sbbc_msg_t	req;	/* request */
19571708Sstevel 	sbbc_msg_t	resp;	/* response */
19581708Sstevel 
19591708Sstevel 	int	i;	/* loop variable for mbox msg_buf */
19601708Sstevel 	int	rv;	/* return value from call to mbox */
19611708Sstevel 
19621708Sstevel 	ASSERT(MUTEX_HELD(&env_cache_lock));
19631708Sstevel 	ASSERT(env_cache[key_posn] != NULL);
19641708Sstevel 
19651708Sstevel 	if (flag == SG_GET_ENV_CONSTANTS) {
19661708Sstevel 		resp.msg_len = sizeof (buf.con);
19671708Sstevel 		resp.msg_buf = (caddr_t)buf.con;
19681708Sstevel 
19691708Sstevel 	} else if (flag == SG_GET_ENV_VOLATILES) {
19701708Sstevel 		resp.msg_len = sizeof (buf.vol);
19711708Sstevel 		resp.msg_buf = (caddr_t)buf.vol;
19721708Sstevel 
19731708Sstevel 	} else if (flag == SG_GET_ENV_THRESHOLDS) {
19741708Sstevel 		resp.msg_len = sizeof (buf.thr);
19751708Sstevel 		resp.msg_buf = (caddr_t)buf.thr;
19761708Sstevel 
19771708Sstevel 	} else {
19781708Sstevel 		*status = EINVAL;
19791708Sstevel 		return (-1);
19801708Sstevel 	}
19811708Sstevel 
19821708Sstevel 	req.msg_type.type = SG_ENV;
19831708Sstevel 	req.msg_type.sub_type = flag;
19841708Sstevel 	req.msg_status = SG_MBOX_STATUS_SUCCESS;
19851708Sstevel 	req.msg_len = 0;
19861708Sstevel 	req.msg_bytes = 0;
19871708Sstevel 	req.msg_data[0] = key;
19881708Sstevel 
19891708Sstevel 	resp.msg_type.type = SG_ENV;
19901708Sstevel 	resp.msg_type.sub_type = flag;
19911708Sstevel 	resp.msg_status = SG_MBOX_STATUS_SUCCESS;
19921708Sstevel 	resp.msg_bytes = 0;
19931708Sstevel 
19941708Sstevel 	/*
19951708Sstevel 	 * We want to avoid the case where an invalid time
19961708Sstevel 	 * is specified by a user (by patching the
19971708Sstevel 	 * global variable <sgenv_max_mbox_wait_time>).
19981708Sstevel 	 *
19991708Sstevel 	 * Any incorrect values are reset to the default time.
20001708Sstevel 	 */
20011708Sstevel 	if (sgenv_max_mbox_wait_time <= max(sbbc_mbox_min_timeout, 0))
20021708Sstevel 		sgenv_max_mbox_wait_time = sbbc_mbox_default_timeout;
20031708Sstevel 
20041708Sstevel 
20051708Sstevel 	rv = sbbc_mbox_request_response(&req, &resp, sgenv_max_mbox_wait_time);
20061708Sstevel 
20071708Sstevel 	*status = resp.msg_status;
20081708Sstevel 
20091708Sstevel 	/*
20101708Sstevel 	 * We now check that the data returned is valid.
20111708Sstevel 	 */
20121708Sstevel 	if (rv != 0) {
20131708Sstevel 		/*
20141708Sstevel 		 * The SBBC driver encountered an error.
20151708Sstevel 		 */
20161708Sstevel 		return (rv);
20171708Sstevel 
20181708Sstevel 	} else {
20191708Sstevel 		/*
20201708Sstevel 		 * The SC encountered an error.
20211708Sstevel 		 */
20221708Sstevel 		switch (*status) {
20231708Sstevel 		case SG_MBOX_STATUS_SUCCESS:
20241708Sstevel 			/*
20251708Sstevel 			 * No problems encountered - continue and return the
20261708Sstevel 			 * new data.
20271708Sstevel 			 */
20281708Sstevel 			break;
20291708Sstevel 
20301708Sstevel 		case ETIMEDOUT:
20311708Sstevel 			/*
20321708Sstevel 			 * For some reason the mailbox failed to return data
20331708Sstevel 			 * and instead timed out so we return ETIMEDOUT
20341708Sstevel 			 */
20351708Sstevel 			return (ETIMEDOUT);
20361708Sstevel 
20371708Sstevel 		case ENXIO:
20381708Sstevel 			/*
20391708Sstevel 			 * no sensors associated with this key, this may have
20401708Sstevel 			 * changed since we read the keys.
20411708Sstevel 			 */
20421708Sstevel 			return (ENXIO);
20431708Sstevel 
20441708Sstevel 		default:
20451708Sstevel 			/*
20461708Sstevel 			 * The contents of the mbox message contain corrupt
20471708Sstevel 			 * data. Flag this as an error to be returned.
20481708Sstevel 			 */
20491708Sstevel 			SGENV_PRINT_MBOX_MSG((&resp), "Env info problem");
20501708Sstevel 			return (EINVAL);
20511708Sstevel 		}
20521708Sstevel 	}
20531708Sstevel 
20541708Sstevel 	/*
20551708Sstevel 	 * Depending on the type of data returned, save the constant/volatile
20561708Sstevel 	 * data returned in the mailbox message into the <env_cache>.
20571708Sstevel 	 */
20581708Sstevel 	for (i = 0; i < resp.msg_data[0]; i++) {
20591708Sstevel 
20601708Sstevel 		if (flag == SG_GET_ENV_CONSTANTS) {
20611708Sstevel 			env_cache[key_posn][i].sd_id.tag_id =
20627656SSherry.Moore@Sun.COM 			    buf.con[i].id.tag_id;
20631708Sstevel 			env_cache[key_posn][i].sd_lo =
20647656SSherry.Moore@Sun.COM 			    buf.con[i].lo;
20651708Sstevel 			env_cache[key_posn][i].sd_hi =
20667656SSherry.Moore@Sun.COM 			    buf.con[i].hi;
20671708Sstevel 
20681708Sstevel 		} else if (flag == SG_GET_ENV_VOLATILES) {
20691708Sstevel 			env_cache[key_posn][i].sd_value =
20707656SSherry.Moore@Sun.COM 			    buf.vol[i].value;
20711708Sstevel 			env_cache[key_posn][i].sd_infostamp =
20727656SSherry.Moore@Sun.COM 			    buf.vol[i].info;
20731708Sstevel 
20741708Sstevel 			sgenv_set_sensor_status(&env_cache[key_posn][i]);
20751708Sstevel 
20761708Sstevel 		} else if (flag == SG_GET_ENV_THRESHOLDS) {
20771708Sstevel 			env_cache[key_posn][i].sd_lo_warn =
20787656SSherry.Moore@Sun.COM 			    buf.thr[i].lo_warn;
20791708Sstevel 			env_cache[key_posn][i].sd_hi_warn =
20807656SSherry.Moore@Sun.COM 			    buf.thr[i].hi_warn;
20811708Sstevel 		}
20821708Sstevel 	}
20831708Sstevel 
20841708Sstevel 	if (flag == SG_GET_ENV_VOLATILES)
20851708Sstevel 		vol_sensor_count[key_posn] = resp.msg_data[0];
20861708Sstevel 
20871708Sstevel 	return (rv);
20881708Sstevel }
20891708Sstevel 
20901708Sstevel 
20911708Sstevel /*
20921708Sstevel  * This function handles any errors received from the mailbox framework while
20931708Sstevel  * getting environmental data.
20941708Sstevel  *
20951708Sstevel  * INPUT PARAMETERS
20961708Sstevel  *	err	- return value from call to mailbox framework.
20971708Sstevel  *	status	- message status returned by mailbox framework.
20981708Sstevel  *	key	- key from previous (if any) reading of env data.
20991708Sstevel  *		  Needed to see if we have old data in the <env_cache>.
21001708Sstevel  *	str	- String indicating what type of env request failed.
21011708Sstevel  *
21021708Sstevel  * RETURN VALUES
21031708Sstevel  *	rv == DDI_FAILURE	- there is no point in continuing processing
21041708Sstevel  *				  the data, we should exit from the kstat
21051708Sstevel  *				  framework.
21061708Sstevel  *	rv != DDI_FAILURE	- error has been handled correctly, continue
21071708Sstevel  *				  processing the data returned from the SC.
21081708Sstevel  */
21091708Sstevel static int
sgenv_handle_env_data_error(int err,int status,int key_posn,envresp_key_t key,char * str)21101708Sstevel sgenv_handle_env_data_error(int err, int status, int key_posn,
21111708Sstevel 				envresp_key_t key, char *str)
21121708Sstevel {
21131708Sstevel 	int	rv = DDI_SUCCESS;
21141708Sstevel 
21151708Sstevel 	ASSERT(str != (char *)NULL);
21161708Sstevel 
21171708Sstevel 	switch (err) {
21181708Sstevel 	case ENXIO:
21191708Sstevel 		/*
21201708Sstevel 		 * The SC has changed the env data associated with this key
21211708Sstevel 		 * since we started getting the data. We cannot tell if the
21221708Sstevel 		 * data has disappeared due to the removal of the board from
21231708Sstevel 		 * our Domain or just that the data has been updated. We
21241708Sstevel 		 * simply return the last known data (if possible) and the
21251708Sstevel 		 * next time we request the env data, the SC will have
21261708Sstevel 		 * finished processing this board so we will receive the
21271708Sstevel 		 * correct key values and we can get the correct data.
21281708Sstevel 		 */
21291708Sstevel 		DCMN_ERR_CACHE(CE_NOTE, "key @ posn %d has changed from %d"
21307656SSherry.Moore@Sun.COM 		    " while %s", key_posn, key, str);
21311708Sstevel 		rv = ENXIO;
21321708Sstevel 		break;
21331708Sstevel 
21341708Sstevel 	default:
21351708Sstevel 		sgenv_mbox_error_msg(str, err, status);
21361708Sstevel 		rv = DDI_FAILURE;
21371708Sstevel 		break;
21381708Sstevel 	}
21391708Sstevel 
21401708Sstevel 	/*
21411708Sstevel 	 * If there was no data in the <env_cache>, we need to clear the data
21421708Sstevel 	 * just added as the <env_cache> will only be partially filled.
21431708Sstevel 	 */
21441708Sstevel 	if (key == 0)
21451708Sstevel 		sgenv_clear_env_cache_entry(key_posn);
21461708Sstevel 
21471708Sstevel 	return (rv);
21481708Sstevel }
21491708Sstevel 
21501708Sstevel 
21511708Sstevel /*
21521708Sstevel  * If the sensor readings for a particular collection of HPUs become invalid,
21531708Sstevel  * then we clear the cache by freeing up the memory.
21541708Sstevel  */
21551708Sstevel static void
sgenv_clear_env_cache_entry(int key_posn)21561708Sstevel sgenv_clear_env_cache_entry(int key_posn)
21571708Sstevel {
21581708Sstevel 	ASSERT(MUTEX_HELD(&env_cache_lock));
21591708Sstevel 
21601708Sstevel 	if (env_cache[key_posn] != NULL) {
21611708Sstevel 		kmem_free(env_cache[key_posn], sizeof (env_sensor_t) *
21627656SSherry.Moore@Sun.COM 		    SGENV_MAX_SENSORS_PER_KEY);
21631708Sstevel 		env_cache[key_posn] = NULL;
21641708Sstevel 		vol_sensor_count[key_posn] = 0;
21651708Sstevel 	}
21661708Sstevel }
21671708Sstevel 
21681708Sstevel 
21691708Sstevel static void
sgenv_mbox_error_msg(char * str,int err,int status)21701708Sstevel sgenv_mbox_error_msg(char *str, int err, int status)
21711708Sstevel {
21721708Sstevel 	/*
21731708Sstevel 	 * We update the count of errors we have encountered during calls to
21741708Sstevel 	 * the mailbox framework (unless we will cause a wraparound)
21751708Sstevel 	 */
21761708Sstevel 	if (sgenv_mbox_error_count < INT_MAX)
21771708Sstevel 		sgenv_mbox_error_count++;
21781708Sstevel 
21791708Sstevel #ifdef DEBUG
21801708Sstevel 	if ((sgenv_debug & SGENV_DEBUG_MSG) == 0)
21811708Sstevel 		return;
21821708Sstevel 
21831708Sstevel 	ASSERT(str != NULL);
21841708Sstevel 
21851708Sstevel 	switch (err) {
21861708Sstevel 	case ENOTSUP:
21871708Sstevel 		DCMN_ERR(CE_WARN, "!This system configuration does not "
21887656SSherry.Moore@Sun.COM 		"support SGENV");
21891708Sstevel 		break;
21901708Sstevel 	case ETIMEDOUT:
21911708Sstevel 		DCMN_ERR(CE_WARN, "!Mailbox timed out while servicing "
21927656SSherry.Moore@Sun.COM 		"SGENV request for %s", str);
21931708Sstevel 		break;
21941708Sstevel 	default:
21951708Sstevel 		DCMN_ERR(CE_WARN, "!Error occurred reading %s, Errno=%d,"
21967656SSherry.Moore@Sun.COM 		" Status=%d", str, err, status);
21971708Sstevel 		break;
21981708Sstevel 	}
21991708Sstevel #endif
22001708Sstevel }
22011708Sstevel 
22021708Sstevel 
22031708Sstevel /*
22041708Sstevel  * INPUT PARAMETERS
22051708Sstevel  *	key_posn -	The position in the env_cache for which we want to
22061708Sstevel  *			allocate space for a HPU's env data.
22071708Sstevel  *
22081708Sstevel  * ERROR VALUES
22091708Sstevel  *	DDI_FAILURE -	We failed to allocate memory for this cache entry.
22101708Sstevel  *			There is no point asking the SC for env data for this
22111708Sstevel  *			HPU as we will have nowhere to store it.
22121708Sstevel  */
22131708Sstevel static int
sgenv_create_env_cache_entry(int key_posn)22141708Sstevel sgenv_create_env_cache_entry(int key_posn)
22151708Sstevel {
22161708Sstevel 	int	i;	/* used to loop thru each sensor to set the status */
22171708Sstevel 
22181708Sstevel 	ASSERT(key_posn < SGENV_MAX_HPU_KEYS);
22191708Sstevel 	ASSERT(key_posn >= 0);
22201708Sstevel 
22211708Sstevel 	env_cache[key_posn] = (env_sensor_t *)kmem_zalloc(
22227656SSherry.Moore@Sun.COM 	    sizeof (env_sensor_t) * SGENV_MAX_SENSORS_PER_KEY, KM_NOSLEEP);
22231708Sstevel 	if (env_cache[key_posn] == NULL) {
22241708Sstevel 		cmn_err(CE_WARN, "Failed to allocate memory for env_cache[%d]",
22257656SSherry.Moore@Sun.COM 		    key_posn);
22261708Sstevel 		return (DDI_FAILURE);
22271708Sstevel 	}
22281708Sstevel 
22291708Sstevel 	for (i = 0; i < SGENV_MAX_SENSORS_PER_KEY; i++)
22301708Sstevel 		env_cache[key_posn][i].sd_status = SG_SENSOR_STATUS_OK;
22311708Sstevel 
22321708Sstevel 	return (DDI_SUCCESS);
22331708Sstevel }
22341708Sstevel 
22351708Sstevel 
22361708Sstevel static void
sgenv_destroy_env_cache(void)22371708Sstevel sgenv_destroy_env_cache(void)
22381708Sstevel {
22391708Sstevel 	int i;
22401708Sstevel 
22411708Sstevel 	ASSERT(MUTEX_HELD(&env_cache_lock) == FALSE);
22421708Sstevel 	mutex_enter(&env_cache_lock);
22431708Sstevel 	for (i = 0; i < SGENV_MAX_HPU_KEYS; i++) {
22441708Sstevel 		if (env_cache[i] != NULL) {
22451708Sstevel 			kmem_free(env_cache[i], sizeof (env_sensor_t) *
22467656SSherry.Moore@Sun.COM 			    SGENV_MAX_SENSORS_PER_KEY);
22471708Sstevel 			env_cache[i] = NULL;
22481708Sstevel 			vol_sensor_count[i] = 0;
22491708Sstevel 		}
22501708Sstevel 	}
22511708Sstevel 	env_cache_updated = FALSE;
22521708Sstevel 
22531708Sstevel 	mutex_exit(&env_cache_lock);
22541708Sstevel }
22551708Sstevel 
22561708Sstevel static void
sgenv_update_env_kstat_size(kstat_t * ksp)22571708Sstevel sgenv_update_env_kstat_size(kstat_t *ksp)
22581708Sstevel {
22591708Sstevel 	int	i;
22601708Sstevel 
22611708Sstevel 	ASSERT(MUTEX_HELD(&env_cache_lock));
22621708Sstevel 
22631708Sstevel 	/* reinitialize this and recount number of sensors */
22641708Sstevel 	ksp->ks_data_size = 0;
22651708Sstevel 
22661708Sstevel 	for (i = 0; i < SGENV_MAX_HPU_KEYS; i++) {
22671708Sstevel 		if (vol_sensor_count[i] <= 0)
22681708Sstevel 			continue;
22691708Sstevel 
22701708Sstevel 		ASSERT(vol_sensor_count[i] <= SGENV_MAX_SENSORS_PER_KEY);
22711708Sstevel 
22721708Sstevel 		/*
22731708Sstevel 		 * increment ksp->ks_data_size by the number of
22741708Sstevel 		 * sensors in the collection <i>.
22751708Sstevel 		 */
22761708Sstevel 		ksp->ks_data_size += vol_sensor_count[i] *
22777656SSherry.Moore@Sun.COM 		    sizeof (env_sensor_t);
22781708Sstevel 	}
22791708Sstevel 	ASSERT(ksp->ks_data_size >= 0);
22801708Sstevel }
22811708Sstevel 
22821708Sstevel 
22831708Sstevel /*
22841708Sstevel  * This function is triggered by the thread that updates the env_cache.
22851708Sstevel  * It checks for any sensors which have exceeded their limits/thresholds
22861708Sstevel  * and generates sysevents for the sensor values that have changed.
22871708Sstevel  */
22881708Sstevel /*ARGSUSED*/
22891708Sstevel static uint_t
sgenv_check_sensor_thresholds(void)22901708Sstevel sgenv_check_sensor_thresholds(void)
22911708Sstevel {
22921979Sarutz 	DCMN_ERR_S(f, "sgenv_poll_env()");
22931708Sstevel 
22941708Sstevel 	int	key;	/* loop through keys */
22951708Sstevel 	int	i;	/* loops through each sensor for each <key> */
22961708Sstevel 
22971708Sstevel 	env_sensor_t		sensor;
22981708Sstevel 	env_sensor_status_t	status;
22991708Sstevel 
23001708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
23011708Sstevel 
23021708Sstevel 	mutex_enter(&env_cache_lock);
23031708Sstevel 
23041708Sstevel 	for (key = 0; key < SGENV_MAX_HPU_KEYS; key++) {
23051708Sstevel 
23061708Sstevel 		if (vol_sensor_count[key] == 0)
23071708Sstevel 			continue;
23081708Sstevel 
23091708Sstevel 		for (i = 0; i < vol_sensor_count[key]; i++) {
23101708Sstevel 			sensor = env_cache[key][i];
23111708Sstevel 			status = sensor.sd_status;
23121708Sstevel 
23131708Sstevel 			if (SG_GET_SENSOR_STATUS(status) ==
23147656SSherry.Moore@Sun.COM 			    SG_GET_PREV_SENSOR_STATUS(status)) {
23151708Sstevel 				continue;
23161708Sstevel 			}
23171708Sstevel 
23181708Sstevel 			/*
23191708Sstevel 			 * This sensor has changed in status since the last
23201708Sstevel 			 * time we polled - we need to inform the sysevent
23211708Sstevel 			 * framework.
23221708Sstevel 			 */
23231708Sstevel 			switch (sensor.sd_id.id.sensor_type) {
23241708Sstevel 			/*
23251708Sstevel 			 * we don't care about the pseudo sensors and
23261708Sstevel 			 * the Fan Status is notified by a separate
23271708Sstevel 			 * unsolicited event so we simply get the next
23281708Sstevel 			 * reading
23291708Sstevel 			 */
23301708Sstevel 			case SG_SENSOR_TYPE_ENVDB:
23311708Sstevel 			case SG_SENSOR_TYPE_COOLING:
23321708Sstevel 				continue;
23331708Sstevel 
23341708Sstevel 			/*
23351708Sstevel 			 * We have handled all the special cases by now.
23361708Sstevel 			 */
23371708Sstevel 			default:
2338*11311SSurya.Prakki@Sun.COM 				(void) sgenv_process_threshold_event(sensor);
23391708Sstevel 				break;
23401708Sstevel 			}
23411708Sstevel 
23421708Sstevel 			SGENV_PRINT_POLL_INFO(sensor);
23431708Sstevel 		}
23441708Sstevel 	}
23451708Sstevel 	mutex_exit(&env_cache_lock);
23461708Sstevel 
23471708Sstevel 	return (DDI_SUCCESS);
23481708Sstevel }
23491708Sstevel 
23501708Sstevel 
23511708Sstevel /*
23521708Sstevel  * This function is passed in an array of length SSM_MAX_INSTANCES and
23531708Sstevel  * it searches OBP to for ssm nodes, and for each one if finds, it sets the
23541708Sstevel  * corresponding position in the array to TRUE.
23551708Sstevel  */
23561708Sstevel static void
sgenv_set_valid_node_positions(uint_t * node_present)23571708Sstevel sgenv_set_valid_node_positions(uint_t *node_present)
23581708Sstevel {
23591708Sstevel 	dev_info_t	*rdip;		/* root dev info ptr */
23601708Sstevel 	dev_info_t	*dip;
23611708Sstevel 
23621708Sstevel 	ASSERT(node_present != NULL);
23631708Sstevel 
23641708Sstevel 	rdip = ddi_root_node();
23651708Sstevel 
23661708Sstevel 	for (dip = ddi_get_child(rdip); dip != NULL;
23677656SSherry.Moore@Sun.COM 	    dip = ddi_get_next_sibling(dip)) {
23681708Sstevel 		if (strncmp("ssm", ddi_node_name(dip), 3) == 0) {
23691708Sstevel 			int	value;
23701708Sstevel 
23711708Sstevel 			value = ddi_getprop(DDI_DEV_T_ANY, dip,
23727656SSherry.Moore@Sun.COM 			    DDI_PROP_DONTPASS, "nodeid", 0);
23731708Sstevel 
23741708Sstevel 			/*
23751708Sstevel 			 * If we get a valid nodeID which has not already
23761708Sstevel 			 * been found in a previous call to this function,
23771708Sstevel 			 * then we set all 10 LSB bits to indicate there may
23781708Sstevel 			 * be a board present in each slot.
23791708Sstevel 			 *
23801708Sstevel 			 * It is the job of sgenv_get_board_info_data() to weed
23811708Sstevel 			 * out the invalid cases when we don't have a
23821708Sstevel 			 * DS chassis.
23831708Sstevel 			 *
23841708Sstevel 			 * NOTE: We make the assumption that a chassis cannot
23851708Sstevel 			 * be DR'ed out, which is true for a Serengeti.
23861708Sstevel 			 * By the time WildCat need this functionality Solaris
23871708Sstevel 			 * will be able to know what kind of a chassis is
23881708Sstevel 			 * present and there will be no need to try and work
23891708Sstevel 			 * this out from the msg_status from the mailbox.
23901708Sstevel 			 */
23911708Sstevel 			if ((value >= 0) &&
23927656SSherry.Moore@Sun.COM 			    (value < SSM_MAX_INSTANCES) &&
23937656SSherry.Moore@Sun.COM 			    (node_present[value] == SGENV_NO_NODE_EXISTS)) {
23941708Sstevel 				node_present[value] = SGENV_NODE_TYPE_DS;
23951708Sstevel 			}
23961708Sstevel 
23971708Sstevel 		}
23981708Sstevel 	}
23991708Sstevel }
24001708Sstevel 
24011708Sstevel 
24021708Sstevel static void
sgenv_set_sensor_status(env_sensor_t * sensor)24031708Sstevel sgenv_set_sensor_status(env_sensor_t *sensor)
24041708Sstevel {
24051708Sstevel 	env_sensor_status_t	*status;
24061708Sstevel 
24071708Sstevel 	ASSERT(sensor != NULL);
24081708Sstevel 	status = &sensor->sd_status;
24091708Sstevel 
24101708Sstevel 	/*
24111708Sstevel 	 * Save the previous status so we can compare them later
24121708Sstevel 	 */
24131708Sstevel 	SG_SET_PREV_SENSOR_STATUS(*status, *status);
24141708Sstevel 
24151708Sstevel 	switch (sensor->sd_id.id.sensor_type) {
24161708Sstevel 	case SG_SENSOR_TYPE_ENVDB:
24171708Sstevel 		/*
24181708Sstevel 		 * We want the status of this sensor to always be OK
24191708Sstevel 		 * The concept of limits/thresholds do not exist for it.
24201708Sstevel 		 */
24211708Sstevel 		SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_OK);
24221708Sstevel 		break;
24231708Sstevel 
24241708Sstevel 	case SG_SENSOR_TYPE_COOLING:
24251708Sstevel 		/*
24261708Sstevel 		 * Fans have no concept of limits/thresholds, they have a state
24271708Sstevel 		 * which we store in the <sd_status> field so that we can see
24281708Sstevel 		 * when this state is changed.
24291708Sstevel 		 */
24301708Sstevel 		if (sensor->sd_value == SGENV_FAN_SPEED_HIGH) {
24311708Sstevel 			SG_SET_SENSOR_STATUS(*status,
24327656SSherry.Moore@Sun.COM 			    SG_SENSOR_STATUS_FAN_HIGH);
24331708Sstevel 
24341708Sstevel 		} else if (sensor->sd_value == SGENV_FAN_SPEED_LOW) {
24351708Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_FAN_LOW);
24361708Sstevel 
24371708Sstevel 		} else if (sensor->sd_value == SGENV_FAN_SPEED_OFF) {
24381708Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_FAN_OFF);
24391708Sstevel 
24401708Sstevel 		} else {
24411708Sstevel 			SG_SET_SENSOR_STATUS(*status,
24427656SSherry.Moore@Sun.COM 			    SG_SENSOR_STATUS_FAN_FAIL);
24431708Sstevel 		}
24441708Sstevel 
24451708Sstevel 		/*
24461708Sstevel 		 * If this is the first time this fan status has been read,
24471708Sstevel 		 * then we need to initialize the previous reading to be the
24481708Sstevel 		 * same as the current reading so that an event is not
24491708Sstevel 		 * triggered.
24501708Sstevel 		 *
24511708Sstevel 		 * [ When the env_cache is being created, the status of the
24521708Sstevel 		 *   sensors is set to SG_SENSOR_STATUS_OK, which is not a
24531708Sstevel 		 *   valid Fan status ].
24541708Sstevel 		 */
24551708Sstevel 		if (SG_GET_PREV_SENSOR_STATUS(*status) == SG_SENSOR_STATUS_OK) {
24561708Sstevel 			SG_SET_PREV_SENSOR_STATUS(*status, *status);
24571708Sstevel 		}
24581708Sstevel 
24591708Sstevel 		break;
24601708Sstevel 
24611708Sstevel 	default:
24621708Sstevel 		if (sensor->sd_value > sensor->sd_hi) {
24631708Sstevel 			SG_SET_SENSOR_STATUS(*status,
24647656SSherry.Moore@Sun.COM 			    SG_SENSOR_STATUS_HI_DANGER);
24651708Sstevel 
24661708Sstevel 		} else if (sensor->sd_value > sensor->sd_hi_warn) {
24671708Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_HI_WARN);
24681708Sstevel 
24691708Sstevel 		} else if (sensor->sd_value < sensor->sd_lo) {
24701708Sstevel 			SG_SET_SENSOR_STATUS(*status,
24717656SSherry.Moore@Sun.COM 			    SG_SENSOR_STATUS_LO_DANGER);
24721708Sstevel 
24731708Sstevel 		} else if (sensor->sd_value < sensor->sd_lo_warn) {
24741708Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_LO_WARN);
24751708Sstevel 
24761708Sstevel 		} else {
24771708Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_OK);
24781708Sstevel 		}
24791708Sstevel 		break;
24801708Sstevel 	}
24811708Sstevel }
24821708Sstevel 
24831708Sstevel 
24841708Sstevel 
24851708Sstevel 
24861708Sstevel /*
24871708Sstevel  * This function, when given an integer arg describing a HPU type,
24881708Sstevel  * returns the descriptive string associated with this HPU type.
24891708Sstevel  */
24901708Sstevel static const char *
sgenv_get_hpu_id_str(uint_t hpu_type)24911708Sstevel sgenv_get_hpu_id_str(uint_t hpu_type)
24921708Sstevel {
24931708Sstevel 	const hpu_value_t *hpu_list = hpus;
24941708Sstevel 
24951708Sstevel 	while (hpu_list->name != (char *)NULL) {
24961708Sstevel 		if (hpu_list->value == hpu_type)
24971708Sstevel 			return (hpu_list->IDstr);
24981708Sstevel 		else
24991708Sstevel 			hpu_list++;
25001708Sstevel 	}
25011708Sstevel 	return ((char *)NULL);
25021708Sstevel }
25031708Sstevel 
25041708Sstevel 
25051708Sstevel /*
25061708Sstevel  * This function, when given an integer arg describing a sensor part,
25071708Sstevel  * returns the descriptive string associated with this sensor part.
25081708Sstevel  */
25091708Sstevel static const char *
sgenv_get_part_str(uint_t sensor_part)25101708Sstevel sgenv_get_part_str(uint_t sensor_part)
25111708Sstevel {
25121708Sstevel 	const part_value_t *part_list = parts;
25131708Sstevel 
25141708Sstevel 	while (part_list->name != (char *)NULL) {
25151708Sstevel 		if (part_list->value == sensor_part)
25161708Sstevel 			return (part_list->name);
25171708Sstevel 		else
25181708Sstevel 			part_list++;
25191708Sstevel 	}
25201708Sstevel 	return ((char *)NULL);
25211708Sstevel }
25221708Sstevel 
25231708Sstevel 
25241708Sstevel /*
25251708Sstevel  * This function, when given an integer arg describing a sensor type,
25261708Sstevel  * returns the descriptive string associated with this sensor type.
25271708Sstevel  */
25281708Sstevel static const char *
sgenv_get_type_str(uint_t sensor_type)25291708Sstevel sgenv_get_type_str(uint_t sensor_type)
25301708Sstevel {
25311708Sstevel 	const type_value_t *type_list = types;
25321708Sstevel 
25331708Sstevel 	while (type_list->name != (char *)NULL) {
25341708Sstevel 		if (type_list->value == sensor_type)
25351708Sstevel 			return (type_list->name);
25361708Sstevel 		else
25371708Sstevel 			type_list++;
25381708Sstevel 	}
25391708Sstevel 	return ((char *)NULL);
25401708Sstevel }
25411708Sstevel 
25421708Sstevel 
25431708Sstevel /*
25441708Sstevel  * This function takes a sensor TagID and generates a string describing
25451708Sstevel  * where in the system the sensor is.
25461708Sstevel  */
25471708Sstevel static void
sgenv_tagid_to_string(sensor_id_t id,char * str)25481708Sstevel sgenv_tagid_to_string(sensor_id_t id, char *str)
25491708Sstevel {
25501708Sstevel 	const char	*hpu_str;
25511708Sstevel 	const char	*part_str;
25521708Sstevel 	const char	*type_str;
25531708Sstevel 
25541708Sstevel 	ASSERT(str != NULL);
25551708Sstevel 
25561708Sstevel 	hpu_str = sgenv_get_hpu_id_str(id.id.hpu_type);
25571708Sstevel 	part_str = sgenv_get_part_str(id.id.sensor_part);
25581708Sstevel 	type_str = sgenv_get_type_str(id.id.sensor_type);
25591708Sstevel 
2560*11311SSurya.Prakki@Sun.COM 	(void) sprintf(str,
2561*11311SSurya.Prakki@Sun.COM 	    "Sensor: Node=%d, Board=%s%d, Device=%s%d, Type=%s%d: reading has ",
25627656SSherry.Moore@Sun.COM 	    id.id.node_id,
25637656SSherry.Moore@Sun.COM 	    ((hpu_str != NULL) ? hpu_str : ""),
25647656SSherry.Moore@Sun.COM 	    id.id.hpu_slot,
25657656SSherry.Moore@Sun.COM 	    ((part_str != NULL) ? part_str : ""),
25667656SSherry.Moore@Sun.COM 	    id.id.sensor_partnum,
25677656SSherry.Moore@Sun.COM 	    ((type_str != NULL) ? type_str : ""),
25687656SSherry.Moore@Sun.COM 	    id.id.sensor_typenum);
25691708Sstevel 
25701708Sstevel }
25711708Sstevel 
25721708Sstevel 
25731708Sstevel /*
25741708Sstevel  * This interrupt handler watches for unsolicited mailbox messages from the SC
25751708Sstevel  * telling it that the Keyswitch Position had changed. It then informs the
25761708Sstevel  * Sysevent Framework of this change.
25771708Sstevel  */
25781708Sstevel static uint_t
sgenv_keyswitch_handler(char * arg)25791708Sstevel sgenv_keyswitch_handler(char *arg)
25801708Sstevel {
25811979Sarutz 	DCMN_ERR_S(f, "sgenv_keyswitch_handler()");
25821708Sstevel 
25831708Sstevel 	sysevent_t		*ev = NULL;
25841708Sstevel 	sysevent_id_t		eid;
25851708Sstevel 	sysevent_value_t	se_val;
25861708Sstevel 	sysevent_attr_list_t	*ev_attr_list = NULL;
25871708Sstevel 	sg_event_key_position_t	*payload = NULL;
25881708Sstevel 	sbbc_msg_t		*msg = NULL;
25891708Sstevel 	int			err;
25901708Sstevel 
25911708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s called", f);
25921708Sstevel 
25931708Sstevel 	if (arg == NULL) {
25941708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
25951708Sstevel 		return (DDI_INTR_CLAIMED);
25961708Sstevel 	}
25971708Sstevel 
25981708Sstevel 	msg = (sbbc_msg_t *)arg;
25991708Sstevel 	if (msg->msg_buf == NULL) {
26001708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
26011708Sstevel 		return (DDI_INTR_CLAIMED);
26021708Sstevel 	}
26031708Sstevel 
26041708Sstevel 	payload = (sg_event_key_position_t *)msg->msg_buf;
26051708Sstevel 	if (payload == NULL) {
26061708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: payload == NULL", f);
26071708Sstevel 		return (DDI_INTR_CLAIMED);
26081708Sstevel 	}
26091708Sstevel 
26101708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "Key posn = %d", (int)*payload);
26111708Sstevel 
26121708Sstevel 
26131708Sstevel 	/*
26141708Sstevel 	 * Allocate memory for sysevent buffer.
26151708Sstevel 	 */
26161708Sstevel 	ev = sysevent_alloc(EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE,
26177656SSherry.Moore@Sun.COM 	    EP_SGENV, SE_NOSLEEP);
26181708Sstevel 	if (ev == NULL) {
26191708Sstevel 		cmn_err(CE_WARN, "%s: Failed to alloc mem for %s/%s event",
26207656SSherry.Moore@Sun.COM 		    f, EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE);
26211708Sstevel 		return (DDI_INTR_CLAIMED);
26221708Sstevel 	}
26231708Sstevel 
26241708Sstevel 
26251708Sstevel 	/*
26261708Sstevel 	 * Set the DOMAIN_WHAT_CHANGED attribute.
26271708Sstevel 	 */
26281708Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
26291708Sstevel 	se_val.value.sv_string = DOMAIN_KEYSWITCH;
26301708Sstevel 	err = sysevent_add_attr(&ev_attr_list, DOMAIN_WHAT_CHANGED,
26317656SSherry.Moore@Sun.COM 	    &se_val, SE_NOSLEEP);
26321708Sstevel 	if (err != 0) {
26331708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
26347656SSherry.Moore@Sun.COM 		    DOMAIN_WHAT_CHANGED, EC_DOMAIN,
26357656SSherry.Moore@Sun.COM 		    ESC_DOMAIN_STATE_CHANGE);
26361708Sstevel 		sysevent_free(ev);
26371708Sstevel 		return (DDI_INTR_CLAIMED);
26381708Sstevel 	}
26391708Sstevel 
26401708Sstevel 
26411708Sstevel 	/*
26421708Sstevel 	 * Log this event with sysevent framework.
26431708Sstevel 	 */
26441708Sstevel 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
26451708Sstevel 		cmn_err(CE_WARN, "Failed to attach attr list for %s/%s event",
26467656SSherry.Moore@Sun.COM 		    EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE);
26471708Sstevel 		sysevent_free_attr(ev_attr_list);
26481708Sstevel 		sysevent_free(ev);
26491708Sstevel 		return (DDI_INTR_CLAIMED);
26501708Sstevel 	}
26511708Sstevel 	err = log_sysevent(ev, SE_NOSLEEP, &eid);
26521708Sstevel 	if (err != 0) {
26531708Sstevel 		cmn_err(CE_WARN, "Failed to log %s/%s event",
26547656SSherry.Moore@Sun.COM 		    EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE);
26551708Sstevel 		sysevent_free(ev);
26561708Sstevel 		return (DDI_INTR_CLAIMED);
26571708Sstevel 	}
26581708Sstevel 
26591708Sstevel 	/* clean up */
26601708Sstevel 	sysevent_free(ev);
26611708Sstevel 
26621708Sstevel 	return (DDI_INTR_CLAIMED);
26631708Sstevel }
26641708Sstevel 
26651708Sstevel 
26661708Sstevel /*
26671708Sstevel  * This interrupt handler watches for unsolicited mailbox messages from the SC
26681708Sstevel  * telling it that an environmental sensor has exceeded a threshold/limit level
26691708Sstevel  * or has returned to normal having previously exceeded a threshold/limit level.
26701708Sstevel  * It then informs the Sysevent Framework of this change and updates the
26711708Sstevel  * env_cache.
26721708Sstevel  */
26731708Sstevel static uint_t
sgenv_env_data_handler(char * arg)26741708Sstevel sgenv_env_data_handler(char *arg)
26751708Sstevel {
26761979Sarutz 	DCMN_ERR_S(f, "sgenv_env_data_handler()");
26771708Sstevel 
26781708Sstevel 	sg_event_env_changed_t	*payload = NULL;
26791708Sstevel 	sbbc_msg_t		*msg = NULL;
26801708Sstevel 
26811708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
26821708Sstevel 
26831708Sstevel 	if (arg == NULL) {
26841708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
26851708Sstevel 		return (DDI_INTR_CLAIMED);
26861708Sstevel 	}
26871708Sstevel 
26881708Sstevel 	msg = (sbbc_msg_t *)arg;
26891708Sstevel 
26901708Sstevel 	if (msg->msg_buf == NULL) {
26911708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
26921708Sstevel 		return (DDI_INTR_CLAIMED);
26931708Sstevel 	}
26941708Sstevel 
26951708Sstevel 	payload = (sg_event_env_changed_t *)msg->msg_buf;
26961708Sstevel 
26971708Sstevel 	/*
26981708Sstevel 	 * We check the first field of the msg_buf to see if the event_type
26991708Sstevel 	 * is SC_EVENT_ENV, if it is then we handle the event.
27001708Sstevel 	 */
27011708Sstevel 	if (payload->event_type != SC_EVENT_ENV) {
27021708Sstevel 		return (DDI_INTR_CLAIMED);
27031708Sstevel 	}
27041708Sstevel 
27051708Sstevel 	/*
27061708Sstevel 	 * We now need to signal to the env background thread to ask the SC
27071708Sstevel 	 * for env readings and discover which sensor caused the SC to send
27081708Sstevel 	 * the ENV event before sending a sysevent to userland.
27091708Sstevel 	 */
27101708Sstevel 	sgenv_indicate_cache_update_needed(ENV_CACHE);
27111708Sstevel 
27121708Sstevel 	return (DDI_INTR_CLAIMED);
27131708Sstevel }
27141708Sstevel 
27151708Sstevel 
27161708Sstevel /*
27171708Sstevel  * This interrupt handler watches for unsolicited mailbox messages from the SC
27181708Sstevel  * telling it that the status of a fan has changed. We register a sysevent
27191708Sstevel  * and trigger a softint to update the env cache.
27201708Sstevel  */
27211708Sstevel static uint_t
sgenv_fan_status_handler(char * arg)27221708Sstevel sgenv_fan_status_handler(char *arg)
27231708Sstevel {
27241979Sarutz 	DCMN_ERR_S(f, "sgenv_fan_status_handler()");
27251708Sstevel 
27261708Sstevel 	sysevent_t		*ev = NULL;
27271708Sstevel 	sysevent_id_t		eid;
27281708Sstevel 	sysevent_value_t	se_val;
27291708Sstevel 	sysevent_attr_list_t	*ev_attr_list = NULL;
27301708Sstevel 	sg_event_fan_status_t	*payload = NULL;
27311708Sstevel 	sbbc_msg_t		*msg = NULL;
27321708Sstevel 	char			fan_str[MAXNAMELEN];
27331708Sstevel 	int			err;
27341708Sstevel 
27351708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
27361708Sstevel 
27371708Sstevel 	if (arg == NULL) {
27381708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
27391708Sstevel 		return (DDI_INTR_CLAIMED);
27401708Sstevel 	}
27411708Sstevel 
27421708Sstevel 	msg = (sbbc_msg_t *)arg;
27431708Sstevel 
27441708Sstevel 	/*
27451708Sstevel 	 * We check the first field of the msg_buf to see if the event_type
27461708Sstevel 	 * is SC_EVENT_FAN
27471708Sstevel 	 */
27481708Sstevel 	if (msg->msg_buf == NULL) {
27491708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
27501708Sstevel 		return (DDI_INTR_CLAIMED);
27511708Sstevel 	}
27521708Sstevel 
27531708Sstevel 	payload = (sg_event_fan_status_t *)msg->msg_buf;
27541708Sstevel 
27551708Sstevel 	/*
27561708Sstevel 	 * If another type of ENV Event triggered this handler then we simply
27571708Sstevel 	 * return now.
27581708Sstevel 	 */
27591708Sstevel 	if (payload->event_type != SC_EVENT_FAN) {
27601708Sstevel 		return (DDI_INTR_CLAIMED);
27611708Sstevel 	}
27621708Sstevel 
27631708Sstevel 	/*
27641708Sstevel 	 * Allocate memory for sysevent buffer.
27651708Sstevel 	 */
27661708Sstevel 	ev = sysevent_alloc(EC_ENV, ESC_ENV_FAN, EP_SGENV, SE_NOSLEEP);
27671708Sstevel 	if (ev == NULL) {
27681708Sstevel 		cmn_err(CE_WARN, "%s: Failed to alloc mem for %s/%s event",
27697656SSherry.Moore@Sun.COM 		    f, EC_ENV, ESC_ENV_FAN);
27701708Sstevel 		return (DDI_INTR_CLAIMED);
27711708Sstevel 	}
27721708Sstevel 
27731708Sstevel 
27741708Sstevel 	/*
27751708Sstevel 	 * Set the following attributes for this event:
27761708Sstevel 	 *
27771708Sstevel 	 *	ENV_FRU_ID
27781708Sstevel 	 *	ENV_FRU_RESOURCE_ID
27791708Sstevel 	 *	ENV_FRU_DEVICE
27801708Sstevel 	 *	ENV_FRU_STATE
27811708Sstevel 	 *	ENV_MSG
27821708Sstevel 	 *
27831708Sstevel 	 */
27841708Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
27851708Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
27861708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_ID, &se_val, SE_NOSLEEP);
27871708Sstevel 	if (err != 0) {
27881708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
27897656SSherry.Moore@Sun.COM 		    ENV_FRU_ID, EC_ENV, ESC_ENV_FAN);
27901708Sstevel 		sysevent_free(ev);
27911708Sstevel 		return (DDI_INTR_CLAIMED);
27921708Sstevel 	}
27931708Sstevel 
27941708Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
27951708Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
27961708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_RESOURCE_ID,
27977656SSherry.Moore@Sun.COM 	    &se_val, SE_NOSLEEP);
27981708Sstevel 	if (err != 0) {
27991708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
28007656SSherry.Moore@Sun.COM 		    ENV_FRU_RESOURCE_ID, EC_ENV, ESC_ENV_FAN);
28011708Sstevel 		sysevent_free_attr(ev_attr_list);
28021708Sstevel 		sysevent_free(ev);
28031708Sstevel 		return (DDI_INTR_CLAIMED);
28041708Sstevel 	}
28051708Sstevel 
28061708Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
28071708Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
28081708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_DEVICE,
28097656SSherry.Moore@Sun.COM 	    &se_val, SE_NOSLEEP);
28101708Sstevel 	if (err != 0) {
28111708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
28127656SSherry.Moore@Sun.COM 		    ENV_FRU_DEVICE, EC_ENV, ESC_ENV_FAN);
28131708Sstevel 		sysevent_free_attr(ev_attr_list);
28141708Sstevel 		sysevent_free(ev);
28151708Sstevel 		return (DDI_INTR_CLAIMED);
28161708Sstevel 	}
28171708Sstevel 
28181708Sstevel 	/*
28191708Sstevel 	 * Checks the fan to see if it has failed.
28201708Sstevel 	 */
28211708Sstevel 	se_val.value_type = SE_DATA_TYPE_INT32;
28221708Sstevel 	switch (payload->fan_speed) {
28231708Sstevel 	case SGENV_FAN_SPEED_OFF:
28241708Sstevel 	case SGENV_FAN_SPEED_LOW:
28251708Sstevel 	case SGENV_FAN_SPEED_HIGH:
28261708Sstevel 		se_val.value.sv_int32 = ENV_OK;
28271708Sstevel 		break;
28281708Sstevel 
28291708Sstevel 	case SGENV_FAN_SPEED_UNKNOWN:
28301708Sstevel 	default:
28311708Sstevel 		se_val.value.sv_int32 = ENV_FAILED;
28321708Sstevel 		break;
28331708Sstevel 	}
28341708Sstevel 
28351708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_STATE,
28367656SSherry.Moore@Sun.COM 	    &se_val, SE_NOSLEEP);
28371708Sstevel 	if (err != 0) {
28381708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
28397656SSherry.Moore@Sun.COM 		    ENV_FRU_STATE, EC_ENV, ESC_ENV_FAN);
28401708Sstevel 		sysevent_free_attr(ev_attr_list);
28411708Sstevel 		sysevent_free(ev);
28421708Sstevel 		return (DDI_INTR_CLAIMED);
28431708Sstevel 	}
28441708Sstevel 
28451708Sstevel 
28461708Sstevel 	/*
28471708Sstevel 	 * Create the message to be sent to sysevent.
28481708Sstevel 	 */
2849*11311SSurya.Prakki@Sun.COM 	(void) sprintf(fan_str,
2850*11311SSurya.Prakki@Sun.COM 	    "The status of the fan in Node%d/Slot%d is now ",
28517656SSherry.Moore@Sun.COM 	    payload->node_id, payload->slot_number);
28521708Sstevel 	switch (payload->fan_speed) {
28531708Sstevel 	case SGENV_FAN_SPEED_OFF:
2854*11311SSurya.Prakki@Sun.COM 		(void) strcat(fan_str, SGENV_FAN_SPEED_OFF_STR);
28551708Sstevel 		break;
28561708Sstevel 
28571708Sstevel 	case SGENV_FAN_SPEED_LOW:
2858*11311SSurya.Prakki@Sun.COM 		(void) strcat(fan_str, SGENV_FAN_SPEED_LOW_STR);
28591708Sstevel 		break;
28601708Sstevel 
28611708Sstevel 	case SGENV_FAN_SPEED_HIGH:
2862*11311SSurya.Prakki@Sun.COM 		(void) strcat(fan_str, SGENV_FAN_SPEED_HIGH_STR);
28631708Sstevel 		break;
28641708Sstevel 
28651708Sstevel 	case SGENV_FAN_SPEED_UNKNOWN:
28661708Sstevel 	default:
2867*11311SSurya.Prakki@Sun.COM 		(void) strcat(fan_str, SGENV_FAN_SPEED_UNKNOWN_STR);
28681708Sstevel 		break;
28691708Sstevel 	}
28701708Sstevel 
28711708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "Fan: %s", fan_str);
28721708Sstevel 
28731708Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
28741708Sstevel 	se_val.value.sv_string = fan_str;
28751708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_MSG, &se_val, SE_NOSLEEP);
28761708Sstevel 	if (err != 0) {
28771708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
28787656SSherry.Moore@Sun.COM 		    ENV_MSG, EC_ENV, ESC_ENV_FAN);
28791708Sstevel 		sysevent_free_attr(ev_attr_list);
28801708Sstevel 		sysevent_free(ev);
28811708Sstevel 		return (DDI_INTR_CLAIMED);
28821708Sstevel 	}
28831708Sstevel 
28841708Sstevel 
28851708Sstevel 	/*
28861708Sstevel 	 * Log this event with sysevent framework.
28871708Sstevel 	 */
28881708Sstevel 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
28891708Sstevel 		cmn_err(CE_WARN, "Failed to attach attr list for %s/%s event",
28907656SSherry.Moore@Sun.COM 		    EC_ENV, ESC_ENV_FAN);
28911708Sstevel 		sysevent_free_attr(ev_attr_list);
28921708Sstevel 		sysevent_free(ev);
28931708Sstevel 		return (DDI_INTR_CLAIMED);
28941708Sstevel 	}
28951708Sstevel 	err = log_sysevent(ev, SE_NOSLEEP, &eid);
28961708Sstevel 	if (err != 0) {
28971708Sstevel 		cmn_err(CE_WARN, "Failed to log %s/%s event",
28987656SSherry.Moore@Sun.COM 		    EC_ENV, ESC_ENV_FAN);
28991708Sstevel 		sysevent_free(ev);
29001708Sstevel 		return (DDI_INTR_CLAIMED);
29011708Sstevel 	}
29021708Sstevel 	sysevent_free(ev);
29031708Sstevel 
29041708Sstevel 	/*
29051708Sstevel 	 * We now need to signal to the env background thread to ask the SC
29061708Sstevel 	 * for env readings and discover which sensor caused the SC to send
29071708Sstevel 	 * the ENV event before sending a sysevent to userland.
29081708Sstevel 	 */
29091708Sstevel 	sgenv_indicate_cache_update_needed(ENV_CACHE);
29101708Sstevel 
29111708Sstevel 	return (DDI_INTR_CLAIMED);
29121708Sstevel }
29131708Sstevel 
29141708Sstevel 
29151708Sstevel /*
29161708Sstevel  * This function informs the Sysevent Framework that a temperature, voltage
29171708Sstevel  * or current reading for a sensor has exceeded its threshold/limit value or
29181708Sstevel  * that the reading has returned to a safe value having exceeded its
29191708Sstevel  * threshold/limit value previously.
29201708Sstevel  */
29211708Sstevel static int
sgenv_process_threshold_event(env_sensor_t sensor)29221708Sstevel sgenv_process_threshold_event(env_sensor_t sensor)
29231708Sstevel {
29241979Sarutz 	DCMN_ERR_S(f, "sgenv_process_threshold_event()");
29251708Sstevel 
29261708Sstevel 	sysevent_t		*ev = NULL;
29271708Sstevel 	sysevent_id_t		eid;
29281708Sstevel 	sysevent_value_t	se_val;
29291708Sstevel 	sysevent_attr_list_t	*ev_attr_list = NULL;
29301708Sstevel 	int			err;
29311708Sstevel 
29321708Sstevel 	char	sensor_str[MAX_TAG_ID_STR_LEN];	/* holds the sensor TagID */
29331708Sstevel 
29341708Sstevel 	/*
29351708Sstevel 	 * This function handles the case when a temperature reading passes
29361708Sstevel 	 * a threshold/limit level and also the case when there are power
29371708Sstevel 	 * fluctuations (voltage/current readings pass a threshold/limit level)
29381708Sstevel 	 * so we need to work out which case it is.
29391708Sstevel 	 *
29401708Sstevel 	 * if <temp_event_type> is TRUE, then need to handle an event
29411708Sstevel 	 * of type ESC_ENV_TEMP.
29421708Sstevel 	 */
29431708Sstevel 	int	temp_event_type;
29441708Sstevel 
29451708Sstevel 	switch (sensor.sd_id.id.sensor_type) {
29461708Sstevel 	case SG_SENSOR_TYPE_TEMPERATURE:
29471708Sstevel 		temp_event_type = TRUE;
29481708Sstevel 		ev = sysevent_alloc(EC_ENV, ESC_ENV_TEMP, EP_SGENV, SE_NOSLEEP);
29491708Sstevel 		if (ev == NULL) {
29501708Sstevel 			cmn_err(CE_WARN, "Failed to allocate sysevent buffer "
29517656SSherry.Moore@Sun.COM 			    "for %s/%s event", EC_ENV, ESC_ENV_TEMP);
29521708Sstevel 			return (DDI_FAILURE);
29531708Sstevel 		}
29541708Sstevel 		break;
29551708Sstevel 
29561708Sstevel 	default:
29571708Sstevel 		temp_event_type = FALSE;
29581708Sstevel 		ev = sysevent_alloc(EC_ENV, ESC_ENV_POWER,
29597656SSherry.Moore@Sun.COM 		    EP_SGENV, SE_NOSLEEP);
29601708Sstevel 		if (ev == NULL) {
29611708Sstevel 			cmn_err(CE_WARN, "Failed to allocate sysevent buffer "
29627656SSherry.Moore@Sun.COM 			    "for %s/%s event", EC_ENV, ESC_ENV_POWER);
29631708Sstevel 			return (DDI_FAILURE);
29641708Sstevel 		}
29651708Sstevel 		break;
29661708Sstevel 	}
29671708Sstevel 
29681708Sstevel 
29691708Sstevel 	/*
29701708Sstevel 	 * Set the following attributes for this event:
29711708Sstevel 	 *
29721708Sstevel 	 *	ENV_FRU_ID
29731708Sstevel 	 *	ENV_FRU_RESOURCE_ID
29741708Sstevel 	 *	ENV_FRU_DEVICE
29751708Sstevel 	 *	ENV_FRU_STATE
29761708Sstevel 	 *	ENV_MSG
29771708Sstevel 	 *
29781708Sstevel 	 */
29791708Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
29801708Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
29811708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_ID, &se_val, SE_NOSLEEP);
29821708Sstevel 	if (err != 0) {
29831708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
29847656SSherry.Moore@Sun.COM 		    ENV_FRU_ID, EC_ENV,
29857656SSherry.Moore@Sun.COM 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
29861708Sstevel 		sysevent_free(ev);
29871708Sstevel 		return (DDI_FAILURE);
29881708Sstevel 	}
29891708Sstevel 
29901708Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
29911708Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
29921708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_RESOURCE_ID,
29937656SSherry.Moore@Sun.COM 	    &se_val, SE_NOSLEEP);
29941708Sstevel 	if (err != 0) {
29951708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
29967656SSherry.Moore@Sun.COM 		    ENV_FRU_RESOURCE_ID, EC_ENV,
29977656SSherry.Moore@Sun.COM 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
29981708Sstevel 		sysevent_free_attr(ev_attr_list);
29991708Sstevel 		sysevent_free(ev);
30001708Sstevel 		return (DDI_FAILURE);
30011708Sstevel 	}
30021708Sstevel 
30031708Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
30041708Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
30051708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_DEVICE,
30067656SSherry.Moore@Sun.COM 	    &se_val, SE_NOSLEEP);
30071708Sstevel 	if (err != 0) {
30081708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
30097656SSherry.Moore@Sun.COM 		    ENV_FRU_DEVICE, EC_ENV,
30107656SSherry.Moore@Sun.COM 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
30111708Sstevel 		sysevent_free_attr(ev_attr_list);
30121708Sstevel 		sysevent_free(ev);
30131708Sstevel 		return (DDI_FAILURE);
30141708Sstevel 	}
30151708Sstevel 
30161708Sstevel 
30171708Sstevel 	/*
30181708Sstevel 	 * We need to find out the status of the reading.
30191708Sstevel 	 */
30201708Sstevel 	se_val.value_type = SE_DATA_TYPE_INT32;
30211708Sstevel 	switch (SG_GET_SENSOR_STATUS(sensor.sd_status)) {
30221708Sstevel 	case SG_SENSOR_STATUS_OK:
30231708Sstevel 		se_val.value.sv_int32 = ENV_OK;
30241708Sstevel 		break;
30251708Sstevel 
30261708Sstevel 	case SG_SENSOR_STATUS_LO_WARN:
30271708Sstevel 	case SG_SENSOR_STATUS_HI_WARN:
30281708Sstevel 		se_val.value.sv_int32 = ENV_WARNING;
30291708Sstevel 		break;
30301708Sstevel 
30311708Sstevel 	case SG_SENSOR_STATUS_LO_DANGER:
30321708Sstevel 	case SG_SENSOR_STATUS_HI_DANGER:
30331708Sstevel 	default:
30341708Sstevel 		se_val.value.sv_int32 = ENV_FAILED;
30351708Sstevel 		break;
30361708Sstevel 	}
30371708Sstevel 
30381708Sstevel 	/*
30391708Sstevel 	 * Add ENV_FRU_STATE attribute.
30401708Sstevel 	 */
30411708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_STATE,
30427656SSherry.Moore@Sun.COM 	    &se_val, SE_NOSLEEP);
30431708Sstevel 	if (err != 0) {
30441708Sstevel 		cmn_err(CE_WARN, "Failed to add attr[%s] for %s/%s event "
30457656SSherry.Moore@Sun.COM 		    "(Err=%d)", ENV_FRU_STATE, EC_ENV,
30467656SSherry.Moore@Sun.COM 		    (temp_event_type ? ESC_ENV_TEMP: ESC_ENV_POWER),
30477656SSherry.Moore@Sun.COM 		    err);
30481708Sstevel 		sysevent_free_attr(ev_attr_list);
30491708Sstevel 		sysevent_free(ev);
30501708Sstevel 		return (DDI_FAILURE);
30511708Sstevel 	}
30521708Sstevel 
30531708Sstevel 
30541708Sstevel 	/*
30551708Sstevel 	 * Save the sensor TagID as a string so that a meaningful message
30561708Sstevel 	 * can be passed to as part of the ENV_MSG attribute.
30571708Sstevel 	 */
30581708Sstevel 	sgenv_tagid_to_string(sensor.sd_id, sensor_str);
30591708Sstevel 
30601708Sstevel 	/*
30611708Sstevel 	 * We need to add a string stating what type of event occurred.
30621708Sstevel 	 */
30631708Sstevel 	switch (SG_GET_SENSOR_STATUS(sensor.sd_status)) {
30641708Sstevel 	case SG_SENSOR_STATUS_OK:
3065*11311SSurya.Prakki@Sun.COM 		(void) strcat(sensor_str, SGENV_EVENT_MSG_OK);
30661708Sstevel 		break;
30671708Sstevel 
30681708Sstevel 	case SG_SENSOR_STATUS_LO_WARN:
3069*11311SSurya.Prakki@Sun.COM 		(void) strcat(sensor_str, SGENV_EVENT_MSG_LO_WARN);
30701708Sstevel 		break;
30711708Sstevel 
30721708Sstevel 	case SG_SENSOR_STATUS_HI_WARN:
3073*11311SSurya.Prakki@Sun.COM 		(void) strcat(sensor_str, SGENV_EVENT_MSG_HI_WARN);
30741708Sstevel 		break;
30751708Sstevel 
30761708Sstevel 	case SG_SENSOR_STATUS_LO_DANGER:
3077*11311SSurya.Prakki@Sun.COM 		(void) strcat(sensor_str, SGENV_EVENT_MSG_LO_DANGER);
30781708Sstevel 		break;
30791708Sstevel 
30801708Sstevel 	case SG_SENSOR_STATUS_HI_DANGER:
3081*11311SSurya.Prakki@Sun.COM 		(void) strcat(sensor_str, SGENV_EVENT_MSG_HI_DANGER);
30821708Sstevel 		break;
30831708Sstevel 
30841708Sstevel 	default:
30851708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: Unknown sensor status", f);
3086*11311SSurya.Prakki@Sun.COM 		(void) strcat(sensor_str, SGENV_EVENT_MSG_UNKNOWN);
30871708Sstevel 		break;
30881708Sstevel 	}
30891708Sstevel 
30901708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "Temp/Power: %s", sensor_str);
30911708Sstevel 
30921708Sstevel 	/*
30931708Sstevel 	 * Add ENV_MSG attribute.
30941708Sstevel 	 */
30951708Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
30961708Sstevel 	se_val.value.sv_string = sensor_str;
30971708Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_MSG, &se_val, SE_NOSLEEP);
30981708Sstevel 	if (err != 0) {
30991708Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
31007656SSherry.Moore@Sun.COM 		    ENV_MSG, EC_ENV,
31017656SSherry.Moore@Sun.COM 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
31021708Sstevel 		sysevent_free_attr(ev_attr_list);
31031708Sstevel 		sysevent_free(ev);
31041708Sstevel 		return (DDI_FAILURE);
31051708Sstevel 	}
31061708Sstevel 
31071708Sstevel 
31081708Sstevel 	/*
31091708Sstevel 	 * Log this event with sysevent framework.
31101708Sstevel 	 */
31111708Sstevel 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
31121708Sstevel 		cmn_err(CE_WARN, "Failed to attach attr list for %s/%s event",
31137656SSherry.Moore@Sun.COM 		    EC_ENV,
31147656SSherry.Moore@Sun.COM 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
31151708Sstevel 		sysevent_free_attr(ev_attr_list);
31161708Sstevel 		sysevent_free(ev);
31171708Sstevel 		return (DDI_FAILURE);
31181708Sstevel 	}
31191708Sstevel 	err = log_sysevent(ev, SE_NOSLEEP, &eid);
31201708Sstevel 	if (err != 0) {
31211708Sstevel 		cmn_err(CE_WARN, "Failed to log %s/%s event", EC_ENV,
31227656SSherry.Moore@Sun.COM 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
31231708Sstevel 		sysevent_free(ev);
31241708Sstevel 		return (DDI_FAILURE);
31251708Sstevel 	}
31261708Sstevel 	sysevent_free(ev);
31271708Sstevel 
31281708Sstevel 	return (DDI_SUCCESS);
31291708Sstevel }
31301708Sstevel 
31311708Sstevel 
31321708Sstevel /*
31331708Sstevel  * This function gets called when sgenv is notified of a DR event.
31341708Sstevel  * We need to update the board and env caches to ensure that they
31351708Sstevel  * now contain the latest system information..
31361708Sstevel  */
31371708Sstevel static uint_t
sgenv_dr_event_handler(char * arg)31381708Sstevel sgenv_dr_event_handler(char *arg)
31391708Sstevel {
31401979Sarutz 	DCMN_ERR_S(f, "sgenv_dr_event_handler()");
31411708Sstevel 
31421708Sstevel 	sg_system_fru_descriptor_t	*payload = NULL;
31431708Sstevel 	sbbc_msg_t			*msg = NULL;
31441708Sstevel 
31451708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
31461708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: Start: %lld", f, gethrtime());
31471708Sstevel 
31481708Sstevel 
31491708Sstevel 	if (arg == NULL) {
31501708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
31511708Sstevel 		return (DDI_INTR_CLAIMED);
31521708Sstevel 	}
31531708Sstevel 
31541708Sstevel 	msg = (sbbc_msg_t *)arg;
31551708Sstevel 
31561708Sstevel 	if (msg->msg_buf == NULL) {
31571708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
31581708Sstevel 		return (DDI_INTR_CLAIMED);
31591708Sstevel 	}
31601708Sstevel 
31611708Sstevel 	payload = (sg_system_fru_descriptor_t *)msg->msg_buf;
31621708Sstevel 
31631708Sstevel 	/*
31641708Sstevel 	 * We check the event_details field of the msg_buf to see if
31651708Sstevel 	 * we need to invalidate the caches
31661708Sstevel 	 */
31671708Sstevel 	switch (payload->event_details) {
31681708Sstevel 	case SG_EVT_BOARD_ABSENT:
31691708Sstevel 	case SG_EVT_BOARD_PRESENT:
31701708Sstevel 	case SG_EVT_UNASSIGN:
31711708Sstevel 	case SG_EVT_ASSIGN:
31721708Sstevel 	case SG_EVT_UNAVAILABLE:
31731708Sstevel 	case SG_EVT_AVAILABLE:
31741708Sstevel 	case SG_EVT_POWER_OFF:
31751708Sstevel 	case SG_EVT_POWER_ON:
31761708Sstevel 	case SG_EVT_PASSED_TEST:
31771708Sstevel 	case SG_EVT_FAILED_TEST:
31781708Sstevel 		/*
31791708Sstevel 		 * We now need to signal to the background threads to poll the
31801708Sstevel 		 * SC for env readings and board info which may have changed
31811708Sstevel 		 * as a result of the DR changes. This will cause the
31821708Sstevel 		 * env_cache and the board_cache to be updated.
31831708Sstevel 		 */
31841708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: about to signal to background "
31857656SSherry.Moore@Sun.COM 		    "threads due to event %d.", f, payload->event_details);
31861708Sstevel 
31871708Sstevel 		sgenv_indicate_cache_update_needed(ENV_CACHE);
31881708Sstevel 		sgenv_indicate_cache_update_needed(BOARD_CACHE);
31891708Sstevel 
31901708Sstevel 		break;
31911708Sstevel 
31921708Sstevel 	default:
31931708Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: Unknown DR event type.", f);
31941708Sstevel 		break;
31951708Sstevel 	}
31961708Sstevel 
31971708Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: Finish: %lld", f, gethrtime());
31981708Sstevel 
31991708Sstevel 	return (DDI_INTR_CLAIMED);
32001708Sstevel }
32011708Sstevel 
32021708Sstevel 
32031708Sstevel /*
32041708Sstevel  * This function is called by the interrupt handlers watching for ENV/DR events
32051708Sstevel  * from the SC. It indicates to the thread responsible for the cache specified
32061708Sstevel  * that it needs to update its data.
32071708Sstevel  */
32081708Sstevel static void
sgenv_indicate_cache_update_needed(int cache_type)32091708Sstevel sgenv_indicate_cache_update_needed(int cache_type)
32101708Sstevel {
32111979Sarutz 	DCMN_ERR_S(f, "sgenv_indicate_cache_update_needed()");
32121708Sstevel 
32131708Sstevel 	/*
32141708Sstevel 	 * If the cache is already being updated, we set a flag to
32151708Sstevel 	 * inform the thread that it needs to reread the data when
32161708Sstevel 	 * it is finished as we cannot be sure if the data was read
32171708Sstevel 	 * before or after the time this handler was triggered.
32181708Sstevel 	 *
32191708Sstevel 	 * Otherwise the thread is waiting for us and we signal
32201708Sstevel 	 * to it to start reading the data.
32211708Sstevel 	 */
32221708Sstevel 	switch (cache_type) {
32231708Sstevel 	case ENV_CACHE:
32241708Sstevel 		mutex_enter(&env_flag_lock);
32251708Sstevel 		if (env_cache_updating) {
32261708Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Thread already "
32277656SSherry.Moore@Sun.COM 			    "updating env cache", f);
32281708Sstevel 			env_cache_update_needed = B_TRUE;
32291708Sstevel 
32301708Sstevel 		} else {
32311708Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Sending signal "
32327656SSherry.Moore@Sun.COM 			    "to env thread", f);
32331708Sstevel 			cv_signal(&env_flag_cond);
32341708Sstevel 		}
32351708Sstevel 		mutex_exit(&env_flag_lock);
32361708Sstevel 		break;
32371708Sstevel 
32381708Sstevel 	case BOARD_CACHE:
32391708Sstevel 		mutex_enter(&board_flag_lock);
32401708Sstevel 		if (board_cache_updating) {
32411708Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Thread already "
32427656SSherry.Moore@Sun.COM 			    "updating board cache", f);
32431708Sstevel 			board_cache_update_needed = B_TRUE;
32441708Sstevel 
32451708Sstevel 		} else {
32461708Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Sending signal "
32477656SSherry.Moore@Sun.COM 			    "to board thread", f);
32481708Sstevel 			cv_signal(&board_flag_cond);
32491708Sstevel 		}
32501708Sstevel 		mutex_exit(&board_flag_lock);
32511708Sstevel 		break;
32521708Sstevel 
32531708Sstevel 	default:
32541708Sstevel 		DCMN_ERR(CE_NOTE, "%s: Unknown cache type:0x%x", f, cache_type);
32551708Sstevel 		break;
32561708Sstevel 	}
32571708Sstevel }
3258