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 2004 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 Enchilada WS.
33 * It provides functionality to get/set temperatures and
34 * fan speeds.
35 *
36 * The environmental policy defaults to the auto mode
37 * 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 <strings.h>
46 #include <stdarg.h>
47 #include <alloca.h>
48 #include <unistd.h>
49 #include <sys/processor.h>
50 #include <syslog.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <picl.h>
54 #include <picltree.h>
55 #include <picldefs.h>
56 #include <pthread.h>
57 #include <signal.h>
58 #include <libdevinfo.h>
59 #include <sys/pm.h>
60 #include <sys/open.h>
61 #include <sys/time.h>
62 #include <sys/utsname.h>
63 #include <sys/systeminfo.h>
64 #include <note.h>
65 #include <sys/i2c/clients/i2c_client.h>
66 #include <sys/i2c/clients/adm1031.h>
67 #include <sys/i2c/clients/pic16f819_reg.h>
68 #include "envd.h"
69 #include <sys/scsi/scsi.h>
70 #include <sys/scsi/generic/commands.h>
71
72
73 /*
74 * PICL plugin entry points
75 */
76 static void piclenvd_register(void);
77 static void piclenvd_init(void);
78 static void piclenvd_fini(void);
79
80 /*
81 * Env setup routines
82 */
83 extern void env_picl_setup(void);
84 extern void env_picl_destroy(void);
85 extern int env_picl_setup_tuneables(void);
86
87 /*
88 * Sleep routine used for polling
89 */
90 static int get_dimm_fan_speed(int, fanspeed_t *);
91 static int is_dimm_fan_failed(void);
92
93 #pragma init(piclenvd_register)
94
95 /*
96 * Plugin registration information
97 */
98 static picld_plugin_reg_t my_reg_info = {
99 PICLD_PLUGIN_VERSION,
100 PICLD_PLUGIN_CRITICAL,
101 "SUNW_piclenvd",
102 piclenvd_init,
103 piclenvd_fini,
104 };
105
106 #define REGISTER_INFORMATION_STRING_LENGTH 16
107 static char dimm_fan_rpm_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
108 static char dimm_fan_status_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
109 static char dimm_fan_command_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
110 static char dimm_fan_debug_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
111
112 static int scsi_log_sense(int fd, uchar_t page_code, uchar_t *pagebuf,
113 uint16_t pagelen);
114 static int get_disk_temp(env_disk_t *);
115 /*
116 * ES Segment data structures
117 */
118 static sensor_ctrl_blk_t sensor_ctrl[MAX_SENSORS];
119 static fan_ctrl_blk_t fan_ctrl[MAX_FANS];
120 static fruenvseg_t *envfru = NULL;
121
122 /*
123 * Env thread variables
124 */
125 static boolean_t system_shutdown_started = B_FALSE;
126 static boolean_t ovtemp_thr1_created = B_FALSE;
127 static pthread_t ovtemp_thr1_id;
128 static pthread_attr_t thr_attr;
129 static boolean_t ovtemp_thr2_created = B_FALSE;
130 static pthread_t ovtemp_thr2_id;
131 static boolean_t dimm_fan_thr_created = B_FALSE;
132 static pthread_t dimm_fan_thr_id;
133 static boolean_t disk_temp_thr_created = B_FALSE;
134 static pthread_t disk_temp_thr_id;
135
136 /*
137 * PM thread related variables
138 */
139 static pthread_t pmthr_tid; /* pmthr thread ID */
140 static int pm_fd = -1; /* PM device file descriptor */
141 static boolean_t pmthr_created = B_FALSE;
142 static int cur_lpstate; /* cur low power state */
143
144 /*
145 * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var
146 * Setting the verbose tuneable also enables debugging for better
147 * control
148 */
149 int env_debug = 0;
150
151 /*
152 * Fan devices
153 */
154 static env_fan_t envd_sys_out_fan = {
155 ENV_SYSTEM_OUT_FAN, ENV_SYSTEM_OUT_FAN_DEVFS, NULL,
156 SYSTEM_OUT_FAN_ID, SYSTEM_OUT_FAN_SPEED_MIN, SYSTEM_OUT_FAN_SPEED_MAX,
157 -1, -1,
158 };
159
160 static env_fan_t envd_sys_in_fan = {
161 ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_INTAKE_FAN_DEVFS, NULL,
162 SYSTEM_INTAKE_FAN_ID, SYSTEM_INTAKE_FAN_SPEED_MIN,
163 SYSTEM_INTAKE_FAN_SPEED_MAX, -1, -1,
164 };
165
166 static env_fan_t envd_cpu0_fan = {
167 ENV_CPU0_FAN, ENV_CPU0_FAN_DEVFS, NULL,
168 CPU0_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1,
169 };
170
171 static env_fan_t envd_cpu1_fan = {
172 ENV_CPU1_FAN, ENV_CPU1_FAN_DEVFS, NULL,
173 CPU1_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1,
174 };
175
176 static env_fan_t envd_dimm_fan = {
177 ENV_DIMM_FAN, ENV_DIMM_FAN_DEVFS, NULL,
178 DIMM_FAN_ID, 100, 100, -1, -1,
179 };
180
181 static env_disk_t envd_disk0 = {
182 ENV_DISK0, ENV_DISK0_DEVFS, DISK0_PHYSPATH, DISK0_NODE_PATH,
183 DISK0_ID, -1, -1,
184 };
185
186 static env_disk_t envd_disk1 = {
187 ENV_DISK1, ENV_DISK1_DEVFS, DISK1_PHYSPATH, DISK1_NODE_PATH,
188 DISK1_ID, -1, -1,
189 };
190
191 /*
192 * The vendor-id and device-id are the properties associated with
193 * the SCSI controller. This is used to identify a particular controller
194 * like LSI1030.
195 */
196 #define VENDOR_ID "vendor-id"
197 #define DEVICE_ID "device-id"
198
199 /*
200 * The implementation for SCSI disk drives to supply info. about
201 * temperature is not mandatory. Hence we first determine if the
202 * temperature page is supported. To do this we need to scan the list
203 * of pages supported.
204 */
205 #define SUPPORTED_LPAGES 0
206 #define TEMPERATURE_PAGE 0x0D
207 #define LOGPAGEHDRSIZE 4
208
209 /*
210 * NULL terminated array of fans
211 */
212 static env_fan_t *envd_fans[] = {
213 &envd_cpu0_fan,
214 &envd_cpu1_fan,
215 &envd_sys_out_fan,
216 &envd_sys_in_fan,
217 &envd_dimm_fan,
218 NULL
219 };
220
221 static env_disk_t *envd_disks[] = {
222 &envd_disk0,
223 &envd_disk1,
224 NULL
225 };
226
227 /*
228 * ADM1031 speedrange map is indexed by a 2-bit value
229 */
230 static int adm_speedrange_map[] = {1, 2, 4, 8};
231
232 /*
233 * ADM1031 devices
234 */
235 static char *hwm_devs[] = {
236 CPU_HWM_DEVFS, /* CPU_HWM_ID */
237 SYS_HWM_DEVFS /* SYS_HWM_ID */
238 };
239
240 /*
241 * Fan names associated with each ADM1031 hwms - used to
242 * print fault messages.
243 */
244 static char *hwm_fans[MAX_HWMS][2] = {
245 {ENV_CPU0_FAN, ENV_CPU1_FAN},
246 {ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_OUT_FAN}
247 };
248
249 /*
250 * Temperature sensors
251 */
252 static env_sensor_t envd_sensors[] = {
253 { SENSOR_CPU0_DIE, SENSOR_CPU0_DIE_DEVFS, NULL,
254 CPU0_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu0_fan, -1},
255 { SENSOR_CPU1_DIE, SENSOR_CPU1_DIE_DEVFS, NULL,
256 CPU1_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu1_fan, -1},
257 { SENSOR_INT_AMB_0, SENSOR_INT_AMB_0_DEVFS, NULL,
258 INT_AMB0_SENSOR_ID, CPU_HWM_ID, NULL, -1},
259 { SENSOR_SYS_OUT, SENSOR_SYS_OUT_DEVFS, NULL,
260 SYS_OUT_SENSOR_ID, SYS_HWM_ID, (void *)&envd_sys_out_fan, -1},
261 { SENSOR_INT_AMB_1, SENSOR_INT_AMB_1_DEVFS, NULL,
262 INT_AMB1_SENSOR_ID, SYS_HWM_ID, NULL, -1},
263 { SENSOR_SYS_IN, SENSOR_SYS_IN_DEVFS, NULL,
264 SYS_IN_SENSOR_ID, SYS_HWM_ID, (void *)&envd_sys_in_fan, -1},
265 };
266 #define N_ENVD_SENSORS (sizeof (envd_sensors)/sizeof (envd_sensors[0]))
267
268 #define NOT_AVAILABLE "NA"
269
270 /*
271 * ADM1031 macros
272 */
273 #define TACH_UNKNOWN 255
274 #define FAN_OUT_OF_RANGE (TACH_UNKNOWN)
275 #define ADM_HYSTERISIS 5
276 #define N_SEQ_TACH 15
277
278 #define TMIN_MASK (0xF8)
279 #define TMIN_SHIFT (3)
280 #define TMIN_UNITS (4) /* increments of 4 degrees celsius */
281 #define TRANGE_MASK (0x7)
282
283 #define TMIN(regval) (((regval & TMIN_MASK) >> TMIN_SHIFT) * TMIN_UNITS)
284 #define TRANGE(regval) (regval & TRANGE_MASK)
285
286 #define GET_TMIN_RANGE(tmin, trange) \
287 ((((tmin / TMIN_UNITS) & TMIN_MASK) << TMIN_SHIFT) | \
288 (trange & TRANGE_MASK))
289
290 #define TACH_ENABLE_MASK (0x0C)
291 #define ADM_SETFANSPEED_CONV(speed) (15 * speed / 100)
292
293 /*
294 * Tuneables
295 */
296 #define ENABLE 1
297 #define DISABLE 0
298
299 int monitor_disk_temp = 1; /* enabled */
300 static int disk_high_warn_temperature = DISK_HIGH_WARN_TEMPERATURE;
301 static int disk_low_warn_temperature = DISK_LOW_WARN_TEMPERATURE;
302 static int disk_high_shutdown_temperature =
303 DISK_HIGH_SHUTDOWN_TEMPERATURE;
304 static int disk_low_shutdown_temperature = DISK_LOW_SHUTDOWN_TEMPERATURE;
305 static int disk_scan_interval = DISK_SCAN_INTERVAL;
306
307 static int get_monitor_cpu_mode(ptree_rarg_t *parg, void *buf);
308 static int set_monitor_cpu_mode(ptree_warg_t *parg, const void *buf);
309 static int get_monitor_sys_mode(ptree_rarg_t *parg, void *buf);
310 static int set_monitor_sys_mode(ptree_warg_t *parg, const void *buf);
311 static int get_int_val(ptree_rarg_t *parg, void *buf);
312 static int set_int_val(ptree_warg_t *parg, const void *buf);
313 static int get_string_val(ptree_rarg_t *parg, void *buf);
314 static int set_string_val(ptree_warg_t *parg, const void *buf);
315 static int get_cpu_tach(ptree_rarg_t *parg, void *buf);
316 static int set_cpu_tach(ptree_warg_t *parg, const void *buf);
317 static int get_sys_tach(ptree_rarg_t *parg, void *buf);
318 static int set_sys_tach(ptree_warg_t *parg, const void *buf);
319
320 static int shutdown_override = 0;
321 static int sensor_poll_interval = SENSORPOLL_INTERVAL;
322 static int warning_interval = WARNING_INTERVAL;
323 static int disk_warning_interval = DISK_WARNING_INTERVAL;
324 static int disk_warning_duration = DISK_WARNING_DURATION;
325 static int shutdown_interval = SHUTDOWN_INTERVAL;
326 static int disk_shutdown_interval = DISK_SHUTDOWN_INTERVAL;
327 static int ovtemp_monitor = 1; /* enabled */
328 static int pm_monitor = 1; /* enabled */
329 static int mon_fanstat = 1; /* enabled */
330
331 static int cpu_mode;
332 static int sys_mode;
333 static int cpu_tach;
334 static int sys_tach;
335 static char shutdown_cmd[] = SHUTDOWN_CMD;
336
337 env_tuneable_t tuneables[] = {
338 {"ovtemp-monitor", PICL_PTYPE_INT, &ovtemp_monitor,
339 &get_int_val, &set_int_val, sizeof (int)},
340
341 {"pm-monitor", PICL_PTYPE_INT, &pm_monitor,
342 &get_int_val, &set_int_val, sizeof (int)},
343
344 {"shutdown-override", PICL_PTYPE_INT, &shutdown_override,
345 &get_int_val, &set_int_val, sizeof (int)},
346
347 {"cpu-hm-automode-enable", PICL_PTYPE_INT, &cpu_mode,
348 &get_monitor_cpu_mode, &set_monitor_cpu_mode,
349 sizeof (int)},
350
351 {"sys-hm-automode-enable", PICL_PTYPE_INT, &sys_mode,
352 &get_monitor_sys_mode, &set_monitor_sys_mode,
353 sizeof (int)},
354
355 {"sensor-poll-interval", PICL_PTYPE_INT,
356 &sensor_poll_interval,
357 &get_int_val, &set_int_val,
358 sizeof (int)},
359
360 {"disk-scan-interval", PICL_PTYPE_INT,
361 &disk_scan_interval,
362 &get_int_val, &set_int_val,
363 sizeof (int)},
364
365 {"warning-interval", PICL_PTYPE_INT, &warning_interval,
366 &get_int_val, &set_int_val,
367 sizeof (int)},
368
369 {"shutdown-interval", PICL_PTYPE_INT, &shutdown_interval,
370 &get_int_val, &set_int_val,
371 sizeof (int)},
372
373 {"disk_warning-interval", PICL_PTYPE_INT, &disk_warning_interval,
374 &get_int_val, &set_int_val,
375 sizeof (int)},
376
377 {"disk_warning-duration", PICL_PTYPE_INT, &disk_warning_duration,
378 &get_int_val, &set_int_val,
379 sizeof (int)},
380
381 {"disk_shutdown-interval", PICL_PTYPE_INT, &disk_shutdown_interval,
382 &get_int_val, &set_int_val,
383 sizeof (int)},
384
385 {"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd,
386 &get_string_val, &set_string_val,
387 sizeof (shutdown_cmd)},
388
389 {"cpu-tach-enable", PICL_PTYPE_INT, &cpu_tach,
390 &get_cpu_tach, &set_cpu_tach,
391 sizeof (int)},
392
393 {"sys-tach-enable", PICL_PTYPE_INT, &sys_tach,
394 &get_sys_tach, &set_sys_tach,
395 sizeof (int)},
396
397 {"monitor-fanstat", PICL_PTYPE_INT, &mon_fanstat,
398 &get_int_val, &set_int_val, sizeof (int)},
399
400 {"monitor-disk-temp", PICL_PTYPE_INT, &monitor_disk_temp,
401 &get_int_val, &set_int_val, sizeof (int)},
402
403 {"disk-high-warn-temperature", PICL_PTYPE_INT,
404 &disk_high_warn_temperature, &get_int_val,
405 &set_int_val, sizeof (int)},
406
407 {"disk-low-warn-temperature", PICL_PTYPE_INT,
408 &disk_low_warn_temperature, &get_int_val,
409 &set_int_val, sizeof (int)},
410
411 {"disk-high-shutdown-temperature", PICL_PTYPE_INT,
412 &disk_high_shutdown_temperature, &get_int_val,
413 &set_int_val, sizeof (int)},
414
415 {"disk-low-shutdown-temperature", PICL_PTYPE_INT,
416 &disk_low_shutdown_temperature, &get_int_val,
417 &set_int_val, sizeof (int)},
418
419 {"verbose", PICL_PTYPE_INT, &env_debug,
420 &get_int_val, &set_int_val, sizeof (int)},
421
422
423 };
424
425 /*
426 * We use this to figure out how many tuneables there are
427 * This is variable because the publishing routine needs this info
428 * in piclenvsetup.c
429 */
430 int ntuneables = (sizeof (tuneables)/sizeof (tuneables[0]));
431
432 /*
433 * Table Handling Code
434 */
435 static void
fini_table(table_t * tblp)436 fini_table(table_t *tblp)
437 {
438 if (tblp == NULL)
439 return;
440 free(tblp->xymap);
441 free(tblp);
442 }
443
444 static table_t *
init_table(int npoints)445 init_table(int npoints)
446 {
447 table_t *tblp;
448 point_t *xy;
449
450 if (npoints == 0)
451 return (NULL);
452
453 if ((tblp = malloc(sizeof (*tblp))) == NULL)
454 return (NULL);
455
456 if ((xy = malloc(sizeof (*xy) * npoints)) == NULL) {
457 free(tblp);
458 return (NULL);
459 }
460
461 tblp->nentries = npoints;
462 tblp->xymap = xy;
463
464 return (tblp);
465 }
466
467 /*
468 * function: calculates y for a given x based on a table of points
469 * for monotonically increasing x values.
470 * 'tbl' specifies the table to use, 'val' specifies the 'x', returns 'y'
471 */
472 static int
y_of_x(table_t * tbl,int xval)473 y_of_x(table_t *tbl, int xval)
474 {
475 int i;
476 int entries;
477 point_t *xymap;
478 float newval;
479 float dy, dx, slope;
480
481 entries = tbl->nentries;
482 xymap = tbl->xymap;
483 /*
484 * If the temperature is outside the correction table
485 * then simply return the original value.
486 */
487 if ((xval < xymap[0].x) || (xval > xymap[entries - 1].x))
488 return (xval);
489 if (xval == xymap[0].x)
490 return (xymap[0].y);
491 if (xval == xymap[entries - 1].x)
492 return (xymap[entries - 1].y);
493
494 for (i = 1; i < entries - 1; i++) {
495 if (xval == xymap[i].x)
496 return (xymap[i].y);
497 if (xval < xymap[i].x)
498 break;
499 }
500
501 /*
502 * Use linear interpolation
503 */
504 dy = (float)(xymap[i].y - xymap[i-1].y);
505 dx = (float)(xymap[i].x - xymap[i-1].x);
506 slope = dy/dx;
507 newval = xymap[i - 1].y + slope * (xval - xymap[i - 1].x);
508 return ((int)(newval + (newval >= 0 ? 0.5 : -0.5)));
509 }
510
511 /*
512 * Get environmental segment from the specified FRU SEEPROM
513 */
514 static int
get_envseg(int fd,void ** envsegp,int * envseglenp)515 get_envseg(int fd, void **envsegp, int *envseglenp)
516 {
517 int i, segcnt, envseglen;
518 section_layout_t section;
519 segment_layout_t segment;
520 uint8_t *envseg;
521
522 if (lseek(fd, (long)SECTION_HDR_OFFSET, 0) == -1L ||
523 read(fd, §ion, sizeof (section)) != sizeof (section)) {
524 return (EINVAL);
525 }
526
527 /*
528 * Verify we have the correct section and contents are valid
529 * For now, we don't verify the CRC.
530 */
531 if (section.header_tag != SECTION_HDR_TAG ||
532 GET_UNALIGN16(§ion.header_version[0]) != SECTION_HDR_VER) {
533 if (env_debug)
534 envd_log(LOG_INFO,
535 "Invalid section header tag:%x version:%x\n",
536 section.header_tag,
537 GET_UNALIGN16(§ion.header_version));
538 return (EINVAL);
539 }
540
541 /*
542 * Locate our environmental segment
543 */
544 segcnt = section.segment_count;
545 for (i = 0; i < segcnt; i++) {
546 if (read(fd, &segment, sizeof (segment)) != sizeof (segment)) {
547 return (EINVAL);
548 }
549 if (env_debug)
550 envd_log(LOG_INFO,
551 "Seg name: %x desc:%x off:%x len:%x\n",
552 GET_UNALIGN16(&segment.name),
553 GET_UNALIGN32(&segment.descriptor[0]),
554 GET_UNALIGN16(&segment.offset),
555 GET_UNALIGN16(&segment.length));
556 if (GET_UNALIGN16(&segment.name) == ENVSEG_NAME)
557 break;
558 }
559
560 if (i >= segcnt) {
561 return (ENOENT);
562 }
563
564 /*
565 * Allocate memory to hold the environmental segment data.
566 */
567 envseglen = GET_UNALIGN16(&segment.length);
568 if ((envseg = malloc(envseglen)) == NULL) {
569 return (ENOMEM);
570 }
571
572 if (lseek(fd, (long)GET_UNALIGN16(&segment.offset), 0) == -1L ||
573 read(fd, envseg, envseglen) != envseglen) {
574 (void) free(envseg);
575 return (EIO);
576 }
577 *envsegp = envseg;
578 *envseglenp = envseglen;
579 return (0);
580 }
581
582 /*
583 * Get all environmental segments
584 * Return NULL on error
585 */
586 static fruenvseg_t *
get_fru_envsegs(void)587 get_fru_envsegs(void)
588 {
589 fruenvseg_t *fruenvsegs;
590 envseg_layout_t *envsegp;
591 void *envsegbufp;
592 int fd, envseglen, hdrlen;
593 char path[PATH_MAX];
594
595 fruenvsegs = NULL;
596 fruenvsegs = malloc(sizeof (*fruenvsegs));
597 if (fruenvsegs == NULL) {
598 return (NULL);
599 }
600
601 /*
602 * Now get the environmental segment from this FRU
603 */
604 (void) snprintf(path, sizeof (path), "%s%s", I2C_DEVFS, MBFRU_DEV);
605 fd = open(path, O_RDONLY);
606 if (fd == -1) {
607 envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, errno, path);
608 free(fruenvsegs);
609 return (NULL);
610 }
611
612 /*
613 * Read environmental segment from this FRU SEEPROM
614 */
615 if (get_envseg(fd, &envsegbufp, &envseglen) != 0) {
616 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, path);
617 free(fruenvsegs);
618 (void) close(fd);
619 return (NULL);
620 }
621
622 /*
623 * Validate envseg version number and header length
624 */
625 envsegp = (envseg_layout_t *)envsegbufp;
626 hdrlen = sizeof (envseg_layout_t) -
627 sizeof (envseg_sensor_t) +
628 (envsegp->sensor_count) * sizeof (envseg_sensor_t);
629
630 if (envsegp->version != ENVSEG_VERSION ||
631 envseglen < hdrlen) {
632 /*
633 * version mismatch or header not big enough
634 */
635 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
636 if (envsegbufp != NULL)
637 (void) free(envsegbufp);
638 free(fruenvsegs);
639 (void) close(fd);
640 return (NULL);
641 }
642
643 fruenvsegs->envseglen = envseglen;
644 fruenvsegs->envsegbufp = envsegbufp;
645 (void) close(fd);
646 return (fruenvsegs);
647 }
648
649 static int
process_fru_seeprom(unsigned char * buff)650 process_fru_seeprom(unsigned char *buff)
651 {
652 id_off_t id;
653 int i;
654 int id_offset = 0;
655 int nsensors;
656 int nfans;
657 env_fan_t *fnodep;
658 env_sensor_t *snodep;
659
660 #define NSENSOR_OFFSET 1
661 #define ID_OFF_SIZE 6
662 #define NFANS_OFFSET(x) ((x * ID_OFF_SIZE) + 2)
663
664 nsensors = (int)buff[NSENSOR_OFFSET];
665 if (nsensors != MAX_SENSORS) {
666 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
667 return (-1);
668 }
669
670 nfans = (int)buff[NFANS_OFFSET(nsensors)];
671 if (nfans != MAX_FANS) {
672 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
673 return (-1);
674 }
675
676 while (nsensors > 0) {
677 (void) memcpy((char *)&id,
678 (char *)&buff[id_offset + 2],
679 ID_OFF_SIZE);
680
681 if (env_debug)
682 envd_log(LOG_ERR, "\n Sensor Id %x offset %x",
683 id.id, id.offset);
684
685 if (id.id > MAX_SENSOR_ID) {
686 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
687 FRU_SEEPROM_NAME);
688 return (-1);
689 }
690
691 /*
692 * Copy into the sensor control block array according to the
693 * sensor ID
694 */
695 (void) memcpy((char *)&sensor_ctrl[id.id],
696 (char *)&buff[id.offset],
697 sizeof (sensor_ctrl_blk_t));
698 nsensors--;
699 id_offset += ID_OFF_SIZE;
700 }
701
702 /*
703 * Skip past no of Fan entry(single byte)
704 */
705 id_offset++;
706 while (nfans > 0) {
707 (void) memcpy((char *)&id, (char *)&buff[id_offset + 2],
708 ID_OFF_SIZE);
709
710 if (env_debug)
711 envd_log(LOG_ERR, "\n Fan Id %x offset %x", id.id,
712 id.offset);
713
714 if (id.id > 3) {
715 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
716 FRU_SEEPROM_NAME);
717 return (-1);
718 }
719
720 (void) memcpy((char *)&fan_ctrl[id.id],
721 (char *)&buff[id.offset], sizeof (fan_ctrl_blk_t));
722
723 nfans--;
724 id_offset += ID_OFF_SIZE;
725 }
726
727 /*
728 * Match Sensor/ES ID and point correct data
729 * based on IDs
730 */
731 for (i = 0; i < N_ENVD_SENSORS; i++) {
732 snodep = &envd_sensors[i];
733 snodep->es_ptr = &sensor_ctrl[snodep->id];
734 }
735
736 /*
737 * Match Fan/ES ID and point to correct ES Data
738 * based on IDs
739 */
740 for (i = 0; (fnodep = envd_fans[i]) != NULL; i++)
741 fnodep->es_ptr = &fan_ctrl[fnodep->id];
742
743 return (0);
744 }
745
746 static int
envd_es_setup(void)747 envd_es_setup(void)
748 {
749 envfru = get_fru_envsegs();
750 if (envfru == NULL) {
751 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
752 return (-1);
753 }
754 return (process_fru_seeprom((uchar_t *)envfru->envsegbufp));
755 }
756
757 static void
envd_es_destroy(void)758 envd_es_destroy(void)
759 {
760 if (envfru != NULL)
761 free(envfru->envsegbufp);
762 }
763
764 /*
765 * Lookup fan and return a pointer to env_fan_t data structure.
766 */
767 env_fan_t *
fan_lookup(char * name)768 fan_lookup(char *name)
769 {
770 int i;
771 env_fan_t *fanp;
772
773 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
774 if (strcmp(fanp->name, name) == 0)
775 return (fanp);
776 }
777 return (NULL);
778 }
779
780 /*
781 * Lookup sensor and return a pointer to env_sensor_t data structure.
782 */
783 env_sensor_t *
sensor_lookup(char * name)784 sensor_lookup(char *name)
785 {
786 env_sensor_t *sensorp;
787 int i;
788
789 for (i = 0; i < N_ENVD_SENSORS; ++i) {
790 sensorp = &envd_sensors[i];
791 if (strcmp(sensorp->name, name) == 0)
792 return (sensorp);
793 }
794 return (NULL);
795 }
796
797 /*
798 * Lookup disk and return a pointer to env_disk_t data structure.
799 */
800 env_disk_t *
disk_lookup(char * name)801 disk_lookup(char *name)
802 {
803 int i;
804 env_disk_t *diskp;
805
806 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
807 if (strncmp(diskp->name, name, strlen(name)) == 0)
808 return (diskp);
809 }
810 return (NULL);
811 }
812
813 /*
814 * Get current temperature
815 * Returns -1 on error, 0 if successful
816 */
817 int
get_temperature(env_sensor_t * sensorp,tempr_t * temp)818 get_temperature(env_sensor_t *sensorp, tempr_t *temp)
819 {
820 int fd = sensorp->fd;
821 int retval = 0;
822
823 if (fd == -1)
824 retval = -1;
825 else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) {
826
827 retval = -1;
828
829 if (sensorp->error == 0) {
830 sensorp->error = 1;
831 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL,
832 sensorp->name, errno, strerror(errno));
833 }
834 } else if (sensorp->error != 0) {
835 sensorp->error = 0;
836 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, sensorp->name);
837 }
838 if (sensorp->crtbl != NULL) {
839 *temp = (tempr_t)y_of_x(sensorp->crtbl, *temp);
840 }
841
842 return (retval);
843 }
844
845 /*
846 * Get current disk temperature
847 * Returns -1 on error, 0 if successful
848 */
849 int
disk_temperature(env_disk_t * diskp,tempr_t * temp)850 disk_temperature(env_disk_t *diskp, tempr_t *temp)
851 {
852 int retval = 0;
853
854 if (diskp == NULL)
855 retval = -1;
856 else {
857 *temp = diskp->current_temp;
858 }
859 return (retval);
860 }
861
862 /*
863 * Get uncorrected current temperature
864 * Returns -1 on error, 0 if successful
865 */
866 static int
get_raw_temperature(env_sensor_t * sensorp,tempr_t * temp)867 get_raw_temperature(env_sensor_t *sensorp, tempr_t *temp)
868 {
869 int fd = sensorp->fd;
870 int retval = 0;
871
872 if (fd == -1)
873 retval = -1;
874 else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) {
875 retval = -1;
876 }
877
878 return (retval);
879 }
880
881 /*
882 * Return Fan RPM given N & tach
883 * count and N are retrived from the
884 * ADM1031 chip.
885 */
886 static int
tach_to_rpm(int n,uint8_t tach)887 tach_to_rpm(int n, uint8_t tach)
888 {
889 if (n * tach == 0)
890 return (0);
891 return ((ADCSAMPLE * 60) / (n * tach));
892 }
893
894 static int
get_raw_fan_speed(env_fan_t * fanp,uint8_t * fanspeedp)895 get_raw_fan_speed(env_fan_t *fanp, uint8_t *fanspeedp)
896 {
897 int fan_fd;
898 int retval = 0;
899
900 fan_fd = fanp->fd;
901
902 if (fan_fd == -1)
903 retval = -1;
904 else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, fanspeedp) == -1) {
905 retval = -1;
906 }
907
908
909 return (retval);
910 }
911
912 /*
913 * Get current fan speed
914 * This function returns a RPM value for fanspeed
915 * in fanspeedp.
916 * Returns -1 on error, 0 if successful
917 */
918 int
get_fan_speed(env_fan_t * fanp,fanspeed_t * fanspeedp)919 get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp)
920 {
921 int fan_fd;
922 uint8_t tach;
923
924 fan_fd = fanp->fd;
925
926 if (fan_fd == -1)
927 return (-1);
928 if (fanp->id == DIMM_FAN_ID) {
929 return (get_dimm_fan_speed(fan_fd, fanspeedp));
930 }
931 if (ioctl(fan_fd, I2C_GET_FAN_SPEED, &tach) == -1) {
932 return (-1);
933 }
934
935 /*
936 * Fanspeeds are reported as 0
937 * if the tach is out of range or fan status is off
938 * and if monitoring fan status is enabled.
939 */
940 if (mon_fanstat && (!fanp->fanstat || tach == FAN_OUT_OF_RANGE)) {
941 *fanspeedp = 0;
942 } else {
943 *fanspeedp =
944 tach_to_rpm(fanp->speedrange, tach);
945 }
946
947 return (0);
948 }
949
950 /*
951 * Set fan speed
952 * This function accepts a percentage of fan speed
953 * from 0-100 and programs the HW monitor fans to the corresponding
954 * fanspeed value.
955 * Returns -1 on error, -2 on invalid args passed, 0 if successful
956 */
957 int
set_fan_speed(env_fan_t * fanp,fanspeed_t fanspeed)958 set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed)
959 {
960 int fan_fd;
961 int retval = 0;
962 uint8_t speed;
963
964 fan_fd = fanp->fd;
965 if (fan_fd == -1)
966 return (-1);
967
968 if (fanspeed < 0 || fanspeed > 100)
969 return (-2);
970
971 speed = (uint8_t)ADM_SETFANSPEED_CONV(fanspeed);
972
973 if (ioctl(fan_fd, I2C_SET_FAN_SPEED, &speed) == -1) {
974 retval = -1;
975 }
976 return (retval);
977 }
978
979 /*
980 * close all fan devices
981 */
982 static void
envd_close_fans(void)983 envd_close_fans(void)
984 {
985 int i;
986 env_fan_t *fanp;
987
988 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
989 if (fanp->fd != -1) {
990 (void) close(fanp->fd);
991 fanp->fd = -1;
992 }
993 }
994 }
995
996 /*
997 * Close sensor devices and freeup resources
998 */
999 static void
envd_close_sensors(void)1000 envd_close_sensors(void)
1001 {
1002 env_sensor_t *sensorp;
1003 int i;
1004
1005 for (i = 0; i < N_ENVD_SENSORS; ++i) {
1006 sensorp = &envd_sensors[i];
1007 if (sensorp->fd != -1) {
1008 (void) close(sensorp->fd);
1009 sensorp->fd = -1;
1010 }
1011 if (sensorp->crtbl != NULL)
1012 fini_table(sensorp->crtbl);
1013 }
1014 }
1015
1016 /*
1017 * Open fan devices and initialize per fan data structure.
1018 * Returns #fans found.
1019 */
1020 static int
envd_setup_fans(void)1021 envd_setup_fans(void)
1022 {
1023 int i, fd;
1024 env_fan_t *fanp;
1025 char path[PATH_MAX];
1026 int fancnt = 0;
1027 uint8_t n = 0;
1028 picl_nodehdl_t tnodeh;
1029 i2c_reg_t i2c_reg;
1030
1031 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
1032 /* make sure cpu0/1 present for validating cpu fans */
1033 if (fanp->id == CPU0_FAN_ID) {
1034 if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) !=
1035 PICL_SUCCESS) {
1036 fanp->present = B_FALSE;
1037 continue;
1038 }
1039 }
1040 if (fanp->id == CPU1_FAN_ID) {
1041 if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) !=
1042 PICL_SUCCESS) {
1043 fanp->present = B_FALSE;
1044 continue;
1045 }
1046 }
1047 if (fanp->id == DIMM_FAN_ID) {
1048 if (ptree_get_node_by_path(DIMM_FAN_CONTROLLER_PATH,
1049 &tnodeh) != PICL_SUCCESS) {
1050 if (env_debug)
1051 envd_log(LOG_ERR,
1052 "dimm Fan not found in the "
1053 "system.\n");
1054 fanp->present = B_FALSE;
1055 continue;
1056 }
1057 }
1058 (void) strcpy(path, "/devices");
1059 (void) strlcat(path, fanp->devfs_path, sizeof (path));
1060 fd = open(path, O_RDWR);
1061 if (fd == -1) {
1062 envd_log(LOG_CRIT,
1063 ENV_FAN_OPEN_FAIL, fanp->name,
1064 fanp->devfs_path, errno, strerror(errno));
1065 fanp->present = B_FALSE;
1066 continue;
1067 }
1068 fanp->fd = fd;
1069 if (fanp->id == DIMM_FAN_ID) {
1070 /*
1071 * set the SW aware bit in command register.
1072 * Clear the Fan fault latch bit.
1073 */
1074 i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER;
1075 i2c_reg.reg_value = (PIC16F819_SW_AWARE_MODE |
1076 PIC16F819_FAN_FAULT_CLEAR);
1077 if (ioctl(fd, I2C_SET_REG, &i2c_reg) == -1) {
1078 if (env_debug)
1079 envd_log(LOG_ERR,
1080 "Error in writing to COMMAND reg. "
1081 "of DIMM FAN controller\n");
1082 }
1083 } else {
1084 /* Get speed range value */
1085 if (ioctl(fd, ADM1031_GET_FAN_FEATURE, &n) != -1) {
1086 fanp->speedrange =
1087 adm_speedrange_map[(n >> 6) & 0x03];
1088 } else {
1089 fanp->speedrange = FAN_RANGE_DEFAULT;
1090 }
1091 }
1092 fanp->present = B_TRUE;
1093 fanp->fanstat = 0;
1094 fanp->cspeed = TACH_UNKNOWN;
1095 fanp->lspeed = TACH_UNKNOWN;
1096 fanp->conccnt = 0;
1097 fancnt++;
1098 }
1099 return (fancnt);
1100 }
1101
1102 static int
envd_setup_disks(void)1103 envd_setup_disks(void)
1104 {
1105 int ret, i, page_index, page_len;
1106 picl_nodehdl_t tnodeh;
1107 env_disk_t *diskp;
1108 uint_t vendor_id;
1109 uint_t device_id;
1110 uchar_t log_page[256];
1111
1112 /*
1113 * Check if the SCSi controller on the system is 1010 or 1030
1114 */
1115
1116 if (ptree_get_node_by_path(SCSI_CONTROLLER_NODE_PATH,
1117 &tnodeh) != PICL_SUCCESS) {
1118 if (env_debug)
1119 envd_log(LOG_ERR,
1120 "On-Board SCSI controller not found "
1121 "in the system.\n");
1122 monitor_disk_temp = 0;
1123 return (-1);
1124 }
1125
1126 if ((ret = ptree_get_propval_by_name(tnodeh, VENDOR_ID,
1127 &vendor_id, sizeof (vendor_id))) != 0) {
1128 if (env_debug)
1129 envd_log(LOG_ERR,
1130 "Error in getting vendor-id for SCSI controller. "
1131 "ret = %d errno = 0x%d\n",
1132 ret, errno);
1133 monitor_disk_temp = 0;
1134 return (-1);
1135 }
1136 if ((ret = ptree_get_propval_by_name(tnodeh, DEVICE_ID,
1137 &device_id, sizeof (device_id))) != 0) {
1138 if (env_debug)
1139 envd_log(LOG_ERR,
1140 "Error in getting device-id for SCSI controller. "
1141 "ret = %d errno = 0x%d\n", ret, errno);
1142 monitor_disk_temp = 0;
1143 return (-1);
1144 }
1145 if (env_debug)
1146 envd_log(LOG_ERR, "vendor-id=0x%x device-id=0x%x\n",
1147 vendor_id, device_id);
1148 if ((vendor_id != LSI1030_VENDOR_ID) ||
1149 (device_id != LSI1030_DEVICE_ID)) {
1150 monitor_disk_temp = 0;
1151 return (-1);
1152 }
1153 /*
1154 * We have found LSI1030 SCSi controller onboard.
1155 */
1156
1157 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
1158
1159 if (ptree_get_node_by_path(diskp->nodepath,
1160 &tnodeh) != PICL_SUCCESS) {
1161 diskp->present = B_FALSE;
1162 if (env_debug)
1163 envd_log(LOG_ERR,
1164 "DISK %d not found in the system.\n",
1165 diskp->id);
1166 continue;
1167 }
1168 diskp->fd = open(diskp->devfs_path, O_RDONLY);
1169 if (diskp->fd == -1) {
1170 diskp->present = B_FALSE;
1171 envd_log(LOG_ERR,
1172 "Error in opening %s errno = 0x%x\n",
1173 diskp->devfs_path, errno);
1174 continue;
1175 }
1176 diskp->present = B_TRUE;
1177 diskp->tpage_supported = B_FALSE;
1178 /*
1179 * Find out if the Temperature page is supported by the disk.
1180 */
1181 ret = scsi_log_sense(diskp->fd, SUPPORTED_LPAGES,
1182 log_page, sizeof (log_page));
1183 if (ret != 0) {
1184 continue;
1185 }
1186 page_len = ((log_page[2] << 8) & 0xFF00) | log_page[3];
1187
1188 for (page_index = LOGPAGEHDRSIZE;
1189 page_index < page_len + LOGPAGEHDRSIZE; page_index++) {
1190 switch (log_page[page_index]) {
1191 case TEMPERATURE_PAGE:
1192 diskp->tpage_supported = B_TRUE;
1193 if (env_debug)
1194 envd_log(LOG_ERR,
1195 "tpage supported for %s\n",
1196 diskp->nodepath);
1197 default:
1198 break;
1199 }
1200 }
1201 diskp->warning_tstamp = 0;
1202 diskp->shutdown_tstamp = 0;
1203 diskp->high_warning = disk_high_warn_temperature;
1204 diskp->low_warning = disk_low_warn_temperature;
1205 diskp->high_shutdown = disk_high_shutdown_temperature;
1206 diskp->low_shutdown = disk_low_shutdown_temperature;
1207 ret = get_disk_temp(diskp);
1208 }
1209 return (0);
1210 }
1211
1212 /*
1213 * Open temperature sensor devices and initialize per sensor data structure.
1214 * Returns #sensors found.
1215 */
1216 static int
envd_setup_sensors(void)1217 envd_setup_sensors(void)
1218 {
1219 env_sensor_t *sensorp;
1220 sensor_ctrl_blk_t *es_ptr;
1221 table_t *tblp;
1222 char path[PATH_MAX];
1223 int sensorcnt = 0;
1224 int i, j, nentries;
1225 int16_t tmin = 0;
1226 picl_nodehdl_t tnodeh;
1227
1228 for (i = 0; i < N_ENVD_SENSORS; ++i) {
1229 sensorp = &envd_sensors[i];
1230 /* Initialize sensor's initial state */
1231 sensorp->shutdown_initiated = B_FALSE;
1232 sensorp->warning_tstamp = 0;
1233 sensorp->shutdown_tstamp = 0;
1234 sensorp->error = 0;
1235 sensorp->crtbl = NULL;
1236 /* make sure cpu0/1 sensors are present */
1237 if (sensorp->id == CPU0_SENSOR_ID) {
1238 if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) !=
1239 PICL_SUCCESS) {
1240 sensorp->present = B_FALSE;
1241 continue;
1242 }
1243 }
1244 if (sensorp->id == CPU1_SENSOR_ID) {
1245 if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) !=
1246 PICL_SUCCESS) {
1247 sensorp->present = B_FALSE;
1248 continue;
1249 }
1250 }
1251 (void) strcpy(path, "/devices");
1252 (void) strlcat(path, sensorp->devfs_path,
1253 sizeof (path));
1254 sensorp->fd = open(path, O_RDWR);
1255 if (sensorp->fd == -1) {
1256 envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL,
1257 sensorp->name, sensorp->devfs_path,
1258 errno, strerror(errno));
1259 sensorp->present = B_FALSE;
1260 continue;
1261 }
1262 sensorp->present = B_TRUE;
1263 sensorcnt++;
1264
1265 /*
1266 * Get Tmin
1267 */
1268
1269 if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE,
1270 &tmin) != -1) {
1271 sensorp->tmin = TMIN(tmin);
1272 } else {
1273 sensorp->tmin = -1;
1274 }
1275 if (env_debug)
1276 envd_log(LOG_ERR, "Sensor %s tmin %d",
1277 sensorp->name, sensorp->tmin);
1278
1279 /*
1280 * Create a correction table
1281 * if correction pairs are present in es
1282 * segment.
1283 */
1284 es_ptr = sensorp->es_ptr;
1285
1286 if (es_ptr == NULL) {
1287 continue;
1288 }
1289 nentries = es_ptr->correctionEntries;
1290
1291 if (nentries <= 2) {
1292 if (env_debug)
1293 envd_log(LOG_CRIT, "sensor correction <2");
1294 continue;
1295 }
1296
1297 sensorp->crtbl = init_table(nentries);
1298 if (sensorp->crtbl == NULL)
1299 continue;
1300 tblp = sensorp->crtbl;
1301 tblp->xymap[0].x =
1302 (char)es_ptr->correctionPair[0].measured;
1303 tblp->xymap[0].y =
1304 (char)es_ptr->correctionPair[0].corrected;
1305
1306 for (j = 1; j < nentries; ++j) {
1307 tblp->xymap[j].x =
1308 (char)es_ptr->correctionPair[j].measured;
1309 tblp->xymap[j].y =
1310 (char)es_ptr->correctionPair[j].corrected;
1311
1312 if (tblp->xymap[j].x <= tblp->xymap[j - 1].x) {
1313 fini_table(tblp);
1314 sensorp->crtbl = NULL;
1315 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
1316 FRU_SEEPROM_NAME);
1317 break;
1318 }
1319 }
1320
1321 if (env_debug) {
1322 envd_log(LOG_CRIT, "Sensor correction %s",
1323 sensorp->name);
1324 for (j = 0; j < nentries; j++)
1325 envd_log(LOG_CRIT, " %d %d",
1326 tblp->xymap[j].x, tblp->xymap[j].y);
1327 }
1328 }
1329 return (sensorcnt);
1330 }
1331
1332 /*
1333 * Modify ADM Tmin/ranges depending what power level
1334 * we are from.
1335 */
1336 static void
updateadm_ranges(char * name,uchar_t cur_lpstate)1337 updateadm_ranges(char *name, uchar_t cur_lpstate)
1338 {
1339 env_sensor_t *sensorp;
1340 fan_ctrl_blk_t *fanctl;
1341 uchar_t tmin;
1342 uchar_t trange;
1343 uint16_t tdata;
1344 int sysfd;
1345 uchar_t sys_id = SYS_HWM_ID;
1346 uint8_t mode;
1347 static uint16_t tsave[2] = {0, 0};
1348 /* Index of saved Tmin/Trange for two sensors */
1349 uint16_t tindex = 0;
1350
1351 sensorp = sensor_lookup(name);
1352 if (sensorp == NULL)
1353 return;
1354
1355 /*
1356 * If there is only one Control pairs then return
1357 */
1358 fanctl = ((env_fan_t *)sensorp->fanp)->es_ptr;
1359
1360 if (fanctl != NULL && fanctl->no_ctl_pairs <= 1)
1361 return;
1362
1363 /*
1364 * if fan control specifies that ranges are same then
1365 * we skip re-programming adm chip.
1366 */
1367
1368 tmin = fanctl->fan_ctl_pairs[0].tMin;
1369 trange = fanctl->fan_ctl_pairs[0].tRange;
1370 if ((tmin == fanctl->fan_ctl_pairs[1].tMin) &&
1371 (trange == fanctl->fan_ctl_pairs[1].tRange))
1372 return;
1373
1374 sysfd = open(hwm_devs[sys_id], O_RDWR);
1375 if (sysfd == -1) {
1376 if (env_debug)
1377 envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[sys_id],
1378 errno, strerror(errno));
1379 return;
1380 }
1381 tindex = ((strcmp(name, SENSOR_SYS_IN) == 0) ? 0 : 1);
1382
1383 /* Read ADM default value only for the first time */
1384 if (tsave[tindex] == 0) {
1385 if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE,
1386 &tsave[tindex]) == -1) {
1387 if (env_debug)
1388 envd_log(LOG_ERR,
1389 "read tminrange ioctl failed");
1390 (void) close(sysfd);
1391 return;
1392 }
1393 }
1394 /*
1395 * Need to reinit ADM to manual mode for Tmin range to be
1396 * effective.
1397 */
1398 mode = ADM1031_MANUAL_MODE;
1399 if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) {
1400 if (env_debug)
1401 envd_log(LOG_ERR, ENV_ADM_MANUAL_MODE);
1402 (void) close(sysfd);
1403 return;
1404 }
1405
1406 if (cur_lpstate == 1) {
1407 /*
1408 * ADM 1031 Tmin/Trange register need to be reprogrammed.
1409 */
1410 tdata = ((fanctl->fan_ctl_pairs[cur_lpstate].tMin / TMIN_UNITS)
1411 << TMIN_SHIFT);
1412 /* Need to pack tRange in ADM bits 2:0 */
1413 switch (fanctl->fan_ctl_pairs[cur_lpstate].tRange) {
1414 case 5:
1415 break;
1416
1417 case 10:
1418 tdata |= 1;
1419 break;
1420
1421 case 20:
1422 tdata |= 2;
1423 break;
1424
1425 case 40:
1426 tdata |= 3;
1427 break;
1428
1429 case 80:
1430 tdata |= 4;
1431 break;
1432 }
1433 } else
1434 tdata = tsave[tindex];
1435
1436 if (ioctl(sensorp->fd, ADM1031_SET_TEMP_MIN_RANGE,
1437 &tdata) != -1)
1438 sensorp->tmin = TMIN(tdata);
1439
1440 mode = ADM1031_AUTO_MODE;
1441 if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) {
1442 if (env_debug)
1443 envd_log(LOG_ERR, ENV_ADM_AUTO_MODE);
1444 }
1445 (void) close(sysfd);
1446 }
1447
1448 /* ARGSUSED */
1449 static void *
pmthr(void * args)1450 pmthr(void *args)
1451 {
1452 pm_state_change_t pmstate;
1453 char physpath[PATH_MAX];
1454 int pre_lpstate;
1455
1456 pmstate.physpath = physpath;
1457 pmstate.size = sizeof (physpath);
1458 cur_lpstate = 0;
1459 pre_lpstate = 1;
1460
1461 pm_fd = open(PM_DEVICE, O_RDWR);
1462 if (pm_fd == -1) {
1463 envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno));
1464 return (NULL);
1465 }
1466 for (;;) {
1467 /*
1468 * Get PM state change events to check if the system
1469 * is in lowest power state and adjust ADM hardware
1470 * monitor's fan speed settings.
1471 *
1472 * To minimize polling, we use the blocking interface
1473 * to get the power state change event here.
1474 */
1475 if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) {
1476 if (errno != EINTR)
1477 break;
1478 continue;
1479 }
1480 do {
1481 if (env_debug) {
1482 envd_log(LOG_INFO,
1483 "pmstate event:0x%x flags:%x"
1484 "comp:%d oldval:%d newval:%d path:%s\n",
1485 pmstate.event, pmstate.flags,
1486 pmstate.component,
1487 pmstate.old_level,
1488 pmstate.new_level,
1489 pmstate.physpath);
1490 }
1491 cur_lpstate =
1492 (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0;
1493 } while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0);
1494 /*
1495 * Change ADM ranges as per E* Requirements. Update
1496 * happens only for valid state changes.
1497 */
1498 if (pre_lpstate != cur_lpstate) {
1499 pre_lpstate = cur_lpstate;
1500 updateadm_ranges(SENSOR_SYS_OUT, cur_lpstate);
1501 updateadm_ranges(SENSOR_SYS_IN, cur_lpstate);
1502 }
1503 }
1504 /* Not reached */
1505 return (NULL);
1506 }
1507
1508 /*
1509 * This function is used to reasonably predict the
1510 * state of the fan (ON/OFF) using tmin and current temperature.
1511 *
1512 * We know the fan is on if temp >= tmin and fan is off if
1513 * temp < (Tmin - Hysterisis).
1514 *
1515 * When the temperature is in between we don't know if the fan is on/off
1516 * because the temperature could be decreasing and not have crossed
1517 * Tmin - hysterisis and vice a versa.
1518 *
1519 * FAN ON
1520 * Tmin
1521 * -------------------------------------------
1522 *
1523 * FAN ON/OFF
1524 *
1525 * --------------------------------------------
1526 * Tmin - Hysterisis
1527 * FAN OFF
1528 *
1529 * To solve the problem of finding out if the fan is on/off in our gray region
1530 * we keep track of the last read tach and the current read tach. From
1531 * experimentation and from discussions with analog devices it is unlikely that
1532 * if the fans are on we will get a constant tach reading more than 5 times in
1533 * a row. This is not but the most fool proof approach but the best we can do.
1534 *
1535 * This routine implements the above logic for a sensor with an
1536 * associated fan. The caller garauntees sensorp and fanp are not null.
1537 */
1538
1539 static void
check_fanstat(env_sensor_t * sensorp)1540 check_fanstat(env_sensor_t *sensorp)
1541 {
1542 env_fan_t *fanp = sensorp->fanp;
1543 tempr_t temp;
1544 uint8_t fanspeed;
1545
1546 if (get_raw_temperature(sensorp, &temp) == -1)
1547 return;
1548
1549 if (temp < (sensorp->tmin - ADM_HYSTERISIS)) {
1550
1551 fanp->fanstat = 0; /* Fan off */
1552 fanp->lspeed = TACH_UNKNOWN; /* Reset Last read tach */
1553 fanp->conccnt = 0;
1554
1555 } else if (temp >= sensorp->tmin) {
1556
1557 fanp->fanstat = 1; /* Fan on */
1558 fanp->lspeed = TACH_UNKNOWN;
1559 fanp->conccnt = 0;
1560
1561 } else {
1562 if (get_raw_fan_speed(fanp, &fanspeed) == -1)
1563 return;
1564
1565 fanp->cspeed = fanspeed;
1566 /*
1567 * First time in the gray area
1568 * set last read speed to current speed
1569 */
1570 if (fanp->lspeed == TACH_UNKNOWN) {
1571 fanp->lspeed = fanspeed;
1572 } else {
1573 if (fanp->lspeed != fanp->cspeed) {
1574 fanp->conccnt = 0;
1575 fanp->fanstat = 1;
1576 } else {
1577 fanp->conccnt++;
1578
1579 if (fanp->conccnt >= N_SEQ_TACH)
1580 fanp->fanstat = 0;
1581 }
1582 fanp->lspeed = fanp->cspeed;
1583 }
1584 }
1585 }
1586 /*
1587 * There is an issue with the ADM1031 chip that causes the chip
1588 * to not update the tach register in case the fan stops. The
1589 * fans stop when the temperature measured (temp) drops below
1590 * Tmin - Hysterisis and turn on when the temp >= Tmin.
1591 *
1592 * Since the tach registers don't update and remain stuck at the
1593 * last read tach value our get_fan_speed function always returns
1594 * a non-zero RPM reading.
1595 *
1596 * To fix this we need to figure out when the fans will be on/off
1597 * depending on the current temperature. Currently we poll for
1598 * interrupts, we can use that loop to determine what the current
1599 * temperature is and if the fans should be on/off.
1600 *
1601 * We get current temperature and check the fans.
1602 */
1603 static void
monitor_fanstat(void)1604 monitor_fanstat(void)
1605 {
1606 env_sensor_t *sensorp;
1607 env_fan_t *fanp;
1608 int i;
1609
1610 for (i = 0; i < N_ENVD_SENSORS; i++) {
1611 sensorp = &envd_sensors[i];
1612
1613 if (!sensorp)
1614 continue;
1615
1616 fanp = sensorp->fanp;
1617
1618 if (!(fanp && fanp->present))
1619 continue;
1620
1621 if (sensorp->tmin != -1) {
1622 check_fanstat(sensorp);
1623 } else {
1624 fanp->fanstat = 1;
1625 }
1626
1627 }
1628 }
1629
1630 static int
handle_overtemp_interrupt(int hwm_id)1631 handle_overtemp_interrupt(int hwm_id)
1632 {
1633 env_sensor_t *sensorp;
1634 tempr_t temp;
1635 uchar_t smap[MAX_SENSORS];
1636 time_t ct;
1637 uchar_t i;
1638 char msgbuf[BUFSIZ];
1639 char syscmd[BUFSIZ];
1640 boolean_t return_flag;
1641 int ret;
1642 timespec_t to;
1643 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
1644 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER;
1645
1646 /* Clear Map of Sensor Entries */
1647 (void) memset(smap, SENSOR_OK, sizeof (smap));
1648
1649 for (;;) {
1650 for (i = 0; i < N_ENVD_SENSORS; i++) {
1651 sensorp = &envd_sensors[i];
1652
1653 /*
1654 * Check whether the sensor belongs to the
1655 * interrupting ADM hardware monitor
1656 */
1657 if (sensorp->hwm_id != hwm_id)
1658 continue;
1659
1660 if (sensorp->present == B_FALSE)
1661 continue;
1662 /*
1663 * if shutdown is initiated then we simply loop
1664 * through the sensors until shutdown
1665 */
1666 if (sensorp->shutdown_initiated == B_TRUE)
1667 continue;
1668
1669 /* get current temp for this sensor */
1670 if (get_temperature(sensorp, &temp) == -1)
1671 continue;
1672
1673 sensorp->cur_temp = temp;
1674
1675 if (env_debug)
1676 envd_log(LOG_ERR,
1677 "sensor name %s, cur temp %d, "
1678 "HW %d LW %d SD %d LS %d\n",
1679 sensorp->name, temp,
1680 sensorp->es_ptr->high_warning,
1681 (int)sensorp->es_ptr->low_warning,
1682 sensorp->es_ptr->high_shutdown,
1683 (int)sensorp->es_ptr->low_shutdown);
1684
1685 if (TEMP_IN_WARNING_RANGE(sensorp->cur_temp, sensorp)) {
1686 /*
1687 * Log on warning atmost one second
1688 */
1689 ct = (time_t)(gethrtime() / NANOSEC);
1690 if ((ct - sensorp->warning_tstamp) >=
1691 warning_interval) {
1692 envd_log(LOG_CRIT,
1693 ENV_WARNING_MSG, sensorp->name,
1694 temp,
1695 sensorp->es_ptr->low_warning,
1696 sensorp->es_ptr->high_warning);
1697 sensorp->warning_tstamp = ct;
1698 }
1699 smap[i] = SENSOR_WARN;
1700 } else {
1701 /*
1702 * We will fall in this caterory only if
1703 * Temperature drops/increases from warning
1704 * threshold. If so we set sensor map to
1705 * OK so that we can exit the loop if
1706 * shutdown not initiated.
1707 */
1708 smap[i] = SENSOR_OK;
1709 }
1710
1711 if (TEMP_IN_SHUTDOWN_RANGE(temp, sensorp) &&
1712 !shutdown_override) {
1713 ct = (time_t)(gethrtime() / NANOSEC);
1714 if (sensorp->shutdown_tstamp == 0)
1715 sensorp->shutdown_tstamp = ct;
1716 if ((ct - sensorp->shutdown_tstamp) >=
1717 shutdown_interval) {
1718 sensorp->shutdown_initiated = B_TRUE;
1719 (void) snprintf(msgbuf, sizeof (msgbuf),
1720 ENV_SHUTDOWN_MSG, sensorp->name,
1721 temp,
1722 sensorp->es_ptr->low_shutdown,
1723 sensorp->es_ptr->high_shutdown);
1724 envd_log(LOG_ALERT, msgbuf);
1725 }
1726 if (system_shutdown_started == B_FALSE) {
1727 (void) snprintf(syscmd, sizeof (syscmd),
1728 "%s \"%s\"", SHUTDOWN_CMD, msgbuf);
1729 envd_log(LOG_ALERT, syscmd);
1730 system_shutdown_started = B_TRUE;
1731 (void) system(syscmd);
1732 }
1733 } else if (sensorp->shutdown_tstamp != 0)
1734 sensorp->shutdown_tstamp = 0;
1735 }
1736
1737 /*
1738 * Sweep thorugh Sensor Map and if warnings OR shutdown
1739 * are not logged then return to caller.
1740 */
1741 return_flag = B_TRUE;
1742 for (i = 0; i < N_ENVD_SENSORS; i++)
1743 if (smap[i] == SENSOR_WARN)
1744 return_flag = B_FALSE;
1745
1746 if ((return_flag == B_TRUE) &&
1747 (system_shutdown_started == B_FALSE)) {
1748 return (1);
1749 }
1750
1751 wait_till_timeout:
1752 /*
1753 * We use pthread_cond_reltimedwait_np to sleep for
1754 * fixed interval of time.
1755 * earlier implementation used alarm() call which
1756 * fails in Multi threaded environment. If multiple
1757 * threads call alarm() only one of the threads is
1758 * sent the SIGALRM signal.
1759 */
1760 (void) pthread_mutex_lock(&env_monitor_mutex);
1761 ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
1762 &env_monitor_mutex, &to);
1763 to.tv_sec = SENSORPOLL_INTERVAL;
1764 to.tv_nsec = 0;
1765 if (ret != ETIMEDOUT) {
1766 (void) pthread_mutex_unlock(&env_monitor_mutex);
1767 goto wait_till_timeout;
1768 }
1769 (void) pthread_mutex_unlock(&env_monitor_mutex);
1770 }
1771 }
1772
1773 /*
1774 * This is env thread which monitors the current temperature when
1775 * warning threshold is exceeded. The job is to make sure it does
1776 * not execced/decrease shutdown threshold. If it does it will start
1777 * forced shutdown to avoid reaching hardware poweroff via THERM interrupt.
1778 * For Enchilada there will be two threads, one for each ADM chip.
1779 */
1780 static void *
ovtemp_thr(void * args)1781 ovtemp_thr(void *args)
1782 {
1783 int fd;
1784 uint8_t stat[2];
1785 int hwm_id = (int)args;
1786 int err;
1787 env_fan_t *fanp;
1788 timespec_t to;
1789 int ret;
1790 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
1791 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER;
1792
1793 fd = open(hwm_devs[hwm_id], O_RDWR);
1794 if (fd == -1) {
1795 envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[hwm_id],
1796 errno, strerror(errno));
1797 return (NULL);
1798 }
1799 if (env_debug)
1800 envd_log(LOG_ERR, "ovtemp thread for %s running...\n",
1801 hwm_devs[hwm_id]);
1802
1803 for (;;) {
1804 /*
1805 * Sleep for specified seconds before issuing IOCTL
1806 * again.
1807 */
1808
1809 /*
1810 * We use pthread_cond_reltimedwait_np to sleep for
1811 * fixed interval of time.
1812 * earlier implementation used alarm() call which
1813 * fails in Multi threaded environment. If multiple
1814 * threads call alarm() only one of the threads is
1815 * sent the SIGALRM signal.
1816 */
1817 (void) pthread_mutex_lock(&env_monitor_mutex);
1818 ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
1819 &env_monitor_mutex, &to);
1820 to.tv_sec = INTERRUPTPOLL_INTERVAL;
1821 to.tv_nsec = 0;
1822 if (ret != ETIMEDOUT) {
1823 (void) pthread_mutex_unlock(&env_monitor_mutex);
1824 continue;
1825 }
1826 (void) pthread_mutex_unlock(&env_monitor_mutex);
1827 /*
1828 * Monitor the sensors to update fan status
1829 */
1830 if (mon_fanstat)
1831 monitor_fanstat();
1832
1833 /*
1834 * Read ADM1031 two Status Registers to determine source
1835 * of Interrupts.
1836 */
1837
1838 if ((err = ioctl(fd, ADM1031_GET_STATUS_1, &stat[0])) != -1)
1839 err = ioctl(fd, ADM1031_GET_STATUS_2, &stat[1]);
1840
1841 if (err == -1) {
1842 if (env_debug)
1843 envd_log(LOG_ERR,
1844 "OverTemp: Status Error");
1845 continue;
1846 }
1847
1848 if (env_debug)
1849 envd_log(LOG_ERR, "INTR %s, Stat1 %x, Stat2 %x",
1850 hwm_devs[hwm_id], stat[0], stat[1]);
1851
1852 if (stat[0] & FANFAULT) {
1853 fanp = fan_lookup(hwm_fans[hwm_id][HWM_FAN1]);
1854 if (fanp && fanp->present)
1855 envd_log(LOG_ERR, ENV_FAN_FAULT,
1856 hwm_devs[hwm_id],
1857 hwm_fans[hwm_id][HWM_FAN1]);
1858 }
1859 if (stat[1] & FANFAULT) {
1860 fanp = fan_lookup(hwm_fans[hwm_id][HWM_FAN2]);
1861 if (fanp && fanp->present)
1862 envd_log(LOG_ERR, ENV_FAN_FAULT,
1863 hwm_devs[hwm_id],
1864 hwm_fans[hwm_id][HWM_FAN2]);
1865 }
1866 /*
1867 * Check respective Remote/Local High, Low before start
1868 * manual monitoring
1869 */
1870 if ((stat[0] & STAT1MASK) || (stat[1] & STAT2MASK))
1871 (void) handle_overtemp_interrupt(hwm_id);
1872
1873 } /* end of for ever loop */
1874 /*NOTREACHED*/
1875 return (NULL);
1876 }
1877
1878 static void *
dimm_fan_thr(void * args)1879 dimm_fan_thr(void *args)
1880 {
1881 char syscmd[BUFSIZ];
1882 char msgbuf[BUFSIZ];
1883 i2c_reg_t i2c_reg;
1884 timespec_t to;
1885 int ret;
1886 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
1887 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER;
1888
1889 for (;;) {
1890 /*
1891 * Sleep for specified seconds before issuing IOCTL
1892 * again.
1893 */
1894 (void) pthread_mutex_lock(&env_monitor_mutex);
1895 ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
1896 &env_monitor_mutex, &to);
1897 to.tv_sec = INTERRUPTPOLL_INTERVAL;
1898 to.tv_nsec = 0;
1899 if (ret != ETIMEDOUT) {
1900 (void) pthread_mutex_unlock(&env_monitor_mutex);
1901 continue;
1902 }
1903 (void) pthread_mutex_unlock(&env_monitor_mutex);
1904 /*
1905 * We write to the comand register periodically
1906 * to inform the PIC firmware that Solaris is
1907 * Monitoring the dimm fan periodically.
1908 */
1909 i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER;
1910 i2c_reg.reg_value = PIC16F819_SW_AWARE_MODE;
1911 if (ioctl(envd_dimm_fan.fd,
1912 I2C_SET_REG, &i2c_reg) == -1) {
1913 if (env_debug)
1914 envd_log(LOG_ERR,
1915 "Error in writing to COMMAND reg. "
1916 "of DIMM FAN controller\n");
1917 }
1918 /*
1919 * We initiate shutdown if fan status indicates
1920 * failure.
1921 */
1922 if (is_dimm_fan_failed() != 0) {
1923 /*
1924 * Mark Dimm fan present as False so that we
1925 * do not WARN the user of the Fan failure
1926 * repeatedly.
1927 */
1928 envd_dimm_fan.present = B_FALSE;
1929 (void) snprintf(msgbuf, sizeof (msgbuf),
1930 ENV_DIMM_FAN_FAILURE_SHUTDOWN_MSG,
1931 ENV_DIMM_FAN,
1932 dimm_fan_rpm_string, dimm_fan_status_string,
1933 dimm_fan_command_string,
1934 dimm_fan_debug_string);
1935 envd_log(LOG_ALERT, msgbuf);
1936
1937 if (system_shutdown_started == B_FALSE) {
1938 system_shutdown_started = B_TRUE;
1939 (void) snprintf(syscmd, sizeof (syscmd),
1940 "%s \"%s\"",
1941 SHUTDOWN_CMD,
1942 msgbuf);
1943 envd_log(LOG_ALERT, syscmd);
1944 (void) system(syscmd);
1945 }
1946 }
1947 }
1948 /*NOTREACHED*/
1949 return (NULL);
1950 }
1951 static int
scsi_log_sense(int fd,uchar_t page_code,uchar_t * pagebuf,uint16_t pagelen)1952 scsi_log_sense(int fd, uchar_t page_code, uchar_t *pagebuf, uint16_t pagelen)
1953 {
1954 struct uscsi_cmd ucmd_buf;
1955 uchar_t cdb_buf[CDB_GROUP1];
1956 struct scsi_extended_sense sense_buf;
1957 int ret_val;
1958
1959 bzero((void *)&cdb_buf, sizeof (cdb_buf));
1960 bzero((void *)&ucmd_buf, sizeof (ucmd_buf));
1961 bzero((void *)&sense_buf, sizeof (sense_buf));
1962
1963 cdb_buf[0] = SCMD_LOG_SENSE_G1;
1964 cdb_buf[2] = (0x01 << 6) | page_code;
1965 cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8);
1966 cdb_buf[8] = (uchar_t)(pagelen & 0x00FF);
1967
1968 ucmd_buf.uscsi_cdb = (char *)cdb_buf;
1969 ucmd_buf.uscsi_cdblen = sizeof (cdb_buf);
1970 ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf;
1971 ucmd_buf.uscsi_buflen = pagelen;
1972 ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf;
1973 ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense);
1974 ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT;
1975 ucmd_buf.uscsi_timeout = 60;
1976
1977 ret_val = ioctl(fd, USCSICMD, ucmd_buf);
1978 if (ret_val == 0 && ucmd_buf.uscsi_status == 0) {
1979 if (env_debug)
1980 envd_log(LOG_ERR,
1981 "log sense command for page_code 0x%x succeeded\n",
1982 page_code);
1983 return (ret_val);
1984 }
1985 if (env_debug)
1986 envd_log(LOG_ERR,
1987 "log sense command failed.ret_val = 0x%x status = 0x%x "
1988 "errno = 0x%x\n",
1989 ret_val, ucmd_buf.uscsi_status, errno);
1990 return (1);
1991 }
1992
1993 static int
get_disk_temp(env_disk_t * diskp)1994 get_disk_temp(env_disk_t *diskp)
1995 {
1996 int ret;
1997 uchar_t tpage[256];
1998
1999 ret = scsi_log_sense(diskp->fd,
2000 TEMPERATURE_PAGE,
2001 tpage, sizeof (tpage));
2002 if (ret != 0) {
2003 diskp->current_temp = DISK_INVALID_TEMP;
2004 diskp->ref_temp = DISK_INVALID_TEMP;
2005 return (-1);
2006 }
2007 /*
2008 * For the current temperature verify that the parameter
2009 * length is 0x02 and the parameter code is 0x00
2010 * Temperature value of 255(0xFF) is considered INVALID.
2011 */
2012 if ((tpage[7] == 0x02) && (tpage[4] == 0x00) &&
2013 (tpage[5] == 0x00)) {
2014 if (tpage[9] == 0xFF) {
2015 diskp->current_temp = DISK_INVALID_TEMP;
2016 return (-1);
2017 } else {
2018 diskp->current_temp = tpage[9];
2019 }
2020 }
2021
2022 /*
2023 * For the reference temperature verify that the parameter
2024 * length is 0x02 and the parameter code is 0x01
2025 * Temperature value of 255(0xFF) is considered INVALID.
2026 */
2027 if ((tpage[13] == 0x02) && (tpage[10] == 0x00) &&
2028 (tpage[11] == 0x01)) {
2029 if (tpage[15] == 0xFF) {
2030 diskp->ref_temp = DISK_INVALID_TEMP;
2031 } else {
2032 diskp->ref_temp = tpage[15];
2033 }
2034 }
2035 return (0);
2036 }
2037
2038 /* ARGSUSED */
2039 static void *
disk_temp_thr(void * args)2040 disk_temp_thr(void *args)
2041 {
2042 char syscmd[BUFSIZ];
2043 char msgbuf[BUFSIZ];
2044 timespec_t to;
2045 int ret, i;
2046 env_disk_t *diskp;
2047 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
2048 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER;
2049 pm_state_change_t pmstate;
2050 int idle_time;
2051 int disk_pm_fd;
2052 time_t ct;
2053
2054 disk_pm_fd = open(PM_DEVICE, O_RDWR);
2055 if (disk_pm_fd == -1) {
2056 envd_log(LOG_ERR,
2057 DISK_TEMP_THREAD_EXITING,
2058 errno, strerror(errno));
2059 return (NULL);
2060 }
2061 for (;;) {
2062 /*
2063 * Sleep for specified seconds before issuing IOCTL
2064 * again.
2065 */
2066 (void) pthread_mutex_lock(&env_monitor_mutex);
2067 ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
2068 &env_monitor_mutex, &to);
2069 to.tv_sec = disk_scan_interval;
2070 to.tv_nsec = 0;
2071 if (ret != ETIMEDOUT) {
2072 (void) pthread_mutex_unlock(&env_monitor_mutex);
2073 continue;
2074 }
2075 (void) pthread_mutex_unlock(&env_monitor_mutex);
2076 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
2077 if (diskp->present == B_FALSE)
2078 continue;
2079 if (diskp->tpage_supported == B_FALSE)
2080 continue;
2081 /*
2082 * If the disk temperature is above the warning
2083 * threshold continue monitoring until the temperature
2084 * drops below warning threshold.
2085 * If the temperature is in the NORMAL range monitor
2086 * only when the disk is BUSY.
2087 * We do not want to read the disk temperature if the
2088 * disk is is idling. The reason for this is disk will
2089 * never get into lowest power mode if we scan the disk
2090 * temperature peridoically.
2091 * To avoid this situation we first determine
2092 * the idle_time of the disk. If the disk has been
2093 * IDLE since we scanned the temperature last time
2094 * we will not read the temperature.
2095 */
2096 if (!DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp,
2097 diskp)) {
2098 pmstate.physpath = diskp->physpath;
2099 pmstate.size = strlen(diskp->physpath);
2100 pmstate.component = 0;
2101 if ((idle_time =
2102 ioctl(disk_pm_fd,
2103 PM_GET_TIME_IDLE, &pmstate)) == -1) {
2104 if (errno != EINTR) {
2105 if (env_debug) {
2106 envd_log(LOG_ERR,
2107 "ioctl "
2108 "PM_GET_TIME_IDLE "
2109 "failed for DISK0."
2110 " errno=0x%x\n",
2111 errno);
2112 }
2113 continue;
2114 }
2115 continue;
2116 }
2117 if (idle_time >= (disk_scan_interval/2)) {
2118 if (env_debug) {
2119 envd_log(LOG_ERR,
2120 "%s idle time = %d\n",
2121 diskp->name, idle_time);
2122 }
2123 continue;
2124 }
2125 }
2126 ret = get_disk_temp(diskp);
2127 if (ret != 0)
2128 continue;
2129 if (env_debug) {
2130 envd_log(LOG_ERR,
2131 "%s temp = %d ref. temp = %d\n",
2132 diskp->name, diskp->current_temp,
2133 diskp->ref_temp);
2134 }
2135 /*
2136 * If this disk already triggered system shutdown, don't
2137 * log any more shutdown/warning messages for it.
2138 */
2139 if (diskp->shutdown_initiated)
2140 continue;
2141
2142 /*
2143 * Check for the temperature in warning and shutdown
2144 * range and take appropriate action.
2145 */
2146 if (DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp,
2147 diskp)) {
2148 /*
2149 * Check if the temperature has been in warning
2150 * range during last disk_warning_duration
2151 * interval.
2152 * If so, the temperature is truly in warning
2153 * range and we need to log a warning message,
2154 * but no more than once every
2155 * disk_warning_interval seconds.
2156 */
2157 time_t wtstamp = diskp->warning_tstamp;
2158
2159 ct = (time_t)(gethrtime() / NANOSEC);
2160 if (diskp->warning_start == 0)
2161 diskp->warning_start = ct;
2162 if (((ct - diskp->warning_start) >=
2163 disk_warning_duration) && (wtstamp == 0 ||
2164 (ct - wtstamp) >= disk_warning_interval)) {
2165 envd_log(LOG_CRIT, ENV_WARNING_MSG,
2166 diskp->name, diskp->current_temp,
2167 diskp->low_warning,
2168 diskp->high_warning);
2169 diskp->warning_tstamp = ct;
2170 }
2171 } else if (diskp->warning_start != 0)
2172 diskp->warning_start = 0;
2173
2174 if (!shutdown_override &&
2175 DISK_TEMP_IN_SHUTDOWN_RANGE(diskp->current_temp,
2176 diskp)) {
2177 ct = (time_t)(gethrtime() / NANOSEC);
2178 if (diskp->shutdown_tstamp == 0)
2179 diskp->shutdown_tstamp = ct;
2180
2181 /*
2182 * Shutdown the system if the temperature
2183 * remains in the shutdown range for over
2184 * disk_shutdown_interval seconds.
2185 */
2186 if ((ct - diskp->shutdown_tstamp) >=
2187 disk_shutdown_interval) {
2188 /* log error */
2189 diskp->shutdown_initiated = B_TRUE;
2190 (void) snprintf(msgbuf, sizeof (msgbuf),
2191 ENV_SHUTDOWN_MSG, diskp->name,
2192 diskp->current_temp,
2193 diskp->low_shutdown,
2194 diskp->high_shutdown);
2195 envd_log(LOG_ALERT, msgbuf);
2196
2197 /* shutdown the system (only once) */
2198 if (system_shutdown_started ==
2199 B_FALSE) {
2200 (void) snprintf(syscmd,
2201 sizeof (syscmd),
2202 "%s \"%s\"", shutdown_cmd,
2203 msgbuf);
2204 envd_log(LOG_ALERT, syscmd);
2205 system_shutdown_started =
2206 B_TRUE;
2207 (void) system(syscmd);
2208 }
2209 }
2210 } else if (diskp->shutdown_tstamp != 0)
2211 diskp->shutdown_tstamp = 0;
2212
2213 }
2214 } /* end of forever loop */
2215 }
2216
2217 /*
2218 * Setup envrionmental monitor state and start threads to monitor
2219 * temperature and power management state.
2220 * Returns -1 on error, 0 if successful.
2221 */
2222 static int
envd_setup(void)2223 envd_setup(void)
2224 {
2225 int ret;
2226
2227 if (getenv("SUNW_piclenvd_debug") != NULL)
2228 env_debug = 1;
2229
2230 if (pthread_attr_init(&thr_attr) != 0 ||
2231 pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) {
2232 return (-1);
2233 }
2234
2235 ret = envd_es_setup();
2236 if (ret < 0) {
2237 ovtemp_monitor = 0;
2238 pm_monitor = 0;
2239 }
2240
2241 /*
2242 * Setup temperature sensors and fail if we can't open
2243 * at least one sensor.
2244 */
2245 if (envd_setup_sensors() <= 0) {
2246 return (0);
2247 }
2248
2249 /*
2250 * Setup fan device (don't fail even if we can't access
2251 * the fan as we can still monitor temeperature.
2252 */
2253 (void) envd_setup_fans();
2254
2255 (void) envd_setup_disks();
2256
2257 /* If ES Segment setup failed,don't create thread */
2258
2259 if (ovtemp_monitor && ovtemp_thr1_created == B_FALSE) {
2260 if (pthread_create(&ovtemp_thr1_id, &thr_attr, ovtemp_thr,
2261 (void *)CPU_HWM_ID) != 0)
2262 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
2263 else
2264 ovtemp_thr1_created = B_TRUE;
2265 }
2266
2267 if (ovtemp_monitor && ovtemp_thr2_created == B_FALSE) {
2268 if (pthread_create(&ovtemp_thr2_id, &thr_attr, ovtemp_thr,
2269 (void *)SYS_HWM_ID) != 0)
2270 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
2271 else
2272 ovtemp_thr2_created = B_TRUE;
2273 }
2274
2275 if (envd_dimm_fan.present) {
2276 if (dimm_fan_thr_created == B_FALSE) {
2277 if (pthread_create(&dimm_fan_thr_id, &thr_attr,
2278 dimm_fan_thr, NULL) != 0)
2279 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
2280 else
2281 dimm_fan_thr_created = B_TRUE;
2282 }
2283 }
2284
2285 /*
2286 * Create a thread to monitor PM state
2287 */
2288 if (pm_monitor && pmthr_created == B_FALSE) {
2289 if (pthread_create(&pmthr_tid, &thr_attr, pmthr,
2290 NULL) != 0)
2291 envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED);
2292 else
2293 pmthr_created = B_TRUE;
2294 }
2295 if (monitor_disk_temp) {
2296 if (disk_temp_thr_created == B_FALSE) {
2297 if (pthread_create(&disk_temp_thr_id, &thr_attr,
2298 disk_temp_thr, NULL) != 0)
2299 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
2300 else
2301 disk_temp_thr_created = B_TRUE;
2302 }
2303 }
2304 return (0);
2305 }
2306
2307 static void
piclenvd_register(void)2308 piclenvd_register(void)
2309 {
2310 picld_plugin_register(&my_reg_info);
2311 }
2312
2313 static void
piclenvd_init(void)2314 piclenvd_init(void)
2315 {
2316
2317 (void) env_picl_setup_tuneables();
2318
2319 /*
2320 * Setup the environmental data structures
2321 */
2322 if (envd_setup() != 0) {
2323 envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED);
2324 return;
2325 }
2326
2327 /*
2328 * Now setup/populate PICL tree
2329 */
2330 env_picl_setup();
2331 }
2332
2333 static void
piclenvd_fini(void)2334 piclenvd_fini(void)
2335 {
2336
2337 /*
2338 * Invoke env_picl_destroy() to remove any PICL nodes/properties
2339 * (including volatile properties) we created. Once this call
2340 * returns, there can't be any more calls from the PICL framework
2341 * to get current temperature or fan speed.
2342 */
2343 env_picl_destroy();
2344 envd_close_sensors();
2345 envd_close_fans();
2346 envd_es_destroy();
2347 }
2348
2349 /*VARARGS2*/
2350 void
envd_log(int pri,const char * fmt,...)2351 envd_log(int pri, const char *fmt, ...)
2352 {
2353 va_list ap;
2354
2355 va_start(ap, fmt);
2356 vsyslog(pri, fmt, ap);
2357 va_end(ap);
2358 }
2359
2360 /*
2361 * Tunables support functions
2362 */
2363 static env_tuneable_t *
tuneable_lookup(picl_prophdl_t proph)2364 tuneable_lookup(picl_prophdl_t proph)
2365 {
2366 int i;
2367 env_tuneable_t *tuneablep = NULL;
2368
2369 for (i = 0; i < ntuneables; i++) {
2370 tuneablep = &tuneables[i];
2371 if (tuneablep->proph == proph)
2372 return (tuneablep);
2373 }
2374
2375 return (NULL);
2376 }
2377
2378 static int
get_cpu_tach(ptree_rarg_t * parg,void * buf)2379 get_cpu_tach(ptree_rarg_t *parg, void *buf)
2380 {
2381 picl_prophdl_t proph;
2382 env_tuneable_t *tuneablep;
2383 int fd;
2384 int8_t cfg;
2385
2386 proph = parg->proph;
2387
2388 tuneablep = tuneable_lookup(proph);
2389
2390 if (tuneablep == NULL)
2391 return (PICL_FAILURE);
2392
2393 fd = open(CPU_HWM_DEVFS, O_RDWR);
2394
2395 if (fd == -1) {
2396 return (PICL_FAILURE);
2397 }
2398
2399 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
2400 return (PICL_FAILURE);
2401 }
2402
2403 if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) {
2404 *((int *)tuneablep->value) = ENABLE;
2405 } else {
2406 *((int *)tuneablep->value) = DISABLE;
2407 }
2408
2409 (void) memcpy(buf, tuneablep->value,
2410 tuneablep->nbytes);
2411
2412 (void) close(fd);
2413 return (PICL_SUCCESS);
2414 }
2415
2416 static int
set_cpu_tach(ptree_warg_t * parg,const void * buf)2417 set_cpu_tach(ptree_warg_t *parg, const void *buf)
2418 {
2419 picl_prophdl_t proph;
2420 env_tuneable_t *tuneablep;
2421 int fd, val;
2422 int8_t cfg;
2423
2424 if (parg->cred.dc_euid != 0)
2425 return (PICL_PERMDENIED);
2426
2427 proph = parg->proph;
2428
2429 tuneablep = tuneable_lookup(proph);
2430
2431 if (tuneablep == NULL)
2432 return (PICL_FAILURE);
2433
2434
2435 fd = open(CPU_HWM_DEVFS, O_RDWR);
2436
2437 if (fd == -1) {
2438 return (PICL_FAILURE);
2439 }
2440
2441 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
2442 return (PICL_FAILURE);
2443 }
2444
2445 (void) memcpy(&val, (caddr_t)buf, sizeof (val));
2446
2447 if (val == ENABLE) {
2448 cfg |= TACH_ENABLE_MASK;
2449 } else if (val == DISABLE) {
2450 cfg &= ~TACH_ENABLE_MASK;
2451 }
2452
2453
2454 if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) {
2455 return (PICL_FAILURE);
2456 }
2457
2458 (void) close(fd);
2459 return (PICL_SUCCESS);
2460 }
2461
2462 static int
get_sys_tach(ptree_rarg_t * parg,void * buf)2463 get_sys_tach(ptree_rarg_t *parg, void *buf)
2464 {
2465 picl_prophdl_t proph;
2466 env_tuneable_t *tuneablep;
2467 int fd;
2468 int8_t cfg;
2469
2470 proph = parg->proph;
2471
2472 tuneablep = tuneable_lookup(proph);
2473
2474 if (tuneablep == NULL)
2475 return (PICL_FAILURE);
2476
2477 fd = open(SYS_HWM_DEVFS, O_RDWR);
2478
2479 if (fd == -1) {
2480 return (PICL_FAILURE);
2481 }
2482
2483 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
2484 return (PICL_FAILURE);
2485 }
2486
2487 if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) {
2488 *((int *)tuneablep->value) = ENABLE;
2489 } else {
2490 *((int *)tuneablep->value) = DISABLE;
2491 }
2492
2493 (void) memcpy(buf, tuneablep->value,
2494 tuneablep->nbytes);
2495
2496 (void) close(fd);
2497 return (PICL_SUCCESS);
2498 }
2499
2500 static int
set_sys_tach(ptree_warg_t * parg,const void * buf)2501 set_sys_tach(ptree_warg_t *parg, const void *buf)
2502 {
2503 picl_prophdl_t proph;
2504 env_tuneable_t *tuneablep;
2505 int fd, val;
2506 int8_t cfg;
2507
2508 if (parg->cred.dc_euid != 0)
2509 return (PICL_PERMDENIED);
2510
2511 proph = parg->proph;
2512
2513 tuneablep = tuneable_lookup(proph);
2514
2515 if (tuneablep == NULL)
2516 return (PICL_FAILURE);
2517
2518
2519 fd = open(SYS_HWM_DEVFS, O_RDWR);
2520
2521 if (fd == -1) {
2522 return (PICL_FAILURE);
2523 }
2524
2525 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
2526 return (PICL_FAILURE);
2527 }
2528
2529 (void) memcpy(&val, buf, sizeof (val));
2530
2531 if (val == ENABLE) {
2532 cfg |= TACH_ENABLE_MASK;
2533 } else if (val == DISABLE) {
2534 cfg &= ~TACH_ENABLE_MASK;
2535 }
2536
2537
2538 if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) {
2539 return (PICL_FAILURE);
2540 }
2541
2542 (void) close(fd);
2543 return (PICL_SUCCESS);
2544 }
2545
2546 static int
get_monitor_cpu_mode(ptree_rarg_t * parg,void * buf)2547 get_monitor_cpu_mode(ptree_rarg_t *parg, void *buf)
2548 {
2549 picl_prophdl_t proph;
2550 env_tuneable_t *tuneablep;
2551 int fd;
2552 int8_t mmode;
2553
2554 proph = parg->proph;
2555
2556 tuneablep = tuneable_lookup(proph);
2557
2558 if (tuneablep == NULL)
2559 return (PICL_FAILURE);
2560
2561 fd = open(CPU_HWM_DEVFS, O_RDWR);
2562
2563 if (fd == -1) {
2564 return (PICL_FAILURE);
2565 }
2566
2567 if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) {
2568 return (PICL_FAILURE);
2569 }
2570
2571 if (mmode == ADM1031_AUTO_MODE) {
2572 *((int *)tuneablep->value) = ENABLE;
2573 } else {
2574 *((int *)tuneablep->value) = DISABLE;
2575 }
2576
2577 (void) memcpy(buf, tuneablep->value,
2578 tuneablep->nbytes);
2579
2580 (void) close(fd);
2581 return (PICL_SUCCESS);
2582 }
2583
2584 static int
set_monitor_cpu_mode(ptree_warg_t * parg,const void * buf)2585 set_monitor_cpu_mode(ptree_warg_t *parg, const void *buf)
2586 {
2587 picl_prophdl_t proph;
2588 env_tuneable_t *tuneablep;
2589 int fd, val;
2590 int8_t mmode;
2591
2592 if (parg->cred.dc_euid != 0)
2593 return (PICL_PERMDENIED);
2594
2595 proph = parg->proph;
2596
2597 tuneablep = tuneable_lookup(proph);
2598
2599 if (tuneablep == NULL)
2600 return (PICL_FAILURE);
2601
2602 fd = open(CPU_HWM_DEVFS, O_RDWR);
2603
2604 if (fd == -1) {
2605 return (PICL_FAILURE);
2606 }
2607
2608 (void) memcpy(&val, buf, sizeof (val));
2609
2610 if (val == ENABLE) {
2611 mmode = ADM1031_AUTO_MODE;
2612 } else if (val == DISABLE) {
2613 mmode = ADM1031_MANUAL_MODE;
2614 }
2615
2616 if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) {
2617 return (PICL_FAILURE);
2618 }
2619
2620 (void) close(fd);
2621 return (PICL_SUCCESS);
2622 }
2623
2624 static int
get_monitor_sys_mode(ptree_rarg_t * parg,void * buf)2625 get_monitor_sys_mode(ptree_rarg_t *parg, void *buf)
2626 {
2627 picl_prophdl_t proph;
2628 env_tuneable_t *tuneablep;
2629 int fd;
2630 int8_t mmode;
2631
2632 proph = parg->proph;
2633
2634 tuneablep = tuneable_lookup(proph);
2635
2636 if (tuneablep == NULL)
2637 return (PICL_FAILURE);
2638
2639 fd = open(SYS_HWM_DEVFS, O_RDWR);
2640
2641 if (fd == -1) {
2642 return (PICL_FAILURE);
2643 }
2644
2645 if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) {
2646 return (PICL_FAILURE);
2647 }
2648
2649 if (mmode == ADM1031_AUTO_MODE) {
2650 *((int *)tuneablep->value) = ENABLE;
2651 } else {
2652 *((int *)tuneablep->value) = DISABLE;
2653 }
2654
2655 (void) memcpy(buf, tuneablep->value,
2656 tuneablep->nbytes);
2657
2658 (void) close(fd);
2659 return (PICL_SUCCESS);
2660 }
2661
2662 static int
set_monitor_sys_mode(ptree_warg_t * parg,const void * buf)2663 set_monitor_sys_mode(ptree_warg_t *parg, const void *buf)
2664 {
2665 picl_prophdl_t proph;
2666 env_tuneable_t *tuneablep;
2667 int fd, val;
2668 int8_t mmode;
2669
2670 if (parg->cred.dc_euid != 0)
2671 return (PICL_PERMDENIED);
2672
2673 proph = parg->proph;
2674
2675 tuneablep = tuneable_lookup(proph);
2676
2677 if (tuneablep == NULL)
2678 return (PICL_FAILURE);
2679
2680 fd = open(SYS_HWM_DEVFS, O_RDWR);
2681
2682 if (fd == -1) {
2683 return (PICL_FAILURE);
2684 }
2685
2686 (void) memcpy(&val, buf, sizeof (val));
2687
2688 if (val == ENABLE) {
2689 mmode = ADM1031_AUTO_MODE;
2690 } else if (val == DISABLE) {
2691 mmode = ADM1031_MANUAL_MODE;
2692 }
2693
2694 if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) {
2695 return (PICL_FAILURE);
2696 }
2697
2698 (void) close(fd);
2699 return (PICL_SUCCESS);
2700 }
2701
2702 static int
get_string_val(ptree_rarg_t * parg,void * buf)2703 get_string_val(ptree_rarg_t *parg, void *buf)
2704 {
2705 picl_prophdl_t proph;
2706 env_tuneable_t *tuneablep;
2707
2708 proph = parg->proph;
2709
2710 tuneablep = tuneable_lookup(proph);
2711
2712 if (tuneablep == NULL)
2713 return (PICL_FAILURE);
2714
2715 (void) memcpy(buf, (caddr_t)tuneablep->value,
2716 tuneablep->nbytes);
2717
2718 return (PICL_SUCCESS);
2719 }
2720
2721 static int
set_string_val(ptree_warg_t * parg,const void * buf)2722 set_string_val(ptree_warg_t *parg, const void *buf)
2723 {
2724 picl_prophdl_t proph;
2725 env_tuneable_t *tuneablep;
2726
2727 if (parg->cred.dc_euid != 0)
2728 return (PICL_PERMDENIED);
2729
2730 proph = parg->proph;
2731
2732 tuneablep = tuneable_lookup(proph);
2733
2734 if (tuneablep == NULL)
2735 return (PICL_FAILURE);
2736
2737 (void) memcpy((caddr_t)tuneables->value, (caddr_t)buf,
2738 tuneables->nbytes);
2739
2740
2741 return (PICL_SUCCESS);
2742 }
2743
2744 static int
get_int_val(ptree_rarg_t * parg,void * buf)2745 get_int_val(ptree_rarg_t *parg, void *buf)
2746 {
2747 picl_prophdl_t proph;
2748 env_tuneable_t *tuneablep;
2749
2750 proph = parg->proph;
2751
2752 tuneablep = tuneable_lookup(proph);
2753
2754 if (tuneablep == NULL)
2755 return (PICL_FAILURE);
2756
2757 (void) memcpy((int *)buf, (int *)tuneablep->value,
2758 tuneablep->nbytes);
2759
2760 return (PICL_SUCCESS);
2761 }
2762
2763 static int
set_int_val(ptree_warg_t * parg,const void * buf)2764 set_int_val(ptree_warg_t *parg, const void *buf)
2765 {
2766 picl_prophdl_t proph;
2767 env_tuneable_t *tuneablep;
2768
2769 if (parg->cred.dc_euid != 0)
2770 return (PICL_PERMDENIED);
2771
2772 proph = parg->proph;
2773
2774 tuneablep = tuneable_lookup(proph);
2775
2776 if (tuneablep == NULL)
2777 return (PICL_FAILURE);
2778
2779 (void) memcpy((int *)tuneablep->value, (int *)buf,
2780 tuneablep->nbytes);
2781
2782 return (PICL_SUCCESS);
2783 }
2784
2785 int
get_dimm_fan_speed(int fan_fd,fanspeed_t * fanspeedp)2786 get_dimm_fan_speed(int fan_fd, fanspeed_t *fanspeedp)
2787 {
2788 int16_t dimm_fan_period;
2789 i2c_reg_t i2c_reg;
2790
2791 /*
2792 * The dimm fan period is 16 bit value and we need to read
2793 * registers 2 and 3 to get the LSB and MSB values.
2794 */
2795 i2c_reg.reg_num = PIC16F819_FAN_PERIOD_MSB_REGISTER;
2796 if (ioctl(fan_fd, I2C_GET_REG, &i2c_reg) == -1) {
2797 if (env_debug)
2798 envd_log(LOG_ERR,
2799 "Error in reading FAN_PERIOD MSB REGISTER\n");
2800 return (-1);
2801 }
2802 dimm_fan_period = (i2c_reg.reg_value << 8);
2803 i2c_reg.reg_num = PIC16F819_FAN_PERIOD_LSB_REGISTER;
2804 if (ioctl(fan_fd, I2C_GET_REG, &i2c_reg) == -1) {
2805 if (env_debug)
2806 envd_log(LOG_ERR,
2807 "Error in reading FAN_PERIOD LSB REGISTER\n");
2808 return (-1);
2809 }
2810 dimm_fan_period |= i2c_reg.reg_value;
2811 if (env_debug)
2812 envd_log(LOG_ERR,
2813 " dimm fan tach period is 0x%x\n", dimm_fan_period);
2814 if (dimm_fan_period == 0) {
2815 if (env_debug)
2816 envd_log(LOG_ERR,
2817 "dimm fan tach period read as zero. Illegal value.\n");
2818 return (-1);
2819 }
2820 *fanspeedp = PIC16F819_FAN_TACH_TO_RPM(dimm_fan_period);
2821 return (0);
2822 }
2823
2824 int
is_dimm_fan_failed(void)2825 is_dimm_fan_failed(void)
2826 {
2827 i2c_reg_t i2c_reg;
2828 fanspeed_t fan_speed;
2829 int retry_count;
2830
2831 if (envd_dimm_fan.fd == -1)
2832 return (-1);
2833 /*
2834 * read register 1 to look at Fan fault bit.
2835 */
2836 i2c_reg.reg_num = PIC16F819_STATUS_REGISTER;
2837 retry_count = MAX_RETRIES_FOR_PIC16F819_REG_READ;
2838 while (retry_count > 0) {
2839 if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) {
2840 retry_count--;
2841 continue;
2842 } else break;
2843 }
2844 if (retry_count != MAX_RETRIES_FOR_PIC16F819_REG_READ) {
2845 if (env_debug)
2846 envd_log(LOG_ERR,
2847 "%d retries attempted in reading STATUS "
2848 "register.\n",
2849 (MAX_RETRIES_FOR_PIC16F819_REG_READ - retry_count));
2850 }
2851 if (retry_count == 0) {
2852 (void) strncpy(dimm_fan_status_string, NOT_AVAILABLE,
2853 sizeof (dimm_fan_status_string));
2854 (void) strncpy(dimm_fan_command_string, NOT_AVAILABLE,
2855 sizeof (dimm_fan_command_string));
2856 (void) strncpy(dimm_fan_debug_string, NOT_AVAILABLE,
2857 sizeof (dimm_fan_debug_string));
2858 (void) strncpy(dimm_fan_rpm_string, NOT_AVAILABLE,
2859 sizeof (dimm_fan_rpm_string));
2860 return (-1);
2861 }
2862 if (env_debug)
2863 envd_log(LOG_ERR,
2864 "DIMM FAN STATUS reg = 0x%x\n", i2c_reg.reg_value);
2865 if (i2c_reg.reg_value & PIC16F819_FAN_FAILED) {
2866 (void) snprintf(dimm_fan_status_string,
2867 sizeof (dimm_fan_status_string), "0x%x",
2868 i2c_reg.reg_value);
2869 i2c_reg.reg_num = PIC16F819_DEBUG_REGISTER;
2870 if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) {
2871 (void) strncpy(dimm_fan_debug_string, NOT_AVAILABLE,
2872 sizeof (dimm_fan_debug_string));
2873 } else {
2874 (void) snprintf(dimm_fan_debug_string,
2875 sizeof (dimm_fan_debug_string),
2876 "0x%x", i2c_reg.reg_value);
2877 }
2878 i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER;
2879 if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) {
2880 (void) strncpy(dimm_fan_command_string, NOT_AVAILABLE,
2881 sizeof (dimm_fan_command_string));
2882 } else {
2883 (void) snprintf(dimm_fan_command_string,
2884 sizeof (dimm_fan_command_string),
2885 "0x%x", i2c_reg.reg_value);
2886 }
2887 if (get_dimm_fan_speed(envd_dimm_fan.fd, &fan_speed) == -1) {
2888 (void) strncpy(dimm_fan_rpm_string, NOT_AVAILABLE,
2889 sizeof (dimm_fan_rpm_string));
2890 } else {
2891 (void) snprintf(dimm_fan_rpm_string,
2892 sizeof (dimm_fan_rpm_string),
2893 "%d", fan_speed);
2894 }
2895 return (1);
2896 } else return (0);
2897 }
2898