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