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