xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/taco/envd/piclenvd.c (revision d583b39bfb4e2571d3e41097c5c357ffe353ad45)
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 2003 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  * This file contains the environmental PICL plug-in module.
31  */
32 
33 /*
34  * This plugin sets up the PICLTREE for Taco.
35  * It provides functionality to get/set temperatures
36  * and fan speeds
37  *
38  * The environmental monitoring policy is the default
39  * auto mode as programmed by OBP at boot time.
40  */
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <sys/sysmacros.h>
45 #include <limits.h>
46 #include <string.h>
47 #include <stdarg.h>
48 #include <alloca.h>
49 #include <unistd.h>
50 #include <sys/processor.h>
51 #include <syslog.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <picl.h>
55 #include <picltree.h>
56 #include <picldefs.h>
57 #include <pthread.h>
58 #include <signal.h>
59 #include <libdevinfo.h>
60 #include <sys/pm.h>
61 #include <sys/open.h>
62 #include <sys/time.h>
63 #include <sys/utsname.h>
64 #include <sys/systeminfo.h>
65 #include <note.h>
66 #include <sys/i2c/clients/i2c_client.h>
67 #include <sys/i2c/clients/adm1031.h>
68 #include "envd.h"
69 
70 /*
71  * PICL plguin entry points
72  */
73 static void piclenvd_register(void);
74 static void piclenvd_init(void);
75 static void piclenvd_fini(void);
76 
77 /*
78  * Env setup routines
79  */
80 extern void env_picl_setup(void);
81 extern void env_picl_destroy(void);
82 extern int env_picl_setup_tuneables(void);
83 
84 /*
85  * Sleep routine used for polling
86  */
87 static uint_t envd_sleep(uint_t);
88 
89 #pragma	init(piclenvd_register)
90 
91 /*
92  * Plugin registration information
93  */
94 static picld_plugin_reg_t my_reg_info = {
95 	PICLD_PLUGIN_VERSION,
96 	PICLD_PLUGIN_CRITICAL,
97 	"SUNW_piclenvd",
98 	piclenvd_init,
99 	piclenvd_fini,
100 };
101 
102 /*
103  * ES Segment data structures
104  */
105 static sensor_ctrl_blk_t	sensor_ctrl[MAX_SENSORS];
106 static fan_ctrl_blk_t		fan_ctrl[MAX_FANS];
107 static fruenvseg_t		*envfru = NULL;
108 
109 /*
110  * Env thread variables
111  */
112 static boolean_t  system_shutdown_started = B_FALSE;
113 static boolean_t  ovtemp_thr_created = B_FALSE;
114 static pthread_t  ovtemp_thr_id;
115 static pthread_attr_t thr_attr;
116 
117 
118 /*
119  * PM thread related variabled
120  */
121 static pthread_t	pmthr_tid;	/* pmthr thread ID */
122 static int		pm_fd = -1;	/* PM device file descriptor */
123 static boolean_t	pmthr_created = B_FALSE;
124 static int		cur_lpstate;	/* cur low power state */
125 
126 /*
127  * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var
128  * Setting the verbose tuneable also enables debugging for better
129  * control
130  */
131 int	env_debug = 0;
132 
133 /*
134  * Fan devices
135  */
136 static env_fan_t envd_sys_out_fan = {
137 	ENV_SYSTEM_OUT_FAN, ENV_SYSTEM_FAN_DEVFS, NULL,
138 	SYSTEM_FAN_ID, SYSTEM_OUT_FAN_SPEED_MIN,
139 	SYSTEM_OUT_FAN_SPEED_MAX, -1, -1,
140 };
141 
142 static env_fan_t envd_sys_in_fan = {
143 	ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_FAN_DEVFS, NULL,
144 	SYSTEM_FAN_ID, SYSTEM_INTAKE_FAN_SPEED_MIN,
145 	SYSTEM_INTAKE_FAN_SPEED_MAX, -1, -1,
146 };
147 
148 static env_fan_t envd_cpu_fan = {
149 	ENV_CPU_FAN, ENV_CPU_FAN_DEVFS, NULL,
150 	CPU_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1,
151 };
152 
153 /*
154  * NULL terminated array of fans
155  */
156 static env_fan_t *envd_fans[] = {
157 	&envd_cpu_fan,
158 	&envd_sys_in_fan,
159 	&envd_sys_out_fan,
160 	NULL
161 };
162 
163 /*
164  * ADM1031 speedrange map is indexed by a 2-bit value
165  */
166 static int	adm_speedrange_map[] = {1, 2, 4, 8};
167 
168 /*
169  * ADM1031 devices
170  */
171 static char	*hwm_devs[] = {
172 	CPU_HWM_DEVFS,	/* CPU_HWM_ID */
173 };
174 
175 /*
176  * Fan names associated with each ADM1031 hwms - used to
177  * print fault messages
178  */
179 static char	*hwm_fans[MAX_HWMS][2] = {
180 	{ENV_CPU_FAN, ENV_SYSTEM_IN_OUT_FANS}
181 };
182 
183 /*
184  * Temperature sensors
185  */
186 static env_sensor_t envd_sensors[] = {
187 	{ SENSOR_CPU_DIE, SENSOR_CPU_DIE_DEVFS, NULL,
188 	    CPU_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu_fan, -1},
189 	{ SENSOR_INT_AMB, SENSOR_INT_AMB_DEVFS, NULL,
190 	    INT_AMB_SENSOR_ID, CPU_HWM_ID, NULL, -1},
191 	{ SENSOR_SYS_IN, SENSOR_SYS_IN_DEVFS, NULL,
192 	    SYS_IN_SENSOR_ID, CPU_HWM_ID, (void *)&envd_sys_in_fan, -1},
193 };
194 #define	N_ENVD_SENSORS	(sizeof (envd_sensors)/sizeof (envd_sensors[0]))
195 
196 /*
197  * ADM1031 macros
198  */
199 #define	TACH_UNKNOWN	255
200 #define	FAN_OUT_OF_RANGE	(TACH_UNKNOWN)
201 #define	ADM_HYSTERISIS	5
202 #define	N_SEQ_TACH	15
203 
204 #define	TMIN_MASK	(0xF8)
205 #define	TMIN_SHIFT	(3)
206 #define	TMIN_UNITS	(4)	/* increments of 4 degrees celsius */
207 #define	TRANGE_MASK	(0x7)
208 
209 #define	TMIN(regval)	(((regval & TMIN_MASK) >> TMIN_SHIFT) * TMIN_UNITS)
210 #define	TRANGE(regval)	(regval & TRANGE_MASK)
211 
212 #define	GET_TMIN_RANGE(tmin, trange) \
213 	((((tmin / TMIN_UNITS) & TMIN_MASK) << TMIN_SHIFT) | \
214 	(trange & TRANGE_MASK))
215 
216 #define	TACH_ENABLE_MASK		(0x0C)
217 #define	MONITOR_ENABLE_MASK		(0x01)
218 #define	ADM_SETFANSPEED_CONV(speed)	(15 * speed / 100)
219 
220 /*
221  * Tuneables
222  */
223 #define	ENABLE	1
224 #define	DISABLE	0
225 
226 static int get_monitor_mode(ptree_rarg_t *parg, void *buf);
227 static int set_monitor_mode(ptree_warg_t *parg, const void *buf);
228 static int get_int_val(ptree_rarg_t *parg, void *buf);
229 static int set_int_val(ptree_warg_t *parg, const void *buf);
230 static int get_string_val(ptree_rarg_t *parg, void *buf);
231 static int set_string_val(ptree_warg_t *parg, const void *buf);
232 static int get_tach(ptree_rarg_t *parg, void *buf);
233 static int set_tach(ptree_warg_t *parg, const void *buf);
234 
235 static int	shutdown_override = 0;
236 static int 	sensor_poll_interval	= SENSORPOLL_INTERVAL;
237 static int	warning_interval	= WARNING_INTERVAL;
238 static int 	shutdown_interval	= SHUTDOWN_INTERVAL;
239 static int	ovtemp_monitor		= 1;	/* enabled */
240 static int	pm_monitor		= 1;	/* enabled */
241 static int	mon_fanstat		= 1;	/* enabled */
242 
243 static int 	hwm_mode;
244 static int 	hwm_tach_enable;
245 static char	shutdown_cmd[] = SHUTDOWN_CMD;
246 
247 env_tuneable_t tuneables[] = {
248 	{"ovtemp-monitor", PICL_PTYPE_INT, &ovtemp_monitor,
249 	    &get_int_val, &set_int_val, sizeof (int)},
250 
251 	{"pm-monitor", PICL_PTYPE_INT, &pm_monitor,
252 	    &get_int_val, &set_int_val, sizeof (int)},
253 
254 	{"shutdown-override", PICL_PTYPE_INT, &shutdown_override,
255 	    &get_int_val, &set_int_val, sizeof (int)},
256 
257 	{"hwm-automode-enable", PICL_PTYPE_INT, &hwm_mode,
258 	    &get_monitor_mode, &set_monitor_mode, sizeof (int)},
259 
260 	{"sensor-poll-interval", PICL_PTYPE_INT,
261 	    &sensor_poll_interval,
262 	    &get_int_val, &set_int_val,
263 	    sizeof (int)},
264 
265 	{"warning-interval", PICL_PTYPE_INT, &warning_interval,
266 	    &get_int_val, &set_int_val,
267 	    sizeof (int)},
268 
269 	{"shutdown-interval", PICL_PTYPE_INT, &shutdown_interval,
270 	    &get_int_val, &set_int_val,
271 	    sizeof (int)},
272 
273 	{"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd,
274 	    &get_string_val, &set_string_val,
275 	    sizeof (shutdown_cmd)},
276 
277 	{"tach-enable", PICL_PTYPE_INT, &hwm_tach_enable,
278 	    &get_tach, &set_tach,
279 	    sizeof (int)},
280 
281 	{"monitor-fanstat", PICL_PTYPE_INT, &mon_fanstat,
282 	    &get_int_val, &set_int_val, sizeof (int)},
283 
284 	{"verbose", PICL_PTYPE_INT, &env_debug,
285 	    &get_int_val, &set_int_val, sizeof (int)},
286 
287 };
288 
289 /*
290  * We use this to figure out how many tuneables there are
291  * This is variable because the publishing routine needs this info
292  * in piclenvsetup.c
293  */
294 int	ntuneables = (sizeof (tuneables)/sizeof (tuneables[0]));
295 
296 /*
297  * Table Handling Code
298  */
299 static void
300 fini_table(table_t *tblp)
301 {
302 	if (tblp == NULL)
303 		return;
304 	free(tblp->xymap);
305 	free(tblp);
306 }
307 
308 static table_t *
309 init_table(int npoints)
310 {
311 	table_t		*tblp;
312 	point_t		*xy;
313 
314 	if (npoints == 0)
315 		return (NULL);
316 
317 	if ((tblp = malloc(sizeof (*tblp))) == NULL)
318 		return (NULL);
319 
320 	if ((xy = malloc(sizeof (*xy) * npoints)) == NULL) {
321 		free(tblp);
322 		return (NULL);
323 	}
324 
325 	tblp->nentries = npoints;
326 	tblp->xymap = xy;
327 
328 	return (tblp);
329 }
330 
331 /*
332  * function: calculates y for a given x based on a table of points
333  * for monotonically increasing x values.
334  * 'tbl' specifies the table to use, 'val' specifies the 'x', returns 'y'
335  */
336 static int
337 y_of_x(table_t *tbl, int xval)
338 {
339 	int		i;
340 	int		entries;
341 	point_t		*xymap;
342 	float		newval;
343 	float		dy, dx, slope;
344 
345 	entries = tbl->nentries;
346 	xymap = tbl->xymap;
347 	if (xval <= xymap[0].x)
348 		return (xymap[0].y);
349 	else if (xval >= xymap[entries - 1].x)
350 		return (xymap[entries - 1].y);
351 
352 	for (i = 1; i < entries - 1; i++) {
353 		if (xval == xymap[i].x)
354 			return (xymap[i].y);
355 		if (xval < xymap[i].x)
356 			break;
357 	}
358 
359 	/*
360 	 * Use linear interpolation
361 	 */
362 	dy = (float)(xymap[i].y - xymap[i-1].y);
363 	dx = (float)(xymap[i].x - xymap[i-1].x);
364 	slope = dy/dx;
365 	newval = xymap[i - 1].y + slope * (xval - xymap[i - 1].x);
366 	return ((int)(newval + (newval >= 0 ? 0.5 : -0.5)));
367 }
368 
369 /*
370  * Get environmental segment from the specified FRU SEEPROM
371  */
372 static int
373 get_envseg(int fd, void **envsegp, int *envseglenp)
374 {
375 	int			i, segcnt, envseglen;
376 	section_layout_t	section;
377 	segment_layout_t	segment;
378 	uint8_t			*envseg;
379 
380 	if (lseek(fd, (long)SECTION_HDR_OFFSET, 0) == -1L ||
381 	    read(fd, &section, sizeof (section)) != sizeof (section)) {
382 		return (EINVAL);
383 	}
384 
385 	/*
386 	 * Verify we have the correct section and contents are valid
387 	 * For now, we don't verify the CRC.
388 	 */
389 	if (section.header_tag != SECTION_HDR_TAG ||
390 	    GET_UNALIGN16(&section.header_version[0]) != SECTION_HDR_VER) {
391 		if (env_debug)
392 			envd_log(LOG_INFO,
393 			    "Invalid section header tag:%x  version:%x\n",
394 			    section.header_tag,
395 			    GET_UNALIGN16(&section.header_version));
396 		return (EINVAL);
397 	}
398 
399 	/*
400 	 * Locate our environmental segment
401 	 */
402 	segcnt = section.segment_count;
403 	for (i = 0; i < segcnt; i++) {
404 		if (read(fd, &segment, sizeof (segment)) != sizeof (segment)) {
405 			return (EINVAL);
406 		}
407 		if (env_debug)
408 			envd_log(LOG_INFO,
409 			    "Seg name: %x  desc:%x off:%x  len:%x\n",
410 			    GET_UNALIGN16(&segment.name),
411 			    GET_UNALIGN32(&segment.descriptor[0]),
412 			    GET_UNALIGN16(&segment.offset),
413 			    GET_UNALIGN16(&segment.length));
414 		if (GET_UNALIGN16(&segment.name) == ENVSEG_NAME)
415 			break;
416 	}
417 
418 	if (i >= segcnt) {
419 		return (ENOENT);
420 	}
421 
422 	/*
423 	 * Allocate memory to hold the environmental segment data.
424 	 */
425 	envseglen = GET_UNALIGN16(&segment.length);
426 	if ((envseg = malloc(envseglen)) == NULL) {
427 		return (ENOMEM);
428 	}
429 
430 	if (lseek(fd, (long)GET_UNALIGN16(&segment.offset), 0) == -1L ||
431 	    read(fd, envseg, envseglen) != envseglen) {
432 		(void) free(envseg);
433 		return (EIO);
434 	}
435 	*envsegp = envseg;
436 	*envseglenp = envseglen;
437 	return (0);
438 }
439 
440 /*
441  * Get all environmental segments
442  */
443 static fruenvseg_t *
444 get_fru_envsegs(void)
445 {
446 	fruenvseg_t		*fruenvsegs;
447 	envseg_layout_t		*envsegp;
448 	void			*envsegbufp;
449 	int			fd, envseglen, hdrlen;
450 	char			path[PATH_MAX];
451 
452 	fruenvsegs = NULL;
453 	fruenvsegs = malloc(sizeof (*fruenvsegs));
454 	if (fruenvsegs == NULL) {
455 		return (NULL);
456 	}
457 
458 	/*
459 	 * Now get the environmental segment from this FRU
460 	 */
461 	(void) snprintf(path, sizeof (path), "%s%s", I2C_DEVFS, MBFRU_DEV);
462 	fd = open(path, O_RDONLY);
463 	if (fd == -1) {
464 		envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, errno, path);
465 		free(fruenvsegs);
466 		return (NULL);
467 	}
468 
469 	/*
470 	 * Read environmental segment from this FRU SEEPROM
471 	 */
472 	if (get_envseg(fd, &envsegbufp, &envseglen) != 0) {
473 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, path);
474 		free(fruenvsegs);
475 		(void) close(fd);
476 		return (NULL);
477 	}
478 
479 	/*
480 	 * Validate envseg version number and header length
481 	 */
482 	envsegp = (envseg_layout_t *)envsegbufp;
483 	hdrlen = sizeof (envseg_layout_t) -
484 	    sizeof (envseg_sensor_t) +
485 	    (envsegp->sensor_count) * sizeof (envseg_sensor_t);
486 
487 	if (envsegp->version != ENVSEG_VERSION ||
488 	    envseglen < hdrlen) {
489 		/*
490 		 * version mismatch or header not big enough
491 		 */
492 		envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, path);
493 		if (envsegbufp != NULL)
494 			(void) free(envsegbufp);
495 		free(fruenvsegs);
496 		(void) close(fd);
497 		return (NULL);
498 	}
499 
500 	fruenvsegs->envseglen = envseglen;
501 	fruenvsegs->envsegbufp = envsegbufp;
502 	(void) close(fd);
503 	return (fruenvsegs);
504 }
505 
506 static	int
507 process_fru_seeprom(unsigned char *buff)
508 {
509 	id_off_t id;
510 	int  i;
511 	int  id_offset = 0;
512 	int  nsensors;
513 	int  nfans;
514 	env_fan_t *fnodep;
515 	env_sensor_t *snodep;
516 
517 #define	NSENSOR_OFFSET	1
518 #define	ID_OFF_SIZE	6
519 #define	NFANS_OFFSET(x)	((x * ID_OFF_SIZE) + 2)
520 
521 	nsensors = (int)buff[NSENSOR_OFFSET];
522 	if (nsensors != MAX_SENSORS) {
523 		envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
524 		return (-1);
525 	}
526 
527 	nfans = (int)buff[NFANS_OFFSET(nsensors)];
528 	if (nfans != MAX_FANS) {
529 		envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
530 		return (-1);
531 	}
532 
533 	while (nsensors > 0) {
534 		(void) memcpy((char *)&id, (char *)&buff[id_offset + 2],
535 		    ID_OFF_SIZE);
536 
537 		if (env_debug)
538 			envd_log(LOG_ERR, "\n Sensor Id %x offset %x",
539 			    id.id, id.offset);
540 
541 		if (id.id > MAX_SENSOR_ID) {
542 			envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
543 			    FRU_SEEPROM_NAME);
544 			return (-1);
545 		}
546 
547 		/*
548 		 * Copy into the sensor control block array according to the
549 		 * sensor ID
550 		 */
551 		(void) memcpy((char *)&sensor_ctrl[id.id],
552 		    (char *)&buff[id.offset],
553 		    sizeof (sensor_ctrl_blk_t));
554 		nsensors--;
555 		id_offset += ID_OFF_SIZE;
556 	}
557 
558 	/*
559 	 * Skip past no of Fan entry(single byte)
560 	 */
561 	id_offset++;
562 	while (nfans > 0) {
563 		(void) memcpy((char *)&id, (char *)&buff[id_offset + 2],
564 		    ID_OFF_SIZE);
565 
566 		if (env_debug)
567 			envd_log(LOG_ERR, "\n Fan Id %x offset %x", id.id,
568 			    id.offset);
569 
570 		(void) memcpy((char *)&fan_ctrl[id.id],
571 		    (char *)&buff[id.offset], sizeof (fan_ctrl_blk_t));
572 
573 		nfans--;
574 		id_offset += ID_OFF_SIZE;
575 	}
576 
577 	/*
578 	 * Match Sensor/ES ID and point correct data
579 	 * based on IDs
580 	 */
581 	for (snodep = envd_sensors; snodep->name != NULL; snodep++)
582 		snodep->es_ptr = &sensor_ctrl[snodep->id];
583 
584 	/*
585 	 * Match Fan/ES ID and point to correct ES Data
586 	 * based on IDs
587 	 */
588 	for (i = 0; (fnodep = envd_fans[i]) != NULL; i++)
589 		fnodep->es_ptr = &fan_ctrl[fnodep->id];
590 
591 	return (0);
592 }
593 
594 static int
595 envd_es_setup()
596 {
597 	envfru = get_fru_envsegs();
598 	if (envfru == NULL) {
599 		envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
600 		return (-1);
601 	}
602 	return (process_fru_seeprom((uchar_t *)envfru->envsegbufp));
603 }
604 
605 static void
606 envd_es_destroy()
607 {
608 	if (envfru != NULL)
609 		free(envfru->envsegbufp);
610 }
611 
612 /*
613  * Lookup fan and return a pointer to env_fan_t data structure.
614  */
615 env_fan_t *
616 fan_lookup(char *name)
617 {
618 	int		i;
619 	env_fan_t	*fanp;
620 
621 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
622 		if (strcmp(fanp->name, name) == 0)
623 			return (fanp);
624 	}
625 	return (NULL);
626 }
627 
628 /*
629  * Lookup sensor and return a pointer to env_sensor_t data structure.
630  */
631 env_sensor_t *
632 sensor_lookup(char *name)
633 {
634 	env_sensor_t	*sensorp;
635 	int		i;
636 
637 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
638 		sensorp = &envd_sensors[i];
639 		if (strcmp(sensorp->name, name) == 0)
640 			return (sensorp);
641 	}
642 	return (NULL);
643 }
644 
645 /*
646  * Get current temperature
647  * Returns -1 on error, 0 if successful
648  */
649 int
650 get_temperature(env_sensor_t *sensorp, tempr_t *temp)
651 {
652 	int	fd = sensorp->fd;
653 	int	retval = 0;
654 
655 	if (fd == -1)
656 		retval = -1;
657 	else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) {
658 		retval = -1;
659 		if (sensorp->error == 0) {
660 			sensorp->error = 1;
661 			envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL,
662 			    sensorp->name, errno, strerror(errno));
663 		}
664 	} else if (sensorp->error != 0) {
665 		sensorp->error = 0;
666 		envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, sensorp->name);
667 	}
668 	if (sensorp->crtbl != NULL) {
669 		*temp = (tempr_t)y_of_x(sensorp->crtbl, *temp);
670 	}
671 
672 	return (retval);
673 }
674 
675 /*
676  * Get uncorrected current temperature
677  * Returns -1 on error, 0 if successful
678  */
679 static int
680 get_raw_temperature(env_sensor_t *sensorp, tempr_t *temp)
681 {
682 	int	fd = sensorp->fd;
683 	int	retval = 0;
684 
685 	if (fd == -1)
686 		retval = -1;
687 	else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) {
688 		retval = -1;
689 	}
690 
691 	return (retval);
692 }
693 
694 /*
695  * Return Fan RPM given N & tach
696  * count and N are retrived from the
697  * ADM1031 chip.
698  */
699 static int
700 tach_to_rpm(int n, uint8_t tach)
701 {
702 	if (n * tach == 0)
703 		return (0);
704 	return ((ADCSAMPLE * 60) / (n * tach));
705 }
706 
707 static int
708 get_raw_fan_speed(env_fan_t *fanp, uint8_t *fanspeedp)
709 {
710 	int	fan_fd;
711 	int	retval = 0;
712 
713 	fan_fd = fanp->fd;
714 
715 	if (fan_fd == -1)
716 		retval = -1;
717 	else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, fanspeedp) == -1) {
718 		retval = -1;
719 	}
720 
721 
722 	return (retval);
723 }
724 /*
725  * Get current fan speed
726  * Returns -1 on error, 0 if successful
727  */
728 int
729 get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp)
730 {
731 	int	fan_fd;
732 	uint8_t tach;
733 
734 	fan_fd = fanp->fd;
735 	if (fan_fd == -1)
736 		return (-1);
737 	else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, &tach) == -1) {
738 		return (-1);
739 	}
740 
741 	/*
742 	 * Fanspeeds are reported as 0
743 	 * if the tach is out of range or fan status is off
744 	 * and if monitoring fan status is enabled.
745 	 */
746 	if (mon_fanstat && (!fanp->fanstat || tach == FAN_OUT_OF_RANGE)) {
747 		*fanspeedp = 0;
748 	} else {
749 		*fanspeedp =
750 		    tach_to_rpm(fanp->speedrange, tach);
751 	}
752 
753 	return (0);
754 }
755 
756 /*
757  * Set fan speed
758  * Returns -1 on error, 0 if successful
759  */
760 int
761 set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed)
762 {
763 	int	fan_fd;
764 	int	retval = 0;
765 	uint8_t	speed;
766 
767 	fan_fd = fanp->fd;
768 	if (fan_fd == -1)
769 		return (-1);
770 
771 	if (fanspeed < 0 || fanspeed > 100)
772 		return (-2);
773 
774 	speed = (uint8_t)ADM_SETFANSPEED_CONV(fanspeed);
775 
776 	if (ioctl(fan_fd, I2C_SET_FAN_SPEED, &speed) == -1) {
777 		retval = -1;
778 	}
779 	return (retval);
780 }
781 
782 /*
783  * close all fan devices
784  */
785 static void
786 envd_close_fans(void)
787 {
788 	int		i;
789 	env_fan_t	*fanp;
790 
791 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
792 		if (fanp->fd != -1) {
793 			(void) close(fanp->fd);
794 			fanp->fd = -1;
795 		}
796 	}
797 }
798 
799 /*
800  * Close sensor devices and freeup resources
801  */
802 static void
803 envd_close_sensors(void)
804 {
805 	env_sensor_t	*sensorp;
806 	int		i;
807 
808 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
809 		sensorp = &envd_sensors[i];
810 		if (sensorp->fd != -1) {
811 			(void) close(sensorp->fd);
812 			sensorp->fd = -1;
813 		}
814 		if (sensorp->crtbl != NULL)
815 			fini_table(sensorp->crtbl);
816 	}
817 }
818 
819 /*
820  * Open fan devices and initialize per fan data structure.
821  * Returns #fans found.
822  */
823 static int
824 envd_setup_fans(void)
825 {
826 	int		i, fd;
827 	env_fan_t	*fanp;
828 	char		path[PATH_MAX];
829 	int		fancnt = 0;
830 	uint8_t		n = 0;
831 
832 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
833 		(void) strcpy(path, "/devices");
834 		(void) strlcat(path, fanp->devfs_path, sizeof (path));
835 		fd = open(path, O_RDWR);
836 		if (fd == -1) {
837 			envd_log(LOG_CRIT,
838 			    ENV_FAN_OPEN_FAIL, fanp->name,
839 			    fanp->devfs_path, errno, strerror(errno));
840 			fanp->present = B_FALSE;
841 			continue;
842 		}
843 		fanp->fd = fd;
844 		if (ioctl(fd, ADM1031_GET_FAN_FEATURE, &n) != -1) {
845 			fanp->speedrange =
846 			    adm_speedrange_map[(n >> 6) & 0x03];
847 		} else {
848 			fanp->speedrange = FAN_RANGE_DEFAULT;
849 		}
850 
851 		fanp->present = B_TRUE;
852 		fanp->fanstat = 0;
853 		fanp->cspeed = TACH_UNKNOWN;
854 		fanp->lspeed = TACH_UNKNOWN;
855 		fanp->conccnt = 0;
856 		fancnt++;
857 	}
858 	return (fancnt);
859 }
860 
861 /*
862  * Open temperature sensor devices and initialize per sensor data structure.
863  * Returns #sensors found.
864  */
865 static int
866 envd_setup_sensors(void)
867 {
868 	env_sensor_t	*sensorp;
869 	sensor_ctrl_blk_t *es_ptr;
870 	table_t		*tblp;
871 	char		path[PATH_MAX];
872 	int		sensorcnt = 0;
873 	int		i, j, nentries;
874 	int16_t		tmin = 0;
875 
876 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
877 		sensorp = &envd_sensors[i];
878 		/* Initialize sensor's initial state */
879 		sensorp->shutdown_initiated = B_FALSE;
880 		sensorp->warning_tstamp = 0;
881 		sensorp->shutdown_tstamp = 0;
882 		sensorp->error = 0;
883 		sensorp->crtbl = NULL;
884 
885 		(void) strcpy(path, "/devices");
886 		(void) strlcat(path, sensorp->devfs_path,
887 		    sizeof (path));
888 		sensorp->fd = open(path, O_RDWR);
889 		if (sensorp->fd == -1) {
890 			envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL,
891 			    sensorp->name, sensorp->devfs_path,
892 			    errno, strerror(errno));
893 			sensorp->present = B_FALSE;
894 			continue;
895 		}
896 		sensorp->present = B_TRUE;
897 		sensorcnt++;
898 
899 		/*
900 		 * Get Tmin
901 		 */
902 
903 		if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE,
904 			&tmin) != -1) {
905 			sensorp->tmin = TMIN(tmin);
906 		} else {
907 			sensorp->tmin = -1;
908 		}
909 		if (env_debug)
910 			envd_log(LOG_ERR, "Sensor %s tmin %d",
911 			    sensorp->name, sensorp->tmin);
912 
913 		/*
914 		 * Create a correction table
915 		 * if correction pairs are present in es
916 		 * segment.
917 		 */
918 		es_ptr = sensorp->es_ptr;
919 
920 		if (es_ptr == NULL) {
921 			continue;
922 		}
923 		nentries = es_ptr->correctionEntries;
924 
925 		if (nentries < 2) {
926 			if (env_debug)
927 				envd_log(LOG_CRIT, "sensor correction <2");
928 			continue;
929 		}
930 
931 		sensorp->crtbl = init_table(nentries);
932 		if (sensorp->crtbl == NULL)
933 			continue;
934 		tblp = sensorp->crtbl;
935 		tblp->xymap[0].x =
936 		    (char)es_ptr->correctionPair[0].measured;
937 		tblp->xymap[0].y =
938 		    (char)es_ptr->correctionPair[0].corrected;
939 
940 		for (j = 1; j < nentries; ++j) {
941 			tblp->xymap[j].x =
942 			    (char)es_ptr->correctionPair[j].measured;
943 			tblp->xymap[j].y =
944 			    (char)es_ptr->correctionPair[j].corrected;
945 
946 			if (tblp->xymap[j].x <= tblp->xymap[j - 1].x) {
947 				fini_table(tblp);
948 				sensorp->crtbl = NULL;
949 				envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
950 				    FRU_SEEPROM_NAME);
951 				break;
952 			}
953 		}
954 
955 		if (env_debug) {
956 			envd_log(LOG_CRIT, "Sensor correction  %s",
957 			    sensorp->name);
958 			for (j = 0; j < nentries; j++)
959 				envd_log(LOG_CRIT, " %d	%d",
960 				    tblp->xymap[j].x, tblp->xymap[j].y);
961 		}
962 	}
963 	return (sensorcnt);
964 }
965 /*
966  * Modify ADM Tmin/ranges depending what power level
967  * we are from.
968  */
969 static void
970 updateadm_ranges(char *name, uchar_t cur_lpstate)
971 {
972 	env_sensor_t *sensorp;
973 	fan_ctrl_blk_t *fanctl;
974 	uchar_t tmin;
975 	uchar_t trange;
976 	uint16_t tdata;
977 	int sysfd;
978 	uchar_t sys_id = CPU_HWM_ID;
979 	uint8_t mode;
980 	static uint16_t tsave = 0;
981 
982 	sensorp = sensor_lookup(name);
983 	if (sensorp == NULL)
984 		return;
985 
986 	/*
987 	 * If there is only one Control pairs then return
988 	 */
989 	fanctl = ((env_fan_t *)sensorp->fanp)->es_ptr;
990 
991 	if (fanctl != NULL && fanctl->no_ctl_pairs <= 1)
992 		return;
993 
994 	/*
995 	 * if fan control specifies that ranges are same then
996 	 * we skip re-programming adm chip.
997 	 */
998 
999 	tmin = fanctl->fan_ctl_pairs[0].tMin;
1000 	trange = fanctl->fan_ctl_pairs[0].tRange;
1001 	if ((tmin == fanctl->fan_ctl_pairs[1].tMin) &&
1002 	    (trange == fanctl->fan_ctl_pairs[1].tRange))
1003 			return;
1004 
1005 	sysfd = open(hwm_devs[sys_id], O_RDWR);
1006 	if (sysfd == -1) {
1007 		if (env_debug)
1008 			envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[sys_id],
1009 				errno, strerror(errno));
1010 		return;
1011 	}
1012 	/* Read ADM default value only for the first time */
1013 	if (tsave == 0) {
1014 		if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE,
1015 			&tsave) == -1) {
1016 			if (env_debug)
1017 				envd_log(LOG_ERR,
1018 				    "read tminrange ioctl failed");
1019 			(void) close(sysfd);
1020 			return;
1021 		}
1022 	}
1023 
1024 	/*
1025 	 * Need to reinit ADM to manual mode for Tmin range to be
1026 	 * effective.
1027 	 */
1028 	mode = ADM1031_MANUAL_MODE;
1029 	if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) {
1030 		if (env_debug)
1031 			envd_log(LOG_ERR, ENV_ADM_MANUAL_MODE);
1032 		(void) close(sysfd);
1033 		return;
1034 	}
1035 
1036 	if (cur_lpstate == 1) {
1037 	/*
1038 	 * ADM 1031 Tmin/Trange register need to be reprogrammed.
1039 	 */
1040 		tdata = ((fanctl->fan_ctl_pairs[cur_lpstate].tMin / TMIN_UNITS)
1041 				<< TMIN_SHIFT);
1042 		/* Need to pack tRange in ADM bits 2:0 */
1043 		switch (fanctl->fan_ctl_pairs[cur_lpstate].tRange) {
1044 			case 5:
1045 				break;
1046 
1047 			case 10:
1048 				tdata |= 1;
1049 				break;
1050 
1051 			case 20:
1052 				tdata |= 2;
1053 				break;
1054 
1055 			case 40:
1056 				tdata |= 3;
1057 				break;
1058 
1059 			case 80:
1060 				tdata |= 4;
1061 				break;
1062 		}
1063 	} else
1064 		tdata = tsave;
1065 
1066 	if (ioctl(sensorp->fd, ADM1031_SET_TEMP_MIN_RANGE,
1067 	    &tdata) != -1)
1068 		sensorp->tmin = TMIN(tdata);
1069 
1070 	sensorp->tmin = TMIN(tdata);
1071 
1072 	mode = ADM1031_AUTO_MODE;
1073 	if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) {
1074 		if (env_debug)
1075 			envd_log(LOG_ERR, ENV_ADM_AUTO_MODE);
1076 	}
1077 	(void) close(sysfd);
1078 }
1079 
1080 /*ARGSUSED*/
1081 static void *
1082 pmthr(void *args)
1083 {
1084 	pm_state_change_t	pmstate;
1085 	char			physpath[PATH_MAX];
1086 	int				pre_lpstate;
1087 
1088 	pmstate.physpath = physpath;
1089 	pmstate.size = sizeof (physpath);
1090 	cur_lpstate = 0;
1091 	pre_lpstate = 1;
1092 
1093 	pm_fd = open(PM_DEVICE, O_RDWR);
1094 	if (pm_fd == -1) {
1095 		envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno));
1096 		return (NULL);
1097 	}
1098 	for (;;) {
1099 		/*
1100 		 * Get PM state change events to check if the system
1101 		 * is in lowest power state and adjust ADM hardware
1102 		 * monitor's fan speed settings.
1103 		 *
1104 		 * To minimize polling, we use the blocking interface
1105 		 * to get the power state change event here.
1106 		 */
1107 		if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) {
1108 			if (errno != EINTR)
1109 				break;
1110 			continue;
1111 		}
1112 		do {
1113 			if (env_debug) {
1114 				envd_log(LOG_INFO,
1115 					"pmstate event:0x%x flags:%x comp:%d "
1116 					"oldval:%d newval:%d path:%s\n",
1117 						pmstate.event, pmstate.flags,
1118 						pmstate.component,
1119 						pmstate.old_level,
1120 						pmstate.new_level,
1121 						pmstate.physpath);
1122 			}
1123 			cur_lpstate =
1124 			    (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0;
1125 		} while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0);
1126 		/*
1127 		 * Change ADM ranges as per E* Requirements. Update
1128 		 * happens only for valid state changes.
1129 		 */
1130 		if (pre_lpstate != cur_lpstate) {
1131 			pre_lpstate = cur_lpstate;
1132 			updateadm_ranges(SENSOR_SYS_IN, cur_lpstate);
1133 		}
1134 	}
1135 	/*NOTREACHED*/
1136 	return (NULL);
1137 }
1138 
1139 /*
1140  * This function is used to reasonably predict the
1141  * state of the fan (ON/OFF) using tmin and current temperature.
1142  *
1143  * We know the fan is on  if temp >= tmin and fan is off if
1144  * temp < (Tmin - Hysterisis).
1145  *
1146  * When the temperature is in between we don't know if the fan is on/off
1147  * because the temperature could be decreasing and not have crossed
1148  * Tmin - hysterisis and vice a versa.
1149  *
1150  *			FAN ON
1151  * Tmin
1152  * 	-------------------------------------------
1153  *
1154  * 			FAN ON/OFF
1155  *
1156  * 	--------------------------------------------
1157  * Tmin - Hysterisis
1158  *			FAN OFF
1159  *
1160  * To solve the problem of finding out if the fan is on/off in our gray region
1161  * we keep track of the last read tach and the current read tach. From
1162  * experimentation and from discussions with analog devices it is unlikely that
1163  * if the fans are on we will get a constant tach reading  more than 5 times in
1164  * a row. This is not the most fool proof approach but the  best we can do.
1165  *
1166  * This routine implements the above logic for a sensor with an
1167  * associated fan. The caller garauntees sensorp and fanp are not null.
1168  */
1169 static void
1170 check_fanstat(env_sensor_t *sensorp)
1171 {
1172 	env_fan_t *fanp = sensorp->fanp;
1173 	tempr_t	temp;
1174 	uint8_t fanspeed;
1175 
1176 	if (get_raw_temperature(sensorp, &temp) == -1)
1177 		return;
1178 
1179 	if (temp < (sensorp->tmin - ADM_HYSTERISIS)) {
1180 
1181 		fanp->fanstat = 0;		/* Fan off */
1182 		fanp->lspeed = TACH_UNKNOWN;	/* Reset Last read tach */
1183 		fanp->conccnt = 0;
1184 
1185 	} else if (temp >= sensorp->tmin) {
1186 
1187 		fanp->fanstat = 1;		/* Fan on */
1188 		fanp->lspeed = TACH_UNKNOWN;
1189 		fanp->conccnt = 0;
1190 
1191 	} else {
1192 		if (get_raw_fan_speed(fanp, &fanspeed) == -1)
1193 			return;
1194 
1195 		fanp->cspeed = fanspeed;
1196 		/*
1197 		 * First time in the gray area
1198 		 * set last read speed to current speed
1199 		 */
1200 		if (fanp->lspeed == TACH_UNKNOWN) {
1201 			fanp->lspeed = fanspeed;
1202 		} else {
1203 			if (fanp->lspeed != fanp->cspeed) {
1204 				fanp->conccnt = 0;
1205 				fanp->fanstat = 1;
1206 			} else {
1207 				fanp->conccnt++;
1208 
1209 				if (fanp->conccnt >= N_SEQ_TACH)
1210 					fanp->fanstat = 0;
1211 			}
1212 			fanp->lspeed = fanp->cspeed;
1213 		}
1214 	}
1215 }
1216 /*
1217  * There is an issue with the ADM1031 chip that causes the chip
1218  * to not update the tach register in case the fan stops. The
1219  * fans stop when the temperature measured (temp) drops below
1220  * Tmin - Hysterisis  and turns the fan on when the temp >= tmin.
1221  *
1222  * Since the tach registers don't update and remain stuck at the
1223  * last read tach value our get_fan_speed function always returns
1224  * a non-zero RPM reading.
1225  *
1226  * To fix this we need to figure out when the fans will be on/off
1227  * depending on the current temperature. Currently we poll for
1228  * interrupts, we can use that loop to determine what the current
1229  * temperature is and if the fans should be on/off.
1230  *
1231  * We get current temperature and check the fans.
1232  */
1233 static void
1234 monitor_fanstat(void)
1235 {
1236 	env_sensor_t *sensorp;
1237 	env_fan_t *fanp;
1238 	int i;
1239 
1240 	for (i = 0; i < N_ENVD_SENSORS; i++) {
1241 		sensorp = &envd_sensors[i];
1242 
1243 		if (!sensorp)
1244 			continue;
1245 
1246 		fanp = sensorp->fanp;
1247 
1248 		if (!fanp)
1249 			continue;
1250 
1251 		if (sensorp->tmin != -1) {
1252 			check_fanstat(sensorp);
1253 		} else {
1254 			fanp->fanstat = 1;
1255 		}
1256 	}
1257 	/*
1258 	 * On Taco both the system fans are driven by one
1259 	 * sensor (sys-in) and connected to the sys-in tach.
1260 	 */
1261 	envd_sys_out_fan.fanstat = envd_sys_in_fan.fanstat;
1262 
1263 }
1264 
1265 static int
1266 handle_overtemp_interrupt(int hwm_id)
1267 {
1268 	env_sensor_t *sensorp;
1269 	tempr_t  temp;
1270 	uchar_t smap[MAX_SENSORS];
1271 	time_t  ct;
1272 	uchar_t i;
1273 	char msgbuf[BUFSIZ];
1274 	char syscmd[BUFSIZ];
1275 	boolean_t return_flag;
1276 
1277 	/* Clear Map of Sensor Entries */
1278 	(void) memset(smap, SENSOR_OK, sizeof (smap));
1279 
1280 	for (;;) {
1281 		for (i = 0; i < N_ENVD_SENSORS; i++) {
1282 			sensorp = &envd_sensors[i];
1283 
1284 			/*
1285 			 * Check whether the sensor belongs to the
1286 			 * interrupting ADM hardware monitor
1287 			 */
1288 			if (sensorp->hwm_id != hwm_id)
1289 				continue;
1290 
1291 			/*
1292 			 * if shutdown is initiated then we simply loop
1293 			 * through the sensors until shutdown
1294 			 */
1295 			if (sensorp->shutdown_initiated == B_TRUE)
1296 				continue;
1297 
1298 			/* get current temp for this sensor */
1299 			if (get_temperature(sensorp, &temp) == -1)
1300 				continue;
1301 
1302 			sensorp->cur_temp = temp;
1303 
1304 			if (env_debug)
1305 				envd_log(LOG_ERR,
1306 					"sensor name %s, cur temp %d, "
1307 					"HW %d LW %d SD %d LS %d\n",
1308 					    sensorp->name, temp,
1309 					    sensorp->es_ptr->high_warning,
1310 					    (int)sensorp->es_ptr->low_warning,
1311 					    sensorp->es_ptr->high_shutdown,
1312 					    (int)sensorp->es_ptr->low_shutdown);
1313 
1314 			if (TEMP_IN_WARNING_RANGE(sensorp->cur_temp, sensorp)) {
1315 				/*
1316 				 * Log on warning atmost one second
1317 				 */
1318 				ct = (time_t)(gethrtime() / NANOSEC);
1319 				if ((ct - sensorp->warning_tstamp) >=
1320 				    warning_interval) {
1321 					envd_log(LOG_CRIT,
1322 					    ENV_WARNING_MSG, sensorp->name,
1323 					    temp,
1324 					    sensorp->es_ptr->low_warning,
1325 					    sensorp->es_ptr->high_warning);
1326 					sensorp->warning_tstamp = ct;
1327 				}
1328 				smap[i] = SENSOR_WARN;
1329 			} else {
1330 				/*
1331 				 * We will fall in this caterory only if
1332 				 * Temperature drops/increases from warning
1333 				 * threshold. If so we set sensor map to
1334 				 * OK so that we can exit the loop if
1335 				 * shutdown not initiated.
1336 				 */
1337 				smap[i] = SENSOR_OK;
1338 			}
1339 
1340 			if (TEMP_IN_SHUTDOWN_RANGE(temp, sensorp) &&
1341 			    !shutdown_override) {
1342 				ct = (time_t)(gethrtime() / NANOSEC);
1343 				if (sensorp->shutdown_tstamp == 0)
1344 					sensorp->shutdown_tstamp = ct;
1345 				if ((ct - sensorp->shutdown_tstamp) >=
1346 				    shutdown_interval) {
1347 					sensorp->shutdown_initiated = B_TRUE;
1348 					(void) snprintf(msgbuf, sizeof (msgbuf),
1349 					    ENV_SHUTDOWN_MSG, sensorp->name,
1350 					    temp,
1351 					    sensorp->es_ptr->low_shutdown,
1352 					    sensorp->es_ptr->high_shutdown);
1353 					envd_log(LOG_ALERT, msgbuf);
1354 				}
1355 				if (system_shutdown_started == B_FALSE) {
1356 					(void) snprintf(syscmd, sizeof (syscmd),
1357 					    "%s \"%s\"", SHUTDOWN_CMD, msgbuf);
1358 					envd_log(LOG_ALERT, syscmd);
1359 					system_shutdown_started = B_TRUE;
1360 					(void) system(syscmd);
1361 				}
1362 			} else if (sensorp->shutdown_tstamp != 0)
1363 				sensorp->shutdown_tstamp = 0;
1364 		}
1365 
1366 		/*
1367 		 * Sweep thorugh Sensor Map and if warnings OR shutdown
1368 		 * are not logged then return to caller.
1369 		 */
1370 		return_flag = B_TRUE;
1371 		for (i = 0; i < N_ENVD_SENSORS; i++)
1372 			if (smap[i] == SENSOR_WARN)
1373 				return_flag = B_FALSE;
1374 
1375 		if ((return_flag == B_TRUE) &&
1376 		    (system_shutdown_started == B_FALSE)) {
1377 			return (1);
1378 		}
1379 
1380 		(void) envd_sleep(SENSORPOLL_INTERVAL);
1381 	}
1382 }
1383 
1384 /*
1385  * This is env thread which monitors the current temperature when
1386  * warning threshold is exceeded. The job is to make sure it does
1387  * not execced/decrease shutdown threshold. If it does it will start
1388  * forced shutdown to avoid reaching hardware poweroff via THERM interrupt.
1389  * For Taco there will be one thread for the ADM chip.
1390  */
1391 static void *
1392 ovtemp_thr(void *args)
1393 {
1394 	int fd;
1395 	uint8_t stat[2];
1396 	int	hwm_id = (int)args;
1397 	int  err;
1398 
1399 	fd = open(hwm_devs[hwm_id], O_RDWR);
1400 	if (fd == -1) {
1401 		envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[hwm_id],
1402 		    errno, strerror(errno));
1403 		return (NULL);
1404 	}
1405 
1406 	for (;;) {
1407 
1408 		/*
1409 		 * Monitor the sensors to update status
1410 		 */
1411 		if (mon_fanstat)
1412 			monitor_fanstat();
1413 
1414 		/*
1415 		 * Sleep for specified seconds before issuing IOCTL
1416 		 * again.
1417 		 */
1418 		(void) envd_sleep(INTERRUPTPOLL_INTERVAL);
1419 
1420 		/*
1421 		 * Read ADM1031 two Status Register to determine source of
1422 		 * Interrupts.
1423 		 */
1424 		if ((err = ioctl(fd, ADM1031_GET_STATUS_1, &stat[0])) != -1)
1425 			err = ioctl(fd, ADM1031_GET_STATUS_2, &stat[1]);
1426 
1427 		if (err == -1) {
1428 			if (env_debug)
1429 				envd_log(LOG_ERR, "OverTemp: Status Error");
1430 			continue;
1431 		}
1432 
1433 		if (env_debug)
1434 			envd_log(LOG_ERR, "INTR %s  Stat1 %x, Stat2 %x",
1435 			    hwm_devs[hwm_id], stat[0], stat[1]);
1436 
1437 		if (stat[0] & FANFAULT)
1438 			envd_log(LOG_ERR, ENV_FAN_FAULT,
1439 			    hwm_devs[hwm_id], hwm_fans[hwm_id][HWM_FAN1]);
1440 
1441 		if (stat[1] & FANFAULT)
1442 			envd_log(LOG_ERR, ENV_FAN_FAULT,
1443 			    hwm_devs[hwm_id], hwm_fans[hwm_id][HWM_FAN2]);
1444 
1445 		/*
1446 		 * Check respective Remote/Local High, Low before start
1447 		 * manual monitoring
1448 		 */
1449 		if ((stat[0] & STAT1MASK) || (stat[1] & STAT2MASK))
1450 			(void) handle_overtemp_interrupt(hwm_id);
1451 	}
1452 	/*NOTREACHED*/
1453 	return (NULL);
1454 }
1455 
1456 /*
1457  * Setup envrionmental monitor state and start threads to monitor
1458  * temperature and power management state.
1459  * Returns -1 on error, 0 if successful.
1460  */
1461 
1462 static int
1463 envd_setup(void)
1464 {
1465 	int	ret;
1466 
1467 	if (getenv("SUNW_piclenvd_debug") != NULL)
1468 			env_debug = 1;
1469 
1470 	if (pthread_attr_init(&thr_attr) != 0 ||
1471 	    pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) {
1472 		return (-1);
1473 	}
1474 
1475 	ret = envd_es_setup();
1476 	if (ret < 0) {
1477 		ovtemp_monitor = 0;
1478 		pm_monitor = 0;
1479 	}
1480 
1481 
1482 	/*
1483 	 * Setup temperature sensors and fail if we can't open
1484 	 * at least one sensor.
1485 	 */
1486 	if (envd_setup_sensors() <= 0) {
1487 		return (NULL);
1488 	}
1489 
1490 	/*
1491 	 * Setup fan device (don't fail even if we can't access
1492 	 * the fan as we can still monitor temeperature.
1493 	 */
1494 	(void) envd_setup_fans();
1495 
1496 	/* If ES Segment setup failed,don't create  thread */
1497 
1498 	if (ovtemp_monitor && ovtemp_thr_created == B_FALSE) {
1499 		if (pthread_create(&ovtemp_thr_id, &thr_attr, ovtemp_thr,
1500 		    (void *)CPU_HWM_ID) != 0)
1501 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
1502 		else
1503 			ovtemp_thr_created = B_TRUE;
1504 	}
1505 
1506 	/*
1507 	 * Create a thread to monitor PM state
1508 	 */
1509 	if (pm_monitor && pmthr_created == B_FALSE) {
1510 		if (pthread_create(&pmthr_tid, &thr_attr, pmthr,
1511 		    NULL) != 0)
1512 			envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED);
1513 		else
1514 			pmthr_created = B_TRUE;
1515 	}
1516 	return (0);
1517 }
1518 
1519 static void
1520 piclenvd_register(void)
1521 {
1522 	picld_plugin_register(&my_reg_info);
1523 }
1524 
1525 static void
1526 piclenvd_init(void)
1527 {
1528 
1529 	(void) env_picl_setup_tuneables();
1530 
1531 	/*
1532 	 * Setup the environmental data structures
1533 	 */
1534 	if (envd_setup() != 0) {
1535 		envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED);
1536 		return;
1537 	}
1538 
1539 	/*
1540 	 * Now setup/populate PICL tree
1541 	 */
1542 	env_picl_setup();
1543 }
1544 
1545 static void
1546 piclenvd_fini(void)
1547 {
1548 
1549 	/*
1550 	 * Invoke env_picl_destroy() to remove any PICL nodes/properties
1551 	 * (including volatile properties) we created. Once this call
1552 	 * returns, there can't be any more calls from the PICL framework
1553 	 * to get current temperature or fan speed.
1554 	 */
1555 	env_picl_destroy();
1556 	envd_close_sensors();
1557 	envd_close_fans();
1558 	envd_es_destroy();
1559 }
1560 
1561 /*VARARGS2*/
1562 void
1563 envd_log(int pri, const char *fmt, ...)
1564 {
1565 	va_list	ap;
1566 
1567 	va_start(ap, fmt);
1568 	vsyslog(pri, fmt, ap);
1569 	va_end(ap);
1570 }
1571 
1572 #ifdef __lint
1573 /*
1574  * Redefine sigwait to posix style external declaration so that LINT
1575  * does not check against libc version of sigwait() and complain as
1576  * it uses different number of arguments.
1577  */
1578 #define	sigwait	my_posix_sigwait
1579 extern int my_posix_sigwait(const sigset_t *set, int *sig);
1580 #endif
1581 
1582 static uint_t
1583 envd_sleep(uint_t sleep_tm)
1584 {
1585 	int sig;
1586 	uint_t unslept;
1587 	sigset_t alrm_mask;
1588 
1589 	if (sleep_tm == 0)
1590 		return (0);
1591 
1592 	(void) sigemptyset(&alrm_mask);
1593 	(void) sigaddset(&alrm_mask, SIGALRM);
1594 
1595 	(void) alarm(sleep_tm);
1596 	(void) sigwait(&alrm_mask, &sig);
1597 
1598 	unslept = alarm(0);
1599 	return (unslept);
1600 }
1601 
1602 /*
1603  * Tunables support functions
1604  */
1605 static env_tuneable_t *
1606 tuneable_lookup(picl_prophdl_t proph)
1607 {
1608 	int i;
1609 	env_tuneable_t	*tuneablep = NULL;
1610 
1611 	for (i = 0; i < ntuneables; i++) {
1612 		tuneablep = &tuneables[i];
1613 		if (tuneablep->proph == proph)
1614 			return (tuneablep);
1615 	}
1616 
1617 	return (NULL);
1618 }
1619 
1620 static int
1621 get_tach(ptree_rarg_t *parg, void *buf)
1622 {
1623 	picl_prophdl_t	proph;
1624 	env_tuneable_t	*tuneablep;
1625 	int		fd;
1626 	int8_t		cfg;
1627 
1628 	proph = parg->proph;
1629 
1630 	tuneablep = tuneable_lookup(proph);
1631 
1632 	if (tuneablep == NULL)
1633 		return (PICL_FAILURE);
1634 
1635 	fd = open(CPU_HWM_DEVFS, O_RDWR);
1636 
1637 	if (fd == -1) {
1638 		return (PICL_FAILURE);
1639 	}
1640 
1641 	if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
1642 		return (PICL_FAILURE);
1643 	}
1644 
1645 	if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) {
1646 		*((int *)tuneablep->value) = ENABLE;
1647 
1648 	} else {
1649 		*((int *)tuneablep->value) = DISABLE;
1650 	}
1651 
1652 	(void) memcpy(buf, tuneablep->value,
1653 	    tuneablep->nbytes);
1654 
1655 	(void) close(fd);
1656 	return (PICL_SUCCESS);
1657 }
1658 
1659 static int
1660 set_tach(ptree_warg_t *parg, const void *buf)
1661 {
1662 	picl_prophdl_t	proph;
1663 	env_tuneable_t	*tuneablep;
1664 	int		 fd, val;
1665 	int8_t		 cfg;
1666 
1667 	if (parg->cred.dc_euid != 0)
1668 		return (PICL_PERMDENIED);
1669 
1670 	proph = parg->proph;
1671 
1672 	tuneablep = tuneable_lookup(proph);
1673 
1674 	if (tuneablep == NULL)
1675 		return (PICL_FAILURE);
1676 
1677 	fd = open(CPU_HWM_DEVFS, O_RDWR);
1678 
1679 	if (fd == -1) {
1680 		return (PICL_FAILURE);
1681 	}
1682 
1683 	if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
1684 		return (PICL_FAILURE);
1685 	}
1686 
1687 	(void) memcpy(&val, (caddr_t)buf, sizeof (val));
1688 
1689 	if (val == ENABLE) {
1690 		cfg |= TACH_ENABLE_MASK;
1691 	} else if (val == DISABLE) {
1692 		cfg &= ~TACH_ENABLE_MASK;
1693 	}
1694 
1695 	if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) {
1696 		return (PICL_FAILURE);
1697 	}
1698 
1699 	(void) close(fd);
1700 	return (PICL_SUCCESS);
1701 }
1702 
1703 static int
1704 get_monitor_mode(ptree_rarg_t *parg, void *buf)
1705 {
1706 	picl_prophdl_t	proph;
1707 	env_tuneable_t	*tuneablep;
1708 	int		fd;
1709 	int8_t		mmode;
1710 
1711 	proph = parg->proph;
1712 
1713 	tuneablep = tuneable_lookup(proph);
1714 
1715 	if (tuneablep == NULL)
1716 		return (PICL_FAILURE);
1717 
1718 	fd = open(CPU_HWM_DEVFS, O_RDWR);
1719 
1720 	if (fd == -1) {
1721 		return (PICL_FAILURE);
1722 	}
1723 
1724 	if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) {
1725 		return (PICL_FAILURE);
1726 	}
1727 
1728 	if (mmode == ADM1031_AUTO_MODE) {
1729 		*((int *)tuneablep->value) = ENABLE;
1730 	} else {
1731 		*((int *)tuneablep->value) = DISABLE;
1732 	}
1733 
1734 	(void) memcpy(buf, tuneablep->value,
1735 	    tuneablep->nbytes);
1736 
1737 	(void) close(fd);
1738 	return (PICL_SUCCESS);
1739 }
1740 
1741 static int
1742 set_monitor_mode(ptree_warg_t *parg, const void *buf)
1743 {
1744 	picl_prophdl_t	proph;
1745 	env_tuneable_t	*tuneablep;
1746 	int		fd, val;
1747 	int8_t		mmode;
1748 
1749 	if (parg->cred.dc_euid != 0)
1750 		return (PICL_PERMDENIED);
1751 
1752 	proph = parg->proph;
1753 
1754 	tuneablep = tuneable_lookup(proph);
1755 
1756 	if (tuneablep == NULL)
1757 		return (PICL_FAILURE);
1758 
1759 	fd = open(CPU_HWM_DEVFS, O_RDWR);
1760 	if (fd == -1) {
1761 		return (PICL_FAILURE);
1762 	}
1763 	(void) memcpy(&val, buf, sizeof (val));
1764 	if (val == ENABLE) {
1765 		mmode = ADM1031_AUTO_MODE;
1766 	} else if (val == DISABLE) {
1767 		mmode = ADM1031_MANUAL_MODE;
1768 	}
1769 
1770 	if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) {
1771 		return (PICL_FAILURE);
1772 	}
1773 
1774 	(void) close(fd);
1775 	return (PICL_SUCCESS);
1776 }
1777 
1778 static int
1779 get_string_val(ptree_rarg_t *parg, void *buf)
1780 {
1781 	picl_prophdl_t	proph;
1782 	env_tuneable_t	*tuneablep;
1783 
1784 	proph = parg->proph;
1785 
1786 	tuneablep = tuneable_lookup(proph);
1787 
1788 	if (tuneablep == NULL)
1789 		return (PICL_FAILURE);
1790 
1791 	(void) memcpy(buf, (caddr_t)tuneablep->value,
1792 	    tuneablep->nbytes);
1793 
1794 	return (PICL_SUCCESS);
1795 }
1796 
1797 static int
1798 set_string_val(ptree_warg_t *parg, const void *buf)
1799 {
1800 	picl_prophdl_t	proph;
1801 	env_tuneable_t	*tuneablep;
1802 
1803 	proph = parg->proph;
1804 
1805 	if (parg->cred.dc_euid != 0)
1806 		return (PICL_PERMDENIED);
1807 
1808 	tuneablep = tuneable_lookup(proph);
1809 
1810 	if (tuneablep == NULL)
1811 		return (PICL_FAILURE);
1812 
1813 	(void) memcpy((caddr_t)tuneables->value, (caddr_t)buf,
1814 	    tuneables->nbytes);
1815 
1816 	return (PICL_SUCCESS);
1817 }
1818 
1819 static int
1820 get_int_val(ptree_rarg_t *parg, void *buf)
1821 {
1822 	picl_prophdl_t	proph;
1823 	env_tuneable_t	*tuneablep;
1824 
1825 	proph = parg->proph;
1826 
1827 	tuneablep = tuneable_lookup(proph);
1828 
1829 	if (tuneablep == NULL)
1830 		return (PICL_FAILURE);
1831 
1832 	(void) memcpy((int *)buf, (int *)tuneablep->value,
1833 	    tuneablep->nbytes);
1834 
1835 	return (PICL_SUCCESS);
1836 }
1837 
1838 static int
1839 set_int_val(ptree_warg_t *parg, const void *buf)
1840 {
1841 	picl_prophdl_t	proph;
1842 	env_tuneable_t	*tuneablep;
1843 
1844 	if (parg->cred.dc_euid != 0)
1845 		return (PICL_PERMDENIED);
1846 
1847 	proph = parg->proph;
1848 
1849 	tuneablep = tuneable_lookup(proph);
1850 
1851 	if (tuneablep == NULL)
1852 		return (PICL_FAILURE);
1853 
1854 	(void) memcpy((int *)tuneablep->value, (int *)buf,
1855 	    tuneablep->nbytes);
1856 
1857 	return (PICL_SUCCESS);
1858 }
1859