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 2006 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 Chicago WS.
35  * It provides functionality to get/set temperatures and
36  * fan speeds.
37  *
38  * The environmental policy defaults to the auto mode
39  * 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 <strings.h>
48 #include <stdarg.h>
49 #include <alloca.h>
50 #include <unistd.h>
51 #include <sys/processor.h>
52 #include <syslog.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <picl.h>
56 #include <picltree.h>
57 #include <picldefs.h>
58 #include <pthread.h>
59 #include <signal.h>
60 #include <libdevinfo.h>
61 #include <sys/pm.h>
62 #include <sys/open.h>
63 #include <sys/time.h>
64 #include <sys/utsname.h>
65 #include <sys/systeminfo.h>
66 #include <note.h>
67 #include <sys/pic16f747.h>
68 #include "envd.h"
69 #include <sys/scsi/scsi.h>
70 #include <sys/scsi/generic/commands.h>
71 
72 int	debug_fd;
73 /*
74  * PICL plugin entry points
75  */
76 static void piclenvd_register(void);
77 static void piclenvd_init(void);
78 static void piclenvd_fini(void);
79 
80 /*
81  * Env setup routines
82  */
83 extern void env_picl_setup(void);
84 extern void env_picl_destroy(void);
85 extern int env_picl_setup_tuneables(void);
86 
87 static boolean_t has_fan_failed(env_fan_t *fanp);
88 
89 /*
90  * PSU fan fault handling
91  */
92 static boolean_t has_psufan_failed(void);
93 static int psufan_last_status = FAN_OK;
94 
95 #pragma init(piclenvd_register)
96 
97 /*
98  * Plugin registration information
99  */
100 static picld_plugin_reg_t my_reg_info = {
101 	PICLD_PLUGIN_VERSION,
102 	PICLD_PLUGIN_CRITICAL,
103 	"SUNW_piclenvd",
104 	piclenvd_init,
105 	piclenvd_fini,
106 };
107 
108 #define	REGISTER_INFORMATION_STRING_LENGTH	16
109 static char fan_rpm_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
110 static char fan_status_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
111 
112 static int	scsi_log_sense(env_disk_t *diskp, uchar_t page_code,
113 			void *pagebuf, uint16_t pagelen, int page_control);
114 static int scsi_mode_select(env_disk_t *diskp, uchar_t page_code,
115 			uchar_t *pagebuf, uint16_t pagelen);
116 
117 static int	get_disk_temp(env_disk_t *);
118 
119 /*
120  * ES Segment stuff
121  */
122 static es_sensor_blk_t sensor_ctl[MAX_SENSORS];
123 
124 /*
125  * Default limits for sensors, in case ES segment is not present, or has
126  * inconsistent information
127  */
128 static es_sensor_blk_t sensor_default_ctl[MAX_SENSORS] = {
129 	{
130 	    CPU0_HIGH_POWER_OFF, CPU0_HIGH_SHUTDOWN, CPU0_HIGH_WARNING,
131 	    CPU0_LOW_WARNING, CPU0_LOW_SHUTDOWN, CPU0_LOW_POWER_OFF
132 	},
133 	{
134 	    CPU1_HIGH_POWER_OFF, CPU1_HIGH_SHUTDOWN, CPU1_HIGH_WARNING,
135 	    CPU1_LOW_WARNING, CPU1_LOW_SHUTDOWN, CPU1_LOW_POWER_OFF
136 	},
137 	{
138 	    ADT7462_HIGH_POWER_OFF, ADT7462_HIGH_SHUTDOWN, ADT7462_HIGH_WARNING,
139 	    ADT7462_LOW_WARNING, ADT7462_LOW_SHUTDOWN, ADT7462_LOW_POWER_OFF
140 	},
141 	{
142 	    MB_HIGH_POWER_OFF, MB_HIGH_SHUTDOWN, MB_HIGH_WARNING,
143 	    MB_LOW_WARNING, MB_LOW_SHUTDOWN, MB_LOW_POWER_OFF
144 	},
145 	{
146 	    LM95221_HIGH_POWER_OFF, LM95221_HIGH_SHUTDOWN, LM95221_HIGH_WARNING,
147 	    LM95221_LOW_WARNING, LM95221_LOW_SHUTDOWN, LM95221_LOW_POWER_OFF
148 	},
149 	{
150 	    FIRE_HIGH_POWER_OFF, FIRE_HIGH_SHUTDOWN, FIRE_HIGH_WARNING,
151 	    FIRE_LOW_WARNING, FIRE_LOW_SHUTDOWN, FIRE_LOW_POWER_OFF
152 	},
153 	{
154 	    LSI1064_HIGH_POWER_OFF, LSI1064_HIGH_SHUTDOWN, LSI1064_HIGH_WARNING,
155 	    LSI1064_LOW_WARNING, LSI1064_LOW_SHUTDOWN, LSI1064_LOW_POWER_OFF
156 	},
157 	{
158 	    FRONT_PANEL_HIGH_POWER_OFF, FRONT_PANEL_HIGH_SHUTDOWN,
159 	    FRONT_PANEL_HIGH_WARNING, FRONT_PANEL_LOW_WARNING,
160 	    FRONT_PANEL_LOW_SHUTDOWN, FRONT_PANEL_LOW_POWER_OFF
161 	},
162 	{
163 	    PSU_HIGH_POWER_OFF, PSU_HIGH_SHUTDOWN, PSU_HIGH_WARNING,
164 	    PSU_LOW_WARNING, PSU_LOW_SHUTDOWN, PSU_LOW_POWER_OFF
165 	}
166 };
167 
168 /*
169  * Env thread variables
170  */
171 static boolean_t  system_shutdown_started = B_FALSE;
172 static boolean_t  system_temp_thr_created = B_FALSE;
173 static pthread_t  system_temp_thr_id;
174 static pthread_attr_t thr_attr;
175 static boolean_t  disk_temp_thr_created = B_FALSE;
176 static pthread_t  disk_temp_thr_id;
177 static boolean_t  fan_thr_created = B_FALSE;
178 static pthread_t  fan_thr_id;
179 
180 /*
181  * PM thread related variables
182  */
183 static pthread_t	pmthr_tid;	/* pmthr thread ID */
184 static int		pm_fd = -1;	/* PM device file descriptor */
185 static boolean_t	pmthr_created = B_FALSE;
186 static int		cur_lpstate;	/* cur low power state */
187 
188 /*
189  * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var
190  * Setting the verbose tuneable also enables debugging for better
191  * control
192  */
193 int	env_debug = 0;
194 
195 /*
196  * These are debug variables for keeping track of the total number
197  * of Fan and Temp sensor retries over the lifetime of the plugin.
198  */
199 static int total_fan_retries = 0;
200 static int total_temp_retries = 0;
201 
202 /*
203  * Fan devices
204  */
205 static env_fan_t envd_system_fan0 = {
206 	ENV_SYSTEM_FAN0, ENV_SYSTEM_FAN0_DEVFS, SYSTEM_FAN0_ID,
207 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
208 };
209 static env_fan_t envd_system_fan1 = {
210 	ENV_SYSTEM_FAN1, ENV_SYSTEM_FAN1_DEVFS, SYSTEM_FAN1_ID,
211 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
212 };
213 static env_fan_t envd_system_fan2 = {
214 	ENV_SYSTEM_FAN2, ENV_SYSTEM_FAN2_DEVFS, SYSTEM_FAN2_ID,
215 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
216 };
217 static env_fan_t envd_system_fan3 = {
218 	ENV_SYSTEM_FAN3, ENV_SYSTEM_FAN3_DEVFS, SYSTEM_FAN3_ID,
219 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
220 };
221 static env_fan_t envd_system_fan4 = {
222 	ENV_SYSTEM_FAN4, ENV_SYSTEM_FAN4_DEVFS, SYSTEM_FAN4_ID,
223 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
224 };
225 
226 /*
227  * Disk devices
228  */
229 static env_disk_t envd_disk0 = {
230 	ENV_DISK0, ENV_DISK0_DEVFS, DISK0_PHYSPATH, DISK0_NODE_PATH,
231 	DISK0_ID, -1,
232 };
233 static env_disk_t envd_disk1 = {
234 	ENV_DISK1, ENV_DISK1_DEVFS, DISK1_PHYSPATH, DISK1_NODE_PATH,
235 	DISK1_ID, -1,
236 };
237 static env_disk_t envd_disk2 = {
238 	ENV_DISK2, ENV_DISK2_DEVFS, DISK2_PHYSPATH, DISK2_NODE_PATH,
239 	DISK2_ID, -1,
240 };
241 static env_disk_t envd_disk3 = {
242 	ENV_DISK3, ENV_DISK3_DEVFS, DISK3_PHYSPATH, DISK3_NODE_PATH,
243 	DISK3_ID, -1,
244 };
245 
246 /*
247  * Sensors
248  */
249 static env_sensor_t envd_sensor_cpu0 = {
250 	SENSOR_CPU0, SENSOR_CPU0_DEVFS, CPU0_SENSOR_ID, -1, NULL,
251 };
252 static env_sensor_t envd_sensor_cpu1 = {
253 	SENSOR_CPU1, SENSOR_CPU1_DEVFS, CPU1_SENSOR_ID, -1, NULL,
254 };
255 static env_sensor_t envd_sensor_adt7462 = {
256 	SENSOR_ADT7462, SENSOR_ADT7462_DEVFS, ADT7462_SENSOR_ID, -1, NULL,
257 };
258 static env_sensor_t envd_sensor_mb = {
259 	SENSOR_MB, SENSOR_MB_DEVFS, MB_SENSOR_ID, -1, NULL,
260 };
261 static env_sensor_t envd_sensor_lm95221 = {
262 	SENSOR_LM95221, SENSOR_LM95221_DEVFS, LM95221_SENSOR_ID, -1, NULL,
263 };
264 static env_sensor_t envd_sensor_fire = {
265 	SENSOR_FIRE, SENSOR_FIRE_DEVFS, FIRE_SENSOR_ID, -1, NULL,
266 };
267 static env_sensor_t envd_sensor_lsi1064 = {
268 	SENSOR_LSI1064, SENSOR_LSI1064_DEVFS, LSI1064_SENSOR_ID, -1, NULL,
269 };
270 static env_sensor_t envd_sensor_front_panel = {
271 	SENSOR_FRONT_PANEL, SENSOR_FRONT_PANEL_DEVFS, FRONT_PANEL_SENSOR_ID,
272 	-1, NULL,
273 };
274 static env_sensor_t envd_sensor_psu = {
275 	SENSOR_PSU, SENSOR_PSU_DEVFS, PSU_SENSOR_ID, -1, NULL,
276 };
277 
278 /*
279  * The vendor-id and device-id are the properties associated with
280  * the SCSI controller. This is used to identify a particular controller
281  * like LSI1064.
282  */
283 #define	VENDOR_ID	"vendor-id"
284 #define	DEVICE_ID	"device-id"
285 
286 /*
287  * The implementation for SCSI disk drives to supply info. about
288  * temperature is not mandatory. Hence we first determine if the
289  * temperature page is supported. To do this we need to scan the list
290  * of pages supported.
291  */
292 #define	SUPPORTED_LPAGES	0
293 #define	TEMPERATURE_PAGE	0x0D
294 #define	LOGPAGEHDRSIZE	4
295 
296 /*
297  * NULL terminated array of fans
298  */
299 static env_fan_t *envd_fans[] = {
300 	&envd_system_fan0,
301 	&envd_system_fan1,
302 	&envd_system_fan2,
303 	&envd_system_fan3,
304 	&envd_system_fan4,
305 	NULL
306 };
307 
308 /*
309  * NULL terminated array of disks
310  */
311 static env_disk_t *envd_disks[] = {
312 	&envd_disk0,
313 	&envd_disk1,
314 	&envd_disk2,
315 	&envd_disk3,
316 	NULL
317 };
318 
319 /*
320  * NULL terminated array of temperature sensors
321  */
322 #define	N_ENVD_SENSORS	9
323 static env_sensor_t *envd_sensors[] = {
324 	&envd_sensor_cpu0,
325 	&envd_sensor_cpu1,
326 	&envd_sensor_adt7462,
327 	&envd_sensor_mb,
328 	&envd_sensor_lm95221,
329 	&envd_sensor_fire,
330 	&envd_sensor_lsi1064,
331 	&envd_sensor_front_panel,
332 	&envd_sensor_psu,
333 	NULL
334 };
335 
336 #define	NOT_AVAILABLE	"NA"
337 
338 /*
339  * Tuneables
340  */
341 #define	ENABLE	1
342 #define	DISABLE	0
343 
344 static	int	disk_high_warn_temperature	= DISK_HIGH_WARN_TEMPERATURE;
345 static	int	disk_low_warn_temperature	= DISK_LOW_WARN_TEMPERATURE;
346 static	int	disk_high_shutdown_temperature	=
347 						DISK_HIGH_SHUTDOWN_TEMPERATURE;
348 static	int	disk_low_shutdown_temperature	= DISK_LOW_SHUTDOWN_TEMPERATURE;
349 
350 static	int	disk_scan_interval		= DISK_SCAN_INTERVAL;
351 static	int	sensor_scan_interval		= SENSOR_SCAN_INTERVAL;
352 static	int	fan_scan_interval		= FAN_SCAN_INTERVAL;
353 
354 static int get_int_val(ptree_rarg_t *parg, void *buf);
355 static int set_int_val(ptree_warg_t *parg, const void *buf);
356 static int get_string_val(ptree_rarg_t *parg, void *buf);
357 static int set_string_val(ptree_warg_t *parg, const void *buf);
358 
359 static int 	shutdown_override	= 0;
360 static int	sensor_warning_interval	= SENSOR_WARNING_INTERVAL;
361 static int	sensor_warning_duration	= SENSOR_WARNING_DURATION;
362 static int	sensor_shutdown_interval = SENSOR_SHUTDOWN_INTERVAL;
363 static int	disk_warning_interval	= DISK_WARNING_INTERVAL;
364 static int	disk_warning_duration	= DISK_WARNING_DURATION;
365 static int 	disk_shutdown_interval	= DISK_SHUTDOWN_INTERVAL;
366 
367 static int	system_temp_monitor	= 1;	/* enabled */
368 static int	fan_monitor		= 1;	/* enabled */
369 static int	pm_monitor		= 1;	/* enabled */
370 
371 /* Disable disk temperature monitoring until we have LSI fw support */
372 int		disk_temp_monitor	= 0;
373 
374 static char	shutdown_cmd[] = SHUTDOWN_CMD;
375 const char	*iofru_devname = I2C_DEVFS "/" IOFRU_DEV;
376 
377 env_tuneable_t tuneables[] = {
378 	{"system_temp-monitor", PICL_PTYPE_INT, &system_temp_monitor,
379 	    &get_int_val, &set_int_val, sizeof (int)},
380 
381 	{"fan-monitor", PICL_PTYPE_INT, &fan_monitor,
382 	    &get_int_val, &set_int_val, sizeof (int)},
383 
384 	{"pm-monitor", PICL_PTYPE_INT, &pm_monitor,
385 	    &get_int_val, &set_int_val, sizeof (int)},
386 
387 	{"shutdown-override", PICL_PTYPE_INT, &shutdown_override,
388 	    &get_int_val, &set_int_val, sizeof (int)},
389 
390 	{"sensor-warning-duration", PICL_PTYPE_INT,
391 	    &sensor_warning_duration,
392 	    &get_int_val, &set_int_val,
393 	    sizeof (int)},
394 
395 	{"disk-scan-interval", PICL_PTYPE_INT,
396 	    &disk_scan_interval,
397 	    &get_int_val, &set_int_val,
398 	    sizeof (int)},
399 
400 	{"fan-scan-interval", PICL_PTYPE_INT,
401 	    &fan_scan_interval,
402 	    &get_int_val, &set_int_val,
403 	    sizeof (int)},
404 
405 	{"sensor-scan-interval", PICL_PTYPE_INT,
406 	    &sensor_scan_interval,
407 	    &get_int_val, &set_int_val,
408 	    sizeof (int)},
409 
410 	{"sensor_warning-interval", PICL_PTYPE_INT, &sensor_warning_interval,
411 	    &get_int_val, &set_int_val,
412 	    sizeof (int)},
413 
414 	{"sensor_shutdown-interval", PICL_PTYPE_INT, &sensor_shutdown_interval,
415 	    &get_int_val, &set_int_val,
416 	    sizeof (int)},
417 
418 	{"disk_warning-interval", PICL_PTYPE_INT, &disk_warning_interval,
419 	    &get_int_val, &set_int_val,
420 	    sizeof (int)},
421 
422 	{"disk_warning-duration", PICL_PTYPE_INT, &disk_warning_duration,
423 	    &get_int_val, &set_int_val,
424 	    sizeof (int)},
425 
426 	{"disk_shutdown-interval", PICL_PTYPE_INT, &disk_shutdown_interval,
427 	    &get_int_val, &set_int_val,
428 	    sizeof (int)},
429 
430 	{"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd,
431 	    &get_string_val, &set_string_val,
432 	    sizeof (shutdown_cmd)},
433 
434 	{"monitor-disk-temp", PICL_PTYPE_INT, &disk_temp_monitor,
435 	    &get_int_val, &set_int_val, sizeof (int)},
436 
437 	{"disk-high-warn-temperature", PICL_PTYPE_INT,
438 	    &disk_high_warn_temperature, &get_int_val,
439 	    &set_int_val, sizeof (int)},
440 
441 	{"disk-low-warn-temperature", PICL_PTYPE_INT,
442 	    &disk_low_warn_temperature, &get_int_val,
443 	    &set_int_val, sizeof (int)},
444 
445 	{"disk-high-shutdown-temperature", PICL_PTYPE_INT,
446 	    &disk_high_shutdown_temperature, &get_int_val,
447 	    &set_int_val, sizeof (int)},
448 
449 	{"disk-low-shutdown-temperature", PICL_PTYPE_INT,
450 	    &disk_low_shutdown_temperature, &get_int_val,
451 	    &set_int_val, sizeof (int)},
452 
453 	{"verbose", PICL_PTYPE_INT, &env_debug,
454 	    &get_int_val, &set_int_val, sizeof (int)}
455 };
456 
457 /*
458  * We use this to figure out how many tuneables there are
459  * This is variable because the publishing routine needs this info
460  * in piclenvsetup.c
461  */
462 int	ntuneables = (sizeof (tuneables)/sizeof (tuneables[0]));
463 
464 /*
465  * Lookup fan and return a pointer to env_fan_t data structure.
466  */
467 env_fan_t *
468 fan_lookup(char *name)
469 {
470 	int		i;
471 	env_fan_t	*fanp;
472 
473 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
474 		if (strcmp(fanp->name, name) == 0)
475 			return (fanp);
476 	}
477 	return (NULL);
478 }
479 
480 /*
481  * Lookup sensor and return a pointer to env_sensor_t data structure.
482  */
483 env_sensor_t *
484 sensor_lookup(char *name)
485 {
486 	env_sensor_t	*sensorp;
487 	int		i;
488 
489 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
490 		sensorp = envd_sensors[i];
491 		if (strcmp(sensorp->name, name) == 0)
492 			return (sensorp);
493 	}
494 	return (NULL);
495 }
496 
497 /*
498  * Lookup disk and return a pointer to env_disk_t data structure.
499  */
500 env_disk_t *
501 disk_lookup(char *name)
502 {
503 	int		i;
504 	env_disk_t	*diskp;
505 
506 	for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
507 		if (strncmp(diskp->name, name, strlen(name)) == 0)
508 			return (diskp);
509 	}
510 	return (NULL);
511 }
512 
513 /*
514  * Get current temperature
515  * Returns -1 on error, 0 if successful
516  */
517 int
518 get_temperature(env_sensor_t *sensorp, tempr_t *temp)
519 {
520 	int	fd = sensorp->fd;
521 	int	retval = 0;
522 
523 	if (fd == -1)
524 		retval = -1;
525 	else if (ioctl(fd, PIC_GET_TEMPERATURE, temp) != 0) {
526 
527 		retval = -1;
528 
529 		sensorp->error++;
530 
531 		if (sensorp->error == MAX_SENSOR_RETRIES) {
532 			envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL,
533 			    sensorp->name, errno, strerror(errno));
534 		}
535 
536 		total_temp_retries++;
537 		(void) sleep(1);
538 
539 	} else if (sensorp->error != 0) {
540 		if (sensorp->error >= MAX_SENSOR_RETRIES) {
541 			envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK,
542 			    sensorp->name);
543 		}
544 
545 		sensorp->error = 0;
546 
547 		if (total_temp_retries && env_debug) {
548 			envd_log(LOG_WARNING,
549 			    "Total retries for sensors = %d",
550 			    total_temp_retries);
551 		}
552 	}
553 
554 	return (retval);
555 }
556 
557 /*
558  * Get current disk temperature
559  * Returns -1 on error, 0 if successful
560  */
561 int
562 disk_temperature(env_disk_t *diskp, tempr_t *temp)
563 {
564 	int	retval = 0;
565 
566 	if (diskp == NULL)
567 		retval = -1;
568 	else
569 		*temp = diskp->current_temp;
570 
571 	return (retval);
572 }
573 
574 /*
575  * Get current fan speed
576  * This function returns a RPM value for fanspeed
577  * in fanspeedp.
578  * Returns -1 on error, 0 if successful
579  */
580 int
581 get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp)
582 {
583 	uint8_t tach;
584 	int	real_tach;
585 	int	retries;
586 
587 	if (fanp->fd == -1)
588 		return (-1);
589 
590 	if (has_fan_failed(fanp)) {
591 		*fanspeedp = 0;
592 		return (0);
593 	}
594 
595 	/* try to read the fan information */
596 	for (retries = 0; retries <= MAX_FAN_RETRIES; retries++) {
597 		if (ioctl(fanp->fd, PIC_GET_FAN_SPEED, &tach) == 0)
598 			break;
599 		(void) sleep(1);
600 	}
601 
602 	total_fan_retries += retries;
603 	if (retries == MAX_FAN_RETRIES)
604 		return (-1);
605 
606 	if (total_fan_retries && env_debug) {
607 		envd_log(LOG_WARNING, "total retries for fan = %d",
608 		    total_fan_retries);
609 	}
610 
611 	real_tach = tach << 8;
612 	*fanspeedp = TACH_TO_RPM(real_tach);
613 	return (0);
614 }
615 
616 /*
617  * Set fan speed
618  * This function accepts a percentage of fan speed
619  * from 0-100 and programs the HW monitor fans to the corresponding
620  * fanspeed value.
621  * Returns -1 on error, -2 on invalid args passed, 0 if successful
622  */
623 int
624 set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed)
625 {
626 	uint8_t	speed;
627 
628 	if (fanp->fd == -1)
629 		return (-1);
630 
631 	if (fanspeed < 0 || fanspeed > 100)
632 		return (-2);
633 
634 	speed = fanspeed;
635 	if (ioctl(fanp->fd, PIC_SET_FAN_SPEED, &speed) != 0)
636 		return (-1);
637 
638 	return (0);
639 }
640 
641 /*
642  * close all fan devices
643  */
644 static void
645 envd_close_fans(void)
646 {
647 	int		i;
648 	env_fan_t	*fanp;
649 
650 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
651 		if (fanp->fd != -1) {
652 			(void) close(fanp->fd);
653 			fanp->fd = -1;
654 		}
655 	}
656 }
657 
658 /*
659  * Close sensor devices and freeup resources
660  */
661 static void
662 envd_close_sensors(void)
663 {
664 	env_sensor_t	*sensorp;
665 	int		i;
666 
667 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
668 		sensorp = envd_sensors[i];
669 		if (sensorp->fd != -1) {
670 			(void) close(sensorp->fd);
671 			sensorp->fd = -1;
672 		}
673 	}
674 }
675 
676 /*
677  * Open fan devices and initialize per fan data structure.
678  */
679 static int
680 envd_setup_fans(void)
681 {
682 	int		i, fd;
683 	env_fan_t	*fanp;
684 	int		fancnt = 0;
685 	picl_nodehdl_t tnodeh;
686 
687 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
688 		fanp->last_status = FAN_OK;
689 
690 		/* Make sure cpu0/1 present for validating cpu fans */
691 		if (fanp->id == CPU0_FAN_ID) {
692 			if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) !=
693 			    PICL_SUCCESS) {
694 					if (env_debug) {
695 						envd_log(LOG_ERR,
696 					"get node by path failed for %s\n",
697 						    CPU0_PATH);
698 					}
699 					fanp->present = B_FALSE;
700 					continue;
701 			}
702 		}
703 		if (fanp->id == CPU1_FAN_ID) {
704 			if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) !=
705 			    PICL_SUCCESS) {
706 					if (env_debug) {
707 						envd_log(LOG_ERR,
708 				"get node by path failed for %s\n", CPU0_PATH);
709 					}
710 					fanp->present = B_FALSE;
711 					continue;
712 			}
713 		}
714 		if ((fd = open(fanp->devfs_path, O_RDWR)) == -1) {
715 			envd_log(LOG_CRIT,
716 			    ENV_FAN_OPEN_FAIL, fanp->name,
717 			    fanp->devfs_path, errno, strerror(errno));
718 			fanp->present = B_FALSE;
719 			continue;
720 		}
721 		fanp->fd = fd;
722 		fanp->present = B_TRUE;
723 		fancnt++;
724 	}
725 
726 	if (fancnt == 0)
727 		return (-1);
728 
729 	return (0);
730 }
731 
732 static int
733 envd_setup_disks(void)
734 {
735 	int	ret, i, page_index, page_len;
736 	picl_nodehdl_t tnodeh;
737 	env_disk_t	*diskp;
738 	uint_t	vendor_id;
739 	uint_t	device_id;
740 	uchar_t	log_page[256];
741 
742 	if (ptree_get_node_by_path(SCSI_CONTROLLER_NODE_PATH,
743 	    &tnodeh) != PICL_SUCCESS) {
744 		if (env_debug) {
745 			envd_log(LOG_ERR, "On-Board SCSI controller %s "
746 			    "not found in the system.\n",
747 			    SCSI_CONTROLLER_NODE_PATH);
748 		}
749 		return (-1);
750 	}
751 
752 	if ((ret = ptree_get_propval_by_name(tnodeh, VENDOR_ID,
753 	    &vendor_id, sizeof (vendor_id))) != 0) {
754 		if (env_debug) {
755 			envd_log(LOG_ERR, "Error in getting vendor-id "
756 			    "for SCSI controller. ret = %d errno = 0x%d\n",
757 			    ret, errno);
758 		}
759 		return (-1);
760 	}
761 	if ((ret = ptree_get_propval_by_name(tnodeh, DEVICE_ID,
762 	    &device_id, sizeof (device_id))) != 0) {
763 		if (env_debug) {
764 			envd_log(LOG_ERR, "Error in getting device-id "
765 			    "for SCSI controller. ret = %d errno = 0x%d\n",
766 			    ret, errno);
767 		}
768 		return (-1);
769 	}
770 
771 	/*
772 	 * We have found LSI1064 SCSi controller onboard.
773 	 */
774 	for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
775 		if (ptree_get_node_by_path(diskp->nodepath,
776 		    &tnodeh) != PICL_SUCCESS) {
777 			diskp->present = B_FALSE;
778 			if (env_debug) {
779 				envd_log(LOG_ERR,
780 				    "DISK %d: %s not found in the system.\n",
781 				    diskp->id, diskp->nodepath);
782 			}
783 			continue;
784 		}
785 		if ((diskp->fd = open(diskp->devfs_path, O_RDONLY)) == -1) {
786 			diskp->present = B_FALSE;
787 			if (env_debug) {
788 				envd_log(LOG_ERR,
789 				    "Error in opening %s errno = 0x%x\n",
790 				    diskp->devfs_path, errno);
791 			}
792 			continue;
793 		}
794 		diskp->present = B_TRUE;
795 		diskp->tpage_supported = B_FALSE;
796 		diskp->smart_supported = B_FALSE;
797 		diskp->warning_tstamp = 0;
798 		diskp->shutdown_tstamp = 0;
799 		diskp->high_warning = disk_high_warn_temperature;
800 		diskp->low_warning = disk_low_warn_temperature;
801 		diskp->high_shutdown = disk_high_shutdown_temperature;
802 		diskp->low_shutdown = disk_low_shutdown_temperature;
803 		/*
804 		 * Find out if the Temperature page is supported by the disk.
805 		 */
806 		if (scsi_log_sense(diskp, SUPPORTED_LPAGES, log_page,
807 		    sizeof (log_page), 1) == 0) {
808 
809 			page_len = ((log_page[2] << 8) & 0xFF00) | log_page[3];
810 
811 			for (page_index = LOGPAGEHDRSIZE;
812 			    page_index < page_len + LOGPAGEHDRSIZE;
813 			    page_index++) {
814 				if (log_page[page_index] != TEMPERATURE_PAGE)
815 					continue;
816 
817 				diskp->tpage_supported = B_TRUE;
818 				if (env_debug) {
819 					envd_log(LOG_ERR,
820 					    "tpage supported for %s\n",
821 					    diskp->nodepath);
822 				}
823 			}
824 		}
825 		/*
826 		 * If the temp log page failed, we can check if this is
827 		 * a SATA drive and attempt to read the temperature
828 		 * using the SMART interface.
829 		 */
830 		if (diskp->tpage_supported != B_TRUE) {
831 			uchar_t iec_page[IEC_PAGE_SIZE];
832 
833 			if (env_debug)
834 				envd_log(LOG_ERR, "Turning on SMART\n");
835 
836 			(void) memset(iec_page, 0, sizeof (iec_page));
837 			iec_page[0] = IEC_PAGE;	/* SMART PAGE */
838 			iec_page[1] = 0xa;	/* length */
839 			/* Notification, only when requested */
840 			iec_page[3] = REPORT_ON_REQUEST;
841 
842 			ret = scsi_mode_select(diskp, IEC_PAGE,
843 			    iec_page, sizeof (iec_page));
844 
845 			/*
846 			 * Since we know this is a SMART capable
847 			 * drive, we will try to set the page and
848 			 * determine if the drive is not capable
849 			 * of reading the TEMP page when we
850 			 * try to read the temperature and disable
851 			 * it then. We do not fail when reading
852 			 * or writing this page because we will
853 			 * determine the SMART capabilities
854 			 * when reading the temperature.
855 			 */
856 			if ((ret != 0) && (env_debug)) {
857 				envd_log(LOG_ERR,
858 				    "Failed to set mode page");
859 			}
860 
861 			diskp->smart_supported = B_TRUE;
862 			diskp->tpage_supported = B_TRUE;
863 		}
864 
865 		if (get_disk_temp(diskp) < 0) {
866 			envd_log(LOG_ERR, " error reading temperature of:%s\n",
867 			    diskp->name);
868 		} else if (env_debug) {
869 			envd_log(LOG_ERR, "%s: temperature = %d\n",
870 			    diskp->name, diskp->current_temp);
871 		}
872 
873 	}
874 
875 	return (0);
876 }
877 
878 static int
879 envd_es_setup(void)
880 {
881 	seeprom_scn_t	scn_hdr;
882 	seeprom_seg_t	seg_hdr;
883 	es_data_t	*envseg;
884 	es_sensor_t	*sensorp;
885 	int		i, fd, id;
886 	int		envseg_len, esd_len;
887 	char		*envsegp;
888 
889 	/*
890 	 * Open the front io fru
891 	 */
892 	if ((fd = open(iofru_devname, O_RDONLY)) == -1) {
893 		envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, iofru_devname, errno);
894 		return (-1);
895 	}
896 
897 	/*
898 	 * Read section header from the fru SEEPROM
899 	 */
900 	if (lseek(fd, SSCN_OFFSET, SEEK_SET) == (off_t)-1 ||
901 	    read(fd, &scn_hdr, sizeof (scn_hdr)) != sizeof (scn_hdr)) {
902 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
903 		(void) close(fd);
904 		return (-1);
905 	}
906 	if ((scn_hdr.sscn_tag != SSCN_TAG) ||
907 	    (GET_UNALIGN16(&scn_hdr.sscn_ver) != SSCN_VER)) {
908 		envd_log(LOG_ERR, ENV_FRU_BAD_SCNHDR, scn_hdr.sscn_tag,
909 		    GET_UNALIGN16(&scn_hdr.sscn_ver));
910 		(void) close(fd);
911 		return (-1);
912 	}
913 
914 	/*
915 	 * Locate environmental segment
916 	 */
917 	for (i = 0; i < scn_hdr.sscn_nsegs; i++) {
918 		if (read(fd, &seg_hdr, sizeof (seg_hdr)) != sizeof (seg_hdr)) {
919 			envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
920 			(void) close(fd);
921 			return (-1);
922 		}
923 
924 		if (env_debug) {
925 			envd_log(LOG_INFO,
926 			    "Seg name: %x off:%x len:%x\n",
927 			    GET_UNALIGN16(&seg_hdr.sseg_name),
928 			    GET_UNALIGN16(&seg_hdr.sseg_off),
929 			    GET_UNALIGN16(&seg_hdr.sseg_len));
930 		}
931 
932 		if (GET_UNALIGN16(&seg_hdr.sseg_name) == ENVSEG_NAME)
933 			break;
934 	}
935 	if (i == scn_hdr.sscn_nsegs) {
936 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
937 		(void) close(fd);
938 		return (-1);
939 	}
940 
941 	/*
942 	 * Read environmental segment
943 	 */
944 	envseg_len = GET_UNALIGN16(&seg_hdr.sseg_len);
945 	if ((envseg = malloc(envseg_len)) == NULL) {
946 		envd_log(LOG_ERR, ENV_FRU_NOMEM_FOR_SEG, envseg_len);
947 		(void) close(fd);
948 		return (-1);
949 	}
950 
951 	if (lseek(fd, (off_t)GET_UNALIGN16(&seg_hdr.sseg_off),
952 	    SEEK_SET) == (off_t)-1 ||
953 	    read(fd, envseg, envseg_len) != envseg_len) {
954 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
955 		free(envseg);
956 		(void) close(fd);
957 		return (-1);
958 	}
959 
960 	/*
961 	 * Check environmental segment data for consistency
962 	 */
963 	esd_len = sizeof (*envseg) +
964 	    (envseg->esd_nsensors - 1) * sizeof (envseg->esd_sensors[0]);
965 	if (envseg->esd_ver != ENVSEG_VERSION || envseg_len < esd_len) {
966 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
967 		free(envseg);
968 		(void) close(fd);
969 		return (-1);
970 	}
971 
972 	/*
973 	 * Process environmental segment data
974 	 */
975 	if (envseg->esd_nsensors > MAX_SENSORS) {
976 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
977 		free(envseg);
978 		(void) close(fd);
979 		return (-1);
980 	}
981 
982 	sensorp = &(envseg->esd_sensors[0]);
983 	envsegp = (char *)envseg;
984 	for (i = 0; i < envseg->esd_nsensors; i++) {
985 		uint32_t ess_id;
986 
987 		(void) memcpy(&ess_id,
988 			sensorp->ess_id, sizeof (sensorp->ess_id));
989 
990 		if (env_debug) {
991 			envd_log(LOG_INFO, "\n Sensor Id %x offset %x",
992 			    ess_id, sensorp->ess_off);
993 		}
994 		if (ess_id >= MAX_SENSORS) {
995 			envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
996 			free(envseg);
997 			(void) close(fd);
998 			return (-1);
999 		}
1000 		(void) memcpy(&sensor_ctl[ess_id], &envsegp[sensorp->ess_off],
1001 		    sizeof (es_sensor_blk_t));
1002 
1003 		sensorp++;
1004 	}
1005 
1006 	/*
1007 	 * Match sensor/ES id and point to correct data based on IDs
1008 	 */
1009 	for (i = 0; i < N_ENVD_SENSORS; i++) {
1010 		id = envd_sensors[i]->id;
1011 		envd_sensors[i]->es = &sensor_ctl[id];
1012 	}
1013 
1014 	/*
1015 	 * Cleanup and return
1016 	 */
1017 	free(envseg);
1018 	(void) close(fd);
1019 
1020 	return (0);
1021 }
1022 
1023 static void
1024 envd_es_default_setup(void)
1025 {
1026 	int	i, id;
1027 
1028 	for (i = 0; i < N_ENVD_SENSORS; i++) {
1029 		id = envd_sensors[i]->id;
1030 		envd_sensors[i]->es = &sensor_default_ctl[id];
1031 	}
1032 }
1033 
1034 /*
1035  * Open temperature sensor devices and initialize per sensor data structure.
1036  */
1037 static int
1038 envd_setup_sensors(void)
1039 {
1040 	env_sensor_t	*sensorp;
1041 	int		sensorcnt = 0;
1042 	int		i;
1043 	picl_nodehdl_t	tnodeh;
1044 
1045 	for (i = 0; i < N_ENVD_SENSORS; i++) {
1046 		if (env_debug)
1047 			envd_log(LOG_ERR, "scanning sensor %d\n", i);
1048 
1049 		sensorp = envd_sensors[i];
1050 
1051 		/* Initialize sensor's initial state */
1052 		sensorp->shutdown_initiated = B_FALSE;
1053 		sensorp->warning_tstamp = 0;
1054 		sensorp->shutdown_tstamp = 0;
1055 		sensorp->error = 0;
1056 
1057 		/* Make sure cpu0/1 sensors are present */
1058 		if (sensorp->id == CPU0_SENSOR_ID) {
1059 			if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) !=
1060 			    PICL_SUCCESS) {
1061 				if (env_debug) {
1062 					envd_log(LOG_ERR,
1063 					    "get node by path failed for %s\n",
1064 					    CPU0_PATH);
1065 				}
1066 				sensorp->present = B_FALSE;
1067 				continue;
1068 			}
1069 		}
1070 		if (sensorp->id == CPU1_SENSOR_ID) {
1071 			if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) !=
1072 			    PICL_SUCCESS) {
1073 				if (env_debug) {
1074 					envd_log(LOG_ERR,
1075 					    "get node by path failed for %s\n",
1076 					    CPU1_PATH);
1077 				}
1078 				sensorp->present = B_FALSE;
1079 				continue;
1080 			}
1081 		}
1082 
1083 		sensorp->fd = open(sensorp->devfs_path, O_RDWR);
1084 		if (sensorp->fd == -1) {
1085 			if (env_debug) {
1086 				envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL,
1087 				    sensorp->name, sensorp->devfs_path,
1088 				    errno, strerror(errno));
1089 			}
1090 			sensorp->present = B_FALSE;
1091 			continue;
1092 		}
1093 
1094 		/*
1095 		 * Determine if the front panel is attached, we want the
1096 		 * information if it exists, but should not shut down
1097 		 * the system if it is removed.
1098 		 */
1099 		if (sensorp->id == FRONT_PANEL_SENSOR_ID) {
1100 			tempr_t temp;
1101 			int	tries;
1102 
1103 			for (tries = 0; tries < MAX_SENSOR_RETRIES; tries++) {
1104 				if (ioctl(sensorp->fd, PIC_GET_TEMPERATURE,
1105 				    &temp) == 0) {
1106 					break;
1107 				}
1108 				(void) sleep(1);
1109 			}
1110 			if (tries == MAX_SENSOR_RETRIES)
1111 				sensorp->present = B_FALSE;
1112 		}
1113 
1114 		sensorp->present = B_TRUE;
1115 		sensorcnt++;
1116 	}
1117 
1118 	if (sensorcnt == 0)
1119 		return (-1);
1120 
1121 	return (0);
1122 }
1123 
1124 /* ARGSUSED */
1125 static void *
1126 pmthr(void *args)
1127 {
1128 	pm_state_change_t	pmstate;
1129 	char			physpath[PATH_MAX];
1130 	int			pre_lpstate;
1131 	uint8_t			estar_state;
1132 	int			env_monitor_fd;
1133 
1134 	pmstate.physpath = physpath;
1135 	pmstate.size = sizeof (physpath);
1136 	cur_lpstate = 0;
1137 	pre_lpstate = 1;
1138 
1139 	pm_fd = open(PM_DEVICE, O_RDWR);
1140 	if (pm_fd == -1) {
1141 		envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno));
1142 		return (NULL);
1143 	}
1144 	for (;;) {
1145 		/*
1146 		 * Get PM state change events to check if the system
1147 		 * is in lowest power state and inform PIC which controls
1148 		 * fan speeds.
1149 		 *
1150 		 * To minimize polling, we use the blocking interface
1151 		 * to get the power state change event here.
1152 		 */
1153 		if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) {
1154 			if (errno != EINTR)
1155 				break;
1156 			continue;
1157 		}
1158 
1159 		do {
1160 			if (env_debug)  {
1161 				envd_log(LOG_INFO,
1162 				"pmstate event:0x%x flags:%x"
1163 				"comp:%d oldval:%d newval:%d path:%s\n",
1164 				    pmstate.event, pmstate.flags,
1165 				    pmstate.component,
1166 				    pmstate.old_level,
1167 				    pmstate.new_level,
1168 				    pmstate.physpath);
1169 			}
1170 			cur_lpstate =
1171 			    (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0;
1172 		} while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0);
1173 
1174 		if (pre_lpstate != cur_lpstate) {
1175 			pre_lpstate = cur_lpstate;
1176 			estar_state = (cur_lpstate & 0x1);
1177 			if (env_debug)
1178 				envd_log(LOG_ERR,
1179 				    "setting PIC ESTAR SATE to %x\n",
1180 				    estar_state);
1181 
1182 			env_monitor_fd = open(ENV_MONITOR_DEVFS, O_RDWR);
1183 			if (env_monitor_fd != -1) {
1184 				if (ioctl(env_monitor_fd, PIC_SET_ESTAR_MODE,
1185 				    &estar_state) < 0) {
1186 					if (env_debug)
1187 						envd_log(LOG_ERR,
1188 					"unable to set ESTAR_MODE in PIC\n");
1189 				}
1190 				(void) close(env_monitor_fd);
1191 			} else {
1192 				if (env_debug)
1193 					envd_log(LOG_ERR,
1194 				"Failed to open %s\n",
1195 					    ENV_MONITOR_DEVFS);
1196 			}
1197 		}
1198 	}
1199 
1200 	/*NOTREACHED*/
1201 	return (NULL);
1202 }
1203 
1204 /*
1205  * This is env thread which monitors the current temperature when
1206  * warning threshold is exceeded. The job is to make sure it does
1207  * not execced/decrease shutdown threshold. If it does it will start
1208  * forced shutdown to avoid reaching hardware poweroff via THERM interrupt.
1209  */
1210 /*ARGSUSED*/
1211 static void *
1212 system_temp_thr(void *args)
1213 {
1214 	char syscmd[BUFSIZ];
1215 	char msgbuf[BUFSIZ];
1216 	timespec_t	to;
1217 	int	ret, i;
1218 	env_sensor_t	*sensorp;
1219 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
1220 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
1221 	time_t	ct;
1222 	tempr_t  temp;
1223 
1224 	for (;;) {
1225 		/*
1226 		 * Sleep for specified seconds before issuing IOCTL
1227 		 * again.
1228 		 */
1229 		(void) pthread_mutex_lock(&env_monitor_mutex);
1230 		ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
1231 		    &env_monitor_mutex, &to);
1232 		to.tv_sec = sensor_scan_interval;
1233 		to.tv_nsec = 0;
1234 		if (ret != ETIMEDOUT) {
1235 			(void) pthread_mutex_unlock(&env_monitor_mutex);
1236 			continue;
1237 		}
1238 
1239 		(void) pthread_mutex_unlock(&env_monitor_mutex);
1240 		for (i = 0; i < N_ENVD_SENSORS; i++) {
1241 			sensorp = envd_sensors[i];
1242 			if (sensorp->present == B_FALSE)
1243 				continue;
1244 			if (get_temperature(sensorp, &temp) == -1)
1245 				continue;
1246 
1247 			sensorp->cur_temp = temp;
1248 			if (env_debug) {
1249 				envd_log(LOG_ERR,
1250 				"%s temp = %d",
1251 				    sensorp->name, sensorp->cur_temp);
1252 			}
1253 
1254 			/*
1255 			 * If this sensor already triggered system shutdown,
1256 			 * don't log any more shutdown/warning messages for it.
1257 			 */
1258 			if (sensorp->shutdown_initiated)
1259 				continue;
1260 
1261 			/*
1262 			 * Check for the temperature in warning and shutdown
1263 			 * range and take appropriate action.
1264 			 */
1265 			if (SENSOR_TEMP_IN_WARNING_RANGE(sensorp->cur_temp,
1266 			    sensorp)) {
1267 				/*
1268 				 * Check if the temperature has been in
1269 				 * warning range during last
1270 				 * sensor_warning_duration interval. If so,
1271 				 * the temperature is truly in warning range
1272 				 * and we need to log a warning message, but
1273 				 * no more than once every
1274 				 * sensor_warning_interval seconds.
1275 				 */
1276 				time_t	wtstamp = sensorp->warning_tstamp;
1277 
1278 				ct = (time_t)(gethrtime() / NANOSEC);
1279 				if (sensorp->warning_start == 0)
1280 					sensorp->warning_start = ct;
1281 				if (((ct - sensorp->warning_start) >=
1282 				    sensor_warning_duration) &&
1283 				    (wtstamp == 0 || (ct - wtstamp) >=
1284 				    sensor_warning_interval)) {
1285 					envd_log(LOG_CRIT, ENV_WARNING_MSG,
1286 					    sensorp->name, sensorp->cur_temp,
1287 					    sensorp->es->esb_low_warning,
1288 					    sensorp->es->esb_high_warning);
1289 					sensorp->warning_tstamp = ct;
1290 				}
1291 			} else if (sensorp->warning_start != 0)
1292 				sensorp->warning_start = 0;
1293 
1294 			if (!shutdown_override &&
1295 			    SENSOR_TEMP_IN_SHUTDOWN_RANGE(sensorp->cur_temp,
1296 			    sensorp)) {
1297 				ct = (time_t)(gethrtime() / NANOSEC);
1298 				if (sensorp->shutdown_tstamp == 0)
1299 					sensorp->shutdown_tstamp = ct;
1300 
1301 				/*
1302 				 * Shutdown the system if the temperature
1303 				 * remains in the shutdown range for over
1304 				 * sensor_shutdown_interval seconds.
1305 				 */
1306 				if ((ct - sensorp->shutdown_tstamp) >=
1307 				    sensor_shutdown_interval) {
1308 					/*
1309 					 * Log error
1310 					 */
1311 					sensorp->shutdown_initiated = B_TRUE;
1312 					(void) snprintf(msgbuf, sizeof (msgbuf),
1313 					    ENV_SHUTDOWN_MSG, sensorp->name,
1314 					    sensorp->cur_temp,
1315 					    sensorp->es->esb_low_shutdown,
1316 					    sensorp->es->esb_high_shutdown);
1317 					envd_log(LOG_ALERT, msgbuf);
1318 
1319 					/*
1320 					 * Shutdown the system (only once)
1321 					 */
1322 					if (system_shutdown_started ==
1323 					    B_FALSE) {
1324 						(void) snprintf(syscmd,
1325 						    sizeof (syscmd),
1326 						    "%s \"%s\"", shutdown_cmd,
1327 						    msgbuf);
1328 
1329 						envd_log(LOG_ALERT, syscmd);
1330 						system_shutdown_started =
1331 						    B_TRUE;
1332 
1333 						(void) system(syscmd);
1334 					}
1335 				}
1336 			} else if (sensorp->shutdown_tstamp != 0)
1337 				sensorp->shutdown_tstamp = 0;
1338 		}
1339 	}	/* end of forever loop */
1340 
1341 	/*NOTREACHED*/
1342 	return (NULL);
1343 }
1344 
1345 static int
1346 scsi_log_sense(env_disk_t *diskp, uchar_t page_code, void *pagebuf,
1347 		uint16_t pagelen, int page_control)
1348 {
1349 	struct uscsi_cmd	ucmd_buf;
1350 	uchar_t		cdb_buf[CDB_GROUP1];
1351 	struct	scsi_extended_sense	sense_buf;
1352 	int	ret_val;
1353 
1354 	bzero(&cdb_buf, sizeof (cdb_buf));
1355 	bzero(&ucmd_buf, sizeof (ucmd_buf));
1356 	bzero(&sense_buf, sizeof (sense_buf));
1357 
1358 	cdb_buf[0] = SCMD_LOG_SENSE_G1;
1359 
1360 	/*
1361 	 * For SATA we need to have the current threshold value set.
1362 	 * For SAS drives we can use the current cumulative value.
1363 	 * This is set for non-SMART drives, by passing a non-zero
1364 	 * page_control.
1365 	 */
1366 	if (page_control)
1367 		cdb_buf[2] = (0x01 << 6) | page_code;
1368 	else
1369 		cdb_buf[2] = page_code;
1370 
1371 	cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8);
1372 	cdb_buf[8] = (uchar_t)(pagelen  & 0x00FF);
1373 
1374 	ucmd_buf.uscsi_cdb = (char *)cdb_buf;
1375 	ucmd_buf.uscsi_cdblen = sizeof (cdb_buf);
1376 	ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf;
1377 	ucmd_buf.uscsi_buflen = pagelen;
1378 	ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf;
1379 	ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense);
1380 	ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT;
1381 	ucmd_buf.uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
1382 
1383 	ret_val = ioctl(diskp->fd, USCSICMD, ucmd_buf);
1384 	if ((ret_val == 0) && (ucmd_buf.uscsi_status == 0)) {
1385 		if (env_debug)
1386 			envd_log(LOG_ERR,
1387 		"log sense command for page_code 0x%x succeeded\n", page_code);
1388 		return (ret_val);
1389 	}
1390 	if (env_debug)
1391 		envd_log(LOG_ERR, "log sense command for %s failed. "
1392 		    "page_code 0x%x ret_val = 0x%x "
1393 		    "status = 0x%x errno = 0x%x\n", diskp->name, page_code,
1394 		    ret_val, ucmd_buf.uscsi_status, errno);
1395 
1396 	return (1);
1397 }
1398 
1399 
1400 static int
1401 get_disk_temp(env_disk_t *diskp)
1402 {
1403 	int	ret;
1404 	uchar_t	tpage[256];
1405 
1406 	if (diskp->smart_supported == B_TRUE) {
1407 		smart_structure	smartpage;
1408 		smart_attribute	*temp_attrib = NULL;
1409 		uint8_t		checksum;
1410 		uint8_t		*index;
1411 		int		i;
1412 
1413 		bzero(&smartpage, sizeof (smartpage));
1414 
1415 		ret = scsi_log_sense(diskp, GET_SMART_INFO,
1416 		    &smartpage, sizeof (smartpage), 0);
1417 
1418 		if (ret != 0) {
1419 			diskp->current_temp = DISK_INVALID_TEMP;
1420 			diskp->ref_temp = DISK_INVALID_TEMP;
1421 			return (-1);
1422 		}
1423 
1424 		/*
1425 		 * verify the checksum of the data. A 2's compliment
1426 		 * of the result addition of the is stored in the
1427 		 * last byte. The sum of all the checksum should be
1428 		 * 0. If the checksum is bad, return an error for
1429 		 * this iteration.
1430 		 */
1431 		index = (uint8_t *)&smartpage;
1432 
1433 		for (i = checksum = 0; i < 512; i++)
1434 			checksum += index[i];
1435 
1436 		if ((checksum != 0) && env_debug) {
1437 			envd_log(LOG_ERR,
1438 			    "SMART checksum error! 0x%x\n", checksum);
1439 
1440 			/*
1441 			 * We got bad data back from the drive, fail this
1442 			 * time around and picl will retry again. If this
1443 			 * continues to fail picl will give this drive a
1444 			 * failed status.
1445 			 */
1446 			diskp->current_temp = DISK_INVALID_TEMP;
1447 			diskp->ref_temp = DISK_INVALID_TEMP;
1448 
1449 			return (-1);
1450 		}
1451 
1452 		/*
1453 		 * Scan through the various SMART data and look for
1454 		 * the complete drive temp.
1455 		 */
1456 
1457 		for (i = 0; (i < SMART_FIELDS) &&
1458 		    (smartpage.attribute[i].id != 0) &&
1459 		    (temp_attrib == NULL); i++) {
1460 
1461 			if (smartpage.attribute[i].id == HDA_TEMP) {
1462 				temp_attrib = &smartpage.attribute[i];
1463 			}
1464 		}
1465 
1466 		/*
1467 		 * If we dont find any temp SMART attributes, this drive
1468 		 * does not support this page, disable temp checking
1469 		 * for this drive.
1470 		 */
1471 		if (temp_attrib == NULL) {
1472 
1473 			/*
1474 			 * If the checksum is valid, the temp. attributes are
1475 			 * not supported, disable this drive from temp.
1476 			 * checking.
1477 			 */
1478 			if (env_debug)
1479 				envd_log(LOG_ERR,
1480 				    "Temp ATTRIBUTE not supported\n");
1481 			diskp->smart_supported = B_FALSE;
1482 			diskp->tpage_supported = B_FALSE;
1483 			diskp->current_temp = DISK_INVALID_TEMP;
1484 			diskp->ref_temp = DISK_INVALID_TEMP;
1485 
1486 			return (-1);
1487 		}
1488 
1489 		if (env_debug) {
1490 			envd_log(LOG_ERR, "flags = 0x%x%x,curr = 0x%x,"
1491 			"data = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
1492 			temp_attrib->flags[0], temp_attrib->flags[1],
1493 			temp_attrib->raw_data[0], temp_attrib->raw_data[1],
1494 			temp_attrib->raw_data[2], temp_attrib->raw_data[3],
1495 			temp_attrib->raw_data[4], temp_attrib->raw_data[5],
1496 			temp_attrib->raw_data[6], temp_attrib->raw_data[7]);
1497 		}
1498 		if (temp_attrib->raw_data[1] != 0xFF) {
1499 			diskp->current_temp = temp_attrib->raw_data[2];
1500 			diskp->ref_temp	= temp_attrib->raw_data[2];
1501 		} else {
1502 			diskp->ref_temp = DISK_INVALID_TEMP;
1503 			diskp->current_temp = DISK_INVALID_TEMP;
1504 
1505 			return (-1);
1506 		}
1507 
1508 	} else {
1509 		ret = scsi_log_sense(diskp, TEMPERATURE_PAGE, tpage,
1510 		    sizeof (tpage), 1);
1511 
1512 		if (ret != 0) {
1513 			diskp->current_temp = DISK_INVALID_TEMP;
1514 			diskp->ref_temp = DISK_INVALID_TEMP;
1515 			return (-1);
1516 		}
1517 		/*
1518 		 * For the current temperature verify that the parameter
1519 		 * length is 0x02 and the parameter code is 0x00
1520 		 * Temperature value of 255(0xFF) is considered INVALID.
1521 		 */
1522 		if ((tpage[7] == 0x02) && (tpage[4] == 0x00) &&
1523 		    (tpage[5] == 0x00)) {
1524 			if (tpage[9] == 0xFF) {
1525 				diskp->current_temp = DISK_INVALID_TEMP;
1526 				return (-1);
1527 			} else {
1528 				diskp->current_temp = tpage[9];
1529 			}
1530 		}
1531 
1532 		/*
1533 		 * For the reference temperature verify that the parameter
1534 		 * length is 0x02 and the parameter code is 0x01
1535 		 * Temperature value of 255(0xFF) is considered INVALID.
1536 		 */
1537 		if ((tpage[13] == 0x02) && (tpage[10] == 0x00) &&
1538 		    (tpage[11] == 0x01)) {
1539 			if (tpage[15] == 0xFF) {
1540 				diskp->ref_temp = DISK_INVALID_TEMP;
1541 			} else {
1542 				diskp->ref_temp = tpage[15];
1543 			}
1544 		}
1545 	}
1546 	return (0);
1547 }
1548 
1549 /* ARGSUSED */
1550 static void *
1551 disk_temp_thr(void *args)
1552 {
1553 	char syscmd[BUFSIZ];
1554 	char msgbuf[BUFSIZ];
1555 	timespec_t	to;
1556 	int	ret, i;
1557 	env_disk_t	*diskp;
1558 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
1559 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
1560 	pm_state_change_t	pmstate;
1561 	int	idle_time;
1562 	int	disk_pm_fd;
1563 	time_t	ct;
1564 
1565 	if ((disk_pm_fd = open(PM_DEVICE, O_RDWR)) == -1) {
1566 		envd_log(LOG_ERR, DISK_TEMP_THREAD_EXITING,
1567 		    errno, strerror(errno));
1568 		return (NULL);
1569 	}
1570 
1571 	for (;;) {
1572 		/*
1573 		 * Sleep for specified seconds before issuing IOCTL
1574 		 * again.
1575 		 */
1576 		(void) pthread_mutex_lock(&env_monitor_mutex);
1577 		ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
1578 		    &env_monitor_mutex, &to);
1579 
1580 		to.tv_sec = disk_scan_interval;
1581 		to.tv_nsec = 0;
1582 
1583 		if (ret != ETIMEDOUT) {
1584 			(void) pthread_mutex_unlock(
1585 			    &env_monitor_mutex);
1586 			continue;
1587 		}
1588 		(void) pthread_mutex_unlock(&env_monitor_mutex);
1589 
1590 		for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
1591 			if (diskp->present == B_FALSE)
1592 				continue;
1593 			if (diskp->tpage_supported == B_FALSE)
1594 				continue;
1595 		/*
1596 		 * If the disk temperature is above the warning threshold
1597 		 * continue monitoring until the temperature drops below
1598 		 * warning threshold.
1599 		 * if the temperature is in the NORMAL range monitor only
1600 		 * when the disk is BUSY.
1601 		 * We do not want to read the disk temperature if the disk is
1602 		 * is idling. The reason for this is disk will never get into
1603 		 * lowest power mode if we scan the disk temperature
1604 		 * peridoically. To avoid this situation we first determine
1605 		 * the idle_time of the disk. If the disk has been IDLE since
1606 		 * we scanned the temperature last time we will not read the
1607 		 * temperature.
1608 		 */
1609 		if (!DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) {
1610 			pmstate.physpath = diskp->physpath;
1611 			pmstate.size = strlen(diskp->physpath);
1612 			pmstate.component = 0;
1613 			if ((idle_time =
1614 			    ioctl(disk_pm_fd, PM_GET_TIME_IDLE,
1615 			    &pmstate)) == -1) {
1616 
1617 				if (errno != EINTR) {
1618 					if (env_debug)
1619 						envd_log(LOG_ERR,
1620 			"ioctl PM_GET_TIME_IDLE failed for DISK0. errno=0x%x\n",
1621 						    errno);
1622 					continue;
1623 				}
1624 				continue;
1625 			}
1626 			if (idle_time >= (disk_scan_interval/2)) {
1627 				if (env_debug) {
1628 					envd_log(LOG_ERR, "%s idle time = %d\n",
1629 					    diskp->name, idle_time);
1630 				}
1631 				continue;
1632 			}
1633 		}
1634 		ret = get_disk_temp(diskp);
1635 		if (ret != 0)
1636 			continue;
1637 		if (env_debug) {
1638 			envd_log(LOG_ERR, "%s temp = %d ref. temp = %d\n",
1639 			    diskp->name, diskp->current_temp, diskp->ref_temp);
1640 		}
1641 		/*
1642 		 * If this disk already triggered system shutdown, don't
1643 		 * log any more shutdown/warning messages for it.
1644 		 */
1645 		if (diskp->shutdown_initiated)
1646 			continue;
1647 
1648 		/*
1649 		 * Check for the temperature in warning and shutdown range
1650 		 * and take appropriate action.
1651 		 */
1652 		if (DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) {
1653 			/*
1654 			 * Check if the temperature has been in warning
1655 			 * range during last disk_warning_duration interval.
1656 			 * If so, the temperature is truly in warning
1657 			 * range and we need to log a warning message,
1658 			 * but no more than once every disk_warning_interval
1659 			 * seconds.
1660 			 */
1661 			time_t	wtstamp = diskp->warning_tstamp;
1662 
1663 			ct = (time_t)(gethrtime() / NANOSEC);
1664 			if (diskp->warning_start == 0)
1665 				diskp->warning_start = ct;
1666 			if (((ct - diskp->warning_start) >=
1667 			    disk_warning_duration) && (wtstamp == 0 ||
1668 			    (ct - wtstamp) >= disk_warning_interval)) {
1669 				envd_log(LOG_CRIT, ENV_WARNING_MSG,
1670 				    diskp->name, diskp->current_temp,
1671 				    diskp->low_warning,
1672 				    diskp->high_warning);
1673 				diskp->warning_tstamp = ct;
1674 			}
1675 		} else if (diskp->warning_start != 0)
1676 			diskp->warning_start = 0;
1677 
1678 		if (!shutdown_override &&
1679 		    DISK_TEMP_IN_SHUTDOWN_RANGE(diskp->current_temp, diskp)) {
1680 			ct = (time_t)(gethrtime() / NANOSEC);
1681 			if (diskp->shutdown_tstamp == 0)
1682 				diskp->shutdown_tstamp = ct;
1683 
1684 			/*
1685 			 * Shutdown the system if the temperature remains
1686 			 * in the shutdown range for over disk_shutdown_interval
1687 			 * seconds.
1688 			 */
1689 			if ((ct - diskp->shutdown_tstamp) >=
1690 			    disk_shutdown_interval) {
1691 				/* log error */
1692 				diskp->shutdown_initiated = B_TRUE;
1693 				(void) snprintf(msgbuf, sizeof (msgbuf),
1694 				    ENV_SHUTDOWN_MSG, diskp->name,
1695 				    diskp->current_temp, diskp->low_shutdown,
1696 				    diskp->high_shutdown);
1697 				envd_log(LOG_ALERT, msgbuf);
1698 
1699 				/* shutdown the system (only once) */
1700 				if (system_shutdown_started == B_FALSE) {
1701 					(void) snprintf(syscmd, sizeof (syscmd),
1702 					    "%s \"%s\"", shutdown_cmd, msgbuf);
1703 					envd_log(LOG_ALERT, syscmd);
1704 					system_shutdown_started = B_TRUE;
1705 					(void) system(syscmd);
1706 				}
1707 			}
1708 		} else if (diskp->shutdown_tstamp != 0)
1709 			diskp->shutdown_tstamp = 0;
1710 		}
1711 	} /* end of forever loop */
1712 }
1713 
1714 static void *
1715 fan_thr(void *args)
1716 {
1717 	char msgbuf[BUFSIZ];
1718 	timespec_t	to;
1719 	int	ret, i;
1720 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
1721 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
1722 	env_fan_t	*fanp;
1723 
1724 #ifdef	__lint
1725 	args = args;
1726 #endif
1727 
1728 	for (;;) {
1729 		/*
1730 		 * Sleep for specified seconds before issuing IOCTL
1731 		 * again.
1732 		 */
1733 		(void) pthread_mutex_lock(&env_monitor_mutex);
1734 		ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
1735 		    &env_monitor_mutex, &to);
1736 		to.tv_sec = fan_scan_interval;
1737 		to.tv_nsec = 0;
1738 		if (ret != ETIMEDOUT) {
1739 			(void) pthread_mutex_unlock(&env_monitor_mutex);
1740 			continue;
1741 		}
1742 		(void) pthread_mutex_unlock(&env_monitor_mutex);
1743 
1744 		for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
1745 			if (fanp->present == B_FALSE)
1746 				continue;
1747 
1748 			if (has_fan_failed(fanp) == B_TRUE) {
1749 				if (fanp->last_status == FAN_FAILED)
1750 					continue;
1751 				fanp->last_status = FAN_FAILED;
1752 				(void) snprintf(msgbuf, sizeof (msgbuf),
1753 				    ENV_FAN_FAILURE_WARNING_MSG, fanp->name,
1754 				    fan_rpm_string, fan_status_string);
1755 				envd_log(LOG_ALERT, msgbuf);
1756 			} else {
1757 				if (fanp->last_status == FAN_OK)
1758 					continue;
1759 				fanp->last_status = FAN_OK;
1760 				(void) snprintf(msgbuf, sizeof (msgbuf),
1761 				    ENV_FAN_OK_MSG, fanp->name);
1762 				envd_log(LOG_ALERT, msgbuf);
1763 			}
1764 		}
1765 
1766 		if (has_psufan_failed() == B_TRUE) {
1767 			if (psufan_last_status == FAN_FAILED)
1768 				continue;
1769 			psufan_last_status = FAN_FAILED;
1770 			(void) snprintf(msgbuf, sizeof (msgbuf),
1771 				ENV_FAN_FAILURE_WARNING_MSG, SENSOR_PSU,
1772 				fan_rpm_string, fan_status_string);
1773 			envd_log(LOG_ALERT, msgbuf);
1774 		} else {
1775 			if (psufan_last_status == FAN_OK)
1776 				continue;
1777 			psufan_last_status = FAN_OK;
1778 			(void) snprintf(msgbuf, sizeof (msgbuf),
1779 				ENV_FAN_OK_MSG, SENSOR_PSU);
1780 			envd_log(LOG_ALERT, msgbuf);
1781 		}
1782 	}
1783 
1784 	/*NOTREACHED*/
1785 	return (NULL);
1786 }
1787 
1788 /*
1789  * Setup envrionmental monitor state and start threads to monitor
1790  * temperature, fan, disk and power management state.
1791  * Returns -1 on error, 0 if successful.
1792  */
1793 static int
1794 envd_setup(void)
1795 {
1796 
1797 	if (getenv("SUNW_piclenvd_debug") != NULL)
1798 		env_debug = 1;
1799 
1800 	if (pthread_attr_init(&thr_attr) != 0 ||
1801 	    pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) {
1802 		return (-1);
1803 	}
1804 
1805 	/*
1806 	 * If ES segment is not present or has inconsistent information, we
1807 	 * use default values for sensor limits. For the sake of simplicity,
1808 	 * we still store these limits internally in the 'es' member in the
1809 	 * structure.
1810 	 */
1811 	if (envd_es_setup() < 0) {
1812 		envd_log(LOG_WARNING, ENV_DEFAULT_LIMITS);
1813 		envd_es_default_setup();
1814 	}
1815 
1816 	if (envd_setup_sensors() < 0) {
1817 		if (env_debug)
1818 			envd_log(LOG_ERR, "Failed to setup sensors\n");
1819 		system_temp_monitor = 0;
1820 	}
1821 
1822 	if (envd_setup_fans() < 0) {
1823 		if (env_debug)
1824 			envd_log(LOG_ERR, "Failed to setup fans\n");
1825 		fan_monitor = 0;
1826 		pm_monitor = 0;
1827 	}
1828 
1829 	/*
1830 	 * Disable disk temperature monitoring until we have
1831 	 * LSI fw support to read SATA disk temperature
1832 	 */
1833 	if (disk_temp_monitor) {
1834 		if (envd_setup_disks() < 0) {
1835 			if (env_debug)
1836 				envd_log(LOG_ERR, "Failed to setup disks\n");
1837 			disk_temp_monitor = 0;
1838 		}
1839 	}
1840 
1841 	/*
1842 	 * Create a thread to monitor system temperatures
1843 	 */
1844 	if ((system_temp_monitor) && (system_temp_thr_created == B_FALSE)) {
1845 		if (pthread_create(&system_temp_thr_id, &thr_attr,
1846 		    system_temp_thr, NULL) != 0) {
1847 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
1848 		} else {
1849 			system_temp_thr_created = B_TRUE;
1850 			if (env_debug)
1851 				envd_log(LOG_ERR,
1852 			"Created thread to monitor system temperatures\n");
1853 		}
1854 	}
1855 
1856 	/*
1857 	 * Create a thread to monitor fans
1858 	 */
1859 	if ((fan_monitor) && (fan_thr_created == B_FALSE)) {
1860 		if (pthread_create(&fan_thr_id, &thr_attr, fan_thr, NULL) != 0)
1861 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
1862 		else {
1863 			fan_thr_created = B_TRUE;
1864 			if (env_debug) {
1865 				envd_log(LOG_ERR,
1866 				    "Created thread to monitor system fans\n");
1867 			}
1868 		}
1869 	}
1870 
1871 	/*
1872 	 * Create a thread to monitor PM state
1873 	 */
1874 	if ((pm_monitor) && (pmthr_created == B_FALSE)) {
1875 		if (pthread_create(&pmthr_tid, &thr_attr, pmthr, NULL) != 0)
1876 			envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED);
1877 		else {
1878 			pmthr_created = B_TRUE;
1879 			if (env_debug)
1880 				envd_log(LOG_ERR,
1881 			"Created thread to monitor system power state\n");
1882 		}
1883 	}
1884 
1885 	/*
1886 	 * Create a thread to monitor disk temperature
1887 	 */
1888 	if ((disk_temp_monitor) && (disk_temp_thr_created == B_FALSE)) {
1889 		if (pthread_create(&disk_temp_thr_id, &thr_attr,
1890 		    disk_temp_thr, NULL) != 0) {
1891 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
1892 		} else {
1893 			disk_temp_thr_created = B_TRUE;
1894 			if (env_debug)
1895 				envd_log(LOG_ERR,
1896 			"Created thread for disk temperatures\n");
1897 		}
1898 	}
1899 
1900 	return (0);
1901 }
1902 
1903 static void
1904 piclenvd_register(void)
1905 {
1906 	picld_plugin_register(&my_reg_info);
1907 }
1908 
1909 static void
1910 piclenvd_init(void)
1911 {
1912 
1913 	(void) env_picl_setup_tuneables();
1914 
1915 	/*
1916 	 * Do not allow disk temperature monitoring to be enabled
1917 	 * via tuneables. Disk temperature monitoring is disabled
1918 	 * until we have LSI fw support to read the temperature of
1919 	 * SATA disks
1920 	 */
1921 	disk_temp_monitor = 0;
1922 
1923 	/*
1924 	 * Setup the environmental data structures
1925 	 */
1926 	if (envd_setup() != 0) {
1927 		envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED);
1928 		return;
1929 	}
1930 
1931 	/*
1932 	 * Now setup/populate PICL tree
1933 	 */
1934 	env_picl_setup();
1935 }
1936 
1937 static void
1938 piclenvd_fini(void)
1939 {
1940 
1941 	/*
1942 	 * Invoke env_picl_destroy() to remove any PICL nodes/properties
1943 	 * (including volatile properties) we created. Once this call
1944 	 * returns, there can't be any more calls from the PICL framework
1945 	 * to get current temperature or fan speed.
1946 	 */
1947 	env_picl_destroy();
1948 	envd_close_sensors();
1949 	envd_close_fans();
1950 }
1951 
1952 /*VARARGS2*/
1953 void
1954 envd_log(int pri, const char *fmt, ...)
1955 {
1956 	va_list	ap;
1957 
1958 	va_start(ap, fmt);
1959 	vsyslog(pri, fmt, ap);
1960 	va_end(ap);
1961 }
1962 
1963 /*
1964  * Tunables support functions
1965  */
1966 static env_tuneable_t *
1967 tuneable_lookup(picl_prophdl_t proph)
1968 {
1969 	int i;
1970 	env_tuneable_t	*tuneablep = NULL;
1971 
1972 	for (i = 0; i < ntuneables; i++) {
1973 		tuneablep = &tuneables[i];
1974 		if (tuneablep->proph == proph)
1975 			return (tuneablep);
1976 	}
1977 
1978 	return (NULL);
1979 }
1980 
1981 static int
1982 get_string_val(ptree_rarg_t *parg, void *buf)
1983 {
1984 	picl_prophdl_t	proph;
1985 	env_tuneable_t	*tuneablep;
1986 
1987 	proph = parg->proph;
1988 
1989 	tuneablep = tuneable_lookup(proph);
1990 
1991 	if (tuneablep == NULL)
1992 		return (PICL_FAILURE);
1993 
1994 	(void) memcpy(buf, tuneablep->value, tuneablep->nbytes);
1995 
1996 	return (PICL_SUCCESS);
1997 }
1998 
1999 static int
2000 set_string_val(ptree_warg_t *parg, const void *buf)
2001 {
2002 	picl_prophdl_t	proph;
2003 	env_tuneable_t	*tuneablep;
2004 
2005 	if (parg->cred.dc_euid != 0)
2006 		return (PICL_PERMDENIED);
2007 
2008 	proph = parg->proph;
2009 
2010 	tuneablep = tuneable_lookup(proph);
2011 
2012 	if (tuneablep == NULL)
2013 		return (PICL_FAILURE);
2014 
2015 	(void) memcpy(tuneables->value, buf, tuneables->nbytes);
2016 
2017 
2018 	return (PICL_SUCCESS);
2019 }
2020 
2021 static int
2022 get_int_val(ptree_rarg_t *parg, void *buf)
2023 {
2024 	picl_prophdl_t	proph;
2025 	env_tuneable_t	*tuneablep;
2026 
2027 	proph = parg->proph;
2028 
2029 	tuneablep = tuneable_lookup(proph);
2030 
2031 	if (tuneablep == NULL)
2032 		return (PICL_FAILURE);
2033 
2034 	(void) memcpy(buf, tuneablep->value, tuneablep->nbytes);
2035 
2036 	return (PICL_SUCCESS);
2037 }
2038 
2039 static int
2040 set_int_val(ptree_warg_t *parg, const void *buf)
2041 {
2042 	picl_prophdl_t	proph;
2043 	env_tuneable_t	*tuneablep;
2044 
2045 	if (parg->cred.dc_euid != 0)
2046 		return (PICL_PERMDENIED);
2047 
2048 	proph = parg->proph;
2049 
2050 	tuneablep = tuneable_lookup(proph);
2051 
2052 	if (tuneablep == NULL)
2053 		return (PICL_FAILURE);
2054 
2055 	(void) memcpy(tuneablep->value, buf, tuneablep->nbytes);
2056 
2057 	return (PICL_SUCCESS);
2058 }
2059 
2060 boolean_t
2061 has_fan_failed(env_fan_t *fanp)
2062 {
2063 	fanspeed_t	fan_speed;
2064 	uchar_t		status;
2065 	uint8_t		tach;
2066 	int		real_tach;
2067 	int		ret, ntries;
2068 
2069 	if (fanp->fd == -1)
2070 		return (B_TRUE);
2071 
2072 	/*
2073 	 * Read RF_FAN_STATUS bit of the fan fault register, retry if
2074 	 * the PIC is busy, with a 1 second delay to allow it to update.
2075 	 */
2076 	for (ntries = 0; ntries < MAX_RETRIES_FOR_FAN_FAULT; ntries++) {
2077 		ret = ioctl(fanp->fd, PIC_GET_FAN_STATUS, &status);
2078 		if ((ret == 0) && ((status & 0x1) == 0))
2079 			break;
2080 		(void) sleep(1);
2081 	}
2082 
2083 	if (ntries > 0) {
2084 		if (env_debug) {
2085 			envd_log(LOG_ERR,
2086 			    "%d retries attempted in reading fan status.\n",
2087 			    ntries);
2088 		}
2089 	}
2090 
2091 	if (ntries == MAX_RETRIES_FOR_FAN_FAULT) {
2092 		(void) strncpy(fan_status_string, NOT_AVAILABLE,
2093 		    sizeof (fan_status_string));
2094 		(void) strncpy(fan_rpm_string, NOT_AVAILABLE,
2095 		    sizeof (fan_rpm_string));
2096 		return (B_TRUE);
2097 	}
2098 
2099 	if (env_debug)
2100 		envd_log(LOG_ERR, "fan status = 0x%x\n", status);
2101 
2102 	/*
2103 	 * ST_FFAULT bit isn't implemented yet and we're reading only
2104 	 * individual fan status
2105 	 */
2106 	if (status & 0x1) {
2107 		(void) snprintf(fan_status_string, sizeof (fan_status_string),
2108 		    "0x%x", status);
2109 		if (ioctl(fanp->fd, PIC_GET_FAN_SPEED, &tach) != 0) {
2110 			(void) strncpy(fan_rpm_string, NOT_AVAILABLE,
2111 			    sizeof (fan_rpm_string));
2112 		} else {
2113 			real_tach = tach << 8;
2114 			fan_speed = TACH_TO_RPM(real_tach);
2115 			(void) snprintf(fan_rpm_string, sizeof (fan_rpm_string),
2116 			    "%d", fan_speed);
2117 		}
2118 		return (B_TRUE);
2119 	}
2120 
2121 	return (B_FALSE);
2122 }
2123 
2124 boolean_t
2125 has_psufan_failed(void)
2126 {
2127 	uchar_t		status;
2128 	int		ret, ntries;
2129 
2130 	if (envd_sensor_psu.fd == -1)
2131 		return (B_FALSE);
2132 
2133 	/*
2134 	 * For psu, only fan fault is visible, no fan speed
2135 	 */
2136 	(void) strncpy(fan_rpm_string, NOT_AVAILABLE, sizeof (fan_rpm_string));
2137 
2138 	/*
2139 	 * Read RF_FAN_STATUS bit of the fan fault register, retry if
2140 	 * the PIC is busy, with a 1 second delay to allow it to update.
2141 	 */
2142 	for (ntries = 0; ntries < MAX_RETRIES_FOR_FAN_FAULT; ntries++) {
2143 		ret = ioctl(envd_sensor_psu.fd, PIC_GET_FAN_STATUS, &status);
2144 		if ((ret == 0) && ((status & 0x1) == 0))
2145 			break;
2146 		(void) sleep(1);
2147 	}
2148 
2149 	if (ntries > 0) {
2150 		if (env_debug) {
2151 			envd_log(LOG_ERR,
2152 			    "%d retries attempted in reading fan status.\n",
2153 			    ntries);
2154 		}
2155 	}
2156 
2157 	if (ntries == MAX_RETRIES_FOR_FAN_FAULT) {
2158 		(void) strncpy(fan_status_string, NOT_AVAILABLE,
2159 		    sizeof (fan_status_string));
2160 		return (B_TRUE);
2161 	}
2162 
2163 	if (env_debug)
2164 		envd_log(LOG_ERR, "fan status = 0x%x\n", status);
2165 
2166 	if (status & 0x1) {
2167 		(void) snprintf(fan_status_string, sizeof (fan_status_string),
2168 		    "0x%x", status);
2169 		return (B_TRUE);
2170 	}
2171 
2172 	return (B_FALSE);
2173 }
2174 
2175 static int
2176 scsi_mode_select(env_disk_t *diskp, uchar_t page_code, uchar_t *pagebuf,
2177     uint16_t pagelen)
2178 {
2179 	struct uscsi_cmd		ucmd_buf;
2180 	uchar_t				cdb_buf[CDB_GROUP1];
2181 	struct scsi_extended_sense	sense_buf;
2182 	int				ret_val;
2183 
2184 	bzero(&cdb_buf, sizeof (cdb_buf));
2185 	bzero(&ucmd_buf, sizeof (ucmd_buf));
2186 	bzero(&sense_buf, sizeof (sense_buf));
2187 
2188 	cdb_buf[0] = SCMD_MODE_SELECT_G1;
2189 	cdb_buf[1] = 1<<PAGE_FMT;
2190 
2191 	cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8);
2192 	cdb_buf[8] = (uchar_t)(pagelen  & 0x00FF);
2193 
2194 	ucmd_buf.uscsi_cdb = (char *)cdb_buf;
2195 	ucmd_buf.uscsi_cdblen = sizeof (cdb_buf);
2196 	ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf;
2197 	ucmd_buf.uscsi_buflen = pagelen;
2198 	ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf;
2199 	ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense);
2200 	ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_WRITE | USCSI_SILENT;
2201 	ucmd_buf.uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
2202 
2203 	ret_val = ioctl(diskp->fd, USCSICMD, ucmd_buf);
2204 
2205 	if (ret_val == 0 && ucmd_buf.uscsi_status == 0) {
2206 		return (ret_val);
2207 	}
2208 	if (env_debug)
2209 		envd_log(LOG_ERR, "mode select command for %s failed. "
2210 		    "page_code 0x%x ret_val = 0x%x "
2211 		    "status = 0x%x errno = 0x%x\n", diskp->name, page_code,
2212 		    ret_val, ucmd_buf.uscsi_status, errno);
2213 
2214 	return (1);
2215 
2216 }
2217