xref: /illumos-gate/usr/src/uts/sun4u/lw8/io/sgenv.c (revision d1d6926f)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
2307d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel 
2803831d35Sstevel /*
2903831d35Sstevel  * Serengeti Environmental Information driver (sgenv)
3003831d35Sstevel  *
3103831d35Sstevel  * This driver requests the environmental properties from the SC. These
3203831d35Sstevel  * request-response transactions are transferred through the SBBC mailbox,
3303831d35Sstevel  * between the Domain and the SC.
3403831d35Sstevel  *
3503831d35Sstevel  * All sensors have the same sort of properties: Low and high limits, warning
3603831d35Sstevel  * thresholds, last measured value, time of measurement, units (e.g., degrees
3703831d35Sstevel  * Celsius, volts, etc.), and so on.
3803831d35Sstevel  *
3903831d35Sstevel  * Each sensor is named by a unique Tag. The Tag identifies the geographical
4003831d35Sstevel  * location of the sensor in the Serengeti, and what it is the sensor measures.
4103831d35Sstevel  *
4203831d35Sstevel  * Requestable sensor properties are broken into two types:  Those which are
4303831d35Sstevel  * quasi-constant (infrequently change) - e.g., tolerance-defining low and high
4403831d35Sstevel  * limits; and those which are volatile (typically change) - e.g., the current
4503831d35Sstevel  * measurement.
4603831d35Sstevel  *
4703831d35Sstevel  * Unfortunately, property sets are too large to comprise a single mailbox
4803831d35Sstevel  * message, so the sets are further subdivided into notionally arbitrary
4903831d35Sstevel  * collections. NOTE: The SC-mailbox framework now supports fragmented messages
5003831d35Sstevel  * which could allow us to request the data in larger chunks in the future.
5103831d35Sstevel  *
5203831d35Sstevel  * Each collection is fetched by a separate transaction.
5303831d35Sstevel  *
5403831d35Sstevel  * Firstly there is a transaction to obtain a list of all collections. Each non-
5503831d35Sstevel  * zero key in this list is associated whith one of the collections of sensors.
5603831d35Sstevel  * (This sparse list of keys is then used as an index to obtain all the sensor
5703831d35Sstevel  * data for each collection).
5803831d35Sstevel  *
5903831d35Sstevel  * For each collection, there is one request-reply transaction to obtain a list
6003831d35Sstevel  * of all sensors in that collection and the limits that apply to each; and a
6103831d35Sstevel  * separate request-reply transaction to obtain the measurements from the
6203831d35Sstevel  * sensors in the collection.
6303831d35Sstevel  *
6403831d35Sstevel  * The sgenv driver assembles each property set from the constituent
6503831d35Sstevel  * collections, and caches the assembled property sets into the appropriate
6603831d35Sstevel  * cache (env_cache, board_cache). The caches are created at startup and are
6703831d35Sstevel  * updated on receipt of events from the SC. These events (which include DR
6803831d35Sstevel  * events and ENV events) notify sgenv of configuration changes and
6903831d35Sstevel  * environmental state changes (such as a sensor state change, Fan speed
7003831d35Sstevel  * change).
7103831d35Sstevel  *
7203831d35Sstevel  * The SC-APP maintains a pseudo-sensor in each collection "measuring" changes
7303831d35Sstevel  * to the quasi-constants in that collection. By monitoring these pseudo-sensor
7403831d35Sstevel  * measurements, the kstat driver avoids redundant or speculative re-fetches of
7503831d35Sstevel  * the quasi-constant properties.
7603831d35Sstevel  */
7703831d35Sstevel 
7803831d35Sstevel #include <sys/time.h>
7903831d35Sstevel #include <sys/errno.h>
8003831d35Sstevel #include <sys/kmem.h>
8103831d35Sstevel #include <sys/stat.h>
8203831d35Sstevel #include <sys/cmn_err.h>
8303831d35Sstevel #include <sys/disp.h>
8403831d35Sstevel 
8503831d35Sstevel #include <sys/conf.h>
8603831d35Sstevel #include <sys/modctl.h>
8703831d35Sstevel #include <sys/devops.h>
8803831d35Sstevel #include <sys/ddi.h>
8903831d35Sstevel #include <sys/sunddi.h>
9003831d35Sstevel 
9103831d35Sstevel #include <sys/sgevents.h>
9203831d35Sstevel #include <sys/sysevent.h>
9303831d35Sstevel #include <sys/sysevent/eventdefs.h>
9403831d35Sstevel #include <sys/sysevent/domain.h>
9503831d35Sstevel #include <sys/sysevent/env.h>
9603831d35Sstevel 
9703831d35Sstevel #include <sys/serengeti.h>
9803831d35Sstevel #include <sys/sgfrutypes.h>
9903831d35Sstevel 
10003831d35Sstevel #include <sys/sgsbbc.h>
10103831d35Sstevel #include <sys/sgsbbc_iosram.h>
10203831d35Sstevel #include <sys/sgsbbc_mailbox.h>
10303831d35Sstevel 
10403831d35Sstevel #include <sys/sbd_ioctl.h>	/* sbd header files needed for board support */
10503831d35Sstevel #include <sys/sbdp_priv.h>
10603831d35Sstevel #include <sys/sbd.h>
10703831d35Sstevel 
10803831d35Sstevel #include <sys/sgenv_impl.h>
10903831d35Sstevel 
11003831d35Sstevel 
11103831d35Sstevel /*
11203831d35Sstevel  * Global Variables - can be patched from Solaris
11303831d35Sstevel  * ==============================================
11403831d35Sstevel  */
11503831d35Sstevel 
11603831d35Sstevel /*
11703831d35Sstevel  * the maximum amount of time this driver is prepared to wait for the mailbox
11803831d35Sstevel  * to reply before it decides to timeout. The value is initially set in the
11903831d35Sstevel  * _init() routine to the global Serengeti variable <sbbc_mbox_default_timeout>
12003831d35Sstevel  * but could be tuned specifically for SGENV after booting up the system.
12103831d35Sstevel  */
12203831d35Sstevel int	sgenv_max_mbox_wait_time = 0;
12303831d35Sstevel 
12403831d35Sstevel #ifdef DEBUG
12503831d35Sstevel /*
12603831d35Sstevel  * This variable controls the level of debug output
12703831d35Sstevel  */
12803831d35Sstevel uint_t		sgenv_debug = SGENV_DEBUG_NONE;
12903831d35Sstevel #endif
13003831d35Sstevel 
13103831d35Sstevel 
13203831d35Sstevel /*
13303831d35Sstevel  * Module Variables
13403831d35Sstevel  * ================
13503831d35Sstevel  */
13603831d35Sstevel 
13703831d35Sstevel /*
13803831d35Sstevel  * Driver entry points
13903831d35Sstevel  */
14003831d35Sstevel static struct cb_ops sgenv_cb_ops = {
14103831d35Sstevel 	nodev,		/* open() */
14203831d35Sstevel 	nodev,		/* close() */
14303831d35Sstevel 	nodev,		/* strategy() */
14403831d35Sstevel 	nodev,		/* print() */
14503831d35Sstevel 	nodev,		/* dump() */
14603831d35Sstevel 	nodev,		/* read() */
14703831d35Sstevel 	nodev,		/* write() */
14803831d35Sstevel 	nodev,		/* ioctl() */
14903831d35Sstevel 	nodev,		/* devmap() */
15003831d35Sstevel 	nodev,		/* mmap() */
15103831d35Sstevel 	ddi_segmap,	/* segmap() */
15203831d35Sstevel 	nochpoll,	/* poll() */
15303831d35Sstevel 	ddi_prop_op,    /* prop_op() */
15403831d35Sstevel 	NULL,		/* cb_str */
15503831d35Sstevel 	D_NEW | D_MP	/* cb_flag */
15603831d35Sstevel };
15703831d35Sstevel 
15803831d35Sstevel 
15903831d35Sstevel static struct dev_ops sgenv_ops = {
16003831d35Sstevel 	DEVO_REV,
16103831d35Sstevel 	0,			/* ref count */
16203831d35Sstevel 	ddi_getinfo_1to1,	/* getinfo() */
16303831d35Sstevel 	nulldev,		/* identify() */
16403831d35Sstevel 	nulldev,		/* probe() */
16503831d35Sstevel 	sgenv_attach,		/* attach() */
16603831d35Sstevel 	sgenv_detach,		/* detach */
16703831d35Sstevel 	nodev,			/* reset */
16803831d35Sstevel 	&sgenv_cb_ops,		/* pointer to cb_ops structure */
16903831d35Sstevel 	(struct bus_ops *)NULL,
17019397407SSherry Moore 	nulldev,		/* power() */
17119397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce() */
17203831d35Sstevel };
17303831d35Sstevel 
17403831d35Sstevel /*
17503831d35Sstevel  * Loadable module support.
17603831d35Sstevel  */
17703831d35Sstevel extern struct mod_ops mod_driverops;
17803831d35Sstevel 
17903831d35Sstevel static struct modldrv modldrv = {
18003831d35Sstevel 	&mod_driverops,			/* Type of module. This is a driver */
18119397407SSherry Moore 	"Environmental Driver",		/* Name of the module */
18203831d35Sstevel 	&sgenv_ops			/* pointer to the dev_ops structure */
18303831d35Sstevel };
18403831d35Sstevel 
18503831d35Sstevel static struct modlinkage modlinkage = {
18603831d35Sstevel 	MODREV_1,
18703831d35Sstevel 	&modldrv,
18803831d35Sstevel 	NULL
18903831d35Sstevel };
19003831d35Sstevel 
19103831d35Sstevel /* Opaque state structure pointer */
19203831d35Sstevel static void		*sgenv_statep;
19303831d35Sstevel 
19403831d35Sstevel /*
19503831d35Sstevel  * <env_cache> is a cache of all the sensor readings which is persistent
19603831d35Sstevel  * between kstat reads. It is created at init and gets updated upon receipt
19703831d35Sstevel  * of events from the SC.
19803831d35Sstevel  *
19903831d35Sstevel  * The kstat_update function takes a copy of the non-zero entries in this
20003831d35Sstevel  * cache and creates a temp buffer called env_cache_snapshot. The
20103831d35Sstevel  * kstat_snapshot function then bcopies the env_cache_snapshot into the
20203831d35Sstevel  * kstat buffer. This is done because there is no way to ensure that the
20303831d35Sstevel  * env_cache won't change between the kstat_update and the kstat_snapshot
20403831d35Sstevel  * which will cause problems as the update sets the ks_data_size.
20503831d35Sstevel  */
20603831d35Sstevel static env_sensor_t	*env_cache[SGENV_MAX_HPU_KEYS] = {NULL};
20703831d35Sstevel static void		*env_cache_snapshot = NULL;
20803831d35Sstevel static size_t		env_cache_snapshot_size = 0;
20903831d35Sstevel 
21003831d35Sstevel /*
21103831d35Sstevel  * This is set to TRUE the first time env data is stored in the cache
21203831d35Sstevel  * so that at least from then on, old data can be returned if a call to
21303831d35Sstevel  * the mailbox fails.
21403831d35Sstevel  */
21503831d35Sstevel static int		env_cache_updated = FALSE;
21603831d35Sstevel 
21703831d35Sstevel /*
21803831d35Sstevel  * This lock is needed by the variable-sized kstat which returns
21903831d35Sstevel  * environmental info. It prevents data-size races with kstat clients.
22003831d35Sstevel  */
22103831d35Sstevel static kmutex_t		env_kstat_lock;
22203831d35Sstevel 
22303831d35Sstevel /*
22403831d35Sstevel  * The <env_cache> can be accessed asynchronously by the polling function
22503831d35Sstevel  * and the kstat_read framework. This mutex ensures that access to the data
22603831d35Sstevel  * is controlled correctly.
22703831d35Sstevel  */
22803831d35Sstevel static kmutex_t		env_cache_lock;
22903831d35Sstevel 
23003831d35Sstevel /*
23103831d35Sstevel  * We need to store the last time we asked the SC for environmental information
23203831d35Sstevel  * so that we do not send too many requests in a short period of time.
23303831d35Sstevel  */
23403831d35Sstevel static hrtime_t		last_env_read_time = 0;
23503831d35Sstevel 
23603831d35Sstevel /*
23703831d35Sstevel  * Variables to coordinate between the handlers which are triggered when
23803831d35Sstevel  * the env cache needs to be updated and the thread which does the work.
23903831d35Sstevel  */
24003831d35Sstevel static volatile int	env_thread_run = 0;
24103831d35Sstevel static kthread_t	*env_thread = NULL;
24203831d35Sstevel static kt_did_t		env_thread_tid;
24303831d35Sstevel 
24403831d35Sstevel static kcondvar_t	env_flag_cond;
24503831d35Sstevel static kmutex_t		env_flag_lock;
24603831d35Sstevel static boolean_t	env_cache_updating = B_FALSE;
24703831d35Sstevel static boolean_t	env_cache_update_needed = B_TRUE;
24803831d35Sstevel 
24903831d35Sstevel /*
25003831d35Sstevel  * <board_cache> is a cache of all the board status info and it is persistent
25103831d35Sstevel  * between kstat reads.
25203831d35Sstevel  *
25303831d35Sstevel  * The kstat_update function takes a copy of the non-zero entries in this
25403831d35Sstevel  * cache and copies them into the board_cache_snapshot buffer. The
25503831d35Sstevel  * kstat_snapshot function then bcopies the board_cache_snapshot into the
25603831d35Sstevel  * kstat buffer. This is done because there is no way to ensure that the
25703831d35Sstevel  * board_cache won't change between the kstat_update and the kstat_snapshot
25803831d35Sstevel  * which will cause problems as the update sets the ks_data_size.
25903831d35Sstevel  */
260*d1d6926fSToomas Soome static sg_board_info_t	board_cache[SG_MAX_BDS] = { 0 };
261*d1d6926fSToomas Soome static sg_board_info_t	board_cache_snapshot[SG_MAX_BDS] = { 0 };
26203831d35Sstevel static int		board_cache_updated = FALSE;
26303831d35Sstevel 
26403831d35Sstevel /*
26503831d35Sstevel  * This mutex ensures the <board_cache> is not destroyed while the board data
26603831d35Sstevel  * is being collected.
26703831d35Sstevel  */
26803831d35Sstevel static kmutex_t		board_cache_lock;
26903831d35Sstevel 
27003831d35Sstevel /*
27103831d35Sstevel  * This lock is needed by the variable-sized kstat which returns
27203831d35Sstevel  * board status info. It prevents data-size races with kstat clients.
27303831d35Sstevel  */
27403831d35Sstevel static kmutex_t		board_kstat_lock;
27503831d35Sstevel 
27603831d35Sstevel /*
27703831d35Sstevel  * This is a count of the number of board readings were stored by
27803831d35Sstevel  * the kstat_update routine - this is needed by the kstat_snapshot routine.
27903831d35Sstevel  */
28003831d35Sstevel static int		board_count = 0;
28103831d35Sstevel static int		board_count_snapshot = 0;
28203831d35Sstevel 
28303831d35Sstevel /*
28403831d35Sstevel  * We need to store the last time we asked the SC for board information
28503831d35Sstevel  * so that we do not send too many requests in a short period of time.
28603831d35Sstevel  */
28703831d35Sstevel static hrtime_t		last_board_read_time = 0;
28803831d35Sstevel 
28903831d35Sstevel /*
29003831d35Sstevel  * Variables to coordinate between the handlers which are triggered when
29103831d35Sstevel  * the board cache needs to be updated and the thread which does the work.
29203831d35Sstevel  */
29303831d35Sstevel static volatile int	board_thread_run = 0;
29403831d35Sstevel static kthread_t	*board_thread = NULL;
29503831d35Sstevel static kt_did_t		board_thread_tid;
29603831d35Sstevel static kcondvar_t	board_flag_cond;
29703831d35Sstevel 
29803831d35Sstevel static kmutex_t		board_flag_lock;
29903831d35Sstevel static boolean_t	board_cache_updating = B_FALSE;
30003831d35Sstevel static boolean_t	board_cache_update_needed = B_TRUE;
30103831d35Sstevel 
30203831d35Sstevel /*
30303831d35Sstevel  * Used to keep track of the number of sensors associated with each key.
30403831d35Sstevel  * The sum of all the values in this array is used to set ks_data_size.
30503831d35Sstevel  */
30603831d35Sstevel static int		vol_sensor_count[SGENV_MAX_HPU_KEYS] = {0};
30703831d35Sstevel 
30803831d35Sstevel /*
30903831d35Sstevel  * This variable keeps a count of the number of errors that have occurred
31003831d35Sstevel  * when we make calls to the mailbox for Env or Board data.
31103831d35Sstevel  */
31203831d35Sstevel static int		sgenv_mbox_error_count = 0;
31303831d35Sstevel 
31403831d35Sstevel /*
31503831d35Sstevel  * mutex which protects the keyswitch interrupt handler.
31603831d35Sstevel  */
31703831d35Sstevel static kmutex_t		keysw_hdlr_lock;
31803831d35Sstevel 
31903831d35Sstevel /*
32003831d35Sstevel  * mutex which protects the env interrupt handler.
32103831d35Sstevel  */
32203831d35Sstevel static kmutex_t		env_hdlr_lock;
32303831d35Sstevel 
32403831d35Sstevel /*
32503831d35Sstevel  * mutex which protects the DR handler interrupt handler.
32603831d35Sstevel  */
32703831d35Sstevel static kmutex_t		dr_hdlr_lock;
32803831d35Sstevel 
32903831d35Sstevel /*
33003831d35Sstevel  * Payloads of the event handlers.
33103831d35Sstevel  */
33203831d35Sstevel static sg_event_key_position_t	keysw_payload;
33303831d35Sstevel static sbbc_msg_t		keysw_payload_msg;
33403831d35Sstevel 
33503831d35Sstevel static sg_event_env_changed_t	env_payload;
33603831d35Sstevel static sbbc_msg_t		env_payload_msg;
33703831d35Sstevel 
33803831d35Sstevel static sg_event_fan_status_t	fan_payload;
33903831d35Sstevel static sbbc_msg_t		fan_payload_msg;
34003831d35Sstevel 
34103831d35Sstevel static sg_system_fru_descriptor_t	dr_payload;
34203831d35Sstevel static sbbc_msg_t			dr_payload_msg;
34303831d35Sstevel 
34403831d35Sstevel /*
34503831d35Sstevel  * The following 3 arrays list all possible HPUs, Parts and Device types
34603831d35Sstevel  */
34703831d35Sstevel 
34803831d35Sstevel /*
34903831d35Sstevel  * ensure that all possible HPUs exported, as described in the main comment
35003831d35Sstevel  * in <sys/sensor_tag.h>, are accounted for here.
35103831d35Sstevel  */
35203831d35Sstevel static const hpu_value_t hpus[] = {
35303831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_UNKNOWN),
35403831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_CPU_BOARD),
35503831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_PCI_IO_BOARD),
35603831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_CPCI_IO_BOARD),
35703831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_SP_CPCI_IO_BOARD),
35803831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_REPEATER_BOARD),
35903831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_L2_REPEATER_BOARD),
36003831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_SYSTEM_CONTROLLER_BOARD),
36103831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_SP_SYSTEM_CONTROLLER_BOARD),
36203831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A123_POWER_SUPPLY),
36303831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A138_POWER_SUPPLY),
36403831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A145_POWER_SUPPLY),
36503831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A152_POWER_SUPPLY),
36603831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_A153_POWER_SUPPLY),
36703831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_RACK_FAN_TRAY),
36803831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_SP_FAN_TRAY),
36903831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_MD_TOP_IO_FAN_TRAY),
37003831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_MD_BOTTOM_IO_FAN_TRAY),
37103831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_R12_THREE_FAN_TRAY),
37203831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_K12_IO_ONE_FAN_TRAY),
37303831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_K12_CPU_THREE_FAN_TRAY),
37403831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_R24_IO_FOUR_FAN_TRAY),
37503831d35Sstevel 	HPU_ENTRY(SG_HPU_TYPE_R24_CPU_SIX_FAN_TRAY),
37603831d35Sstevel 	0,	(char *)NULL
37703831d35Sstevel };
37803831d35Sstevel 
37903831d35Sstevel static const struct part_value parts[] = {
38003831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_SBBC),
38103831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_SDC),
38203831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_AR),
38303831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_CBH),
38403831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_DX),
38503831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_CHEETAH),
38603831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_1_5_VDC),
38703831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_3_3_VDC),
38803831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_5_VDC),
38903831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_12_VDC),
39003831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_48_VDC),
39103831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_CURRENT),
39203831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_BOARD),
39303831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_SCAPP),
39403831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_SCHIZO),
39503831d35Sstevel 	PART_VALUE(SG_SENSOR_PART_FAN),
39603831d35Sstevel 	0,	(char *)NULL
39703831d35Sstevel };
39803831d35Sstevel 
39903831d35Sstevel static const struct type_value types[] = {
40003831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_CURRENT, SG_CURRENT_SCALE),
40103831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_TEMPERATURE, SG_TEMPERATURE_SCALE),
40203831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_1_5_VDC, SG_1_5_VDC_SCALE),
40303831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_1_8_VDC, SG_1_8_VDC_SCALE),
40403831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_3_3_VDC, SG_3_3_VDC_SCALE),
40503831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_5_VDC, SG_5_VDC_SCALE),
40603831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_12_VDC, SG_12_VDC_SCALE),
40703831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_48_VDC, SG_48_VDC_SCALE),
40803831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_ENVDB, 1),
40903831d35Sstevel 	TYPE_VALUE(SG_SENSOR_TYPE_COOLING, 1),
41003831d35Sstevel 	0,	(char *)NULL
41103831d35Sstevel };
41203831d35Sstevel 
41303831d35Sstevel int
_init(void)41403831d35Sstevel _init(void)
41503831d35Sstevel {
41603831d35Sstevel 	int	error = 0;
41703831d35Sstevel 
41803831d35Sstevel 	error = ddi_soft_state_init(&sgenv_statep,
41919397407SSherry Moore 	    sizeof (sgenv_soft_state_t), 1);
42003831d35Sstevel 
42103831d35Sstevel 	if (error)
42203831d35Sstevel 		return (error);
42303831d35Sstevel 
42403831d35Sstevel 	error = mod_install(&modlinkage);
42503831d35Sstevel 	if (error) {
42603831d35Sstevel 		ddi_soft_state_fini(&sgenv_statep);
42703831d35Sstevel 		return (error);
42803831d35Sstevel 	}
42903831d35Sstevel 
43003831d35Sstevel 	mutex_init(&env_kstat_lock, NULL, MUTEX_DEFAULT, NULL);
43103831d35Sstevel 	mutex_init(&env_cache_lock, NULL, MUTEX_DEFAULT, NULL);
43203831d35Sstevel 	mutex_init(&env_flag_lock, NULL, MUTEX_DEFAULT, NULL);
43303831d35Sstevel 	cv_init(&env_flag_cond, NULL, CV_DEFAULT, NULL);
43403831d35Sstevel 
43503831d35Sstevel 	mutex_init(&board_cache_lock, NULL, MUTEX_DEFAULT, NULL);
43603831d35Sstevel 	mutex_init(&board_kstat_lock, NULL, MUTEX_DEFAULT, NULL);
43703831d35Sstevel 	mutex_init(&board_flag_lock, NULL, MUTEX_DEFAULT, NULL);
43803831d35Sstevel 	cv_init(&board_flag_cond, NULL, CV_DEFAULT, NULL);
43903831d35Sstevel 
44003831d35Sstevel 	mutex_init(&keysw_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
44103831d35Sstevel 	mutex_init(&env_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
44203831d35Sstevel 	mutex_init(&dr_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
44303831d35Sstevel 
44403831d35Sstevel 	/* set the default timeout value */
44503831d35Sstevel 	sgenv_max_mbox_wait_time = sbbc_mbox_default_timeout;
44603831d35Sstevel 
44703831d35Sstevel 	return (error);
44803831d35Sstevel }
44903831d35Sstevel 
45003831d35Sstevel 
45103831d35Sstevel int
_info(struct modinfo * modinfop)45203831d35Sstevel _info(struct modinfo *modinfop)
45303831d35Sstevel {
45403831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
45503831d35Sstevel }
45603831d35Sstevel 
45703831d35Sstevel 
45803831d35Sstevel int
_fini(void)45903831d35Sstevel _fini(void)
46003831d35Sstevel {
46103831d35Sstevel 	int	error = 0;
46203831d35Sstevel 
46303831d35Sstevel 	error = mod_remove(&modlinkage);
46403831d35Sstevel 	if (error)
46503831d35Sstevel 		return (error);
46603831d35Sstevel 
46703831d35Sstevel 	mutex_destroy(&env_kstat_lock);
46803831d35Sstevel 	mutex_destroy(&env_cache_lock);
46903831d35Sstevel 
47003831d35Sstevel 	mutex_destroy(&board_cache_lock);
47103831d35Sstevel 	mutex_destroy(&board_kstat_lock);
47203831d35Sstevel 
47303831d35Sstevel 	mutex_destroy(&keysw_hdlr_lock);
47403831d35Sstevel 	mutex_destroy(&env_hdlr_lock);
47503831d35Sstevel 	mutex_destroy(&dr_hdlr_lock);
47603831d35Sstevel 
47703831d35Sstevel 	ddi_soft_state_fini(&sgenv_statep);
47803831d35Sstevel 
47903831d35Sstevel 	return (error);
48003831d35Sstevel }
48103831d35Sstevel 
48203831d35Sstevel 
48303831d35Sstevel static int
sgenv_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)48403831d35Sstevel sgenv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
48503831d35Sstevel {
48603831d35Sstevel 	sgenv_soft_state_t	*softsp;
48703831d35Sstevel 
48803831d35Sstevel 	int			instance;
48903831d35Sstevel 	int			err;
49003831d35Sstevel 
49103831d35Sstevel 	switch (cmd) {
49203831d35Sstevel 	case DDI_ATTACH:
49303831d35Sstevel 
49403831d35Sstevel 		instance = ddi_get_instance(dip);
49503831d35Sstevel 
49603831d35Sstevel 		/* allocate a global sgenv_soft_state structure */
49703831d35Sstevel 		err = ddi_soft_state_zalloc(sgenv_statep, instance);
49803831d35Sstevel 		if (err != DDI_SUCCESS) {
49903831d35Sstevel 			cmn_err(CE_WARN, "attach: could not allocate state "
50019397407SSherry Moore 			    "structure for inst %d.", instance);
50103831d35Sstevel 			return (DDI_FAILURE);
50203831d35Sstevel 		}
50303831d35Sstevel 
50403831d35Sstevel 		softsp = ddi_get_soft_state(sgenv_statep, instance);
50503831d35Sstevel 		if (softsp == NULL) {
50603831d35Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
50703831d35Sstevel 			cmn_err(CE_WARN, "attach: could not get state "
50819397407SSherry Moore 			    "structure for inst %d.", instance);
50903831d35Sstevel 			return (DDI_FAILURE);
51003831d35Sstevel 		}
51103831d35Sstevel 
51203831d35Sstevel 		softsp->dip = dip;
51303831d35Sstevel 		softsp->instance = instance;
51403831d35Sstevel 
51503831d35Sstevel 		err = sgenv_add_kstats(softsp);
51603831d35Sstevel 		if (err != 0) {
51703831d35Sstevel 			/*
51803831d35Sstevel 			 * Some of the kstats may have been created before the
51903831d35Sstevel 			 * error occurred in sgenv_add_kstats(), so we call
52003831d35Sstevel 			 * sgenv_remove_kstats() which removes any kstats
52103831d35Sstevel 			 * already created.
52203831d35Sstevel 			 */
52303831d35Sstevel 			sgenv_remove_kstats(softsp);
52403831d35Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
52503831d35Sstevel 			return (DDI_FAILURE);
52603831d35Sstevel 		}
52703831d35Sstevel 
52803831d35Sstevel 		/*
52903831d35Sstevel 		 * Before we setup the framework to read the data from the SC
53003831d35Sstevel 		 * we need to ensure the caches are initialized correctly.
53103831d35Sstevel 		 */
53203831d35Sstevel 		sgenv_init_board_cache();
53303831d35Sstevel 		sgenv_init_env_cache();
53403831d35Sstevel 
53503831d35Sstevel 		/*
53603831d35Sstevel 		 * Add the threads which will update the env and board caches
53703831d35Sstevel 		 * and post events to Sysevent Framework in the background
53803831d35Sstevel 		 * when the interrupt handlers watching for ENV/DR events
53903831d35Sstevel 		 * indicate to the threads that they need to do so.
54003831d35Sstevel 		 */
54103831d35Sstevel 		err = sgenv_create_cache_update_threads();
54203831d35Sstevel 		if (err != DDI_SUCCESS) {
54303831d35Sstevel 			sgenv_remove_kstats(softsp);
54403831d35Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
54503831d35Sstevel 			return (DDI_FAILURE);
54603831d35Sstevel 		}
54703831d35Sstevel 
54803831d35Sstevel 		err = ddi_create_minor_node(dip, SGENV_DRV_NAME, S_IFCHR,
549*d1d6926fSToomas Soome 		    instance, DDI_PSEUDO, 0);
55003831d35Sstevel 		if (err != DDI_SUCCESS) {
55103831d35Sstevel 			sgenv_remove_kstats(softsp);
55207d06da5SSurya Prakki 			(void) sgenv_remove_cache_update_threads();
55303831d35Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
55403831d35Sstevel 			return (DDI_FAILURE);
55503831d35Sstevel 		}
55603831d35Sstevel 
55703831d35Sstevel 		/*
55803831d35Sstevel 		 * Add the handlers which watch for unsolicited messages
55903831d35Sstevel 		 * and post event to Sysevent Framework.
56003831d35Sstevel 		 */
56103831d35Sstevel 		err = sgenv_add_intr_handlers();
56203831d35Sstevel 		if (err != DDI_SUCCESS) {
56303831d35Sstevel 			cmn_err(CE_WARN, "Failed to add event handlers");
56407d06da5SSurya Prakki 			(void) sgenv_remove_intr_handlers();
56503831d35Sstevel 			sgenv_remove_kstats(softsp);
56607d06da5SSurya Prakki 			(void) sgenv_remove_cache_update_threads();
56703831d35Sstevel 			ddi_soft_state_free(sgenv_statep, instance);
56803831d35Sstevel 			return (DDI_FAILURE);
56903831d35Sstevel 		}
57003831d35Sstevel 
57103831d35Sstevel 		ddi_report_dev(dip);
57203831d35Sstevel 
57303831d35Sstevel 		return (DDI_SUCCESS);
57403831d35Sstevel 
57503831d35Sstevel 	case DDI_RESUME:
57603831d35Sstevel 		return (DDI_SUCCESS);
57703831d35Sstevel 
57803831d35Sstevel 	default:
57903831d35Sstevel 		return (DDI_FAILURE);
58003831d35Sstevel 	}
58103831d35Sstevel }
58203831d35Sstevel 
58303831d35Sstevel 
58403831d35Sstevel static int
sgenv_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)58503831d35Sstevel sgenv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
58603831d35Sstevel {
58703831d35Sstevel 	sgenv_soft_state_t	*softsp;
58803831d35Sstevel 
58903831d35Sstevel 	int	instance;
59003831d35Sstevel 	int	err;
59103831d35Sstevel 
59203831d35Sstevel 	switch (cmd) {
59303831d35Sstevel 	case DDI_DETACH:
59403831d35Sstevel 
59503831d35Sstevel 		instance = ddi_get_instance(dip);
59603831d35Sstevel 
59703831d35Sstevel 		softsp = ddi_get_soft_state(sgenv_statep, instance);
59803831d35Sstevel 		if (softsp == NULL) {
59903831d35Sstevel 			cmn_err(CE_WARN, "detach: could not get state "
60019397407SSherry Moore 			    "structure for inst %d.", instance);
60103831d35Sstevel 			return (DDI_FAILURE);
60203831d35Sstevel 		}
60303831d35Sstevel 
60403831d35Sstevel 		err = sgenv_remove_cache_update_threads();
60503831d35Sstevel 		if (err != DDI_SUCCESS) {
60603831d35Sstevel 			cmn_err(CE_WARN, "Failed to remove update threads");
60703831d35Sstevel 		}
60803831d35Sstevel 
60903831d35Sstevel 		/*
61003831d35Sstevel 		 * Remove the handlers which watch for unsolicited messages
61103831d35Sstevel 		 * and post event to Sysevent Framework.
61203831d35Sstevel 		 */
61303831d35Sstevel 		err = sgenv_remove_intr_handlers();
61403831d35Sstevel 		if (err != DDI_SUCCESS) {
61503831d35Sstevel 			cmn_err(CE_WARN, "Failed to remove event handlers");
61603831d35Sstevel 		}
61703831d35Sstevel 
61803831d35Sstevel 		sgenv_remove_kstats(softsp);
61903831d35Sstevel 
62003831d35Sstevel 		ddi_soft_state_free(sgenv_statep, instance);
62103831d35Sstevel 
62203831d35Sstevel 		ddi_remove_minor_node(dip, NULL);
62303831d35Sstevel 
62403831d35Sstevel 		return (DDI_SUCCESS);
62503831d35Sstevel 
62603831d35Sstevel 	case DDI_SUSPEND:
62703831d35Sstevel 		return (DDI_SUCCESS);
62803831d35Sstevel 
62903831d35Sstevel 	default:
63003831d35Sstevel 		return (DDI_FAILURE);
63103831d35Sstevel 	}
63203831d35Sstevel }
63303831d35Sstevel 
63403831d35Sstevel 
63503831d35Sstevel static int
sgenv_add_kstats(sgenv_soft_state_t * softsp)63603831d35Sstevel sgenv_add_kstats(sgenv_soft_state_t *softsp)
63703831d35Sstevel {
63803831d35Sstevel 	kstat_t		*ksp;
63903831d35Sstevel 	kstat_named_t	*keyswitch_named_data;
64003831d35Sstevel 
64103831d35Sstevel 	int		inst = softsp->instance;
64203831d35Sstevel 
64303831d35Sstevel 	/*
64403831d35Sstevel 	 * Create the 'keyswitch position' named kstat.
64503831d35Sstevel 	 */
64603831d35Sstevel 	ksp = kstat_create(SGENV_DRV_NAME, inst, SG_KEYSWITCH_KSTAT_NAME,
647*d1d6926fSToomas Soome 	    "misc", KSTAT_TYPE_NAMED, 1, 0);
64803831d35Sstevel 
64903831d35Sstevel 	if (ksp != NULL) {
65003831d35Sstevel 		/* initialize the named kstat */
65103831d35Sstevel 		keyswitch_named_data = (struct kstat_named *)(ksp->ks_data);
65203831d35Sstevel 
65303831d35Sstevel 		kstat_named_init(&keyswitch_named_data[0],
65419397407SSherry Moore 		    POSITION_KSTAT_NAME,
65519397407SSherry Moore 		    KSTAT_DATA_INT32);
65603831d35Sstevel 
65703831d35Sstevel 		ksp->ks_update = sgenv_keyswitch_kstat_update;
65803831d35Sstevel 		kstat_install(ksp);
65903831d35Sstevel 
66003831d35Sstevel 		/* update the soft state */
66103831d35Sstevel 		softsp->keyswitch_ksp = ksp;
66203831d35Sstevel 
66303831d35Sstevel 	} else {
66403831d35Sstevel 		cmn_err(CE_WARN, "Keyswitch: kstat_create failed");
66503831d35Sstevel 		return (-1);
66603831d35Sstevel 	}
66703831d35Sstevel 
66803831d35Sstevel 
66903831d35Sstevel 	/*
67003831d35Sstevel 	 * Environmental Information.
67103831d35Sstevel 	 */
67203831d35Sstevel 	ksp = kstat_create(SGENV_DRV_NAME, inst, SG_ENV_INFO_KSTAT_NAME,
67319397407SSherry Moore 	    "misc", KSTAT_TYPE_RAW, 0,
67419397407SSherry Moore 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE);
67503831d35Sstevel 
67603831d35Sstevel 	if (ksp != NULL) {
67703831d35Sstevel 		ksp->ks_data = NULL;
67803831d35Sstevel 		ksp->ks_data_size = 0;
67903831d35Sstevel 		ksp->ks_snaptime = 0;
68003831d35Sstevel 		ksp->ks_update = sgenv_env_info_kstat_update;
68103831d35Sstevel 		ksp->ks_snapshot = sgenv_env_info_kstat_snapshot;
68203831d35Sstevel 		ksp->ks_lock = &env_kstat_lock;
68303831d35Sstevel 		kstat_install(ksp);
68403831d35Sstevel 
68503831d35Sstevel 		/* update the soft state */
68603831d35Sstevel 		softsp->env_info_ksp = ksp;
68703831d35Sstevel 
68803831d35Sstevel 	} else {
68903831d35Sstevel 		cmn_err(CE_WARN, "Environmental Info: kstat_create failed");
69003831d35Sstevel 		return (-1);
69103831d35Sstevel 	}
69203831d35Sstevel 
69303831d35Sstevel 
69403831d35Sstevel 	/*
69503831d35Sstevel 	 * Board Status Information.
69603831d35Sstevel 	 */
69703831d35Sstevel 	ksp = kstat_create(SGENV_DRV_NAME, inst, SG_BOARD_STATUS_KSTAT_NAME,
69819397407SSherry Moore 	    "misc", KSTAT_TYPE_RAW, 0,
69919397407SSherry Moore 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE);
70003831d35Sstevel 
70103831d35Sstevel 	if (ksp != NULL) {
70203831d35Sstevel 		ksp->ks_data = NULL;
70303831d35Sstevel 		ksp->ks_data_size = 0;
70403831d35Sstevel 		ksp->ks_snaptime = 0;
70503831d35Sstevel 		ksp->ks_update = sgenv_board_info_kstat_update;
70603831d35Sstevel 		ksp->ks_snapshot = sgenv_board_info_kstat_snapshot;
70703831d35Sstevel 		ksp->ks_lock = &board_kstat_lock;
70803831d35Sstevel 		kstat_install(ksp);
70903831d35Sstevel 
71003831d35Sstevel 		/* update the soft state */
71103831d35Sstevel 		softsp->board_info_ksp = ksp;
71203831d35Sstevel 
71303831d35Sstevel 	} else {
71403831d35Sstevel 		cmn_err(CE_WARN, "Board Status Info: kstat_create failed");
71503831d35Sstevel 		return (-1);
71603831d35Sstevel 	}
71703831d35Sstevel 
71803831d35Sstevel 	return (0);
71903831d35Sstevel }
72003831d35Sstevel 
72103831d35Sstevel 
72203831d35Sstevel static void
sgenv_remove_kstats(sgenv_soft_state_t * softsp)72303831d35Sstevel sgenv_remove_kstats(sgenv_soft_state_t *softsp)
72403831d35Sstevel {
72503831d35Sstevel 	kstat_t	*ksp;
72603831d35Sstevel 
72703831d35Sstevel 	ksp = softsp->keyswitch_ksp;
72803831d35Sstevel 	if (ksp != NULL) {
72903831d35Sstevel 		softsp->keyswitch_ksp = NULL;
73003831d35Sstevel 		kstat_delete(ksp);
73103831d35Sstevel 	}
73203831d35Sstevel 
73303831d35Sstevel 	ksp = softsp->env_info_ksp;
73403831d35Sstevel 	if (ksp != NULL) {
73503831d35Sstevel 		sgenv_destroy_env_cache();
73603831d35Sstevel 		softsp->env_info_ksp = NULL;
73703831d35Sstevel 		ksp->ks_lock = NULL;
73803831d35Sstevel 		kstat_delete(ksp);
73903831d35Sstevel 	}
74003831d35Sstevel 
74103831d35Sstevel 	ksp = softsp->board_info_ksp;
74203831d35Sstevel 	if (ksp != NULL) {
74303831d35Sstevel 		softsp->board_info_ksp = NULL;
74403831d35Sstevel 		ksp->ks_lock = NULL;
74503831d35Sstevel 		kstat_delete(ksp);
74603831d35Sstevel 	}
74703831d35Sstevel }
74803831d35Sstevel 
74903831d35Sstevel 
75003831d35Sstevel /*
75103831d35Sstevel  * This function registers mailbox interrupt handlers to watch for certain
75203831d35Sstevel  * unsolicited mailbox messages, which indicate that some event has occurred.
75303831d35Sstevel  *
75403831d35Sstevel  * Currently only the following events are handled:
75503831d35Sstevel  *	MBOX_EVENT_KEY_SWITCH
75603831d35Sstevel  *	MBOX_EVENT_ENV
75703831d35Sstevel  *		- Thresholds/Limits Exceeded
75803831d35Sstevel  *		- Fan Status changed
75903831d35Sstevel  *
76003831d35Sstevel  * ERRORS:
76103831d35Sstevel  *	We return DDI_FAILURE if we fail to register any one of the
76203831d35Sstevel  *	interrupt handlers.
76303831d35Sstevel  */
76403831d35Sstevel static int
sgenv_add_intr_handlers(void)76503831d35Sstevel sgenv_add_intr_handlers(void)
76603831d35Sstevel {
76703831d35Sstevel 	int	err;
76803831d35Sstevel 
76903831d35Sstevel 	/*
77003831d35Sstevel 	 * Register an interrupt handler with the sgsbbc driver for the
77103831d35Sstevel 	 * MBOX_EVENT_KEY_SWITCH events.
77203831d35Sstevel 	 *	- The virtual keyswitch has changed, we generate a sysevent.
77303831d35Sstevel 	 */
77403831d35Sstevel 	keysw_payload_msg.msg_buf = (caddr_t)&keysw_payload;
77503831d35Sstevel 	keysw_payload_msg.msg_len = sizeof (keysw_payload);
77603831d35Sstevel 
77703831d35Sstevel 	err = sbbc_mbox_reg_intr(MBOX_EVENT_KEY_SWITCH, sgenv_keyswitch_handler,
77819397407SSherry Moore 	    &keysw_payload_msg, NULL, &keysw_hdlr_lock);
77903831d35Sstevel 	if (err != 0) {
78003831d35Sstevel 		cmn_err(CE_WARN, "Failed to register MBOX_EVENT_KEY_SWITCH "
78119397407SSherry Moore 		    "handler. Err=%d", err);
78203831d35Sstevel 		return (DDI_FAILURE);
78303831d35Sstevel 	}
78403831d35Sstevel 
78503831d35Sstevel 	/*
78603831d35Sstevel 	 * Register an interrupt handler with the sgsbbc driver for the
78703831d35Sstevel 	 * MBOX_EVENT_ENV events.
78803831d35Sstevel 	 *	- Thresholds/Limits Exceeded, we generate a sysevent
78903831d35Sstevel 	 *	and we update our caches.
79003831d35Sstevel 	 */
79103831d35Sstevel 	env_payload_msg.msg_buf = (caddr_t)&env_payload;
79203831d35Sstevel 	env_payload_msg.msg_len = sizeof (env_payload);
79303831d35Sstevel 
79403831d35Sstevel 	err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, sgenv_env_data_handler,
79519397407SSherry Moore 	    &env_payload_msg, NULL, &env_hdlr_lock);
79603831d35Sstevel 	if (err != 0) {
79703831d35Sstevel 		cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV "
79819397407SSherry Moore 		    "(env) handler. Err=%d", err);
79903831d35Sstevel 		return (DDI_FAILURE);
80003831d35Sstevel 	}
80103831d35Sstevel 
80203831d35Sstevel 	/*
80303831d35Sstevel 	 * Register an interrupt handler with the sgsbbc driver for the
80403831d35Sstevel 	 * MBOX_EVENT_ENV events.
80503831d35Sstevel 	 *	- Fan Status changed, we generate a sysevent, and
80603831d35Sstevel 	 *	we update the env cache only.
80703831d35Sstevel 	 */
80803831d35Sstevel 	fan_payload_msg.msg_buf = (caddr_t)&fan_payload;
80903831d35Sstevel 	fan_payload_msg.msg_len = sizeof (fan_payload);
81003831d35Sstevel 
81103831d35Sstevel 	err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, sgenv_fan_status_handler,
81219397407SSherry Moore 	    &fan_payload_msg, NULL, &env_hdlr_lock);
81303831d35Sstevel 	if (err != 0) {
81403831d35Sstevel 		cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV (fan)"
81519397407SSherry Moore 		    "handler. Err=%d", err);
81603831d35Sstevel 		return (DDI_FAILURE);
81703831d35Sstevel 	}
81803831d35Sstevel 
81903831d35Sstevel 	/*
82003831d35Sstevel 	 * Register an interrupt handler with the sgsbbc driver for the
82103831d35Sstevel 	 * MBOX_EVENT_GENERIC events.
82203831d35Sstevel 	 *	- DR state change, we update our caches.
82303831d35Sstevel 	 */
82403831d35Sstevel 	dr_payload_msg.msg_buf = (caddr_t)&dr_payload;
82503831d35Sstevel 	dr_payload_msg.msg_len = sizeof (dr_payload);
82603831d35Sstevel 
82703831d35Sstevel 	err = sbbc_mbox_reg_intr(MBOX_EVENT_GENERIC, sgenv_dr_event_handler,
82819397407SSherry Moore 	    &dr_payload_msg, NULL, &dr_hdlr_lock);
82903831d35Sstevel 	if (err != 0) {
83003831d35Sstevel 		cmn_err(CE_WARN, "Failed to register MBOX_EVENT_GENERIC (DR)"
83119397407SSherry Moore 		    "handler. Err=%d", err);
83203831d35Sstevel 		return (DDI_FAILURE);
83303831d35Sstevel 	}
83403831d35Sstevel 
83503831d35Sstevel 	return (DDI_SUCCESS);
83603831d35Sstevel }
83703831d35Sstevel 
83803831d35Sstevel /*
83903831d35Sstevel  * This function unregisters the mailbox interrupt handlers.
84003831d35Sstevel  *
84103831d35Sstevel  * ERRORS:
84203831d35Sstevel  *	We return DDI_FAILURE if we fail to register any one of the
84303831d35Sstevel  *	interrupt handlers.
84403831d35Sstevel  */
84503831d35Sstevel static int
sgenv_remove_intr_handlers(void)84603831d35Sstevel sgenv_remove_intr_handlers(void)
84703831d35Sstevel {
84803831d35Sstevel 	int	rv = DDI_SUCCESS;
84903831d35Sstevel 	int	err;
85003831d35Sstevel 
85103831d35Sstevel 	err = sbbc_mbox_unreg_intr(MBOX_EVENT_KEY_SWITCH,
85219397407SSherry Moore 	    sgenv_keyswitch_handler);
85303831d35Sstevel 	if (err != 0) {
85403831d35Sstevel 		cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_KEY_SWITCH "
85519397407SSherry Moore 		    "handler. Err=%d", err);
85603831d35Sstevel 		rv = DDI_FAILURE;
85703831d35Sstevel 	}
85803831d35Sstevel 
85903831d35Sstevel 	err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, sgenv_env_data_handler);
86003831d35Sstevel 	if (err != 0) {
86103831d35Sstevel 		cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV (env)"
86219397407SSherry Moore 		    "handler. Err=%d", err);
86303831d35Sstevel 		rv = DDI_FAILURE;
86403831d35Sstevel 	}
86503831d35Sstevel 
86603831d35Sstevel 	err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, sgenv_fan_status_handler);
86703831d35Sstevel 	if (err != 0) {
86803831d35Sstevel 		cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV (fan)"
86919397407SSherry Moore 		    "handler. Err=%d", err);
87003831d35Sstevel 		rv = DDI_FAILURE;
87103831d35Sstevel 	}
87203831d35Sstevel 
87303831d35Sstevel 	err = sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, sgenv_dr_event_handler);
87403831d35Sstevel 	if (err != 0) {
87503831d35Sstevel 		cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_GENERIC (DR) "
87619397407SSherry Moore 		    "handler. Err=%d", err);
87703831d35Sstevel 		rv = DDI_FAILURE;
87803831d35Sstevel 	}
87903831d35Sstevel 
88003831d35Sstevel 	return (rv);
88103831d35Sstevel }
88203831d35Sstevel 
88303831d35Sstevel 
88403831d35Sstevel static int
sgenv_create_cache_update_threads(void)88503831d35Sstevel sgenv_create_cache_update_threads(void)
88603831d35Sstevel {
887a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_create_cache_update_threads()");
88803831d35Sstevel 
88903831d35Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "Entering %s", f);
89003831d35Sstevel 
89103831d35Sstevel 	/* Create thread to ensure env_cache is updated */
89203831d35Sstevel 	env_thread_run = 1;
89303831d35Sstevel 
89403831d35Sstevel 	env_thread = thread_create(NULL, 0, sgenv_update_env_cache,
89503831d35Sstevel 	    NULL, 0, &p0, TS_RUN, minclsyspri);
89603831d35Sstevel 	env_thread_tid = env_thread->t_did;
89703831d35Sstevel 
89803831d35Sstevel 	/* Create thread to ensure board_cache is updated */
89903831d35Sstevel 	board_thread_run = 1;
90003831d35Sstevel 
90103831d35Sstevel 	board_thread = thread_create(NULL, 0, sgenv_update_board_cache,
90203831d35Sstevel 	    NULL, 0, &p0, TS_RUN, minclsyspri);
90303831d35Sstevel 	board_thread_tid = board_thread->t_did;
90403831d35Sstevel 
90503831d35Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "Exiting %s", f);
90603831d35Sstevel 
90703831d35Sstevel 	return (DDI_SUCCESS);
90803831d35Sstevel }
90903831d35Sstevel 
91003831d35Sstevel 
91103831d35Sstevel static int
sgenv_remove_cache_update_threads(void)91203831d35Sstevel sgenv_remove_cache_update_threads(void)
91303831d35Sstevel {
914a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_remove_cache_update_threads()");
91503831d35Sstevel 
91603831d35Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "%s: Waiting for cache update threads", f);
91703831d35Sstevel 
91803831d35Sstevel 	/* Cause the env_cache thread to terminate. */
91903831d35Sstevel 	mutex_enter(&env_flag_lock);
92003831d35Sstevel 	env_thread_run = 0;
92103831d35Sstevel 	cv_signal(&env_flag_cond);
92203831d35Sstevel 	mutex_exit(&env_flag_lock);
92303831d35Sstevel 
92403831d35Sstevel 	thread_join(env_thread_tid);
92503831d35Sstevel 
92603831d35Sstevel 	/* Cause the board_cache thread to terminate. */
92703831d35Sstevel 	mutex_enter(&board_flag_lock);
92803831d35Sstevel 	board_thread_run = 0;
92903831d35Sstevel 	cv_signal(&board_flag_cond);
93003831d35Sstevel 	mutex_exit(&board_flag_lock);
93103831d35Sstevel 
93203831d35Sstevel 	thread_join(board_thread_tid);
93303831d35Sstevel 
93403831d35Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "%s: cache update threads finished", f);
93503831d35Sstevel 
93603831d35Sstevel 	return (DDI_SUCCESS);
93703831d35Sstevel }
93803831d35Sstevel 
93903831d35Sstevel 
94003831d35Sstevel static int
sgenv_keyswitch_kstat_update(kstat_t * ksp,int rw)94103831d35Sstevel sgenv_keyswitch_kstat_update(kstat_t *ksp, int rw)
94203831d35Sstevel {
94303831d35Sstevel 	sg_keyswitch_kstat_t	*keysw_data;
94403831d35Sstevel 
94503831d35Sstevel 	int8_t	posn;	/* keysw posn read from IO-SRAM */
94603831d35Sstevel 	int	size;	/* size of IO-SRAM chunk */
94703831d35Sstevel 	int	rv = 0;	/* return value of iosram_read() */
94803831d35Sstevel 
94903831d35Sstevel 	keysw_data	= (sg_keyswitch_kstat_t *)ksp->ks_data;
95003831d35Sstevel 
95103831d35Sstevel 	switch (rw) {
95203831d35Sstevel 	case KSTAT_WRITE:
95303831d35Sstevel 		/*
95403831d35Sstevel 		 * Write not permitted
95503831d35Sstevel 		 */
95603831d35Sstevel 		return (EACCES);
95703831d35Sstevel 
95803831d35Sstevel 	case KSTAT_READ:
95903831d35Sstevel 		/*
96003831d35Sstevel 		 * Get the size of the keyswitch IO-SRAM chunk.
96103831d35Sstevel 		 * This should be one byte.
96203831d35Sstevel 		 *
96303831d35Sstevel 		 * If the size is not 1 byte we set the position to UNKNOWN
96403831d35Sstevel 		 *
96503831d35Sstevel 		 * Otherwise we read the keyswitch position from IO-SRAM.
96603831d35Sstevel 		 * Then check that this is a valid keyswitch position.
96703831d35Sstevel 		 * If it is not valid then something is corrupt and set
96803831d35Sstevel 		 * the position to UNKNOWN.
96903831d35Sstevel 		 */
97003831d35Sstevel 		size = iosram_size(SBBC_KEYSWITCH_KEY);
97103831d35Sstevel 		if (size != 1) {
97203831d35Sstevel 			posn = SG_KEYSWITCH_POSN_UNKNOWN;
97303831d35Sstevel 			rv = -1;
97403831d35Sstevel 
97503831d35Sstevel 		} else if ((rv = iosram_read(SBBC_KEYSWITCH_KEY, 0,
97619397407SSherry Moore 		    (char *)&posn, size)) != 0) {
97703831d35Sstevel 			posn = SG_KEYSWITCH_POSN_UNKNOWN;
97803831d35Sstevel 
97903831d35Sstevel 		} else {
98003831d35Sstevel 			/* Check posn is not corrupt */
98103831d35Sstevel 			switch (posn) {
98203831d35Sstevel 				case SG_KEYSWITCH_POSN_ON:
98303831d35Sstevel 				case SG_KEYSWITCH_POSN_DIAG:
98403831d35Sstevel 				case SG_KEYSWITCH_POSN_SECURE:
98503831d35Sstevel 					/* value read from kstat is OK */
98603831d35Sstevel 					break;
98703831d35Sstevel 
98803831d35Sstevel 				default:
98903831d35Sstevel 					/* value read from kstat is corrupt */
99003831d35Sstevel 					posn = SG_KEYSWITCH_POSN_UNKNOWN;
99103831d35Sstevel 					break;
99203831d35Sstevel 			}
99303831d35Sstevel 		}
99403831d35Sstevel 
99503831d35Sstevel 		/* Write position to kstat. */
99603831d35Sstevel 		keysw_data->keyswitch_position.value.i32 = posn;
99703831d35Sstevel 
99803831d35Sstevel 		return (rv);
99903831d35Sstevel 
100003831d35Sstevel 	default:
100103831d35Sstevel 		return (EINVAL);
100203831d35Sstevel 	}
100303831d35Sstevel }
100403831d35Sstevel 
100503831d35Sstevel static void
sgenv_init_env_cache(void)100603831d35Sstevel sgenv_init_env_cache(void)
100703831d35Sstevel {
100803831d35Sstevel 	ASSERT(env_thread_run == 0);
100903831d35Sstevel 	ASSERT(env_thread == NULL);
101003831d35Sstevel }
101103831d35Sstevel 
101203831d35Sstevel 
101303831d35Sstevel /*
101403831d35Sstevel  * This thread runs in the background and waits for an interrupt handler
101503831d35Sstevel  * registered to wait for ENV/DR events from the SC to signal/flag that we
101603831d35Sstevel  * need to update our Env Cache.
101703831d35Sstevel  */
101803831d35Sstevel static void
sgenv_update_env_cache(void)101903831d35Sstevel sgenv_update_env_cache(void)
102003831d35Sstevel {
1021a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_update_env_cache()");
102203831d35Sstevel 
102303831d35Sstevel 	mutex_enter(&env_flag_lock);
102403831d35Sstevel 
102503831d35Sstevel 	while (env_thread_run == 1) {
102603831d35Sstevel 
102703831d35Sstevel 		/*
102803831d35Sstevel 		 * We check to see if the update needed flag is set.
102903831d35Sstevel 		 * If it is then this means that:
103003831d35Sstevel 		 *	1) This is the first time through the while loop
103103831d35Sstevel 		 *	   and we need to initialize the cache.
103203831d35Sstevel 		 *	2) An interrupt handler was triggered while we
103303831d35Sstevel 		 *	   we were updating the env cache during the previous
103403831d35Sstevel 		 *	   iteration of the while loop and we need to refresh
103503831d35Sstevel 		 *	   the env data to ensure we are completely up to date.
103603831d35Sstevel 		 *
103703831d35Sstevel 		 * Otherwise we wait until we get a signal from one of the
103803831d35Sstevel 		 * interrupt handlers.
103903831d35Sstevel 		 */
104003831d35Sstevel 		if (env_cache_update_needed) {
104103831d35Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: update needed", f);
104203831d35Sstevel 
104303831d35Sstevel 			env_cache_update_needed = B_FALSE;
104403831d35Sstevel 
104503831d35Sstevel 		} else {
104603831d35Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Waiting for signal", f);
104703831d35Sstevel 
104803831d35Sstevel 			cv_wait(&env_flag_cond, &env_flag_lock);
104903831d35Sstevel 
105003831d35Sstevel 			/* Check if we are being asked to terminate */
105103831d35Sstevel 			if (env_thread_run == 0) {
105203831d35Sstevel 				break;
105303831d35Sstevel 			}
105403831d35Sstevel 
105503831d35Sstevel 			env_cache_updating = B_TRUE;
105603831d35Sstevel 		}
105703831d35Sstevel 
105803831d35Sstevel 		mutex_exit(&env_flag_lock);
105907d06da5SSurya Prakki 		(void) sgenv_get_env_info_data();
106003831d35Sstevel 
106107d06da5SSurya Prakki 		(void) sgenv_check_sensor_thresholds();
106203831d35Sstevel 		mutex_enter(&env_flag_lock);
106303831d35Sstevel 
106403831d35Sstevel 		if (env_cache_update_needed == B_FALSE)
106503831d35Sstevel 			env_cache_updating = B_FALSE;
106603831d35Sstevel 	}
106703831d35Sstevel 
106803831d35Sstevel 	mutex_exit(&env_flag_lock);
106903831d35Sstevel 
107003831d35Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "Exiting %s", f);
107103831d35Sstevel 
107203831d35Sstevel 	env_thread_run = -1;
107303831d35Sstevel 	thread_exit();
107403831d35Sstevel }
107503831d35Sstevel 
107603831d35Sstevel 
107703831d35Sstevel /*
107803831d35Sstevel  * We always return what is in the env_cache. It is up to the SC to ensure
107903831d35Sstevel  * that the env_cache is current by sending events to us when something
108003831d35Sstevel  * changes. The cache will then be updated by going to the SC to get the
108103831d35Sstevel  * new data. That way the kstat_update code can always be sure that it gets
108203831d35Sstevel  * current data without having to wait while the SC responds (slowly) to our
108303831d35Sstevel  * request for data.
108403831d35Sstevel  *
108503831d35Sstevel  * The way the update and snapshot code works, we cannot be guaranteed that
108603831d35Sstevel  * someone won't grab the env_cache_lock between the update and snapshot
108703831d35Sstevel  * calls so we use a temporary snapshot of the env_cache. We cannot hold
108803831d35Sstevel  * any locks across the calls from the update to the snapshot as we are
108903831d35Sstevel  * not guaranteed that the snapshot function will be called. So we create
109003831d35Sstevel  * the snapshot of the env_cache in the update routine and dump this to the
109103831d35Sstevel  * kstat user buffer in the snapshot routine. (There are error conditions in
109203831d35Sstevel  * which the snapshot will not be called by the kstat framework so we need
109303831d35Sstevel  * to handle these appropriately.)
109403831d35Sstevel  */
109503831d35Sstevel static int
sgenv_env_info_kstat_update(kstat_t * ksp,int rw)109603831d35Sstevel sgenv_env_info_kstat_update(kstat_t *ksp, int rw)
109703831d35Sstevel {
1098a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_env_info_kstat_update()");
109903831d35Sstevel 
110003831d35Sstevel 	int		err = 0;
110103831d35Sstevel 	int		key_posn;
110203831d35Sstevel 	env_sensor_t	*ptr;
110303831d35Sstevel 
110403831d35Sstevel 	switch (rw) {
110503831d35Sstevel 	case KSTAT_WRITE:
110603831d35Sstevel 		/*
110703831d35Sstevel 		 * Write not permitted
110803831d35Sstevel 		 */
110903831d35Sstevel 		return (EACCES);
111003831d35Sstevel 
111103831d35Sstevel 	case KSTAT_READ:
111203831d35Sstevel 
111303831d35Sstevel 		mutex_enter(&env_cache_lock);
111403831d35Sstevel 		/*
111503831d35Sstevel 		 * We now need to ensure that there is enough room allocated
111603831d35Sstevel 		 * by the kstat framework to return the data via ks_data.
111703831d35Sstevel 		 * It is possible there may be no data in the cache but
111803831d35Sstevel 		 * we still return zero sized kstats to ensure no client breaks
111903831d35Sstevel 		 */
112003831d35Sstevel 		sgenv_update_env_kstat_size(ksp);
112103831d35Sstevel 
112203831d35Sstevel 		/*
112303831d35Sstevel 		 * If the snapshot still has data (this could be because the
112403831d35Sstevel 		 * kstat framework discovered an error and did not call the
112503831d35Sstevel 		 * snapshot code which should have freed this buffer) we free
112603831d35Sstevel 		 * it here.
112703831d35Sstevel 		 */
112803831d35Sstevel 		if ((env_cache_snapshot != NULL) &&
112919397407SSherry Moore 		    (env_cache_snapshot_size > 0)) {
113003831d35Sstevel 			DCMN_ERR_CACHE(CE_NOTE, "%s freeing "
113119397407SSherry Moore 			    "env_cache_snapshot buf", f);
113203831d35Sstevel 			kmem_free(env_cache_snapshot, env_cache_snapshot_size);
113303831d35Sstevel 		}
113403831d35Sstevel 
113503831d35Sstevel 		/*
113603831d35Sstevel 		 * Create a new snapshot buffer based on ks_data_size
113703831d35Sstevel 		 */
113803831d35Sstevel 		env_cache_snapshot_size = ksp->ks_data_size;
113903831d35Sstevel 		env_cache_snapshot = kmem_zalloc(
114019397407SSherry Moore 		    env_cache_snapshot_size, KM_SLEEP);
114103831d35Sstevel 
114203831d35Sstevel 		/*
114303831d35Sstevel 		 * We need to take a fresh snapshot of the env_cache here.
114403831d35Sstevel 		 * For each sensor collection, we check to see if there is
114503831d35Sstevel 		 * data in the cache (ie. != NULL). If there is, we copy it
114603831d35Sstevel 		 * into the snapshot.
114703831d35Sstevel 		 */
114803831d35Sstevel 		ptr = env_cache_snapshot;
114903831d35Sstevel 		for (key_posn = 0; key_posn < SGENV_MAX_HPU_KEYS; key_posn++) {
115003831d35Sstevel 			if (vol_sensor_count[key_posn] <= 0)
115103831d35Sstevel 				continue;
115203831d35Sstevel 
115303831d35Sstevel 			ASSERT(vol_sensor_count[key_posn] <=
115419397407SSherry Moore 			    SGENV_MAX_SENSORS_PER_KEY);
115503831d35Sstevel 
115603831d35Sstevel 			/*
115703831d35Sstevel 			 * <env_cache> entry should have been allocated
115803831d35Sstevel 			 * in the kstat_update function already.
115903831d35Sstevel 			 *
116003831d35Sstevel 			 * If this <env_cache> entry is NULL, then
116103831d35Sstevel 			 * it has already been destroyed or cleared
116203831d35Sstevel 			 * and the sensor readings have disappeared.
116303831d35Sstevel 			 */
116403831d35Sstevel 			if (env_cache[key_posn] == NULL) {
116503831d35Sstevel 				DCMN_ERR(CE_NOTE, "!Cache entry %d has "
116619397407SSherry Moore 				    "disappeared", key_posn);
116703831d35Sstevel 				vol_sensor_count[key_posn] = 0;
116803831d35Sstevel 				continue;
116903831d35Sstevel 			}
117003831d35Sstevel 
117103831d35Sstevel 			bcopy(&env_cache[key_posn][0], ptr,
117203831d35Sstevel 			    sizeof (env_sensor_t) *
117303831d35Sstevel 			    vol_sensor_count[key_posn]);
117403831d35Sstevel 			ptr += vol_sensor_count[key_posn];
117503831d35Sstevel 		}
117603831d35Sstevel 		mutex_exit(&env_cache_lock);
117703831d35Sstevel 
117803831d35Sstevel 		return (err);
117903831d35Sstevel 
118003831d35Sstevel 	default:
118103831d35Sstevel 		return (EINVAL);
118203831d35Sstevel 	}
118303831d35Sstevel }
118403831d35Sstevel 
118503831d35Sstevel static int
sgenv_env_info_kstat_snapshot(kstat_t * ksp,void * buf,int rw)118603831d35Sstevel sgenv_env_info_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
118703831d35Sstevel {
1188a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_env_info_kstat_snapshot()");
118903831d35Sstevel 
119003831d35Sstevel 	switch (rw) {
119103831d35Sstevel 	case KSTAT_WRITE:
119203831d35Sstevel 		/*
119303831d35Sstevel 		 * Write not permitted
119403831d35Sstevel 		 */
119503831d35Sstevel 		return (EACCES);
119603831d35Sstevel 
119703831d35Sstevel 	case KSTAT_READ:
119803831d35Sstevel 
119903831d35Sstevel 		/*
120003831d35Sstevel 		 * We have taken a snapshot of the env_cache in the
120103831d35Sstevel 		 * update routine so we simply bcopy this into the
120203831d35Sstevel 		 * kstat buf. No locks needed here.
120303831d35Sstevel 		 */
120403831d35Sstevel 		if (env_cache_snapshot_size > 0)
120503831d35Sstevel 			bcopy(env_cache_snapshot, buf, env_cache_snapshot_size);
120603831d35Sstevel 
120703831d35Sstevel 		ksp->ks_snaptime = last_env_read_time;
120803831d35Sstevel 
120903831d35Sstevel 		/*
121003831d35Sstevel 		 * Free the memory used by the snapshot. If for some reason
121103831d35Sstevel 		 * the kstat framework does not call this snapshot routine,
121203831d35Sstevel 		 * we also have a check in the update routine so the next
121303831d35Sstevel 		 * time it is called it checks for this condition and frees
121403831d35Sstevel 		 * the snapshot buffer there.
121503831d35Sstevel 		 */
121603831d35Sstevel 		DCMN_ERR_CACHE(CE_NOTE, "%s freeing env_cache_snapshot buf", f);
121703831d35Sstevel 		kmem_free(env_cache_snapshot, env_cache_snapshot_size);
121803831d35Sstevel 		env_cache_snapshot = NULL;
121903831d35Sstevel 		env_cache_snapshot_size = 0;
122003831d35Sstevel 
122103831d35Sstevel 		return (0);
122203831d35Sstevel 
122303831d35Sstevel 	default:
122403831d35Sstevel 		return (EINVAL);
122503831d35Sstevel 	}
122603831d35Sstevel }
122703831d35Sstevel 
122803831d35Sstevel static void
sgenv_init_board_cache(void)122903831d35Sstevel sgenv_init_board_cache(void)
123003831d35Sstevel {
123103831d35Sstevel 	int	i;
123203831d35Sstevel 
123303831d35Sstevel 	ASSERT(board_thread_run == 0);
123403831d35Sstevel 	ASSERT(board_thread == NULL);
123503831d35Sstevel 
123603831d35Sstevel 	/*
123703831d35Sstevel 	 * Init all node-ids to be -1.
123803831d35Sstevel 	 */
123903831d35Sstevel 	mutex_enter(&board_cache_lock);
124003831d35Sstevel 	for (i = 0; i < SG_MAX_BDS; i++)
124103831d35Sstevel 		board_cache[i].node_id = (-1);
124203831d35Sstevel 	mutex_exit(&board_cache_lock);
124303831d35Sstevel }
124403831d35Sstevel 
124503831d35Sstevel 
124603831d35Sstevel /*
124703831d35Sstevel  * This thread runs in the background and waits for an interrupt handler
124803831d35Sstevel  * registered to wait for DR events from the SC to signal/flag that we
124903831d35Sstevel  * need to update our Board Cache.
125003831d35Sstevel  */
125103831d35Sstevel static void
sgenv_update_board_cache(void)125203831d35Sstevel sgenv_update_board_cache(void)
125303831d35Sstevel {
1254a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_update_board_cache()");
125503831d35Sstevel 
125603831d35Sstevel 	mutex_enter(&board_flag_lock);
125703831d35Sstevel 
125803831d35Sstevel 	while (board_thread_run == 1) {
125903831d35Sstevel 
126003831d35Sstevel 		/*
126103831d35Sstevel 		 * We check to see if the update needed flag is set.
126203831d35Sstevel 		 * If it is then this means that:
126303831d35Sstevel 		 *	1) This is the first time through the while loop
126403831d35Sstevel 		 *	   and we need to initialize the cache.
126503831d35Sstevel 		 *	2) An interrupt handler was triggered while we
126603831d35Sstevel 		 *	   we were updating the cache during the previous
126703831d35Sstevel 		 *	   iteration of the while loop and we need to refresh
126803831d35Sstevel 		 *	   the env data to ensure we are completely up to date.
126903831d35Sstevel 		 *
127003831d35Sstevel 		 * Otherwise we wait until we get a signal from one of the
127103831d35Sstevel 		 * interrupt handlers.
127203831d35Sstevel 		 */
127303831d35Sstevel 		if (board_cache_update_needed) {
127403831d35Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: update needed", f);
127503831d35Sstevel 			board_cache_update_needed = B_FALSE;
127603831d35Sstevel 
127703831d35Sstevel 		} else {
127803831d35Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Waiting for signal", f);
127903831d35Sstevel 
128003831d35Sstevel 			cv_wait(&board_flag_cond, &board_flag_lock);
128103831d35Sstevel 
128203831d35Sstevel 			/* Check if we are being asked to terminate */
128303831d35Sstevel 			if (board_thread_run == 0) {
128403831d35Sstevel 				break;
128503831d35Sstevel 			}
128603831d35Sstevel 
128703831d35Sstevel 			board_cache_updating = B_TRUE;
128803831d35Sstevel 		}
128903831d35Sstevel 
129003831d35Sstevel 		mutex_exit(&board_flag_lock);
129107d06da5SSurya Prakki 		(void) sgenv_get_board_info_data();
129203831d35Sstevel 		mutex_enter(&board_flag_lock);
129303831d35Sstevel 
129403831d35Sstevel 		if (board_cache_update_needed == B_FALSE)
129503831d35Sstevel 			board_cache_updating = B_FALSE;
129603831d35Sstevel 	}
129703831d35Sstevel 
129803831d35Sstevel 	mutex_exit(&board_flag_lock);
129903831d35Sstevel 
130003831d35Sstevel 	DCMN_ERR_THREAD(CE_NOTE, "Exiting %s", f);
130103831d35Sstevel 
130203831d35Sstevel 	board_thread_run = -1;
130303831d35Sstevel 	thread_exit();
130403831d35Sstevel }
130503831d35Sstevel 
130603831d35Sstevel 
130703831d35Sstevel /*
130803831d35Sstevel  * We always return what is in the board_cache. It is up to the SC to ensure
130903831d35Sstevel  * that the board_cache is current by sending events to us when something
131003831d35Sstevel  * changes. The cache will then be updated by going to the SC to get the
131103831d35Sstevel  * new data. That way the kstat_update code can always be sure that it gets
131203831d35Sstevel  * current data without having to wait while the SC responds (slowly) to our
131303831d35Sstevel  * request for data.
131403831d35Sstevel  *
131503831d35Sstevel  * The way the update and snapshot code works, we cannot be guaranteed that
131603831d35Sstevel  * someone won't grab the board_cache_lock between the update and snapshot
131703831d35Sstevel  * calls so we use a snapshot buffer of the board_cache. We cannot hold
131803831d35Sstevel  * any locks across the calls from the update to the snapshot as we are
131903831d35Sstevel  * not guaranteed that the snapshot function will be called. So we create
132003831d35Sstevel  * the snapshot of the board_cache in the update routine and dump this to the
132103831d35Sstevel  * kstat user buffer in the snapshot routine. (There are error conditions in
132203831d35Sstevel  * which the snapshot will not be called by the kstat framework so we need
132303831d35Sstevel  * to handle these appropriately.)
132403831d35Sstevel  */
132503831d35Sstevel static int
sgenv_board_info_kstat_update(kstat_t * ksp,int rw)132603831d35Sstevel sgenv_board_info_kstat_update(kstat_t *ksp, int rw)
132703831d35Sstevel {
132803831d35Sstevel 	int		i;
132903831d35Sstevel 
133003831d35Sstevel 	switch (rw) {
133103831d35Sstevel 	case KSTAT_WRITE:
133203831d35Sstevel 		/*
133303831d35Sstevel 		 * Write not permitted
133403831d35Sstevel 		 */
133503831d35Sstevel 		return (EACCES);
133603831d35Sstevel 
133703831d35Sstevel 	case KSTAT_READ:
133803831d35Sstevel 		/*
133903831d35Sstevel 		 * The board_cache is created during startup, and so should be
134003831d35Sstevel 		 * available before a user can log in and trigger a kstat read,
134103831d35Sstevel 		 * but we check just in case.
134203831d35Sstevel 		 */
134303831d35Sstevel 		if (board_cache_updated == FALSE)
134403831d35Sstevel 			return (ENXIO);
134503831d35Sstevel 
134603831d35Sstevel 		mutex_enter(&board_cache_lock);
134703831d35Sstevel 
134803831d35Sstevel 		/*
134903831d35Sstevel 		 * Set <ks_data_size> to the new number of board readings so
135003831d35Sstevel 		 * that the snapshot routine can allocate the correctly sized
135103831d35Sstevel 		 * kstat.
135203831d35Sstevel 		 */
135303831d35Sstevel 		ksp->ks_data_size = board_count * sizeof (sg_board_info_t);
135403831d35Sstevel 
135503831d35Sstevel 		board_count_snapshot = board_count;
135603831d35Sstevel 
135703831d35Sstevel 		/*
135803831d35Sstevel 		 * We are now guaranteed that that board_cache is not in flux
135903831d35Sstevel 		 * (as we have the lock) so we take a copy of the board_cache
136003831d35Sstevel 		 * into the board_cache_snapshot so that the snapshot routine
136103831d35Sstevel 		 * can copy it from the board_cache_snapshot into the user kstat
136203831d35Sstevel 		 * buffer.
136303831d35Sstevel 		 */
136403831d35Sstevel 		for (i = 0; i < SG_MAX_BDS; i++) {
136503831d35Sstevel 			board_cache_snapshot[i] = board_cache[i];
136603831d35Sstevel 		}
136703831d35Sstevel 
136803831d35Sstevel 		mutex_exit(&board_cache_lock);
136903831d35Sstevel 
137003831d35Sstevel 		return (0);
137103831d35Sstevel 
137203831d35Sstevel 	default:
137303831d35Sstevel 		return (EINVAL);
137403831d35Sstevel 	}
137503831d35Sstevel }
137603831d35Sstevel 
137703831d35Sstevel static int
sgenv_board_info_kstat_snapshot(kstat_t * ksp,void * buf,int rw)137803831d35Sstevel sgenv_board_info_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
137903831d35Sstevel {
1380a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_board_info_kstat_snapshot()");
138103831d35Sstevel 
138203831d35Sstevel 	sg_board_info_t	*bdp;
138303831d35Sstevel 	int		i, num_bds = 0;
138403831d35Sstevel 
138503831d35Sstevel 	switch (rw) {
138603831d35Sstevel 	case KSTAT_WRITE:
138703831d35Sstevel 		/*
138803831d35Sstevel 		 * Write not permitted
138903831d35Sstevel 		 */
139003831d35Sstevel 		return (EACCES);
139103831d35Sstevel 
139203831d35Sstevel 	case KSTAT_READ:
139303831d35Sstevel 
139403831d35Sstevel 		if (board_cache_updated == FALSE) {
139503831d35Sstevel 			ksp->ks_data_size = 0;
139603831d35Sstevel 			ksp->ks_data = NULL;
139703831d35Sstevel 			return (ENOMEM);
139803831d35Sstevel 		}
139903831d35Sstevel 
140003831d35Sstevel 		/*
140103831d35Sstevel 		 * Update the snap_time with the last time we got fresh data
140203831d35Sstevel 		 * from the SC.
140303831d35Sstevel 		 */
140403831d35Sstevel 		ksp->ks_snaptime = last_board_read_time;
140503831d35Sstevel 
140603831d35Sstevel 		ASSERT(board_count_snapshot <= SG_MAX_BDS);
140703831d35Sstevel 		/*
140803831d35Sstevel 		 * For each entry in the board_cache_snapshot we check to see
140903831d35Sstevel 		 * if the node_id is != NULL before we copy it into
141003831d35Sstevel 		 * the kstat buf.
141103831d35Sstevel 		 */
141203831d35Sstevel 		for (i = 0; i < SG_MAX_BDS; i++) {
141303831d35Sstevel 			bdp = &board_cache_snapshot[i];
141403831d35Sstevel 			DCMN_ERR_CACHE(CE_NOTE, "%s: looking at "
141519397407SSherry Moore 			    "cache_snapshot entry[%d], node=%d",
141619397407SSherry Moore 			    f, i, bdp->node_id);
141703831d35Sstevel 			if (bdp->node_id >= 0) {
141803831d35Sstevel 				/*
141903831d35Sstevel 				 * Need a check to ensure that the buf
142003831d35Sstevel 				 * is still within the allocated size.
142103831d35Sstevel 				 * We check how many boards are already
142203831d35Sstevel 				 * in the user buf before adding one.
142303831d35Sstevel 				 */
142403831d35Sstevel 				num_bds++;
142503831d35Sstevel 				if (num_bds > board_count_snapshot) {
142603831d35Sstevel 					ksp->ks_data_size = 0;
142703831d35Sstevel 					ksp->ks_data = NULL;
142803831d35Sstevel 					DCMN_ERR(CE_WARN, "%s: buf overflow."
142903831d35Sstevel 					    " %d >= %d.",
143003831d35Sstevel 					    f, num_bds, board_count_snapshot);
143103831d35Sstevel 					return (EIO);
143203831d35Sstevel 				}
143303831d35Sstevel 
143403831d35Sstevel 				DCMN_ERR_CACHE(CE_NOTE, "%s: about to bcopy"
143519397407SSherry Moore 				    " cache_snapshot entry[%d], node=%d,"
143619397407SSherry Moore 				    " board=%d", f, i, bdp->node_id,
143719397407SSherry Moore 				    bdp->board_num);
143803831d35Sstevel 				bcopy(bdp, buf, sizeof (sg_board_info_t));
143903831d35Sstevel 				buf = ((sg_board_info_t *)buf) + 1;
144003831d35Sstevel 			}
144103831d35Sstevel 		}
144203831d35Sstevel 		return (0);
144303831d35Sstevel 
144403831d35Sstevel 	default:
144503831d35Sstevel 		return (EINVAL);
144603831d35Sstevel 	}
144703831d35Sstevel }
144803831d35Sstevel 
144903831d35Sstevel 
145003831d35Sstevel /*
145103831d35Sstevel  * This function coordinates reading the env data from the SC.
145203831d35Sstevel  *
145303831d35Sstevel  * ERROR:
1454*d1d6926fSToomas Soome  *	If an error occurs while making a call to the mailbox and we have data
145503831d35Sstevel  *	in the cache from a previous call to the SC, we return an error of 0.
145603831d35Sstevel  *	That way the kstat framework will return the old data instead of
145703831d35Sstevel  *	returning an error and an empty kstat.
145803831d35Sstevel  */
145903831d35Sstevel static int
sgenv_get_env_info_data(void)146003831d35Sstevel sgenv_get_env_info_data(void)
146103831d35Sstevel {
1462a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_get_env_info_data()");
146303831d35Sstevel 
146403831d35Sstevel 	envresp_key_t	new_keys[SGENV_MAX_HPU_KEYS] = {0};
146503831d35Sstevel 	envresp_key_t	old_key;
146603831d35Sstevel 	envresp_key_t	key;
146703831d35Sstevel 
146803831d35Sstevel 	int	i;
146903831d35Sstevel 
147003831d35Sstevel 	int	err = 0;	/* return value of func's which get env data */
147103831d35Sstevel 	int	status = 0;	/* reason why env data func returned an error */
147203831d35Sstevel 
147303831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: entered.", f);
147403831d35Sstevel 
147503831d35Sstevel 	err = sgenv_get_hpu_keys(new_keys, &status);
147603831d35Sstevel 
147703831d35Sstevel 	if (err != 0) {
147803831d35Sstevel 		/*
147903831d35Sstevel 		 * If we get an error getting the key values, then we return
148003831d35Sstevel 		 * as we cannot proceed any farther. If there is old env data
148103831d35Sstevel 		 * in the cache, then we return zero so that the kstat
148203831d35Sstevel 		 * framework will export the old data.
148303831d35Sstevel 		 */
148403831d35Sstevel 		if (env_cache_updated == FALSE) {
148503831d35Sstevel 			sgenv_mbox_error_msg("HPU Keys", err, status);
148603831d35Sstevel 			return (err);
148703831d35Sstevel 		} else {
148803831d35Sstevel 			sgenv_mbox_error_msg("HPU Keys", err, status);
148903831d35Sstevel 			return (0);
149003831d35Sstevel 		}
149103831d35Sstevel 	}
149203831d35Sstevel 
149303831d35Sstevel 
149403831d35Sstevel 	for (i = 0; i < SGENV_MAX_HPU_KEYS; i++) {
149503831d35Sstevel 
149603831d35Sstevel 		if (vol_sensor_count[i] == 0) {
149703831d35Sstevel 			/* empty collection */
149803831d35Sstevel 			old_key = 0;
149903831d35Sstevel 		} else {
150003831d35Sstevel 			/*
150103831d35Sstevel 			 * populated collection:
150203831d35Sstevel 			 * (assert size is OK, and 1st sensor is pseudo-sensor)
150303831d35Sstevel 			 */
150403831d35Sstevel 			ASSERT(env_cache[i] != NULL);
150503831d35Sstevel 			ASSERT(env_cache[i][0].sd_id.id.sensor_part ==
150619397407SSherry Moore 			    SG_SENSOR_PART_SCAPP);
150703831d35Sstevel 			ASSERT(env_cache[i][0].sd_id.id.sensor_type ==
150819397407SSherry Moore 			    SG_SENSOR_TYPE_ENVDB);
150903831d35Sstevel 			ASSERT(SG_INFO_VALUESTATUS(env_cache[i][0].sd_infostamp)
151019397407SSherry Moore 			    == SG_INFO_VALUE_OK);
151103831d35Sstevel 
151203831d35Sstevel 			old_key = env_cache[i][0].sd_value;
151303831d35Sstevel 		}
151403831d35Sstevel 
151503831d35Sstevel 		key = new_keys[i];
151603831d35Sstevel 
151703831d35Sstevel 		/*
151803831d35Sstevel 		 * No data is associated with this key position and there was
151903831d35Sstevel 		 * no data on the previous read either so we simply continue
152003831d35Sstevel 		 * to the next key position.
152103831d35Sstevel 		 */
152203831d35Sstevel 		if ((key == 0) && (old_key == 0)) {
152303831d35Sstevel 			ASSERT(env_cache[i] == NULL);
152403831d35Sstevel 			continue;
152503831d35Sstevel 		}
152603831d35Sstevel 
152703831d35Sstevel 
152803831d35Sstevel 		/*
152903831d35Sstevel 		 * We need to grab this lock every time we are going to
153003831d35Sstevel 		 * update a HPU. However, a kstat_read can grab
153103831d35Sstevel 		 * the env_cache_lock when it wants to get a snapshot of
153203831d35Sstevel 		 * the env_cache. This has the affect of stopping the
153303831d35Sstevel 		 * active env_cache writer after they have updated the
153403831d35Sstevel 		 * active HPU, allowing the kstat_read to get a dump of
153503831d35Sstevel 		 * the env_cache, then the env_cache writer can resume
153603831d35Sstevel 		 * updating the cache. For performance it is more important
153703831d35Sstevel 		 * that the kstat_read completes quickly so we allow the
153803831d35Sstevel 		 * kstat_read to interrupt the updating of the env_cache.
153903831d35Sstevel 		 * The updating can take anything from a few seconds to
154003831d35Sstevel 		 * several minutes to complete.
154103831d35Sstevel 		 */
154203831d35Sstevel 		mutex_enter(&env_cache_lock);
154303831d35Sstevel 
154403831d35Sstevel 		/*
154503831d35Sstevel 		 * If the key just read is zero, then the
154603831d35Sstevel 		 * group of sensors have been removed by
154703831d35Sstevel 		 * some means and we need to zero out
154803831d35Sstevel 		 * the env_cache. (this ensures that data
154903831d35Sstevel 		 * belonging to a removed board is not
155003831d35Sstevel 		 * returned)
155103831d35Sstevel 		 */
155203831d35Sstevel 		if (key == 0) {
155303831d35Sstevel 			ASSERT(old_key != 0);
155403831d35Sstevel 			(void) sgenv_clear_env_cache_entry(i);
155503831d35Sstevel 			mutex_exit(&env_cache_lock);
155603831d35Sstevel 			continue;
155703831d35Sstevel 		}
155803831d35Sstevel 
155903831d35Sstevel 		/*
156003831d35Sstevel 		 * Check to see if this key has changed since
156103831d35Sstevel 		 * the last read.
156203831d35Sstevel 		 *
156303831d35Sstevel 		 * If it has changed, we need to update everything.
156403831d35Sstevel 		 *
156503831d35Sstevel 		 * If it hasn't we simply read the volatiles
156603831d35Sstevel 		 * and check to see if the constants have changed.
156703831d35Sstevel 		 */
156803831d35Sstevel 		if (key != old_key) {
156903831d35Sstevel 			/*
157003831d35Sstevel 			 * If the key is non-zero, then a new HPU has
157103831d35Sstevel 			 * been added to the system or it has changed
157203831d35Sstevel 			 * somehow and we need to re-read everything.
157303831d35Sstevel 			 * (we also need to zero out the env_cache as
157403831d35Sstevel 			 * there may be less sensors returned now and
157503831d35Sstevel 			 * the old ones may not be overwritten)
157603831d35Sstevel 			 */
157703831d35Sstevel 
157803831d35Sstevel 			/*
157903831d35Sstevel 			 * If the <env_cache> has not already been
158003831d35Sstevel 			 * allocated for this key position then we
158103831d35Sstevel 			 * go ahead and allocate it.
158203831d35Sstevel 			 */
158303831d35Sstevel 			if (env_cache[i] == NULL) {
158403831d35Sstevel 				err = sgenv_create_env_cache_entry(i);
158503831d35Sstevel 				if (err == DDI_FAILURE) {
158603831d35Sstevel 					mutex_exit(&env_cache_lock);
158703831d35Sstevel 					continue;
158803831d35Sstevel 				}
158903831d35Sstevel 			}
159003831d35Sstevel 
159103831d35Sstevel 			err = sgenv_get_env_data(new_keys[i], i,
159219397407SSherry Moore 			    SG_GET_ENV_CONSTANTS, &status);
159303831d35Sstevel 			if (err) {
159403831d35Sstevel 				err = sgenv_handle_env_data_error(err, status,
159519397407SSherry Moore 				    i, old_key, "Constant Data");
159603831d35Sstevel 				mutex_exit(&env_cache_lock);
159703831d35Sstevel 				if (err != DDI_FAILURE) {
159803831d35Sstevel 					continue;
159903831d35Sstevel 				} else if (env_cache_updated == TRUE) {
160003831d35Sstevel 					return (0);
160103831d35Sstevel 				} else {
160203831d35Sstevel 					return (DDI_FAILURE);
160303831d35Sstevel 				}
160403831d35Sstevel 			}
160503831d35Sstevel 
160603831d35Sstevel 			err = sgenv_get_env_data(new_keys[i], i,
160719397407SSherry Moore 			    SG_GET_ENV_THRESHOLDS, &status);
160803831d35Sstevel 			if (err) {
160903831d35Sstevel 				err = sgenv_handle_env_data_error(err, status,
161019397407SSherry Moore 				    i, old_key, "Threshold Data");
161103831d35Sstevel 				mutex_exit(&env_cache_lock);
161203831d35Sstevel 				if (err != DDI_FAILURE) {
161303831d35Sstevel 					continue;
161403831d35Sstevel 				} else if (env_cache_updated == TRUE) {
161503831d35Sstevel 					return (0);
161603831d35Sstevel 				} else {
161703831d35Sstevel 					return (DDI_FAILURE);
161803831d35Sstevel 				}
161903831d35Sstevel 			}
162003831d35Sstevel 
162103831d35Sstevel 			err = sgenv_get_env_data(new_keys[i], i,
162219397407SSherry Moore 			    SG_GET_ENV_VOLATILES, &status);
162303831d35Sstevel 			if (err) {
162403831d35Sstevel 				err = sgenv_handle_env_data_error(err, status,
162519397407SSherry Moore 				    i, old_key, "Volatile Data (fresh)");
162603831d35Sstevel 				mutex_exit(&env_cache_lock);
162703831d35Sstevel 				if (err != DDI_FAILURE) {
162803831d35Sstevel 					continue;
162903831d35Sstevel 				} else if (env_cache_updated == TRUE) {
163003831d35Sstevel 					return (0);
163103831d35Sstevel 				} else {
163203831d35Sstevel 					return (DDI_FAILURE);
163303831d35Sstevel 				}
163403831d35Sstevel 			}
163503831d35Sstevel 
163603831d35Sstevel 			/*
163703831d35Sstevel 			 * As we have successfully got env data for a HPU,
163803831d35Sstevel 			 * we ensure <env_cache_updated> is set to TRUE so that
163903831d35Sstevel 			 * in the future, if an error occurs during the mailbox
164003831d35Sstevel 			 * transfer, we know that there is old data for at
164103831d35Sstevel 			 * least one HPU in the <env_cache> which could be
164203831d35Sstevel 			 * returned instead of returning an error to the kstat
164303831d35Sstevel 			 * framework indicating that we have no data to return.
164403831d35Sstevel 			 */
164503831d35Sstevel 			env_cache_updated = TRUE;
164603831d35Sstevel 			last_env_read_time = gethrtime();
164703831d35Sstevel 
164803831d35Sstevel 		} else {
164903831d35Sstevel 			/*
165003831d35Sstevel 			 * key == old_key
165103831d35Sstevel 			 *
165203831d35Sstevel 			 * Handle the case when the value of the old key and
165303831d35Sstevel 			 * the new key are identical.
165403831d35Sstevel 			 */
165503831d35Sstevel 			ASSERT(env_cache[i] != NULL);
165603831d35Sstevel 
165703831d35Sstevel 			/*
165803831d35Sstevel 			 * If the keys are identical, then the quasi-constants
165903831d35Sstevel 			 * should not have changed (and so don't need updating).
166003831d35Sstevel 			 * Similarly for the threshold readings.
166103831d35Sstevel 			 */
166203831d35Sstevel 
166303831d35Sstevel 			/* Update the volatile data */
166403831d35Sstevel 			err = sgenv_get_env_data(new_keys[i], i,
166519397407SSherry Moore 			    SG_GET_ENV_VOLATILES, &status);
166603831d35Sstevel 			if (err) {
166703831d35Sstevel 				err = sgenv_handle_env_data_error(err, status,
166819397407SSherry Moore 				    i, old_key, "Volatile Data (update)");
166903831d35Sstevel 				mutex_exit(&env_cache_lock);
167003831d35Sstevel 				if (err == DDI_FAILURE) {
167103831d35Sstevel 					return (0);
167203831d35Sstevel 				} else {
167303831d35Sstevel 					continue;
167403831d35Sstevel 				}
167503831d35Sstevel 			}
167603831d35Sstevel 
167703831d35Sstevel 		}
167803831d35Sstevel 		mutex_exit(&env_cache_lock);
167903831d35Sstevel 	}
168003831d35Sstevel 
168103831d35Sstevel 	return (0);
168203831d35Sstevel }
168303831d35Sstevel 
168403831d35Sstevel 
168503831d35Sstevel static int
sgenv_get_board_info_data(void)168603831d35Sstevel sgenv_get_board_info_data(void)
168703831d35Sstevel {
168803831d35Sstevel 	/*
168903831d35Sstevel 	 * This array keeps track of the valid nodes in a system. A call is
169003831d35Sstevel 	 * made to OBP to get the "nodeid" property from all the ssm nodes,
169103831d35Sstevel 	 * and for each nodeid found, that position in the array is set to
169203831d35Sstevel 	 * TRUE. For a Serengeti only one position in the array will be TRUE.
169303831d35Sstevel 	 */
169403831d35Sstevel 	static uint_t node_present[SSM_MAX_INSTANCES] = {SGENV_NO_NODE_EXISTS};
169503831d35Sstevel 
169603831d35Sstevel 	static fn_t	f = "sgenv_get_board_info_data()";
169703831d35Sstevel 	static int	first_time = TRUE;
169803831d35Sstevel 
169903831d35Sstevel 	sbbc_msg_t	req;
170003831d35Sstevel 	sbbc_msg_t	resp;
170103831d35Sstevel 	int		node;	/* loop index */
170203831d35Sstevel 	int		board;	/* loop index */
170303831d35Sstevel 	show_board_t	show_bd, *shbp = &show_bd;
170403831d35Sstevel 	info_t		inform;
170503831d35Sstevel 	int		status;	/* msg_status returned by response */
170603831d35Sstevel 	int		rv = 0;	/* return value of call to mailbox */
170703831d35Sstevel 	sg_board_info_t	*ptr;
170803831d35Sstevel 
170903831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: entered.", f);
171003831d35Sstevel 
171103831d35Sstevel 	if (first_time) {
171203831d35Sstevel 		sgenv_set_valid_node_positions(node_present);
171303831d35Sstevel 		first_time = FALSE;
171403831d35Sstevel 	}
171503831d35Sstevel 
171603831d35Sstevel 	for (node = 0; node < SSM_MAX_INSTANCES; node++) {
171703831d35Sstevel 
171803831d35Sstevel 		if (node_present[node] == SGENV_NO_NODE_EXISTS)
171903831d35Sstevel 			continue;
172003831d35Sstevel 
172103831d35Sstevel 		for (board = 0; board < SG_MAX_BDS; board++) {
172203831d35Sstevel 
172303831d35Sstevel 			/*
172403831d35Sstevel 			 * If we have discovered in a previous call to the SC
172503831d35Sstevel 			 * that there is no board in this slot on this type of
172603831d35Sstevel 			 * chassis then we don't waste resources asking the SC
172703831d35Sstevel 			 * for nonexistent data.
172803831d35Sstevel 			 */
172903831d35Sstevel 			if ((node_present[node] & (1 << board)) == 0)
173003831d35Sstevel 				continue;
173103831d35Sstevel 
173203831d35Sstevel 			inform.board = board;
173303831d35Sstevel 			inform.node = node;
173403831d35Sstevel 			inform.revision = 0xdead;
173503831d35Sstevel 
173603831d35Sstevel 			req.msg_type.type = DR_MBOX;
173703831d35Sstevel 			req.msg_type.sub_type = DR_MBOX_SHOW_BOARD;
173803831d35Sstevel 			req.msg_status = SG_MBOX_STATUS_SUCCESS;
173903831d35Sstevel 			req.msg_len = sizeof (info_t);
174003831d35Sstevel 			req.msg_bytes = sizeof (info_t);
174103831d35Sstevel 			req.msg_buf = (caddr_t)&inform;
174203831d35Sstevel 
174303831d35Sstevel 			bzero(shbp, sizeof (show_board_t));
174403831d35Sstevel 			shbp->s_cond = -1;
174503831d35Sstevel 			shbp->s_power = -1;
174603831d35Sstevel 			shbp->s_assigned = -1;
174703831d35Sstevel 			shbp->s_claimed = -1;
174803831d35Sstevel 			shbp->s_present = -1;
174903831d35Sstevel 
175003831d35Sstevel 			resp.msg_type.type = DR_MBOX;
175103831d35Sstevel 			resp.msg_type.sub_type = DR_MBOX_SHOW_BOARD;
175203831d35Sstevel 			resp.msg_bytes = sizeof (show_board_t);
175303831d35Sstevel 			resp.msg_status = SG_MBOX_STATUS_SUCCESS;
175403831d35Sstevel 			resp.msg_len = sizeof (show_board_t);
175503831d35Sstevel 			resp.msg_buf = (caddr_t)shbp;
175603831d35Sstevel 
175703831d35Sstevel 
175803831d35Sstevel 			/*
175903831d35Sstevel 			 * We want to avoid the case where an invalid time
176003831d35Sstevel 			 * is specified by a user (by patching the
176103831d35Sstevel 			 * global variable <sgenv_max_mbox_wait_time>).
176203831d35Sstevel 			 *
176303831d35Sstevel 			 * Any incorrect values are reset to the default time.
176403831d35Sstevel 			 */
176503831d35Sstevel 			if (sgenv_max_mbox_wait_time <=
176619397407SSherry Moore 			    max(sbbc_mbox_min_timeout, 0))
176703831d35Sstevel 				sgenv_max_mbox_wait_time =
176819397407SSherry Moore 				    sbbc_mbox_default_timeout;
176903831d35Sstevel 
177003831d35Sstevel 			rv = sbbc_mbox_request_response(&req, &resp,
177119397407SSherry Moore 			    sgenv_max_mbox_wait_time);
177203831d35Sstevel 			status = resp.msg_status;
177303831d35Sstevel 
177403831d35Sstevel 			if ((rv) || (status != SG_MBOX_STATUS_SUCCESS)) {
177503831d35Sstevel 				/*
177603831d35Sstevel 				 * errors from Solaris sgsbbc driver
177703831d35Sstevel 				 */
177803831d35Sstevel 				if (status > SG_MBOX_STATUS_SUCCESS) {
177903831d35Sstevel 					sgenv_mbox_error_msg("Board Info", rv,
178019397407SSherry Moore 					    resp.msg_status);
178103831d35Sstevel 					return (rv);
178203831d35Sstevel 				}
178303831d35Sstevel 
178403831d35Sstevel 				/*
178503831d35Sstevel 				 * errors from SCAPP
178603831d35Sstevel 				 */
178703831d35Sstevel 				if (status == SG_MBOX_STATUS_ILLEGAL_NODE) {
178803831d35Sstevel 					sgenv_mbox_error_msg("Board Info", rv,
178919397407SSherry Moore 					    resp.msg_status);
179003831d35Sstevel 					node_present[node] =
179119397407SSherry Moore 					    SGENV_NO_NODE_EXISTS;
179203831d35Sstevel 
179303831d35Sstevel 					/*
179403831d35Sstevel 					 * No point looping through the rest of
179503831d35Sstevel 					 * the boards associated with this node.
179603831d35Sstevel 					 */
179703831d35Sstevel 					break;
179803831d35Sstevel 
179903831d35Sstevel 				} else if (status ==
180019397407SSherry Moore 				    SG_MBOX_STATUS_ILLEGAL_SLOT) {
180103831d35Sstevel 
180203831d35Sstevel 					/*
180303831d35Sstevel 					 * We clear the bit representing <board>
180403831d35Sstevel 					 * in <node> to indicate that this slot
180503831d35Sstevel 					 * cannot exist on this chassis.
180603831d35Sstevel 					 */
180703831d35Sstevel 					node_present[node] &= (~(1 << board) &
180819397407SSherry Moore 					    SGENV_NODE_TYPE_DS);
180903831d35Sstevel 					continue;
181003831d35Sstevel 
181103831d35Sstevel 				} else if (status ==
181219397407SSherry Moore 				    SG_MBOX_STATUS_BOARD_ACCESS_DENIED) {
181303831d35Sstevel 					/*
181403831d35Sstevel 					 * We cannot access data for this slot,
181503831d35Sstevel 					 * however we may be able to do so in
181603831d35Sstevel 					 * the future. We do nothing.
181703831d35Sstevel 					 */
181803831d35Sstevel 					rv = rv;
181903831d35Sstevel 				} else {
182003831d35Sstevel 					char	err_msg[40];
182103831d35Sstevel 
182207d06da5SSurya Prakki 					(void) sprintf(err_msg,
182307d06da5SSurya Prakki 					    "Board data for "
182419397407SSherry Moore 					    "Node%d/Slot%d", node, board);
182503831d35Sstevel 					sgenv_mbox_error_msg(err_msg, rv,
182619397407SSherry Moore 					    resp.msg_status);
182703831d35Sstevel 
182803831d35Sstevel 					if (rv == 0)
182903831d35Sstevel 						rv = status;
183003831d35Sstevel 
183103831d35Sstevel 					continue;
183203831d35Sstevel 				}
183303831d35Sstevel 			}
183403831d35Sstevel 
183503831d35Sstevel 			mutex_enter(&board_cache_lock);
183603831d35Sstevel 			ptr = &board_cache[board];
183703831d35Sstevel 
183803831d35Sstevel 			/*
183903831d35Sstevel 			 * Check if the SC returns data for this board.
184003831d35Sstevel 			 */
184103831d35Sstevel 			if (shbp->s_assigned == -1) {
184203831d35Sstevel 				/*
184303831d35Sstevel 				 * If this cache entry used to have data and
184403831d35Sstevel 				 * now doesn't we decrement the board_count
184503831d35Sstevel 				 * clear the env_cache. The board must have
184603831d35Sstevel 				 * been removed.
184703831d35Sstevel 				 */
184803831d35Sstevel 				if (ptr->node_id != -1) {
184903831d35Sstevel 					board_count--;
185003831d35Sstevel 
185103831d35Sstevel 					/*
185203831d35Sstevel 					 * clear board_cache entry by
185303831d35Sstevel 					 * setting node_id to -1;
185403831d35Sstevel 					 */
185503831d35Sstevel 					ptr->node_id = -1;
185603831d35Sstevel 					DCMN_ERR_CACHE(CE_NOTE, "%s: "
185719397407SSherry Moore 					    "Clearing cache line %d [%p]",
185807d06da5SSurya Prakki 					    f, board, (void *)ptr);
185903831d35Sstevel 				}
186003831d35Sstevel 			} else {
186103831d35Sstevel 				/*
186203831d35Sstevel 				 * If this cache entry was previously empty
186303831d35Sstevel 				 * and we now have data for it we increment
186403831d35Sstevel 				 * the board_count. A new board must have
186503831d35Sstevel 				 * been added.
186603831d35Sstevel 				 */
186703831d35Sstevel 				if (ptr->node_id == -1)
186803831d35Sstevel 					board_count++;
186903831d35Sstevel 				/*
187003831d35Sstevel 				 * update the board_cache entry
187103831d35Sstevel 				 */
187203831d35Sstevel 				DCMN_ERR_CACHE(CE_NOTE, "%s: "
187319397407SSherry Moore 				    "Writing data for bd=%d into "
187419397407SSherry Moore 				    " the board_cache at [%p]",
187507d06da5SSurya Prakki 				    f, board, (void *)ptr);
187603831d35Sstevel 				ptr->node_id = node;
187703831d35Sstevel 				ptr->board_num = board;
187803831d35Sstevel 				ptr->condition = shbp->s_cond;
187903831d35Sstevel 				ptr->assigned = shbp->s_assigned;
188003831d35Sstevel 				ptr->claimed = shbp->s_claimed;
188103831d35Sstevel 				ptr->present = shbp->s_present;
188203831d35Sstevel 				ptr->led.led_status =
188319397407SSherry Moore 				    shbp->s_ledstatus;
188403831d35Sstevel 				last_board_read_time = gethrtime();
188503831d35Sstevel 			}
188603831d35Sstevel 			mutex_exit(&board_cache_lock);
188703831d35Sstevel 		} /* board */
188803831d35Sstevel 	} /* node */
188903831d35Sstevel 
189003831d35Sstevel 	/*
189103831d35Sstevel 	 * Indicate that have managed to store valid data in the <board_cache>
189203831d35Sstevel 	 * at least once.
189303831d35Sstevel 	 */
189403831d35Sstevel 	if (board_count > 0)
189503831d35Sstevel 		board_cache_updated = TRUE;
189603831d35Sstevel 
189703831d35Sstevel 
189803831d35Sstevel 	return (rv);
189903831d35Sstevel }
190003831d35Sstevel 
190103831d35Sstevel 
190203831d35Sstevel static int
sgenv_get_hpu_keys(envresp_key_t * new,int * status)190303831d35Sstevel sgenv_get_hpu_keys(envresp_key_t *new, int *status)
190403831d35Sstevel {
190503831d35Sstevel 	sbbc_msg_t	req;	/* request */
190603831d35Sstevel 	sbbc_msg_t	resp;	/* response */
190703831d35Sstevel 
190803831d35Sstevel 	int	rv;	/* return value from call to mbox */
190903831d35Sstevel 
191003831d35Sstevel 	req.msg_type.type = SG_ENV;
191103831d35Sstevel 	req.msg_type.sub_type = SG_GET_ENV_HPU_KEYS;
191203831d35Sstevel 	req.msg_status = SG_MBOX_STATUS_SUCCESS;
191303831d35Sstevel 	req.msg_len = 0;
191403831d35Sstevel 	req.msg_bytes = 0;
191503831d35Sstevel 
191603831d35Sstevel 	resp.msg_type.type = SG_ENV;
191703831d35Sstevel 	resp.msg_type.sub_type = SG_GET_ENV_HPU_KEYS;
191803831d35Sstevel 	resp.msg_status = SG_MBOX_STATUS_SUCCESS;
191903831d35Sstevel 	resp.msg_len = sizeof (envresp_key_t) * SGENV_MAX_HPU_KEYS;
192003831d35Sstevel 	resp.msg_bytes = 0;
192103831d35Sstevel 	resp.msg_buf = (caddr_t)new;
192203831d35Sstevel 
192303831d35Sstevel 	/*
192403831d35Sstevel 	 * We want to avoid the case where an invalid time
192503831d35Sstevel 	 * is specified by a user (by patching the
192603831d35Sstevel 	 * global variable <sgenv_max_mbox_wait_time>).
192703831d35Sstevel 	 *
192803831d35Sstevel 	 * Any incorrect values are reset to the default time.
192903831d35Sstevel 	 */
193003831d35Sstevel 	if (sgenv_max_mbox_wait_time <= max(sbbc_mbox_min_timeout, 0))
193103831d35Sstevel 		sgenv_max_mbox_wait_time = sbbc_mbox_default_timeout;
193203831d35Sstevel 
193303831d35Sstevel 	rv = sbbc_mbox_request_response(&req, &resp, sgenv_max_mbox_wait_time);
193403831d35Sstevel 
193503831d35Sstevel 	*status = resp.msg_status;
193603831d35Sstevel 
193703831d35Sstevel 	return (rv);
193803831d35Sstevel }
193903831d35Sstevel 
194003831d35Sstevel 
194103831d35Sstevel static int
sgenv_get_env_data(envresp_key_t key,int key_posn,uint16_t flag,int * status)194203831d35Sstevel sgenv_get_env_data(envresp_key_t key, int key_posn, uint16_t flag, int *status)
194303831d35Sstevel {
194403831d35Sstevel 	/*
194503831d35Sstevel 	 * Only one of these buffers is ever going to be used in a call
194603831d35Sstevel 	 * so to save kernel stack space we use a union.
194703831d35Sstevel 	 */
194803831d35Sstevel 	union {
194903831d35Sstevel 		envresp_constants_t	con[SGENV_MAX_SENSORS_PER_KEY];
195003831d35Sstevel 		envresp_volatiles_t	vol[SGENV_MAX_SENSORS_PER_KEY];
195103831d35Sstevel 		envresp_thresholds_t	thr[SGENV_MAX_SENSORS_PER_KEY];
195203831d35Sstevel 	} buf;
195303831d35Sstevel 
195403831d35Sstevel 	sbbc_msg_t	req;	/* request */
195503831d35Sstevel 	sbbc_msg_t	resp;	/* response */
195603831d35Sstevel 
195703831d35Sstevel 	int	i;	/* loop variable for mbox msg_buf */
195803831d35Sstevel 	int	rv;	/* return value from call to mbox */
195903831d35Sstevel 
196003831d35Sstevel 	ASSERT(MUTEX_HELD(&env_cache_lock));
196103831d35Sstevel 	ASSERT(env_cache[key_posn] != NULL);
196203831d35Sstevel 
196303831d35Sstevel 	if (flag == SG_GET_ENV_CONSTANTS) {
196403831d35Sstevel 		resp.msg_len = sizeof (buf.con);
196503831d35Sstevel 		resp.msg_buf = (caddr_t)buf.con;
196603831d35Sstevel 
196703831d35Sstevel 	} else if (flag == SG_GET_ENV_VOLATILES) {
196803831d35Sstevel 		resp.msg_len = sizeof (buf.vol);
196903831d35Sstevel 		resp.msg_buf = (caddr_t)buf.vol;
197003831d35Sstevel 
197103831d35Sstevel 	} else if (flag == SG_GET_ENV_THRESHOLDS) {
197203831d35Sstevel 		resp.msg_len = sizeof (buf.thr);
197303831d35Sstevel 		resp.msg_buf = (caddr_t)buf.thr;
197403831d35Sstevel 
197503831d35Sstevel 	} else {
197603831d35Sstevel 		*status = EINVAL;
197703831d35Sstevel 		return (-1);
197803831d35Sstevel 	}
197903831d35Sstevel 
198003831d35Sstevel 	req.msg_type.type = SG_ENV;
198103831d35Sstevel 	req.msg_type.sub_type = flag;
198203831d35Sstevel 	req.msg_status = SG_MBOX_STATUS_SUCCESS;
198303831d35Sstevel 	req.msg_len = 0;
198403831d35Sstevel 	req.msg_bytes = 0;
198503831d35Sstevel 	req.msg_data[0] = key;
198603831d35Sstevel 
198703831d35Sstevel 	resp.msg_type.type = SG_ENV;
198803831d35Sstevel 	resp.msg_type.sub_type = flag;
198903831d35Sstevel 	resp.msg_status = SG_MBOX_STATUS_SUCCESS;
199003831d35Sstevel 	resp.msg_bytes = 0;
199103831d35Sstevel 
199203831d35Sstevel 	/*
199303831d35Sstevel 	 * We want to avoid the case where an invalid time
199403831d35Sstevel 	 * is specified by a user (by patching the
199503831d35Sstevel 	 * global variable <sgenv_max_mbox_wait_time>).
199603831d35Sstevel 	 *
199703831d35Sstevel 	 * Any incorrect values are reset to the default time.
199803831d35Sstevel 	 */
199903831d35Sstevel 	if (sgenv_max_mbox_wait_time <= max(sbbc_mbox_min_timeout, 0))
200003831d35Sstevel 		sgenv_max_mbox_wait_time = sbbc_mbox_default_timeout;
200103831d35Sstevel 
200203831d35Sstevel 
200303831d35Sstevel 	rv = sbbc_mbox_request_response(&req, &resp, sgenv_max_mbox_wait_time);
200403831d35Sstevel 
200503831d35Sstevel 	*status = resp.msg_status;
200603831d35Sstevel 
200703831d35Sstevel 	/*
200803831d35Sstevel 	 * We now check that the data returned is valid.
200903831d35Sstevel 	 */
201003831d35Sstevel 	if (rv != 0) {
201103831d35Sstevel 		/*
201203831d35Sstevel 		 * The SBBC driver encountered an error.
201303831d35Sstevel 		 */
201403831d35Sstevel 		return (rv);
201503831d35Sstevel 
201603831d35Sstevel 	} else {
201703831d35Sstevel 		/*
201803831d35Sstevel 		 * The SC encountered an error.
201903831d35Sstevel 		 */
202003831d35Sstevel 		switch (*status) {
202103831d35Sstevel 		case SG_MBOX_STATUS_SUCCESS:
202203831d35Sstevel 			/*
202303831d35Sstevel 			 * No problems encountered - continue and return the
202403831d35Sstevel 			 * new data.
202503831d35Sstevel 			 */
202603831d35Sstevel 			break;
202703831d35Sstevel 
202803831d35Sstevel 		case ETIMEDOUT:
202903831d35Sstevel 			/*
203003831d35Sstevel 			 * For some reason the mailbox failed to return data
203103831d35Sstevel 			 * and instead timed out so we return ETIMEDOUT
203203831d35Sstevel 			 */
203303831d35Sstevel 			return (ETIMEDOUT);
203403831d35Sstevel 
203503831d35Sstevel 		case ENXIO:
203603831d35Sstevel 			/*
203703831d35Sstevel 			 * no sensors associated with this key, this may have
203803831d35Sstevel 			 * changed since we read the keys.
203903831d35Sstevel 			 */
204003831d35Sstevel 			return (ENXIO);
204103831d35Sstevel 
204203831d35Sstevel 		default:
204303831d35Sstevel 			/*
204403831d35Sstevel 			 * The contents of the mbox message contain corrupt
204503831d35Sstevel 			 * data. Flag this as an error to be returned.
204603831d35Sstevel 			 */
204703831d35Sstevel 			SGENV_PRINT_MBOX_MSG((&resp), "Env info problem");
204803831d35Sstevel 			return (EINVAL);
204903831d35Sstevel 		}
205003831d35Sstevel 	}
205103831d35Sstevel 
205203831d35Sstevel 	/*
205303831d35Sstevel 	 * Depending on the type of data returned, save the constant/volatile
205403831d35Sstevel 	 * data returned in the mailbox message into the <env_cache>.
205503831d35Sstevel 	 */
205603831d35Sstevel 	for (i = 0; i < resp.msg_data[0]; i++) {
205703831d35Sstevel 
205803831d35Sstevel 		if (flag == SG_GET_ENV_CONSTANTS) {
205903831d35Sstevel 			env_cache[key_posn][i].sd_id.tag_id =
206019397407SSherry Moore 			    buf.con[i].id.tag_id;
206103831d35Sstevel 			env_cache[key_posn][i].sd_lo =
206219397407SSherry Moore 			    buf.con[i].lo;
206303831d35Sstevel 			env_cache[key_posn][i].sd_hi =
206419397407SSherry Moore 			    buf.con[i].hi;
206503831d35Sstevel 
206603831d35Sstevel 		} else if (flag == SG_GET_ENV_VOLATILES) {
206703831d35Sstevel 			env_cache[key_posn][i].sd_value =
206819397407SSherry Moore 			    buf.vol[i].value;
206903831d35Sstevel 			env_cache[key_posn][i].sd_infostamp =
207019397407SSherry Moore 			    buf.vol[i].info;
207103831d35Sstevel 
207203831d35Sstevel 			sgenv_set_sensor_status(&env_cache[key_posn][i]);
207303831d35Sstevel 
207403831d35Sstevel 		} else if (flag == SG_GET_ENV_THRESHOLDS) {
207503831d35Sstevel 			env_cache[key_posn][i].sd_lo_warn =
207619397407SSherry Moore 			    buf.thr[i].lo_warn;
207703831d35Sstevel 			env_cache[key_posn][i].sd_hi_warn =
207819397407SSherry Moore 			    buf.thr[i].hi_warn;
207903831d35Sstevel 		}
208003831d35Sstevel 	}
208103831d35Sstevel 
208203831d35Sstevel 	if (flag == SG_GET_ENV_VOLATILES)
208303831d35Sstevel 		vol_sensor_count[key_posn] = resp.msg_data[0];
208403831d35Sstevel 
208503831d35Sstevel 	return (rv);
208603831d35Sstevel }
208703831d35Sstevel 
208803831d35Sstevel 
208903831d35Sstevel /*
209003831d35Sstevel  * This function handles any errors received from the mailbox framework while
209103831d35Sstevel  * getting environmental data.
209203831d35Sstevel  *
209303831d35Sstevel  * INPUT PARAMETERS
209403831d35Sstevel  *	err	- return value from call to mailbox framework.
209503831d35Sstevel  *	status	- message status returned by mailbox framework.
209603831d35Sstevel  *	key	- key from previous (if any) reading of env data.
209703831d35Sstevel  *		  Needed to see if we have old data in the <env_cache>.
209803831d35Sstevel  *	str	- String indicating what type of env request failed.
209903831d35Sstevel  *
210003831d35Sstevel  * RETURN VALUES
210103831d35Sstevel  *	rv == DDI_FAILURE	- there is no point in continuing processing
210203831d35Sstevel  *				  the data, we should exit from the kstat
210303831d35Sstevel  *				  framework.
210403831d35Sstevel  *	rv != DDI_FAILURE	- error has been handled correctly, continue
210503831d35Sstevel  *				  processing the data returned from the SC.
210603831d35Sstevel  */
210703831d35Sstevel static int
sgenv_handle_env_data_error(int err,int status,int key_posn,envresp_key_t key,char * str)210803831d35Sstevel sgenv_handle_env_data_error(int err, int status, int key_posn,
2109*d1d6926fSToomas Soome     envresp_key_t key, char *str)
211003831d35Sstevel {
211103831d35Sstevel 	int	rv = DDI_SUCCESS;
211203831d35Sstevel 
211303831d35Sstevel 	ASSERT(str != (char *)NULL);
211403831d35Sstevel 
211503831d35Sstevel 	switch (err) {
211603831d35Sstevel 	case ENXIO:
211703831d35Sstevel 		/*
211803831d35Sstevel 		 * The SC has changed the env data associated with this key
211903831d35Sstevel 		 * since we started getting the data. We cannot tell if the
212003831d35Sstevel 		 * data has disappeared due to the removal of the board from
212103831d35Sstevel 		 * our Domain or just that the data has been updated. We
212203831d35Sstevel 		 * simply return the last known data (if possible) and the
212303831d35Sstevel 		 * next time we request the env data, the SC will have
212403831d35Sstevel 		 * finished processing this board so we will receive the
212503831d35Sstevel 		 * correct key values and we can get the correct data.
212603831d35Sstevel 		 */
212703831d35Sstevel 		DCMN_ERR_CACHE(CE_NOTE, "key @ posn %d has changed from %d"
212819397407SSherry Moore 		    " while %s", key_posn, key, str);
212903831d35Sstevel 		rv = ENXIO;
213003831d35Sstevel 		break;
213103831d35Sstevel 
213203831d35Sstevel 	default:
213303831d35Sstevel 		sgenv_mbox_error_msg(str, err, status);
213403831d35Sstevel 		rv = DDI_FAILURE;
213503831d35Sstevel 		break;
213603831d35Sstevel 	}
213703831d35Sstevel 
213803831d35Sstevel 	/*
213903831d35Sstevel 	 * If there was no data in the <env_cache>, we need to clear the data
214003831d35Sstevel 	 * just added as the <env_cache> will only be partially filled.
214103831d35Sstevel 	 */
214203831d35Sstevel 	if (key == 0)
214303831d35Sstevel 		sgenv_clear_env_cache_entry(key_posn);
214403831d35Sstevel 
214503831d35Sstevel 	return (rv);
214603831d35Sstevel }
214703831d35Sstevel 
214803831d35Sstevel 
214903831d35Sstevel /*
215003831d35Sstevel  * If the sensor readings for a particular collection of HPUs become invalid,
215103831d35Sstevel  * then we clear the cache by freeing up the memory.
215203831d35Sstevel  */
215303831d35Sstevel static void
sgenv_clear_env_cache_entry(int key_posn)215403831d35Sstevel sgenv_clear_env_cache_entry(int key_posn)
215503831d35Sstevel {
215603831d35Sstevel 	ASSERT(MUTEX_HELD(&env_cache_lock));
215703831d35Sstevel 
215803831d35Sstevel 	if (env_cache[key_posn] != NULL) {
215903831d35Sstevel 		kmem_free(env_cache[key_posn], sizeof (env_sensor_t) *
216019397407SSherry Moore 		    SGENV_MAX_SENSORS_PER_KEY);
216103831d35Sstevel 		env_cache[key_posn] = NULL;
216203831d35Sstevel 		vol_sensor_count[key_posn] = 0;
216303831d35Sstevel 	}
216403831d35Sstevel }
216503831d35Sstevel 
216603831d35Sstevel 
216703831d35Sstevel static void
sgenv_mbox_error_msg(char * str,int err,int status)216803831d35Sstevel sgenv_mbox_error_msg(char *str, int err, int status)
216903831d35Sstevel {
217003831d35Sstevel 	/*
217103831d35Sstevel 	 * We update the count of errors we have encountered during calls to
217203831d35Sstevel 	 * the mailbox framework (unless we will cause a wraparound)
217303831d35Sstevel 	 */
217403831d35Sstevel 	if (sgenv_mbox_error_count < INT_MAX)
217503831d35Sstevel 		sgenv_mbox_error_count++;
217603831d35Sstevel 
217703831d35Sstevel #ifdef DEBUG
217803831d35Sstevel 	if ((sgenv_debug & SGENV_DEBUG_MSG) == 0)
217903831d35Sstevel 		return;
218003831d35Sstevel 
218103831d35Sstevel 	ASSERT(str != NULL);
218203831d35Sstevel 
218303831d35Sstevel 	switch (err) {
218403831d35Sstevel 	case ENOTSUP:
218503831d35Sstevel 		DCMN_ERR(CE_WARN, "!This system configuration does not "
218619397407SSherry Moore 		"support SGENV");
218703831d35Sstevel 		break;
218803831d35Sstevel 	case ETIMEDOUT:
218903831d35Sstevel 		DCMN_ERR(CE_WARN, "!Mailbox timed out while servicing "
219019397407SSherry Moore 		"SGENV request for %s", str);
219103831d35Sstevel 		break;
219203831d35Sstevel 	default:
219303831d35Sstevel 		DCMN_ERR(CE_WARN, "!Error occurred reading %s, Errno=%d,"
219419397407SSherry Moore 		" Status=%d", str, err, status);
219503831d35Sstevel 		break;
219603831d35Sstevel 	}
219703831d35Sstevel #endif
219803831d35Sstevel }
219903831d35Sstevel 
220003831d35Sstevel 
220103831d35Sstevel /*
220203831d35Sstevel  * INPUT PARAMETERS
220303831d35Sstevel  *	key_posn -	The position in the env_cache for which we want to
220403831d35Sstevel  *			allocate space for a HPU's env data.
220503831d35Sstevel  *
220603831d35Sstevel  * ERROR VALUES
220703831d35Sstevel  *	DDI_FAILURE -	We failed to allocate memory for this cache entry.
220803831d35Sstevel  *			There is no point asking the SC for env data for this
220903831d35Sstevel  *			HPU as we will have nowhere to store it.
221003831d35Sstevel  */
221103831d35Sstevel static int
sgenv_create_env_cache_entry(int key_posn)221203831d35Sstevel sgenv_create_env_cache_entry(int key_posn)
221303831d35Sstevel {
221403831d35Sstevel 	int	i;	/* used to loop thru each sensor to set the status */
221503831d35Sstevel 
221603831d35Sstevel 	ASSERT(key_posn < SGENV_MAX_HPU_KEYS);
221703831d35Sstevel 	ASSERT(key_posn >= 0);
221803831d35Sstevel 
221903831d35Sstevel 	env_cache[key_posn] = (env_sensor_t *)kmem_zalloc(
222019397407SSherry Moore 	    sizeof (env_sensor_t) * SGENV_MAX_SENSORS_PER_KEY, KM_NOSLEEP);
222103831d35Sstevel 	if (env_cache[key_posn] == NULL) {
222203831d35Sstevel 		cmn_err(CE_WARN, "Failed to allocate memory for env_cache[%d]",
222319397407SSherry Moore 		    key_posn);
222403831d35Sstevel 		return (DDI_FAILURE);
222503831d35Sstevel 	}
222603831d35Sstevel 
222703831d35Sstevel 	for (i = 0; i < SGENV_MAX_SENSORS_PER_KEY; i++)
222803831d35Sstevel 		env_cache[key_posn][i].sd_status = SG_SENSOR_STATUS_OK;
222903831d35Sstevel 
223003831d35Sstevel 	return (DDI_SUCCESS);
223103831d35Sstevel }
223203831d35Sstevel 
223303831d35Sstevel 
223403831d35Sstevel static void
sgenv_destroy_env_cache(void)223503831d35Sstevel sgenv_destroy_env_cache(void)
223603831d35Sstevel {
223703831d35Sstevel 	int i;
223803831d35Sstevel 
223903831d35Sstevel 	ASSERT(MUTEX_HELD(&env_cache_lock) == FALSE);
224003831d35Sstevel 	mutex_enter(&env_cache_lock);
224103831d35Sstevel 	for (i = 0; i < SGENV_MAX_HPU_KEYS; i++) {
224203831d35Sstevel 		if (env_cache[i] != NULL) {
224303831d35Sstevel 			kmem_free(env_cache[i], sizeof (env_sensor_t) *
224419397407SSherry Moore 			    SGENV_MAX_SENSORS_PER_KEY);
224503831d35Sstevel 			env_cache[i] = NULL;
224603831d35Sstevel 			vol_sensor_count[i] = 0;
224703831d35Sstevel 		}
224803831d35Sstevel 	}
224903831d35Sstevel 	env_cache_updated = FALSE;
225003831d35Sstevel 
225103831d35Sstevel 	mutex_exit(&env_cache_lock);
225203831d35Sstevel }
225303831d35Sstevel 
225403831d35Sstevel static void
sgenv_update_env_kstat_size(kstat_t * ksp)225503831d35Sstevel sgenv_update_env_kstat_size(kstat_t *ksp)
225603831d35Sstevel {
225703831d35Sstevel 	int	i;
225803831d35Sstevel 
225903831d35Sstevel 	ASSERT(MUTEX_HELD(&env_cache_lock));
226003831d35Sstevel 
226103831d35Sstevel 	/* reinitialize this and recount number of sensors */
226203831d35Sstevel 	ksp->ks_data_size = 0;
226303831d35Sstevel 
226403831d35Sstevel 	for (i = 0; i < SGENV_MAX_HPU_KEYS; i++) {
226503831d35Sstevel 		if (vol_sensor_count[i] <= 0)
226603831d35Sstevel 			continue;
226703831d35Sstevel 
226803831d35Sstevel 		ASSERT(vol_sensor_count[i] <= SGENV_MAX_SENSORS_PER_KEY);
226903831d35Sstevel 
227003831d35Sstevel 		/*
227103831d35Sstevel 		 * increment ksp->ks_data_size by the number of
227203831d35Sstevel 		 * sensors in the collection <i>.
227303831d35Sstevel 		 */
227403831d35Sstevel 		ksp->ks_data_size += vol_sensor_count[i] *
227519397407SSherry Moore 		    sizeof (env_sensor_t);
227603831d35Sstevel 	}
227703831d35Sstevel 	ASSERT(ksp->ks_data_size >= 0);
227803831d35Sstevel }
227903831d35Sstevel 
228003831d35Sstevel 
228103831d35Sstevel /*
228203831d35Sstevel  * This function is triggered by the thread that updates the env_cache.
228303831d35Sstevel  * It checks for any sensors which have exceeded their limits/thresholds
228403831d35Sstevel  * and generates sysevents for the sensor values that have changed.
228503831d35Sstevel  */
228603831d35Sstevel /*ARGSUSED*/
228703831d35Sstevel static uint_t
sgenv_check_sensor_thresholds(void)228803831d35Sstevel sgenv_check_sensor_thresholds(void)
228903831d35Sstevel {
2290a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_poll_env()");
229103831d35Sstevel 
229203831d35Sstevel 	int	key;	/* loop through keys */
229303831d35Sstevel 	int	i;	/* loops through each sensor for each <key> */
229403831d35Sstevel 
229503831d35Sstevel 	env_sensor_t		sensor;
229603831d35Sstevel 	env_sensor_status_t	status;
229703831d35Sstevel 
229803831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
229903831d35Sstevel 
230003831d35Sstevel 	mutex_enter(&env_cache_lock);
230103831d35Sstevel 
230203831d35Sstevel 	for (key = 0; key < SGENV_MAX_HPU_KEYS; key++) {
230303831d35Sstevel 
230403831d35Sstevel 		if (vol_sensor_count[key] == 0)
230503831d35Sstevel 			continue;
230603831d35Sstevel 
230703831d35Sstevel 		for (i = 0; i < vol_sensor_count[key]; i++) {
230803831d35Sstevel 			sensor = env_cache[key][i];
230903831d35Sstevel 			status = sensor.sd_status;
231003831d35Sstevel 
231103831d35Sstevel 			if (SG_GET_SENSOR_STATUS(status) ==
231219397407SSherry Moore 			    SG_GET_PREV_SENSOR_STATUS(status)) {
231303831d35Sstevel 				continue;
231403831d35Sstevel 			}
231503831d35Sstevel 
231603831d35Sstevel 			/*
231703831d35Sstevel 			 * This sensor has changed in status since the last
231803831d35Sstevel 			 * time we polled - we need to inform the sysevent
231903831d35Sstevel 			 * framework.
232003831d35Sstevel 			 */
232103831d35Sstevel 			switch (sensor.sd_id.id.sensor_type) {
232203831d35Sstevel 			/*
232303831d35Sstevel 			 * we don't care about the pseudo sensors and
232403831d35Sstevel 			 * the Fan Status is notified by a separate
232503831d35Sstevel 			 * unsolicited event so we simply get the next
232603831d35Sstevel 			 * reading
232703831d35Sstevel 			 */
232803831d35Sstevel 			case SG_SENSOR_TYPE_ENVDB:
232903831d35Sstevel 			case SG_SENSOR_TYPE_COOLING:
233003831d35Sstevel 				continue;
233103831d35Sstevel 
233203831d35Sstevel 			/*
233303831d35Sstevel 			 * We have handled all the special cases by now.
233403831d35Sstevel 			 */
233503831d35Sstevel 			default:
233607d06da5SSurya Prakki 				(void) sgenv_process_threshold_event(sensor);
233703831d35Sstevel 				break;
233803831d35Sstevel 			}
233903831d35Sstevel 
234003831d35Sstevel 			SGENV_PRINT_POLL_INFO(sensor);
234103831d35Sstevel 		}
234203831d35Sstevel 	}
234303831d35Sstevel 	mutex_exit(&env_cache_lock);
234403831d35Sstevel 
234503831d35Sstevel 	return (DDI_SUCCESS);
234603831d35Sstevel }
234703831d35Sstevel 
234803831d35Sstevel 
234903831d35Sstevel /*
235003831d35Sstevel  * This function is passed in an array of length SSM_MAX_INSTANCES and
235103831d35Sstevel  * it searches OBP to for ssm nodes, and for each one if finds, it sets the
235203831d35Sstevel  * corresponding position in the array to TRUE.
235303831d35Sstevel  */
235403831d35Sstevel static void
sgenv_set_valid_node_positions(uint_t * node_present)235503831d35Sstevel sgenv_set_valid_node_positions(uint_t *node_present)
235603831d35Sstevel {
235703831d35Sstevel 	dev_info_t	*rdip;		/* root dev info ptr */
235803831d35Sstevel 	dev_info_t	*dip;
235903831d35Sstevel 
236003831d35Sstevel 	ASSERT(node_present != NULL);
236103831d35Sstevel 
236203831d35Sstevel 	rdip = ddi_root_node();
236303831d35Sstevel 
236403831d35Sstevel 	for (dip = ddi_get_child(rdip); dip != NULL;
236519397407SSherry Moore 	    dip = ddi_get_next_sibling(dip)) {
236603831d35Sstevel 		if (strncmp("ssm", ddi_node_name(dip), 3) == 0) {
236703831d35Sstevel 			int	value;
236803831d35Sstevel 
236903831d35Sstevel 			value = ddi_getprop(DDI_DEV_T_ANY, dip,
237019397407SSherry Moore 			    DDI_PROP_DONTPASS, "nodeid", 0);
237103831d35Sstevel 
237203831d35Sstevel 			/*
237303831d35Sstevel 			 * If we get a valid nodeID which has not already
237403831d35Sstevel 			 * been found in a previous call to this function,
237503831d35Sstevel 			 * then we set all 10 LSB bits to indicate there may
237603831d35Sstevel 			 * be a board present in each slot.
237703831d35Sstevel 			 *
237803831d35Sstevel 			 * It is the job of sgenv_get_board_info_data() to weed
237903831d35Sstevel 			 * out the invalid cases when we don't have a
238003831d35Sstevel 			 * DS chassis.
238103831d35Sstevel 			 *
238203831d35Sstevel 			 * NOTE: We make the assumption that a chassis cannot
238303831d35Sstevel 			 * be DR'ed out, which is true for a Serengeti.
238403831d35Sstevel 			 * By the time WildCat need this functionality Solaris
238503831d35Sstevel 			 * will be able to know what kind of a chassis is
238603831d35Sstevel 			 * present and there will be no need to try and work
238703831d35Sstevel 			 * this out from the msg_status from the mailbox.
238803831d35Sstevel 			 */
238903831d35Sstevel 			if ((value >= 0) &&
239019397407SSherry Moore 			    (value < SSM_MAX_INSTANCES) &&
239119397407SSherry Moore 			    (node_present[value] == SGENV_NO_NODE_EXISTS)) {
239203831d35Sstevel 				node_present[value] = SGENV_NODE_TYPE_DS;
239303831d35Sstevel 			}
239403831d35Sstevel 
239503831d35Sstevel 		}
239603831d35Sstevel 	}
239703831d35Sstevel }
239803831d35Sstevel 
239903831d35Sstevel 
240003831d35Sstevel static void
sgenv_set_sensor_status(env_sensor_t * sensor)240103831d35Sstevel sgenv_set_sensor_status(env_sensor_t *sensor)
240203831d35Sstevel {
240303831d35Sstevel 	env_sensor_status_t	*status;
240403831d35Sstevel 
240503831d35Sstevel 	ASSERT(sensor != NULL);
240603831d35Sstevel 	status = &sensor->sd_status;
240703831d35Sstevel 
240803831d35Sstevel 	/*
240903831d35Sstevel 	 * Save the previous status so we can compare them later
241003831d35Sstevel 	 */
241103831d35Sstevel 	SG_SET_PREV_SENSOR_STATUS(*status, *status);
241203831d35Sstevel 
241303831d35Sstevel 	switch (sensor->sd_id.id.sensor_type) {
241403831d35Sstevel 	case SG_SENSOR_TYPE_ENVDB:
241503831d35Sstevel 		/*
241603831d35Sstevel 		 * We want the status of this sensor to always be OK
241703831d35Sstevel 		 * The concept of limits/thresholds do not exist for it.
241803831d35Sstevel 		 */
241903831d35Sstevel 		SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_OK);
242003831d35Sstevel 		break;
242103831d35Sstevel 
242203831d35Sstevel 	case SG_SENSOR_TYPE_COOLING:
242303831d35Sstevel 		/*
242403831d35Sstevel 		 * Fans have no concept of limits/thresholds, they have a state
242503831d35Sstevel 		 * which we store in the <sd_status> field so that we can see
242603831d35Sstevel 		 * when this state is changed.
242703831d35Sstevel 		 */
242803831d35Sstevel 		if (sensor->sd_value == SGENV_FAN_SPEED_HIGH) {
242903831d35Sstevel 			SG_SET_SENSOR_STATUS(*status,
243019397407SSherry Moore 			    SG_SENSOR_STATUS_FAN_HIGH);
243103831d35Sstevel 
243203831d35Sstevel 		} else if (sensor->sd_value == SGENV_FAN_SPEED_LOW) {
243303831d35Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_FAN_LOW);
243403831d35Sstevel 
243503831d35Sstevel 		} else if (sensor->sd_value == SGENV_FAN_SPEED_OFF) {
243603831d35Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_FAN_OFF);
243703831d35Sstevel 
243803831d35Sstevel 		} else {
243903831d35Sstevel 			SG_SET_SENSOR_STATUS(*status,
244019397407SSherry Moore 			    SG_SENSOR_STATUS_FAN_FAIL);
244103831d35Sstevel 		}
244203831d35Sstevel 
244303831d35Sstevel 		/*
244403831d35Sstevel 		 * If this is the first time this fan status has been read,
244503831d35Sstevel 		 * then we need to initialize the previous reading to be the
244603831d35Sstevel 		 * same as the current reading so that an event is not
244703831d35Sstevel 		 * triggered.
244803831d35Sstevel 		 *
244903831d35Sstevel 		 * [ When the env_cache is being created, the status of the
245003831d35Sstevel 		 *   sensors is set to SG_SENSOR_STATUS_OK, which is not a
245103831d35Sstevel 		 *   valid Fan status ].
245203831d35Sstevel 		 */
245303831d35Sstevel 		if (SG_GET_PREV_SENSOR_STATUS(*status) == SG_SENSOR_STATUS_OK) {
245403831d35Sstevel 			SG_SET_PREV_SENSOR_STATUS(*status, *status);
245503831d35Sstevel 		}
245603831d35Sstevel 
245703831d35Sstevel 		break;
245803831d35Sstevel 
245903831d35Sstevel 	default:
246003831d35Sstevel 		if (sensor->sd_value > sensor->sd_hi) {
246103831d35Sstevel 			SG_SET_SENSOR_STATUS(*status,
246219397407SSherry Moore 			    SG_SENSOR_STATUS_HI_DANGER);
246303831d35Sstevel 
246403831d35Sstevel 		} else if (sensor->sd_value > sensor->sd_hi_warn) {
246503831d35Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_HI_WARN);
246603831d35Sstevel 
246703831d35Sstevel 		} else if (sensor->sd_value < sensor->sd_lo) {
246803831d35Sstevel 			SG_SET_SENSOR_STATUS(*status,
246919397407SSherry Moore 			    SG_SENSOR_STATUS_LO_DANGER);
247003831d35Sstevel 
247103831d35Sstevel 		} else if (sensor->sd_value < sensor->sd_lo_warn) {
247203831d35Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_LO_WARN);
247303831d35Sstevel 
247403831d35Sstevel 		} else {
247503831d35Sstevel 			SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_OK);
247603831d35Sstevel 		}
247703831d35Sstevel 		break;
247803831d35Sstevel 	}
247903831d35Sstevel }
248003831d35Sstevel 
248103831d35Sstevel 
248203831d35Sstevel 
248303831d35Sstevel 
248403831d35Sstevel /*
248503831d35Sstevel  * This function, when given an integer arg describing a HPU type,
248603831d35Sstevel  * returns the descriptive string associated with this HPU type.
248703831d35Sstevel  */
248803831d35Sstevel static const char *
sgenv_get_hpu_id_str(uint_t hpu_type)248903831d35Sstevel sgenv_get_hpu_id_str(uint_t hpu_type)
249003831d35Sstevel {
249103831d35Sstevel 	const hpu_value_t *hpu_list = hpus;
249203831d35Sstevel 
249303831d35Sstevel 	while (hpu_list->name != (char *)NULL) {
249403831d35Sstevel 		if (hpu_list->value == hpu_type)
249503831d35Sstevel 			return (hpu_list->IDstr);
249603831d35Sstevel 		else
249703831d35Sstevel 			hpu_list++;
249803831d35Sstevel 	}
249903831d35Sstevel 	return ((char *)NULL);
250003831d35Sstevel }
250103831d35Sstevel 
250203831d35Sstevel 
250303831d35Sstevel /*
250403831d35Sstevel  * This function, when given an integer arg describing a sensor part,
250503831d35Sstevel  * returns the descriptive string associated with this sensor part.
250603831d35Sstevel  */
250703831d35Sstevel static const char *
sgenv_get_part_str(uint_t sensor_part)250803831d35Sstevel sgenv_get_part_str(uint_t sensor_part)
250903831d35Sstevel {
251003831d35Sstevel 	const part_value_t *part_list = parts;
251103831d35Sstevel 
251203831d35Sstevel 	while (part_list->name != (char *)NULL) {
251303831d35Sstevel 		if (part_list->value == sensor_part)
251403831d35Sstevel 			return (part_list->name);
251503831d35Sstevel 		else
251603831d35Sstevel 			part_list++;
251703831d35Sstevel 	}
251803831d35Sstevel 	return ((char *)NULL);
251903831d35Sstevel }
252003831d35Sstevel 
252103831d35Sstevel 
252203831d35Sstevel /*
252303831d35Sstevel  * This function, when given an integer arg describing a sensor type,
252403831d35Sstevel  * returns the descriptive string associated with this sensor type.
252503831d35Sstevel  */
252603831d35Sstevel static const char *
sgenv_get_type_str(uint_t sensor_type)252703831d35Sstevel sgenv_get_type_str(uint_t sensor_type)
252803831d35Sstevel {
252903831d35Sstevel 	const type_value_t *type_list = types;
253003831d35Sstevel 
253103831d35Sstevel 	while (type_list->name != (char *)NULL) {
253203831d35Sstevel 		if (type_list->value == sensor_type)
253303831d35Sstevel 			return (type_list->name);
253403831d35Sstevel 		else
253503831d35Sstevel 			type_list++;
253603831d35Sstevel 	}
253703831d35Sstevel 	return ((char *)NULL);
253803831d35Sstevel }
253903831d35Sstevel 
254003831d35Sstevel 
254103831d35Sstevel /*
254203831d35Sstevel  * This function takes a sensor TagID and generates a string describing
254303831d35Sstevel  * where in the system the sensor is.
254403831d35Sstevel  */
254503831d35Sstevel static void
sgenv_tagid_to_string(sensor_id_t id,char * str)254603831d35Sstevel sgenv_tagid_to_string(sensor_id_t id, char *str)
254703831d35Sstevel {
254803831d35Sstevel 	const char	*hpu_str;
254903831d35Sstevel 	const char	*part_str;
255003831d35Sstevel 	const char	*type_str;
255103831d35Sstevel 
255203831d35Sstevel 	ASSERT(str != NULL);
255303831d35Sstevel 
255403831d35Sstevel 	hpu_str = sgenv_get_hpu_id_str(id.id.hpu_type);
255503831d35Sstevel 	part_str = sgenv_get_part_str(id.id.sensor_part);
255603831d35Sstevel 	type_str = sgenv_get_type_str(id.id.sensor_type);
255703831d35Sstevel 
255807d06da5SSurya Prakki 	(void) sprintf(str,
255907d06da5SSurya Prakki 	    "Sensor: Node=%d, Board=%s%d, Device=%s%d, Type=%s%d: reading has ",
256019397407SSherry Moore 	    id.id.node_id,
256119397407SSherry Moore 	    ((hpu_str != NULL) ? hpu_str : ""),
256219397407SSherry Moore 	    id.id.hpu_slot,
256319397407SSherry Moore 	    ((part_str != NULL) ? part_str : ""),
256419397407SSherry Moore 	    id.id.sensor_partnum,
256519397407SSherry Moore 	    ((type_str != NULL) ? type_str : ""),
256619397407SSherry Moore 	    id.id.sensor_typenum);
256703831d35Sstevel 
256803831d35Sstevel }
256903831d35Sstevel 
257003831d35Sstevel 
257103831d35Sstevel /*
257203831d35Sstevel  * This interrupt handler watches for unsolicited mailbox messages from the SC
257303831d35Sstevel  * telling it that the Keyswitch Position had changed. It then informs the
257403831d35Sstevel  * Sysevent Framework of this change.
257503831d35Sstevel  */
257603831d35Sstevel static uint_t
sgenv_keyswitch_handler(char * arg)257703831d35Sstevel sgenv_keyswitch_handler(char *arg)
257803831d35Sstevel {
2579a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_keyswitch_handler()");
258003831d35Sstevel 
258103831d35Sstevel 	sysevent_t		*ev = NULL;
258203831d35Sstevel 	sysevent_id_t		eid;
258303831d35Sstevel 	sysevent_value_t	se_val;
258403831d35Sstevel 	sysevent_attr_list_t	*ev_attr_list = NULL;
258503831d35Sstevel 	sg_event_key_position_t	*payload = NULL;
258603831d35Sstevel 	sbbc_msg_t		*msg = NULL;
258703831d35Sstevel 	int			err;
258803831d35Sstevel 
258903831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s called", f);
259003831d35Sstevel 
259103831d35Sstevel 	if (arg == NULL) {
259203831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
259303831d35Sstevel 		return (DDI_INTR_CLAIMED);
259403831d35Sstevel 	}
259503831d35Sstevel 
259603831d35Sstevel 	msg = (sbbc_msg_t *)arg;
259703831d35Sstevel 	if (msg->msg_buf == NULL) {
259803831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
259903831d35Sstevel 		return (DDI_INTR_CLAIMED);
260003831d35Sstevel 	}
260103831d35Sstevel 
260203831d35Sstevel 	payload = (sg_event_key_position_t *)msg->msg_buf;
260303831d35Sstevel 	if (payload == NULL) {
260403831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: payload == NULL", f);
260503831d35Sstevel 		return (DDI_INTR_CLAIMED);
260603831d35Sstevel 	}
260703831d35Sstevel 
260803831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "Key posn = %d", (int)*payload);
260903831d35Sstevel 
261003831d35Sstevel 
261103831d35Sstevel 	/*
261203831d35Sstevel 	 * Allocate memory for sysevent buffer.
261303831d35Sstevel 	 */
261403831d35Sstevel 	ev = sysevent_alloc(EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE,
261519397407SSherry Moore 	    EP_SGENV, SE_NOSLEEP);
261603831d35Sstevel 	if (ev == NULL) {
261703831d35Sstevel 		cmn_err(CE_WARN, "%s: Failed to alloc mem for %s/%s event",
261819397407SSherry Moore 		    f, EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE);
261903831d35Sstevel 		return (DDI_INTR_CLAIMED);
262003831d35Sstevel 	}
262103831d35Sstevel 
262203831d35Sstevel 
262303831d35Sstevel 	/*
262403831d35Sstevel 	 * Set the DOMAIN_WHAT_CHANGED attribute.
262503831d35Sstevel 	 */
262603831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
262703831d35Sstevel 	se_val.value.sv_string = DOMAIN_KEYSWITCH;
262803831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, DOMAIN_WHAT_CHANGED,
262919397407SSherry Moore 	    &se_val, SE_NOSLEEP);
263003831d35Sstevel 	if (err != 0) {
263103831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
263219397407SSherry Moore 		    DOMAIN_WHAT_CHANGED, EC_DOMAIN,
263319397407SSherry Moore 		    ESC_DOMAIN_STATE_CHANGE);
263403831d35Sstevel 		sysevent_free(ev);
263503831d35Sstevel 		return (DDI_INTR_CLAIMED);
263603831d35Sstevel 	}
263703831d35Sstevel 
263803831d35Sstevel 
263903831d35Sstevel 	/*
264003831d35Sstevel 	 * Log this event with sysevent framework.
264103831d35Sstevel 	 */
264203831d35Sstevel 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
264303831d35Sstevel 		cmn_err(CE_WARN, "Failed to attach attr list for %s/%s event",
264419397407SSherry Moore 		    EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE);
264503831d35Sstevel 		sysevent_free_attr(ev_attr_list);
264603831d35Sstevel 		sysevent_free(ev);
264703831d35Sstevel 		return (DDI_INTR_CLAIMED);
264803831d35Sstevel 	}
264903831d35Sstevel 	err = log_sysevent(ev, SE_NOSLEEP, &eid);
265003831d35Sstevel 	if (err != 0) {
265103831d35Sstevel 		cmn_err(CE_WARN, "Failed to log %s/%s event",
265219397407SSherry Moore 		    EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE);
265303831d35Sstevel 		sysevent_free(ev);
265403831d35Sstevel 		return (DDI_INTR_CLAIMED);
265503831d35Sstevel 	}
265603831d35Sstevel 
265703831d35Sstevel 	/* clean up */
265803831d35Sstevel 	sysevent_free(ev);
265903831d35Sstevel 
266003831d35Sstevel 	return (DDI_INTR_CLAIMED);
266103831d35Sstevel }
266203831d35Sstevel 
266303831d35Sstevel 
266403831d35Sstevel /*
266503831d35Sstevel  * This interrupt handler watches for unsolicited mailbox messages from the SC
266603831d35Sstevel  * telling it that an environmental sensor has exceeded a threshold/limit level
266703831d35Sstevel  * or has returned to normal having previously exceeded a threshold/limit level.
266803831d35Sstevel  * It then informs the Sysevent Framework of this change and updates the
266903831d35Sstevel  * env_cache.
267003831d35Sstevel  */
267103831d35Sstevel static uint_t
sgenv_env_data_handler(char * arg)267203831d35Sstevel sgenv_env_data_handler(char *arg)
267303831d35Sstevel {
2674a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_env_data_handler()");
267503831d35Sstevel 
267603831d35Sstevel 	sg_event_env_changed_t	*payload = NULL;
267703831d35Sstevel 	sbbc_msg_t		*msg = NULL;
267803831d35Sstevel 
267903831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
268003831d35Sstevel 
268103831d35Sstevel 	if (arg == NULL) {
268203831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
268303831d35Sstevel 		return (DDI_INTR_CLAIMED);
268403831d35Sstevel 	}
268503831d35Sstevel 
268603831d35Sstevel 	msg = (sbbc_msg_t *)arg;
268703831d35Sstevel 
268803831d35Sstevel 	if (msg->msg_buf == NULL) {
268903831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
269003831d35Sstevel 		return (DDI_INTR_CLAIMED);
269103831d35Sstevel 	}
269203831d35Sstevel 
269303831d35Sstevel 	payload = (sg_event_env_changed_t *)msg->msg_buf;
269403831d35Sstevel 
269503831d35Sstevel 	/*
269603831d35Sstevel 	 * We check the first field of the msg_buf to see if the event_type
269703831d35Sstevel 	 * is SC_EVENT_ENV, if it is then we handle the event.
269803831d35Sstevel 	 */
269903831d35Sstevel 	if (payload->event_type != SC_EVENT_ENV) {
270003831d35Sstevel 		return (DDI_INTR_CLAIMED);
270103831d35Sstevel 	}
270203831d35Sstevel 
270303831d35Sstevel 	/*
270403831d35Sstevel 	 * We now need to signal to the env background thread to ask the SC
270503831d35Sstevel 	 * for env readings and discover which sensor caused the SC to send
270603831d35Sstevel 	 * the ENV event before sending a sysevent to userland.
270703831d35Sstevel 	 */
270803831d35Sstevel 	sgenv_indicate_cache_update_needed(ENV_CACHE);
270903831d35Sstevel 
271003831d35Sstevel 	return (DDI_INTR_CLAIMED);
271103831d35Sstevel }
271203831d35Sstevel 
271303831d35Sstevel 
271403831d35Sstevel /*
271503831d35Sstevel  * This interrupt handler watches for unsolicited mailbox messages from the SC
271603831d35Sstevel  * telling it that the status of a fan has changed. We register a sysevent
271703831d35Sstevel  * and trigger a softint to update the env cache.
271803831d35Sstevel  */
271903831d35Sstevel static uint_t
sgenv_fan_status_handler(char * arg)272003831d35Sstevel sgenv_fan_status_handler(char *arg)
272103831d35Sstevel {
2722a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_fan_status_handler()");
272303831d35Sstevel 
272403831d35Sstevel 	sysevent_t		*ev = NULL;
272503831d35Sstevel 	sysevent_id_t		eid;
272603831d35Sstevel 	sysevent_value_t	se_val;
272703831d35Sstevel 	sysevent_attr_list_t	*ev_attr_list = NULL;
272803831d35Sstevel 	sg_event_fan_status_t	*payload = NULL;
272903831d35Sstevel 	sbbc_msg_t		*msg = NULL;
273003831d35Sstevel 	char			fan_str[MAXNAMELEN];
273103831d35Sstevel 	int			err;
273203831d35Sstevel 
273303831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
273403831d35Sstevel 
273503831d35Sstevel 	if (arg == NULL) {
273603831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
273703831d35Sstevel 		return (DDI_INTR_CLAIMED);
273803831d35Sstevel 	}
273903831d35Sstevel 
274003831d35Sstevel 	msg = (sbbc_msg_t *)arg;
274103831d35Sstevel 
274203831d35Sstevel 	/*
274303831d35Sstevel 	 * We check the first field of the msg_buf to see if the event_type
274403831d35Sstevel 	 * is SC_EVENT_FAN
274503831d35Sstevel 	 */
274603831d35Sstevel 	if (msg->msg_buf == NULL) {
274703831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
274803831d35Sstevel 		return (DDI_INTR_CLAIMED);
274903831d35Sstevel 	}
275003831d35Sstevel 
275103831d35Sstevel 	payload = (sg_event_fan_status_t *)msg->msg_buf;
275203831d35Sstevel 
275303831d35Sstevel 	/*
275403831d35Sstevel 	 * If another type of ENV Event triggered this handler then we simply
275503831d35Sstevel 	 * return now.
275603831d35Sstevel 	 */
275703831d35Sstevel 	if (payload->event_type != SC_EVENT_FAN) {
275803831d35Sstevel 		return (DDI_INTR_CLAIMED);
275903831d35Sstevel 	}
276003831d35Sstevel 
276103831d35Sstevel 	/*
276203831d35Sstevel 	 * Allocate memory for sysevent buffer.
276303831d35Sstevel 	 */
276403831d35Sstevel 	ev = sysevent_alloc(EC_ENV, ESC_ENV_FAN, EP_SGENV, SE_NOSLEEP);
276503831d35Sstevel 	if (ev == NULL) {
276603831d35Sstevel 		cmn_err(CE_WARN, "%s: Failed to alloc mem for %s/%s event",
276719397407SSherry Moore 		    f, EC_ENV, ESC_ENV_FAN);
276803831d35Sstevel 		return (DDI_INTR_CLAIMED);
276903831d35Sstevel 	}
277003831d35Sstevel 
277103831d35Sstevel 
277203831d35Sstevel 	/*
277303831d35Sstevel 	 * Set the following attributes for this event:
277403831d35Sstevel 	 *
277503831d35Sstevel 	 *	ENV_FRU_ID
277603831d35Sstevel 	 *	ENV_FRU_RESOURCE_ID
277703831d35Sstevel 	 *	ENV_FRU_DEVICE
277803831d35Sstevel 	 *	ENV_FRU_STATE
277903831d35Sstevel 	 *	ENV_MSG
278003831d35Sstevel 	 *
278103831d35Sstevel 	 */
278203831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
278303831d35Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
278403831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_ID, &se_val, SE_NOSLEEP);
278503831d35Sstevel 	if (err != 0) {
278603831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
278719397407SSherry Moore 		    ENV_FRU_ID, EC_ENV, ESC_ENV_FAN);
278803831d35Sstevel 		sysevent_free(ev);
278903831d35Sstevel 		return (DDI_INTR_CLAIMED);
279003831d35Sstevel 	}
279103831d35Sstevel 
279203831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
279303831d35Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
279403831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_RESOURCE_ID,
279519397407SSherry Moore 	    &se_val, SE_NOSLEEP);
279603831d35Sstevel 	if (err != 0) {
279703831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
279819397407SSherry Moore 		    ENV_FRU_RESOURCE_ID, EC_ENV, ESC_ENV_FAN);
279903831d35Sstevel 		sysevent_free_attr(ev_attr_list);
280003831d35Sstevel 		sysevent_free(ev);
280103831d35Sstevel 		return (DDI_INTR_CLAIMED);
280203831d35Sstevel 	}
280303831d35Sstevel 
280403831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
280503831d35Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
280603831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_DEVICE,
280719397407SSherry Moore 	    &se_val, SE_NOSLEEP);
280803831d35Sstevel 	if (err != 0) {
280903831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
281019397407SSherry Moore 		    ENV_FRU_DEVICE, EC_ENV, ESC_ENV_FAN);
281103831d35Sstevel 		sysevent_free_attr(ev_attr_list);
281203831d35Sstevel 		sysevent_free(ev);
281303831d35Sstevel 		return (DDI_INTR_CLAIMED);
281403831d35Sstevel 	}
281503831d35Sstevel 
281603831d35Sstevel 	/*
281703831d35Sstevel 	 * Checks the fan to see if it has failed.
281803831d35Sstevel 	 */
281903831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_INT32;
282003831d35Sstevel 	switch (payload->fan_speed) {
282103831d35Sstevel 	case SGENV_FAN_SPEED_OFF:
282203831d35Sstevel 	case SGENV_FAN_SPEED_LOW:
282303831d35Sstevel 	case SGENV_FAN_SPEED_HIGH:
282403831d35Sstevel 		se_val.value.sv_int32 = ENV_OK;
282503831d35Sstevel 		break;
282603831d35Sstevel 
282703831d35Sstevel 	case SGENV_FAN_SPEED_UNKNOWN:
282803831d35Sstevel 	default:
282903831d35Sstevel 		se_val.value.sv_int32 = ENV_FAILED;
283003831d35Sstevel 		break;
283103831d35Sstevel 	}
283203831d35Sstevel 
283303831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_STATE,
283419397407SSherry Moore 	    &se_val, SE_NOSLEEP);
283503831d35Sstevel 	if (err != 0) {
283603831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
283719397407SSherry Moore 		    ENV_FRU_STATE, EC_ENV, ESC_ENV_FAN);
283803831d35Sstevel 		sysevent_free_attr(ev_attr_list);
283903831d35Sstevel 		sysevent_free(ev);
284003831d35Sstevel 		return (DDI_INTR_CLAIMED);
284103831d35Sstevel 	}
284203831d35Sstevel 
284303831d35Sstevel 
284403831d35Sstevel 	/*
284503831d35Sstevel 	 * Create the message to be sent to sysevent.
284603831d35Sstevel 	 */
284707d06da5SSurya Prakki 	(void) sprintf(fan_str,
284807d06da5SSurya Prakki 	    "The status of the fan in Node%d/Slot%d is now ",
284919397407SSherry Moore 	    payload->node_id, payload->slot_number);
285003831d35Sstevel 	switch (payload->fan_speed) {
285103831d35Sstevel 	case SGENV_FAN_SPEED_OFF:
285207d06da5SSurya Prakki 		(void) strcat(fan_str, SGENV_FAN_SPEED_OFF_STR);
285303831d35Sstevel 		break;
285403831d35Sstevel 
285503831d35Sstevel 	case SGENV_FAN_SPEED_LOW:
285607d06da5SSurya Prakki 		(void) strcat(fan_str, SGENV_FAN_SPEED_LOW_STR);
285703831d35Sstevel 		break;
285803831d35Sstevel 
285903831d35Sstevel 	case SGENV_FAN_SPEED_HIGH:
286007d06da5SSurya Prakki 		(void) strcat(fan_str, SGENV_FAN_SPEED_HIGH_STR);
286103831d35Sstevel 		break;
286203831d35Sstevel 
286303831d35Sstevel 	case SGENV_FAN_SPEED_UNKNOWN:
286403831d35Sstevel 	default:
286507d06da5SSurya Prakki 		(void) strcat(fan_str, SGENV_FAN_SPEED_UNKNOWN_STR);
286603831d35Sstevel 		break;
286703831d35Sstevel 	}
286803831d35Sstevel 
286903831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "Fan: %s", fan_str);
287003831d35Sstevel 
287103831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
287203831d35Sstevel 	se_val.value.sv_string = fan_str;
287303831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_MSG, &se_val, SE_NOSLEEP);
287403831d35Sstevel 	if (err != 0) {
287503831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
287619397407SSherry Moore 		    ENV_MSG, EC_ENV, ESC_ENV_FAN);
287703831d35Sstevel 		sysevent_free_attr(ev_attr_list);
287803831d35Sstevel 		sysevent_free(ev);
287903831d35Sstevel 		return (DDI_INTR_CLAIMED);
288003831d35Sstevel 	}
288103831d35Sstevel 
288203831d35Sstevel 
288303831d35Sstevel 	/*
288403831d35Sstevel 	 * Log this event with sysevent framework.
288503831d35Sstevel 	 */
288603831d35Sstevel 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
288703831d35Sstevel 		cmn_err(CE_WARN, "Failed to attach attr list for %s/%s event",
288819397407SSherry Moore 		    EC_ENV, ESC_ENV_FAN);
288903831d35Sstevel 		sysevent_free_attr(ev_attr_list);
289003831d35Sstevel 		sysevent_free(ev);
289103831d35Sstevel 		return (DDI_INTR_CLAIMED);
289203831d35Sstevel 	}
289303831d35Sstevel 	err = log_sysevent(ev, SE_NOSLEEP, &eid);
289403831d35Sstevel 	if (err != 0) {
289503831d35Sstevel 		cmn_err(CE_WARN, "Failed to log %s/%s event",
289619397407SSherry Moore 		    EC_ENV, ESC_ENV_FAN);
289703831d35Sstevel 		sysevent_free(ev);
289803831d35Sstevel 		return (DDI_INTR_CLAIMED);
289903831d35Sstevel 	}
290003831d35Sstevel 	sysevent_free(ev);
290103831d35Sstevel 
290203831d35Sstevel 	/*
290303831d35Sstevel 	 * We now need to signal to the env background thread to ask the SC
290403831d35Sstevel 	 * for env readings and discover which sensor caused the SC to send
290503831d35Sstevel 	 * the ENV event before sending a sysevent to userland.
290603831d35Sstevel 	 */
290703831d35Sstevel 	sgenv_indicate_cache_update_needed(ENV_CACHE);
290803831d35Sstevel 
290903831d35Sstevel 	return (DDI_INTR_CLAIMED);
291003831d35Sstevel }
291103831d35Sstevel 
291203831d35Sstevel 
291303831d35Sstevel /*
291403831d35Sstevel  * This function informs the Sysevent Framework that a temperature, voltage
291503831d35Sstevel  * or current reading for a sensor has exceeded its threshold/limit value or
291603831d35Sstevel  * that the reading has returned to a safe value having exceeded its
291703831d35Sstevel  * threshold/limit value previously.
291803831d35Sstevel  */
291903831d35Sstevel static int
sgenv_process_threshold_event(env_sensor_t sensor)292003831d35Sstevel sgenv_process_threshold_event(env_sensor_t sensor)
292103831d35Sstevel {
2922a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_process_threshold_event()");
292303831d35Sstevel 
292403831d35Sstevel 	sysevent_t		*ev = NULL;
292503831d35Sstevel 	sysevent_id_t		eid;
292603831d35Sstevel 	sysevent_value_t	se_val;
292703831d35Sstevel 	sysevent_attr_list_t	*ev_attr_list = NULL;
292803831d35Sstevel 	int			err;
292903831d35Sstevel 
293003831d35Sstevel 	char	sensor_str[MAX_TAG_ID_STR_LEN];	/* holds the sensor TagID */
293103831d35Sstevel 
293203831d35Sstevel 	/*
293303831d35Sstevel 	 * This function handles the case when a temperature reading passes
293403831d35Sstevel 	 * a threshold/limit level and also the case when there are power
293503831d35Sstevel 	 * fluctuations (voltage/current readings pass a threshold/limit level)
293603831d35Sstevel 	 * so we need to work out which case it is.
293703831d35Sstevel 	 *
293803831d35Sstevel 	 * if <temp_event_type> is TRUE, then need to handle an event
293903831d35Sstevel 	 * of type ESC_ENV_TEMP.
294003831d35Sstevel 	 */
294103831d35Sstevel 	int	temp_event_type;
294203831d35Sstevel 
294303831d35Sstevel 	switch (sensor.sd_id.id.sensor_type) {
294403831d35Sstevel 	case SG_SENSOR_TYPE_TEMPERATURE:
294503831d35Sstevel 		temp_event_type = TRUE;
294603831d35Sstevel 		ev = sysevent_alloc(EC_ENV, ESC_ENV_TEMP, EP_SGENV, SE_NOSLEEP);
294703831d35Sstevel 		if (ev == NULL) {
294803831d35Sstevel 			cmn_err(CE_WARN, "Failed to allocate sysevent buffer "
294919397407SSherry Moore 			    "for %s/%s event", EC_ENV, ESC_ENV_TEMP);
295003831d35Sstevel 			return (DDI_FAILURE);
295103831d35Sstevel 		}
295203831d35Sstevel 		break;
295303831d35Sstevel 
295403831d35Sstevel 	default:
295503831d35Sstevel 		temp_event_type = FALSE;
295603831d35Sstevel 		ev = sysevent_alloc(EC_ENV, ESC_ENV_POWER,
295719397407SSherry Moore 		    EP_SGENV, SE_NOSLEEP);
295803831d35Sstevel 		if (ev == NULL) {
295903831d35Sstevel 			cmn_err(CE_WARN, "Failed to allocate sysevent buffer "
296019397407SSherry Moore 			    "for %s/%s event", EC_ENV, ESC_ENV_POWER);
296103831d35Sstevel 			return (DDI_FAILURE);
296203831d35Sstevel 		}
296303831d35Sstevel 		break;
296403831d35Sstevel 	}
296503831d35Sstevel 
296603831d35Sstevel 
296703831d35Sstevel 	/*
296803831d35Sstevel 	 * Set the following attributes for this event:
296903831d35Sstevel 	 *
297003831d35Sstevel 	 *	ENV_FRU_ID
297103831d35Sstevel 	 *	ENV_FRU_RESOURCE_ID
297203831d35Sstevel 	 *	ENV_FRU_DEVICE
297303831d35Sstevel 	 *	ENV_FRU_STATE
297403831d35Sstevel 	 *	ENV_MSG
297503831d35Sstevel 	 *
297603831d35Sstevel 	 */
297703831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
297803831d35Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
297903831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_ID, &se_val, SE_NOSLEEP);
298003831d35Sstevel 	if (err != 0) {
298103831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
298219397407SSherry Moore 		    ENV_FRU_ID, EC_ENV,
298319397407SSherry Moore 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
298403831d35Sstevel 		sysevent_free(ev);
298503831d35Sstevel 		return (DDI_FAILURE);
298603831d35Sstevel 	}
298703831d35Sstevel 
298803831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
298903831d35Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
299003831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_RESOURCE_ID,
299119397407SSherry Moore 	    &se_val, SE_NOSLEEP);
299203831d35Sstevel 	if (err != 0) {
299303831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
299419397407SSherry Moore 		    ENV_FRU_RESOURCE_ID, EC_ENV,
299519397407SSherry Moore 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
299603831d35Sstevel 		sysevent_free_attr(ev_attr_list);
299703831d35Sstevel 		sysevent_free(ev);
299803831d35Sstevel 		return (DDI_FAILURE);
299903831d35Sstevel 	}
300003831d35Sstevel 
300103831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
300203831d35Sstevel 	se_val.value.sv_string = ENV_RESERVED_ATTR;
300303831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_DEVICE,
300419397407SSherry Moore 	    &se_val, SE_NOSLEEP);
300503831d35Sstevel 	if (err != 0) {
300603831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
300719397407SSherry Moore 		    ENV_FRU_DEVICE, EC_ENV,
300819397407SSherry Moore 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
300903831d35Sstevel 		sysevent_free_attr(ev_attr_list);
301003831d35Sstevel 		sysevent_free(ev);
301103831d35Sstevel 		return (DDI_FAILURE);
301203831d35Sstevel 	}
301303831d35Sstevel 
301403831d35Sstevel 
301503831d35Sstevel 	/*
301603831d35Sstevel 	 * We need to find out the status of the reading.
301703831d35Sstevel 	 */
301803831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_INT32;
301903831d35Sstevel 	switch (SG_GET_SENSOR_STATUS(sensor.sd_status)) {
302003831d35Sstevel 	case SG_SENSOR_STATUS_OK:
302103831d35Sstevel 		se_val.value.sv_int32 = ENV_OK;
302203831d35Sstevel 		break;
302303831d35Sstevel 
302403831d35Sstevel 	case SG_SENSOR_STATUS_LO_WARN:
302503831d35Sstevel 	case SG_SENSOR_STATUS_HI_WARN:
302603831d35Sstevel 		se_val.value.sv_int32 = ENV_WARNING;
302703831d35Sstevel 		break;
302803831d35Sstevel 
302903831d35Sstevel 	case SG_SENSOR_STATUS_LO_DANGER:
303003831d35Sstevel 	case SG_SENSOR_STATUS_HI_DANGER:
303103831d35Sstevel 	default:
303203831d35Sstevel 		se_val.value.sv_int32 = ENV_FAILED;
303303831d35Sstevel 		break;
303403831d35Sstevel 	}
303503831d35Sstevel 
303603831d35Sstevel 	/*
303703831d35Sstevel 	 * Add ENV_FRU_STATE attribute.
303803831d35Sstevel 	 */
303903831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_FRU_STATE,
304019397407SSherry Moore 	    &se_val, SE_NOSLEEP);
304103831d35Sstevel 	if (err != 0) {
304203831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr[%s] for %s/%s event "
304319397407SSherry Moore 		    "(Err=%d)", ENV_FRU_STATE, EC_ENV,
304419397407SSherry Moore 		    (temp_event_type ? ESC_ENV_TEMP: ESC_ENV_POWER),
304519397407SSherry Moore 		    err);
304603831d35Sstevel 		sysevent_free_attr(ev_attr_list);
304703831d35Sstevel 		sysevent_free(ev);
304803831d35Sstevel 		return (DDI_FAILURE);
304903831d35Sstevel 	}
305003831d35Sstevel 
305103831d35Sstevel 
305203831d35Sstevel 	/*
305303831d35Sstevel 	 * Save the sensor TagID as a string so that a meaningful message
305403831d35Sstevel 	 * can be passed to as part of the ENV_MSG attribute.
305503831d35Sstevel 	 */
305603831d35Sstevel 	sgenv_tagid_to_string(sensor.sd_id, sensor_str);
305703831d35Sstevel 
305803831d35Sstevel 	/*
305903831d35Sstevel 	 * We need to add a string stating what type of event occurred.
306003831d35Sstevel 	 */
306103831d35Sstevel 	switch (SG_GET_SENSOR_STATUS(sensor.sd_status)) {
306203831d35Sstevel 	case SG_SENSOR_STATUS_OK:
306307d06da5SSurya Prakki 		(void) strcat(sensor_str, SGENV_EVENT_MSG_OK);
306403831d35Sstevel 		break;
306503831d35Sstevel 
306603831d35Sstevel 	case SG_SENSOR_STATUS_LO_WARN:
306707d06da5SSurya Prakki 		(void) strcat(sensor_str, SGENV_EVENT_MSG_LO_WARN);
306803831d35Sstevel 		break;
306903831d35Sstevel 
307003831d35Sstevel 	case SG_SENSOR_STATUS_HI_WARN:
307107d06da5SSurya Prakki 		(void) strcat(sensor_str, SGENV_EVENT_MSG_HI_WARN);
307203831d35Sstevel 		break;
307303831d35Sstevel 
307403831d35Sstevel 	case SG_SENSOR_STATUS_LO_DANGER:
307507d06da5SSurya Prakki 		(void) strcat(sensor_str, SGENV_EVENT_MSG_LO_DANGER);
307603831d35Sstevel 		break;
307703831d35Sstevel 
307803831d35Sstevel 	case SG_SENSOR_STATUS_HI_DANGER:
307907d06da5SSurya Prakki 		(void) strcat(sensor_str, SGENV_EVENT_MSG_HI_DANGER);
308003831d35Sstevel 		break;
308103831d35Sstevel 
308203831d35Sstevel 	default:
308303831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: Unknown sensor status", f);
308407d06da5SSurya Prakki 		(void) strcat(sensor_str, SGENV_EVENT_MSG_UNKNOWN);
308503831d35Sstevel 		break;
308603831d35Sstevel 	}
308703831d35Sstevel 
308803831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "Temp/Power: %s", sensor_str);
308903831d35Sstevel 
309003831d35Sstevel 	/*
309103831d35Sstevel 	 * Add ENV_MSG attribute.
309203831d35Sstevel 	 */
309303831d35Sstevel 	se_val.value_type = SE_DATA_TYPE_STRING;
309403831d35Sstevel 	se_val.value.sv_string = sensor_str;
309503831d35Sstevel 	err = sysevent_add_attr(&ev_attr_list, ENV_MSG, &se_val, SE_NOSLEEP);
309603831d35Sstevel 	if (err != 0) {
309703831d35Sstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
309819397407SSherry Moore 		    ENV_MSG, EC_ENV,
309919397407SSherry Moore 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
310003831d35Sstevel 		sysevent_free_attr(ev_attr_list);
310103831d35Sstevel 		sysevent_free(ev);
310203831d35Sstevel 		return (DDI_FAILURE);
310303831d35Sstevel 	}
310403831d35Sstevel 
310503831d35Sstevel 
310603831d35Sstevel 	/*
310703831d35Sstevel 	 * Log this event with sysevent framework.
310803831d35Sstevel 	 */
310903831d35Sstevel 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
311003831d35Sstevel 		cmn_err(CE_WARN, "Failed to attach attr list for %s/%s event",
311119397407SSherry Moore 		    EC_ENV,
311219397407SSherry Moore 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
311303831d35Sstevel 		sysevent_free_attr(ev_attr_list);
311403831d35Sstevel 		sysevent_free(ev);
311503831d35Sstevel 		return (DDI_FAILURE);
311603831d35Sstevel 	}
311703831d35Sstevel 	err = log_sysevent(ev, SE_NOSLEEP, &eid);
311803831d35Sstevel 	if (err != 0) {
311903831d35Sstevel 		cmn_err(CE_WARN, "Failed to log %s/%s event", EC_ENV,
312019397407SSherry Moore 		    (temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
312103831d35Sstevel 		sysevent_free(ev);
312203831d35Sstevel 		return (DDI_FAILURE);
312303831d35Sstevel 	}
312403831d35Sstevel 	sysevent_free(ev);
312503831d35Sstevel 
312603831d35Sstevel 	return (DDI_SUCCESS);
312703831d35Sstevel }
312803831d35Sstevel 
312903831d35Sstevel 
313003831d35Sstevel /*
313103831d35Sstevel  * This function gets called when sgenv is notified of a DR event.
313203831d35Sstevel  * We need to update the board and env caches to ensure that they
313303831d35Sstevel  * now contain the latest system information..
313403831d35Sstevel  */
313503831d35Sstevel static uint_t
sgenv_dr_event_handler(char * arg)313603831d35Sstevel sgenv_dr_event_handler(char *arg)
313703831d35Sstevel {
3138a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_dr_event_handler()");
313903831d35Sstevel 
314003831d35Sstevel 	sg_system_fru_descriptor_t	*payload = NULL;
314103831d35Sstevel 	sbbc_msg_t			*msg = NULL;
314203831d35Sstevel 
314303831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
314403831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: Start: %lld", f, gethrtime());
314503831d35Sstevel 
314603831d35Sstevel 
314703831d35Sstevel 	if (arg == NULL) {
314803831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
314903831d35Sstevel 		return (DDI_INTR_CLAIMED);
315003831d35Sstevel 	}
315103831d35Sstevel 
315203831d35Sstevel 	msg = (sbbc_msg_t *)arg;
315303831d35Sstevel 
315403831d35Sstevel 	if (msg->msg_buf == NULL) {
315503831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
315603831d35Sstevel 		return (DDI_INTR_CLAIMED);
315703831d35Sstevel 	}
315803831d35Sstevel 
315903831d35Sstevel 	payload = (sg_system_fru_descriptor_t *)msg->msg_buf;
316003831d35Sstevel 
316103831d35Sstevel 	/*
316203831d35Sstevel 	 * We check the event_details field of the msg_buf to see if
316303831d35Sstevel 	 * we need to invalidate the caches
316403831d35Sstevel 	 */
316503831d35Sstevel 	switch (payload->event_details) {
316603831d35Sstevel 	case SG_EVT_BOARD_ABSENT:
316703831d35Sstevel 	case SG_EVT_BOARD_PRESENT:
316803831d35Sstevel 	case SG_EVT_UNASSIGN:
316903831d35Sstevel 	case SG_EVT_ASSIGN:
317003831d35Sstevel 	case SG_EVT_UNAVAILABLE:
317103831d35Sstevel 	case SG_EVT_AVAILABLE:
317203831d35Sstevel 	case SG_EVT_POWER_OFF:
317303831d35Sstevel 	case SG_EVT_POWER_ON:
317403831d35Sstevel 	case SG_EVT_PASSED_TEST:
317503831d35Sstevel 	case SG_EVT_FAILED_TEST:
317603831d35Sstevel 		/*
317703831d35Sstevel 		 * We now need to signal to the background threads to poll the
317803831d35Sstevel 		 * SC for env readings and board info which may have changed
317903831d35Sstevel 		 * as a result of the DR changes. This will cause the
318003831d35Sstevel 		 * env_cache and the board_cache to be updated.
318103831d35Sstevel 		 */
318203831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: about to signal to background "
318319397407SSherry Moore 		    "threads due to event %d.", f, payload->event_details);
318403831d35Sstevel 
318503831d35Sstevel 		sgenv_indicate_cache_update_needed(ENV_CACHE);
318603831d35Sstevel 		sgenv_indicate_cache_update_needed(BOARD_CACHE);
318703831d35Sstevel 
318803831d35Sstevel 		break;
318903831d35Sstevel 
319003831d35Sstevel 	default:
319103831d35Sstevel 		DCMN_ERR_EVENT(CE_NOTE, "%s: Unknown DR event type.", f);
319203831d35Sstevel 		break;
319303831d35Sstevel 	}
319403831d35Sstevel 
319503831d35Sstevel 	DCMN_ERR_EVENT(CE_NOTE, "%s: Finish: %lld", f, gethrtime());
319603831d35Sstevel 
319703831d35Sstevel 	return (DDI_INTR_CLAIMED);
319803831d35Sstevel }
319903831d35Sstevel 
320003831d35Sstevel 
320103831d35Sstevel /*
320203831d35Sstevel  * This function is called by the interrupt handlers watching for ENV/DR events
320303831d35Sstevel  * from the SC. It indicates to the thread responsible for the cache specified
320403831d35Sstevel  * that it needs to update its data.
320503831d35Sstevel  */
320603831d35Sstevel static void
sgenv_indicate_cache_update_needed(int cache_type)320703831d35Sstevel sgenv_indicate_cache_update_needed(int cache_type)
320803831d35Sstevel {
3209a5df24e1Sarutz 	DCMN_ERR_S(f, "sgenv_indicate_cache_update_needed()");
321003831d35Sstevel 
321103831d35Sstevel 	/*
321203831d35Sstevel 	 * If the cache is already being updated, we set a flag to
321303831d35Sstevel 	 * inform the thread that it needs to reread the data when
321403831d35Sstevel 	 * it is finished as we cannot be sure if the data was read
321503831d35Sstevel 	 * before or after the time this handler was triggered.
321603831d35Sstevel 	 *
321703831d35Sstevel 	 * Otherwise the thread is waiting for us and we signal
321803831d35Sstevel 	 * to it to start reading the data.
321903831d35Sstevel 	 */
322003831d35Sstevel 	switch (cache_type) {
322103831d35Sstevel 	case ENV_CACHE:
322203831d35Sstevel 		mutex_enter(&env_flag_lock);
322303831d35Sstevel 		if (env_cache_updating) {
322403831d35Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Thread already "
322519397407SSherry Moore 			    "updating env cache", f);
322603831d35Sstevel 			env_cache_update_needed = B_TRUE;
322703831d35Sstevel 
322803831d35Sstevel 		} else {
322903831d35Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Sending signal "
323019397407SSherry Moore 			    "to env thread", f);
323103831d35Sstevel 			cv_signal(&env_flag_cond);
323203831d35Sstevel 		}
323303831d35Sstevel 		mutex_exit(&env_flag_lock);
323403831d35Sstevel 		break;
323503831d35Sstevel 
323603831d35Sstevel 	case BOARD_CACHE:
323703831d35Sstevel 		mutex_enter(&board_flag_lock);
323803831d35Sstevel 		if (board_cache_updating) {
323903831d35Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Thread already "
324019397407SSherry Moore 			    "updating board cache", f);
324103831d35Sstevel 			board_cache_update_needed = B_TRUE;
324203831d35Sstevel 
324303831d35Sstevel 		} else {
324403831d35Sstevel 			DCMN_ERR_THREAD(CE_NOTE, "%s: Sending signal "
324519397407SSherry Moore 			    "to board thread", f);
324603831d35Sstevel 			cv_signal(&board_flag_cond);
324703831d35Sstevel 		}
324803831d35Sstevel 		mutex_exit(&board_flag_lock);
324903831d35Sstevel 		break;
325003831d35Sstevel 
325103831d35Sstevel 	default:
325203831d35Sstevel 		DCMN_ERR(CE_NOTE, "%s: Unknown cache type:0x%x", f, cache_type);
325303831d35Sstevel 		break;
325403831d35Sstevel 	}
325503831d35Sstevel }
3256