xref: /titanic_52/usr/src/uts/sun4u/javelin/io/envctrltwo.c (revision 193974072f41a843678abf5f61979c748687e66b)
13db86aabSstevel /*
23db86aabSstevel  * CDDL HEADER START
33db86aabSstevel  *
43db86aabSstevel  * The contents of this file are subject to the terms of the
53db86aabSstevel  * Common Development and Distribution License (the "License").
63db86aabSstevel  * You may not use this file except in compliance with the License.
73db86aabSstevel  *
83db86aabSstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93db86aabSstevel  * or http://www.opensolaris.org/os/licensing.
103db86aabSstevel  * See the License for the specific language governing permissions
113db86aabSstevel  * and limitations under the License.
123db86aabSstevel  *
133db86aabSstevel  * When distributing Covered Code, include this CDDL HEADER in each
143db86aabSstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153db86aabSstevel  * If applicable, add the following below this CDDL HEADER, with the
163db86aabSstevel  * fields enclosed by brackets "[]" replaced with your own identifying
173db86aabSstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
183db86aabSstevel  *
193db86aabSstevel  * CDDL HEADER END
203db86aabSstevel  */
213db86aabSstevel 
223db86aabSstevel /*
23*19397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
243db86aabSstevel  * Use is subject to license terms.
253db86aabSstevel  */
263db86aabSstevel 
273db86aabSstevel 
283db86aabSstevel /*
293db86aabSstevel  * ENVCTRLTWO_ Environment Monitoring driver for i2c on Javelin
303db86aabSstevel  *
313db86aabSstevel  */
323db86aabSstevel #include <sys/param.h>
333db86aabSstevel #include <sys/types.h>
343db86aabSstevel #include <sys/signal.h>
353db86aabSstevel #include <sys/errno.h>
363db86aabSstevel #include <sys/file.h>
373db86aabSstevel #include <sys/termio.h>
383db86aabSstevel #include <sys/termios.h>
393db86aabSstevel #include <sys/cmn_err.h>
403db86aabSstevel #include <sys/stream.h>
413db86aabSstevel #include <sys/strsun.h>
423db86aabSstevel #include <sys/stropts.h>
433db86aabSstevel #include <sys/strtty.h>
443db86aabSstevel #include <sys/debug.h>
453db86aabSstevel #include <sys/eucioctl.h>
463db86aabSstevel #include <sys/cred.h>
473db86aabSstevel #include <sys/uio.h>
483db86aabSstevel #include <sys/stat.h>
493db86aabSstevel #include <sys/kmem.h>
503db86aabSstevel 
513db86aabSstevel #include <sys/ddi.h>
523db86aabSstevel #include <sys/sunddi.h>
533db86aabSstevel #include <sys/obpdefs.h>
543db86aabSstevel #include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
553db86aabSstevel #include <sys/modctl.h>		/* for modldrv */
563db86aabSstevel #include <sys/stat.h>		/* ddi_create_minor_node S_IFCHR */
573db86aabSstevel #include <sys/open.h>		/* for open params.	 */
583db86aabSstevel #include <sys/uio.h>		/* for read/write */
593db86aabSstevel #include <sys/envctrl_gen.h>	/* user level generic visible definitions */
603db86aabSstevel #include <sys/envctrl_ue250.h>	/* user level UE250 visible definitions */
613db86aabSstevel #include <javelin/sys/envctrltwo.h> /* definitions for Javelin */
623db86aabSstevel #include <io/envctrl_targets.c>
633db86aabSstevel #include <sys/priv_names.h>
643db86aabSstevel 
653db86aabSstevel /* driver entry point fn definitions */
663db86aabSstevel static int 	envctrl_open(dev_t *, int, int, cred_t *);
673db86aabSstevel static int	envctrl_close(dev_t, int, int, cred_t *);
683db86aabSstevel static int	envctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
693db86aabSstevel static uint_t 	envctrl_bus_isr(caddr_t);
703db86aabSstevel static uint_t 	envctrl_dev_isr(caddr_t);
713db86aabSstevel 
723db86aabSstevel /* configuration entry point fn definitions */
733db86aabSstevel static int 	envctrl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
743db86aabSstevel static int	envctrl_attach(dev_info_t *, ddi_attach_cmd_t);
753db86aabSstevel static int	envctrl_detach(dev_info_t *, ddi_detach_cmd_t);
763db86aabSstevel 
773db86aabSstevel /* Driver private routines */
783db86aabSstevel #ifdef GET_CPU_TEMP
793db86aabSstevel static int	envctrl_get_cpu_temp(struct envctrlunit *, int);
803db86aabSstevel #endif
813db86aabSstevel static void	envctrl_fan_fail_service(struct envctrlunit *);
823db86aabSstevel static void	envctrl_PS_intr_service(struct envctrlunit *);
833db86aabSstevel static void	envctrl_ps_probe(struct envctrlunit *);
843db86aabSstevel static void	envctrl_tempr_poll(void *);
853db86aabSstevel static void	envctrl_pshotplug_poll(void *);
863db86aabSstevel static void	envctrl_led_blink(void *);
873db86aabSstevel static void	envctrl_init_bus(struct envctrlunit *);
883db86aabSstevel static void	envctrl_reset_dflop(struct envctrlunit *);
893db86aabSstevel static void	envctrl_enable_devintrs(struct envctrlunit *);
903db86aabSstevel static void	envctrl_intr_latch_clr(struct envctrlunit *);
913db86aabSstevel static void	envctrl_abort_seq_handler(char *msg);
923db86aabSstevel static int	envctrl_get_fpm_status(struct envctrlunit *, uint8_t *);
933db86aabSstevel static int	envctrl_set_fsp(struct envctrlunit *, uint8_t *);
943db86aabSstevel static int	envctrl_set_dskled(struct envctrlunit *,
953db86aabSstevel 				struct envctrl_chip *);
963db86aabSstevel static int	envctrl_get_dskled(struct envctrlunit *,
973db86aabSstevel 				struct envctrl_chip *);
983db86aabSstevel static int	envctrl_set_fanspeed(struct envctrlunit *,
993db86aabSstevel 			struct envctrl_chip *);
1003db86aabSstevel static void	envctrl_probe_cpus(struct envctrlunit *);
1013db86aabSstevel static int	envctrl_match_cpu(dev_info_t *, void *);
1023db86aabSstevel static int	envctrl_isother_fault_led(struct envctrlunit *,
1033db86aabSstevel 		    uint8_t, uint8_t);
1043db86aabSstevel static int	envctrl_check_sys_temperatures(struct envctrlunit *);
1053db86aabSstevel static void	envctrl_check_disk_kstats(struct envctrlunit *);
1063db86aabSstevel static void	envctrl_update_disk_kstats(struct envctrlunit *,
1073db86aabSstevel 			uint8_t, uint8_t);
1083db86aabSstevel static int	envctrl_read_chip(struct envctrlunit *, int, int, int,
1093db86aabSstevel 			uint8_t *, int);
1103db86aabSstevel static int	envctrl_write_chip(struct envctrlunit *, int, int, int,
1113db86aabSstevel 			uint8_t *, int);
1123db86aabSstevel static int	envctrl_check_tempr_levels(struct envctrlunit *,
1133db86aabSstevel 		int, uint8_t *, int);
1143db86aabSstevel static void	envctrl_update_fanspeed(struct envctrlunit *);
1153db86aabSstevel 
1163db86aabSstevel /* Kstat routines */
1173db86aabSstevel static void	envctrl_add_kstats(struct envctrlunit *);
1183db86aabSstevel static int	envctrl_ps_kstat_update(kstat_t *, int);
1193db86aabSstevel static int	envctrl_fanstat_kstat_update(kstat_t *, int);
1203db86aabSstevel static int	envctrl_encl_kstat_update(kstat_t *, int);
1213db86aabSstevel static int	envctrl_temp_kstat_update(kstat_t *, int);
1223db86aabSstevel static int	envctrl_disk_kstat_update(kstat_t *, int);
1233db86aabSstevel static void	envctrl_init_encl_kstats(struct envctrlunit *);
1243db86aabSstevel 
1253db86aabSstevel extern void power_down(const char *);
1263db86aabSstevel extern int prom_getprop();
1273db86aabSstevel extern int prom_getproplen();
1283db86aabSstevel extern	void	prom_printf(const char *fmt, ...);
1293db86aabSstevel extern void (*abort_seq_handler)();
1303db86aabSstevel 
1313db86aabSstevel static void    *envctrlsoft_statep;
1323db86aabSstevel 
1333db86aabSstevel static char driver_name[] = "envctrltwo";
1343db86aabSstevel static uchar_t _cpu_temps[256];
1353db86aabSstevel static uchar_t _cpu_fan_speeds[256];
1363db86aabSstevel static int psok[2] = {-1, -1};
1373db86aabSstevel static int pspr[2] = {-1, -1};
1383db86aabSstevel static uint8_t idle_fanspeed;
1393db86aabSstevel 
1403db86aabSstevel static int power_flt_led_lit = 0;
1413db86aabSstevel 
1423db86aabSstevel extern void pci_thermal_rem_intr(dev_info_t *, uint_t);
1433db86aabSstevel 
1443db86aabSstevel /* Local Variables */
1453db86aabSstevel /* Indicates whether or not the overtemp thread has been started */
1463db86aabSstevel static int envctrl_debug_flags = 0;
1473db86aabSstevel static int envctrl_power_off_overide = 0;
1483db86aabSstevel static int envctrl_max_retries = 200;
1493db86aabSstevel static int envctrl_allow_detach = 0;
1503db86aabSstevel static int envctrl_numcpus = 1;
1513db86aabSstevel static int envctrl_handler = 1; /* 1 is the default */
1523db86aabSstevel static clock_t overtemp_timeout_hz;
1533db86aabSstevel static clock_t blink_timeout_hz;
1543db86aabSstevel static clock_t pshotplug_timeout_hz;
1553db86aabSstevel static clock_t warning_timeout_hz;
1563db86aabSstevel /*
1573db86aabSstevel  * Temperature levels :
1583db86aabSstevel  * green = OK  - no action needed
1593db86aabSstevel  * yellow = warning - display warning message and poll faster
1603db86aabSstevel  * red = critical - shutdown system
1613db86aabSstevel  */
1623db86aabSstevel enum levels {green, yellow, red};
1633db86aabSstevel 
1643db86aabSstevel #define	DPRINTF1 if (envctrl_debug_flags && (envctrl_debug_flags & 0x1)) printf
1653db86aabSstevel #define	DPRINTF2 if (envctrl_debug_flags && (envctrl_debug_flags & 0x2)) printf
1663db86aabSstevel #define	DPRINTF3 if (envctrl_debug_flags && (envctrl_debug_flags & 0x4)) printf
1673db86aabSstevel 
1683db86aabSstevel #define	JAV_FAN_SPEED_SF_NUM	107
1693db86aabSstevel #define	JAV_FAN_SPEED_SF_DEN	100
1703db86aabSstevel #define	JAV_MAX_TEMP_SENSORS	6
1713db86aabSstevel #define	JAV_FSP_MASK		0xC0
1723db86aabSstevel #define	FAN_DRIFT		25
1733db86aabSstevel #define	MAX_FAN_SPEED		255
1743db86aabSstevel #define	MAX_DEVS		16
1753db86aabSstevel 
1763db86aabSstevel #define	ENVCTRL_UE250_INTR_LATCH_INIT0 0xFE
1773db86aabSstevel #define	ENVCTRL_UE250_INTR_LATCH_INIT1 0xFF
1783db86aabSstevel 
1793db86aabSstevel static int t_scale_num[8];
1803db86aabSstevel static int t_scale_den[8];
1813db86aabSstevel static uint8_t t_addr[8];
1823db86aabSstevel static uint8_t t_port[8];
1833db86aabSstevel static int sensor_types[] = { ENVCTRL_UE250_CPU0_SENSOR,
1843db86aabSstevel 			ENVCTRL_UE250_CPU1_SENSOR, ENVCTRL_UE250_MB0_SENSOR,
1853db86aabSstevel 			ENVCTRL_UE250_MB1_SENSOR, ENVCTRL_UE250_PDB_SENSOR,
1863db86aabSstevel 			ENVCTRL_UE250_SCSI_SENSOR };
1873db86aabSstevel 
1883db86aabSstevel static struct cb_ops envctrl_cb_ops = {
1893db86aabSstevel 	envctrl_open,		/* cb_open */
1903db86aabSstevel 	envctrl_close,		/* cb_close */
1913db86aabSstevel 	nodev,			/* cb_strategy */
1923db86aabSstevel 	nodev,			/* cb_print */
1933db86aabSstevel 	nodev,			/* cb_dump */
1943db86aabSstevel 	nodev,			/* cb_read */
1953db86aabSstevel 	nodev,			/* cb_write */
1963db86aabSstevel 	envctrl_ioctl,		/* cb_ioctl */
1973db86aabSstevel 	nodev,			/* cb_devmap */
1983db86aabSstevel 	nodev,			/* cb_mmap */
1993db86aabSstevel 	nodev,			/* cb_segmap */
2003db86aabSstevel 	nochpoll,		/* cb_chpoll */
2013db86aabSstevel 	ddi_prop_op,		/* cb_prop_op */
2023db86aabSstevel 	NULL,			/* cb_stream */
2033db86aabSstevel 	(int)(D_NEW | D_MP)	/* cb_flag */
2043db86aabSstevel };
2053db86aabSstevel 
2063db86aabSstevel /*
2073db86aabSstevel  * Declare ops vectors for auto configuration.
2083db86aabSstevel  */
2093db86aabSstevel struct dev_ops  envctrltwo_ops = {
2103db86aabSstevel 	DEVO_REV,		/* devo_rev */
2113db86aabSstevel 	0,			/* devo_refcnt */
2123db86aabSstevel 	envctrl_getinfo,	/* devo_getinfo */
2133db86aabSstevel 	nulldev,		/* devo_identify */
2143db86aabSstevel 	nulldev,		/* devo_probe */
2153db86aabSstevel 	envctrl_attach,		/* devo_attach */
2163db86aabSstevel 	envctrl_detach,		/* devo_detach */
2173db86aabSstevel 	nodev,			/* devo_reset */
2183db86aabSstevel 	&envctrl_cb_ops,	/* devo_cb_ops */
2193db86aabSstevel 	(struct bus_ops *)NULL,	/* devo_bus_ops */
220*19397407SSherry Moore 	nulldev,		/* devo_power */
221*19397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
2223db86aabSstevel };
2233db86aabSstevel 
2243db86aabSstevel extern struct mod_ops mod_driverops;
2253db86aabSstevel 
2263db86aabSstevel static struct modldrv envctrlmodldrv = {
2273db86aabSstevel 	&mod_driverops,		/* type of module - driver */
228*19397407SSherry Moore 	"I2C ENVCTRLTWO_driver",
2293db86aabSstevel 	&envctrltwo_ops,
2303db86aabSstevel };
2313db86aabSstevel 
2323db86aabSstevel static struct modlinkage envctrlmodlinkage = {
2333db86aabSstevel 	MODREV_1,
2343db86aabSstevel 	&envctrlmodldrv,
2353db86aabSstevel 	0
2363db86aabSstevel };
2373db86aabSstevel 
2383db86aabSstevel int
2393db86aabSstevel _init(void)
2403db86aabSstevel {
2413db86aabSstevel 	register int    error;
2423db86aabSstevel 
2433db86aabSstevel 	if ((error = mod_install(&envctrlmodlinkage)) == 0) {
2443db86aabSstevel 		(void) ddi_soft_state_init(&envctrlsoft_statep,
2453db86aabSstevel 		    sizeof (struct envctrlunit), 1);
2463db86aabSstevel 	}
2473db86aabSstevel 
2483db86aabSstevel 	return (error);
2493db86aabSstevel }
2503db86aabSstevel 
2513db86aabSstevel int
2523db86aabSstevel _fini(void)
2533db86aabSstevel {
2543db86aabSstevel 	register int    error;
2553db86aabSstevel 
2563db86aabSstevel 	if ((error = mod_remove(&envctrlmodlinkage)) == 0)
2573db86aabSstevel 		ddi_soft_state_fini(&envctrlsoft_statep);
2583db86aabSstevel 
2593db86aabSstevel 	return (error);
2603db86aabSstevel }
2613db86aabSstevel 
2623db86aabSstevel int
2633db86aabSstevel _info(struct modinfo *modinfop)
2643db86aabSstevel {
2653db86aabSstevel 	return (mod_info(&envctrlmodlinkage, modinfop));
2663db86aabSstevel }
2673db86aabSstevel 
2683db86aabSstevel static int
2693db86aabSstevel envctrl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2703db86aabSstevel {
2713db86aabSstevel 	register int	instance;
2723db86aabSstevel 	char		name[16];
2733db86aabSstevel 	uint8_t fspval;
2743db86aabSstevel 	register struct	envctrlunit *unitp;
2753db86aabSstevel 	struct ddi_device_acc_attr attr;
2763db86aabSstevel 	uchar_t *creg_prop;
2773db86aabSstevel 	uint_t len, tblsz;
2783db86aabSstevel 	int i, j, k, status;
2793db86aabSstevel 	uint8_t fanspeed;
2803db86aabSstevel 
2813db86aabSstevel 	status = len = tblsz = 0;
2823db86aabSstevel 
2833db86aabSstevel 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2843db86aabSstevel 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2853db86aabSstevel 
2863db86aabSstevel 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
2873db86aabSstevel 
2883db86aabSstevel 	instance = ddi_get_instance(dip);
2893db86aabSstevel 
2903db86aabSstevel 	switch (cmd) {
2913db86aabSstevel 	case DDI_ATTACH:
2923db86aabSstevel 		break;
2933db86aabSstevel 	case DDI_RESUME:
2943db86aabSstevel 		if (!(unitp = ddi_get_soft_state(envctrlsoft_statep, instance)))
2953db86aabSstevel 			return (DDI_FAILURE);
2963db86aabSstevel 		mutex_enter(&unitp->umutex);
2973db86aabSstevel 		if (!unitp->suspended) {
2983db86aabSstevel 			mutex_exit(&unitp->umutex);
2993db86aabSstevel 			return (DDI_FAILURE);
3003db86aabSstevel 		}
3013db86aabSstevel 		unitp->suspended = 0;
3023db86aabSstevel 		unitp->initting = B_TRUE;
3033db86aabSstevel 		envctrl_init_bus(unitp);
3043db86aabSstevel 		unitp->initting = B_FALSE;
3053db86aabSstevel 
3063db86aabSstevel 		envctrl_ps_probe(unitp);
3073db86aabSstevel 		envctrl_probe_cpus(unitp);
3083db86aabSstevel 		mutex_exit(&unitp->umutex);
3093db86aabSstevel 
3103db86aabSstevel 		return (DDI_SUCCESS);
3113db86aabSstevel 
3123db86aabSstevel 	default:
3133db86aabSstevel 		return (DDI_FAILURE);
3143db86aabSstevel 	}
3153db86aabSstevel 
3163db86aabSstevel 	/* Set up timer values */
3173db86aabSstevel 	overtemp_timeout_hz = drv_usectohz(ENVCTRL_UE250_OVERTEMP_TIMEOUT_USEC);
3183db86aabSstevel 	blink_timeout_hz = drv_usectohz(ENVCTRL_UE250_BLINK_TIMEOUT_USEC);
3193db86aabSstevel 	pshotplug_timeout_hz =
3203db86aabSstevel 	    drv_usectohz(ENVCTRL_UE250_BLINK_TIMEOUT_USEC * 2);
3213db86aabSstevel 	/*
3223db86aabSstevel 	 * On a cooling failure, either a fan failure or temperature
3233db86aabSstevel 	 * exceeding a WARNING level, the temperature poll thread
3243db86aabSstevel 	 * will run every 6 seconds.
3253db86aabSstevel 	 */
3263db86aabSstevel 	warning_timeout_hz =
3273db86aabSstevel 	    drv_usectohz(ENVCTRL_UE250_OVERTEMP_TIMEOUT_USEC / 6);
3283db86aabSstevel 
3293db86aabSstevel 	if (ddi_soft_state_zalloc(envctrlsoft_statep, instance) != 0) {
3303db86aabSstevel 		cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n",
3313db86aabSstevel 		    ddi_get_name(dip), instance);
3323db86aabSstevel 		goto failed;
3333db86aabSstevel 	}
3343db86aabSstevel 
3353db86aabSstevel 	unitp = ddi_get_soft_state(envctrlsoft_statep, instance);
3363db86aabSstevel 
3373db86aabSstevel 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&unitp->bus_ctl_regs, 0,
3383db86aabSstevel 	    sizeof (struct ehc_pcd8584_regs), &attr,
3393db86aabSstevel 	    &unitp->ctlr_handle) != DDI_SUCCESS) {
3403db86aabSstevel 		cmn_err(CE_WARN, "%s%d: failed to map in bus_control regs\n",
3413db86aabSstevel 		    ddi_get_name(dip), instance);
3423db86aabSstevel 		return (DDI_FAILURE);
3433db86aabSstevel 	}
3443db86aabSstevel 
3453db86aabSstevel 	/*
3463db86aabSstevel 	 * If the PCI nexus has added a thermal interrupt, we first need
3473db86aabSstevel 	 * to remove that interrupt handler.
3483db86aabSstevel 	 *
3493db86aabSstevel 	 * WARNING: Removing another driver's interrupt handler is not
3503db86aabSstevel 	 * allowed. The pci_thermal_rem_intr() call below is needed to retain
3513db86aabSstevel 	 * the legacy behavior on Javelin systems.
3523db86aabSstevel 	 */
3533db86aabSstevel 
3543db86aabSstevel 	pci_thermal_rem_intr(dip, (uint_t)0);
3553db86aabSstevel 
3563db86aabSstevel 	/* add interrupts */
3573db86aabSstevel 
3583db86aabSstevel 	if (ddi_get_iblock_cookie(dip, 1,
3593db86aabSstevel 	    &unitp->ic_trap_cookie) != DDI_SUCCESS)  {
3603db86aabSstevel 		cmn_err(CE_WARN, "%s%d: ddi_get_iblock_cookie FAILED \n",
3613db86aabSstevel 		    ddi_get_name(dip), instance);
3623db86aabSstevel 		goto failed;
3633db86aabSstevel 	}
3643db86aabSstevel 
3653db86aabSstevel 	mutex_init(&unitp->umutex, NULL, MUTEX_DRIVER,
3663db86aabSstevel 	    (void *)unitp->ic_trap_cookie);
3673db86aabSstevel 
3683db86aabSstevel 
3693db86aabSstevel 	if (ddi_add_intr(dip, 0, &unitp->ic_trap_cookie, NULL, envctrl_bus_isr,
3703db86aabSstevel 	    (caddr_t)unitp) != DDI_SUCCESS) {
3713db86aabSstevel 		cmn_err(CE_WARN, "%s%d: failed to add hard intr \n",
3723db86aabSstevel 		    ddi_get_name(dip), instance);
3733db86aabSstevel 		goto remlock;
3743db86aabSstevel 	}
3753db86aabSstevel 
3763db86aabSstevel 
3773db86aabSstevel 	if (ddi_add_intr(dip, 1, &unitp->ic_trap_cookie, NULL, envctrl_dev_isr,
3783db86aabSstevel 	    (caddr_t)unitp) != DDI_SUCCESS) {
3793db86aabSstevel 		cmn_err(CE_WARN, "%s%d: failed to add hard intr \n",
3803db86aabSstevel 		    ddi_get_name(dip), instance);
3813db86aabSstevel 		goto remhardintr;
3823db86aabSstevel 	}
3833db86aabSstevel 
3843db86aabSstevel 
3853db86aabSstevel 	(void) sprintf(name, "envctrltwo%d", instance);
3863db86aabSstevel 
3873db86aabSstevel 	if (ddi_create_priv_minor_node(dip, name, S_IFCHR, instance,
3883db86aabSstevel 	    DDI_PSEUDO, 0, PRIV_SYS_CONFIG, PRIV_SYS_CONFIG, 0666) ==
3893db86aabSstevel 	    DDI_FAILURE) {
3903db86aabSstevel 		goto remhardintr1;
3913db86aabSstevel 	}
3923db86aabSstevel 
3933db86aabSstevel 	mutex_enter(&unitp->umutex);
3943db86aabSstevel 
3953db86aabSstevel 	/*
3963db86aabSstevel 	 * Javelin will not have a workstation configuration so activity
3973db86aabSstevel 	 * LED will always blink.
3983db86aabSstevel 	 */
3993db86aabSstevel 	unitp->activity_led_blink = B_TRUE;
4003db86aabSstevel 	unitp->shutdown = B_FALSE;
4013db86aabSstevel 	unitp->num_ps_present = 0;
4023db86aabSstevel 	unitp->num_encl_present = 1;
4033db86aabSstevel 	unitp->current_mode = ENVCTRL_NORMAL_MODE;
4043db86aabSstevel 	if (envctrl_numcpus > 1) {
4053db86aabSstevel 		unitp->num_cpus_present = envctrl_numcpus;
4063db86aabSstevel 	}
4073db86aabSstevel 	envctrl_probe_cpus(unitp);
4083db86aabSstevel 	if ((unitp->cpu_pr_location[ENVCTRL_CPU0] == B_FALSE) ||
4093db86aabSstevel 	    (unitp->cpu_pr_location[ENVCTRL_CPU1] == B_FALSE))
4103db86aabSstevel 		/* Only one CPU in the system */
4113db86aabSstevel 		unitp->num_temps_present = 5;
4123db86aabSstevel 	else
4133db86aabSstevel 		unitp->num_temps_present = 6;
4143db86aabSstevel 	unitp->num_fans_present = 1;
4153db86aabSstevel 	unitp->dip = dip;
4163db86aabSstevel 
4173db86aabSstevel 	mutex_exit(&unitp->umutex);
4183db86aabSstevel 
4193db86aabSstevel 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4203db86aabSstevel 	    "cpu-temp-factors", &creg_prop, &len) != DDI_PROP_SUCCESS) {
4213db86aabSstevel 		cmn_err(CE_WARN,
4223db86aabSstevel 		    "%s%d: Unable to read cpu-temp-factors property",
4233db86aabSstevel 		    ddi_get_name(dip), instance);
4243db86aabSstevel 		return (DDI_NOT_WELL_FORMED);
4253db86aabSstevel 	}
4263db86aabSstevel 	tblsz = (sizeof (_cpu_temps) / sizeof (uchar_t));
4273db86aabSstevel 
4283db86aabSstevel 	if (len <= tblsz && status == DDI_PROP_SUCCESS) {
4293db86aabSstevel 		for (i = 0; i < len; i++) {
4303db86aabSstevel 			_cpu_temps[i+2] = creg_prop[i];
4313db86aabSstevel 		}
4323db86aabSstevel 	}
4333db86aabSstevel 	_cpu_temps[0] = _cpu_temps[1] = _cpu_temps[2];
4343db86aabSstevel 
4353db86aabSstevel 	ddi_prop_free((void *)creg_prop);
4363db86aabSstevel 
4373db86aabSstevel 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4383db86aabSstevel 	    "cpu-fan-speeds", &creg_prop, &len) != DDI_PROP_SUCCESS) {
4393db86aabSstevel 		cmn_err(CE_WARN,
4403db86aabSstevel 		    "%s%d: Unable to read cpu-fan-speeds property",
4413db86aabSstevel 		    ddi_get_name(dip), instance);
4423db86aabSstevel 		return (DDI_NOT_WELL_FORMED);
4433db86aabSstevel 	}
4443db86aabSstevel 	tblsz = (sizeof (_cpu_fan_speeds) / sizeof (uchar_t));
4453db86aabSstevel 
4463db86aabSstevel 	if (len <= tblsz && status == DDI_PROP_SUCCESS) {
4473db86aabSstevel 		for (i = 0; i < len; i++) {
4483db86aabSstevel 			_cpu_fan_speeds[i+2] = creg_prop[i];
4493db86aabSstevel 		}
4503db86aabSstevel 	}
4513db86aabSstevel 	_cpu_fan_speeds[0] = _cpu_fan_speeds[1] = _cpu_fan_speeds[2];
4523db86aabSstevel 
4533db86aabSstevel 	ddi_prop_free((void *)creg_prop);
4543db86aabSstevel 
4553db86aabSstevel 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4563db86aabSstevel 	    "thermisters", &creg_prop, &len) != DDI_PROP_SUCCESS) {
4573db86aabSstevel 		cmn_err(CE_WARN,
4583db86aabSstevel 		    "%s%d: Unable to read thermisters property",
4593db86aabSstevel 		    ddi_get_name(dip), instance);
4603db86aabSstevel 		return (DDI_NOT_WELL_FORMED);
4613db86aabSstevel 	}
4623db86aabSstevel 
4633db86aabSstevel 	mutex_enter(&unitp->umutex);
4643db86aabSstevel 
4653db86aabSstevel 	j = 0; k = 0;
4663db86aabSstevel 	for (i = 0; i < JAV_MAX_TEMP_SENSORS; i++) {
4673db86aabSstevel 		/* Type */
4683db86aabSstevel 		unitp->temp_kstats[k].type = sensor_types[i];
4693db86aabSstevel 		/* Address */
4703db86aabSstevel 		t_addr[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
4713db86aabSstevel 		    creg_prop[j+2] << 8 | creg_prop[j+3];
4723db86aabSstevel 		j += 4;
4733db86aabSstevel 		/* Port */
4743db86aabSstevel 		t_port[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
4753db86aabSstevel 		    creg_prop[j+2] << 8 | creg_prop[j+3];
4763db86aabSstevel 		j += 4;
4773db86aabSstevel 		/* Min */
4783db86aabSstevel 		unitp->temp_kstats[k].min =
4793db86aabSstevel 		    creg_prop[j] << 24 | creg_prop[j+1] << 16 |
4803db86aabSstevel 		    creg_prop[j+2] << 8 | creg_prop[j+3];
4813db86aabSstevel 		j += 4;
4823db86aabSstevel 		/* Warning threshold */
4833db86aabSstevel 		unitp->temp_kstats[k].warning_threshold =
4843db86aabSstevel 		    creg_prop[j] << 24 | creg_prop[j+1] << 16 |
4853db86aabSstevel 		    creg_prop[j+2] << 8 | creg_prop[j+3];
4863db86aabSstevel 		j += 4;
4873db86aabSstevel 		/* Shutdown threshold */
4883db86aabSstevel 		unitp->temp_kstats[k].shutdown_threshold =
4893db86aabSstevel 		    creg_prop[j] << 24 | creg_prop[j+1] << 16 |
4903db86aabSstevel 		    creg_prop[j+2] << 8 | creg_prop[j+3];
4913db86aabSstevel 		j += 4;
4923db86aabSstevel 		/* Numerator of scale factor */
4933db86aabSstevel 		t_scale_num[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
4943db86aabSstevel 		    creg_prop[j+2] << 8 | creg_prop[j+3];
4953db86aabSstevel 		j += 4;
4963db86aabSstevel 		/* Denominator of scale factor */
4973db86aabSstevel 		t_scale_den[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
4983db86aabSstevel 		    creg_prop[j+2] << 8 | creg_prop[j+3];
4993db86aabSstevel 		j += 4;
5003db86aabSstevel 		bcopy((caddr_t)&creg_prop[j], unitp->temp_kstats[k].label,
5013db86aabSstevel 		    (size_t)sizeof (&creg_prop[j]));
5023db86aabSstevel 		while (creg_prop[j] != '\0') j++;
5033db86aabSstevel 		j++;
5043db86aabSstevel 		if (t_addr[k] == ENVCTRL_UE250_CPU_TEMP_DEV) {
5053db86aabSstevel 			if (((t_port[k] == ENVCTRL_UE250_CPU0_PORT) &&
506*19397407SSherry Moore 			    (unitp->cpu_pr_location[ENVCTRL_CPU0] ==
507*19397407SSherry Moore 			    B_FALSE)) ||
5083db86aabSstevel 			    ((t_port[k] == ENVCTRL_UE250_CPU1_PORT) &&
5093db86aabSstevel 			    (unitp->cpu_pr_location[ENVCTRL_CPU1] == B_FALSE)))
5103db86aabSstevel 				/* Don't increment the kstat line count */
5113db86aabSstevel #ifdef lint
5123db86aabSstevel 				k = k;
5133db86aabSstevel #else
5143db86aabSstevel 				;
5153db86aabSstevel #endif
5163db86aabSstevel 			else
5173db86aabSstevel 				k++;
5183db86aabSstevel 		} else
5193db86aabSstevel 			k++;
5203db86aabSstevel 	}
5213db86aabSstevel 
5223db86aabSstevel 	ddi_prop_free((void *)creg_prop);
5233db86aabSstevel 
5243db86aabSstevel 	/* initialize the envctrl bus controller */
5253db86aabSstevel 
5263db86aabSstevel 	unitp->initting = B_TRUE;
5273db86aabSstevel 	envctrl_init_bus(unitp);
5283db86aabSstevel 	DPRINTF1("envctrl_attach(): Completed initialization of PCF8584");
5293db86aabSstevel 	unitp->initting = B_FALSE;
5303db86aabSstevel 	drv_usecwait(1000);
5313db86aabSstevel 
5323db86aabSstevel 	unitp->timeout_id = 0;
5333db86aabSstevel 	unitp->blink_timeout_id = 0;
5343db86aabSstevel 
5353db86aabSstevel 	unitp->fan_failed = 0;
5363db86aabSstevel 	unitp->fan_kstats.fans_ok = B_TRUE;
5373db86aabSstevel 	unitp->tempr_warning = 0;
5383db86aabSstevel 
5393db86aabSstevel 	envctrl_ps_probe(unitp);
5403db86aabSstevel 
5413db86aabSstevel 	unitp->initting = B_TRUE;
5423db86aabSstevel 	envctrl_fan_fail_service(unitp);
5433db86aabSstevel 	unitp->initting = B_FALSE;
5443db86aabSstevel 
5453db86aabSstevel 	/*
5463db86aabSstevel 	 * Fans could be blasting, turn them down.
5473db86aabSstevel 	 */
5483db86aabSstevel 	fanspeed = 0x0;
5493db86aabSstevel 	status = envctrl_write_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2, 0,
5503db86aabSstevel 	    &fanspeed, 1);
5513db86aabSstevel 	if (status == DDI_FAILURE)
5523db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Write to PCF8591 (SETFAN) failed\n",
5533db86aabSstevel 		    ddi_get_name(dip), instance);
5543db86aabSstevel 
5553db86aabSstevel 	/*
5563db86aabSstevel 	 * we need to init the fan kstats before the tempr_poll
5573db86aabSstevel 	 */
5583db86aabSstevel 	envctrl_add_kstats(unitp);
5593db86aabSstevel 	envctrl_init_encl_kstats(unitp);
5603db86aabSstevel 	envctrl_check_disk_kstats(unitp);
5613db86aabSstevel 
5623db86aabSstevel 	envctrl_update_fanspeed(unitp);
5633db86aabSstevel 	idle_fanspeed = unitp->fan_kstats.fanspeed;
5643db86aabSstevel 
5653db86aabSstevel 	if (unitp->activity_led_blink == B_TRUE) {
5663db86aabSstevel 		unitp->present_led_state = B_FALSE;
5673db86aabSstevel 		mutex_exit(&unitp->umutex);
5683db86aabSstevel 		envctrl_led_blink((void *)unitp);
5693db86aabSstevel 		mutex_enter(&unitp->umutex);
5703db86aabSstevel 	} else {
5713db86aabSstevel 		fspval = ENVCTRL_UE250_FSP_ACTIVE;
5723db86aabSstevel 		(void) envctrl_set_fsp(unitp, &fspval);
5733db86aabSstevel 	}
5743db86aabSstevel 
5753db86aabSstevel 	mutex_exit(&unitp->umutex);
5763db86aabSstevel 
5773db86aabSstevel 	envctrl_tempr_poll((void *)unitp);
5783db86aabSstevel 
5793db86aabSstevel 	/*
5803db86aabSstevel 	 * interpose envctrl's abort sequence handler
5813db86aabSstevel 	 */
5823db86aabSstevel 	if (envctrl_handler) {
5833db86aabSstevel 		abort_seq_handler = envctrl_abort_seq_handler;
5843db86aabSstevel 	}
5853db86aabSstevel 
5863db86aabSstevel 	ddi_report_dev(dip);
5873db86aabSstevel 
5883db86aabSstevel 	return (DDI_SUCCESS);
5893db86aabSstevel 
5903db86aabSstevel remhardintr1:
5913db86aabSstevel 	ddi_remove_intr(dip, (uint_t)1, unitp->ic_trap_cookie);
5923db86aabSstevel remhardintr:
5933db86aabSstevel 	ddi_remove_intr(dip, (uint_t)0, unitp->ic_trap_cookie);
5943db86aabSstevel 
5953db86aabSstevel remlock:
5963db86aabSstevel 	mutex_destroy(&unitp->umutex);
5973db86aabSstevel 
5983db86aabSstevel failed:
5993db86aabSstevel 	if (unitp->ctlr_handle)
6003db86aabSstevel 		ddi_regs_map_free(&unitp->ctlr_handle);
6013db86aabSstevel 
6023db86aabSstevel 	cmn_err(CE_WARN, "%s%d: attach failed\n", ddi_get_name(dip), instance);
6033db86aabSstevel 
6043db86aabSstevel 	return (DDI_FAILURE);
6053db86aabSstevel 
6063db86aabSstevel }
6073db86aabSstevel 
6083db86aabSstevel static int
6093db86aabSstevel envctrl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
6103db86aabSstevel {
6113db86aabSstevel 	int		instance;
6123db86aabSstevel 	register struct envctrlunit *unitp;
6133db86aabSstevel 
6143db86aabSstevel 	instance = ddi_get_instance(dip);
6153db86aabSstevel 	unitp = ddi_get_soft_state(envctrlsoft_statep, instance);
6163db86aabSstevel 
6173db86aabSstevel 	switch (cmd) {
6183db86aabSstevel 	case DDI_DETACH:
6193db86aabSstevel 		if (envctrl_allow_detach) {
6203db86aabSstevel 
6213db86aabSstevel 			if (unitp->psksp != NULL) {
6223db86aabSstevel 				kstat_delete(unitp->psksp);
6233db86aabSstevel 			}
6243db86aabSstevel 			if (unitp->fanksp != NULL) {
6253db86aabSstevel 				kstat_delete(unitp->fanksp);
6263db86aabSstevel 			}
6273db86aabSstevel 			if (unitp->enclksp != NULL) {
6283db86aabSstevel 				kstat_delete(unitp->enclksp);
6293db86aabSstevel 			}
6303db86aabSstevel 			if (unitp->tempksp != NULL) {
6313db86aabSstevel 				kstat_delete(unitp->tempksp);
6323db86aabSstevel 			}
6333db86aabSstevel 			if (unitp->diskksp != NULL) {
6343db86aabSstevel 				kstat_delete(unitp->diskksp);
6353db86aabSstevel 			}
6363db86aabSstevel 
6373db86aabSstevel 			if (unitp->timeout_id != 0) {
6383db86aabSstevel 				(void) untimeout(unitp->timeout_id);
6393db86aabSstevel 				unitp->timeout_id = 0;
6403db86aabSstevel 			}
6413db86aabSstevel 			if (unitp->blink_timeout_id != 0) {
6423db86aabSstevel 				(void) untimeout(unitp->blink_timeout_id);
6433db86aabSstevel 				unitp->blink_timeout_id = 0;
6443db86aabSstevel 			}
6453db86aabSstevel 
6463db86aabSstevel 			ddi_remove_minor_node(dip, NULL);
6473db86aabSstevel 
6483db86aabSstevel 			ddi_remove_intr(dip, (uint_t)0, unitp->ic_trap_cookie);
6493db86aabSstevel 			ddi_remove_intr(dip, (uint_t)1, unitp->ic_trap_cookie);
6503db86aabSstevel 
6513db86aabSstevel 			ddi_regs_map_free(&unitp->ctlr_handle);
6523db86aabSstevel 
6533db86aabSstevel 			mutex_destroy(&unitp->umutex);
6543db86aabSstevel 
6553db86aabSstevel 			return (DDI_SUCCESS);
6563db86aabSstevel 		} else {
6573db86aabSstevel 			return (DDI_FAILURE);
6583db86aabSstevel 		}
6593db86aabSstevel 
6603db86aabSstevel 	case DDI_SUSPEND:
6613db86aabSstevel 		if (!(unitp = ddi_get_soft_state(envctrlsoft_statep, instance)))
6623db86aabSstevel 			return (DDI_FAILURE);
6633db86aabSstevel 		mutex_enter(&unitp->umutex);
6643db86aabSstevel 		if (unitp->suspended) {
6653db86aabSstevel 			cmn_err(CE_WARN, "%s%d: envctrltwo already suspended\n",
6663db86aabSstevel 			    ddi_get_name(dip), instance);
6673db86aabSstevel 			mutex_exit(&unitp->umutex);
6683db86aabSstevel 			return (DDI_FAILURE);
6693db86aabSstevel 		}
6703db86aabSstevel 		unitp->suspended = 1;
6713db86aabSstevel 		mutex_exit(&unitp->umutex);
6723db86aabSstevel 		return (DDI_SUCCESS);
6733db86aabSstevel 
6743db86aabSstevel 	default:
6753db86aabSstevel 		cmn_err(CE_WARN, "%s%d: suspend general fault\n",
6763db86aabSstevel 		    ddi_get_name(dip), instance);
6773db86aabSstevel 		return (DDI_FAILURE);
6783db86aabSstevel 	}
6793db86aabSstevel 
6803db86aabSstevel 
6813db86aabSstevel }
6823db86aabSstevel int
6833db86aabSstevel envctrl_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
6843db86aabSstevel     void **result)
6853db86aabSstevel {
6863db86aabSstevel 	dev_t	dev = (dev_t)arg;
6873db86aabSstevel 	struct envctrlunit *unitp;
6883db86aabSstevel 	int	instance, ret;
6893db86aabSstevel 
6903db86aabSstevel 	instance = getminor(dev);
6913db86aabSstevel 
6923db86aabSstevel #ifdef lint
6933db86aabSstevel 	dip = dip;
6943db86aabSstevel #endif
6953db86aabSstevel 
6963db86aabSstevel 
6973db86aabSstevel 	switch (infocmd) {
6983db86aabSstevel 		case DDI_INFO_DEVT2DEVINFO:
6993db86aabSstevel 			if ((unitp = (struct envctrlunit *)
7003db86aabSstevel 			    ddi_get_soft_state(envctrlsoft_statep,
7013db86aabSstevel 			    instance)) != NULL) {
7023db86aabSstevel 				*result = unitp->dip;
7033db86aabSstevel 				ret = DDI_SUCCESS;
7043db86aabSstevel 			} else {
7053db86aabSstevel 				*result = NULL;
7063db86aabSstevel 				ret = DDI_FAILURE;
7073db86aabSstevel 			}
7083db86aabSstevel 			break;
7093db86aabSstevel 		case DDI_INFO_DEVT2INSTANCE:
7103db86aabSstevel 			*result = (void *)(uintptr_t)instance;
7113db86aabSstevel 			ret = DDI_SUCCESS;
7123db86aabSstevel 			break;
7133db86aabSstevel 		default:
7143db86aabSstevel 			ret = DDI_FAILURE;
7153db86aabSstevel 			break;
7163db86aabSstevel 	}
7173db86aabSstevel 
7183db86aabSstevel 	return (ret);
7193db86aabSstevel }
7203db86aabSstevel 
7213db86aabSstevel /* ARGSUSED1 */
7223db86aabSstevel static int
7233db86aabSstevel envctrl_open(dev_t *dev, int flag, int otyp, cred_t *cred_p)
7243db86aabSstevel {
7253db86aabSstevel 	struct envctrlunit *unitp;
7263db86aabSstevel 	int status = 0;
7273db86aabSstevel 	register int	instance;
7283db86aabSstevel 
7293db86aabSstevel 	instance = getminor(*dev);
7303db86aabSstevel 	if (instance < 0)
7313db86aabSstevel 		return (ENXIO);
7323db86aabSstevel 	unitp = (struct envctrlunit *)
7333db86aabSstevel 	    ddi_get_soft_state(envctrlsoft_statep, instance);
7343db86aabSstevel 
7353db86aabSstevel 	if (unitp == NULL)
7363db86aabSstevel 		return (ENXIO);
7373db86aabSstevel 
7383db86aabSstevel 	if (otyp != OTYP_CHR)
7393db86aabSstevel 		return (EINVAL);
7403db86aabSstevel 
7413db86aabSstevel 	mutex_enter(&unitp->umutex);
7423db86aabSstevel 
7433db86aabSstevel 	if (flag & FWRITE) {
7443db86aabSstevel 		if ((unitp->oflag & FWRITE)) {
7453db86aabSstevel 			mutex_exit(&unitp->umutex);
7463db86aabSstevel 			return (EBUSY);
7473db86aabSstevel 		} else {
7483db86aabSstevel 			unitp->oflag |= FWRITE;
7493db86aabSstevel 		}
7503db86aabSstevel 	}
7513db86aabSstevel 
7523db86aabSstevel 	mutex_exit(&unitp->umutex);
7533db86aabSstevel 	return (status);
7543db86aabSstevel }
7553db86aabSstevel 
7563db86aabSstevel /*ARGSUSED1*/
7573db86aabSstevel static int
7583db86aabSstevel envctrl_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
7593db86aabSstevel {
7603db86aabSstevel 	struct envctrlunit *unitp;
7613db86aabSstevel 	register int    instance;
7623db86aabSstevel 
7633db86aabSstevel 	instance = getminor(dev);
7643db86aabSstevel 	if (instance < 0)
7653db86aabSstevel 		return (ENXIO);
7663db86aabSstevel 	unitp = (struct envctrlunit *)
7673db86aabSstevel 	    ddi_get_soft_state(envctrlsoft_statep, instance);
7683db86aabSstevel 	if (unitp == NULL)
7693db86aabSstevel 		return (ENXIO);
7703db86aabSstevel 
7713db86aabSstevel 	mutex_enter(&unitp->umutex);
7723db86aabSstevel 
7733db86aabSstevel 	unitp->oflag = B_FALSE;
7743db86aabSstevel 	unitp->current_mode = ENVCTRL_NORMAL_MODE;
7753db86aabSstevel 
7763db86aabSstevel 	mutex_exit(&unitp->umutex);
7773db86aabSstevel 	return (DDI_SUCCESS);
7783db86aabSstevel }
7793db86aabSstevel 
7803db86aabSstevel 
7813db86aabSstevel /*
7823db86aabSstevel  * standard put procedure for envctrl
7833db86aabSstevel  */
7843db86aabSstevel static int
7853db86aabSstevel envctrl_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
7863db86aabSstevel 	int *rvalp)
7873db86aabSstevel {
7883db86aabSstevel 	struct envctrlunit *unitp;
7893db86aabSstevel 	register int	instance;
7903db86aabSstevel 	uint8_t wdval, tempr;
7913db86aabSstevel 	struct envctrl_chip fanspeed;
7923db86aabSstevel 	struct envctrl_chip ledchip, envcchip;
7933db86aabSstevel 	struct envctrl_chip temp, a_fanspeed;
7943db86aabSstevel 	int rval = 0, status, tfanspeed;
7953db86aabSstevel 
7963db86aabSstevel #ifdef lint
7973db86aabSstevel 	cred_p = cred_p;
7983db86aabSstevel 	rvalp = rvalp;
7993db86aabSstevel #endif
8003db86aabSstevel 	instance = getminor(dev);
8013db86aabSstevel 	unitp = (struct envctrlunit *)
8023db86aabSstevel 	    ddi_get_soft_state(envctrlsoft_statep, instance);
8033db86aabSstevel 
8043db86aabSstevel 	if ((cmd == ENVCTRL_IOC_SETFAN2) ||
8053db86aabSstevel 	    (cmd == ENVCTRL_IOC_GETFAN2) ||
8063db86aabSstevel 	    (cmd == ENVCTRL_IOC_SETMODE) ||
8073db86aabSstevel 	    (cmd == ENVCTRL_IOC_GETMODE) ||
8083db86aabSstevel 	    (cmd == ENVCTRL_IOC_GETTEMP2) ||
8093db86aabSstevel 	    (cmd == ENVCTRL_IOC_SETFSP2) ||
8103db86aabSstevel 	    (cmd == ENVCTRL_IOC_GETFSP2) ||
8113db86aabSstevel 	    (cmd == ENVCTRL_IOC_RESETTMPR) ||
8123db86aabSstevel 	    (cmd == ENVCTRL_IOC_SETDSKLED2) ||
8133db86aabSstevel 	    (cmd == ENVCTRL_IOC_GETDSKLED2))
8143db86aabSstevel 		if ((caddr_t)arg == NULL)
8153db86aabSstevel 			return (EFAULT);
8163db86aabSstevel 
8173db86aabSstevel 	switch (cmd) {
8183db86aabSstevel 	case ENVCTRL_IOC_SETMODE:
8193db86aabSstevel 		/* Set mode */
8203db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&wdval, sizeof (uint8_t),
8213db86aabSstevel 		    flag)) {
8223db86aabSstevel 			rval = EFAULT;
8233db86aabSstevel 			break;
8243db86aabSstevel 		}
8253db86aabSstevel 		if (wdval == ENVCTRL_DIAG_MODE ||
8263db86aabSstevel 		    wdval == ENVCTRL_NORMAL_MODE) {
8273db86aabSstevel 			mutex_enter(&unitp->umutex);
8283db86aabSstevel 			unitp->current_mode = wdval;
8293db86aabSstevel 			if (unitp->timeout_id != 0 &&
8303db86aabSstevel 			    wdval == ENVCTRL_DIAG_MODE) {
8313db86aabSstevel 				(void) untimeout(unitp->timeout_id);
8323db86aabSstevel 				unitp->timeout_id =
8333db86aabSstevel 				    (timeout(envctrl_tempr_poll,
8343db86aabSstevel 				    (caddr_t)unitp, overtemp_timeout_hz));
8353db86aabSstevel 			}
8363db86aabSstevel 			if (wdval == ENVCTRL_NORMAL_MODE) {
8373db86aabSstevel 				/*
8383db86aabSstevel 				 * Fans could be blasting, turn them down.
8393db86aabSstevel 				 */
8403db86aabSstevel 				tempr = 0x0;
8413db86aabSstevel 				status = envctrl_write_chip(unitp,
8423db86aabSstevel 				    ENVCTRL_PCF8591, EHC_DEV2, 0,
8433db86aabSstevel 				    &tempr, 1);
8443db86aabSstevel 				if (status == DDI_FAILURE)
8453db86aabSstevel 					cmn_err(CE_WARN,
846*19397407SSherry Moore 					    "%s%d: Write to PCF8591 "
847*19397407SSherry Moore 					    "(SETMODE) failed\n",
8483db86aabSstevel 					    driver_name, unitp->instance);
8493db86aabSstevel 
8503db86aabSstevel 				/*
8513db86aabSstevel 				 * This delay allows the fans to time to
8523db86aabSstevel 				 * change speed
8533db86aabSstevel 				 */
8543db86aabSstevel 				drv_usecwait(100000);
8553db86aabSstevel 				(void) envctrl_check_sys_temperatures(unitp);
8563db86aabSstevel 				unitp->current_mode = ENVCTRL_DIAG_MODE;
8573db86aabSstevel 				envctrl_fan_fail_service(unitp);
8583db86aabSstevel 				unitp->current_mode = ENVCTRL_NORMAL_MODE;
8593db86aabSstevel 			}
8603db86aabSstevel 			mutex_exit(&unitp->umutex);
8613db86aabSstevel 		} else {
8623db86aabSstevel 			rval = EINVAL;
8633db86aabSstevel 		}
8643db86aabSstevel 		break;
8653db86aabSstevel 	case ENVCTRL_IOC_GETMODE:
8663db86aabSstevel 		wdval = unitp->current_mode;
8673db86aabSstevel 		if (ddi_copyout((caddr_t)&wdval, (caddr_t)arg,
8683db86aabSstevel 		    sizeof (uint8_t), flag)) {
8693db86aabSstevel 			rval = EFAULT;
8703db86aabSstevel 		}
8713db86aabSstevel 		break;
8723db86aabSstevel 	case ENVCTRL_IOC_RESETTMPR:
8733db86aabSstevel 		/*
8743db86aabSstevel 		 * For diags, cancel the curent temp poll
8753db86aabSstevel 		 * and reset it for a new one.
8763db86aabSstevel 		 */
8773db86aabSstevel 		if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
8783db86aabSstevel 			if (unitp->timeout_id != 0) {
8793db86aabSstevel 				(void) untimeout(unitp->timeout_id);
8803db86aabSstevel 				unitp->timeout_id = 0;
8813db86aabSstevel 			}
8823db86aabSstevel 			envctrl_tempr_poll((void *)unitp);
8833db86aabSstevel 		} else {
8843db86aabSstevel 			rval = EINVAL;
8853db86aabSstevel 		}
8863db86aabSstevel 		break;
8873db86aabSstevel 	case ENVCTRL_IOC_GETTEMP2:
8883db86aabSstevel 		/* Get the user buffer address */
8893db86aabSstevel 
8903db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
8913db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
8923db86aabSstevel 			rval = EFAULT;
8933db86aabSstevel 			break;
8943db86aabSstevel 		}
8953db86aabSstevel 		if (((temp.chip_num != ENVCTRL_DEV2) &&
8963db86aabSstevel 		    (temp.chip_num != ENVCTRL_DEV7)) ||
8973db86aabSstevel 		    (temp.index > EHC_PCF8591_CH_3)) {
8983db86aabSstevel 			rval = EINVAL;
8993db86aabSstevel 			break;
9003db86aabSstevel 		}
9013db86aabSstevel 		mutex_enter(&unitp->umutex);
9023db86aabSstevel 		status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
9033db86aabSstevel 		    temp.chip_num, temp.index, &temp.val, 1);
9043db86aabSstevel 		mutex_exit(&unitp->umutex);
9053db86aabSstevel 		if (status == DDI_FAILURE) {
9063db86aabSstevel 			cmn_err(CE_WARN,
9073db86aabSstevel 			    "%s%d: Read from PCF8591 (IOC_GETTEMP) failed",
9083db86aabSstevel 			    driver_name, unitp->instance);
9093db86aabSstevel 			rval = EINVAL;
9103db86aabSstevel 			break;
9113db86aabSstevel 		}
9123db86aabSstevel 		if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
9133db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
9143db86aabSstevel 			rval = EFAULT;
9153db86aabSstevel 		}
9163db86aabSstevel 		break;
9173db86aabSstevel 	case ENVCTRL_IOC_SETTEMP:
9183db86aabSstevel 		rval = EINVAL;
9193db86aabSstevel 		break;
9203db86aabSstevel 	case ENVCTRL_IOC_SETWDT:
9213db86aabSstevel 		rval = EINVAL;
9223db86aabSstevel 		break;
9233db86aabSstevel 	case ENVCTRL_IOC_SETFAN2:
9243db86aabSstevel 		/* NOTE: need to sanity check values coming from userland */
9253db86aabSstevel 		if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
9263db86aabSstevel 			if (ddi_copyin((caddr_t)arg, (caddr_t)&fanspeed,
9273db86aabSstevel 				sizeof (struct envctrl_chip), flag)) {
9283db86aabSstevel 				rval = EFAULT;
9293db86aabSstevel 				break;
9303db86aabSstevel 			}
9313db86aabSstevel 			if ((fanspeed.type != ENVCTRL_PCF8591) ||
9323db86aabSstevel 			    (fanspeed.chip_num != ENVCTRL_DEV2) ||
9333db86aabSstevel 			    (fanspeed.index > EHC_PCF8591_CH_3)) {
9343db86aabSstevel 				rval = EINVAL;
9353db86aabSstevel 				break;
9363db86aabSstevel 			}
9373db86aabSstevel 			mutex_enter(&unitp->umutex);
9383db86aabSstevel 			status = envctrl_set_fanspeed(unitp, &fanspeed);
9393db86aabSstevel 			if (status == DDI_FAILURE) {
9403db86aabSstevel 				cmn_err(CE_WARN,
941*19397407SSherry Moore 				    "%s%d: Write to PCF8591 "
942*19397407SSherry Moore 				    "(IOC_SETFAN) failed",
9433db86aabSstevel 				    driver_name, unitp->instance);
9443db86aabSstevel 				rval = EINVAL;
9453db86aabSstevel 			}
9463db86aabSstevel 			mutex_exit(&unitp->umutex);
9473db86aabSstevel 		} else {
9483db86aabSstevel 			rval = EINVAL;
9493db86aabSstevel 		}
9503db86aabSstevel 		break;
9513db86aabSstevel 	case ENVCTRL_IOC_GETFAN2:
9523db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&a_fanspeed,
9533db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
9543db86aabSstevel 			rval = EFAULT;
9553db86aabSstevel 			break;
9563db86aabSstevel 		}
9573db86aabSstevel 		if ((a_fanspeed.type != ENVCTRL_PCF8591) ||
9583db86aabSstevel 		    (a_fanspeed.chip_num != ENVCTRL_DEV2) ||
9593db86aabSstevel 		    (a_fanspeed.index != EHC_PCF8591_CH_1)) {
9603db86aabSstevel 			rval = EINVAL;
9613db86aabSstevel 			break;
9623db86aabSstevel 		}
9633db86aabSstevel 		mutex_enter(&unitp->umutex);
9643db86aabSstevel 		status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
9653db86aabSstevel 		    a_fanspeed.chip_num, a_fanspeed.index,
9663db86aabSstevel 		    &a_fanspeed.val, 1);
9673db86aabSstevel 		mutex_exit(&unitp->umutex);
9683db86aabSstevel 		if (status == DDI_FAILURE) {
9693db86aabSstevel 			cmn_err(CE_WARN,
9703db86aabSstevel 			    "%s%d: Read of PCF8591 (IOC_GETFAN) failed",
9713db86aabSstevel 			    driver_name, unitp->instance);
9723db86aabSstevel 			rval = EINVAL;
9733db86aabSstevel 			break;
9743db86aabSstevel 		}
9753db86aabSstevel 		/*
9763db86aabSstevel 		 * Due to hardware limitation, the actual fan speed
9773db86aabSstevel 		 * is always a little less than what it was set to by
9783db86aabSstevel 		 * software. Hence, we scale up the read fan speed value
9793db86aabSstevel 		 * to more closely match the set value.
9803db86aabSstevel 		 */
9813db86aabSstevel 		if ((tfanspeed = ((int)a_fanspeed.val * JAV_FAN_SPEED_SF_NUM) /
9823db86aabSstevel 		    JAV_FAN_SPEED_SF_DEN) > 255)
9833db86aabSstevel 			a_fanspeed.val = 255;
9843db86aabSstevel 		else
9853db86aabSstevel 			a_fanspeed.val = tfanspeed & 0xFF;
9863db86aabSstevel 		unitp->fan_kstats.fanspeed = a_fanspeed.val;
9873db86aabSstevel 		if (ddi_copyout((caddr_t)&a_fanspeed, (caddr_t)arg,
9883db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
9893db86aabSstevel 			rval = EFAULT;
9903db86aabSstevel 		}
9913db86aabSstevel 		break;
9923db86aabSstevel 	case ENVCTRL_IOC_SETFSP2:
9933db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&envcchip,
9943db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
9953db86aabSstevel 			rval = EFAULT;
9963db86aabSstevel 			break;
9973db86aabSstevel 		}
9983db86aabSstevel 		if ((envcchip.type != ENVCTRL_PCF8574A) ||
9993db86aabSstevel 		    (envcchip.chip_num != ENVCTRL_DEV6)) {
10003db86aabSstevel 			rval = EINVAL;
10013db86aabSstevel 			break;
10023db86aabSstevel 		}
10033db86aabSstevel 		wdval = envcchip.val;
10043db86aabSstevel 		mutex_enter(&unitp->umutex);
10053db86aabSstevel 		/*
10063db86aabSstevel 		 * If a user is in normal mode and they try
10073db86aabSstevel 		 * to set anything other than a disk fault or
10083db86aabSstevel 		 * a gen fault it is an invalid operation.
10093db86aabSstevel 		 * in diag mode we allow everything to be
10103db86aabSstevel 		 * twiddled.
10113db86aabSstevel 		 */
10123db86aabSstevel 		if (unitp->current_mode == ENVCTRL_NORMAL_MODE) {
10133db86aabSstevel 			if (wdval & ~ENVCTRL_UE250_FSP_USRMASK) {
10143db86aabSstevel 				mutex_exit(&unitp->umutex);
10153db86aabSstevel 				rval = EINVAL;
10163db86aabSstevel 				break;
10173db86aabSstevel 			}
10183db86aabSstevel 		}
10193db86aabSstevel 		if (wdval & ENVCTRL_UE250_FSP_PS_ERR)
10203db86aabSstevel 			power_flt_led_lit = 1;
10213db86aabSstevel 		status = envctrl_set_fsp(unitp, &wdval);
10223db86aabSstevel 		mutex_exit(&unitp->umutex);
10233db86aabSstevel 		if (status == DDI_FAILURE) {
10243db86aabSstevel 			cmn_err(CE_WARN,
10253db86aabSstevel 			    "%s%d: Read of PCF8574A (IOC_SETFSP) failed",
10263db86aabSstevel 			    driver_name, unitp->instance);
10273db86aabSstevel 			rval = EINVAL;
10283db86aabSstevel 		}
10293db86aabSstevel 		break;
10303db86aabSstevel 	case ENVCTRL_IOC_GETFSP2:
10313db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&envcchip,
10323db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
10333db86aabSstevel 			rval = EFAULT;
10343db86aabSstevel 			break;
10353db86aabSstevel 		}
10363db86aabSstevel 		if ((envcchip.type != ENVCTRL_PCF8574A) ||
10373db86aabSstevel 		    (envcchip.chip_num != ENVCTRL_DEV6)) {
10383db86aabSstevel 			rval = EINVAL;
10393db86aabSstevel 			break;
10403db86aabSstevel 		}
10413db86aabSstevel 		mutex_enter(&unitp->umutex);
10423db86aabSstevel 		status = envctrl_get_fpm_status(unitp, &wdval);
10433db86aabSstevel 		mutex_exit(&unitp->umutex);
10443db86aabSstevel 		if (status == DDI_FAILURE) {
10453db86aabSstevel 			cmn_err(CE_WARN,
10463db86aabSstevel 			    "%s%d: Read of PCF8574A (IOC_GETFSP) failed",
10473db86aabSstevel 			    driver_name, unitp->instance);
10483db86aabSstevel 			rval = EINVAL;
10493db86aabSstevel 		} else {
10503db86aabSstevel 			envcchip.val = wdval;
10513db86aabSstevel 			if (ddi_copyout((caddr_t)&envcchip, (caddr_t)arg,
10523db86aabSstevel 				sizeof (struct envctrl_chip), flag)) {
10533db86aabSstevel 				rval = EFAULT;
10543db86aabSstevel 			}
10553db86aabSstevel 		}
10563db86aabSstevel 		break;
10573db86aabSstevel 	case ENVCTRL_IOC_SETDSKLED2:
10583db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ledchip,
10593db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
10603db86aabSstevel 			rval = EFAULT;
10613db86aabSstevel 			break;
10623db86aabSstevel 		}
10633db86aabSstevel 		if ((ledchip.type != ENVCTRL_PCF8574A) ||
10643db86aabSstevel 		    (ledchip.chip_num != ENVCTRL_DEV7)) {
10653db86aabSstevel 			rval = EINVAL;
10663db86aabSstevel 			break;
10673db86aabSstevel 		}
10683db86aabSstevel 		mutex_enter(&unitp->umutex);
10693db86aabSstevel 		if (envctrl_set_dskled(unitp, &ledchip)) {
10703db86aabSstevel 			rval = EINVAL;
10713db86aabSstevel 		}
10723db86aabSstevel 		mutex_exit(&unitp->umutex);
10733db86aabSstevel 		break;
10743db86aabSstevel 	case ENVCTRL_IOC_GETDSKLED2:
10753db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ledchip,
10763db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
10773db86aabSstevel 			rval = EFAULT;
10783db86aabSstevel 			break;
10793db86aabSstevel 		}
10803db86aabSstevel 		if ((ledchip.type != ENVCTRL_PCF8574A) ||
10813db86aabSstevel 		    (ledchip.chip_num != ENVCTRL_DEV7)) {
10823db86aabSstevel 			rval = EINVAL;
10833db86aabSstevel 			break;
10843db86aabSstevel 		}
10853db86aabSstevel 		mutex_enter(&unitp->umutex);
10863db86aabSstevel 		if (envctrl_get_dskled(unitp, &ledchip)) {
10873db86aabSstevel 			rval = EINVAL;
10883db86aabSstevel 		} else {
10893db86aabSstevel 			if (ddi_copyout((caddr_t)&ledchip, (caddr_t)arg,
10903db86aabSstevel 				sizeof (struct envctrl_chip), flag)) {
10913db86aabSstevel 				rval = EFAULT;
10923db86aabSstevel 			}
10933db86aabSstevel 		}
10943db86aabSstevel 		mutex_exit(&unitp->umutex);
10953db86aabSstevel 		break;
10963db86aabSstevel 	case ENVCTRL_IOC_SETRAW:
10973db86aabSstevel 		if (unitp->current_mode != ENVCTRL_DIAG_MODE) {
10983db86aabSstevel 			rval = EINVAL;
10993db86aabSstevel 			break;
11003db86aabSstevel 		}
11013db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
11023db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
11033db86aabSstevel 			rval = EFAULT;
11043db86aabSstevel 			break;
11053db86aabSstevel 		}
11063db86aabSstevel 		mutex_enter(&unitp->umutex);
11073db86aabSstevel 		status = envctrl_write_chip(unitp, temp.type, temp.chip_num,
11083db86aabSstevel 		    temp.index, &temp.val, 1);
11093db86aabSstevel 		if (status == DDI_FAILURE) {
11103db86aabSstevel 			cmn_err(CE_WARN,
11113db86aabSstevel 			    "%s%d: Write to chip (IOC_SETRAW) failed",
11123db86aabSstevel 			    driver_name, unitp->instance);
11133db86aabSstevel 			rval = EINVAL;
11143db86aabSstevel 		}
11153db86aabSstevel 		mutex_exit(&unitp->umutex);
11163db86aabSstevel 		break;
11173db86aabSstevel 	case ENVCTRL_IOC_GETRAW:
11183db86aabSstevel 		if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
11193db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
11203db86aabSstevel 			rval = EFAULT;
11213db86aabSstevel 			break;
11223db86aabSstevel 		}
11233db86aabSstevel 		mutex_enter(&unitp->umutex);
11243db86aabSstevel 		status = envctrl_read_chip(unitp, temp.type, temp.chip_num,
11253db86aabSstevel 		    temp.index, &temp.val, 1);
11263db86aabSstevel 		if (status == DDI_FAILURE) {
11273db86aabSstevel 			cmn_err(CE_WARN,
11283db86aabSstevel 			    "%s%d: Read of chip (IOC_GETRAW) failed",
11293db86aabSstevel 			    driver_name, unitp->instance);
11303db86aabSstevel 			rval = EINVAL;
11313db86aabSstevel 		}
11323db86aabSstevel 		mutex_exit(&unitp->umutex);
11333db86aabSstevel 		if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
11343db86aabSstevel 			sizeof (struct envctrl_chip), flag)) {
11353db86aabSstevel 			rval = EFAULT;
11363db86aabSstevel 		}
11373db86aabSstevel 		break;
11383db86aabSstevel 	default:
11393db86aabSstevel 		rval = EINVAL;
11403db86aabSstevel 	}
11413db86aabSstevel 
11423db86aabSstevel 	return (rval);
11433db86aabSstevel }
11443db86aabSstevel 
11453db86aabSstevel uint_t
11463db86aabSstevel envctrl_bus_isr(caddr_t arg)
11473db86aabSstevel {
11483db86aabSstevel 	struct envctrlunit *unitp = (struct envctrlunit *)(void *)arg;
11493db86aabSstevel 	int ic = DDI_INTR_UNCLAIMED;
11503db86aabSstevel 
11513db86aabSstevel 	mutex_enter(&unitp->umutex);
11523db86aabSstevel 
11533db86aabSstevel 	/*
11543db86aabSstevel 	 * NOT USED
11553db86aabSstevel 	 */
11563db86aabSstevel 
11573db86aabSstevel 	mutex_exit(&unitp->umutex);
11583db86aabSstevel 	return (ic);
11593db86aabSstevel }
11603db86aabSstevel 
11613db86aabSstevel uint_t
11623db86aabSstevel envctrl_dev_isr(caddr_t arg)
11633db86aabSstevel {
11643db86aabSstevel 	struct envctrlunit *unitp = (struct envctrlunit *)(void *)arg;
11653db86aabSstevel 	uint8_t recv_data;
11663db86aabSstevel 	int ic;
11673db86aabSstevel 	int retrys = 0;
11683db86aabSstevel 	int status;
11693db86aabSstevel 	static int spurious_intr_count = 0;
11703db86aabSstevel 
11713db86aabSstevel 	ic = DDI_INTR_UNCLAIMED;
11723db86aabSstevel 
11733db86aabSstevel 	mutex_enter(&unitp->umutex);
11743db86aabSstevel 
11753db86aabSstevel 
11763db86aabSstevel 	/*
11773db86aabSstevel 	 * First check to see if it is an interrupt for us by
11783db86aabSstevel 	 * looking at the "ganged" interrupt and vector
11793db86aabSstevel 	 * according to the major type
11803db86aabSstevel 	 * 0x70 is the addr of the ganged interrupt controller.
11813db86aabSstevel 	 * Address map for the port byte read is as follows
11823db86aabSstevel 	 * MSB
11833db86aabSstevel 	 * -------------------------
11843db86aabSstevel 	 * |  |  |  |  |  |  |  |  |
11853db86aabSstevel 	 * -------------------------
11863db86aabSstevel 	 *  P7 P6 P5 P4 P3 P2 P1 P0
11873db86aabSstevel 	 * P0 = Spare
11883db86aabSstevel 	 * P1 = Thermal Interrupt
11893db86aabSstevel 	 * P2 = Disk Interrupt
11903db86aabSstevel 	 * P3 = Interrupt clock enable
11913db86aabSstevel 	 * P4 = Fan Fail Interrupt
11923db86aabSstevel 	 * P5 =	Front Panel Interrupt
11933db86aabSstevel 	 * P6 = Power Supply Interrupt
11943db86aabSstevel 	 * P7 = Enable Interrupts
11953db86aabSstevel 	 */
11963db86aabSstevel 
11973db86aabSstevel 	do {
11983db86aabSstevel 		status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
11993db86aabSstevel 		    ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
12003db86aabSstevel 		    &recv_data, 1);
12013db86aabSstevel 
12023db86aabSstevel 		/*
12033db86aabSstevel 		 * This extra read is needed since the first read is discarded
12043db86aabSstevel 		 * and the second read seems to return 0xFF.
12053db86aabSstevel 		 */
12063db86aabSstevel 		if (recv_data == 0xFF) {
12073db86aabSstevel 			status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
12083db86aabSstevel 			    ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
12093db86aabSstevel 			    &recv_data, 1);
12103db86aabSstevel 		}
12113db86aabSstevel 
12123db86aabSstevel 		/*
12133db86aabSstevel 		 * if the i2c bus is hung it is imperative that this
12143db86aabSstevel 		 * be cleared on an interrupt or else it will
12153db86aabSstevel 		 * hang the system with continuous interrupts
12163db86aabSstevel 		 */
12173db86aabSstevel 
12183db86aabSstevel 		if (status == DDI_FAILURE) {
12193db86aabSstevel 			drv_usecwait(1000);
12203db86aabSstevel 			if (retrys < envctrl_max_retries) {
12213db86aabSstevel 				retrys++;
12223db86aabSstevel 			} else {
12233db86aabSstevel 				cmn_err(CE_WARN,
12243db86aabSstevel 				    "%s%d: Read of PCF8574A (INT) failed\n",
12253db86aabSstevel 				    driver_name, unitp->instance);
12263db86aabSstevel 				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
12273db86aabSstevel 				mutex_exit(&unitp->umutex);
12283db86aabSstevel 				ic = DDI_INTR_CLAIMED;
12293db86aabSstevel 				return (ic);
12303db86aabSstevel 			}
12313db86aabSstevel 		}
12323db86aabSstevel 	} while (status != DDI_SUCCESS);
12333db86aabSstevel 
12343db86aabSstevel 	DPRINTF1("Interrupt routine called, interrupt = %X\n", recv_data);
12353db86aabSstevel 	if (!(recv_data & EHC_PCF8574_PORT0)) {
12363db86aabSstevel 		ic = DDI_INTR_CLAIMED;
12373db86aabSstevel 	}
12383db86aabSstevel 
12393db86aabSstevel 	if (!(recv_data & EHC_PCF8574_PORT1)) {
12403db86aabSstevel 		DPRINTF1("Temperature interrupt detected\n");
12413db86aabSstevel 		(void) envctrl_check_sys_temperatures(unitp);
12423db86aabSstevel 
12433db86aabSstevel 		/*
12443db86aabSstevel 		 * Clear the interrupt latches
12453db86aabSstevel 		 */
12463db86aabSstevel 		envctrl_intr_latch_clr(unitp);
12473db86aabSstevel 
12483db86aabSstevel 		ic = DDI_INTR_CLAIMED;
12493db86aabSstevel 	}
12503db86aabSstevel 
12513db86aabSstevel 	if (!(recv_data & EHC_PCF8574_PORT2)) {
12523db86aabSstevel 		DPRINTF1("Disk interrupt detected\n");
12533db86aabSstevel 		envctrl_check_disk_kstats(unitp);
12543db86aabSstevel 		ic = DDI_INTR_CLAIMED;
12553db86aabSstevel 	}
12563db86aabSstevel 
12573db86aabSstevel 	if (!(recv_data & EHC_PCF8574_PORT3)) {
12583db86aabSstevel 		ic = DDI_INTR_CLAIMED;
12593db86aabSstevel 	}
12603db86aabSstevel 
12613db86aabSstevel 	if (!(recv_data & EHC_PCF8574_PORT4)) {
12623db86aabSstevel 		/*
12633db86aabSstevel 		 * Check for a fan fail
12643db86aabSstevel 		 */
12653db86aabSstevel 		DPRINTF1("Fan interrupt detected\n");
12663db86aabSstevel 		envctrl_fan_fail_service(unitp);
12673db86aabSstevel 
12683db86aabSstevel 		/*
12693db86aabSstevel 		 * Clear the interrupt latches
12703db86aabSstevel 		 */
12713db86aabSstevel 		envctrl_intr_latch_clr(unitp);
12723db86aabSstevel 
12733db86aabSstevel 		ic = DDI_INTR_CLAIMED;
12743db86aabSstevel 	}
12753db86aabSstevel 
12763db86aabSstevel 	if (!(recv_data & EHC_PCF8574_PORT5)) {
12773db86aabSstevel 		DPRINTF1("Keyswitch interrupt detected\n");
12783db86aabSstevel 		(void) envctrl_get_fpm_status(unitp, (uint8_t *)NULL);
12793db86aabSstevel 		ic = DDI_INTR_CLAIMED;
12803db86aabSstevel 	}
12813db86aabSstevel 
12823db86aabSstevel 	if (!(recv_data & EHC_PCF8574_PORT6)) {
12833db86aabSstevel 		DPRINTF1("Power supply interrupt detected\n");
12843db86aabSstevel 		envctrl_PS_intr_service(unitp);
12853db86aabSstevel 		ic = DDI_INTR_CLAIMED;
12863db86aabSstevel 	}
12873db86aabSstevel 
12883db86aabSstevel 	if (!(recv_data & EHC_PCF8574_PORT7)) {
12893db86aabSstevel 		ic = DDI_INTR_CLAIMED;
12903db86aabSstevel 	}
12913db86aabSstevel 
12923db86aabSstevel 	/*
12933db86aabSstevel 	 * The interrupt routine got called but the interrupt chip
12943db86aabSstevel 	 * shows no interrupt present. If this happens more than 256
12953db86aabSstevel 	 * times in a row, there is probably some hardware problem so
12963db86aabSstevel 	 * send a warning message to the console.
12973db86aabSstevel 	 */
12983db86aabSstevel 	if ((recv_data == 0xFF)) {
12993db86aabSstevel 		if (spurious_intr_count == 255)
13003db86aabSstevel 			cmn_err(CE_WARN,
13013db86aabSstevel 			    "%s%d: Received 256 spurious interrupts\n",
13023db86aabSstevel 			    driver_name, unitp->instance);
13033db86aabSstevel 		spurious_intr_count++;
13043db86aabSstevel 		ic = DDI_INTR_CLAIMED;
13053db86aabSstevel 	} else
13063db86aabSstevel 		spurious_intr_count = 0;
13073db86aabSstevel 
13083db86aabSstevel 	mutex_exit(&unitp->umutex);
13093db86aabSstevel 	return (ic);
13103db86aabSstevel 
13113db86aabSstevel }
13123db86aabSstevel 
13133db86aabSstevel 
13143db86aabSstevel static int
13153db86aabSstevel envctrl_read_chip(struct envctrlunit *unitp, int type, int chip_num, int port,
13163db86aabSstevel 	uint8_t *data, int num)
13173db86aabSstevel {
13183db86aabSstevel 	int retrys = 0, autoincr = 0;
13193db86aabSstevel 	int status;
13203db86aabSstevel 
13213db86aabSstevel 	/*
13223db86aabSstevel 	 * If more than one read is requested, set auto-increment bit
13233db86aabSstevel 	 */
13243db86aabSstevel 	if (num > 1)
13253db86aabSstevel 		autoincr = 1;
13263db86aabSstevel 
13273db86aabSstevel 	do {
13283db86aabSstevel 		if (type == ENVCTRL_PCF8574A) {
13293db86aabSstevel 			status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
13303db86aabSstevel 			    ENVCTRL_UE250_PCF8574A_BASE_ADDR | chip_num,
13313db86aabSstevel 			    data, num);
13323db86aabSstevel 		} else if (type == ENVCTRL_PCF8574) {
13333db86aabSstevel 			status = ehc_read_pcf8574((struct ehc_envcunit *)unitp,
13343db86aabSstevel 			    ENVCTRL_UE250_PCF8574_BASE_ADDR | chip_num,
13353db86aabSstevel 			    data, num);
13363db86aabSstevel 		} else if (type == ENVCTRL_PCF8591) {
13373db86aabSstevel 			status = ehc_read_pcf8591((struct ehc_envcunit *)unitp,
13383db86aabSstevel 			    ENVCTRL_UE250_PCF8591_BASE_ADDR | chip_num,
13393db86aabSstevel 			    port, autoincr, 0, 1, data, num);
13403db86aabSstevel 		}
13413db86aabSstevel 		/*
13423db86aabSstevel 		 * If the bus hangs, attempt a recovery
13433db86aabSstevel 		 */
13443db86aabSstevel 		if (status == DDI_FAILURE) {
13453db86aabSstevel 			drv_usecwait(1000);
13463db86aabSstevel 			if (retrys < envctrl_max_retries) {
13473db86aabSstevel 				retrys++;
13483db86aabSstevel 			} else {
13493db86aabSstevel 				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
13503db86aabSstevel 				break;
13513db86aabSstevel 			}
13523db86aabSstevel 		}
13533db86aabSstevel 	} while (status != DDI_SUCCESS);
13543db86aabSstevel 
13553db86aabSstevel 	return (status);
13563db86aabSstevel }
13573db86aabSstevel 
13583db86aabSstevel static int
13593db86aabSstevel envctrl_write_chip(struct envctrlunit *unitp, int type, int chip_num, int port,
13603db86aabSstevel 	uint8_t *data, int num)
13613db86aabSstevel {
13623db86aabSstevel 	int retrys = 0, autoincr = 0;
13633db86aabSstevel 	int status;
13643db86aabSstevel 
13653db86aabSstevel 	/*
13663db86aabSstevel 	 * Incase some applications mistakenly include the chips base addr
13673db86aabSstevel 	 */
13683db86aabSstevel 	chip_num = chip_num & 0xF;
13693db86aabSstevel 
13703db86aabSstevel 	/*
13713db86aabSstevel 	 * If more than one write is requested, set auto-increment bit
13723db86aabSstevel 	 */
13733db86aabSstevel 	if (num > 1)
13743db86aabSstevel 		autoincr = 1;
13753db86aabSstevel 
13763db86aabSstevel 	do {
13773db86aabSstevel 		if (type == ENVCTRL_PCF8574A) {
13783db86aabSstevel 			status = ehc_write_pcf8574a(
13793db86aabSstevel 			    (struct ehc_envcunit *)unitp,
13803db86aabSstevel 			    ENVCTRL_UE250_PCF8574A_BASE_ADDR | chip_num,
13813db86aabSstevel 			    data, num);
13823db86aabSstevel 		} else if (type == ENVCTRL_PCF8574) {
13833db86aabSstevel 			status = ehc_write_pcf8574((struct ehc_envcunit *)unitp,
13843db86aabSstevel 			    ENVCTRL_UE250_PCF8574_BASE_ADDR | chip_num,
13853db86aabSstevel 			    data, num);
13863db86aabSstevel 		} else if (type == ENVCTRL_PCF8591) {
13873db86aabSstevel 			status = ehc_write_pcf8591((struct ehc_envcunit *)unitp,
13883db86aabSstevel 			    ENVCTRL_UE250_PCF8591_BASE_ADDR | chip_num,
13893db86aabSstevel 			    port, autoincr, 0, 1, data, num);
13903db86aabSstevel 		}
13913db86aabSstevel 
13923db86aabSstevel 		/*
13933db86aabSstevel 		 * If the bus hangs, attempt a recovery
13943db86aabSstevel 		 */
13953db86aabSstevel 		if (status == DDI_FAILURE) {
13963db86aabSstevel 			drv_usecwait(1000);
13973db86aabSstevel 			if (retrys < envctrl_max_retries) {
13983db86aabSstevel 				retrys++;
13993db86aabSstevel 			} else {
14003db86aabSstevel 				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
14013db86aabSstevel 				break;
14023db86aabSstevel 			}
14033db86aabSstevel 		}
14043db86aabSstevel 	} while (status != DDI_SUCCESS);
14053db86aabSstevel 
14063db86aabSstevel 	return (status);
14073db86aabSstevel }
14083db86aabSstevel 
14093db86aabSstevel #ifdef GET_CPU_TEMP
14103db86aabSstevel static int
14113db86aabSstevel envctrl_get_cpu_temp(struct envctrlunit *unitp, int cpunum)
14123db86aabSstevel {
14133db86aabSstevel 	uint8_t recv_data;
14143db86aabSstevel 	int status;
14153db86aabSstevel 
14163db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
14173db86aabSstevel 
14183db86aabSstevel 	/*
14193db86aabSstevel 	 * This routine takes in the number of the port that
14203db86aabSstevel 	 * we want to read in the 8591. This should be the
14213db86aabSstevel 	 * location of the CPU thermistor for one of the 2
14223db86aabSstevel 	 * cpu's. It will return a normalized value
14233db86aabSstevel 	 * to the caller.
14243db86aabSstevel 	 */
14253db86aabSstevel 
14263db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV7, cpunum,
14273db86aabSstevel 	    &recv_data, 1);
14283db86aabSstevel 	if (status == DDI_FAILURE) {
14293db86aabSstevel 		cmn_err(CE_WARN, "%s%d: CPU TEMP read failed\n",
14303db86aabSstevel 		    driver_name, unitp->instance);
14313db86aabSstevel 		return (ENVCTRL_UE250_MAX_CPU_TEMP - 10);
14323db86aabSstevel 	}
14333db86aabSstevel 
14343db86aabSstevel 	return (_cpu_temps[recv_data]);
14353db86aabSstevel }
14363db86aabSstevel #endif
14373db86aabSstevel 
14383db86aabSstevel static void
14393db86aabSstevel envctrl_tempr_poll(void *arg)
14403db86aabSstevel {
14413db86aabSstevel 	int diag_flag = 0, status;
14423db86aabSstevel 	struct envctrlunit *unitp = (struct envctrlunit *)arg;
14433db86aabSstevel 
14443db86aabSstevel 	mutex_enter(&unitp->umutex);
14453db86aabSstevel 
14463db86aabSstevel 	if (unitp->shutdown == B_TRUE) {
14473db86aabSstevel 		(void) power_down("Fatal System Environmental Control Error");
14483db86aabSstevel 	}
14493db86aabSstevel 
14503db86aabSstevel 	/*
14513db86aabSstevel 	 * Clear the interrupt latches
14523db86aabSstevel 	 */
14533db86aabSstevel 	envctrl_intr_latch_clr(unitp);
14543db86aabSstevel 
14553db86aabSstevel 	envctrl_reset_dflop(unitp);
14563db86aabSstevel 	envctrl_enable_devintrs(unitp);
14573db86aabSstevel 	/*
14583db86aabSstevel 	 * if we are in diag mode and the temp poll thread goes off,
14593db86aabSstevel 	 * this means that the system is too heavily loaded and the 60 second
14603db86aabSstevel 	 * window to execute the test is failing.
14613db86aabSstevel 	 */
14623db86aabSstevel 	if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
14633db86aabSstevel 		diag_flag++;
14643db86aabSstevel 		if (envctrl_debug_flags) {
14653db86aabSstevel 			cmn_err(CE_WARN, "%s%d: "
14663db86aabSstevel 			    "Tempr poll went off while in DIAG MODE\n",
14673db86aabSstevel 			    driver_name, unitp->instance);
14683db86aabSstevel 		}
14693db86aabSstevel 	}
14703db86aabSstevel 	unitp->current_mode = ENVCTRL_NORMAL_MODE;
14713db86aabSstevel 	DPRINTF1("envctrl_tempr_poll(): Checking system temps\n");
14723db86aabSstevel 	status = envctrl_check_sys_temperatures(unitp);
14733db86aabSstevel 	if (status == DDI_FAILURE) {
14743db86aabSstevel 		cmn_err(CE_WARN,
14753db86aabSstevel 		    "%s%d: Failure detected during temperature poll",
14763db86aabSstevel 		    driver_name, unitp->instance);
14773db86aabSstevel 	}
14783db86aabSstevel 
14793db86aabSstevel 	if (diag_flag == 0) {
14803db86aabSstevel 		envctrl_fan_fail_service(unitp);
14813db86aabSstevel 	}
14823db86aabSstevel 
14833db86aabSstevel 	/* Turn of the power fault LED if ps_ok is asserted */
14843db86aabSstevel 	envctrl_ps_probe(unitp);
14853db86aabSstevel 
14863db86aabSstevel 	/* now have this thread sleep for a while */
14873db86aabSstevel 	if ((unitp->fan_failed == B_TRUE) || (unitp->tempr_warning == B_TRUE)) {
14883db86aabSstevel 		/*
14893db86aabSstevel 		 * A thermal warning or fan failure condition exists.
14903db86aabSstevel 		 * Temperature poll thread will run every 10 seconds.
14913db86aabSstevel 		 */
14923db86aabSstevel 		if (unitp->timeout_id != 0)
14933db86aabSstevel 			(void) untimeout(unitp->timeout_id);
14943db86aabSstevel 		unitp->timeout_id = (timeout(envctrl_tempr_poll,
14953db86aabSstevel 		    (caddr_t)unitp, warning_timeout_hz));
14963db86aabSstevel 	} else {
14973db86aabSstevel 		/*
14983db86aabSstevel 		 * No thermal warning or fan failure condition exists.
14993db86aabSstevel 		 * This thread is set to run every 60 seconds.
15003db86aabSstevel 		 */
15013db86aabSstevel 		unitp->timeout_id = (timeout(envctrl_tempr_poll,
15023db86aabSstevel 		    (caddr_t)unitp, overtemp_timeout_hz));
15033db86aabSstevel 	}
15043db86aabSstevel 
15053db86aabSstevel 	mutex_exit(&unitp->umutex);
15063db86aabSstevel }
15073db86aabSstevel 
15083db86aabSstevel static void
15093db86aabSstevel envctrl_led_blink(void *arg)
15103db86aabSstevel {
15113db86aabSstevel 	uint8_t val, tmpval;
15123db86aabSstevel 	int status;
15133db86aabSstevel 	struct envctrlunit *unitp = (struct envctrlunit *)arg;
15143db86aabSstevel 
15153db86aabSstevel 	mutex_enter(&unitp->umutex);
15163db86aabSstevel 
15173db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
15183db86aabSstevel 	    0, &val, 1);
15193db86aabSstevel 	if (status == DDI_FAILURE) {
15203db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Failed to read FSP LEDs",
15213db86aabSstevel 		    driver_name, unitp->instance);
15223db86aabSstevel 		/* now have this thread sleep for a while */
15233db86aabSstevel 		unitp->blink_timeout_id = (timeout(envctrl_led_blink,
15243db86aabSstevel 		    (caddr_t)unitp, blink_timeout_hz));
15253db86aabSstevel 		mutex_exit(&unitp->umutex);
15263db86aabSstevel 		return;
15273db86aabSstevel 	}
15283db86aabSstevel 
15293db86aabSstevel 	if (unitp->present_led_state == B_TRUE) {
15303db86aabSstevel 		/*
15313db86aabSstevel 		 * Now we need to "or" in fault bits of the FSP
15323db86aabSstevel 		 * module for the mass storage fault led.
15333db86aabSstevel 		 * and set it.
15343db86aabSstevel 		 */
15353db86aabSstevel 		val = (val & ~(EHC_PCF8574_PORT4) | JAV_FSP_MASK);
15363db86aabSstevel 		unitp->present_led_state = B_FALSE;
15373db86aabSstevel 	} else {
15383db86aabSstevel 		val = (val | EHC_PCF8574_PORT4 | JAV_FSP_MASK);
15393db86aabSstevel 		unitp->present_led_state = B_TRUE;
15403db86aabSstevel 	}
15413db86aabSstevel 
15423db86aabSstevel 	/*
15433db86aabSstevel 	 * A static global variable, power_flt_led_lit, is used to keep
15443db86aabSstevel 	 * track of periods when the software has lit the power fault LED.
15453db86aabSstevel 	 * Whenever the power fault LED is lit and this variable is not set,
15463db86aabSstevel 	 * then the power fault LED has been lit by hardware. In this case
15473db86aabSstevel 	 * mask out the power fault LED in the byte. This is a fix for
15483db86aabSstevel 	 * bug 4144872.
15493db86aabSstevel 	 */
15503db86aabSstevel 	tmpval = ~val;
15513db86aabSstevel 	if (tmpval & ENVCTRL_UE250_FSP_PS_ERR) {
15523db86aabSstevel 		if (power_flt_led_lit == 0) {
15533db86aabSstevel 			/*
15543db86aabSstevel 			 * Turn off power fault bit in the FSP byte.
15553db86aabSstevel 			 */
15563db86aabSstevel 			tmpval &= ~(ENVCTRL_UE250_FSP_PS_ERR);
15573db86aabSstevel 		}
15583db86aabSstevel 	}
15593db86aabSstevel 	val = ~tmpval;
15603db86aabSstevel 
15613db86aabSstevel 	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
15623db86aabSstevel 	    0, &val, 1);
15633db86aabSstevel 	if (status == DDI_FAILURE) {
15643db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Failed to blink activity LED",
15653db86aabSstevel 		    driver_name, unitp->instance);
15663db86aabSstevel 		/* now have this thread sleep for a while */
15673db86aabSstevel 		unitp->blink_timeout_id = (timeout(envctrl_led_blink,
15683db86aabSstevel 		    (caddr_t)unitp, blink_timeout_hz));
15693db86aabSstevel 		mutex_exit(&unitp->umutex);
15703db86aabSstevel 		return;
15713db86aabSstevel 	}
15723db86aabSstevel 
15733db86aabSstevel 	/* now have this thread sleep for a while */
15743db86aabSstevel 	unitp->blink_timeout_id = (timeout(envctrl_led_blink,
15753db86aabSstevel 	    (caddr_t)unitp, blink_timeout_hz));
15763db86aabSstevel 
15773db86aabSstevel 	mutex_exit(&unitp->umutex);
15783db86aabSstevel }
15793db86aabSstevel 
15803db86aabSstevel static int
15813db86aabSstevel envctrl_check_sys_temperatures(struct envctrlunit *unitp)
15823db86aabSstevel {
15833db86aabSstevel 	uint8_t buf[8];
15843db86aabSstevel 	enum levels warning_level, level;
15853db86aabSstevel 	uint8_t fspval;
15863db86aabSstevel 	int status, warning_count = 0;
15873db86aabSstevel 
15883db86aabSstevel retrytemp1:
15893db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2,
15903db86aabSstevel 	    0, buf, 4);
15913db86aabSstevel 	if (status == DDI_FAILURE) {
15923db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Temperature read failed (PDB)",
15933db86aabSstevel 		    driver_name, unitp->instance);
15943db86aabSstevel 		return (status);
15953db86aabSstevel 	}
15963db86aabSstevel 
15973db86aabSstevel 	warning_level = envctrl_check_tempr_levels(unitp, EHC_DEV2,
15983db86aabSstevel 	    buf, warning_count);
15993db86aabSstevel 	level = warning_level;
16003db86aabSstevel 
16013db86aabSstevel 	if (warning_level != green) {
16023db86aabSstevel 		if (warning_count == 0) {
16033db86aabSstevel 			warning_count++;
16043db86aabSstevel 			drv_usecwait(1000);
16053db86aabSstevel 			goto retrytemp1;
16063db86aabSstevel 		}
16073db86aabSstevel 		if (warning_level == yellow)
16083db86aabSstevel 			unitp->tempr_warning = B_TRUE;
16093db86aabSstevel 		else if (warning_level == red) {
16103db86aabSstevel 				unitp->tempr_warning = B_TRUE;
16113db86aabSstevel 				if (!envctrl_power_off_overide)
16123db86aabSstevel 					unitp->shutdown = B_TRUE;
16133db86aabSstevel 		}
16143db86aabSstevel 	}
16153db86aabSstevel 
16163db86aabSstevel 	warning_count = 0;
16173db86aabSstevel retrytemp2:
16183db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV7,
16193db86aabSstevel 	    0, buf+4, 4);
16203db86aabSstevel 	if (status == DDI_FAILURE) {
16213db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Temperature read failed (MBD)",
16223db86aabSstevel 		    driver_name, unitp->instance);
16233db86aabSstevel 		return (status);
16243db86aabSstevel 	}
16253db86aabSstevel 
16263db86aabSstevel 	warning_level = envctrl_check_tempr_levels(unitp, EHC_DEV7,
16273db86aabSstevel 	    buf+4, warning_count);
16283db86aabSstevel 
16293db86aabSstevel 	if (warning_level != green) {
16303db86aabSstevel 		if (warning_count == 0) {
16313db86aabSstevel 			warning_count++;
16323db86aabSstevel 			drv_usecwait(1000);
16333db86aabSstevel 			goto retrytemp2;
16343db86aabSstevel 		}
16353db86aabSstevel 		if ((warning_level == yellow) && (unitp->shutdown == B_FALSE))
16363db86aabSstevel 			unitp->tempr_warning = B_TRUE;
16373db86aabSstevel 		else if (warning_level == red) {
16383db86aabSstevel 				unitp->tempr_warning = B_TRUE;
16393db86aabSstevel 				if (!envctrl_power_off_overide)
16403db86aabSstevel 					unitp->shutdown = B_TRUE;
16413db86aabSstevel 		}
16423db86aabSstevel 	} else if ((level == green) && (unitp->tempr_warning == B_TRUE)) {
16433db86aabSstevel 		/*
16443db86aabSstevel 		 * Current tempr. poll shows all levels normal.
16453db86aabSstevel 		 * If the previous poll showed warning levels, we need
16463db86aabSstevel 		 * to clear that status
16473db86aabSstevel 		 */
16483db86aabSstevel 		cmn_err(CE_NOTE,
16493db86aabSstevel 		"TEMPERATURE NORMAL: all sensors back to normal readings");
16503db86aabSstevel 		unitp->tempr_warning = B_FALSE;
16513db86aabSstevel 	}
16523db86aabSstevel 
16533db86aabSstevel 	status = envctrl_get_fpm_status(unitp, &fspval);
16543db86aabSstevel 	if (status == DDI_FAILURE) {
16553db86aabSstevel 		cmn_err(CE_WARN,
16563db86aabSstevel 		    "%s%d: Read of Front Status Panel LEDs failed",
16573db86aabSstevel 		    driver_name, unitp->instance);
16583db86aabSstevel 	}
16593db86aabSstevel 
16603db86aabSstevel 	if ((unitp->tempr_warning == B_TRUE) || (unitp->shutdown == B_TRUE))
16613db86aabSstevel 		fspval |= (ENVCTRL_UE250_FSP_TEMP_ERR |
16623db86aabSstevel 		    ENVCTRL_UE250_FSP_GEN_ERR);
16633db86aabSstevel 	else {
16643db86aabSstevel 		if (envctrl_isother_fault_led(unitp, fspval,
16653db86aabSstevel 		    ENVCTRL_UE250_FSP_TEMP_ERR)) {
16663db86aabSstevel 			fspval &= ~(ENVCTRL_UE250_FSP_TEMP_ERR);
16673db86aabSstevel 		} else {
16683db86aabSstevel 			fspval &= ~(ENVCTRL_UE250_FSP_TEMP_ERR |
16693db86aabSstevel 			    ENVCTRL_UE250_FSP_GEN_ERR);
16703db86aabSstevel 		}
16713db86aabSstevel 	}
16723db86aabSstevel 	status = envctrl_set_fsp(unitp, &fspval);
16733db86aabSstevel 	if (status == DDI_FAILURE) {
16743db86aabSstevel 		cmn_err(CE_WARN,
16753db86aabSstevel 		    "%s%d: Setting of Front Status Panel LEDs failed",
16763db86aabSstevel 		    driver_name, unitp->instance);
16773db86aabSstevel 	}
16783db86aabSstevel 
16793db86aabSstevel 	/*
16803db86aabSstevel 	 * Have this thread run again in about 10 seconds
16813db86aabSstevel 	 */
16823db86aabSstevel 	if (unitp->tempr_warning == B_TRUE) {
16833db86aabSstevel 		if (unitp->timeout_id != 0) {
16843db86aabSstevel 			(void) untimeout(unitp->timeout_id);
16853db86aabSstevel 			unitp->timeout_id = (timeout(envctrl_tempr_poll,
16863db86aabSstevel 			    (caddr_t)unitp, warning_timeout_hz));
16873db86aabSstevel 		}
16883db86aabSstevel 	}
16893db86aabSstevel 
16903db86aabSstevel 	return (status);
16913db86aabSstevel }
16923db86aabSstevel 
16933db86aabSstevel static int
16943db86aabSstevel envctrl_check_tempr_levels(struct envctrlunit *unitp, int chip_num,
16953db86aabSstevel 	uint8_t *data, int count)
16963db86aabSstevel {
16973db86aabSstevel 	uint_t temp_degree_c;
16983db86aabSstevel 	uint8_t buf[8];
16993db86aabSstevel 	enum levels warning_level = green;
17003db86aabSstevel 	int i, j;
17013db86aabSstevel 	int status;
17023db86aabSstevel 	uint8_t fanspeed;
17033db86aabSstevel 	int tval;
17043db86aabSstevel 
17053db86aabSstevel 	for (i = 0; i < 4; i++) {
17063db86aabSstevel 		if (chip_num == EHC_DEV2) {
17073db86aabSstevel 			if (i == 1) {
17083db86aabSstevel 				tval = ((int)data[i] * JAV_FAN_SPEED_SF_NUM) /
17093db86aabSstevel 				    JAV_FAN_SPEED_SF_DEN;
17103db86aabSstevel 				if (tval > 255)
17113db86aabSstevel 					unitp->fan_kstats.fanspeed = 255;
17123db86aabSstevel 				else
17133db86aabSstevel 					unitp->fan_kstats.fanspeed = tval;
17143db86aabSstevel 				DPRINTF1("device %X, fan = %d %d\n", chip_num,
17153db86aabSstevel 				    unitp->fan_kstats.fanspeed, data[i]);
17163db86aabSstevel 				continue;
17173db86aabSstevel 			} else if (i == 2)
17183db86aabSstevel 				continue;
17193db86aabSstevel 		}
17203db86aabSstevel 		if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
17213db86aabSstevel 		    (i == ENVCTRL_UE250_CPU1_PORT)))
17223db86aabSstevel 			if (unitp->cpu_pr_location[i] == B_FALSE)
17233db86aabSstevel 				continue;
17243db86aabSstevel 
17253db86aabSstevel 		j = 0;
17263db86aabSstevel 		while ((((t_addr[j] & 0xF) != chip_num) || (t_port[j] != i)) &&
17273db86aabSstevel 		    (j < unitp->num_temps_present))
17283db86aabSstevel 			j++;
17293db86aabSstevel 		if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
17303db86aabSstevel 		    (i == ENVCTRL_UE250_CPU1_PORT)))
17313db86aabSstevel 			temp_degree_c = _cpu_temps[data[i]];
17323db86aabSstevel 		else
17333db86aabSstevel 			temp_degree_c = ((int)data[i] * t_scale_num[j]) /
17343db86aabSstevel 			    t_scale_den[j];
17353db86aabSstevel 
17363db86aabSstevel 		/*
17373db86aabSstevel 		 * Javelin hardware will not control fan speeds based on
17383db86aabSstevel 		 * cpu temperature values because the voltages corresponding
17393db86aabSstevel 		 * to the cpu temperatures are based on an inverted scale
17403db86aabSstevel 		 * compared to the ambient temperatures and thus can be
17413db86aabSstevel 		 * fed to the same fan control circuit. As a result, it
17423db86aabSstevel 		 * has been decided that software will control fan speed
17433db86aabSstevel 		 * if cpu temperatures rise.
17443db86aabSstevel 		 */
17453db86aabSstevel 		if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
17463db86aabSstevel 		    (i == ENVCTRL_UE250_CPU1_PORT)) &&
17473db86aabSstevel 		    (unitp->current_mode == ENVCTRL_NORMAL_MODE)) {
17483db86aabSstevel 			if (_cpu_fan_speeds[data[ENVCTRL_UE250_CPU0_PORT]] >
17493db86aabSstevel 			    _cpu_fan_speeds[data[ENVCTRL_UE250_CPU1_PORT]])
17503db86aabSstevel 				fanspeed =
1751*19397407SSherry Moore 				    _cpu_fan_speeds[
1752*19397407SSherry Moore 				    data[ENVCTRL_UE250_CPU0_PORT]];
17533db86aabSstevel 			else
17543db86aabSstevel 				fanspeed =
1755*19397407SSherry Moore 				    _cpu_fan_speeds[
1756*19397407SSherry Moore 				    data[ENVCTRL_UE250_CPU1_PORT]];
17573db86aabSstevel 			status = envctrl_write_chip(unitp, ENVCTRL_PCF8591,
17583db86aabSstevel 			    EHC_DEV2, 0, &fanspeed, 1);
17593db86aabSstevel 			if (status == DDI_FAILURE)
17603db86aabSstevel 				cmn_err(CE_WARN,
17613db86aabSstevel 				    "%s%d: Write to PCF8591 (SETFAN) failed\n",
17623db86aabSstevel 				    driver_name, unitp->instance);
17633db86aabSstevel 			status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
17643db86aabSstevel 			    EHC_DEV2, 0, buf, 4);
17653db86aabSstevel 			if (status == DDI_FAILURE)
17663db86aabSstevel 				cmn_err(CE_WARN,
17673db86aabSstevel 				    "%s%d: Fan speed read failed (PDB)",
17683db86aabSstevel 				    driver_name, unitp->instance);
17693db86aabSstevel 			tval = ((int)buf[1] * JAV_FAN_SPEED_SF_NUM) /
17703db86aabSstevel 			    JAV_FAN_SPEED_SF_DEN;
17713db86aabSstevel 			if (tval > 255)
17723db86aabSstevel 				unitp->fan_kstats.fanspeed = 255;
17733db86aabSstevel 			else
17743db86aabSstevel 				unitp->fan_kstats.fanspeed = tval;
17753db86aabSstevel 		}
17763db86aabSstevel 
17773db86aabSstevel 		DPRINTF1("device %X, temp = %d %d loc = %s\n", chip_num,
17783db86aabSstevel 		    temp_degree_c, data[i], unitp->temp_kstats[j].label);
17793db86aabSstevel 
17803db86aabSstevel 		unitp->temp_kstats[j].value = temp_degree_c;
17813db86aabSstevel 		if ((temp_degree_c >=
17823db86aabSstevel 		    unitp->temp_kstats[j].warning_threshold) ||
17833db86aabSstevel 		    (temp_degree_c < unitp->temp_kstats[j].min)) {
17843db86aabSstevel 			if (warning_level < yellow)
17853db86aabSstevel 				warning_level = yellow;
17863db86aabSstevel 			if (count != 0)
17873db86aabSstevel 				cmn_err(CE_WARN,
1788*19397407SSherry Moore 				    "TEMPERATURE WARNING: %d degrees "
1789*19397407SSherry Moore 				    "celsius at location %s",
17903db86aabSstevel 				    temp_degree_c, unitp->temp_kstats[j].label);
17913db86aabSstevel 		}
17923db86aabSstevel 		if (temp_degree_c >=
17933db86aabSstevel 		    unitp->temp_kstats[j].shutdown_threshold) {
17943db86aabSstevel 			if (warning_level < red)
17953db86aabSstevel 				warning_level = red;
17963db86aabSstevel 			if (count != 0) {
17973db86aabSstevel 				cmn_err(CE_WARN,
1798*19397407SSherry Moore 				    "TEMPERATURE CRITICAL: %d "
1799*19397407SSherry Moore 				    "degrees celsius at location %s",
18003db86aabSstevel 				    temp_degree_c, unitp->temp_kstats[j].label);
18013db86aabSstevel 				if (!envctrl_power_off_overide)
18023db86aabSstevel 					cmn_err(CE_WARN,
1803*19397407SSherry Moore 					    "System shutdown in "
1804*19397407SSherry Moore 					    "10 seconds ...");
18053db86aabSstevel 			}
18063db86aabSstevel 		}
18073db86aabSstevel 	}
18083db86aabSstevel 	return (warning_level);
18093db86aabSstevel }
18103db86aabSstevel 
18113db86aabSstevel static void
18123db86aabSstevel envctrl_update_fanspeed(struct envctrlunit *unitp)
18133db86aabSstevel {
18143db86aabSstevel 	uint8_t buf[8];
18153db86aabSstevel 	int tval;
18163db86aabSstevel 	int status;
18173db86aabSstevel 
18183db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2,
18193db86aabSstevel 	    0, buf, 4);
18203db86aabSstevel 	if (status == DDI_FAILURE) {
18213db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Fan speed read failed ",
18223db86aabSstevel 		    driver_name, unitp->instance);
18233db86aabSstevel 	}
18243db86aabSstevel 
18253db86aabSstevel 	tval = ((int)buf[ENVCTRL_PORT1] * JAV_FAN_SPEED_SF_NUM) /
18263db86aabSstevel 	    JAV_FAN_SPEED_SF_DEN;
18273db86aabSstevel 	if (tval > 255)
18283db86aabSstevel 		unitp->fan_kstats.fanspeed = 255;
18293db86aabSstevel 	else
18303db86aabSstevel 		unitp->fan_kstats.fanspeed = tval;
18313db86aabSstevel }
18323db86aabSstevel 
18333db86aabSstevel /* called with mutex held */
18343db86aabSstevel static void
18353db86aabSstevel envctrl_fan_fail_service(struct envctrlunit *unitp)
18363db86aabSstevel {
18373db86aabSstevel 	uint8_t recv_data, fpmstat;
18383db86aabSstevel 	int retrys = 0;
18393db86aabSstevel 	int status;
18403db86aabSstevel 
18413db86aabSstevel 	/*
18423db86aabSstevel 	 * The fan fail interrupt is read from address 0x70
18433db86aabSstevel 	 * on the envctrl bus.
18443db86aabSstevel 	 */
18453db86aabSstevel 
18463db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
18473db86aabSstevel 
18483db86aabSstevel 	/*
18493db86aabSstevel 	 * Clear the interrupt latches to handle spurious interrupts
18503db86aabSstevel 	 */
18513db86aabSstevel 	envctrl_intr_latch_clr(unitp);
18523db86aabSstevel 
18533db86aabSstevel 	do {
18543db86aabSstevel 		status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
18553db86aabSstevel 		    ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
18563db86aabSstevel 		    &recv_data, 1);
18573db86aabSstevel 		/*
18583db86aabSstevel 		 * This extra read is needed since the first read is discarded
18593db86aabSstevel 		 * and the second read seems to return 0xFF.
18603db86aabSstevel 		 */
18613db86aabSstevel 		if (recv_data == 0xFF) {
18623db86aabSstevel 			status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
18633db86aabSstevel 			    ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
18643db86aabSstevel 			    &recv_data, 1);
18653db86aabSstevel 		}
18663db86aabSstevel 
18673db86aabSstevel 		if (status == DDI_FAILURE) {
18683db86aabSstevel 			drv_usecwait(1000);
18693db86aabSstevel 			if (retrys < envctrl_max_retries) {
18703db86aabSstevel 				retrys++;
18713db86aabSstevel 			} else {
18723db86aabSstevel 				cmn_err(CE_WARN,
18733db86aabSstevel 				"%s%d: Read of PCF8574A (INTFAN) failed",
18743db86aabSstevel 				    driver_name, unitp->instance);
18753db86aabSstevel 				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
18763db86aabSstevel 				return;
18773db86aabSstevel 			}
18783db86aabSstevel 		}
18793db86aabSstevel 	} while (status != DDI_SUCCESS);
18803db86aabSstevel 
18813db86aabSstevel 	/* If the fan fail interrupt is now absent */
18823db86aabSstevel 	if (recv_data & EHC_PCF8574_PORT4) {
18833db86aabSstevel 		if (unitp->fan_failed == B_TRUE) {
18843db86aabSstevel 			if (unitp->current_mode == ENVCTRL_NORMAL_MODE)
18853db86aabSstevel 				cmn_err(CE_CONT,
18863db86aabSstevel 				    "Fan failure has been cleared\n");
18873db86aabSstevel 			unitp->fan_kstats.fans_ok = B_TRUE;
18883db86aabSstevel 			/*
18893db86aabSstevel 			 * Clear general fault LED if no other faults
18903db86aabSstevel 			 */
18913db86aabSstevel 			status = envctrl_get_fpm_status(unitp, &fpmstat);
18923db86aabSstevel 			if (status == DDI_FAILURE) {
18933db86aabSstevel 				cmn_err(CE_WARN,
1894*19397407SSherry Moore 				    "%s%d: Read of Front Status "
1895*19397407SSherry Moore 				    "Panel LEDs failed",
18963db86aabSstevel 				    driver_name, unitp->instance);
18973db86aabSstevel 			}
18983db86aabSstevel 			if (!(envctrl_isother_fault_led(unitp, fpmstat, 0))) {
18993db86aabSstevel 				fpmstat &= ~(ENVCTRL_UE250_FSP_GEN_ERR);
19003db86aabSstevel 			}
19013db86aabSstevel 			if (unitp->shutdown != B_TRUE) {
19023db86aabSstevel 				status = envctrl_set_fsp(unitp, &fpmstat);
19033db86aabSstevel 				if (status == DDI_FAILURE) {
19043db86aabSstevel 					cmn_err(CE_WARN, "%s%d: "
1905*19397407SSherry Moore 					    "Setting of Front Status "
1906*19397407SSherry Moore 					    "Panel LEDs failed",
19073db86aabSstevel 					    driver_name, unitp->instance);
19083db86aabSstevel 				}
19093db86aabSstevel 			}
19103db86aabSstevel 			/*
19113db86aabSstevel 			 * This should be set after envctrl_isother_fault_led()
19123db86aabSstevel 			 * is called
19133db86aabSstevel 			 */
19143db86aabSstevel 			unitp->fan_failed = B_FALSE;
19153db86aabSstevel 		}
19163db86aabSstevel 	} else {
19173db86aabSstevel 		if (unitp->fan_failed == B_FALSE) {
19183db86aabSstevel 			if (unitp->current_mode == ENVCTRL_NORMAL_MODE)
19193db86aabSstevel 				cmn_err(CE_WARN,
19203db86aabSstevel 				    "Fan failure has been detected");
19213db86aabSstevel 			unitp->fan_failed = B_TRUE;
19223db86aabSstevel 			unitp->fan_kstats.fans_ok = B_FALSE;
19233db86aabSstevel 			/*
19243db86aabSstevel 			 * Set general fault LED
19253db86aabSstevel 			 */
19263db86aabSstevel 			status = envctrl_get_fpm_status(unitp, &fpmstat);
19273db86aabSstevel 			if (status == DDI_FAILURE) {
19283db86aabSstevel 				cmn_err(CE_WARN,
1929*19397407SSherry Moore 				    "%s%d: Read of Front Status "
1930*19397407SSherry Moore 				    "Panel LEDs failed",
19313db86aabSstevel 				    driver_name, unitp->instance);
19323db86aabSstevel 				return;
19333db86aabSstevel 			}
19343db86aabSstevel 			fpmstat |= ENVCTRL_UE250_FSP_GEN_ERR;
19353db86aabSstevel 			status = envctrl_set_fsp(unitp, &fpmstat);
19363db86aabSstevel 			if (status == DDI_FAILURE) {
19373db86aabSstevel 				cmn_err(CE_WARN, "%s%d: "
19383db86aabSstevel 				    "Setting of Front Status Panel LEDs failed",
19393db86aabSstevel 				    driver_name, unitp->instance);
19403db86aabSstevel 			}
19413db86aabSstevel 			/*
19423db86aabSstevel 			 * A fan failure condition exists.
19433db86aabSstevel 			 * Temperature poll thread should run every 10 seconds.
19443db86aabSstevel 			 */
19453db86aabSstevel 			if (unitp->timeout_id != 0) {
19463db86aabSstevel 				(void) untimeout(unitp->timeout_id);
1947*19397407SSherry Moore 				unitp->timeout_id =
1948*19397407SSherry Moore 				    (timeout(envctrl_tempr_poll,
19493db86aabSstevel 				    (caddr_t)unitp, warning_timeout_hz));
19503db86aabSstevel 			}
19513db86aabSstevel 		}
19523db86aabSstevel 	}
19533db86aabSstevel }
19543db86aabSstevel 
19553db86aabSstevel /*
19563db86aabSstevel  * Check for power supply insertion and failure.
19573db86aabSstevel  * This is a bit tricky, because a power supply insertion will
19583db86aabSstevel  * cause the ps_ok line to go active as well as PS present in the
19593db86aabSstevel  * new supply. If we detect an insertion clear
19603db86aabSstevel  * interrupts, disable interrupts, wait for a couple of seconds
19613db86aabSstevel  * come back and see if the PSOK bit is set, PS_PRESENT is set
19623db86aabSstevel  * and the share fail interrupts are gone. If not this is a
19633db86aabSstevel  * real load share fail event.
19643db86aabSstevel  * Called with mutex held
19653db86aabSstevel  */
19663db86aabSstevel 
19673db86aabSstevel static void
19683db86aabSstevel envctrl_PS_intr_service(struct envctrlunit *unitp)
19693db86aabSstevel {
19703db86aabSstevel 
19713db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
19723db86aabSstevel 
19733db86aabSstevel 	if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
19743db86aabSstevel 		return;
19753db86aabSstevel 	}
19763db86aabSstevel 
19773db86aabSstevel 	/*
19783db86aabSstevel 	 * setup a timeout thread to poll the ps after a
19793db86aabSstevel 	 * couple of seconds. This allows for the PS to settle
19803db86aabSstevel 	 * and doesn't report false errors on a hotplug
19813db86aabSstevel 	 */
19823db86aabSstevel 
19833db86aabSstevel 	unitp->pshotplug_id = (timeout(envctrl_pshotplug_poll,
19843db86aabSstevel 	    (caddr_t)unitp, pshotplug_timeout_hz));
19853db86aabSstevel 
19863db86aabSstevel }
19873db86aabSstevel 
19883db86aabSstevel static void
19893db86aabSstevel envctrl_init_bus(struct envctrlunit *unitp)
19903db86aabSstevel {
19913db86aabSstevel 	ehc_init_pcf8584((struct ehc_envcunit *)unitp);
19923db86aabSstevel 
19933db86aabSstevel 	/*
19943db86aabSstevel 	 * Clear the interrupt latches
19953db86aabSstevel 	 */
19963db86aabSstevel 	envctrl_intr_latch_clr(unitp);
19973db86aabSstevel 
19983db86aabSstevel 	envctrl_reset_dflop(unitp);
19993db86aabSstevel 
20003db86aabSstevel 	envctrl_enable_devintrs(unitp);
20013db86aabSstevel }
20023db86aabSstevel 
20033db86aabSstevel /* called with mutex held */
20043db86aabSstevel static void
20053db86aabSstevel envctrl_reset_dflop(struct envctrlunit *unitp)
20063db86aabSstevel {
20073db86aabSstevel 	int status;
20083db86aabSstevel 	uint8_t value;
20093db86aabSstevel 
20103db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
20113db86aabSstevel 
20123db86aabSstevel 	value = ENVCTRL_UE250_DFLOP_INIT0;
20133db86aabSstevel 	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
20143db86aabSstevel 	    0, &value, 1);
20153db86aabSstevel 	if (status == DDI_FAILURE) {
20163db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (DFLOP_INIT0) failed",
20173db86aabSstevel 		    driver_name, unitp->instance);
20183db86aabSstevel 	}
20193db86aabSstevel 
20203db86aabSstevel 	value = ENVCTRL_UE250_DFLOP_INIT1;
20213db86aabSstevel 	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
20223db86aabSstevel 	    0, &value, 1);
20233db86aabSstevel 	if (status == DDI_FAILURE) {
20243db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (DFLOP_INIT1) failed",
20253db86aabSstevel 		    driver_name, unitp->instance);
20263db86aabSstevel 	}
20273db86aabSstevel }
20283db86aabSstevel 
20293db86aabSstevel /* called with mutex held */
20303db86aabSstevel static void
20313db86aabSstevel envctrl_enable_devintrs(struct envctrlunit *unitp)
20323db86aabSstevel {
20333db86aabSstevel 	int status;
20343db86aabSstevel 	uint8_t value;
20353db86aabSstevel 
20363db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
20373db86aabSstevel 
20383db86aabSstevel 	value = ENVCTRL_UE250_DEVINTR_INIT0;
20393db86aabSstevel 	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
20403db86aabSstevel 	    0, &value, 1);
20413db86aabSstevel 	if (status == DDI_FAILURE) {
20423db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_INIT0) failed",
20433db86aabSstevel 		    driver_name, unitp->instance);
20443db86aabSstevel 	}
20453db86aabSstevel 
20463db86aabSstevel 	value = ENVCTRL_UE250_DEVINTR_INIT1;
20473db86aabSstevel 	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
20483db86aabSstevel 	    0, &value, 1);
20493db86aabSstevel 	if (status == DDI_FAILURE) {
20503db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_INIT1) failed",
20513db86aabSstevel 		    driver_name, unitp->instance);
20523db86aabSstevel 	}
20533db86aabSstevel }
20543db86aabSstevel 
20553db86aabSstevel static void
20563db86aabSstevel envctrl_intr_latch_clr(struct envctrlunit *unitp)
20573db86aabSstevel {
20583db86aabSstevel 	int status;
20593db86aabSstevel 	uint8_t value;
20603db86aabSstevel 
20613db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
20623db86aabSstevel 
20633db86aabSstevel 	value = ENVCTRL_UE250_INTR_LATCH_INIT0;
20643db86aabSstevel 	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
20653db86aabSstevel 	    0, &value, 1);
20663db86aabSstevel 	if (status == DDI_FAILURE) {
20673db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_LATCH0) failed",
20683db86aabSstevel 		    driver_name, unitp->instance);
20693db86aabSstevel 	}
20703db86aabSstevel 
20713db86aabSstevel 	value = ENVCTRL_UE250_INTR_LATCH_INIT1;
20723db86aabSstevel 	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
20733db86aabSstevel 	    0, &value, 1);
20743db86aabSstevel 	if (status == DDI_FAILURE) {
20753db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_LATCH1) failed",
20763db86aabSstevel 		    driver_name, unitp->instance);
20773db86aabSstevel 	}
20783db86aabSstevel }
20793db86aabSstevel 
20803db86aabSstevel /* Called with unitp mutex held */
20813db86aabSstevel static void
20823db86aabSstevel envctrl_ps_probe(struct envctrlunit *unitp)
20833db86aabSstevel {
20843db86aabSstevel 
20853db86aabSstevel 	uint8_t recv_data, fpmstat;
20863db86aabSstevel 	int i, j;
20873db86aabSstevel 	int ps_error = 0, ps_present_port, power_ok_port;
20883db86aabSstevel 	int status;
20893db86aabSstevel 
20903db86aabSstevel 
20913db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
20923db86aabSstevel 
20933db86aabSstevel 	unitp->num_ps_present = 0;
20943db86aabSstevel 
20953db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV1,
20963db86aabSstevel 	    0, &recv_data, 1);
20973db86aabSstevel 	if (status == DDI_FAILURE) {
20983db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Read of PCF8574 (PS) failed",
20993db86aabSstevel 		    driver_name, unitp->instance);
21003db86aabSstevel 		return;
21013db86aabSstevel 	}
21023db86aabSstevel 
21033db86aabSstevel 	for (i = 0, j = 0; i < ENVCTRL_UE250_MAXPS; i++) {
21043db86aabSstevel 		unitp->ps_kstats[i].slot = -1;
21053db86aabSstevel 
21063db86aabSstevel 		/*
21073db86aabSstevel 		 * Port 0 = PS0 Present
21083db86aabSstevel 		 * Port 1 = PS1 Present
21093db86aabSstevel 		 * Port 2 = SPARE
21103db86aabSstevel 		 * Port 3 = SPARE
21113db86aabSstevel 		 * Port 4 = PS0 OK
21123db86aabSstevel 		 * Port 5 = PS1 OK
21133db86aabSstevel 		 * Port 6 = SPARE
21143db86aabSstevel 		 * Port 7 = SPARE
21153db86aabSstevel 		 */
21163db86aabSstevel 
21173db86aabSstevel 		/*
21183db86aabSstevel 		 * Port 0 = PS Present
21193db86aabSstevel 		 * Port is pulled LOW "0" to indicate
21203db86aabSstevel 		 * present.
21213db86aabSstevel 		 */
21223db86aabSstevel 
21233db86aabSstevel 		switch (i) {
21243db86aabSstevel 		case 0:
21253db86aabSstevel 			ps_present_port = EHC_PCF8574_PORT0;
21263db86aabSstevel 			power_ok_port = EHC_PCF8574_PORT4;
21273db86aabSstevel 			break;
21283db86aabSstevel 		case 1:
21293db86aabSstevel 			ps_present_port = EHC_PCF8574_PORT1;
21303db86aabSstevel 			power_ok_port = EHC_PCF8574_PORT5;
21313db86aabSstevel 			break;
21323db86aabSstevel 		}
21333db86aabSstevel 
21343db86aabSstevel 		if (!(recv_data & ps_present_port)) {
21353db86aabSstevel 			/* update unit kstat array */
21363db86aabSstevel 			unitp->ps_kstats[j].slot = i;
21373db86aabSstevel 			++unitp->num_ps_present;
21383db86aabSstevel 
21393db86aabSstevel 			if (pspr[i] == 0) {
21403db86aabSstevel 				cmn_err(CE_NOTE,
21413db86aabSstevel 				    "Power Supply %d inserted\n", i);
21423db86aabSstevel 			}
21433db86aabSstevel 			pspr[i] = 1;
21443db86aabSstevel 
21453db86aabSstevel 			if (!(recv_data & power_ok_port)) {
21463db86aabSstevel 				cmn_err(CE_WARN,
21473db86aabSstevel 				    "Power Supply %d NOT okay\n", i);
21483db86aabSstevel 				unitp->ps_kstats[j].ps_ok = B_FALSE;
21493db86aabSstevel 				ps_error++;
21503db86aabSstevel 				psok[i] = 0;
21513db86aabSstevel 			} else {
21523db86aabSstevel 				unitp->ps_kstats[j].ps_ok = B_TRUE;
21533db86aabSstevel 				if (psok[i] == 0)
21543db86aabSstevel 					cmn_err(CE_NOTE,
21553db86aabSstevel 					    "Power Supply %d okay\n", i);
21563db86aabSstevel 				psok[i] = 1;
21573db86aabSstevel 			}
21583db86aabSstevel 
21593db86aabSstevel 			if (!(recv_data & EHC_PCF8574_PORT2)) {
21603db86aabSstevel 				cmn_err(CE_WARN,
21613db86aabSstevel 				    "PS %d Shouln't interrupt\n", i);
21623db86aabSstevel 				ps_error++;
21633db86aabSstevel 			}
21643db86aabSstevel 
21653db86aabSstevel 			if (!(recv_data & EHC_PCF8574_PORT3)) {
21663db86aabSstevel 				cmn_err(CE_WARN,
21673db86aabSstevel 				    "PS %d Shouln't interrupt\n", i);
21683db86aabSstevel 				ps_error++;
21693db86aabSstevel 			}
21703db86aabSstevel 
21713db86aabSstevel 			if (!(recv_data & EHC_PCF8574_PORT6)) {
21723db86aabSstevel 				cmn_err(CE_WARN,
21733db86aabSstevel 				    "PS %d Shouln't interrupt\n", i);
21743db86aabSstevel 				ps_error++;
21753db86aabSstevel 			}
21763db86aabSstevel 
21773db86aabSstevel 			if (!(recv_data & EHC_PCF8574_PORT7)) {
21783db86aabSstevel 				cmn_err(CE_WARN,
21793db86aabSstevel 				    "PS %d Shouln't interrupt\n", i);
21803db86aabSstevel 				ps_error++;
21813db86aabSstevel 			}
21823db86aabSstevel 			j++;
21833db86aabSstevel 		} else {
21843db86aabSstevel 			if (pspr[i] == 1) {
21853db86aabSstevel 				cmn_err(CE_NOTE,
21863db86aabSstevel 				    "Power Supply %d removed\n", i);
21873db86aabSstevel 			}
21883db86aabSstevel 			pspr[i] = 0;
21893db86aabSstevel 		}
21903db86aabSstevel 	}
21913db86aabSstevel 
21923db86aabSstevel 	status = envctrl_get_fpm_status(unitp, &fpmstat);
21933db86aabSstevel 	if (status == DDI_FAILURE) {
21943db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Read of Front Status Panel LEDs failed",
21953db86aabSstevel 		    driver_name, unitp->instance);
21963db86aabSstevel 	}
21973db86aabSstevel 	if (ps_error) {
21983db86aabSstevel 		fpmstat |= (ENVCTRL_UE250_FSP_PS_ERR |
21993db86aabSstevel 		    ENVCTRL_UE250_FSP_GEN_ERR);
22003db86aabSstevel 	} else {
22013db86aabSstevel 		if (envctrl_isother_fault_led(unitp, fpmstat,
22023db86aabSstevel 		    ENVCTRL_UE250_FSP_PS_ERR)) {
22033db86aabSstevel 			fpmstat &= ~(ENVCTRL_UE250_FSP_PS_ERR);
22043db86aabSstevel 		} else {
22053db86aabSstevel 			fpmstat &= ~(ENVCTRL_UE250_FSP_PS_ERR |
22063db86aabSstevel 			    ENVCTRL_UE250_FSP_GEN_ERR);
22073db86aabSstevel 		}
22083db86aabSstevel 	}
22093db86aabSstevel 	status = envctrl_set_fsp(unitp, &fpmstat);
22103db86aabSstevel 	if (status == DDI_FAILURE) {
22113db86aabSstevel 		cmn_err(CE_WARN,
22123db86aabSstevel 		    "%s%d: Setting of Front Status Panel LEDs failed",
22133db86aabSstevel 		    driver_name, unitp->instance);
22143db86aabSstevel 	}
22153db86aabSstevel 
22163db86aabSstevel 	if (ps_error) {
22173db86aabSstevel 		power_flt_led_lit = 1;
22183db86aabSstevel 	} else {
22193db86aabSstevel 		power_flt_led_lit = 0;
22203db86aabSstevel 	}
22213db86aabSstevel }
22223db86aabSstevel 
22233db86aabSstevel /*
22243db86aabSstevel  * consider key switch position when handling an abort sequence
22253db86aabSstevel  */
22263db86aabSstevel static void
22273db86aabSstevel envctrl_abort_seq_handler(char *msg)
22283db86aabSstevel {
22293db86aabSstevel 	struct envctrlunit *unitp;
22303db86aabSstevel 	int i;
22313db86aabSstevel 	uint8_t secure = 0;
22323db86aabSstevel 
22333db86aabSstevel 	/*
22343db86aabSstevel 	 * Find the instance of the device available on this host.
22353db86aabSstevel 	 * Note that there may be only one, but the instance may
22363db86aabSstevel 	 * not be zero.
22373db86aabSstevel 	 */
22383db86aabSstevel 	for (i = 0; i < MAX_DEVS; i++) {
22393db86aabSstevel 		if (unitp = (struct envctrlunit *)
22403db86aabSstevel 		    ddi_get_soft_state(envctrlsoft_statep, i))
22413db86aabSstevel 			break;
22423db86aabSstevel 	}
22433db86aabSstevel 
22443db86aabSstevel 	ASSERT(unitp);
22453db86aabSstevel 
22463db86aabSstevel 	secure = unitp->encl_kstats.value;
22473db86aabSstevel 
22483db86aabSstevel 	if ((secure & ENVCTRL_UE250_FSP_KEYMASK) ==
22493db86aabSstevel 	    ENVCTRL_UE250_FSP_KEYLOCKED) {
22503db86aabSstevel 			cmn_err(CE_CONT,
22513db86aabSstevel 			    "%s%d: ignoring debug enter sequence\n",
22523db86aabSstevel 			    driver_name, unitp->instance);
22533db86aabSstevel 	} else {
22543db86aabSstevel 		if (envctrl_debug_flags) {
22553db86aabSstevel 			cmn_err(CE_CONT, "%s%d: allowing debug enter\n",
22563db86aabSstevel 			    driver_name, unitp->instance);
22573db86aabSstevel 		}
22583db86aabSstevel 		debug_enter(msg);
22593db86aabSstevel 	}
22603db86aabSstevel }
22613db86aabSstevel 
22623db86aabSstevel /*
22633db86aabSstevel  * get the front Panel module LED and keyswitch status.
22643db86aabSstevel  * this part is addressed at 0x7C on the i2c bus.
22653db86aabSstevel  * called with mutex held
22663db86aabSstevel  */
22673db86aabSstevel static int
22683db86aabSstevel envctrl_get_fpm_status(struct envctrlunit *unitp, uint8_t *val)
22693db86aabSstevel {
22703db86aabSstevel 	uint8_t recv_data;
22713db86aabSstevel 	int status;
22723db86aabSstevel 
22733db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
22743db86aabSstevel 
22753db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
22763db86aabSstevel 	    0, &recv_data, 1);
22773db86aabSstevel 	if (status == DDI_FAILURE) {
22783db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Read from PCF8574A (FSP) failed",
22793db86aabSstevel 		    driver_name, unitp->instance);
22803db86aabSstevel 		return (status);
22813db86aabSstevel 	}
22823db86aabSstevel 
22833db86aabSstevel 	recv_data = ~recv_data;
22843db86aabSstevel 	if (val != (uint8_t *)NULL)
22853db86aabSstevel 		*val = recv_data;
22863db86aabSstevel 
22873db86aabSstevel 	/* Update kstats */
22883db86aabSstevel 	unitp->encl_kstats.value = recv_data;
22893db86aabSstevel 
22903db86aabSstevel 	return (status);
22913db86aabSstevel }
22923db86aabSstevel 
22933db86aabSstevel static int
22943db86aabSstevel envctrl_set_fsp(struct envctrlunit *unitp, uint8_t *val)
22953db86aabSstevel {
22963db86aabSstevel 	uint8_t value;
22973db86aabSstevel 	int status = DDI_SUCCESS;
22983db86aabSstevel 	uint8_t confirm_val = 0, confirm_val_hold;
22993db86aabSstevel 	int confirm_count = 0, confirm_max = 20;
23003db86aabSstevel 
23013db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
23023db86aabSstevel 
23033db86aabSstevel 	value = ENVCTRL_UE250_FSP_OFF; /* init all values to off */
23043db86aabSstevel 
23053db86aabSstevel 	/*
23063db86aabSstevel 	 * strip off bits that are R/O
23073db86aabSstevel 	 */
23083db86aabSstevel 	value = (~(ENVCTRL_UE250_FSP_KEYMASK | ENVCTRL_UE250_FSP_POMASK) &
23093db86aabSstevel 	    (*val));
23103db86aabSstevel 
23113db86aabSstevel 	confirm_val_hold = value;
23123db86aabSstevel 
23133db86aabSstevel 	value = ~value;
23143db86aabSstevel 
23153db86aabSstevel 	while (confirm_count < confirm_max) {
23163db86aabSstevel 		status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
23173db86aabSstevel 		    0, &value, 1);
23183db86aabSstevel 		if (status == DDI_FAILURE) {
23193db86aabSstevel 			cmn_err(CE_WARN, "%s%d: Write to PCF8574A (FSP) failed",
23203db86aabSstevel 			    driver_name, unitp->instance);
23213db86aabSstevel 			break;
23223db86aabSstevel 		} else {
23233db86aabSstevel 			/*
23243db86aabSstevel 			 * Sometimes the i2c hardware status is not
23253db86aabSstevel 			 * completely dependable as far as reporting
23263db86aabSstevel 			 * a condition where the set does not take
23273db86aabSstevel 			 * place. So we read back the set value to
23283db86aabSstevel 			 * confirm what we set.
23293db86aabSstevel 			 */
23303db86aabSstevel 			status = envctrl_get_fpm_status(unitp, &confirm_val);
23313db86aabSstevel 			confirm_val = ~(ENVCTRL_UE250_FSP_KEYMASK |
23323db86aabSstevel 			    ENVCTRL_UE250_FSP_POMASK) & confirm_val;
23333db86aabSstevel 			if (status == DDI_FAILURE) {
23343db86aabSstevel 				cmn_err(CE_WARN,
23353db86aabSstevel 				"%s%d: Read of PCF8574A (FSP) failed",
23363db86aabSstevel 				    driver_name, unitp->instance);
23373db86aabSstevel 				break;
23383db86aabSstevel 			} else if (confirm_val != confirm_val_hold) {
23393db86aabSstevel 				confirm_count++;
23403db86aabSstevel 				drv_usecwait(1000);
23413db86aabSstevel 				continue;
23423db86aabSstevel 			} else
23433db86aabSstevel 				/*
23443db86aabSstevel 				 * Set was confirmed.
23453db86aabSstevel 				 */
23463db86aabSstevel 				break;
23473db86aabSstevel 		}
23483db86aabSstevel 	}
23493db86aabSstevel 
23503db86aabSstevel 	if (confirm_count == confirm_max)
23513db86aabSstevel 		status = DDI_FAILURE;
23523db86aabSstevel 
23533db86aabSstevel 	return (status);
23543db86aabSstevel 
23553db86aabSstevel }
23563db86aabSstevel 
23573db86aabSstevel static int
23583db86aabSstevel envctrl_get_dskled(struct envctrlunit *unitp, struct envctrl_chip *chip)
23593db86aabSstevel {
23603db86aabSstevel 	int status;
23613db86aabSstevel 
23623db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
23633db86aabSstevel 
23643db86aabSstevel 	if (chip->chip_num != EHC_DEV7 ||
23653db86aabSstevel 	    chip->type != ENVCTRL_PCF8574A) {
23663db86aabSstevel 		return (DDI_FAILURE);
23673db86aabSstevel 	}
23683db86aabSstevel 
23693db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
23703db86aabSstevel 	    0, &chip->val, 1);
23713db86aabSstevel 	if (status == DDI_FAILURE) {
23723db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
23733db86aabSstevel 		    driver_name, unitp->instance);
23743db86aabSstevel 	}
23753db86aabSstevel 	chip->val = ~chip->val;
23763db86aabSstevel 
23773db86aabSstevel 	return (status);
23783db86aabSstevel }
23793db86aabSstevel 
23803db86aabSstevel static int
23813db86aabSstevel envctrl_set_dskled(struct envctrlunit *unitp, struct envctrl_chip *chip)
23823db86aabSstevel {
23833db86aabSstevel 	uint8_t val;
23843db86aabSstevel 	int status;
23853db86aabSstevel 	struct envctrl_chip confirm_chip;
23863db86aabSstevel 	uint8_t confirm_val_hold;
23873db86aabSstevel 	int confirm_count = 0, confirm_max = 20;
23883db86aabSstevel 
23893db86aabSstevel 	/*
23903db86aabSstevel 	 * We need to check the type of disk led being set. If it
23913db86aabSstevel 	 * is a 4 slot backplane then the upper 4 bits (7, 6, 5, 4) are
23923db86aabSstevel 	 * invalid.
23933db86aabSstevel 	 */
23943db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
23953db86aabSstevel 
23963db86aabSstevel 
23973db86aabSstevel 	if (chip->chip_num != EHC_DEV7)
23983db86aabSstevel 		return (DDI_FAILURE);
23993db86aabSstevel 
24003db86aabSstevel 	if (chip->type != ENVCTRL_PCF8574A)
24013db86aabSstevel 		return (DDI_FAILURE);
24023db86aabSstevel 
24033db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
24043db86aabSstevel 	    0, &val, 1);
24053db86aabSstevel 	if (status == DDI_FAILURE) {
24063db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (FSP) failed",
24073db86aabSstevel 		    driver_name, unitp->instance);
24083db86aabSstevel 		return (status);
24093db86aabSstevel 	}
24103db86aabSstevel 
24113db86aabSstevel 	val = ~val;
24123db86aabSstevel 	if ((chip->val & 0x3F) == 0) {
24133db86aabSstevel 		if (!(envctrl_isother_fault_led(unitp, val,
24143db86aabSstevel 		    ENVCTRL_UE250_FSP_DISK_ERR))) {
24153db86aabSstevel 			val &= ~(ENVCTRL_UE250_FSP_DISK_ERR);
24163db86aabSstevel 		} else {
24173db86aabSstevel 			val &= ~(ENVCTRL_UE250_FSP_DISK_ERR |
24183db86aabSstevel 			    ENVCTRL_UE250_FSP_GEN_ERR);
24193db86aabSstevel 		}
24203db86aabSstevel 		val = (val & ~(ENVCTRL_UE250_FSP_DISK_ERR |
24213db86aabSstevel 		    ENVCTRL_UE250_FSP_GEN_ERR));
24223db86aabSstevel 	} else {
24233db86aabSstevel 		val = (val | (ENVCTRL_UE250_FSP_DISK_ERR |
24243db86aabSstevel 		    ENVCTRL_UE250_FSP_GEN_ERR));
24253db86aabSstevel 	}
24263db86aabSstevel 
24273db86aabSstevel 	status = envctrl_set_fsp(unitp, &val);
24283db86aabSstevel 	if (status == DDI_FAILURE) {
24293db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (FSP) failed",
24303db86aabSstevel 		    driver_name, unitp->instance);
24313db86aabSstevel 		return (status);
24323db86aabSstevel 	}
24333db86aabSstevel 
24343db86aabSstevel 
24353db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV5,
24363db86aabSstevel 	    0, &val, 1);
24373db86aabSstevel 	if (status == DDI_FAILURE) {
24383db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
24393db86aabSstevel 		    driver_name, unitp->instance);
24403db86aabSstevel 		return (status);
24413db86aabSstevel 	}
24423db86aabSstevel 
24433db86aabSstevel 	envctrl_update_disk_kstats(unitp, val, ~(chip->val));
24443db86aabSstevel 
24453db86aabSstevel 	/*
24463db86aabSstevel 	 * we take the ones compliment of the val passed in
24473db86aabSstevel 	 * because the hardware thinks that a "low" or "0"
24483db86aabSstevel 	 * is the way to indicate a fault. of course software
24493db86aabSstevel 	 * knows that a 1 is a TRUE state or fault. ;-)
24503db86aabSstevel 	 */
24513db86aabSstevel 
24523db86aabSstevel 	confirm_val_hold = chip->val;
24533db86aabSstevel 
24543db86aabSstevel 	chip->val = ~(chip->val);
24553db86aabSstevel 
24563db86aabSstevel 	while (confirm_count < confirm_max) {
24573db86aabSstevel 		status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
24583db86aabSstevel 		    0, &chip->val, 1);
24593db86aabSstevel 		if (status == DDI_FAILURE) {
24603db86aabSstevel 			cmn_err(CE_WARN, "%s%d: Write PCF8574A (DISKFL) failed",
24613db86aabSstevel 			    driver_name, unitp->instance);
24623db86aabSstevel 			return (status);
24633db86aabSstevel 		} else {
24643db86aabSstevel 			/*
24653db86aabSstevel 			 * Sometimes the i2c hardware status is not
24663db86aabSstevel 			 * completely dependable as far as reporting
24673db86aabSstevel 			 * a condition where the set does not take
24683db86aabSstevel 			 * place. So we read back the set value to
24693db86aabSstevel 			 * confirm what we set.
24703db86aabSstevel 			 */
24713db86aabSstevel 			confirm_chip.type = chip->type;
24723db86aabSstevel 			confirm_chip.chip_num = chip->chip_num;
24733db86aabSstevel 			confirm_chip.index = chip->index;
24743db86aabSstevel 			status = envctrl_get_dskled(unitp, &confirm_chip);
24753db86aabSstevel 			if (status != DDI_SUCCESS) {
24763db86aabSstevel 				return (status);
24773db86aabSstevel 			} else if (confirm_chip.val != confirm_val_hold) {
24783db86aabSstevel 				confirm_count++;
24793db86aabSstevel 				drv_usecwait(1000);
24803db86aabSstevel 				continue;
24813db86aabSstevel 			} else
24823db86aabSstevel 				/*
24833db86aabSstevel 				 * Set was confirmed.
24843db86aabSstevel 				 */
24853db86aabSstevel 				break;
24863db86aabSstevel 		}
24873db86aabSstevel 	}
24883db86aabSstevel 
24893db86aabSstevel 	if (confirm_count == confirm_max)
24903db86aabSstevel 		return (DDI_FAILURE);
24913db86aabSstevel 
24923db86aabSstevel 	return (DDI_SUCCESS);
24933db86aabSstevel }
24943db86aabSstevel 
24953db86aabSstevel /*
24963db86aabSstevel  * After setting the fan speed, we read back the fan speed to confirm
24973db86aabSstevel  * that the new value is within an acceptable range, else we retry.
24983db86aabSstevel  * We do not confirm the fan speed if the set value is below the
24993db86aabSstevel  * hardware determined speed (based on system temeratures).
25003db86aabSstevel  */
25013db86aabSstevel static int
25023db86aabSstevel envctrl_set_fanspeed(struct envctrlunit *unitp, struct envctrl_chip *fanspeed)
25033db86aabSstevel {
25043db86aabSstevel 	int readback_speed, max_speed;
25053db86aabSstevel 	int status;
25063db86aabSstevel 	int confirm_count = 0, confirm_max = 20;
25073db86aabSstevel 	uint8_t fanspeed_hold;
25083db86aabSstevel 
25093db86aabSstevel 	fanspeed_hold = fanspeed->val;
25103db86aabSstevel 	while (confirm_count < confirm_max) {
25113db86aabSstevel 		status = envctrl_write_chip(unitp, ENVCTRL_PCF8591,
25123db86aabSstevel 		    EHC_DEV2, 0, &fanspeed->val, 1);
25133db86aabSstevel 		if (status == DDI_FAILURE) {
25143db86aabSstevel 			envctrl_fan_fail_service(unitp);
25153db86aabSstevel 			cmn_err(CE_WARN,
25163db86aabSstevel 			"%s%d: Set fanspeed failed", driver_name,
25173db86aabSstevel 			    unitp->instance);
25183db86aabSstevel 			return (status);
25193db86aabSstevel 		} else {
25203db86aabSstevel 			drv_usecwait(100000);
25213db86aabSstevel 			envctrl_update_fanspeed(unitp);
25223db86aabSstevel 			readback_speed = unitp->fan_kstats.fanspeed;
25233db86aabSstevel 			if (fanspeed_hold > idle_fanspeed) {
25243db86aabSstevel 				max_speed =
2525*19397407SSherry Moore 				    (fanspeed->val + FAN_DRIFT >
2526*19397407SSherry Moore 				    MAX_FAN_SPEED) ?  MAX_FAN_SPEED :
2527*19397407SSherry Moore 				    (fanspeed->val + FAN_DRIFT);
25283db86aabSstevel 				if ((readback_speed < fanspeed->val -
25293db86aabSstevel 				    FAN_DRIFT) ||
25303db86aabSstevel 				    (readback_speed > max_speed)) {
25313db86aabSstevel 					confirm_count++;
25323db86aabSstevel 					drv_usecwait(1000);
25333db86aabSstevel 					continue;
25343db86aabSstevel 				}
25353db86aabSstevel 			}
25363db86aabSstevel 			break;
25373db86aabSstevel 		}
25383db86aabSstevel 	}
25393db86aabSstevel 
25403db86aabSstevel 	if (confirm_count == confirm_max)
25413db86aabSstevel 		return (DDI_FAILURE);
25423db86aabSstevel 
25433db86aabSstevel 	return (DDI_SUCCESS);
25443db86aabSstevel }
25453db86aabSstevel 
25463db86aabSstevel static void
25473db86aabSstevel envctrl_add_kstats(struct envctrlunit *unitp)
25483db86aabSstevel {
25493db86aabSstevel 
25503db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
25513db86aabSstevel 
25523db86aabSstevel 	if ((unitp->enclksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
25533db86aabSstevel 	    ENVCTRL_KSTAT_ENCL, "misc", KSTAT_TYPE_RAW,
25543db86aabSstevel 	    sizeof (unitp->encl_kstats),
25553db86aabSstevel 	    KSTAT_FLAG_PERSISTENT)) == NULL) {
25563db86aabSstevel 		cmn_err(CE_WARN, "%s%d: encl raw kstat_create failed",
25573db86aabSstevel 		    driver_name, unitp->instance);
25583db86aabSstevel 		return;
25593db86aabSstevel 	}
25603db86aabSstevel 
25613db86aabSstevel 	unitp->enclksp->ks_update = envctrl_encl_kstat_update;
25623db86aabSstevel 	unitp->enclksp->ks_private = (void *)unitp;
25633db86aabSstevel 	kstat_install(unitp->enclksp);
25643db86aabSstevel 
25653db86aabSstevel 
25663db86aabSstevel 	if ((unitp->fanksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
25673db86aabSstevel 	    ENVCTRL_KSTAT_FANSTAT, "misc", KSTAT_TYPE_RAW,
25683db86aabSstevel 	    sizeof (unitp->fan_kstats),
25693db86aabSstevel 	    KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
25703db86aabSstevel 		cmn_err(CE_WARN, "%s%d: fans kstat_create failed",
25713db86aabSstevel 		    driver_name, unitp->instance);
25723db86aabSstevel 		return;
25733db86aabSstevel 	}
25743db86aabSstevel 
25753db86aabSstevel 	unitp->fanksp->ks_update = envctrl_fanstat_kstat_update;
25763db86aabSstevel 	unitp->fanksp->ks_private = (void *)unitp;
25773db86aabSstevel 	kstat_install(unitp->fanksp);
25783db86aabSstevel 
25793db86aabSstevel 	if ((unitp->psksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
25803db86aabSstevel 	    ENVCTRL_KSTAT_PSNAME2, "misc", KSTAT_TYPE_RAW,
25813db86aabSstevel 	    sizeof (unitp->ps_kstats),
25823db86aabSstevel 	    KSTAT_FLAG_PERSISTENT)) == NULL) {
25833db86aabSstevel 		cmn_err(CE_WARN, "%s%d: ps name kstat_create failed",
25843db86aabSstevel 		    driver_name, unitp->instance);
25853db86aabSstevel 		return;
25863db86aabSstevel 	}
25873db86aabSstevel 
25883db86aabSstevel 	unitp->psksp->ks_update = envctrl_ps_kstat_update;
25893db86aabSstevel 	unitp->psksp->ks_private = (void *)unitp;
25903db86aabSstevel 	kstat_install(unitp->psksp);
25913db86aabSstevel 
25923db86aabSstevel 	if ((unitp->tempksp = kstat_create(ENVCTRL_MODULE_NAME,
25933db86aabSstevel 	    unitp->instance, ENVCTRL_KSTAT_TEMPERATURE, "misc", KSTAT_TYPE_RAW,
25943db86aabSstevel 	    sizeof (unitp->temp_kstats),
25953db86aabSstevel 	    KSTAT_FLAG_PERSISTENT)) == NULL) {
25963db86aabSstevel 		cmn_err(CE_WARN, "%s%d: temp name kstat_create failed",
25973db86aabSstevel 		    driver_name, unitp->instance);
25983db86aabSstevel 		return;
25993db86aabSstevel 	}
26003db86aabSstevel 
26013db86aabSstevel 	unitp->tempksp->ks_update = envctrl_temp_kstat_update;
26023db86aabSstevel 	unitp->tempksp->ks_private = (void *)unitp;
26033db86aabSstevel 	kstat_install(unitp->tempksp);
26043db86aabSstevel 
26053db86aabSstevel 	if ((unitp->diskksp = kstat_create(ENVCTRL_MODULE_NAME,
26063db86aabSstevel 	    unitp->instance, ENVCTRL_KSTAT_DISK, "misc", KSTAT_TYPE_RAW,
26073db86aabSstevel 	    sizeof (unitp->disk_kstats),
26083db86aabSstevel 	    KSTAT_FLAG_PERSISTENT)) == NULL) {
26093db86aabSstevel 		cmn_err(CE_WARN, "%s%d: disk name kstat_create failed",
26103db86aabSstevel 		    driver_name, unitp->instance);
26113db86aabSstevel 		return;
26123db86aabSstevel 	}
26133db86aabSstevel 
26143db86aabSstevel 	unitp->diskksp->ks_update = envctrl_disk_kstat_update;
26153db86aabSstevel 	unitp->diskksp->ks_private = (void *)unitp;
26163db86aabSstevel 	kstat_install(unitp->diskksp);
26173db86aabSstevel 
26183db86aabSstevel }
26193db86aabSstevel 
26203db86aabSstevel static int
26213db86aabSstevel envctrl_ps_kstat_update(kstat_t *ksp, int rw)
26223db86aabSstevel {
26233db86aabSstevel 	struct envctrlunit *unitp;
26243db86aabSstevel 	char *kstatp;
26253db86aabSstevel 
26263db86aabSstevel 
26273db86aabSstevel 
26283db86aabSstevel 	unitp = (struct envctrlunit *)ksp->ks_private;
26293db86aabSstevel 
26303db86aabSstevel 	mutex_enter(&unitp->umutex);
26313db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
26323db86aabSstevel 
26333db86aabSstevel 	kstatp = (char *)ksp->ks_data;
26343db86aabSstevel 
26353db86aabSstevel 	if (rw == KSTAT_WRITE) {
26363db86aabSstevel 		mutex_exit(&unitp->umutex);
26373db86aabSstevel 		return (EACCES);
26383db86aabSstevel 	} else {
26393db86aabSstevel 
26403db86aabSstevel 		unitp->psksp->ks_ndata = unitp->num_ps_present;
26413db86aabSstevel 		bcopy((caddr_t)&unitp->ps_kstats, kstatp,
26423db86aabSstevel 		    sizeof (unitp->ps_kstats));
26433db86aabSstevel 	}
26443db86aabSstevel 	mutex_exit(&unitp->umutex);
26453db86aabSstevel 	return (DDI_SUCCESS);
26463db86aabSstevel }
26473db86aabSstevel 
26483db86aabSstevel static int
26493db86aabSstevel envctrl_fanstat_kstat_update(kstat_t *ksp, int rw)
26503db86aabSstevel {
26513db86aabSstevel 	struct envctrlunit *unitp;
26523db86aabSstevel 	char *kstatp;
26533db86aabSstevel 
26543db86aabSstevel 	kstatp = (char *)ksp->ks_data;
26553db86aabSstevel 	unitp = (struct envctrlunit *)ksp->ks_private;
26563db86aabSstevel 
26573db86aabSstevel 	mutex_enter(&unitp->umutex);
26583db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
26593db86aabSstevel 
26603db86aabSstevel 	if (rw == KSTAT_WRITE) {
26613db86aabSstevel 		mutex_exit(&unitp->umutex);
26623db86aabSstevel 		return (EACCES);
26633db86aabSstevel 	} else {
26643db86aabSstevel 		unitp->fanksp->ks_ndata = unitp->num_fans_present;
26653db86aabSstevel 		bcopy((caddr_t)&unitp->fan_kstats, kstatp,
26663db86aabSstevel 		    sizeof (unitp->fan_kstats));
26673db86aabSstevel 	}
26683db86aabSstevel 	mutex_exit(&unitp->umutex);
26693db86aabSstevel 	return (DDI_SUCCESS);
26703db86aabSstevel }
26713db86aabSstevel 
26723db86aabSstevel static int
26733db86aabSstevel envctrl_encl_kstat_update(kstat_t *ksp, int rw)
26743db86aabSstevel {
26753db86aabSstevel 	struct envctrlunit *unitp;
26763db86aabSstevel 	char *kstatp;
26773db86aabSstevel 	int status;
26783db86aabSstevel 
26793db86aabSstevel 
26803db86aabSstevel 	kstatp = (char *)ksp->ks_data;
26813db86aabSstevel 	unitp = (struct envctrlunit *)ksp->ks_private;
26823db86aabSstevel 
26833db86aabSstevel 	mutex_enter(&unitp->umutex);
26843db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
26853db86aabSstevel 
26863db86aabSstevel 	if (rw == KSTAT_WRITE) {
26873db86aabSstevel 		mutex_exit(&unitp->umutex);
26883db86aabSstevel 		return (EACCES);
26893db86aabSstevel 	} else {
26903db86aabSstevel 
26913db86aabSstevel 		unitp->enclksp->ks_ndata = unitp->num_encl_present;
26923db86aabSstevel 		status = envctrl_get_fpm_status(unitp, (uint8_t *)NULL);
26933db86aabSstevel 		if (status == DDI_SUCCESS)
26943db86aabSstevel 			bcopy((caddr_t)&unitp->encl_kstats, kstatp,
26953db86aabSstevel 			    sizeof (unitp->encl_kstats));
26963db86aabSstevel 	}
26973db86aabSstevel 	mutex_exit(&unitp->umutex);
26983db86aabSstevel 	return (DDI_SUCCESS);
26993db86aabSstevel }
27003db86aabSstevel 
27013db86aabSstevel static int
27023db86aabSstevel envctrl_temp_kstat_update(kstat_t *ksp, int rw)
27033db86aabSstevel {
27043db86aabSstevel 	struct envctrlunit *unitp;
27053db86aabSstevel 	char *kstatp;
27063db86aabSstevel 
27073db86aabSstevel 	kstatp = (char *)ksp->ks_data;
27083db86aabSstevel 	unitp = (struct envctrlunit *)ksp->ks_private;
27093db86aabSstevel 
27103db86aabSstevel 	mutex_enter(&unitp->umutex);
27113db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
27123db86aabSstevel 
27133db86aabSstevel 	if (rw == KSTAT_WRITE) {
27143db86aabSstevel 		mutex_exit(&unitp->umutex);
27153db86aabSstevel 		return (EACCES);
27163db86aabSstevel 	} else {
27173db86aabSstevel 		unitp->tempksp->ks_ndata = unitp->num_temps_present;
27183db86aabSstevel 		bcopy((caddr_t)unitp->temp_kstats, kstatp,
27193db86aabSstevel 		    sizeof (unitp->temp_kstats));
27203db86aabSstevel 	}
27213db86aabSstevel 	mutex_exit(&unitp->umutex);
27223db86aabSstevel 	return (DDI_SUCCESS);
27233db86aabSstevel }
27243db86aabSstevel 
27253db86aabSstevel static int
27263db86aabSstevel envctrl_disk_kstat_update(kstat_t *ksp, int rw)
27273db86aabSstevel {
27283db86aabSstevel 	struct envctrlunit *unitp;
27293db86aabSstevel 	char *kstatp;
27303db86aabSstevel 
27313db86aabSstevel 	kstatp = (char *)ksp->ks_data;
27323db86aabSstevel 	unitp = (struct envctrlunit *)ksp->ks_private;
27333db86aabSstevel 
27343db86aabSstevel 	mutex_enter(&unitp->umutex);
27353db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
27363db86aabSstevel 
27373db86aabSstevel 	if (rw == KSTAT_WRITE) {
27383db86aabSstevel 		mutex_exit(&unitp->umutex);
27393db86aabSstevel 		return (EACCES);
27403db86aabSstevel 	} else {
27413db86aabSstevel 		unitp->diskksp->ks_ndata = unitp->num_disks_present;
27423db86aabSstevel 		bcopy((caddr_t)unitp->disk_kstats, kstatp,
27433db86aabSstevel 		    sizeof (unitp->disk_kstats));
27443db86aabSstevel 	}
27453db86aabSstevel 	mutex_exit(&unitp->umutex);
27463db86aabSstevel 	return (DDI_SUCCESS);
27473db86aabSstevel }
27483db86aabSstevel 
27493db86aabSstevel static void
27503db86aabSstevel envctrl_init_encl_kstats(struct envctrlunit *unitp)
27513db86aabSstevel {
27523db86aabSstevel 	uint8_t val;
27533db86aabSstevel 	int status;
27543db86aabSstevel 
27553db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
27563db86aabSstevel 
27573db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
27583db86aabSstevel 	    0, &val, 1);
27593db86aabSstevel 	if (status == DDI_FAILURE) {
27603db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (FSP) failed",
27613db86aabSstevel 		    driver_name, unitp->instance);
27623db86aabSstevel 		return;
27633db86aabSstevel 	}
27643db86aabSstevel 
27653db86aabSstevel 	unitp->encl_kstats.value = val;
27663db86aabSstevel }
27673db86aabSstevel 
27683db86aabSstevel static void
27693db86aabSstevel envctrl_check_disk_kstats(struct envctrlunit *unitp)
27703db86aabSstevel {
27713db86aabSstevel 	uint8_t diskpr, diskfl;
27723db86aabSstevel 	int status;
27733db86aabSstevel 
27743db86aabSstevel 	ASSERT(MUTEX_HELD(&unitp->umutex));
27753db86aabSstevel 
27763db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV5,
27773db86aabSstevel 	    0, &diskpr, 1);
27783db86aabSstevel 	if (status == DDI_FAILURE) {
27793db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKPR) failed",
27803db86aabSstevel 		    driver_name, unitp->instance);
27813db86aabSstevel 	}
27823db86aabSstevel 
27833db86aabSstevel 	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
27843db86aabSstevel 	    0, &diskfl, 1);
27853db86aabSstevel 	if (status == DDI_FAILURE) {
27863db86aabSstevel 		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
27873db86aabSstevel 		    driver_name, unitp->instance);
27883db86aabSstevel 	}
27893db86aabSstevel 
27903db86aabSstevel 	envctrl_update_disk_kstats(unitp, diskpr, diskfl);
27913db86aabSstevel 
27923db86aabSstevel }
27933db86aabSstevel 
27943db86aabSstevel static void
27953db86aabSstevel envctrl_update_disk_kstats(struct envctrlunit *unitp, uint8_t diskpr,
27963db86aabSstevel 	uint8_t diskfl)
27973db86aabSstevel {
27983db86aabSstevel 	int i, j, count = 0;
27993db86aabSstevel 
28003db86aabSstevel 	DPRINTF1("diskpr = %X, diskfl = %X\n", diskpr, diskfl);
28013db86aabSstevel 	for (i = 0, j = 1; i < ENVCTRL_UE250_MAX_DISKS; i++, j = j << 1) {
28023db86aabSstevel 		if (!(diskpr & j)) {
28033db86aabSstevel 			if (!(diskfl & j))
28043db86aabSstevel 				unitp->disk_kstats[count].disk_ok = 0;
28053db86aabSstevel 			else
28063db86aabSstevel 				unitp->disk_kstats[count].disk_ok = 1;
28073db86aabSstevel 			unitp->disk_kstats[count].slot = i;
28083db86aabSstevel 			count++;
28093db86aabSstevel 		}
28103db86aabSstevel 	}
28113db86aabSstevel 
28123db86aabSstevel 	unitp->num_disks_present = count;
28133db86aabSstevel }
28143db86aabSstevel 
28153db86aabSstevel static void
28163db86aabSstevel envctrl_probe_cpus(struct envctrlunit *unitp)
28173db86aabSstevel {
28183db86aabSstevel 	int instance;
28193db86aabSstevel 
28203db86aabSstevel 	/*
28213db86aabSstevel 	 * The cpu search is as follows:
28223db86aabSstevel 	 * If there is only 1 CPU module it is named as
28233db86aabSstevel 	 * SUNW,UltraSPARC. If this is a match we still don't
28243db86aabSstevel 	 * know what slot the cpu module is in therefore
28253db86aabSstevel 	 * we need to check the "upa-portid" property.
28263db86aabSstevel 	 * If we have more than 1 cpu, then they are appended by
28273db86aabSstevel 	 * instance numbers and slot locations. e.g.
28283db86aabSstevel 	 * SUNW,UltraSPARC@1,0 (slot 1). it would have been
28293db86aabSstevel 	 * nice to have the naming consistent for one CPU e.g.
28303db86aabSstevel 	 * SUNW,UltraSPARC@0,0...sigh
28313db86aabSstevel 	 */
28323db86aabSstevel 
28333db86aabSstevel 	for (instance = 0; instance < ENVCTRL_MAX_CPUS; instance++) {
28343db86aabSstevel 		unitp->cpu_pr_location[instance] = B_FALSE;
28353db86aabSstevel 	}
28363db86aabSstevel 
28373db86aabSstevel 	ddi_walk_devs(ddi_root_node(), envctrl_match_cpu, unitp);
28383db86aabSstevel }
28393db86aabSstevel 
28403db86aabSstevel static int
28413db86aabSstevel envctrl_match_cpu(dev_info_t *dip, void *arg)
28423db86aabSstevel {
28433db86aabSstevel 
28443db86aabSstevel 	int cpu_slot;
28453db86aabSstevel 	char name[32];
28463db86aabSstevel 	char name1[32];
28473db86aabSstevel 	struct envctrlunit *unitp = (struct envctrlunit *)arg;
28483db86aabSstevel 
28493db86aabSstevel 	(void) sprintf(name, "%s", ENVCTRL_ULTRA1CPU_STRING);
28503db86aabSstevel 	(void) sprintf(name1, "%s", ENVCTRL_ULTRA2CPU_STRING);
28513db86aabSstevel 
28523db86aabSstevel 	if ((strcmp(ddi_node_name(dip), name) == 0) ||
28533db86aabSstevel 	    (strcmp(ddi_node_name(dip), name1) == 0)) {
28543db86aabSstevel 		if ((cpu_slot = (int)ddi_getprop(DDI_DEV_T_ANY, dip,
28553db86aabSstevel 		    DDI_PROP_DONTPASS, "upa-portid",
28563db86aabSstevel 		    -1)) == -1) {
28573db86aabSstevel 			cmn_err(CE_WARN, "%s%d: no cpu upa-portid",
28583db86aabSstevel 			    driver_name, unitp->instance);
28593db86aabSstevel 		} else {
28603db86aabSstevel 			unitp->cpu_pr_location[cpu_slot] = B_TRUE;
28613db86aabSstevel 			unitp->num_cpus_present++;
28623db86aabSstevel 		}
28633db86aabSstevel 	}
28643db86aabSstevel 
28653db86aabSstevel 	return (DDI_WALK_CONTINUE);
28663db86aabSstevel }
28673db86aabSstevel 
28683db86aabSstevel /*
28693db86aabSstevel  * This routine returns TRUE if some other error condition
28703db86aabSstevel  * has set the GEN_ERR FAULT LED. Tp further complicate this
28713db86aabSstevel  * LED panel we have overloaded the GEN_ERR LED to indicate
28723db86aabSstevel  * that a fan fault has occurred without having a fan fault
28733db86aabSstevel  * LED as does all other error conditions. So we just take the
28743db86aabSstevel  * software state and return true. The whole purpose of this functon
28753db86aabSstevel  * is to tell us wehther or not we can shut off the GEN_FAULT LED.
28763db86aabSstevel  * NOTE: this ledval is usually one of the following FSP vals
28773db86aabSstevel  * EXCEPT in the case of the fan fail.. we pass in a "0".
28783db86aabSstevel  */
28793db86aabSstevel 
28803db86aabSstevel static int
28813db86aabSstevel envctrl_isother_fault_led(struct envctrlunit *unitp, uint8_t fspval,
28823db86aabSstevel     uint8_t thisled)
28833db86aabSstevel {
28843db86aabSstevel 	int status = B_FALSE;
28853db86aabSstevel 
28863db86aabSstevel 	if (fspval != 0) {
28873db86aabSstevel 		fspval = (fspval & ~(thisled));
28883db86aabSstevel 	}
28893db86aabSstevel 	if ((unitp->fan_failed == B_TRUE) && thisled != 0) {
28903db86aabSstevel 		status = B_TRUE;
28913db86aabSstevel 	} else if (fspval & ENVCTRL_UE250_FSP_DISK_ERR) {
28923db86aabSstevel 		status = B_TRUE;
28933db86aabSstevel 	} else if (fspval & ENVCTRL_UE250_FSP_PS_ERR) {
28943db86aabSstevel 		status = B_TRUE;
28953db86aabSstevel 	} else if (fspval & ENVCTRL_UE250_FSP_TEMP_ERR) {
28963db86aabSstevel 		status = B_TRUE;
28973db86aabSstevel 	}
28983db86aabSstevel 	return (status);
28993db86aabSstevel }
29003db86aabSstevel 
29013db86aabSstevel static void
29023db86aabSstevel envctrl_pshotplug_poll(void *arg)
29033db86aabSstevel {
29043db86aabSstevel 	struct envctrlunit *unitp = (struct envctrlunit *)arg;
29053db86aabSstevel 
29063db86aabSstevel 	mutex_enter(&unitp->umutex);
29073db86aabSstevel 
29083db86aabSstevel 	envctrl_ps_probe(unitp);
29093db86aabSstevel 
29103db86aabSstevel 	mutex_exit(&unitp->umutex);
29113db86aabSstevel }
2912