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