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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 }