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