xref: /titanic_44/usr/src/cmd/picl/plugins/sun4u/snowbird/envmond/piclsensors.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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