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