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 #include <sys/sysmacros.h>
56
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
_init(void)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(×ync_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
_info(struct modinfo * modinfop)335 _info(struct modinfo *modinfop)
336 {
337 return (mod_info(&modlinkage, modinfop));
338 }
339
340
341 int
_fini(void)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(×ync_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
rmclomv_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)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
rmclomv_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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, 0);
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
rmclomv_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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(×ync_lock);
512 tid = timesync_tid;
513 timesync_tid = 0;
514 timesync_interval = 0;
515 mutex_exit(×ync_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
rmclomv_add_intr_handlers()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
rmclomv_remove_intr_handlers(void)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
rmclomv_abort_seq_handler(char * msg)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
rmclomv_break_intr(caddr_t arg)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 *
create_cache_section(int sensor_type,int num)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
free_section(rmclomv_cache_section_t * section)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
add_section(rmclomv_cache_section_t ** head,rmclomv_cache_section_t * section)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
rmclomv_reset_cache(rmclomv_cache_section_t * new_chain,rmclomv_cache_section_t * new_subchain,dp_get_sysinfo_r_t * sysinfo)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 *
rmclomv_find_section(rmclomv_cache_section_t * start,uint16_t sensor)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 *
rmclomv_key_position(enum rmc_keyswitch_pos pos)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
get_sensor_by_name(const rmclomv_cache_section_t * section,const char * name,int * index)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
rmclomv_hdl_to_envhdl(dp_handle_t hdl,envmon_handle_t * envhdl)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
rmclomv_dr_data_handler(const char * fru_name,int hint)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
fan_sysevent(char * fru_name,char * sensor_name,int sub_event)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
threshold_sysevent(char * fru_name,char * sensor_name,int sub_event,char event_type)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
rmclomv_event_data_handler(char * arg)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
rmclomv_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)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
rmclomv_close(dev_t dev,int flag,int otyp,cred_t * cred_p)1163 rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
1164 {
1165 return (DDI_SUCCESS);
1166 }
1167
1168 static int
rmclomv_do_cmd(int req_cmd,int resp_cmd,int resp_len,intptr_t arg_req,intptr_t arg_res)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
validate_section_entry(rmclomv_cache_section_t * section,int index)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 = §ion->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
add_names_to_section(rmclomv_cache_section_t * section)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 = §ion->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
make_psu_subsections(rmclomv_cache_section_t * psu_section,rmclomv_cache_section_t ** chain_head,dp_get_psu_status_r_t * psu_resp)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
refresh_name_cache(int force_fail)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), (intptr_t)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)&i_cmd, (intptr_t)&i_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
set_val_unav(envmon_sensor_t * sensor)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
set_fan_unav(envmon_fan_t * fan)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
do_psu_cmd(intptr_t arg,int mode,envmon_indicator_t * env_ind,dp_get_psu_status_t * rmc_psu,dp_get_psu_status_r_t * rmc_psu_r,int detector_type)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
rmclomv_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)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 (intptr_t)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 (intptr_t)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
rmclomv_checkrmc(caddr_t arg)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), (intptr_t)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
rmclomv_checkrmc_start(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
rmclomv_checkrmc_destroy(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
rmclomv_checkrmc_wakeup(void * arg)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
rmclomv_refresh(caddr_t arg)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
rmclomv_refresh_start(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
rmclomv_refresh_destroy(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
rmclomv_refresh_wakeup(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
send_watchdog_msg(int msg)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
rmc_set_watchdog_timer(uint_t timeoutval)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
rmc_clear_watchdog_timer(void)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
plat_timesync(void * arg)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, (intptr_t)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(×ync_lock);
3436 if (timesync_interval != 0)
3437 timesync_tid = timeout(plat_timesync, NULL, timesync_interval);
3438 mutex_exit(×ync_lock);
3439 }
3440
3441 /*
3442 * Interfaces to get/set alarm relays from outside
3443 */
3444 int
rmclomv_alarm_get(int alarm_type,int * alarm_state)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
rmclomv_alarm_set(int alarm_type,int new_state)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