xref: /onnv-gate/usr/src/uts/sun4u/io/rmclomv.c (revision 7656:2621e50fdf4a)
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 = &section->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 = &section->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)&ampi_cmd, (intptr_t)&ampi_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