1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * Littleneck platform specific environment monitoring policies
31 */
32
33 #include <syslog.h>
34 #include <unistd.h>
35 #include <stdio.h>
36 #include <libintl.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <fcntl.h>
42 #include <sys/time.h>
43 #include <sys/time_impl.h>
44 #include <sys/signal.h>
45 #include <sys/devctl.h>
46 #include <libdevinfo.h>
47 #include <libdevice.h>
48 #include <picl.h>
49 #include <picltree.h>
50 #include <limits.h>
51 #include <sys/systeminfo.h>
52 #include <psvc_objects.h>
53
54 /*LINTLIBRARY*/
55
56 #define LOWTEMP_CRITICAL_MSG \
57 gettext("CRITICAL : LOW TEMPERATURE DETECTED %d, %s")
58 #define LOWTEMP_WARNING_MSG \
59 gettext("WARNING : LOW TEMPERATURE DETECTED %d, %s")
60 #define HIGHTEMP_CRITICAL_MSG \
61 gettext("CRITICAL : HIGH TEMPERATURE DETECTED %d, %s")
62 #define HIGHTEMP_WARNING_MSG \
63 gettext("WARNING : HIGH TEMPERATURE DETECTED %d, %s")
64 #define DEVICE_INSERTED_MSG gettext("Device %s inserted")
65 #define DEVICE_REMOVED_MSG gettext("Device %s removed")
66 #define PS_TYPE_MSG \
67 gettext("WARNING: Incorrect type power supply inserted, device %s")
68 #define DEVICE_FAILURE_MSG \
69 gettext("WARNING: Device %s failure detected by sensor %s\n")
70 #define DEVICE_OK_MSG gettext("Device %s OK")
71 #define DEVTREE_NODE_CREATE_FAILED \
72 gettext("psvc PICL plugin: Failed to create node for %s, errno = %d")
73 #define DEVTREE_NODE_DELETE_FAILED \
74 gettext("psvc PICL plugin: Failed to delete node for %s, errno = %d")
75 #define NO_FRU_INFO \
76 gettext("No FRU Information for %s using default temperatures\n")
77
78 static char *shutdown_string = "shutdown -y -g 60 -i 5 \"OVERTEMP condition\"";
79
80 typedef struct seg_desc {
81 int32_t segdesc;
82 int16_t segoffset;
83 int16_t seglength;
84 } seg_desc_t;
85
86 static int32_t find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment,
87 char *seg_to_find);
88
89 static int temp_attr[] = {
90 PSVC_HW_HI_SHUT_ATTR, PSVC_HI_SHUT_ATTR, PSVC_HI_WARN_ATTR,
91 PSVC_LO_WARN_ATTR, PSVC_LO_SHUT_ATTR, PSVC_HW_LO_SHUT_ATTR
92 };
93
94 #define MAX_TEMP_ATTR (sizeof (temp_attr)/sizeof (temp_attr[0]))
95 #define TEMP_OFFSET 12
96 #define PART_NO_OFFSET 152
97 #define NUM_OF_SEG_ADDR 0x1805
98 #define SEG_DESC_START 0x1806
99 #define PSVC_NO_DEVICE -2
100
101 /*
102 * The I2C bus is noisy, and the state may be incorrectly reported as
103 * having changed. When the state changes, we attempt to confirm by
104 * retrying. If any retries indicate that the state has not changed, we
105 * assume the state change(s) were incorrect and the state has not changed.
106 * The following variables are used to store the tuneable values read in
107 * from the optional i2cparam.conf file for this shared object library.
108 */
109 static int n_retry_temp = PSVC_THRESHOLD_COUNTER;
110 static int retry_sleep_temp = 1;
111 static int n_retry_hotplug = PSVC_NUM_OF_RETRIES;
112 static int retry_sleep_hotplug = 1;
113 static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES;
114 static int retry_sleep_temp_shutdown = 1;
115
116 typedef struct {
117 int *pvar;
118 char *texttag;
119 } i2c_noise_param_t;
120
121 static i2c_noise_param_t i2cparams[] = {
122 &n_retry_temp, "n_retry_temp",
123 &retry_sleep_temp, "retry_sleep_temp",
124 &n_retry_hotplug, "n_retry_hotplug",
125 &retry_sleep_hotplug, "retry_sleep_hotplug",
126 NULL, NULL
127 };
128
129 #pragma init(i2cparams_load)
130
131 static void
i2cparams_debug(i2c_noise_param_t * pi2cparams,char * platform,int usingDefaults)132 i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform,
133 int usingDefaults)
134 {
135 char s[128];
136 i2c_noise_param_t *p;
137
138 if (!usingDefaults) {
139 (void) snprintf(s, sizeof (s),
140 "# Values from /usr/platform/%s/lib/i2cparam.conf\n",
141 platform);
142 syslog(LOG_WARNING, "%s", s);
143 } else {
144 /* no file - we're using the defaults */
145 (void) snprintf(s, sizeof (s),
146 "# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n",
147 platform);
148 }
149 (void) fputs(s, stdout);
150 p = pi2cparams;
151 while (p->pvar != NULL) {
152 (void) snprintf(s, sizeof (s), "%s %d\n", p->texttag,
153 *(p->pvar));
154 if (!usingDefaults)
155 syslog(LOG_WARNING, "%s", s);
156 (void) fputs(s, stdout);
157 p++;
158 }
159 }
160
161 static void
i2cparams_load(void)162 i2cparams_load(void)
163 {
164 FILE *fp;
165 char filename[PATH_MAX];
166 char platform[64];
167 char s[128];
168 char var[128];
169 int val;
170 i2c_noise_param_t *p;
171
172 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
173 syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno));
174 return;
175 }
176 (void) snprintf(filename, sizeof (filename),
177 "/usr/platform/%s/lib/i2cparam.conf", platform);
178 /* read thru the i2cparam.conf file and set variables */
179 if ((fp = fopen(filename, "r")) != NULL) {
180 while (fgets(s, sizeof (s), fp) != NULL) {
181 if (s[0] == '#') /* skip comment lines */
182 continue;
183 /* try to find a string match and get the value */
184 if (sscanf(s, "%127s %d", var, &val) != 2)
185 continue;
186 if (val < 1)
187 val = 1; /* clamp min value */
188 p = &(i2cparams[0]);
189 while (p->pvar != NULL) {
190 if (strncmp(p->texttag, var, sizeof (var)) ==
191 0) {
192 *(p->pvar) = val;
193 break;
194 }
195 p++;
196 }
197 }
198 (void) fclose(fp);
199 }
200 /* output the values of the parameters */
201 i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0));
202 }
203
204
205 int32_t
find_segment(psvc_opaque_t hdlp,char * fru,seg_desc_t * segment,char seg_to_find[2])206 find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment,
207 char seg_to_find[2])
208 {
209 int32_t seg_found = 0, status;
210 int32_t seg_desc_start = SEG_DESC_START, j;
211 int8_t seg_count;
212 char seg_name[2];
213 fru_info_t fru_data;
214
215 /*
216 * Read the number of segments in the Read Only section
217 */
218 fru_data.buf_start = NUM_OF_SEG_ADDR;
219 fru_data.buf = (char *)&seg_count;
220 fru_data.read_size = 1;
221
222 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
223 &fru_data);
224 /*
225 * We test for ENOENT and ENXIO because Littleneck does not
226 * have actual presence sensors and so the only way to see
227 * if a part is there or not is to actually make a call to
228 * that part.
229 */
230 if (status != PSVC_SUCCESS) {
231 if ((errno == ENOENT) || (errno == ENXIO))
232 return (PSVC_NO_DEVICE);
233 else
234 return (PSVC_FAILURE);
235 }
236 /*
237 * Read in each segment to find the segment we are looking for
238 */
239 for (j = 0; (j < seg_count) && (!(seg_found)); j++) {
240 fru_data.buf_start = seg_desc_start;
241 fru_data.buf = seg_name;
242 fru_data.read_size = 2;
243
244 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
245 &fru_data);
246
247 seg_desc_start = seg_desc_start + 2;
248 fru_data.buf_start = seg_desc_start;
249 fru_data.buf = (char *)segment;
250 fru_data.read_size = sizeof (seg_desc_t);
251
252 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
253 &fru_data);
254 if (status != PSVC_SUCCESS) {
255 syslog(LOG_ERR,
256 "Failed psvc_get_attr for FRU info\n");
257 return (PSVC_FAILURE);
258 }
259 seg_desc_start = seg_desc_start + sizeof (seg_desc_t);
260 if (memcmp(seg_name, seg_to_find, 2) == 0) {
261 seg_found = 1;
262 }
263 }
264 return (seg_found);
265 }
266
267 int32_t
psvc_update_thresholds_0(psvc_opaque_t hdlp,char * id)268 psvc_update_thresholds_0(psvc_opaque_t hdlp, char *id)
269 {
270 int32_t status = PSVC_SUCCESS;
271 fru_info_t fru_data;
272 char *fru, part_no[7];
273 int16_t data_offset;
274 int32_t fru_count, i, j, temp_address;
275 int32_t seg_found, temp;
276 seg_desc_t segment;
277 int8_t temps[MAX_TEMP_ATTR];
278 int32_t num_of_parts = 2;
279 char fruless_parts[2][7] = {"5015988", "5015675"};
280 int fd;
281 FILE *fp;
282
283 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fru_count,
284 PSVC_FRU);
285 if (status == PSVC_FAILURE)
286 return (status);
287
288 for (i = 0; i < fru_count; i++) {
289 seg_found = 0;
290 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
291 &fru, PSVC_FRU, i);
292 if (status != PSVC_SUCCESS)
293 return (status);
294 seg_found = find_segment(hdlp, fru, &segment, "ES");
295 if (seg_found == PSVC_FAILURE)
296 return (PSVC_FAILURE);
297 else if (seg_found == PSVC_NO_DEVICE)
298 return (PSVC_SUCCESS);
299 if (seg_found) {
300 /*
301 * For Littleneck we need to read the offset of the
302 * die-sensor data record
303 */
304 temp_address = segment.segoffset + TEMP_OFFSET;
305 fru_data.buf_start = temp_address;
306 fru_data.buf = (char *)&data_offset;
307 fru_data.read_size = sizeof (data_offset);
308 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
309 &fru_data);
310 if (status != PSVC_SUCCESS) {
311 syslog(LOG_ERR,
312 "Failed psvc_get_attr for FRU info\n");
313 return (status);
314 }
315
316 /*
317 * Now go and get the new temperature settings
318 */
319 temp_address = segment.segoffset + data_offset;
320 fru_data.buf_start = temp_address;
321 fru_data.buf = (char *)&temps;
322 fru_data.read_size = sizeof (temps);
323 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
324 &fru_data);
325 if (status != PSVC_SUCCESS) {
326 syslog(LOG_ERR,
327 "Failed psvc_get_attr for FRU info\n");
328 return (status);
329 } else {
330 /*
331 * Now set the updated Thresholds
332 */
333 for (j = 0; j < MAX_TEMP_ATTR; j++) {
334 temp = temps[j];
335 status = psvc_set_attr(hdlp, id,
336 temp_attr[j], &temp);
337 }
338 }
339 } else {
340 /*
341 * For Littleneck only we need to check for the part
342 * number of the CPU as there are parts that do not
343 * have the ES segment programmed.
344 */
345 seg_found = find_segment(hdlp, fru, &segment, "SD");
346 if (seg_found == PSVC_FAILURE)
347 return (PSVC_FAILURE);
348 if (seg_found) {
349 /*
350 * We now goto the SD segment to get the part
351 * number.
352 */
353 fru_data.buf_start =
354 segment.segoffset + PART_NO_OFFSET;
355 fru_data.buf = part_no;
356 fru_data.read_size = sizeof (part_no);
357 status = psvc_get_attr(hdlp, fru,
358 PSVC_FRU_INFO_ATTR, &fru_data);
359 if (status != PSVC_SUCCESS) {
360 syslog(LOG_ERR, "Failed psvc_get_attr"
361 "for FRU info\n");
362 return (status);
363 }
364 /*
365 * We are go through the parts list to see
366 * if the part number from the FRU is in
367 * this list. If it is we simply return
368 * as the FRU is not programmed.
369 */
370 for (j = 0; j < num_of_parts; j++) {
371 if (memcmp(fruless_parts[j], part_no,
372 7) == 0) {
373 return (status);
374 }
375 }
376 }
377
378 /*
379 * If the Part is not in the Part list and we
380 * get to here this means that the FRU is
381 * considered broken (no ES segment found)
382 * and we need to report this.
383 */
384 /*
385 * We make this open, write, close, call
386 * because picld starts in rcS.d while print
387 * services does not start until later
388 * (either rc2.d or rc3.d).
389 */
390 fd = open("/dev/console", O_WRONLY | O_NOCTTY);
391 if (fd != -1) {
392 fp = fdopen(fd, "w+");
393 if (fp != NULL) {
394 fprintf(fp, NO_FRU_INFO, id);
395 fclose(fp);
396 }
397 close(fd);
398 }
399 syslog(LOG_NOTICE, NO_FRU_INFO, id);
400 }
401 }
402 return (status);
403 }
404
405 int32_t
psvc_check_temperature_policy_0(psvc_opaque_t hdlp,char * id)406 psvc_check_temperature_policy_0(psvc_opaque_t hdlp, char *id)
407 {
408 int32_t lo_warn, hi_warn, lo_shut, hi_shut;
409 uint64_t features;
410 int32_t temp;
411 char previous_state[32];
412 char state[32];
413 char fault[32];
414 char label[32];
415 boolean_t pr;
416 int32_t status = PSVC_SUCCESS;
417 int retry;
418 int8_t temp_oor;
419
420 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &pr);
421 if ((status != PSVC_SUCCESS) || (pr != PSVC_PRESENT)) {
422 return (status);
423 }
424
425 status = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features);
426 if (status != PSVC_SUCCESS)
427 return (status);
428
429 status = psvc_get_attr(hdlp, id, PSVC_LO_WARN_ATTR, &lo_warn);
430 if (status != PSVC_SUCCESS)
431 return (status);
432
433 status = psvc_get_attr(hdlp, id, PSVC_LO_SHUT_ATTR, &lo_shut);
434 if (status != PSVC_SUCCESS)
435 return (status);
436
437 status = psvc_get_attr(hdlp, id, PSVC_HI_WARN_ATTR, &hi_warn);
438 if (status != PSVC_SUCCESS)
439 return (status);
440
441 status = psvc_get_attr(hdlp, id, PSVC_HI_SHUT_ATTR, &hi_shut);
442 if (status != PSVC_SUCCESS)
443 return (status);
444
445 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
446 if (status != PSVC_SUCCESS)
447 return (status);
448
449 retry = 0;
450 do {
451 if (retry)
452 (void) sleep(retry_sleep_temp);
453 status = psvc_get_attr(hdlp, id, PSVC_SENSOR_VALUE_ATTR, &temp);
454 if (status != PSVC_SUCCESS) {
455 if ((errno == ENOENT) || (errno == ENXIO))
456 return (PSVC_SUCCESS);
457 else
458 return (PSVC_FAILURE);
459 }
460 temp_oor = 0;
461 if (((features & PSVC_LOW_SHUT) && temp <= lo_shut) ||
462 ((features & PSVC_LOW_WARN) && temp <= lo_warn) ||
463 ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) ||
464 ((features & PSVC_HIGH_WARN) && temp >= hi_warn))
465 temp_oor = 1;
466 retry++;
467 } while ((retry < n_retry_temp) && temp_oor);
468
469 if ((features & PSVC_LOW_SHUT) && temp <= lo_shut) {
470 strcpy(state, PSVC_ERROR);
471 strcpy(fault, PSVC_TEMP_LO_SHUT);
472 syslog(LOG_ERR, LOWTEMP_CRITICAL_MSG, temp, label);
473 } else if ((features & PSVC_LOW_WARN) && temp <= lo_warn) {
474 strcpy(state, PSVC_ERROR);
475 strcpy(fault, PSVC_TEMP_LO_WARN);
476 syslog(LOG_ERR, LOWTEMP_WARNING_MSG, temp, label);
477 } else if ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) {
478 strcpy(state, PSVC_ERROR);
479 strcpy(fault, PSVC_TEMP_HI_SHUT);
480 syslog(LOG_ERR, HIGHTEMP_CRITICAL_MSG, temp, label);
481 } else if ((features & PSVC_HIGH_WARN) && temp >= hi_warn) {
482 strcpy(state, PSVC_ERROR);
483 strcpy(fault, PSVC_TEMP_HI_WARN);
484 syslog(LOG_ERR, HIGHTEMP_WARNING_MSG, temp, label);
485 } else {
486 /* within limits */
487 strcpy(state, PSVC_OK);
488 strcpy(fault, PSVC_NO_FAULT);
489 }
490
491 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
492 if (status != PSVC_SUCCESS)
493 return (status);
494 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
495 if (status != PSVC_SUCCESS)
496 return (status);
497 status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
498 previous_state);
499 if (status != PSVC_SUCCESS)
500 return (status);
501
502 if (strcmp(previous_state, state) != 0) {
503 char *led_id;
504 uint8_t _8bit_val;
505
506 led_id = "SYSTEM_FAULT_LED_WR";
507
508 status = psvc_get_attr(hdlp, led_id,
509 PSVC_GPIO_VALUE_ATTR, &_8bit_val);
510 if (status != PSVC_SUCCESS)
511 return (status);
512 if (strcmp(state, PSVC_ERROR) == 0)
513 _8bit_val &= 0xef; /* clear bit 4 */
514 else
515 _8bit_val |= 0x10; /* set bit 4 */
516 _8bit_val |= 0xe4; /* set bits 3, 5, 6, 7 */
517
518 status = psvc_set_attr(hdlp, led_id,
519 PSVC_GPIO_VALUE_ATTR, &_8bit_val);
520 if (status != PSVC_SUCCESS)
521 return (status);
522
523 }
524
525 return (PSVC_SUCCESS);
526 }
527
528 static int32_t ps0_addr[] = {0, 0xac};
529 static int32_t ps1_addr[] = {0, 0xae};
530
531 int32_t
psvc_ps_hotplug_policy_0(psvc_opaque_t hdlp,char * id)532 psvc_ps_hotplug_policy_0(psvc_opaque_t hdlp, char *id)
533 {
534 boolean_t presence, previous_presence;
535 int32_t status = PSVC_SUCCESS;
536 char label[32];
537 int i;
538 int32_t led_count;
539 char state[32], fault[32];
540 boolean_t ps_type;
541 char *sensor_id, *led_id;
542 char led_state[32];
543 picl_nodehdl_t parent_node;
544 char parent_path[256];
545 picl_nodehdl_t child_node;
546 int ps_instance;
547 devctl_hdl_t bus_handle, dev_handle;
548 devctl_ddef_t ddef_hdl;
549 char devpath[256];
550 int retry;
551
552 status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
553 &previous_presence);
554 if (status != PSVC_SUCCESS)
555 return (status);
556 retry = 0;
557 do {
558 if (retry)
559 (void) sleep(retry_sleep_hotplug);
560 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
561 if (status != PSVC_SUCCESS)
562 return (status);
563 retry++;
564 } while ((retry < n_retry_hotplug) && (presence != previous_presence));
565
566 if (presence == previous_presence) {
567 /* No change */
568 return (status);
569 }
570
571 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
572 if (status != PSVC_SUCCESS)
573 return (status);
574
575 /* Convert name to node and parent path */
576 psvcplugin_lookup(id, parent_path, &child_node);
577
578 if (presence == PSVC_PRESENT) {
579
580 /* may detect presence before all connections are made */
581 sleep(1);
582
583 /* Device added */
584 syslog(LOG_ERR, DEVICE_INSERTED_MSG, label);
585
586
587 /* Verify P/S is correct type */
588 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
589 &sensor_id, PSVC_DEV_TYPE_SENSOR, 0);
590 if (status != PSVC_SUCCESS)
591 return (status);
592 status = psvc_get_attr(hdlp, sensor_id,
593 PSVC_GPIO_VALUE_ATTR, &ps_type);
594 if (status != PSVC_SUCCESS)
595 return (status);
596
597 if (ps_type == 1) { /* correct p/s */
598 strcpy(state, PSVC_OK);
599 strcpy(fault, PSVC_NO_FAULT);
600 strcpy(led_state, PSVC_LED_OFF);
601 } else { /* wrong type */
602 strcpy(state, PSVC_ERROR);
603 strcpy(fault, PSVC_PS_TYPE_FLT);
604 strcpy(led_state, PSVC_LED_ON);
605 syslog(LOG_ERR, PS_TYPE_MSG, label);
606
607 }
608 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
609 if (status != PSVC_SUCCESS)
610 return (status);
611 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
612 if (status != PSVC_SUCCESS)
613 return (status);
614
615 /* Set state of fault LEDs */
616 status = psvc_get_attr(hdlp, sensor_id, PSVC_ASSOC_MATCHES_ATTR,
617 &led_count, PSVC_DEV_FAULT_LED);
618 if (status != PSVC_SUCCESS) {
619 syslog(LOG_ERR,
620 gettext("Failed for PSVC_DEV_FAULT_LED\n"));
621 return (status);
622 }
623 for (i = 0; i < led_count; ++i) {
624 status = psvc_get_attr(hdlp, sensor_id,
625 PSVC_ASSOC_ID_ATTR, &led_id,
626 PSVC_DEV_FAULT_LED, i);
627 if (status != PSVC_SUCCESS)
628 return (status);
629 status = psvc_set_attr(hdlp, led_id,
630 PSVC_LED_STATE_ATTR, led_state);
631 if (status != PSVC_SUCCESS)
632 return (status);
633 }
634 ptree_get_node_by_path(parent_path, &parent_node);
635 ptree_add_node(parent_node, child_node);
636 } else {
637 /* Device removed */
638 syslog(LOG_ERR, DEVICE_REMOVED_MSG, label);
639 ptree_delete_node(child_node);
640 }
641
642 status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
643 if (status != PSVC_SUCCESS)
644 return (status);
645
646 status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &ps_instance);
647 if (status != PSVC_SUCCESS)
648 return (status);
649
650 if (presence != PSVC_PRESENT) {
651 if (ps_instance == 0)
652 strcpy(devpath,
653 "/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ac:power-supply");
654 else
655 strcpy(devpath,
656 "/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ae:power-supply");
657
658 dev_handle = devctl_device_acquire(devpath, 0);
659
660 if (devctl_device_remove(dev_handle)) {
661 syslog(LOG_ERR, DEVTREE_NODE_DELETE_FAILED, label,
662 errno);
663 status = PSVC_FAILURE;
664 } else {
665 devctl_release(dev_handle);
666 status = PSVC_SUCCESS;
667 }
668 return (status);
669 }
670
671 /*
672 * We fall through to here if the device has been inserted.
673 * Add the devinfo tree node entry for the seeprom and attach
674 * the i2c seeprom driver
675 */
676 ddef_hdl = devctl_ddef_alloc("power-supply", 0);
677 (void) devctl_ddef_string(ddef_hdl, "compatible", "i2c-at24c64");
678 if (ps_instance == 0) {
679 (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps0_addr);
680 } else {
681 (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps1_addr);
682 }
683
684 bus_handle = devctl_bus_acquire(
685 "/devices/pci@8,700000/ebus@5/i2c@1,30:i2c", 0);
686 if (devctl_bus_dev_create(bus_handle, ddef_hdl, 0, &dev_handle)) {
687 syslog(LOG_ERR, DEVTREE_NODE_CREATE_FAILED, label, errno);
688 status = PSVC_FAILURE;
689 } else
690 devctl_release(dev_handle);
691
692 devctl_release(bus_handle);
693 devctl_ddef_free(ddef_hdl);
694
695 return (status);
696 }
697
698 int32_t
psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp,char * id)699 psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp, char *id)
700 {
701 int32_t sensor_count;
702 char *led_id, *sensor_id;
703 int i;
704 char state[32], fault[32], previous_state[32];
705 int32_t status = PSVC_SUCCESS;
706 boolean_t present;
707
708 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &present);
709 if (status == PSVC_FAILURE)
710 return (status);
711
712 if (present == PSVC_ABSENT) {
713 errno = ENODEV;
714 return (PSVC_FAILURE);
715 }
716
717 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
718 PSVC_DEV_FAULT_SENSOR);
719 for (i = 0; i < sensor_count; ++i) {
720 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
721 &sensor_id, PSVC_DEV_FAULT_SENSOR, i);
722 if (status != PSVC_SUCCESS)
723 return (status);
724
725 status = psvc_get_attr(hdlp, sensor_id,
726 PSVC_SWITCH_STATE_ATTR, state);
727 if (status != PSVC_SUCCESS)
728 return (status);
729
730 if (strcmp(state, PSVC_SWITCH_ON) == 0) {
731 strcpy(state, PSVC_ERROR);
732 strcpy(fault, PSVC_GEN_FAULT);
733 } else {
734 strcpy(state, PSVC_OK);
735 strcpy(fault, PSVC_NO_FAULT);
736 }
737
738 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
739 if (status != PSVC_SUCCESS)
740 return (status);
741 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
742 if (status != PSVC_SUCCESS)
743 return (status);
744 status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
745 previous_state);
746 if (status != PSVC_SUCCESS)
747 return (status);
748
749 if (strcmp(state, previous_state) != 0) {
750 char sensor_label[32];
751 char dev_label[32];
752 uint8_t _8bit_val;
753
754 psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, dev_label);
755 psvc_get_attr(hdlp, sensor_id, PSVC_LABEL_ATTR,
756 sensor_label);
757 if (strcmp(state, PSVC_ERROR) == 0)
758 syslog(LOG_ERR, DEVICE_FAILURE_MSG, dev_label,
759 sensor_label);
760 else
761 syslog(LOG_ERR, DEVICE_OK_MSG, dev_label);
762
763 led_id = "SYSTEM_FAULT_LED_WR";
764
765 status = psvc_get_attr(hdlp, led_id,
766 PSVC_GPIO_VALUE_ATTR, &_8bit_val);
767 if (status != PSVC_SUCCESS)
768 return (status);
769
770 if (strcmp(state, PSVC_ERROR) == 0)
771 _8bit_val &= 0xef; /* clear bit 4 */
772 else
773 _8bit_val |= 0x10; /* set bit 4 */
774 _8bit_val |= 0xe4; /* set bits 3, 5, 6, 7 */
775
776 status = psvc_set_attr(hdlp, led_id,
777 PSVC_GPIO_VALUE_ATTR, &_8bit_val);
778 if (status != PSVC_SUCCESS)
779 return (status);
780
781 }
782 }
783
784 return (PSVC_SUCCESS);
785 }
786
787 int32_t
psvc_init_led_policy_0(psvc_opaque_t hdlp,char * id)788 psvc_init_led_policy_0(psvc_opaque_t hdlp, char *id)
789 {
790 int32_t status = PSVC_SUCCESS;
791 uint8_t _8bit_val;
792
793 status = psvc_get_attr(hdlp, id,
794 PSVC_GPIO_VALUE_ATTR, &_8bit_val);
795 if (status != PSVC_SUCCESS)
796 return (status);
797
798 _8bit_val &= 0xef; /* clear bit 4 */
799 _8bit_val |= 0xf4; /* set bits 3, 5, 6, 7 */
800
801 status = psvc_set_attr(hdlp, id,
802 PSVC_GPIO_VALUE_ATTR, &_8bit_val);
803 if (status != PSVC_SUCCESS)
804 return (status);
805
806 return (status);
807 }
808
809 static int32_t
check_cpu_temp_fault(psvc_opaque_t hdlp,char * cpu,int32_t cpu_count)810 check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count)
811 {
812 char *sensorid;
813 int32_t sensor_count;
814 int32_t status = PSVC_SUCCESS;
815 int32_t i;
816 char fault[32];
817 int retry;
818 int8_t temp_oor;
819
820 psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
821 PSVC_DEV_TEMP_SENSOR);
822 for (i = 0; i < sensor_count; ++i) {
823 status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR,
824 &sensorid, PSVC_DEV_TEMP_SENSOR, i);
825 if (status == PSVC_FAILURE)
826 return (status);
827
828 retry = 0;
829 do {
830 if (retry)
831 (void) sleep(retry_sleep_temp_shutdown);
832 status = psvc_get_attr(hdlp, sensorid,
833 PSVC_FAULTID_ATTR, fault);
834 if (status == PSVC_FAILURE)
835 return (status);
836 temp_oor = 0;
837 if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) ||
838 (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) {
839 temp_oor = 1;
840 }
841 retry++;
842 } while ((retry < n_retry_temp_shutdown) && temp_oor);
843
844 if (temp_oor) {
845 system(shutdown_string);
846 }
847 }
848
849 return (status);
850 }
851
852 int32_t
psvc_shutdown_policy_0(psvc_opaque_t hdlp,char * id)853 psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id)
854 {
855 int32_t cpu_count;
856 char *cpuid;
857 int32_t i;
858 boolean_t present;
859 int32_t status = PSVC_SUCCESS;
860
861 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
862 PSVC_CPU);
863 for (i = 0; i < cpu_count; ++i) {
864
865 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid,
866 PSVC_CPU, i);
867 if (status == PSVC_FAILURE)
868 return (status);
869
870 status = psvc_get_attr(hdlp, cpuid,
871 PSVC_PRESENCE_ATTR, &present);
872 if (status == PSVC_FAILURE && present == PSVC_PRESENT)
873 return (status);
874 if (present == PSVC_PRESENT) {
875 status = check_cpu_temp_fault(hdlp, cpuid, cpu_count);
876 if (status == PSVC_FAILURE && errno != ENODEV)
877 return (status);
878 }
879 }
880
881 return (PSVC_SUCCESS);
882 }
883