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