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 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Cherrystone platform specific environment monitoring policies
29 */
30
31 #include <syslog.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <libintl.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <sys/types.h>
40 #include <sys/time.h>
41 #include <sys/time_impl.h>
42 #include <sys/signal.h>
43 #include <sys/devctl.h>
44 #include <libdevinfo.h>
45 #include <libdevice.h>
46 #include <picl.h>
47 #include <picltree.h>
48 #include <sys/i2c/clients/i2c_client.h>
49 #include <hbaapi.h>
50 #include <limits.h>
51 #include <sys/systeminfo.h>
52
53 #include <psvc_objects.h>
54
55 /* Device paths for power supply hotplug handling */
56 #define SEG5_ADDR 0x30
57 #define EBUS_DEV_NAME "/devices/pci@9,700000/ebus@1/"
58 #define SEG5_DEV_NAME EBUS_DEV_NAME "i2c@1,30/"
59 #define SEG5_ADDR_DEV_FMT EBUS_DEV_NAME "i2c@1,%x:devctl"
60
61 #define QLC_NODE "/pci@9,600000/SUNW,qlc@2"
62
63 #define DISK_DRV "ssd"
64 #define MAX_DISKS 2
65 #define WWN_SIZE 8
66 #define ONBOARD_CONTR "../../devices/pci@9,600000/SUNW,qlc@2/fp@0,0:fc"
67
68 /* Bit masks so we don't "wedge" the inputs */
69 #define PCF8574_BIT_WRITE_VALUE(byte, bit, value)\
70 ((value << bit) | (byte & (~(0x01 << bit))))
71
72 #define PDB_MUST_BE_1 0xBF
73 #define PSU_MUST_BE_1 0x7F
74 #define DISKBP_MUST_BE_1 0x0F
75
76 /*LINTLIBRARY*/
77
78 #define PSVC_MAX_STR_LEN 32
79
80 #define PS_MAX_FAULT_SENSORS 3
81
82 /*
83 * Keep track of the power supply's fail status for reporting if/when
84 * they go good.
85 * ID's:
86 * O PSx_FAULT_SENSOR
87 * 1 Doesn't matter -- only need 0 to be PSx_FAULT_SENSOR
88 * 2 Doesn't matter
89 */
90 static char *ps_prev_id[2][3] =
91 {{NULL, NULL, NULL}, {NULL, NULL, NULL}};
92 static int ps_prev_failed[2][3] = {{0, 0, 0}, {0, 0, 0}};
93
94 /*
95 * Keep track of the power supply's previous presence
96 * because PSVC doesn't do that for us.
97 */
98 static boolean_t ps_prev_present[2];
99 static boolean_t ps_present[2];
100
101 /* Local Routines for the environmental policies */
102 static int ac_unplugged(psvc_opaque_t, char *);
103 static int ac_power_check(psvc_opaque_t, char *, char *);
104
105 /*
106 * The I2C bus is noisy, and the state may be incorrectly reported as
107 * having changed. When the state changes, we attempt to confirm by
108 * retrying. If any retries indicate that the state has not changed, we
109 * assume the state change(s) were incorrect and the state has not changed.
110 * The following variables are used to store the tuneable values read in
111 * from the optional i2cparam.conf file for this shared object library.
112 */
113 static int n_retry_fan = PSVC_NUM_OF_RETRIES;
114 static int retry_sleep_fan = 1;
115 static int n_retry_ps_status = PSVC_NUM_OF_RETRIES;
116 static int retry_sleep_ps_status = 1;
117 static int n_retry_pshp = PSVC_NUM_OF_RETRIES;
118 static int retry_sleep_pshp = 1;
119 static int n_retry_diskhp = PSVC_NUM_OF_RETRIES;
120 static int retry_sleep_diskhp = 1;
121 static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES;
122 static int retry_sleep_temp_shutdown = 1;
123 static int n_retry_fsp_fault = PSVC_NUM_OF_RETRIES;
124 static int retry_sleep_fsp_fault = 1;
125
126 typedef struct {
127 int *pvar;
128 char *texttag;
129 } i2c_noise_param_t;
130
131 static i2c_noise_param_t i2cparams[] = {
132 &n_retry_fan, "n_retry_fan",
133 &retry_sleep_fan, "retry_sleep_fan",
134 &n_retry_ps_status, "n_retry_ps_status",
135 &retry_sleep_ps_status, "retry_sleep_ps_status",
136 &n_retry_pshp, "n_retry_pshp",
137 &retry_sleep_pshp, "retry_sleep_pshp",
138 &n_retry_diskhp, "n_retry_diskhp",
139 &retry_sleep_diskhp, "retry_sleep_diskhp",
140 &n_retry_temp_shutdown, "n_retry_temp_shutdown",
141 &retry_sleep_temp_shutdown, "retry_sleep_temp_shutdown",
142 &n_retry_fsp_fault, "n_retry_fsp_fault",
143 &retry_sleep_fsp_fault, "retry_sleep_fsp_fault",
144 NULL, NULL
145 };
146
147 #pragma init(i2cparams_load)
148
149 static void
i2cparams_debug(i2c_noise_param_t * pi2cparams,char * platform,int usingDefaults)150 i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform,
151 int usingDefaults)
152 {
153 char s[128];
154 i2c_noise_param_t *p;
155
156 if (!usingDefaults) {
157 (void) snprintf(s, sizeof (s),
158 "# Values from /usr/platform/%s/lib/i2cparam.conf\n",
159 platform);
160 syslog(LOG_WARNING, "%s", s);
161 } else {
162 /* no file - we're using the defaults */
163 (void) snprintf(s, sizeof (s),
164 "# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n",
165 platform);
166 }
167 (void) fputs(s, stdout);
168 p = pi2cparams;
169 while (p->pvar != NULL) {
170 (void) snprintf(s, sizeof (s), "%s %d\n", p->texttag,
171 *(p->pvar));
172 if (!usingDefaults)
173 syslog(LOG_WARNING, "%s", s);
174 (void) fputs(s, stdout);
175 p++;
176 }
177 }
178
179 static void
i2cparams_load(void)180 i2cparams_load(void)
181 {
182 FILE *fp;
183 char filename[PATH_MAX];
184 char platform[64];
185 char s[128];
186 char var[128];
187 int val;
188 i2c_noise_param_t *p;
189
190 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
191 syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno));
192 return;
193 }
194 (void) snprintf(filename, sizeof (filename),
195 "/usr/platform/%s/lib/i2cparam.conf", platform);
196 /* read thru the i2cparam.conf file and set variables */
197 if ((fp = fopen(filename, "r")) != NULL) {
198 while (fgets(s, sizeof (s), fp) != NULL) {
199 if (s[0] == '#') /* skip comment lines */
200 continue;
201 /* try to find a string match and get the value */
202 if (sscanf(s, "%127s %d", var, &val) != 2)
203 continue;
204 if (val < 1)
205 val = 1; /* clamp min value */
206 p = &(i2cparams[0]);
207 while (p->pvar != NULL) {
208 if (strncmp(p->texttag, var, sizeof (var)) ==
209 0) {
210 *(p->pvar) = val;
211 break;
212 }
213 p++;
214 }
215 }
216 (void) fclose(fp);
217 }
218 /* output the values of the parameters */
219 i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0));
220 }
221
222 /*
223 * Create an I2C device node.
224 */
225 static int
create_i2c_node(char * nd_name,char * nd_compat,int nd_nexi,int * nd_reg)226 create_i2c_node(char *nd_name, char *nd_compat, int nd_nexi, int *nd_reg)
227 {
228 devctl_ddef_t ddef_hdl = NULL;
229 devctl_hdl_t bus_hdl = NULL;
230 devctl_hdl_t dev_hdl = NULL;
231 char buf[MAXPATHLEN];
232 char dev_path[MAXPATHLEN];
233 int rv = PSVC_FAILURE;
234
235 (void) snprintf(buf, sizeof (buf), SEG5_ADDR_DEV_FMT, nd_nexi);
236 bus_hdl = devctl_bus_acquire(buf, 0);
237 if (bus_hdl == NULL)
238 goto bad;
239
240 /* device definition properties */
241 ddef_hdl = devctl_ddef_alloc(nd_name, 0);
242 (void) devctl_ddef_string(ddef_hdl, "compatible", nd_compat);
243 (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, nd_reg);
244
245 /* create the device node */
246 if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl))
247 goto bad;
248
249 if (devctl_get_pathname(dev_hdl, dev_path, MAXPATHLEN) == NULL)
250 goto bad;
251
252 #ifdef DEBUG
253 syslog(LOG_ERR, "PSVC: create_i2c_node: Device node created: (%s)",
254 dev_path);
255 #endif
256 rv = PSVC_SUCCESS;
257 bad:
258 if (dev_hdl) devctl_release(dev_hdl);
259 if (ddef_hdl) devctl_ddef_free(ddef_hdl);
260 if (bus_hdl) devctl_release(bus_hdl);
261 return (rv);
262 }
263
264 /*
265 * Delete an I2C device node given the device path.
266 */
267 static void
delete_i2c_node(char * nd)268 delete_i2c_node(char *nd)
269 {
270 int rv;
271 devctl_hdl_t dev_hdl;
272
273 dev_hdl = devctl_device_acquire(nd, 0);
274 if (dev_hdl == NULL) {
275 return;
276 }
277
278 rv = devctl_device_remove(dev_hdl);
279 if (rv != DDI_SUCCESS)
280 perror(nd);
281 #ifdef DEBUG
282 else
283 syslog(LOG_ERR, "Device node deleted: (%s)", nd);
284 #endif
285 devctl_release(dev_hdl);
286 }
287
288
289 /* PCF8574 Reset Function */
290 static int
send_pcf8574_reset(psvc_opaque_t hdlp,char * reset_dev)291 send_pcf8574_reset(psvc_opaque_t hdlp, char *reset_dev)
292 {
293 int err;
294 uint8_t reset_bits[2] = {0x7F, 0xFF};
295 int i;
296 for (i = 0; i < 2; i++) {
297 err = psvc_set_attr(hdlp, reset_dev, PSVC_GPIO_VALUE_ATTR,
298 &reset_bits[i]);
299 if (err != PSVC_SUCCESS) {
300 #ifdef DEBUG
301 syslog(LOG_ERR,
302 gettext("Reset to %s with 0x%x failed"),
303 reset_dev, reset_bits[i]);
304 #endif
305 return (err);
306 }
307 }
308 /* Need to give u-code a chance to update */
309 sleep(3);
310 return (err);
311 }
312
313 static int
pcf8574_write_bit(psvc_opaque_t hdlp,char * id,uint8_t bit_num,uint8_t bit_val,uint8_t write_must_be_1)314 pcf8574_write_bit(psvc_opaque_t hdlp, char *id, uint8_t bit_num,
315 uint8_t bit_val, uint8_t write_must_be_1)
316 {
317 int rv = PSVC_FAILURE;
318 uint8_t byte;
319
320 rv = psvc_get_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte);
321 if (rv != PSVC_SUCCESS)
322 return (rv);
323
324 byte = PCF8574_BIT_WRITE_VALUE(byte, bit_num, bit_val);
325 byte |= write_must_be_1;
326 rv = psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte);
327 return (rv);
328 }
329
330 /*
331 * To enable the i2c bus, we must toggle bit 6 on the PDB's
332 * PCF8574 (0x4C) high->low->high
333 */
334 static int
pdb_enable_i2c(psvc_opaque_t hdlp)335 pdb_enable_i2c(psvc_opaque_t hdlp)
336 {
337 int rv = PSVC_SUCCESS, i;
338 int bit_vals[3] = {1, 0, 1};
339 int bit_num = 6;
340
341 for (i = 0; i < 3; i++) {
342 rv = pcf8574_write_bit(hdlp, "PDB_PORT", bit_num, bit_vals[i],
343 PDB_MUST_BE_1);
344 if (rv != PSVC_SUCCESS) {
345 goto bad;
346 }
347 }
348 return (rv);
349 bad:
350 #ifdef DEBUG
351 syslog(LOG_ERR, gettext("PDB I2C Bus Enabling Failed"));
352 #endif
353 return (rv);
354 }
355
356 int32_t
psvc_init_disk_bp_policy_0(psvc_opaque_t hdlp,char * id)357 psvc_init_disk_bp_policy_0(psvc_opaque_t hdlp, char *id)
358 {
359 uint8_t reset = 0xFF;
360 return (psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR,
361 &reset));
362 }
363
364 int32_t
pcf8574_init_policy_0(psvc_opaque_t hdlp,char * id)365 pcf8574_init_policy_0(psvc_opaque_t hdlp, char *id)
366 {
367 return (send_pcf8574_reset(hdlp, id));
368 }
369
370 static int32_t
check_fan(psvc_opaque_t hdlp,char * tray_id,char * fan_id,boolean_t * fault_on)371 check_fan(psvc_opaque_t hdlp, char *tray_id, char *fan_id, boolean_t *fault_on)
372 {
373 int status;
374 int speed;
375 int low_thresh;
376 boolean_t have_fault = 0;
377 char *tach_id;
378 char state[PSVC_MAX_STR_LEN];
379 char prev_state[PSVC_MAX_STR_LEN];
380 char fault_state[PSVC_MAX_STR_LEN];
381 int retry;
382
383 /* Get this fan object's corresponding fan tach */
384 status = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR,
385 &tach_id, PSVC_FAN_SPEED_TACHOMETER, 0);
386 if (status != PSVC_SUCCESS)
387 return (status);
388
389 /* Get the low fan speed threshold */
390 status = psvc_get_attr(hdlp, tach_id, PSVC_LO_WARN_ATTR, &low_thresh);
391 if (status != PSVC_SUCCESS)
392 return (status);
393
394 retry = 0;
395 do {
396 if (retry)
397 (void) sleep(retry_sleep_fan);
398 /* Get the fan speed */
399 status = psvc_get_attr(hdlp, tach_id, PSVC_SENSOR_VALUE_ATTR,
400 &speed);
401 if (status != PSVC_SUCCESS)
402 return (status);
403
404 if (speed <= low_thresh) { /* We see a fault */
405 strlcpy(fault_state, "DEVICE_FAIL",
406 sizeof (fault_state));
407 strlcpy(state, PSVC_ERROR, sizeof (state));
408 have_fault = 1;
409 } else { /* Fault gone? */
410 strlcpy(fault_state, PSVC_NO_FAULT,
411 sizeof (fault_state));
412 strlcpy(state, PSVC_OK, sizeof (state));
413 have_fault = 0;
414 }
415 retry++;
416 } while ((retry < n_retry_fan) && (speed <= low_thresh));
417
418 /* Assign new states to the fan object */
419 status = psvc_set_attr(hdlp, fan_id, PSVC_FAULTID_ATTR, fault_state);
420 if (status != PSVC_SUCCESS)
421 return (status);
422 status = psvc_set_attr(hdlp, fan_id, PSVC_STATE_ATTR, state);
423 if (status != PSVC_SUCCESS)
424 return (status);
425
426 /* Get state and previous state */
427 status = psvc_get_attr(hdlp, fan_id, PSVC_STATE_ATTR, state);
428 if (status != PSVC_SUCCESS)
429 return (status);
430 status = psvc_get_attr(hdlp, fan_id, PSVC_PREV_STATE_ATTR, prev_state);
431 if (status != PSVC_SUCCESS)
432 return (status);
433
434 /* Display notices */
435 if (strcmp(state, PSVC_OK) != 0) {
436 syslog(LOG_ERR, gettext("WARNING: %s (%s) failure detected"),
437 tray_id, fan_id);
438 } else {
439 if (strcmp(state, prev_state) != 0) {
440 syslog(LOG_ERR, gettext("NOTICE: Device %s (%s) OK"),
441 tray_id, fan_id);
442 }
443 }
444
445 *fault_on |= have_fault;
446 return (PSVC_SUCCESS);
447 }
448
449 /*
450 * This policy acts on fan trays. It looks at each of its fans
451 * and checks the speeds. If the fan speed is less than the threshold,
452 * then indicate: console, log, LED.
453 */
454 int32_t
psvc_fan_fault_check_policy_0(psvc_opaque_t hdlp,char * id)455 psvc_fan_fault_check_policy_0(psvc_opaque_t hdlp, char *id)
456 {
457 int fan_count;
458 int led_count;
459 int err, i;
460 char *led_id;
461 char *fan_id;
462 char led_state[PSVC_MAX_STR_LEN];
463 char state[PSVC_MAX_STR_LEN];
464 char prev_state[PSVC_MAX_STR_LEN];
465 boolean_t fault_on = 0;
466
467 /* Get the number of fans associated with this fan tray. */
468 err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fan_count,
469 PSVC_FAN_TRAY_FANS);
470 if (err != PSVC_SUCCESS)
471 return (err);
472
473 for (i = 0; i < fan_count; i++) {
474 err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
475 &fan_id, PSVC_FAN_TRAY_FANS, i);
476 if (err != PSVC_SUCCESS)
477 return (err);
478
479 err = check_fan(hdlp, id, fan_id, &fault_on);
480 if (err != PSVC_SUCCESS)
481 return (err);
482 }
483
484 if (fault_on) {
485 strlcpy(led_state, PSVC_LED_ON, sizeof (led_state));
486 err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_ERROR);
487 if (err != PSVC_SUCCESS)
488 return (err);
489
490 } else {
491 strlcpy(led_state, PSVC_LED_OFF, sizeof (led_state));
492 err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_OK);
493 if (err != PSVC_SUCCESS)
494 return (err);
495 }
496
497 err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
498 if (err != PSVC_SUCCESS)
499 return (err);
500 err = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, prev_state);
501 if (err != PSVC_SUCCESS)
502 return (err);
503
504 /*
505 * Set leds according to the fan tray's states.
506 * (we only do this if there is a change of state in order
507 * to reduce i2c traffic)
508 */
509 if (strcmp(state, prev_state) != 0) {
510 err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
511 &led_count, PSVC_DEV_FAULT_LED);
512 if (err != PSVC_SUCCESS)
513 return (err);
514 for (i = 0; i < led_count; i++) {
515 err = psvc_get_attr(hdlp, id,
516 PSVC_ASSOC_ID_ATTR, &led_id,
517 PSVC_DEV_FAULT_LED, i);
518 if (err != PSVC_SUCCESS)
519 return (err);
520 err = psvc_set_attr(hdlp, led_id,
521 PSVC_LED_STATE_ATTR, led_state);
522 if (err != PSVC_SUCCESS)
523 return (err);
524 err = psvc_get_attr(hdlp, led_id,
525 PSVC_LED_STATE_ATTR, led_state);
526 if (err != PSVC_SUCCESS)
527 return (err);
528 }
529 }
530 return (err);
531 }
532
533 static int32_t
check_cpu_temp_fault(psvc_opaque_t hdlp,char * cpu,int32_t cpu_count)534 check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count)
535 {
536 char *sensorid;
537 int32_t sensor_count;
538 int32_t status = PSVC_SUCCESS;
539 int32_t i;
540 char fault[PSVC_MAX_STR_LEN];
541 int retry;
542
543 psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
544 PSVC_DEV_TEMP_SENSOR);
545 for (i = 0; i < sensor_count; ++i) {
546 status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR,
547 &sensorid, PSVC_DEV_TEMP_SENSOR, i);
548 if (status == PSVC_FAILURE)
549 return (status);
550
551 retry = 0;
552 do {
553 if (retry)
554 (void) sleep(retry_sleep_temp_shutdown);
555 status = psvc_get_attr(hdlp, sensorid,
556 PSVC_FAULTID_ATTR, fault);
557 if (status == PSVC_FAILURE)
558 return (status);
559 retry++;
560 } while (((strcmp(fault, PSVC_TEMP_LO_SHUT) == 0) ||
561 (strcmp(fault, PSVC_TEMP_HI_SHUT) == 0)) &&
562 (retry < n_retry_temp_shutdown));
563
564 if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) ||
565 (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) {
566 system("shutdown -y -g 60 -i 5 \"OVERTEMP condition\"");
567 }
568 }
569
570 return (status);
571 }
572
573 int32_t
psvc_shutdown_policy_0(psvc_opaque_t hdlp,char * id)574 psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id)
575 {
576 int32_t cpu_count;
577 char *cpuid;
578 int32_t i;
579 boolean_t present;
580 int32_t status = PSVC_SUCCESS;
581
582 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
583 PSVC_CPU);
584 for (i = 0; i < cpu_count; ++i) {
585
586 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid,
587 PSVC_CPU, i);
588 if (status == PSVC_FAILURE)
589 return (status);
590
591 status = psvc_get_attr(hdlp, cpuid,
592 PSVC_PRESENCE_ATTR, &present);
593 if (status == PSVC_FAILURE && present == PSVC_PRESENT)
594 return (status);
595 if (present == PSVC_PRESENT) {
596 status = check_cpu_temp_fault(hdlp, cpuid, cpu_count);
597 if (status == PSVC_FAILURE && errno != ENODEV)
598 return (status);
599 }
600 }
601
602 return (PSVC_SUCCESS);
603 }
604
605 /*
606 * Checks device specified by the PSVC_DEV_FAULT_SENSOR association
607 * for errors, and if there is, then report and turn on the FSP Fault
608 * Led.
609 */
610 int32_t
psvc_fsp_device_fault_check_policy_0(psvc_opaque_t hdlp,char * id)611 psvc_fsp_device_fault_check_policy_0(psvc_opaque_t hdlp, char *id)
612 {
613 int32_t status;
614 int32_t i;
615 int32_t device_count = 0;
616 char device_state[PSVC_MAX_STR_LEN];
617 char *device_id;
618 int32_t failed_count = 0;
619 static int32_t led_on = 0;
620 int retry;
621
622 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
623 &device_count, PSVC_DEV_FAULT_SENSOR);
624 if (status != PSVC_SUCCESS)
625 return (status);
626
627 for (i = 0; i < device_count; i++) {
628 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
629 &device_id, PSVC_DEV_FAULT_SENSOR, i);
630 if (status != PSVC_SUCCESS)
631 return (status);
632
633 retry = 0;
634 do {
635 if (retry)
636 (void) sleep(retry_sleep_fsp_fault);
637 status = psvc_get_attr(hdlp, device_id, PSVC_STATE_ATTR,
638 device_state);
639 if (status != PSVC_SUCCESS)
640 return (status);
641
642 if (strcmp(device_state, PSVC_OK) != 0 &&
643 strcmp(device_state, PSVC_HOTPLUGGED) != 0 &&
644 strcmp(device_state, "NO AC POWER") != 0 &&
645 strlen(device_state) != 0) {
646 failed_count++;
647 }
648 retry++;
649 } while ((retry < n_retry_fsp_fault) && (failed_count));
650 }
651 if (failed_count == 0 && led_on) {
652 syslog(LOG_ERR, gettext("%s has turned OFF"), id);
653 status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR,
654 PSVC_LED_OFF);
655 led_on = 0;
656 }
657
658 if (failed_count > 0 && ! led_on) {
659 syslog(LOG_ERR,
660 gettext("%s has turned ON"), id);
661 status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR,
662 PSVC_LED_ON);
663 led_on = 1;
664 }
665
666 return (PSVC_SUCCESS);
667 }
668
669 /* Power Supply Policy Helper and Worker Functions */
670 static void
ps_reset_prev_failed(int index)671 ps_reset_prev_failed(int index)
672 {
673 int i;
674 /* Reset the power supply's failure information */
675 for (i = 0; i < 3; i++) {
676 ps_prev_id[index][i] = NULL;
677 ps_prev_failed[index][i] = 0;
678 }
679
680 }
681 static int
check_i2c_access(psvc_opaque_t hdlp,char * id)682 check_i2c_access(psvc_opaque_t hdlp, char *id)
683 {
684 int rv;
685 char state[PSVC_MAX_STR_LEN];
686 char ps_fault_sensor[PSVC_MAX_STR_LEN];
687
688 snprintf(ps_fault_sensor, sizeof (ps_fault_sensor),
689 "%s_FAULT_SENSOR", id);
690
691 rv = psvc_get_attr(hdlp, ps_fault_sensor, PSVC_SWITCH_STATE_ATTR,
692 &state);
693 return (rv);
694 }
695
696 /*
697 * This routine takes in the PSVC handle pointer, the PS name, and the
698 * instance number (0 or 1). It simply make a psvc_get call to get the
699 * presence of each of the children under the PS. This call will set the
700 * presence state of the child device if it was not there when the system
701 * was booted.
702 */
703 static int
handle_ps_hotplug_children_presence(psvc_opaque_t hdlp,char * id)704 handle_ps_hotplug_children_presence(psvc_opaque_t hdlp, char *id)
705 {
706 char *child_add_on[4] = {"_RESET", "_LOGICAL_STATE", "_AC_IN_SENSOR",
707 "_FAULT_SENSOR"};
708 int add_ons = 4;
709 char addon_id[PICL_PROPNAMELEN_MAX];
710 char *sensor_id;
711 int32_t status = PSVC_SUCCESS;
712 boolean_t presence;
713 int j;
714
715 /* Go through the add on list and set presence */
716 for (j = 0; j < add_ons; j++) {
717 snprintf(addon_id, sizeof (addon_id), "%s%s", id,
718 child_add_on[j]);
719 status = psvc_get_attr(hdlp, addon_id, PSVC_PRESENCE_ATTR,
720 &presence);
721 if (status != PSVC_SUCCESS)
722 return (status);
723 }
724
725 /* Go through each PS's fault sensors */
726 for (j = 0; j < PS_MAX_FAULT_SENSORS; j++) {
727 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
728 &(sensor_id), PSVC_DEV_FAULT_SENSOR, j);
729 if (status != PSVC_SUCCESS)
730 return (status);
731 status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR,
732 &presence);
733 if (status != PSVC_SUCCESS)
734 return (status);
735 }
736
737 /* Go through each PS's onboard i2c hardware */
738 for (j = 0; j < 2; j++) {
739 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
740 &(sensor_id), PSVC_PHYSICAL_DEVICE, j);
741 if (status != PSVC_SUCCESS)
742 return (status);
743 status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR,
744 &presence);
745 if (status != PSVC_SUCCESS)
746 return (status);
747 }
748
749 return (status);
750 }
751
752 static int
handle_ps_hotplug(psvc_opaque_t hdlp,char * id,boolean_t present)753 handle_ps_hotplug(psvc_opaque_t hdlp, char *id, boolean_t present)
754 {
755 int32_t status = PSVC_SUCCESS;
756 int32_t instance;
757 picl_nodehdl_t parent_node;
758 picl_nodehdl_t child_node;
759 char info[PSVC_MAX_STR_LEN];
760 char ps_logical_state[PICL_PROPNAMELEN_MAX];
761 char parent_path[PICL_PROPNAMELEN_MAX];
762 char ps_path[PICL_PROPNAMELEN_MAX];
763 static int fruprom_addr[2][2] = { {0, 0xa2}, {0, 0xa0} };
764 static int pcf8574_addr[2][2] = { {0, 0x72}, {0, 0x70} };
765 char dev_path[MAXPATHLEN];
766
767 /* Convert name to node and parent path */
768 psvcplugin_lookup(id, parent_path, &child_node);
769
770 /*
771 * Get the power supply's instance.
772 * Used to index the xxx_addr arrays
773 */
774 status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
775 if (status != PSVC_SUCCESS)
776 return (status);
777
778 if (present == PSVC_PRESENT && !ps_prev_present[instance]) {
779 /* Service Power Supply Insertion */
780 syslog(LOG_ERR, gettext("Device %s inserted"), id);
781
782 /* PICL Tree Maintenance */
783 ptree_get_node_by_path(parent_path, &parent_node);
784 ptree_add_node(parent_node, child_node);
785 snprintf(ps_path, sizeof (ps_path), "%s/%s", parent_path, id);
786 psvcplugin_add_children(ps_path);
787
788 /*
789 * This code to update the presences of power supply
790 * child devices in the event that picld was started
791 * without a power supply present. This call makes
792 * the devices available after that initial insertion.
793 */
794 status = handle_ps_hotplug_children_presence(hdlp, id);
795
796 /*
797 * Device Tree Maintenance
798 * Add the devinfo tree node entry for the pcf8574 and seeprom
799 * and attach their drivers.
800 */
801 status |= create_i2c_node("ioexp", "i2c-pcf8574", SEG5_ADDR,
802 pcf8574_addr[instance]);
803 status |= create_i2c_node("fru", "i2c-at24c64", SEG5_ADDR,
804 fruprom_addr[instance]);
805 } else {
806 /* Service Power Supply Removal */
807 syslog(LOG_ERR, gettext("Device %s removed"), id);
808
809 /* Reset the power supply's failure information */
810 ps_reset_prev_failed(instance);
811
812 /* PICL Tree Maintenance */
813 if (ptree_delete_node(child_node) != PICL_SUCCESS)
814 syslog(LOG_ERR, "ptree_delete_node failed!");
815
816 /*
817 * The hardcoded subscript in pcf8574_add[instance][1]
818 * refers to the address. We are appending the address to
819 * device path. Both elements are used when creating
820 * the i2c node (above).
821 */
822 snprintf(dev_path, sizeof (dev_path),
823 SEG5_DEV_NAME"ioexp@0,%x:pcf8574",
824 pcf8574_addr[instance][1]);
825 delete_i2c_node(dev_path);
826
827 snprintf(dev_path, sizeof (dev_path),
828 SEG5_DEV_NAME"fru@0,%x:fru", fruprom_addr[instance][1]);
829 delete_i2c_node(dev_path);
830 }
831
832 snprintf(ps_logical_state, sizeof (ps_logical_state),
833 "%s_LOGICAL_STATE", id);
834
835 strlcpy(info, PSVC_OK, sizeof (info));
836 status |= psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, info);
837 status |= psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR, info);
838
839 strlcpy(info, PSVC_NO_FAULT, sizeof (info));
840 status |= psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, info);
841
842 /* Enable the i2c connection to the power supply */
843 status |= pdb_enable_i2c(hdlp);
844 return (status);
845 }
846
847 /*
848 * check_ps_state() Checks for:
849 *
850 * - Failure bits:
851 * Power Supply Fan Failure
852 * Power Supply Temperature Failure
853 * Power Supply Generic Fault
854 * Power Supply AC Cord Plugged In
855 *
856 * - If we see a "bad" state we will report an error.
857 *
858 * - "Bad" states:
859 * Fault bit shows fault.
860 * Temperature fault shows fault.
861 * Fan fault shows fault.
862 * AC power NOT okay to supply.
863 *
864 * - If we see that the AC Cord is not plugged in, then the the other
865 * failure bits are invalid.
866 *
867 * - Send pcf8574_reset at the end of the policy if we see
868 * any "bad" states.
869 */
870 static int32_t
check_ps_state(psvc_opaque_t hdlp,char * id)871 check_ps_state(psvc_opaque_t hdlp, char *id)
872 {
873 int32_t sensor_count;
874 int32_t status = PSVC_SUCCESS;
875 int32_t i;
876 int32_t fault_on = 0;
877 char *sensor_id;
878 char ps_ok_sensor[PICL_PROPNAMELEN_MAX];
879 char ps_logical_state[PICL_PROPNAMELEN_MAX];
880 char ps_reset[PICL_PROPNAMELEN_MAX];
881 char previous_state[PSVC_MAX_STR_LEN];
882 char state[PSVC_MAX_STR_LEN];
883 char fault[PSVC_MAX_STR_LEN];
884 int ps_okay = 1; /* Keep track of the PDB PS OK Bit */
885 int instance;
886 int retry;
887
888 /* Logical state id */
889 snprintf(ps_logical_state, sizeof (ps_logical_state),
890 "%s_LOGICAL_STATE", id);
891
892 /*
893 * ac_power_check updates the Power Supply state with "NO AC POWER" if
894 * the power cord is out OR PSVC_OK if the power cord is in.
895 */
896 status = ac_power_check(hdlp, id, ps_logical_state);
897 if (status == PSVC_FAILURE)
898 return (status);
899
900 /*
901 * After running ac_power_check we now need to get the current state
902 * of the PS. If the power supply state is "NO AC POWER" then we do
903 * not need to check for failures and we return.
904 */
905 status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
906 if (status != PSVC_SUCCESS)
907 return (status);
908
909 if (strcmp(state, "NO AC POWER") == 0)
910 return (status);
911
912 status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, previous_state);
913 if (status != PSVC_SUCCESS)
914 return (status);
915
916 snprintf(ps_ok_sensor, sizeof (ps_ok_sensor), "%s_OK_SENSOR", id);
917 retry = 0;
918 do {
919 if (retry)
920 (void) sleep(retry_sleep_ps_status);
921 /* Handle the PDB P/S OK Bit */
922 status = psvc_get_attr(hdlp, ps_ok_sensor,
923 PSVC_SWITCH_STATE_ATTR, state);
924 if (status != PSVC_SUCCESS)
925 return (status);
926 retry++;
927 } while ((retry < n_retry_ps_status) &&
928 (strcmp(previous_state, state)));
929
930
931 /*
932 * If there is a change of state (current state differs from
933 * previous state, then assign the error values.
934 */
935 if (strcmp(previous_state, state) != 0) {
936 if (strcmp(state, PSVC_SWITCH_OFF) == 0) {
937 strlcpy(state, PSVC_ERROR, sizeof (state));
938 strlcpy(fault, "DEVICE_FAIL", sizeof (fault));
939 fault_on = 1;
940 syslog(LOG_ERR, gettext(
941 "Device %s: Failure Detected -- %s "
942 "shutdown!"), id, id);
943 ps_okay = 0;
944 } else {
945 strlcpy(state, PSVC_OK, sizeof (state));
946 strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
947 }
948
949 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
950 if (status != PSVC_SUCCESS)
951 return (status);
952
953 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
954 if (status != PSVC_SUCCESS)
955 return (status);
956 }
957
958 status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
959 if (status != PSVC_SUCCESS)
960 return (status);
961
962 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
963 PSVC_DEV_FAULT_SENSOR);
964 if (status != PSVC_SUCCESS) {
965 return (status);
966 }
967
968 /* Handle the power supply fail bits. */
969 for (i = 0; i < sensor_count; i++) {
970 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
971 &sensor_id, PSVC_DEV_FAULT_SENSOR, i);
972 if (status != PSVC_SUCCESS)
973 return (status);
974
975 retry = 0;
976 do {
977 if (retry)
978 (void) sleep(retry_sleep_ps_status);
979 status = psvc_get_attr(hdlp, sensor_id,
980 PSVC_SWITCH_STATE_ATTR, state);
981 if (status != PSVC_SUCCESS)
982 return (status);
983 retry++;
984 } while ((retry < n_retry_ps_status) &&
985 (strcmp(state, PSVC_SWITCH_ON) == 0));
986
987 if (strcmp(state, PSVC_SWITCH_ON) == 0) {
988 if (ps_prev_id[instance][i] == NULL)
989 ps_prev_id[instance][i] = sensor_id;
990
991 if (ps_prev_failed[instance][i] != 1)
992 ps_prev_failed[instance][i] = 1;
993 fault_on = 1;
994 /*
995 * The first sensor in the list is:
996 * PSx_DEV_FAULT_SENSOR. If this is on, we do not
997 * want to merely report that it's on, but rather
998 * report that there was a fault detected, thus
999 * improving diagnosability.
1000 */
1001 if (i == 0) {
1002 /*
1003 * Don't notify if the PDB PS OKAY Bit is
1004 * "0"
1005 */
1006 if (ps_okay)
1007 syslog(LOG_ERR, gettext(
1008 "Device %s: Fault Detected"),
1009 id);
1010 } else {
1011 syslog(LOG_ERR, gettext("Warning %s: %s is ON"),
1012 id, sensor_id);
1013 }
1014 }
1015 }
1016
1017 status = psvc_get_attr(hdlp, ps_logical_state,
1018 PSVC_STATE_ATTR, state);
1019 if (status != PSVC_SUCCESS)
1020 return (status);
1021
1022 status = psvc_get_attr(hdlp, ps_logical_state,
1023 PSVC_PREV_STATE_ATTR, previous_state);
1024 if (status != PSVC_SUCCESS)
1025 return (status);
1026
1027 /*
1028 * If we encountered a fault of any kind (something before
1029 * has set 'fault_on' to '1') then we want to send the reset
1030 * signal to the power supply's PCF8574 and also set
1031 * 'ps_logical_state' to "ERROR" so that the FSP General Fault
1032 * LED will light.
1033 */
1034 if (fault_on) {
1035 if (ps_okay) {
1036 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
1037 PSVC_GEN_FAULT);
1038 if (status != PSVC_SUCCESS)
1039 return (status);
1040 }
1041 status = psvc_set_attr(hdlp, ps_logical_state,
1042 PSVC_STATE_ATTR, PSVC_ERROR);
1043 if (status != PSVC_SUCCESS)
1044 return (status);
1045 /*
1046 * "id" is in the form of "PSx", We need to make it
1047 * PSx_RESET.
1048 */
1049 snprintf(ps_reset, sizeof (ps_reset), "%s_RESET", id);
1050 status = send_pcf8574_reset(hdlp, ps_reset);
1051 return (status);
1052 }
1053
1054 /*
1055 * There was no fault encountered so we want to
1056 * set 'ps_logical_state' to "OK"
1057 */
1058 if (strcmp(state, PSVC_OK) != 0) {
1059 for (i = 0; i < 3; i++) {
1060 char *sensor = ps_prev_id[instance][i];
1061 int *prev_failed = &ps_prev_failed[instance][i];
1062 if (sensor == NULL)
1063 continue;
1064 if (*prev_failed == 0)
1065 continue;
1066 *prev_failed = 0;
1067 if (i == 0) {
1068 /*
1069 * Don't notifiy if we have a power supply
1070 * failure (PDB PS OKAY == 0
1071 */
1072 if (ps_okay)
1073 syslog(LOG_ERR, gettext(
1074 "Notice %s: Fault Cleared"),
1075 id);
1076 } else {
1077 syslog(LOG_ERR, gettext("Notice %s: %s is OFF"),
1078 id, sensor);
1079 }
1080 }
1081
1082 status = psvc_set_attr(hdlp, ps_logical_state,
1083 PSVC_STATE_ATTR, PSVC_OK);
1084 if (status != PSVC_SUCCESS)
1085 return (status);
1086 syslog(LOG_ERR, gettext("Device %s Okay"), id);
1087 }
1088
1089 return (PSVC_SUCCESS);
1090 }
1091
1092 /*
1093 * This routine takes in a handle pointer and a Power Supply id. It then gets
1094 * the switch state for the PSx_AC_IN_SENSOR. If the switch is OFF the cord is
1095 * unplugged and we return a true (1). If the switch is ON then the cord is
1096 * plugged in and we return a false (0). If the get_attr call fails we return
1097 * PSVC_FAILURE (-1).
1098 */
1099 static int
ac_unplugged(psvc_opaque_t hdlp,char * id)1100 ac_unplugged(psvc_opaque_t hdlp, char *id)
1101 {
1102 int32_t status = PSVC_SUCCESS;
1103 char ac_sensor_id[PICL_PROPNAMELEN_MAX];
1104 char ac_switch_state[PSVC_MAX_STR_LEN];
1105
1106 snprintf(ac_sensor_id, sizeof (ac_sensor_id), "%s_AC_IN_SENSOR", id);
1107
1108 status = psvc_get_attr(hdlp, ac_sensor_id, PSVC_SWITCH_STATE_ATTR,
1109 ac_switch_state);
1110 if (status == PSVC_FAILURE) {
1111 return (status);
1112 }
1113
1114 if (strcmp(ac_switch_state, PSVC_SWITCH_OFF) == 0) {
1115 return (1);
1116 } else {
1117 return (0);
1118 }
1119 }
1120
1121 /*
1122 * This routine expects a handle pointer, a Power Supply ID, and a PS logical
1123 * state switch ID. It check to see if the power cord has been removed from or
1124 * inserted to the power supply. It then updates the PS state accordingly.
1125 */
1126 static int
ac_power_check(psvc_opaque_t hdlp,char * id,char * ps_logical_state)1127 ac_power_check(psvc_opaque_t hdlp, char *id, char *ps_logical_state)
1128 {
1129 int32_t status = PSVC_SUCCESS;
1130 int32_t sensor_count;
1131 char *sensor_id;
1132 char state[PSVC_MAX_STR_LEN];
1133 int unplugged, i;
1134
1135 status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
1136 if (status != PSVC_SUCCESS)
1137 return (status);
1138
1139 /*
1140 * Check for AC Power Cord. ac_unplugged will return true if the PS is
1141 * unplugged, a false is the PS is plugged in, and PSVC_FAILURE if the
1142 * call to get the state fails.
1143 */
1144 unplugged = ac_unplugged(hdlp, id);
1145 if (status == PSVC_FAILURE) {
1146 return (status);
1147 }
1148
1149 /*
1150 * If power cord is not in, then we set the fault and error
1151 * states to "".
1152 * If power cord is in, then we check the devices.
1153 */
1154 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
1155 PSVC_DEV_FAULT_SENSOR);
1156 if (status != PSVC_SUCCESS) {
1157 return (status);
1158 }
1159
1160 if ((unplugged) && (strcmp(state, "NO AC POWER") != 0)) {
1161 /* set id's state to "NO AC POWER" */
1162 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
1163 "NO AC POWER");
1164 if (status != PSVC_SUCCESS)
1165 return (status);
1166 /*
1167 * Set this state so that the FSP Fault LED lights
1168 * when there is no AC Power to the power supply.
1169 */
1170 status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR,
1171 PSVC_ERROR);
1172 if (status != PSVC_SUCCESS)
1173 return (status);
1174
1175 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
1176 "NO AC POWER");
1177 if (status != PSVC_SUCCESS)
1178 return (status);
1179
1180 syslog(LOG_ERR, gettext("Device %s AC UNAVAILABLE"), id);
1181
1182 /* Set fault sensor states to "" */
1183 for (i = 0; i < sensor_count; ++i) {
1184 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
1185 &sensor_id, PSVC_DEV_FAULT_SENSOR, i);
1186 if (status != PSVC_SUCCESS)
1187 return (status);
1188
1189 status = psvc_set_attr(hdlp, sensor_id,
1190 PSVC_FAULTID_ATTR, "");
1191 if (status != PSVC_SUCCESS)
1192 return (status);
1193 }
1194 }
1195
1196 /* Power cord is plugged in */
1197 if ((!unplugged) && (strcmp(state, "NO AC POWER") == 0)) {
1198 /* Default the state to "OK" */
1199 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
1200 PSVC_OK);
1201 if (status != PSVC_SUCCESS)
1202 return (status);
1203 /* Default the PS_LOGICAL_STATE to "OK" */
1204 status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR,
1205 PSVC_OK);
1206 if (status != PSVC_SUCCESS)
1207 return (status);
1208 /* Display message */
1209 syslog(LOG_ERR, gettext("Device %s AC AVAILABLE"), id);
1210 }
1211
1212 return (status);
1213 }
1214
1215 int32_t
psvc_init_ps_presence(psvc_opaque_t hdlp,char * id)1216 psvc_init_ps_presence(psvc_opaque_t hdlp, char *id)
1217 {
1218 int err;
1219 int instance;
1220 boolean_t presence;
1221
1222 err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
1223 err |= psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
1224 ps_prev_present[instance] = ps_present[instance] = presence;
1225 return (err);
1226 }
1227
1228 int32_t
psvc_ps_monitor_policy_0(psvc_opaque_t hdlp,char * id)1229 psvc_ps_monitor_policy_0(psvc_opaque_t hdlp, char *id)
1230 {
1231 int err;
1232 int instance;
1233 static int failed_last_time[2] = {0, 0};
1234 int retry;
1235
1236 err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
1237 if (err != PSVC_SUCCESS)
1238 return (err);
1239
1240 /* copy current presence to previous presence */
1241 ps_prev_present[instance] = ps_present[instance];
1242
1243 retry = 0;
1244 do {
1245 if (retry)
1246 (void) sleep(retry_sleep_pshp);
1247 /* Get new presence */
1248 err = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR,
1249 &ps_present[instance]);
1250 if (err != PSVC_SUCCESS)
1251 goto out;
1252 retry++;
1253 } while ((retry < n_retry_pshp) &&
1254 (ps_present[instance] != ps_prev_present[instance]));
1255
1256 /* Sustained Hotplug detected */
1257 if (ps_present[instance] != ps_prev_present[instance]) {
1258 err = handle_ps_hotplug(hdlp, id, ps_present[instance]);
1259 return (err);
1260 }
1261
1262 /* If our power supply is not present, we're done */
1263 if (!ps_present[instance])
1264 return (PSVC_SUCCESS);
1265
1266 err = check_i2c_access(hdlp, id);
1267 if (err != PSVC_SUCCESS) {
1268 /* Quickie hotplug */
1269 if (ps_present[instance] == PSVC_PRESENT &&
1270 ps_prev_present[instance] == PSVC_PRESENT) {
1271 syslog(LOG_ERR, "Device %s removed", id);
1272 /* Reset prev_failed information */
1273 ps_reset_prev_failed(instance);
1274 ps_prev_present[instance] = 0;
1275 handle_ps_hotplug(hdlp, id, ps_present[instance]);
1276 /* We ignore the error on a quickie hotplug */
1277 return (PSVC_SUCCESS);
1278 }
1279 /* There was an actual i2c access error */
1280 goto out;
1281 }
1282
1283 err = check_ps_state(hdlp, id);
1284 if (err != PSVC_SUCCESS)
1285 goto out;
1286
1287 failed_last_time[instance] = 0;
1288 return (err);
1289
1290 out:
1291 if (! failed_last_time[instance]) {
1292 /*
1293 * We ignore the error condition the first time thru
1294 * because the PS could have been removed after (or
1295 * during) our call to check_ps_hotplug().
1296 *
1297 * If the problem is still there the next time, then
1298 * we'll raise a flag.
1299 *
1300 * The instance determines which power supply the policy
1301 * errored on. For instance PS0 might have failed and then
1302 * PS1 might have failed, but we'll display a warning
1303 * even though there might not be anything actually wrong.
1304 * The instance keeps track of which failure occurred so
1305 * we warn on the corresponding occurrence of errors.
1306 */
1307 failed_last_time[instance] = 1;
1308 return (PSVC_SUCCESS);
1309 }
1310 return (err);
1311 }
1312
1313 static int
light_disk_fault_leds(psvc_opaque_t hdlp,char * id,boolean_t disk_presence)1314 light_disk_fault_leds(psvc_opaque_t hdlp, char *id, boolean_t disk_presence)
1315 {
1316 int err;
1317 int bit_nums[MAX_DISKS] = {6, 7};
1318 uint8_t led_masks[MAX_DISKS] = {0x40, 0x80};
1319 int instance;
1320 int bit_value;
1321 char state[PSVC_MAX_STR_LEN];
1322 uint8_t byte;
1323
1324 if (disk_presence != PSVC_PRESENT)
1325 return (PSVC_SUCCESS);
1326
1327 err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
1328 if (err != PSVC_SUCCESS)
1329 return (err);
1330
1331 err = psvc_get_attr(hdlp, "DISK_PORT", PSVC_GPIO_VALUE_ATTR,
1332 &byte);
1333 if (err != PSVC_SUCCESS)
1334 return (err);
1335
1336 err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
1337 if (err != PSVC_SUCCESS)
1338 return (err);
1339 if (strcmp(state, PSVC_OK) == 0 || strcmp(state, "") == 0) { /* OK */
1340 if (byte & led_masks[instance]) { /* Led is OFF */
1341 return (err); /* Done. */
1342 } else { /* Led is ON, Turn if OFF */
1343 bit_value = 1; /* Active Low */
1344 err = pcf8574_write_bit(hdlp, "DISK_PORT",
1345 bit_nums[instance], bit_value,
1346 DISKBP_MUST_BE_1);
1347 if (err != PSVC_SUCCESS)
1348 return (err);
1349 }
1350 } else { /* Disk is NOT OK */
1351 if (byte & led_masks[instance]) { /* Led is OFF, Turn it ON */
1352 bit_value = 0; /* Active Low */
1353 err = pcf8574_write_bit(hdlp, "DISK_PORT",
1354 bit_nums[instance], bit_value,
1355 DISKBP_MUST_BE_1);
1356 if (err != PSVC_SUCCESS)
1357 return (err);
1358 } else {
1359 return (err); /* Done. */
1360 }
1361 }
1362 return (err);
1363 }
1364
1365 int
verify_disk_wwn(char * wwn)1366 verify_disk_wwn(char *wwn)
1367 {
1368 HBA_PORTATTRIBUTES hbaPortAttrs, discPortAttrs;
1369 HBA_HANDLE handle;
1370 HBA_STATUS status;
1371 HBA_ADAPTERATTRIBUTES hbaAttrs;
1372 HBA_UINT32 numberOfAdapters, hbaCount, hbaPort, discPort;
1373 char adaptername[256];
1374 char vwwn[WWN_SIZE * 2];
1375 char OSDeviceName[PATH_MAX + 1];
1376 int count, linksize;
1377
1378 /* Load common lib */
1379 status = HBA_LoadLibrary();
1380 if (status != HBA_STATUS_OK) {
1381 (void) HBA_FreeLibrary();
1382 return (HBA_STATUS_ERROR);
1383 }
1384
1385 /*
1386 * Since devfs can store multiple instances
1387 * of a target the validity of the WWN of a disk is
1388 * verified with an actual probe of internal disks
1389 */
1390
1391 /* Cycle through FC-AL Adapters and search for WWN */
1392 numberOfAdapters = HBA_GetNumberOfAdapters();
1393 for (hbaCount = 0; hbaCount < numberOfAdapters; hbaCount++) {
1394 if ((status = HBA_GetAdapterName(hbaCount, adaptername)) !=
1395 HBA_STATUS_OK)
1396 continue;
1397
1398 handle = HBA_OpenAdapter(adaptername);
1399 if (handle == 0)
1400 continue;
1401
1402 /* Get Adapter Attributes */
1403 if ((status = HBA_GetAdapterAttributes(handle,
1404 &hbaAttrs)) != HBA_STATUS_OK) {
1405 HBA_CloseAdapter(handle);
1406 continue;
1407 }
1408
1409 /* Get Adapter's Port Attributes */
1410 for (hbaPort = 0;
1411 hbaPort < hbaAttrs.NumberOfPorts; hbaPort++) {
1412 if ((status = HBA_GetAdapterPortAttributes(handle,
1413 hbaPort, &hbaPortAttrs)) != HBA_STATUS_OK)
1414 continue;
1415
1416 /*
1417 * Verify whether this is onboard controller.
1418 * HBAAPI provides path of symbol link to
1419 * to the qlc node therefore readlink() is
1420 * needed to obtain hard link
1421 */
1422 linksize = readlink(hbaPortAttrs.OSDeviceName,
1423 OSDeviceName, PATH_MAX);
1424
1425 /*
1426 * If readlink does not return size of onboard
1427 * controller than don't bother checking device
1428 */
1429 if ((linksize + 1) != sizeof (ONBOARD_CONTR))
1430 continue;
1431
1432 OSDeviceName[linksize] = '\0';
1433 if (strcmp(OSDeviceName, ONBOARD_CONTR) != 0)
1434 continue;
1435
1436 /* Get Discovered Port Attributes */
1437 for (discPort = 0;
1438 discPort < hbaPortAttrs.NumberofDiscoveredPorts;
1439 discPort++) {
1440 status = HBA_GetDiscoveredPortAttributes(
1441 handle, hbaPort, discPort,
1442 &discPortAttrs);
1443 if (status != HBA_STATUS_OK)
1444 continue;
1445
1446 /* Get target info */
1447 for (count = 0; count < WWN_SIZE; count++)
1448 (void) sprintf(&vwwn[count * 2],
1449 "%2.2x",
1450 discPortAttrs.NodeWWN.wwn[count]);
1451
1452 if (strcmp(wwn, vwwn) == 0) {
1453 HBA_CloseAdapter(handle);
1454 (void) HBA_FreeLibrary();
1455 return (HBA_STATUS_OK);
1456 }
1457
1458 }
1459 }
1460 HBA_CloseAdapter(handle);
1461 }
1462 (void) HBA_FreeLibrary();
1463 return (HBA_STATUS_ERROR_ILLEGAL_WWN);
1464 }
1465
1466 static int
light_disk_ok2remove_leds(psvc_opaque_t hdlp,boolean_t * disk_present)1467 light_disk_ok2remove_leds(psvc_opaque_t hdlp, boolean_t *disk_present)
1468 {
1469 di_node_t node;
1470 di_node_t root_node;
1471 di_minor_t min_node;
1472 int *prop;
1473 int n;
1474 int target;
1475 int rv;
1476 int disk_online = 0;
1477 static int prev_online[MAX_DISKS] = {-1, -1};
1478 int bit_nums[MAX_DISKS] = {4, 5};
1479 int bit_val;
1480 int count;
1481 char *dev_path;
1482 char wwn[WWN_SIZE * 2];
1483 uchar_t *prop_wwn;
1484
1485 root_node = di_init("/", DINFOCPYALL);
1486 if (root_node == DI_NODE_NIL)
1487 return (PSVC_FAILURE);
1488
1489 for (node = di_drv_first_node(DISK_DRV, root_node);
1490 node != DI_NODE_NIL;
1491 node = di_drv_next_node(node)) {
1492 n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "target", &prop);
1493 if (n == -1)
1494 continue;
1495 target = *prop;
1496 if (target < 0 || target > 1)
1497 continue;
1498
1499 if (! disk_present[target])
1500 continue;
1501
1502 dev_path = di_devfs_path(node);
1503 if (memcmp(dev_path, QLC_NODE, (sizeof (QLC_NODE) - 1)) != 0) {
1504 /*
1505 * This isn't our FC-AL controller, so this
1506 * must be an external disk on Loop B. Skip it.
1507 */
1508 di_devfs_path_free(dev_path);
1509 continue;
1510 }
1511 di_devfs_path_free(dev_path);
1512
1513 /*
1514 * Verify if disk is valid by checking WWN
1515 * because devfs retains stale data.
1516 */
1517 n = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
1518 "node-wwn", &prop_wwn);
1519 if (n == -1)
1520 continue;
1521
1522 for (count = 0; count < WWN_SIZE; count++)
1523 (void) sprintf(&wwn[count * 2], "%2.2x",
1524 prop_wwn[count]);
1525
1526 n = verify_disk_wwn(wwn);
1527 if (n == HBA_STATUS_ERROR_ILLEGAL_WWN)
1528 continue;
1529
1530 min_node = di_minor_next(node, DI_MINOR_NIL);
1531 disk_online = (min_node != DI_MINOR_NIL);
1532 if ((disk_online == 0) && (prev_online[target] == 1)) {
1533 /* Light Led */
1534 bit_val = 0;
1535 rv = pcf8574_write_bit(hdlp, "DISK_PORT",
1536 bit_nums[target], bit_val, DISKBP_MUST_BE_1);
1537 if (rv != PSVC_SUCCESS)
1538 goto done;
1539 } else if ((prev_online[target] == 0) && (disk_online == 1)) {
1540 /* Unlight Led */
1541 bit_val = 1;
1542 rv = pcf8574_write_bit(hdlp, "DISK_PORT",
1543 bit_nums[target], bit_val, DISKBP_MUST_BE_1);
1544 if (rv != PSVC_SUCCESS)
1545 goto done;
1546 }
1547 if (disk_online != prev_online[target])
1548 prev_online[target] = disk_online;
1549 }
1550 done:
1551 di_fini(root_node);
1552 return (rv);
1553 }
1554
1555 static int
check_disk_fault(psvc_opaque_t hdlp,char * id,boolean_t disk_presence)1556 check_disk_fault(psvc_opaque_t hdlp, char *id, boolean_t disk_presence)
1557 {
1558 int32_t status = PSVC_SUCCESS;
1559 int32_t fault_on = 0;
1560 char *sensor_id;
1561 char disk_state[PSVC_MAX_STR_LEN];
1562 char state[PSVC_MAX_STR_LEN];
1563 char fault[PSVC_MAX_STR_LEN];
1564 boolean_t change_of_state = 0;
1565
1566 if (disk_presence != PSVC_PRESENT)
1567 return (PSVC_SUCCESS);
1568
1569 status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, disk_state);
1570 if (status != PSVC_SUCCESS)
1571 return (status);
1572
1573 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
1574 &sensor_id, PSVC_DEV_FAULT_SENSOR, 0);
1575 if (status != PSVC_SUCCESS)
1576 return (status);
1577
1578 status = psvc_get_attr(hdlp, sensor_id, PSVC_SWITCH_STATE_ATTR, state);
1579 if (status != PSVC_SUCCESS)
1580 return (status);
1581
1582 /* Fault detected */
1583 if (strcmp(state, PSVC_SWITCH_ON) == 0) {
1584 strlcpy(state, PSVC_ERROR, sizeof (state));
1585 strlcpy(fault, PSVC_GEN_FAULT, sizeof (fault));
1586 fault_on = 1;
1587 } else { /* No fault detected */
1588 if (strcmp(disk_state, PSVC_OK) != 0)
1589 change_of_state = 1;
1590 strlcpy(state, PSVC_OK, sizeof (state));
1591 strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
1592 }
1593
1594 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
1595 if (status != PSVC_SUCCESS)
1596 return (status);
1597
1598 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
1599 if (status != PSVC_SUCCESS)
1600 return (status);
1601
1602 if (fault_on) {
1603 syslog(LOG_ERR, gettext("Fault detected: %s"), id);
1604
1605 } else {
1606 if (change_of_state)
1607 syslog(LOG_ERR, gettext("Notice: %s okay"), id);
1608 }
1609 return (PSVC_SUCCESS);
1610 }
1611
1612 static int
check_disk_hotplug(psvc_opaque_t hdlp,char * id,boolean_t * disk_presence,int disk_instance)1613 check_disk_hotplug(psvc_opaque_t hdlp, char *id, boolean_t *disk_presence,
1614 int disk_instance)
1615 {
1616 boolean_t presence;
1617 boolean_t previous_presence;
1618 int32_t status = PSVC_SUCCESS;
1619 char label[PSVC_MAX_STR_LEN];
1620 uint8_t disk_leds[MAX_DISKS][2] = {{4, 6}, {5, 7}};
1621 int retry;
1622
1623 status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
1624 &previous_presence);
1625 if (status != PSVC_SUCCESS)
1626 return (status);
1627
1628 retry = 0;
1629 do {
1630 if (retry)
1631 (void) sleep(retry_sleep_diskhp);
1632 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR,
1633 &presence);
1634 if (status != PSVC_SUCCESS)
1635 return (status);
1636 retry++;
1637 } while ((retry < n_retry_diskhp) &&
1638 (presence != previous_presence));
1639
1640 *disk_presence = presence;
1641
1642 if (presence != previous_presence) {
1643 char parent_path[PICL_PROPNAMELEN_MAX];
1644 picl_nodehdl_t child_node;
1645
1646 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
1647 if (status != PSVC_SUCCESS)
1648 return (status);
1649
1650 /* return parent path and node for an object */
1651 psvcplugin_lookup(id, parent_path, &child_node);
1652
1653 if (presence == PSVC_PRESENT) {
1654 picl_nodehdl_t parent_node;
1655 char state[PSVC_MAX_STR_LEN];
1656 char fault[PSVC_MAX_STR_LEN];
1657
1658 syslog(LOG_ERR, gettext("Device %s inserted"), label);
1659 strlcpy(state, PSVC_OK, sizeof (state));
1660 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
1661 state);
1662 if (status != PSVC_SUCCESS)
1663 return (status);
1664
1665 strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
1666 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
1667 fault);
1668 if (status != PSVC_SUCCESS) {
1669 return (status);
1670 }
1671
1672 status = ptree_get_node_by_path(parent_path,
1673 &parent_node);
1674 if (status != PICL_SUCCESS)
1675 return (PSVC_FAILURE);
1676 status = ptree_add_node(parent_node, child_node);
1677 if (status != PICL_SUCCESS)
1678 return (PSVC_FAILURE);
1679 } else {
1680 /*
1681 * Disk Removed so we need to turn off these LEDs:
1682 * DISKx_FLT_LED
1683 * DISKx_REMOVE_LED
1684 */
1685 int i;
1686 int bit_val = 1; /* Active Low */
1687 for (i = 0; i < 2; i++) {
1688 status = pcf8574_write_bit(hdlp, "DISK_PORT",
1689 disk_leds[disk_instance][i], bit_val,
1690 DISKBP_MUST_BE_1);
1691 if (status != PSVC_SUCCESS)
1692 syslog(LOG_ERR, "Failed in turning off"
1693 " %d's LEDs", id);
1694 }
1695 syslog(LOG_ERR, gettext("Device %s removed"), label);
1696 ptree_delete_node(child_node);
1697 }
1698 }
1699
1700 status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
1701 if (status != PSVC_SUCCESS)
1702 return (status);
1703
1704 return (status);
1705 }
1706
1707 int32_t
psvc_disk_monitor_policy_0(psvc_opaque_t hdlp,char * id)1708 psvc_disk_monitor_policy_0(psvc_opaque_t hdlp, char *id)
1709 {
1710 int rv, err, i;
1711 char *disks[MAX_DISKS] = {"DISK0", "DISK1"};
1712 int saved_errno = 0;
1713 boolean_t disk_present[MAX_DISKS] = {0, 0};
1714
1715 for (i = 0; i < MAX_DISKS; i++) {
1716 err = check_disk_hotplug(hdlp, disks[i], &disk_present[i], i);
1717 if (err) saved_errno = errno;
1718 rv = err;
1719
1720 err = check_disk_fault(hdlp, disks[i], disk_present[i]);
1721 if (err) saved_errno = errno;
1722 rv |= err;
1723
1724 err |= light_disk_fault_leds(hdlp, disks[i], disk_present[i]);
1725 if (err) saved_errno = errno;
1726 rv |= err;
1727 }
1728
1729 err = light_disk_ok2remove_leds(hdlp, disk_present);
1730 if (err) saved_errno = errno;
1731 rv |= err;
1732
1733 errno = saved_errno;
1734 return (rv);
1735 }
1736
1737 /*
1738 * Read in temperature thresholds from FRU Prom and update the
1739 * default values.
1740 */
1741
1742 #define START_OFFSET 0x1800 /* Last 2K of SEEPROM */
1743 #define NUM_SEG_OFFSET 0x1805 /* Number of segments */
1744 #define SEG_TABLE_OFFSET 0x1806 /* Segment description tables */
1745
1746 static int32_t
read_sc_segment(psvc_opaque_t hdlp,char * id,char * fru_id,int offset)1747 read_sc_segment(psvc_opaque_t hdlp, char *id, char *fru_id, int offset)
1748 {
1749 static int thresh_names[] = {
1750 PSVC_HW_LO_SHUT_ATTR,
1751 PSVC_LO_SHUT_ATTR,
1752 PSVC_LO_WARN_ATTR,
1753 PSVC_NOT_USED, /* LOW MODE */
1754 PSVC_OPTIMAL_TEMP_ATTR,
1755 PSVC_HI_WARN_ATTR,
1756 PSVC_HI_SHUT_ATTR,
1757 PSVC_HW_HI_SHUT_ATTR
1758 };
1759 int8_t amb_temp_array[8];
1760 int i;
1761 fru_info_t fru_info;
1762 int err;
1763
1764 fru_info.buf_start = offset + 8;
1765 fru_info.buf = amb_temp_array;
1766 fru_info.read_size = 8;
1767
1768 err = psvc_get_attr(hdlp, fru_id, PSVC_FRU_INFO_ATTR, &fru_info);
1769 if (err != PSVC_SUCCESS)
1770 return (err);
1771
1772 for (i = 0; i < 8; i++) {
1773 int32_t temp = amb_temp_array[i];
1774 if (thresh_names[i] == PSVC_NOT_USED)
1775 continue;
1776 err = psvc_set_attr(hdlp, id, thresh_names[i], &temp);
1777 if (err != PSVC_SUCCESS)
1778 return (err);
1779 }
1780 return (PSVC_SUCCESS);
1781 }
1782
1783 int32_t
update_disk_bp_temp_thresholds(psvc_opaque_t hdlp,char * id)1784 update_disk_bp_temp_thresholds(psvc_opaque_t hdlp, char *id)
1785 {
1786
1787 char *fru;
1788 fru_info_t fru_info;
1789 int16_t seg_offset;
1790 int8_t byte;
1791 int8_t seg_count;
1792 char seg_name[2];
1793 int current_offset, i, err;
1794
1795 err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &fru, PSVC_FRU, 0);
1796 if (err != PSVC_SUCCESS)
1797 return (err);
1798
1799 /* Sanity Check */
1800 fru_info.buf_start = START_OFFSET;
1801 fru_info.buf = &byte;
1802 fru_info.read_size = 1;
1803
1804 err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
1805 if (err != PSVC_SUCCESS)
1806 return (err);
1807 if (*fru_info.buf != 8) {
1808 syslog(LOG_ERR, "Notice: FRU Prom %s not programmed", fru);
1809 }
1810 /* Should do CRC Check on fru */
1811
1812 /* Get Segment Count */
1813 fru_info.buf_start = NUM_SEG_OFFSET;
1814 fru_info.buf = &seg_count;
1815 fru_info.read_size = 1;
1816
1817 err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
1818 if (err != PSVC_SUCCESS)
1819 return (err);
1820
1821 current_offset = SEG_TABLE_OFFSET;
1822 for (i = 0; i < seg_count; i++) {
1823 fru_info.buf_start = current_offset;
1824 fru_info.buf = seg_name;
1825 fru_info.read_size = 2;
1826 err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
1827 if (err != PSVC_SUCCESS)
1828 return (err);
1829
1830 if (memcmp(seg_name, "SC", 2) == 0) {
1831 current_offset += 6; /* Skip over description */
1832 fru_info.buf_start = current_offset;
1833 fru_info.buf = (char *)&seg_offset;
1834 fru_info.read_size = 2;
1835 psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
1836 &fru_info);
1837 return (read_sc_segment(hdlp, id, fru, seg_offset));
1838 }
1839 current_offset += 10;
1840 }
1841
1842 return (PSVC_SUCCESS);
1843 }
1844