1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <limits.h>
32 #include <sys/systeminfo.h>
33 #include <pthread.h>
34 #include <syslog.h>
35 #include <picl.h>
36 #include <picltree.h>
37 #include <picldefs.h>
38 #include <string.h>
39 #include <strings.h>
40 #include <sys/param.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <stropts.h>
46 #include <assert.h>
47 #include <libnvpair.h>
48 #include <libintl.h>
49 #include <poll.h>
50 #include <smclib.h>
51 #include "piclenvmond.h"
52 #include "picldr.h"
53
54 /* external functions */
55 extern picl_errno_t env_platmod_init();
56 extern void env_platmod_handle_event(const char *, const void *, size_t);
57 extern picl_errno_t env_platmod_create_sensors();
58 extern picl_errno_t env_platmod_setup_hotswap();
59 extern picl_errno_t env_platmod_sp_monitor();
60 extern picl_errno_t env_platmod_handle_bus_if_change(uint8_t);
61 extern picl_errno_t env_platmod_handle_latch_open();
62 extern void env_platmod_handle_sensor_event(void *);
63 extern int process_platmod_sp_state_change_notif(void *);
64 extern int process_platmod_change_cpu_node_state(void *);
65 extern int process_platmod_change_cpci_state(void *);
66 extern int process_platmod_async_msg_notif(void *);
67 extern void process_platmod_sp_heartbeat(uint8_t);
68 extern picl_errno_t env_platmod_create_hotswap_prop();
69 extern picl_errno_t env_create_property(int ptype, int pmode,
70 size_t psize, char *pname, int (*readfn)(ptree_rarg_t *, void *),
71 int (*writefn)(ptree_warg_t *, const void *),
72 picl_nodehdl_t nodeh, picl_prophdl_t *propp, void *vbuf);
73 extern char *strtok_r(char *s1, const char *s2, char **lasts);
74
75 /* external variables */
76 extern int env_debug;
77
78 static char sys_name[SYS_NMLN];
79 static char chassisconf_name[SYS_NMLN];
80 static boolean_t parse_config_file = B_FALSE;
81 static int8_t alarm_check_interval = -1;
82 static picl_nodehdl_t frutreeh = 0;
83 static pthread_t polling_threadID;
84 static boolean_t create_polling_thr = B_TRUE;
85
86 /* globals */
87 uint8_t cpu_geo_addr = 0;
88 picl_nodehdl_t rooth = 0, chassis_nodehdl = 0, cpu_nodehdl = 0;
89 picl_nodehdl_t platformh = 0, sysmgmth = 0, cpu_lnodehdl = 0;
90
91 /*
92 * envmond policy structure
93 */
94 typedef struct _policy {
95 uint8_t interval;
96 char *pname;
97 char *argp;
98 struct _policy *nextp;
99 } env_policy_t;
100
101 /*
102 * read_policy_configuration - extract info. from the envmond.conf
103 */
104 static int
env_read_policy_configuration(char * conffile,env_policy_t ** policypp)105 env_read_policy_configuration(char *conffile, env_policy_t **policypp)
106 {
107 FILE *fp;
108 char buf[RECORD_MAXSIZE];
109 char *token, *lasts;
110 env_policy_t *policyp;
111
112 if ((fp = fopen(conffile, "r")) == NULL) {
113 return (-1);
114 }
115 while (fgets(buf, sizeof (buf), fp) != NULL) {
116 if (buf[0] && (buf[0] == '#' || buf[0] == '\n')) {
117 continue;
118 }
119 token = (char *)strtok_r(buf, RECORD_WHITESPACE, &lasts);
120 if (token == NULL) {
121 continue;
122 }
123 policyp = (env_policy_t *)malloc(sizeof (env_policy_t));
124 if (policyp == NULL) {
125 goto errors;
126 }
127 policyp->interval = (uint8_t)strtoul(token, NULL, 0);
128 token = (char *)strtok_r(lasts, RECORD_WHITESPACE, &lasts);
129 if (token == NULL) {
130 free(policyp);
131 } else {
132 policyp->pname = strdup(token);
133 if (NULL == policyp->pname) {
134 goto errors;
135 }
136 }
137 if (lasts) {
138 policyp->argp = strdup(lasts);
139 if (policyp->argp == NULL) {
140 goto errors;
141 }
142 } else {
143 policyp->argp = NULL;
144 }
145 policyp->nextp = *policypp;
146 *policypp = policyp;
147 }
148 (void) fclose(fp);
149 return (0);
150
151 errors:
152 (void) fclose(fp);
153 while (*policypp) {
154 policyp = *policypp;
155 *policypp = (*policypp)->nextp;
156 free(policyp->pname);
157 free(policyp->argp);
158 free(policyp);
159 }
160 return (-1);
161 }
162
163 /*
164 * supports environmental policies
165 */
166 static void
env_parse_config_file()167 env_parse_config_file()
168 {
169 char conffile[MAXPATHLEN];
170 env_policy_t *policyp, *tmp;
171 struct stat st;
172
173 if (parse_config_file == B_FALSE) {
174 return;
175 }
176 (void) snprintf(conffile, sizeof (conffile), ENV_CONFIG_FILE,
177 sys_name);
178 bzero(&st, sizeof (st));
179 if (stat(conffile, &st) == -1) {
180 return;
181 }
182
183 policyp = NULL;
184 if (env_read_policy_configuration(conffile, &policyp) == -1) {
185 return;
186 }
187 assert(policyp);
188
189 while (policyp) {
190 tmp = policyp;
191 policyp = policyp->nextp;
192 if (strcmp(tmp->pname, SERVICE_PROCESSOR) == 0) {
193 alarm_check_interval = tmp->interval;
194 if (env_debug & DEBUG)
195 syslog(LOG_INFO, "Alarm Heartbeat frequency: "
196 "%d seconds", alarm_check_interval);
197 }
198 free(tmp->pname);
199 free(tmp->argp);
200 free(tmp);
201 }
202 }
203
204 /*
205 * detects the presence of RTM for CPU board
206 */
207 static boolean_t
is_rtm_present()208 is_rtm_present()
209 {
210 sc_reqmsg_t req_pkt;
211 sc_rspmsg_t rsp_pkt;
212 uint8_t size = 0;
213
214 req_pkt.data[0] = ENV_RTM_BUS_ID;
215 req_pkt.data[1] = ENV_RTM_SLAVE_ADDR;
216 req_pkt.data[2] = ENV_RTM_READ_SIZE;
217 size = ENV_RTM_PKT_LEN;
218
219 /* initialize the request packet */
220 (void) smc_init_smc_msg(&req_pkt, SMC_MASTER_RW_CMD,
221 DEFAULT_SEQN, size);
222
223 /* make a call to smc library to send cmd */
224 if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
225 POLL_TIMEOUT) != SMC_SUCCESS) {
226 return (B_FALSE);
227 }
228 return (B_TRUE);
229 }
230
231 /*
232 * this routine does the following:
233 * 1. initializes the CPU geo-addr
234 * 2. gets the system name
235 * 3. create the chassis type property
236 * 4. creates the conf_file property
237 */
238 static picl_errno_t
env_set_cpu_info()239 env_set_cpu_info()
240 {
241 int rc = 0;
242 sc_reqmsg_t req_pkt;
243 sc_rspmsg_t rsp_pkt;
244 uint8_t size = 0;
245 char conf_name[PICL_PROPNAMELEN_MAX];
246
247 /* get the geo_addr */
248 /* initialize the request packet */
249 (void) smc_init_smc_msg(&req_pkt, SMC_GET_GEOGRAPHICAL_ADDRESS,
250 DEFAULT_SEQN, size);
251
252 /* make a call to smc library to send cmd */
253 if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
254 POLL_TIMEOUT) != SMC_SUCCESS) {
255 return (PICL_FAILURE);
256 }
257 cpu_geo_addr = rsp_pkt.data[0];
258
259 /* get the system name */
260 if (sysinfo(SI_PLATFORM, sys_name, sizeof (sys_name)) == -1) {
261 return (PICL_FAILURE);
262 }
263 (void) strncpy(chassisconf_name, sys_name,
264 sizeof (chassisconf_name));
265
266 /* initialize the node handles */
267 if ((rc = ptree_get_root(&rooth)) != PICL_SUCCESS) {
268 return (rc);
269 }
270
271 if ((rc = ptree_get_node_by_path(FRUTREE_PATH, &frutreeh)) !=
272 PICL_SUCCESS) {
273 return (rc);
274 }
275
276 if ((rc = ptree_get_node_by_path(PICL_FRUTREE_CHASSIS,
277 &chassis_nodehdl)) != PICL_SUCCESS) {
278 return (rc);
279 }
280
281 /* create the chassis type property */
282 if ((rc = env_create_property(PICL_PTYPE_CHARSTRING,
283 PICL_READ, PICL_PROPNAMELEN_MAX, PICL_PROP_CHASSIS_TYPE,
284 NULLREAD, NULLWRITE, chassis_nodehdl, (picl_prophdl_t *)NULL,
285 chassisconf_name)) != PICL_SUCCESS) {
286 return (rc);
287 }
288
289 /*
290 * create dummy prop to inform frutree plugin abt conf file
291 * (rtm based or w/o rtm)
292 * frutree plugin removes this prop after reading the value
293 */
294 if (is_rtm_present() == B_TRUE) {
295 (void) snprintf(conf_name, sizeof (conf_name),
296 "%s.RTM.conf", chassisconf_name);
297 } else {
298 (void) snprintf(conf_name, sizeof (conf_name),
299 "%s.conf", chassisconf_name);
300 }
301
302 if ((rc = env_create_property(PICL_PTYPE_CHARSTRING,
303 PICL_READ, PICL_PROPNAMELEN_MAX, PICL_PROP_CONF_FILE, NULLREAD,
304 NULLWRITE, chassis_nodehdl, (picl_prophdl_t *)NULL,
305 conf_name)) != PICL_SUCCESS) {
306 return (rc);
307 }
308 return (PICL_SUCCESS);
309 }
310
311 /*
312 * initialization
313 */
314 picl_errno_t
env_init()315 env_init()
316 {
317 picl_errno_t rc = PICL_SUCCESS;
318
319 if ((rc = env_set_cpu_info()) != PICL_SUCCESS) {
320 return (rc);
321 }
322
323 /* parse the configuration file */
324 env_parse_config_file();
325
326 /*
327 * do any platform specific intialization if required
328 * IMPORTANT: must post dr_incoming resource event on
329 * chassis after doing all the reqd checks
330 */
331 rc = env_platmod_init();
332 return (rc);
333 }
334
335 /*
336 * sets smc global enables
337 */
338 static int
env_set_smc_global_enables(boolean_t ipmi_enable)339 env_set_smc_global_enables(boolean_t ipmi_enable)
340 {
341 sc_reqmsg_t req_pkt;
342 sc_rspmsg_t rsp_pkt;
343 uint8_t size = 0;
344
345 /* initialize the request packet */
346 (void) smc_init_smc_msg(&req_pkt, SMC_GET_GLOBAL_ENABLES,
347 DEFAULT_SEQN, size);
348
349 /* make a call to smc library to send cmd */
350 if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
351 POLL_TIMEOUT) != SMC_SUCCESS) {
352 return (-1);
353 }
354
355 req_pkt.data[0] = rsp_pkt.data[0];
356 req_pkt.data[1] = rsp_pkt.data[1];
357 if (ipmi_enable) {
358 req_pkt.data[1] |= ENV_IPMI_ENABLE_MASK;
359 req_pkt.data[1] &= ENV_SENSOR_ENABLE_MASK;
360 } else {
361 req_pkt.data[1] &= ENV_IPMI_DISABLE_MASK;
362 req_pkt.data[1] |= ENV_SENSOR_DISABLE_MASK;
363 }
364 size = ENV_SET_GLOBAL_PKT_LEN;
365 (void) smc_init_smc_msg(&req_pkt, SMC_SET_GLOBAL_ENABLES,
366 DEFAULT_SEQN, size);
367
368 /* make a call to smc library to send cmd */
369 if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
370 POLL_TIMEOUT) != SMC_SUCCESS) {
371 return (-1);
372 }
373 return (0);
374 }
375
376 /*
377 * wrapper smc drv open
378 */
379 int
env_open_smc(void)380 env_open_smc(void)
381 {
382 int fd;
383 if ((fd = open(SMC_NODE, O_RDWR)) < 0) {
384 return (-1);
385 }
386 return (fd);
387 }
388
389 static picl_smc_event_t
env_handle_smc_local_event(void * res_datap)390 env_handle_smc_local_event(void *res_datap)
391 {
392 picl_errno_t rc = PICL_SUCCESS;
393 uint8_t event = SMC_LOCAL_EVENT;
394 uint8_t event_data = BYTE_0(res_datap);
395
396 if (env_debug & EVENTS)
397 syslog(LOG_INFO, "Local Event Received, data %x\n", event_data);
398
399 switch (event_data) {
400 case SMC_LOCAL_EVENT_BRIDGE_IN_RESET : /*FALLTHRU*/
401 case SMC_LOCAL_EVENT_BRIDGE_OUT_OF_RESET :
402 if ((rc = env_platmod_handle_bus_if_change(
403 event_data)) != PICL_SUCCESS) {
404 syslog(LOG_ERR, gettext("SUNW_envmond:Error"
405 " in handling bus interface change "
406 "event, error = %d"), rc);
407 }
408 break;
409 case SMC_LOCAL_EVENT_LATCH_OPENED:
410 syslog(LOG_INFO, gettext("LATCH OPEN DETECTED"));
411 if ((rc = env_platmod_handle_latch_open()) !=
412 PICL_SUCCESS) {
413 syslog(LOG_ERR, gettext("SUNW_envmond:Error"
414 " in handling latch open event, "
415 "error = %d"), rc);
416 }
417 break;
418 default:
419 break;
420 }
421 return (event);
422 }
423
424 static void
env_handle_async_msg_event(void * res_datap)425 env_handle_async_msg_event(void *res_datap)
426 {
427 int rc = SMC_SUCCESS;
428 uint8_t event = BYTE_6(res_datap);
429
430 if (env_debug & EVENTS)
431 syslog(LOG_INFO, "Asynchronous Event %x Received, data %x\n",
432 event, BYTE_7(res_datap));
433 switch (event) {
434 /*
435 * This message comes to CPU when the service processor is going offline
436 * or online.
437 */
438 case EVENT_MSG_AC_STATE_CHANGE:
439 if ((rc = process_platmod_sp_state_change_notif(res_datap)) !=
440 SMC_SUCCESS) {
441 syslog(LOG_ERR, gettext("SUNW_envmond:Error in handling"
442 "service processor change of state event, "
443 "error = %d"), rc);
444 }
445 break;
446 /*
447 * This message comes to CPU when service processor
448 * requests the CPU to go online or offline (shutdown).
449 */
450 case EVENT_MSG_CHANGE_CPU_NODE_STATE:
451 if ((rc = process_platmod_change_cpu_node_state(res_datap)) !=
452 SMC_SUCCESS) {
453 syslog(LOG_ERR, gettext("SUNW_envmond:Error in handling"
454 "cpu change of state event, error = %d"), rc);
455 }
456 break;
457 /*
458 * This message comes to CPU(Satellite) when the
459 * other node (Host) is going online or offline.
460 */
461 case EVENT_MSG_CHANGE_CPCI_STATE:
462 if ((rc = process_platmod_change_cpci_state(res_datap)) !=
463 SMC_SUCCESS) {
464 syslog(LOG_ERR, gettext("SUNW_envmond:Error in handling"
465 "cpci change state event, error = %d"), rc);
466 }
467 break;
468 /*
469 * This message comes from service processor to inform
470 * change in states for other nodes
471 */
472 case EVENT_MSG_ASYNC_EVENT_NOTIFICATION:
473 if ((rc = process_platmod_async_msg_notif(res_datap)) !=
474 SMC_SUCCESS) {
475 syslog(LOG_ERR, gettext("SUNW_envmond:Error in handling"
476 "async event notification, error = %d"), rc);
477 }
478 break;
479 case MSG_GET_CPU_NODE_STATE:
480 /* respond to the service processor heartbeat */
481 process_platmod_sp_heartbeat(BYTE_5(res_datap));
482 break;
483 default:
484 event = NO_EVENT;
485 break;
486 }
487 }
488
489 /*ARGSUSED*/
490 static picl_smc_event_t
env_process_smc_event(int fd,void ** datapp)491 env_process_smc_event(int fd, void **datapp)
492 {
493 sc_rspmsg_t rsp_msg;
494 picl_smc_event_t event;
495 void *res_datap = NULL;
496
497 if (read(fd, (char *)&rsp_msg, SC_MSG_MAX_SIZE) < 0) {
498 return (NO_EVENT);
499 }
500
501 if (SC_MSG_CC(&rsp_msg) != 0) {
502 return (NO_EVENT);
503 }
504
505 res_datap = SC_MSG_DATA(&rsp_msg);
506 if (env_debug & EVENTS)
507 syslog(LOG_INFO, "Async Msg Cmd,data0,2 = %x,%x,%x\n",
508 SC_MSG_CMD(&rsp_msg), BYTE_0(res_datap),
509 BYTE_2(res_datap));
510
511 if (SC_MSG_CMD(&rsp_msg) == SMC_SMC_LOCAL_EVENT_NOTIF) {
512 event = env_handle_smc_local_event(res_datap);
513 } else { /* it must be an IPMI event */
514 switch (BYTE_2(res_datap)) {
515 case 0x3:
516 case 0x4:
517 if (env_debug & DEBUG)
518 syslog(LOG_INFO, gettext("SUNW_envmond: "
519 " Sensor Event Received\n"));
520 /* sensor event */
521 switch (BYTE_3(res_datap)) {
522 case TEMPERATURE_SENSOR_TYPE:
523 event = TEMPERATURE_SENSOR_EVENT;
524 env_platmod_handle_sensor_event(res_datap);
525 break;
526 default:
527 syslog(LOG_ERR, gettext("SUNW_envmond:Unknown "
528 "sensor Event:%d\n"), BYTE_3(res_datap));
529 event = NO_EVENT;
530 break;
531 }
532 default:
533 env_handle_async_msg_event(res_datap);
534 break;
535 }
536 }
537 return (event);
538 }
539
540 /*
541 * polls SMC driver for SMC events
542 */
543 /*ARGSUSED*/
544 static void *
env_polling_thread(void * args)545 env_polling_thread(void *args)
546 {
547 int poll_rc;
548 struct pollfd poll_fds[1];
549 void *datap;
550 int smcfd;
551 struct strioctl strio;
552 sc_cmdspec_t set;
553
554 smcfd = env_open_smc();
555 if (smcfd == -1) {
556 syslog(LOG_ERR, gettext("SUNW_envmond:Error in polling, "
557 "Open of SMC drv failed"));
558 create_polling_thr = B_TRUE;
559 return (NULL);
560 }
561
562 set.args[0] = SMC_SENSOR_EVENT_ENABLE_SET;
563 set.attribute = SC_ATTR_SHARED;
564 strio.ic_cmd = SCIOC_MSG_SPEC;
565 strio.ic_timout = 0;
566 strio.ic_len = ENV_SENSOR_EV_ENABLE_PKT_LEN;
567 strio.ic_dp = (char *)&set;
568 if (ioctl(smcfd, I_STR, &strio) < 0) {
569 syslog(LOG_ERR, gettext("SUNW_envmond:Request for "
570 "Sensor events failed"));
571 (void) close(smcfd);
572 create_polling_thr = B_TRUE;
573 return (NULL);
574 }
575
576 /* request for async messages */
577 poll_fds[0].fd = smcfd;
578 poll_fds[0].events = POLLIN|POLLPRI;
579 poll_fds[0].revents = 0;
580
581 set.attribute = SC_ATTR_SHARED;
582 set.args[0] = SMC_IPMI_RESPONSE_NOTIF;
583 set.args[1] = SMC_SMC_LOCAL_EVENT_NOTIF;
584 strio.ic_cmd = SCIOC_MSG_SPEC;
585 strio.ic_timout = 0;
586 strio.ic_len = ENV_IPMI_SMC_ENABLE_PKT_LEN;
587 strio.ic_dp = (char *)&set;
588 if (ioctl(smcfd, I_STR, &strio) == -1) {
589 syslog(LOG_ERR, gettext("SUNW_envmond:Request for"
590 "Async messages failed"));
591 (void) close(smcfd);
592 create_polling_thr = B_TRUE;
593 return (NULL);
594 }
595
596 /* Now wait for SMC events to come */
597 for (;;) {
598 poll_rc = poll(poll_fds, 1, -1); /* poll forever */
599 if (poll_rc < 0) {
600 syslog(LOG_ERR, gettext("SUNW_envmond:Event "
601 "processing halted"));
602 break;
603 }
604 if (env_process_smc_event(smcfd, &datap) == NO_EVENT) {
605 syslog(LOG_ERR, gettext("SUNW_envmond:"
606 "wrong event data posted from SMC"));
607 }
608 }
609 (void) close(smcfd);
610 create_polling_thr = B_TRUE;
611 return (NULL);
612 }
613
614 /*
615 * (to be)Called during chassis configuration. It does the following tasks.
616 * Set global enables on SMC
617 * Register for local(SMC) events and remote(IPMI) messages (State Change msgs)
618 * creates sensor nodes
619 * Initialize hotswap
620 * Initiallize the interaction with service processor
621 */
622 static picl_errno_t
env_start_services(void)623 env_start_services(void)
624 {
625 int rc;
626 if (env_debug & DEBUG) {
627 syslog(LOG_INFO, "env_start_services begin");
628 }
629
630 /* set the SMC global enables */
631 if (env_set_smc_global_enables(B_TRUE) == -1) {
632 syslog(LOG_ERR, gettext("SUNW_envmond:Setting SMC "
633 "Globals failed"));
634 return (PICL_FAILURE);
635 }
636
637 /* start a worker thread to poll for SMC events */
638 if (create_polling_thr) {
639 rc = pthread_create(&polling_threadID, NULL,
640 &env_polling_thread, NULL);
641 if (rc != 0) {
642 syslog(LOG_ERR, gettext("SUNW_envmond:Error in "
643 "creating polling thread"));
644 return (PICL_FAILURE);
645 }
646 create_polling_thr = B_FALSE;
647 }
648
649 /* create the sensor nodes */
650 if ((rc = env_platmod_create_sensors()) != PICL_SUCCESS) {
651 syslog(LOG_ERR, gettext("SUNW_envmond:Error in creating sensor"
652 " nodes, error = %d"), rc);
653 }
654
655 /* intialize the hotswap framework */
656 if ((rc = env_platmod_setup_hotswap()) != PICL_SUCCESS) {
657 syslog(LOG_ERR, gettext("SUNW_envmond:Error in hotswap "
658 "initialization, error = %d"), rc);
659 }
660
661 if ((rc = env_platmod_create_hotswap_prop()) != PICL_SUCCESS) {
662 syslog(LOG_ERR, gettext("SUNW_envmond:Error in creating "
663 "hotswap prop, error = %d"), rc);
664 }
665
666 /* intialize interaction with service processor */
667 if ((rc = env_platmod_sp_monitor()) != PICL_SUCCESS) {
668 syslog(LOG_ERR, gettext("SUNW_envmond:Failed to interact with"
669 " service processor, error = %d"), rc);
670 }
671 return (PICL_SUCCESS);
672 }
673
674 static picl_errno_t
env_handle_chassis_configuring_event(char * state)675 env_handle_chassis_configuring_event(char *state)
676 {
677 picl_errno_t rc = PICL_SUCCESS;
678 picl_prophdl_t proph;
679 picl_nodehdl_t rtm_lnodehdl = 0;
680 char *cpu_name = PICL_NODE_CPU;
681 char *rtm_name = PICL_NODE_RTM;
682 uint64_t status_time;
683
684 if (strcmp(state, PICLEVENTARGVAL_CONFIGURING) != 0) {
685 return (PICL_SUCCESS);
686 }
687
688 /* initialize cpu loc node handle */
689 if (cpu_lnodehdl == 0) {
690 if ((rc = ptree_find_node(chassis_nodehdl,
691 PICL_PROP_NAME, PICL_PTYPE_CHARSTRING,
692 cpu_name, (strlen(cpu_name) + 1),
693 &cpu_lnodehdl)) != PICL_SUCCESS) {
694 syslog(LOG_ERR, gettext("SUNW_envmond: failed "
695 " to get CPU nodehdl, error = %d"), rc);
696 return (rc);
697 }
698 }
699
700 /* create geo-addr prop under CPU location */
701 if (ptree_get_prop_by_name(cpu_lnodehdl, PICL_PROP_GEO_ADDR,
702 &proph) == PICL_PROPNOTFOUND) {
703 if ((rc = env_create_property(PICL_PTYPE_UNSIGNED_INT,
704 PICL_READ, sizeof (cpu_geo_addr),
705 PICL_PROP_GEO_ADDR, NULLREAD, NULLWRITE,
706 cpu_lnodehdl, &proph,
707 (void *)&cpu_geo_addr)) != PICL_SUCCESS) {
708 return (rc);
709 }
710 }
711 if (ptree_get_prop_by_name(cpu_lnodehdl,
712 PICL_PROP_STATUS_TIME, &proph) != PICL_SUCCESS) {
713 status_time = (uint64_t)time(NULL);
714 (void) env_create_property(PICL_PTYPE_TIMESTAMP,
715 PICL_READ, sizeof (status_time),
716 PICL_PROP_STATUS_TIME, NULLREAD, NULLWRITE,
717 cpu_lnodehdl, &proph, &status_time);
718 }
719
720 /* create geo address property for RTM node (if present) */
721 (void) ptree_find_node(chassis_nodehdl,
722 PICL_PROP_NAME, PICL_PTYPE_CHARSTRING, rtm_name,
723 (strlen(rtm_name) + 1), &rtm_lnodehdl);
724
725 if (rtm_lnodehdl == 0) { /* RTM not present */
726 return (PICL_SUCCESS);
727 }
728
729 if (ptree_get_prop_by_name(rtm_lnodehdl, PICL_PROP_GEO_ADDR,
730 &proph) == PICL_PROPNOTFOUND) {
731 if ((rc = env_create_property(PICL_PTYPE_UNSIGNED_INT,
732 PICL_READ, sizeof (cpu_geo_addr), PICL_PROP_GEO_ADDR,
733 NULLREAD, NULLWRITE, rtm_lnodehdl, &proph,
734 &cpu_geo_addr)) != PICL_SUCCESS) {
735 syslog(LOG_ERR, gettext("SUNW_envmond:Failed "
736 "to create CPU geo-addr, error = %d"), rc);
737 return (rc);
738 }
739 }
740 if (ptree_get_prop_by_name(rtm_lnodehdl,
741 PICL_PROP_STATUS_TIME, &proph) != PICL_SUCCESS) {
742 status_time = (uint64_t)time(NULL);
743 (void) env_create_property(PICL_PTYPE_TIMESTAMP,
744 PICL_READ, sizeof (status_time), PICL_PROP_STATUS_TIME,
745 NULLREAD, NULLWRITE, rtm_lnodehdl, &proph,
746 &status_time);
747 }
748
749 /* start all the environment monitoring services */
750 if ((rc = env_start_services()) != PICL_SUCCESS) {
751 return (rc);
752 }
753 return (PICL_SUCCESS);
754 }
755
756 /*
757 * routine to handle all the picl state and condition change events
758 */
759 void
env_handle_event(const char * ename,const void * earg,size_t size)760 env_handle_event(const char *ename, const void *earg, size_t size)
761 {
762 picl_nodehdl_t nodeh = 0;
763 nvlist_t *nvlp;
764 char *value;
765 boolean_t state_event;
766 char result[PICL_PROPNAMELEN_MAX];
767
768 if (!ename) {
769 return;
770 }
771 if (strcmp(ename, PICLEVENT_STATE_CHANGE) == 0) {
772 state_event = B_TRUE;
773 } else if (strcmp(ename, PICLEVENT_CONDITION_CHANGE) == 0) {
774 state_event = B_FALSE;
775 } else {
776 return;
777 }
778
779 /* unpack the nvlist and get the information */
780 if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
781 return;
782 }
783 if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh) == -1) {
784 nvlist_free(nvlp);
785 return;
786 }
787 if (nvlist_lookup_string(nvlp, (state_event) ?
788 PICLEVENTARG_STATE :
789 PICLEVENTARG_CONDITION, &value) != 0) {
790 nvlist_free(nvlp);
791 return;
792 }
793
794 if (env_debug & PICLEVENTS) {
795 if (ptree_get_propval_by_name(nodeh, PICL_PROP_NAME,
796 result, sizeof (result)) != PICL_SUCCESS) {
797 syslog(LOG_ERR, " SUNW_envmond: error in getting"
798 " %s", PICL_PROP_NAME);
799 nvlist_free(nvlp);
800 return;
801 }
802 syslog(LOG_INFO, "SUNW_envmond: %s (%s) on %s",
803 ename, value, result);
804 }
805
806 if (chassis_nodehdl == 0 && state_event) {
807 if (ptree_get_propval_by_name(nodeh, PICL_PROP_NAME,
808 result, sizeof (result)) != PICL_SUCCESS) {
809 nvlist_free(nvlp);
810 return;
811 }
812 if (strcmp(result, PICL_NODE_CHASSIS) == 0) {
813 chassis_nodehdl = nodeh;
814 }
815 }
816 if (nodeh == chassis_nodehdl && state_event) {
817 (void) env_handle_chassis_configuring_event(value);
818 }
819 /* do any platform specific handling that is reqd */
820 env_platmod_handle_event(ename, earg, size);
821 nvlist_free(nvlp);
822 }
823