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