13db86aabSstevel /* 23db86aabSstevel * CDDL HEADER START 33db86aabSstevel * 43db86aabSstevel * The contents of this file are subject to the terms of the 53db86aabSstevel * Common Development and Distribution License (the "License"). 63db86aabSstevel * You may not use this file except in compliance with the License. 73db86aabSstevel * 83db86aabSstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93db86aabSstevel * or http://www.opensolaris.org/os/licensing. 103db86aabSstevel * See the License for the specific language governing permissions 113db86aabSstevel * and limitations under the License. 123db86aabSstevel * 133db86aabSstevel * When distributing Covered Code, include this CDDL HEADER in each 143db86aabSstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153db86aabSstevel * If applicable, add the following below this CDDL HEADER, with the 163db86aabSstevel * fields enclosed by brackets "[]" replaced with your own identifying 173db86aabSstevel * information: Portions Copyright [yyyy] [name of copyright owner] 183db86aabSstevel * 193db86aabSstevel * CDDL HEADER END 203db86aabSstevel */ 213db86aabSstevel 223db86aabSstevel /* 2319397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243db86aabSstevel * Use is subject to license terms. 253db86aabSstevel */ 263db86aabSstevel 273db86aabSstevel 283db86aabSstevel #include <sys/types.h> 293db86aabSstevel #include <sys/stat.h> 303db86aabSstevel #include <sys/conf.h> 313db86aabSstevel #include <sys/modctl.h> 323db86aabSstevel #include <sys/callb.h> 333db86aabSstevel #include <sys/strlog.h> 343db86aabSstevel #include <sys/cyclic.h> 353db86aabSstevel #include <sys/rmc_comm_dp.h> 363db86aabSstevel #include <sys/rmc_comm_dp_boot.h> 373db86aabSstevel #include <sys/rmc_comm_drvintf.h> 383db86aabSstevel #include <sys/rmc_comm.h> 393db86aabSstevel #include <sys/machsystm.h> 403db86aabSstevel #include <sys/sysevent.h> 413db86aabSstevel #include <sys/sysevent/dr.h> 423db86aabSstevel #include <sys/sysevent/env.h> 433db86aabSstevel #include <sys/sysevent/eventdefs.h> 443db86aabSstevel #include <sys/file.h> 453db86aabSstevel #include <sys/disp.h> 463db86aabSstevel #include <sys/reboot.h> 473db86aabSstevel #include <sys/envmon.h> 483db86aabSstevel #include <sys/rmclomv_impl.h> 493db86aabSstevel #include <sys/cpu_sgnblk_defs.h> 503db86aabSstevel #include <sys/utsname.h> 513db86aabSstevel #include <sys/systeminfo.h> 523db86aabSstevel #include <sys/ddi.h> 533db86aabSstevel #include <sys/time.h> 543db86aabSstevel #include <sys/promif.h> 55*5c5f1371SRichard Lowe #include <sys/sysmacros.h> 563db86aabSstevel 573db86aabSstevel #define RMCRESBUFLEN 1024 583db86aabSstevel #define DATE_TIME_MSG_SIZE 78 593db86aabSstevel #define RMCLOMV_WATCHDOG_MODE "rmclomv-watchdog-mode" 60f594b28aSjfrank #define DELAY_TIME 5000000 /* 5 seconds, in microseconds */ 61f594b28aSjfrank #define CPU_SIGNATURE_DELAY_TIME 5000000 /* 5 secs, in microsecs */ 623db86aabSstevel 633db86aabSstevel extern void pmugpio_watchdog_pat(); 643db86aabSstevel 653db86aabSstevel extern int watchdog_activated; 663db86aabSstevel static int last_watchdog_msg = 1; 673db86aabSstevel extern int watchdog_enable; 683db86aabSstevel extern int boothowto; 693db86aabSstevel 703db86aabSstevel int rmclomv_watchdog_mode; 713db86aabSstevel 723db86aabSstevel /* 733db86aabSstevel * functions local to this driver. 743db86aabSstevel */ 753db86aabSstevel static int rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 763db86aabSstevel void **resultp); 773db86aabSstevel static int rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 783db86aabSstevel static int rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 793db86aabSstevel static uint_t rmclomv_break_intr(caddr_t arg); 803db86aabSstevel static int rmclomv_add_intr_handlers(void); 813db86aabSstevel static int rmclomv_remove_intr_handlers(void); 823db86aabSstevel static uint_t rmclomv_event_data_handler(char *); 833db86aabSstevel static void rmclomv_dr_data_handler(const char *, int); 843db86aabSstevel static int rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); 853db86aabSstevel static int rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p); 863db86aabSstevel static int rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 873db86aabSstevel cred_t *cred_p, int *rval_p); 883db86aabSstevel static void rmclomv_checkrmc_start(void); 893db86aabSstevel static void rmclomv_checkrmc_destroy(void); 903db86aabSstevel static void rmclomv_checkrmc_wakeup(void *); 913db86aabSstevel static void rmclomv_refresh_start(void); 923db86aabSstevel static void rmclomv_refresh_destroy(void); 933db86aabSstevel static void rmclomv_refresh_wakeup(void); 943db86aabSstevel static void rmclomv_reset_cache(rmclomv_cache_section_t *new_chain, 953db86aabSstevel rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo); 963db86aabSstevel static rmclomv_cache_section_t *rmclomv_find_section( 973db86aabSstevel rmclomv_cache_section_t *start, uint16_t sensor); 983db86aabSstevel static rmclomv_cache_section_t *create_cache_section(int sensor_type, int num); 993db86aabSstevel static int get_sensor_by_name(const rmclomv_cache_section_t *section, 1003db86aabSstevel const char *name, int *index); 1013db86aabSstevel static int validate_section_entry(rmclomv_cache_section_t *section, 1023db86aabSstevel int index); 1033db86aabSstevel static int add_names_to_section(rmclomv_cache_section_t *section); 1043db86aabSstevel static void free_section(rmclomv_cache_section_t *section); 1053db86aabSstevel static void add_section(rmclomv_cache_section_t **head, 1063db86aabSstevel rmclomv_cache_section_t *section); 1073db86aabSstevel static int rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len, 1083db86aabSstevel intptr_t arg_req, intptr_t arg_res); 1093db86aabSstevel static void refresh_name_cache(int force_fail); 1103db86aabSstevel static void set_val_unav(envmon_sensor_t *sensor); 1113db86aabSstevel static void set_fan_unav(envmon_fan_t *fan); 1123db86aabSstevel static int do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind, 1133db86aabSstevel dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r, 1143db86aabSstevel int detector_type); 1153db86aabSstevel static uint_t rmc_set_watchdog_timer(uint_t timeoutval); 1163db86aabSstevel static uint_t rmc_clear_watchdog_timer(void); 1173db86aabSstevel static void send_watchdog_msg(int msg); 1183db86aabSstevel static void plat_timesync(void *arg); 1193db86aabSstevel 120da14cebeSEric Cheng static kmutex_t timesync_lock; 121da14cebeSEric Cheng static clock_t timesync_interval = 0; 122da14cebeSEric Cheng static timeout_id_t timesync_tid = 0; 123da14cebeSEric Cheng 1243db86aabSstevel /* 1253db86aabSstevel * Driver entry points 1263db86aabSstevel */ 1273db86aabSstevel static struct cb_ops rmclomv_cb_ops = { 1283db86aabSstevel rmclomv_open, /* open */ 1293db86aabSstevel rmclomv_close, /* close */ 1303db86aabSstevel nodev, /* strategy() */ 1313db86aabSstevel nodev, /* print() */ 1323db86aabSstevel nodev, /* dump() */ 1333db86aabSstevel nodev, /* read() */ 1343db86aabSstevel nodev, /* write() */ 1353db86aabSstevel rmclomv_ioctl, /* ioctl() */ 1363db86aabSstevel nodev, /* devmap() */ 1373db86aabSstevel nodev, /* mmap() */ 1383db86aabSstevel ddi_segmap, /* segmap() */ 1393db86aabSstevel nochpoll, /* poll() */ 1403db86aabSstevel ddi_prop_op, /* prop_op() */ 1413db86aabSstevel NULL, /* cb_str */ 1423db86aabSstevel D_NEW | D_MP /* cb_flag */ 1433db86aabSstevel }; 1443db86aabSstevel 1453db86aabSstevel 1463db86aabSstevel static struct dev_ops rmclomv_ops = { 1473db86aabSstevel DEVO_REV, 1483db86aabSstevel 0, /* ref count */ 1493db86aabSstevel rmclomv_getinfo, /* getinfo() */ 1503db86aabSstevel nulldev, /* identify() */ 1513db86aabSstevel nulldev, /* probe() */ 1523db86aabSstevel rmclomv_attach, /* attach() */ 1533db86aabSstevel rmclomv_detach, /* detach */ 1543db86aabSstevel nodev, /* reset */ 1553db86aabSstevel &rmclomv_cb_ops, /* pointer to cb_ops structure */ 1563db86aabSstevel (struct bus_ops *)NULL, 15719397407SSherry Moore nulldev, /* power() */ 15819397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 1593db86aabSstevel }; 1603db86aabSstevel 1613db86aabSstevel /* 1623db86aabSstevel * Loadable module support. 1633db86aabSstevel */ 1643db86aabSstevel extern struct mod_ops mod_driverops; 1653db86aabSstevel 1663db86aabSstevel static struct modldrv modldrv = { 1673db86aabSstevel &mod_driverops, /* Type of module. This is a driver */ 16819397407SSherry Moore "rmclomv control driver", /* Name of the module */ 1693db86aabSstevel &rmclomv_ops /* pointer to the dev_ops structure */ 1703db86aabSstevel }; 1713db86aabSstevel 1723db86aabSstevel static struct modlinkage modlinkage = { 1733db86aabSstevel MODREV_1, 1743db86aabSstevel &modldrv, 1753db86aabSstevel NULL 1763db86aabSstevel }; 1773db86aabSstevel 1783db86aabSstevel /* 1793db86aabSstevel * Device info 1803db86aabSstevel */ 1813db86aabSstevel static dev_info_t *rmclomv_dip = NULL; 1823db86aabSstevel static int rmclomv_break_requested = B_FALSE; 1833db86aabSstevel static ddi_softintr_t rmclomv_softintr_id; 1843db86aabSstevel static ddi_iblock_cookie_t rmclomv_soft_iblock_cookie; 1853db86aabSstevel 1863db86aabSstevel extern void (*abort_seq_handler)(); 1873db86aabSstevel /* key_position is effective key-position. Set to locked if unknown */ 1883db86aabSstevel static rsci8 key_position = RMC_KEYSWITCH_POS_LOCKED; 1893db86aabSstevel /* real_key_position starts off as unknown and records value actually seen */ 1903db86aabSstevel static rsci8 real_key_position = RMC_KEYSWITCH_POS_UNKNOWN; 1913db86aabSstevel static void rmclomv_abort_seq_handler(char *msg); 1923db86aabSstevel 1933db86aabSstevel /* 1943db86aabSstevel * mutexes which protect the interrupt handlers. 1953db86aabSstevel */ 1963db86aabSstevel static kmutex_t rmclomv_event_hdlr_lock; 1973db86aabSstevel static kmutex_t rmclomv_refresh_lock; 1983db86aabSstevel static kcondvar_t rmclomv_refresh_sig_cv; 1993db86aabSstevel static kmutex_t rmclomv_checkrmc_lock; 2003db86aabSstevel static kcondvar_t rmclomv_checkrmc_sig_cv; 2013db86aabSstevel 2023db86aabSstevel /* 2033db86aabSstevel * mutex to protect the handle_name cache 2043db86aabSstevel */ 2053db86aabSstevel static kmutex_t rmclomv_cache_lock; 2063db86aabSstevel 2073db86aabSstevel /* 2083db86aabSstevel * mutex to protect the RMC state 2093db86aabSstevel */ 2103db86aabSstevel static kmutex_t rmclomv_state_lock; 2113db86aabSstevel 2123db86aabSstevel /* 2133db86aabSstevel * Payloads of the event handlers. 2143db86aabSstevel */ 2153db86aabSstevel static dp_event_notification_t rmclomv_event_payload; 2163db86aabSstevel static rmc_comm_msg_t rmclomv_event_payload_msg; 2173db86aabSstevel 2183db86aabSstevel /* 2193db86aabSstevel * Checkrmc commands.. 2203db86aabSstevel */ 2213db86aabSstevel #define RMCLOMV_CHECKRMC_EXITNOW (-1) 2223db86aabSstevel #define RMCLOMV_CHECKRMC_WAIT 0 2233db86aabSstevel #define RMCLOMV_CHECKRMC_PROCESSNOW 1 2243db86aabSstevel 2253db86aabSstevel /* 2263db86aabSstevel * Checkrmc thread state 2273db86aabSstevel */ 2283db86aabSstevel static int rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT; 2293db86aabSstevel static kt_did_t rmclomv_checkrmc_tid = 0; 2303db86aabSstevel 2313db86aabSstevel /* 2323db86aabSstevel * RMC state data 2333db86aabSstevel */ 2343db86aabSstevel #define RMCLOMV_RMCSTATE_UNKNOWN 0 2353db86aabSstevel #define RMCLOMV_RMCSTATE_OK 1 2363db86aabSstevel #define RMCLOMV_RMCSTATE_FAILED 2 2373db86aabSstevel #define RMCLOMV_RMCSTATE_DOWNLOAD 3 2383db86aabSstevel 2393db86aabSstevel /* 2403db86aabSstevel * RMC error indicator values (status from last RMC command) 2413db86aabSstevel */ 2423db86aabSstevel #define RMCLOMV_RMCERROR_NONE 0 2433db86aabSstevel 2443db86aabSstevel /* fail RMC after 5 minutes without a good response */ 2453db86aabSstevel #define RMCLOMV_RMCFAILTHRESHOLD 5 2463db86aabSstevel 2473db86aabSstevel /* 2483db86aabSstevel * rmclomv_rmc_state is the state reported in OperationalStatus. 2493db86aabSstevel * rmclomv_rmc_error reflects the result of the last RMC interaction. 2503db86aabSstevel * rmclomv_rmcfailcount is used by the rmclomv_checkrmc thread to count 2513db86aabSstevel * failures in its regular status polls. Once RMCLOMV_RMCFAILTHRESHOLD 2523db86aabSstevel * is reached, rmclomv_rmc_state is marked as RMCLOMV_RMCSTATE_FAILED. 2533db86aabSstevel */ 2543db86aabSstevel static int rmclomv_rmc_state = RMCLOMV_RMCSTATE_UNKNOWN; 2553db86aabSstevel static int rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE; 2563db86aabSstevel static int rmclomv_rmcfailcount; 2573db86aabSstevel 2583db86aabSstevel /* 2593db86aabSstevel * Refresh commands.. 2603db86aabSstevel */ 2613db86aabSstevel #define RMCLOMV_REFRESH_EXITNOW (-1) 2623db86aabSstevel #define RMCLOMV_REFRESH_WAIT 0 2633db86aabSstevel #define RMCLOMV_REFRESH_PROCESSNOW 1 2643db86aabSstevel 2653db86aabSstevel /* 2663db86aabSstevel * Refresh thread state 2673db86aabSstevel */ 2683db86aabSstevel static int rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT; 2693db86aabSstevel static kt_did_t rmclomv_refresh_tid = 0; 2703db86aabSstevel 2713db86aabSstevel /* 2723db86aabSstevel * timeout id 2733db86aabSstevel */ 2743db86aabSstevel static timeout_id_t timer_id; 2753db86aabSstevel 2763db86aabSstevel /* 2773db86aabSstevel * Handle-name cache 2783db86aabSstevel */ 2793db86aabSstevel #define LOCK_CACHE mutex_enter(&rmclomv_cache_lock); 2803db86aabSstevel #define RELEASE_CACHE mutex_exit(&rmclomv_cache_lock); 2813db86aabSstevel static rmclomv_cache_section_t *rmclomv_cache; /* main handle-names */ 2823db86aabSstevel static rmclomv_cache_section_t *rmclomv_subcache; /* derived names */ 2833db86aabSstevel static dp_get_sysinfo_r_t rmclomv_sysinfo_data; 2843db86aabSstevel static boolean_t rmclomv_sysinfo_valid; 2853db86aabSstevel static int rmclomv_cache_valid; 2863db86aabSstevel 2873db86aabSstevel extern pri_t maxclsyspri; 2883db86aabSstevel 2893db86aabSstevel /* 2903db86aabSstevel * static strings 2913db86aabSstevel */ 2923db86aabSstevel static const char str_percent[] = "%"; 2933db86aabSstevel static const char str_rpm[] = " rpm"; 2943db86aabSstevel static const char str_ip_volts_ind[] = "P_PWR"; 2953db86aabSstevel static const char str_ip2_volts_ind[] = "P_PWR2"; 2963db86aabSstevel static const char str_ff_pok_ind[] = "FF_POK"; 2973db86aabSstevel static const char str_vlo_volts_ind[] = "FF_UV"; 2983db86aabSstevel static const char str_vhi_volts_ind[] = "FF_OV"; 2993db86aabSstevel static const char str_chi_amps_ind[] = "FF_OC"; 3003db86aabSstevel static const char str_chi_nr_ind[] = "FF_NR"; 3013db86aabSstevel static const char str_ot_tmpr_ind[] = "FF_OT"; 3023db86aabSstevel static const char str_fan_ind[] = "FF_FAN"; 3033db86aabSstevel static const char str_pdct_fan_ind[] = "FF_PDCT_FAN"; 3043db86aabSstevel static const char str_sc[] = "SC"; 3053db86aabSstevel 3063db86aabSstevel int 3073db86aabSstevel _init(void) 3083db86aabSstevel { 3093db86aabSstevel int error = 0; 3103db86aabSstevel 3113db86aabSstevel mutex_init(&rmclomv_event_hdlr_lock, NULL, MUTEX_DEFAULT, NULL); 3123db86aabSstevel mutex_init(&rmclomv_checkrmc_lock, NULL, MUTEX_DRIVER, NULL); 3133db86aabSstevel mutex_init(&rmclomv_refresh_lock, NULL, MUTEX_DRIVER, NULL); 3143db86aabSstevel mutex_init(&rmclomv_cache_lock, NULL, MUTEX_DRIVER, NULL); 3153db86aabSstevel mutex_init(&rmclomv_state_lock, NULL, MUTEX_DRIVER, NULL); 316da14cebeSEric Cheng mutex_init(×ync_lock, NULL, MUTEX_DEFAULT, NULL); 3173db86aabSstevel cv_init(&rmclomv_checkrmc_sig_cv, NULL, CV_DRIVER, NULL); 3183db86aabSstevel cv_init(&rmclomv_refresh_sig_cv, NULL, CV_DRIVER, NULL); 3193db86aabSstevel 3203db86aabSstevel error = mod_install(&modlinkage); 3213db86aabSstevel if (error) { 3223db86aabSstevel cv_destroy(&rmclomv_refresh_sig_cv); 3233db86aabSstevel cv_destroy(&rmclomv_checkrmc_sig_cv); 3243db86aabSstevel mutex_destroy(&rmclomv_state_lock); 3253db86aabSstevel mutex_destroy(&rmclomv_cache_lock); 3263db86aabSstevel mutex_destroy(&rmclomv_refresh_lock); 3273db86aabSstevel mutex_destroy(&rmclomv_checkrmc_lock); 3283db86aabSstevel mutex_destroy(&rmclomv_event_hdlr_lock); 3293db86aabSstevel } 3303db86aabSstevel return (error); 3313db86aabSstevel } 3323db86aabSstevel 3333db86aabSstevel 3343db86aabSstevel int 3353db86aabSstevel _info(struct modinfo *modinfop) 3363db86aabSstevel { 3373db86aabSstevel return (mod_info(&modlinkage, modinfop)); 3383db86aabSstevel } 3393db86aabSstevel 3403db86aabSstevel 3413db86aabSstevel int 3423db86aabSstevel _fini(void) 3433db86aabSstevel { 3443db86aabSstevel int error = 0; 3453db86aabSstevel 3463db86aabSstevel error = mod_remove(&modlinkage); 3473db86aabSstevel if (error) 3483db86aabSstevel return (error); 3493db86aabSstevel cv_destroy(&rmclomv_refresh_sig_cv); 3503db86aabSstevel cv_destroy(&rmclomv_checkrmc_sig_cv); 351da14cebeSEric Cheng mutex_destroy(×ync_lock); 3523db86aabSstevel mutex_destroy(&rmclomv_state_lock); 3533db86aabSstevel mutex_destroy(&rmclomv_cache_lock); 3543db86aabSstevel mutex_destroy(&rmclomv_refresh_lock); 3553db86aabSstevel mutex_destroy(&rmclomv_checkrmc_lock); 3563db86aabSstevel mutex_destroy(&rmclomv_event_hdlr_lock); 3573db86aabSstevel return (error); 3583db86aabSstevel } 3593db86aabSstevel 3603db86aabSstevel 3613db86aabSstevel /* ARGSUSED */ 3623db86aabSstevel static int 3633db86aabSstevel rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 3643db86aabSstevel { 3653db86aabSstevel minor_t m = getminor((dev_t)arg); 3663db86aabSstevel 3673db86aabSstevel switch (cmd) { 3683db86aabSstevel case DDI_INFO_DEVT2DEVINFO: 3693db86aabSstevel if ((m != 0) || (rmclomv_dip == NULL)) { 3703db86aabSstevel *resultp = NULL; 3713db86aabSstevel return (DDI_FAILURE); 3723db86aabSstevel } 3733db86aabSstevel *resultp = rmclomv_dip; 3743db86aabSstevel return (DDI_SUCCESS); 3753db86aabSstevel case DDI_INFO_DEVT2INSTANCE: 3763db86aabSstevel *resultp = (void *)(uintptr_t)m; 3773db86aabSstevel return (DDI_SUCCESS); 3783db86aabSstevel default: 3793db86aabSstevel return (DDI_FAILURE); 3803db86aabSstevel } 3813db86aabSstevel } 3823db86aabSstevel 3833db86aabSstevel 3843db86aabSstevel static int 3853db86aabSstevel rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3863db86aabSstevel { 3873db86aabSstevel int instance; 3883db86aabSstevel int err; 3893db86aabSstevel char *wdog_state; 3903db86aabSstevel int attaching = 1; 3913db86aabSstevel 3923db86aabSstevel switch (cmd) { 3933db86aabSstevel case DDI_ATTACH: 3943db86aabSstevel /* 3953db86aabSstevel * only allow one instance 3963db86aabSstevel */ 3973db86aabSstevel instance = ddi_get_instance(dip); 3983db86aabSstevel if (instance != 0) 3993db86aabSstevel return (DDI_FAILURE); 4003db86aabSstevel 4013db86aabSstevel err = ddi_create_minor_node(dip, "rmclomv", S_IFCHR, 4023db86aabSstevel instance, DDI_PSEUDO, NULL); 4033db86aabSstevel if (err != DDI_SUCCESS) 4043db86aabSstevel return (DDI_FAILURE); 4053db86aabSstevel 4063db86aabSstevel /* 4073db86aabSstevel * Register with rmc_comm to prevent it being detached 4083db86aabSstevel * (in the unlikely event that its attach succeeded on a 4093db86aabSstevel * platform whose platmod doesn't lock it down). 4103db86aabSstevel */ 4113db86aabSstevel err = rmc_comm_register(); 4123db86aabSstevel if (err != DDI_SUCCESS) { 4133db86aabSstevel ddi_remove_minor_node(dip, NULL); 4143db86aabSstevel return (DDI_FAILURE); 4153db86aabSstevel } 4163db86aabSstevel 4173db86aabSstevel /* Remember the dev info */ 4183db86aabSstevel rmclomv_dip = dip; 4193db86aabSstevel 4203db86aabSstevel /* 4213db86aabSstevel * Add the handlers which watch for unsolicited messages 4223db86aabSstevel * and post event to Sysevent Framework. 4233db86aabSstevel */ 4243db86aabSstevel err = rmclomv_add_intr_handlers(); 4253db86aabSstevel if (err != DDI_SUCCESS) { 4263db86aabSstevel rmc_comm_unregister(); 4273db86aabSstevel ddi_remove_minor_node(dip, NULL); 4283db86aabSstevel rmclomv_dip = NULL; 4293db86aabSstevel return (DDI_FAILURE); 4303db86aabSstevel } 4313db86aabSstevel 4323db86aabSstevel rmclomv_checkrmc_start(); 4333db86aabSstevel rmclomv_refresh_start(); 4343db86aabSstevel 4353db86aabSstevel abort_seq_handler = rmclomv_abort_seq_handler; 4363db86aabSstevel ddi_report_dev(dip); 4373db86aabSstevel 4383db86aabSstevel /* 4393db86aabSstevel * Check whether we have an application watchdog 4403db86aabSstevel */ 4413db86aabSstevel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 4423db86aabSstevel DDI_PROP_DONTPASS, RMCLOMV_WATCHDOG_MODE, 4433db86aabSstevel &wdog_state) == DDI_PROP_SUCCESS) { 4443db86aabSstevel if (strcmp(wdog_state, "app") == 0) { 4453db86aabSstevel rmclomv_watchdog_mode = 1; 4463db86aabSstevel watchdog_enable = 0; 4473db86aabSstevel } 4483db86aabSstevel else 4493db86aabSstevel rmclomv_watchdog_mode = 0; 4503db86aabSstevel ddi_prop_free(wdog_state); 4513db86aabSstevel } 4523db86aabSstevel 4533db86aabSstevel tod_ops.tod_set_watchdog_timer = rmc_set_watchdog_timer; 4543db86aabSstevel tod_ops.tod_clear_watchdog_timer = rmc_clear_watchdog_timer; 4553db86aabSstevel 4563db86aabSstevel /* 4573db86aabSstevel * Now is a good time to activate hardware watchdog 4583db86aabSstevel * (if one exists). 4593db86aabSstevel */ 4603db86aabSstevel mutex_enter(&tod_lock); 4613db86aabSstevel if (watchdog_enable && tod_ops.tod_set_watchdog_timer != NULL) 4623db86aabSstevel err = tod_ops.tod_set_watchdog_timer(0); 4633db86aabSstevel mutex_exit(&tod_lock); 4643db86aabSstevel if (err != 0) 4653db86aabSstevel printf("Hardware watchdog enabled\n"); 4663db86aabSstevel 4673db86aabSstevel /* 4683db86aabSstevel * Set time interval and start timesync routine. 4693db86aabSstevel * Also just this once set the Solaris clock 4703db86aabSstevel * to the RMC clock. 4713db86aabSstevel */ 4723db86aabSstevel timesync_interval = drv_usectohz(5*60 * MICROSEC); 4733db86aabSstevel plat_timesync((void *) &attaching); 4743db86aabSstevel 4753db86aabSstevel return (DDI_SUCCESS); 4763db86aabSstevel case DDI_RESUME: 4773db86aabSstevel return (DDI_SUCCESS); 4783db86aabSstevel default: 4793db86aabSstevel return (DDI_FAILURE); 4803db86aabSstevel } 4813db86aabSstevel } 4823db86aabSstevel 4833db86aabSstevel 4843db86aabSstevel static int 4853db86aabSstevel rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4863db86aabSstevel { 487da14cebeSEric Cheng timeout_id_t tid; 4883db86aabSstevel int instance; 4893db86aabSstevel int err; 4903db86aabSstevel 4913db86aabSstevel switch (cmd) { 4923db86aabSstevel case DDI_DETACH: 4933db86aabSstevel instance = ddi_get_instance(dip); 4943db86aabSstevel if (instance != 0) 4953db86aabSstevel return (DDI_FAILURE); 4963db86aabSstevel 4973db86aabSstevel /* 4983db86aabSstevel * Remove the handlers which watch for unsolicited messages 4993db86aabSstevel * and post event to Sysevent Framework. 5003db86aabSstevel */ 5013db86aabSstevel err = rmclomv_remove_intr_handlers(); 5023db86aabSstevel if (err != DDI_SUCCESS) { 5033db86aabSstevel cmn_err(CE_WARN, "Failed to remove event handlers"); 5043db86aabSstevel return (DDI_FAILURE); 5053db86aabSstevel } 5063db86aabSstevel rmclomv_checkrmc_destroy(); 5073db86aabSstevel rmclomv_refresh_destroy(); 5083db86aabSstevel rmclomv_reset_cache(NULL, NULL, NULL); 5093db86aabSstevel ddi_remove_minor_node(dip, NULL); 5103db86aabSstevel 511da14cebeSEric Cheng mutex_enter(×ync_lock); 512da14cebeSEric Cheng tid = timesync_tid; 513da14cebeSEric Cheng timesync_tid = 0; 514da14cebeSEric Cheng timesync_interval = 0; 515da14cebeSEric Cheng mutex_exit(×ync_lock); 516da14cebeSEric Cheng (void) untimeout(tid); 517da14cebeSEric Cheng 5183db86aabSstevel /* Forget the dev info */ 5193db86aabSstevel rmclomv_dip = NULL; 5203db86aabSstevel rmc_comm_unregister(); 5213db86aabSstevel return (DDI_SUCCESS); 5223db86aabSstevel case DDI_SUSPEND: 5233db86aabSstevel return (DDI_SUCCESS); 5243db86aabSstevel default: 5253db86aabSstevel return (DDI_FAILURE); 5263db86aabSstevel } 5273db86aabSstevel } 5283db86aabSstevel 5293db86aabSstevel static int 5303db86aabSstevel rmclomv_add_intr_handlers() 5313db86aabSstevel { 5323db86aabSstevel int err; 5333db86aabSstevel 5343db86aabSstevel if (ddi_get_soft_iblock_cookie(rmclomv_dip, DDI_SOFTINT_HIGH, 5353db86aabSstevel &rmclomv_soft_iblock_cookie) != DDI_SUCCESS) { 5363db86aabSstevel return (DDI_FAILURE); 5373db86aabSstevel } 5383db86aabSstevel err = ddi_add_softintr(rmclomv_dip, DDI_SOFTINT_HIGH, 5393db86aabSstevel &rmclomv_softintr_id, &rmclomv_soft_iblock_cookie, NULL, 5403db86aabSstevel rmclomv_break_intr, NULL); 5413db86aabSstevel if (err != DDI_SUCCESS) 5423db86aabSstevel return (DDI_FAILURE); 5433db86aabSstevel rmclomv_event_payload_msg.msg_buf = (caddr_t)&rmclomv_event_payload; 5443db86aabSstevel rmclomv_event_payload_msg.msg_len = sizeof (rmclomv_event_payload); 5453db86aabSstevel err = rmc_comm_reg_intr(DP_RMC_EVENTS, rmclomv_event_data_handler, 5463db86aabSstevel &rmclomv_event_payload_msg, NULL, &rmclomv_event_hdlr_lock); 5473db86aabSstevel if (err != 0) { 5483db86aabSstevel ddi_remove_softintr(rmclomv_softintr_id); 5493db86aabSstevel return (DDI_FAILURE); 5503db86aabSstevel } 5513db86aabSstevel return (DDI_SUCCESS); 5523db86aabSstevel } 5533db86aabSstevel 5543db86aabSstevel static int 5553db86aabSstevel rmclomv_remove_intr_handlers(void) 5563db86aabSstevel { 5573db86aabSstevel int err = rmc_comm_unreg_intr(DP_RMC_EVENTS, 5583db86aabSstevel rmclomv_event_data_handler); 5593db86aabSstevel if (err != 0) { 5603db86aabSstevel cmn_err(CE_WARN, "Failed to unregister DP_RMC_EVENTS " 5613db86aabSstevel "handler. Err=%d", err); 5623db86aabSstevel return (DDI_FAILURE); 5633db86aabSstevel } 5643db86aabSstevel ddi_remove_softintr(rmclomv_softintr_id); 5653db86aabSstevel return (DDI_SUCCESS); 5663db86aabSstevel } 5673db86aabSstevel 5683db86aabSstevel static void 5693db86aabSstevel rmclomv_abort_seq_handler(char *msg) 5703db86aabSstevel { 5713db86aabSstevel if (key_position == RMC_KEYSWITCH_POS_LOCKED) 5723db86aabSstevel cmn_err(CE_CONT, "KEY in LOCKED position, " 5733db86aabSstevel "ignoring debug enter sequence"); 5743db86aabSstevel else { 5753db86aabSstevel rmclomv_break_requested = B_TRUE; 5763db86aabSstevel if (msg != NULL) 5773db86aabSstevel prom_printf("%s\n", msg); 5783db86aabSstevel 5793db86aabSstevel ddi_trigger_softintr(rmclomv_softintr_id); 5803db86aabSstevel } 5813db86aabSstevel } 5823db86aabSstevel 5833db86aabSstevel /* ARGSUSED */ 5843db86aabSstevel static uint_t 5853db86aabSstevel rmclomv_break_intr(caddr_t arg) 5863db86aabSstevel { 5873db86aabSstevel if (rmclomv_break_requested) { 5883db86aabSstevel rmclomv_break_requested = B_FALSE; 5893db86aabSstevel debug_enter(NULL); 5903db86aabSstevel return (DDI_INTR_CLAIMED); 5913db86aabSstevel } 5923db86aabSstevel 5933db86aabSstevel return (DDI_INTR_UNCLAIMED); 5943db86aabSstevel } 5953db86aabSstevel 5963db86aabSstevel /* 5973db86aabSstevel * Create a cache section structure 5983db86aabSstevel */ 5993db86aabSstevel static rmclomv_cache_section_t * 6003db86aabSstevel create_cache_section(int sensor_type, int num) 6013db86aabSstevel { 6023db86aabSstevel size_t len = offsetof(rmclomv_cache_section_t, entry[0]) + 6033db86aabSstevel num * sizeof (rmclomv_cache_entry_t); 6043db86aabSstevel rmclomv_cache_section_t *ptr = kmem_zalloc(len, KM_SLEEP); 6053db86aabSstevel ptr->next_section = NULL; 6063db86aabSstevel ptr->sensor_type = sensor_type; 6073db86aabSstevel ptr->num_entries = num; 6083db86aabSstevel ptr->section_len = len; 6093db86aabSstevel return (ptr); 6103db86aabSstevel } 6113db86aabSstevel 6123db86aabSstevel /* 6133db86aabSstevel * Free a cache_section. 6143db86aabSstevel */ 6153db86aabSstevel static void 6163db86aabSstevel free_section(rmclomv_cache_section_t *section) 6173db86aabSstevel { 6183db86aabSstevel size_t len = section->section_len; 6193db86aabSstevel kmem_free(section, len); 6203db86aabSstevel } 6213db86aabSstevel 6223db86aabSstevel /* 6233db86aabSstevel * adds supplied section to end of cache chain 6243db86aabSstevel * must be called with cache locked 6253db86aabSstevel */ 6263db86aabSstevel static void 6273db86aabSstevel add_section(rmclomv_cache_section_t **head, rmclomv_cache_section_t *section) 6283db86aabSstevel { 6293db86aabSstevel section->next_section = *head; 6303db86aabSstevel *head = section; 6313db86aabSstevel } 6323db86aabSstevel 6333db86aabSstevel /* 6343db86aabSstevel * This function releases all cache sections and exchanges the two 6353db86aabSstevel * chain heads for new values. 6363db86aabSstevel */ 6373db86aabSstevel static void 6383db86aabSstevel rmclomv_reset_cache(rmclomv_cache_section_t *new_chain, 6393db86aabSstevel rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo) 6403db86aabSstevel { 6413db86aabSstevel rmclomv_cache_section_t *first; 6423db86aabSstevel rmclomv_cache_section_t *sub_first; 6433db86aabSstevel rmclomv_cache_section_t *next; 6443db86aabSstevel 6453db86aabSstevel LOCK_CACHE 6463db86aabSstevel 6473db86aabSstevel rmclomv_cache_valid = (new_chain != NULL); 6483db86aabSstevel first = rmclomv_cache; 6493db86aabSstevel rmclomv_cache = new_chain; 6503db86aabSstevel sub_first = rmclomv_subcache; 6513db86aabSstevel rmclomv_subcache = new_subchain; 6523db86aabSstevel 6533db86aabSstevel if (sysinfo == NULL) 6543db86aabSstevel bzero(&rmclomv_sysinfo_data, sizeof (rmclomv_sysinfo_data)); 6553db86aabSstevel else 6563db86aabSstevel bcopy(sysinfo, &rmclomv_sysinfo_data, 6573db86aabSstevel sizeof (rmclomv_sysinfo_data)); 6583db86aabSstevel 6593db86aabSstevel rmclomv_sysinfo_valid = (sysinfo != NULL); 6603db86aabSstevel 6613db86aabSstevel RELEASE_CACHE 6623db86aabSstevel 6633db86aabSstevel while (first != NULL) { 6643db86aabSstevel next = first->next_section; 6653db86aabSstevel free_section(first); 6663db86aabSstevel first = next; 6673db86aabSstevel } 6683db86aabSstevel 6693db86aabSstevel while (sub_first != NULL) { 6703db86aabSstevel next = sub_first->next_section; 6713db86aabSstevel free_section(sub_first); 6723db86aabSstevel sub_first = next; 6733db86aabSstevel } 6743db86aabSstevel } 6753db86aabSstevel 6763db86aabSstevel /* 6773db86aabSstevel * cache must be locked before calling rmclomv_find_section 6783db86aabSstevel */ 6793db86aabSstevel static rmclomv_cache_section_t * 6803db86aabSstevel rmclomv_find_section(rmclomv_cache_section_t *start, uint16_t sensor) 6813db86aabSstevel { 6823db86aabSstevel rmclomv_cache_section_t *next = start; 6833db86aabSstevel 6843db86aabSstevel while ((next != NULL) && (next->sensor_type != sensor)) 6853db86aabSstevel next = next->next_section; 6863db86aabSstevel 6873db86aabSstevel return (next); 6883db86aabSstevel } 6893db86aabSstevel 6903db86aabSstevel /* 6913db86aabSstevel * Return a string presenting the keyswitch position 6923db86aabSstevel * For unknown values returns "Unknown" 6933db86aabSstevel */ 6943db86aabSstevel static char * 6953db86aabSstevel rmclomv_key_position(enum rmc_keyswitch_pos pos) 6963db86aabSstevel { 6973db86aabSstevel switch (pos) { 6983db86aabSstevel 6993db86aabSstevel case RMC_KEYSWITCH_POS_NORMAL: 7003db86aabSstevel return ("NORMAL"); 7013db86aabSstevel case RMC_KEYSWITCH_POS_DIAG: 7023db86aabSstevel return ("DIAG"); 7033db86aabSstevel case RMC_KEYSWITCH_POS_LOCKED: 7043db86aabSstevel return ("LOCKED"); 7053db86aabSstevel case RMC_KEYSWITCH_POS_OFF: 7063db86aabSstevel return ("STBY"); 7073db86aabSstevel default: 7083db86aabSstevel return ("UNKNOWN"); 7093db86aabSstevel } 7103db86aabSstevel } 7113db86aabSstevel 7123db86aabSstevel /* 7133db86aabSstevel * The sensor id name is sought in the supplied section and if found 7143db86aabSstevel * its index within the section is written to *index. 7153db86aabSstevel * Return value is zero for success, otherwise -1. 7163db86aabSstevel * The cache must be locked before calling get_sensor_by_name 7173db86aabSstevel */ 7183db86aabSstevel static int 7193db86aabSstevel get_sensor_by_name(const rmclomv_cache_section_t *section, 7203db86aabSstevel const char *name, int *index) 7213db86aabSstevel { 7223db86aabSstevel int i; 7233db86aabSstevel 7243db86aabSstevel for (i = 0; i < section->num_entries; i++) { 7253db86aabSstevel if (strcmp(name, section->entry[i].handle_name.name) == 0) { 7263db86aabSstevel *index = i; 7273db86aabSstevel return (0); 7283db86aabSstevel } 7293db86aabSstevel } 7303db86aabSstevel 7313db86aabSstevel *index = 0; 7323db86aabSstevel return (-1); 7333db86aabSstevel } 7343db86aabSstevel 7353db86aabSstevel /* 7363db86aabSstevel * fills in the envmon_handle name 7373db86aabSstevel * if it is unknown (not cached), the dp_handle_t is returned as a hex-digit 7383db86aabSstevel * string 7393db86aabSstevel */ 7403db86aabSstevel static void 7413db86aabSstevel rmclomv_hdl_to_envhdl(dp_handle_t hdl, envmon_handle_t *envhdl) 7423db86aabSstevel { 7433db86aabSstevel rmclomv_cache_section_t *next; 7443db86aabSstevel int i; 7453db86aabSstevel 7463db86aabSstevel LOCK_CACHE 7473db86aabSstevel 7483db86aabSstevel for (next = rmclomv_cache; next != NULL; next = next->next_section) { 7493db86aabSstevel for (i = 0; i < next->num_entries; i++) { 7503db86aabSstevel if (next->entry[i].handle == hdl) { 7513db86aabSstevel *envhdl = next->entry[i].handle_name; 7523db86aabSstevel RELEASE_CACHE 7533db86aabSstevel return; 7543db86aabSstevel } 7553db86aabSstevel } 7563db86aabSstevel } 7573db86aabSstevel 7583db86aabSstevel /* 7593db86aabSstevel * Sought handle not currently cached. 7603db86aabSstevel */ 7613db86aabSstevel RELEASE_CACHE 7623db86aabSstevel 7633db86aabSstevel (void) snprintf(envhdl->name, sizeof (envhdl->name), 7643db86aabSstevel "Unknown SC node 0x%x", hdl); 7653db86aabSstevel } 7663db86aabSstevel 7673db86aabSstevel static void 7683db86aabSstevel rmclomv_dr_data_handler(const char *fru_name, int hint) 7693db86aabSstevel { 7703db86aabSstevel int err = 0; 7713db86aabSstevel nvlist_t *attr_list; 7723db86aabSstevel char attach_pnt[MAXPATHLEN]; 7733db86aabSstevel 7743db86aabSstevel (void) snprintf(attach_pnt, sizeof (attach_pnt), "%s", fru_name); 7753db86aabSstevel 7763db86aabSstevel err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP); 7773db86aabSstevel if (err != 0) { 7783db86aabSstevel cmn_err(CE_WARN, 7793db86aabSstevel "Failed to allocate name-value list for %s event", EC_DR); 7803db86aabSstevel return; 7813db86aabSstevel } 7823db86aabSstevel 7833db86aabSstevel err = nvlist_add_string(attr_list, DR_AP_ID, attach_pnt); 7843db86aabSstevel if (err != 0) { 7853db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s event", 7863db86aabSstevel DR_AP_ID, EC_DR); 7873db86aabSstevel nvlist_free(attr_list); 7883db86aabSstevel return; 7893db86aabSstevel } 7903db86aabSstevel 7913db86aabSstevel /* 7923db86aabSstevel * Add the hint 7933db86aabSstevel */ 7943db86aabSstevel err = nvlist_add_string(attr_list, DR_HINT, SE_HINT2STR(hint)); 7953db86aabSstevel if (err != 0) { 7963db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s event", 7973db86aabSstevel DR_HINT, EC_DR); 7983db86aabSstevel nvlist_free(attr_list); 7993db86aabSstevel return; 8003db86aabSstevel } 8013db86aabSstevel 8023db86aabSstevel err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_DR, 8033db86aabSstevel ESC_DR_AP_STATE_CHANGE, attr_list, NULL, DDI_NOSLEEP); 8043db86aabSstevel if (err != 0) { 8053db86aabSstevel cmn_err(CE_WARN, "Failed to log %s/%s event", 8063db86aabSstevel DR_AP_ID, EC_DR); 8073db86aabSstevel } 8083db86aabSstevel 8093db86aabSstevel nvlist_free(attr_list); 8103db86aabSstevel } 8113db86aabSstevel 8123db86aabSstevel static void 8133db86aabSstevel fan_sysevent(char *fru_name, char *sensor_name, int sub_event) 8143db86aabSstevel { 8153db86aabSstevel nvlist_t *attr_list; 8163db86aabSstevel char fan_str[MAXNAMELEN]; 8173db86aabSstevel int err; 8183db86aabSstevel 8193db86aabSstevel err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP); 8203db86aabSstevel if (err != 0) { 8213db86aabSstevel cmn_err(CE_WARN, 8223db86aabSstevel "Failed to allocate name-value list for %s/%s event", 8233db86aabSstevel EC_ENV, ESC_ENV_FAN); 8243db86aabSstevel return; 8253db86aabSstevel } 8263db86aabSstevel 8273db86aabSstevel err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name); 8283db86aabSstevel if (err != 0) { 8293db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 8303db86aabSstevel ENV_FRU_ID, EC_ENV, ESC_ENV_FAN); 8313db86aabSstevel nvlist_free(attr_list); 8323db86aabSstevel return; 8333db86aabSstevel } 8343db86aabSstevel 8353db86aabSstevel err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name); 8363db86aabSstevel if (err != 0) { 8373db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 8383db86aabSstevel ENV_FRU_RESOURCE_ID, EC_ENV, ESC_ENV_FAN); 8393db86aabSstevel nvlist_free(attr_list); 8403db86aabSstevel return; 8413db86aabSstevel } 8423db86aabSstevel 8433db86aabSstevel err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR); 8443db86aabSstevel if (err != 0) { 8453db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 8463db86aabSstevel ENV_FRU_DEVICE, EC_ENV, ESC_ENV_FAN); 8473db86aabSstevel nvlist_free(attr_list); 8483db86aabSstevel return; 8493db86aabSstevel } 8503db86aabSstevel 8513db86aabSstevel err = nvlist_add_int32(attr_list, ENV_FRU_STATE, 8523db86aabSstevel (sub_event == RMC_ENV_FAULT_EVENT) ? ENV_FAILED : ENV_OK); 8533db86aabSstevel if (err != 0) { 8543db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 8553db86aabSstevel ENV_FRU_STATE, EC_ENV, ESC_ENV_FAN); 8563db86aabSstevel nvlist_free(attr_list); 8573db86aabSstevel return; 8583db86aabSstevel } 8593db86aabSstevel 8603db86aabSstevel if (sub_event == RMC_ENV_FAULT_EVENT) { 8613db86aabSstevel (void) snprintf(fan_str, sizeof (fan_str), 8623db86aabSstevel "fan %s/%s is now failed", fru_name, sensor_name); 8633db86aabSstevel } else { 8643db86aabSstevel (void) snprintf(fan_str, sizeof (fan_str), 8653db86aabSstevel "fan %s/%s is now ok", fru_name, sensor_name); 8663db86aabSstevel } 8673db86aabSstevel err = nvlist_add_string(attr_list, ENV_MSG, fan_str); 8683db86aabSstevel if (err != 0) { 8693db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 8703db86aabSstevel ENV_MSG, EC_ENV, ESC_ENV_FAN); 8713db86aabSstevel nvlist_free(attr_list); 8723db86aabSstevel return; 8733db86aabSstevel } 8743db86aabSstevel 8753db86aabSstevel err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV, 8763db86aabSstevel ESC_ENV_FAN, attr_list, NULL, DDI_NOSLEEP); 8773db86aabSstevel if (err != 0) { 8783db86aabSstevel cmn_err(CE_WARN, "Failed to log %s/%s event", 8793db86aabSstevel EC_ENV, ESC_ENV_FAN); 8803db86aabSstevel } 8813db86aabSstevel 8823db86aabSstevel cmn_err(CE_NOTE, "%s", fan_str); 8833db86aabSstevel nvlist_free(attr_list); 8843db86aabSstevel } 8853db86aabSstevel 8863db86aabSstevel static void 8873db86aabSstevel threshold_sysevent(char *fru_name, char *sensor_name, int sub_event, 8883db86aabSstevel char event_type) 8893db86aabSstevel { 8903db86aabSstevel nvlist_t *attr_list; 8913db86aabSstevel int err; 8923db86aabSstevel char *subclass; 8933db86aabSstevel char sensor_str[MAXNAMELEN]; 8943db86aabSstevel 8953db86aabSstevel subclass = (event_type == 'T') ? ESC_ENV_TEMP : ESC_ENV_POWER; 8963db86aabSstevel 8973db86aabSstevel err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP); 8983db86aabSstevel if (err != 0) { 8993db86aabSstevel cmn_err(CE_WARN, 9003db86aabSstevel "Failed to allocate name-value list for %s/%s event", 9013db86aabSstevel EC_ENV, subclass); 9023db86aabSstevel return; 9033db86aabSstevel } 9043db86aabSstevel 9053db86aabSstevel err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name); 9063db86aabSstevel if (err != 0) { 9073db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 9083db86aabSstevel ENV_FRU_ID, EC_ENV, subclass); 9093db86aabSstevel nvlist_free(attr_list); 9103db86aabSstevel return; 9113db86aabSstevel } 9123db86aabSstevel 9133db86aabSstevel err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name); 9143db86aabSstevel if (err != 0) { 9153db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 9163db86aabSstevel ENV_FRU_RESOURCE_ID, EC_ENV, subclass); 9173db86aabSstevel nvlist_free(attr_list); 9183db86aabSstevel return; 9193db86aabSstevel } 9203db86aabSstevel 9213db86aabSstevel err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR); 9223db86aabSstevel if (err != 0) { 9233db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 9243db86aabSstevel ENV_FRU_DEVICE, EC_ENV, subclass); 9253db86aabSstevel nvlist_free(attr_list); 9263db86aabSstevel return; 9273db86aabSstevel } 9283db86aabSstevel 9293db86aabSstevel switch (sub_event) { 9303db86aabSstevel case RMC_ENV_OK_EVENT: 9313db86aabSstevel err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_OK); 9323db86aabSstevel break; 9333db86aabSstevel case RMC_ENV_WARNING_THRESHOLD_EVENT: 9343db86aabSstevel err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_WARNING); 9353db86aabSstevel break; 9363db86aabSstevel case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT: 9373db86aabSstevel err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_FAILED); 9383db86aabSstevel break; 9393db86aabSstevel } 9403db86aabSstevel if (err != 0) { 9413db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 9423db86aabSstevel ENV_FRU_STATE, EC_ENV, subclass); 9433db86aabSstevel nvlist_free(attr_list); 9443db86aabSstevel return; 9453db86aabSstevel } 9463db86aabSstevel 9473db86aabSstevel switch (sub_event) { 9483db86aabSstevel case RMC_ENV_OK_EVENT: 9493db86aabSstevel (void) snprintf(sensor_str, sizeof (sensor_str), 9503db86aabSstevel "sensor %s/%s is now ok", fru_name, 9513db86aabSstevel sensor_name); 9523db86aabSstevel break; 9533db86aabSstevel case RMC_ENV_WARNING_THRESHOLD_EVENT: 9543db86aabSstevel (void) snprintf(sensor_str, sizeof (sensor_str), 9553db86aabSstevel "sensor %s/%s is now outside warning thresholds", fru_name, 9563db86aabSstevel sensor_name); 9573db86aabSstevel break; 9583db86aabSstevel case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT: 9593db86aabSstevel (void) snprintf(sensor_str, sizeof (sensor_str), 9603db86aabSstevel "sensor %s/%s is now outside shutdown thresholds", fru_name, 9613db86aabSstevel sensor_name); 9623db86aabSstevel break; 9633db86aabSstevel } 9643db86aabSstevel err = nvlist_add_string(attr_list, ENV_MSG, sensor_str); 9653db86aabSstevel if (err != 0) { 9663db86aabSstevel cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 9673db86aabSstevel ENV_MSG, EC_ENV, subclass); 9683db86aabSstevel nvlist_free(attr_list); 9693db86aabSstevel return; 9703db86aabSstevel } 9713db86aabSstevel 9723db86aabSstevel err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV, 9733db86aabSstevel subclass, attr_list, NULL, DDI_NOSLEEP); 9743db86aabSstevel if (err != 0) { 9753db86aabSstevel cmn_err(CE_WARN, "Failed to log %s/%s event", 9763db86aabSstevel EC_ENV, subclass); 9773db86aabSstevel } 9783db86aabSstevel 9793db86aabSstevel cmn_err(CE_NOTE, "%s", sensor_str); 9803db86aabSstevel nvlist_free(attr_list); 9813db86aabSstevel } 9823db86aabSstevel 9833db86aabSstevel static uint_t 9843db86aabSstevel rmclomv_event_data_handler(char *arg) 9853db86aabSstevel { 9863db86aabSstevel dp_event_notification_t *payload; 9873db86aabSstevel rmc_comm_msg_t *msg; 9883db86aabSstevel envmon_handle_t envhdl; 9893db86aabSstevel int hint; 9903db86aabSstevel char *ptr, *save_ptr; 9913db86aabSstevel 9923db86aabSstevel if (arg == NULL) { 9933db86aabSstevel return (DDI_INTR_CLAIMED); 9943db86aabSstevel } 9953db86aabSstevel 9963db86aabSstevel msg = (rmc_comm_msg_t *)arg; 9973db86aabSstevel if (msg->msg_buf == NULL) { 9983db86aabSstevel return (DDI_INTR_CLAIMED); 9993db86aabSstevel } 10003db86aabSstevel 10013db86aabSstevel payload = (dp_event_notification_t *)msg->msg_buf; 10023db86aabSstevel switch (payload->event) { 10033db86aabSstevel 10043db86aabSstevel case RMC_KEYSWITCH_EVENT: 10053db86aabSstevel real_key_position = payload->event_info.ev_keysw.key_position; 10063db86aabSstevel cmn_err(CE_NOTE, "keyswitch change event - state = %s", 10073db86aabSstevel rmclomv_key_position(real_key_position)); 10083db86aabSstevel if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) && 10093db86aabSstevel (real_key_position <= RMC_KEYSWITCH_POS_OFF)) { 10103db86aabSstevel key_position = real_key_position; 10113db86aabSstevel } else { 10123db86aabSstevel /* treat unknown key position as locked */ 10133db86aabSstevel key_position = RMC_KEYSWITCH_POS_LOCKED; 10143db86aabSstevel } 10153db86aabSstevel break; 10163db86aabSstevel 10173db86aabSstevel case RMC_HPU_EVENT: 10183db86aabSstevel /* 10193db86aabSstevel * send appropriate sysevent 10203db86aabSstevel */ 10213db86aabSstevel switch (payload->event_info.ev_hpunot.sub_event) { 10223db86aabSstevel case RMC_HPU_REMOVE_EVENT: 10233db86aabSstevel hint = SE_HINT_REMOVE; 10243db86aabSstevel break; 10253db86aabSstevel case RMC_HPU_INSERT_EVENT: 10263db86aabSstevel hint = SE_HINT_INSERT; 10273db86aabSstevel break; 10283db86aabSstevel default: 10293db86aabSstevel hint = SE_NO_HINT; 10303db86aabSstevel break; 10313db86aabSstevel } 10323db86aabSstevel rmclomv_hdl_to_envhdl(payload->event_info.ev_hpunot.hpu_hdl, 10333db86aabSstevel &envhdl); 10343db86aabSstevel rmclomv_dr_data_handler(envhdl.name, hint); 10353db86aabSstevel break; 10363db86aabSstevel 10373db86aabSstevel case RMC_INIT_EVENT: 10383db86aabSstevel /* 10393db86aabSstevel * Wake up the refresh thread. 10403db86aabSstevel */ 10413db86aabSstevel rmclomv_refresh_wakeup(); 10423db86aabSstevel 10433db86aabSstevel /* 10443db86aabSstevel * Wake up the checkrmc thread for an early indication to PICL 10453db86aabSstevel */ 10463db86aabSstevel rmclomv_checkrmc_wakeup(NULL); 10473db86aabSstevel break; 10483db86aabSstevel 10493db86aabSstevel case RMC_ENV_EVENT: 10503db86aabSstevel rmclomv_hdl_to_envhdl(payload->event_info.ev_envnot.env_hdl, 10513db86aabSstevel &envhdl); 10523db86aabSstevel 10533db86aabSstevel /* split name into fru name and sensor name */ 10543db86aabSstevel ptr = strchr(envhdl.name, '.'); 10553db86aabSstevel 10563db86aabSstevel /* must have at least one '.' */ 10573db86aabSstevel if (ptr == NULL) 10583db86aabSstevel break; 10593db86aabSstevel 10603db86aabSstevel /* find last '.' - convert the others to '/' */ 10613db86aabSstevel for (;;) { 10623db86aabSstevel save_ptr = ptr; 10633db86aabSstevel ptr = strchr(ptr, '.'); 10643db86aabSstevel if (ptr == NULL) { 10653db86aabSstevel ptr = save_ptr; 10663db86aabSstevel break; 10673db86aabSstevel } 10683db86aabSstevel *save_ptr = '/'; 10693db86aabSstevel } 10703db86aabSstevel *ptr = '\0'; 10713db86aabSstevel ptr++; 10723db86aabSstevel /* is it a voltage or temperature sensor? */ 10733db86aabSstevel if ((*ptr == 'V' || *ptr == 'T') && *(ptr + 1) == '_') { 10743db86aabSstevel switch (payload->event_info.ev_envnot.sub_event) { 10753db86aabSstevel case RMC_ENV_WARNING_THRESHOLD_EVENT: 10763db86aabSstevel case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT: 10773db86aabSstevel case RMC_ENV_OK_EVENT: 10783db86aabSstevel threshold_sysevent(envhdl.name, ptr, 10793db86aabSstevel payload->event_info.ev_envnot.sub_event, 10803db86aabSstevel *ptr); 10813db86aabSstevel break; 10823db86aabSstevel default: 10833db86aabSstevel break; 10843db86aabSstevel } 10853db86aabSstevel } 10863db86aabSstevel 10873db86aabSstevel /* 10883db86aabSstevel * is it a fan sensor? 10893db86aabSstevel * Fan sensor names end either in RS, F0 or F1 10903db86aabSstevel */ 10913db86aabSstevel if ((*ptr == 'R' && *(ptr + 1) == 'S' && *(ptr + 2) == '\0') || 10923db86aabSstevel (*ptr == 'F' && *(ptr + 1) == '0' && *(ptr + 2) == '\0') || 10933db86aabSstevel (*ptr == 'F' && *(ptr + 1) == '1' && *(ptr + 2) == '\0')) { 10943db86aabSstevel switch (payload->event_info.ev_envnot.sub_event) { 10953db86aabSstevel case RMC_ENV_FAULT_EVENT: 10963db86aabSstevel case RMC_ENV_OK_EVENT: 10973db86aabSstevel fan_sysevent(envhdl.name, ptr, 10983db86aabSstevel payload->event_info.ev_envnot.sub_event); 10993db86aabSstevel break; 11003db86aabSstevel default: 11013db86aabSstevel break; 11023db86aabSstevel } 11033db86aabSstevel } 11043db86aabSstevel break; 11053db86aabSstevel 11063db86aabSstevel case RMC_LOG_EVENT: 11073db86aabSstevel { 11083db86aabSstevel int level = 10; 11093db86aabSstevel int flags = SL_NOTE | SL_CONSOLE; 11103db86aabSstevel char *message = 11113db86aabSstevel (char *)payload->event_info.ev_rmclog.log_record; 11123db86aabSstevel 11133db86aabSstevel message[ payload->event_info.ev_rmclog.log_record_size] = '\0'; 11143db86aabSstevel 11153db86aabSstevel /* 11163db86aabSstevel * Logs have a 10 character prefix - specifying the severity of 11173db86aabSstevel * the event being logged. Thus all the magic number 10s down 11183db86aabSstevel * here 11193db86aabSstevel */ 11203db86aabSstevel if (0 == strncmp("CRITICAL: ", message, 10)) { 11213db86aabSstevel message += 10; 11223db86aabSstevel level = 0; 11233db86aabSstevel flags = SL_FATAL | SL_ERROR | SL_CONSOLE; 11243db86aabSstevel } else if (0 == strncmp("MAJOR: ", message, 10)) { 11253db86aabSstevel message += 10; 11263db86aabSstevel level = 5; 11273db86aabSstevel flags = SL_WARN | SL_ERROR | SL_CONSOLE; 11283db86aabSstevel } else if (0 == strncmp("MINOR: ", message, 10)) { 11293db86aabSstevel message += 10; 11303db86aabSstevel level = 10; 11313db86aabSstevel flags = SL_NOTE | SL_CONSOLE; 11323db86aabSstevel } 11333db86aabSstevel 11343db86aabSstevel (void) strlog(0, 0, level, flags, message); 11353db86aabSstevel break; 11363db86aabSstevel } 11373db86aabSstevel 11383db86aabSstevel default: 11393db86aabSstevel return (DDI_INTR_CLAIMED); 11403db86aabSstevel } 11413db86aabSstevel 11423db86aabSstevel return (DDI_INTR_CLAIMED); 11433db86aabSstevel } 11443db86aabSstevel 11453db86aabSstevel /*ARGSUSED*/ 11463db86aabSstevel static int 11473db86aabSstevel rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 11483db86aabSstevel { 11493db86aabSstevel int error = 0; 11503db86aabSstevel int instance = getminor(*dev_p); 11513db86aabSstevel 11523db86aabSstevel if (instance != 0) 11533db86aabSstevel return (ENXIO); 11543db86aabSstevel 11553db86aabSstevel if ((flag & FWRITE) != 0 && (error = drv_priv(cred_p)) != 0) 11563db86aabSstevel return (error); 11573db86aabSstevel 11583db86aabSstevel return (0); 11593db86aabSstevel } 11603db86aabSstevel 11613db86aabSstevel /*ARGSUSED*/ 11623db86aabSstevel static int 11633db86aabSstevel rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 11643db86aabSstevel { 11653db86aabSstevel return (DDI_SUCCESS); 11663db86aabSstevel } 11673db86aabSstevel 11683db86aabSstevel static int 11693db86aabSstevel rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len, intptr_t arg_req, 11703db86aabSstevel intptr_t arg_res) 11713db86aabSstevel { 11723db86aabSstevel rmc_comm_msg_t request, *reqp = &request; 11733db86aabSstevel rmc_comm_msg_t response, *resp = &response; 11743db86aabSstevel int rv = 0; 11753db86aabSstevel 11763db86aabSstevel bzero((caddr_t)&request, sizeof (request)); 11773db86aabSstevel reqp->msg_type = req_cmd; 11783db86aabSstevel reqp->msg_buf = (caddr_t)arg_req; 11793db86aabSstevel bzero((caddr_t)&response, sizeof (response)); 11803db86aabSstevel resp->msg_type = resp_cmd; 11813db86aabSstevel resp->msg_buf = (caddr_t)arg_res; 11823db86aabSstevel resp->msg_len = resp_len; 11833db86aabSstevel 11843db86aabSstevel switch (req_cmd) { 11853db86aabSstevel case DP_GET_SYSINFO: 11863db86aabSstevel resp->msg_len = sizeof (dp_get_sysinfo_r_t); 11873db86aabSstevel break; 11883db86aabSstevel case DP_GET_EVENT_LOG: 11893db86aabSstevel resp->msg_len = sizeof (dp_get_event_log_r_t); 11903db86aabSstevel break; 11913db86aabSstevel case DP_GET_VOLTS: 11923db86aabSstevel reqp->msg_len = sizeof (dp_get_volts_t); 11933db86aabSstevel break; 11943db86aabSstevel case DP_GET_TEMPERATURES: 11953db86aabSstevel reqp->msg_len = sizeof (dp_get_temperatures_t); 11963db86aabSstevel break; 11973db86aabSstevel case DP_GET_CIRCUIT_BRKS: 11983db86aabSstevel reqp->msg_len = sizeof (dp_get_circuit_brks_t); 11993db86aabSstevel break; 12003db86aabSstevel case DP_GET_FAN_STATUS: 12013db86aabSstevel reqp->msg_len = sizeof (dp_get_fan_status_t); 12023db86aabSstevel break; 12033db86aabSstevel case DP_GET_PSU_STATUS: 12043db86aabSstevel reqp->msg_len = sizeof (dp_get_psu_status_t); 12053db86aabSstevel break; 12063db86aabSstevel case DP_GET_LED_STATE: 12073db86aabSstevel reqp->msg_len = sizeof (dp_get_led_state_t); 12083db86aabSstevel break; 12093db86aabSstevel case DP_SET_LED_STATE: 12103db86aabSstevel reqp->msg_len = sizeof (dp_set_led_state_t); 12113db86aabSstevel break; 12123db86aabSstevel case DP_GET_FRU_STATUS: 12133db86aabSstevel reqp->msg_len = sizeof (dp_get_fru_status_t); 12143db86aabSstevel break; 12153db86aabSstevel case DP_GET_HANDLE_NAME: 12163db86aabSstevel reqp->msg_len = sizeof (dp_get_handle_name_t); 12173db86aabSstevel break; 12183db86aabSstevel case DP_GET_ALARM_STATE: 12193db86aabSstevel reqp->msg_len = sizeof (dp_get_alarm_state_t); 12203db86aabSstevel break; 12213db86aabSstevel case DP_SET_ALARM_STATE: 12223db86aabSstevel reqp->msg_len = sizeof (dp_set_alarm_state_t); 12233db86aabSstevel break; 12243db86aabSstevel case DP_GET_SDP_VERSION: 12253db86aabSstevel resp->msg_len = sizeof (dp_get_sdp_version_r_t); 12263db86aabSstevel break; 12273db86aabSstevel case DP_GET_CHASSIS_SERIALNUM: 12283db86aabSstevel reqp->msg_len = 0; 12293db86aabSstevel break; 12303db86aabSstevel case DP_GET_DATE_TIME: 12313db86aabSstevel reqp->msg_len = 0; 12323db86aabSstevel break; 12333db86aabSstevel default: 12343db86aabSstevel return (EINVAL); 12353db86aabSstevel } 12363db86aabSstevel 12373db86aabSstevel rv = rmc_comm_request_response(reqp, resp, 12383db86aabSstevel RMCLOMV_DEFAULT_MAX_MBOX_WAIT_TIME); 12393db86aabSstevel 12403db86aabSstevel if (rv != RCNOERR) { 12413db86aabSstevel /* 12423db86aabSstevel * RMC returned an error or failed to respond. 12433db86aabSstevel * Where the RMC itself is implicated, rmclomv_rmc_error 12443db86aabSstevel * is set non-zero. It is cleared after an error free exchange. 12453db86aabSstevel * Two failure cases are distinguished: 12463db86aabSstevel * RMCLOMV_RMCSTATE_FAILED and RMCLOMV_RMCSTATE_DOWNLOAD. 12473db86aabSstevel */ 12483db86aabSstevel switch (rv) { 12493db86aabSstevel case RCENOSOFTSTATE: 12503db86aabSstevel /* invalid/NULL soft state structure */ 12513db86aabSstevel return (EIO); 12523db86aabSstevel case RCENODATALINK: 12533db86aabSstevel /* 12543db86aabSstevel * firmware download in progress, 12553db86aabSstevel * can you come back later? 12563db86aabSstevel */ 12573db86aabSstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_DOWNLOAD; 12583db86aabSstevel rmclomv_rmc_state = RMCLOMV_RMCSTATE_DOWNLOAD; 12593db86aabSstevel return (EAGAIN); 12603db86aabSstevel case RCENOMEM: 12613db86aabSstevel /* memory problems */ 12623db86aabSstevel return (ENOMEM); 12633db86aabSstevel case RCECANTRESEND: 12643db86aabSstevel /* resend failed */ 12653db86aabSstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 12663db86aabSstevel return (EIO); 12673db86aabSstevel case RCEMAXRETRIES: 12683db86aabSstevel /* reply not received - retries exceeded */ 12693db86aabSstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 12703db86aabSstevel return (EINTR); 12713db86aabSstevel case RCETIMEOUT: 12723db86aabSstevel /* reply not received - command has timed out */ 12733db86aabSstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 12743db86aabSstevel return (EINTR); 12753db86aabSstevel case RCEINVCMD: 12763db86aabSstevel /* data protocol cmd not supported */ 12773db86aabSstevel return (ENOTSUP); 12783db86aabSstevel case RCEINVARG: 12793db86aabSstevel /* invalid argument(s) */ 12803db86aabSstevel return (ENOTSUP); 12813db86aabSstevel case RCEGENERIC: 12823db86aabSstevel /* generic error */ 12833db86aabSstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 12843db86aabSstevel return (EIO); 12853db86aabSstevel default: 12863db86aabSstevel rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 12873db86aabSstevel return (EIO); 12883db86aabSstevel } 12893db86aabSstevel } 12903db86aabSstevel 12913db86aabSstevel rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE; 12923db86aabSstevel return (0); 12933db86aabSstevel } 12943db86aabSstevel 12953db86aabSstevel /* 12963db86aabSstevel * validate_section_entry checks that the entry at the specified index 12973db86aabSstevel * is valid and not duplicated by an entry above. If these tests fail 12983db86aabSstevel * the entry is removed and B_FALSE returned. Otherwise returns B_TRUE. 12993db86aabSstevel */ 13003db86aabSstevel static int 13013db86aabSstevel validate_section_entry(rmclomv_cache_section_t *section, int index) 13023db86aabSstevel { 13033db86aabSstevel int i; 13043db86aabSstevel rmclomv_cache_entry_t *entry; 13053db86aabSstevel 13063db86aabSstevel for (i = index; i < section->num_entries; i++) { 13073db86aabSstevel entry = §ion->entry[i]; 13083db86aabSstevel if (entry->handle_name.name[0] == '\0') { 13093db86aabSstevel cmn_err(CE_WARN, 13103db86aabSstevel "rmclomv: empty handle_name, handle 0x%x type %x", 13113db86aabSstevel entry->handle, section->sensor_type); 13123db86aabSstevel } else if (entry->ind_mask != 0) { 13133db86aabSstevel continue; /* skip special entries */ 13143db86aabSstevel } else if (entry->handle == DP_NULL_HANDLE) { 13153db86aabSstevel cmn_err(CE_WARN, 13163db86aabSstevel "rmclomv: null handle id for \"%s\" type %x", 13173db86aabSstevel entry->handle_name.name, section->sensor_type); 13183db86aabSstevel } else if (i == index) { 13193db86aabSstevel continue; 13203db86aabSstevel } else if (section->entry[index].handle == entry->handle) { 13213db86aabSstevel cmn_err(CE_WARN, 13223db86aabSstevel "rmclomv: duplicate handle 0x%x type %x", 13233db86aabSstevel entry->handle, section->sensor_type); 13243db86aabSstevel } else if (strcmp(entry->handle_name.name, 13253db86aabSstevel section->entry[index].handle_name.name) == 0) { 13263db86aabSstevel cmn_err(CE_WARN, 13273db86aabSstevel "rmclomv: duplicate handle_name \"%s\", " 13283db86aabSstevel "handle 0x%x type %x", entry->handle_name.name, 13293db86aabSstevel entry->handle, section->sensor_type); 13303db86aabSstevel } else 13313db86aabSstevel continue; 13323db86aabSstevel 13333db86aabSstevel /* 13343db86aabSstevel * need to remove the entry at index 13353db86aabSstevel */ 13363db86aabSstevel section->num_entries--; 13373db86aabSstevel 13383db86aabSstevel for (i = index; i < section->num_entries; i++) { 13393db86aabSstevel section->entry[i] = section->entry[i + 1]; 13403db86aabSstevel } 13413db86aabSstevel 13423db86aabSstevel return (B_FALSE); 13433db86aabSstevel } 13443db86aabSstevel 13453db86aabSstevel return (B_TRUE); 13463db86aabSstevel } 13473db86aabSstevel 13483db86aabSstevel /* 13493db86aabSstevel * Populate a section containing handles with corresponding names 13503db86aabSstevel * The supplied section structure must not be publically visible and the 13513db86aabSstevel * name cache must not be locked either (because RMC i/o is required). 13523db86aabSstevel * 13533db86aabSstevel * This is the place where a sanity check is applied. Entries containing 13543db86aabSstevel * duplicate handles, duplicate names or empty names are removed and the 13553db86aabSstevel * structure is compacted. As a result num_entries may be reduced. 13563db86aabSstevel */ 13573db86aabSstevel static int 13583db86aabSstevel add_names_to_section(rmclomv_cache_section_t *section) 13593db86aabSstevel { 13603db86aabSstevel int retval = 0; 13613db86aabSstevel int ditched = B_FALSE; 13623db86aabSstevel int index; 13633db86aabSstevel dp_get_handle_name_r_t handle_name_r; 13643db86aabSstevel rmclomv_cache_entry_t *entry; 13653db86aabSstevel 13663db86aabSstevel for (index = 0; index < section->num_entries; index++) { 13673db86aabSstevel entry = §ion->entry[index]; 13683db86aabSstevel if (entry->ind_mask != 0) 13693db86aabSstevel continue; /* skip special entries */ 13703db86aabSstevel handle_name_r.handle = entry->handle; 13713db86aabSstevel retval = rmclomv_do_cmd(DP_GET_HANDLE_NAME, 13723db86aabSstevel DP_GET_HANDLE_NAME_R, sizeof (handle_name_r), 13733db86aabSstevel (intptr_t)&handle_name_r, (intptr_t)&handle_name_r); 13743db86aabSstevel if (retval == 0) 13753db86aabSstevel bcopy(handle_name_r.name, 13763db86aabSstevel entry->handle_name.name, DP_MAX_HANDLE_NAME); 13773db86aabSstevel } 13783db86aabSstevel 13793db86aabSstevel /* 13803db86aabSstevel * now ditch invalid and duplicate entries 13813db86aabSstevel */ 13823db86aabSstevel for (index = 0; index < section->num_entries; index++) { 13833db86aabSstevel while (validate_section_entry(section, index) == B_FALSE) 13843db86aabSstevel ditched = B_TRUE; 13853db86aabSstevel } 13863db86aabSstevel 13873db86aabSstevel if (ditched) 13883db86aabSstevel cmn_err(CE_WARN, "Retaining %d nodes of type %d", 13893db86aabSstevel section->num_entries, section->sensor_type); 13903db86aabSstevel 13913db86aabSstevel return (retval); 13923db86aabSstevel } 13933db86aabSstevel 13943db86aabSstevel /* 13953db86aabSstevel * The supplied (PSU) cache section is traversed and entries are created 13963db86aabSstevel * for the individual indicators belonging to a PSU. These entries are 13973db86aabSstevel * placed in a private chain. The caller, subsequently acquires the 13983db86aabSstevel * cache lock and copies the chain head to make it public. 13993db86aabSstevel * The handle-names for PSU indicators are derived from the parent PSU 14003db86aabSstevel * handle-name. 14013db86aabSstevel * NOTE: add_names_to_section() may have reduced psu_section->num_entries 14023db86aabSstevel * so DON'T USE psu_resp->num_psus 14033db86aabSstevel */ 14043db86aabSstevel static void 14053db86aabSstevel make_psu_subsections(rmclomv_cache_section_t *psu_section, 14063db86aabSstevel rmclomv_cache_section_t **chain_head, dp_get_psu_status_r_t *psu_resp) 14073db86aabSstevel { 14083db86aabSstevel int index; 14093db86aabSstevel int subindex = 0; 14103db86aabSstevel rmclomv_cache_section_t *subsection; 14113db86aabSstevel rmclomv_cache_entry_t *src_entry; 14123db86aabSstevel rmclomv_cache_entry_t *dst_entry; 14133db86aabSstevel 14143db86aabSstevel subsection = create_cache_section(RMCLOMV_VOLT_IND, 14153db86aabSstevel RMCLOMV_MAX_VI_PER_PSU * psu_section->num_entries); 14163db86aabSstevel for (index = 0; index < psu_section->num_entries; index++) { 14173db86aabSstevel src_entry = &psu_section->entry[index]; 14183db86aabSstevel if ((psu_resp->psu_status[index].mask & 14193db86aabSstevel DP_PSU_INPUT_STATUS) != 0) { 14203db86aabSstevel dst_entry = &subsection->entry[subindex++]; 14213db86aabSstevel dst_entry->handle = src_entry->handle; 14223db86aabSstevel dst_entry->ind_mask = DP_PSU_INPUT_STATUS; 14233db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 14243db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 14253db86aabSstevel src_entry->handle_name.name, 14263db86aabSstevel str_ip_volts_ind); 14273db86aabSstevel } 14283db86aabSstevel 14293db86aabSstevel if ((psu_resp->psu_status[index].mask & 14303db86aabSstevel DP_PSU_SEC_INPUT_STATUS) != 0) { 14313db86aabSstevel dst_entry = &subsection->entry[subindex++]; 14323db86aabSstevel dst_entry->handle = src_entry->handle; 14333db86aabSstevel dst_entry->ind_mask = DP_PSU_SEC_INPUT_STATUS; 14343db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 14353db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 14363db86aabSstevel src_entry->handle_name.name, 14373db86aabSstevel str_ip2_volts_ind); 14383db86aabSstevel } 14393db86aabSstevel 14403db86aabSstevel if ((psu_resp->psu_status[index].mask & 14413db86aabSstevel DP_PSU_OUTPUT_STATUS) != 0) { 14423db86aabSstevel dst_entry = &subsection->entry[subindex++]; 14433db86aabSstevel dst_entry->handle = src_entry->handle; 14443db86aabSstevel dst_entry->ind_mask = DP_PSU_OUTPUT_STATUS; 14453db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 14463db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 14473db86aabSstevel src_entry->handle_name.name, 14483db86aabSstevel str_ff_pok_ind); 14493db86aabSstevel } 14503db86aabSstevel 14513db86aabSstevel if ((psu_resp->psu_status[index].mask & 14523db86aabSstevel DP_PSU_OUTPUT_VLO_STATUS) != 0) { 14533db86aabSstevel dst_entry = &subsection->entry[subindex++]; 14543db86aabSstevel dst_entry->handle = src_entry->handle; 14553db86aabSstevel dst_entry->ind_mask = DP_PSU_OUTPUT_VLO_STATUS; 14563db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 14573db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 14583db86aabSstevel src_entry->handle_name.name, 14593db86aabSstevel str_vlo_volts_ind); 14603db86aabSstevel } 14613db86aabSstevel 14623db86aabSstevel if ((psu_resp->psu_status[index].mask & 14633db86aabSstevel DP_PSU_OUTPUT_VHI_STATUS) != 0) { 14643db86aabSstevel dst_entry = &subsection->entry[subindex++]; 14653db86aabSstevel dst_entry->handle = src_entry->handle; 14663db86aabSstevel dst_entry->ind_mask = DP_PSU_OUTPUT_VHI_STATUS; 14673db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 14683db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 14693db86aabSstevel src_entry->handle_name.name, 14703db86aabSstevel str_vhi_volts_ind); 14713db86aabSstevel } 14723db86aabSstevel } 14733db86aabSstevel /* 14743db86aabSstevel * Adjust number of entries value in cache section 14753db86aabSstevel * to match the facts. 14763db86aabSstevel */ 14773db86aabSstevel subsection->num_entries = subindex; 14783db86aabSstevel add_section(chain_head, subsection); 14793db86aabSstevel 14803db86aabSstevel subsection = create_cache_section(RMCLOMV_AMP_IND, 14813db86aabSstevel RMCLOMV_MAX_CI_PER_PSU * psu_section->num_entries); 14823db86aabSstevel subindex = 0; 14833db86aabSstevel for (index = 0; index < psu_section->num_entries; index++) { 14843db86aabSstevel int mask = psu_resp->psu_status[index].mask; 14853db86aabSstevel src_entry = &psu_section->entry[index]; 14863db86aabSstevel if ((mask & DP_PSU_OUTPUT_AHI_STATUS) != 0) { 14873db86aabSstevel dst_entry = &subsection->entry[subindex++]; 14883db86aabSstevel dst_entry->handle = src_entry->handle; 14893db86aabSstevel dst_entry->ind_mask = DP_PSU_OUTPUT_AHI_STATUS; 14903db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 14913db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 14923db86aabSstevel src_entry->handle_name.name, 14933db86aabSstevel str_chi_amps_ind); 14943db86aabSstevel } 14953db86aabSstevel if ((mask & DP_PSU_NR_WARNING) != 0) { 14963db86aabSstevel dst_entry = &subsection->entry[subindex++]; 14973db86aabSstevel dst_entry->handle = src_entry->handle; 14983db86aabSstevel dst_entry->ind_mask = DP_PSU_NR_WARNING; 14993db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 15003db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 15013db86aabSstevel src_entry->handle_name.name, 15023db86aabSstevel str_chi_nr_ind); 15033db86aabSstevel } 15043db86aabSstevel } 15053db86aabSstevel subsection->num_entries = subindex; 15063db86aabSstevel add_section(chain_head, subsection); 15073db86aabSstevel 15083db86aabSstevel subsection = create_cache_section(RMCLOMV_TEMP_IND, 15093db86aabSstevel psu_section->num_entries); 15103db86aabSstevel subindex = 0; 15113db86aabSstevel for (index = 0; index < psu_section->num_entries; index++) { 15123db86aabSstevel if ((psu_resp->psu_status[index].mask & 15133db86aabSstevel DP_PSU_OVERTEMP_FAULT) != 0) { 15143db86aabSstevel src_entry = &psu_section->entry[index]; 15153db86aabSstevel dst_entry = &subsection->entry[subindex++]; 15163db86aabSstevel dst_entry->handle = src_entry->handle; 15173db86aabSstevel dst_entry->ind_mask = DP_PSU_OVERTEMP_FAULT; 15183db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 15193db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 15203db86aabSstevel src_entry->handle_name.name, 15213db86aabSstevel str_ot_tmpr_ind); 15223db86aabSstevel } 15233db86aabSstevel } 15243db86aabSstevel subsection->num_entries = subindex; 15253db86aabSstevel add_section(chain_head, subsection); 15263db86aabSstevel 15273db86aabSstevel subsection = create_cache_section(RMCLOMV_FAN_IND, 15283db86aabSstevel RMCLOMV_MAX_FI_PER_PSU * psu_section->num_entries); 15293db86aabSstevel subindex = 0; 15303db86aabSstevel for (index = 0; index < psu_section->num_entries; index++) { 15313db86aabSstevel int mask = psu_resp->psu_status[index].mask; 15323db86aabSstevel src_entry = &psu_section->entry[index]; 15333db86aabSstevel if ((mask & DP_PSU_FAN_FAULT) != 0) { 15343db86aabSstevel dst_entry = &subsection->entry[subindex++]; 15353db86aabSstevel dst_entry->handle = src_entry->handle; 15363db86aabSstevel dst_entry->ind_mask = DP_PSU_FAN_FAULT; 15373db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 15383db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 15393db86aabSstevel src_entry->handle_name.name, str_fan_ind); 15403db86aabSstevel } 15413db86aabSstevel if ((mask & DP_PSU_PDCT_FAN) != 0) { 15423db86aabSstevel dst_entry = &subsection->entry[subindex++]; 15433db86aabSstevel dst_entry->handle = src_entry->handle; 15443db86aabSstevel dst_entry->ind_mask = DP_PSU_PDCT_FAN; 15453db86aabSstevel (void) snprintf(dst_entry->handle_name.name, 15463db86aabSstevel ENVMON_MAXNAMELEN, "%s.%s", 15473db86aabSstevel src_entry->handle_name.name, str_pdct_fan_ind); 15483db86aabSstevel } 15493db86aabSstevel } 15503db86aabSstevel subsection->num_entries = subindex; 15513db86aabSstevel add_section(chain_head, subsection); 15523db86aabSstevel } 15533db86aabSstevel 15543db86aabSstevel static void 15553db86aabSstevel refresh_name_cache(int force_fail) 15563db86aabSstevel { 15573db86aabSstevel union { 15583db86aabSstevel dp_get_volts_t u_volts_cmd; 15593db86aabSstevel dp_get_temperatures_t u_temp_cmd; 15603db86aabSstevel dp_get_circuit_brks_t u_ampi_cmd; 15613db86aabSstevel dp_get_fan_status_t u_fan_cmd; 15623db86aabSstevel dp_get_psu_status_t u_psu_cmd; 15633db86aabSstevel dp_get_fru_status_t u_fru_cmd; 15643db86aabSstevel dp_get_led_state_t u_led_cmd; 15653db86aabSstevel dp_set_led_state_t u_setled_cmd; 15663db86aabSstevel dp_get_alarm_state_t u_alarm_cmd; 15673db86aabSstevel dp_set_alarm_state_t u_setalarm_cmd; 15683db86aabSstevel } rmc_cmdbuf; 15693db86aabSstevel 15703db86aabSstevel /* defines for accessing union fields */ 15713db86aabSstevel #define volts_cmd rmc_cmdbuf.u_volts_cmd 15723db86aabSstevel #define temp_cmd rmc_cmdbuf.u_temp_cmd 15733db86aabSstevel #define ampi_cmd rmc_cmdbuf.u_ampi_cmd 15743db86aabSstevel #define fan_cmd rmc_cmdbuf.u_fan_cmd 15753db86aabSstevel #define psu_cmd rmc_cmdbuf.u_psu_cmd 15763db86aabSstevel #define fru_cmd rmc_cmdbuf.u_fru_cmd 15773db86aabSstevel #define led_cmd rmc_cmdbuf.u_led_cmd 15783db86aabSstevel #define setled_cmd rmc_cmdbuf.u_setled_cmd 15793db86aabSstevel #define alarm_cmd rmc_cmdbuf.u_alarm_cmd 15803db86aabSstevel #define setalarm_cmd rmc_cmdbuf.u_setalarm_cmd 15813db86aabSstevel 15823db86aabSstevel /* 15833db86aabSstevel * Data area to read sensor data into 15843db86aabSstevel */ 15853db86aabSstevel static union { 15863db86aabSstevel char reservation[RMCRESBUFLEN]; 15873db86aabSstevel dp_get_volts_r_t u_volts_r; 15883db86aabSstevel dp_get_temperatures_r_t u_temp_r; 15893db86aabSstevel dp_get_circuit_brks_r_t u_ampi_r; 15903db86aabSstevel dp_get_fan_status_r_t u_fan_r; 15913db86aabSstevel dp_get_psu_status_r_t u_psu_r; 15923db86aabSstevel dp_get_fru_status_r_t u_fru_r; 15933db86aabSstevel dp_get_led_state_r_t u_led_r; 15943db86aabSstevel dp_set_led_state_r_t u_setled_r; 15953db86aabSstevel dp_get_alarm_state_r_t u_alarm_r; 15963db86aabSstevel dp_set_alarm_state_r_t u_setalarm_r; 15973db86aabSstevel } rmc_sensbuf; 15983db86aabSstevel 15993db86aabSstevel /* defines for accessing union fields */ 16003db86aabSstevel #define volts_r rmc_sensbuf.u_volts_r 16013db86aabSstevel #define temp_r rmc_sensbuf.u_temp_r 16023db86aabSstevel #define ampi_r rmc_sensbuf.u_ampi_r 16033db86aabSstevel #define fan_r rmc_sensbuf.u_fan_r 16043db86aabSstevel #define psu_r rmc_sensbuf.u_psu_r 16053db86aabSstevel #define fru_r rmc_sensbuf.u_fru_r 16063db86aabSstevel #define led_r rmc_sensbuf.u_led_r 16073db86aabSstevel #define setled_r rmc_sensbuf.u_setled_r 16083db86aabSstevel #define alarm_r rmc_sensbuf.u_alarm_r 16093db86aabSstevel #define setalarm_r rmc_sensbuf.u_setalarm_r 16103db86aabSstevel 16113db86aabSstevel int retval = force_fail; 16123db86aabSstevel int retval1 = retval; 16133db86aabSstevel int index; 16143db86aabSstevel rmclomv_cache_section_t *my_chain = NULL; 16153db86aabSstevel rmclomv_cache_section_t *derived_chain = NULL; 16163db86aabSstevel rmclomv_cache_section_t *section; 16173db86aabSstevel rmclomv_cache_section_t *psu_section; 16183db86aabSstevel rmclomv_cache_section_t *fru_section; 16193db86aabSstevel dp_get_sysinfo_r_t sysinfo; 16203db86aabSstevel rmclomv_cache_entry_t *entry; 16213db86aabSstevel 16223db86aabSstevel if (retval == 0) { 16233db86aabSstevel retval = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R, 16243db86aabSstevel sizeof (sysinfo), NULL, (intptr_t)&sysinfo); 16253db86aabSstevel } 16263db86aabSstevel if (retval == 0) { 16273db86aabSstevel fru_cmd.handle = DP_NULL_HANDLE; 16283db86aabSstevel retval = rmclomv_do_cmd(DP_GET_FRU_STATUS, DP_GET_FRU_STATUS_R, 16293db86aabSstevel RMCRESBUFLEN, (intptr_t)&fru_cmd, (intptr_t)&fru_r); 16303db86aabSstevel } 16313db86aabSstevel if (retval != 0) 16323db86aabSstevel fru_r.num_frus = 0; 16333db86aabSstevel 16343db86aabSstevel /* 16353db86aabSstevel * Reserve space for special additional entries in the FRU section 16363db86aabSstevel */ 16373db86aabSstevel fru_section = create_cache_section(RMCLOMV_HPU_IND, 16383db86aabSstevel RMCLOMV_NUM_SPECIAL_FRUS + fru_r.num_frus); 16393db86aabSstevel 16403db86aabSstevel /* 16413db86aabSstevel * add special entry for RMC itself 16423db86aabSstevel */ 16433db86aabSstevel entry = &fru_section->entry[0]; 16443db86aabSstevel (void) snprintf(entry->handle_name.name, sizeof (envmon_handle_t), 16453db86aabSstevel "SC"); 16463db86aabSstevel entry->handle = 0; 16473db86aabSstevel entry->ind_mask = 1; /* flag as a special entry */ 16483db86aabSstevel 16493db86aabSstevel /* 16503db86aabSstevel * populate any other FRU entries 16513db86aabSstevel */ 16523db86aabSstevel for (index = 0; index < fru_r.num_frus; index++) { 16533db86aabSstevel fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].handle = 16543db86aabSstevel fru_r.fru_status[index].handle; 16553db86aabSstevel fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].ind_mask = 16563db86aabSstevel 0; 16573db86aabSstevel } 16583db86aabSstevel 16593db86aabSstevel my_chain = fru_section; 16603db86aabSstevel 16613db86aabSstevel if (retval == 0) { 16623db86aabSstevel volts_cmd.handle = DP_NULL_HANDLE; 16633db86aabSstevel retval = rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R, 16643db86aabSstevel RMCRESBUFLEN, (intptr_t)&volts_cmd, (intptr_t)&volts_r); 16653db86aabSstevel } 16663db86aabSstevel if (retval == 0) { 16673db86aabSstevel section = create_cache_section(RMCLOMV_VOLT_SENS, 16683db86aabSstevel volts_r.num_volts); 16693db86aabSstevel for (index = 0; index < volts_r.num_volts; index++) { 16703db86aabSstevel section->entry[index].handle = 16713db86aabSstevel volts_r.volt_status[index].handle; 16723db86aabSstevel } 16733db86aabSstevel add_section(&my_chain, section); 16743db86aabSstevel } 16753db86aabSstevel if (retval == 0) { 16763db86aabSstevel temp_cmd.handle = DP_NULL_HANDLE; 16773db86aabSstevel retval = rmclomv_do_cmd(DP_GET_TEMPERATURES, 16783db86aabSstevel DP_GET_TEMPERATURES_R, RMCRESBUFLEN, 16793db86aabSstevel (intptr_t)&temp_cmd, (intptr_t)&temp_r); 16803db86aabSstevel } 16813db86aabSstevel if (retval == 0) { 16823db86aabSstevel section = create_cache_section(RMCLOMV_TEMP_SENS, 16833db86aabSstevel temp_r.num_temps); 16843db86aabSstevel for (index = 0; index < temp_r.num_temps; index++) { 16853db86aabSstevel section->entry[index].handle = 16863db86aabSstevel temp_r.temp_status[index].handle; 16873db86aabSstevel } 16883db86aabSstevel add_section(&my_chain, section); 16893db86aabSstevel } 16903db86aabSstevel if (retval == 0) { 16913db86aabSstevel fan_cmd.handle = DP_NULL_HANDLE; 16923db86aabSstevel retval = rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R, 16933db86aabSstevel RMCRESBUFLEN, (intptr_t)&fan_cmd, (intptr_t)&fan_r); 16943db86aabSstevel } 16953db86aabSstevel if (retval == 0) { 16963db86aabSstevel section = create_cache_section(RMCLOMV_FAN_SENS, 16973db86aabSstevel fan_r.num_fans); 16983db86aabSstevel for (index = 0; index < fan_r.num_fans; index++) { 16993db86aabSstevel section->entry[index].handle = 17003db86aabSstevel fan_r.fan_status[index].handle; 17013db86aabSstevel } 17023db86aabSstevel add_section(&my_chain, section); 17033db86aabSstevel } 17043db86aabSstevel if (retval == 0) { 17053db86aabSstevel ampi_cmd.handle = DP_NULL_HANDLE; 17063db86aabSstevel retval = rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS, 17073db86aabSstevel DP_GET_CIRCUIT_BRKS_R, RMCRESBUFLEN, 17083db86aabSstevel (intptr_t)&i_cmd, (intptr_t)&i_r); 17093db86aabSstevel } 17103db86aabSstevel if (retval == 0) { 17113db86aabSstevel section = create_cache_section(RMCLOMV_AMP_IND, 17123db86aabSstevel ampi_r.num_circuit_brks); 17133db86aabSstevel for (index = 0; index < ampi_r.num_circuit_brks; index++) { 17143db86aabSstevel section->entry[index].handle = 17153db86aabSstevel ampi_r.circuit_brk_status[index].handle; 17163db86aabSstevel } 17173db86aabSstevel add_section(&my_chain, section); 17183db86aabSstevel } 17193db86aabSstevel if (retval == 0) { 17203db86aabSstevel led_cmd.handle = DP_NULL_HANDLE; 17213db86aabSstevel retval = rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R, 17223db86aabSstevel RMCRESBUFLEN, (intptr_t)&led_cmd, (intptr_t)&led_r); 17233db86aabSstevel } 17243db86aabSstevel if (retval == 0) { 17253db86aabSstevel section = create_cache_section(RMCLOMV_LED_IND, 17263db86aabSstevel led_r.num_leds); 17273db86aabSstevel for (index = 0; index < led_r.num_leds; index++) { 17283db86aabSstevel section->entry[index].handle = 17293db86aabSstevel led_r.led_state[index].handle; 17303db86aabSstevel } 17313db86aabSstevel add_section(&my_chain, section); 17323db86aabSstevel } 17333db86aabSstevel /* 17343db86aabSstevel * The command DP_GET_ALARM_STATE may not be valid on 17353db86aabSstevel * some RMC versions, so we ignore the return value 17363db86aabSstevel * and proceed 17373db86aabSstevel */ 17383db86aabSstevel if (retval == 0) { 17393db86aabSstevel alarm_cmd.handle = DP_NULL_HANDLE; 17403db86aabSstevel retval1 = rmclomv_do_cmd(DP_GET_ALARM_STATE, 17413db86aabSstevel DP_GET_ALARM_STATE_R, RMCRESBUFLEN, 17423db86aabSstevel (intptr_t)&alarm_cmd, (intptr_t)&alarm_r); 17433db86aabSstevel if ((retval1 == 0) && alarm_r.num_alarms) { 17443db86aabSstevel section = create_cache_section(RMCLOMV_ALARM_IND, 17453db86aabSstevel alarm_r.num_alarms); 17463db86aabSstevel for (index = 0; index < alarm_r.num_alarms; index++) { 17473db86aabSstevel section->entry[index].handle = 17483db86aabSstevel alarm_r.alarm_state[index].handle; 17493db86aabSstevel } 17503db86aabSstevel add_section(&my_chain, section); 17513db86aabSstevel } 17523db86aabSstevel } 17533db86aabSstevel if (retval == 0) { 17543db86aabSstevel psu_cmd.handle = DP_NULL_HANDLE; 17553db86aabSstevel retval = rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R, 17563db86aabSstevel RMCRESBUFLEN, (intptr_t)&psu_cmd, (intptr_t)&psu_r); 17573db86aabSstevel } 17583db86aabSstevel if (retval == 0) { 17593db86aabSstevel /* 17603db86aabSstevel * WARNING: 17613db86aabSstevel * ======= 17623db86aabSstevel * The PSUs must be probed last so that the response data 17633db86aabSstevel * (psu_r) is available for make_psu_subsections() below. 17643db86aabSstevel * Note that all the responses share the same data area 17653db86aabSstevel * which is declared as a union. 17663db86aabSstevel */ 17673db86aabSstevel psu_section = create_cache_section(RMCLOMV_PSU_IND, 17683db86aabSstevel psu_r.num_psus); 17693db86aabSstevel for (index = 0; index < psu_r.num_psus; index++) { 17703db86aabSstevel psu_section->entry[index].handle = 17713db86aabSstevel psu_r.psu_status[index].handle; 17723db86aabSstevel } 17733db86aabSstevel add_section(&my_chain, psu_section); 17743db86aabSstevel } 17753db86aabSstevel if (retval == 0) { 17763db86aabSstevel for (section = my_chain; 17773db86aabSstevel section != NULL; 17783db86aabSstevel section = section->next_section) { 17793db86aabSstevel retval = add_names_to_section(section); 17803db86aabSstevel if (retval != 0) { 17813db86aabSstevel break; 17823db86aabSstevel } 17833db86aabSstevel } 17843db86aabSstevel } 17853db86aabSstevel 17863db86aabSstevel /* 17873db86aabSstevel * now add nodes derived from PSUs 17883db86aabSstevel */ 17893db86aabSstevel if (retval == 0) { 17903db86aabSstevel make_psu_subsections(psu_section, &derived_chain, &psu_r); 17913db86aabSstevel /* 17923db86aabSstevel * name cache sections all set, exchange new for old 17933db86aabSstevel */ 17943db86aabSstevel rmclomv_reset_cache(my_chain, derived_chain, &sysinfo); 17953db86aabSstevel } else { 17963db86aabSstevel /* 17973db86aabSstevel * RMC is not responding, ditch any existing cache 17983db86aabSstevel * and just leave the special SC FRU node 17993db86aabSstevel */ 18003db86aabSstevel rmclomv_reset_cache(my_chain, NULL, NULL); 18013db86aabSstevel } 18023db86aabSstevel } 18033db86aabSstevel 18043db86aabSstevel static void 18053db86aabSstevel set_val_unav(envmon_sensor_t *sensor) 18063db86aabSstevel { 18073db86aabSstevel sensor->value = ENVMON_VAL_UNAVAILABLE; 18083db86aabSstevel sensor->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE; 18093db86aabSstevel sensor->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE; 18103db86aabSstevel sensor->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE; 18113db86aabSstevel sensor->highthresholds.warning = ENVMON_VAL_UNAVAILABLE; 18123db86aabSstevel sensor->highthresholds.shutdown = ENVMON_VAL_UNAVAILABLE; 18133db86aabSstevel sensor->highthresholds.poweroff = ENVMON_VAL_UNAVAILABLE; 18143db86aabSstevel } 18153db86aabSstevel 18163db86aabSstevel static void 18173db86aabSstevel set_fan_unav(envmon_fan_t *fan) 18183db86aabSstevel { 18193db86aabSstevel fan->speed = ENVMON_VAL_UNAVAILABLE; 18203db86aabSstevel fan->units[0] = '\0'; 18213db86aabSstevel fan->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE; 18223db86aabSstevel fan->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE; 18233db86aabSstevel fan->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE; 18243db86aabSstevel } 18253db86aabSstevel 18263db86aabSstevel static int 18273db86aabSstevel do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind, 18283db86aabSstevel dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r, 18293db86aabSstevel int detector_type) 18303db86aabSstevel { 18313db86aabSstevel int index; 18323db86aabSstevel uint16_t sensor_status; 18333db86aabSstevel rmclomv_cache_section_t *section; 18343db86aabSstevel uint16_t indicator_mask; 18353db86aabSstevel 18363db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)env_ind, 18373db86aabSstevel sizeof (envmon_indicator_t), mode) != 0) 18383db86aabSstevel return (EFAULT); 18393db86aabSstevel 18403db86aabSstevel /* ensure we've got PSU handles cached */ 18413db86aabSstevel LOCK_CACHE 18423db86aabSstevel 18433db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 18443db86aabSstevel section = rmclomv_find_section(rmclomv_subcache, detector_type); 18453db86aabSstevel if (env_ind->id.name[0] == '\0') { 18463db86aabSstevel /* request for first handle */ 18473db86aabSstevel if ((section == NULL) || (section->num_entries == 0)) 18483db86aabSstevel env_ind->next_id.name[0] = '\0'; 18493db86aabSstevel else 18503db86aabSstevel env_ind->next_id = section->entry[0].handle_name; 18513db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 18523db86aabSstevel } else { 18533db86aabSstevel /* ensure name is properly terminated */ 18543db86aabSstevel env_ind->id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 18553db86aabSstevel if ((section == NULL) || (get_sensor_by_name(section, 18563db86aabSstevel env_ind->id.name, &index)) != 0) { 18573db86aabSstevel env_ind->next_id.name[0] = '\0'; 18583db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 18593db86aabSstevel } else if (index + 1 < section->num_entries) 18603db86aabSstevel env_ind->next_id = 18613db86aabSstevel section->entry[index + 1].handle_name; 18623db86aabSstevel else 18633db86aabSstevel env_ind->next_id.name[0] = '\0'; 18643db86aabSstevel } 18653db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 18663db86aabSstevel /* 18673db86aabSstevel * user correctly identified a sensor, note its 18683db86aabSstevel * handle value and request the indicator status 18693db86aabSstevel */ 18703db86aabSstevel rmc_psu->handle = section->entry[index].handle; 18713db86aabSstevel indicator_mask = section->entry[index].ind_mask; 18723db86aabSstevel } 18733db86aabSstevel 18743db86aabSstevel RELEASE_CACHE 18753db86aabSstevel 18763db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 18773db86aabSstevel rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R, 18783db86aabSstevel sizeof (dp_get_psu_status_r_t), (intptr_t)rmc_psu, 18793db86aabSstevel (intptr_t)rmc_psu_r) != 0)) { 18803db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 18813db86aabSstevel } 18823db86aabSstevel if ((env_ind->sensor_status = sensor_status) == ENVMON_SENSOR_OK) { 18833db86aabSstevel /* 18843db86aabSstevel * copy results into buffer for user 18853db86aabSstevel */ 18863db86aabSstevel if ((rmc_psu_r->psu_status[0].flag & DP_PSU_PRESENCE) == 0) 18873db86aabSstevel env_ind->sensor_status |= ENVMON_NOT_PRESENT; 18883db86aabSstevel if (rmc_psu_r->psu_status[0].sensor_status != 18893db86aabSstevel DP_SENSOR_DATA_AVAILABLE) 18903db86aabSstevel env_ind->sensor_status |= ENVMON_INACCESSIBLE; 18913db86aabSstevel env_ind->condition = 18923db86aabSstevel (rmc_psu_r->psu_status[0].flag & indicator_mask) == 0 ? 18933db86aabSstevel 0 : 1; 18943db86aabSstevel } 18953db86aabSstevel 18963db86aabSstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) 18973db86aabSstevel env_ind->sensor_status = ENVMON_INACCESSIBLE; 18983db86aabSstevel 18993db86aabSstevel if (ddi_copyout((caddr_t)env_ind, (caddr_t)arg, 19003db86aabSstevel sizeof (envmon_indicator_t), mode) != 0) 19013db86aabSstevel return (EFAULT); 19023db86aabSstevel 19033db86aabSstevel return (0); 19043db86aabSstevel } 19053db86aabSstevel 19063db86aabSstevel /*ARGSUSED*/ 19073db86aabSstevel static int 19083db86aabSstevel rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 19093db86aabSstevel int *rval_p) 19103db86aabSstevel { 19113db86aabSstevel int instance = getminor(dev); 19123db86aabSstevel envmon_sysinfo_t lomv_sysinfo; 19133db86aabSstevel union { 19143db86aabSstevel envmon_sensor_t u_env_sensor; 19153db86aabSstevel envmon_indicator_t u_env_ind; 19163db86aabSstevel envmon_fan_t u_env_fan; 19173db86aabSstevel envmon_led_info_t u_env_ledinfo; 19183db86aabSstevel envmon_led_ctl_t u_env_ledctl; 19193db86aabSstevel envmon_hpu_t u_env_hpu; 19203db86aabSstevel envmon_alarm_info_t u_env_alarminfo; 19213db86aabSstevel envmon_alarm_ctl_t u_env_alarmctl; 19223db86aabSstevel } env_buf; 19233db86aabSstevel #define env_sensor env_buf.u_env_sensor 19243db86aabSstevel #define env_ind env_buf.u_env_ind 19253db86aabSstevel #define env_fan env_buf.u_env_fan 19263db86aabSstevel #define env_ledinfo env_buf.u_env_ledinfo 19273db86aabSstevel #define env_ledctl env_buf.u_env_ledctl 19283db86aabSstevel #define env_hpu env_buf.u_env_hpu 19293db86aabSstevel #define env_alarminfo env_buf.u_env_alarminfo 19303db86aabSstevel #define env_alarmctl env_buf.u_env_alarmctl 19313db86aabSstevel 19323db86aabSstevel union { 19333db86aabSstevel dp_get_volts_t u_rmc_volts; 19343db86aabSstevel dp_get_temperatures_t u_rmc_temp; 19353db86aabSstevel dp_get_circuit_brks_t u_rmc_ampi; 19363db86aabSstevel dp_get_fan_status_t u_rmc_fan; 19373db86aabSstevel dp_get_psu_status_t u_rmc_psu; 19383db86aabSstevel dp_get_fru_status_t u_rmc_fru; 19393db86aabSstevel dp_get_led_state_t u_rmc_led; 19403db86aabSstevel dp_set_led_state_t u_rmc_setled; 19413db86aabSstevel dp_get_alarm_state_t u_rmc_alarm; 19423db86aabSstevel dp_set_alarm_state_t u_rmc_setalarm; 19433db86aabSstevel } rmc_reqbuf; 19443db86aabSstevel #define rmc_volts rmc_reqbuf.u_rmc_volts 19453db86aabSstevel #define rmc_temp rmc_reqbuf.u_rmc_temp 19463db86aabSstevel #define rmc_ampi rmc_reqbuf.u_rmc_ampi 19473db86aabSstevel #define rmc_fan rmc_reqbuf.u_rmc_fan 19483db86aabSstevel #define rmc_psu rmc_reqbuf.u_rmc_psu 19493db86aabSstevel #define rmc_fru rmc_reqbuf.u_rmc_fru 19503db86aabSstevel #define rmc_led rmc_reqbuf.u_rmc_led 19513db86aabSstevel #define rmc_setled rmc_reqbuf.u_rmc_setled 19523db86aabSstevel #define rmc_alarm rmc_reqbuf.u_rmc_alarm 19533db86aabSstevel #define rmc_setalarm rmc_reqbuf.u_rmc_setalarm 19543db86aabSstevel 19553db86aabSstevel union { 19563db86aabSstevel dp_get_volts_r_t u_rmc_volts_r; 19573db86aabSstevel dp_get_temperatures_r_t u_rmc_temp_r; 19583db86aabSstevel dp_get_circuit_brks_r_t u_rmc_ampi_r; 19593db86aabSstevel dp_get_fan_status_r_t u_rmc_fan_r; 19603db86aabSstevel dp_get_psu_status_r_t u_rmc_psu_r; 19613db86aabSstevel dp_get_fru_status_r_t u_rmc_fru_r; 19623db86aabSstevel dp_get_led_state_r_t u_rmc_led_r; 19633db86aabSstevel dp_set_led_state_r_t u_rmc_setled_r; 19643db86aabSstevel dp_get_alarm_state_r_t u_rmc_alarm_r; 19653db86aabSstevel dp_set_alarm_state_r_t u_rmc_setalarm_r; 19663db86aabSstevel dp_get_sdp_version_r_t u_rmc_sdpversion_r; 19673db86aabSstevel dp_get_serialnum_r_t u_rmc_serialnum_r; 19683db86aabSstevel } rmc_resbuf; 19693db86aabSstevel #define rmc_volts_r rmc_resbuf.u_rmc_volts_r 19703db86aabSstevel #define rmc_temp_r rmc_resbuf.u_rmc_temp_r 19713db86aabSstevel #define rmc_ampi_r rmc_resbuf.u_rmc_ampi_r 19723db86aabSstevel #define rmc_fan_r rmc_resbuf.u_rmc_fan_r 19733db86aabSstevel #define rmc_psu_r rmc_resbuf.u_rmc_psu_r 19743db86aabSstevel #define rmc_fru_r rmc_resbuf.u_rmc_fru_r 19753db86aabSstevel #define rmc_led_r rmc_resbuf.u_rmc_led_r 19763db86aabSstevel #define rmc_setled_r rmc_resbuf.u_rmc_setled_r 19773db86aabSstevel #define rmc_alarm_r rmc_resbuf.u_rmc_alarm_r 19783db86aabSstevel #define rmc_setalarm_r rmc_resbuf.u_rmc_setalarm_r 19793db86aabSstevel #define rmc_sdpver_r rmc_resbuf.u_rmc_sdpversion_r 19803db86aabSstevel #define rmc_serialnum_r rmc_resbuf.u_rmc_serialnum_r 19813db86aabSstevel 19823db86aabSstevel int retval = 0; 19833db86aabSstevel int special = 0; 19843db86aabSstevel int index; 19853db86aabSstevel uint16_t sensor_status; 19863db86aabSstevel rmclomv_cache_section_t *section; 19873db86aabSstevel envmon_chassis_t chassis; 19883db86aabSstevel 19893db86aabSstevel if (instance != 0) 19903db86aabSstevel return (ENXIO); 19913db86aabSstevel 19923db86aabSstevel switch (cmd) { 19933db86aabSstevel case ENVMONIOCSYSINFO: 19943db86aabSstevel 19953db86aabSstevel LOCK_CACHE 19963db86aabSstevel 19973db86aabSstevel /* 19983db86aabSstevel * A number of OK/not_OK indicators are supported by PSUs 19993db86aabSstevel * (voltage, current, fan, temperature). So the maximum 20003db86aabSstevel * number of such indicators relates to the maximum number 20013db86aabSstevel * of power-supplies. 20023db86aabSstevel */ 20033db86aabSstevel if (rmclomv_sysinfo_valid) { 20043db86aabSstevel lomv_sysinfo.maxVoltSens = rmclomv_sysinfo_data.maxVolt; 20053db86aabSstevel lomv_sysinfo.maxVoltInd = 20063db86aabSstevel RMCLOMV_MAX_VI_PER_PSU * 20073db86aabSstevel rmclomv_sysinfo_data.maxPSU; 20083db86aabSstevel /* 20093db86aabSstevel * the ALOM-Solaris interface does not include 20103db86aabSstevel * amp sensors, so we can hard code this value 20113db86aabSstevel */ 20123db86aabSstevel lomv_sysinfo.maxAmpSens = 0; 20133db86aabSstevel lomv_sysinfo.maxAmpInd = 20143db86aabSstevel rmclomv_sysinfo_data.maxCircuitBrks + 20153db86aabSstevel (RMCLOMV_MAX_CI_PER_PSU * 20163db86aabSstevel rmclomv_sysinfo_data.maxPSU); 20173db86aabSstevel lomv_sysinfo.maxTempSens = rmclomv_sysinfo_data.maxTemp; 20183db86aabSstevel lomv_sysinfo.maxTempInd = 20193db86aabSstevel (RMCLOMV_MAX_TI_PER_PSU * 20203db86aabSstevel rmclomv_sysinfo_data.maxPSU); 20213db86aabSstevel lomv_sysinfo.maxFanSens = rmclomv_sysinfo_data.maxFan; 20223db86aabSstevel lomv_sysinfo.maxFanInd = 20233db86aabSstevel RMCLOMV_MAX_FI_PER_PSU * 20243db86aabSstevel rmclomv_sysinfo_data.maxPSU; 20253db86aabSstevel lomv_sysinfo.maxLED = rmclomv_sysinfo_data.maxLED; 20263db86aabSstevel lomv_sysinfo.maxHPU = RMCLOMV_NUM_SPECIAL_FRUS + 20273db86aabSstevel rmclomv_sysinfo_data.maxFRU; 20283db86aabSstevel } else { 20293db86aabSstevel bzero(&lomv_sysinfo, sizeof (lomv_sysinfo)); 20303db86aabSstevel lomv_sysinfo.maxHPU = 1; /* just the SC node */ 20313db86aabSstevel } 20323db86aabSstevel 20333db86aabSstevel RELEASE_CACHE 20343db86aabSstevel 20353db86aabSstevel if (ddi_copyout((caddr_t)&lomv_sysinfo, (caddr_t)arg, 20363db86aabSstevel sizeof (lomv_sysinfo), mode) != 0) 20373db86aabSstevel return (EFAULT); 20383db86aabSstevel break; 20393db86aabSstevel 20403db86aabSstevel case ENVMONIOCVOLTSENSOR: 20413db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor, 20423db86aabSstevel sizeof (envmon_sensor_t), mode) != 0) 20433db86aabSstevel return (EFAULT); 20443db86aabSstevel 20453db86aabSstevel /* see if we've got volts handles cached */ 20463db86aabSstevel LOCK_CACHE 20473db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 20483db86aabSstevel 20493db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 20503db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 20513db86aabSstevel RMCLOMV_VOLT_SENS)) == NULL)) { 20523db86aabSstevel env_sensor.next_id.name[0] = '\0'; 20533db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 20543db86aabSstevel } else if (env_sensor.id.name[0] == '\0') { 20553db86aabSstevel /* request for first handle */ 20563db86aabSstevel if (section->num_entries == 0) 20573db86aabSstevel env_sensor.next_id.name[0] = '\0'; 20583db86aabSstevel else 20593db86aabSstevel env_sensor.next_id = 20603db86aabSstevel section->entry[0].handle_name; 20613db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 20623db86aabSstevel } else { 20633db86aabSstevel /* ensure name is properly terminated */ 20643db86aabSstevel env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 20653db86aabSstevel if (get_sensor_by_name(section, env_sensor.id.name, 20663db86aabSstevel &index) != 0) { 20673db86aabSstevel env_sensor.next_id.name[0] = '\0'; 20683db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 20693db86aabSstevel } else if (index + 1 < section->num_entries) 20703db86aabSstevel env_sensor.next_id = 20713db86aabSstevel section->entry[index + 1].handle_name; 20723db86aabSstevel else 20733db86aabSstevel env_sensor.next_id.name[0] = '\0'; 20743db86aabSstevel } 20753db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 20763db86aabSstevel /* 20773db86aabSstevel * user correctly identified a sensor, note its 20783db86aabSstevel * handle value and request the sensor value 20793db86aabSstevel */ 20803db86aabSstevel rmc_volts.handle = section->entry[index].handle; 20813db86aabSstevel } 20823db86aabSstevel RELEASE_CACHE 20833db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 20843db86aabSstevel rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R, 20853db86aabSstevel sizeof (rmc_volts_r), (intptr_t)&rmc_volts, 20863db86aabSstevel (intptr_t)&rmc_volts_r) != 0)) { 20873db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 20883db86aabSstevel } 20893db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && 20903db86aabSstevel (rmc_volts_r.volt_status[0].sensor_status == 20913db86aabSstevel DP_SENSOR_NOT_PRESENT)) { 20923db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 20933db86aabSstevel } 20943db86aabSstevel if ((env_sensor.sensor_status = sensor_status) == 20953db86aabSstevel ENVMON_SENSOR_OK) { 20963db86aabSstevel /* 20973db86aabSstevel * copy results into buffer for user 20983db86aabSstevel */ 20993db86aabSstevel if (rmc_volts_r.volt_status[0].sensor_status != 21003db86aabSstevel DP_SENSOR_DATA_AVAILABLE) 21013db86aabSstevel env_sensor.sensor_status = ENVMON_INACCESSIBLE; 21023db86aabSstevel env_sensor.value = 21033db86aabSstevel rmc_volts_r.volt_status[0].reading; 21043db86aabSstevel env_sensor.lowthresholds.warning = 21053db86aabSstevel rmc_volts_r.volt_status[0].low_warning; 21063db86aabSstevel env_sensor.lowthresholds.shutdown = 21073db86aabSstevel rmc_volts_r.volt_status[0].low_soft_shutdown; 21083db86aabSstevel env_sensor.lowthresholds.poweroff = 21093db86aabSstevel rmc_volts_r.volt_status[0].low_hard_shutdown; 21103db86aabSstevel env_sensor.highthresholds.warning = 21113db86aabSstevel rmc_volts_r.volt_status[0].high_warning; 21123db86aabSstevel env_sensor.highthresholds.shutdown = 21133db86aabSstevel rmc_volts_r.volt_status[0].high_soft_shutdown; 21143db86aabSstevel env_sensor.highthresholds.poweroff = 21153db86aabSstevel rmc_volts_r.volt_status[0].high_hard_shutdown; 21163db86aabSstevel } 21173db86aabSstevel if (env_sensor.sensor_status != ENVMON_SENSOR_OK || 21183db86aabSstevel rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) 21193db86aabSstevel set_val_unav(&env_sensor); 21203db86aabSstevel 21213db86aabSstevel if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg, 21223db86aabSstevel sizeof (envmon_sensor_t), mode) != 0) 21233db86aabSstevel return (EFAULT); 21243db86aabSstevel break; 21253db86aabSstevel 21263db86aabSstevel case ENVMONIOCVOLTIND: 21273db86aabSstevel return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r, 21283db86aabSstevel RMCLOMV_VOLT_IND)); 21293db86aabSstevel 21303db86aabSstevel case ENVMONIOCTEMPIND: 21313db86aabSstevel return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r, 21323db86aabSstevel RMCLOMV_TEMP_IND)); 21333db86aabSstevel 21343db86aabSstevel case ENVMONIOCFANIND: 21353db86aabSstevel return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r, 21363db86aabSstevel RMCLOMV_FAN_IND)); 21373db86aabSstevel 21383db86aabSstevel case ENVMONIOCAMPSENSOR: 21393db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor, 21403db86aabSstevel sizeof (envmon_sensor_t), mode) != 0) 21413db86aabSstevel return (EFAULT); 21423db86aabSstevel 21433db86aabSstevel env_sensor.sensor_status = ENVMON_NOT_PRESENT; 21443db86aabSstevel env_sensor.next_id.name[0] = '\0'; 21453db86aabSstevel 21463db86aabSstevel if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg, 21473db86aabSstevel sizeof (envmon_sensor_t), mode) != 0) 21483db86aabSstevel return (EFAULT); 21493db86aabSstevel break; 21503db86aabSstevel 21513db86aabSstevel case ENVMONIOCTEMPSENSOR: 21523db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor, 21533db86aabSstevel sizeof (envmon_sensor_t), mode) != 0) 21543db86aabSstevel return (EFAULT); 21553db86aabSstevel 21563db86aabSstevel /* see if we've got temperature handles cached */ 21573db86aabSstevel LOCK_CACHE 21583db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 21593db86aabSstevel 21603db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 21613db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 21623db86aabSstevel RMCLOMV_TEMP_SENS)) == NULL)) { 21633db86aabSstevel env_sensor.next_id.name[0] = '\0'; 21643db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 21653db86aabSstevel } else if (env_sensor.id.name[0] == '\0') { 21663db86aabSstevel /* request for first handle */ 21673db86aabSstevel if (section->num_entries == 0) 21683db86aabSstevel env_sensor.next_id.name[0] = '\0'; 21693db86aabSstevel else 21703db86aabSstevel env_sensor.next_id = 21713db86aabSstevel section->entry[0].handle_name; 21723db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 21733db86aabSstevel } else { 21743db86aabSstevel /* ensure name is properly terminated */ 21753db86aabSstevel env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 21763db86aabSstevel if (get_sensor_by_name(section, env_sensor.id.name, 21773db86aabSstevel &index) != 0) { 21783db86aabSstevel env_sensor.next_id.name[0] = '\0'; 21793db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 21803db86aabSstevel } else if (index + 1 < section->num_entries) 21813db86aabSstevel env_sensor.next_id = 21823db86aabSstevel section->entry[index + 1].handle_name; 21833db86aabSstevel else 21843db86aabSstevel env_sensor.next_id.name[0] = '\0'; 21853db86aabSstevel } 21863db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 21873db86aabSstevel /* 21883db86aabSstevel * user correctly identified a sensor, note its 21893db86aabSstevel * handle value and request the sensor value 21903db86aabSstevel */ 21913db86aabSstevel rmc_temp.handle = section->entry[index].handle; 21923db86aabSstevel } 21933db86aabSstevel RELEASE_CACHE 21943db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 21953db86aabSstevel rmclomv_do_cmd(DP_GET_TEMPERATURES, DP_GET_TEMPERATURES_R, 21963db86aabSstevel sizeof (rmc_temp_r), (intptr_t)&rmc_temp, 21973db86aabSstevel (intptr_t)&rmc_temp_r) != 0)) { 21983db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 21993db86aabSstevel } 22003db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && 22013db86aabSstevel (rmc_temp_r.temp_status[0].sensor_status == 22023db86aabSstevel DP_SENSOR_NOT_PRESENT)) { 22033db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 22043db86aabSstevel } 22053db86aabSstevel if ((env_sensor.sensor_status = sensor_status) == 22063db86aabSstevel ENVMON_SENSOR_OK) { 22073db86aabSstevel /* 22083db86aabSstevel * copy results into buffer for user 22093db86aabSstevel */ 22103db86aabSstevel if (rmc_temp_r.temp_status[0].sensor_status != 22113db86aabSstevel DP_SENSOR_DATA_AVAILABLE) 22123db86aabSstevel env_sensor.sensor_status = ENVMON_INACCESSIBLE; 22133db86aabSstevel env_sensor.value = 22143db86aabSstevel rmc_temp_r.temp_status[0].value; 22153db86aabSstevel env_sensor.lowthresholds.warning = 22163db86aabSstevel rmc_temp_r.temp_status[0].low_warning; 22173db86aabSstevel env_sensor.lowthresholds.shutdown = 22183db86aabSstevel rmc_temp_r.temp_status[0].low_soft_shutdown; 22193db86aabSstevel env_sensor.lowthresholds.poweroff = 22203db86aabSstevel rmc_temp_r.temp_status[0].low_hard_shutdown; 22213db86aabSstevel env_sensor.highthresholds.warning = 22223db86aabSstevel rmc_temp_r.temp_status[0].high_warning; 22233db86aabSstevel env_sensor.highthresholds.shutdown = 22243db86aabSstevel rmc_temp_r.temp_status[0].high_soft_shutdown; 22253db86aabSstevel env_sensor.highthresholds.poweroff = 22263db86aabSstevel rmc_temp_r.temp_status[0].high_hard_shutdown; 22273db86aabSstevel } 22283db86aabSstevel if (env_sensor.sensor_status != ENVMON_SENSOR_OK || 22293db86aabSstevel rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) 22303db86aabSstevel set_val_unav(&env_sensor); 22313db86aabSstevel 22323db86aabSstevel if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg, 22333db86aabSstevel sizeof (envmon_sensor_t), mode) != 0) 22343db86aabSstevel return (EFAULT); 22353db86aabSstevel break; 22363db86aabSstevel 22373db86aabSstevel 22383db86aabSstevel case ENVMONIOCFAN: 22393db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_fan, 22403db86aabSstevel sizeof (envmon_fan_t), mode) != 0) 22413db86aabSstevel return (EFAULT); 22423db86aabSstevel 22433db86aabSstevel /* see if we've got fan handles cached */ 22443db86aabSstevel LOCK_CACHE 22453db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 22463db86aabSstevel 22473db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 22483db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 22493db86aabSstevel RMCLOMV_FAN_SENS)) == NULL)) { 22503db86aabSstevel env_fan.next_id.name[0] = '\0'; 22513db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 22523db86aabSstevel } else if (env_fan.id.name[0] == '\0') { 22533db86aabSstevel /* request for first handle */ 22543db86aabSstevel if (section->num_entries == 0) 22553db86aabSstevel env_fan.next_id.name[0] = '\0'; 22563db86aabSstevel else 22573db86aabSstevel env_fan.next_id = 22583db86aabSstevel section->entry[0].handle_name; 22593db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 22603db86aabSstevel } else { 22613db86aabSstevel /* ensure name is properly terminated */ 22623db86aabSstevel env_fan.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 22633db86aabSstevel if (get_sensor_by_name(section, env_fan.id.name, 22643db86aabSstevel &index) != 0) { 22653db86aabSstevel env_fan.next_id.name[0] = '\0'; 22663db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 22673db86aabSstevel } else if (index + 1 < section->num_entries) 22683db86aabSstevel env_fan.next_id = 22693db86aabSstevel section->entry[index + 1].handle_name; 22703db86aabSstevel else 22713db86aabSstevel env_fan.next_id.name[0] = '\0'; 22723db86aabSstevel } 22733db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 22743db86aabSstevel /* 22753db86aabSstevel * user correctly identified a sensor, note its 22763db86aabSstevel * handle value and request the sensor value 22773db86aabSstevel */ 22783db86aabSstevel rmc_fan.handle = section->entry[index].handle; 22793db86aabSstevel } 22803db86aabSstevel RELEASE_CACHE 22813db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 22823db86aabSstevel rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R, 22833db86aabSstevel sizeof (rmc_fan_r), (intptr_t)&rmc_fan, 22843db86aabSstevel (intptr_t)&rmc_fan_r) != 0)) { 22853db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 22863db86aabSstevel } 22873db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && 22883db86aabSstevel (rmc_fan_r.fan_status[0].sensor_status == 22893db86aabSstevel DP_SENSOR_NOT_PRESENT)) { 22903db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 22913db86aabSstevel } 22923db86aabSstevel if ((env_fan.sensor_status = sensor_status) == 22933db86aabSstevel ENVMON_SENSOR_OK) { 22943db86aabSstevel if ((rmc_fan_r.fan_status[0].flag & 22953db86aabSstevel DP_FAN_PRESENCE) == 0) 22963db86aabSstevel env_fan.sensor_status = ENVMON_NOT_PRESENT; 22973db86aabSstevel if (rmc_fan_r.fan_status[0].sensor_status != 22983db86aabSstevel DP_SENSOR_DATA_AVAILABLE) 22993db86aabSstevel env_fan.sensor_status |= ENVMON_INACCESSIBLE; 23003db86aabSstevel if (env_fan.sensor_status == ENVMON_SENSOR_OK) { 23013db86aabSstevel /* 23023db86aabSstevel * copy results into buffer for user 23033db86aabSstevel */ 23043db86aabSstevel env_fan.speed = 23053db86aabSstevel rmc_fan_r.fan_status[0].speed; 23063db86aabSstevel env_fan.lowthresholds.warning = 23073db86aabSstevel rmc_fan_r.fan_status[0].minspeed; 23083db86aabSstevel env_fan.lowthresholds.shutdown = 23093db86aabSstevel ENVMON_VAL_UNAVAILABLE; 23103db86aabSstevel env_fan.lowthresholds.poweroff = 23113db86aabSstevel ENVMON_VAL_UNAVAILABLE; 23123db86aabSstevel if ((rmc_fan_r.fan_status[0].flag & 23133db86aabSstevel DP_FAN_SPEED_VAL_UNIT) == 0) 23143db86aabSstevel bcopy(str_rpm, env_fan.units, 23153db86aabSstevel sizeof (str_rpm)); 23163db86aabSstevel else 23173db86aabSstevel bcopy(str_percent, env_fan.units, 23183db86aabSstevel sizeof (str_percent)); 23193db86aabSstevel } 23203db86aabSstevel } 23213db86aabSstevel if (env_fan.sensor_status != ENVMON_SENSOR_OK || 23223db86aabSstevel rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) 23233db86aabSstevel set_fan_unav(&env_fan); 23243db86aabSstevel 23253db86aabSstevel if (ddi_copyout((caddr_t)&env_fan, (caddr_t)arg, 23263db86aabSstevel sizeof (envmon_fan_t), mode) != 0) 23273db86aabSstevel return (EFAULT); 23283db86aabSstevel break; 23293db86aabSstevel 23303db86aabSstevel case ENVMONIOCAMPIND: 23313db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ind, 23323db86aabSstevel sizeof (envmon_indicator_t), mode) != 0) 23333db86aabSstevel return (EFAULT); 23343db86aabSstevel 23353db86aabSstevel /* see if we've got amp indicator handles cached */ 23363db86aabSstevel LOCK_CACHE 23373db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 23383db86aabSstevel 23393db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 23403db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 23413db86aabSstevel RMCLOMV_AMP_IND)) == NULL)) { 23423db86aabSstevel RELEASE_CACHE 23433db86aabSstevel return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, 23443db86aabSstevel &rmc_psu_r, RMCLOMV_AMP_IND)); 23453db86aabSstevel } else if (env_ind.id.name[0] == '\0') { 23463db86aabSstevel /* request for first handle */ 23473db86aabSstevel if (section->num_entries == 0) { 23483db86aabSstevel RELEASE_CACHE 23493db86aabSstevel return (do_psu_cmd(arg, mode, &env_ind, 23503db86aabSstevel &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND)); 23513db86aabSstevel } 23523db86aabSstevel env_ind.next_id = section->entry[0].handle_name; 23533db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 23543db86aabSstevel } else { 23553db86aabSstevel /* ensure name is properly terminated */ 23563db86aabSstevel env_ind.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 23573db86aabSstevel if (get_sensor_by_name(section, env_ind.id.name, 23583db86aabSstevel &index) != 0) { 23593db86aabSstevel RELEASE_CACHE 23603db86aabSstevel return (do_psu_cmd(arg, mode, &env_ind, 23613db86aabSstevel &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND)); 23623db86aabSstevel } 23633db86aabSstevel if (index + 1 < section->num_entries) { 23643db86aabSstevel env_ind.next_id = 23653db86aabSstevel section->entry[index + 1].handle_name; 23663db86aabSstevel } else { 23673db86aabSstevel rmclomv_cache_section_t *sub_section = 23683db86aabSstevel rmclomv_find_section(rmclomv_subcache, 23693db86aabSstevel RMCLOMV_AMP_IND); 23703db86aabSstevel if ((sub_section == NULL) || 23713db86aabSstevel (sub_section->num_entries == 0)) 23723db86aabSstevel env_ind.next_id.name[0] = '\0'; 23733db86aabSstevel else 23743db86aabSstevel env_ind.next_id = 23753db86aabSstevel sub_section->entry[0].handle_name; 23763db86aabSstevel } 23773db86aabSstevel } 23783db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 23793db86aabSstevel /* 23803db86aabSstevel * user correctly identified an indicator, note its 23813db86aabSstevel * handle value and request the indicator status 23823db86aabSstevel */ 23833db86aabSstevel rmc_ampi.handle = section->entry[index].handle; 23843db86aabSstevel } 23853db86aabSstevel RELEASE_CACHE 23863db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 23873db86aabSstevel rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS, DP_GET_CIRCUIT_BRKS_R, 23883db86aabSstevel sizeof (rmc_ampi_r), (intptr_t)&rmc_ampi, 23893db86aabSstevel (intptr_t)&rmc_ampi_r) != 0)) { 23903db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 23913db86aabSstevel } 23923db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && 23933db86aabSstevel (rmc_ampi_r.circuit_brk_status[0].sensor_status == 23943db86aabSstevel DP_SENSOR_NOT_PRESENT)) { 23953db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 23963db86aabSstevel } 23973db86aabSstevel if ((env_ind.sensor_status = sensor_status) == 23983db86aabSstevel ENVMON_SENSOR_OK) { 23993db86aabSstevel /* 24003db86aabSstevel * copy results into buffer for user 24013db86aabSstevel */ 24023db86aabSstevel if (rmc_ampi_r.circuit_brk_status[0].sensor_status != 24033db86aabSstevel DP_SENSOR_DATA_AVAILABLE) 24043db86aabSstevel env_ind.sensor_status = ENVMON_INACCESSIBLE; 24053db86aabSstevel env_ind.condition = 24063db86aabSstevel rmc_ampi_r.circuit_brk_status[0].status; 24073db86aabSstevel } 24083db86aabSstevel 24093db86aabSstevel /* 24103db86aabSstevel * If rmclomv_rmc_error is set there is no way 24113db86aabSstevel * that we read information from RSC. Just copy 24123db86aabSstevel * out an inaccessible evironmental. 24133db86aabSstevel */ 24143db86aabSstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) { 24153db86aabSstevel env_ind.sensor_status = ENVMON_INACCESSIBLE; 24163db86aabSstevel env_ind.condition = ENVMON_INACCESSIBLE; 24173db86aabSstevel } 24183db86aabSstevel 24193db86aabSstevel if (ddi_copyout((caddr_t)&env_ind, (caddr_t)arg, 24203db86aabSstevel sizeof (envmon_indicator_t), mode) != 0) 24213db86aabSstevel return (EFAULT); 24223db86aabSstevel break; 24233db86aabSstevel 24243db86aabSstevel case ENVMONIOCHPU: 24253db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_hpu, 24263db86aabSstevel sizeof (envmon_hpu_t), mode) != 0) 24273db86aabSstevel return (EFAULT); 24283db86aabSstevel 24293db86aabSstevel /* see if we've got hpu handles cached */ 24303db86aabSstevel LOCK_CACHE 24313db86aabSstevel 24323db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 24333db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 24343db86aabSstevel RMCLOMV_HPU_IND)) == NULL)) { 24353db86aabSstevel RELEASE_CACHE 24363db86aabSstevel return (EAGAIN); 24373db86aabSstevel } 24383db86aabSstevel 24393db86aabSstevel /* 24403db86aabSstevel * At this point the cache is locked and section points to 24413db86aabSstevel * the section relating to hpus. 24423db86aabSstevel */ 24433db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 24443db86aabSstevel if (env_hpu.id.name[0] == '\0') { 24453db86aabSstevel /* request for first handle */ 24463db86aabSstevel if (section->num_entries == 0) 24473db86aabSstevel env_hpu.next_id.name[0] = '\0'; 24483db86aabSstevel else 24493db86aabSstevel env_hpu.next_id = 24503db86aabSstevel section->entry[0].handle_name; 24513db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 24523db86aabSstevel } else { 24533db86aabSstevel /* ensure name is properly terminated */ 24543db86aabSstevel env_hpu.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 24553db86aabSstevel if (get_sensor_by_name(section, env_hpu.id.name, 24563db86aabSstevel &index) != 0) { 24573db86aabSstevel env_hpu.next_id.name[0] = '\0'; 24583db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 24593db86aabSstevel } else if (index + 1 < section->num_entries) 24603db86aabSstevel env_hpu.next_id = 24613db86aabSstevel section->entry[index + 1].handle_name; 24623db86aabSstevel else 24633db86aabSstevel env_hpu.next_id.name[0] = '\0'; 24643db86aabSstevel } 24653db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 24663db86aabSstevel /* 24673db86aabSstevel * user correctly identified an hpu, note its 24683db86aabSstevel * handle value and request the hpu status 24693db86aabSstevel */ 24703db86aabSstevel rmc_fru.handle = section->entry[index].handle; 24713db86aabSstevel special = section->entry[index].ind_mask; 24723db86aabSstevel } 24733db86aabSstevel RELEASE_CACHE 24743db86aabSstevel if ((env_hpu.sensor_status = sensor_status) == 24753db86aabSstevel ENVMON_SENSOR_OK) { 24763db86aabSstevel env_hpu.fru_status = ENVMON_FRU_PRESENT; 24773db86aabSstevel 24783db86aabSstevel if (special != 0) { 24793db86aabSstevel /* this is the pseudo SC node */ 24803db86aabSstevel mutex_enter(&rmclomv_state_lock); 24813db86aabSstevel switch (rmclomv_rmc_state) { 24823db86aabSstevel case RMCLOMV_RMCSTATE_OK: 24833db86aabSstevel break; 24843db86aabSstevel case RMCLOMV_RMCSTATE_FAILED: 24853db86aabSstevel env_hpu.fru_status = ENVMON_FRU_FAULT; 24863db86aabSstevel break; 24873db86aabSstevel case RMCLOMV_RMCSTATE_DOWNLOAD: 24883db86aabSstevel env_hpu.fru_status = 24893db86aabSstevel ENVMON_FRU_DOWNLOAD; 24903db86aabSstevel break; 24913db86aabSstevel default: 24923db86aabSstevel env_hpu.sensor_status = 24933db86aabSstevel ENVMON_INACCESSIBLE; 24943db86aabSstevel break; 24953db86aabSstevel } 24963db86aabSstevel mutex_exit(&rmclomv_state_lock); 24973db86aabSstevel } else if (rmclomv_rmc_error || 24983db86aabSstevel rmclomv_do_cmd(DP_GET_FRU_STATUS, 24993db86aabSstevel DP_GET_FRU_STATUS_R, sizeof (rmc_fru_r), 25003db86aabSstevel (intptr_t)&rmc_fru, (intptr_t)&rmc_fru_r) != 0) { 25013db86aabSstevel env_hpu.sensor_status = ENVMON_INACCESSIBLE; 25023db86aabSstevel } else { 25033db86aabSstevel /* 25043db86aabSstevel * copy results into buffer for user 25053db86aabSstevel */ 25063db86aabSstevel if (rmc_fru_r.fru_status[0].presence == 0) { 25073db86aabSstevel env_hpu.sensor_status = 25083db86aabSstevel ENVMON_NOT_PRESENT; 25093db86aabSstevel env_hpu.fru_status = 25103db86aabSstevel ENVMON_FRU_NOT_PRESENT; 25113db86aabSstevel } else if (rmc_fru_r.fru_status[0].sensor_status 25123db86aabSstevel != DP_SENSOR_DATA_AVAILABLE) { 25133db86aabSstevel env_hpu.sensor_status = 25143db86aabSstevel ENVMON_INACCESSIBLE; 25153db86aabSstevel } else { 25163db86aabSstevel uint8_t status = 25173db86aabSstevel rmc_fru_r.fru_status[0].status; 25183db86aabSstevel if (status == DP_FRU_STATUS_UNKNOWN) { 25193db86aabSstevel env_hpu.sensor_status = 25203db86aabSstevel ENVMON_INACCESSIBLE; 25213db86aabSstevel } else if (status != DP_FRU_STATUS_OK) { 25223db86aabSstevel env_hpu.fru_status = 25233db86aabSstevel ENVMON_FRU_FAULT; 25243db86aabSstevel } 25253db86aabSstevel } 25263db86aabSstevel } 25273db86aabSstevel } 25283db86aabSstevel 25293db86aabSstevel /* 25303db86aabSstevel * If rmclomv_rmc_error is set there is no way 25313db86aabSstevel * that we read information from RSC. Just copy 25323db86aabSstevel * out an inaccessible environmental. 25333db86aabSstevel */ 25343db86aabSstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) { 25353db86aabSstevel env_hpu.sensor_status = ENVMON_INACCESSIBLE; 25363db86aabSstevel env_hpu.fru_status = ENVMON_INACCESSIBLE; 25373db86aabSstevel } 25383db86aabSstevel 25393db86aabSstevel if (ddi_copyout((caddr_t)&env_hpu, (caddr_t)arg, 25403db86aabSstevel sizeof (envmon_hpu_t), mode) != 0) 25413db86aabSstevel return (EFAULT); 25423db86aabSstevel break; 25433db86aabSstevel 25443db86aabSstevel case ENVMONIOCGETLED: 25453db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledinfo, 25463db86aabSstevel sizeof (envmon_led_info_t), mode) != 0) 25473db86aabSstevel return (EFAULT); 25483db86aabSstevel 25493db86aabSstevel /* see if we've got LED handles cached */ 25503db86aabSstevel LOCK_CACHE 25513db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 25523db86aabSstevel 25533db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 25543db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 25553db86aabSstevel RMCLOMV_LED_IND)) == NULL)) { 25563db86aabSstevel env_ledinfo.next_id.name[0] = '\0'; 25573db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 25583db86aabSstevel } else if (env_ledinfo.id.name[0] == '\0') { 25593db86aabSstevel /* request for first handle */ 25603db86aabSstevel if (section->num_entries == 0) 25613db86aabSstevel env_ledinfo.next_id.name[0] = '\0'; 25623db86aabSstevel else 25633db86aabSstevel env_ledinfo.next_id = 25643db86aabSstevel section->entry[0].handle_name; 25653db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 25663db86aabSstevel } else { 25673db86aabSstevel /* ensure name is properly terminated */ 25683db86aabSstevel env_ledinfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 25693db86aabSstevel if (get_sensor_by_name(section, env_ledinfo.id.name, 25703db86aabSstevel &index) != 0) { 25713db86aabSstevel env_ledinfo.next_id.name[0] = '\0'; 25723db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 25733db86aabSstevel } else if (index + 1 < section->num_entries) 25743db86aabSstevel env_ledinfo.next_id = 25753db86aabSstevel section->entry[index + 1].handle_name; 25763db86aabSstevel else 25773db86aabSstevel env_ledinfo.next_id.name[0] = '\0'; 25783db86aabSstevel } 25793db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 25803db86aabSstevel /* 25813db86aabSstevel * user correctly identified a LED, note its 25823db86aabSstevel * handle value and request the LED status 25833db86aabSstevel */ 25843db86aabSstevel rmc_led.handle = section->entry[index].handle; 25853db86aabSstevel } 25863db86aabSstevel RELEASE_CACHE 25873db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 25883db86aabSstevel rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R, 25893db86aabSstevel sizeof (rmc_led_r), (intptr_t)&rmc_led, 25903db86aabSstevel (intptr_t)&rmc_led_r) != 0)) { 25913db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 25923db86aabSstevel } 25933db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && 25943db86aabSstevel (rmc_led_r.led_state[0].sensor_status == 25953db86aabSstevel DP_SENSOR_NOT_PRESENT)) { 25963db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 25973db86aabSstevel } 25983db86aabSstevel if ((env_ledinfo.sensor_status = sensor_status) == 25993db86aabSstevel ENVMON_SENSOR_OK) { 26003db86aabSstevel /* 26013db86aabSstevel * copy results into buffer for user 26023db86aabSstevel * start with some defaults then override 26033db86aabSstevel */ 26043db86aabSstevel env_ledinfo.sensor_status = ENVMON_SENSOR_OK; 26053db86aabSstevel env_ledinfo.led_state = ENVMON_LED_OFF; 26063db86aabSstevel env_ledinfo.led_color = ENVMON_LED_CLR_NONE; 26073db86aabSstevel 26083db86aabSstevel if (rmc_led_r.led_state[0].sensor_status != 26093db86aabSstevel DP_SENSOR_DATA_AVAILABLE) 26103db86aabSstevel env_ledinfo.sensor_status = ENVMON_INACCESSIBLE; 26113db86aabSstevel else { 26123db86aabSstevel dp_led_state_t ledState; 26133db86aabSstevel ledState = rmc_led_r.led_state[0]; 26143db86aabSstevel env_ledinfo.led_color = (int8_t)ledState.colour; 26153db86aabSstevel 26163db86aabSstevel switch (ledState.state) { 26173db86aabSstevel case (rsci8)DP_LED_OFF: 26183db86aabSstevel break; 26193db86aabSstevel case (rsci8)DP_LED_ON: 26203db86aabSstevel env_ledinfo.led_state = ENVMON_LED_ON; 26213db86aabSstevel break; 26223db86aabSstevel case (rsci8)DP_LED_BLINKING: 26233db86aabSstevel env_ledinfo.led_state = 26243db86aabSstevel ENVMON_LED_BLINKING; 26253db86aabSstevel break; 26263db86aabSstevel case (rsci8)DP_LED_FLASHING: 26273db86aabSstevel env_ledinfo.led_state = 26283db86aabSstevel ENVMON_LED_FLASHING; 26293db86aabSstevel break; 26303db86aabSstevel default: 26313db86aabSstevel break; 26323db86aabSstevel } 26333db86aabSstevel } 26343db86aabSstevel } 26353db86aabSstevel 26363db86aabSstevel /* 26373db86aabSstevel * If rmclomv_rmc_error is set there is no way 26383db86aabSstevel * that we read information from RSC. Just copy 26393db86aabSstevel * out an inaccessible environmental. 26403db86aabSstevel */ 26413db86aabSstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) { 26423db86aabSstevel env_ledinfo.sensor_status = ENVMON_INACCESSIBLE; 26433db86aabSstevel env_ledinfo.led_state = ENVMON_INACCESSIBLE; 26443db86aabSstevel } 26453db86aabSstevel 26463db86aabSstevel if (ddi_copyout((caddr_t)&env_ledinfo, (caddr_t)arg, 26473db86aabSstevel sizeof (envmon_led_info_t), mode) != 0) 26483db86aabSstevel return (EFAULT); 26493db86aabSstevel break; 26503db86aabSstevel 26513db86aabSstevel case ENVMONIOCSETLED: 26523db86aabSstevel if ((mode & FWRITE) == 0) 26533db86aabSstevel return (EACCES); 26543db86aabSstevel if (drv_priv(cred_p) != 0) 26553db86aabSstevel return (EPERM); 26563db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledctl, 26573db86aabSstevel sizeof (envmon_led_ctl_t), mode) != 0) 26583db86aabSstevel return (EFAULT); 26593db86aabSstevel if (env_ledctl.led_state < RMCLOMV_MIN_LED_STATE || 26603db86aabSstevel env_ledctl.led_state > RMCLOMV_MAX_LED_STATE) 26613db86aabSstevel return (EINVAL); 26623db86aabSstevel /* 26633db86aabSstevel * Ensure name is properly terminated. 26643db86aabSstevel */ 26653db86aabSstevel env_ledctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 26663db86aabSstevel 26673db86aabSstevel /* see if we've got LED handles cached */ 26683db86aabSstevel LOCK_CACHE 26693db86aabSstevel 26703db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 26713db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 26723db86aabSstevel RMCLOMV_LED_IND)) == NULL) || 26733db86aabSstevel (get_sensor_by_name(section, env_ledctl.id.name, 26743db86aabSstevel &index) != 0)) { 26753db86aabSstevel RELEASE_CACHE 26763db86aabSstevel return (EINVAL); /* no such LED */ 26773db86aabSstevel } 26783db86aabSstevel /* 26793db86aabSstevel * user correctly identified a LED, note its handle value 26803db86aabSstevel */ 26813db86aabSstevel rmc_setled.handle = section->entry[index].handle; 26823db86aabSstevel RELEASE_CACHE 26833db86aabSstevel switch (env_ledctl.led_state) { 26843db86aabSstevel case ENVMON_LED_ON: 26853db86aabSstevel rmc_setled.state = DP_LED_ON; 26863db86aabSstevel break; 26873db86aabSstevel case ENVMON_LED_BLINKING: 26883db86aabSstevel rmc_setled.state = DP_LED_BLINKING; 26893db86aabSstevel break; 26903db86aabSstevel case ENVMON_LED_FLASHING: 26913db86aabSstevel rmc_setled.state = DP_LED_FLASHING; 26923db86aabSstevel break; 26933db86aabSstevel default: 26943db86aabSstevel rmc_setled.state = DP_LED_OFF; 26953db86aabSstevel break; 26963db86aabSstevel } 26973db86aabSstevel retval = rmclomv_do_cmd(DP_SET_LED_STATE, DP_SET_LED_STATE_R, 26983db86aabSstevel sizeof (rmc_setled_r), (intptr_t)&rmc_setled, 26993db86aabSstevel (intptr_t)&rmc_setled_r); 27003db86aabSstevel 27013db86aabSstevel if (retval != 0) { 27023db86aabSstevel break; 27033db86aabSstevel } 27043db86aabSstevel 27053db86aabSstevel if (rmc_setled_r.status != 0) { 27063db86aabSstevel cmn_err(CE_WARN, "ENVMONIOCSETLED: \"%s\" status: 0x%x", 27073db86aabSstevel env_ledctl.id.name, rmc_setled_r.status); 27083db86aabSstevel return (EIO); 27093db86aabSstevel } 27103db86aabSstevel break; 27113db86aabSstevel 27123db86aabSstevel case ENVMONIOCGETKEYSW: 27133db86aabSstevel { 27143db86aabSstevel enum rmc_keyswitch_pos rmc_pos = real_key_position; 27153db86aabSstevel envmon_keysw_pos_t envmon_pos; 27163db86aabSstevel 27173db86aabSstevel /* 27183db86aabSstevel * Yes, I know this is ugly, but the V210 has no keyswitch, 27193db86aabSstevel * even though the ALOM returns a value for it 27203db86aabSstevel */ 27213db86aabSstevel if (strcmp(platform, "SUNW,Sun-Fire-V210") == 0) { 27223db86aabSstevel return (ENOTSUP); 27233db86aabSstevel } 27243db86aabSstevel 27253db86aabSstevel switch (rmc_pos) { 27263db86aabSstevel 27273db86aabSstevel case RMC_KEYSWITCH_POS_NORMAL: 27283db86aabSstevel envmon_pos = ENVMON_KEYSW_POS_NORMAL; 27293db86aabSstevel break; 27303db86aabSstevel case RMC_KEYSWITCH_POS_DIAG: 27313db86aabSstevel envmon_pos = ENVMON_KEYSW_POS_DIAG; 27323db86aabSstevel break; 27333db86aabSstevel case RMC_KEYSWITCH_POS_LOCKED: 27343db86aabSstevel envmon_pos = ENVMON_KEYSW_POS_LOCKED; 27353db86aabSstevel break; 27363db86aabSstevel case RMC_KEYSWITCH_POS_OFF: 27373db86aabSstevel envmon_pos = ENVMON_KEYSW_POS_OFF; 27383db86aabSstevel break; 27393db86aabSstevel default: 27403db86aabSstevel envmon_pos = ENVMON_KEYSW_POS_UNKNOWN; 27413db86aabSstevel break; 27423db86aabSstevel } 27433db86aabSstevel 27443db86aabSstevel if (ddi_copyout((caddr_t)&envmon_pos, (caddr_t)arg, 27453db86aabSstevel sizeof (envmon_pos), mode) != 0) 27463db86aabSstevel return (EFAULT); 27473db86aabSstevel break; 27483db86aabSstevel } 27493db86aabSstevel 27503db86aabSstevel case ENVMONIOCGETALARM: 27513db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarminfo, 27523db86aabSstevel sizeof (envmon_alarm_info_t), mode) != 0) 27533db86aabSstevel return (EFAULT); 27543db86aabSstevel 27553db86aabSstevel /* see if we've got ALARM handles cached */ 27563db86aabSstevel LOCK_CACHE 27573db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 27583db86aabSstevel 27593db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 27603db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 27613db86aabSstevel RMCLOMV_ALARM_IND)) == NULL)) { 27623db86aabSstevel env_alarminfo.next_id.name[0] = '\0'; 27633db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 27643db86aabSstevel } else if (env_alarminfo.id.name[0] == '\0') { 27653db86aabSstevel /* request for first handle */ 27663db86aabSstevel if (section->num_entries == 0) 27673db86aabSstevel env_alarminfo.next_id.name[0] = '\0'; 27683db86aabSstevel else 27693db86aabSstevel env_alarminfo.next_id = 27703db86aabSstevel section->entry[0].handle_name; 27713db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 27723db86aabSstevel } else { 27733db86aabSstevel /* ensure name is properly terminated */ 27743db86aabSstevel env_alarminfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 27753db86aabSstevel if (get_sensor_by_name(section, env_alarminfo.id.name, 27763db86aabSstevel &index) != 0) { 27773db86aabSstevel env_alarminfo.next_id.name[0] = '\0'; 27783db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 27793db86aabSstevel } else if (index + 1 < section->num_entries) 27803db86aabSstevel env_alarminfo.next_id = 27813db86aabSstevel section->entry[index + 1].handle_name; 27823db86aabSstevel else 27833db86aabSstevel env_alarminfo.next_id.name[0] = '\0'; 27843db86aabSstevel } 27853db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 27863db86aabSstevel /* 27873db86aabSstevel * user correctly identified a ALARM, note its 27883db86aabSstevel * handle value and request the ALARM status 27893db86aabSstevel */ 27903db86aabSstevel rmc_alarm.handle = section->entry[index].handle; 27913db86aabSstevel } 27923db86aabSstevel RELEASE_CACHE 27933db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && 27943db86aabSstevel (rmclomv_rmc_error || 27953db86aabSstevel rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R, 27963db86aabSstevel sizeof (rmc_alarm_r), (intptr_t)&rmc_alarm, 27973db86aabSstevel (intptr_t)&rmc_alarm_r) != 0)) { 27983db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 27993db86aabSstevel } 28003db86aabSstevel if ((env_alarminfo.sensor_status = sensor_status) == 28013db86aabSstevel ENVMON_SENSOR_OK) { 28023db86aabSstevel /* 28033db86aabSstevel * copy results into buffer for user 28043db86aabSstevel * start with some defaults then override 28053db86aabSstevel */ 28063db86aabSstevel env_alarminfo.sensor_status = ENVMON_SENSOR_OK; 28073db86aabSstevel env_alarminfo.alarm_state = ENVMON_ALARM_OFF; 28083db86aabSstevel 28093db86aabSstevel if (rmc_alarm_r.alarm_state[0].sensor_status != 28103db86aabSstevel DP_SENSOR_DATA_AVAILABLE) 28113db86aabSstevel env_alarminfo.sensor_status = 28123db86aabSstevel ENVMON_INACCESSIBLE; 28133db86aabSstevel else { 28143db86aabSstevel dp_alarm_state_t alarmState; 28153db86aabSstevel alarmState = rmc_alarm_r.alarm_state[0]; 28163db86aabSstevel 28173db86aabSstevel switch (alarmState.state) { 28183db86aabSstevel case DP_ALARM_OFF: 28193db86aabSstevel break; 28203db86aabSstevel case DP_ALARM_ON: 28213db86aabSstevel env_alarminfo.alarm_state = 28223db86aabSstevel ENVMON_ALARM_ON; 28233db86aabSstevel break; 28243db86aabSstevel default: 28253db86aabSstevel break; 28263db86aabSstevel } 28273db86aabSstevel } 28283db86aabSstevel } 28293db86aabSstevel 28303db86aabSstevel /* 28313db86aabSstevel * If rmclomv_rmc_error is set there is no way 28323db86aabSstevel * that we read information from RSC. Just copy 28333db86aabSstevel * out an inaccessible environmental. 28343db86aabSstevel */ 28353db86aabSstevel if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) { 28363db86aabSstevel env_alarminfo.sensor_status = ENVMON_INACCESSIBLE; 28373db86aabSstevel env_alarminfo.alarm_state = ENVMON_INACCESSIBLE; 28383db86aabSstevel } 28393db86aabSstevel 28403db86aabSstevel if (ddi_copyout((caddr_t)&env_alarminfo, (caddr_t)arg, 28413db86aabSstevel sizeof (envmon_alarm_info_t), mode) != 0) 28423db86aabSstevel return (EFAULT); 28433db86aabSstevel break; 28443db86aabSstevel 28453db86aabSstevel case ENVMONIOCSETALARM: 28463db86aabSstevel if ((mode & FWRITE) == 0) 28473db86aabSstevel return (EACCES); 28483db86aabSstevel if (drv_priv(cred_p) != 0) 28493db86aabSstevel return (EPERM); 28503db86aabSstevel if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarmctl, 28513db86aabSstevel sizeof (envmon_alarm_ctl_t), mode) != 0) 28523db86aabSstevel return (EFAULT); 28533db86aabSstevel if (env_alarmctl.alarm_state < RMCLOMV_MIN_ALARM_STATE || 28543db86aabSstevel env_alarmctl.alarm_state > RMCLOMV_MAX_ALARM_STATE) 28553db86aabSstevel return (EINVAL); 28563db86aabSstevel /* 28573db86aabSstevel * Ensure name is properly terminated. 28583db86aabSstevel */ 28593db86aabSstevel env_alarmctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 28603db86aabSstevel 28613db86aabSstevel /* see if we've got ALARM handles cached */ 28623db86aabSstevel LOCK_CACHE 28633db86aabSstevel 28643db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 28653db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 28663db86aabSstevel RMCLOMV_ALARM_IND)) == NULL) || 28673db86aabSstevel (get_sensor_by_name(section, env_alarmctl.id.name, 28683db86aabSstevel &index) != 0)) { 28693db86aabSstevel RELEASE_CACHE 28703db86aabSstevel return (EINVAL); /* no such ALARM */ 28713db86aabSstevel } 28723db86aabSstevel /* 28733db86aabSstevel * user correctly identified a ALARM, note its handle value 28743db86aabSstevel */ 28753db86aabSstevel rmc_setalarm.handle = section->entry[index].handle; 28763db86aabSstevel RELEASE_CACHE 28773db86aabSstevel rmc_setalarm.state = (rsci8)env_alarmctl.alarm_state; 28783db86aabSstevel retval = rmclomv_do_cmd(DP_SET_ALARM_STATE, 28793db86aabSstevel DP_SET_ALARM_STATE_R, 28803db86aabSstevel sizeof (rmc_setalarm_r), 28813db86aabSstevel (intptr_t)&rmc_setalarm, 28823db86aabSstevel (intptr_t)&rmc_setalarm_r); 28833db86aabSstevel 28843db86aabSstevel if (retval != 0) { 28853db86aabSstevel break; 28863db86aabSstevel } 28873db86aabSstevel 28883db86aabSstevel if (rmc_setalarm_r.status != 0) { 28893db86aabSstevel cmn_err(CE_WARN, "ENVMONIOCSETALARM: \"%s\" status: " 28903db86aabSstevel "0x%x", env_alarmctl.id.name, 28913db86aabSstevel rmc_setalarm_r.status); 28923db86aabSstevel return (EIO); 28933db86aabSstevel } 28943db86aabSstevel break; 28953db86aabSstevel 28963db86aabSstevel case ENVMONIOCCHASSISSERIALNUM: 28973db86aabSstevel retval = rmclomv_do_cmd(DP_GET_SDP_VERSION, 28983db86aabSstevel DP_GET_SDP_VERSION_R, sizeof (rmc_sdpver_r), 28993db86aabSstevel NULL, (intptr_t)&rmc_sdpver_r); 29003db86aabSstevel 29013db86aabSstevel if (retval != 0) { 29023db86aabSstevel cmn_err(CE_WARN, "DP_GET_SDP_VERSION failed, ret=%d\n", 29033db86aabSstevel retval); 29043db86aabSstevel break; 29053db86aabSstevel } else if (rmc_sdpver_r.version < SDP_RESPONDS_TO_ALL_CMDS) { 29063db86aabSstevel retval = ENOTSUP; 29073db86aabSstevel break; 29083db86aabSstevel } 29093db86aabSstevel retval = rmclomv_do_cmd(DP_GET_CHASSIS_SERIALNUM, 29103db86aabSstevel DP_GET_CHASSIS_SERIALNUM_R, sizeof (rmc_serialnum_r), 29113db86aabSstevel NULL, (intptr_t)&rmc_serialnum_r); 29123db86aabSstevel 29133db86aabSstevel if (retval != 0) { 29143db86aabSstevel break; 29153db86aabSstevel } 29163db86aabSstevel bcopy(rmc_serialnum_r.chassis_serial_number, 29173db86aabSstevel chassis.serial_number, 29183db86aabSstevel sizeof (rmc_serialnum_r.chassis_serial_number)); 29193db86aabSstevel 29203db86aabSstevel if (ddi_copyout((caddr_t)&chassis, (caddr_t)arg, 29213db86aabSstevel sizeof (chassis), mode) != 0) { 29223db86aabSstevel return (EFAULT); 29233db86aabSstevel } 29243db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 29253db86aabSstevel break; 29263db86aabSstevel 29273db86aabSstevel default: 29283db86aabSstevel retval = ENOTSUP; 29293db86aabSstevel break; 29303db86aabSstevel } 29313db86aabSstevel 29323db86aabSstevel return (retval); 29333db86aabSstevel } 29343db86aabSstevel 29353db86aabSstevel /* ARGSUSED */ 29363db86aabSstevel static void 29373db86aabSstevel rmclomv_checkrmc(caddr_t arg) 29383db86aabSstevel { 29393db86aabSstevel callb_cpr_t cprinfo; 29403db86aabSstevel int err; 29413db86aabSstevel int retries; 29423db86aabSstevel int state; 29433db86aabSstevel dp_get_sysinfo_r_t sysinfo; 29443db86aabSstevel 29453db86aabSstevel CALLB_CPR_INIT(&cprinfo, &rmclomv_checkrmc_lock, callb_generic_cpr, 29463db86aabSstevel "rmclomv_checkrmc"); 29473db86aabSstevel 29483db86aabSstevel mutex_enter(&rmclomv_checkrmc_lock); 29493db86aabSstevel for (;;) { 29503db86aabSstevel /* 29513db86aabSstevel * Initial entry to this for loop is made with 29523db86aabSstevel * rmclomv_checkrmc_sig set to RMCLOMV_PROCESS_NOW. So the 29533db86aabSstevel * following while loop drops through the first time. A 29543db86aabSstevel * timeout call is made just before polling the RMC. Its 29553db86aabSstevel * interrupt routine sustains this loop by injecting additional 29563db86aabSstevel * state changes and cv events. 29573db86aabSstevel */ 29583db86aabSstevel /* 29593db86aabSstevel * Wait for someone to tell me to continue. 29603db86aabSstevel */ 29613db86aabSstevel while (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_WAIT) { 29623db86aabSstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 29633db86aabSstevel cv_wait(&rmclomv_checkrmc_sig_cv, 29643db86aabSstevel &rmclomv_checkrmc_lock); 29653db86aabSstevel CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_checkrmc_lock); 29663db86aabSstevel } 29673db86aabSstevel 29683db86aabSstevel mutex_exit(&rmclomv_checkrmc_lock); 29693db86aabSstevel /* 29703db86aabSstevel * mustn't hold same lock as timeout called with 29713db86aabSstevel * when cancelling timer 29723db86aabSstevel */ 29733db86aabSstevel if (timer_id != 0) { 29743db86aabSstevel (void) untimeout(timer_id); 29753db86aabSstevel timer_id = 0; 29763db86aabSstevel } 29773db86aabSstevel mutex_enter(&rmclomv_checkrmc_lock); 29783db86aabSstevel 29793db86aabSstevel /* RMCLOMV_CHECKRMC_EXITNOW implies signal by _detach(). */ 29803db86aabSstevel if (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_EXITNOW) { 29813db86aabSstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT; 29823db86aabSstevel 29833db86aabSstevel /* rmclomv_checkrmc_lock is held at this point! */ 29843db86aabSstevel CALLB_CPR_EXIT(&cprinfo); 29853db86aabSstevel 29863db86aabSstevel thread_exit(); 29873db86aabSstevel /* NOTREACHED */ 29883db86aabSstevel } 29893db86aabSstevel 29903db86aabSstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT; 29913db86aabSstevel 29923db86aabSstevel /* 29933db86aabSstevel * If the RMC is not responding, rmclomv_do_cmd() takes a 29943db86aabSstevel * long time and eventually times out. We conclude that the 29953db86aabSstevel * RMC is broken if it doesn't respond to a number of polls 29963db86aabSstevel * made 60 secs apart. So that the rmclomv_do_cmd() time-out 29973db86aabSstevel * period isn't added to our 60 second timer, make the 29983db86aabSstevel * timeout() call before calling rmclomv_do_cmd(). 29993db86aabSstevel */ 30003db86aabSstevel if (timer_id == 0) { 30013db86aabSstevel timer_id = timeout(rmclomv_checkrmc_wakeup, NULL, 30023db86aabSstevel 60 * drv_usectohz(1000000)); 30033db86aabSstevel } 30043db86aabSstevel 30053db86aabSstevel mutex_exit(&rmclomv_checkrmc_lock); 30063db86aabSstevel 30073db86aabSstevel err = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R, 30083db86aabSstevel sizeof (sysinfo), NULL, (intptr_t)&sysinfo); 30093db86aabSstevel if (err == 0) { 30103db86aabSstevel mutex_enter(&rmclomv_state_lock); 30113db86aabSstevel state = rmclomv_rmc_state; 30123db86aabSstevel /* successful poll, reset fail count */ 30133db86aabSstevel rmclomv_rmcfailcount = 0; 30143db86aabSstevel mutex_exit(&rmclomv_state_lock); 30153db86aabSstevel 30163db86aabSstevel if (state != RMCLOMV_RMCSTATE_OK) { 30173db86aabSstevel rmclomv_refresh_wakeup(); 30183db86aabSstevel } 30193db86aabSstevel } 30203db86aabSstevel if ((err != 0) && 30213db86aabSstevel (rmclomv_rmc_error != RMCLOMV_RMCSTATE_DOWNLOAD)) { 30223db86aabSstevel /* 30233db86aabSstevel * Failed response or no response from RMC. 30243db86aabSstevel * Count the failure. 30253db86aabSstevel * If threshold exceeded, send a DR event. 30263db86aabSstevel */ 30273db86aabSstevel mutex_enter(&rmclomv_state_lock); 30283db86aabSstevel retries = rmclomv_rmcfailcount; 30293db86aabSstevel state = rmclomv_rmc_state; 30303db86aabSstevel if (retries == RMCLOMV_RMCFAILTHRESHOLD) 30313db86aabSstevel rmclomv_rmc_state = RMCLOMV_RMCSTATE_FAILED; 30323db86aabSstevel if (rmclomv_rmcfailcount <= RMCLOMV_RMCFAILTHRESHOLD) 30333db86aabSstevel rmclomv_rmcfailcount++; 30343db86aabSstevel mutex_exit(&rmclomv_state_lock); 30353db86aabSstevel 30363db86aabSstevel if (retries == RMCLOMV_RMCFAILTHRESHOLD) { 30373db86aabSstevel cmn_err(CE_WARN, "SC %s responding", 30383db86aabSstevel state == RMCLOMV_RMCSTATE_OK ? 30393db86aabSstevel "has stopped" : "is not"); 30403db86aabSstevel refresh_name_cache(B_TRUE); 30413db86aabSstevel rmclomv_dr_data_handler(str_sc, SE_NO_HINT); 30423db86aabSstevel } 30433db86aabSstevel } 30443db86aabSstevel 30453db86aabSstevel /* 30463db86aabSstevel * Re-enter the lock to prepare for another iteration. 30473db86aabSstevel * We must have the lock here to protect rmclomv_checkrmc_sig. 30483db86aabSstevel */ 30493db86aabSstevel mutex_enter(&rmclomv_checkrmc_lock); 30503db86aabSstevel } 30513db86aabSstevel } 30523db86aabSstevel 30533db86aabSstevel static void 30543db86aabSstevel rmclomv_checkrmc_start(void) 30553db86aabSstevel { 30563db86aabSstevel kthread_t *tp; 30573db86aabSstevel 30583db86aabSstevel mutex_enter(&rmclomv_checkrmc_lock); 30593db86aabSstevel 30603db86aabSstevel if (rmclomv_checkrmc_tid == 0) { 30613db86aabSstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW; 30623db86aabSstevel 30633db86aabSstevel tp = thread_create(NULL, 0, rmclomv_checkrmc, NULL, 0, 30643db86aabSstevel &p0, TS_RUN, maxclsyspri); 30653db86aabSstevel rmclomv_checkrmc_tid = tp->t_did; 30663db86aabSstevel } 30673db86aabSstevel 30683db86aabSstevel mutex_exit(&rmclomv_checkrmc_lock); 30693db86aabSstevel } 30703db86aabSstevel 30713db86aabSstevel static void 30723db86aabSstevel rmclomv_checkrmc_destroy(void) 30733db86aabSstevel { 30743db86aabSstevel kt_did_t tid; 30753db86aabSstevel 30763db86aabSstevel mutex_enter(&rmclomv_checkrmc_lock); 30773db86aabSstevel tid = rmclomv_checkrmc_tid; 30783db86aabSstevel if (tid != 0) { 30793db86aabSstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_EXITNOW; 30803db86aabSstevel cv_signal(&rmclomv_checkrmc_sig_cv); 30813db86aabSstevel rmclomv_checkrmc_tid = 0; 30823db86aabSstevel } 30833db86aabSstevel mutex_exit(&rmclomv_checkrmc_lock); 30843db86aabSstevel 30853db86aabSstevel /* 30863db86aabSstevel * Wait for rmclomv_checkrmc() to finish 30873db86aabSstevel */ 30883db86aabSstevel if (tid != 0) 30893db86aabSstevel thread_join(tid); 30903db86aabSstevel } 30913db86aabSstevel 30923db86aabSstevel /*ARGSUSED*/ 30933db86aabSstevel static void 30943db86aabSstevel rmclomv_checkrmc_wakeup(void *arg) 30953db86aabSstevel { 30963db86aabSstevel mutex_enter(&rmclomv_checkrmc_lock); 30973db86aabSstevel 30983db86aabSstevel if (rmclomv_checkrmc_sig != RMCLOMV_CHECKRMC_EXITNOW) 30993db86aabSstevel rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW; 31003db86aabSstevel cv_signal(&rmclomv_checkrmc_sig_cv); 31013db86aabSstevel 31023db86aabSstevel mutex_exit(&rmclomv_checkrmc_lock); 31033db86aabSstevel } 31043db86aabSstevel 31053db86aabSstevel /* ARGSUSED */ 31063db86aabSstevel static void 31073db86aabSstevel rmclomv_refresh(caddr_t arg) 31083db86aabSstevel { 31093db86aabSstevel void (*plat_nodename_set_fun)(void); 31103db86aabSstevel sig_state_t *current_sgn_p; 31113db86aabSstevel callb_cpr_t cprinfo; 31123db86aabSstevel int state; 3113f594b28aSjfrank int tmp_checkrmc_sig; 31143db86aabSstevel 31153db86aabSstevel CALLB_CPR_INIT(&cprinfo, &rmclomv_refresh_lock, callb_generic_cpr, 31163db86aabSstevel "rmclomv_refresh"); 31173db86aabSstevel 3118f594b28aSjfrank /* 3119f594b28aSjfrank * Wait until the rmclomv_checkrmc() thread has had a chance to 3120f594b28aSjfrank * run its main loop. This is done so that rmclomv_refresh will 3121f594b28aSjfrank * only run its main loop once at start of day; otherwise, it may 3122f594b28aSjfrank * run twice and generate warning messages when redundantly populating 3123f594b28aSjfrank * its internal cache. 3124f594b28aSjfrank */ 3125f594b28aSjfrank do { 3126f594b28aSjfrank delay(drv_usectohz(DELAY_TIME)); 3127f594b28aSjfrank mutex_enter(&rmclomv_checkrmc_lock); 3128f594b28aSjfrank tmp_checkrmc_sig = rmclomv_checkrmc_sig; 3129f594b28aSjfrank mutex_exit(&rmclomv_checkrmc_lock); 3130f594b28aSjfrank } while (tmp_checkrmc_sig != RMCLOMV_CHECKRMC_WAIT); 3131f594b28aSjfrank 31323db86aabSstevel mutex_enter(&rmclomv_refresh_lock); 31333db86aabSstevel for (;;) { 31343db86aabSstevel 31353db86aabSstevel /* 31363db86aabSstevel * Wait for someone to tell me to continue. 31373db86aabSstevel */ 31383db86aabSstevel while (rmclomv_refresh_sig == RMCLOMV_REFRESH_WAIT) { 31393db86aabSstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 31403db86aabSstevel cv_wait(&rmclomv_refresh_sig_cv, &rmclomv_refresh_lock); 31413db86aabSstevel CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_refresh_lock); 31423db86aabSstevel } 31433db86aabSstevel 31443db86aabSstevel /* RMCLOMV_REFRESH_EXITNOW implies signal by _detach(). */ 31453db86aabSstevel if (rmclomv_refresh_sig == RMCLOMV_REFRESH_EXITNOW) { 31463db86aabSstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT; 31473db86aabSstevel 31483db86aabSstevel /* rmclomv_refresh_lock is held at this point! */ 31493db86aabSstevel CALLB_CPR_EXIT(&cprinfo); 31503db86aabSstevel 31513db86aabSstevel thread_exit(); 31523db86aabSstevel /* NOTREACHED */ 31533db86aabSstevel } 31543db86aabSstevel 31553db86aabSstevel ASSERT(rmclomv_refresh_sig == RMCLOMV_REFRESH_PROCESSNOW); 31563db86aabSstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT; 31573db86aabSstevel 31583db86aabSstevel mutex_exit(&rmclomv_refresh_lock); 31593db86aabSstevel 31603db86aabSstevel refresh_name_cache(B_FALSE); 31613db86aabSstevel 31623db86aabSstevel /* 31633db86aabSstevel * We're not going to access rmclomv_sysinfo_data here, 31643db86aabSstevel * so there's no point in locking it before reading 31653db86aabSstevel * rmclomv_sysinfo_valid. Also this avoids holding two 31663db86aabSstevel * locks at once and the concommitant worry about deadlocks. 31673db86aabSstevel */ 31683db86aabSstevel if (rmclomv_sysinfo_valid) { 31693db86aabSstevel /* 31703db86aabSstevel * We've just successfully read the RMC sysinfo 31713db86aabSstevel * so the RMC must be operational. Update its 31723db86aabSstevel * state and if it was previously not OK, refresh 31733db86aabSstevel * nodename, CPU signatures and watchdog settings. 31743db86aabSstevel */ 31753db86aabSstevel mutex_enter(&rmclomv_state_lock); 31763db86aabSstevel rmclomv_rmcfailcount = 0; 31773db86aabSstevel state = rmclomv_rmc_state; 31783db86aabSstevel rmclomv_rmc_state = RMCLOMV_RMCSTATE_OK; 31793db86aabSstevel mutex_exit(&rmclomv_state_lock); 31803db86aabSstevel 31813db86aabSstevel if (state != RMCLOMV_RMCSTATE_OK) { 31823db86aabSstevel rmclomv_dr_data_handler(str_sc, SE_NO_HINT); 31833db86aabSstevel if (state == RMCLOMV_RMCSTATE_FAILED) { 31843db86aabSstevel cmn_err(CE_NOTE, "SC recovered"); 31853db86aabSstevel } 31863db86aabSstevel } 31873db86aabSstevel 31883db86aabSstevel if (utsname.nodename[0] != 0) { 31893db86aabSstevel plat_nodename_set_fun = 31903db86aabSstevel (void (*)(void))modgetsymvalue( 31913db86aabSstevel "plat_nodename_set", 0); 31923db86aabSstevel if (plat_nodename_set_fun != NULL) 31933db86aabSstevel plat_nodename_set_fun(); 31943db86aabSstevel } 31953db86aabSstevel 31963db86aabSstevel current_sgn_p = (sig_state_t *)modgetsymvalue( 31973db86aabSstevel "current_sgn", 0); 31983db86aabSstevel 3199f594b28aSjfrank /* 3200f594b28aSjfrank * Delay before calling CPU_SIGNATURE, to allow 3201f594b28aSjfrank * any pending asynchronous communications (i.e. 3202f594b28aSjfrank * plat_timesync()) to complete. This helps to 3203f594b28aSjfrank * prevent the situation where the message associated 3204f594b28aSjfrank * with the CPU_SIGNATURE state cannot be sent to the 3205f594b28aSjfrank * system controller. 3206f594b28aSjfrank */ 32073db86aabSstevel if ((current_sgn_p != NULL) && 32083db86aabSstevel (current_sgn_p->state_t.sig != 0)) { 3209f594b28aSjfrank delay(drv_usectohz(CPU_SIGNATURE_DELAY_TIME)); 32103db86aabSstevel CPU_SIGNATURE(current_sgn_p->state_t.sig, 32113db86aabSstevel current_sgn_p->state_t.state, 32123db86aabSstevel current_sgn_p->state_t.sub_state, -1); 32133db86aabSstevel 32143db86aabSstevel if (!(boothowto & RB_DEBUG)) { 3215f594b28aSjfrank /* 3216f594b28aSjfrank * Delay before calling 3217f594b28aSjfrank * send_watchdog_msg, to allow 3218f594b28aSjfrank * CPU_SIGNATURE() time to 3219f594b28aSjfrank * complete; this increases the 3220f594b28aSjfrank * chances of successfully sending 3221f594b28aSjfrank * the watchdog message to the 3222f594b28aSjfrank * system controller. 3223f594b28aSjfrank */ 3224f594b28aSjfrank delay(drv_usectohz( 3225f594b28aSjfrank CPU_SIGNATURE_DELAY_TIME)); 32263db86aabSstevel send_watchdog_msg(last_watchdog_msg); 32273db86aabSstevel } 32283db86aabSstevel } 32293db86aabSstevel } 32303db86aabSstevel 32313db86aabSstevel /* 32323db86aabSstevel * update keyswitch value in case it changed while the 32333db86aabSstevel * RMC was out of action 32343db86aabSstevel */ 32353db86aabSstevel LOCK_CACHE 32363db86aabSstevel if (rmclomv_sysinfo_valid) { 32373db86aabSstevel real_key_position = rmclomv_sysinfo_data.keyswitch; 32383db86aabSstevel if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) && 32393db86aabSstevel (real_key_position <= RMC_KEYSWITCH_POS_OFF)) { 32403db86aabSstevel key_position = real_key_position; 32413db86aabSstevel } else { 32423db86aabSstevel /* treat unknown key position as locked */ 32433db86aabSstevel key_position = RMC_KEYSWITCH_POS_LOCKED; 32443db86aabSstevel } 32453db86aabSstevel } else { 32463db86aabSstevel /* treat unreadable key position as locked */ 32473db86aabSstevel key_position = RMC_KEYSWITCH_POS_LOCKED; 32483db86aabSstevel real_key_position = RMC_KEYSWITCH_POS_UNKNOWN; 32493db86aabSstevel } 32503db86aabSstevel RELEASE_CACHE 32513db86aabSstevel 32523db86aabSstevel /* 32533db86aabSstevel * Re-enter the lock to prepare for another iteration. 32543db86aabSstevel * We must have the lock here to protect rmclomv_refresh_sig. 32553db86aabSstevel */ 32563db86aabSstevel mutex_enter(&rmclomv_refresh_lock); 32573db86aabSstevel } 32583db86aabSstevel } 32593db86aabSstevel 32603db86aabSstevel static void 32613db86aabSstevel rmclomv_refresh_start(void) 32623db86aabSstevel { 32633db86aabSstevel kthread_t *tp; 32643db86aabSstevel 32653db86aabSstevel mutex_enter(&rmclomv_refresh_lock); 32663db86aabSstevel 32673db86aabSstevel if (rmclomv_refresh_tid == 0) { 32683db86aabSstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW; 32693db86aabSstevel 32703db86aabSstevel tp = thread_create(NULL, 0, rmclomv_refresh, NULL, 0, 32713db86aabSstevel &p0, TS_RUN, maxclsyspri); 32723db86aabSstevel rmclomv_refresh_tid = tp->t_did; 32733db86aabSstevel } 32743db86aabSstevel 32753db86aabSstevel mutex_exit(&rmclomv_refresh_lock); 32763db86aabSstevel } 32773db86aabSstevel 32783db86aabSstevel static void 32793db86aabSstevel rmclomv_refresh_destroy(void) 32803db86aabSstevel { 32813db86aabSstevel kt_did_t tid; 32823db86aabSstevel 32833db86aabSstevel mutex_enter(&rmclomv_refresh_lock); 32843db86aabSstevel tid = rmclomv_refresh_tid; 32853db86aabSstevel if (tid != 0) { 32863db86aabSstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_EXITNOW; 32873db86aabSstevel cv_signal(&rmclomv_refresh_sig_cv); 32883db86aabSstevel rmclomv_refresh_tid = 0; 32893db86aabSstevel } 32903db86aabSstevel mutex_exit(&rmclomv_refresh_lock); 32913db86aabSstevel 32923db86aabSstevel /* 32933db86aabSstevel * Wait for rmclomv_refresh() to finish 32943db86aabSstevel */ 32953db86aabSstevel if (tid != 0) 32963db86aabSstevel thread_join(tid); 32973db86aabSstevel } 32983db86aabSstevel 32993db86aabSstevel static void 33003db86aabSstevel rmclomv_refresh_wakeup(void) 33013db86aabSstevel { 33023db86aabSstevel mutex_enter(&rmclomv_refresh_lock); 33033db86aabSstevel 33043db86aabSstevel if (rmclomv_refresh_sig != RMCLOMV_REFRESH_EXITNOW) 33053db86aabSstevel rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW; 33063db86aabSstevel cv_signal(&rmclomv_refresh_sig_cv); 33073db86aabSstevel 33083db86aabSstevel mutex_exit(&rmclomv_refresh_lock); 33093db86aabSstevel } 33103db86aabSstevel 33113db86aabSstevel static void 33123db86aabSstevel send_watchdog_msg(int msg) 33133db86aabSstevel { 33143db86aabSstevel rmc_comm_msg_t request; 33153db86aabSstevel dp_set_host_watchdog_t watchdog_msg; 33163db86aabSstevel 33173db86aabSstevel if (rmclomv_watchdog_mode) 33183db86aabSstevel return; 33193db86aabSstevel 33203db86aabSstevel watchdog_msg.enable = msg; 33213db86aabSstevel request.msg_type = DP_SET_HOST_WATCHDOG; 33223db86aabSstevel request.msg_len = sizeof (watchdog_msg); 33233db86aabSstevel request.msg_buf = (caddr_t)&watchdog_msg; 33243db86aabSstevel (void) rmc_comm_request_nowait(&request, (msg == 1) ? 33253db86aabSstevel RMC_COMM_DREQ_URGENT : 0); 33263db86aabSstevel } 33273db86aabSstevel 33283db86aabSstevel /*ARGSUSED*/ 33293db86aabSstevel static uint_t 33303db86aabSstevel rmc_set_watchdog_timer(uint_t timeoutval) 33313db86aabSstevel { 33323db86aabSstevel ASSERT(MUTEX_HELD(&tod_lock)); 33333db86aabSstevel 33343db86aabSstevel if ((watchdog_enable == 0) || (watchdog_available == 0)) { 33353db86aabSstevel return (0); 33363db86aabSstevel } 33373db86aabSstevel 33383db86aabSstevel /* 33393db86aabSstevel * If boothowto has RB_DEBUG set we never want to set the watchdog 33403db86aabSstevel * support on. 33413db86aabSstevel */ 33423db86aabSstevel if (boothowto & RB_DEBUG) { 33433db86aabSstevel return (0); 33443db86aabSstevel } 33453db86aabSstevel 33463db86aabSstevel /* 33473db86aabSstevel * When the watchdog is shut off last_watchdog_msg goes from a 33483db86aabSstevel * 0 to a 1. So we must test to see that last_watchdog_msg is 33493db86aabSstevel * set to 1 indicating that watchdog was shut off and 33503db86aabSstevel * After which we set last_watchdog_msg back to 0 so that we do not 33513db86aabSstevel * run this code 33523db86aabSstevel * again. 33533db86aabSstevel */ 33543db86aabSstevel if (last_watchdog_msg == 1) { 33553db86aabSstevel send_watchdog_msg(0); 33563db86aabSstevel last_watchdog_msg = 0; 33573db86aabSstevel } 33583db86aabSstevel 33593db86aabSstevel pmugpio_watchdog_pat(); 33603db86aabSstevel 33613db86aabSstevel watchdog_activated = 1; 33623db86aabSstevel 33633db86aabSstevel return (1); 33643db86aabSstevel } 33653db86aabSstevel 33663db86aabSstevel static uint_t 33673db86aabSstevel rmc_clear_watchdog_timer(void) 33683db86aabSstevel { 33693db86aabSstevel ASSERT(MUTEX_HELD(&tod_lock)); 33703db86aabSstevel if ((watchdog_activated == 0) || (boothowto & RB_DEBUG)) 33713db86aabSstevel return (0); 33723db86aabSstevel 33733db86aabSstevel send_watchdog_msg(1); 33743db86aabSstevel last_watchdog_msg = 1; 33753db86aabSstevel watchdog_activated = 0; 33763db86aabSstevel 33773db86aabSstevel return (0); 33783db86aabSstevel } 33793db86aabSstevel 33803db86aabSstevel static void 33813db86aabSstevel plat_timesync(void *arg) 33823db86aabSstevel { 33833db86aabSstevel timestruc_t now; 33843db86aabSstevel todinfo_t tod; 33853db86aabSstevel rmc_comm_msg_t request; 33863db86aabSstevel dp_set_date_time_t set_time_msg; 33873db86aabSstevel int retval; 33883db86aabSstevel timestruc_t ts; 33893db86aabSstevel dp_get_date_time_r_t *date_and_time_info; 33903db86aabSstevel int buffer[DATE_TIME_MSG_SIZE]; 33913db86aabSstevel 33923db86aabSstevel /* Is the system coming up? */ 33933db86aabSstevel if (arg != NULL) { 33943db86aabSstevel /* Request the time from the RMC clock. */ 33953db86aabSstevel retval = rmclomv_do_cmd(DP_GET_DATE_TIME, DP_GET_DATE_TIME_R, 33963db86aabSstevel DATE_TIME_MSG_SIZE, NULL, (intptr_t)&buffer); 33973db86aabSstevel 33983db86aabSstevel /* 33993db86aabSstevel * If we were able to get the time lets set the local clock. 34003db86aabSstevel * The time returned from RMC is in Unix time format. 34013db86aabSstevel * 34023db86aabSstevel * If we couldn't get the time we'll accept the drift so as not 34033db86aabSstevel * to cause congestion on the I2C bus or cause boot 34043db86aabSstevel * performance regressions. 34053db86aabSstevel */ 34063db86aabSstevel if (retval == RCNOERR) { 34073db86aabSstevel date_and_time_info = (dp_get_date_time_r_t *)buffer; 34083db86aabSstevel ts.tv_sec = date_and_time_info->current_datetime; 34093db86aabSstevel ts.tv_nsec = 0; 34103db86aabSstevel mutex_enter(&tod_lock); 34113db86aabSstevel tod_set(ts); 34123db86aabSstevel set_hrestime(&ts); 34133db86aabSstevel mutex_exit(&tod_lock); 34143db86aabSstevel } 34153db86aabSstevel } 34163db86aabSstevel 34173db86aabSstevel gethrestime(&now); 34183db86aabSstevel mutex_enter(&tod_lock); 34193db86aabSstevel tod = utc_to_tod(now.tv_sec); 34203db86aabSstevel mutex_exit(&tod_lock); 34213db86aabSstevel 34223db86aabSstevel set_time_msg.year = tod.tod_year; 34233db86aabSstevel set_time_msg.month = tod.tod_month - 1; 34243db86aabSstevel set_time_msg.day = tod.tod_day; 34253db86aabSstevel set_time_msg.hour = tod.tod_hour; 34263db86aabSstevel set_time_msg.minute = tod.tod_min; 34273db86aabSstevel set_time_msg.second = tod.tod_sec; 34283db86aabSstevel 34293db86aabSstevel request.msg_type = DP_SET_DATE_TIME; 34303db86aabSstevel request.msg_len = sizeof (set_time_msg); 34313db86aabSstevel request.msg_buf = (caddr_t)&set_time_msg; 34323db86aabSstevel 34333db86aabSstevel (void) rmc_comm_request_nowait(&request, 0); 34343db86aabSstevel 3435da14cebeSEric Cheng mutex_enter(×ync_lock); 3436da14cebeSEric Cheng if (timesync_interval != 0) 3437da14cebeSEric Cheng timesync_tid = timeout(plat_timesync, NULL, timesync_interval); 3438da14cebeSEric Cheng mutex_exit(×ync_lock); 34393db86aabSstevel } 34403db86aabSstevel 34413db86aabSstevel /* 34423db86aabSstevel * Interfaces to get/set alarm relays from outside 34433db86aabSstevel */ 34443db86aabSstevel int 34453db86aabSstevel rmclomv_alarm_get(int alarm_type, int *alarm_state) 34463db86aabSstevel { 34473db86aabSstevel rmclomv_cache_section_t *section; 34483db86aabSstevel int index; 34493db86aabSstevel uint16_t sensor_status; 34503db86aabSstevel dp_get_alarm_state_t u_rmc_alarm; 34513db86aabSstevel dp_get_alarm_state_r_t u_rmc_alarm_r; 34523db86aabSstevel 34533db86aabSstevel /* see if we've got ALARM handles cached */ 34543db86aabSstevel LOCK_CACHE 34553db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 34563db86aabSstevel 34573db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 34583db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 34593db86aabSstevel RMCLOMV_ALARM_IND)) == NULL)) { 34603db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 34613db86aabSstevel } 34623db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 34633db86aabSstevel /* 34643db86aabSstevel * user correctly identified a ALARM, note its 34653db86aabSstevel * handle value and request the ALARM status 34663db86aabSstevel */ 34673db86aabSstevel index = alarm_type; 34683db86aabSstevel if (index >= section->num_entries) 34693db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 34703db86aabSstevel else 34713db86aabSstevel u_rmc_alarm.handle = section->entry[index].handle; 34723db86aabSstevel } 34733db86aabSstevel RELEASE_CACHE 34743db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 34753db86aabSstevel rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R, 34763db86aabSstevel sizeof (u_rmc_alarm_r), (intptr_t)&u_rmc_alarm, 34773db86aabSstevel (intptr_t)&u_rmc_alarm_r) != 0)) { 34783db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 34793db86aabSstevel } 34803db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 34813db86aabSstevel /* 34823db86aabSstevel * copy results into buffer for user 34833db86aabSstevel * start with some defaults then override 34843db86aabSstevel */ 34853db86aabSstevel *alarm_state = 0; 34863db86aabSstevel 34873db86aabSstevel if (u_rmc_alarm_r.alarm_state[0].sensor_status != 34883db86aabSstevel DP_SENSOR_DATA_AVAILABLE) 34893db86aabSstevel return (ENXIO); 34903db86aabSstevel else { 34913db86aabSstevel dp_alarm_state_t alarmState; 34923db86aabSstevel alarmState = u_rmc_alarm_r.alarm_state[0]; 34933db86aabSstevel 34943db86aabSstevel switch (alarmState.state) { 34953db86aabSstevel case DP_ALARM_OFF: 34963db86aabSstevel break; 34973db86aabSstevel case DP_ALARM_ON: 34983db86aabSstevel *alarm_state = 1; 34993db86aabSstevel break; 35003db86aabSstevel default: 35013db86aabSstevel break; 35023db86aabSstevel } 35033db86aabSstevel } 35043db86aabSstevel } else 35053db86aabSstevel return (ENXIO); 35063db86aabSstevel 35073db86aabSstevel return (0); 35083db86aabSstevel } 35093db86aabSstevel 35103db86aabSstevel int 35113db86aabSstevel rmclomv_alarm_set(int alarm_type, int new_state) 35123db86aabSstevel { 35133db86aabSstevel rmclomv_cache_section_t *section; 35143db86aabSstevel int index; 35153db86aabSstevel uint16_t sensor_status; 35163db86aabSstevel dp_set_alarm_state_t u_rmc_setalarm; 35173db86aabSstevel dp_set_alarm_state_r_t u_rmc_setalarm_r; 35183db86aabSstevel 35193db86aabSstevel /* see if we've got ALARM handles cached */ 35203db86aabSstevel LOCK_CACHE 35213db86aabSstevel sensor_status = ENVMON_SENSOR_OK; 35223db86aabSstevel 35233db86aabSstevel if ((rmclomv_cache_valid == B_FALSE) || 35243db86aabSstevel ((section = rmclomv_find_section(rmclomv_cache, 35253db86aabSstevel RMCLOMV_ALARM_IND)) == NULL)) { 35263db86aabSstevel sensor_status = ENVMON_NOT_PRESENT; 35273db86aabSstevel } 35283db86aabSstevel if (sensor_status == ENVMON_SENSOR_OK) { 35293db86aabSstevel /* 35303db86aabSstevel * user correctly identified a ALARM, note its 35313db86aabSstevel * handle value and request the ALARM status 35323db86aabSstevel */ 35333db86aabSstevel index = alarm_type; 35343db86aabSstevel if (index >= section->num_entries) 35353db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 35363db86aabSstevel else { 35373db86aabSstevel u_rmc_setalarm.handle = section->entry[index].handle; 35383db86aabSstevel u_rmc_setalarm.state = new_state; 35393db86aabSstevel } 35403db86aabSstevel } 35413db86aabSstevel RELEASE_CACHE 35423db86aabSstevel if ((sensor_status == ENVMON_SENSOR_OK) && 35433db86aabSstevel (rmclomv_rmc_error || 35443db86aabSstevel rmclomv_do_cmd(DP_SET_ALARM_STATE, DP_SET_ALARM_STATE_R, 35453db86aabSstevel sizeof (u_rmc_setalarm_r), (intptr_t)&u_rmc_setalarm, 35463db86aabSstevel (intptr_t)&u_rmc_setalarm_r) != 0)) { 35473db86aabSstevel sensor_status = ENVMON_INACCESSIBLE; 35483db86aabSstevel } 35493db86aabSstevel 35503db86aabSstevel if (u_rmc_setalarm_r.status != DP_SET_ALARM_OK) { 35513db86aabSstevel return (EIO); 35523db86aabSstevel } 35533db86aabSstevel 35543db86aabSstevel if (sensor_status != ENVMON_SENSOR_OK) { 35553db86aabSstevel return (ENXIO); 35563db86aabSstevel } 35573db86aabSstevel 35583db86aabSstevel return (0); 35593db86aabSstevel } 3560