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 /*
  30  * Routines in this file are used to manage CPU temperature sensor
  31  */
  32 
  33 #include <stdio.h>
  34 #include <unistd.h>
  35 #include <smclib.h>
  36 #include <libintl.h>
  37 #include <syslog.h>
  38 #include <pthread.h>
  39 #include <string.h>
  40 #include <strings.h>
  41 #include <picl.h>
  42 #include <picltree.h>
  43 #include <picldefs.h>
  44 #include <pthread.h>
  45 #include <errno.h>
  46 #include <stropts.h>
  47 #include "piclenvmond.h"
  48 #include "piclsensors.h"
  49 
  50 #define NULLREAD        (int (*)(ptree_rarg_t *, void *))0
  51 #define NULLWRITE       (int (*)(ptree_warg_t *, const void *))0
  52 #define POLL_TIMEOUT    5000
  53 #define BUF_SIZE        50
  54 
  55 /* packet lengths */
  56 #define ENV_GET_THRESHOLD_PKT_LEN       1
  57 #define ENV_SET_THRESHOLD_PKT_LEN       8
  58 #define ENV_READ_SENSOR_PKT_LEN         1
  59 #define ENV_SENSOR_EVENT_ENABLE_PKT_LEN 2
  60 
  61 /* req pkt data */
  62 #define ENV_SENSOR_EVENT_ENABLE_MASK    0x80
  63 
  64 /* ptree wrapper to create property */
  65 extern picl_errno_t env_create_property(int ptype, int pmode,
  66         size_t psize, char *pname, int (*readfn)(ptree_rarg_t *, void *),
  67         int (*writefn)(ptree_warg_t *, const void *),
  68         picl_nodehdl_t nodeh, picl_prophdl_t *propp, void *vbuf);
  69 extern int post_sensor_event(picl_nodehdl_t, char *, uint8_t);
  70 extern int env_open_smc(void);
  71 extern int env_debug;
  72 
  73 /* globals */
  74 int sensor_fd = -1;
  75 picl_nodehdl_t  sensorh = 0;
  76 pthread_t env_temp_thr_tid;
  77 
  78 /* local vars */
  79 static env_temp_sensor_t temp_sensor;
  80 static pthread_mutex_t sensor_mutex = PTHREAD_MUTEX_INITIALIZER;
  81 static pthread_mutex_t env_temp_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
  82 static pthread_cond_t env_temp_monitor_cv = PTHREAD_COND_INITIALIZER;
  83 static env_temp_threshold_t env_curr_state = NORMAL_THRESHOLD;
  84 static char *env_thresholds[] = {
  85         PICL_PROP_LOW_WARNING,
  86         PICL_PROP_LOW_SHUTDOWN,
  87         PICL_PROP_LOW_POWER_OFF,
  88         PICL_PROP_HIGH_WARNING,
  89         PICL_PROP_HIGH_SHUTDOWN,
  90         PICL_PROP_HIGH_POWER_OFF
  91 };
  92 static int cpu_sensor_geo_addr = 0;
  93 
  94 /* local func prototypes */
  95 static void *env_temp_monitor(void *args);
  96 
  97 /*
  98  * Reads the threshold value from hardware
  99  */
 100 static picl_errno_t
 101 env_get_temp_threshold(int sensor_no, int threshold_no,
 102         int8_t *threshold_reading)
 103 {
 104         sc_reqmsg_t req_pkt;
 105         sc_rspmsg_t rsp_pkt;
 106         smc_errno_t rc =  SMC_SUCCESS;
 107         uint8_t size = 0;
 108 
 109         if (threshold_no < 1 || threshold_no > 6) {
 110                 return (PICL_INVALIDARG);
 111         }
 112 
 113         req_pkt.data[0] = sensor_no;
 114         size = ENV_GET_THRESHOLD_PKT_LEN;
 115         /* initialize the request packet */
 116         (void) smc_init_smc_msg(&req_pkt, SMC_SENSOR_THRESHOLD_GET,
 117                 DEFAULT_SEQN, size);
 118 
 119         /* make a call to smc library to send cmd */
 120         if ((rc = smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
 121                 POLL_TIMEOUT)) != SMC_SUCCESS) {
 122                 syslog(LOG_ERR, SMC_GET_SENSOR_THRES_FAILED,
 123                         sensor_no, rc);
 124                 return (PICL_FAILURE);
 125         }
 126 
 127         switch (threshold_no) {
 128         case LOW_WARNING_THRESHOLD:
 129                 if (LOW_WARNING_BIT(rsp_pkt.data[0])) {
 130                         *threshold_reading = rsp_pkt.data[1];
 131                 } else {
 132                         return (PICL_PERMDENIED);
 133                 }
 134                 break;
 135         case LOW_SHUTDOWN_THRESHOLD:
 136                 if (LOW_SHUTDOWN_BIT(rsp_pkt.data[0])) {
 137                         *threshold_reading = rsp_pkt.data[2];
 138                 } else {
 139                         return (PICL_PERMDENIED);
 140                 }
 141                 break;
 142         case LOW_POWEROFF_THRESHOLD:
 143                 if (LOW_POWEROFF_BIT(rsp_pkt.data[0])) {
 144                         *threshold_reading = rsp_pkt.data[3];
 145                 } else {
 146                         return (PICL_PERMDENIED);
 147                 }
 148                 break;
 149         case HIGH_WARNING_THRESHOLD:
 150                 if (HIGH_WARNING_BIT(rsp_pkt.data[0])) {
 151                         *threshold_reading = rsp_pkt.data[4];
 152                 } else {
 153                         return (PICL_PERMDENIED);
 154                 }
 155                 break;
 156         case HIGH_SHUTDOWN_THRESHOLD:
 157                 if (HIGH_SHUTDOWN_BIT(rsp_pkt.data[0])) {
 158                         *threshold_reading = rsp_pkt.data[5];
 159                 } else {
 160                         return (PICL_PERMDENIED);
 161                 }
 162                 break;
 163         case HIGH_POWEROFF_THRESHOLD:
 164                 if (HIGH_POWEROFF_BIT(rsp_pkt.data[0])) {
 165                         *threshold_reading = rsp_pkt.data[6];
 166                 } else {
 167                         return (PICL_PERMDENIED);
 168                 }
 169                 break;
 170         default:
 171                 return (PICL_INVALIDARG);
 172         }
 173         return (PICL_SUCCESS);
 174 }
 175 
 176 /*
 177  * Sets the threshold temperature specified in given sensor number
 178  */
 179 static picl_errno_t
 180 env_set_temp_threshold(int sensor_no, int threshold_no,
 181         int8_t set_value)
 182 {
 183         sc_reqmsg_t req_pkt;
 184         sc_rspmsg_t rsp_pkt;
 185         smc_errno_t rc;
 186         uint8_t size = 0;
 187 
 188         if (threshold_no < 1 || threshold_no > 6) {
 189                 return (PICL_INVALIDARG);
 190         }
 191 
 192         req_pkt.data[0] = (int8_t)sensor_no;
 193         req_pkt.data[1] = 0x01 << (threshold_no - 1);     /* set the bit mask */
 194         req_pkt.data[1 + threshold_no] = set_value;
 195         size = ENV_SET_THRESHOLD_PKT_LEN;
 196 
 197         /* initialize the request packet */
 198         (void) smc_init_smc_msg(&req_pkt, SMC_SENSOR_THRESHOLD_SET,
 199                 DEFAULT_SEQN, size);
 200 
 201         /* make a call to smc library to send cmd */
 202         if ((rc = smc_send_msg(sensor_fd, &req_pkt, &rsp_pkt,
 203                 POLL_TIMEOUT)) != SMC_SUCCESS) {
 204                 syslog(LOG_ERR, SMC_SET_SENSOR_THRES_FAILED,
 205                         sensor_no, rc);
 206                 return (PICL_FAILURE);
 207         }
 208         return (PICL_SUCCESS);
 209 }
 210 
 211 /*
 212  * returns the sensor reading of the SMC sensor specified in sensor_no
 213  */
 214 static picl_errno_t
 215 env_get_sensor_reading(uint8_t sensor_no, int8_t *sensor_reading)
 216 {
 217         sc_reqmsg_t req_pkt;
 218         sc_rspmsg_t rsp_pkt;
 219         smc_errno_t rc =  SMC_SUCCESS;
 220         uint8_t size = 0;
 221 
 222         req_pkt.data[0] = sensor_no;
 223         /* initialize the request packet */
 224         size = ENV_READ_SENSOR_PKT_LEN;
 225         (void) smc_init_smc_msg(&req_pkt, SMC_SENSOR_READING_GET,
 226                 DEFAULT_SEQN, size);
 227 
 228         /* make a call to smc library to send cmd */
 229         if ((rc = smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
 230                 POLL_TIMEOUT)) != SMC_SUCCESS) {
 231                 syslog(LOG_ERR, SMC_GET_SENSOR_READING_FAILED,
 232                         sensor_no, rc);
 233                 return (PICL_FAILURE);
 234         }
 235         *sensor_reading = rsp_pkt.data[0];
 236         return (PICL_SUCCESS);
 237 }
 238 
 239 /*
 240  * volatile call back function to read the current temparature
 241  */
 242 static int
 243 get_curr_temp(ptree_rarg_t *argp, void  *bufp)
 244 {
 245         uint8_t sensor_no;
 246         int8_t  sensor_reading;
 247         picl_errno_t rc;
 248 
 249         if ((rc = ptree_get_propval_by_name(argp->nodeh,
 250                 PICL_PROP_GEO_ADDR, &sensor_no, sizeof (sensor_no))) !=
 251                 PICL_SUCCESS) {
 252                 return (rc);
 253         }
 254 
 255         /* read the temp from SMC f/w */
 256         if ((rc = env_get_sensor_reading(sensor_no, &sensor_reading)) !=
 257                 PICL_SUCCESS) {
 258                 return (rc);
 259         }
 260         *(int8_t *)bufp = sensor_reading;
 261 
 262         /* update the internal cache */
 263         (void) pthread_mutex_lock(&sensor_mutex);
 264         temp_sensor.curr_temp = sensor_reading;
 265         (void) pthread_mutex_unlock(&sensor_mutex);
 266 
 267         return (PICL_SUCCESS);
 268 }
 269 
 270 /*
 271  * volatile function that returns the state of sensor
 272  */
 273 static int
 274 get_sensor_condition(ptree_rarg_t *argp, void *bufp)
 275 {
 276         uint8_t sensor_no;
 277         picl_errno_t rc =  PICL_SUCCESS;
 278         int8_t          sensor_reading;
 279 
 280         if ((rc = ptree_get_propval_by_name(argp->nodeh,
 281                 PICL_PROP_GEO_ADDR, &sensor_no, sizeof (sensor_no))) !=
 282                 PICL_SUCCESS) {
 283                 return (rc);
 284         }
 285 
 286         /* read the curr temp from SMC f/w */
 287         if ((rc = env_get_sensor_reading(sensor_no, &sensor_reading)) !=
 288                 PICL_SUCCESS) {
 289                 (void) pthread_mutex_lock(&sensor_mutex);
 290                 (void) strncpy(temp_sensor.state, PICLEVENTARGVAL_UNKNOWN,
 291                         sizeof (temp_sensor.state));
 292                 (void) strncpy((char *)bufp, PICLEVENTARGVAL_UNKNOWN,
 293                         PICL_PROPNAMELEN_MAX);
 294                 (void) pthread_mutex_unlock(&sensor_mutex);
 295                 return (PICL_SUCCESS);
 296         }
 297 
 298         (void) pthread_mutex_lock(&sensor_mutex);
 299 
 300         if (sensor_reading > temp_sensor.hi_shutdown ||
 301                 sensor_reading < temp_sensor.lo_shutdown)
 302                 (void) strncpy(temp_sensor.state,
 303                         PICLEVENTARGVAL_SENSOR_COND_SHUTDOWN,
 304                         sizeof (temp_sensor.state));
 305         else if (sensor_reading > temp_sensor.hi_warning ||
 306                 sensor_reading < temp_sensor.lo_warning)
 307                 (void) strncpy(temp_sensor.state,
 308                         PICLEVENTARGVAL_SENSOR_COND_WARNING,
 309                         sizeof (temp_sensor.state));
 310         else
 311                 (void) strncpy(temp_sensor.state, PICLEVENTARGVAL_OK,
 312                         sizeof (temp_sensor.state));
 313         (void) strncpy((char *)bufp, temp_sensor.state,
 314                 PICL_PROPNAMELEN_MAX);
 315 
 316         (void) pthread_mutex_unlock(&sensor_mutex);
 317         return (PICL_SUCCESS);
 318 }
 319 
 320 /*
 321  * volatile property to read sensor thresholds
 322  */
 323 static int
 324 get_sensor_thr(ptree_rarg_t *argp, void *bufp)
 325 {
 326         picl_errno_t rc = PICL_SUCCESS;
 327         ptree_propinfo_t pi;
 328         char prop_name[PICL_PROPNAMELEN_MAX];
 329 
 330         if ((rc = ptree_get_propinfo(argp->proph, &pi)) != PICL_SUCCESS) {
 331                 return (rc);
 332         }
 333         (void) strncpy(prop_name, pi.piclinfo.name, sizeof (prop_name));
 334 
 335         (void) pthread_mutex_lock(&sensor_mutex);
 336 
 337         if (strcmp(prop_name, PICL_PROP_LOW_WARNING) == 0) {
 338                 *(int8_t *)bufp = temp_sensor.lo_warning;
 339         } else if (strcmp(prop_name, PICL_PROP_LOW_SHUTDOWN) == 0) {
 340                 *(int8_t *)bufp = temp_sensor.lo_shutdown;
 341         } else if (strcmp(prop_name, PICL_PROP_LOW_POWER_OFF) == 0) {
 342                 *(int8_t *)bufp = temp_sensor.lo_poweroff;
 343         } else if (strcmp(prop_name, PICL_PROP_HIGH_WARNING) == 0) {
 344                 *(int8_t *)bufp = temp_sensor.hi_warning;
 345         } else if (strcmp(prop_name, PICL_PROP_HIGH_SHUTDOWN) == 0) {
 346                 *(int8_t *)bufp = temp_sensor.hi_shutdown;
 347         } else if (strcmp(prop_name, PICL_PROP_HIGH_POWER_OFF) == 0) {
 348                 *(int8_t *)bufp = temp_sensor.hi_poweroff;
 349         } else {
 350                 rc = PICL_INVALIDARG;
 351         }
 352 
 353         (void) pthread_mutex_unlock(&sensor_mutex);
 354         return (rc);
 355 }
 356 
 357 /*
 358  * volatile callback function to set the temp thresholds
 359  */
 360 static int
 361 set_sensor_thr(ptree_warg_t *argp, const void *bufp)
 362 {
 363         picl_errno_t rc = PICL_SUCCESS;
 364         ptree_propinfo_t pi;
 365         int threshold_no = 0;
 366         int8_t  temp = *(int8_t *)bufp;
 367         char    cmd[BUF_SIZE];
 368         char prop_name[PICL_PROPNAMELEN_MAX];
 369 
 370         if ((rc = ptree_get_propinfo(argp->proph, &pi)) != PICL_SUCCESS) {
 371                 return (rc);
 372         }
 373         (void) strncpy(prop_name, pi.piclinfo.name, sizeof (prop_name));
 374         cmd[0] = '\0';
 375 
 376         (void) pthread_mutex_lock(&sensor_mutex);
 377 
 378         if (strcmp(prop_name, PICL_PROP_LOW_WARNING) == 0) {
 379                 /* warning cannot be less than shutdown threshold */
 380                 if (temp <= temp_sensor.lo_shutdown) {
 381                         (void) pthread_mutex_unlock(&sensor_mutex);
 382                         return (PICL_INVALIDARG);
 383                 }
 384                 threshold_no = LOW_WARNING_THRESHOLD;
 385         } else if (strcmp(prop_name, PICL_PROP_LOW_SHUTDOWN) == 0) {
 386                 /* shutdown cannot be greater than warning threshold */
 387                 if (temp >= temp_sensor.lo_warning) {
 388                         (void) pthread_mutex_unlock(&sensor_mutex);
 389                         return (PICL_INVALIDARG);
 390                 }
 391                 threshold_no = LOW_SHUTDOWN_THRESHOLD;
 392         } else if (strcmp(prop_name, PICL_PROP_LOW_POWER_OFF) == 0) {
 393                 (void) pthread_mutex_unlock(&sensor_mutex);
 394                 return (PICL_PERMDENIED);
 395         } else if (strcmp(prop_name, PICL_PROP_HIGH_WARNING) == 0) {
 396                 if ((temp + 5) > temp_sensor.hi_shutdown) {
 397                         (void) pthread_mutex_unlock(&sensor_mutex);
 398                         return (PICL_INVALIDARG);
 399                 }
 400                 /* change the OBP nvram property */
 401                 (void) snprintf(cmd, sizeof (cmd),
 402                         EEPROM_WARNING_CMD, temp);
 403                 threshold_no = HIGH_WARNING_THRESHOLD;
 404         } else if (strcmp(prop_name, PICL_PROP_HIGH_SHUTDOWN) == 0) {
 405                 if ((temp - 5) < temp_sensor.hi_warning) {
 406                         (void) pthread_mutex_unlock(&sensor_mutex);
 407                         return (PICL_INVALIDARG);
 408                 }
 409                 /* change the OBP nvram property */
 410                 (void) snprintf(cmd, sizeof (cmd),
 411                         EEPROM_SHUTDOWN_CMD, temp);
 412                 threshold_no = HIGH_SHUTDOWN_THRESHOLD;
 413         } else if (strcmp(prop_name, PICL_PROP_HIGH_POWER_OFF) == 0) {
 414                 if (temp > MAX_POWEROFF_TEMP ||
 415                         (temp - 5) < temp_sensor.hi_shutdown) {
 416                         (void) pthread_mutex_unlock(&sensor_mutex);
 417                         return (PICL_INVALIDARG);
 418                 }
 419                 /* change the OBP nvram property */
 420                 threshold_no = HIGH_POWEROFF_THRESHOLD;
 421                 (void) snprintf(cmd, sizeof (cmd),
 422                         EEPROM_POWEROFF_CMD, temp);
 423         } else {
 424                 (void) pthread_mutex_unlock(&sensor_mutex);
 425                 return (PICL_INVALIDARG);
 426         }
 427         (void) pthread_mutex_unlock(&sensor_mutex);
 428 
 429         if ((rc = env_set_temp_threshold(cpu_sensor_geo_addr,
 430                 threshold_no, temp)) != PICL_SUCCESS) {
 431                 return (rc);
 432         }
 433 
 434         (void) pthread_mutex_lock(&sensor_mutex);
 435         switch (threshold_no) {
 436         case LOW_WARNING_THRESHOLD:
 437                 temp_sensor.lo_warning = temp;
 438                 break;
 439         case LOW_SHUTDOWN_THRESHOLD:
 440                 temp_sensor.lo_shutdown = temp;
 441                 break;
 442         case LOW_POWEROFF_THRESHOLD:
 443                 temp_sensor.lo_poweroff = temp;
 444                 break;
 445         case HIGH_WARNING_THRESHOLD:
 446                 temp_sensor.hi_warning = temp;
 447                 break;
 448         case HIGH_SHUTDOWN_THRESHOLD:
 449                 temp_sensor.hi_shutdown = temp;
 450                 break;
 451         case HIGH_POWEROFF_THRESHOLD:
 452                 temp_sensor.hi_poweroff = temp;
 453                 break;
 454         }
 455         (void) pthread_mutex_unlock(&sensor_mutex);
 456 
 457         /* execute the cmd to change OBP nvram property */
 458         if (cmd[0]) {
 459                 (void) pclose(popen(cmd, "w"));
 460         }
 461         return (PICL_SUCCESS);
 462 }
 463 
 464 /*
 465  * this routine reads the hardware state and initialises the internal
 466  * cache for temperature thresholds
 467  */
 468 static picl_errno_t
 469 env_init_temp_sensor_values(int sensor_no, env_temp_sensor_t *sensor)
 470 {
 471         if (env_get_sensor_reading(sensor_no, &sensor->curr_temp) !=
 472                 PICL_SUCCESS) {
 473                 return (PICL_FAILURE);
 474         }
 475 
 476         if (env_get_temp_threshold(sensor_no, LOW_WARNING_THRESHOLD,
 477                 &sensor->lo_warning) != PICL_SUCCESS) {
 478                 syslog(LOG_ERR, SMC_GET_LWT_FAILED);
 479                 return (PICL_FAILURE);
 480         }
 481 
 482         if (env_get_temp_threshold(sensor_no, LOW_SHUTDOWN_THRESHOLD,
 483                 &sensor->lo_shutdown) != PICL_SUCCESS) {
 484                 syslog(LOG_ERR, SMC_GET_LST_FAILED);
 485                 return (PICL_FAILURE);
 486         }
 487 
 488         if (env_get_temp_threshold(sensor_no, LOW_POWEROFF_THRESHOLD,
 489                 &sensor->lo_poweroff) != PICL_SUCCESS) {
 490                 syslog(LOG_ERR, SMC_GET_LPT_FAILED);
 491                 return (PICL_FAILURE);
 492         }
 493 
 494         if (env_get_temp_threshold(sensor_no, HIGH_WARNING_THRESHOLD,
 495                 &sensor->hi_warning) != PICL_SUCCESS) {
 496                 syslog(LOG_ERR, SMC_SET_LWT_FAILED);
 497                 return (PICL_FAILURE);
 498         }
 499 
 500         if (env_get_temp_threshold(sensor_no, HIGH_SHUTDOWN_THRESHOLD,
 501                 &sensor->hi_shutdown) != PICL_SUCCESS) {
 502                 syslog(LOG_ERR, SMC_SET_LST_FAILED);
 503                 return (PICL_FAILURE);
 504         }
 505 
 506         if (env_get_temp_threshold(sensor_no, HIGH_POWEROFF_THRESHOLD,
 507                 &sensor->hi_poweroff) != PICL_SUCCESS) {
 508                 syslog(LOG_ERR, SMC_SET_LPT_FAILED);
 509                 return (PICL_FAILURE);
 510         }
 511 
 512         if (sensor->curr_temp > sensor->hi_shutdown ||
 513                 sensor->curr_temp < sensor->lo_shutdown) {
 514                 (void) strncpy(sensor->state,
 515                         PICLEVENTARGVAL_SENSOR_COND_SHUTDOWN,
 516                         sizeof (sensor->state));
 517         } else if (sensor->curr_temp > sensor->hi_warning ||
 518                 sensor->curr_temp < sensor->lo_warning) {
 519                 (void) strncpy(sensor->state,
 520                         PICLEVENTARGVAL_SENSOR_COND_WARNING,
 521                         sizeof (sensor->state));
 522         } else {
 523                 (void) strncpy(sensor->state, PICLEVENTARGVAL_OK,
 524                         sizeof (sensor->state));
 525         }
 526         return (PICL_SUCCESS);
 527 }
 528 
 529 /*
 530  * sensor_event_enable_set: enables or disables Event Message generation
 531  * from a sensor specified by sensor_no
 532  */
 533 static int
 534 sensor_event_enable_set(uint8_t sensor_no, boolean_t enable)
 535 {
 536         smc_errno_t rc = SMC_SUCCESS;
 537         sc_reqmsg_t req_pkt;
 538         sc_rspmsg_t rsp_pkt;
 539         uint8_t size = 0;
 540 
 541         req_pkt.data[0] = sensor_no;
 542         req_pkt.data[1] = 0;
 543         if (enable) {
 544                 req_pkt.data[1] |= ENV_SENSOR_EVENT_ENABLE_MASK;
 545         }
 546         size = ENV_SENSOR_EVENT_ENABLE_PKT_LEN;
 547 
 548         (void) smc_init_smc_msg(&req_pkt, SMC_SENSOR_EVENT_ENABLE_SET,
 549                 DEFAULT_SEQN, size);
 550 
 551         /* make a call to smc library to send cmd */
 552         if ((rc = smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
 553                 POLL_TIMEOUT)) != SMC_SUCCESS) {
 554                 syslog(LOG_ERR, SMC_ENABLE_SENSOR_EVENT_FAILED, rc);
 555                 return (PICL_FAILURE);
 556         }
 557         return (PICL_SUCCESS);
 558 }
 559 
 560 /*
 561  * creates temperature sensor node and all of its properties
 562  */
 563 picl_errno_t
 564 env_create_temp_sensor_node(picl_nodehdl_t parenth, uint8_t sensor_no)
 565 {
 566         int i = 0;
 567         picl_errno_t rc = PICL_SUCCESS;
 568         int8_t  sensor_reading = 0;
 569         struct strioctl strio;
 570         sc_cmdspec_t    set;
 571 
 572         sensor_fd = env_open_smc();
 573         if (sensor_fd < 0) {
 574                 syslog(LOG_ERR, gettext("SUNW_envmond:Error in "
 575                         "opening SMC(failed to create sensor nodes)"));
 576                 return (PICL_FAILURE);
 577         }
 578 
 579         /* grab exclusive access to set the thresholds */
 580         set.args[0]     = SMC_SENSOR_THRESHOLD_SET;
 581         set.attribute   = SC_ATTR_EXCLUSIVE;
 582         strio.ic_cmd    = SCIOC_MSG_SPEC;
 583         strio.ic_timout = 0;
 584         strio.ic_len    = 2;
 585         strio.ic_dp     = (char *)&set;
 586         if (ioctl(sensor_fd, I_STR, &strio) < 0) {
 587                 syslog(LOG_ERR, SMC_GET_EXCLUSIVE_ERR);
 588                 (void) close(sensor_fd);
 589                 return (PICL_FAILURE);
 590         }
 591 
 592         cpu_sensor_geo_addr = sensor_no;
 593         /* create temperature sensor node */
 594         if ((rc = ptree_create_and_add_node(parenth, CPU_SENSOR,
 595                 PICL_CLASS_TEMPERATURE_SENSOR, &sensorh)) !=
 596                 PICL_SUCCESS) {
 597                 (void) close(sensor_fd);
 598                 return (rc);
 599         }
 600 
 601         /* create Label prop. */
 602         if ((rc = env_create_property(PICL_PTYPE_CHARSTRING, PICL_READ,
 603                 PICL_PROPNAMELEN_MAX, PICL_PROP_LABEL, NULLREAD,
 604                 NULLWRITE, sensorh, (picl_prophdl_t *)NULL,
 605                 (char *)PICL_PROPVAL_LABEL_AMBIENT)) != PICL_SUCCESS) {
 606                 (void) ptree_delete_node(sensorh);
 607                 (void) ptree_destroy_node(sensorh);
 608                 (void) close(sensor_fd);
 609                 return (rc);
 610         }
 611 
 612         /* create the geo-addr property */
 613         if ((rc = env_create_property(PICL_PTYPE_UNSIGNED_INT,
 614                 PICL_READ, sizeof (sensor_no), PICL_PROP_GEO_ADDR,
 615                 NULLREAD, NULLWRITE, sensorh, (picl_prophdl_t *)NULL,
 616                 &sensor_no)) != PICL_SUCCESS) {
 617                 (void) ptree_delete_node(sensorh);
 618                 (void) ptree_destroy_node(sensorh);
 619                 (void) close(sensor_fd);
 620                 return (rc);
 621         }
 622 
 623         /* read the current temp from hardware */
 624         if (env_get_sensor_reading(sensor_no, &sensor_reading) !=
 625                 PICL_SUCCESS) {
 626                 (void) ptree_delete_node(sensorh);
 627                 (void) ptree_destroy_node(sensorh);
 628                 (void) close(sensor_fd);
 629                 return (PICL_FAILURE);
 630         }
 631 
 632         /* create temperature prop. */
 633         if ((rc = env_create_property(PICL_PTYPE_INT,
 634                 PICL_READ + PICL_VOLATILE, sizeof (sensor_reading),
 635                 PICL_PROP_TEMPERATURE, get_curr_temp,
 636                 NULLWRITE, sensorh, (picl_prophdl_t *)NULL,
 637                 &sensor_reading)) != PICL_SUCCESS) {
 638                 (void) ptree_delete_node(sensorh);
 639                 (void) ptree_destroy_node(sensorh);
 640                 (void) close(sensor_fd);
 641                 return (rc);
 642         }
 643 
 644         /* create the threshold properties */
 645         for (i = 0; i < NUM_OF_THRESHOLDS; i++) {
 646                 if ((rc = env_create_property(PICL_PTYPE_INT,
 647                         PICL_READ + PICL_WRITE + PICL_VOLATILE,
 648                         sizeof (uint8_t), env_thresholds[i],
 649                         get_sensor_thr, set_sensor_thr,
 650                         sensorh, (picl_prophdl_t *)NULL,
 651                         (void *)NULL)) != PICL_SUCCESS) {
 652                         (void) ptree_delete_node(sensorh);
 653                         (void) ptree_destroy_node(sensorh);
 654                         (void) close(sensor_fd);
 655                         return (rc);
 656                 }
 657         }
 658 
 659         /* intialise the internal cache */
 660         if (env_init_temp_sensor_values(cpu_sensor_geo_addr,
 661                 &temp_sensor) != PICL_SUCCESS) {
 662                 (void) ptree_delete_node(sensorh);
 663                 (void) ptree_destroy_node(sensorh);
 664                 (void) close(sensor_fd);
 665                 return (PICL_FAILURE);
 666         }
 667 
 668         /* create STATE prop. */
 669         if ((rc = env_create_property(PICL_PTYPE_CHARSTRING,
 670                 PICL_READ + PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
 671                 PICL_PROP_CONDITION, get_sensor_condition, NULLWRITE,
 672                 sensorh, (picl_prophdl_t *)NULL,
 673                 temp_sensor.state)) != PICL_SUCCESS) {
 674                 (void) ptree_delete_node(sensorh);
 675                 (void) ptree_destroy_node(sensorh);
 676                 (void) close(sensor_fd);
 677                 return (rc);
 678         }
 679 
 680         /* start temperature monitoring thread */
 681         if (pthread_create(&env_temp_thr_tid, NULL,
 682                 &env_temp_monitor, NULL) != 0) {
 683                 syslog(LOG_ERR, gettext("SUNW_envmond:Error in "
 684                         "creating temperature monitor thread"));
 685         }
 686 
 687         /* enable sensor-event */
 688         (void) sensor_event_enable_set(sensor_no, B_TRUE);
 689         return (PICL_SUCCESS);
 690 }
 691 
 692 /*
 693  * handles the sensor events (post corresponding Condition picl event)
 694  */
 695 void
 696 env_handle_sensor_event(void *res_datap)
 697 {
 698         uint8_t offset;
 699         char sensor_cond[BUF_SIZE];
 700 
 701         if (BYTE_4(res_datap) != cpu_sensor_geo_addr) {
 702                 return;
 703         }
 704 
 705         if (BYTE_5(res_datap) != THRESHOLD_TYPE) {
 706                 return;
 707         }
 708 
 709         if (env_debug & DEBUG) {
 710                 syslog(LOG_INFO, "Temperature = %d\n", BYTE_7(res_datap));
 711                 syslog(LOG_INFO,
 712                         "Threshold changed to %d\n", BYTE_8(res_datap));
 713         }
 714 
 715         /* Threshold event */
 716         offset = BYTE_6(res_datap) & 0x0F;  /* first 4 bits */
 717         switch (offset) {
 718         case 0:
 719                 (void) pthread_mutex_lock(&env_temp_monitor_mutex);
 720                 if (env_curr_state == LOW_WARNING_THRESHOLD) {
 721                         (void) pthread_cond_signal(&env_temp_monitor_cv);
 722                         (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 723                         return;
 724                 }
 725                 env_curr_state = LOW_WARNING_THRESHOLD;
 726                 (void) pthread_cond_signal(&env_temp_monitor_cv);
 727                 (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 728                 (void) strncpy(sensor_cond,
 729                         PICLEVENTARGVAL_SENSOR_COND_WARNING,
 730                         sizeof (sensor_cond));
 731                 syslog(LOG_CRIT, gettext("SUNW_envmond:current temperature (%d)"
 732                         " is below lower warning temperature (%d).\n"),
 733                                 BYTE_7(res_datap), BYTE_8(res_datap));
 734                 break;
 735         case 2:
 736                 (void) pthread_mutex_lock(&env_temp_monitor_mutex);
 737                 if (env_curr_state == LOW_SHUTDOWN_THRESHOLD) {
 738                         (void) pthread_cond_signal(&env_temp_monitor_cv);
 739                         (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 740                         return;
 741                 }
 742                 env_curr_state = LOW_SHUTDOWN_THRESHOLD;
 743                 (void) pthread_cond_signal(&env_temp_monitor_cv);
 744                 (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 745                 (void) strncpy(sensor_cond,
 746                         PICLEVENTARGVAL_SENSOR_COND_SHUTDOWN,
 747                         sizeof (sensor_cond));
 748                 syslog(LOG_CRIT, gettext("SUNW_envmond:current temperature (%d)"
 749                         " is below lower critical temperature (%d).\n"),
 750                                 BYTE_7(res_datap), BYTE_8(res_datap));
 751                 break;
 752         case 7:
 753                 (void) pthread_mutex_lock(&env_temp_monitor_mutex);
 754                 if (env_curr_state == HIGH_WARNING_THRESHOLD) {
 755                         (void) pthread_cond_signal(&env_temp_monitor_cv);
 756                         (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 757                         return;
 758                 }
 759                 env_curr_state = HIGH_WARNING_THRESHOLD;
 760                 (void) pthread_cond_signal(&env_temp_monitor_cv);
 761                 (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 762                 (void) strncpy(sensor_cond,
 763                         PICLEVENTARGVAL_SENSOR_COND_WARNING,
 764                         sizeof (sensor_cond));
 765                 syslog(LOG_CRIT, gettext("SUNW_envmond:current temperature (%d)"
 766                         " exceeds upper warning temperature (%d).\n"),
 767                                 BYTE_7(res_datap), BYTE_8(res_datap));
 768                 break;
 769         case 9:
 770                 (void) pthread_mutex_lock(&env_temp_monitor_mutex);
 771                 if (env_curr_state == HIGH_SHUTDOWN_THRESHOLD) {
 772                         (void) pthread_cond_signal(&env_temp_monitor_cv);
 773                         (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 774                         return;
 775                 }
 776                 env_curr_state = HIGH_SHUTDOWN_THRESHOLD;
 777                 (void) pthread_cond_signal(&env_temp_monitor_cv);
 778                 (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 779                 (void) strncpy(sensor_cond,
 780                         PICLEVENTARGVAL_SENSOR_COND_SHUTDOWN,
 781                         sizeof (sensor_cond));
 782                 syslog(LOG_CRIT, gettext("SUNW_envmond:current temperature (%d)"
 783                         " exceeds upper critical temperature (%d).\n"),
 784                                 BYTE_7(res_datap), BYTE_8(res_datap));
 785                 break;
 786         default:
 787                 (void) strncpy(sensor_cond, PICLEVENTARGVAL_UNKNOWN,
 788                         sizeof (sensor_cond));
 789                 break;
 790         }
 791 
 792         if (post_sensor_event(sensorh, sensor_cond, NO_COND_TIMEDWAIT)
 793                 != PICL_SUCCESS) {
 794                 syslog(LOG_ERR, gettext("SUNW_envmond:Error in posting "
 795                         "%s event"), PICLEVENT_CONDITION_CHANGE);
 796         }
 797 }
 798 
 799 /*
 800  * this thread monitors the temperature when the current temperature
 801  * raises above high warning threshold
 802  */
 803 /*ARGSUSED*/
 804 static void *
 805 env_temp_monitor(void *args)
 806 {
 807         int ret;
 808         timespec_t to;
 809         int8_t sensor_reading;
 810         char sensor_cond[BUF_SIZE];
 811 
 812         (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 813         (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 814 
 815         for (;;) {
 816                 (void) pthread_mutex_lock(&env_temp_monitor_mutex);
 817                 if (env_curr_state == NORMAL_THRESHOLD) {
 818                         pthread_cond_wait(&env_temp_monitor_cv,
 819                                 &env_temp_monitor_mutex);
 820                 }
 821 
 822                 /* check until temp drops below warning threshold */
 823                 to.tv_sec = ENV_TEMP_MONITOR_TIME;
 824                 to.tv_nsec = 0;
 825                 ret = pthread_cond_reltimedwait_np(&env_temp_monitor_cv,
 826                         &env_temp_monitor_mutex, &to);
 827                 if (ret != ETIMEDOUT) {
 828                         (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 829                         continue;
 830                 }
 831 
 832                 /* read the present temperature */
 833                 if (env_get_sensor_reading(cpu_sensor_geo_addr,
 834                         &sensor_reading) != PICL_SUCCESS) {
 835                         (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 836                         continue;
 837                 }
 838 
 839                 (void) pthread_mutex_lock(&sensor_mutex);
 840                 if (sensor_reading < temp_sensor.hi_warning &&
 841                         sensor_reading > temp_sensor.lo_warning) {
 842                         /* temperature is ok now */
 843                         (void) strncpy(sensor_cond, PICLEVENTARGVAL_OK,
 844                                 sizeof (sensor_cond));
 845                         env_curr_state = NORMAL_THRESHOLD;
 846                 }
 847                 (void) pthread_mutex_unlock(&sensor_mutex);
 848 
 849                 if (env_curr_state == NORMAL_THRESHOLD) {
 850                         syslog(LOG_NOTICE, gettext("SUNW_envmond:Current "
 851                                 "temperature is ok now"));
 852                         if (post_sensor_event(sensorh, sensor_cond,
 853                                 NO_COND_TIMEDWAIT) != PICL_SUCCESS) {
 854                                 syslog(LOG_ERR, gettext("SUNW_envmond:Error in"
 855                                         " posting %s event"),
 856                                                 PICLEVENT_CONDITION_CHANGE);
 857                         }
 858                 }
 859                 (void) pthread_mutex_unlock(&env_temp_monitor_mutex);
 860         }
 861         /*NOTREACHED*/
 862         return (NULL);
 863 }