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