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 /* 23*07d06da5SSurya 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 */ 26003831d35Sstevel static sg_board_info_t board_cache[SG_MAX_BDS] = {NULL}; 26103831d35Sstevel static sg_board_info_t board_cache_snapshot[SG_MAX_BDS] = {NULL}; 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 41403831d35Sstevel _init(void) 41503831d35Sstevel { 41603831d35Sstevel int error = 0; 41703831d35Sstevel 41803831d35Sstevel error = ddi_soft_state_init(&sgenv_statep, 41903831d35Sstevel 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 45203831d35Sstevel _info(struct modinfo *modinfop) 45303831d35Sstevel { 45403831d35Sstevel return (mod_info(&modlinkage, modinfop)); 45503831d35Sstevel } 45603831d35Sstevel 45703831d35Sstevel 45803831d35Sstevel int 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 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 " 50003831d35Sstevel "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 " 50803831d35Sstevel "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, 54903831d35Sstevel instance, DDI_PSEUDO, NULL); 55003831d35Sstevel if (err != DDI_SUCCESS) { 55103831d35Sstevel sgenv_remove_kstats(softsp); 552*07d06da5SSurya 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"); 564*07d06da5SSurya Prakki (void) sgenv_remove_intr_handlers(); 56503831d35Sstevel sgenv_remove_kstats(softsp); 566*07d06da5SSurya 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 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 " 60003831d35Sstevel "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 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, 64703831d35Sstevel "misc", KSTAT_TYPE_NAMED, 1, NULL); 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], 65403831d35Sstevel POSITION_KSTAT_NAME, 65503831d35Sstevel 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, 67303831d35Sstevel "misc", KSTAT_TYPE_RAW, 0, 67403831d35Sstevel 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, 69803831d35Sstevel "misc", KSTAT_TYPE_RAW, 0, 69903831d35Sstevel 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 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 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, 77803831d35Sstevel &keysw_payload_msg, NULL, &keysw_hdlr_lock); 77903831d35Sstevel if (err != 0) { 78003831d35Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_KEY_SWITCH " 78103831d35Sstevel "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, 79503831d35Sstevel &env_payload_msg, NULL, &env_hdlr_lock); 79603831d35Sstevel if (err != 0) { 79703831d35Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV " 79803831d35Sstevel "(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, 81203831d35Sstevel &fan_payload_msg, NULL, &env_hdlr_lock); 81303831d35Sstevel if (err != 0) { 81403831d35Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV (fan)" 81503831d35Sstevel "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, 82803831d35Sstevel &dr_payload_msg, NULL, &dr_hdlr_lock); 82903831d35Sstevel if (err != 0) { 83003831d35Sstevel cmn_err(CE_WARN, "Failed to register MBOX_EVENT_GENERIC (DR)" 83103831d35Sstevel "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 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, 85203831d35Sstevel sgenv_keyswitch_handler); 85303831d35Sstevel if (err != 0) { 85403831d35Sstevel cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_KEY_SWITCH " 85503831d35Sstevel "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)" 86203831d35Sstevel "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)" 86903831d35Sstevel "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) " 87603831d35Sstevel "handler. Err=%d", err); 87703831d35Sstevel rv = DDI_FAILURE; 87803831d35Sstevel } 87903831d35Sstevel 88003831d35Sstevel return (rv); 88103831d35Sstevel } 88203831d35Sstevel 88303831d35Sstevel 88403831d35Sstevel static int 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 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 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, 97603831d35Sstevel (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 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 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); 1059*07d06da5SSurya Prakki (void) sgenv_get_env_info_data(); 106003831d35Sstevel 1061*07d06da5SSurya 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 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) && 112903831d35Sstevel (env_cache_snapshot_size > 0)) { 113003831d35Sstevel DCMN_ERR_CACHE(CE_NOTE, "%s freeing " 113103831d35Sstevel "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( 114003831d35Sstevel 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] <= 115403831d35Sstevel 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 " 116603831d35Sstevel "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 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 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 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); 1291*07d06da5SSurya 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 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 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 " 141503831d35Sstevel "cache_snapshot entry[%d], node=%d", 141603831d35Sstevel 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" 143503831d35Sstevel " cache_snapshot entry[%d], node=%d," 143603831d35Sstevel " board=%d", f, i, bdp->node_id, 143703831d35Sstevel 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: 145403831d35Sstevel * 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 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 == 150603831d35Sstevel SG_SENSOR_PART_SCAPP); 150703831d35Sstevel ASSERT(env_cache[i][0].sd_id.id.sensor_type == 150803831d35Sstevel SG_SENSOR_TYPE_ENVDB); 150903831d35Sstevel ASSERT(SG_INFO_VALUESTATUS(env_cache[i][0].sd_infostamp) 151003831d35Sstevel == 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, 159203831d35Sstevel SG_GET_ENV_CONSTANTS, &status); 159303831d35Sstevel if (err) { 159403831d35Sstevel err = sgenv_handle_env_data_error(err, status, 159503831d35Sstevel 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, 160703831d35Sstevel SG_GET_ENV_THRESHOLDS, &status); 160803831d35Sstevel if (err) { 160903831d35Sstevel err = sgenv_handle_env_data_error(err, status, 161003831d35Sstevel 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, 162203831d35Sstevel SG_GET_ENV_VOLATILES, &status); 162303831d35Sstevel if (err) { 162403831d35Sstevel err = sgenv_handle_env_data_error(err, status, 162503831d35Sstevel 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, 166503831d35Sstevel SG_GET_ENV_VOLATILES, &status); 166603831d35Sstevel if (err) { 166703831d35Sstevel err = sgenv_handle_env_data_error(err, status, 166803831d35Sstevel 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 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 <= 176603831d35Sstevel max(sbbc_mbox_min_timeout, 0)) 176703831d35Sstevel sgenv_max_mbox_wait_time = 176803831d35Sstevel sbbc_mbox_default_timeout; 176903831d35Sstevel 177003831d35Sstevel rv = sbbc_mbox_request_response(&req, &resp, 177103831d35Sstevel 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, 178003831d35Sstevel 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, 178903831d35Sstevel resp.msg_status); 179003831d35Sstevel node_present[node] = 179103831d35Sstevel 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 == 180003831d35Sstevel 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) & 180803831d35Sstevel SGENV_NODE_TYPE_DS); 180903831d35Sstevel continue; 181003831d35Sstevel 181103831d35Sstevel } else if (status == 181203831d35Sstevel 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 1822*07d06da5SSurya Prakki (void) sprintf(err_msg, 1823*07d06da5SSurya Prakki "Board data for " 182403831d35Sstevel "Node%d/Slot%d", node, board); 182503831d35Sstevel sgenv_mbox_error_msg(err_msg, rv, 182603831d35Sstevel 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: " 185703831d35Sstevel "Clearing cache line %d [%p]", 1858*07d06da5SSurya 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: " 187303831d35Sstevel "Writing data for bd=%d into " 187403831d35Sstevel " the board_cache at [%p]", 1875*07d06da5SSurya 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 = 188303831d35Sstevel 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 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 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 = 206003831d35Sstevel buf.con[i].id.tag_id; 206103831d35Sstevel env_cache[key_posn][i].sd_lo = 206203831d35Sstevel buf.con[i].lo; 206303831d35Sstevel env_cache[key_posn][i].sd_hi = 206403831d35Sstevel buf.con[i].hi; 206503831d35Sstevel 206603831d35Sstevel } else if (flag == SG_GET_ENV_VOLATILES) { 206703831d35Sstevel env_cache[key_posn][i].sd_value = 206803831d35Sstevel buf.vol[i].value; 206903831d35Sstevel env_cache[key_posn][i].sd_infostamp = 207003831d35Sstevel 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 = 207603831d35Sstevel buf.thr[i].lo_warn; 207703831d35Sstevel env_cache[key_posn][i].sd_hi_warn = 207803831d35Sstevel 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 210803831d35Sstevel sgenv_handle_env_data_error(int err, int status, int key_posn, 210903831d35Sstevel 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" 212803831d35Sstevel " 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 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) * 216003831d35Sstevel 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 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 " 218603831d35Sstevel "support SGENV"); 218703831d35Sstevel break; 218803831d35Sstevel case ETIMEDOUT: 218903831d35Sstevel DCMN_ERR(CE_WARN, "!Mailbox timed out while servicing " 219003831d35Sstevel "SGENV request for %s", str); 219103831d35Sstevel break; 219203831d35Sstevel default: 219303831d35Sstevel DCMN_ERR(CE_WARN, "!Error occurred reading %s, Errno=%d," 219403831d35Sstevel " 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 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( 222003831d35Sstevel 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]", 222303831d35Sstevel 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 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) * 224403831d35Sstevel 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 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] * 227503831d35Sstevel 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 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) == 231203831d35Sstevel 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: 2336*07d06da5SSurya 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 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; 236503831d35Sstevel 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, 237003831d35Sstevel 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) && 239003831d35Sstevel (value < SSM_MAX_INSTANCES) && 239103831d35Sstevel (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 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, 243003831d35Sstevel 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, 244003831d35Sstevel 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, 246203831d35Sstevel 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, 246903831d35Sstevel 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 * 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 * 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 * 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 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 2558*07d06da5SSurya Prakki (void) sprintf(str, 2559*07d06da5SSurya Prakki "Sensor: Node=%d, Board=%s%d, Device=%s%d, Type=%s%d: reading has ", 256003831d35Sstevel id.id.node_id, 256103831d35Sstevel ((hpu_str != NULL) ? hpu_str : ""), 256203831d35Sstevel id.id.hpu_slot, 256303831d35Sstevel ((part_str != NULL) ? part_str : ""), 256403831d35Sstevel id.id.sensor_partnum, 256503831d35Sstevel ((type_str != NULL) ? type_str : ""), 256603831d35Sstevel 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 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, 261503831d35Sstevel EP_SGENV, SE_NOSLEEP); 261603831d35Sstevel if (ev == NULL) { 261703831d35Sstevel cmn_err(CE_WARN, "%s: Failed to alloc mem for %s/%s event", 261803831d35Sstevel 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, 262903831d35Sstevel &se_val, SE_NOSLEEP); 263003831d35Sstevel if (err != 0) { 263103831d35Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 263203831d35Sstevel DOMAIN_WHAT_CHANGED, EC_DOMAIN, 263303831d35Sstevel 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", 264403831d35Sstevel 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", 265203831d35Sstevel 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 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 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", 276703831d35Sstevel 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", 278703831d35Sstevel 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, 279503831d35Sstevel &se_val, SE_NOSLEEP); 279603831d35Sstevel if (err != 0) { 279703831d35Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 279803831d35Sstevel 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, 280703831d35Sstevel &se_val, SE_NOSLEEP); 280803831d35Sstevel if (err != 0) { 280903831d35Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 281003831d35Sstevel 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, 283403831d35Sstevel &se_val, SE_NOSLEEP); 283503831d35Sstevel if (err != 0) { 283603831d35Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 283703831d35Sstevel 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 */ 2847*07d06da5SSurya Prakki (void) sprintf(fan_str, 2848*07d06da5SSurya Prakki "The status of the fan in Node%d/Slot%d is now ", 284903831d35Sstevel payload->node_id, payload->slot_number); 285003831d35Sstevel switch (payload->fan_speed) { 285103831d35Sstevel case SGENV_FAN_SPEED_OFF: 2852*07d06da5SSurya Prakki (void) strcat(fan_str, SGENV_FAN_SPEED_OFF_STR); 285303831d35Sstevel break; 285403831d35Sstevel 285503831d35Sstevel case SGENV_FAN_SPEED_LOW: 2856*07d06da5SSurya Prakki (void) strcat(fan_str, SGENV_FAN_SPEED_LOW_STR); 285703831d35Sstevel break; 285803831d35Sstevel 285903831d35Sstevel case SGENV_FAN_SPEED_HIGH: 2860*07d06da5SSurya Prakki (void) strcat(fan_str, SGENV_FAN_SPEED_HIGH_STR); 286103831d35Sstevel break; 286203831d35Sstevel 286303831d35Sstevel case SGENV_FAN_SPEED_UNKNOWN: 286403831d35Sstevel default: 2865*07d06da5SSurya 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", 287603831d35Sstevel 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", 288803831d35Sstevel 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", 289603831d35Sstevel 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 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 " 294903831d35Sstevel "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, 295703831d35Sstevel EP_SGENV, SE_NOSLEEP); 295803831d35Sstevel if (ev == NULL) { 295903831d35Sstevel cmn_err(CE_WARN, "Failed to allocate sysevent buffer " 296003831d35Sstevel "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", 298203831d35Sstevel ENV_FRU_ID, EC_ENV, 298303831d35Sstevel (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, 299103831d35Sstevel &se_val, SE_NOSLEEP); 299203831d35Sstevel if (err != 0) { 299303831d35Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 299403831d35Sstevel ENV_FRU_RESOURCE_ID, EC_ENV, 299503831d35Sstevel (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, 300403831d35Sstevel &se_val, SE_NOSLEEP); 300503831d35Sstevel if (err != 0) { 300603831d35Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 300703831d35Sstevel ENV_FRU_DEVICE, EC_ENV, 300803831d35Sstevel (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, 304003831d35Sstevel &se_val, SE_NOSLEEP); 304103831d35Sstevel if (err != 0) { 304203831d35Sstevel cmn_err(CE_WARN, "Failed to add attr[%s] for %s/%s event " 304303831d35Sstevel "(Err=%d)", ENV_FRU_STATE, EC_ENV, 304403831d35Sstevel (temp_event_type ? ESC_ENV_TEMP: ESC_ENV_POWER), 304503831d35Sstevel 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: 3063*07d06da5SSurya Prakki (void) strcat(sensor_str, SGENV_EVENT_MSG_OK); 306403831d35Sstevel break; 306503831d35Sstevel 306603831d35Sstevel case SG_SENSOR_STATUS_LO_WARN: 3067*07d06da5SSurya Prakki (void) strcat(sensor_str, SGENV_EVENT_MSG_LO_WARN); 306803831d35Sstevel break; 306903831d35Sstevel 307003831d35Sstevel case SG_SENSOR_STATUS_HI_WARN: 3071*07d06da5SSurya Prakki (void) strcat(sensor_str, SGENV_EVENT_MSG_HI_WARN); 307203831d35Sstevel break; 307303831d35Sstevel 307403831d35Sstevel case SG_SENSOR_STATUS_LO_DANGER: 3075*07d06da5SSurya Prakki (void) strcat(sensor_str, SGENV_EVENT_MSG_LO_DANGER); 307603831d35Sstevel break; 307703831d35Sstevel 307803831d35Sstevel case SG_SENSOR_STATUS_HI_DANGER: 3079*07d06da5SSurya 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); 3084*07d06da5SSurya 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", 309803831d35Sstevel ENV_MSG, EC_ENV, 309903831d35Sstevel (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", 311103831d35Sstevel EC_ENV, 311203831d35Sstevel (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, 312003831d35Sstevel (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 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 " 318303831d35Sstevel "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 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 " 322503831d35Sstevel "updating env cache", f); 322603831d35Sstevel env_cache_update_needed = B_TRUE; 322703831d35Sstevel 322803831d35Sstevel } else { 322903831d35Sstevel DCMN_ERR_THREAD(CE_NOTE, "%s: Sending signal " 323003831d35Sstevel "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 " 324003831d35Sstevel "updating board cache", f); 324103831d35Sstevel board_cache_update_needed = B_TRUE; 324203831d35Sstevel 324303831d35Sstevel } else { 324403831d35Sstevel DCMN_ERR_THREAD(CE_NOTE, "%s: Sending signal " 324503831d35Sstevel "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