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 }