12305Sstevel /*
22305Sstevel * CDDL HEADER START
32305Sstevel *
42305Sstevel * The contents of this file are subject to the terms of the
52305Sstevel * Common Development and Distribution License (the "License").
62305Sstevel * You may not use this file except in compliance with the License.
72305Sstevel *
82305Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92305Sstevel * or http://www.opensolaris.org/os/licensing.
102305Sstevel * See the License for the specific language governing permissions
112305Sstevel * and limitations under the License.
122305Sstevel *
132305Sstevel * When distributing Covered Code, include this CDDL HEADER in each
142305Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152305Sstevel * If applicable, add the following below this CDDL HEADER, with the
162305Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
172305Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
182305Sstevel *
192305Sstevel * CDDL HEADER END
202305Sstevel */
212305Sstevel
222305Sstevel /*
237656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
242305Sstevel * Use is subject to license terms.
252305Sstevel */
262305Sstevel
272305Sstevel
282305Sstevel #include <sys/types.h>
292305Sstevel #include <sys/stat.h>
302305Sstevel #include <sys/conf.h>
312305Sstevel #include <sys/modctl.h>
322305Sstevel #include <sys/callb.h>
332305Sstevel #include <sys/strlog.h>
342305Sstevel #include <sys/cyclic.h>
352305Sstevel #include <sys/rmc_comm_dp.h>
362305Sstevel #include <sys/rmc_comm_dp_boot.h>
372305Sstevel #include <sys/rmc_comm_drvintf.h>
382305Sstevel #include <sys/rmc_comm.h>
392305Sstevel #include <sys/machsystm.h>
402305Sstevel #include <sys/sysevent.h>
412305Sstevel #include <sys/sysevent/dr.h>
422305Sstevel #include <sys/sysevent/env.h>
432305Sstevel #include <sys/sysevent/eventdefs.h>
442305Sstevel #include <sys/file.h>
452305Sstevel #include <sys/disp.h>
462305Sstevel #include <sys/reboot.h>
472305Sstevel #include <sys/envmon.h>
482305Sstevel #include <sys/rmclomv_impl.h>
492305Sstevel #include <sys/cpu_sgnblk_defs.h>
502305Sstevel #include <sys/utsname.h>
512305Sstevel #include <sys/systeminfo.h>
522305Sstevel #include <sys/ddi.h>
532305Sstevel #include <sys/time.h>
542305Sstevel #include <sys/promif.h>
552305Sstevel
562305Sstevel #define offsetof(s, m) (size_t)(&(((s *)0)->m))
572305Sstevel #define RMCRESBUFLEN 1024
582305Sstevel #define DATE_TIME_MSG_SIZE 78
592305Sstevel #define RMCLOMV_WATCHDOG_MODE "rmclomv-watchdog-mode"
605593Sjfrank #define DELAY_TIME 5000000 /* 5 seconds, in microseconds */
615593Sjfrank #define CPU_SIGNATURE_DELAY_TIME 5000000 /* 5 secs, in microsecs */
622305Sstevel
632305Sstevel extern void pmugpio_watchdog_pat();
642305Sstevel
652305Sstevel extern int watchdog_activated;
662305Sstevel static int last_watchdog_msg = 1;
672305Sstevel extern int watchdog_enable;
682305Sstevel extern int boothowto;
692305Sstevel
702305Sstevel int rmclomv_watchdog_mode;
712305Sstevel
722305Sstevel /*
732305Sstevel * functions local to this driver.
742305Sstevel */
752305Sstevel static int rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
762305Sstevel void **resultp);
772305Sstevel static int rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
782305Sstevel static int rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
792305Sstevel static uint_t rmclomv_break_intr(caddr_t arg);
802305Sstevel static int rmclomv_add_intr_handlers(void);
812305Sstevel static int rmclomv_remove_intr_handlers(void);
822305Sstevel static uint_t rmclomv_event_data_handler(char *);
832305Sstevel static void rmclomv_dr_data_handler(const char *, int);
842305Sstevel static int rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
852305Sstevel static int rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
862305Sstevel static int rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
872305Sstevel cred_t *cred_p, int *rval_p);
882305Sstevel static void rmclomv_checkrmc_start(void);
892305Sstevel static void rmclomv_checkrmc_destroy(void);
902305Sstevel static void rmclomv_checkrmc_wakeup(void *);
912305Sstevel static void rmclomv_refresh_start(void);
922305Sstevel static void rmclomv_refresh_destroy(void);
932305Sstevel static void rmclomv_refresh_wakeup(void);
942305Sstevel static void rmclomv_reset_cache(rmclomv_cache_section_t *new_chain,
952305Sstevel rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo);
962305Sstevel static rmclomv_cache_section_t *rmclomv_find_section(
972305Sstevel rmclomv_cache_section_t *start, uint16_t sensor);
982305Sstevel static rmclomv_cache_section_t *create_cache_section(int sensor_type, int num);
992305Sstevel static int get_sensor_by_name(const rmclomv_cache_section_t *section,
1002305Sstevel const char *name, int *index);
1012305Sstevel static int validate_section_entry(rmclomv_cache_section_t *section,
1022305Sstevel int index);
1032305Sstevel static int add_names_to_section(rmclomv_cache_section_t *section);
1042305Sstevel static void free_section(rmclomv_cache_section_t *section);
1052305Sstevel static void add_section(rmclomv_cache_section_t **head,
1062305Sstevel rmclomv_cache_section_t *section);
1072305Sstevel static int rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len,
1082305Sstevel intptr_t arg_req, intptr_t arg_res);
1092305Sstevel static void refresh_name_cache(int force_fail);
1102305Sstevel static void set_val_unav(envmon_sensor_t *sensor);
1112305Sstevel static void set_fan_unav(envmon_fan_t *fan);
1122305Sstevel static int do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind,
1132305Sstevel dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r,
1142305Sstevel int detector_type);
1152305Sstevel static uint_t rmc_set_watchdog_timer(uint_t timeoutval);
1162305Sstevel static uint_t rmc_clear_watchdog_timer(void);
1172305Sstevel static void send_watchdog_msg(int msg);
1182305Sstevel static void plat_timesync(void *arg);
1192305Sstevel
120*8275SEric Cheng static kmutex_t timesync_lock;
121*8275SEric Cheng static clock_t timesync_interval = 0;
122*8275SEric Cheng static timeout_id_t timesync_tid = 0;
123*8275SEric Cheng
1242305Sstevel /*
1252305Sstevel * Driver entry points
1262305Sstevel */
1272305Sstevel static struct cb_ops rmclomv_cb_ops = {
1282305Sstevel rmclomv_open, /* open */
1292305Sstevel rmclomv_close, /* close */
1302305Sstevel nodev, /* strategy() */
1312305Sstevel nodev, /* print() */
1322305Sstevel nodev, /* dump() */
1332305Sstevel nodev, /* read() */
1342305Sstevel nodev, /* write() */
1352305Sstevel rmclomv_ioctl, /* ioctl() */
1362305Sstevel nodev, /* devmap() */
1372305Sstevel nodev, /* mmap() */
1382305Sstevel ddi_segmap, /* segmap() */
1392305Sstevel nochpoll, /* poll() */
1402305Sstevel ddi_prop_op, /* prop_op() */
1412305Sstevel NULL, /* cb_str */
1422305Sstevel D_NEW | D_MP /* cb_flag */
1432305Sstevel };
1442305Sstevel
1452305Sstevel
1462305Sstevel static struct dev_ops rmclomv_ops = {
1472305Sstevel DEVO_REV,
1482305Sstevel 0, /* ref count */
1492305Sstevel rmclomv_getinfo, /* getinfo() */
1502305Sstevel nulldev, /* identify() */
1512305Sstevel nulldev, /* probe() */
1522305Sstevel rmclomv_attach, /* attach() */
1532305Sstevel rmclomv_detach, /* detach */
1542305Sstevel nodev, /* reset */
1552305Sstevel &rmclomv_cb_ops, /* pointer to cb_ops structure */
1562305Sstevel (struct bus_ops *)NULL,
1577656SSherry.Moore@Sun.COM nulldev, /* power() */
1587656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */
1592305Sstevel };
1602305Sstevel
1612305Sstevel /*
1622305Sstevel * Loadable module support.
1632305Sstevel */
1642305Sstevel extern struct mod_ops mod_driverops;
1652305Sstevel
1662305Sstevel static struct modldrv modldrv = {
1672305Sstevel &mod_driverops, /* Type of module. This is a driver */
1687656SSherry.Moore@Sun.COM "rmclomv control driver", /* Name of the module */
1692305Sstevel &rmclomv_ops /* pointer to the dev_ops structure */
1702305Sstevel };
1712305Sstevel
1722305Sstevel static struct modlinkage modlinkage = {
1732305Sstevel MODREV_1,
1742305Sstevel &modldrv,
1752305Sstevel NULL
1762305Sstevel };
1772305Sstevel
1782305Sstevel /*
1792305Sstevel * Device info
1802305Sstevel */
1812305Sstevel static dev_info_t *rmclomv_dip = NULL;
1822305Sstevel static int rmclomv_break_requested = B_FALSE;
1832305Sstevel static ddi_softintr_t rmclomv_softintr_id;
1842305Sstevel static ddi_iblock_cookie_t rmclomv_soft_iblock_cookie;
1852305Sstevel
1862305Sstevel extern void (*abort_seq_handler)();
1872305Sstevel /* key_position is effective key-position. Set to locked if unknown */
1882305Sstevel static rsci8 key_position = RMC_KEYSWITCH_POS_LOCKED;
1892305Sstevel /* real_key_position starts off as unknown and records value actually seen */
1902305Sstevel static rsci8 real_key_position = RMC_KEYSWITCH_POS_UNKNOWN;
1912305Sstevel static void rmclomv_abort_seq_handler(char *msg);
1922305Sstevel
1932305Sstevel /*
1942305Sstevel * mutexes which protect the interrupt handlers.
1952305Sstevel */
1962305Sstevel static kmutex_t rmclomv_event_hdlr_lock;
1972305Sstevel static kmutex_t rmclomv_refresh_lock;
1982305Sstevel static kcondvar_t rmclomv_refresh_sig_cv;
1992305Sstevel static kmutex_t rmclomv_checkrmc_lock;
2002305Sstevel static kcondvar_t rmclomv_checkrmc_sig_cv;
2012305Sstevel
2022305Sstevel /*
2032305Sstevel * mutex to protect the handle_name cache
2042305Sstevel */
2052305Sstevel static kmutex_t rmclomv_cache_lock;
2062305Sstevel
2072305Sstevel /*
2082305Sstevel * mutex to protect the RMC state
2092305Sstevel */
2102305Sstevel static kmutex_t rmclomv_state_lock;
2112305Sstevel
2122305Sstevel /*
2132305Sstevel * Payloads of the event handlers.
2142305Sstevel */
2152305Sstevel static dp_event_notification_t rmclomv_event_payload;
2162305Sstevel static rmc_comm_msg_t rmclomv_event_payload_msg;
2172305Sstevel
2182305Sstevel /*
2192305Sstevel * Checkrmc commands..
2202305Sstevel */
2212305Sstevel #define RMCLOMV_CHECKRMC_EXITNOW (-1)
2222305Sstevel #define RMCLOMV_CHECKRMC_WAIT 0
2232305Sstevel #define RMCLOMV_CHECKRMC_PROCESSNOW 1
2242305Sstevel
2252305Sstevel /*
2262305Sstevel * Checkrmc thread state
2272305Sstevel */
2282305Sstevel static int rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
2292305Sstevel static kt_did_t rmclomv_checkrmc_tid = 0;
2302305Sstevel
2312305Sstevel /*
2322305Sstevel * RMC state data
2332305Sstevel */
2342305Sstevel #define RMCLOMV_RMCSTATE_UNKNOWN 0
2352305Sstevel #define RMCLOMV_RMCSTATE_OK 1
2362305Sstevel #define RMCLOMV_RMCSTATE_FAILED 2
2372305Sstevel #define RMCLOMV_RMCSTATE_DOWNLOAD 3
2382305Sstevel
2392305Sstevel /*
2402305Sstevel * RMC error indicator values (status from last RMC command)
2412305Sstevel */
2422305Sstevel #define RMCLOMV_RMCERROR_NONE 0
2432305Sstevel
2442305Sstevel /* fail RMC after 5 minutes without a good response */
2452305Sstevel #define RMCLOMV_RMCFAILTHRESHOLD 5
2462305Sstevel
2472305Sstevel /*
2482305Sstevel * rmclomv_rmc_state is the state reported in OperationalStatus.
2492305Sstevel * rmclomv_rmc_error reflects the result of the last RMC interaction.
2502305Sstevel * rmclomv_rmcfailcount is used by the rmclomv_checkrmc thread to count
2512305Sstevel * failures in its regular status polls. Once RMCLOMV_RMCFAILTHRESHOLD
2522305Sstevel * is reached, rmclomv_rmc_state is marked as RMCLOMV_RMCSTATE_FAILED.
2532305Sstevel */
2542305Sstevel static int rmclomv_rmc_state = RMCLOMV_RMCSTATE_UNKNOWN;
2552305Sstevel static int rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE;
2562305Sstevel static int rmclomv_rmcfailcount;
2572305Sstevel
2582305Sstevel /*
2592305Sstevel * Refresh commands..
2602305Sstevel */
2612305Sstevel #define RMCLOMV_REFRESH_EXITNOW (-1)
2622305Sstevel #define RMCLOMV_REFRESH_WAIT 0
2632305Sstevel #define RMCLOMV_REFRESH_PROCESSNOW 1
2642305Sstevel
2652305Sstevel /*
2662305Sstevel * Refresh thread state
2672305Sstevel */
2682305Sstevel static int rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
2692305Sstevel static kt_did_t rmclomv_refresh_tid = 0;
2702305Sstevel
2712305Sstevel /*
2722305Sstevel * timeout id
2732305Sstevel */
2742305Sstevel static timeout_id_t timer_id;
2752305Sstevel
2762305Sstevel /*
2772305Sstevel * Handle-name cache
2782305Sstevel */
2792305Sstevel #define LOCK_CACHE mutex_enter(&rmclomv_cache_lock);
2802305Sstevel #define RELEASE_CACHE mutex_exit(&rmclomv_cache_lock);
2812305Sstevel static rmclomv_cache_section_t *rmclomv_cache; /* main handle-names */
2822305Sstevel static rmclomv_cache_section_t *rmclomv_subcache; /* derived names */
2832305Sstevel static dp_get_sysinfo_r_t rmclomv_sysinfo_data;
2842305Sstevel static boolean_t rmclomv_sysinfo_valid;
2852305Sstevel static int rmclomv_cache_valid;
2862305Sstevel
2872305Sstevel extern pri_t maxclsyspri;
2882305Sstevel
2892305Sstevel /*
2902305Sstevel * static strings
2912305Sstevel */
2922305Sstevel static const char str_percent[] = "%";
2932305Sstevel static const char str_rpm[] = " rpm";
2942305Sstevel static const char str_ip_volts_ind[] = "P_PWR";
2952305Sstevel static const char str_ip2_volts_ind[] = "P_PWR2";
2962305Sstevel static const char str_ff_pok_ind[] = "FF_POK";
2972305Sstevel static const char str_vlo_volts_ind[] = "FF_UV";
2982305Sstevel static const char str_vhi_volts_ind[] = "FF_OV";
2992305Sstevel static const char str_chi_amps_ind[] = "FF_OC";
3002305Sstevel static const char str_chi_nr_ind[] = "FF_NR";
3012305Sstevel static const char str_ot_tmpr_ind[] = "FF_OT";
3022305Sstevel static const char str_fan_ind[] = "FF_FAN";
3032305Sstevel static const char str_pdct_fan_ind[] = "FF_PDCT_FAN";
3042305Sstevel static const char str_sc[] = "SC";
3052305Sstevel
3062305Sstevel int
_init(void)3072305Sstevel _init(void)
3082305Sstevel {
3092305Sstevel int error = 0;
3102305Sstevel
3112305Sstevel mutex_init(&rmclomv_event_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
3122305Sstevel mutex_init(&rmclomv_checkrmc_lock, NULL, MUTEX_DRIVER, NULL);
3132305Sstevel mutex_init(&rmclomv_refresh_lock, NULL, MUTEX_DRIVER, NULL);
3142305Sstevel mutex_init(&rmclomv_cache_lock, NULL, MUTEX_DRIVER, NULL);
3152305Sstevel mutex_init(&rmclomv_state_lock, NULL, MUTEX_DRIVER, NULL);
316*8275SEric Cheng mutex_init(×ync_lock, NULL, MUTEX_DEFAULT, NULL);
3172305Sstevel cv_init(&rmclomv_checkrmc_sig_cv, NULL, CV_DRIVER, NULL);
3182305Sstevel cv_init(&rmclomv_refresh_sig_cv, NULL, CV_DRIVER, NULL);
3192305Sstevel
3202305Sstevel error = mod_install(&modlinkage);
3212305Sstevel if (error) {
3222305Sstevel cv_destroy(&rmclomv_refresh_sig_cv);
3232305Sstevel cv_destroy(&rmclomv_checkrmc_sig_cv);
3242305Sstevel mutex_destroy(&rmclomv_state_lock);
3252305Sstevel mutex_destroy(&rmclomv_cache_lock);
3262305Sstevel mutex_destroy(&rmclomv_refresh_lock);
3272305Sstevel mutex_destroy(&rmclomv_checkrmc_lock);
3282305Sstevel mutex_destroy(&rmclomv_event_hdlr_lock);
3292305Sstevel }
3302305Sstevel return (error);
3312305Sstevel }
3322305Sstevel
3332305Sstevel
3342305Sstevel int
_info(struct modinfo * modinfop)3352305Sstevel _info(struct modinfo *modinfop)
3362305Sstevel {
3372305Sstevel return (mod_info(&modlinkage, modinfop));
3382305Sstevel }
3392305Sstevel
3402305Sstevel
3412305Sstevel int
_fini(void)3422305Sstevel _fini(void)
3432305Sstevel {
3442305Sstevel int error = 0;
3452305Sstevel
3462305Sstevel error = mod_remove(&modlinkage);
3472305Sstevel if (error)
3482305Sstevel return (error);
3492305Sstevel cv_destroy(&rmclomv_refresh_sig_cv);
3502305Sstevel cv_destroy(&rmclomv_checkrmc_sig_cv);
351*8275SEric Cheng mutex_destroy(×ync_lock);
3522305Sstevel mutex_destroy(&rmclomv_state_lock);
3532305Sstevel mutex_destroy(&rmclomv_cache_lock);
3542305Sstevel mutex_destroy(&rmclomv_refresh_lock);
3552305Sstevel mutex_destroy(&rmclomv_checkrmc_lock);
3562305Sstevel mutex_destroy(&rmclomv_event_hdlr_lock);
3572305Sstevel return (error);
3582305Sstevel }
3592305Sstevel
3602305Sstevel
3612305Sstevel /* ARGSUSED */
3622305Sstevel static int
rmclomv_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)3632305Sstevel rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
3642305Sstevel {
3652305Sstevel minor_t m = getminor((dev_t)arg);
3662305Sstevel
3672305Sstevel switch (cmd) {
3682305Sstevel case DDI_INFO_DEVT2DEVINFO:
3692305Sstevel if ((m != 0) || (rmclomv_dip == NULL)) {
3702305Sstevel *resultp = NULL;
3712305Sstevel return (DDI_FAILURE);
3722305Sstevel }
3732305Sstevel *resultp = rmclomv_dip;
3742305Sstevel return (DDI_SUCCESS);
3752305Sstevel case DDI_INFO_DEVT2INSTANCE:
3762305Sstevel *resultp = (void *)(uintptr_t)m;
3772305Sstevel return (DDI_SUCCESS);
3782305Sstevel default:
3792305Sstevel return (DDI_FAILURE);
3802305Sstevel }
3812305Sstevel }
3822305Sstevel
3832305Sstevel
3842305Sstevel static int
rmclomv_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3852305Sstevel rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3862305Sstevel {
3872305Sstevel int instance;
3882305Sstevel int err;
3892305Sstevel char *wdog_state;
3902305Sstevel int attaching = 1;
3912305Sstevel
3922305Sstevel switch (cmd) {
3932305Sstevel case DDI_ATTACH:
3942305Sstevel /*
3952305Sstevel * only allow one instance
3962305Sstevel */
3972305Sstevel instance = ddi_get_instance(dip);
3982305Sstevel if (instance != 0)
3992305Sstevel return (DDI_FAILURE);
4002305Sstevel
4012305Sstevel err = ddi_create_minor_node(dip, "rmclomv", S_IFCHR,
4025593Sjfrank instance, DDI_PSEUDO, NULL);
4032305Sstevel if (err != DDI_SUCCESS)
4042305Sstevel return (DDI_FAILURE);
4052305Sstevel
4062305Sstevel /*
4072305Sstevel * Register with rmc_comm to prevent it being detached
4082305Sstevel * (in the unlikely event that its attach succeeded on a
4092305Sstevel * platform whose platmod doesn't lock it down).
4102305Sstevel */
4112305Sstevel err = rmc_comm_register();
4122305Sstevel if (err != DDI_SUCCESS) {
4132305Sstevel ddi_remove_minor_node(dip, NULL);
4142305Sstevel return (DDI_FAILURE);
4152305Sstevel }
4162305Sstevel
4172305Sstevel /* Remember the dev info */
4182305Sstevel rmclomv_dip = dip;
4192305Sstevel
4202305Sstevel /*
4212305Sstevel * Add the handlers which watch for unsolicited messages
4222305Sstevel * and post event to Sysevent Framework.
4232305Sstevel */
4242305Sstevel err = rmclomv_add_intr_handlers();
4252305Sstevel if (err != DDI_SUCCESS) {
4262305Sstevel rmc_comm_unregister();
4272305Sstevel ddi_remove_minor_node(dip, NULL);
4282305Sstevel rmclomv_dip = NULL;
4292305Sstevel return (DDI_FAILURE);
4302305Sstevel }
4312305Sstevel
4322305Sstevel rmclomv_checkrmc_start();
4332305Sstevel rmclomv_refresh_start();
4342305Sstevel
4352305Sstevel abort_seq_handler = rmclomv_abort_seq_handler;
4362305Sstevel ddi_report_dev(dip);
4372305Sstevel
4382305Sstevel /*
4392305Sstevel * Check whether we have an application watchdog
4402305Sstevel */
4412305Sstevel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
4425593Sjfrank DDI_PROP_DONTPASS, RMCLOMV_WATCHDOG_MODE,
4435593Sjfrank &wdog_state) == DDI_PROP_SUCCESS) {
4442305Sstevel if (strcmp(wdog_state, "app") == 0) {
4452305Sstevel rmclomv_watchdog_mode = 1;
4462305Sstevel watchdog_enable = 0;
4472305Sstevel }
4482305Sstevel else
4492305Sstevel rmclomv_watchdog_mode = 0;
4502305Sstevel ddi_prop_free(wdog_state);
4512305Sstevel }
4522305Sstevel
4532305Sstevel tod_ops.tod_set_watchdog_timer = rmc_set_watchdog_timer;
4542305Sstevel tod_ops.tod_clear_watchdog_timer = rmc_clear_watchdog_timer;
4552305Sstevel
4562305Sstevel /*
4572305Sstevel * Now is a good time to activate hardware watchdog
4582305Sstevel * (if one exists).
4592305Sstevel */
4602305Sstevel mutex_enter(&tod_lock);
4612305Sstevel if (watchdog_enable && tod_ops.tod_set_watchdog_timer != NULL)
4622305Sstevel err = tod_ops.tod_set_watchdog_timer(0);
4632305Sstevel mutex_exit(&tod_lock);
4642305Sstevel if (err != 0)
4652305Sstevel printf("Hardware watchdog enabled\n");
4662305Sstevel
4672305Sstevel /*
4682305Sstevel * Set time interval and start timesync routine.
4692305Sstevel * Also just this once set the Solaris clock
4702305Sstevel * to the RMC clock.
4712305Sstevel */
4722305Sstevel timesync_interval = drv_usectohz(5*60 * MICROSEC);
4732305Sstevel plat_timesync((void *) &attaching);
4742305Sstevel
4752305Sstevel return (DDI_SUCCESS);
4762305Sstevel case DDI_RESUME:
4772305Sstevel return (DDI_SUCCESS);
4782305Sstevel default:
4792305Sstevel return (DDI_FAILURE);
4802305Sstevel }
4812305Sstevel }
4822305Sstevel
4832305Sstevel
4842305Sstevel static int
rmclomv_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4852305Sstevel rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4862305Sstevel {
487*8275SEric Cheng timeout_id_t tid;
488*8275SEric Cheng int instance;
489*8275SEric Cheng int err;
4902305Sstevel
4912305Sstevel switch (cmd) {
4922305Sstevel case DDI_DETACH:
4932305Sstevel instance = ddi_get_instance(dip);
4942305Sstevel if (instance != 0)
4952305Sstevel return (DDI_FAILURE);
4962305Sstevel
4972305Sstevel /*
4982305Sstevel * Remove the handlers which watch for unsolicited messages
4992305Sstevel * and post event to Sysevent Framework.
5002305Sstevel */
5012305Sstevel err = rmclomv_remove_intr_handlers();
5022305Sstevel if (err != DDI_SUCCESS) {
5032305Sstevel cmn_err(CE_WARN, "Failed to remove event handlers");
5042305Sstevel return (DDI_FAILURE);
5052305Sstevel }
5062305Sstevel rmclomv_checkrmc_destroy();
5072305Sstevel rmclomv_refresh_destroy();
5082305Sstevel rmclomv_reset_cache(NULL, NULL, NULL);
5092305Sstevel ddi_remove_minor_node(dip, NULL);
5102305Sstevel
511*8275SEric Cheng mutex_enter(×ync_lock);
512*8275SEric Cheng tid = timesync_tid;
513*8275SEric Cheng timesync_tid = 0;
514*8275SEric Cheng timesync_interval = 0;
515*8275SEric Cheng mutex_exit(×ync_lock);
516*8275SEric Cheng (void) untimeout(tid);
517*8275SEric Cheng
5182305Sstevel /* Forget the dev info */
5192305Sstevel rmclomv_dip = NULL;
5202305Sstevel rmc_comm_unregister();
5212305Sstevel return (DDI_SUCCESS);
5222305Sstevel case DDI_SUSPEND:
5232305Sstevel return (DDI_SUCCESS);
5242305Sstevel default:
5252305Sstevel return (DDI_FAILURE);
5262305Sstevel }
5272305Sstevel }
5282305Sstevel
5292305Sstevel static int
rmclomv_add_intr_handlers()5302305Sstevel rmclomv_add_intr_handlers()
5312305Sstevel {
5322305Sstevel int err;
5332305Sstevel
5342305Sstevel if (ddi_get_soft_iblock_cookie(rmclomv_dip, DDI_SOFTINT_HIGH,
5352305Sstevel &rmclomv_soft_iblock_cookie) != DDI_SUCCESS) {
5362305Sstevel return (DDI_FAILURE);
5372305Sstevel }
5382305Sstevel err = ddi_add_softintr(rmclomv_dip, DDI_SOFTINT_HIGH,
5392305Sstevel &rmclomv_softintr_id, &rmclomv_soft_iblock_cookie, NULL,
5402305Sstevel rmclomv_break_intr, NULL);
5412305Sstevel if (err != DDI_SUCCESS)
5422305Sstevel return (DDI_FAILURE);
5432305Sstevel rmclomv_event_payload_msg.msg_buf = (caddr_t)&rmclomv_event_payload;
5442305Sstevel rmclomv_event_payload_msg.msg_len = sizeof (rmclomv_event_payload);
5452305Sstevel err = rmc_comm_reg_intr(DP_RMC_EVENTS, rmclomv_event_data_handler,
5462305Sstevel &rmclomv_event_payload_msg, NULL, &rmclomv_event_hdlr_lock);
5472305Sstevel if (err != 0) {
5482305Sstevel ddi_remove_softintr(rmclomv_softintr_id);
5492305Sstevel return (DDI_FAILURE);
5502305Sstevel }
5512305Sstevel return (DDI_SUCCESS);
5522305Sstevel }
5532305Sstevel
5542305Sstevel static int
rmclomv_remove_intr_handlers(void)5552305Sstevel rmclomv_remove_intr_handlers(void)
5562305Sstevel {
5572305Sstevel int err = rmc_comm_unreg_intr(DP_RMC_EVENTS,
5582305Sstevel rmclomv_event_data_handler);
5592305Sstevel if (err != 0) {
5602305Sstevel cmn_err(CE_WARN, "Failed to unregister DP_RMC_EVENTS "
5615593Sjfrank "handler. Err=%d", err);
5622305Sstevel return (DDI_FAILURE);
5632305Sstevel }
5642305Sstevel ddi_remove_softintr(rmclomv_softintr_id);
5652305Sstevel return (DDI_SUCCESS);
5662305Sstevel }
5672305Sstevel
5682305Sstevel static void
rmclomv_abort_seq_handler(char * msg)5692305Sstevel rmclomv_abort_seq_handler(char *msg)
5702305Sstevel {
5712305Sstevel if (key_position == RMC_KEYSWITCH_POS_LOCKED)
5722305Sstevel cmn_err(CE_CONT, "KEY in LOCKED position, "
5735593Sjfrank "ignoring debug enter sequence");
5742305Sstevel else {
5752305Sstevel rmclomv_break_requested = B_TRUE;
5762305Sstevel if (msg != NULL)
5772305Sstevel prom_printf("%s\n", msg);
5782305Sstevel
5792305Sstevel ddi_trigger_softintr(rmclomv_softintr_id);
5802305Sstevel }
5812305Sstevel }
5822305Sstevel
5832305Sstevel /* ARGSUSED */
5842305Sstevel static uint_t
rmclomv_break_intr(caddr_t arg)5852305Sstevel rmclomv_break_intr(caddr_t arg)
5862305Sstevel {
5872305Sstevel if (rmclomv_break_requested) {
5882305Sstevel rmclomv_break_requested = B_FALSE;
5892305Sstevel debug_enter(NULL);
5902305Sstevel return (DDI_INTR_CLAIMED);
5912305Sstevel }
5922305Sstevel
5932305Sstevel return (DDI_INTR_UNCLAIMED);
5942305Sstevel }
5952305Sstevel
5962305Sstevel /*
5972305Sstevel * Create a cache section structure
5982305Sstevel */
5992305Sstevel static rmclomv_cache_section_t *
create_cache_section(int sensor_type,int num)6002305Sstevel create_cache_section(int sensor_type, int num)
6012305Sstevel {
6022305Sstevel size_t len = offsetof(rmclomv_cache_section_t, entry[0]) +
6032305Sstevel num * sizeof (rmclomv_cache_entry_t);
6042305Sstevel rmclomv_cache_section_t *ptr = kmem_zalloc(len, KM_SLEEP);
6052305Sstevel ptr->next_section = NULL;
6062305Sstevel ptr->sensor_type = sensor_type;
6072305Sstevel ptr->num_entries = num;
6082305Sstevel ptr->section_len = len;
6092305Sstevel return (ptr);
6102305Sstevel }
6112305Sstevel
6122305Sstevel /*
6132305Sstevel * Free a cache_section.
6142305Sstevel */
6152305Sstevel static void
free_section(rmclomv_cache_section_t * section)6162305Sstevel free_section(rmclomv_cache_section_t *section)
6172305Sstevel {
6182305Sstevel size_t len = section->section_len;
6192305Sstevel kmem_free(section, len);
6202305Sstevel }
6212305Sstevel
6222305Sstevel /*
6232305Sstevel * adds supplied section to end of cache chain
6242305Sstevel * must be called with cache locked
6252305Sstevel */
6262305Sstevel static void
add_section(rmclomv_cache_section_t ** head,rmclomv_cache_section_t * section)6272305Sstevel add_section(rmclomv_cache_section_t **head, rmclomv_cache_section_t *section)
6282305Sstevel {
6292305Sstevel section->next_section = *head;
6302305Sstevel *head = section;
6312305Sstevel }
6322305Sstevel
6332305Sstevel /*
6342305Sstevel * This function releases all cache sections and exchanges the two
6352305Sstevel * chain heads for new values.
6362305Sstevel */
6372305Sstevel static void
rmclomv_reset_cache(rmclomv_cache_section_t * new_chain,rmclomv_cache_section_t * new_subchain,dp_get_sysinfo_r_t * sysinfo)6382305Sstevel rmclomv_reset_cache(rmclomv_cache_section_t *new_chain,
6392305Sstevel rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo)
6402305Sstevel {
6412305Sstevel rmclomv_cache_section_t *first;
6422305Sstevel rmclomv_cache_section_t *sub_first;
6432305Sstevel rmclomv_cache_section_t *next;
6442305Sstevel
6452305Sstevel LOCK_CACHE
6462305Sstevel
6472305Sstevel rmclomv_cache_valid = (new_chain != NULL);
6482305Sstevel first = rmclomv_cache;
6492305Sstevel rmclomv_cache = new_chain;
6502305Sstevel sub_first = rmclomv_subcache;
6512305Sstevel rmclomv_subcache = new_subchain;
6522305Sstevel
6532305Sstevel if (sysinfo == NULL)
6542305Sstevel bzero(&rmclomv_sysinfo_data, sizeof (rmclomv_sysinfo_data));
6552305Sstevel else
6562305Sstevel bcopy(sysinfo, &rmclomv_sysinfo_data,
6572305Sstevel sizeof (rmclomv_sysinfo_data));
6582305Sstevel
6592305Sstevel rmclomv_sysinfo_valid = (sysinfo != NULL);
6602305Sstevel
6612305Sstevel RELEASE_CACHE
6622305Sstevel
6632305Sstevel while (first != NULL) {
6642305Sstevel next = first->next_section;
6652305Sstevel free_section(first);
6662305Sstevel first = next;
6672305Sstevel }
6682305Sstevel
6692305Sstevel while (sub_first != NULL) {
6702305Sstevel next = sub_first->next_section;
6712305Sstevel free_section(sub_first);
6722305Sstevel sub_first = next;
6732305Sstevel }
6742305Sstevel }
6752305Sstevel
6762305Sstevel /*
6772305Sstevel * cache must be locked before calling rmclomv_find_section
6782305Sstevel */
6792305Sstevel static rmclomv_cache_section_t *
rmclomv_find_section(rmclomv_cache_section_t * start,uint16_t sensor)6802305Sstevel rmclomv_find_section(rmclomv_cache_section_t *start, uint16_t sensor)
6812305Sstevel {
6822305Sstevel rmclomv_cache_section_t *next = start;
6832305Sstevel
6842305Sstevel while ((next != NULL) && (next->sensor_type != sensor))
6852305Sstevel next = next->next_section;
6862305Sstevel
6872305Sstevel return (next);
6882305Sstevel }
6892305Sstevel
6902305Sstevel /*
6912305Sstevel * Return a string presenting the keyswitch position
6922305Sstevel * For unknown values returns "Unknown"
6932305Sstevel */
6942305Sstevel static char *
rmclomv_key_position(enum rmc_keyswitch_pos pos)6952305Sstevel rmclomv_key_position(enum rmc_keyswitch_pos pos)
6962305Sstevel {
6972305Sstevel switch (pos) {
6982305Sstevel
6992305Sstevel case RMC_KEYSWITCH_POS_NORMAL:
7002305Sstevel return ("NORMAL");
7012305Sstevel case RMC_KEYSWITCH_POS_DIAG:
7022305Sstevel return ("DIAG");
7032305Sstevel case RMC_KEYSWITCH_POS_LOCKED:
7042305Sstevel return ("LOCKED");
7052305Sstevel case RMC_KEYSWITCH_POS_OFF:
7062305Sstevel return ("STBY");
7072305Sstevel default:
7082305Sstevel return ("UNKNOWN");
7092305Sstevel }
7102305Sstevel }
7112305Sstevel
7122305Sstevel /*
7132305Sstevel * The sensor id name is sought in the supplied section and if found
7142305Sstevel * its index within the section is written to *index.
7152305Sstevel * Return value is zero for success, otherwise -1.
7162305Sstevel * The cache must be locked before calling get_sensor_by_name
7172305Sstevel */
7182305Sstevel static int
get_sensor_by_name(const rmclomv_cache_section_t * section,const char * name,int * index)7192305Sstevel get_sensor_by_name(const rmclomv_cache_section_t *section,
7202305Sstevel const char *name, int *index)
7212305Sstevel {
7222305Sstevel int i;
7232305Sstevel
7242305Sstevel for (i = 0; i < section->num_entries; i++) {
7252305Sstevel if (strcmp(name, section->entry[i].handle_name.name) == 0) {
7262305Sstevel *index = i;
7272305Sstevel return (0);
7282305Sstevel }
7292305Sstevel }
7302305Sstevel
7312305Sstevel *index = 0;
7322305Sstevel return (-1);
7332305Sstevel }
7342305Sstevel
7352305Sstevel /*
7362305Sstevel * fills in the envmon_handle name
7372305Sstevel * if it is unknown (not cached), the dp_handle_t is returned as a hex-digit
7382305Sstevel * string
7392305Sstevel */
7402305Sstevel static void
rmclomv_hdl_to_envhdl(dp_handle_t hdl,envmon_handle_t * envhdl)7412305Sstevel rmclomv_hdl_to_envhdl(dp_handle_t hdl, envmon_handle_t *envhdl)
7422305Sstevel {
7432305Sstevel rmclomv_cache_section_t *next;
7442305Sstevel int i;
7452305Sstevel
7462305Sstevel LOCK_CACHE
7472305Sstevel
7482305Sstevel for (next = rmclomv_cache; next != NULL; next = next->next_section) {
7492305Sstevel for (i = 0; i < next->num_entries; i++) {
7502305Sstevel if (next->entry[i].handle == hdl) {
7515593Sjfrank *envhdl = next->entry[i].handle_name;
7525593Sjfrank RELEASE_CACHE
7535593Sjfrank return;
7542305Sstevel }
7552305Sstevel }
7562305Sstevel }
7572305Sstevel
7582305Sstevel /*
7592305Sstevel * Sought handle not currently cached.
7602305Sstevel */
7612305Sstevel RELEASE_CACHE
7622305Sstevel
7632305Sstevel (void) snprintf(envhdl->name, sizeof (envhdl->name),
7642305Sstevel "Unknown SC node 0x%x", hdl);
7652305Sstevel }
7662305Sstevel
7672305Sstevel static void
rmclomv_dr_data_handler(const char * fru_name,int hint)7682305Sstevel rmclomv_dr_data_handler(const char *fru_name, int hint)
7692305Sstevel {
7702305Sstevel int err = 0;
7712305Sstevel nvlist_t *attr_list;
7722305Sstevel char attach_pnt[MAXPATHLEN];
7732305Sstevel
7742305Sstevel (void) snprintf(attach_pnt, sizeof (attach_pnt), "%s", fru_name);
7752305Sstevel
7762305Sstevel err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
7772305Sstevel if (err != 0) {
7782305Sstevel cmn_err(CE_WARN,
7792305Sstevel "Failed to allocate name-value list for %s event", EC_DR);
7802305Sstevel return;
7812305Sstevel }
7822305Sstevel
7832305Sstevel err = nvlist_add_string(attr_list, DR_AP_ID, attach_pnt);
7842305Sstevel if (err != 0) {
7852305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
7862305Sstevel DR_AP_ID, EC_DR);
7872305Sstevel nvlist_free(attr_list);
7882305Sstevel return;
7892305Sstevel }
7902305Sstevel
7912305Sstevel /*
7922305Sstevel * Add the hint
7932305Sstevel */
7942305Sstevel err = nvlist_add_string(attr_list, DR_HINT, SE_HINT2STR(hint));
7952305Sstevel if (err != 0) {
7962305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
7972305Sstevel DR_HINT, EC_DR);
7982305Sstevel nvlist_free(attr_list);
7992305Sstevel return;
8002305Sstevel }
8012305Sstevel
8022305Sstevel err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_DR,
8032305Sstevel ESC_DR_AP_STATE_CHANGE, attr_list, NULL, DDI_NOSLEEP);
8042305Sstevel if (err != 0) {
8052305Sstevel cmn_err(CE_WARN, "Failed to log %s/%s event",
8062305Sstevel DR_AP_ID, EC_DR);
8072305Sstevel }
8082305Sstevel
8092305Sstevel nvlist_free(attr_list);
8102305Sstevel }
8112305Sstevel
8122305Sstevel static void
fan_sysevent(char * fru_name,char * sensor_name,int sub_event)8132305Sstevel fan_sysevent(char *fru_name, char *sensor_name, int sub_event)
8142305Sstevel {
8152305Sstevel nvlist_t *attr_list;
8162305Sstevel char fan_str[MAXNAMELEN];
8172305Sstevel int err;
8182305Sstevel
8192305Sstevel err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
8202305Sstevel if (err != 0) {
8212305Sstevel cmn_err(CE_WARN,
8222305Sstevel "Failed to allocate name-value list for %s/%s event",
8232305Sstevel EC_ENV, ESC_ENV_FAN);
8242305Sstevel return;
8252305Sstevel }
8262305Sstevel
8272305Sstevel err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name);
8282305Sstevel if (err != 0) {
8292305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
8302305Sstevel ENV_FRU_ID, EC_ENV, ESC_ENV_FAN);
8312305Sstevel nvlist_free(attr_list);
8322305Sstevel return;
8332305Sstevel }
8342305Sstevel
8352305Sstevel err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name);
8362305Sstevel if (err != 0) {
8372305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
8382305Sstevel ENV_FRU_RESOURCE_ID, EC_ENV, ESC_ENV_FAN);
8392305Sstevel nvlist_free(attr_list);
8402305Sstevel return;
8412305Sstevel }
8422305Sstevel
8432305Sstevel err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR);
8442305Sstevel if (err != 0) {
8452305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
8462305Sstevel ENV_FRU_DEVICE, EC_ENV, ESC_ENV_FAN);
8472305Sstevel nvlist_free(attr_list);
8482305Sstevel return;
8492305Sstevel }
8502305Sstevel
8512305Sstevel err = nvlist_add_int32(attr_list, ENV_FRU_STATE,
8522305Sstevel (sub_event == RMC_ENV_FAULT_EVENT) ? ENV_FAILED : ENV_OK);
8532305Sstevel if (err != 0) {
8542305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
8552305Sstevel ENV_FRU_STATE, EC_ENV, ESC_ENV_FAN);
8562305Sstevel nvlist_free(attr_list);
8572305Sstevel return;
8582305Sstevel }
8592305Sstevel
8602305Sstevel if (sub_event == RMC_ENV_FAULT_EVENT) {
8612305Sstevel (void) snprintf(fan_str, sizeof (fan_str),
8622305Sstevel "fan %s/%s is now failed", fru_name, sensor_name);
8632305Sstevel } else {
8642305Sstevel (void) snprintf(fan_str, sizeof (fan_str),
8652305Sstevel "fan %s/%s is now ok", fru_name, sensor_name);
8662305Sstevel }
8672305Sstevel err = nvlist_add_string(attr_list, ENV_MSG, fan_str);
8682305Sstevel if (err != 0) {
8692305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
8702305Sstevel ENV_MSG, EC_ENV, ESC_ENV_FAN);
8712305Sstevel nvlist_free(attr_list);
8722305Sstevel return;
8732305Sstevel }
8742305Sstevel
8752305Sstevel err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV,
8762305Sstevel ESC_ENV_FAN, attr_list, NULL, DDI_NOSLEEP);
8772305Sstevel if (err != 0) {
8782305Sstevel cmn_err(CE_WARN, "Failed to log %s/%s event",
8792305Sstevel EC_ENV, ESC_ENV_FAN);
8802305Sstevel }
8812305Sstevel
8822305Sstevel cmn_err(CE_NOTE, "%s", fan_str);
8832305Sstevel nvlist_free(attr_list);
8842305Sstevel }
8852305Sstevel
8862305Sstevel static void
threshold_sysevent(char * fru_name,char * sensor_name,int sub_event,char event_type)8872305Sstevel threshold_sysevent(char *fru_name, char *sensor_name, int sub_event,
8882305Sstevel char event_type)
8892305Sstevel {
8902305Sstevel nvlist_t *attr_list;
8912305Sstevel int err;
8922305Sstevel char *subclass;
8932305Sstevel char sensor_str[MAXNAMELEN];
8942305Sstevel
8952305Sstevel subclass = (event_type == 'T') ? ESC_ENV_TEMP : ESC_ENV_POWER;
8962305Sstevel
8972305Sstevel err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
8982305Sstevel if (err != 0) {
8992305Sstevel cmn_err(CE_WARN,
9002305Sstevel "Failed to allocate name-value list for %s/%s event",
9012305Sstevel EC_ENV, subclass);
9022305Sstevel return;
9032305Sstevel }
9042305Sstevel
9052305Sstevel err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name);
9062305Sstevel if (err != 0) {
9072305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
9082305Sstevel ENV_FRU_ID, EC_ENV, subclass);
9092305Sstevel nvlist_free(attr_list);
9102305Sstevel return;
9112305Sstevel }
9122305Sstevel
9132305Sstevel err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name);
9142305Sstevel if (err != 0) {
9152305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
9162305Sstevel ENV_FRU_RESOURCE_ID, EC_ENV, subclass);
9172305Sstevel nvlist_free(attr_list);
9182305Sstevel return;
9192305Sstevel }
9202305Sstevel
9212305Sstevel err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR);
9222305Sstevel if (err != 0) {
9232305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
9242305Sstevel ENV_FRU_DEVICE, EC_ENV, subclass);
9252305Sstevel nvlist_free(attr_list);
9262305Sstevel return;
9272305Sstevel }
9282305Sstevel
9292305Sstevel switch (sub_event) {
9302305Sstevel case RMC_ENV_OK_EVENT:
9312305Sstevel err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_OK);
9322305Sstevel break;
9332305Sstevel case RMC_ENV_WARNING_THRESHOLD_EVENT:
9342305Sstevel err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_WARNING);
9352305Sstevel break;
9362305Sstevel case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
9372305Sstevel err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_FAILED);
9382305Sstevel break;
9392305Sstevel }
9402305Sstevel if (err != 0) {
9412305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
9422305Sstevel ENV_FRU_STATE, EC_ENV, subclass);
9432305Sstevel nvlist_free(attr_list);
9442305Sstevel return;
9452305Sstevel }
9462305Sstevel
9472305Sstevel switch (sub_event) {
9482305Sstevel case RMC_ENV_OK_EVENT:
9492305Sstevel (void) snprintf(sensor_str, sizeof (sensor_str),
9502305Sstevel "sensor %s/%s is now ok", fru_name,
9512305Sstevel sensor_name);
9522305Sstevel break;
9532305Sstevel case RMC_ENV_WARNING_THRESHOLD_EVENT:
9542305Sstevel (void) snprintf(sensor_str, sizeof (sensor_str),
9552305Sstevel "sensor %s/%s is now outside warning thresholds", fru_name,
9562305Sstevel sensor_name);
9572305Sstevel break;
9582305Sstevel case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
9592305Sstevel (void) snprintf(sensor_str, sizeof (sensor_str),
9602305Sstevel "sensor %s/%s is now outside shutdown thresholds", fru_name,
9612305Sstevel sensor_name);
9622305Sstevel break;
9632305Sstevel }
9642305Sstevel err = nvlist_add_string(attr_list, ENV_MSG, sensor_str);
9652305Sstevel if (err != 0) {
9662305Sstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
9672305Sstevel ENV_MSG, EC_ENV, subclass);
9682305Sstevel nvlist_free(attr_list);
9692305Sstevel return;
9702305Sstevel }
9712305Sstevel
9722305Sstevel err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV,
9732305Sstevel subclass, attr_list, NULL, DDI_NOSLEEP);
9742305Sstevel if (err != 0) {
9752305Sstevel cmn_err(CE_WARN, "Failed to log %s/%s event",
9762305Sstevel EC_ENV, subclass);
9772305Sstevel }
9782305Sstevel
9792305Sstevel cmn_err(CE_NOTE, "%s", sensor_str);
9802305Sstevel nvlist_free(attr_list);
9812305Sstevel }
9822305Sstevel
9832305Sstevel static uint_t
rmclomv_event_data_handler(char * arg)9842305Sstevel rmclomv_event_data_handler(char *arg)
9852305Sstevel {
9862305Sstevel dp_event_notification_t *payload;
9872305Sstevel rmc_comm_msg_t *msg;
9882305Sstevel envmon_handle_t envhdl;
9892305Sstevel int hint;
9902305Sstevel char *ptr, *save_ptr;
9912305Sstevel
9922305Sstevel if (arg == NULL) {
9932305Sstevel return (DDI_INTR_CLAIMED);
9942305Sstevel }
9952305Sstevel
9962305Sstevel msg = (rmc_comm_msg_t *)arg;
9972305Sstevel if (msg->msg_buf == NULL) {
9982305Sstevel return (DDI_INTR_CLAIMED);
9992305Sstevel }
10002305Sstevel
10012305Sstevel payload = (dp_event_notification_t *)msg->msg_buf;
10022305Sstevel switch (payload->event) {
10032305Sstevel
10042305Sstevel case RMC_KEYSWITCH_EVENT:
10052305Sstevel real_key_position = payload->event_info.ev_keysw.key_position;
10062305Sstevel cmn_err(CE_NOTE, "keyswitch change event - state = %s",
10072305Sstevel rmclomv_key_position(real_key_position));
10082305Sstevel if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) &&
10092305Sstevel (real_key_position <= RMC_KEYSWITCH_POS_OFF)) {
10102305Sstevel key_position = real_key_position;
10112305Sstevel } else {
10122305Sstevel /* treat unknown key position as locked */
10132305Sstevel key_position = RMC_KEYSWITCH_POS_LOCKED;
10142305Sstevel }
10152305Sstevel break;
10162305Sstevel
10172305Sstevel case RMC_HPU_EVENT:
10182305Sstevel /*
10192305Sstevel * send appropriate sysevent
10202305Sstevel */
10212305Sstevel switch (payload->event_info.ev_hpunot.sub_event) {
10222305Sstevel case RMC_HPU_REMOVE_EVENT:
10232305Sstevel hint = SE_HINT_REMOVE;
10242305Sstevel break;
10252305Sstevel case RMC_HPU_INSERT_EVENT:
10262305Sstevel hint = SE_HINT_INSERT;
10272305Sstevel break;
10282305Sstevel default:
10292305Sstevel hint = SE_NO_HINT;
10302305Sstevel break;
10312305Sstevel }
10322305Sstevel rmclomv_hdl_to_envhdl(payload->event_info.ev_hpunot.hpu_hdl,
10332305Sstevel &envhdl);
10342305Sstevel rmclomv_dr_data_handler(envhdl.name, hint);
10352305Sstevel break;
10362305Sstevel
10372305Sstevel case RMC_INIT_EVENT:
10382305Sstevel /*
10392305Sstevel * Wake up the refresh thread.
10402305Sstevel */
10412305Sstevel rmclomv_refresh_wakeup();
10422305Sstevel
10432305Sstevel /*
10442305Sstevel * Wake up the checkrmc thread for an early indication to PICL
10452305Sstevel */
10462305Sstevel rmclomv_checkrmc_wakeup(NULL);
10472305Sstevel break;
10482305Sstevel
10492305Sstevel case RMC_ENV_EVENT:
10502305Sstevel rmclomv_hdl_to_envhdl(payload->event_info.ev_envnot.env_hdl,
10512305Sstevel &envhdl);
10522305Sstevel
10532305Sstevel /* split name into fru name and sensor name */
10542305Sstevel ptr = strchr(envhdl.name, '.');
10552305Sstevel
10562305Sstevel /* must have at least one '.' */
10572305Sstevel if (ptr == NULL)
10582305Sstevel break;
10592305Sstevel
10602305Sstevel /* find last '.' - convert the others to '/' */
10612305Sstevel for (;;) {
10622305Sstevel save_ptr = ptr;
10632305Sstevel ptr = strchr(ptr, '.');
10642305Sstevel if (ptr == NULL) {
10652305Sstevel ptr = save_ptr;
10662305Sstevel break;
10672305Sstevel }
10682305Sstevel *save_ptr = '/';
10692305Sstevel }
10702305Sstevel *ptr = '\0';
10712305Sstevel ptr++;
10722305Sstevel /* is it a voltage or temperature sensor? */
10732305Sstevel if ((*ptr == 'V' || *ptr == 'T') && *(ptr + 1) == '_') {
10742305Sstevel switch (payload->event_info.ev_envnot.sub_event) {
10752305Sstevel case RMC_ENV_WARNING_THRESHOLD_EVENT:
10762305Sstevel case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
10772305Sstevel case RMC_ENV_OK_EVENT:
10782305Sstevel threshold_sysevent(envhdl.name, ptr,
10792305Sstevel payload->event_info.ev_envnot.sub_event,
10802305Sstevel *ptr);
10812305Sstevel break;
10822305Sstevel default:
10832305Sstevel break;
10842305Sstevel }
10852305Sstevel }
10862305Sstevel
10872305Sstevel /*
10882305Sstevel * is it a fan sensor?
10892305Sstevel * Fan sensor names end either in RS, F0 or F1
10902305Sstevel */
10912305Sstevel if ((*ptr == 'R' && *(ptr + 1) == 'S' && *(ptr + 2) == '\0') ||
10922305Sstevel (*ptr == 'F' && *(ptr + 1) == '0' && *(ptr + 2) == '\0') ||
10932305Sstevel (*ptr == 'F' && *(ptr + 1) == '1' && *(ptr + 2) == '\0')) {
10942305Sstevel switch (payload->event_info.ev_envnot.sub_event) {
10952305Sstevel case RMC_ENV_FAULT_EVENT:
10962305Sstevel case RMC_ENV_OK_EVENT:
10972305Sstevel fan_sysevent(envhdl.name, ptr,
10982305Sstevel payload->event_info.ev_envnot.sub_event);
10992305Sstevel break;
11002305Sstevel default:
11012305Sstevel break;
11022305Sstevel }
11032305Sstevel }
11042305Sstevel break;
11052305Sstevel
11062305Sstevel case RMC_LOG_EVENT:
11072305Sstevel {
11082305Sstevel int level = 10;
11092305Sstevel int flags = SL_NOTE | SL_CONSOLE;
11102305Sstevel char *message =
11112305Sstevel (char *)payload->event_info.ev_rmclog.log_record;
11122305Sstevel
11132305Sstevel message[ payload->event_info.ev_rmclog.log_record_size] = '\0';
11142305Sstevel
11152305Sstevel /*
11162305Sstevel * Logs have a 10 character prefix - specifying the severity of
11172305Sstevel * the event being logged. Thus all the magic number 10s down
11182305Sstevel * here
11192305Sstevel */
11202305Sstevel if (0 == strncmp("CRITICAL: ", message, 10)) {
11212305Sstevel message += 10;
11222305Sstevel level = 0;
11232305Sstevel flags = SL_FATAL | SL_ERROR | SL_CONSOLE;
11242305Sstevel } else if (0 == strncmp("MAJOR: ", message, 10)) {
11252305Sstevel message += 10;
11262305Sstevel level = 5;
11272305Sstevel flags = SL_WARN | SL_ERROR | SL_CONSOLE;
11282305Sstevel } else if (0 == strncmp("MINOR: ", message, 10)) {
11292305Sstevel message += 10;
11302305Sstevel level = 10;
11312305Sstevel flags = SL_NOTE | SL_CONSOLE;
11322305Sstevel }
11332305Sstevel
11342305Sstevel (void) strlog(0, 0, level, flags, message);
11352305Sstevel break;
11362305Sstevel }
11372305Sstevel
11382305Sstevel default:
11392305Sstevel return (DDI_INTR_CLAIMED);
11402305Sstevel }
11412305Sstevel
11422305Sstevel return (DDI_INTR_CLAIMED);
11432305Sstevel }
11442305Sstevel
11452305Sstevel /*ARGSUSED*/
11462305Sstevel static int
rmclomv_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)11472305Sstevel rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
11482305Sstevel {
11492305Sstevel int error = 0;
11502305Sstevel int instance = getminor(*dev_p);
11512305Sstevel
11522305Sstevel if (instance != 0)
11532305Sstevel return (ENXIO);
11542305Sstevel
11552305Sstevel if ((flag & FWRITE) != 0 && (error = drv_priv(cred_p)) != 0)
11562305Sstevel return (error);
11572305Sstevel
11582305Sstevel return (0);
11592305Sstevel }
11602305Sstevel
11612305Sstevel /*ARGSUSED*/
11622305Sstevel static int
rmclomv_close(dev_t dev,int flag,int otyp,cred_t * cred_p)11632305Sstevel rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
11642305Sstevel {
11652305Sstevel return (DDI_SUCCESS);
11662305Sstevel }
11672305Sstevel
11682305Sstevel static int
rmclomv_do_cmd(int req_cmd,int resp_cmd,int resp_len,intptr_t arg_req,intptr_t arg_res)11692305Sstevel rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len, intptr_t arg_req,
11702305Sstevel intptr_t arg_res)
11712305Sstevel {
11722305Sstevel rmc_comm_msg_t request, *reqp = &request;
11732305Sstevel rmc_comm_msg_t response, *resp = &response;
11742305Sstevel int rv = 0;
11752305Sstevel
11762305Sstevel bzero((caddr_t)&request, sizeof (request));
11772305Sstevel reqp->msg_type = req_cmd;
11782305Sstevel reqp->msg_buf = (caddr_t)arg_req;
11792305Sstevel bzero((caddr_t)&response, sizeof (response));
11802305Sstevel resp->msg_type = resp_cmd;
11812305Sstevel resp->msg_buf = (caddr_t)arg_res;
11822305Sstevel resp->msg_len = resp_len;
11832305Sstevel
11842305Sstevel switch (req_cmd) {
11852305Sstevel case DP_GET_SYSINFO:
11862305Sstevel resp->msg_len = sizeof (dp_get_sysinfo_r_t);
11872305Sstevel break;
11882305Sstevel case DP_GET_EVENT_LOG:
11892305Sstevel resp->msg_len = sizeof (dp_get_event_log_r_t);
11902305Sstevel break;
11912305Sstevel case DP_GET_VOLTS:
11922305Sstevel reqp->msg_len = sizeof (dp_get_volts_t);
11932305Sstevel break;
11942305Sstevel case DP_GET_TEMPERATURES:
11952305Sstevel reqp->msg_len = sizeof (dp_get_temperatures_t);
11962305Sstevel break;
11972305Sstevel case DP_GET_CIRCUIT_BRKS:
11982305Sstevel reqp->msg_len = sizeof (dp_get_circuit_brks_t);
11992305Sstevel break;
12002305Sstevel case DP_GET_FAN_STATUS:
12012305Sstevel reqp->msg_len = sizeof (dp_get_fan_status_t);
12022305Sstevel break;
12032305Sstevel case DP_GET_PSU_STATUS:
12042305Sstevel reqp->msg_len = sizeof (dp_get_psu_status_t);
12052305Sstevel break;
12062305Sstevel case DP_GET_LED_STATE:
12072305Sstevel reqp->msg_len = sizeof (dp_get_led_state_t);
12082305Sstevel break;
12092305Sstevel case DP_SET_LED_STATE:
12102305Sstevel reqp->msg_len = sizeof (dp_set_led_state_t);
12112305Sstevel break;
12122305Sstevel case DP_GET_FRU_STATUS:
12132305Sstevel reqp->msg_len = sizeof (dp_get_fru_status_t);
12142305Sstevel break;
12152305Sstevel case DP_GET_HANDLE_NAME:
12162305Sstevel reqp->msg_len = sizeof (dp_get_handle_name_t);
12172305Sstevel break;
12182305Sstevel case DP_GET_ALARM_STATE:
12192305Sstevel reqp->msg_len = sizeof (dp_get_alarm_state_t);
12202305Sstevel break;
12212305Sstevel case DP_SET_ALARM_STATE:
12222305Sstevel reqp->msg_len = sizeof (dp_set_alarm_state_t);
12232305Sstevel break;
12242305Sstevel case DP_GET_SDP_VERSION:
12252305Sstevel resp->msg_len = sizeof (dp_get_sdp_version_r_t);
12262305Sstevel break;
12272305Sstevel case DP_GET_CHASSIS_SERIALNUM:
12282305Sstevel reqp->msg_len = 0;
12292305Sstevel break;
12302305Sstevel case DP_GET_DATE_TIME:
12312305Sstevel reqp->msg_len = 0;
12322305Sstevel break;
12332305Sstevel default:
12342305Sstevel return (EINVAL);
12352305Sstevel }
12362305Sstevel
12372305Sstevel rv = rmc_comm_request_response(reqp, resp,
12382305Sstevel RMCLOMV_DEFAULT_MAX_MBOX_WAIT_TIME);
12392305Sstevel
12402305Sstevel if (rv != RCNOERR) {
12412305Sstevel /*
12422305Sstevel * RMC returned an error or failed to respond.
12432305Sstevel * Where the RMC itself is implicated, rmclomv_rmc_error
12442305Sstevel * is set non-zero. It is cleared after an error free exchange.
12452305Sstevel * Two failure cases are distinguished:
12462305Sstevel * RMCLOMV_RMCSTATE_FAILED and RMCLOMV_RMCSTATE_DOWNLOAD.
12472305Sstevel */
12482305Sstevel switch (rv) {
12492305Sstevel case RCENOSOFTSTATE:
12502305Sstevel /* invalid/NULL soft state structure */
12512305Sstevel return (EIO);
12522305Sstevel case RCENODATALINK:
12532305Sstevel /*
12542305Sstevel * firmware download in progress,
12552305Sstevel * can you come back later?
12562305Sstevel */
12572305Sstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_DOWNLOAD;
12582305Sstevel rmclomv_rmc_state = RMCLOMV_RMCSTATE_DOWNLOAD;
12592305Sstevel return (EAGAIN);
12602305Sstevel case RCENOMEM:
12612305Sstevel /* memory problems */
12622305Sstevel return (ENOMEM);
12632305Sstevel case RCECANTRESEND:
12642305Sstevel /* resend failed */
12652305Sstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
12662305Sstevel return (EIO);
12672305Sstevel case RCEMAXRETRIES:
12682305Sstevel /* reply not received - retries exceeded */
12692305Sstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
12702305Sstevel return (EINTR);
12712305Sstevel case RCETIMEOUT:
12722305Sstevel /* reply not received - command has timed out */
12732305Sstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
12742305Sstevel return (EINTR);
12752305Sstevel case RCEINVCMD:
12762305Sstevel /* data protocol cmd not supported */
12772305Sstevel return (ENOTSUP);
12782305Sstevel case RCEINVARG:
12792305Sstevel /* invalid argument(s) */
12802305Sstevel return (ENOTSUP);
12812305Sstevel case RCEGENERIC:
12822305Sstevel /* generic error */
12832305Sstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
12842305Sstevel return (EIO);
12852305Sstevel default:
12862305Sstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
12872305Sstevel return (EIO);
12882305Sstevel }
12892305Sstevel }
12902305Sstevel
12912305Sstevel rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE;
12922305Sstevel return (0);
12932305Sstevel }
12942305Sstevel
12952305Sstevel /*
12962305Sstevel * validate_section_entry checks that the entry at the specified index
12972305Sstevel * is valid and not duplicated by an entry above. If these tests fail
12982305Sstevel * the entry is removed and B_FALSE returned. Otherwise returns B_TRUE.
12992305Sstevel */
13002305Sstevel static int
validate_section_entry(rmclomv_cache_section_t * section,int index)13012305Sstevel validate_section_entry(rmclomv_cache_section_t *section, int index)
13022305Sstevel {
13032305Sstevel int i;
13042305Sstevel rmclomv_cache_entry_t *entry;
13052305Sstevel
13062305Sstevel for (i = index; i < section->num_entries; i++) {
13072305Sstevel entry = §ion->entry[i];
13082305Sstevel if (entry->handle_name.name[0] == '\0') {
13092305Sstevel cmn_err(CE_WARN,
13102305Sstevel "rmclomv: empty handle_name, handle 0x%x type %x",
13112305Sstevel entry->handle, section->sensor_type);
13122305Sstevel } else if (entry->ind_mask != 0) {
13132305Sstevel continue; /* skip special entries */
13142305Sstevel } else if (entry->handle == DP_NULL_HANDLE) {
13152305Sstevel cmn_err(CE_WARN,
13162305Sstevel "rmclomv: null handle id for \"%s\" type %x",
13172305Sstevel entry->handle_name.name, section->sensor_type);
13182305Sstevel } else if (i == index) {
13192305Sstevel continue;
13202305Sstevel } else if (section->entry[index].handle == entry->handle) {
13212305Sstevel cmn_err(CE_WARN,
13222305Sstevel "rmclomv: duplicate handle 0x%x type %x",
13232305Sstevel entry->handle, section->sensor_type);
13242305Sstevel } else if (strcmp(entry->handle_name.name,
13252305Sstevel section->entry[index].handle_name.name) == 0) {
13262305Sstevel cmn_err(CE_WARN,
13272305Sstevel "rmclomv: duplicate handle_name \"%s\", "
13282305Sstevel "handle 0x%x type %x", entry->handle_name.name,
13292305Sstevel entry->handle, section->sensor_type);
13302305Sstevel } else
13312305Sstevel continue;
13322305Sstevel
13332305Sstevel /*
13342305Sstevel * need to remove the entry at index
13352305Sstevel */
13362305Sstevel section->num_entries--;
13372305Sstevel
13382305Sstevel for (i = index; i < section->num_entries; i++) {
13392305Sstevel section->entry[i] = section->entry[i + 1];
13402305Sstevel }
13412305Sstevel
13422305Sstevel return (B_FALSE);
13432305Sstevel }
13442305Sstevel
13452305Sstevel return (B_TRUE);
13462305Sstevel }
13472305Sstevel
13482305Sstevel /*
13492305Sstevel * Populate a section containing handles with corresponding names
13502305Sstevel * The supplied section structure must not be publically visible and the
13512305Sstevel * name cache must not be locked either (because RMC i/o is required).
13522305Sstevel *
13532305Sstevel * This is the place where a sanity check is applied. Entries containing
13542305Sstevel * duplicate handles, duplicate names or empty names are removed and the
13552305Sstevel * structure is compacted. As a result num_entries may be reduced.
13562305Sstevel */
13572305Sstevel static int
add_names_to_section(rmclomv_cache_section_t * section)13582305Sstevel add_names_to_section(rmclomv_cache_section_t *section)
13592305Sstevel {
13602305Sstevel int retval = 0;
13612305Sstevel int ditched = B_FALSE;
13622305Sstevel int index;
13632305Sstevel dp_get_handle_name_r_t handle_name_r;
13642305Sstevel rmclomv_cache_entry_t *entry;
13652305Sstevel
13662305Sstevel for (index = 0; index < section->num_entries; index++) {
13672305Sstevel entry = §ion->entry[index];
13682305Sstevel if (entry->ind_mask != 0)
13692305Sstevel continue; /* skip special entries */
13702305Sstevel handle_name_r.handle = entry->handle;
13712305Sstevel retval = rmclomv_do_cmd(DP_GET_HANDLE_NAME,
13722305Sstevel DP_GET_HANDLE_NAME_R, sizeof (handle_name_r),
13732305Sstevel (intptr_t)&handle_name_r, (intptr_t)&handle_name_r);
13742305Sstevel if (retval == 0)
13752305Sstevel bcopy(handle_name_r.name,
13762305Sstevel entry->handle_name.name, DP_MAX_HANDLE_NAME);
13772305Sstevel }
13782305Sstevel
13792305Sstevel /*
13802305Sstevel * now ditch invalid and duplicate entries
13812305Sstevel */
13822305Sstevel for (index = 0; index < section->num_entries; index++) {
13832305Sstevel while (validate_section_entry(section, index) == B_FALSE)
13842305Sstevel ditched = B_TRUE;
13852305Sstevel }
13862305Sstevel
13872305Sstevel if (ditched)
13882305Sstevel cmn_err(CE_WARN, "Retaining %d nodes of type %d",
13892305Sstevel section->num_entries, section->sensor_type);
13902305Sstevel
13912305Sstevel return (retval);
13922305Sstevel }
13932305Sstevel
13942305Sstevel /*
13952305Sstevel * The supplied (PSU) cache section is traversed and entries are created
13962305Sstevel * for the individual indicators belonging to a PSU. These entries are
13972305Sstevel * placed in a private chain. The caller, subsequently acquires the
13982305Sstevel * cache lock and copies the chain head to make it public.
13992305Sstevel * The handle-names for PSU indicators are derived from the parent PSU
14002305Sstevel * handle-name.
14012305Sstevel * NOTE: add_names_to_section() may have reduced psu_section->num_entries
14022305Sstevel * so DON'T USE psu_resp->num_psus
14032305Sstevel */
14042305Sstevel static void
make_psu_subsections(rmclomv_cache_section_t * psu_section,rmclomv_cache_section_t ** chain_head,dp_get_psu_status_r_t * psu_resp)14052305Sstevel make_psu_subsections(rmclomv_cache_section_t *psu_section,
14062305Sstevel rmclomv_cache_section_t **chain_head, dp_get_psu_status_r_t *psu_resp)
14072305Sstevel {
14082305Sstevel int index;
14092305Sstevel int subindex = 0;
14102305Sstevel rmclomv_cache_section_t *subsection;
14112305Sstevel rmclomv_cache_entry_t *src_entry;
14122305Sstevel rmclomv_cache_entry_t *dst_entry;
14132305Sstevel
14142305Sstevel subsection = create_cache_section(RMCLOMV_VOLT_IND,
14152305Sstevel RMCLOMV_MAX_VI_PER_PSU * psu_section->num_entries);
14162305Sstevel for (index = 0; index < psu_section->num_entries; index++) {
14172305Sstevel src_entry = &psu_section->entry[index];
14182305Sstevel if ((psu_resp->psu_status[index].mask &
14192305Sstevel DP_PSU_INPUT_STATUS) != 0) {
14202305Sstevel dst_entry = &subsection->entry[subindex++];
14212305Sstevel dst_entry->handle = src_entry->handle;
14222305Sstevel dst_entry->ind_mask = DP_PSU_INPUT_STATUS;
14232305Sstevel (void) snprintf(dst_entry->handle_name.name,
14242305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
14252305Sstevel src_entry->handle_name.name,
14262305Sstevel str_ip_volts_ind);
14272305Sstevel }
14282305Sstevel
14292305Sstevel if ((psu_resp->psu_status[index].mask &
14302305Sstevel DP_PSU_SEC_INPUT_STATUS) != 0) {
14312305Sstevel dst_entry = &subsection->entry[subindex++];
14322305Sstevel dst_entry->handle = src_entry->handle;
14332305Sstevel dst_entry->ind_mask = DP_PSU_SEC_INPUT_STATUS;
14342305Sstevel (void) snprintf(dst_entry->handle_name.name,
14352305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
14362305Sstevel src_entry->handle_name.name,
14372305Sstevel str_ip2_volts_ind);
14382305Sstevel }
14392305Sstevel
14402305Sstevel if ((psu_resp->psu_status[index].mask &
14412305Sstevel DP_PSU_OUTPUT_STATUS) != 0) {
14422305Sstevel dst_entry = &subsection->entry[subindex++];
14432305Sstevel dst_entry->handle = src_entry->handle;
14442305Sstevel dst_entry->ind_mask = DP_PSU_OUTPUT_STATUS;
14452305Sstevel (void) snprintf(dst_entry->handle_name.name,
14462305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
14472305Sstevel src_entry->handle_name.name,
14482305Sstevel str_ff_pok_ind);
14492305Sstevel }
14502305Sstevel
14512305Sstevel if ((psu_resp->psu_status[index].mask &
14522305Sstevel DP_PSU_OUTPUT_VLO_STATUS) != 0) {
14532305Sstevel dst_entry = &subsection->entry[subindex++];
14542305Sstevel dst_entry->handle = src_entry->handle;
14552305Sstevel dst_entry->ind_mask = DP_PSU_OUTPUT_VLO_STATUS;
14562305Sstevel (void) snprintf(dst_entry->handle_name.name,
14572305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
14582305Sstevel src_entry->handle_name.name,
14592305Sstevel str_vlo_volts_ind);
14602305Sstevel }
14612305Sstevel
14622305Sstevel if ((psu_resp->psu_status[index].mask &
14632305Sstevel DP_PSU_OUTPUT_VHI_STATUS) != 0) {
14642305Sstevel dst_entry = &subsection->entry[subindex++];
14652305Sstevel dst_entry->handle = src_entry->handle;
14662305Sstevel dst_entry->ind_mask = DP_PSU_OUTPUT_VHI_STATUS;
14672305Sstevel (void) snprintf(dst_entry->handle_name.name,
14682305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
14692305Sstevel src_entry->handle_name.name,
14702305Sstevel str_vhi_volts_ind);
14712305Sstevel }
14722305Sstevel }
14732305Sstevel /*
14742305Sstevel * Adjust number of entries value in cache section
14752305Sstevel * to match the facts.
14762305Sstevel */
14772305Sstevel subsection->num_entries = subindex;
14782305Sstevel add_section(chain_head, subsection);
14792305Sstevel
14802305Sstevel subsection = create_cache_section(RMCLOMV_AMP_IND,
14812305Sstevel RMCLOMV_MAX_CI_PER_PSU * psu_section->num_entries);
14822305Sstevel subindex = 0;
14832305Sstevel for (index = 0; index < psu_section->num_entries; index++) {
14842305Sstevel int mask = psu_resp->psu_status[index].mask;
14852305Sstevel src_entry = &psu_section->entry[index];
14862305Sstevel if ((mask & DP_PSU_OUTPUT_AHI_STATUS) != 0) {
14872305Sstevel dst_entry = &subsection->entry[subindex++];
14882305Sstevel dst_entry->handle = src_entry->handle;
14892305Sstevel dst_entry->ind_mask = DP_PSU_OUTPUT_AHI_STATUS;
14902305Sstevel (void) snprintf(dst_entry->handle_name.name,
14912305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
14922305Sstevel src_entry->handle_name.name,
14932305Sstevel str_chi_amps_ind);
14942305Sstevel }
14952305Sstevel if ((mask & DP_PSU_NR_WARNING) != 0) {
14962305Sstevel dst_entry = &subsection->entry[subindex++];
14972305Sstevel dst_entry->handle = src_entry->handle;
14982305Sstevel dst_entry->ind_mask = DP_PSU_NR_WARNING;
14992305Sstevel (void) snprintf(dst_entry->handle_name.name,
15002305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
15012305Sstevel src_entry->handle_name.name,
15022305Sstevel str_chi_nr_ind);
15032305Sstevel }
15042305Sstevel }
15052305Sstevel subsection->num_entries = subindex;
15062305Sstevel add_section(chain_head, subsection);
15072305Sstevel
15082305Sstevel subsection = create_cache_section(RMCLOMV_TEMP_IND,
15092305Sstevel psu_section->num_entries);
15102305Sstevel subindex = 0;
15112305Sstevel for (index = 0; index < psu_section->num_entries; index++) {
15122305Sstevel if ((psu_resp->psu_status[index].mask &
15132305Sstevel DP_PSU_OVERTEMP_FAULT) != 0) {
15142305Sstevel src_entry = &psu_section->entry[index];
15152305Sstevel dst_entry = &subsection->entry[subindex++];
15162305Sstevel dst_entry->handle = src_entry->handle;
15172305Sstevel dst_entry->ind_mask = DP_PSU_OVERTEMP_FAULT;
15182305Sstevel (void) snprintf(dst_entry->handle_name.name,
15192305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
15202305Sstevel src_entry->handle_name.name,
15212305Sstevel str_ot_tmpr_ind);
15222305Sstevel }
15232305Sstevel }
15242305Sstevel subsection->num_entries = subindex;
15252305Sstevel add_section(chain_head, subsection);
15262305Sstevel
15272305Sstevel subsection = create_cache_section(RMCLOMV_FAN_IND,
15282305Sstevel RMCLOMV_MAX_FI_PER_PSU * psu_section->num_entries);
15292305Sstevel subindex = 0;
15302305Sstevel for (index = 0; index < psu_section->num_entries; index++) {
15312305Sstevel int mask = psu_resp->psu_status[index].mask;
15322305Sstevel src_entry = &psu_section->entry[index];
15332305Sstevel if ((mask & DP_PSU_FAN_FAULT) != 0) {
15342305Sstevel dst_entry = &subsection->entry[subindex++];
15352305Sstevel dst_entry->handle = src_entry->handle;
15362305Sstevel dst_entry->ind_mask = DP_PSU_FAN_FAULT;
15372305Sstevel (void) snprintf(dst_entry->handle_name.name,
15382305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
15392305Sstevel src_entry->handle_name.name, str_fan_ind);
15402305Sstevel }
15412305Sstevel if ((mask & DP_PSU_PDCT_FAN) != 0) {
15422305Sstevel dst_entry = &subsection->entry[subindex++];
15432305Sstevel dst_entry->handle = src_entry->handle;
15442305Sstevel dst_entry->ind_mask = DP_PSU_PDCT_FAN;
15452305Sstevel (void) snprintf(dst_entry->handle_name.name,
15462305Sstevel ENVMON_MAXNAMELEN, "%s.%s",
15472305Sstevel src_entry->handle_name.name, str_pdct_fan_ind);
15482305Sstevel }
15492305Sstevel }
15502305Sstevel subsection->num_entries = subindex;
15512305Sstevel add_section(chain_head, subsection);
15522305Sstevel }
15532305Sstevel
15542305Sstevel static void
refresh_name_cache(int force_fail)15552305Sstevel refresh_name_cache(int force_fail)
15562305Sstevel {
15572305Sstevel union {
15582305Sstevel dp_get_volts_t u_volts_cmd;
15592305Sstevel dp_get_temperatures_t u_temp_cmd;
15602305Sstevel dp_get_circuit_brks_t u_ampi_cmd;
15612305Sstevel dp_get_fan_status_t u_fan_cmd;
15622305Sstevel dp_get_psu_status_t u_psu_cmd;
15632305Sstevel dp_get_fru_status_t u_fru_cmd;
15642305Sstevel dp_get_led_state_t u_led_cmd;
15652305Sstevel dp_set_led_state_t u_setled_cmd;
15662305Sstevel dp_get_alarm_state_t u_alarm_cmd;
15672305Sstevel dp_set_alarm_state_t u_setalarm_cmd;
15682305Sstevel } rmc_cmdbuf;
15692305Sstevel
15702305Sstevel /* defines for accessing union fields */
15712305Sstevel #define volts_cmd rmc_cmdbuf.u_volts_cmd
15722305Sstevel #define temp_cmd rmc_cmdbuf.u_temp_cmd
15732305Sstevel #define ampi_cmd rmc_cmdbuf.u_ampi_cmd
15742305Sstevel #define fan_cmd rmc_cmdbuf.u_fan_cmd
15752305Sstevel #define psu_cmd rmc_cmdbuf.u_psu_cmd
15762305Sstevel #define fru_cmd rmc_cmdbuf.u_fru_cmd
15772305Sstevel #define led_cmd rmc_cmdbuf.u_led_cmd
15782305Sstevel #define setled_cmd rmc_cmdbuf.u_setled_cmd
15792305Sstevel #define alarm_cmd rmc_cmdbuf.u_alarm_cmd
15802305Sstevel #define setalarm_cmd rmc_cmdbuf.u_setalarm_cmd
15812305Sstevel
15822305Sstevel /*
15832305Sstevel * Data area to read sensor data into
15842305Sstevel */
15852305Sstevel static union {
15862305Sstevel char reservation[RMCRESBUFLEN];
15872305Sstevel dp_get_volts_r_t u_volts_r;
15882305Sstevel dp_get_temperatures_r_t u_temp_r;
15892305Sstevel dp_get_circuit_brks_r_t u_ampi_r;
15902305Sstevel dp_get_fan_status_r_t u_fan_r;
15912305Sstevel dp_get_psu_status_r_t u_psu_r;
15922305Sstevel dp_get_fru_status_r_t u_fru_r;
15932305Sstevel dp_get_led_state_r_t u_led_r;
15942305Sstevel dp_set_led_state_r_t u_setled_r;
15952305Sstevel dp_get_alarm_state_r_t u_alarm_r;
15962305Sstevel dp_set_alarm_state_r_t u_setalarm_r;
15972305Sstevel } rmc_sensbuf;
15982305Sstevel
15992305Sstevel /* defines for accessing union fields */
16002305Sstevel #define volts_r rmc_sensbuf.u_volts_r
16012305Sstevel #define temp_r rmc_sensbuf.u_temp_r
16022305Sstevel #define ampi_r rmc_sensbuf.u_ampi_r
16032305Sstevel #define fan_r rmc_sensbuf.u_fan_r
16042305Sstevel #define psu_r rmc_sensbuf.u_psu_r
16052305Sstevel #define fru_r rmc_sensbuf.u_fru_r
16062305Sstevel #define led_r rmc_sensbuf.u_led_r
16072305Sstevel #define setled_r rmc_sensbuf.u_setled_r
16082305Sstevel #define alarm_r rmc_sensbuf.u_alarm_r
16092305Sstevel #define setalarm_r rmc_sensbuf.u_setalarm_r
16102305Sstevel
16112305Sstevel int retval = force_fail;
16122305Sstevel int retval1 = retval;
16132305Sstevel int index;
16142305Sstevel rmclomv_cache_section_t *my_chain = NULL;
16152305Sstevel rmclomv_cache_section_t *derived_chain = NULL;
16162305Sstevel rmclomv_cache_section_t *section;
16172305Sstevel rmclomv_cache_section_t *psu_section;
16182305Sstevel rmclomv_cache_section_t *fru_section;
16192305Sstevel dp_get_sysinfo_r_t sysinfo;
16202305Sstevel rmclomv_cache_entry_t *entry;
16212305Sstevel
16222305Sstevel if (retval == 0) {
16232305Sstevel retval = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R,
16242305Sstevel sizeof (sysinfo), NULL, (intptr_t)&sysinfo);
16252305Sstevel }
16262305Sstevel if (retval == 0) {
16272305Sstevel fru_cmd.handle = DP_NULL_HANDLE;
16282305Sstevel retval = rmclomv_do_cmd(DP_GET_FRU_STATUS, DP_GET_FRU_STATUS_R,
16292305Sstevel RMCRESBUFLEN, (intptr_t)&fru_cmd, (intptr_t)&fru_r);
16302305Sstevel }
16312305Sstevel if (retval != 0)
16322305Sstevel fru_r.num_frus = 0;
16332305Sstevel
16342305Sstevel /*
16352305Sstevel * Reserve space for special additional entries in the FRU section
16362305Sstevel */
16372305Sstevel fru_section = create_cache_section(RMCLOMV_HPU_IND,
16382305Sstevel RMCLOMV_NUM_SPECIAL_FRUS + fru_r.num_frus);
16392305Sstevel
16402305Sstevel /*
16412305Sstevel * add special entry for RMC itself
16422305Sstevel */
16432305Sstevel entry = &fru_section->entry[0];
16442305Sstevel (void) snprintf(entry->handle_name.name, sizeof (envmon_handle_t),
16452305Sstevel "SC");
16462305Sstevel entry->handle = 0;
16472305Sstevel entry->ind_mask = 1; /* flag as a special entry */
16482305Sstevel
16492305Sstevel /*
16502305Sstevel * populate any other FRU entries
16512305Sstevel */
16522305Sstevel for (index = 0; index < fru_r.num_frus; index++) {
16532305Sstevel fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].handle =
16542305Sstevel fru_r.fru_status[index].handle;
16552305Sstevel fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].ind_mask =
16562305Sstevel 0;
16572305Sstevel }
16582305Sstevel
16592305Sstevel my_chain = fru_section;
16602305Sstevel
16612305Sstevel if (retval == 0) {
16622305Sstevel volts_cmd.handle = DP_NULL_HANDLE;
16632305Sstevel retval = rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R,
16642305Sstevel RMCRESBUFLEN, (intptr_t)&volts_cmd, (intptr_t)&volts_r);
16652305Sstevel }
16662305Sstevel if (retval == 0) {
16672305Sstevel section = create_cache_section(RMCLOMV_VOLT_SENS,
16682305Sstevel volts_r.num_volts);
16692305Sstevel for (index = 0; index < volts_r.num_volts; index++) {
16702305Sstevel section->entry[index].handle =
16712305Sstevel volts_r.volt_status[index].handle;
16722305Sstevel }
16732305Sstevel add_section(&my_chain, section);
16742305Sstevel }
16752305Sstevel if (retval == 0) {
16762305Sstevel temp_cmd.handle = DP_NULL_HANDLE;
16772305Sstevel retval = rmclomv_do_cmd(DP_GET_TEMPERATURES,
16782305Sstevel DP_GET_TEMPERATURES_R, RMCRESBUFLEN,
16792305Sstevel (intptr_t)&temp_cmd, (intptr_t)&temp_r);
16802305Sstevel }
16812305Sstevel if (retval == 0) {
16822305Sstevel section = create_cache_section(RMCLOMV_TEMP_SENS,
16832305Sstevel temp_r.num_temps);
16842305Sstevel for (index = 0; index < temp_r.num_temps; index++) {
16852305Sstevel section->entry[index].handle =
16862305Sstevel temp_r.temp_status[index].handle;
16872305Sstevel }
16882305Sstevel add_section(&my_chain, section);
16892305Sstevel }
16902305Sstevel if (retval == 0) {
16912305Sstevel fan_cmd.handle = DP_NULL_HANDLE;
16922305Sstevel retval = rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R,
16932305Sstevel RMCRESBUFLEN, (intptr_t)&fan_cmd, (intptr_t)&fan_r);
16942305Sstevel }
16952305Sstevel if (retval == 0) {
16962305Sstevel section = create_cache_section(RMCLOMV_FAN_SENS,
16972305Sstevel fan_r.num_fans);
16982305Sstevel for (index = 0; index < fan_r.num_fans; index++) {
16992305Sstevel section->entry[index].handle =
17002305Sstevel fan_r.fan_status[index].handle;
17012305Sstevel }
17022305Sstevel add_section(&my_chain, section);
17032305Sstevel }
17042305Sstevel if (retval == 0) {
17052305Sstevel ampi_cmd.handle = DP_NULL_HANDLE;
17062305Sstevel retval = rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS,
17072305Sstevel DP_GET_CIRCUIT_BRKS_R, RMCRESBUFLEN,
17082305Sstevel (intptr_t)&i_cmd, (intptr_t)&i_r);
17092305Sstevel }
17102305Sstevel if (retval == 0) {
17112305Sstevel section = create_cache_section(RMCLOMV_AMP_IND,
17122305Sstevel ampi_r.num_circuit_brks);
17132305Sstevel for (index = 0; index < ampi_r.num_circuit_brks; index++) {
17142305Sstevel section->entry[index].handle =
17152305Sstevel ampi_r.circuit_brk_status[index].handle;
17162305Sstevel }
17172305Sstevel add_section(&my_chain, section);
17182305Sstevel }
17192305Sstevel if (retval == 0) {
17202305Sstevel led_cmd.handle = DP_NULL_HANDLE;
17212305Sstevel retval = rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R,
17222305Sstevel RMCRESBUFLEN, (intptr_t)&led_cmd, (intptr_t)&led_r);
17232305Sstevel }
17242305Sstevel if (retval == 0) {
17252305Sstevel section = create_cache_section(RMCLOMV_LED_IND,
17262305Sstevel led_r.num_leds);
17272305Sstevel for (index = 0; index < led_r.num_leds; index++) {
17282305Sstevel section->entry[index].handle =
17292305Sstevel led_r.led_state[index].handle;
17302305Sstevel }
17312305Sstevel add_section(&my_chain, section);
17322305Sstevel }
17332305Sstevel /*
17342305Sstevel * The command DP_GET_ALARM_STATE may not be valid on
17352305Sstevel * some RMC versions, so we ignore the return value
17362305Sstevel * and proceed
17372305Sstevel */
17382305Sstevel if (retval == 0) {
17392305Sstevel alarm_cmd.handle = DP_NULL_HANDLE;
17402305Sstevel retval1 = rmclomv_do_cmd(DP_GET_ALARM_STATE,
17415593Sjfrank DP_GET_ALARM_STATE_R, RMCRESBUFLEN,
17425593Sjfrank (intptr_t)&alarm_cmd, (intptr_t)&alarm_r);
17432305Sstevel if ((retval1 == 0) && alarm_r.num_alarms) {
17442305Sstevel section = create_cache_section(RMCLOMV_ALARM_IND,
17455593Sjfrank alarm_r.num_alarms);
17462305Sstevel for (index = 0; index < alarm_r.num_alarms; index++) {
17472305Sstevel section->entry[index].handle =
17485593Sjfrank alarm_r.alarm_state[index].handle;
17492305Sstevel }
17502305Sstevel add_section(&my_chain, section);
17512305Sstevel }
17522305Sstevel }
17532305Sstevel if (retval == 0) {
17542305Sstevel psu_cmd.handle = DP_NULL_HANDLE;
17552305Sstevel retval = rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R,
17562305Sstevel RMCRESBUFLEN, (intptr_t)&psu_cmd, (intptr_t)&psu_r);
17572305Sstevel }
17582305Sstevel if (retval == 0) {
17592305Sstevel /*
17602305Sstevel * WARNING:
17612305Sstevel * =======
17622305Sstevel * The PSUs must be probed last so that the response data
17632305Sstevel * (psu_r) is available for make_psu_subsections() below.
17642305Sstevel * Note that all the responses share the same data area
17652305Sstevel * which is declared as a union.
17662305Sstevel */
17672305Sstevel psu_section = create_cache_section(RMCLOMV_PSU_IND,
17682305Sstevel psu_r.num_psus);
17692305Sstevel for (index = 0; index < psu_r.num_psus; index++) {
17702305Sstevel psu_section->entry[index].handle =
17712305Sstevel psu_r.psu_status[index].handle;
17722305Sstevel }
17732305Sstevel add_section(&my_chain, psu_section);
17742305Sstevel }
17752305Sstevel if (retval == 0) {
17762305Sstevel for (section = my_chain;
17772305Sstevel section != NULL;
17782305Sstevel section = section->next_section) {
17792305Sstevel retval = add_names_to_section(section);
17802305Sstevel if (retval != 0) {
17812305Sstevel break;
17822305Sstevel }
17832305Sstevel }
17842305Sstevel }
17852305Sstevel
17862305Sstevel /*
17872305Sstevel * now add nodes derived from PSUs
17882305Sstevel */
17892305Sstevel if (retval == 0) {
17902305Sstevel make_psu_subsections(psu_section, &derived_chain, &psu_r);
17912305Sstevel /*
17922305Sstevel * name cache sections all set, exchange new for old
17932305Sstevel */
17942305Sstevel rmclomv_reset_cache(my_chain, derived_chain, &sysinfo);
17952305Sstevel } else {
17962305Sstevel /*
17972305Sstevel * RMC is not responding, ditch any existing cache
17982305Sstevel * and just leave the special SC FRU node
17992305Sstevel */
18002305Sstevel rmclomv_reset_cache(my_chain, NULL, NULL);
18012305Sstevel }
18022305Sstevel }
18032305Sstevel
18042305Sstevel static void
set_val_unav(envmon_sensor_t * sensor)18052305Sstevel set_val_unav(envmon_sensor_t *sensor)
18062305Sstevel {
18072305Sstevel sensor->value = ENVMON_VAL_UNAVAILABLE;
18082305Sstevel sensor->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE;
18092305Sstevel sensor->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
18102305Sstevel sensor->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
18112305Sstevel sensor->highthresholds.warning = ENVMON_VAL_UNAVAILABLE;
18122305Sstevel sensor->highthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
18132305Sstevel sensor->highthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
18142305Sstevel }
18152305Sstevel
18162305Sstevel static void
set_fan_unav(envmon_fan_t * fan)18172305Sstevel set_fan_unav(envmon_fan_t *fan)
18182305Sstevel {
18192305Sstevel fan->speed = ENVMON_VAL_UNAVAILABLE;
18202305Sstevel fan->units[0] = '\0';
18212305Sstevel fan->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE;
18222305Sstevel fan->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
18232305Sstevel fan->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
18242305Sstevel }
18252305Sstevel
18262305Sstevel static int
do_psu_cmd(intptr_t arg,int mode,envmon_indicator_t * env_ind,dp_get_psu_status_t * rmc_psu,dp_get_psu_status_r_t * rmc_psu_r,int detector_type)18272305Sstevel do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind,
18282305Sstevel dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r,
18292305Sstevel int detector_type)
18302305Sstevel {
18312305Sstevel int index;
18322305Sstevel uint16_t sensor_status;
18332305Sstevel rmclomv_cache_section_t *section;
18342305Sstevel uint16_t indicator_mask;
18352305Sstevel
18362305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)env_ind,
18372305Sstevel sizeof (envmon_indicator_t), mode) != 0)
18382305Sstevel return (EFAULT);
18392305Sstevel
18402305Sstevel /* ensure we've got PSU handles cached */
18412305Sstevel LOCK_CACHE
18422305Sstevel
18432305Sstevel sensor_status = ENVMON_SENSOR_OK;
18442305Sstevel section = rmclomv_find_section(rmclomv_subcache, detector_type);
18452305Sstevel if (env_ind->id.name[0] == '\0') {
18462305Sstevel /* request for first handle */
18472305Sstevel if ((section == NULL) || (section->num_entries == 0))
18482305Sstevel env_ind->next_id.name[0] = '\0';
18492305Sstevel else
18502305Sstevel env_ind->next_id = section->entry[0].handle_name;
18512305Sstevel sensor_status = ENVMON_NOT_PRESENT;
18522305Sstevel } else {
18532305Sstevel /* ensure name is properly terminated */
18542305Sstevel env_ind->id.name[ENVMON_MAXNAMELEN - 1] = '\0';
18552305Sstevel if ((section == NULL) || (get_sensor_by_name(section,
18562305Sstevel env_ind->id.name, &index)) != 0) {
18572305Sstevel env_ind->next_id.name[0] = '\0';
18582305Sstevel sensor_status = ENVMON_NOT_PRESENT;
18592305Sstevel } else if (index + 1 < section->num_entries)
18602305Sstevel env_ind->next_id =
18612305Sstevel section->entry[index + 1].handle_name;
18622305Sstevel else
18632305Sstevel env_ind->next_id.name[0] = '\0';
18642305Sstevel }
18652305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
18662305Sstevel /*
18672305Sstevel * user correctly identified a sensor, note its
18682305Sstevel * handle value and request the indicator status
18692305Sstevel */
18702305Sstevel rmc_psu->handle = section->entry[index].handle;
18712305Sstevel indicator_mask = section->entry[index].ind_mask;
18722305Sstevel }
18732305Sstevel
18742305Sstevel RELEASE_CACHE
18752305Sstevel
18762305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
18772305Sstevel rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R,
18782305Sstevel sizeof (dp_get_psu_status_r_t), (intptr_t)rmc_psu,
18792305Sstevel (intptr_t)rmc_psu_r) != 0)) {
18802305Sstevel sensor_status = ENVMON_INACCESSIBLE;
18812305Sstevel }
18822305Sstevel if ((env_ind->sensor_status = sensor_status) == ENVMON_SENSOR_OK) {
18832305Sstevel /*
18842305Sstevel * copy results into buffer for user
18852305Sstevel */
18862305Sstevel if ((rmc_psu_r->psu_status[0].flag & DP_PSU_PRESENCE) == 0)
18872305Sstevel env_ind->sensor_status |= ENVMON_NOT_PRESENT;
18882305Sstevel if (rmc_psu_r->psu_status[0].sensor_status !=
18892305Sstevel DP_SENSOR_DATA_AVAILABLE)
18902305Sstevel env_ind->sensor_status |= ENVMON_INACCESSIBLE;
18912305Sstevel env_ind->condition =
18922305Sstevel (rmc_psu_r->psu_status[0].flag & indicator_mask) == 0 ?
18932305Sstevel 0 : 1;
18942305Sstevel }
18952305Sstevel
18962305Sstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
18975593Sjfrank env_ind->sensor_status = ENVMON_INACCESSIBLE;
18982305Sstevel
18992305Sstevel if (ddi_copyout((caddr_t)env_ind, (caddr_t)arg,
19002305Sstevel sizeof (envmon_indicator_t), mode) != 0)
19012305Sstevel return (EFAULT);
19022305Sstevel
19032305Sstevel return (0);
19042305Sstevel }
19052305Sstevel
19062305Sstevel /*ARGSUSED*/
19072305Sstevel static int
rmclomv_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)19082305Sstevel rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
19092305Sstevel int *rval_p)
19102305Sstevel {
19112305Sstevel int instance = getminor(dev);
19122305Sstevel envmon_sysinfo_t lomv_sysinfo;
19132305Sstevel union {
19142305Sstevel envmon_sensor_t u_env_sensor;
19152305Sstevel envmon_indicator_t u_env_ind;
19162305Sstevel envmon_fan_t u_env_fan;
19172305Sstevel envmon_led_info_t u_env_ledinfo;
19182305Sstevel envmon_led_ctl_t u_env_ledctl;
19192305Sstevel envmon_hpu_t u_env_hpu;
19202305Sstevel envmon_alarm_info_t u_env_alarminfo;
19212305Sstevel envmon_alarm_ctl_t u_env_alarmctl;
19222305Sstevel } env_buf;
19232305Sstevel #define env_sensor env_buf.u_env_sensor
19242305Sstevel #define env_ind env_buf.u_env_ind
19252305Sstevel #define env_fan env_buf.u_env_fan
19262305Sstevel #define env_ledinfo env_buf.u_env_ledinfo
19272305Sstevel #define env_ledctl env_buf.u_env_ledctl
19282305Sstevel #define env_hpu env_buf.u_env_hpu
19292305Sstevel #define env_alarminfo env_buf.u_env_alarminfo
19302305Sstevel #define env_alarmctl env_buf.u_env_alarmctl
19312305Sstevel
19322305Sstevel union {
19332305Sstevel dp_get_volts_t u_rmc_volts;
19342305Sstevel dp_get_temperatures_t u_rmc_temp;
19352305Sstevel dp_get_circuit_brks_t u_rmc_ampi;
19362305Sstevel dp_get_fan_status_t u_rmc_fan;
19372305Sstevel dp_get_psu_status_t u_rmc_psu;
19382305Sstevel dp_get_fru_status_t u_rmc_fru;
19392305Sstevel dp_get_led_state_t u_rmc_led;
19402305Sstevel dp_set_led_state_t u_rmc_setled;
19412305Sstevel dp_get_alarm_state_t u_rmc_alarm;
19422305Sstevel dp_set_alarm_state_t u_rmc_setalarm;
19432305Sstevel } rmc_reqbuf;
19442305Sstevel #define rmc_volts rmc_reqbuf.u_rmc_volts
19452305Sstevel #define rmc_temp rmc_reqbuf.u_rmc_temp
19462305Sstevel #define rmc_ampi rmc_reqbuf.u_rmc_ampi
19472305Sstevel #define rmc_fan rmc_reqbuf.u_rmc_fan
19482305Sstevel #define rmc_psu rmc_reqbuf.u_rmc_psu
19492305Sstevel #define rmc_fru rmc_reqbuf.u_rmc_fru
19502305Sstevel #define rmc_led rmc_reqbuf.u_rmc_led
19512305Sstevel #define rmc_setled rmc_reqbuf.u_rmc_setled
19522305Sstevel #define rmc_alarm rmc_reqbuf.u_rmc_alarm
19532305Sstevel #define rmc_setalarm rmc_reqbuf.u_rmc_setalarm
19542305Sstevel
19552305Sstevel union {
19562305Sstevel dp_get_volts_r_t u_rmc_volts_r;
19572305Sstevel dp_get_temperatures_r_t u_rmc_temp_r;
19582305Sstevel dp_get_circuit_brks_r_t u_rmc_ampi_r;
19592305Sstevel dp_get_fan_status_r_t u_rmc_fan_r;
19602305Sstevel dp_get_psu_status_r_t u_rmc_psu_r;
19612305Sstevel dp_get_fru_status_r_t u_rmc_fru_r;
19622305Sstevel dp_get_led_state_r_t u_rmc_led_r;
19632305Sstevel dp_set_led_state_r_t u_rmc_setled_r;
19642305Sstevel dp_get_alarm_state_r_t u_rmc_alarm_r;
19652305Sstevel dp_set_alarm_state_r_t u_rmc_setalarm_r;
19662305Sstevel dp_get_sdp_version_r_t u_rmc_sdpversion_r;
19672305Sstevel dp_get_serialnum_r_t u_rmc_serialnum_r;
19682305Sstevel } rmc_resbuf;
19692305Sstevel #define rmc_volts_r rmc_resbuf.u_rmc_volts_r
19702305Sstevel #define rmc_temp_r rmc_resbuf.u_rmc_temp_r
19712305Sstevel #define rmc_ampi_r rmc_resbuf.u_rmc_ampi_r
19722305Sstevel #define rmc_fan_r rmc_resbuf.u_rmc_fan_r
19732305Sstevel #define rmc_psu_r rmc_resbuf.u_rmc_psu_r
19742305Sstevel #define rmc_fru_r rmc_resbuf.u_rmc_fru_r
19752305Sstevel #define rmc_led_r rmc_resbuf.u_rmc_led_r
19762305Sstevel #define rmc_setled_r rmc_resbuf.u_rmc_setled_r
19772305Sstevel #define rmc_alarm_r rmc_resbuf.u_rmc_alarm_r
19782305Sstevel #define rmc_setalarm_r rmc_resbuf.u_rmc_setalarm_r
19792305Sstevel #define rmc_sdpver_r rmc_resbuf.u_rmc_sdpversion_r
19802305Sstevel #define rmc_serialnum_r rmc_resbuf.u_rmc_serialnum_r
19812305Sstevel
19822305Sstevel int retval = 0;
19832305Sstevel int special = 0;
19842305Sstevel int index;
19852305Sstevel uint16_t sensor_status;
19862305Sstevel rmclomv_cache_section_t *section;
19872305Sstevel envmon_chassis_t chassis;
19882305Sstevel
19892305Sstevel if (instance != 0)
19902305Sstevel return (ENXIO);
19912305Sstevel
19922305Sstevel switch (cmd) {
19932305Sstevel case ENVMONIOCSYSINFO:
19942305Sstevel
19952305Sstevel LOCK_CACHE
19962305Sstevel
19972305Sstevel /*
19982305Sstevel * A number of OK/not_OK indicators are supported by PSUs
19992305Sstevel * (voltage, current, fan, temperature). So the maximum
20002305Sstevel * number of such indicators relates to the maximum number
20012305Sstevel * of power-supplies.
20022305Sstevel */
20032305Sstevel if (rmclomv_sysinfo_valid) {
20042305Sstevel lomv_sysinfo.maxVoltSens = rmclomv_sysinfo_data.maxVolt;
20052305Sstevel lomv_sysinfo.maxVoltInd =
20062305Sstevel RMCLOMV_MAX_VI_PER_PSU *
20072305Sstevel rmclomv_sysinfo_data.maxPSU;
20082305Sstevel /*
20092305Sstevel * the ALOM-Solaris interface does not include
20102305Sstevel * amp sensors, so we can hard code this value
20112305Sstevel */
20122305Sstevel lomv_sysinfo.maxAmpSens = 0;
20132305Sstevel lomv_sysinfo.maxAmpInd =
20142305Sstevel rmclomv_sysinfo_data.maxCircuitBrks +
20152305Sstevel (RMCLOMV_MAX_CI_PER_PSU *
20162305Sstevel rmclomv_sysinfo_data.maxPSU);
20172305Sstevel lomv_sysinfo.maxTempSens = rmclomv_sysinfo_data.maxTemp;
20182305Sstevel lomv_sysinfo.maxTempInd =
20192305Sstevel (RMCLOMV_MAX_TI_PER_PSU *
20202305Sstevel rmclomv_sysinfo_data.maxPSU);
20212305Sstevel lomv_sysinfo.maxFanSens = rmclomv_sysinfo_data.maxFan;
20222305Sstevel lomv_sysinfo.maxFanInd =
20232305Sstevel RMCLOMV_MAX_FI_PER_PSU *
20242305Sstevel rmclomv_sysinfo_data.maxPSU;
20252305Sstevel lomv_sysinfo.maxLED = rmclomv_sysinfo_data.maxLED;
20262305Sstevel lomv_sysinfo.maxHPU = RMCLOMV_NUM_SPECIAL_FRUS +
20272305Sstevel rmclomv_sysinfo_data.maxFRU;
20282305Sstevel } else {
20292305Sstevel bzero(&lomv_sysinfo, sizeof (lomv_sysinfo));
20302305Sstevel lomv_sysinfo.maxHPU = 1; /* just the SC node */
20312305Sstevel }
20322305Sstevel
20332305Sstevel RELEASE_CACHE
20342305Sstevel
20352305Sstevel if (ddi_copyout((caddr_t)&lomv_sysinfo, (caddr_t)arg,
20362305Sstevel sizeof (lomv_sysinfo), mode) != 0)
20372305Sstevel return (EFAULT);
20382305Sstevel break;
20392305Sstevel
20402305Sstevel case ENVMONIOCVOLTSENSOR:
20412305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
20422305Sstevel sizeof (envmon_sensor_t), mode) != 0)
20432305Sstevel return (EFAULT);
20442305Sstevel
20452305Sstevel /* see if we've got volts handles cached */
20462305Sstevel LOCK_CACHE
20472305Sstevel sensor_status = ENVMON_SENSOR_OK;
20482305Sstevel
20492305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
20502305Sstevel ((section = rmclomv_find_section(rmclomv_cache,
20512305Sstevel RMCLOMV_VOLT_SENS)) == NULL)) {
20522305Sstevel env_sensor.next_id.name[0] = '\0';
20532305Sstevel sensor_status = ENVMON_NOT_PRESENT;
20542305Sstevel } else if (env_sensor.id.name[0] == '\0') {
20552305Sstevel /* request for first handle */
20562305Sstevel if (section->num_entries == 0)
20572305Sstevel env_sensor.next_id.name[0] = '\0';
20582305Sstevel else
20592305Sstevel env_sensor.next_id =
20602305Sstevel section->entry[0].handle_name;
20612305Sstevel sensor_status = ENVMON_NOT_PRESENT;
20622305Sstevel } else {
20632305Sstevel /* ensure name is properly terminated */
20642305Sstevel env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
20652305Sstevel if (get_sensor_by_name(section, env_sensor.id.name,
20662305Sstevel &index) != 0) {
20672305Sstevel env_sensor.next_id.name[0] = '\0';
20682305Sstevel sensor_status = ENVMON_NOT_PRESENT;
20692305Sstevel } else if (index + 1 < section->num_entries)
20702305Sstevel env_sensor.next_id =
20712305Sstevel section->entry[index + 1].handle_name;
20722305Sstevel else
20732305Sstevel env_sensor.next_id.name[0] = '\0';
20742305Sstevel }
20752305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
20762305Sstevel /*
20772305Sstevel * user correctly identified a sensor, note its
20782305Sstevel * handle value and request the sensor value
20792305Sstevel */
20802305Sstevel rmc_volts.handle = section->entry[index].handle;
20812305Sstevel }
20822305Sstevel RELEASE_CACHE
20832305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
20842305Sstevel rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R,
20852305Sstevel sizeof (rmc_volts_r), (intptr_t)&rmc_volts,
20862305Sstevel (intptr_t)&rmc_volts_r) != 0)) {
20872305Sstevel sensor_status = ENVMON_INACCESSIBLE;
20882305Sstevel }
20892305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) &&
20902305Sstevel (rmc_volts_r.volt_status[0].sensor_status ==
20912305Sstevel DP_SENSOR_NOT_PRESENT)) {
20922305Sstevel sensor_status = ENVMON_NOT_PRESENT;
20932305Sstevel }
20942305Sstevel if ((env_sensor.sensor_status = sensor_status) ==
20952305Sstevel ENVMON_SENSOR_OK) {
20962305Sstevel /*
20972305Sstevel * copy results into buffer for user
20982305Sstevel */
20992305Sstevel if (rmc_volts_r.volt_status[0].sensor_status !=
21002305Sstevel DP_SENSOR_DATA_AVAILABLE)
21012305Sstevel env_sensor.sensor_status = ENVMON_INACCESSIBLE;
21022305Sstevel env_sensor.value =
21032305Sstevel rmc_volts_r.volt_status[0].reading;
21042305Sstevel env_sensor.lowthresholds.warning =
21052305Sstevel rmc_volts_r.volt_status[0].low_warning;
21062305Sstevel env_sensor.lowthresholds.shutdown =
21072305Sstevel rmc_volts_r.volt_status[0].low_soft_shutdown;
21082305Sstevel env_sensor.lowthresholds.poweroff =
21092305Sstevel rmc_volts_r.volt_status[0].low_hard_shutdown;
21102305Sstevel env_sensor.highthresholds.warning =
21112305Sstevel rmc_volts_r.volt_status[0].high_warning;
21122305Sstevel env_sensor.highthresholds.shutdown =
21132305Sstevel rmc_volts_r.volt_status[0].high_soft_shutdown;
21142305Sstevel env_sensor.highthresholds.poweroff =
21152305Sstevel rmc_volts_r.volt_status[0].high_hard_shutdown;
21162305Sstevel }
21172305Sstevel if (env_sensor.sensor_status != ENVMON_SENSOR_OK ||
21182305Sstevel rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
21192305Sstevel set_val_unav(&env_sensor);
21202305Sstevel
21212305Sstevel if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
21222305Sstevel sizeof (envmon_sensor_t), mode) != 0)
21232305Sstevel return (EFAULT);
21242305Sstevel break;
21252305Sstevel
21262305Sstevel case ENVMONIOCVOLTIND:
21272305Sstevel return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
21282305Sstevel RMCLOMV_VOLT_IND));
21292305Sstevel
21302305Sstevel case ENVMONIOCTEMPIND:
21312305Sstevel return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
21322305Sstevel RMCLOMV_TEMP_IND));
21332305Sstevel
21342305Sstevel case ENVMONIOCFANIND:
21352305Sstevel return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
21362305Sstevel RMCLOMV_FAN_IND));
21372305Sstevel
21382305Sstevel case ENVMONIOCAMPSENSOR:
21392305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
21402305Sstevel sizeof (envmon_sensor_t), mode) != 0)
21412305Sstevel return (EFAULT);
21422305Sstevel
21432305Sstevel env_sensor.sensor_status = ENVMON_NOT_PRESENT;
21442305Sstevel env_sensor.next_id.name[0] = '\0';
21452305Sstevel
21462305Sstevel if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
21472305Sstevel sizeof (envmon_sensor_t), mode) != 0)
21482305Sstevel return (EFAULT);
21492305Sstevel break;
21502305Sstevel
21512305Sstevel case ENVMONIOCTEMPSENSOR:
21522305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
21532305Sstevel sizeof (envmon_sensor_t), mode) != 0)
21542305Sstevel return (EFAULT);
21552305Sstevel
21562305Sstevel /* see if we've got temperature handles cached */
21572305Sstevel LOCK_CACHE
21582305Sstevel sensor_status = ENVMON_SENSOR_OK;
21592305Sstevel
21602305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
21612305Sstevel ((section = rmclomv_find_section(rmclomv_cache,
21622305Sstevel RMCLOMV_TEMP_SENS)) == NULL)) {
21632305Sstevel env_sensor.next_id.name[0] = '\0';
21642305Sstevel sensor_status = ENVMON_NOT_PRESENT;
21652305Sstevel } else if (env_sensor.id.name[0] == '\0') {
21662305Sstevel /* request for first handle */
21672305Sstevel if (section->num_entries == 0)
21682305Sstevel env_sensor.next_id.name[0] = '\0';
21692305Sstevel else
21702305Sstevel env_sensor.next_id =
21712305Sstevel section->entry[0].handle_name;
21722305Sstevel sensor_status = ENVMON_NOT_PRESENT;
21732305Sstevel } else {
21742305Sstevel /* ensure name is properly terminated */
21752305Sstevel env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
21762305Sstevel if (get_sensor_by_name(section, env_sensor.id.name,
21772305Sstevel &index) != 0) {
21782305Sstevel env_sensor.next_id.name[0] = '\0';
21792305Sstevel sensor_status = ENVMON_NOT_PRESENT;
21802305Sstevel } else if (index + 1 < section->num_entries)
21812305Sstevel env_sensor.next_id =
21822305Sstevel section->entry[index + 1].handle_name;
21832305Sstevel else
21842305Sstevel env_sensor.next_id.name[0] = '\0';
21852305Sstevel }
21862305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
21872305Sstevel /*
21882305Sstevel * user correctly identified a sensor, note its
21892305Sstevel * handle value and request the sensor value
21902305Sstevel */
21912305Sstevel rmc_temp.handle = section->entry[index].handle;
21922305Sstevel }
21932305Sstevel RELEASE_CACHE
21942305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
21952305Sstevel rmclomv_do_cmd(DP_GET_TEMPERATURES, DP_GET_TEMPERATURES_R,
21962305Sstevel sizeof (rmc_temp_r), (intptr_t)&rmc_temp,
21972305Sstevel (intptr_t)&rmc_temp_r) != 0)) {
21982305Sstevel sensor_status = ENVMON_INACCESSIBLE;
21992305Sstevel }
22002305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) &&
22012305Sstevel (rmc_temp_r.temp_status[0].sensor_status ==
22022305Sstevel DP_SENSOR_NOT_PRESENT)) {
22032305Sstevel sensor_status = ENVMON_NOT_PRESENT;
22042305Sstevel }
22052305Sstevel if ((env_sensor.sensor_status = sensor_status) ==
22062305Sstevel ENVMON_SENSOR_OK) {
22072305Sstevel /*
22082305Sstevel * copy results into buffer for user
22092305Sstevel */
22102305Sstevel if (rmc_temp_r.temp_status[0].sensor_status !=
22112305Sstevel DP_SENSOR_DATA_AVAILABLE)
22122305Sstevel env_sensor.sensor_status = ENVMON_INACCESSIBLE;
22132305Sstevel env_sensor.value =
22142305Sstevel rmc_temp_r.temp_status[0].value;
22152305Sstevel env_sensor.lowthresholds.warning =
22162305Sstevel rmc_temp_r.temp_status[0].low_warning;
22172305Sstevel env_sensor.lowthresholds.shutdown =
22182305Sstevel rmc_temp_r.temp_status[0].low_soft_shutdown;
22192305Sstevel env_sensor.lowthresholds.poweroff =
22202305Sstevel rmc_temp_r.temp_status[0].low_hard_shutdown;
22212305Sstevel env_sensor.highthresholds.warning =
22222305Sstevel rmc_temp_r.temp_status[0].high_warning;
22232305Sstevel env_sensor.highthresholds.shutdown =
22242305Sstevel rmc_temp_r.temp_status[0].high_soft_shutdown;
22252305Sstevel env_sensor.highthresholds.poweroff =
22262305Sstevel rmc_temp_r.temp_status[0].high_hard_shutdown;
22272305Sstevel }
22282305Sstevel if (env_sensor.sensor_status != ENVMON_SENSOR_OK ||
22292305Sstevel rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
22302305Sstevel set_val_unav(&env_sensor);
22312305Sstevel
22322305Sstevel if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
22332305Sstevel sizeof (envmon_sensor_t), mode) != 0)
22342305Sstevel return (EFAULT);
22352305Sstevel break;
22362305Sstevel
22372305Sstevel
22382305Sstevel case ENVMONIOCFAN:
22392305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_fan,
22402305Sstevel sizeof (envmon_fan_t), mode) != 0)
22412305Sstevel return (EFAULT);
22422305Sstevel
22432305Sstevel /* see if we've got fan handles cached */
22442305Sstevel LOCK_CACHE
22452305Sstevel sensor_status = ENVMON_SENSOR_OK;
22462305Sstevel
22472305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
22482305Sstevel ((section = rmclomv_find_section(rmclomv_cache,
22492305Sstevel RMCLOMV_FAN_SENS)) == NULL)) {
22502305Sstevel env_fan.next_id.name[0] = '\0';
22512305Sstevel sensor_status = ENVMON_NOT_PRESENT;
22522305Sstevel } else if (env_fan.id.name[0] == '\0') {
22532305Sstevel /* request for first handle */
22542305Sstevel if (section->num_entries == 0)
22552305Sstevel env_fan.next_id.name[0] = '\0';
22562305Sstevel else
22572305Sstevel env_fan.next_id =
22582305Sstevel section->entry[0].handle_name;
22592305Sstevel sensor_status = ENVMON_NOT_PRESENT;
22602305Sstevel } else {
22612305Sstevel /* ensure name is properly terminated */
22622305Sstevel env_fan.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
22632305Sstevel if (get_sensor_by_name(section, env_fan.id.name,
22642305Sstevel &index) != 0) {
22652305Sstevel env_fan.next_id.name[0] = '\0';
22662305Sstevel sensor_status = ENVMON_NOT_PRESENT;
22672305Sstevel } else if (index + 1 < section->num_entries)
22682305Sstevel env_fan.next_id =
22692305Sstevel section->entry[index + 1].handle_name;
22702305Sstevel else
22712305Sstevel env_fan.next_id.name[0] = '\0';
22722305Sstevel }
22732305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
22742305Sstevel /*
22752305Sstevel * user correctly identified a sensor, note its
22762305Sstevel * handle value and request the sensor value
22772305Sstevel */
22782305Sstevel rmc_fan.handle = section->entry[index].handle;
22792305Sstevel }
22802305Sstevel RELEASE_CACHE
22812305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
22822305Sstevel rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R,
22832305Sstevel sizeof (rmc_fan_r), (intptr_t)&rmc_fan,
22842305Sstevel (intptr_t)&rmc_fan_r) != 0)) {
22852305Sstevel sensor_status = ENVMON_INACCESSIBLE;
22862305Sstevel }
22872305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) &&
22882305Sstevel (rmc_fan_r.fan_status[0].sensor_status ==
22892305Sstevel DP_SENSOR_NOT_PRESENT)) {
22902305Sstevel sensor_status = ENVMON_NOT_PRESENT;
22912305Sstevel }
22922305Sstevel if ((env_fan.sensor_status = sensor_status) ==
22932305Sstevel ENVMON_SENSOR_OK) {
22942305Sstevel if ((rmc_fan_r.fan_status[0].flag &
22952305Sstevel DP_FAN_PRESENCE) == 0)
22962305Sstevel env_fan.sensor_status = ENVMON_NOT_PRESENT;
22972305Sstevel if (rmc_fan_r.fan_status[0].sensor_status !=
22982305Sstevel DP_SENSOR_DATA_AVAILABLE)
22992305Sstevel env_fan.sensor_status |= ENVMON_INACCESSIBLE;
23002305Sstevel if (env_fan.sensor_status == ENVMON_SENSOR_OK) {
23012305Sstevel /*
23022305Sstevel * copy results into buffer for user
23032305Sstevel */
23042305Sstevel env_fan.speed =
23052305Sstevel rmc_fan_r.fan_status[0].speed;
23062305Sstevel env_fan.lowthresholds.warning =
23072305Sstevel rmc_fan_r.fan_status[0].minspeed;
23082305Sstevel env_fan.lowthresholds.shutdown =
23092305Sstevel ENVMON_VAL_UNAVAILABLE;
23102305Sstevel env_fan.lowthresholds.poweroff =
23112305Sstevel ENVMON_VAL_UNAVAILABLE;
23122305Sstevel if ((rmc_fan_r.fan_status[0].flag &
23132305Sstevel DP_FAN_SPEED_VAL_UNIT) == 0)
23142305Sstevel bcopy(str_rpm, env_fan.units,
23152305Sstevel sizeof (str_rpm));
23162305Sstevel else
23172305Sstevel bcopy(str_percent, env_fan.units,
23182305Sstevel sizeof (str_percent));
23192305Sstevel }
23202305Sstevel }
23212305Sstevel if (env_fan.sensor_status != ENVMON_SENSOR_OK ||
23222305Sstevel rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
23232305Sstevel set_fan_unav(&env_fan);
23242305Sstevel
23252305Sstevel if (ddi_copyout((caddr_t)&env_fan, (caddr_t)arg,
23262305Sstevel sizeof (envmon_fan_t), mode) != 0)
23272305Sstevel return (EFAULT);
23282305Sstevel break;
23292305Sstevel
23302305Sstevel case ENVMONIOCAMPIND:
23312305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ind,
23322305Sstevel sizeof (envmon_indicator_t), mode) != 0)
23332305Sstevel return (EFAULT);
23342305Sstevel
23352305Sstevel /* see if we've got amp indicator handles cached */
23362305Sstevel LOCK_CACHE
23372305Sstevel sensor_status = ENVMON_SENSOR_OK;
23382305Sstevel
23392305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
23402305Sstevel ((section = rmclomv_find_section(rmclomv_cache,
23412305Sstevel RMCLOMV_AMP_IND)) == NULL)) {
23422305Sstevel RELEASE_CACHE
23432305Sstevel return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu,
23442305Sstevel &rmc_psu_r, RMCLOMV_AMP_IND));
23452305Sstevel } else if (env_ind.id.name[0] == '\0') {
23462305Sstevel /* request for first handle */
23472305Sstevel if (section->num_entries == 0) {
23482305Sstevel RELEASE_CACHE
23492305Sstevel return (do_psu_cmd(arg, mode, &env_ind,
23502305Sstevel &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND));
23512305Sstevel }
23522305Sstevel env_ind.next_id = section->entry[0].handle_name;
23532305Sstevel sensor_status = ENVMON_NOT_PRESENT;
23542305Sstevel } else {
23552305Sstevel /* ensure name is properly terminated */
23562305Sstevel env_ind.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
23572305Sstevel if (get_sensor_by_name(section, env_ind.id.name,
23582305Sstevel &index) != 0) {
23592305Sstevel RELEASE_CACHE
23602305Sstevel return (do_psu_cmd(arg, mode, &env_ind,
23612305Sstevel &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND));
23622305Sstevel }
23632305Sstevel if (index + 1 < section->num_entries) {
23642305Sstevel env_ind.next_id =
23652305Sstevel section->entry[index + 1].handle_name;
23662305Sstevel } else {
23672305Sstevel rmclomv_cache_section_t *sub_section =
23682305Sstevel rmclomv_find_section(rmclomv_subcache,
23692305Sstevel RMCLOMV_AMP_IND);
23702305Sstevel if ((sub_section == NULL) ||
23712305Sstevel (sub_section->num_entries == 0))
23722305Sstevel env_ind.next_id.name[0] = '\0';
23732305Sstevel else
23742305Sstevel env_ind.next_id =
23752305Sstevel sub_section->entry[0].handle_name;
23762305Sstevel }
23772305Sstevel }
23782305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
23792305Sstevel /*
23802305Sstevel * user correctly identified an indicator, note its
23812305Sstevel * handle value and request the indicator status
23822305Sstevel */
23832305Sstevel rmc_ampi.handle = section->entry[index].handle;
23842305Sstevel }
23852305Sstevel RELEASE_CACHE
23862305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
23872305Sstevel rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS, DP_GET_CIRCUIT_BRKS_R,
23882305Sstevel sizeof (rmc_ampi_r), (intptr_t)&rmc_ampi,
23892305Sstevel (intptr_t)&rmc_ampi_r) != 0)) {
23902305Sstevel sensor_status = ENVMON_INACCESSIBLE;
23912305Sstevel }
23922305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) &&
23932305Sstevel (rmc_ampi_r.circuit_brk_status[0].sensor_status ==
23942305Sstevel DP_SENSOR_NOT_PRESENT)) {
23952305Sstevel sensor_status = ENVMON_NOT_PRESENT;
23962305Sstevel }
23972305Sstevel if ((env_ind.sensor_status = sensor_status) ==
23982305Sstevel ENVMON_SENSOR_OK) {
23992305Sstevel /*
24002305Sstevel * copy results into buffer for user
24012305Sstevel */
24022305Sstevel if (rmc_ampi_r.circuit_brk_status[0].sensor_status !=
24032305Sstevel DP_SENSOR_DATA_AVAILABLE)
24042305Sstevel env_ind.sensor_status = ENVMON_INACCESSIBLE;
24052305Sstevel env_ind.condition =
24062305Sstevel rmc_ampi_r.circuit_brk_status[0].status;
24072305Sstevel }
24082305Sstevel
24092305Sstevel /*
24102305Sstevel * If rmclomv_rmc_error is set there is no way
24112305Sstevel * that we read information from RSC. Just copy
24122305Sstevel * out an inaccessible evironmental.
24132305Sstevel */
24142305Sstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
24155593Sjfrank env_ind.sensor_status = ENVMON_INACCESSIBLE;
24165593Sjfrank env_ind.condition = ENVMON_INACCESSIBLE;
24172305Sstevel }
24182305Sstevel
24192305Sstevel if (ddi_copyout((caddr_t)&env_ind, (caddr_t)arg,
24202305Sstevel sizeof (envmon_indicator_t), mode) != 0)
24212305Sstevel return (EFAULT);
24222305Sstevel break;
24232305Sstevel
24242305Sstevel case ENVMONIOCHPU:
24252305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_hpu,
24262305Sstevel sizeof (envmon_hpu_t), mode) != 0)
24272305Sstevel return (EFAULT);
24282305Sstevel
24292305Sstevel /* see if we've got hpu handles cached */
24302305Sstevel LOCK_CACHE
24312305Sstevel
24322305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
24332305Sstevel ((section = rmclomv_find_section(rmclomv_cache,
24342305Sstevel RMCLOMV_HPU_IND)) == NULL)) {
24352305Sstevel RELEASE_CACHE
24362305Sstevel return (EAGAIN);
24372305Sstevel }
24382305Sstevel
24392305Sstevel /*
24402305Sstevel * At this point the cache is locked and section points to
24412305Sstevel * the section relating to hpus.
24422305Sstevel */
24432305Sstevel sensor_status = ENVMON_SENSOR_OK;
24442305Sstevel if (env_hpu.id.name[0] == '\0') {
24452305Sstevel /* request for first handle */
24462305Sstevel if (section->num_entries == 0)
24472305Sstevel env_hpu.next_id.name[0] = '\0';
24482305Sstevel else
24492305Sstevel env_hpu.next_id =
24502305Sstevel section->entry[0].handle_name;
24512305Sstevel sensor_status = ENVMON_NOT_PRESENT;
24522305Sstevel } else {
24532305Sstevel /* ensure name is properly terminated */
24542305Sstevel env_hpu.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
24552305Sstevel if (get_sensor_by_name(section, env_hpu.id.name,
24562305Sstevel &index) != 0) {
24572305Sstevel env_hpu.next_id.name[0] = '\0';
24582305Sstevel sensor_status = ENVMON_NOT_PRESENT;
24592305Sstevel } else if (index + 1 < section->num_entries)
24602305Sstevel env_hpu.next_id =
24612305Sstevel section->entry[index + 1].handle_name;
24622305Sstevel else
24632305Sstevel env_hpu.next_id.name[0] = '\0';
24642305Sstevel }
24652305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
24662305Sstevel /*
24672305Sstevel * user correctly identified an hpu, note its
24682305Sstevel * handle value and request the hpu status
24692305Sstevel */
24702305Sstevel rmc_fru.handle = section->entry[index].handle;
24712305Sstevel special = section->entry[index].ind_mask;
24722305Sstevel }
24732305Sstevel RELEASE_CACHE
24742305Sstevel if ((env_hpu.sensor_status = sensor_status) ==
24752305Sstevel ENVMON_SENSOR_OK) {
24762305Sstevel env_hpu.fru_status = ENVMON_FRU_PRESENT;
24772305Sstevel
24782305Sstevel if (special != 0) {
24792305Sstevel /* this is the pseudo SC node */
24802305Sstevel mutex_enter(&rmclomv_state_lock);
24812305Sstevel switch (rmclomv_rmc_state) {
24822305Sstevel case RMCLOMV_RMCSTATE_OK:
24832305Sstevel break;
24842305Sstevel case RMCLOMV_RMCSTATE_FAILED:
24852305Sstevel env_hpu.fru_status = ENVMON_FRU_FAULT;
24862305Sstevel break;
24872305Sstevel case RMCLOMV_RMCSTATE_DOWNLOAD:
24882305Sstevel env_hpu.fru_status =
24892305Sstevel ENVMON_FRU_DOWNLOAD;
24902305Sstevel break;
24912305Sstevel default:
24922305Sstevel env_hpu.sensor_status =
24932305Sstevel ENVMON_INACCESSIBLE;
24942305Sstevel break;
24952305Sstevel }
24962305Sstevel mutex_exit(&rmclomv_state_lock);
24972305Sstevel } else if (rmclomv_rmc_error ||
24982305Sstevel rmclomv_do_cmd(DP_GET_FRU_STATUS,
24992305Sstevel DP_GET_FRU_STATUS_R, sizeof (rmc_fru_r),
25002305Sstevel (intptr_t)&rmc_fru, (intptr_t)&rmc_fru_r) != 0) {
25012305Sstevel env_hpu.sensor_status = ENVMON_INACCESSIBLE;
25022305Sstevel } else {
25032305Sstevel /*
25042305Sstevel * copy results into buffer for user
25052305Sstevel */
25062305Sstevel if (rmc_fru_r.fru_status[0].presence == 0) {
25072305Sstevel env_hpu.sensor_status =
25082305Sstevel ENVMON_NOT_PRESENT;
25092305Sstevel env_hpu.fru_status =
25102305Sstevel ENVMON_FRU_NOT_PRESENT;
25112305Sstevel } else if (rmc_fru_r.fru_status[0].sensor_status
25122305Sstevel != DP_SENSOR_DATA_AVAILABLE) {
25132305Sstevel env_hpu.sensor_status =
25142305Sstevel ENVMON_INACCESSIBLE;
25152305Sstevel } else {
25162305Sstevel uint8_t status =
25172305Sstevel rmc_fru_r.fru_status[0].status;
25182305Sstevel if (status == DP_FRU_STATUS_UNKNOWN) {
25192305Sstevel env_hpu.sensor_status =
25202305Sstevel ENVMON_INACCESSIBLE;
25212305Sstevel } else if (status != DP_FRU_STATUS_OK) {
25222305Sstevel env_hpu.fru_status =
25232305Sstevel ENVMON_FRU_FAULT;
25242305Sstevel }
25252305Sstevel }
25262305Sstevel }
25272305Sstevel }
25282305Sstevel
25292305Sstevel /*
25302305Sstevel * If rmclomv_rmc_error is set there is no way
25312305Sstevel * that we read information from RSC. Just copy
25322305Sstevel * out an inaccessible environmental.
25332305Sstevel */
25342305Sstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
25355593Sjfrank env_hpu.sensor_status = ENVMON_INACCESSIBLE;
25365593Sjfrank env_hpu.fru_status = ENVMON_INACCESSIBLE;
25372305Sstevel }
25382305Sstevel
25392305Sstevel if (ddi_copyout((caddr_t)&env_hpu, (caddr_t)arg,
25402305Sstevel sizeof (envmon_hpu_t), mode) != 0)
25412305Sstevel return (EFAULT);
25422305Sstevel break;
25432305Sstevel
25442305Sstevel case ENVMONIOCGETLED:
25452305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledinfo,
25462305Sstevel sizeof (envmon_led_info_t), mode) != 0)
25472305Sstevel return (EFAULT);
25482305Sstevel
25492305Sstevel /* see if we've got LED handles cached */
25502305Sstevel LOCK_CACHE
25512305Sstevel sensor_status = ENVMON_SENSOR_OK;
25522305Sstevel
25532305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
25542305Sstevel ((section = rmclomv_find_section(rmclomv_cache,
25552305Sstevel RMCLOMV_LED_IND)) == NULL)) {
25562305Sstevel env_ledinfo.next_id.name[0] = '\0';
25572305Sstevel sensor_status = ENVMON_NOT_PRESENT;
25582305Sstevel } else if (env_ledinfo.id.name[0] == '\0') {
25592305Sstevel /* request for first handle */
25602305Sstevel if (section->num_entries == 0)
25612305Sstevel env_ledinfo.next_id.name[0] = '\0';
25622305Sstevel else
25632305Sstevel env_ledinfo.next_id =
25642305Sstevel section->entry[0].handle_name;
25652305Sstevel sensor_status = ENVMON_NOT_PRESENT;
25662305Sstevel } else {
25672305Sstevel /* ensure name is properly terminated */
25682305Sstevel env_ledinfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
25692305Sstevel if (get_sensor_by_name(section, env_ledinfo.id.name,
25702305Sstevel &index) != 0) {
25712305Sstevel env_ledinfo.next_id.name[0] = '\0';
25722305Sstevel sensor_status = ENVMON_NOT_PRESENT;
25732305Sstevel } else if (index + 1 < section->num_entries)
25742305Sstevel env_ledinfo.next_id =
25752305Sstevel section->entry[index + 1].handle_name;
25762305Sstevel else
25772305Sstevel env_ledinfo.next_id.name[0] = '\0';
25782305Sstevel }
25792305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
25802305Sstevel /*
25812305Sstevel * user correctly identified a LED, note its
25822305Sstevel * handle value and request the LED status
25832305Sstevel */
25842305Sstevel rmc_led.handle = section->entry[index].handle;
25852305Sstevel }
25862305Sstevel RELEASE_CACHE
25872305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
25882305Sstevel rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R,
25892305Sstevel sizeof (rmc_led_r), (intptr_t)&rmc_led,
25902305Sstevel (intptr_t)&rmc_led_r) != 0)) {
25912305Sstevel sensor_status = ENVMON_INACCESSIBLE;
25922305Sstevel }
25932305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) &&
25942305Sstevel (rmc_led_r.led_state[0].sensor_status ==
25952305Sstevel DP_SENSOR_NOT_PRESENT)) {
25962305Sstevel sensor_status = ENVMON_NOT_PRESENT;
25972305Sstevel }
25982305Sstevel if ((env_ledinfo.sensor_status = sensor_status) ==
25992305Sstevel ENVMON_SENSOR_OK) {
26002305Sstevel /*
26012305Sstevel * copy results into buffer for user
26022305Sstevel * start with some defaults then override
26032305Sstevel */
26042305Sstevel env_ledinfo.sensor_status = ENVMON_SENSOR_OK;
26052305Sstevel env_ledinfo.led_state = ENVMON_LED_OFF;
26062305Sstevel env_ledinfo.led_color = ENVMON_LED_CLR_NONE;
26072305Sstevel
26082305Sstevel if (rmc_led_r.led_state[0].sensor_status !=
26092305Sstevel DP_SENSOR_DATA_AVAILABLE)
26102305Sstevel env_ledinfo.sensor_status = ENVMON_INACCESSIBLE;
26112305Sstevel else {
26122305Sstevel dp_led_state_t ledState;
26132305Sstevel ledState = rmc_led_r.led_state[0];
26142305Sstevel env_ledinfo.led_color = (int8_t)ledState.colour;
26152305Sstevel
26162305Sstevel switch (ledState.state) {
26172305Sstevel case (rsci8)DP_LED_OFF:
26182305Sstevel break;
26192305Sstevel case (rsci8)DP_LED_ON:
26202305Sstevel env_ledinfo.led_state = ENVMON_LED_ON;
26212305Sstevel break;
26222305Sstevel case (rsci8)DP_LED_BLINKING:
26232305Sstevel env_ledinfo.led_state =
26242305Sstevel ENVMON_LED_BLINKING;
26252305Sstevel break;
26262305Sstevel case (rsci8)DP_LED_FLASHING:
26272305Sstevel env_ledinfo.led_state =
26282305Sstevel ENVMON_LED_FLASHING;
26292305Sstevel break;
26302305Sstevel default:
26312305Sstevel break;
26322305Sstevel }
26332305Sstevel }
26342305Sstevel }
26352305Sstevel
26362305Sstevel /*
26372305Sstevel * If rmclomv_rmc_error is set there is no way
26382305Sstevel * that we read information from RSC. Just copy
26392305Sstevel * out an inaccessible environmental.
26402305Sstevel */
26412305Sstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
26425593Sjfrank env_ledinfo.sensor_status = ENVMON_INACCESSIBLE;
26435593Sjfrank env_ledinfo.led_state = ENVMON_INACCESSIBLE;
26442305Sstevel }
26452305Sstevel
26462305Sstevel if (ddi_copyout((caddr_t)&env_ledinfo, (caddr_t)arg,
26472305Sstevel sizeof (envmon_led_info_t), mode) != 0)
26482305Sstevel return (EFAULT);
26492305Sstevel break;
26502305Sstevel
26512305Sstevel case ENVMONIOCSETLED:
26522305Sstevel if ((mode & FWRITE) == 0)
26532305Sstevel return (EACCES);
26542305Sstevel if (drv_priv(cred_p) != 0)
26552305Sstevel return (EPERM);
26562305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledctl,
26572305Sstevel sizeof (envmon_led_ctl_t), mode) != 0)
26582305Sstevel return (EFAULT);
26592305Sstevel if (env_ledctl.led_state < RMCLOMV_MIN_LED_STATE ||
26602305Sstevel env_ledctl.led_state > RMCLOMV_MAX_LED_STATE)
26612305Sstevel return (EINVAL);
26622305Sstevel /*
26632305Sstevel * Ensure name is properly terminated.
26642305Sstevel */
26652305Sstevel env_ledctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
26662305Sstevel
26672305Sstevel /* see if we've got LED handles cached */
26682305Sstevel LOCK_CACHE
26692305Sstevel
26702305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
26712305Sstevel ((section = rmclomv_find_section(rmclomv_cache,
26722305Sstevel RMCLOMV_LED_IND)) == NULL) ||
26732305Sstevel (get_sensor_by_name(section, env_ledctl.id.name,
26742305Sstevel &index) != 0)) {
26752305Sstevel RELEASE_CACHE
26762305Sstevel return (EINVAL); /* no such LED */
26772305Sstevel }
26782305Sstevel /*
26792305Sstevel * user correctly identified a LED, note its handle value
26802305Sstevel */
26812305Sstevel rmc_setled.handle = section->entry[index].handle;
26822305Sstevel RELEASE_CACHE
26832305Sstevel switch (env_ledctl.led_state) {
26842305Sstevel case ENVMON_LED_ON:
26852305Sstevel rmc_setled.state = DP_LED_ON;
26862305Sstevel break;
26872305Sstevel case ENVMON_LED_BLINKING:
26882305Sstevel rmc_setled.state = DP_LED_BLINKING;
26892305Sstevel break;
26902305Sstevel case ENVMON_LED_FLASHING:
26912305Sstevel rmc_setled.state = DP_LED_FLASHING;
26922305Sstevel break;
26932305Sstevel default:
26942305Sstevel rmc_setled.state = DP_LED_OFF;
26952305Sstevel break;
26962305Sstevel }
26972305Sstevel retval = rmclomv_do_cmd(DP_SET_LED_STATE, DP_SET_LED_STATE_R,
26982305Sstevel sizeof (rmc_setled_r), (intptr_t)&rmc_setled,
26992305Sstevel (intptr_t)&rmc_setled_r);
27002305Sstevel
27012305Sstevel if (retval != 0) {
27022305Sstevel break;
27032305Sstevel }
27042305Sstevel
27052305Sstevel if (rmc_setled_r.status != 0) {
27062305Sstevel cmn_err(CE_WARN, "ENVMONIOCSETLED: \"%s\" status: 0x%x",
27072305Sstevel env_ledctl.id.name, rmc_setled_r.status);
27082305Sstevel return (EIO);
27092305Sstevel }
27102305Sstevel break;
27112305Sstevel
27122305Sstevel case ENVMONIOCGETKEYSW:
27132305Sstevel {
27142305Sstevel enum rmc_keyswitch_pos rmc_pos = real_key_position;
27152305Sstevel envmon_keysw_pos_t envmon_pos;
27162305Sstevel
27172305Sstevel /*
27182305Sstevel * Yes, I know this is ugly, but the V210 has no keyswitch,
27192305Sstevel * even though the ALOM returns a value for it
27202305Sstevel */
27212305Sstevel if (strcmp(platform, "SUNW,Sun-Fire-V210") == 0) {
27222305Sstevel return (ENOTSUP);
27232305Sstevel }
27242305Sstevel
27252305Sstevel switch (rmc_pos) {
27262305Sstevel
27272305Sstevel case RMC_KEYSWITCH_POS_NORMAL:
27282305Sstevel envmon_pos = ENVMON_KEYSW_POS_NORMAL;
27292305Sstevel break;
27302305Sstevel case RMC_KEYSWITCH_POS_DIAG:
27312305Sstevel envmon_pos = ENVMON_KEYSW_POS_DIAG;
27322305Sstevel break;
27332305Sstevel case RMC_KEYSWITCH_POS_LOCKED:
27342305Sstevel envmon_pos = ENVMON_KEYSW_POS_LOCKED;
27352305Sstevel break;
27362305Sstevel case RMC_KEYSWITCH_POS_OFF:
27372305Sstevel envmon_pos = ENVMON_KEYSW_POS_OFF;
27382305Sstevel break;
27392305Sstevel default:
27402305Sstevel envmon_pos = ENVMON_KEYSW_POS_UNKNOWN;
27412305Sstevel break;
27422305Sstevel }
27432305Sstevel
27442305Sstevel if (ddi_copyout((caddr_t)&envmon_pos, (caddr_t)arg,
27452305Sstevel sizeof (envmon_pos), mode) != 0)
27462305Sstevel return (EFAULT);
27472305Sstevel break;
27482305Sstevel }
27492305Sstevel
27502305Sstevel case ENVMONIOCGETALARM:
27512305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarminfo,
27522305Sstevel sizeof (envmon_alarm_info_t), mode) != 0)
27532305Sstevel return (EFAULT);
27542305Sstevel
27552305Sstevel /* see if we've got ALARM handles cached */
27562305Sstevel LOCK_CACHE
27572305Sstevel sensor_status = ENVMON_SENSOR_OK;
27582305Sstevel
27592305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
27602305Sstevel ((section = rmclomv_find_section(rmclomv_cache,
27612305Sstevel RMCLOMV_ALARM_IND)) == NULL)) {
27622305Sstevel env_alarminfo.next_id.name[0] = '\0';
27632305Sstevel sensor_status = ENVMON_NOT_PRESENT;
27642305Sstevel } else if (env_alarminfo.id.name[0] == '\0') {
27652305Sstevel /* request for first handle */
27662305Sstevel if (section->num_entries == 0)
27672305Sstevel env_alarminfo.next_id.name[0] = '\0';
27682305Sstevel else
27692305Sstevel env_alarminfo.next_id =
27702305Sstevel section->entry[0].handle_name;
27712305Sstevel sensor_status = ENVMON_NOT_PRESENT;
27722305Sstevel } else {
27732305Sstevel /* ensure name is properly terminated */
27742305Sstevel env_alarminfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
27752305Sstevel if (get_sensor_by_name(section, env_alarminfo.id.name,
27762305Sstevel &index) != 0) {
27772305Sstevel env_alarminfo.next_id.name[0] = '\0';
27782305Sstevel sensor_status = ENVMON_NOT_PRESENT;
27792305Sstevel } else if (index + 1 < section->num_entries)
27802305Sstevel env_alarminfo.next_id =
27812305Sstevel section->entry[index + 1].handle_name;
27822305Sstevel else
27832305Sstevel env_alarminfo.next_id.name[0] = '\0';
27842305Sstevel }
27852305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
27862305Sstevel /*
27872305Sstevel * user correctly identified a ALARM, note its
27882305Sstevel * handle value and request the ALARM status
27892305Sstevel */
27902305Sstevel rmc_alarm.handle = section->entry[index].handle;
27912305Sstevel }
27922305Sstevel RELEASE_CACHE
27932305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) &&
27945593Sjfrank (rmclomv_rmc_error ||
27952305Sstevel rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R,
27962305Sstevel sizeof (rmc_alarm_r), (intptr_t)&rmc_alarm,
27972305Sstevel (intptr_t)&rmc_alarm_r) != 0)) {
27982305Sstevel sensor_status = ENVMON_INACCESSIBLE;
27992305Sstevel }
28002305Sstevel if ((env_alarminfo.sensor_status = sensor_status) ==
28012305Sstevel ENVMON_SENSOR_OK) {
28022305Sstevel /*
28032305Sstevel * copy results into buffer for user
28042305Sstevel * start with some defaults then override
28052305Sstevel */
28062305Sstevel env_alarminfo.sensor_status = ENVMON_SENSOR_OK;
28072305Sstevel env_alarminfo.alarm_state = ENVMON_ALARM_OFF;
28082305Sstevel
28092305Sstevel if (rmc_alarm_r.alarm_state[0].sensor_status !=
28102305Sstevel DP_SENSOR_DATA_AVAILABLE)
28112305Sstevel env_alarminfo.sensor_status =
28125593Sjfrank ENVMON_INACCESSIBLE;
28132305Sstevel else {
28142305Sstevel dp_alarm_state_t alarmState;
28152305Sstevel alarmState = rmc_alarm_r.alarm_state[0];
28162305Sstevel
28172305Sstevel switch (alarmState.state) {
28182305Sstevel case DP_ALARM_OFF:
28192305Sstevel break;
28202305Sstevel case DP_ALARM_ON:
28212305Sstevel env_alarminfo.alarm_state =
28225593Sjfrank ENVMON_ALARM_ON;
28232305Sstevel break;
28242305Sstevel default:
28252305Sstevel break;
28262305Sstevel }
28272305Sstevel }
28282305Sstevel }
28292305Sstevel
28302305Sstevel /*
28312305Sstevel * If rmclomv_rmc_error is set there is no way
28322305Sstevel * that we read information from RSC. Just copy
28332305Sstevel * out an inaccessible environmental.
28342305Sstevel */
28352305Sstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
28365593Sjfrank env_alarminfo.sensor_status = ENVMON_INACCESSIBLE;
28375593Sjfrank env_alarminfo.alarm_state = ENVMON_INACCESSIBLE;
28382305Sstevel }
28392305Sstevel
28402305Sstevel if (ddi_copyout((caddr_t)&env_alarminfo, (caddr_t)arg,
28412305Sstevel sizeof (envmon_alarm_info_t), mode) != 0)
28422305Sstevel return (EFAULT);
28432305Sstevel break;
28442305Sstevel
28452305Sstevel case ENVMONIOCSETALARM:
28462305Sstevel if ((mode & FWRITE) == 0)
28472305Sstevel return (EACCES);
28482305Sstevel if (drv_priv(cred_p) != 0)
28492305Sstevel return (EPERM);
28502305Sstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarmctl,
28512305Sstevel sizeof (envmon_alarm_ctl_t), mode) != 0)
28522305Sstevel return (EFAULT);
28532305Sstevel if (env_alarmctl.alarm_state < RMCLOMV_MIN_ALARM_STATE ||
28542305Sstevel env_alarmctl.alarm_state > RMCLOMV_MAX_ALARM_STATE)
28552305Sstevel return (EINVAL);
28562305Sstevel /*
28572305Sstevel * Ensure name is properly terminated.
28582305Sstevel */
28592305Sstevel env_alarmctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
28602305Sstevel
28612305Sstevel /* see if we've got ALARM handles cached */
28622305Sstevel LOCK_CACHE
28632305Sstevel
28642305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
28652305Sstevel ((section = rmclomv_find_section(rmclomv_cache,
28662305Sstevel RMCLOMV_ALARM_IND)) == NULL) ||
28672305Sstevel (get_sensor_by_name(section, env_alarmctl.id.name,
28682305Sstevel &index) != 0)) {
28692305Sstevel RELEASE_CACHE
28702305Sstevel return (EINVAL); /* no such ALARM */
28712305Sstevel }
28722305Sstevel /*
28732305Sstevel * user correctly identified a ALARM, note its handle value
28742305Sstevel */
28752305Sstevel rmc_setalarm.handle = section->entry[index].handle;
28762305Sstevel RELEASE_CACHE
28772305Sstevel rmc_setalarm.state = (rsci8)env_alarmctl.alarm_state;
28782305Sstevel retval = rmclomv_do_cmd(DP_SET_ALARM_STATE,
28795593Sjfrank DP_SET_ALARM_STATE_R,
28805593Sjfrank sizeof (rmc_setalarm_r),
28815593Sjfrank (intptr_t)&rmc_setalarm,
28825593Sjfrank (intptr_t)&rmc_setalarm_r);
28832305Sstevel
28842305Sstevel if (retval != 0) {
28852305Sstevel break;
28862305Sstevel }
28872305Sstevel
28882305Sstevel if (rmc_setalarm_r.status != 0) {
28892305Sstevel cmn_err(CE_WARN, "ENVMONIOCSETALARM: \"%s\" status: "
28905593Sjfrank "0x%x", env_alarmctl.id.name,
28915593Sjfrank rmc_setalarm_r.status);
28922305Sstevel return (EIO);
28932305Sstevel }
28942305Sstevel break;
28952305Sstevel
28962305Sstevel case ENVMONIOCCHASSISSERIALNUM:
28972305Sstevel retval = rmclomv_do_cmd(DP_GET_SDP_VERSION,
28982305Sstevel DP_GET_SDP_VERSION_R, sizeof (rmc_sdpver_r),
28992305Sstevel NULL, (intptr_t)&rmc_sdpver_r);
29002305Sstevel
29012305Sstevel if (retval != 0) {
29022305Sstevel cmn_err(CE_WARN, "DP_GET_SDP_VERSION failed, ret=%d\n",
29032305Sstevel retval);
29042305Sstevel break;
29052305Sstevel } else if (rmc_sdpver_r.version < SDP_RESPONDS_TO_ALL_CMDS) {
29062305Sstevel retval = ENOTSUP;
29072305Sstevel break;
29082305Sstevel }
29092305Sstevel retval = rmclomv_do_cmd(DP_GET_CHASSIS_SERIALNUM,
29102305Sstevel DP_GET_CHASSIS_SERIALNUM_R, sizeof (rmc_serialnum_r),
29112305Sstevel NULL, (intptr_t)&rmc_serialnum_r);
29122305Sstevel
29132305Sstevel if (retval != 0) {
29142305Sstevel break;
29152305Sstevel }
29162305Sstevel bcopy(rmc_serialnum_r.chassis_serial_number,
29172305Sstevel chassis.serial_number,
29182305Sstevel sizeof (rmc_serialnum_r.chassis_serial_number));
29192305Sstevel
29202305Sstevel if (ddi_copyout((caddr_t)&chassis, (caddr_t)arg,
29212305Sstevel sizeof (chassis), mode) != 0) {
29222305Sstevel return (EFAULT);
29232305Sstevel }
29242305Sstevel sensor_status = ENVMON_SENSOR_OK;
29252305Sstevel break;
29262305Sstevel
29272305Sstevel default:
29282305Sstevel retval = ENOTSUP;
29292305Sstevel break;
29302305Sstevel }
29312305Sstevel
29322305Sstevel return (retval);
29332305Sstevel }
29342305Sstevel
29352305Sstevel /* ARGSUSED */
29362305Sstevel static void
rmclomv_checkrmc(caddr_t arg)29372305Sstevel rmclomv_checkrmc(caddr_t arg)
29382305Sstevel {
29392305Sstevel callb_cpr_t cprinfo;
29402305Sstevel int err;
29412305Sstevel int retries;
29422305Sstevel int state;
29432305Sstevel dp_get_sysinfo_r_t sysinfo;
29442305Sstevel
29452305Sstevel CALLB_CPR_INIT(&cprinfo, &rmclomv_checkrmc_lock, callb_generic_cpr,
29462305Sstevel "rmclomv_checkrmc");
29472305Sstevel
29482305Sstevel mutex_enter(&rmclomv_checkrmc_lock);
29492305Sstevel for (;;) {
29502305Sstevel /*
29512305Sstevel * Initial entry to this for loop is made with
29522305Sstevel * rmclomv_checkrmc_sig set to RMCLOMV_PROCESS_NOW. So the
29532305Sstevel * following while loop drops through the first time. A
29542305Sstevel * timeout call is made just before polling the RMC. Its
29552305Sstevel * interrupt routine sustains this loop by injecting additional
29562305Sstevel * state changes and cv events.
29572305Sstevel */
29582305Sstevel /*
29592305Sstevel * Wait for someone to tell me to continue.
29602305Sstevel */
29612305Sstevel while (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_WAIT) {
29622305Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo);
29632305Sstevel cv_wait(&rmclomv_checkrmc_sig_cv,
29642305Sstevel &rmclomv_checkrmc_lock);
29652305Sstevel CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_checkrmc_lock);
29662305Sstevel }
29672305Sstevel
29682305Sstevel mutex_exit(&rmclomv_checkrmc_lock);
29692305Sstevel /*
29702305Sstevel * mustn't hold same lock as timeout called with
29712305Sstevel * when cancelling timer
29722305Sstevel */
29732305Sstevel if (timer_id != 0) {
29742305Sstevel (void) untimeout(timer_id);
29752305Sstevel timer_id = 0;
29762305Sstevel }
29772305Sstevel mutex_enter(&rmclomv_checkrmc_lock);
29782305Sstevel
29792305Sstevel /* RMCLOMV_CHECKRMC_EXITNOW implies signal by _detach(). */
29802305Sstevel if (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_EXITNOW) {
29812305Sstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
29822305Sstevel
29832305Sstevel /* rmclomv_checkrmc_lock is held at this point! */
29842305Sstevel CALLB_CPR_EXIT(&cprinfo);
29852305Sstevel
29862305Sstevel thread_exit();
29872305Sstevel /* NOTREACHED */
29882305Sstevel }
29892305Sstevel
29902305Sstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
29912305Sstevel
29922305Sstevel /*
29932305Sstevel * If the RMC is not responding, rmclomv_do_cmd() takes a
29942305Sstevel * long time and eventually times out. We conclude that the
29952305Sstevel * RMC is broken if it doesn't respond to a number of polls
29962305Sstevel * made 60 secs apart. So that the rmclomv_do_cmd() time-out
29972305Sstevel * period isn't added to our 60 second timer, make the
29982305Sstevel * timeout() call before calling rmclomv_do_cmd().
29992305Sstevel */
30002305Sstevel if (timer_id == 0) {
30012305Sstevel timer_id = timeout(rmclomv_checkrmc_wakeup, NULL,
30022305Sstevel 60 * drv_usectohz(1000000));
30032305Sstevel }
30042305Sstevel
30052305Sstevel mutex_exit(&rmclomv_checkrmc_lock);
30062305Sstevel
30072305Sstevel err = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R,
30082305Sstevel sizeof (sysinfo), NULL, (intptr_t)&sysinfo);
30092305Sstevel if (err == 0) {
30102305Sstevel mutex_enter(&rmclomv_state_lock);
30112305Sstevel state = rmclomv_rmc_state;
30122305Sstevel /* successful poll, reset fail count */
30132305Sstevel rmclomv_rmcfailcount = 0;
30142305Sstevel mutex_exit(&rmclomv_state_lock);
30152305Sstevel
30162305Sstevel if (state != RMCLOMV_RMCSTATE_OK) {
30172305Sstevel rmclomv_refresh_wakeup();
30182305Sstevel }
30192305Sstevel }
30202305Sstevel if ((err != 0) &&
30212305Sstevel (rmclomv_rmc_error != RMCLOMV_RMCSTATE_DOWNLOAD)) {
30222305Sstevel /*
30232305Sstevel * Failed response or no response from RMC.
30242305Sstevel * Count the failure.
30252305Sstevel * If threshold exceeded, send a DR event.
30262305Sstevel */
30272305Sstevel mutex_enter(&rmclomv_state_lock);
30282305Sstevel retries = rmclomv_rmcfailcount;
30292305Sstevel state = rmclomv_rmc_state;
30302305Sstevel if (retries == RMCLOMV_RMCFAILTHRESHOLD)
30312305Sstevel rmclomv_rmc_state = RMCLOMV_RMCSTATE_FAILED;
30322305Sstevel if (rmclomv_rmcfailcount <= RMCLOMV_RMCFAILTHRESHOLD)
30332305Sstevel rmclomv_rmcfailcount++;
30342305Sstevel mutex_exit(&rmclomv_state_lock);
30352305Sstevel
30362305Sstevel if (retries == RMCLOMV_RMCFAILTHRESHOLD) {
30372305Sstevel cmn_err(CE_WARN, "SC %s responding",
30382305Sstevel state == RMCLOMV_RMCSTATE_OK ?
30392305Sstevel "has stopped" : "is not");
30402305Sstevel refresh_name_cache(B_TRUE);
30412305Sstevel rmclomv_dr_data_handler(str_sc, SE_NO_HINT);
30422305Sstevel }
30432305Sstevel }
30442305Sstevel
30452305Sstevel /*
30462305Sstevel * Re-enter the lock to prepare for another iteration.
30472305Sstevel * We must have the lock here to protect rmclomv_checkrmc_sig.
30482305Sstevel */
30492305Sstevel mutex_enter(&rmclomv_checkrmc_lock);
30502305Sstevel }
30512305Sstevel }
30522305Sstevel
30532305Sstevel static void
rmclomv_checkrmc_start(void)30542305Sstevel rmclomv_checkrmc_start(void)
30552305Sstevel {
30562305Sstevel kthread_t *tp;
30572305Sstevel
30582305Sstevel mutex_enter(&rmclomv_checkrmc_lock);
30592305Sstevel
30602305Sstevel if (rmclomv_checkrmc_tid == 0) {
30612305Sstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW;
30622305Sstevel
30632305Sstevel tp = thread_create(NULL, 0, rmclomv_checkrmc, NULL, 0,
30642305Sstevel &p0, TS_RUN, maxclsyspri);
30652305Sstevel rmclomv_checkrmc_tid = tp->t_did;
30662305Sstevel }
30672305Sstevel
30682305Sstevel mutex_exit(&rmclomv_checkrmc_lock);
30692305Sstevel }
30702305Sstevel
30712305Sstevel static void
rmclomv_checkrmc_destroy(void)30722305Sstevel rmclomv_checkrmc_destroy(void)
30732305Sstevel {
30742305Sstevel kt_did_t tid;
30752305Sstevel
30762305Sstevel mutex_enter(&rmclomv_checkrmc_lock);
30772305Sstevel tid = rmclomv_checkrmc_tid;
30782305Sstevel if (tid != 0) {
30792305Sstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_EXITNOW;
30802305Sstevel cv_signal(&rmclomv_checkrmc_sig_cv);
30812305Sstevel rmclomv_checkrmc_tid = 0;
30822305Sstevel }
30832305Sstevel mutex_exit(&rmclomv_checkrmc_lock);
30842305Sstevel
30852305Sstevel /*
30862305Sstevel * Wait for rmclomv_checkrmc() to finish
30872305Sstevel */
30882305Sstevel if (tid != 0)
30892305Sstevel thread_join(tid);
30902305Sstevel }
30912305Sstevel
30922305Sstevel /*ARGSUSED*/
30932305Sstevel static void
rmclomv_checkrmc_wakeup(void * arg)30942305Sstevel rmclomv_checkrmc_wakeup(void *arg)
30952305Sstevel {
30962305Sstevel mutex_enter(&rmclomv_checkrmc_lock);
30972305Sstevel
30982305Sstevel if (rmclomv_checkrmc_sig != RMCLOMV_CHECKRMC_EXITNOW)
30992305Sstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW;
31002305Sstevel cv_signal(&rmclomv_checkrmc_sig_cv);
31012305Sstevel
31022305Sstevel mutex_exit(&rmclomv_checkrmc_lock);
31032305Sstevel }
31042305Sstevel
31052305Sstevel /* ARGSUSED */
31062305Sstevel static void
rmclomv_refresh(caddr_t arg)31072305Sstevel rmclomv_refresh(caddr_t arg)
31082305Sstevel {
31092305Sstevel void (*plat_nodename_set_fun)(void);
31102305Sstevel sig_state_t *current_sgn_p;
31112305Sstevel callb_cpr_t cprinfo;
31122305Sstevel int state;
31135593Sjfrank int tmp_checkrmc_sig;
31142305Sstevel
31152305Sstevel CALLB_CPR_INIT(&cprinfo, &rmclomv_refresh_lock, callb_generic_cpr,
31162305Sstevel "rmclomv_refresh");
31172305Sstevel
31185593Sjfrank /*
31195593Sjfrank * Wait until the rmclomv_checkrmc() thread has had a chance to
31205593Sjfrank * run its main loop. This is done so that rmclomv_refresh will
31215593Sjfrank * only run its main loop once at start of day; otherwise, it may
31225593Sjfrank * run twice and generate warning messages when redundantly populating
31235593Sjfrank * its internal cache.
31245593Sjfrank */
31255593Sjfrank do {
31265593Sjfrank delay(drv_usectohz(DELAY_TIME));
31275593Sjfrank mutex_enter(&rmclomv_checkrmc_lock);
31285593Sjfrank tmp_checkrmc_sig = rmclomv_checkrmc_sig;
31295593Sjfrank mutex_exit(&rmclomv_checkrmc_lock);
31305593Sjfrank } while (tmp_checkrmc_sig != RMCLOMV_CHECKRMC_WAIT);
31315593Sjfrank
31322305Sstevel mutex_enter(&rmclomv_refresh_lock);
31332305Sstevel for (;;) {
31342305Sstevel
31352305Sstevel /*
31362305Sstevel * Wait for someone to tell me to continue.
31372305Sstevel */
31382305Sstevel while (rmclomv_refresh_sig == RMCLOMV_REFRESH_WAIT) {
31392305Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo);
31402305Sstevel cv_wait(&rmclomv_refresh_sig_cv, &rmclomv_refresh_lock);
31412305Sstevel CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_refresh_lock);
31422305Sstevel }
31432305Sstevel
31442305Sstevel /* RMCLOMV_REFRESH_EXITNOW implies signal by _detach(). */
31452305Sstevel if (rmclomv_refresh_sig == RMCLOMV_REFRESH_EXITNOW) {
31462305Sstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
31472305Sstevel
31482305Sstevel /* rmclomv_refresh_lock is held at this point! */
31492305Sstevel CALLB_CPR_EXIT(&cprinfo);
31502305Sstevel
31512305Sstevel thread_exit();
31522305Sstevel /* NOTREACHED */
31532305Sstevel }
31542305Sstevel
31552305Sstevel ASSERT(rmclomv_refresh_sig == RMCLOMV_REFRESH_PROCESSNOW);
31562305Sstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
31572305Sstevel
31582305Sstevel mutex_exit(&rmclomv_refresh_lock);
31592305Sstevel
31602305Sstevel refresh_name_cache(B_FALSE);
31612305Sstevel
31622305Sstevel /*
31632305Sstevel * We're not going to access rmclomv_sysinfo_data here,
31642305Sstevel * so there's no point in locking it before reading
31652305Sstevel * rmclomv_sysinfo_valid. Also this avoids holding two
31662305Sstevel * locks at once and the concommitant worry about deadlocks.
31672305Sstevel */
31682305Sstevel if (rmclomv_sysinfo_valid) {
31692305Sstevel /*
31702305Sstevel * We've just successfully read the RMC sysinfo
31712305Sstevel * so the RMC must be operational. Update its
31722305Sstevel * state and if it was previously not OK, refresh
31732305Sstevel * nodename, CPU signatures and watchdog settings.
31742305Sstevel */
31752305Sstevel mutex_enter(&rmclomv_state_lock);
31762305Sstevel rmclomv_rmcfailcount = 0;
31772305Sstevel state = rmclomv_rmc_state;
31782305Sstevel rmclomv_rmc_state = RMCLOMV_RMCSTATE_OK;
31792305Sstevel mutex_exit(&rmclomv_state_lock);
31802305Sstevel
31812305Sstevel if (state != RMCLOMV_RMCSTATE_OK) {
31822305Sstevel rmclomv_dr_data_handler(str_sc, SE_NO_HINT);
31832305Sstevel if (state == RMCLOMV_RMCSTATE_FAILED) {
31842305Sstevel cmn_err(CE_NOTE, "SC recovered");
31852305Sstevel }
31862305Sstevel }
31872305Sstevel
31882305Sstevel if (utsname.nodename[0] != 0) {
31892305Sstevel plat_nodename_set_fun =
31902305Sstevel (void (*)(void))modgetsymvalue(
31912305Sstevel "plat_nodename_set", 0);
31922305Sstevel if (plat_nodename_set_fun != NULL)
31932305Sstevel plat_nodename_set_fun();
31942305Sstevel }
31952305Sstevel
31962305Sstevel current_sgn_p = (sig_state_t *)modgetsymvalue(
31972305Sstevel "current_sgn", 0);
31982305Sstevel
31995593Sjfrank /*
32005593Sjfrank * Delay before calling CPU_SIGNATURE, to allow
32015593Sjfrank * any pending asynchronous communications (i.e.
32025593Sjfrank * plat_timesync()) to complete. This helps to
32035593Sjfrank * prevent the situation where the message associated
32045593Sjfrank * with the CPU_SIGNATURE state cannot be sent to the
32055593Sjfrank * system controller.
32065593Sjfrank */
32072305Sstevel if ((current_sgn_p != NULL) &&
32082305Sstevel (current_sgn_p->state_t.sig != 0)) {
32095593Sjfrank delay(drv_usectohz(CPU_SIGNATURE_DELAY_TIME));
32102305Sstevel CPU_SIGNATURE(current_sgn_p->state_t.sig,
32112305Sstevel current_sgn_p->state_t.state,
32122305Sstevel current_sgn_p->state_t.sub_state, -1);
32132305Sstevel
32142305Sstevel if (!(boothowto & RB_DEBUG)) {
32155593Sjfrank /*
32165593Sjfrank * Delay before calling
32175593Sjfrank * send_watchdog_msg, to allow
32185593Sjfrank * CPU_SIGNATURE() time to
32195593Sjfrank * complete; this increases the
32205593Sjfrank * chances of successfully sending
32215593Sjfrank * the watchdog message to the
32225593Sjfrank * system controller.
32235593Sjfrank */
32245593Sjfrank delay(drv_usectohz(
32255593Sjfrank CPU_SIGNATURE_DELAY_TIME));
32262305Sstevel send_watchdog_msg(last_watchdog_msg);
32272305Sstevel }
32282305Sstevel }
32292305Sstevel }
32302305Sstevel
32312305Sstevel /*
32322305Sstevel * update keyswitch value in case it changed while the
32332305Sstevel * RMC was out of action
32342305Sstevel */
32352305Sstevel LOCK_CACHE
32362305Sstevel if (rmclomv_sysinfo_valid) {
32372305Sstevel real_key_position = rmclomv_sysinfo_data.keyswitch;
32382305Sstevel if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) &&
32392305Sstevel (real_key_position <= RMC_KEYSWITCH_POS_OFF)) {
32402305Sstevel key_position = real_key_position;
32412305Sstevel } else {
32422305Sstevel /* treat unknown key position as locked */
32432305Sstevel key_position = RMC_KEYSWITCH_POS_LOCKED;
32442305Sstevel }
32452305Sstevel } else {
32462305Sstevel /* treat unreadable key position as locked */
32472305Sstevel key_position = RMC_KEYSWITCH_POS_LOCKED;
32482305Sstevel real_key_position = RMC_KEYSWITCH_POS_UNKNOWN;
32492305Sstevel }
32502305Sstevel RELEASE_CACHE
32512305Sstevel
32522305Sstevel /*
32532305Sstevel * Re-enter the lock to prepare for another iteration.
32542305Sstevel * We must have the lock here to protect rmclomv_refresh_sig.
32552305Sstevel */
32562305Sstevel mutex_enter(&rmclomv_refresh_lock);
32572305Sstevel }
32582305Sstevel }
32592305Sstevel
32602305Sstevel static void
rmclomv_refresh_start(void)32612305Sstevel rmclomv_refresh_start(void)
32622305Sstevel {
32632305Sstevel kthread_t *tp;
32642305Sstevel
32652305Sstevel mutex_enter(&rmclomv_refresh_lock);
32662305Sstevel
32672305Sstevel if (rmclomv_refresh_tid == 0) {
32682305Sstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW;
32692305Sstevel
32702305Sstevel tp = thread_create(NULL, 0, rmclomv_refresh, NULL, 0,
32712305Sstevel &p0, TS_RUN, maxclsyspri);
32722305Sstevel rmclomv_refresh_tid = tp->t_did;
32732305Sstevel }
32742305Sstevel
32752305Sstevel mutex_exit(&rmclomv_refresh_lock);
32762305Sstevel }
32772305Sstevel
32782305Sstevel static void
rmclomv_refresh_destroy(void)32792305Sstevel rmclomv_refresh_destroy(void)
32802305Sstevel {
32812305Sstevel kt_did_t tid;
32822305Sstevel
32832305Sstevel mutex_enter(&rmclomv_refresh_lock);
32842305Sstevel tid = rmclomv_refresh_tid;
32852305Sstevel if (tid != 0) {
32862305Sstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_EXITNOW;
32872305Sstevel cv_signal(&rmclomv_refresh_sig_cv);
32882305Sstevel rmclomv_refresh_tid = 0;
32892305Sstevel }
32902305Sstevel mutex_exit(&rmclomv_refresh_lock);
32912305Sstevel
32922305Sstevel /*
32932305Sstevel * Wait for rmclomv_refresh() to finish
32942305Sstevel */
32952305Sstevel if (tid != 0)
32962305Sstevel thread_join(tid);
32972305Sstevel }
32982305Sstevel
32992305Sstevel static void
rmclomv_refresh_wakeup(void)33002305Sstevel rmclomv_refresh_wakeup(void)
33012305Sstevel {
33022305Sstevel mutex_enter(&rmclomv_refresh_lock);
33032305Sstevel
33042305Sstevel if (rmclomv_refresh_sig != RMCLOMV_REFRESH_EXITNOW)
33052305Sstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW;
33062305Sstevel cv_signal(&rmclomv_refresh_sig_cv);
33072305Sstevel
33082305Sstevel mutex_exit(&rmclomv_refresh_lock);
33092305Sstevel }
33102305Sstevel
33112305Sstevel static void
send_watchdog_msg(int msg)33122305Sstevel send_watchdog_msg(int msg)
33132305Sstevel {
33142305Sstevel rmc_comm_msg_t request;
33152305Sstevel dp_set_host_watchdog_t watchdog_msg;
33162305Sstevel
33172305Sstevel if (rmclomv_watchdog_mode)
33182305Sstevel return;
33192305Sstevel
33202305Sstevel watchdog_msg.enable = msg;
33212305Sstevel request.msg_type = DP_SET_HOST_WATCHDOG;
33222305Sstevel request.msg_len = sizeof (watchdog_msg);
33232305Sstevel request.msg_buf = (caddr_t)&watchdog_msg;
33242305Sstevel (void) rmc_comm_request_nowait(&request, (msg == 1) ?
33252305Sstevel RMC_COMM_DREQ_URGENT : 0);
33262305Sstevel }
33272305Sstevel
33282305Sstevel /*ARGSUSED*/
33292305Sstevel static uint_t
rmc_set_watchdog_timer(uint_t timeoutval)33302305Sstevel rmc_set_watchdog_timer(uint_t timeoutval)
33312305Sstevel {
33322305Sstevel ASSERT(MUTEX_HELD(&tod_lock));
33332305Sstevel
33342305Sstevel if ((watchdog_enable == 0) || (watchdog_available == 0)) {
33352305Sstevel return (0);
33362305Sstevel }
33372305Sstevel
33382305Sstevel /*
33392305Sstevel * If boothowto has RB_DEBUG set we never want to set the watchdog
33402305Sstevel * support on.
33412305Sstevel */
33422305Sstevel if (boothowto & RB_DEBUG) {
33432305Sstevel return (0);
33442305Sstevel }
33452305Sstevel
33462305Sstevel /*
33472305Sstevel * When the watchdog is shut off last_watchdog_msg goes from a
33482305Sstevel * 0 to a 1. So we must test to see that last_watchdog_msg is
33492305Sstevel * set to 1 indicating that watchdog was shut off and
33502305Sstevel * After which we set last_watchdog_msg back to 0 so that we do not
33512305Sstevel * run this code
33522305Sstevel * again.
33532305Sstevel */
33542305Sstevel if (last_watchdog_msg == 1) {
33552305Sstevel send_watchdog_msg(0);
33562305Sstevel last_watchdog_msg = 0;
33572305Sstevel }
33582305Sstevel
33592305Sstevel pmugpio_watchdog_pat();
33602305Sstevel
33612305Sstevel watchdog_activated = 1;
33622305Sstevel
33632305Sstevel return (1);
33642305Sstevel }
33652305Sstevel
33662305Sstevel static uint_t
rmc_clear_watchdog_timer(void)33672305Sstevel rmc_clear_watchdog_timer(void)
33682305Sstevel {
33692305Sstevel ASSERT(MUTEX_HELD(&tod_lock));
33702305Sstevel if ((watchdog_activated == 0) || (boothowto & RB_DEBUG))
33712305Sstevel return (0);
33722305Sstevel
33732305Sstevel send_watchdog_msg(1);
33742305Sstevel last_watchdog_msg = 1;
33752305Sstevel watchdog_activated = 0;
33762305Sstevel
33772305Sstevel return (0);
33782305Sstevel }
33792305Sstevel
33802305Sstevel static void
plat_timesync(void * arg)33812305Sstevel plat_timesync(void *arg)
33822305Sstevel {
33832305Sstevel timestruc_t now;
33842305Sstevel todinfo_t tod;
33852305Sstevel rmc_comm_msg_t request;
33862305Sstevel dp_set_date_time_t set_time_msg;
33872305Sstevel int retval;
33882305Sstevel timestruc_t ts;
33892305Sstevel dp_get_date_time_r_t *date_and_time_info;
33902305Sstevel int buffer[DATE_TIME_MSG_SIZE];
33912305Sstevel
33922305Sstevel /* Is the system coming up? */
33932305Sstevel if (arg != NULL) {
33942305Sstevel /* Request the time from the RMC clock. */
33952305Sstevel retval = rmclomv_do_cmd(DP_GET_DATE_TIME, DP_GET_DATE_TIME_R,
33962305Sstevel DATE_TIME_MSG_SIZE, NULL, (intptr_t)&buffer);
33972305Sstevel
33982305Sstevel /*
33992305Sstevel * If we were able to get the time lets set the local clock.
34002305Sstevel * The time returned from RMC is in Unix time format.
34012305Sstevel *
34022305Sstevel * If we couldn't get the time we'll accept the drift so as not
34032305Sstevel * to cause congestion on the I2C bus or cause boot
34042305Sstevel * performance regressions.
34052305Sstevel */
34062305Sstevel if (retval == RCNOERR) {
34072305Sstevel date_and_time_info = (dp_get_date_time_r_t *)buffer;
34082305Sstevel ts.tv_sec = date_and_time_info->current_datetime;
34092305Sstevel ts.tv_nsec = 0;
34102305Sstevel mutex_enter(&tod_lock);
34112305Sstevel tod_set(ts);
34122305Sstevel set_hrestime(&ts);
34132305Sstevel mutex_exit(&tod_lock);
34142305Sstevel }
34152305Sstevel }
34162305Sstevel
34172305Sstevel gethrestime(&now);
34182305Sstevel mutex_enter(&tod_lock);
34192305Sstevel tod = utc_to_tod(now.tv_sec);
34202305Sstevel mutex_exit(&tod_lock);
34212305Sstevel
34222305Sstevel set_time_msg.year = tod.tod_year;
34232305Sstevel set_time_msg.month = tod.tod_month - 1;
34242305Sstevel set_time_msg.day = tod.tod_day;
34252305Sstevel set_time_msg.hour = tod.tod_hour;
34262305Sstevel set_time_msg.minute = tod.tod_min;
34272305Sstevel set_time_msg.second = tod.tod_sec;
34282305Sstevel
34292305Sstevel request.msg_type = DP_SET_DATE_TIME;
34302305Sstevel request.msg_len = sizeof (set_time_msg);
34312305Sstevel request.msg_buf = (caddr_t)&set_time_msg;
34322305Sstevel
34332305Sstevel (void) rmc_comm_request_nowait(&request, 0);
34342305Sstevel
3435*8275SEric Cheng mutex_enter(×ync_lock);
3436*8275SEric Cheng if (timesync_interval != 0)
3437*8275SEric Cheng timesync_tid = timeout(plat_timesync, NULL, timesync_interval);
3438*8275SEric Cheng mutex_exit(×ync_lock);
34392305Sstevel }
34402305Sstevel
34412305Sstevel /*
34422305Sstevel * Interfaces to get/set alarm relays from outside
34432305Sstevel */
34442305Sstevel int
rmclomv_alarm_get(int alarm_type,int * alarm_state)34452305Sstevel rmclomv_alarm_get(int alarm_type, int *alarm_state)
34462305Sstevel {
34472305Sstevel rmclomv_cache_section_t *section;
34482305Sstevel int index;
34492305Sstevel uint16_t sensor_status;
34502305Sstevel dp_get_alarm_state_t u_rmc_alarm;
34512305Sstevel dp_get_alarm_state_r_t u_rmc_alarm_r;
34522305Sstevel
34532305Sstevel /* see if we've got ALARM handles cached */
34542305Sstevel LOCK_CACHE
34552305Sstevel sensor_status = ENVMON_SENSOR_OK;
34562305Sstevel
34572305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
34585593Sjfrank ((section = rmclomv_find_section(rmclomv_cache,
34595593Sjfrank RMCLOMV_ALARM_IND)) == NULL)) {
34602305Sstevel sensor_status = ENVMON_NOT_PRESENT;
34612305Sstevel }
34622305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
34632305Sstevel /*
34642305Sstevel * user correctly identified a ALARM, note its
34652305Sstevel * handle value and request the ALARM status
34662305Sstevel */
34672305Sstevel index = alarm_type;
34682305Sstevel if (index >= section->num_entries)
34692305Sstevel sensor_status = ENVMON_INACCESSIBLE;
34702305Sstevel else
34712305Sstevel u_rmc_alarm.handle = section->entry[index].handle;
34722305Sstevel }
34732305Sstevel RELEASE_CACHE
34742305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
34755593Sjfrank rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R,
34765593Sjfrank sizeof (u_rmc_alarm_r), (intptr_t)&u_rmc_alarm,
34775593Sjfrank (intptr_t)&u_rmc_alarm_r) != 0)) {
34782305Sstevel sensor_status = ENVMON_INACCESSIBLE;
34792305Sstevel }
34802305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
34812305Sstevel /*
34822305Sstevel * copy results into buffer for user
34832305Sstevel * start with some defaults then override
34842305Sstevel */
34852305Sstevel *alarm_state = 0;
34862305Sstevel
34872305Sstevel if (u_rmc_alarm_r.alarm_state[0].sensor_status !=
34885593Sjfrank DP_SENSOR_DATA_AVAILABLE)
34892305Sstevel return (ENXIO);
34902305Sstevel else {
34912305Sstevel dp_alarm_state_t alarmState;
34922305Sstevel alarmState = u_rmc_alarm_r.alarm_state[0];
34932305Sstevel
34942305Sstevel switch (alarmState.state) {
34952305Sstevel case DP_ALARM_OFF:
34962305Sstevel break;
34972305Sstevel case DP_ALARM_ON:
34982305Sstevel *alarm_state = 1;
34992305Sstevel break;
35002305Sstevel default:
35012305Sstevel break;
35022305Sstevel }
35032305Sstevel }
35042305Sstevel } else
35052305Sstevel return (ENXIO);
35062305Sstevel
35072305Sstevel return (0);
35082305Sstevel }
35092305Sstevel
35102305Sstevel int
rmclomv_alarm_set(int alarm_type,int new_state)35112305Sstevel rmclomv_alarm_set(int alarm_type, int new_state)
35122305Sstevel {
35132305Sstevel rmclomv_cache_section_t *section;
35142305Sstevel int index;
35152305Sstevel uint16_t sensor_status;
35162305Sstevel dp_set_alarm_state_t u_rmc_setalarm;
35172305Sstevel dp_set_alarm_state_r_t u_rmc_setalarm_r;
35182305Sstevel
35192305Sstevel /* see if we've got ALARM handles cached */
35202305Sstevel LOCK_CACHE
35212305Sstevel sensor_status = ENVMON_SENSOR_OK;
35222305Sstevel
35232305Sstevel if ((rmclomv_cache_valid == B_FALSE) ||
35245593Sjfrank ((section = rmclomv_find_section(rmclomv_cache,
35255593Sjfrank RMCLOMV_ALARM_IND)) == NULL)) {
35262305Sstevel sensor_status = ENVMON_NOT_PRESENT;
35272305Sstevel }
35282305Sstevel if (sensor_status == ENVMON_SENSOR_OK) {
35292305Sstevel /*
35302305Sstevel * user correctly identified a ALARM, note its
35312305Sstevel * handle value and request the ALARM status
35322305Sstevel */
35332305Sstevel index = alarm_type;
35342305Sstevel if (index >= section->num_entries)
35352305Sstevel sensor_status = ENVMON_INACCESSIBLE;
35362305Sstevel else {
35372305Sstevel u_rmc_setalarm.handle = section->entry[index].handle;
35382305Sstevel u_rmc_setalarm.state = new_state;
35392305Sstevel }
35402305Sstevel }
35412305Sstevel RELEASE_CACHE
35422305Sstevel if ((sensor_status == ENVMON_SENSOR_OK) &&
35435593Sjfrank (rmclomv_rmc_error ||
35445593Sjfrank rmclomv_do_cmd(DP_SET_ALARM_STATE, DP_SET_ALARM_STATE_R,
35455593Sjfrank sizeof (u_rmc_setalarm_r), (intptr_t)&u_rmc_setalarm,
35465593Sjfrank (intptr_t)&u_rmc_setalarm_r) != 0)) {
35472305Sstevel sensor_status = ENVMON_INACCESSIBLE;
35482305Sstevel }
35492305Sstevel
35502305Sstevel if (u_rmc_setalarm_r.status != DP_SET_ALARM_OK) {
35512305Sstevel return (EIO);
35522305Sstevel }
35532305Sstevel
35542305Sstevel if (sensor_status != ENVMON_SENSOR_OK) {
35552305Sstevel return (ENXIO);
35562305Sstevel }
35572305Sstevel
35582305Sstevel return (0);
35592305Sstevel }
3560