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