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