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