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 }