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