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 <limits.h>
  31 #include <unistd.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 <libnvpair.h>
  40 #include <libintl.h>
  41 #include <librcm.h>
  42 #include <stropts.h>
  43 #include <smclib.h>
  44 #include <sys/sysevent/dr.h>
  45 #include "piclenvmond.h"
  46 #include "picldr.h"
  47 
  48 /* local defines */
  49 #define RESET_CPU "/usr/sbin/shutdown -y -g 0 -i6"
  50 #define SHUTDOWN_CPU "/usr/sbin/shutdown -y -g 0 -i0"
  51 #define RCM_ABSTRACT_RESOURCE   "SUNW_snowbird/board0/CPU1"
  52 #define CPU_SENSOR_GEO_ADDR     0xe
  53 #define IS_HEALTHY              0x01
  54 #define PICL_NODE_SYSMGMT       "sysmgmt"
  55 #define SYSMGMT_PATH            PLATFORM_PATH"/pci/pci/isa/sysmgmt"
  56 #define BUF_SIZE                7
  57 
  58 /* external functions */
  59 extern picl_errno_t env_create_property(int, int, size_t, char *,
  60         int (*readfn)(ptree_rarg_t *, void *),
  61         int (*writefn)(ptree_warg_t *, const void *),
  62         picl_nodehdl_t, picl_prophdl_t *, void *);
  63 extern picl_errno_t post_dr_req_event(picl_nodehdl_t, char *, uint8_t);
  64 extern picl_errno_t post_dr_ap_state_change_event(picl_nodehdl_t, char *,
  65         uint8_t);
  66 extern boolean_t env_admin_lock_enabled(picl_nodehdl_t);
  67 extern picl_errno_t env_create_temp_sensor_node(picl_nodehdl_t, uint8_t);
  68 extern void env_handle_sensor_event(void *);
  69 extern int env_open_smc();
  70 
  71 /* external variables */
  72 extern int env_debug;
  73 extern uint8_t cpu_geo_addr;
  74 extern picl_nodehdl_t rooth, platformh, sysmgmth, sensorh;
  75 extern picl_nodehdl_t chassis_nodehdl, cpu_nodehdl, cpu_lnodehdl;
  76 
  77 /* locals */
  78 static pthread_mutex_t env_dmc_mutex = PTHREAD_MUTEX_INITIALIZER;
  79 static pthread_cond_t env_dmc_cond = PTHREAD_COND_INITIALIZER;
  80 static boolean_t env_reset_cpu = B_FALSE;
  81 static boolean_t env_shutdown_system = B_FALSE;
  82 static env_state_event_t env_chassis_state = FRU_STATE_UNKNOWN;
  83 static char *rcm_abstr_cp2300_name = RCM_ABSTRACT_RESOURCE;
  84 static boolean_t env_got_dmc_msg = B_FALSE;
  85 static long env_dmc_wait_time = 15;
  86 static pthread_t dmc_thr_tid;
  87 
  88 /*
  89  * issue halt or reboot based on the reset_cpu flag
  90  */
  91 /*ARGSUSED*/
  92 static void
  93 shutdown_cpu(boolean_t force)
  94 {
  95         if (env_shutdown_system) {
  96                 if (env_reset_cpu) {
  97                         (void) pclose(popen(RESET_CPU, "w"));
  98                 } else {
  99                         (void) pclose(popen(SHUTDOWN_CPU, "w"));
 100                 }
 101         }
 102 }
 103 
 104 /*
 105  * inform RCM framework that the remove op is successful
 106  */
 107 static void
 108 confirm_rcm(char *abstr_name, rcm_handle_t *rhandle)
 109 {
 110         rcm_notify_remove(rhandle, abstr_name, 0, NULL);
 111 }
 112 
 113 /*
 114  * inform RCM framework that the remove op is failed
 115  */
 116 static void
 117 fail_rcm(char *abstr_name, rcm_handle_t *rhandle)
 118 {
 119         (void) rcm_notify_online(rhandle, abstr_name, 0, NULL);
 120 }
 121 
 122 /*
 123  * check RCM framework if it is ok to offline a device
 124  */
 125 static int
 126 check_rcm(char *rcm_abstr_cp2300_name, uint_t flags)
 127 {
 128         rcm_info_t *rinfo;
 129         rcm_handle_t *rhandle;
 130         int rv;
 131 
 132         if (rcm_alloc_handle(NULL, 0, NULL, &rhandle) != RCM_SUCCESS) {
 133                 return (RCM_FAILURE);
 134         }
 135 
 136         rv = rcm_request_offline(rhandle, rcm_abstr_cp2300_name,
 137                 flags, &rinfo);
 138 
 139         if (rv == RCM_FAILURE) {
 140                 rcm_free_info(rinfo);
 141                 fail_rcm(rcm_abstr_cp2300_name, rhandle);
 142                 rcm_free_handle(rhandle);
 143                 return (RCM_FAILURE);
 144         }
 145         if (rv == RCM_CONFLICT) {
 146                 rcm_free_info(rinfo);
 147                 rcm_free_handle(rhandle);
 148                 return (RCM_CONFLICT);
 149         }
 150 
 151         confirm_rcm(rcm_abstr_cp2300_name, rhandle);
 152         rcm_free_info(rinfo);
 153         rcm_free_handle(rhandle);
 154         return (RCM_SUCCESS);
 155 }
 156 
 157 /*
 158  * utility routine to send response to an IPMI message
 159  */
 160 static int
 161 send_response2remote_device(uint8_t ipmb_addr, uint8_t cmd, uint8_t reqseq_lun,
 162         uint8_t cc)
 163 {
 164         int rc = SMC_SUCCESS;
 165         sc_reqmsg_t req_pkt;
 166         sc_rspmsg_t rsp_pkt;
 167         uint8_t data = cc; /* completion code */
 168 
 169         /* make a call to ctsmc lib */
 170         (void) smc_init_ipmi_msg(&req_pkt, cmd, DEFAULT_FD, 1, &data,
 171                 (reqseq_lun >> 2), ipmb_addr, SMC_NETFN_APP_RSP,
 172                 (reqseq_lun & 0x03));
 173         rc = smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
 174                 POLL_TIMEOUT);
 175 
 176         if (rc != SMC_SUCCESS)
 177                 syslog(LOG_ERR, gettext("SUNW_envmond:Error in sending response"
 178                         " to %x, error = %d"), ipmb_addr, rc);
 179         return (rc);
 180 }
 181 
 182 /*
 183  * do all the checks like adminlock check, rcm check and initiate
 184  * shutdown
 185  */
 186 /*ARGSUSED*/
 187 static int
 188 initiate_shutdown(boolean_t force)
 189 {
 190         int rv;
 191         uint_t  rcmflags = 0;
 192         struct timespec rqtp, rmtp;
 193 
 194         if (!env_shutdown_system) {
 195                 return (-1);
 196         }
 197 
 198         /* check the adminlock prop */
 199         if ((!force) && (env_admin_lock_enabled(cpu_nodehdl))) {
 200                 syslog(LOG_ERR, gettext("SUNW_envmond: "
 201                         "CPU in use! Cannot shutdown"));
 202                 return (-1);
 203         }
 204 
 205         if (force) {
 206                 rcmflags = RCM_FORCE;
 207         }
 208 
 209         /* check with rcm framework */
 210         rv = check_rcm(rcm_abstr_cp2300_name, rcmflags);
 211 
 212         if ((rv == RCM_FAILURE) || (rv == RCM_CONFLICT)) {
 213                 syslog(LOG_ERR, gettext("SUNW_envmond: RCM error %d, Cannot"
 214                         " shutdown"), rv);
 215                 return (-1);
 216         }
 217 
 218         /*
 219          * force events on chassis node
 220          */
 221         if (force) {
 222                 if (post_dr_req_event(chassis_nodehdl, DR_REQ_OUTGOING_RES,
 223                         NO_WAIT) == PICL_SUCCESS) {
 224                         /* wait a little for clean up of frutree */
 225                         rqtp.tv_sec = 5;
 226                         rqtp.tv_nsec = 0;
 227                         (void) nanosleep(&rqtp, &rmtp);
 228                 }
 229                 /*
 230                  * If force option is set, do it right here for now
 231                  * since there is no way to pass this info via events
 232                  * to frutree framework.
 233                  */
 234                 shutdown_cpu(force);
 235                 return (0);
 236         }
 237 
 238         if (post_dr_req_event(chassis_nodehdl, DR_REQ_OUTGOING_RES, NO_WAIT)
 239                 != PICL_SUCCESS) {
 240                 syslog(LOG_ERR, gettext("SUNW_envmond:cannot shutdown "
 241                         "the host CPU."));
 242                 return (-1);
 243         }
 244         return (0);
 245 }
 246 
 247 /*
 248  * get the HEALTHY# line state
 249  * Return -1 for Error
 250  *         0 for HEALTHY# down
 251  *         1 for HEALTHY# up
 252  */
 253 static int
 254 env_get_healthy_status()
 255 {
 256         sc_reqmsg_t     req_pkt;
 257         sc_rspmsg_t     rsp_pkt;
 258         uint8_t         size = 0;
 259 
 260         /* initialize the request packet */
 261         (void) smc_init_smc_msg(&req_pkt, SMC_GET_EXECUTION_STATE,
 262                 DEFAULT_SEQN, size);
 263 
 264         /* make a call to smc library to send cmd */
 265         if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
 266                 POLL_TIMEOUT) != SMC_SUCCESS) {
 267                 return (-1);
 268         }
 269         return (rsp_pkt.data[0] & IS_HEALTHY);
 270 }
 271 
 272 /*
 273  * initialization
 274  */
 275 picl_errno_t
 276 env_platmod_init()
 277 {
 278         picl_errno_t rc =  PICL_SUCCESS;
 279 
 280         if (rooth == 0) {
 281                 if (ptree_get_root(&rooth) != PICL_SUCCESS) {
 282                         return (rc);
 283                 }
 284         }
 285 
 286         if (chassis_nodehdl == 0) {
 287                 if ((rc = ptree_get_node_by_path(PICL_FRUTREE_CHASSIS,
 288                         &chassis_nodehdl)) != PICL_SUCCESS) {
 289                         return (rc);
 290                 }
 291         }
 292         if (post_dr_req_event(chassis_nodehdl, DR_REQ_INCOMING_RES,
 293                 NO_WAIT) != PICL_SUCCESS) {
 294                 syslog(LOG_ERR, gettext("SUNW_envmond: Error in "
 295                         "Posting configure event for Chassis node"));
 296                 rc = PICL_FAILURE;
 297         }
 298         return (rc);
 299 }
 300 
 301 /*
 302  * release all the resources
 303  */
 304 void
 305 env_platmod_fini()
 306 {
 307         cpu_geo_addr = 0;
 308         rooth = platformh = sysmgmth = 0;
 309         chassis_nodehdl = cpu_nodehdl = cpu_lnodehdl = 0;
 310         env_chassis_state = FRU_STATE_UNKNOWN;
 311         (void) ptree_delete_node(sensorh);
 312         (void) ptree_destroy_node(sensorh);
 313 }
 314 
 315 /*
 316  * handle chassis state change
 317  */
 318 static void
 319 env_handle_chassis_state_event(char *state)
 320 {
 321         if (strcmp(state, PICLEVENTARGVAL_CONFIGURING) == 0) {
 322                 env_chassis_state = FRU_STATE_CONFIGURING;
 323                 return;
 324         }
 325 
 326         if (strcmp(state, PICLEVENTARGVAL_UNCONFIGURED) == 0) {
 327                 if (env_chassis_state == FRU_STATE_CONFIGURING ||
 328                         env_chassis_state == FRU_STATE_UNKNOWN) {
 329                         /* picl intialization is failed, dont issue shutdown */
 330                         env_chassis_state = FRU_STATE_UNCONFIGURED;
 331                         return;
 332                 }
 333                 env_chassis_state = FRU_STATE_UNCONFIGURED;
 334                 if (env_reset_cpu) {
 335                         (void) pclose(popen(RESET_CPU, "w"));
 336                 } else {
 337                         (void) pclose(popen(SHUTDOWN_CPU, "w"));
 338                 }
 339                 return;
 340         }
 341 
 342         if (strcmp(state, PICLEVENTARGVAL_CONFIGURED) == 0) {
 343                 env_chassis_state = FRU_STATE_CONFIGURED;
 344         }
 345 }
 346 
 347 /*
 348  *  event handler for watchdog state change event
 349  */
 350 static picl_errno_t
 351 env_handle_watchdog_expiry(picl_nodehdl_t wd_nodehdl)
 352 {
 353         picl_errno_t rc = PICL_SUCCESS;
 354         char class[PICL_CLASSNAMELEN_MAX];
 355         char value[PICL_PROPNAMELEN_MAX];
 356         char cond[BUF_SIZE];
 357 
 358         if ((rc = ptree_get_propval_by_name(wd_nodehdl,
 359                 PICL_PROP_CLASSNAME, class,
 360                 PICL_CLASSNAMELEN_MAX)) != PICL_SUCCESS) {
 361                 return (rc);
 362         }
 363 
 364         /* if the event is not of watchdog-timer, return */
 365         if (strcmp(class, PICL_CLASS_WATCHDOG_TIMER) != 0) {
 366                 return (PICL_INVALIDARG);
 367         }
 368 
 369         if ((rc = ptree_get_propval_by_name(wd_nodehdl,
 370                 PICL_PROP_WATCHDOG_ACTION, value, sizeof (value))) !=
 371                 PICL_SUCCESS) {
 372                 return (rc);
 373         }
 374 
 375         /* if action is none, dont do anything */
 376         if (strcmp(value, PICL_PROPVAL_WD_ACTION_ALARM) != 0) {
 377                 return (PICL_SUCCESS);
 378         }
 379 
 380         (void) strncpy(cond, PICLEVENTARGVAL_FAILED, sizeof (cond));
 381         /* update CPU condition to failed */
 382         if ((rc = ptree_update_propval_by_name(cpu_nodehdl,
 383                 PICL_PROP_CONDITION, cond, sizeof (cond))) != PICL_SUCCESS) {
 384                 return (rc);
 385         }
 386 
 387         /* post dr ap state change event */
 388         rc = post_dr_ap_state_change_event(cpu_nodehdl,
 389                 DR_RESERVED_ATTR, NO_COND_TIMEDWAIT);
 390         return (rc);
 391 }
 392 
 393 /*
 394  * rotine that handles all the picl state and condition change events
 395  */
 396 void
 397 env_platmod_handle_event(const char *ename, const void *earg, size_t size)
 398 {
 399         picl_errno_t            rc;
 400         picl_nodehdl_t          nodeh = 0;
 401         picl_prophdl_t          proph;
 402         nvlist_t                *nvlp;
 403         char                    *value;
 404         boolean_t               state_event;
 405         env_state_event_t       event;
 406         char                    result[PICL_PROPNAMELEN_MAX];
 407         uint64_t                status_time, cond_time;
 408         char                    cond[BUF_SIZE];
 409 
 410         if (!ename) {
 411                 return;
 412         }
 413         if (strcmp(ename, PICLEVENT_STATE_CHANGE) == 0) {
 414                 state_event = B_TRUE;
 415         } else if (strcmp(ename, PICLEVENT_CONDITION_CHANGE) == 0) {
 416                 state_event = B_FALSE;
 417         } else {
 418                 syslog(LOG_ERR, gettext("SUNW_envmond: unknown event:%s\n"),
 419                         ename);
 420                 return;
 421         }
 422 
 423         /* unpack the nvlist and get the information */
 424         if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
 425                 return;
 426         }
 427         if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh) == -1) {
 428                 nvlist_free(nvlp);
 429                 return;
 430         }
 431         if (nvlist_lookup_string(nvlp, (state_event) ?
 432                 PICLEVENTARG_STATE :
 433                 PICLEVENTARG_CONDITION, &value) != 0) {
 434                 nvlist_free(nvlp);
 435                 return;
 436         }
 437 
 438         if (env_debug & PICLEVENTS) {
 439                 if (ptree_get_propval_by_name(nodeh, PICL_PROP_NAME,
 440                         result, sizeof (result)) != PICL_SUCCESS) {
 441                         syslog(LOG_ERR, " SUNW_envmond: error in getting"
 442                                 " node name");
 443                         nvlist_free(nvlp);
 444                         return;
 445                 }
 446                 syslog(LOG_INFO, "SUNW_envmond: %s (%s) on %s",
 447                         ename, value, result);
 448         }
 449 
 450         if (chassis_nodehdl == 0 && state_event) {
 451                 if (ptree_get_propval_by_name(nodeh, PICL_PROP_NAME,
 452                         result, sizeof (result)) != PICL_SUCCESS) {
 453                         nvlist_free(nvlp);
 454                         return;
 455                 }
 456                 if (strcmp(result, PICL_NODE_CHASSIS) == 0) {
 457                         chassis_nodehdl = nodeh;
 458                 }
 459         }
 460 
 461         if (nodeh == chassis_nodehdl && state_event) {
 462                 env_handle_chassis_state_event(value);
 463                 nvlist_free(nvlp);
 464                 return;
 465         }
 466 
 467         if (strcmp(PICLEVENTARGVAL_DISCONNECTED, value) == 0) {
 468                 event = LOC_STATE_DISCONNECTED;
 469         } else if (strcmp(PICLEVENTARGVAL_CONNECTED, value) == 0) {
 470                 event = LOC_STATE_CONNECTED;
 471         } else if (strcmp(PICLEVENTARGVAL_EMPTY, value) == 0) {
 472                 event = LOC_STATE_EMPTY;
 473         } else if (strcmp(PICLEVENTARGVAL_CONFIGURED, value) == 0) {
 474                 event = FRU_STATE_CONFIGURED;
 475         } else if (strcmp(PICLEVENTARGVAL_UNCONFIGURED, value) == 0) {
 476                 event = FRU_STATE_UNCONFIGURED;
 477         } else if (strcmp(PICL_PROPVAL_WD_STATE_EXPIRED, value) == 0) {
 478                 /* watchdog expiry event */
 479                 if ((rc = env_handle_watchdog_expiry(nodeh)) != PICL_SUCCESS) {
 480                         syslog(LOG_ERR, gettext("SUNW_envmond:Error in handling"
 481                                 "watchdog expiry event"));
 482                 }
 483                 nvlist_free(nvlp);
 484                 return;
 485         } else {
 486                 nvlist_free(nvlp);
 487                 return;
 488         }
 489 
 490         switch (event) {
 491         case LOC_STATE_EMPTY:
 492                 break;
 493 
 494         case LOC_STATE_DISCONNECTED:
 495                 if (nodeh == cpu_lnodehdl) {
 496                         (void) initiate_shutdown(B_FALSE);
 497                 }
 498                 break;
 499         case LOC_STATE_CONNECTED:
 500                 if (nodeh != cpu_lnodehdl) {
 501                         break;
 502                 }
 503                 if (ptree_get_propval_by_name(cpu_lnodehdl,
 504                         PICL_PROP_CHILD, &cpu_nodehdl,
 505                         sizeof (picl_nodehdl_t)) != PICL_SUCCESS) {
 506                         syslog(LOG_ERR, gettext("SUNW_envmond:Cannot "
 507                                 "initialize CPU node handle %llx"), nodeh);
 508                         cpu_nodehdl = 0;
 509                 }
 510                 break;
 511         case FRU_STATE_CONFIGURED:
 512                 if (nodeh != cpu_nodehdl) {
 513                         break;
 514                 }
 515                 if (ptree_get_prop_by_name(cpu_nodehdl,
 516                         PICL_PROP_STATUS_TIME, &proph) != PICL_SUCCESS) {
 517                                 status_time = (uint64_t)time(NULL);
 518                                 (void) env_create_property(PICL_PTYPE_TIMESTAMP,
 519                                         PICL_READ, sizeof (status_time),
 520                                         PICL_PROP_STATUS_TIME, NULLREAD,
 521                                         NULLWRITE, cpu_nodehdl, &proph,
 522                                         &status_time);
 523                 }
 524                 if (ptree_get_prop_by_name(cpu_nodehdl,
 525                         PICL_PROP_CONDITION_TIME, &proph) != PICL_SUCCESS) {
 526                                 cond_time = (uint64_t)time(NULL);
 527                                 (void) env_create_property(PICL_PTYPE_TIMESTAMP,
 528                                         PICL_READ, sizeof (cond_time),
 529                                         PICL_PROP_CONDITION_TIME, NULLREAD,
 530                                         NULLWRITE, cpu_nodehdl, &proph,
 531                                         &cond_time);
 532                         }
 533                 env_shutdown_system = B_FALSE;
 534                 /* if HEALTHY# is UP update the condition to "ok" */
 535                 switch (env_get_healthy_status()) {
 536                 case 0:
 537                 /* update CPU condition to failed */
 538                 (void) strncpy(cond, PICLEVENTARGVAL_FAILED, sizeof (cond));
 539                 break;
 540                 case 1:
 541                 /* update CPU condition to ok */
 542                 (void) strncpy(cond, PICLEVENTARGVAL_OK, sizeof (cond));
 543                 break;
 544                 case -1:        /*FALLTHRU*/
 545                 default:
 546                 /* update the condition to unknown */
 547                 (void) strncpy(cond, PICLEVENTARGVAL_UNKNOWN, sizeof (cond));
 548                         syslog(LOG_ERR, gettext("SUNW_envmond:Error in "
 549                                 "reading HEALTHY# status"));
 550                 }
 551 
 552                 if ((rc = ptree_update_propval_by_name(cpu_nodehdl,
 553                         PICL_PROP_CONDITION, cond, sizeof (cond))) !=
 554                         PICL_SUCCESS) {
 555                         syslog(LOG_ERR, gettext("SUNW_envmond:Error in "
 556                                 "updating CPU condition, error = %d"), rc);
 557                 }
 558                 break;
 559         case FRU_STATE_UNCONFIGURED:
 560                 if (env_reset_cpu && nodeh == cpu_nodehdl) {
 561                         (void) initiate_shutdown(B_FALSE);
 562                 }
 563                 break;
 564         default:
 565         break;
 566         } /* end of switch */
 567         nvlist_free(nvlp);
 568 }
 569 
 570 /*
 571  * This thread waits for dmc message to come, as it has to send
 572  * response ACK back to DMC. Otherwise DMC may think that message
 573  * is lost and issues poweroff on a node. So there is a chance for
 574  * CPU to be powered off in the middle of shutdown process. If the
 575  * DMC message didnt come, then process the local shutdown request.
 576  */
 577 /*ARGSUSED*/
 578 static void *
 579 env_wait_for_dmc_msg(void *args)
 580 {
 581         struct timeval  ct;
 582         struct timespec to;
 583 
 584         (void) pthread_mutex_lock(&env_dmc_mutex);
 585         if (env_got_dmc_msg == B_TRUE) {
 586                 (void) pthread_mutex_unlock(&env_dmc_mutex);
 587                 return (NULL);
 588         }
 589 
 590         /*
 591          * wait for specified time to check if dmc sends the
 592          * shutdown request
 593          */
 594         (void) gettimeofday(&ct, NULL);
 595         to.tv_sec = ct.tv_sec + env_dmc_wait_time;
 596         to.tv_nsec = 0;
 597         (void) pthread_cond_timedwait(&env_dmc_cond,
 598                 &env_dmc_mutex, &to);
 599         if (env_got_dmc_msg == B_TRUE) {
 600                 (void) pthread_mutex_unlock(&env_dmc_mutex);
 601                 return (NULL);
 602         }
 603         (void) pthread_mutex_unlock(&env_dmc_mutex);
 604 
 605         env_shutdown_system = B_TRUE;
 606         env_reset_cpu = B_FALSE;
 607         (void) initiate_shutdown(B_FALSE);
 608         return (NULL);
 609 }
 610 
 611 /*
 612  * Handle the Latch open event(shutdown the node)
 613  */
 614 picl_errno_t
 615 env_platmod_handle_latch_open()
 616 {
 617         /*
 618          * create a thread to process local event after waiting for DMC CPU
 619          * node state offline message
 620          */
 621         if (pthread_create(&dmc_thr_tid, NULL, &env_wait_for_dmc_msg,
 622                 NULL) != 0) {
 623                 syslog(LOG_ERR, gettext("SUNW_envmond:Error in creating "
 624                         "dmc thread"));
 625                 return (PICL_FAILURE);
 626         }
 627         return (PICL_SUCCESS);
 628 }
 629 
 630 /*
 631  * For Sanibel, hotswap initialization is not reqd.
 632  */
 633 picl_errno_t
 634 env_platmod_setup_hotswap()
 635 {
 636         return (PICL_SUCCESS);
 637 }
 638 
 639 /*
 640  * For sanibel this supoort is not required
 641  */
 642 picl_errno_t
 643 env_platmod_sp_monitor()
 644 {
 645         return (PICL_SUCCESS);
 646 }
 647 
 648 /*
 649  * For sanibel this supoort is not required
 650  */
 651 picl_errno_t
 652 env_platmod_create_hotswap_prop()
 653 {
 654         return (PICL_SUCCESS);
 655 }
 656 
 657 /*
 658  * For sanibel this supoort is not required
 659  */
 660 /*ARGSUSED*/
 661 void
 662 process_platmod_sp_heartbeat(uint8_t data)
 663 {
 664 }
 665 
 666 /*
 667  * For sanibel this supoort is not required
 668  */
 669 /*ARGSUSED*/
 670 int
 671 process_platmod_async_msg_notif(void *resdatap)
 672 {
 673         return (0);
 674 }
 675 
 676 /*
 677  * For sanibel this supoort is not required
 678  */
 679 /*ARGSUSED*/
 680 int
 681 process_platmod_change_cpci_state(void *res_datap)
 682 {
 683         return (0);
 684 }
 685 
 686 /*
 687  * handle request from service processor for shutdown/online
 688  */
 689 int
 690 process_platmod_change_cpu_node_state(void *res_datap)
 691 {
 692         int rc = SMC_SUCCESS;
 693         uint8_t state = BYTE_7(res_datap);
 694         boolean_t force_flag = B_FALSE;
 695 
 696         switch (state & 1) {
 697         case CPU_NODE_STATE_OFFLINE:
 698                 (void) pthread_mutex_lock(&env_dmc_mutex);
 699                 env_got_dmc_msg = B_TRUE;
 700                 (void) pthread_cond_signal(&env_dmc_cond);
 701                 (void) pthread_mutex_unlock(&env_dmc_mutex);
 702                 env_shutdown_system = B_TRUE;
 703                 if ((state >> 2) & 1)
 704                         env_reset_cpu = B_TRUE;
 705                 if (state >> 1 & 1) { /* force flag set? */
 706                         force_flag = B_TRUE;
 707                 } else {
 708                         force_flag = B_FALSE;
 709                 }
 710 
 711                 if (initiate_shutdown(force_flag) == 0) {
 712                         if ((rc = send_response2remote_device(SMC_BMC_ADDR,
 713                                 EVENT_MSG_CHANGE_CPU_NODE_STATE,
 714                                 BYTE_5(res_datap), 0x0)) != SMC_SUCCESS) {
 715                                 return (rc);
 716                         }
 717                 } else {
 718                         if ((rc = send_response2remote_device(SMC_BMC_ADDR,
 719                                 EVENT_MSG_CHANGE_CPU_NODE_STATE,
 720                                 BYTE_5(res_datap), 0xFF)) != SMC_SUCCESS) {
 721                                 return (rc);
 722                         }
 723                         env_shutdown_system = B_FALSE;
 724                         if ((state >> 2) & 1)
 725                                 env_reset_cpu = B_FALSE;
 726                 }
 727                 break;
 728         case CPU_NODE_STATE_ONLINE:
 729                 if ((rc =  send_response2remote_device(SMC_BMC_ADDR,
 730                         EVENT_MSG_CHANGE_CPU_NODE_STATE,
 731                         BYTE_5(res_datap), 0x0)) != SMC_SUCCESS) {
 732                         return (rc);
 733                 }
 734                 break;
 735         default:
 736                 break;
 737         }
 738         return (0);
 739 }
 740 
 741 /*
 742  * Handle change in state of service processor
 743  */
 744 int
 745 process_platmod_sp_state_change_notif(void *res_datap)
 746 {
 747         int rc = SMC_SUCCESS;
 748         uint8_t state = BYTE_7(res_datap);
 749         uint8_t rq_addr = BYTE_4(res_datap);
 750 
 751         if (rq_addr != SMC_BMC_ADDR) {
 752                 return (PICL_FAILURE);
 753         }
 754 
 755         switch (state) {
 756         case CPU_NODE_STATE_ONLINE:
 757                 /* Send ACK to service processor */
 758                 if ((rc = send_response2remote_device(SMC_BMC_ADDR,
 759                         EVENT_MSG_AC_STATE_CHANGE,
 760                         BYTE_5(res_datap), 0x0)) != SMC_SUCCESS) {
 761                         return (rc);
 762                 }
 763                 break;
 764 
 765         case CPU_NODE_STATE_OFFLINE:
 766                 /* Send ACK to service processor */
 767                 if ((rc = send_response2remote_device(SMC_BMC_ADDR,
 768                         EVENT_MSG_AC_STATE_CHANGE,
 769                         BYTE_5(res_datap), 0x0)) != SMC_SUCCESS) {
 770                         return (rc);
 771                 }
 772                 break;
 773 
 774         default:
 775                 if ((rc = send_response2remote_device(SMC_BMC_ADDR,
 776                         EVENT_MSG_AC_STATE_CHANGE,
 777                         BYTE_5(res_datap), 0xFF)) != SMC_SUCCESS) {
 778                         return (rc);
 779                 }
 780                 break;
 781         }
 782         return (0);
 783 }
 784 
 785 /*
 786  * For sanibel this supoort is not required
 787  */
 788 /*ARGSUSED*/
 789 picl_errno_t
 790 env_platmod_handle_bus_if_change(uint8_t data)
 791 {
 792         return (PICL_SUCCESS);
 793 }
 794 
 795 /*
 796  * create the temperature sensor nodes
 797  */
 798 picl_errno_t
 799 env_platmod_create_sensors()
 800 {
 801         picl_errno_t rc = PICL_SUCCESS;
 802 
 803         if (rooth == 0) {
 804                 if ((rc = ptree_get_root(&rooth)) != PICL_SUCCESS) {
 805                         return (rc);
 806                 }
 807         }
 808 
 809         if (platformh == 0) {
 810                 if ((rc = ptree_get_node_by_path(PLATFORM_PATH,
 811                         &platformh)) != PICL_SUCCESS) {
 812                         return (rc);
 813                 }
 814         }
 815 
 816         if (sysmgmth == 0) {
 817                 if ((rc = ptree_get_node_by_path(SYSMGMT_PATH,
 818                         &sysmgmth)) != PICL_SUCCESS) {
 819                         return (rc);
 820                 }
 821         }
 822 
 823         rc = env_create_temp_sensor_node(sysmgmth, CPU_SENSOR_GEO_ADDR);
 824         return (rc);
 825 }
 826 
 827 /*
 828  * handler for sensor event
 829  */
 830 void
 831 env_platmod_handle_sensor_event(void *res_datap)
 832 {
 833         if (BYTE_4(res_datap) != CPU_SENSOR_GEO_ADDR) {
 834                 return;
 835         }
 836         env_handle_sensor_event(res_datap);
 837 }