xref: /titanic_52/usr/src/uts/sun4u/io/rmclomv.c (revision 3db86aab554edbb4244c8d1a1c90f152eee768af)
1*3db86aabSstevel /*
2*3db86aabSstevel  * CDDL HEADER START
3*3db86aabSstevel  *
4*3db86aabSstevel  * The contents of this file are subject to the terms of the
5*3db86aabSstevel  * Common Development and Distribution License (the "License").
6*3db86aabSstevel  * You may not use this file except in compliance with the License.
7*3db86aabSstevel  *
8*3db86aabSstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3db86aabSstevel  * or http://www.opensolaris.org/os/licensing.
10*3db86aabSstevel  * See the License for the specific language governing permissions
11*3db86aabSstevel  * and limitations under the License.
12*3db86aabSstevel  *
13*3db86aabSstevel  * When distributing Covered Code, include this CDDL HEADER in each
14*3db86aabSstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3db86aabSstevel  * If applicable, add the following below this CDDL HEADER, with the
16*3db86aabSstevel  * fields enclosed by brackets "[]" replaced with your own identifying
17*3db86aabSstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3db86aabSstevel  *
19*3db86aabSstevel  * CDDL HEADER END
20*3db86aabSstevel  */
21*3db86aabSstevel 
22*3db86aabSstevel /*
23*3db86aabSstevel  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*3db86aabSstevel  * Use is subject to license terms.
25*3db86aabSstevel  */
26*3db86aabSstevel 
27*3db86aabSstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*3db86aabSstevel 
29*3db86aabSstevel #include <sys/types.h>
30*3db86aabSstevel #include <sys/stat.h>
31*3db86aabSstevel #include <sys/conf.h>
32*3db86aabSstevel #include <sys/modctl.h>
33*3db86aabSstevel #include <sys/callb.h>
34*3db86aabSstevel #include <sys/strlog.h>
35*3db86aabSstevel #include <sys/cyclic.h>
36*3db86aabSstevel #include <sys/rmc_comm_dp.h>
37*3db86aabSstevel #include <sys/rmc_comm_dp_boot.h>
38*3db86aabSstevel #include <sys/rmc_comm_drvintf.h>
39*3db86aabSstevel #include <sys/rmc_comm.h>
40*3db86aabSstevel #include <sys/machsystm.h>
41*3db86aabSstevel #include <sys/sysevent.h>
42*3db86aabSstevel #include <sys/sysevent/dr.h>
43*3db86aabSstevel #include <sys/sysevent/env.h>
44*3db86aabSstevel #include <sys/sysevent/eventdefs.h>
45*3db86aabSstevel #include <sys/file.h>
46*3db86aabSstevel #include <sys/disp.h>
47*3db86aabSstevel #include <sys/reboot.h>
48*3db86aabSstevel #include <sys/envmon.h>
49*3db86aabSstevel #include <sys/rmclomv_impl.h>
50*3db86aabSstevel #include <sys/cpu_sgnblk_defs.h>
51*3db86aabSstevel #include <sys/utsname.h>
52*3db86aabSstevel #include <sys/systeminfo.h>
53*3db86aabSstevel #include <sys/ddi.h>
54*3db86aabSstevel #include <sys/time.h>
55*3db86aabSstevel #include <sys/promif.h>
56*3db86aabSstevel 
57*3db86aabSstevel #define	offsetof(s, m)	(size_t)(&(((s *)0)->m))
58*3db86aabSstevel #define	RMCRESBUFLEN	1024
59*3db86aabSstevel #define	DATE_TIME_MSG_SIZE	78
60*3db86aabSstevel #define	RMCLOMV_WATCHDOG_MODE	"rmclomv-watchdog-mode"
61*3db86aabSstevel 
62*3db86aabSstevel extern void	pmugpio_watchdog_pat();
63*3db86aabSstevel static clock_t	timesync_interval;
64*3db86aabSstevel 
65*3db86aabSstevel extern int	watchdog_activated;
66*3db86aabSstevel static int	last_watchdog_msg = 1;
67*3db86aabSstevel extern int	watchdog_enable;
68*3db86aabSstevel extern int	boothowto;
69*3db86aabSstevel 
70*3db86aabSstevel int		rmclomv_watchdog_mode;
71*3db86aabSstevel 
72*3db86aabSstevel /*
73*3db86aabSstevel  * functions local to this driver.
74*3db86aabSstevel  */
75*3db86aabSstevel static int	rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
76*3db86aabSstevel     void **resultp);
77*3db86aabSstevel static int	rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
78*3db86aabSstevel static int	rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
79*3db86aabSstevel static uint_t	rmclomv_break_intr(caddr_t arg);
80*3db86aabSstevel static int	rmclomv_add_intr_handlers(void);
81*3db86aabSstevel static int	rmclomv_remove_intr_handlers(void);
82*3db86aabSstevel static uint_t	rmclomv_event_data_handler(char *);
83*3db86aabSstevel static void	rmclomv_dr_data_handler(const char *, int);
84*3db86aabSstevel static int	rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
85*3db86aabSstevel static int	rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
86*3db86aabSstevel static int	rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
87*3db86aabSstevel     cred_t *cred_p, int *rval_p);
88*3db86aabSstevel static void	rmclomv_checkrmc_start(void);
89*3db86aabSstevel static void	rmclomv_checkrmc_destroy(void);
90*3db86aabSstevel static void	rmclomv_checkrmc_wakeup(void *);
91*3db86aabSstevel static void	rmclomv_refresh_start(void);
92*3db86aabSstevel static void	rmclomv_refresh_destroy(void);
93*3db86aabSstevel static void	rmclomv_refresh_wakeup(void);
94*3db86aabSstevel static void	rmclomv_reset_cache(rmclomv_cache_section_t *new_chain,
95*3db86aabSstevel     rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo);
96*3db86aabSstevel static rmclomv_cache_section_t *rmclomv_find_section(
97*3db86aabSstevel     rmclomv_cache_section_t *start, uint16_t sensor);
98*3db86aabSstevel static rmclomv_cache_section_t *create_cache_section(int sensor_type, int num);
99*3db86aabSstevel static int	get_sensor_by_name(const rmclomv_cache_section_t *section,
100*3db86aabSstevel     const char *name, int *index);
101*3db86aabSstevel static int	validate_section_entry(rmclomv_cache_section_t *section,
102*3db86aabSstevel     int index);
103*3db86aabSstevel static int	add_names_to_section(rmclomv_cache_section_t *section);
104*3db86aabSstevel static void	free_section(rmclomv_cache_section_t *section);
105*3db86aabSstevel static void	add_section(rmclomv_cache_section_t **head,
106*3db86aabSstevel     rmclomv_cache_section_t *section);
107*3db86aabSstevel static int	rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len,
108*3db86aabSstevel     intptr_t arg_req, intptr_t arg_res);
109*3db86aabSstevel static void	refresh_name_cache(int force_fail);
110*3db86aabSstevel static void	set_val_unav(envmon_sensor_t *sensor);
111*3db86aabSstevel static void	set_fan_unav(envmon_fan_t *fan);
112*3db86aabSstevel static int	do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind,
113*3db86aabSstevel     dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r,
114*3db86aabSstevel     int detector_type);
115*3db86aabSstevel static uint_t rmc_set_watchdog_timer(uint_t timeoutval);
116*3db86aabSstevel static uint_t rmc_clear_watchdog_timer(void);
117*3db86aabSstevel static void send_watchdog_msg(int msg);
118*3db86aabSstevel static void plat_timesync(void *arg);
119*3db86aabSstevel 
120*3db86aabSstevel /*
121*3db86aabSstevel  * Driver entry points
122*3db86aabSstevel  */
123*3db86aabSstevel static struct cb_ops rmclomv_cb_ops = {
124*3db86aabSstevel 	rmclomv_open,	/* open */
125*3db86aabSstevel 	rmclomv_close,	/* close */
126*3db86aabSstevel 	nodev,		/* strategy() */
127*3db86aabSstevel 	nodev,		/* print() */
128*3db86aabSstevel 	nodev,		/* dump() */
129*3db86aabSstevel 	nodev,		/* read() */
130*3db86aabSstevel 	nodev,		/* write() */
131*3db86aabSstevel 	rmclomv_ioctl,	/* ioctl() */
132*3db86aabSstevel 	nodev,		/* devmap() */
133*3db86aabSstevel 	nodev,		/* mmap() */
134*3db86aabSstevel 	ddi_segmap,	/* segmap() */
135*3db86aabSstevel 	nochpoll,	/* poll() */
136*3db86aabSstevel 	ddi_prop_op,    /* prop_op() */
137*3db86aabSstevel 	NULL,		/* cb_str */
138*3db86aabSstevel 	D_NEW | D_MP	/* cb_flag */
139*3db86aabSstevel };
140*3db86aabSstevel 
141*3db86aabSstevel 
142*3db86aabSstevel static struct dev_ops rmclomv_ops = {
143*3db86aabSstevel 	DEVO_REV,
144*3db86aabSstevel 	0,			/* ref count */
145*3db86aabSstevel 	rmclomv_getinfo,	/* getinfo() */
146*3db86aabSstevel 	nulldev,		/* identify() */
147*3db86aabSstevel 	nulldev,		/* probe() */
148*3db86aabSstevel 	rmclomv_attach,		/* attach() */
149*3db86aabSstevel 	rmclomv_detach,		/* detach */
150*3db86aabSstevel 	nodev,			/* reset */
151*3db86aabSstevel 	&rmclomv_cb_ops,		/* pointer to cb_ops structure */
152*3db86aabSstevel 	(struct bus_ops *)NULL,
153*3db86aabSstevel 	nulldev			/* power() */
154*3db86aabSstevel };
155*3db86aabSstevel 
156*3db86aabSstevel /*
157*3db86aabSstevel  * Loadable module support.
158*3db86aabSstevel  */
159*3db86aabSstevel extern struct mod_ops mod_driverops;
160*3db86aabSstevel 
161*3db86aabSstevel static struct modldrv modldrv = {
162*3db86aabSstevel 	&mod_driverops,			/* Type of module. This is a driver */
163*3db86aabSstevel 	"rmclomv control driver v%I%",	/* Name of the module */
164*3db86aabSstevel 	&rmclomv_ops			/* pointer to the dev_ops structure */
165*3db86aabSstevel };
166*3db86aabSstevel 
167*3db86aabSstevel static struct modlinkage modlinkage = {
168*3db86aabSstevel 	MODREV_1,
169*3db86aabSstevel 	&modldrv,
170*3db86aabSstevel 	NULL
171*3db86aabSstevel };
172*3db86aabSstevel 
173*3db86aabSstevel /*
174*3db86aabSstevel  * Device info
175*3db86aabSstevel  */
176*3db86aabSstevel static dev_info_t		*rmclomv_dip = NULL;
177*3db86aabSstevel static int			rmclomv_break_requested = B_FALSE;
178*3db86aabSstevel static ddi_softintr_t		rmclomv_softintr_id;
179*3db86aabSstevel static ddi_iblock_cookie_t	rmclomv_soft_iblock_cookie;
180*3db86aabSstevel 
181*3db86aabSstevel extern void (*abort_seq_handler)();
182*3db86aabSstevel /* key_position is effective key-position. Set to locked if unknown */
183*3db86aabSstevel static rsci8 key_position = RMC_KEYSWITCH_POS_LOCKED;
184*3db86aabSstevel /* real_key_position starts off as unknown and records value actually seen */
185*3db86aabSstevel static rsci8 real_key_position = RMC_KEYSWITCH_POS_UNKNOWN;
186*3db86aabSstevel static void rmclomv_abort_seq_handler(char *msg);
187*3db86aabSstevel 
188*3db86aabSstevel /*
189*3db86aabSstevel  * mutexes which protect the interrupt handlers.
190*3db86aabSstevel  */
191*3db86aabSstevel static kmutex_t		rmclomv_event_hdlr_lock;
192*3db86aabSstevel static kmutex_t		rmclomv_refresh_lock;
193*3db86aabSstevel static kcondvar_t	rmclomv_refresh_sig_cv;
194*3db86aabSstevel static kmutex_t		rmclomv_checkrmc_lock;
195*3db86aabSstevel static kcondvar_t	rmclomv_checkrmc_sig_cv;
196*3db86aabSstevel 
197*3db86aabSstevel /*
198*3db86aabSstevel  * mutex to protect the handle_name cache
199*3db86aabSstevel  */
200*3db86aabSstevel static kmutex_t		rmclomv_cache_lock;
201*3db86aabSstevel 
202*3db86aabSstevel /*
203*3db86aabSstevel  * mutex to protect the RMC state
204*3db86aabSstevel  */
205*3db86aabSstevel static kmutex_t		rmclomv_state_lock;
206*3db86aabSstevel 
207*3db86aabSstevel /*
208*3db86aabSstevel  * Payloads of the event handlers.
209*3db86aabSstevel  */
210*3db86aabSstevel static dp_event_notification_t	rmclomv_event_payload;
211*3db86aabSstevel static rmc_comm_msg_t	rmclomv_event_payload_msg;
212*3db86aabSstevel 
213*3db86aabSstevel /*
214*3db86aabSstevel  * Checkrmc commands..
215*3db86aabSstevel  */
216*3db86aabSstevel #define	RMCLOMV_CHECKRMC_EXITNOW	(-1)
217*3db86aabSstevel #define	RMCLOMV_CHECKRMC_WAIT		0
218*3db86aabSstevel #define	RMCLOMV_CHECKRMC_PROCESSNOW	1
219*3db86aabSstevel 
220*3db86aabSstevel /*
221*3db86aabSstevel  * Checkrmc thread state
222*3db86aabSstevel  */
223*3db86aabSstevel static int rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
224*3db86aabSstevel static kt_did_t rmclomv_checkrmc_tid = 0;
225*3db86aabSstevel 
226*3db86aabSstevel /*
227*3db86aabSstevel  * RMC state data
228*3db86aabSstevel  */
229*3db86aabSstevel #define	RMCLOMV_RMCSTATE_UNKNOWN	0
230*3db86aabSstevel #define	RMCLOMV_RMCSTATE_OK		1
231*3db86aabSstevel #define	RMCLOMV_RMCSTATE_FAILED		2
232*3db86aabSstevel #define	RMCLOMV_RMCSTATE_DOWNLOAD	3
233*3db86aabSstevel 
234*3db86aabSstevel /*
235*3db86aabSstevel  * RMC error indicator values (status from last RMC command)
236*3db86aabSstevel  */
237*3db86aabSstevel #define	RMCLOMV_RMCERROR_NONE		0
238*3db86aabSstevel 
239*3db86aabSstevel /* fail RMC after 5 minutes without a good response */
240*3db86aabSstevel #define	RMCLOMV_RMCFAILTHRESHOLD	5
241*3db86aabSstevel 
242*3db86aabSstevel /*
243*3db86aabSstevel  * rmclomv_rmc_state is the state reported in OperationalStatus.
244*3db86aabSstevel  * rmclomv_rmc_error reflects the result of the last RMC interaction.
245*3db86aabSstevel  * rmclomv_rmcfailcount is used by the rmclomv_checkrmc thread to count
246*3db86aabSstevel  * failures in its regular status polls. Once RMCLOMV_RMCFAILTHRESHOLD
247*3db86aabSstevel  * is reached, rmclomv_rmc_state is marked as RMCLOMV_RMCSTATE_FAILED.
248*3db86aabSstevel  */
249*3db86aabSstevel static int	rmclomv_rmc_state = RMCLOMV_RMCSTATE_UNKNOWN;
250*3db86aabSstevel static int	rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE;
251*3db86aabSstevel static int	rmclomv_rmcfailcount;
252*3db86aabSstevel 
253*3db86aabSstevel /*
254*3db86aabSstevel  * Refresh commands..
255*3db86aabSstevel  */
256*3db86aabSstevel #define	RMCLOMV_REFRESH_EXITNOW		(-1)
257*3db86aabSstevel #define	RMCLOMV_REFRESH_WAIT		0
258*3db86aabSstevel #define	RMCLOMV_REFRESH_PROCESSNOW	1
259*3db86aabSstevel 
260*3db86aabSstevel /*
261*3db86aabSstevel  * Refresh thread state
262*3db86aabSstevel  */
263*3db86aabSstevel static int rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
264*3db86aabSstevel static kt_did_t rmclomv_refresh_tid = 0;
265*3db86aabSstevel 
266*3db86aabSstevel /*
267*3db86aabSstevel  * timeout id
268*3db86aabSstevel  */
269*3db86aabSstevel static timeout_id_t	timer_id;
270*3db86aabSstevel 
271*3db86aabSstevel /*
272*3db86aabSstevel  * Handle-name cache
273*3db86aabSstevel  */
274*3db86aabSstevel #define	LOCK_CACHE		mutex_enter(&rmclomv_cache_lock);
275*3db86aabSstevel #define	RELEASE_CACHE		mutex_exit(&rmclomv_cache_lock);
276*3db86aabSstevel static rmclomv_cache_section_t	*rmclomv_cache;		/* main handle-names */
277*3db86aabSstevel static rmclomv_cache_section_t	*rmclomv_subcache;	/* derived names */
278*3db86aabSstevel static dp_get_sysinfo_r_t	rmclomv_sysinfo_data;
279*3db86aabSstevel static boolean_t		rmclomv_sysinfo_valid;
280*3db86aabSstevel static int			rmclomv_cache_valid;
281*3db86aabSstevel 
282*3db86aabSstevel extern pri_t maxclsyspri;
283*3db86aabSstevel 
284*3db86aabSstevel /*
285*3db86aabSstevel  * static strings
286*3db86aabSstevel  */
287*3db86aabSstevel static const char	str_percent[]		= "%";
288*3db86aabSstevel static const char	str_rpm[]		= " rpm";
289*3db86aabSstevel static const char	str_ip_volts_ind[]	= "P_PWR";
290*3db86aabSstevel static const char	str_ip2_volts_ind[]	= "P_PWR2";
291*3db86aabSstevel static const char	str_ff_pok_ind[]	= "FF_POK";
292*3db86aabSstevel static const char	str_vlo_volts_ind[]	= "FF_UV";
293*3db86aabSstevel static const char	str_vhi_volts_ind[]	= "FF_OV";
294*3db86aabSstevel static const char	str_chi_amps_ind[]	= "FF_OC";
295*3db86aabSstevel static const char	str_chi_nr_ind[]	= "FF_NR";
296*3db86aabSstevel static const char	str_ot_tmpr_ind[]	= "FF_OT";
297*3db86aabSstevel static const char	str_fan_ind[]		= "FF_FAN";
298*3db86aabSstevel static const char	str_pdct_fan_ind[]	= "FF_PDCT_FAN";
299*3db86aabSstevel static const char	str_sc[]		= "SC";
300*3db86aabSstevel 
301*3db86aabSstevel int
302*3db86aabSstevel _init(void)
303*3db86aabSstevel {
304*3db86aabSstevel 	int	error = 0;
305*3db86aabSstevel 
306*3db86aabSstevel 	mutex_init(&rmclomv_event_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
307*3db86aabSstevel 	mutex_init(&rmclomv_checkrmc_lock, NULL, MUTEX_DRIVER, NULL);
308*3db86aabSstevel 	mutex_init(&rmclomv_refresh_lock, NULL, MUTEX_DRIVER, NULL);
309*3db86aabSstevel 	mutex_init(&rmclomv_cache_lock, NULL, MUTEX_DRIVER, NULL);
310*3db86aabSstevel 	mutex_init(&rmclomv_state_lock, NULL, MUTEX_DRIVER, NULL);
311*3db86aabSstevel 	cv_init(&rmclomv_checkrmc_sig_cv, NULL, CV_DRIVER, NULL);
312*3db86aabSstevel 	cv_init(&rmclomv_refresh_sig_cv, NULL, CV_DRIVER, NULL);
313*3db86aabSstevel 
314*3db86aabSstevel 	error = mod_install(&modlinkage);
315*3db86aabSstevel 	if (error) {
316*3db86aabSstevel 		cv_destroy(&rmclomv_refresh_sig_cv);
317*3db86aabSstevel 		cv_destroy(&rmclomv_checkrmc_sig_cv);
318*3db86aabSstevel 		mutex_destroy(&rmclomv_state_lock);
319*3db86aabSstevel 		mutex_destroy(&rmclomv_cache_lock);
320*3db86aabSstevel 		mutex_destroy(&rmclomv_refresh_lock);
321*3db86aabSstevel 		mutex_destroy(&rmclomv_checkrmc_lock);
322*3db86aabSstevel 		mutex_destroy(&rmclomv_event_hdlr_lock);
323*3db86aabSstevel 	}
324*3db86aabSstevel 	return (error);
325*3db86aabSstevel }
326*3db86aabSstevel 
327*3db86aabSstevel 
328*3db86aabSstevel int
329*3db86aabSstevel _info(struct modinfo *modinfop)
330*3db86aabSstevel {
331*3db86aabSstevel 	return (mod_info(&modlinkage, modinfop));
332*3db86aabSstevel }
333*3db86aabSstevel 
334*3db86aabSstevel 
335*3db86aabSstevel int
336*3db86aabSstevel _fini(void)
337*3db86aabSstevel {
338*3db86aabSstevel 	int	error = 0;
339*3db86aabSstevel 
340*3db86aabSstevel 	error = mod_remove(&modlinkage);
341*3db86aabSstevel 	if (error)
342*3db86aabSstevel 		return (error);
343*3db86aabSstevel 	cv_destroy(&rmclomv_refresh_sig_cv);
344*3db86aabSstevel 	cv_destroy(&rmclomv_checkrmc_sig_cv);
345*3db86aabSstevel 	mutex_destroy(&rmclomv_state_lock);
346*3db86aabSstevel 	mutex_destroy(&rmclomv_cache_lock);
347*3db86aabSstevel 	mutex_destroy(&rmclomv_refresh_lock);
348*3db86aabSstevel 	mutex_destroy(&rmclomv_checkrmc_lock);
349*3db86aabSstevel 	mutex_destroy(&rmclomv_event_hdlr_lock);
350*3db86aabSstevel 	return (error);
351*3db86aabSstevel }
352*3db86aabSstevel 
353*3db86aabSstevel 
354*3db86aabSstevel /* ARGSUSED */
355*3db86aabSstevel static int
356*3db86aabSstevel rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
357*3db86aabSstevel {
358*3db86aabSstevel 	minor_t m = getminor((dev_t)arg);
359*3db86aabSstevel 
360*3db86aabSstevel 	switch (cmd) {
361*3db86aabSstevel 	case DDI_INFO_DEVT2DEVINFO:
362*3db86aabSstevel 		if ((m != 0) || (rmclomv_dip == NULL)) {
363*3db86aabSstevel 			*resultp = NULL;
364*3db86aabSstevel 			return (DDI_FAILURE);
365*3db86aabSstevel 		}
366*3db86aabSstevel 		*resultp = rmclomv_dip;
367*3db86aabSstevel 		return (DDI_SUCCESS);
368*3db86aabSstevel 	case DDI_INFO_DEVT2INSTANCE:
369*3db86aabSstevel 		*resultp = (void *)(uintptr_t)m;
370*3db86aabSstevel 		return (DDI_SUCCESS);
371*3db86aabSstevel 	default:
372*3db86aabSstevel 		return (DDI_FAILURE);
373*3db86aabSstevel 	}
374*3db86aabSstevel }
375*3db86aabSstevel 
376*3db86aabSstevel 
377*3db86aabSstevel static int
378*3db86aabSstevel rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
379*3db86aabSstevel {
380*3db86aabSstevel 	int			instance;
381*3db86aabSstevel 	int			err;
382*3db86aabSstevel 	char			*wdog_state;
383*3db86aabSstevel 	int			attaching = 1;
384*3db86aabSstevel 
385*3db86aabSstevel 	switch (cmd) {
386*3db86aabSstevel 	case DDI_ATTACH:
387*3db86aabSstevel 		/*
388*3db86aabSstevel 		 * only allow one instance
389*3db86aabSstevel 		 */
390*3db86aabSstevel 		instance = ddi_get_instance(dip);
391*3db86aabSstevel 		if (instance != 0)
392*3db86aabSstevel 			return (DDI_FAILURE);
393*3db86aabSstevel 
394*3db86aabSstevel 		err = ddi_create_minor_node(dip, "rmclomv", S_IFCHR,
395*3db86aabSstevel 			instance, DDI_PSEUDO, NULL);
396*3db86aabSstevel 		if (err != DDI_SUCCESS)
397*3db86aabSstevel 			return (DDI_FAILURE);
398*3db86aabSstevel 
399*3db86aabSstevel 		/*
400*3db86aabSstevel 		 * Register with rmc_comm to prevent it being detached
401*3db86aabSstevel 		 * (in the unlikely event that its attach succeeded on a
402*3db86aabSstevel 		 * platform whose platmod doesn't lock it down).
403*3db86aabSstevel 		 */
404*3db86aabSstevel 		err = rmc_comm_register();
405*3db86aabSstevel 		if (err != DDI_SUCCESS) {
406*3db86aabSstevel 			ddi_remove_minor_node(dip, NULL);
407*3db86aabSstevel 			return (DDI_FAILURE);
408*3db86aabSstevel 		}
409*3db86aabSstevel 
410*3db86aabSstevel 		/* Remember the dev info */
411*3db86aabSstevel 		rmclomv_dip = dip;
412*3db86aabSstevel 
413*3db86aabSstevel 		/*
414*3db86aabSstevel 		 * Add the handlers which watch for unsolicited messages
415*3db86aabSstevel 		 * and post event to Sysevent Framework.
416*3db86aabSstevel 		 */
417*3db86aabSstevel 		err = rmclomv_add_intr_handlers();
418*3db86aabSstevel 		if (err != DDI_SUCCESS) {
419*3db86aabSstevel 			rmc_comm_unregister();
420*3db86aabSstevel 			ddi_remove_minor_node(dip, NULL);
421*3db86aabSstevel 			rmclomv_dip = NULL;
422*3db86aabSstevel 			return (DDI_FAILURE);
423*3db86aabSstevel 		}
424*3db86aabSstevel 
425*3db86aabSstevel 		rmclomv_checkrmc_start();
426*3db86aabSstevel 		rmclomv_refresh_start();
427*3db86aabSstevel 
428*3db86aabSstevel 		abort_seq_handler = rmclomv_abort_seq_handler;
429*3db86aabSstevel 		ddi_report_dev(dip);
430*3db86aabSstevel 
431*3db86aabSstevel 		/*
432*3db86aabSstevel 		 * Check whether we have an application watchdog
433*3db86aabSstevel 		 */
434*3db86aabSstevel 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
435*3db86aabSstevel 			DDI_PROP_DONTPASS, RMCLOMV_WATCHDOG_MODE,
436*3db86aabSstevel 			&wdog_state) == DDI_PROP_SUCCESS) {
437*3db86aabSstevel 			if (strcmp(wdog_state, "app") == 0) {
438*3db86aabSstevel 				rmclomv_watchdog_mode = 1;
439*3db86aabSstevel 				watchdog_enable = 0;
440*3db86aabSstevel 			}
441*3db86aabSstevel 			else
442*3db86aabSstevel 				rmclomv_watchdog_mode = 0;
443*3db86aabSstevel 			ddi_prop_free(wdog_state);
444*3db86aabSstevel 		}
445*3db86aabSstevel 
446*3db86aabSstevel 		tod_ops.tod_set_watchdog_timer = rmc_set_watchdog_timer;
447*3db86aabSstevel 		tod_ops.tod_clear_watchdog_timer = rmc_clear_watchdog_timer;
448*3db86aabSstevel 
449*3db86aabSstevel 		/*
450*3db86aabSstevel 		 * Now is a good time to activate hardware watchdog
451*3db86aabSstevel 		 * (if one exists).
452*3db86aabSstevel 		 */
453*3db86aabSstevel 		mutex_enter(&tod_lock);
454*3db86aabSstevel 		if (watchdog_enable && tod_ops.tod_set_watchdog_timer != NULL)
455*3db86aabSstevel 			err = tod_ops.tod_set_watchdog_timer(0);
456*3db86aabSstevel 		mutex_exit(&tod_lock);
457*3db86aabSstevel 		if (err != 0)
458*3db86aabSstevel 			printf("Hardware watchdog enabled\n");
459*3db86aabSstevel 
460*3db86aabSstevel 		/*
461*3db86aabSstevel 		 * Set time interval and start timesync routine.
462*3db86aabSstevel 		 * Also just this once set the Solaris clock
463*3db86aabSstevel 		 * to the RMC clock.
464*3db86aabSstevel 		 */
465*3db86aabSstevel 		timesync_interval = drv_usectohz(5*60 * MICROSEC);
466*3db86aabSstevel 		plat_timesync((void *) &attaching);
467*3db86aabSstevel 
468*3db86aabSstevel 		return (DDI_SUCCESS);
469*3db86aabSstevel 	case DDI_RESUME:
470*3db86aabSstevel 		return (DDI_SUCCESS);
471*3db86aabSstevel 	default:
472*3db86aabSstevel 		return (DDI_FAILURE);
473*3db86aabSstevel 	}
474*3db86aabSstevel }
475*3db86aabSstevel 
476*3db86aabSstevel 
477*3db86aabSstevel static int
478*3db86aabSstevel rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
479*3db86aabSstevel {
480*3db86aabSstevel 	int	instance;
481*3db86aabSstevel 	int	err;
482*3db86aabSstevel 
483*3db86aabSstevel 	switch (cmd) {
484*3db86aabSstevel 	case DDI_DETACH:
485*3db86aabSstevel 		instance = ddi_get_instance(dip);
486*3db86aabSstevel 		if (instance != 0)
487*3db86aabSstevel 			return (DDI_FAILURE);
488*3db86aabSstevel 
489*3db86aabSstevel 		/*
490*3db86aabSstevel 		 * Remove the handlers which watch for unsolicited messages
491*3db86aabSstevel 		 * and post event to Sysevent Framework.
492*3db86aabSstevel 		 */
493*3db86aabSstevel 		err = rmclomv_remove_intr_handlers();
494*3db86aabSstevel 		if (err != DDI_SUCCESS) {
495*3db86aabSstevel 			cmn_err(CE_WARN, "Failed to remove event handlers");
496*3db86aabSstevel 			return (DDI_FAILURE);
497*3db86aabSstevel 		}
498*3db86aabSstevel 		rmclomv_checkrmc_destroy();
499*3db86aabSstevel 		rmclomv_refresh_destroy();
500*3db86aabSstevel 		rmclomv_reset_cache(NULL, NULL, NULL);
501*3db86aabSstevel 		ddi_remove_minor_node(dip, NULL);
502*3db86aabSstevel 
503*3db86aabSstevel 		/* Forget the dev info */
504*3db86aabSstevel 		rmclomv_dip = NULL;
505*3db86aabSstevel 		rmc_comm_unregister();
506*3db86aabSstevel 		return (DDI_SUCCESS);
507*3db86aabSstevel 	case DDI_SUSPEND:
508*3db86aabSstevel 		return (DDI_SUCCESS);
509*3db86aabSstevel 	default:
510*3db86aabSstevel 		return (DDI_FAILURE);
511*3db86aabSstevel 	}
512*3db86aabSstevel }
513*3db86aabSstevel 
514*3db86aabSstevel static int
515*3db86aabSstevel rmclomv_add_intr_handlers()
516*3db86aabSstevel {
517*3db86aabSstevel 	int	err;
518*3db86aabSstevel 
519*3db86aabSstevel 	if (ddi_get_soft_iblock_cookie(rmclomv_dip, DDI_SOFTINT_HIGH,
520*3db86aabSstevel 	    &rmclomv_soft_iblock_cookie) != DDI_SUCCESS) {
521*3db86aabSstevel 		return (DDI_FAILURE);
522*3db86aabSstevel 	}
523*3db86aabSstevel 	err = ddi_add_softintr(rmclomv_dip, DDI_SOFTINT_HIGH,
524*3db86aabSstevel 	    &rmclomv_softintr_id, &rmclomv_soft_iblock_cookie, NULL,
525*3db86aabSstevel 	    rmclomv_break_intr, NULL);
526*3db86aabSstevel 	if (err != DDI_SUCCESS)
527*3db86aabSstevel 		return (DDI_FAILURE);
528*3db86aabSstevel 	rmclomv_event_payload_msg.msg_buf = (caddr_t)&rmclomv_event_payload;
529*3db86aabSstevel 	rmclomv_event_payload_msg.msg_len = sizeof (rmclomv_event_payload);
530*3db86aabSstevel 	err = rmc_comm_reg_intr(DP_RMC_EVENTS, rmclomv_event_data_handler,
531*3db86aabSstevel 	    &rmclomv_event_payload_msg, NULL, &rmclomv_event_hdlr_lock);
532*3db86aabSstevel 	if (err != 0) {
533*3db86aabSstevel 		ddi_remove_softintr(rmclomv_softintr_id);
534*3db86aabSstevel 		return (DDI_FAILURE);
535*3db86aabSstevel 	}
536*3db86aabSstevel 	return (DDI_SUCCESS);
537*3db86aabSstevel }
538*3db86aabSstevel 
539*3db86aabSstevel static int
540*3db86aabSstevel rmclomv_remove_intr_handlers(void)
541*3db86aabSstevel {
542*3db86aabSstevel 	int err = rmc_comm_unreg_intr(DP_RMC_EVENTS,
543*3db86aabSstevel 	    rmclomv_event_data_handler);
544*3db86aabSstevel 	if (err != 0) {
545*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to unregister DP_RMC_EVENTS "
546*3db86aabSstevel 			"handler. Err=%d", err);
547*3db86aabSstevel 		return (DDI_FAILURE);
548*3db86aabSstevel 	}
549*3db86aabSstevel 	ddi_remove_softintr(rmclomv_softintr_id);
550*3db86aabSstevel 	return (DDI_SUCCESS);
551*3db86aabSstevel }
552*3db86aabSstevel 
553*3db86aabSstevel static void
554*3db86aabSstevel rmclomv_abort_seq_handler(char *msg)
555*3db86aabSstevel {
556*3db86aabSstevel 	if (key_position == RMC_KEYSWITCH_POS_LOCKED)
557*3db86aabSstevel 		cmn_err(CE_CONT, "KEY in LOCKED position, "
558*3db86aabSstevel 			"ignoring debug enter sequence");
559*3db86aabSstevel 	else  {
560*3db86aabSstevel 		rmclomv_break_requested = B_TRUE;
561*3db86aabSstevel 		if (msg != NULL)
562*3db86aabSstevel 			prom_printf("%s\n", msg);
563*3db86aabSstevel 
564*3db86aabSstevel 		ddi_trigger_softintr(rmclomv_softintr_id);
565*3db86aabSstevel 	}
566*3db86aabSstevel }
567*3db86aabSstevel 
568*3db86aabSstevel /* ARGSUSED */
569*3db86aabSstevel static uint_t
570*3db86aabSstevel rmclomv_break_intr(caddr_t arg)
571*3db86aabSstevel {
572*3db86aabSstevel 	if (rmclomv_break_requested) {
573*3db86aabSstevel 		rmclomv_break_requested = B_FALSE;
574*3db86aabSstevel 		debug_enter(NULL);
575*3db86aabSstevel 		return (DDI_INTR_CLAIMED);
576*3db86aabSstevel 	}
577*3db86aabSstevel 
578*3db86aabSstevel 	return (DDI_INTR_UNCLAIMED);
579*3db86aabSstevel }
580*3db86aabSstevel 
581*3db86aabSstevel /*
582*3db86aabSstevel  * Create a cache section structure
583*3db86aabSstevel  */
584*3db86aabSstevel static rmclomv_cache_section_t *
585*3db86aabSstevel create_cache_section(int sensor_type, int num)
586*3db86aabSstevel {
587*3db86aabSstevel 	size_t len = offsetof(rmclomv_cache_section_t, entry[0]) +
588*3db86aabSstevel 	    num * sizeof (rmclomv_cache_entry_t);
589*3db86aabSstevel 	rmclomv_cache_section_t *ptr = kmem_zalloc(len, KM_SLEEP);
590*3db86aabSstevel 	ptr->next_section = NULL;
591*3db86aabSstevel 	ptr->sensor_type = sensor_type;
592*3db86aabSstevel 	ptr->num_entries = num;
593*3db86aabSstevel 	ptr->section_len = len;
594*3db86aabSstevel 	return (ptr);
595*3db86aabSstevel }
596*3db86aabSstevel 
597*3db86aabSstevel /*
598*3db86aabSstevel  * Free a cache_section.
599*3db86aabSstevel  */
600*3db86aabSstevel static void
601*3db86aabSstevel free_section(rmclomv_cache_section_t *section)
602*3db86aabSstevel {
603*3db86aabSstevel 	size_t len = section->section_len;
604*3db86aabSstevel 	kmem_free(section, len);
605*3db86aabSstevel }
606*3db86aabSstevel 
607*3db86aabSstevel /*
608*3db86aabSstevel  * adds supplied section to end of cache chain
609*3db86aabSstevel  * must be called with cache locked
610*3db86aabSstevel  */
611*3db86aabSstevel static void
612*3db86aabSstevel add_section(rmclomv_cache_section_t **head, rmclomv_cache_section_t *section)
613*3db86aabSstevel {
614*3db86aabSstevel 	section->next_section = *head;
615*3db86aabSstevel 	*head = section;
616*3db86aabSstevel }
617*3db86aabSstevel 
618*3db86aabSstevel /*
619*3db86aabSstevel  * This function releases all cache sections and exchanges the two
620*3db86aabSstevel  * chain heads for new values.
621*3db86aabSstevel  */
622*3db86aabSstevel static void
623*3db86aabSstevel rmclomv_reset_cache(rmclomv_cache_section_t *new_chain,
624*3db86aabSstevel     rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo)
625*3db86aabSstevel {
626*3db86aabSstevel 	rmclomv_cache_section_t	*first;
627*3db86aabSstevel 	rmclomv_cache_section_t	*sub_first;
628*3db86aabSstevel 	rmclomv_cache_section_t	*next;
629*3db86aabSstevel 
630*3db86aabSstevel 	LOCK_CACHE
631*3db86aabSstevel 
632*3db86aabSstevel 	rmclomv_cache_valid = (new_chain != NULL);
633*3db86aabSstevel 	first = rmclomv_cache;
634*3db86aabSstevel 	rmclomv_cache = new_chain;
635*3db86aabSstevel 	sub_first = rmclomv_subcache;
636*3db86aabSstevel 	rmclomv_subcache = new_subchain;
637*3db86aabSstevel 
638*3db86aabSstevel 	if (sysinfo == NULL)
639*3db86aabSstevel 		bzero(&rmclomv_sysinfo_data, sizeof (rmclomv_sysinfo_data));
640*3db86aabSstevel 	else
641*3db86aabSstevel 		bcopy(sysinfo, &rmclomv_sysinfo_data,
642*3db86aabSstevel 		    sizeof (rmclomv_sysinfo_data));
643*3db86aabSstevel 
644*3db86aabSstevel 	rmclomv_sysinfo_valid = (sysinfo != NULL);
645*3db86aabSstevel 
646*3db86aabSstevel 	RELEASE_CACHE
647*3db86aabSstevel 
648*3db86aabSstevel 	while (first != NULL) {
649*3db86aabSstevel 		next = first->next_section;
650*3db86aabSstevel 		free_section(first);
651*3db86aabSstevel 		first = next;
652*3db86aabSstevel 	}
653*3db86aabSstevel 
654*3db86aabSstevel 	while (sub_first != NULL) {
655*3db86aabSstevel 		next = sub_first->next_section;
656*3db86aabSstevel 		free_section(sub_first);
657*3db86aabSstevel 		sub_first = next;
658*3db86aabSstevel 	}
659*3db86aabSstevel }
660*3db86aabSstevel 
661*3db86aabSstevel /*
662*3db86aabSstevel  * cache must be locked before calling rmclomv_find_section
663*3db86aabSstevel  */
664*3db86aabSstevel static rmclomv_cache_section_t *
665*3db86aabSstevel rmclomv_find_section(rmclomv_cache_section_t *start, uint16_t sensor)
666*3db86aabSstevel {
667*3db86aabSstevel 	rmclomv_cache_section_t	*next = start;
668*3db86aabSstevel 
669*3db86aabSstevel 	while ((next != NULL) && (next->sensor_type != sensor))
670*3db86aabSstevel 		next = next->next_section;
671*3db86aabSstevel 
672*3db86aabSstevel 	return (next);
673*3db86aabSstevel }
674*3db86aabSstevel 
675*3db86aabSstevel /*
676*3db86aabSstevel  * Return a string presenting the keyswitch position
677*3db86aabSstevel  * For unknown values returns "Unknown"
678*3db86aabSstevel  */
679*3db86aabSstevel static char *
680*3db86aabSstevel rmclomv_key_position(enum rmc_keyswitch_pos pos)
681*3db86aabSstevel {
682*3db86aabSstevel 	switch (pos) {
683*3db86aabSstevel 
684*3db86aabSstevel 	case RMC_KEYSWITCH_POS_NORMAL:
685*3db86aabSstevel 		return ("NORMAL");
686*3db86aabSstevel 	case RMC_KEYSWITCH_POS_DIAG:
687*3db86aabSstevel 		return ("DIAG");
688*3db86aabSstevel 	case RMC_KEYSWITCH_POS_LOCKED:
689*3db86aabSstevel 		return ("LOCKED");
690*3db86aabSstevel 	case RMC_KEYSWITCH_POS_OFF:
691*3db86aabSstevel 		return ("STBY");
692*3db86aabSstevel 	default:
693*3db86aabSstevel 		return ("UNKNOWN");
694*3db86aabSstevel 	}
695*3db86aabSstevel }
696*3db86aabSstevel 
697*3db86aabSstevel /*
698*3db86aabSstevel  * The sensor id name is sought in the supplied section and if found
699*3db86aabSstevel  * its index within the section is written to *index.
700*3db86aabSstevel  * Return value is zero for success, otherwise -1.
701*3db86aabSstevel  * The cache must be locked before calling get_sensor_by_name
702*3db86aabSstevel  */
703*3db86aabSstevel static int
704*3db86aabSstevel get_sensor_by_name(const rmclomv_cache_section_t *section,
705*3db86aabSstevel     const char *name, int *index)
706*3db86aabSstevel {
707*3db86aabSstevel 	int i;
708*3db86aabSstevel 
709*3db86aabSstevel 	for (i = 0; i < section->num_entries; i++) {
710*3db86aabSstevel 		if (strcmp(name, section->entry[i].handle_name.name) == 0) {
711*3db86aabSstevel 			*index = i;
712*3db86aabSstevel 			return (0);
713*3db86aabSstevel 		}
714*3db86aabSstevel 	}
715*3db86aabSstevel 
716*3db86aabSstevel 	*index = 0;
717*3db86aabSstevel 	return (-1);
718*3db86aabSstevel }
719*3db86aabSstevel 
720*3db86aabSstevel /*
721*3db86aabSstevel  * fills in the envmon_handle name
722*3db86aabSstevel  * if it is unknown (not cached), the dp_handle_t is returned as a hex-digit
723*3db86aabSstevel  * string
724*3db86aabSstevel  */
725*3db86aabSstevel static void
726*3db86aabSstevel rmclomv_hdl_to_envhdl(dp_handle_t hdl, envmon_handle_t *envhdl)
727*3db86aabSstevel {
728*3db86aabSstevel 	rmclomv_cache_section_t *next;
729*3db86aabSstevel 	int			i;
730*3db86aabSstevel 
731*3db86aabSstevel 	LOCK_CACHE
732*3db86aabSstevel 
733*3db86aabSstevel 	for (next = rmclomv_cache; next != NULL; next = next->next_section) {
734*3db86aabSstevel 		for (i = 0; i < next->num_entries; i++) {
735*3db86aabSstevel 			if (next->entry[i].handle == hdl) {
736*3db86aabSstevel 				    *envhdl = next->entry[i].handle_name;
737*3db86aabSstevel 				    RELEASE_CACHE
738*3db86aabSstevel 				    return;
739*3db86aabSstevel 			}
740*3db86aabSstevel 		}
741*3db86aabSstevel 	}
742*3db86aabSstevel 
743*3db86aabSstevel 	/*
744*3db86aabSstevel 	 * Sought handle not currently cached.
745*3db86aabSstevel 	 */
746*3db86aabSstevel 	RELEASE_CACHE
747*3db86aabSstevel 
748*3db86aabSstevel 	(void) snprintf(envhdl->name, sizeof (envhdl->name),
749*3db86aabSstevel 	    "Unknown SC node 0x%x", hdl);
750*3db86aabSstevel }
751*3db86aabSstevel 
752*3db86aabSstevel static void
753*3db86aabSstevel rmclomv_dr_data_handler(const char *fru_name, int hint)
754*3db86aabSstevel {
755*3db86aabSstevel 	int				err = 0;
756*3db86aabSstevel 	nvlist_t			*attr_list;
757*3db86aabSstevel 	char				attach_pnt[MAXPATHLEN];
758*3db86aabSstevel 
759*3db86aabSstevel 	(void) snprintf(attach_pnt, sizeof (attach_pnt), "%s", fru_name);
760*3db86aabSstevel 
761*3db86aabSstevel 	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
762*3db86aabSstevel 	if (err != 0) {
763*3db86aabSstevel 		cmn_err(CE_WARN,
764*3db86aabSstevel 		    "Failed to allocate name-value list for %s event", EC_DR);
765*3db86aabSstevel 		return;
766*3db86aabSstevel 	}
767*3db86aabSstevel 
768*3db86aabSstevel 	err = nvlist_add_string(attr_list, DR_AP_ID, attach_pnt);
769*3db86aabSstevel 	if (err != 0) {
770*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
771*3db86aabSstevel 		    DR_AP_ID, EC_DR);
772*3db86aabSstevel 		nvlist_free(attr_list);
773*3db86aabSstevel 		return;
774*3db86aabSstevel 	}
775*3db86aabSstevel 
776*3db86aabSstevel 	/*
777*3db86aabSstevel 	 * Add the hint
778*3db86aabSstevel 	 */
779*3db86aabSstevel 	err = nvlist_add_string(attr_list, DR_HINT, SE_HINT2STR(hint));
780*3db86aabSstevel 	if (err != 0) {
781*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
782*3db86aabSstevel 		    DR_HINT, EC_DR);
783*3db86aabSstevel 		nvlist_free(attr_list);
784*3db86aabSstevel 		return;
785*3db86aabSstevel 	}
786*3db86aabSstevel 
787*3db86aabSstevel 	err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_DR,
788*3db86aabSstevel 	    ESC_DR_AP_STATE_CHANGE, attr_list, NULL, DDI_NOSLEEP);
789*3db86aabSstevel 	if (err != 0) {
790*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to log %s/%s event",
791*3db86aabSstevel 		    DR_AP_ID, EC_DR);
792*3db86aabSstevel 	}
793*3db86aabSstevel 
794*3db86aabSstevel 	nvlist_free(attr_list);
795*3db86aabSstevel }
796*3db86aabSstevel 
797*3db86aabSstevel static void
798*3db86aabSstevel fan_sysevent(char *fru_name, char *sensor_name, int sub_event)
799*3db86aabSstevel {
800*3db86aabSstevel 	nvlist_t		*attr_list;
801*3db86aabSstevel 	char			fan_str[MAXNAMELEN];
802*3db86aabSstevel 	int			err;
803*3db86aabSstevel 
804*3db86aabSstevel 	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
805*3db86aabSstevel 	if (err != 0) {
806*3db86aabSstevel 		cmn_err(CE_WARN,
807*3db86aabSstevel 		    "Failed to allocate name-value list for %s/%s event",
808*3db86aabSstevel 		    EC_ENV, ESC_ENV_FAN);
809*3db86aabSstevel 		return;
810*3db86aabSstevel 	}
811*3db86aabSstevel 
812*3db86aabSstevel 	err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name);
813*3db86aabSstevel 	if (err != 0) {
814*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
815*3db86aabSstevel 		    ENV_FRU_ID, EC_ENV, ESC_ENV_FAN);
816*3db86aabSstevel 		nvlist_free(attr_list);
817*3db86aabSstevel 		return;
818*3db86aabSstevel 	}
819*3db86aabSstevel 
820*3db86aabSstevel 	err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name);
821*3db86aabSstevel 	if (err != 0) {
822*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
823*3db86aabSstevel 		    ENV_FRU_RESOURCE_ID, EC_ENV, ESC_ENV_FAN);
824*3db86aabSstevel 		nvlist_free(attr_list);
825*3db86aabSstevel 		return;
826*3db86aabSstevel 	}
827*3db86aabSstevel 
828*3db86aabSstevel 	err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR);
829*3db86aabSstevel 	if (err != 0) {
830*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
831*3db86aabSstevel 		    ENV_FRU_DEVICE, EC_ENV, ESC_ENV_FAN);
832*3db86aabSstevel 		nvlist_free(attr_list);
833*3db86aabSstevel 		return;
834*3db86aabSstevel 	}
835*3db86aabSstevel 
836*3db86aabSstevel 	err = nvlist_add_int32(attr_list, ENV_FRU_STATE,
837*3db86aabSstevel 	    (sub_event == RMC_ENV_FAULT_EVENT) ? ENV_FAILED : ENV_OK);
838*3db86aabSstevel 	if (err != 0) {
839*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
840*3db86aabSstevel 		    ENV_FRU_STATE, EC_ENV, ESC_ENV_FAN);
841*3db86aabSstevel 		nvlist_free(attr_list);
842*3db86aabSstevel 		return;
843*3db86aabSstevel 	}
844*3db86aabSstevel 
845*3db86aabSstevel 	if (sub_event == RMC_ENV_FAULT_EVENT) {
846*3db86aabSstevel 		(void) snprintf(fan_str, sizeof (fan_str),
847*3db86aabSstevel 		    "fan %s/%s is now failed", fru_name, sensor_name);
848*3db86aabSstevel 	} else {
849*3db86aabSstevel 		(void) snprintf(fan_str, sizeof (fan_str),
850*3db86aabSstevel 		    "fan %s/%s is now ok", fru_name, sensor_name);
851*3db86aabSstevel 	}
852*3db86aabSstevel 	err = nvlist_add_string(attr_list, ENV_MSG, fan_str);
853*3db86aabSstevel 	if (err != 0) {
854*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
855*3db86aabSstevel 		    ENV_MSG, EC_ENV, ESC_ENV_FAN);
856*3db86aabSstevel 		nvlist_free(attr_list);
857*3db86aabSstevel 		return;
858*3db86aabSstevel 	}
859*3db86aabSstevel 
860*3db86aabSstevel 	err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV,
861*3db86aabSstevel 	    ESC_ENV_FAN, attr_list, NULL, DDI_NOSLEEP);
862*3db86aabSstevel 	if (err != 0) {
863*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to log %s/%s event",
864*3db86aabSstevel 		    EC_ENV, ESC_ENV_FAN);
865*3db86aabSstevel 	}
866*3db86aabSstevel 
867*3db86aabSstevel 	cmn_err(CE_NOTE, "%s", fan_str);
868*3db86aabSstevel 	nvlist_free(attr_list);
869*3db86aabSstevel }
870*3db86aabSstevel 
871*3db86aabSstevel static void
872*3db86aabSstevel threshold_sysevent(char *fru_name, char *sensor_name, int sub_event,
873*3db86aabSstevel 	char event_type)
874*3db86aabSstevel {
875*3db86aabSstevel 	nvlist_t		*attr_list;
876*3db86aabSstevel 	int			err;
877*3db86aabSstevel 	char			*subclass;
878*3db86aabSstevel 	char			sensor_str[MAXNAMELEN];
879*3db86aabSstevel 
880*3db86aabSstevel 	subclass = (event_type == 'T') ? ESC_ENV_TEMP : ESC_ENV_POWER;
881*3db86aabSstevel 
882*3db86aabSstevel 	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
883*3db86aabSstevel 	if (err != 0) {
884*3db86aabSstevel 		cmn_err(CE_WARN,
885*3db86aabSstevel 		    "Failed to allocate name-value list for %s/%s event",
886*3db86aabSstevel 		    EC_ENV, subclass);
887*3db86aabSstevel 		return;
888*3db86aabSstevel 	}
889*3db86aabSstevel 
890*3db86aabSstevel 	err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name);
891*3db86aabSstevel 	if (err != 0) {
892*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
893*3db86aabSstevel 		    ENV_FRU_ID, EC_ENV, subclass);
894*3db86aabSstevel 		nvlist_free(attr_list);
895*3db86aabSstevel 		return;
896*3db86aabSstevel 	}
897*3db86aabSstevel 
898*3db86aabSstevel 	err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name);
899*3db86aabSstevel 	if (err != 0) {
900*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
901*3db86aabSstevel 		    ENV_FRU_RESOURCE_ID, EC_ENV, subclass);
902*3db86aabSstevel 		nvlist_free(attr_list);
903*3db86aabSstevel 		return;
904*3db86aabSstevel 	}
905*3db86aabSstevel 
906*3db86aabSstevel 	err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR);
907*3db86aabSstevel 	if (err != 0) {
908*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
909*3db86aabSstevel 		    ENV_FRU_DEVICE, EC_ENV, subclass);
910*3db86aabSstevel 		nvlist_free(attr_list);
911*3db86aabSstevel 		return;
912*3db86aabSstevel 	}
913*3db86aabSstevel 
914*3db86aabSstevel 	switch (sub_event) {
915*3db86aabSstevel 	case RMC_ENV_OK_EVENT:
916*3db86aabSstevel 		err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_OK);
917*3db86aabSstevel 		break;
918*3db86aabSstevel 	case RMC_ENV_WARNING_THRESHOLD_EVENT:
919*3db86aabSstevel 		err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_WARNING);
920*3db86aabSstevel 		break;
921*3db86aabSstevel 	case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
922*3db86aabSstevel 		err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_FAILED);
923*3db86aabSstevel 		break;
924*3db86aabSstevel 	}
925*3db86aabSstevel 	if (err != 0) {
926*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
927*3db86aabSstevel 		    ENV_FRU_STATE, EC_ENV, subclass);
928*3db86aabSstevel 		nvlist_free(attr_list);
929*3db86aabSstevel 		return;
930*3db86aabSstevel 	}
931*3db86aabSstevel 
932*3db86aabSstevel 	switch (sub_event) {
933*3db86aabSstevel 	case RMC_ENV_OK_EVENT:
934*3db86aabSstevel 		(void) snprintf(sensor_str, sizeof (sensor_str),
935*3db86aabSstevel 		    "sensor %s/%s is now ok", fru_name,
936*3db86aabSstevel 		    sensor_name);
937*3db86aabSstevel 		break;
938*3db86aabSstevel 	case RMC_ENV_WARNING_THRESHOLD_EVENT:
939*3db86aabSstevel 		(void) snprintf(sensor_str, sizeof (sensor_str),
940*3db86aabSstevel 		    "sensor %s/%s is now outside warning thresholds", fru_name,
941*3db86aabSstevel 		    sensor_name);
942*3db86aabSstevel 		break;
943*3db86aabSstevel 	case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
944*3db86aabSstevel 		(void) snprintf(sensor_str, sizeof (sensor_str),
945*3db86aabSstevel 		    "sensor %s/%s is now outside shutdown thresholds", fru_name,
946*3db86aabSstevel 		    sensor_name);
947*3db86aabSstevel 		break;
948*3db86aabSstevel 	}
949*3db86aabSstevel 	err = nvlist_add_string(attr_list, ENV_MSG, sensor_str);
950*3db86aabSstevel 	if (err != 0) {
951*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
952*3db86aabSstevel 		    ENV_MSG, EC_ENV, subclass);
953*3db86aabSstevel 		nvlist_free(attr_list);
954*3db86aabSstevel 		return;
955*3db86aabSstevel 	}
956*3db86aabSstevel 
957*3db86aabSstevel 	err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV,
958*3db86aabSstevel 	    subclass, attr_list, NULL, DDI_NOSLEEP);
959*3db86aabSstevel 	if (err != 0) {
960*3db86aabSstevel 		cmn_err(CE_WARN, "Failed to log %s/%s event",
961*3db86aabSstevel 		    EC_ENV, subclass);
962*3db86aabSstevel 	}
963*3db86aabSstevel 
964*3db86aabSstevel 	cmn_err(CE_NOTE, "%s", sensor_str);
965*3db86aabSstevel 	nvlist_free(attr_list);
966*3db86aabSstevel }
967*3db86aabSstevel 
968*3db86aabSstevel static uint_t
969*3db86aabSstevel rmclomv_event_data_handler(char *arg)
970*3db86aabSstevel {
971*3db86aabSstevel 	dp_event_notification_t	*payload;
972*3db86aabSstevel 	rmc_comm_msg_t	*msg;
973*3db86aabSstevel 	envmon_handle_t envhdl;
974*3db86aabSstevel 	int hint;
975*3db86aabSstevel 	char *ptr, *save_ptr;
976*3db86aabSstevel 
977*3db86aabSstevel 	if (arg == NULL) {
978*3db86aabSstevel 		return (DDI_INTR_CLAIMED);
979*3db86aabSstevel 	}
980*3db86aabSstevel 
981*3db86aabSstevel 	msg = (rmc_comm_msg_t *)arg;
982*3db86aabSstevel 	if (msg->msg_buf == NULL) {
983*3db86aabSstevel 		return (DDI_INTR_CLAIMED);
984*3db86aabSstevel 	}
985*3db86aabSstevel 
986*3db86aabSstevel 	payload = (dp_event_notification_t *)msg->msg_buf;
987*3db86aabSstevel 	switch (payload->event) {
988*3db86aabSstevel 
989*3db86aabSstevel 	case RMC_KEYSWITCH_EVENT:
990*3db86aabSstevel 		real_key_position = payload->event_info.ev_keysw.key_position;
991*3db86aabSstevel 		cmn_err(CE_NOTE, "keyswitch change event - state = %s",
992*3db86aabSstevel 		    rmclomv_key_position(real_key_position));
993*3db86aabSstevel 		if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) &&
994*3db86aabSstevel 		    (real_key_position <= RMC_KEYSWITCH_POS_OFF)) {
995*3db86aabSstevel 			key_position = real_key_position;
996*3db86aabSstevel 		} else {
997*3db86aabSstevel 			/* treat unknown key position as locked */
998*3db86aabSstevel 			key_position = RMC_KEYSWITCH_POS_LOCKED;
999*3db86aabSstevel 		}
1000*3db86aabSstevel 		break;
1001*3db86aabSstevel 
1002*3db86aabSstevel 	case RMC_HPU_EVENT:
1003*3db86aabSstevel 		/*
1004*3db86aabSstevel 		 * send appropriate sysevent
1005*3db86aabSstevel 		 */
1006*3db86aabSstevel 		switch (payload->event_info.ev_hpunot.sub_event) {
1007*3db86aabSstevel 		case RMC_HPU_REMOVE_EVENT:
1008*3db86aabSstevel 			hint = SE_HINT_REMOVE;
1009*3db86aabSstevel 			break;
1010*3db86aabSstevel 		case RMC_HPU_INSERT_EVENT:
1011*3db86aabSstevel 			hint = SE_HINT_INSERT;
1012*3db86aabSstevel 			break;
1013*3db86aabSstevel 		default:
1014*3db86aabSstevel 			hint = SE_NO_HINT;
1015*3db86aabSstevel 			break;
1016*3db86aabSstevel 		}
1017*3db86aabSstevel 		rmclomv_hdl_to_envhdl(payload->event_info.ev_hpunot.hpu_hdl,
1018*3db86aabSstevel 		    &envhdl);
1019*3db86aabSstevel 		rmclomv_dr_data_handler(envhdl.name, hint);
1020*3db86aabSstevel 		break;
1021*3db86aabSstevel 
1022*3db86aabSstevel 	case RMC_INIT_EVENT:
1023*3db86aabSstevel 		/*
1024*3db86aabSstevel 		 * Wake up the refresh thread.
1025*3db86aabSstevel 		 */
1026*3db86aabSstevel 		rmclomv_refresh_wakeup();
1027*3db86aabSstevel 
1028*3db86aabSstevel 		/*
1029*3db86aabSstevel 		 * Wake up the checkrmc thread for an early indication to PICL
1030*3db86aabSstevel 		 */
1031*3db86aabSstevel 		rmclomv_checkrmc_wakeup(NULL);
1032*3db86aabSstevel 		break;
1033*3db86aabSstevel 
1034*3db86aabSstevel 	case RMC_ENV_EVENT:
1035*3db86aabSstevel 		rmclomv_hdl_to_envhdl(payload->event_info.ev_envnot.env_hdl,
1036*3db86aabSstevel 		    &envhdl);
1037*3db86aabSstevel 
1038*3db86aabSstevel 		/* split name into fru name and sensor name */
1039*3db86aabSstevel 		ptr = strchr(envhdl.name, '.');
1040*3db86aabSstevel 
1041*3db86aabSstevel 		/* must have at least one '.' */
1042*3db86aabSstevel 		if (ptr == NULL)
1043*3db86aabSstevel 			break;
1044*3db86aabSstevel 
1045*3db86aabSstevel 		/* find last '.' - convert the others to '/' */
1046*3db86aabSstevel 		for (;;) {
1047*3db86aabSstevel 			save_ptr = ptr;
1048*3db86aabSstevel 			ptr = strchr(ptr, '.');
1049*3db86aabSstevel 			if (ptr == NULL) {
1050*3db86aabSstevel 				ptr = save_ptr;
1051*3db86aabSstevel 				break;
1052*3db86aabSstevel 			}
1053*3db86aabSstevel 			*save_ptr = '/';
1054*3db86aabSstevel 		}
1055*3db86aabSstevel 		*ptr = '\0';
1056*3db86aabSstevel 		ptr++;
1057*3db86aabSstevel 		/* is it a voltage or temperature sensor? */
1058*3db86aabSstevel 		if ((*ptr == 'V' || *ptr == 'T') && *(ptr + 1) == '_') {
1059*3db86aabSstevel 			switch (payload->event_info.ev_envnot.sub_event) {
1060*3db86aabSstevel 			case RMC_ENV_WARNING_THRESHOLD_EVENT:
1061*3db86aabSstevel 			case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT:
1062*3db86aabSstevel 			case RMC_ENV_OK_EVENT:
1063*3db86aabSstevel 				threshold_sysevent(envhdl.name, ptr,
1064*3db86aabSstevel 				    payload->event_info.ev_envnot.sub_event,
1065*3db86aabSstevel 				    *ptr);
1066*3db86aabSstevel 				break;
1067*3db86aabSstevel 			default:
1068*3db86aabSstevel 				break;
1069*3db86aabSstevel 			}
1070*3db86aabSstevel 		}
1071*3db86aabSstevel 
1072*3db86aabSstevel 		/*
1073*3db86aabSstevel 		 * is it a fan sensor?
1074*3db86aabSstevel 		 * Fan sensor names end either in RS, F0 or F1
1075*3db86aabSstevel 		 */
1076*3db86aabSstevel 		if ((*ptr == 'R' && *(ptr + 1) == 'S' && *(ptr + 2) == '\0') ||
1077*3db86aabSstevel 		    (*ptr == 'F' && *(ptr + 1) == '0' && *(ptr + 2) == '\0') ||
1078*3db86aabSstevel 		    (*ptr == 'F' && *(ptr + 1) == '1' && *(ptr + 2) == '\0')) {
1079*3db86aabSstevel 			switch (payload->event_info.ev_envnot.sub_event) {
1080*3db86aabSstevel 			case RMC_ENV_FAULT_EVENT:
1081*3db86aabSstevel 			case RMC_ENV_OK_EVENT:
1082*3db86aabSstevel 				fan_sysevent(envhdl.name, ptr,
1083*3db86aabSstevel 				    payload->event_info.ev_envnot.sub_event);
1084*3db86aabSstevel 				break;
1085*3db86aabSstevel 			default:
1086*3db86aabSstevel 				break;
1087*3db86aabSstevel 			}
1088*3db86aabSstevel 		}
1089*3db86aabSstevel 		break;
1090*3db86aabSstevel 
1091*3db86aabSstevel 	case RMC_LOG_EVENT:
1092*3db86aabSstevel 	{
1093*3db86aabSstevel 		int level = 10;
1094*3db86aabSstevel 		int flags = SL_NOTE | SL_CONSOLE;
1095*3db86aabSstevel 		char *message =
1096*3db86aabSstevel 		    (char *)payload->event_info.ev_rmclog.log_record;
1097*3db86aabSstevel 
1098*3db86aabSstevel 		message[ payload->event_info.ev_rmclog.log_record_size] = '\0';
1099*3db86aabSstevel 
1100*3db86aabSstevel 		/*
1101*3db86aabSstevel 		 * Logs have a 10 character prefix - specifying the severity of
1102*3db86aabSstevel 		 * the event being logged. Thus all the magic number 10s down
1103*3db86aabSstevel 		 * here
1104*3db86aabSstevel 		 */
1105*3db86aabSstevel 		if (0 == strncmp("CRITICAL: ", message, 10)) {
1106*3db86aabSstevel 			message += 10;
1107*3db86aabSstevel 			level = 0;
1108*3db86aabSstevel 			flags = SL_FATAL | SL_ERROR | SL_CONSOLE;
1109*3db86aabSstevel 		} else if (0 == strncmp("MAJOR:    ", message, 10)) {
1110*3db86aabSstevel 			message += 10;
1111*3db86aabSstevel 			level = 5;
1112*3db86aabSstevel 			flags = SL_WARN | SL_ERROR | SL_CONSOLE;
1113*3db86aabSstevel 		} else if (0 == strncmp("MINOR:    ", message, 10)) {
1114*3db86aabSstevel 			message += 10;
1115*3db86aabSstevel 			level = 10;
1116*3db86aabSstevel 			flags = SL_NOTE | SL_CONSOLE;
1117*3db86aabSstevel 		}
1118*3db86aabSstevel 
1119*3db86aabSstevel 		(void) strlog(0, 0, level, flags, message);
1120*3db86aabSstevel 		break;
1121*3db86aabSstevel 	}
1122*3db86aabSstevel 
1123*3db86aabSstevel 	default:
1124*3db86aabSstevel 		return (DDI_INTR_CLAIMED);
1125*3db86aabSstevel 	}
1126*3db86aabSstevel 
1127*3db86aabSstevel 	return (DDI_INTR_CLAIMED);
1128*3db86aabSstevel }
1129*3db86aabSstevel 
1130*3db86aabSstevel /*ARGSUSED*/
1131*3db86aabSstevel static int
1132*3db86aabSstevel rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
1133*3db86aabSstevel {
1134*3db86aabSstevel 	int error = 0;
1135*3db86aabSstevel 	int instance = getminor(*dev_p);
1136*3db86aabSstevel 
1137*3db86aabSstevel 	if (instance != 0)
1138*3db86aabSstevel 		return (ENXIO);
1139*3db86aabSstevel 
1140*3db86aabSstevel 	if ((flag & FWRITE) != 0 && (error = drv_priv(cred_p)) != 0)
1141*3db86aabSstevel 		return (error);
1142*3db86aabSstevel 
1143*3db86aabSstevel 	return (0);
1144*3db86aabSstevel }
1145*3db86aabSstevel 
1146*3db86aabSstevel /*ARGSUSED*/
1147*3db86aabSstevel static int
1148*3db86aabSstevel rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
1149*3db86aabSstevel {
1150*3db86aabSstevel 	return (DDI_SUCCESS);
1151*3db86aabSstevel }
1152*3db86aabSstevel 
1153*3db86aabSstevel static int
1154*3db86aabSstevel rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len, intptr_t arg_req,
1155*3db86aabSstevel     intptr_t arg_res)
1156*3db86aabSstevel {
1157*3db86aabSstevel 	rmc_comm_msg_t request, *reqp = &request;
1158*3db86aabSstevel 	rmc_comm_msg_t response, *resp = &response;
1159*3db86aabSstevel 	int rv = 0;
1160*3db86aabSstevel 
1161*3db86aabSstevel 	bzero((caddr_t)&request, sizeof (request));
1162*3db86aabSstevel 	reqp->msg_type = req_cmd;
1163*3db86aabSstevel 	reqp->msg_buf = (caddr_t)arg_req;
1164*3db86aabSstevel 	bzero((caddr_t)&response, sizeof (response));
1165*3db86aabSstevel 	resp->msg_type = resp_cmd;
1166*3db86aabSstevel 	resp->msg_buf = (caddr_t)arg_res;
1167*3db86aabSstevel 	resp->msg_len = resp_len;
1168*3db86aabSstevel 
1169*3db86aabSstevel 	switch (req_cmd) {
1170*3db86aabSstevel 	case DP_GET_SYSINFO:
1171*3db86aabSstevel 		resp->msg_len = sizeof (dp_get_sysinfo_r_t);
1172*3db86aabSstevel 		break;
1173*3db86aabSstevel 	case DP_GET_EVENT_LOG:
1174*3db86aabSstevel 		resp->msg_len = sizeof (dp_get_event_log_r_t);
1175*3db86aabSstevel 		break;
1176*3db86aabSstevel 	case DP_GET_VOLTS:
1177*3db86aabSstevel 		reqp->msg_len = sizeof (dp_get_volts_t);
1178*3db86aabSstevel 		break;
1179*3db86aabSstevel 	case DP_GET_TEMPERATURES:
1180*3db86aabSstevel 		reqp->msg_len = sizeof (dp_get_temperatures_t);
1181*3db86aabSstevel 		break;
1182*3db86aabSstevel 	case DP_GET_CIRCUIT_BRKS:
1183*3db86aabSstevel 		reqp->msg_len = sizeof (dp_get_circuit_brks_t);
1184*3db86aabSstevel 		break;
1185*3db86aabSstevel 	case DP_GET_FAN_STATUS:
1186*3db86aabSstevel 		reqp->msg_len = sizeof (dp_get_fan_status_t);
1187*3db86aabSstevel 		break;
1188*3db86aabSstevel 	case DP_GET_PSU_STATUS:
1189*3db86aabSstevel 		reqp->msg_len = sizeof (dp_get_psu_status_t);
1190*3db86aabSstevel 		break;
1191*3db86aabSstevel 	case DP_GET_LED_STATE:
1192*3db86aabSstevel 		reqp->msg_len = sizeof (dp_get_led_state_t);
1193*3db86aabSstevel 		break;
1194*3db86aabSstevel 	case DP_SET_LED_STATE:
1195*3db86aabSstevel 		reqp->msg_len = sizeof (dp_set_led_state_t);
1196*3db86aabSstevel 		break;
1197*3db86aabSstevel 	case DP_GET_FRU_STATUS:
1198*3db86aabSstevel 		reqp->msg_len = sizeof (dp_get_fru_status_t);
1199*3db86aabSstevel 		break;
1200*3db86aabSstevel 	case DP_GET_HANDLE_NAME:
1201*3db86aabSstevel 		reqp->msg_len = sizeof (dp_get_handle_name_t);
1202*3db86aabSstevel 		break;
1203*3db86aabSstevel 	case DP_GET_ALARM_STATE:
1204*3db86aabSstevel 		reqp->msg_len = sizeof (dp_get_alarm_state_t);
1205*3db86aabSstevel 		break;
1206*3db86aabSstevel 	case DP_SET_ALARM_STATE:
1207*3db86aabSstevel 		reqp->msg_len = sizeof (dp_set_alarm_state_t);
1208*3db86aabSstevel 		break;
1209*3db86aabSstevel 	case DP_GET_SDP_VERSION:
1210*3db86aabSstevel 		resp->msg_len = sizeof (dp_get_sdp_version_r_t);
1211*3db86aabSstevel 		break;
1212*3db86aabSstevel 	case DP_GET_CHASSIS_SERIALNUM:
1213*3db86aabSstevel 		reqp->msg_len = 0;
1214*3db86aabSstevel 		break;
1215*3db86aabSstevel 	case DP_GET_DATE_TIME:
1216*3db86aabSstevel 		reqp->msg_len = 0;
1217*3db86aabSstevel 		break;
1218*3db86aabSstevel 	default:
1219*3db86aabSstevel 		return (EINVAL);
1220*3db86aabSstevel 	}
1221*3db86aabSstevel 
1222*3db86aabSstevel 	rv = rmc_comm_request_response(reqp, resp,
1223*3db86aabSstevel 	    RMCLOMV_DEFAULT_MAX_MBOX_WAIT_TIME);
1224*3db86aabSstevel 
1225*3db86aabSstevel 	if (rv != RCNOERR) {
1226*3db86aabSstevel 		/*
1227*3db86aabSstevel 		 * RMC returned an error or failed to respond.
1228*3db86aabSstevel 		 * Where the RMC itself is implicated, rmclomv_rmc_error
1229*3db86aabSstevel 		 * is set non-zero. It is cleared after an error free exchange.
1230*3db86aabSstevel 		 * Two failure cases are distinguished:
1231*3db86aabSstevel 		 * RMCLOMV_RMCSTATE_FAILED and RMCLOMV_RMCSTATE_DOWNLOAD.
1232*3db86aabSstevel 		 */
1233*3db86aabSstevel 		switch (rv) {
1234*3db86aabSstevel 		case RCENOSOFTSTATE:
1235*3db86aabSstevel 			/* invalid/NULL soft state structure */
1236*3db86aabSstevel 			return (EIO);
1237*3db86aabSstevel 		case RCENODATALINK:
1238*3db86aabSstevel 			/*
1239*3db86aabSstevel 			 * firmware download in progress,
1240*3db86aabSstevel 			 * can you come back later?
1241*3db86aabSstevel 			 */
1242*3db86aabSstevel 			rmclomv_rmc_error = RMCLOMV_RMCSTATE_DOWNLOAD;
1243*3db86aabSstevel 			rmclomv_rmc_state = RMCLOMV_RMCSTATE_DOWNLOAD;
1244*3db86aabSstevel 			return (EAGAIN);
1245*3db86aabSstevel 		case RCENOMEM:
1246*3db86aabSstevel 			/* memory problems */
1247*3db86aabSstevel 			return (ENOMEM);
1248*3db86aabSstevel 		case RCECANTRESEND:
1249*3db86aabSstevel 			/* resend failed */
1250*3db86aabSstevel 			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1251*3db86aabSstevel 			return (EIO);
1252*3db86aabSstevel 		case RCEMAXRETRIES:
1253*3db86aabSstevel 			/* reply not received - retries exceeded */
1254*3db86aabSstevel 			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1255*3db86aabSstevel 			return (EINTR);
1256*3db86aabSstevel 		case RCETIMEOUT:
1257*3db86aabSstevel 			/* reply not received - command has timed out */
1258*3db86aabSstevel 			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1259*3db86aabSstevel 			return (EINTR);
1260*3db86aabSstevel 		case RCEINVCMD:
1261*3db86aabSstevel 			/* data protocol cmd not supported */
1262*3db86aabSstevel 			return (ENOTSUP);
1263*3db86aabSstevel 		case RCEINVARG:
1264*3db86aabSstevel 			/* invalid argument(s) */
1265*3db86aabSstevel 			return (ENOTSUP);
1266*3db86aabSstevel 		case RCEGENERIC:
1267*3db86aabSstevel 			/* generic error */
1268*3db86aabSstevel 			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1269*3db86aabSstevel 			return (EIO);
1270*3db86aabSstevel 		default:
1271*3db86aabSstevel 			rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED;
1272*3db86aabSstevel 			return (EIO);
1273*3db86aabSstevel 		}
1274*3db86aabSstevel 	}
1275*3db86aabSstevel 
1276*3db86aabSstevel 	rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE;
1277*3db86aabSstevel 	return (0);
1278*3db86aabSstevel }
1279*3db86aabSstevel 
1280*3db86aabSstevel /*
1281*3db86aabSstevel  * validate_section_entry checks that the entry at the specified index
1282*3db86aabSstevel  * is valid and not duplicated by an entry above. If these tests fail
1283*3db86aabSstevel  * the entry is removed and B_FALSE returned. Otherwise returns B_TRUE.
1284*3db86aabSstevel  */
1285*3db86aabSstevel static int
1286*3db86aabSstevel validate_section_entry(rmclomv_cache_section_t *section, int index)
1287*3db86aabSstevel {
1288*3db86aabSstevel 	int			i;
1289*3db86aabSstevel 	rmclomv_cache_entry_t	*entry;
1290*3db86aabSstevel 
1291*3db86aabSstevel 	for (i = index; i < section->num_entries; i++) {
1292*3db86aabSstevel 		entry = &section->entry[i];
1293*3db86aabSstevel 		if (entry->handle_name.name[0] == '\0') {
1294*3db86aabSstevel 			cmn_err(CE_WARN,
1295*3db86aabSstevel 			    "rmclomv: empty handle_name, handle 0x%x type %x",
1296*3db86aabSstevel 			    entry->handle, section->sensor_type);
1297*3db86aabSstevel 		} else if (entry->ind_mask != 0) {
1298*3db86aabSstevel 			continue;	/* skip special entries */
1299*3db86aabSstevel 		} else if (entry->handle == DP_NULL_HANDLE) {
1300*3db86aabSstevel 			cmn_err(CE_WARN,
1301*3db86aabSstevel 			    "rmclomv: null handle id for \"%s\" type %x",
1302*3db86aabSstevel 			    entry->handle_name.name, section->sensor_type);
1303*3db86aabSstevel 		} else if (i == index) {
1304*3db86aabSstevel 			continue;
1305*3db86aabSstevel 		} else if (section->entry[index].handle == entry->handle) {
1306*3db86aabSstevel 			cmn_err(CE_WARN,
1307*3db86aabSstevel 			    "rmclomv: duplicate handle 0x%x type %x",
1308*3db86aabSstevel 			    entry->handle, section->sensor_type);
1309*3db86aabSstevel 		} else if (strcmp(entry->handle_name.name,
1310*3db86aabSstevel 		    section->entry[index].handle_name.name) == 0) {
1311*3db86aabSstevel 			cmn_err(CE_WARN,
1312*3db86aabSstevel 			    "rmclomv: duplicate handle_name \"%s\", "
1313*3db86aabSstevel 			    "handle 0x%x type %x", entry->handle_name.name,
1314*3db86aabSstevel 			    entry->handle, section->sensor_type);
1315*3db86aabSstevel 		} else
1316*3db86aabSstevel 			continue;
1317*3db86aabSstevel 
1318*3db86aabSstevel 		/*
1319*3db86aabSstevel 		 * need to remove the entry at index
1320*3db86aabSstevel 		 */
1321*3db86aabSstevel 		section->num_entries--;
1322*3db86aabSstevel 
1323*3db86aabSstevel 		for (i = index; i < section->num_entries; i++) {
1324*3db86aabSstevel 			section->entry[i] = section->entry[i + 1];
1325*3db86aabSstevel 		}
1326*3db86aabSstevel 
1327*3db86aabSstevel 		return (B_FALSE);
1328*3db86aabSstevel 	}
1329*3db86aabSstevel 
1330*3db86aabSstevel 	return (B_TRUE);
1331*3db86aabSstevel }
1332*3db86aabSstevel 
1333*3db86aabSstevel /*
1334*3db86aabSstevel  * Populate a section containing handles with corresponding names
1335*3db86aabSstevel  * The supplied section structure must not be publically visible and the
1336*3db86aabSstevel  * name cache must not be locked either (because RMC i/o is required).
1337*3db86aabSstevel  *
1338*3db86aabSstevel  * This is the place where a sanity check is applied. Entries containing
1339*3db86aabSstevel  * duplicate handles, duplicate names or empty names are removed and the
1340*3db86aabSstevel  * structure is compacted. As a result num_entries may be reduced.
1341*3db86aabSstevel  */
1342*3db86aabSstevel static int
1343*3db86aabSstevel add_names_to_section(rmclomv_cache_section_t *section)
1344*3db86aabSstevel {
1345*3db86aabSstevel 	int			retval = 0;
1346*3db86aabSstevel 	int			ditched = B_FALSE;
1347*3db86aabSstevel 	int			index;
1348*3db86aabSstevel 	dp_get_handle_name_r_t	handle_name_r;
1349*3db86aabSstevel 	rmclomv_cache_entry_t	*entry;
1350*3db86aabSstevel 
1351*3db86aabSstevel 	for (index = 0; index < section->num_entries; index++) {
1352*3db86aabSstevel 		entry = &section->entry[index];
1353*3db86aabSstevel 		if (entry->ind_mask != 0)
1354*3db86aabSstevel 			continue;	/* skip special entries */
1355*3db86aabSstevel 		handle_name_r.handle = entry->handle;
1356*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_HANDLE_NAME,
1357*3db86aabSstevel 		    DP_GET_HANDLE_NAME_R, sizeof (handle_name_r),
1358*3db86aabSstevel 		    (intptr_t)&handle_name_r, (intptr_t)&handle_name_r);
1359*3db86aabSstevel 		if (retval == 0)
1360*3db86aabSstevel 			bcopy(handle_name_r.name,
1361*3db86aabSstevel 			    entry->handle_name.name, DP_MAX_HANDLE_NAME);
1362*3db86aabSstevel 	}
1363*3db86aabSstevel 
1364*3db86aabSstevel 	/*
1365*3db86aabSstevel 	 * now ditch invalid and duplicate entries
1366*3db86aabSstevel 	 */
1367*3db86aabSstevel 	for (index = 0; index < section->num_entries; index++) {
1368*3db86aabSstevel 		while (validate_section_entry(section, index) == B_FALSE)
1369*3db86aabSstevel 			ditched = B_TRUE;
1370*3db86aabSstevel 	}
1371*3db86aabSstevel 
1372*3db86aabSstevel 	if (ditched)
1373*3db86aabSstevel 		cmn_err(CE_WARN, "Retaining %d nodes of type %d",
1374*3db86aabSstevel 		    section->num_entries, section->sensor_type);
1375*3db86aabSstevel 
1376*3db86aabSstevel 	return (retval);
1377*3db86aabSstevel }
1378*3db86aabSstevel 
1379*3db86aabSstevel /*
1380*3db86aabSstevel  * The supplied (PSU) cache section is traversed and entries are created
1381*3db86aabSstevel  * for the individual indicators belonging to a PSU. These entries are
1382*3db86aabSstevel  * placed in a private chain. The caller, subsequently acquires the
1383*3db86aabSstevel  * cache lock and copies the chain head to make it public.
1384*3db86aabSstevel  * The handle-names for PSU indicators are derived from the parent PSU
1385*3db86aabSstevel  * handle-name.
1386*3db86aabSstevel  * NOTE: add_names_to_section() may have reduced psu_section->num_entries
1387*3db86aabSstevel  *       so DON'T USE psu_resp->num_psus
1388*3db86aabSstevel  */
1389*3db86aabSstevel static void
1390*3db86aabSstevel make_psu_subsections(rmclomv_cache_section_t *psu_section,
1391*3db86aabSstevel     rmclomv_cache_section_t **chain_head, dp_get_psu_status_r_t *psu_resp)
1392*3db86aabSstevel {
1393*3db86aabSstevel 	int			index;
1394*3db86aabSstevel 	int			subindex = 0;
1395*3db86aabSstevel 	rmclomv_cache_section_t	*subsection;
1396*3db86aabSstevel 	rmclomv_cache_entry_t	*src_entry;
1397*3db86aabSstevel 	rmclomv_cache_entry_t	*dst_entry;
1398*3db86aabSstevel 
1399*3db86aabSstevel 	subsection = create_cache_section(RMCLOMV_VOLT_IND,
1400*3db86aabSstevel 	    RMCLOMV_MAX_VI_PER_PSU * psu_section->num_entries);
1401*3db86aabSstevel 	for (index = 0; index < psu_section->num_entries; index++) {
1402*3db86aabSstevel 		src_entry = &psu_section->entry[index];
1403*3db86aabSstevel 		if ((psu_resp->psu_status[index].mask &
1404*3db86aabSstevel 		    DP_PSU_INPUT_STATUS) != 0) {
1405*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1406*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1407*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_INPUT_STATUS;
1408*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1409*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1410*3db86aabSstevel 			    src_entry->handle_name.name,
1411*3db86aabSstevel 			    str_ip_volts_ind);
1412*3db86aabSstevel 		}
1413*3db86aabSstevel 
1414*3db86aabSstevel 		if ((psu_resp->psu_status[index].mask &
1415*3db86aabSstevel 		    DP_PSU_SEC_INPUT_STATUS) != 0) {
1416*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1417*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1418*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_SEC_INPUT_STATUS;
1419*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1420*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1421*3db86aabSstevel 			    src_entry->handle_name.name,
1422*3db86aabSstevel 			    str_ip2_volts_ind);
1423*3db86aabSstevel 		}
1424*3db86aabSstevel 
1425*3db86aabSstevel 		if ((psu_resp->psu_status[index].mask &
1426*3db86aabSstevel 		    DP_PSU_OUTPUT_STATUS) != 0) {
1427*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1428*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1429*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_OUTPUT_STATUS;
1430*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1431*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1432*3db86aabSstevel 			    src_entry->handle_name.name,
1433*3db86aabSstevel 			    str_ff_pok_ind);
1434*3db86aabSstevel 		}
1435*3db86aabSstevel 
1436*3db86aabSstevel 		if ((psu_resp->psu_status[index].mask &
1437*3db86aabSstevel 		    DP_PSU_OUTPUT_VLO_STATUS) != 0) {
1438*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1439*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1440*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_OUTPUT_VLO_STATUS;
1441*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1442*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1443*3db86aabSstevel 			    src_entry->handle_name.name,
1444*3db86aabSstevel 			    str_vlo_volts_ind);
1445*3db86aabSstevel 		}
1446*3db86aabSstevel 
1447*3db86aabSstevel 		if ((psu_resp->psu_status[index].mask &
1448*3db86aabSstevel 		    DP_PSU_OUTPUT_VHI_STATUS) != 0) {
1449*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1450*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1451*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_OUTPUT_VHI_STATUS;
1452*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1453*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1454*3db86aabSstevel 			    src_entry->handle_name.name,
1455*3db86aabSstevel 			    str_vhi_volts_ind);
1456*3db86aabSstevel 		}
1457*3db86aabSstevel 	}
1458*3db86aabSstevel 	/*
1459*3db86aabSstevel 	 * Adjust number of entries value in cache section
1460*3db86aabSstevel 	 * to match the facts.
1461*3db86aabSstevel 	 */
1462*3db86aabSstevel 	subsection->num_entries = subindex;
1463*3db86aabSstevel 	add_section(chain_head, subsection);
1464*3db86aabSstevel 
1465*3db86aabSstevel 	subsection = create_cache_section(RMCLOMV_AMP_IND,
1466*3db86aabSstevel 	    RMCLOMV_MAX_CI_PER_PSU * psu_section->num_entries);
1467*3db86aabSstevel 	subindex = 0;
1468*3db86aabSstevel 	for (index = 0; index < psu_section->num_entries; index++) {
1469*3db86aabSstevel 		int mask = psu_resp->psu_status[index].mask;
1470*3db86aabSstevel 		src_entry = &psu_section->entry[index];
1471*3db86aabSstevel 		if ((mask & DP_PSU_OUTPUT_AHI_STATUS) != 0) {
1472*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1473*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1474*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_OUTPUT_AHI_STATUS;
1475*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1476*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1477*3db86aabSstevel 			    src_entry->handle_name.name,
1478*3db86aabSstevel 			    str_chi_amps_ind);
1479*3db86aabSstevel 		}
1480*3db86aabSstevel 		if ((mask & DP_PSU_NR_WARNING) != 0) {
1481*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1482*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1483*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_NR_WARNING;
1484*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1485*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1486*3db86aabSstevel 			    src_entry->handle_name.name,
1487*3db86aabSstevel 			    str_chi_nr_ind);
1488*3db86aabSstevel 		}
1489*3db86aabSstevel 	}
1490*3db86aabSstevel 	subsection->num_entries = subindex;
1491*3db86aabSstevel 	add_section(chain_head, subsection);
1492*3db86aabSstevel 
1493*3db86aabSstevel 	subsection = create_cache_section(RMCLOMV_TEMP_IND,
1494*3db86aabSstevel 	    psu_section->num_entries);
1495*3db86aabSstevel 	subindex = 0;
1496*3db86aabSstevel 	for (index = 0; index < psu_section->num_entries; index++) {
1497*3db86aabSstevel 		if ((psu_resp->psu_status[index].mask &
1498*3db86aabSstevel 		    DP_PSU_OVERTEMP_FAULT) != 0) {
1499*3db86aabSstevel 			src_entry = &psu_section->entry[index];
1500*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1501*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1502*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_OVERTEMP_FAULT;
1503*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1504*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1505*3db86aabSstevel 			    src_entry->handle_name.name,
1506*3db86aabSstevel 			    str_ot_tmpr_ind);
1507*3db86aabSstevel 		}
1508*3db86aabSstevel 	}
1509*3db86aabSstevel 	subsection->num_entries = subindex;
1510*3db86aabSstevel 	add_section(chain_head, subsection);
1511*3db86aabSstevel 
1512*3db86aabSstevel 	subsection = create_cache_section(RMCLOMV_FAN_IND,
1513*3db86aabSstevel 	    RMCLOMV_MAX_FI_PER_PSU * psu_section->num_entries);
1514*3db86aabSstevel 	subindex = 0;
1515*3db86aabSstevel 	for (index = 0; index < psu_section->num_entries; index++) {
1516*3db86aabSstevel 		int mask = psu_resp->psu_status[index].mask;
1517*3db86aabSstevel 		src_entry = &psu_section->entry[index];
1518*3db86aabSstevel 		if ((mask & DP_PSU_FAN_FAULT) != 0) {
1519*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1520*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1521*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_FAN_FAULT;
1522*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1523*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1524*3db86aabSstevel 			    src_entry->handle_name.name, str_fan_ind);
1525*3db86aabSstevel 		}
1526*3db86aabSstevel 		if ((mask & DP_PSU_PDCT_FAN) != 0) {
1527*3db86aabSstevel 			dst_entry = &subsection->entry[subindex++];
1528*3db86aabSstevel 			dst_entry->handle = src_entry->handle;
1529*3db86aabSstevel 			dst_entry->ind_mask = DP_PSU_PDCT_FAN;
1530*3db86aabSstevel 			(void) snprintf(dst_entry->handle_name.name,
1531*3db86aabSstevel 			    ENVMON_MAXNAMELEN, "%s.%s",
1532*3db86aabSstevel 			    src_entry->handle_name.name, str_pdct_fan_ind);
1533*3db86aabSstevel 		}
1534*3db86aabSstevel 	}
1535*3db86aabSstevel 	subsection->num_entries = subindex;
1536*3db86aabSstevel 	add_section(chain_head, subsection);
1537*3db86aabSstevel }
1538*3db86aabSstevel 
1539*3db86aabSstevel static void
1540*3db86aabSstevel refresh_name_cache(int force_fail)
1541*3db86aabSstevel {
1542*3db86aabSstevel 	union {
1543*3db86aabSstevel 		dp_get_volts_t		u_volts_cmd;
1544*3db86aabSstevel 		dp_get_temperatures_t	u_temp_cmd;
1545*3db86aabSstevel 		dp_get_circuit_brks_t	u_ampi_cmd;
1546*3db86aabSstevel 		dp_get_fan_status_t	u_fan_cmd;
1547*3db86aabSstevel 		dp_get_psu_status_t	u_psu_cmd;
1548*3db86aabSstevel 		dp_get_fru_status_t	u_fru_cmd;
1549*3db86aabSstevel 		dp_get_led_state_t	u_led_cmd;
1550*3db86aabSstevel 		dp_set_led_state_t	u_setled_cmd;
1551*3db86aabSstevel 		dp_get_alarm_state_t	u_alarm_cmd;
1552*3db86aabSstevel 		dp_set_alarm_state_t	u_setalarm_cmd;
1553*3db86aabSstevel 	} rmc_cmdbuf;
1554*3db86aabSstevel 
1555*3db86aabSstevel /* defines for accessing union fields */
1556*3db86aabSstevel #define	volts_cmd	rmc_cmdbuf.u_volts_cmd
1557*3db86aabSstevel #define	temp_cmd	rmc_cmdbuf.u_temp_cmd
1558*3db86aabSstevel #define	ampi_cmd	rmc_cmdbuf.u_ampi_cmd
1559*3db86aabSstevel #define	fan_cmd		rmc_cmdbuf.u_fan_cmd
1560*3db86aabSstevel #define	psu_cmd		rmc_cmdbuf.u_psu_cmd
1561*3db86aabSstevel #define	fru_cmd		rmc_cmdbuf.u_fru_cmd
1562*3db86aabSstevel #define	led_cmd		rmc_cmdbuf.u_led_cmd
1563*3db86aabSstevel #define	setled_cmd	rmc_cmdbuf.u_setled_cmd
1564*3db86aabSstevel #define	alarm_cmd	rmc_cmdbuf.u_alarm_cmd
1565*3db86aabSstevel #define	setalarm_cmd	rmc_cmdbuf.u_setalarm_cmd
1566*3db86aabSstevel 
1567*3db86aabSstevel 	/*
1568*3db86aabSstevel 	 * Data area to read sensor data into
1569*3db86aabSstevel 	 */
1570*3db86aabSstevel 	static union {
1571*3db86aabSstevel 		char			reservation[RMCRESBUFLEN];
1572*3db86aabSstevel 		dp_get_volts_r_t	u_volts_r;
1573*3db86aabSstevel 		dp_get_temperatures_r_t	u_temp_r;
1574*3db86aabSstevel 		dp_get_circuit_brks_r_t	u_ampi_r;
1575*3db86aabSstevel 		dp_get_fan_status_r_t	u_fan_r;
1576*3db86aabSstevel 		dp_get_psu_status_r_t	u_psu_r;
1577*3db86aabSstevel 		dp_get_fru_status_r_t	u_fru_r;
1578*3db86aabSstevel 		dp_get_led_state_r_t	u_led_r;
1579*3db86aabSstevel 		dp_set_led_state_r_t	u_setled_r;
1580*3db86aabSstevel 		dp_get_alarm_state_r_t	u_alarm_r;
1581*3db86aabSstevel 		dp_set_alarm_state_r_t	u_setalarm_r;
1582*3db86aabSstevel 	} rmc_sensbuf;
1583*3db86aabSstevel 
1584*3db86aabSstevel /* defines for accessing union fields */
1585*3db86aabSstevel #define	volts_r		rmc_sensbuf.u_volts_r
1586*3db86aabSstevel #define	temp_r		rmc_sensbuf.u_temp_r
1587*3db86aabSstevel #define	ampi_r		rmc_sensbuf.u_ampi_r
1588*3db86aabSstevel #define	fan_r		rmc_sensbuf.u_fan_r
1589*3db86aabSstevel #define	psu_r		rmc_sensbuf.u_psu_r
1590*3db86aabSstevel #define	fru_r		rmc_sensbuf.u_fru_r
1591*3db86aabSstevel #define	led_r		rmc_sensbuf.u_led_r
1592*3db86aabSstevel #define	setled_r	rmc_sensbuf.u_setled_r
1593*3db86aabSstevel #define	alarm_r		rmc_sensbuf.u_alarm_r
1594*3db86aabSstevel #define	setalarm_r	rmc_sensbuf.u_setalarm_r
1595*3db86aabSstevel 
1596*3db86aabSstevel 	int			retval = force_fail;
1597*3db86aabSstevel 	int			retval1 = retval;
1598*3db86aabSstevel 	int			index;
1599*3db86aabSstevel 	rmclomv_cache_section_t	*my_chain = NULL;
1600*3db86aabSstevel 	rmclomv_cache_section_t	*derived_chain = NULL;
1601*3db86aabSstevel 	rmclomv_cache_section_t	*section;
1602*3db86aabSstevel 	rmclomv_cache_section_t	*psu_section;
1603*3db86aabSstevel 	rmclomv_cache_section_t	*fru_section;
1604*3db86aabSstevel 	dp_get_sysinfo_r_t	sysinfo;
1605*3db86aabSstevel 	rmclomv_cache_entry_t	*entry;
1606*3db86aabSstevel 
1607*3db86aabSstevel 	if (retval == 0) {
1608*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R,
1609*3db86aabSstevel 		    sizeof (sysinfo), NULL, (intptr_t)&sysinfo);
1610*3db86aabSstevel 	}
1611*3db86aabSstevel 	if (retval == 0) {
1612*3db86aabSstevel 		fru_cmd.handle = DP_NULL_HANDLE;
1613*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_FRU_STATUS, DP_GET_FRU_STATUS_R,
1614*3db86aabSstevel 		    RMCRESBUFLEN, (intptr_t)&fru_cmd, (intptr_t)&fru_r);
1615*3db86aabSstevel 	}
1616*3db86aabSstevel 	if (retval != 0)
1617*3db86aabSstevel 		fru_r.num_frus = 0;
1618*3db86aabSstevel 
1619*3db86aabSstevel 	/*
1620*3db86aabSstevel 	 * Reserve space for special additional entries in the FRU section
1621*3db86aabSstevel 	 */
1622*3db86aabSstevel 	fru_section = create_cache_section(RMCLOMV_HPU_IND,
1623*3db86aabSstevel 	    RMCLOMV_NUM_SPECIAL_FRUS + fru_r.num_frus);
1624*3db86aabSstevel 
1625*3db86aabSstevel 	/*
1626*3db86aabSstevel 	 * add special entry for RMC itself
1627*3db86aabSstevel 	 */
1628*3db86aabSstevel 	entry = &fru_section->entry[0];
1629*3db86aabSstevel 	(void) snprintf(entry->handle_name.name, sizeof (envmon_handle_t),
1630*3db86aabSstevel 	    "SC");
1631*3db86aabSstevel 	entry->handle = 0;
1632*3db86aabSstevel 	entry->ind_mask = 1;	/* flag as a special entry */
1633*3db86aabSstevel 
1634*3db86aabSstevel 	/*
1635*3db86aabSstevel 	 * populate any other FRU entries
1636*3db86aabSstevel 	 */
1637*3db86aabSstevel 	for (index = 0; index < fru_r.num_frus; index++) {
1638*3db86aabSstevel 		fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].handle =
1639*3db86aabSstevel 		    fru_r.fru_status[index].handle;
1640*3db86aabSstevel 		fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].ind_mask =
1641*3db86aabSstevel 		    0;
1642*3db86aabSstevel 	}
1643*3db86aabSstevel 
1644*3db86aabSstevel 	my_chain = fru_section;
1645*3db86aabSstevel 
1646*3db86aabSstevel 	if (retval == 0) {
1647*3db86aabSstevel 		volts_cmd.handle = DP_NULL_HANDLE;
1648*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R,
1649*3db86aabSstevel 		    RMCRESBUFLEN, (intptr_t)&volts_cmd, (intptr_t)&volts_r);
1650*3db86aabSstevel 	}
1651*3db86aabSstevel 	if (retval == 0) {
1652*3db86aabSstevel 		section = create_cache_section(RMCLOMV_VOLT_SENS,
1653*3db86aabSstevel 		    volts_r.num_volts);
1654*3db86aabSstevel 		for (index = 0; index < volts_r.num_volts; index++) {
1655*3db86aabSstevel 			section->entry[index].handle =
1656*3db86aabSstevel 			    volts_r.volt_status[index].handle;
1657*3db86aabSstevel 		}
1658*3db86aabSstevel 		add_section(&my_chain, section);
1659*3db86aabSstevel 	}
1660*3db86aabSstevel 	if (retval == 0) {
1661*3db86aabSstevel 		temp_cmd.handle = DP_NULL_HANDLE;
1662*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_TEMPERATURES,
1663*3db86aabSstevel 		    DP_GET_TEMPERATURES_R, RMCRESBUFLEN,
1664*3db86aabSstevel 		    (intptr_t)&temp_cmd, (intptr_t)&temp_r);
1665*3db86aabSstevel 	}
1666*3db86aabSstevel 	if (retval == 0) {
1667*3db86aabSstevel 		section = create_cache_section(RMCLOMV_TEMP_SENS,
1668*3db86aabSstevel 		    temp_r.num_temps);
1669*3db86aabSstevel 		for (index = 0; index < temp_r.num_temps; index++) {
1670*3db86aabSstevel 			section->entry[index].handle =
1671*3db86aabSstevel 			    temp_r.temp_status[index].handle;
1672*3db86aabSstevel 		}
1673*3db86aabSstevel 		add_section(&my_chain, section);
1674*3db86aabSstevel 	}
1675*3db86aabSstevel 	if (retval == 0) {
1676*3db86aabSstevel 		fan_cmd.handle = DP_NULL_HANDLE;
1677*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R,
1678*3db86aabSstevel 		    RMCRESBUFLEN, (intptr_t)&fan_cmd, (intptr_t)&fan_r);
1679*3db86aabSstevel 	}
1680*3db86aabSstevel 	if (retval == 0) {
1681*3db86aabSstevel 		section = create_cache_section(RMCLOMV_FAN_SENS,
1682*3db86aabSstevel 		    fan_r.num_fans);
1683*3db86aabSstevel 		for (index = 0; index < fan_r.num_fans; index++) {
1684*3db86aabSstevel 			section->entry[index].handle =
1685*3db86aabSstevel 			    fan_r.fan_status[index].handle;
1686*3db86aabSstevel 		}
1687*3db86aabSstevel 		add_section(&my_chain, section);
1688*3db86aabSstevel 	}
1689*3db86aabSstevel 	if (retval == 0) {
1690*3db86aabSstevel 		ampi_cmd.handle = DP_NULL_HANDLE;
1691*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS,
1692*3db86aabSstevel 		    DP_GET_CIRCUIT_BRKS_R, RMCRESBUFLEN,
1693*3db86aabSstevel 		    (intptr_t)&ampi_cmd, (intptr_t)&ampi_r);
1694*3db86aabSstevel 	}
1695*3db86aabSstevel 	if (retval == 0) {
1696*3db86aabSstevel 		section = create_cache_section(RMCLOMV_AMP_IND,
1697*3db86aabSstevel 		    ampi_r.num_circuit_brks);
1698*3db86aabSstevel 		for (index = 0; index < ampi_r.num_circuit_brks; index++) {
1699*3db86aabSstevel 			section->entry[index].handle =
1700*3db86aabSstevel 			    ampi_r.circuit_brk_status[index].handle;
1701*3db86aabSstevel 		}
1702*3db86aabSstevel 		add_section(&my_chain, section);
1703*3db86aabSstevel 	}
1704*3db86aabSstevel 	if (retval == 0) {
1705*3db86aabSstevel 		led_cmd.handle = DP_NULL_HANDLE;
1706*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R,
1707*3db86aabSstevel 		    RMCRESBUFLEN, (intptr_t)&led_cmd, (intptr_t)&led_r);
1708*3db86aabSstevel 	}
1709*3db86aabSstevel 	if (retval == 0) {
1710*3db86aabSstevel 		section = create_cache_section(RMCLOMV_LED_IND,
1711*3db86aabSstevel 		    led_r.num_leds);
1712*3db86aabSstevel 		for (index = 0; index < led_r.num_leds; index++) {
1713*3db86aabSstevel 			section->entry[index].handle =
1714*3db86aabSstevel 			    led_r.led_state[index].handle;
1715*3db86aabSstevel 		}
1716*3db86aabSstevel 		add_section(&my_chain, section);
1717*3db86aabSstevel 	}
1718*3db86aabSstevel 	/*
1719*3db86aabSstevel 	 * The command DP_GET_ALARM_STATE may not be valid on
1720*3db86aabSstevel 	 * some RMC versions, so we ignore the return value
1721*3db86aabSstevel 	 * and proceed
1722*3db86aabSstevel 	 */
1723*3db86aabSstevel 	if (retval == 0) {
1724*3db86aabSstevel 		alarm_cmd.handle = DP_NULL_HANDLE;
1725*3db86aabSstevel 		retval1 = rmclomv_do_cmd(DP_GET_ALARM_STATE,
1726*3db86aabSstevel 			DP_GET_ALARM_STATE_R, RMCRESBUFLEN,
1727*3db86aabSstevel 			(intptr_t)&alarm_cmd, (intptr_t)&alarm_r);
1728*3db86aabSstevel 		if ((retval1 == 0) && alarm_r.num_alarms) {
1729*3db86aabSstevel 			section = create_cache_section(RMCLOMV_ALARM_IND,
1730*3db86aabSstevel 				alarm_r.num_alarms);
1731*3db86aabSstevel 			for (index = 0; index < alarm_r.num_alarms; index++) {
1732*3db86aabSstevel 				section->entry[index].handle =
1733*3db86aabSstevel 					alarm_r.alarm_state[index].handle;
1734*3db86aabSstevel 			}
1735*3db86aabSstevel 			add_section(&my_chain, section);
1736*3db86aabSstevel 		}
1737*3db86aabSstevel 	}
1738*3db86aabSstevel 	if (retval == 0) {
1739*3db86aabSstevel 		psu_cmd.handle = DP_NULL_HANDLE;
1740*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R,
1741*3db86aabSstevel 		    RMCRESBUFLEN, (intptr_t)&psu_cmd, (intptr_t)&psu_r);
1742*3db86aabSstevel 	}
1743*3db86aabSstevel 	if (retval == 0) {
1744*3db86aabSstevel 		/*
1745*3db86aabSstevel 		 * WARNING:
1746*3db86aabSstevel 		 * =======
1747*3db86aabSstevel 		 * The PSUs must be probed last so that the response data
1748*3db86aabSstevel 		 * (psu_r) is available for make_psu_subsections() below.
1749*3db86aabSstevel 		 * Note that all the responses share the same data area
1750*3db86aabSstevel 		 * which is declared as a union.
1751*3db86aabSstevel 		 */
1752*3db86aabSstevel 		psu_section = create_cache_section(RMCLOMV_PSU_IND,
1753*3db86aabSstevel 		    psu_r.num_psus);
1754*3db86aabSstevel 		for (index = 0; index < psu_r.num_psus; index++) {
1755*3db86aabSstevel 			psu_section->entry[index].handle =
1756*3db86aabSstevel 			    psu_r.psu_status[index].handle;
1757*3db86aabSstevel 		}
1758*3db86aabSstevel 		add_section(&my_chain, psu_section);
1759*3db86aabSstevel 	}
1760*3db86aabSstevel 	if (retval == 0) {
1761*3db86aabSstevel 		for (section = my_chain;
1762*3db86aabSstevel 		    section != NULL;
1763*3db86aabSstevel 		    section = section->next_section) {
1764*3db86aabSstevel 			retval = add_names_to_section(section);
1765*3db86aabSstevel 			if (retval != 0) {
1766*3db86aabSstevel 				break;
1767*3db86aabSstevel 			}
1768*3db86aabSstevel 		}
1769*3db86aabSstevel 	}
1770*3db86aabSstevel 
1771*3db86aabSstevel 	/*
1772*3db86aabSstevel 	 * now add nodes derived from PSUs
1773*3db86aabSstevel 	 */
1774*3db86aabSstevel 	if (retval == 0) {
1775*3db86aabSstevel 		make_psu_subsections(psu_section, &derived_chain, &psu_r);
1776*3db86aabSstevel 		/*
1777*3db86aabSstevel 		 * name cache sections all set, exchange new for old
1778*3db86aabSstevel 		 */
1779*3db86aabSstevel 		rmclomv_reset_cache(my_chain, derived_chain, &sysinfo);
1780*3db86aabSstevel 	} else {
1781*3db86aabSstevel 		/*
1782*3db86aabSstevel 		 * RMC is not responding, ditch any existing cache
1783*3db86aabSstevel 		 * and just leave the special SC FRU node
1784*3db86aabSstevel 		 */
1785*3db86aabSstevel 		rmclomv_reset_cache(my_chain, NULL, NULL);
1786*3db86aabSstevel 	}
1787*3db86aabSstevel }
1788*3db86aabSstevel 
1789*3db86aabSstevel static void
1790*3db86aabSstevel set_val_unav(envmon_sensor_t *sensor)
1791*3db86aabSstevel {
1792*3db86aabSstevel 	sensor->value = ENVMON_VAL_UNAVAILABLE;
1793*3db86aabSstevel 	sensor->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE;
1794*3db86aabSstevel 	sensor->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
1795*3db86aabSstevel 	sensor->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
1796*3db86aabSstevel 	sensor->highthresholds.warning = ENVMON_VAL_UNAVAILABLE;
1797*3db86aabSstevel 	sensor->highthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
1798*3db86aabSstevel 	sensor->highthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
1799*3db86aabSstevel }
1800*3db86aabSstevel 
1801*3db86aabSstevel static void
1802*3db86aabSstevel set_fan_unav(envmon_fan_t *fan)
1803*3db86aabSstevel {
1804*3db86aabSstevel 	fan->speed = ENVMON_VAL_UNAVAILABLE;
1805*3db86aabSstevel 	fan->units[0] = '\0';
1806*3db86aabSstevel 	fan->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE;
1807*3db86aabSstevel 	fan->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE;
1808*3db86aabSstevel 	fan->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE;
1809*3db86aabSstevel }
1810*3db86aabSstevel 
1811*3db86aabSstevel static int
1812*3db86aabSstevel do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind,
1813*3db86aabSstevel     dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r,
1814*3db86aabSstevel     int detector_type)
1815*3db86aabSstevel {
1816*3db86aabSstevel 	int			index;
1817*3db86aabSstevel 	uint16_t		sensor_status;
1818*3db86aabSstevel 	rmclomv_cache_section_t	*section;
1819*3db86aabSstevel 	uint16_t		indicator_mask;
1820*3db86aabSstevel 
1821*3db86aabSstevel 	if (ddi_copyin((caddr_t)arg, (caddr_t)env_ind,
1822*3db86aabSstevel 	    sizeof (envmon_indicator_t), mode) != 0)
1823*3db86aabSstevel 		return (EFAULT);
1824*3db86aabSstevel 
1825*3db86aabSstevel 	/* ensure we've got PSU handles cached */
1826*3db86aabSstevel 	LOCK_CACHE
1827*3db86aabSstevel 
1828*3db86aabSstevel 	sensor_status = ENVMON_SENSOR_OK;
1829*3db86aabSstevel 	section = rmclomv_find_section(rmclomv_subcache, detector_type);
1830*3db86aabSstevel 	if (env_ind->id.name[0] == '\0') {
1831*3db86aabSstevel 		/* request for first handle */
1832*3db86aabSstevel 		if ((section == NULL) || (section->num_entries == 0))
1833*3db86aabSstevel 			env_ind->next_id.name[0] = '\0';
1834*3db86aabSstevel 		else
1835*3db86aabSstevel 			env_ind->next_id = section->entry[0].handle_name;
1836*3db86aabSstevel 		sensor_status = ENVMON_NOT_PRESENT;
1837*3db86aabSstevel 	} else {
1838*3db86aabSstevel 		/* ensure name is properly terminated */
1839*3db86aabSstevel 		env_ind->id.name[ENVMON_MAXNAMELEN - 1] = '\0';
1840*3db86aabSstevel 		if ((section == NULL) || (get_sensor_by_name(section,
1841*3db86aabSstevel 		    env_ind->id.name, &index)) != 0) {
1842*3db86aabSstevel 			env_ind->next_id.name[0] = '\0';
1843*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
1844*3db86aabSstevel 		} else if (index + 1 < section->num_entries)
1845*3db86aabSstevel 			env_ind->next_id =
1846*3db86aabSstevel 			    section->entry[index + 1].handle_name;
1847*3db86aabSstevel 		else
1848*3db86aabSstevel 			env_ind->next_id.name[0] = '\0';
1849*3db86aabSstevel 	}
1850*3db86aabSstevel 	if (sensor_status == ENVMON_SENSOR_OK) {
1851*3db86aabSstevel 		/*
1852*3db86aabSstevel 		 * user correctly identified a sensor, note its
1853*3db86aabSstevel 		 * handle value and request the indicator status
1854*3db86aabSstevel 		 */
1855*3db86aabSstevel 		rmc_psu->handle = section->entry[index].handle;
1856*3db86aabSstevel 		indicator_mask = section->entry[index].ind_mask;
1857*3db86aabSstevel 	}
1858*3db86aabSstevel 
1859*3db86aabSstevel 	RELEASE_CACHE
1860*3db86aabSstevel 
1861*3db86aabSstevel 	if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
1862*3db86aabSstevel 	    rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R,
1863*3db86aabSstevel 	    sizeof (dp_get_psu_status_r_t), (intptr_t)rmc_psu,
1864*3db86aabSstevel 	    (intptr_t)rmc_psu_r) != 0)) {
1865*3db86aabSstevel 		sensor_status = ENVMON_INACCESSIBLE;
1866*3db86aabSstevel 	}
1867*3db86aabSstevel 	if ((env_ind->sensor_status = sensor_status) == ENVMON_SENSOR_OK) {
1868*3db86aabSstevel 		/*
1869*3db86aabSstevel 		 * copy results into buffer for user
1870*3db86aabSstevel 		 */
1871*3db86aabSstevel 		if ((rmc_psu_r->psu_status[0].flag & DP_PSU_PRESENCE) == 0)
1872*3db86aabSstevel 			env_ind->sensor_status |= ENVMON_NOT_PRESENT;
1873*3db86aabSstevel 		if (rmc_psu_r->psu_status[0].sensor_status !=
1874*3db86aabSstevel 		    DP_SENSOR_DATA_AVAILABLE)
1875*3db86aabSstevel 			env_ind->sensor_status |= ENVMON_INACCESSIBLE;
1876*3db86aabSstevel 		env_ind->condition =
1877*3db86aabSstevel 		    (rmc_psu_r->psu_status[0].flag & indicator_mask) == 0 ?
1878*3db86aabSstevel 		    0 : 1;
1879*3db86aabSstevel 	}
1880*3db86aabSstevel 
1881*3db86aabSstevel 	if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
1882*3db86aabSstevel 	    env_ind->sensor_status = ENVMON_INACCESSIBLE;
1883*3db86aabSstevel 
1884*3db86aabSstevel 	if (ddi_copyout((caddr_t)env_ind, (caddr_t)arg,
1885*3db86aabSstevel 	    sizeof (envmon_indicator_t), mode) != 0)
1886*3db86aabSstevel 		return (EFAULT);
1887*3db86aabSstevel 
1888*3db86aabSstevel 	return (0);
1889*3db86aabSstevel }
1890*3db86aabSstevel 
1891*3db86aabSstevel /*ARGSUSED*/
1892*3db86aabSstevel static int
1893*3db86aabSstevel rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
1894*3db86aabSstevel     int *rval_p)
1895*3db86aabSstevel {
1896*3db86aabSstevel 	int instance = getminor(dev);
1897*3db86aabSstevel 	envmon_sysinfo_t lomv_sysinfo;
1898*3db86aabSstevel 	union {
1899*3db86aabSstevel 		envmon_sensor_t		u_env_sensor;
1900*3db86aabSstevel 		envmon_indicator_t	u_env_ind;
1901*3db86aabSstevel 		envmon_fan_t		u_env_fan;
1902*3db86aabSstevel 		envmon_led_info_t	u_env_ledinfo;
1903*3db86aabSstevel 		envmon_led_ctl_t	u_env_ledctl;
1904*3db86aabSstevel 		envmon_hpu_t		u_env_hpu;
1905*3db86aabSstevel 		envmon_alarm_info_t	u_env_alarminfo;
1906*3db86aabSstevel 		envmon_alarm_ctl_t	u_env_alarmctl;
1907*3db86aabSstevel 	} env_buf;
1908*3db86aabSstevel #define	env_sensor	env_buf.u_env_sensor
1909*3db86aabSstevel #define	env_ind		env_buf.u_env_ind
1910*3db86aabSstevel #define	env_fan		env_buf.u_env_fan
1911*3db86aabSstevel #define	env_ledinfo	env_buf.u_env_ledinfo
1912*3db86aabSstevel #define	env_ledctl	env_buf.u_env_ledctl
1913*3db86aabSstevel #define	env_hpu		env_buf.u_env_hpu
1914*3db86aabSstevel #define	env_alarminfo	env_buf.u_env_alarminfo
1915*3db86aabSstevel #define	env_alarmctl	env_buf.u_env_alarmctl
1916*3db86aabSstevel 
1917*3db86aabSstevel 	union {
1918*3db86aabSstevel 		dp_get_volts_t		u_rmc_volts;
1919*3db86aabSstevel 		dp_get_temperatures_t	u_rmc_temp;
1920*3db86aabSstevel 		dp_get_circuit_brks_t	u_rmc_ampi;
1921*3db86aabSstevel 		dp_get_fan_status_t	u_rmc_fan;
1922*3db86aabSstevel 		dp_get_psu_status_t	u_rmc_psu;
1923*3db86aabSstevel 		dp_get_fru_status_t	u_rmc_fru;
1924*3db86aabSstevel 		dp_get_led_state_t	u_rmc_led;
1925*3db86aabSstevel 		dp_set_led_state_t	u_rmc_setled;
1926*3db86aabSstevel 		dp_get_alarm_state_t	u_rmc_alarm;
1927*3db86aabSstevel 		dp_set_alarm_state_t	u_rmc_setalarm;
1928*3db86aabSstevel 	} rmc_reqbuf;
1929*3db86aabSstevel #define	rmc_volts	rmc_reqbuf.u_rmc_volts
1930*3db86aabSstevel #define	rmc_temp	rmc_reqbuf.u_rmc_temp
1931*3db86aabSstevel #define	rmc_ampi	rmc_reqbuf.u_rmc_ampi
1932*3db86aabSstevel #define	rmc_fan		rmc_reqbuf.u_rmc_fan
1933*3db86aabSstevel #define	rmc_psu		rmc_reqbuf.u_rmc_psu
1934*3db86aabSstevel #define	rmc_fru		rmc_reqbuf.u_rmc_fru
1935*3db86aabSstevel #define	rmc_led		rmc_reqbuf.u_rmc_led
1936*3db86aabSstevel #define	rmc_setled	rmc_reqbuf.u_rmc_setled
1937*3db86aabSstevel #define	rmc_alarm	rmc_reqbuf.u_rmc_alarm
1938*3db86aabSstevel #define	rmc_setalarm	rmc_reqbuf.u_rmc_setalarm
1939*3db86aabSstevel 
1940*3db86aabSstevel 	union {
1941*3db86aabSstevel 		dp_get_volts_r_t	u_rmc_volts_r;
1942*3db86aabSstevel 		dp_get_temperatures_r_t	u_rmc_temp_r;
1943*3db86aabSstevel 		dp_get_circuit_brks_r_t	u_rmc_ampi_r;
1944*3db86aabSstevel 		dp_get_fan_status_r_t	u_rmc_fan_r;
1945*3db86aabSstevel 		dp_get_psu_status_r_t	u_rmc_psu_r;
1946*3db86aabSstevel 		dp_get_fru_status_r_t	u_rmc_fru_r;
1947*3db86aabSstevel 		dp_get_led_state_r_t	u_rmc_led_r;
1948*3db86aabSstevel 		dp_set_led_state_r_t	u_rmc_setled_r;
1949*3db86aabSstevel 		dp_get_alarm_state_r_t	u_rmc_alarm_r;
1950*3db86aabSstevel 		dp_set_alarm_state_r_t	u_rmc_setalarm_r;
1951*3db86aabSstevel 		dp_get_sdp_version_r_t	u_rmc_sdpversion_r;
1952*3db86aabSstevel 		dp_get_serialnum_r_t	u_rmc_serialnum_r;
1953*3db86aabSstevel 	} rmc_resbuf;
1954*3db86aabSstevel #define	rmc_volts_r	rmc_resbuf.u_rmc_volts_r
1955*3db86aabSstevel #define	rmc_temp_r	rmc_resbuf.u_rmc_temp_r
1956*3db86aabSstevel #define	rmc_ampi_r	rmc_resbuf.u_rmc_ampi_r
1957*3db86aabSstevel #define	rmc_fan_r	rmc_resbuf.u_rmc_fan_r
1958*3db86aabSstevel #define	rmc_psu_r	rmc_resbuf.u_rmc_psu_r
1959*3db86aabSstevel #define	rmc_fru_r	rmc_resbuf.u_rmc_fru_r
1960*3db86aabSstevel #define	rmc_led_r	rmc_resbuf.u_rmc_led_r
1961*3db86aabSstevel #define	rmc_setled_r	rmc_resbuf.u_rmc_setled_r
1962*3db86aabSstevel #define	rmc_alarm_r	rmc_resbuf.u_rmc_alarm_r
1963*3db86aabSstevel #define	rmc_setalarm_r	rmc_resbuf.u_rmc_setalarm_r
1964*3db86aabSstevel #define	rmc_sdpver_r	rmc_resbuf.u_rmc_sdpversion_r
1965*3db86aabSstevel #define	rmc_serialnum_r	rmc_resbuf.u_rmc_serialnum_r
1966*3db86aabSstevel 
1967*3db86aabSstevel 	int			retval = 0;
1968*3db86aabSstevel 	int			special = 0;
1969*3db86aabSstevel 	int			index;
1970*3db86aabSstevel 	uint16_t		sensor_status;
1971*3db86aabSstevel 	rmclomv_cache_section_t	*section;
1972*3db86aabSstevel 	envmon_chassis_t chassis;
1973*3db86aabSstevel 
1974*3db86aabSstevel 	if (instance != 0)
1975*3db86aabSstevel 		return (ENXIO);
1976*3db86aabSstevel 
1977*3db86aabSstevel 	switch (cmd) {
1978*3db86aabSstevel 	case ENVMONIOCSYSINFO:
1979*3db86aabSstevel 
1980*3db86aabSstevel 		LOCK_CACHE
1981*3db86aabSstevel 
1982*3db86aabSstevel 		/*
1983*3db86aabSstevel 		 * A number of OK/not_OK indicators are supported by PSUs
1984*3db86aabSstevel 		 * (voltage, current, fan, temperature). So the maximum
1985*3db86aabSstevel 		 * number of such indicators relates to the maximum number
1986*3db86aabSstevel 		 * of power-supplies.
1987*3db86aabSstevel 		 */
1988*3db86aabSstevel 		if (rmclomv_sysinfo_valid) {
1989*3db86aabSstevel 			lomv_sysinfo.maxVoltSens = rmclomv_sysinfo_data.maxVolt;
1990*3db86aabSstevel 			lomv_sysinfo.maxVoltInd =
1991*3db86aabSstevel 			    RMCLOMV_MAX_VI_PER_PSU *
1992*3db86aabSstevel 			    rmclomv_sysinfo_data.maxPSU;
1993*3db86aabSstevel 			/*
1994*3db86aabSstevel 			 * the ALOM-Solaris interface does not include
1995*3db86aabSstevel 			 * amp sensors, so we can hard code this value
1996*3db86aabSstevel 			 */
1997*3db86aabSstevel 			lomv_sysinfo.maxAmpSens = 0;
1998*3db86aabSstevel 			lomv_sysinfo.maxAmpInd =
1999*3db86aabSstevel 			    rmclomv_sysinfo_data.maxCircuitBrks +
2000*3db86aabSstevel 			    (RMCLOMV_MAX_CI_PER_PSU *
2001*3db86aabSstevel 			    rmclomv_sysinfo_data.maxPSU);
2002*3db86aabSstevel 			lomv_sysinfo.maxTempSens = rmclomv_sysinfo_data.maxTemp;
2003*3db86aabSstevel 			lomv_sysinfo.maxTempInd =
2004*3db86aabSstevel 			    (RMCLOMV_MAX_TI_PER_PSU *
2005*3db86aabSstevel 			    rmclomv_sysinfo_data.maxPSU);
2006*3db86aabSstevel 			lomv_sysinfo.maxFanSens = rmclomv_sysinfo_data.maxFan;
2007*3db86aabSstevel 			lomv_sysinfo.maxFanInd =
2008*3db86aabSstevel 			    RMCLOMV_MAX_FI_PER_PSU *
2009*3db86aabSstevel 			    rmclomv_sysinfo_data.maxPSU;
2010*3db86aabSstevel 			lomv_sysinfo.maxLED = rmclomv_sysinfo_data.maxLED;
2011*3db86aabSstevel 			lomv_sysinfo.maxHPU = RMCLOMV_NUM_SPECIAL_FRUS +
2012*3db86aabSstevel 			    rmclomv_sysinfo_data.maxFRU;
2013*3db86aabSstevel 		} else {
2014*3db86aabSstevel 			bzero(&lomv_sysinfo, sizeof (lomv_sysinfo));
2015*3db86aabSstevel 			lomv_sysinfo.maxHPU = 1;	/* just the SC node */
2016*3db86aabSstevel 		}
2017*3db86aabSstevel 
2018*3db86aabSstevel 		RELEASE_CACHE
2019*3db86aabSstevel 
2020*3db86aabSstevel 		if (ddi_copyout((caddr_t)&lomv_sysinfo, (caddr_t)arg,
2021*3db86aabSstevel 		    sizeof (lomv_sysinfo), mode) != 0)
2022*3db86aabSstevel 			return (EFAULT);
2023*3db86aabSstevel 		break;
2024*3db86aabSstevel 
2025*3db86aabSstevel 	case ENVMONIOCVOLTSENSOR:
2026*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
2027*3db86aabSstevel 		    sizeof (envmon_sensor_t), mode) != 0)
2028*3db86aabSstevel 			return (EFAULT);
2029*3db86aabSstevel 
2030*3db86aabSstevel 		/* see if we've got volts handles cached */
2031*3db86aabSstevel 		LOCK_CACHE
2032*3db86aabSstevel 		sensor_status = ENVMON_SENSOR_OK;
2033*3db86aabSstevel 
2034*3db86aabSstevel 		if ((rmclomv_cache_valid == B_FALSE) ||
2035*3db86aabSstevel 		    ((section = rmclomv_find_section(rmclomv_cache,
2036*3db86aabSstevel 		    RMCLOMV_VOLT_SENS)) == NULL)) {
2037*3db86aabSstevel 			env_sensor.next_id.name[0] = '\0';
2038*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2039*3db86aabSstevel 		} else if (env_sensor.id.name[0] == '\0') {
2040*3db86aabSstevel 			/* request for first handle */
2041*3db86aabSstevel 			if (section->num_entries == 0)
2042*3db86aabSstevel 				env_sensor.next_id.name[0] = '\0';
2043*3db86aabSstevel 			else
2044*3db86aabSstevel 				env_sensor.next_id =
2045*3db86aabSstevel 				    section->entry[0].handle_name;
2046*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2047*3db86aabSstevel 		} else {
2048*3db86aabSstevel 			/* ensure name is properly terminated */
2049*3db86aabSstevel 			env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2050*3db86aabSstevel 			if (get_sensor_by_name(section, env_sensor.id.name,
2051*3db86aabSstevel 			    &index) != 0) {
2052*3db86aabSstevel 				env_sensor.next_id.name[0] = '\0';
2053*3db86aabSstevel 				sensor_status = ENVMON_NOT_PRESENT;
2054*3db86aabSstevel 			} else if (index + 1 < section->num_entries)
2055*3db86aabSstevel 				env_sensor.next_id =
2056*3db86aabSstevel 				    section->entry[index + 1].handle_name;
2057*3db86aabSstevel 			else
2058*3db86aabSstevel 				env_sensor.next_id.name[0] = '\0';
2059*3db86aabSstevel 		}
2060*3db86aabSstevel 		if (sensor_status == ENVMON_SENSOR_OK) {
2061*3db86aabSstevel 			/*
2062*3db86aabSstevel 			 * user correctly identified a sensor, note its
2063*3db86aabSstevel 			 * handle value and request the sensor value
2064*3db86aabSstevel 			 */
2065*3db86aabSstevel 			rmc_volts.handle = section->entry[index].handle;
2066*3db86aabSstevel 		}
2067*3db86aabSstevel 		RELEASE_CACHE
2068*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2069*3db86aabSstevel 		    rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R,
2070*3db86aabSstevel 		    sizeof (rmc_volts_r), (intptr_t)&rmc_volts,
2071*3db86aabSstevel 		    (intptr_t)&rmc_volts_r) != 0)) {
2072*3db86aabSstevel 			sensor_status = ENVMON_INACCESSIBLE;
2073*3db86aabSstevel 		}
2074*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) &&
2075*3db86aabSstevel 		    (rmc_volts_r.volt_status[0].sensor_status ==
2076*3db86aabSstevel 		    DP_SENSOR_NOT_PRESENT)) {
2077*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2078*3db86aabSstevel 		}
2079*3db86aabSstevel 		if ((env_sensor.sensor_status = sensor_status) ==
2080*3db86aabSstevel 		    ENVMON_SENSOR_OK) {
2081*3db86aabSstevel 			/*
2082*3db86aabSstevel 			 * copy results into buffer for user
2083*3db86aabSstevel 			 */
2084*3db86aabSstevel 			if (rmc_volts_r.volt_status[0].sensor_status !=
2085*3db86aabSstevel 			    DP_SENSOR_DATA_AVAILABLE)
2086*3db86aabSstevel 				env_sensor.sensor_status = ENVMON_INACCESSIBLE;
2087*3db86aabSstevel 			env_sensor.value =
2088*3db86aabSstevel 			    rmc_volts_r.volt_status[0].reading;
2089*3db86aabSstevel 			env_sensor.lowthresholds.warning =
2090*3db86aabSstevel 			    rmc_volts_r.volt_status[0].low_warning;
2091*3db86aabSstevel 			env_sensor.lowthresholds.shutdown =
2092*3db86aabSstevel 			    rmc_volts_r.volt_status[0].low_soft_shutdown;
2093*3db86aabSstevel 			env_sensor.lowthresholds.poweroff =
2094*3db86aabSstevel 			    rmc_volts_r.volt_status[0].low_hard_shutdown;
2095*3db86aabSstevel 			env_sensor.highthresholds.warning =
2096*3db86aabSstevel 			    rmc_volts_r.volt_status[0].high_warning;
2097*3db86aabSstevel 			env_sensor.highthresholds.shutdown =
2098*3db86aabSstevel 			    rmc_volts_r.volt_status[0].high_soft_shutdown;
2099*3db86aabSstevel 			env_sensor.highthresholds.poweroff =
2100*3db86aabSstevel 			    rmc_volts_r.volt_status[0].high_hard_shutdown;
2101*3db86aabSstevel 		}
2102*3db86aabSstevel 		if (env_sensor.sensor_status != ENVMON_SENSOR_OK ||
2103*3db86aabSstevel 		    rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
2104*3db86aabSstevel 			set_val_unav(&env_sensor);
2105*3db86aabSstevel 
2106*3db86aabSstevel 		if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
2107*3db86aabSstevel 		    sizeof (envmon_sensor_t), mode) != 0)
2108*3db86aabSstevel 			return (EFAULT);
2109*3db86aabSstevel 		break;
2110*3db86aabSstevel 
2111*3db86aabSstevel 	case ENVMONIOCVOLTIND:
2112*3db86aabSstevel 		return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
2113*3db86aabSstevel 		    RMCLOMV_VOLT_IND));
2114*3db86aabSstevel 
2115*3db86aabSstevel 	case ENVMONIOCTEMPIND:
2116*3db86aabSstevel 		return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
2117*3db86aabSstevel 		    RMCLOMV_TEMP_IND));
2118*3db86aabSstevel 
2119*3db86aabSstevel 	case ENVMONIOCFANIND:
2120*3db86aabSstevel 		return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r,
2121*3db86aabSstevel 		    RMCLOMV_FAN_IND));
2122*3db86aabSstevel 
2123*3db86aabSstevel 	case ENVMONIOCAMPSENSOR:
2124*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
2125*3db86aabSstevel 		    sizeof (envmon_sensor_t), mode) != 0)
2126*3db86aabSstevel 			return (EFAULT);
2127*3db86aabSstevel 
2128*3db86aabSstevel 		env_sensor.sensor_status = ENVMON_NOT_PRESENT;
2129*3db86aabSstevel 		env_sensor.next_id.name[0] = '\0';
2130*3db86aabSstevel 
2131*3db86aabSstevel 		if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
2132*3db86aabSstevel 		    sizeof (envmon_sensor_t), mode) != 0)
2133*3db86aabSstevel 			return (EFAULT);
2134*3db86aabSstevel 		break;
2135*3db86aabSstevel 
2136*3db86aabSstevel 	case ENVMONIOCTEMPSENSOR:
2137*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor,
2138*3db86aabSstevel 		    sizeof (envmon_sensor_t), mode) != 0)
2139*3db86aabSstevel 			return (EFAULT);
2140*3db86aabSstevel 
2141*3db86aabSstevel 		/* see if we've got temperature handles cached */
2142*3db86aabSstevel 		LOCK_CACHE
2143*3db86aabSstevel 		sensor_status = ENVMON_SENSOR_OK;
2144*3db86aabSstevel 
2145*3db86aabSstevel 		if ((rmclomv_cache_valid == B_FALSE) ||
2146*3db86aabSstevel 		    ((section = rmclomv_find_section(rmclomv_cache,
2147*3db86aabSstevel 		    RMCLOMV_TEMP_SENS)) == NULL)) {
2148*3db86aabSstevel 			env_sensor.next_id.name[0] = '\0';
2149*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2150*3db86aabSstevel 		} else if (env_sensor.id.name[0] == '\0') {
2151*3db86aabSstevel 			/* request for first handle */
2152*3db86aabSstevel 			if (section->num_entries == 0)
2153*3db86aabSstevel 				env_sensor.next_id.name[0] = '\0';
2154*3db86aabSstevel 			else
2155*3db86aabSstevel 				env_sensor.next_id =
2156*3db86aabSstevel 				    section->entry[0].handle_name;
2157*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2158*3db86aabSstevel 		} else {
2159*3db86aabSstevel 			/* ensure name is properly terminated */
2160*3db86aabSstevel 			env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2161*3db86aabSstevel 			if (get_sensor_by_name(section, env_sensor.id.name,
2162*3db86aabSstevel 			    &index) != 0) {
2163*3db86aabSstevel 				env_sensor.next_id.name[0] = '\0';
2164*3db86aabSstevel 				sensor_status = ENVMON_NOT_PRESENT;
2165*3db86aabSstevel 			} else if (index + 1 < section->num_entries)
2166*3db86aabSstevel 				env_sensor.next_id =
2167*3db86aabSstevel 				    section->entry[index + 1].handle_name;
2168*3db86aabSstevel 			else
2169*3db86aabSstevel 				env_sensor.next_id.name[0] = '\0';
2170*3db86aabSstevel 		}
2171*3db86aabSstevel 		if (sensor_status == ENVMON_SENSOR_OK) {
2172*3db86aabSstevel 			/*
2173*3db86aabSstevel 			 * user correctly identified a sensor, note its
2174*3db86aabSstevel 			 * handle value and request the sensor value
2175*3db86aabSstevel 			 */
2176*3db86aabSstevel 			rmc_temp.handle = section->entry[index].handle;
2177*3db86aabSstevel 		}
2178*3db86aabSstevel 		RELEASE_CACHE
2179*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2180*3db86aabSstevel 		    rmclomv_do_cmd(DP_GET_TEMPERATURES, DP_GET_TEMPERATURES_R,
2181*3db86aabSstevel 		    sizeof (rmc_temp_r), (intptr_t)&rmc_temp,
2182*3db86aabSstevel 		    (intptr_t)&rmc_temp_r) != 0)) {
2183*3db86aabSstevel 			sensor_status = ENVMON_INACCESSIBLE;
2184*3db86aabSstevel 		}
2185*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) &&
2186*3db86aabSstevel 		    (rmc_temp_r.temp_status[0].sensor_status ==
2187*3db86aabSstevel 		    DP_SENSOR_NOT_PRESENT)) {
2188*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2189*3db86aabSstevel 		}
2190*3db86aabSstevel 		if ((env_sensor.sensor_status = sensor_status) ==
2191*3db86aabSstevel 		    ENVMON_SENSOR_OK) {
2192*3db86aabSstevel 			/*
2193*3db86aabSstevel 			 * copy results into buffer for user
2194*3db86aabSstevel 			 */
2195*3db86aabSstevel 			if (rmc_temp_r.temp_status[0].sensor_status !=
2196*3db86aabSstevel 			    DP_SENSOR_DATA_AVAILABLE)
2197*3db86aabSstevel 				env_sensor.sensor_status = ENVMON_INACCESSIBLE;
2198*3db86aabSstevel 			env_sensor.value =
2199*3db86aabSstevel 			    rmc_temp_r.temp_status[0].value;
2200*3db86aabSstevel 			env_sensor.lowthresholds.warning =
2201*3db86aabSstevel 			    rmc_temp_r.temp_status[0].low_warning;
2202*3db86aabSstevel 			env_sensor.lowthresholds.shutdown =
2203*3db86aabSstevel 			    rmc_temp_r.temp_status[0].low_soft_shutdown;
2204*3db86aabSstevel 			env_sensor.lowthresholds.poweroff =
2205*3db86aabSstevel 			    rmc_temp_r.temp_status[0].low_hard_shutdown;
2206*3db86aabSstevel 			env_sensor.highthresholds.warning =
2207*3db86aabSstevel 			    rmc_temp_r.temp_status[0].high_warning;
2208*3db86aabSstevel 			env_sensor.highthresholds.shutdown =
2209*3db86aabSstevel 			    rmc_temp_r.temp_status[0].high_soft_shutdown;
2210*3db86aabSstevel 			env_sensor.highthresholds.poweroff =
2211*3db86aabSstevel 			    rmc_temp_r.temp_status[0].high_hard_shutdown;
2212*3db86aabSstevel 		}
2213*3db86aabSstevel 		if (env_sensor.sensor_status != ENVMON_SENSOR_OK ||
2214*3db86aabSstevel 		    rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
2215*3db86aabSstevel 			set_val_unav(&env_sensor);
2216*3db86aabSstevel 
2217*3db86aabSstevel 		if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg,
2218*3db86aabSstevel 		    sizeof (envmon_sensor_t), mode) != 0)
2219*3db86aabSstevel 			return (EFAULT);
2220*3db86aabSstevel 		break;
2221*3db86aabSstevel 
2222*3db86aabSstevel 
2223*3db86aabSstevel 	case ENVMONIOCFAN:
2224*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_fan,
2225*3db86aabSstevel 		    sizeof (envmon_fan_t), mode) != 0)
2226*3db86aabSstevel 			return (EFAULT);
2227*3db86aabSstevel 
2228*3db86aabSstevel 		/* see if we've got fan handles cached */
2229*3db86aabSstevel 		LOCK_CACHE
2230*3db86aabSstevel 		sensor_status = ENVMON_SENSOR_OK;
2231*3db86aabSstevel 
2232*3db86aabSstevel 		if ((rmclomv_cache_valid == B_FALSE) ||
2233*3db86aabSstevel 		    ((section = rmclomv_find_section(rmclomv_cache,
2234*3db86aabSstevel 		    RMCLOMV_FAN_SENS)) == NULL)) {
2235*3db86aabSstevel 			env_fan.next_id.name[0] = '\0';
2236*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2237*3db86aabSstevel 		} else if (env_fan.id.name[0] == '\0') {
2238*3db86aabSstevel 			/* request for first handle */
2239*3db86aabSstevel 			if (section->num_entries == 0)
2240*3db86aabSstevel 				env_fan.next_id.name[0] = '\0';
2241*3db86aabSstevel 			else
2242*3db86aabSstevel 				env_fan.next_id =
2243*3db86aabSstevel 				    section->entry[0].handle_name;
2244*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2245*3db86aabSstevel 		} else {
2246*3db86aabSstevel 			/* ensure name is properly terminated */
2247*3db86aabSstevel 			env_fan.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2248*3db86aabSstevel 			if (get_sensor_by_name(section, env_fan.id.name,
2249*3db86aabSstevel 			    &index) != 0) {
2250*3db86aabSstevel 				env_fan.next_id.name[0] = '\0';
2251*3db86aabSstevel 				sensor_status = ENVMON_NOT_PRESENT;
2252*3db86aabSstevel 			} else if (index + 1 < section->num_entries)
2253*3db86aabSstevel 				env_fan.next_id =
2254*3db86aabSstevel 				    section->entry[index + 1].handle_name;
2255*3db86aabSstevel 			else
2256*3db86aabSstevel 				env_fan.next_id.name[0] = '\0';
2257*3db86aabSstevel 		}
2258*3db86aabSstevel 		if (sensor_status == ENVMON_SENSOR_OK) {
2259*3db86aabSstevel 			/*
2260*3db86aabSstevel 			 * user correctly identified a sensor, note its
2261*3db86aabSstevel 			 * handle value and request the sensor value
2262*3db86aabSstevel 			 */
2263*3db86aabSstevel 			rmc_fan.handle = section->entry[index].handle;
2264*3db86aabSstevel 		}
2265*3db86aabSstevel 		RELEASE_CACHE
2266*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2267*3db86aabSstevel 		    rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R,
2268*3db86aabSstevel 		    sizeof (rmc_fan_r), (intptr_t)&rmc_fan,
2269*3db86aabSstevel 		    (intptr_t)&rmc_fan_r) != 0)) {
2270*3db86aabSstevel 			sensor_status = ENVMON_INACCESSIBLE;
2271*3db86aabSstevel 		}
2272*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) &&
2273*3db86aabSstevel 		    (rmc_fan_r.fan_status[0].sensor_status ==
2274*3db86aabSstevel 		    DP_SENSOR_NOT_PRESENT)) {
2275*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2276*3db86aabSstevel 		}
2277*3db86aabSstevel 		if ((env_fan.sensor_status = sensor_status) ==
2278*3db86aabSstevel 		    ENVMON_SENSOR_OK) {
2279*3db86aabSstevel 			if ((rmc_fan_r.fan_status[0].flag &
2280*3db86aabSstevel 			    DP_FAN_PRESENCE) == 0)
2281*3db86aabSstevel 				env_fan.sensor_status = ENVMON_NOT_PRESENT;
2282*3db86aabSstevel 			if (rmc_fan_r.fan_status[0].sensor_status !=
2283*3db86aabSstevel 			    DP_SENSOR_DATA_AVAILABLE)
2284*3db86aabSstevel 				env_fan.sensor_status |= ENVMON_INACCESSIBLE;
2285*3db86aabSstevel 			if (env_fan.sensor_status == ENVMON_SENSOR_OK) {
2286*3db86aabSstevel 				/*
2287*3db86aabSstevel 				 * copy results into buffer for user
2288*3db86aabSstevel 				 */
2289*3db86aabSstevel 				env_fan.speed =
2290*3db86aabSstevel 				    rmc_fan_r.fan_status[0].speed;
2291*3db86aabSstevel 				env_fan.lowthresholds.warning =
2292*3db86aabSstevel 				    rmc_fan_r.fan_status[0].minspeed;
2293*3db86aabSstevel 				env_fan.lowthresholds.shutdown =
2294*3db86aabSstevel 				    ENVMON_VAL_UNAVAILABLE;
2295*3db86aabSstevel 				env_fan.lowthresholds.poweroff =
2296*3db86aabSstevel 				    ENVMON_VAL_UNAVAILABLE;
2297*3db86aabSstevel 				if ((rmc_fan_r.fan_status[0].flag &
2298*3db86aabSstevel 				    DP_FAN_SPEED_VAL_UNIT) == 0)
2299*3db86aabSstevel 					bcopy(str_rpm, env_fan.units,
2300*3db86aabSstevel 					    sizeof (str_rpm));
2301*3db86aabSstevel 				else
2302*3db86aabSstevel 					bcopy(str_percent, env_fan.units,
2303*3db86aabSstevel 					    sizeof (str_percent));
2304*3db86aabSstevel 			}
2305*3db86aabSstevel 		}
2306*3db86aabSstevel 		if (env_fan.sensor_status != ENVMON_SENSOR_OK ||
2307*3db86aabSstevel 		    rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE)
2308*3db86aabSstevel 			set_fan_unav(&env_fan);
2309*3db86aabSstevel 
2310*3db86aabSstevel 		if (ddi_copyout((caddr_t)&env_fan, (caddr_t)arg,
2311*3db86aabSstevel 		    sizeof (envmon_fan_t), mode) != 0)
2312*3db86aabSstevel 			return (EFAULT);
2313*3db86aabSstevel 		break;
2314*3db86aabSstevel 
2315*3db86aabSstevel 	case ENVMONIOCAMPIND:
2316*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ind,
2317*3db86aabSstevel 		    sizeof (envmon_indicator_t), mode) != 0)
2318*3db86aabSstevel 			return (EFAULT);
2319*3db86aabSstevel 
2320*3db86aabSstevel 		/* see if we've got amp indicator handles cached */
2321*3db86aabSstevel 		LOCK_CACHE
2322*3db86aabSstevel 		sensor_status = ENVMON_SENSOR_OK;
2323*3db86aabSstevel 
2324*3db86aabSstevel 		if ((rmclomv_cache_valid == B_FALSE) ||
2325*3db86aabSstevel 		    ((section = rmclomv_find_section(rmclomv_cache,
2326*3db86aabSstevel 		    RMCLOMV_AMP_IND)) == NULL)) {
2327*3db86aabSstevel 			RELEASE_CACHE
2328*3db86aabSstevel 			return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu,
2329*3db86aabSstevel 			    &rmc_psu_r, RMCLOMV_AMP_IND));
2330*3db86aabSstevel 		} else if (env_ind.id.name[0] == '\0') {
2331*3db86aabSstevel 			/* request for first handle */
2332*3db86aabSstevel 			if (section->num_entries == 0) {
2333*3db86aabSstevel 				RELEASE_CACHE
2334*3db86aabSstevel 				return (do_psu_cmd(arg, mode, &env_ind,
2335*3db86aabSstevel 				    &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND));
2336*3db86aabSstevel 			}
2337*3db86aabSstevel 			env_ind.next_id = section->entry[0].handle_name;
2338*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2339*3db86aabSstevel 		} else {
2340*3db86aabSstevel 			/* ensure name is properly terminated */
2341*3db86aabSstevel 			env_ind.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2342*3db86aabSstevel 			if (get_sensor_by_name(section, env_ind.id.name,
2343*3db86aabSstevel 			    &index) != 0) {
2344*3db86aabSstevel 				RELEASE_CACHE
2345*3db86aabSstevel 				return (do_psu_cmd(arg, mode, &env_ind,
2346*3db86aabSstevel 				    &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND));
2347*3db86aabSstevel 			}
2348*3db86aabSstevel 			if (index + 1 < section->num_entries) {
2349*3db86aabSstevel 				env_ind.next_id =
2350*3db86aabSstevel 				    section->entry[index + 1].handle_name;
2351*3db86aabSstevel 			} else {
2352*3db86aabSstevel 				rmclomv_cache_section_t	*sub_section =
2353*3db86aabSstevel 				    rmclomv_find_section(rmclomv_subcache,
2354*3db86aabSstevel 				    RMCLOMV_AMP_IND);
2355*3db86aabSstevel 				if ((sub_section == NULL) ||
2356*3db86aabSstevel 				    (sub_section->num_entries == 0))
2357*3db86aabSstevel 					env_ind.next_id.name[0] = '\0';
2358*3db86aabSstevel 				else
2359*3db86aabSstevel 					env_ind.next_id =
2360*3db86aabSstevel 					    sub_section->entry[0].handle_name;
2361*3db86aabSstevel 			}
2362*3db86aabSstevel 		}
2363*3db86aabSstevel 		if (sensor_status == ENVMON_SENSOR_OK) {
2364*3db86aabSstevel 			/*
2365*3db86aabSstevel 			 * user correctly identified an indicator, note its
2366*3db86aabSstevel 			 * handle value and request the indicator status
2367*3db86aabSstevel 			 */
2368*3db86aabSstevel 			rmc_ampi.handle = section->entry[index].handle;
2369*3db86aabSstevel 		}
2370*3db86aabSstevel 		RELEASE_CACHE
2371*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2372*3db86aabSstevel 		    rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS, DP_GET_CIRCUIT_BRKS_R,
2373*3db86aabSstevel 		    sizeof (rmc_ampi_r), (intptr_t)&rmc_ampi,
2374*3db86aabSstevel 		    (intptr_t)&rmc_ampi_r) != 0)) {
2375*3db86aabSstevel 			sensor_status = ENVMON_INACCESSIBLE;
2376*3db86aabSstevel 		}
2377*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) &&
2378*3db86aabSstevel 		    (rmc_ampi_r.circuit_brk_status[0].sensor_status ==
2379*3db86aabSstevel 		    DP_SENSOR_NOT_PRESENT)) {
2380*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2381*3db86aabSstevel 		}
2382*3db86aabSstevel 		if ((env_ind.sensor_status = sensor_status) ==
2383*3db86aabSstevel 		    ENVMON_SENSOR_OK) {
2384*3db86aabSstevel 			/*
2385*3db86aabSstevel 			 * copy results into buffer for user
2386*3db86aabSstevel 			 */
2387*3db86aabSstevel 			if (rmc_ampi_r.circuit_brk_status[0].sensor_status !=
2388*3db86aabSstevel 			    DP_SENSOR_DATA_AVAILABLE)
2389*3db86aabSstevel 				env_ind.sensor_status = ENVMON_INACCESSIBLE;
2390*3db86aabSstevel 			env_ind.condition =
2391*3db86aabSstevel 			    rmc_ampi_r.circuit_brk_status[0].status;
2392*3db86aabSstevel 		}
2393*3db86aabSstevel 
2394*3db86aabSstevel 		/*
2395*3db86aabSstevel 		 * If rmclomv_rmc_error is set there is no way
2396*3db86aabSstevel 		 * that we read information from RSC. Just copy
2397*3db86aabSstevel 		 * out an inaccessible evironmental.
2398*3db86aabSstevel 		 */
2399*3db86aabSstevel 		if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
2400*3db86aabSstevel 		    env_ind.sensor_status = ENVMON_INACCESSIBLE;
2401*3db86aabSstevel 		    env_ind.condition = ENVMON_INACCESSIBLE;
2402*3db86aabSstevel 		}
2403*3db86aabSstevel 
2404*3db86aabSstevel 		if (ddi_copyout((caddr_t)&env_ind, (caddr_t)arg,
2405*3db86aabSstevel 		    sizeof (envmon_indicator_t), mode) != 0)
2406*3db86aabSstevel 			return (EFAULT);
2407*3db86aabSstevel 		break;
2408*3db86aabSstevel 
2409*3db86aabSstevel 	case ENVMONIOCHPU:
2410*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_hpu,
2411*3db86aabSstevel 		    sizeof (envmon_hpu_t), mode) != 0)
2412*3db86aabSstevel 			return (EFAULT);
2413*3db86aabSstevel 
2414*3db86aabSstevel 		/* see if we've got hpu handles cached */
2415*3db86aabSstevel 		LOCK_CACHE
2416*3db86aabSstevel 
2417*3db86aabSstevel 		if ((rmclomv_cache_valid == B_FALSE) ||
2418*3db86aabSstevel 		    ((section = rmclomv_find_section(rmclomv_cache,
2419*3db86aabSstevel 		    RMCLOMV_HPU_IND)) == NULL)) {
2420*3db86aabSstevel 			RELEASE_CACHE
2421*3db86aabSstevel 			return (EAGAIN);
2422*3db86aabSstevel 		}
2423*3db86aabSstevel 
2424*3db86aabSstevel 		/*
2425*3db86aabSstevel 		 * At this point the cache is locked and section points to
2426*3db86aabSstevel 		 * the section relating to hpus.
2427*3db86aabSstevel 		 */
2428*3db86aabSstevel 		sensor_status = ENVMON_SENSOR_OK;
2429*3db86aabSstevel 		if (env_hpu.id.name[0] == '\0') {
2430*3db86aabSstevel 			/* request for first handle */
2431*3db86aabSstevel 			if (section->num_entries == 0)
2432*3db86aabSstevel 				env_hpu.next_id.name[0] = '\0';
2433*3db86aabSstevel 			else
2434*3db86aabSstevel 				env_hpu.next_id =
2435*3db86aabSstevel 				    section->entry[0].handle_name;
2436*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2437*3db86aabSstevel 		} else {
2438*3db86aabSstevel 			/* ensure name is properly terminated */
2439*3db86aabSstevel 			env_hpu.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2440*3db86aabSstevel 			if (get_sensor_by_name(section, env_hpu.id.name,
2441*3db86aabSstevel 			    &index) != 0) {
2442*3db86aabSstevel 				env_hpu.next_id.name[0] = '\0';
2443*3db86aabSstevel 				sensor_status = ENVMON_NOT_PRESENT;
2444*3db86aabSstevel 			} else if (index + 1 < section->num_entries)
2445*3db86aabSstevel 				env_hpu.next_id =
2446*3db86aabSstevel 				    section->entry[index + 1].handle_name;
2447*3db86aabSstevel 			else
2448*3db86aabSstevel 				env_hpu.next_id.name[0] = '\0';
2449*3db86aabSstevel 		}
2450*3db86aabSstevel 		if (sensor_status == ENVMON_SENSOR_OK) {
2451*3db86aabSstevel 			/*
2452*3db86aabSstevel 			 * user correctly identified an hpu, note its
2453*3db86aabSstevel 			 * handle value and request the hpu status
2454*3db86aabSstevel 			 */
2455*3db86aabSstevel 			rmc_fru.handle = section->entry[index].handle;
2456*3db86aabSstevel 			special = section->entry[index].ind_mask;
2457*3db86aabSstevel 		}
2458*3db86aabSstevel 		RELEASE_CACHE
2459*3db86aabSstevel 		if ((env_hpu.sensor_status = sensor_status) ==
2460*3db86aabSstevel 		    ENVMON_SENSOR_OK) {
2461*3db86aabSstevel 			env_hpu.fru_status = ENVMON_FRU_PRESENT;
2462*3db86aabSstevel 
2463*3db86aabSstevel 			if (special != 0) {
2464*3db86aabSstevel 				/* this is the pseudo SC node */
2465*3db86aabSstevel 				mutex_enter(&rmclomv_state_lock);
2466*3db86aabSstevel 				switch (rmclomv_rmc_state) {
2467*3db86aabSstevel 				case RMCLOMV_RMCSTATE_OK:
2468*3db86aabSstevel 					break;
2469*3db86aabSstevel 				case RMCLOMV_RMCSTATE_FAILED:
2470*3db86aabSstevel 					env_hpu.fru_status = ENVMON_FRU_FAULT;
2471*3db86aabSstevel 					break;
2472*3db86aabSstevel 				case RMCLOMV_RMCSTATE_DOWNLOAD:
2473*3db86aabSstevel 					env_hpu.fru_status =
2474*3db86aabSstevel 					    ENVMON_FRU_DOWNLOAD;
2475*3db86aabSstevel 					break;
2476*3db86aabSstevel 				default:
2477*3db86aabSstevel 					env_hpu.sensor_status =
2478*3db86aabSstevel 					    ENVMON_INACCESSIBLE;
2479*3db86aabSstevel 					break;
2480*3db86aabSstevel 				}
2481*3db86aabSstevel 				mutex_exit(&rmclomv_state_lock);
2482*3db86aabSstevel 			} else if (rmclomv_rmc_error ||
2483*3db86aabSstevel 			    rmclomv_do_cmd(DP_GET_FRU_STATUS,
2484*3db86aabSstevel 			    DP_GET_FRU_STATUS_R, sizeof (rmc_fru_r),
2485*3db86aabSstevel 			    (intptr_t)&rmc_fru, (intptr_t)&rmc_fru_r) != 0) {
2486*3db86aabSstevel 				env_hpu.sensor_status = ENVMON_INACCESSIBLE;
2487*3db86aabSstevel 			} else {
2488*3db86aabSstevel 				/*
2489*3db86aabSstevel 				 * copy results into buffer for user
2490*3db86aabSstevel 				 */
2491*3db86aabSstevel 				if (rmc_fru_r.fru_status[0].presence == 0) {
2492*3db86aabSstevel 					env_hpu.sensor_status =
2493*3db86aabSstevel 					    ENVMON_NOT_PRESENT;
2494*3db86aabSstevel 					env_hpu.fru_status =
2495*3db86aabSstevel 					    ENVMON_FRU_NOT_PRESENT;
2496*3db86aabSstevel 				} else if (rmc_fru_r.fru_status[0].sensor_status
2497*3db86aabSstevel 				    != DP_SENSOR_DATA_AVAILABLE) {
2498*3db86aabSstevel 					env_hpu.sensor_status =
2499*3db86aabSstevel 					    ENVMON_INACCESSIBLE;
2500*3db86aabSstevel 				} else {
2501*3db86aabSstevel 					uint8_t status =
2502*3db86aabSstevel 					    rmc_fru_r.fru_status[0].status;
2503*3db86aabSstevel 					if (status == DP_FRU_STATUS_UNKNOWN) {
2504*3db86aabSstevel 						env_hpu.sensor_status =
2505*3db86aabSstevel 						    ENVMON_INACCESSIBLE;
2506*3db86aabSstevel 					} else if (status != DP_FRU_STATUS_OK) {
2507*3db86aabSstevel 						env_hpu.fru_status =
2508*3db86aabSstevel 						    ENVMON_FRU_FAULT;
2509*3db86aabSstevel 					}
2510*3db86aabSstevel 				}
2511*3db86aabSstevel 			}
2512*3db86aabSstevel 		}
2513*3db86aabSstevel 
2514*3db86aabSstevel 		/*
2515*3db86aabSstevel 		 * If rmclomv_rmc_error is set there is no way
2516*3db86aabSstevel 		 * that we read information from RSC. Just copy
2517*3db86aabSstevel 		 * out an inaccessible environmental.
2518*3db86aabSstevel 		 */
2519*3db86aabSstevel 		if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
2520*3db86aabSstevel 		    env_hpu.sensor_status = ENVMON_INACCESSIBLE;
2521*3db86aabSstevel 		    env_hpu.fru_status = ENVMON_INACCESSIBLE;
2522*3db86aabSstevel 		}
2523*3db86aabSstevel 
2524*3db86aabSstevel 		if (ddi_copyout((caddr_t)&env_hpu, (caddr_t)arg,
2525*3db86aabSstevel 		    sizeof (envmon_hpu_t), mode) != 0)
2526*3db86aabSstevel 			return (EFAULT);
2527*3db86aabSstevel 		break;
2528*3db86aabSstevel 
2529*3db86aabSstevel 	case ENVMONIOCGETLED:
2530*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledinfo,
2531*3db86aabSstevel 		    sizeof (envmon_led_info_t), mode) != 0)
2532*3db86aabSstevel 			return (EFAULT);
2533*3db86aabSstevel 
2534*3db86aabSstevel 		/* see if we've got LED handles cached */
2535*3db86aabSstevel 		LOCK_CACHE
2536*3db86aabSstevel 		sensor_status = ENVMON_SENSOR_OK;
2537*3db86aabSstevel 
2538*3db86aabSstevel 		if ((rmclomv_cache_valid == B_FALSE) ||
2539*3db86aabSstevel 		    ((section = rmclomv_find_section(rmclomv_cache,
2540*3db86aabSstevel 		    RMCLOMV_LED_IND)) == NULL)) {
2541*3db86aabSstevel 			env_ledinfo.next_id.name[0] = '\0';
2542*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2543*3db86aabSstevel 		} else if (env_ledinfo.id.name[0] == '\0') {
2544*3db86aabSstevel 			/* request for first handle */
2545*3db86aabSstevel 			if (section->num_entries == 0)
2546*3db86aabSstevel 				env_ledinfo.next_id.name[0] = '\0';
2547*3db86aabSstevel 			else
2548*3db86aabSstevel 				env_ledinfo.next_id =
2549*3db86aabSstevel 				    section->entry[0].handle_name;
2550*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2551*3db86aabSstevel 		} else {
2552*3db86aabSstevel 			/* ensure name is properly terminated */
2553*3db86aabSstevel 			env_ledinfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2554*3db86aabSstevel 			if (get_sensor_by_name(section, env_ledinfo.id.name,
2555*3db86aabSstevel 			    &index) != 0) {
2556*3db86aabSstevel 				env_ledinfo.next_id.name[0] = '\0';
2557*3db86aabSstevel 				sensor_status = ENVMON_NOT_PRESENT;
2558*3db86aabSstevel 			} else if (index + 1 < section->num_entries)
2559*3db86aabSstevel 				env_ledinfo.next_id =
2560*3db86aabSstevel 				    section->entry[index + 1].handle_name;
2561*3db86aabSstevel 			else
2562*3db86aabSstevel 				env_ledinfo.next_id.name[0] = '\0';
2563*3db86aabSstevel 		}
2564*3db86aabSstevel 		if (sensor_status == ENVMON_SENSOR_OK) {
2565*3db86aabSstevel 			/*
2566*3db86aabSstevel 			 * user correctly identified a LED, note its
2567*3db86aabSstevel 			 * handle value and request the LED status
2568*3db86aabSstevel 			 */
2569*3db86aabSstevel 			rmc_led.handle = section->entry[index].handle;
2570*3db86aabSstevel 		}
2571*3db86aabSstevel 		RELEASE_CACHE
2572*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
2573*3db86aabSstevel 		    rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R,
2574*3db86aabSstevel 		    sizeof (rmc_led_r), (intptr_t)&rmc_led,
2575*3db86aabSstevel 		    (intptr_t)&rmc_led_r) != 0)) {
2576*3db86aabSstevel 			sensor_status = ENVMON_INACCESSIBLE;
2577*3db86aabSstevel 		}
2578*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) &&
2579*3db86aabSstevel 		    (rmc_led_r.led_state[0].sensor_status ==
2580*3db86aabSstevel 		    DP_SENSOR_NOT_PRESENT)) {
2581*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2582*3db86aabSstevel 		}
2583*3db86aabSstevel 		if ((env_ledinfo.sensor_status = sensor_status) ==
2584*3db86aabSstevel 		    ENVMON_SENSOR_OK) {
2585*3db86aabSstevel 			/*
2586*3db86aabSstevel 			 * copy results into buffer for user
2587*3db86aabSstevel 			 * start with some defaults then override
2588*3db86aabSstevel 			 */
2589*3db86aabSstevel 			env_ledinfo.sensor_status = ENVMON_SENSOR_OK;
2590*3db86aabSstevel 			env_ledinfo.led_state = ENVMON_LED_OFF;
2591*3db86aabSstevel 			env_ledinfo.led_color = ENVMON_LED_CLR_NONE;
2592*3db86aabSstevel 
2593*3db86aabSstevel 			if (rmc_led_r.led_state[0].sensor_status !=
2594*3db86aabSstevel 			    DP_SENSOR_DATA_AVAILABLE)
2595*3db86aabSstevel 				env_ledinfo.sensor_status = ENVMON_INACCESSIBLE;
2596*3db86aabSstevel 			else {
2597*3db86aabSstevel 				dp_led_state_t ledState;
2598*3db86aabSstevel 				ledState = rmc_led_r.led_state[0];
2599*3db86aabSstevel 				env_ledinfo.led_color = (int8_t)ledState.colour;
2600*3db86aabSstevel 
2601*3db86aabSstevel 				switch (ledState.state) {
2602*3db86aabSstevel 				case (rsci8)DP_LED_OFF:
2603*3db86aabSstevel 					break;
2604*3db86aabSstevel 				case (rsci8)DP_LED_ON:
2605*3db86aabSstevel 					env_ledinfo.led_state = ENVMON_LED_ON;
2606*3db86aabSstevel 					break;
2607*3db86aabSstevel 				case (rsci8)DP_LED_BLINKING:
2608*3db86aabSstevel 					env_ledinfo.led_state =
2609*3db86aabSstevel 					    ENVMON_LED_BLINKING;
2610*3db86aabSstevel 					break;
2611*3db86aabSstevel 				case (rsci8)DP_LED_FLASHING:
2612*3db86aabSstevel 					env_ledinfo.led_state =
2613*3db86aabSstevel 					    ENVMON_LED_FLASHING;
2614*3db86aabSstevel 					break;
2615*3db86aabSstevel 				default:
2616*3db86aabSstevel 					break;
2617*3db86aabSstevel 				}
2618*3db86aabSstevel 			}
2619*3db86aabSstevel 		}
2620*3db86aabSstevel 
2621*3db86aabSstevel 		/*
2622*3db86aabSstevel 		 * If rmclomv_rmc_error is set there is no way
2623*3db86aabSstevel 		 * that we read information from RSC. Just copy
2624*3db86aabSstevel 		 * out an inaccessible environmental.
2625*3db86aabSstevel 		 */
2626*3db86aabSstevel 		if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
2627*3db86aabSstevel 		    env_ledinfo.sensor_status = ENVMON_INACCESSIBLE;
2628*3db86aabSstevel 		    env_ledinfo.led_state = ENVMON_INACCESSIBLE;
2629*3db86aabSstevel 		}
2630*3db86aabSstevel 
2631*3db86aabSstevel 		if (ddi_copyout((caddr_t)&env_ledinfo, (caddr_t)arg,
2632*3db86aabSstevel 		    sizeof (envmon_led_info_t), mode) != 0)
2633*3db86aabSstevel 			return (EFAULT);
2634*3db86aabSstevel 		break;
2635*3db86aabSstevel 
2636*3db86aabSstevel 	case ENVMONIOCSETLED:
2637*3db86aabSstevel 		if ((mode & FWRITE) == 0)
2638*3db86aabSstevel 			return (EACCES);
2639*3db86aabSstevel 		if (drv_priv(cred_p) != 0)
2640*3db86aabSstevel 			return (EPERM);
2641*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledctl,
2642*3db86aabSstevel 		    sizeof (envmon_led_ctl_t), mode) != 0)
2643*3db86aabSstevel 			return (EFAULT);
2644*3db86aabSstevel 		if (env_ledctl.led_state < RMCLOMV_MIN_LED_STATE ||
2645*3db86aabSstevel 		    env_ledctl.led_state > RMCLOMV_MAX_LED_STATE)
2646*3db86aabSstevel 			return (EINVAL);
2647*3db86aabSstevel 		/*
2648*3db86aabSstevel 		 * Ensure name is properly terminated.
2649*3db86aabSstevel 		 */
2650*3db86aabSstevel 		env_ledctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2651*3db86aabSstevel 
2652*3db86aabSstevel 		/* see if we've got LED handles cached */
2653*3db86aabSstevel 		LOCK_CACHE
2654*3db86aabSstevel 
2655*3db86aabSstevel 		if ((rmclomv_cache_valid == B_FALSE) ||
2656*3db86aabSstevel 		    ((section = rmclomv_find_section(rmclomv_cache,
2657*3db86aabSstevel 		    RMCLOMV_LED_IND)) == NULL) ||
2658*3db86aabSstevel 		    (get_sensor_by_name(section, env_ledctl.id.name,
2659*3db86aabSstevel 		    &index) != 0)) {
2660*3db86aabSstevel 			RELEASE_CACHE
2661*3db86aabSstevel 			return (EINVAL);	/* no such LED */
2662*3db86aabSstevel 		}
2663*3db86aabSstevel 		/*
2664*3db86aabSstevel 		 * user correctly identified a LED, note its handle value
2665*3db86aabSstevel 		 */
2666*3db86aabSstevel 		rmc_setled.handle = section->entry[index].handle;
2667*3db86aabSstevel 		RELEASE_CACHE
2668*3db86aabSstevel 		switch (env_ledctl.led_state) {
2669*3db86aabSstevel 		case ENVMON_LED_ON:
2670*3db86aabSstevel 			rmc_setled.state = DP_LED_ON;
2671*3db86aabSstevel 			break;
2672*3db86aabSstevel 		case ENVMON_LED_BLINKING:
2673*3db86aabSstevel 			rmc_setled.state = DP_LED_BLINKING;
2674*3db86aabSstevel 			break;
2675*3db86aabSstevel 		case ENVMON_LED_FLASHING:
2676*3db86aabSstevel 			rmc_setled.state = DP_LED_FLASHING;
2677*3db86aabSstevel 			break;
2678*3db86aabSstevel 		default:
2679*3db86aabSstevel 			rmc_setled.state = DP_LED_OFF;
2680*3db86aabSstevel 			break;
2681*3db86aabSstevel 		}
2682*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_SET_LED_STATE, DP_SET_LED_STATE_R,
2683*3db86aabSstevel 		    sizeof (rmc_setled_r), (intptr_t)&rmc_setled,
2684*3db86aabSstevel 		    (intptr_t)&rmc_setled_r);
2685*3db86aabSstevel 
2686*3db86aabSstevel 		if (retval != 0) {
2687*3db86aabSstevel 			break;
2688*3db86aabSstevel 		}
2689*3db86aabSstevel 
2690*3db86aabSstevel 		if (rmc_setled_r.status != 0) {
2691*3db86aabSstevel 			cmn_err(CE_WARN, "ENVMONIOCSETLED: \"%s\" status: 0x%x",
2692*3db86aabSstevel 			    env_ledctl.id.name, rmc_setled_r.status);
2693*3db86aabSstevel 			return (EIO);
2694*3db86aabSstevel 		}
2695*3db86aabSstevel 		break;
2696*3db86aabSstevel 
2697*3db86aabSstevel 	case ENVMONIOCGETKEYSW:
2698*3db86aabSstevel 	{
2699*3db86aabSstevel 		enum rmc_keyswitch_pos	rmc_pos = real_key_position;
2700*3db86aabSstevel 		envmon_keysw_pos_t	envmon_pos;
2701*3db86aabSstevel 
2702*3db86aabSstevel 		/*
2703*3db86aabSstevel 		 * Yes, I know this is ugly, but the V210 has no keyswitch,
2704*3db86aabSstevel 		 * even though the ALOM returns a value for it
2705*3db86aabSstevel 		 */
2706*3db86aabSstevel 		if (strcmp(platform, "SUNW,Sun-Fire-V210") == 0) {
2707*3db86aabSstevel 			return (ENOTSUP);
2708*3db86aabSstevel 		}
2709*3db86aabSstevel 
2710*3db86aabSstevel 		switch (rmc_pos) {
2711*3db86aabSstevel 
2712*3db86aabSstevel 		case RMC_KEYSWITCH_POS_NORMAL:
2713*3db86aabSstevel 			envmon_pos = ENVMON_KEYSW_POS_NORMAL;
2714*3db86aabSstevel 			break;
2715*3db86aabSstevel 		case RMC_KEYSWITCH_POS_DIAG:
2716*3db86aabSstevel 			envmon_pos = ENVMON_KEYSW_POS_DIAG;
2717*3db86aabSstevel 			break;
2718*3db86aabSstevel 		case RMC_KEYSWITCH_POS_LOCKED:
2719*3db86aabSstevel 			envmon_pos = ENVMON_KEYSW_POS_LOCKED;
2720*3db86aabSstevel 			break;
2721*3db86aabSstevel 		case RMC_KEYSWITCH_POS_OFF:
2722*3db86aabSstevel 			envmon_pos = ENVMON_KEYSW_POS_OFF;
2723*3db86aabSstevel 			break;
2724*3db86aabSstevel 		default:
2725*3db86aabSstevel 			envmon_pos = ENVMON_KEYSW_POS_UNKNOWN;
2726*3db86aabSstevel 			break;
2727*3db86aabSstevel 		}
2728*3db86aabSstevel 
2729*3db86aabSstevel 		if (ddi_copyout((caddr_t)&envmon_pos, (caddr_t)arg,
2730*3db86aabSstevel 		    sizeof (envmon_pos), mode) != 0)
2731*3db86aabSstevel 			return (EFAULT);
2732*3db86aabSstevel 		break;
2733*3db86aabSstevel 	}
2734*3db86aabSstevel 
2735*3db86aabSstevel 	case ENVMONIOCGETALARM:
2736*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarminfo,
2737*3db86aabSstevel 		    sizeof (envmon_alarm_info_t), mode) != 0)
2738*3db86aabSstevel 			return (EFAULT);
2739*3db86aabSstevel 
2740*3db86aabSstevel 		/* see if we've got ALARM handles cached */
2741*3db86aabSstevel 		LOCK_CACHE
2742*3db86aabSstevel 		sensor_status = ENVMON_SENSOR_OK;
2743*3db86aabSstevel 
2744*3db86aabSstevel 		if ((rmclomv_cache_valid == B_FALSE) ||
2745*3db86aabSstevel 		    ((section = rmclomv_find_section(rmclomv_cache,
2746*3db86aabSstevel 		    RMCLOMV_ALARM_IND)) == NULL)) {
2747*3db86aabSstevel 			env_alarminfo.next_id.name[0] = '\0';
2748*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2749*3db86aabSstevel 		} else if (env_alarminfo.id.name[0] == '\0') {
2750*3db86aabSstevel 			/* request for first handle */
2751*3db86aabSstevel 			if (section->num_entries == 0)
2752*3db86aabSstevel 				env_alarminfo.next_id.name[0] = '\0';
2753*3db86aabSstevel 			else
2754*3db86aabSstevel 				env_alarminfo.next_id =
2755*3db86aabSstevel 				    section->entry[0].handle_name;
2756*3db86aabSstevel 			sensor_status = ENVMON_NOT_PRESENT;
2757*3db86aabSstevel 		} else {
2758*3db86aabSstevel 			/* ensure name is properly terminated */
2759*3db86aabSstevel 			env_alarminfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2760*3db86aabSstevel 			if (get_sensor_by_name(section, env_alarminfo.id.name,
2761*3db86aabSstevel 			    &index) != 0) {
2762*3db86aabSstevel 				env_alarminfo.next_id.name[0] = '\0';
2763*3db86aabSstevel 				sensor_status = ENVMON_NOT_PRESENT;
2764*3db86aabSstevel 			} else if (index + 1 < section->num_entries)
2765*3db86aabSstevel 				env_alarminfo.next_id =
2766*3db86aabSstevel 				    section->entry[index + 1].handle_name;
2767*3db86aabSstevel 			else
2768*3db86aabSstevel 				env_alarminfo.next_id.name[0] = '\0';
2769*3db86aabSstevel 		}
2770*3db86aabSstevel 		if (sensor_status == ENVMON_SENSOR_OK) {
2771*3db86aabSstevel 			/*
2772*3db86aabSstevel 			 * user correctly identified a ALARM, note its
2773*3db86aabSstevel 			 * handle value and request the ALARM status
2774*3db86aabSstevel 			 */
2775*3db86aabSstevel 			rmc_alarm.handle = section->entry[index].handle;
2776*3db86aabSstevel 		}
2777*3db86aabSstevel 		RELEASE_CACHE
2778*3db86aabSstevel 		if ((sensor_status == ENVMON_SENSOR_OK) &&
2779*3db86aabSstevel 			(rmclomv_rmc_error ||
2780*3db86aabSstevel 		    rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R,
2781*3db86aabSstevel 		    sizeof (rmc_alarm_r), (intptr_t)&rmc_alarm,
2782*3db86aabSstevel 		    (intptr_t)&rmc_alarm_r) != 0)) {
2783*3db86aabSstevel 			sensor_status = ENVMON_INACCESSIBLE;
2784*3db86aabSstevel 		}
2785*3db86aabSstevel 		if ((env_alarminfo.sensor_status = sensor_status) ==
2786*3db86aabSstevel 		    ENVMON_SENSOR_OK) {
2787*3db86aabSstevel 			/*
2788*3db86aabSstevel 			 * copy results into buffer for user
2789*3db86aabSstevel 			 * start with some defaults then override
2790*3db86aabSstevel 			 */
2791*3db86aabSstevel 			env_alarminfo.sensor_status = ENVMON_SENSOR_OK;
2792*3db86aabSstevel 			env_alarminfo.alarm_state = ENVMON_ALARM_OFF;
2793*3db86aabSstevel 
2794*3db86aabSstevel 			if (rmc_alarm_r.alarm_state[0].sensor_status !=
2795*3db86aabSstevel 			    DP_SENSOR_DATA_AVAILABLE)
2796*3db86aabSstevel 				env_alarminfo.sensor_status =
2797*3db86aabSstevel 					ENVMON_INACCESSIBLE;
2798*3db86aabSstevel 			else {
2799*3db86aabSstevel 				dp_alarm_state_t alarmState;
2800*3db86aabSstevel 				alarmState = rmc_alarm_r.alarm_state[0];
2801*3db86aabSstevel 
2802*3db86aabSstevel 				switch (alarmState.state) {
2803*3db86aabSstevel 				case DP_ALARM_OFF:
2804*3db86aabSstevel 					break;
2805*3db86aabSstevel 				case DP_ALARM_ON:
2806*3db86aabSstevel 					env_alarminfo.alarm_state =
2807*3db86aabSstevel 						ENVMON_ALARM_ON;
2808*3db86aabSstevel 					break;
2809*3db86aabSstevel 				default:
2810*3db86aabSstevel 					break;
2811*3db86aabSstevel 				}
2812*3db86aabSstevel 			}
2813*3db86aabSstevel 		}
2814*3db86aabSstevel 
2815*3db86aabSstevel 		/*
2816*3db86aabSstevel 		 * If rmclomv_rmc_error is set there is no way
2817*3db86aabSstevel 		 * that we read information from RSC. Just copy
2818*3db86aabSstevel 		 * out an inaccessible environmental.
2819*3db86aabSstevel 		 */
2820*3db86aabSstevel 		if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) {
2821*3db86aabSstevel 		    env_alarminfo.sensor_status = ENVMON_INACCESSIBLE;
2822*3db86aabSstevel 		    env_alarminfo.alarm_state = ENVMON_INACCESSIBLE;
2823*3db86aabSstevel 		}
2824*3db86aabSstevel 
2825*3db86aabSstevel 		if (ddi_copyout((caddr_t)&env_alarminfo, (caddr_t)arg,
2826*3db86aabSstevel 		    sizeof (envmon_alarm_info_t), mode) != 0)
2827*3db86aabSstevel 			return (EFAULT);
2828*3db86aabSstevel 		break;
2829*3db86aabSstevel 
2830*3db86aabSstevel 	case ENVMONIOCSETALARM:
2831*3db86aabSstevel 		if ((mode & FWRITE) == 0)
2832*3db86aabSstevel 			return (EACCES);
2833*3db86aabSstevel 		if (drv_priv(cred_p) != 0)
2834*3db86aabSstevel 			return (EPERM);
2835*3db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarmctl,
2836*3db86aabSstevel 		    sizeof (envmon_alarm_ctl_t), mode) != 0)
2837*3db86aabSstevel 			return (EFAULT);
2838*3db86aabSstevel 		if (env_alarmctl.alarm_state < RMCLOMV_MIN_ALARM_STATE ||
2839*3db86aabSstevel 		    env_alarmctl.alarm_state > RMCLOMV_MAX_ALARM_STATE)
2840*3db86aabSstevel 			return (EINVAL);
2841*3db86aabSstevel 		/*
2842*3db86aabSstevel 		 * Ensure name is properly terminated.
2843*3db86aabSstevel 		 */
2844*3db86aabSstevel 		env_alarmctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0';
2845*3db86aabSstevel 
2846*3db86aabSstevel 		/* see if we've got ALARM handles cached */
2847*3db86aabSstevel 		LOCK_CACHE
2848*3db86aabSstevel 
2849*3db86aabSstevel 		if ((rmclomv_cache_valid == B_FALSE) ||
2850*3db86aabSstevel 		    ((section = rmclomv_find_section(rmclomv_cache,
2851*3db86aabSstevel 		    RMCLOMV_ALARM_IND)) == NULL) ||
2852*3db86aabSstevel 		    (get_sensor_by_name(section, env_alarmctl.id.name,
2853*3db86aabSstevel 		    &index) != 0)) {
2854*3db86aabSstevel 			RELEASE_CACHE
2855*3db86aabSstevel 			return (EINVAL);	/* no such ALARM */
2856*3db86aabSstevel 		}
2857*3db86aabSstevel 		/*
2858*3db86aabSstevel 		 * user correctly identified a ALARM, note its handle value
2859*3db86aabSstevel 		 */
2860*3db86aabSstevel 		rmc_setalarm.handle = section->entry[index].handle;
2861*3db86aabSstevel 		RELEASE_CACHE
2862*3db86aabSstevel 		rmc_setalarm.state = (rsci8)env_alarmctl.alarm_state;
2863*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_SET_ALARM_STATE,
2864*3db86aabSstevel 					DP_SET_ALARM_STATE_R,
2865*3db86aabSstevel 					sizeof (rmc_setalarm_r),
2866*3db86aabSstevel 					(intptr_t)&rmc_setalarm,
2867*3db86aabSstevel 					(intptr_t)&rmc_setalarm_r);
2868*3db86aabSstevel 
2869*3db86aabSstevel 		if (retval != 0) {
2870*3db86aabSstevel 			break;
2871*3db86aabSstevel 		}
2872*3db86aabSstevel 
2873*3db86aabSstevel 		if (rmc_setalarm_r.status != 0) {
2874*3db86aabSstevel 			cmn_err(CE_WARN, "ENVMONIOCSETALARM: \"%s\" status: "
2875*3db86aabSstevel 				"0x%x", env_alarmctl.id.name,
2876*3db86aabSstevel 				rmc_setalarm_r.status);
2877*3db86aabSstevel 			return (EIO);
2878*3db86aabSstevel 		}
2879*3db86aabSstevel 		break;
2880*3db86aabSstevel 
2881*3db86aabSstevel 	case ENVMONIOCCHASSISSERIALNUM:
2882*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_SDP_VERSION,
2883*3db86aabSstevel 		    DP_GET_SDP_VERSION_R, sizeof (rmc_sdpver_r),
2884*3db86aabSstevel 		    NULL, (intptr_t)&rmc_sdpver_r);
2885*3db86aabSstevel 
2886*3db86aabSstevel 		if (retval != 0) {
2887*3db86aabSstevel 			cmn_err(CE_WARN, "DP_GET_SDP_VERSION failed, ret=%d\n",
2888*3db86aabSstevel 			    retval);
2889*3db86aabSstevel 			break;
2890*3db86aabSstevel 		} else if (rmc_sdpver_r.version < SDP_RESPONDS_TO_ALL_CMDS) {
2891*3db86aabSstevel 			retval = ENOTSUP;
2892*3db86aabSstevel 			break;
2893*3db86aabSstevel 		}
2894*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_CHASSIS_SERIALNUM,
2895*3db86aabSstevel 		    DP_GET_CHASSIS_SERIALNUM_R, sizeof (rmc_serialnum_r),
2896*3db86aabSstevel 		    NULL, (intptr_t)&rmc_serialnum_r);
2897*3db86aabSstevel 
2898*3db86aabSstevel 		if (retval != 0) {
2899*3db86aabSstevel 			break;
2900*3db86aabSstevel 		}
2901*3db86aabSstevel 		bcopy(rmc_serialnum_r.chassis_serial_number,
2902*3db86aabSstevel 		    chassis.serial_number,
2903*3db86aabSstevel 		    sizeof (rmc_serialnum_r.chassis_serial_number));
2904*3db86aabSstevel 
2905*3db86aabSstevel 		if (ddi_copyout((caddr_t)&chassis, (caddr_t)arg,
2906*3db86aabSstevel 		    sizeof (chassis), mode) != 0) {
2907*3db86aabSstevel 			return (EFAULT);
2908*3db86aabSstevel 		}
2909*3db86aabSstevel 		sensor_status = ENVMON_SENSOR_OK;
2910*3db86aabSstevel 		break;
2911*3db86aabSstevel 
2912*3db86aabSstevel 	default:
2913*3db86aabSstevel 		retval = ENOTSUP;
2914*3db86aabSstevel 		break;
2915*3db86aabSstevel 	}
2916*3db86aabSstevel 
2917*3db86aabSstevel 	return (retval);
2918*3db86aabSstevel }
2919*3db86aabSstevel 
2920*3db86aabSstevel /* ARGSUSED */
2921*3db86aabSstevel static void
2922*3db86aabSstevel rmclomv_checkrmc(caddr_t arg)
2923*3db86aabSstevel {
2924*3db86aabSstevel 	callb_cpr_t		cprinfo;
2925*3db86aabSstevel 	int			err;
2926*3db86aabSstevel 	int			retries;
2927*3db86aabSstevel 	int			state;
2928*3db86aabSstevel 	dp_get_sysinfo_r_t 	sysinfo;
2929*3db86aabSstevel 
2930*3db86aabSstevel 	CALLB_CPR_INIT(&cprinfo, &rmclomv_checkrmc_lock, callb_generic_cpr,
2931*3db86aabSstevel 	    "rmclomv_checkrmc");
2932*3db86aabSstevel 
2933*3db86aabSstevel 	mutex_enter(&rmclomv_checkrmc_lock);
2934*3db86aabSstevel 	for (;;) {
2935*3db86aabSstevel 		/*
2936*3db86aabSstevel 		 * Initial entry to this for loop is made with
2937*3db86aabSstevel 		 * rmclomv_checkrmc_sig set to RMCLOMV_PROCESS_NOW. So the
2938*3db86aabSstevel 		 * following while loop drops through the first time. A
2939*3db86aabSstevel 		 * timeout call is made just before polling the RMC. Its
2940*3db86aabSstevel 		 * interrupt routine sustains this loop by injecting additional
2941*3db86aabSstevel 		 * state changes and cv events.
2942*3db86aabSstevel 		 */
2943*3db86aabSstevel 		/*
2944*3db86aabSstevel 		 * Wait for someone to tell me to continue.
2945*3db86aabSstevel 		 */
2946*3db86aabSstevel 		while (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_WAIT) {
2947*3db86aabSstevel 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
2948*3db86aabSstevel 			cv_wait(&rmclomv_checkrmc_sig_cv,
2949*3db86aabSstevel 			    &rmclomv_checkrmc_lock);
2950*3db86aabSstevel 			CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_checkrmc_lock);
2951*3db86aabSstevel 		}
2952*3db86aabSstevel 
2953*3db86aabSstevel 		mutex_exit(&rmclomv_checkrmc_lock);
2954*3db86aabSstevel 		/*
2955*3db86aabSstevel 		 * mustn't hold same lock as timeout called with
2956*3db86aabSstevel 		 * when cancelling timer
2957*3db86aabSstevel 		 */
2958*3db86aabSstevel 		if (timer_id != 0) {
2959*3db86aabSstevel 			(void) untimeout(timer_id);
2960*3db86aabSstevel 			timer_id = 0;
2961*3db86aabSstevel 		}
2962*3db86aabSstevel 		mutex_enter(&rmclomv_checkrmc_lock);
2963*3db86aabSstevel 
2964*3db86aabSstevel 		/* RMCLOMV_CHECKRMC_EXITNOW implies signal by _detach(). */
2965*3db86aabSstevel 		if (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_EXITNOW) {
2966*3db86aabSstevel 			rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
2967*3db86aabSstevel 
2968*3db86aabSstevel 			/* rmclomv_checkrmc_lock is held at this point! */
2969*3db86aabSstevel 			CALLB_CPR_EXIT(&cprinfo);
2970*3db86aabSstevel 
2971*3db86aabSstevel 			thread_exit();
2972*3db86aabSstevel 			/* NOTREACHED */
2973*3db86aabSstevel 		}
2974*3db86aabSstevel 
2975*3db86aabSstevel 		rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT;
2976*3db86aabSstevel 
2977*3db86aabSstevel 		/*
2978*3db86aabSstevel 		 * If the RMC is not responding, rmclomv_do_cmd() takes a
2979*3db86aabSstevel 		 * long time and eventually times out. We conclude that the
2980*3db86aabSstevel 		 * RMC is broken if it doesn't respond to a number of polls
2981*3db86aabSstevel 		 * made 60 secs apart. So that the rmclomv_do_cmd() time-out
2982*3db86aabSstevel 		 * period isn't added to our 60 second timer, make the
2983*3db86aabSstevel 		 * timeout() call before calling rmclomv_do_cmd().
2984*3db86aabSstevel 		 */
2985*3db86aabSstevel 		if (timer_id == 0) {
2986*3db86aabSstevel 			timer_id = timeout(rmclomv_checkrmc_wakeup, NULL,
2987*3db86aabSstevel 			    60 * drv_usectohz(1000000));
2988*3db86aabSstevel 		}
2989*3db86aabSstevel 
2990*3db86aabSstevel 		mutex_exit(&rmclomv_checkrmc_lock);
2991*3db86aabSstevel 
2992*3db86aabSstevel 		err = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R,
2993*3db86aabSstevel 		    sizeof (sysinfo), NULL, (intptr_t)&sysinfo);
2994*3db86aabSstevel 		if (err == 0) {
2995*3db86aabSstevel 			mutex_enter(&rmclomv_state_lock);
2996*3db86aabSstevel 			state = rmclomv_rmc_state;
2997*3db86aabSstevel 			/* successful poll, reset fail count */
2998*3db86aabSstevel 			rmclomv_rmcfailcount = 0;
2999*3db86aabSstevel 			mutex_exit(&rmclomv_state_lock);
3000*3db86aabSstevel 
3001*3db86aabSstevel 			if (state != RMCLOMV_RMCSTATE_OK) {
3002*3db86aabSstevel 				rmclomv_refresh_wakeup();
3003*3db86aabSstevel 			}
3004*3db86aabSstevel 		}
3005*3db86aabSstevel 		if ((err != 0) &&
3006*3db86aabSstevel 		    (rmclomv_rmc_error != RMCLOMV_RMCSTATE_DOWNLOAD)) {
3007*3db86aabSstevel 			/*
3008*3db86aabSstevel 			 * Failed response or no response from RMC.
3009*3db86aabSstevel 			 * Count the failure.
3010*3db86aabSstevel 			 * If threshold exceeded, send a DR event.
3011*3db86aabSstevel 			 */
3012*3db86aabSstevel 			mutex_enter(&rmclomv_state_lock);
3013*3db86aabSstevel 			retries = rmclomv_rmcfailcount;
3014*3db86aabSstevel 			state = rmclomv_rmc_state;
3015*3db86aabSstevel 			if (retries == RMCLOMV_RMCFAILTHRESHOLD)
3016*3db86aabSstevel 				rmclomv_rmc_state = RMCLOMV_RMCSTATE_FAILED;
3017*3db86aabSstevel 			if (rmclomv_rmcfailcount <= RMCLOMV_RMCFAILTHRESHOLD)
3018*3db86aabSstevel 				rmclomv_rmcfailcount++;
3019*3db86aabSstevel 			mutex_exit(&rmclomv_state_lock);
3020*3db86aabSstevel 
3021*3db86aabSstevel 			if (retries == RMCLOMV_RMCFAILTHRESHOLD) {
3022*3db86aabSstevel 				cmn_err(CE_WARN, "SC %s responding",
3023*3db86aabSstevel 				    state == RMCLOMV_RMCSTATE_OK ?
3024*3db86aabSstevel 				    "has stopped" : "is not");
3025*3db86aabSstevel 				refresh_name_cache(B_TRUE);
3026*3db86aabSstevel 				rmclomv_dr_data_handler(str_sc, SE_NO_HINT);
3027*3db86aabSstevel 			}
3028*3db86aabSstevel 		}
3029*3db86aabSstevel 
3030*3db86aabSstevel 		/*
3031*3db86aabSstevel 		 * Re-enter the lock to prepare for another iteration.
3032*3db86aabSstevel 		 * We must have the lock here to protect rmclomv_checkrmc_sig.
3033*3db86aabSstevel 		 */
3034*3db86aabSstevel 		mutex_enter(&rmclomv_checkrmc_lock);
3035*3db86aabSstevel 	}
3036*3db86aabSstevel }
3037*3db86aabSstevel 
3038*3db86aabSstevel static void
3039*3db86aabSstevel rmclomv_checkrmc_start(void)
3040*3db86aabSstevel {
3041*3db86aabSstevel 	kthread_t *tp;
3042*3db86aabSstevel 
3043*3db86aabSstevel 	mutex_enter(&rmclomv_checkrmc_lock);
3044*3db86aabSstevel 
3045*3db86aabSstevel 	if (rmclomv_checkrmc_tid == 0) {
3046*3db86aabSstevel 		rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW;
3047*3db86aabSstevel 
3048*3db86aabSstevel 		tp = thread_create(NULL, 0, rmclomv_checkrmc, NULL, 0,
3049*3db86aabSstevel 		    &p0, TS_RUN, maxclsyspri);
3050*3db86aabSstevel 		rmclomv_checkrmc_tid = tp->t_did;
3051*3db86aabSstevel 	}
3052*3db86aabSstevel 
3053*3db86aabSstevel 	mutex_exit(&rmclomv_checkrmc_lock);
3054*3db86aabSstevel }
3055*3db86aabSstevel 
3056*3db86aabSstevel static void
3057*3db86aabSstevel rmclomv_checkrmc_destroy(void)
3058*3db86aabSstevel {
3059*3db86aabSstevel 	kt_did_t tid;
3060*3db86aabSstevel 
3061*3db86aabSstevel 	mutex_enter(&rmclomv_checkrmc_lock);
3062*3db86aabSstevel 	tid = rmclomv_checkrmc_tid;
3063*3db86aabSstevel 	if (tid != 0) {
3064*3db86aabSstevel 		rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_EXITNOW;
3065*3db86aabSstevel 		cv_signal(&rmclomv_checkrmc_sig_cv);
3066*3db86aabSstevel 		rmclomv_checkrmc_tid = 0;
3067*3db86aabSstevel 	}
3068*3db86aabSstevel 	mutex_exit(&rmclomv_checkrmc_lock);
3069*3db86aabSstevel 
3070*3db86aabSstevel 	/*
3071*3db86aabSstevel 	 * Wait for rmclomv_checkrmc() to finish
3072*3db86aabSstevel 	 */
3073*3db86aabSstevel 	if (tid != 0)
3074*3db86aabSstevel 		thread_join(tid);
3075*3db86aabSstevel }
3076*3db86aabSstevel 
3077*3db86aabSstevel /*ARGSUSED*/
3078*3db86aabSstevel static void
3079*3db86aabSstevel rmclomv_checkrmc_wakeup(void *arg)
3080*3db86aabSstevel {
3081*3db86aabSstevel 	mutex_enter(&rmclomv_checkrmc_lock);
3082*3db86aabSstevel 
3083*3db86aabSstevel 	if (rmclomv_checkrmc_sig != RMCLOMV_CHECKRMC_EXITNOW)
3084*3db86aabSstevel 		rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW;
3085*3db86aabSstevel 	cv_signal(&rmclomv_checkrmc_sig_cv);
3086*3db86aabSstevel 
3087*3db86aabSstevel 	mutex_exit(&rmclomv_checkrmc_lock);
3088*3db86aabSstevel }
3089*3db86aabSstevel 
3090*3db86aabSstevel /* ARGSUSED */
3091*3db86aabSstevel static void
3092*3db86aabSstevel rmclomv_refresh(caddr_t arg)
3093*3db86aabSstevel {
3094*3db86aabSstevel 	void			(*plat_nodename_set_fun)(void);
3095*3db86aabSstevel 	sig_state_t		*current_sgn_p;
3096*3db86aabSstevel 	callb_cpr_t		cprinfo;
3097*3db86aabSstevel 	int			state;
3098*3db86aabSstevel 
3099*3db86aabSstevel 	CALLB_CPR_INIT(&cprinfo, &rmclomv_refresh_lock, callb_generic_cpr,
3100*3db86aabSstevel 	    "rmclomv_refresh");
3101*3db86aabSstevel 
3102*3db86aabSstevel 	delay(drv_usectohz(5000000));
3103*3db86aabSstevel 	mutex_enter(&rmclomv_refresh_lock);
3104*3db86aabSstevel 	for (;;) {
3105*3db86aabSstevel 
3106*3db86aabSstevel 		/*
3107*3db86aabSstevel 		 * Wait for someone to tell me to continue.
3108*3db86aabSstevel 		 */
3109*3db86aabSstevel 		while (rmclomv_refresh_sig == RMCLOMV_REFRESH_WAIT) {
3110*3db86aabSstevel 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
3111*3db86aabSstevel 			cv_wait(&rmclomv_refresh_sig_cv, &rmclomv_refresh_lock);
3112*3db86aabSstevel 			CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_refresh_lock);
3113*3db86aabSstevel 		}
3114*3db86aabSstevel 
3115*3db86aabSstevel 		/* RMCLOMV_REFRESH_EXITNOW implies signal by _detach(). */
3116*3db86aabSstevel 		if (rmclomv_refresh_sig == RMCLOMV_REFRESH_EXITNOW) {
3117*3db86aabSstevel 			rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
3118*3db86aabSstevel 
3119*3db86aabSstevel 			/* rmclomv_refresh_lock is held at this point! */
3120*3db86aabSstevel 			CALLB_CPR_EXIT(&cprinfo);
3121*3db86aabSstevel 
3122*3db86aabSstevel 			thread_exit();
3123*3db86aabSstevel 			/* NOTREACHED */
3124*3db86aabSstevel 		}
3125*3db86aabSstevel 
3126*3db86aabSstevel 		ASSERT(rmclomv_refresh_sig == RMCLOMV_REFRESH_PROCESSNOW);
3127*3db86aabSstevel 		rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT;
3128*3db86aabSstevel 
3129*3db86aabSstevel 		mutex_exit(&rmclomv_refresh_lock);
3130*3db86aabSstevel 
3131*3db86aabSstevel 		refresh_name_cache(B_FALSE);
3132*3db86aabSstevel 
3133*3db86aabSstevel 		/*
3134*3db86aabSstevel 		 * We're not going to access rmclomv_sysinfo_data here,
3135*3db86aabSstevel 		 * so there's no point in locking it before reading
3136*3db86aabSstevel 		 * rmclomv_sysinfo_valid. Also this avoids holding two
3137*3db86aabSstevel 		 * locks at once and the concommitant worry about deadlocks.
3138*3db86aabSstevel 		 */
3139*3db86aabSstevel 		if (rmclomv_sysinfo_valid) {
3140*3db86aabSstevel 			/*
3141*3db86aabSstevel 			 * We've just successfully read the RMC sysinfo
3142*3db86aabSstevel 			 * so the RMC must be operational. Update its
3143*3db86aabSstevel 			 * state and if it was previously not OK, refresh
3144*3db86aabSstevel 			 * nodename, CPU signatures and watchdog settings.
3145*3db86aabSstevel 			 */
3146*3db86aabSstevel 			mutex_enter(&rmclomv_state_lock);
3147*3db86aabSstevel 			rmclomv_rmcfailcount = 0;
3148*3db86aabSstevel 			state = rmclomv_rmc_state;
3149*3db86aabSstevel 			rmclomv_rmc_state = RMCLOMV_RMCSTATE_OK;
3150*3db86aabSstevel 			mutex_exit(&rmclomv_state_lock);
3151*3db86aabSstevel 
3152*3db86aabSstevel 			if (state != RMCLOMV_RMCSTATE_OK) {
3153*3db86aabSstevel 				rmclomv_dr_data_handler(str_sc, SE_NO_HINT);
3154*3db86aabSstevel 				if (state == RMCLOMV_RMCSTATE_FAILED) {
3155*3db86aabSstevel 					cmn_err(CE_NOTE, "SC recovered");
3156*3db86aabSstevel 				}
3157*3db86aabSstevel 			}
3158*3db86aabSstevel 
3159*3db86aabSstevel 			if (utsname.nodename[0] != 0) {
3160*3db86aabSstevel 				plat_nodename_set_fun =
3161*3db86aabSstevel 				    (void (*)(void))modgetsymvalue(
3162*3db86aabSstevel 				    "plat_nodename_set", 0);
3163*3db86aabSstevel 				if (plat_nodename_set_fun != NULL)
3164*3db86aabSstevel 					plat_nodename_set_fun();
3165*3db86aabSstevel 			}
3166*3db86aabSstevel 
3167*3db86aabSstevel 			current_sgn_p = (sig_state_t *)modgetsymvalue(
3168*3db86aabSstevel 			    "current_sgn", 0);
3169*3db86aabSstevel 
3170*3db86aabSstevel 			if ((current_sgn_p != NULL) &&
3171*3db86aabSstevel 			    (current_sgn_p->state_t.sig != 0)) {
3172*3db86aabSstevel 				CPU_SIGNATURE(current_sgn_p->state_t.sig,
3173*3db86aabSstevel 				    current_sgn_p->state_t.state,
3174*3db86aabSstevel 				    current_sgn_p->state_t.sub_state, -1);
3175*3db86aabSstevel 
3176*3db86aabSstevel 				if (!(boothowto & RB_DEBUG)) {
3177*3db86aabSstevel 					send_watchdog_msg(last_watchdog_msg);
3178*3db86aabSstevel 				}
3179*3db86aabSstevel 			}
3180*3db86aabSstevel 		}
3181*3db86aabSstevel 
3182*3db86aabSstevel 		/*
3183*3db86aabSstevel 		 * update keyswitch value in case it changed while the
3184*3db86aabSstevel 		 * RMC was out of action
3185*3db86aabSstevel 		 */
3186*3db86aabSstevel 		LOCK_CACHE
3187*3db86aabSstevel 		if (rmclomv_sysinfo_valid) {
3188*3db86aabSstevel 			real_key_position = rmclomv_sysinfo_data.keyswitch;
3189*3db86aabSstevel 			if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) &&
3190*3db86aabSstevel 			    (real_key_position <= RMC_KEYSWITCH_POS_OFF)) {
3191*3db86aabSstevel 				key_position = real_key_position;
3192*3db86aabSstevel 			} else {
3193*3db86aabSstevel 				/* treat unknown key position as locked */
3194*3db86aabSstevel 				key_position = RMC_KEYSWITCH_POS_LOCKED;
3195*3db86aabSstevel 			}
3196*3db86aabSstevel 		} else {
3197*3db86aabSstevel 			/* treat unreadable key position as locked */
3198*3db86aabSstevel 			key_position = RMC_KEYSWITCH_POS_LOCKED;
3199*3db86aabSstevel 			real_key_position = RMC_KEYSWITCH_POS_UNKNOWN;
3200*3db86aabSstevel 		}
3201*3db86aabSstevel 		RELEASE_CACHE
3202*3db86aabSstevel 
3203*3db86aabSstevel 		/*
3204*3db86aabSstevel 		 * Re-enter the lock to prepare for another iteration.
3205*3db86aabSstevel 		 * We must have the lock here to protect rmclomv_refresh_sig.
3206*3db86aabSstevel 		 */
3207*3db86aabSstevel 		mutex_enter(&rmclomv_refresh_lock);
3208*3db86aabSstevel 	}
3209*3db86aabSstevel }
3210*3db86aabSstevel 
3211*3db86aabSstevel static void
3212*3db86aabSstevel rmclomv_refresh_start(void)
3213*3db86aabSstevel {
3214*3db86aabSstevel 	kthread_t *tp;
3215*3db86aabSstevel 
3216*3db86aabSstevel 	mutex_enter(&rmclomv_refresh_lock);
3217*3db86aabSstevel 
3218*3db86aabSstevel 	if (rmclomv_refresh_tid == 0) {
3219*3db86aabSstevel 		rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW;
3220*3db86aabSstevel 
3221*3db86aabSstevel 		tp = thread_create(NULL, 0, rmclomv_refresh, NULL, 0,
3222*3db86aabSstevel 		    &p0, TS_RUN, maxclsyspri);
3223*3db86aabSstevel 		rmclomv_refresh_tid = tp->t_did;
3224*3db86aabSstevel 	}
3225*3db86aabSstevel 
3226*3db86aabSstevel 	mutex_exit(&rmclomv_refresh_lock);
3227*3db86aabSstevel }
3228*3db86aabSstevel 
3229*3db86aabSstevel static void
3230*3db86aabSstevel rmclomv_refresh_destroy(void)
3231*3db86aabSstevel {
3232*3db86aabSstevel 	kt_did_t tid;
3233*3db86aabSstevel 
3234*3db86aabSstevel 	mutex_enter(&rmclomv_refresh_lock);
3235*3db86aabSstevel 	tid = rmclomv_refresh_tid;
3236*3db86aabSstevel 	if (tid != 0) {
3237*3db86aabSstevel 		rmclomv_refresh_sig = RMCLOMV_REFRESH_EXITNOW;
3238*3db86aabSstevel 		cv_signal(&rmclomv_refresh_sig_cv);
3239*3db86aabSstevel 		rmclomv_refresh_tid = 0;
3240*3db86aabSstevel 	}
3241*3db86aabSstevel 	mutex_exit(&rmclomv_refresh_lock);
3242*3db86aabSstevel 
3243*3db86aabSstevel 	/*
3244*3db86aabSstevel 	 * Wait for rmclomv_refresh() to finish
3245*3db86aabSstevel 	 */
3246*3db86aabSstevel 	if (tid != 0)
3247*3db86aabSstevel 		thread_join(tid);
3248*3db86aabSstevel }
3249*3db86aabSstevel 
3250*3db86aabSstevel static void
3251*3db86aabSstevel rmclomv_refresh_wakeup(void)
3252*3db86aabSstevel {
3253*3db86aabSstevel 	mutex_enter(&rmclomv_refresh_lock);
3254*3db86aabSstevel 
3255*3db86aabSstevel 	if (rmclomv_refresh_sig != RMCLOMV_REFRESH_EXITNOW)
3256*3db86aabSstevel 		rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW;
3257*3db86aabSstevel 	cv_signal(&rmclomv_refresh_sig_cv);
3258*3db86aabSstevel 
3259*3db86aabSstevel 	mutex_exit(&rmclomv_refresh_lock);
3260*3db86aabSstevel }
3261*3db86aabSstevel 
3262*3db86aabSstevel static void
3263*3db86aabSstevel send_watchdog_msg(int msg)
3264*3db86aabSstevel {
3265*3db86aabSstevel 	rmc_comm_msg_t request;
3266*3db86aabSstevel 	dp_set_host_watchdog_t watchdog_msg;
3267*3db86aabSstevel 
3268*3db86aabSstevel 	if (rmclomv_watchdog_mode)
3269*3db86aabSstevel 		return;
3270*3db86aabSstevel 
3271*3db86aabSstevel 	watchdog_msg.enable = msg;
3272*3db86aabSstevel 	request.msg_type = DP_SET_HOST_WATCHDOG;
3273*3db86aabSstevel 	request.msg_len = sizeof (watchdog_msg);
3274*3db86aabSstevel 	request.msg_buf = (caddr_t)&watchdog_msg;
3275*3db86aabSstevel 	(void) rmc_comm_request_nowait(&request, (msg == 1) ?
3276*3db86aabSstevel 	    RMC_COMM_DREQ_URGENT : 0);
3277*3db86aabSstevel }
3278*3db86aabSstevel 
3279*3db86aabSstevel /*ARGSUSED*/
3280*3db86aabSstevel static uint_t
3281*3db86aabSstevel rmc_set_watchdog_timer(uint_t timeoutval)
3282*3db86aabSstevel {
3283*3db86aabSstevel 	ASSERT(MUTEX_HELD(&tod_lock));
3284*3db86aabSstevel 
3285*3db86aabSstevel 	if ((watchdog_enable == 0) || (watchdog_available == 0)) {
3286*3db86aabSstevel 		return (0);
3287*3db86aabSstevel 	}
3288*3db86aabSstevel 
3289*3db86aabSstevel 	/*
3290*3db86aabSstevel 	 * If boothowto has RB_DEBUG set we never want to set the watchdog
3291*3db86aabSstevel 	 * support on.
3292*3db86aabSstevel 	 */
3293*3db86aabSstevel 	if (boothowto & RB_DEBUG) {
3294*3db86aabSstevel 		return (0);
3295*3db86aabSstevel 	}
3296*3db86aabSstevel 
3297*3db86aabSstevel 	/*
3298*3db86aabSstevel 	 * When the watchdog is shut off last_watchdog_msg goes from a
3299*3db86aabSstevel 	 * 0 to a 1. So we must test to see that last_watchdog_msg is
3300*3db86aabSstevel 	 * set to 1 indicating that watchdog was shut off and
3301*3db86aabSstevel 	 * After which we set last_watchdog_msg back to 0 so that we do not
3302*3db86aabSstevel 	 * run this code
3303*3db86aabSstevel 	 * again.
3304*3db86aabSstevel 	 */
3305*3db86aabSstevel 	if (last_watchdog_msg == 1) {
3306*3db86aabSstevel 		send_watchdog_msg(0);
3307*3db86aabSstevel 		last_watchdog_msg = 0;
3308*3db86aabSstevel 	}
3309*3db86aabSstevel 
3310*3db86aabSstevel 	pmugpio_watchdog_pat();
3311*3db86aabSstevel 
3312*3db86aabSstevel 	watchdog_activated = 1;
3313*3db86aabSstevel 
3314*3db86aabSstevel 	return (1);
3315*3db86aabSstevel }
3316*3db86aabSstevel 
3317*3db86aabSstevel static uint_t
3318*3db86aabSstevel rmc_clear_watchdog_timer(void)
3319*3db86aabSstevel {
3320*3db86aabSstevel 	ASSERT(MUTEX_HELD(&tod_lock));
3321*3db86aabSstevel 	if ((watchdog_activated == 0) || (boothowto & RB_DEBUG))
3322*3db86aabSstevel 		return (0);
3323*3db86aabSstevel 
3324*3db86aabSstevel 	send_watchdog_msg(1);
3325*3db86aabSstevel 	last_watchdog_msg = 1;
3326*3db86aabSstevel 	watchdog_activated = 0;
3327*3db86aabSstevel 
3328*3db86aabSstevel 	return (0);
3329*3db86aabSstevel }
3330*3db86aabSstevel 
3331*3db86aabSstevel static void
3332*3db86aabSstevel plat_timesync(void *arg)
3333*3db86aabSstevel {
3334*3db86aabSstevel 	timestruc_t now;
3335*3db86aabSstevel 	todinfo_t tod;
3336*3db86aabSstevel 	rmc_comm_msg_t request;
3337*3db86aabSstevel 	dp_set_date_time_t set_time_msg;
3338*3db86aabSstevel 	int retval;
3339*3db86aabSstevel 	timestruc_t ts;
3340*3db86aabSstevel 	dp_get_date_time_r_t *date_and_time_info;
3341*3db86aabSstevel 	int buffer[DATE_TIME_MSG_SIZE];
3342*3db86aabSstevel 
3343*3db86aabSstevel 	/* Is the system coming up? */
3344*3db86aabSstevel 	if (arg != NULL) {
3345*3db86aabSstevel 		/* Request the time from the RMC clock. */
3346*3db86aabSstevel 		retval = rmclomv_do_cmd(DP_GET_DATE_TIME, DP_GET_DATE_TIME_R,
3347*3db86aabSstevel 		    DATE_TIME_MSG_SIZE, NULL, (intptr_t)&buffer);
3348*3db86aabSstevel 
3349*3db86aabSstevel 		/*
3350*3db86aabSstevel 		 * If we were able to get the time lets set the local clock.
3351*3db86aabSstevel 		 * The time returned from RMC is in Unix time format.
3352*3db86aabSstevel 		 *
3353*3db86aabSstevel 		 * If we couldn't get the time we'll accept the drift so as not
3354*3db86aabSstevel 		 * to cause congestion on the I2C bus or cause boot
3355*3db86aabSstevel 		 * performance regressions.
3356*3db86aabSstevel 		 */
3357*3db86aabSstevel 		if (retval == RCNOERR) {
3358*3db86aabSstevel 			date_and_time_info = (dp_get_date_time_r_t *)buffer;
3359*3db86aabSstevel 			ts.tv_sec = date_and_time_info->current_datetime;
3360*3db86aabSstevel 			ts.tv_nsec = 0;
3361*3db86aabSstevel 			mutex_enter(&tod_lock);
3362*3db86aabSstevel 			tod_set(ts);
3363*3db86aabSstevel 			set_hrestime(&ts);
3364*3db86aabSstevel 			mutex_exit(&tod_lock);
3365*3db86aabSstevel 		}
3366*3db86aabSstevel 	}
3367*3db86aabSstevel 
3368*3db86aabSstevel 	gethrestime(&now);
3369*3db86aabSstevel 	mutex_enter(&tod_lock);
3370*3db86aabSstevel 	tod = utc_to_tod(now.tv_sec);
3371*3db86aabSstevel 	mutex_exit(&tod_lock);
3372*3db86aabSstevel 
3373*3db86aabSstevel 	set_time_msg.year	= tod.tod_year;
3374*3db86aabSstevel 	set_time_msg.month	= tod.tod_month - 1;
3375*3db86aabSstevel 	set_time_msg.day	= tod.tod_day;
3376*3db86aabSstevel 	set_time_msg.hour	= tod.tod_hour;
3377*3db86aabSstevel 	set_time_msg.minute	= tod.tod_min;
3378*3db86aabSstevel 	set_time_msg.second	= tod.tod_sec;
3379*3db86aabSstevel 
3380*3db86aabSstevel 	request.msg_type = DP_SET_DATE_TIME;
3381*3db86aabSstevel 	request.msg_len = sizeof (set_time_msg);
3382*3db86aabSstevel 	request.msg_buf = (caddr_t)&set_time_msg;
3383*3db86aabSstevel 
3384*3db86aabSstevel 	(void) rmc_comm_request_nowait(&request, 0);
3385*3db86aabSstevel 
3386*3db86aabSstevel 	(void) timeout(plat_timesync, NULL, timesync_interval);
3387*3db86aabSstevel }
3388*3db86aabSstevel 
3389*3db86aabSstevel /*
3390*3db86aabSstevel  * Interfaces to get/set alarm relays from outside
3391*3db86aabSstevel  */
3392*3db86aabSstevel int
3393*3db86aabSstevel rmclomv_alarm_get(int alarm_type, int *alarm_state)
3394*3db86aabSstevel {
3395*3db86aabSstevel 	rmclomv_cache_section_t	*section;
3396*3db86aabSstevel 	int			index;
3397*3db86aabSstevel 	uint16_t		sensor_status;
3398*3db86aabSstevel 	dp_get_alarm_state_t	u_rmc_alarm;
3399*3db86aabSstevel 	dp_get_alarm_state_r_t	u_rmc_alarm_r;
3400*3db86aabSstevel 
3401*3db86aabSstevel 	/* see if we've got ALARM handles cached */
3402*3db86aabSstevel 	LOCK_CACHE
3403*3db86aabSstevel 	sensor_status = ENVMON_SENSOR_OK;
3404*3db86aabSstevel 
3405*3db86aabSstevel 	if ((rmclomv_cache_valid == B_FALSE) ||
3406*3db86aabSstevel 		((section = rmclomv_find_section(rmclomv_cache,
3407*3db86aabSstevel 		RMCLOMV_ALARM_IND)) == NULL)) {
3408*3db86aabSstevel 		sensor_status = ENVMON_NOT_PRESENT;
3409*3db86aabSstevel 	}
3410*3db86aabSstevel 	if (sensor_status == ENVMON_SENSOR_OK) {
3411*3db86aabSstevel 		/*
3412*3db86aabSstevel 		 * user correctly identified a ALARM, note its
3413*3db86aabSstevel 		 * handle value and request the ALARM status
3414*3db86aabSstevel 		 */
3415*3db86aabSstevel 		index = alarm_type;
3416*3db86aabSstevel 		if (index >= section->num_entries)
3417*3db86aabSstevel 			sensor_status = ENVMON_INACCESSIBLE;
3418*3db86aabSstevel 		else
3419*3db86aabSstevel 			u_rmc_alarm.handle = section->entry[index].handle;
3420*3db86aabSstevel 	}
3421*3db86aabSstevel 	RELEASE_CACHE
3422*3db86aabSstevel 	if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error ||
3423*3db86aabSstevel 		rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R,
3424*3db86aabSstevel 		sizeof (u_rmc_alarm_r), (intptr_t)&u_rmc_alarm,
3425*3db86aabSstevel 		(intptr_t)&u_rmc_alarm_r) != 0)) {
3426*3db86aabSstevel 		sensor_status = ENVMON_INACCESSIBLE;
3427*3db86aabSstevel 	}
3428*3db86aabSstevel 	if (sensor_status == ENVMON_SENSOR_OK) {
3429*3db86aabSstevel 		/*
3430*3db86aabSstevel 		 * copy results into buffer for user
3431*3db86aabSstevel 		 * start with some defaults then override
3432*3db86aabSstevel 		 */
3433*3db86aabSstevel 		*alarm_state = 0;
3434*3db86aabSstevel 
3435*3db86aabSstevel 		if (u_rmc_alarm_r.alarm_state[0].sensor_status !=
3436*3db86aabSstevel 			DP_SENSOR_DATA_AVAILABLE)
3437*3db86aabSstevel 			return (ENXIO);
3438*3db86aabSstevel 		else {
3439*3db86aabSstevel 			dp_alarm_state_t alarmState;
3440*3db86aabSstevel 			alarmState = u_rmc_alarm_r.alarm_state[0];
3441*3db86aabSstevel 
3442*3db86aabSstevel 			switch (alarmState.state) {
3443*3db86aabSstevel 			case DP_ALARM_OFF:
3444*3db86aabSstevel 				break;
3445*3db86aabSstevel 			case DP_ALARM_ON:
3446*3db86aabSstevel 				*alarm_state = 1;
3447*3db86aabSstevel 				break;
3448*3db86aabSstevel 			default:
3449*3db86aabSstevel 				break;
3450*3db86aabSstevel 			}
3451*3db86aabSstevel 		}
3452*3db86aabSstevel 	} else
3453*3db86aabSstevel 		return (ENXIO);
3454*3db86aabSstevel 
3455*3db86aabSstevel 	return (0);
3456*3db86aabSstevel }
3457*3db86aabSstevel 
3458*3db86aabSstevel int
3459*3db86aabSstevel rmclomv_alarm_set(int alarm_type, int new_state)
3460*3db86aabSstevel {
3461*3db86aabSstevel 	rmclomv_cache_section_t	*section;
3462*3db86aabSstevel 	int			index;
3463*3db86aabSstevel 	uint16_t		sensor_status;
3464*3db86aabSstevel 	dp_set_alarm_state_t	u_rmc_setalarm;
3465*3db86aabSstevel 	dp_set_alarm_state_r_t	u_rmc_setalarm_r;
3466*3db86aabSstevel 
3467*3db86aabSstevel 	/* see if we've got ALARM handles cached */
3468*3db86aabSstevel 	LOCK_CACHE
3469*3db86aabSstevel 	sensor_status = ENVMON_SENSOR_OK;
3470*3db86aabSstevel 
3471*3db86aabSstevel 	if ((rmclomv_cache_valid == B_FALSE) ||
3472*3db86aabSstevel 		((section = rmclomv_find_section(rmclomv_cache,
3473*3db86aabSstevel 		RMCLOMV_ALARM_IND)) == NULL)) {
3474*3db86aabSstevel 		sensor_status = ENVMON_NOT_PRESENT;
3475*3db86aabSstevel 	}
3476*3db86aabSstevel 	if (sensor_status == ENVMON_SENSOR_OK) {
3477*3db86aabSstevel 		/*
3478*3db86aabSstevel 		 * user correctly identified a ALARM, note its
3479*3db86aabSstevel 		 * handle value and request the ALARM status
3480*3db86aabSstevel 		 */
3481*3db86aabSstevel 		index = alarm_type;
3482*3db86aabSstevel 		if (index >= section->num_entries)
3483*3db86aabSstevel 			sensor_status = ENVMON_INACCESSIBLE;
3484*3db86aabSstevel 		else {
3485*3db86aabSstevel 			u_rmc_setalarm.handle = section->entry[index].handle;
3486*3db86aabSstevel 			u_rmc_setalarm.state = new_state;
3487*3db86aabSstevel 		}
3488*3db86aabSstevel 	}
3489*3db86aabSstevel 	RELEASE_CACHE
3490*3db86aabSstevel 	if ((sensor_status == ENVMON_SENSOR_OK) &&
3491*3db86aabSstevel 		(rmclomv_rmc_error ||
3492*3db86aabSstevel 		rmclomv_do_cmd(DP_SET_ALARM_STATE, DP_SET_ALARM_STATE_R,
3493*3db86aabSstevel 		sizeof (u_rmc_setalarm_r), (intptr_t)&u_rmc_setalarm,
3494*3db86aabSstevel 		(intptr_t)&u_rmc_setalarm_r) != 0)) {
3495*3db86aabSstevel 		sensor_status = ENVMON_INACCESSIBLE;
3496*3db86aabSstevel 	}
3497*3db86aabSstevel 
3498*3db86aabSstevel 	if (u_rmc_setalarm_r.status != DP_SET_ALARM_OK) {
3499*3db86aabSstevel 		return (EIO);
3500*3db86aabSstevel 	}
3501*3db86aabSstevel 
3502*3db86aabSstevel 	if (sensor_status != ENVMON_SENSOR_OK) {
3503*3db86aabSstevel 		return (ENXIO);
3504*3db86aabSstevel 	}
3505*3db86aabSstevel 
3506*3db86aabSstevel 	return (0);
3507*3db86aabSstevel }
3508