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