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