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