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