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
env_get_temp_threshold(int sensor_no,int threshold_no,int8_t * threshold_reading)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
env_set_temp_threshold(int sensor_no,int threshold_no,int8_t set_value)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
env_get_sensor_reading(uint8_t sensor_no,int8_t * sensor_reading)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
get_curr_temp(ptree_rarg_t * argp,void * bufp)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
get_sensor_condition(ptree_rarg_t * argp,void * bufp)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
get_sensor_thr(ptree_rarg_t * argp,void * bufp)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
set_sensor_thr(ptree_warg_t * argp,const void * bufp)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
env_init_temp_sensor_values(int sensor_no,env_temp_sensor_t * sensor)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
sensor_event_enable_set(uint8_t sensor_no,boolean_t enable)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
env_create_temp_sensor_node(picl_nodehdl_t parenth,uint8_t sensor_no)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
env_handle_sensor_event(void * res_datap)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 *
env_temp_monitor(void * args)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 }
864