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