1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28/*
29 * ENVCTRLTWO_ Environment Monitoring driver for i2c on Javelin
30 *
31 */
32#include <sys/param.h>
33#include <sys/types.h>
34#include <sys/signal.h>
35#include <sys/errno.h>
36#include <sys/file.h>
37#include <sys/termio.h>
38#include <sys/termios.h>
39#include <sys/cmn_err.h>
40#include <sys/stream.h>
41#include <sys/strsun.h>
42#include <sys/stropts.h>
43#include <sys/strtty.h>
44#include <sys/debug.h>
45#include <sys/eucioctl.h>
46#include <sys/cred.h>
47#include <sys/uio.h>
48#include <sys/stat.h>
49#include <sys/kmem.h>
50
51#include <sys/ddi.h>
52#include <sys/sunddi.h>
53#include <sys/obpdefs.h>
54#include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
55#include <sys/modctl.h>		/* for modldrv */
56#include <sys/stat.h>		/* ddi_create_minor_node S_IFCHR */
57#include <sys/open.h>		/* for open params.	 */
58#include <sys/uio.h>		/* for read/write */
59#include <sys/envctrl_gen.h>	/* user level generic visible definitions */
60#include <sys/envctrl_ue250.h>	/* user level UE250 visible definitions */
61#include <javelin/sys/envctrltwo.h> /* definitions for Javelin */
62#include <io/envctrl_targets.c>
63#include <sys/priv_names.h>
64
65/* driver entry point fn definitions */
66static int 	envctrl_open(dev_t *, int, int, cred_t *);
67static int	envctrl_close(dev_t, int, int, cred_t *);
68static int	envctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
69static uint_t 	envctrl_bus_isr(caddr_t);
70static uint_t 	envctrl_dev_isr(caddr_t);
71
72/* configuration entry point fn definitions */
73static int 	envctrl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
74static int	envctrl_attach(dev_info_t *, ddi_attach_cmd_t);
75static int	envctrl_detach(dev_info_t *, ddi_detach_cmd_t);
76
77/* Driver private routines */
78#ifdef GET_CPU_TEMP
79static int	envctrl_get_cpu_temp(struct envctrlunit *, int);
80#endif
81static void	envctrl_fan_fail_service(struct envctrlunit *);
82static void	envctrl_PS_intr_service(struct envctrlunit *);
83static void	envctrl_ps_probe(struct envctrlunit *);
84static void	envctrl_tempr_poll(void *);
85static void	envctrl_pshotplug_poll(void *);
86static void	envctrl_led_blink(void *);
87static void	envctrl_init_bus(struct envctrlunit *);
88static void	envctrl_reset_dflop(struct envctrlunit *);
89static void	envctrl_enable_devintrs(struct envctrlunit *);
90static void	envctrl_intr_latch_clr(struct envctrlunit *);
91static void	envctrl_abort_seq_handler(char *msg);
92static int	envctrl_get_fpm_status(struct envctrlunit *, uint8_t *);
93static int	envctrl_set_fsp(struct envctrlunit *, uint8_t *);
94static int	envctrl_set_dskled(struct envctrlunit *,
95				struct envctrl_chip *);
96static int	envctrl_get_dskled(struct envctrlunit *,
97				struct envctrl_chip *);
98static int	envctrl_set_fanspeed(struct envctrlunit *,
99			struct envctrl_chip *);
100static void	envctrl_probe_cpus(struct envctrlunit *);
101static int	envctrl_match_cpu(dev_info_t *, void *);
102static int	envctrl_isother_fault_led(struct envctrlunit *,
103		    uint8_t, uint8_t);
104static int	envctrl_check_sys_temperatures(struct envctrlunit *);
105static void	envctrl_check_disk_kstats(struct envctrlunit *);
106static void	envctrl_update_disk_kstats(struct envctrlunit *,
107			uint8_t, uint8_t);
108static int	envctrl_read_chip(struct envctrlunit *, int, int, int,
109			uint8_t *, int);
110static int	envctrl_write_chip(struct envctrlunit *, int, int, int,
111			uint8_t *, int);
112static int	envctrl_check_tempr_levels(struct envctrlunit *,
113		int, uint8_t *, int);
114static void	envctrl_update_fanspeed(struct envctrlunit *);
115
116/* Kstat routines */
117static void	envctrl_add_kstats(struct envctrlunit *);
118static int	envctrl_ps_kstat_update(kstat_t *, int);
119static int	envctrl_fanstat_kstat_update(kstat_t *, int);
120static int	envctrl_encl_kstat_update(kstat_t *, int);
121static int	envctrl_temp_kstat_update(kstat_t *, int);
122static int	envctrl_disk_kstat_update(kstat_t *, int);
123static void	envctrl_init_encl_kstats(struct envctrlunit *);
124
125extern void power_down(const char *);
126extern int prom_getprop();
127extern int prom_getproplen();
128extern	void	prom_printf(const char *fmt, ...);
129extern void (*abort_seq_handler)();
130
131static void    *envctrlsoft_statep;
132
133static char driver_name[] = "envctrltwo";
134static uchar_t _cpu_temps[256];
135static uchar_t _cpu_fan_speeds[256];
136static int psok[2] = {-1, -1};
137static int pspr[2] = {-1, -1};
138static uint8_t idle_fanspeed;
139
140static int power_flt_led_lit = 0;
141
142extern void pci_thermal_rem_intr(dev_info_t *, uint_t);
143
144/* Local Variables */
145/* Indicates whether or not the overtemp thread has been started */
146static int envctrl_debug_flags = 0;
147static int envctrl_power_off_overide = 0;
148static int envctrl_max_retries = 200;
149static int envctrl_allow_detach = 0;
150static int envctrl_numcpus = 1;
151static int envctrl_handler = 1; /* 1 is the default */
152static clock_t overtemp_timeout_hz;
153static clock_t blink_timeout_hz;
154static clock_t pshotplug_timeout_hz;
155static clock_t warning_timeout_hz;
156/*
157 * Temperature levels :
158 * green = OK  - no action needed
159 * yellow = warning - display warning message and poll faster
160 * red = critical - shutdown system
161 */
162enum levels {green, yellow, red};
163
164#define	DPRINTF1 if (envctrl_debug_flags && (envctrl_debug_flags & 0x1)) printf
165#define	DPRINTF2 if (envctrl_debug_flags && (envctrl_debug_flags & 0x2)) printf
166#define	DPRINTF3 if (envctrl_debug_flags && (envctrl_debug_flags & 0x4)) printf
167
168#define	JAV_FAN_SPEED_SF_NUM	107
169#define	JAV_FAN_SPEED_SF_DEN	100
170#define	JAV_MAX_TEMP_SENSORS	6
171#define	JAV_FSP_MASK		0xC0
172#define	FAN_DRIFT		25
173#define	MAX_FAN_SPEED		255
174#define	MAX_DEVS		16
175
176#define	ENVCTRL_UE250_INTR_LATCH_INIT0 0xFE
177#define	ENVCTRL_UE250_INTR_LATCH_INIT1 0xFF
178
179static int t_scale_num[8];
180static int t_scale_den[8];
181static uint8_t t_addr[8];
182static uint8_t t_port[8];
183static int sensor_types[] = { ENVCTRL_UE250_CPU0_SENSOR,
184			ENVCTRL_UE250_CPU1_SENSOR, ENVCTRL_UE250_MB0_SENSOR,
185			ENVCTRL_UE250_MB1_SENSOR, ENVCTRL_UE250_PDB_SENSOR,
186			ENVCTRL_UE250_SCSI_SENSOR };
187
188static struct cb_ops envctrl_cb_ops = {
189	envctrl_open,		/* cb_open */
190	envctrl_close,		/* cb_close */
191	nodev,			/* cb_strategy */
192	nodev,			/* cb_print */
193	nodev,			/* cb_dump */
194	nodev,			/* cb_read */
195	nodev,			/* cb_write */
196	envctrl_ioctl,		/* cb_ioctl */
197	nodev,			/* cb_devmap */
198	nodev,			/* cb_mmap */
199	nodev,			/* cb_segmap */
200	nochpoll,		/* cb_chpoll */
201	ddi_prop_op,		/* cb_prop_op */
202	NULL,			/* cb_stream */
203	(int)(D_NEW | D_MP)	/* cb_flag */
204};
205
206/*
207 * Declare ops vectors for auto configuration.
208 */
209struct dev_ops  envctrltwo_ops = {
210	DEVO_REV,		/* devo_rev */
211	0,			/* devo_refcnt */
212	envctrl_getinfo,	/* devo_getinfo */
213	nulldev,		/* devo_identify */
214	nulldev,		/* devo_probe */
215	envctrl_attach,		/* devo_attach */
216	envctrl_detach,		/* devo_detach */
217	nodev,			/* devo_reset */
218	&envctrl_cb_ops,	/* devo_cb_ops */
219	(struct bus_ops *)NULL,	/* devo_bus_ops */
220	nulldev,		/* devo_power */
221	ddi_quiesce_not_supported,	/* devo_quiesce */
222};
223
224extern struct mod_ops mod_driverops;
225
226static struct modldrv envctrlmodldrv = {
227	&mod_driverops,		/* type of module - driver */
228	"I2C ENVCTRLTWO_driver",
229	&envctrltwo_ops,
230};
231
232static struct modlinkage envctrlmodlinkage = {
233	MODREV_1,
234	&envctrlmodldrv,
235	0
236};
237
238int
239_init(void)
240{
241	register int    error;
242
243	if ((error = mod_install(&envctrlmodlinkage)) == 0) {
244		(void) ddi_soft_state_init(&envctrlsoft_statep,
245		    sizeof (struct envctrlunit), 1);
246	}
247
248	return (error);
249}
250
251int
252_fini(void)
253{
254	register int    error;
255
256	if ((error = mod_remove(&envctrlmodlinkage)) == 0)
257		ddi_soft_state_fini(&envctrlsoft_statep);
258
259	return (error);
260}
261
262int
263_info(struct modinfo *modinfop)
264{
265	return (mod_info(&envctrlmodlinkage, modinfop));
266}
267
268static int
269envctrl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
270{
271	register int	instance;
272	char		name[16];
273	uint8_t fspval;
274	register struct	envctrlunit *unitp;
275	struct ddi_device_acc_attr attr;
276	uchar_t *creg_prop;
277	uint_t len, tblsz;
278	int i, j, k, status;
279	uint8_t fanspeed;
280
281	status = len = tblsz = 0;
282
283	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
284	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
285
286	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
287
288	instance = ddi_get_instance(dip);
289
290	switch (cmd) {
291	case DDI_ATTACH:
292		break;
293	case DDI_RESUME:
294		if (!(unitp = ddi_get_soft_state(envctrlsoft_statep, instance)))
295			return (DDI_FAILURE);
296		mutex_enter(&unitp->umutex);
297		if (!unitp->suspended) {
298			mutex_exit(&unitp->umutex);
299			return (DDI_FAILURE);
300		}
301		unitp->suspended = 0;
302		unitp->initting = B_TRUE;
303		envctrl_init_bus(unitp);
304		unitp->initting = B_FALSE;
305
306		envctrl_ps_probe(unitp);
307		envctrl_probe_cpus(unitp);
308		mutex_exit(&unitp->umutex);
309
310		return (DDI_SUCCESS);
311
312	default:
313		return (DDI_FAILURE);
314	}
315
316	/* Set up timer values */
317	overtemp_timeout_hz = drv_usectohz(ENVCTRL_UE250_OVERTEMP_TIMEOUT_USEC);
318	blink_timeout_hz = drv_usectohz(ENVCTRL_UE250_BLINK_TIMEOUT_USEC);
319	pshotplug_timeout_hz =
320	    drv_usectohz(ENVCTRL_UE250_BLINK_TIMEOUT_USEC * 2);
321	/*
322	 * On a cooling failure, either a fan failure or temperature
323	 * exceeding a WARNING level, the temperature poll thread
324	 * will run every 6 seconds.
325	 */
326	warning_timeout_hz =
327	    drv_usectohz(ENVCTRL_UE250_OVERTEMP_TIMEOUT_USEC / 6);
328
329	if (ddi_soft_state_zalloc(envctrlsoft_statep, instance) != 0) {
330		cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n",
331		    ddi_get_name(dip), instance);
332		goto failed;
333	}
334
335	unitp = ddi_get_soft_state(envctrlsoft_statep, instance);
336
337	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&unitp->bus_ctl_regs, 0,
338	    sizeof (struct ehc_pcd8584_regs), &attr,
339	    &unitp->ctlr_handle) != DDI_SUCCESS) {
340		cmn_err(CE_WARN, "%s%d: failed to map in bus_control regs\n",
341		    ddi_get_name(dip), instance);
342		return (DDI_FAILURE);
343	}
344
345	/*
346	 * If the PCI nexus has added a thermal interrupt, we first need
347	 * to remove that interrupt handler.
348	 *
349	 * WARNING: Removing another driver's interrupt handler is not
350	 * allowed. The pci_thermal_rem_intr() call below is needed to retain
351	 * the legacy behavior on Javelin systems.
352	 */
353
354	pci_thermal_rem_intr(dip, (uint_t)0);
355
356	/* add interrupts */
357
358	if (ddi_get_iblock_cookie(dip, 1,
359	    &unitp->ic_trap_cookie) != DDI_SUCCESS)  {
360		cmn_err(CE_WARN, "%s%d: ddi_get_iblock_cookie FAILED \n",
361		    ddi_get_name(dip), instance);
362		goto failed;
363	}
364
365	mutex_init(&unitp->umutex, NULL, MUTEX_DRIVER,
366	    (void *)unitp->ic_trap_cookie);
367
368
369	if (ddi_add_intr(dip, 0, &unitp->ic_trap_cookie, NULL, envctrl_bus_isr,
370	    (caddr_t)unitp) != DDI_SUCCESS) {
371		cmn_err(CE_WARN, "%s%d: failed to add hard intr \n",
372		    ddi_get_name(dip), instance);
373		goto remlock;
374	}
375
376
377	if (ddi_add_intr(dip, 1, &unitp->ic_trap_cookie, NULL, envctrl_dev_isr,
378	    (caddr_t)unitp) != DDI_SUCCESS) {
379		cmn_err(CE_WARN, "%s%d: failed to add hard intr \n",
380		    ddi_get_name(dip), instance);
381		goto remhardintr;
382	}
383
384
385	(void) sprintf(name, "envctrltwo%d", instance);
386
387	if (ddi_create_priv_minor_node(dip, name, S_IFCHR, instance,
388	    DDI_PSEUDO, 0, PRIV_SYS_CONFIG, PRIV_SYS_CONFIG, 0666) ==
389	    DDI_FAILURE) {
390		goto remhardintr1;
391	}
392
393	mutex_enter(&unitp->umutex);
394
395	/*
396	 * Javelin will not have a workstation configuration so activity
397	 * LED will always blink.
398	 */
399	unitp->activity_led_blink = B_TRUE;
400	unitp->shutdown = B_FALSE;
401	unitp->num_ps_present = 0;
402	unitp->num_encl_present = 1;
403	unitp->current_mode = ENVCTRL_NORMAL_MODE;
404	if (envctrl_numcpus > 1) {
405		unitp->num_cpus_present = envctrl_numcpus;
406	}
407	envctrl_probe_cpus(unitp);
408	if ((unitp->cpu_pr_location[ENVCTRL_CPU0] == B_FALSE) ||
409	    (unitp->cpu_pr_location[ENVCTRL_CPU1] == B_FALSE))
410		/* Only one CPU in the system */
411		unitp->num_temps_present = 5;
412	else
413		unitp->num_temps_present = 6;
414	unitp->num_fans_present = 1;
415	unitp->dip = dip;
416
417	mutex_exit(&unitp->umutex);
418
419	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
420	    "cpu-temp-factors", &creg_prop, &len) != DDI_PROP_SUCCESS) {
421		cmn_err(CE_WARN,
422		    "%s%d: Unable to read cpu-temp-factors property",
423		    ddi_get_name(dip), instance);
424		return (DDI_NOT_WELL_FORMED);
425	}
426	tblsz = (sizeof (_cpu_temps) / sizeof (uchar_t));
427
428	if (len <= tblsz && status == DDI_PROP_SUCCESS) {
429		for (i = 0; i < len; i++) {
430			_cpu_temps[i+2] = creg_prop[i];
431		}
432	}
433	_cpu_temps[0] = _cpu_temps[1] = _cpu_temps[2];
434
435	ddi_prop_free((void *)creg_prop);
436
437	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
438	    "cpu-fan-speeds", &creg_prop, &len) != DDI_PROP_SUCCESS) {
439		cmn_err(CE_WARN,
440		    "%s%d: Unable to read cpu-fan-speeds property",
441		    ddi_get_name(dip), instance);
442		return (DDI_NOT_WELL_FORMED);
443	}
444	tblsz = (sizeof (_cpu_fan_speeds) / sizeof (uchar_t));
445
446	if (len <= tblsz && status == DDI_PROP_SUCCESS) {
447		for (i = 0; i < len; i++) {
448			_cpu_fan_speeds[i+2] = creg_prop[i];
449		}
450	}
451	_cpu_fan_speeds[0] = _cpu_fan_speeds[1] = _cpu_fan_speeds[2];
452
453	ddi_prop_free((void *)creg_prop);
454
455	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
456	    "thermisters", &creg_prop, &len) != DDI_PROP_SUCCESS) {
457		cmn_err(CE_WARN,
458		    "%s%d: Unable to read thermisters property",
459		    ddi_get_name(dip), instance);
460		return (DDI_NOT_WELL_FORMED);
461	}
462
463	mutex_enter(&unitp->umutex);
464
465	j = 0; k = 0;
466	for (i = 0; i < JAV_MAX_TEMP_SENSORS; i++) {
467		/* Type */
468		unitp->temp_kstats[k].type = sensor_types[i];
469		/* Address */
470		t_addr[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
471		    creg_prop[j+2] << 8 | creg_prop[j+3];
472		j += 4;
473		/* Port */
474		t_port[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
475		    creg_prop[j+2] << 8 | creg_prop[j+3];
476		j += 4;
477		/* Min */
478		unitp->temp_kstats[k].min =
479		    creg_prop[j] << 24 | creg_prop[j+1] << 16 |
480		    creg_prop[j+2] << 8 | creg_prop[j+3];
481		j += 4;
482		/* Warning threshold */
483		unitp->temp_kstats[k].warning_threshold =
484		    creg_prop[j] << 24 | creg_prop[j+1] << 16 |
485		    creg_prop[j+2] << 8 | creg_prop[j+3];
486		j += 4;
487		/* Shutdown threshold */
488		unitp->temp_kstats[k].shutdown_threshold =
489		    creg_prop[j] << 24 | creg_prop[j+1] << 16 |
490		    creg_prop[j+2] << 8 | creg_prop[j+3];
491		j += 4;
492		/* Numerator of scale factor */
493		t_scale_num[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
494		    creg_prop[j+2] << 8 | creg_prop[j+3];
495		j += 4;
496		/* Denominator of scale factor */
497		t_scale_den[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
498		    creg_prop[j+2] << 8 | creg_prop[j+3];
499		j += 4;
500		bcopy((caddr_t)&creg_prop[j], unitp->temp_kstats[k].label,
501		    (size_t)sizeof (&creg_prop[j]));
502		while (creg_prop[j] != '\0') j++;
503		j++;
504		if (t_addr[k] == ENVCTRL_UE250_CPU_TEMP_DEV) {
505			if (((t_port[k] == ENVCTRL_UE250_CPU0_PORT) &&
506			    (unitp->cpu_pr_location[ENVCTRL_CPU0] ==
507			    B_FALSE)) ||
508			    ((t_port[k] == ENVCTRL_UE250_CPU1_PORT) &&
509			    (unitp->cpu_pr_location[ENVCTRL_CPU1] == B_FALSE)))
510				/* Don't increment the kstat line count */
511#ifdef lint
512				k = k;
513#else
514				;
515#endif
516			else
517				k++;
518		} else
519			k++;
520	}
521
522	ddi_prop_free((void *)creg_prop);
523
524	/* initialize the envctrl bus controller */
525
526	unitp->initting = B_TRUE;
527	envctrl_init_bus(unitp);
528	DPRINTF1("envctrl_attach(): Completed initialization of PCF8584");
529	unitp->initting = B_FALSE;
530	drv_usecwait(1000);
531
532	unitp->timeout_id = 0;
533	unitp->blink_timeout_id = 0;
534
535	unitp->fan_failed = 0;
536	unitp->fan_kstats.fans_ok = B_TRUE;
537	unitp->tempr_warning = 0;
538
539	envctrl_ps_probe(unitp);
540
541	unitp->initting = B_TRUE;
542	envctrl_fan_fail_service(unitp);
543	unitp->initting = B_FALSE;
544
545	/*
546	 * Fans could be blasting, turn them down.
547	 */
548	fanspeed = 0x0;
549	status = envctrl_write_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2, 0,
550	    &fanspeed, 1);
551	if (status == DDI_FAILURE)
552		cmn_err(CE_WARN, "%s%d: Write to PCF8591 (SETFAN) failed\n",
553		    ddi_get_name(dip), instance);
554
555	/*
556	 * we need to init the fan kstats before the tempr_poll
557	 */
558	envctrl_add_kstats(unitp);
559	envctrl_init_encl_kstats(unitp);
560	envctrl_check_disk_kstats(unitp);
561
562	envctrl_update_fanspeed(unitp);
563	idle_fanspeed = unitp->fan_kstats.fanspeed;
564
565	if (unitp->activity_led_blink == B_TRUE) {
566		unitp->present_led_state = B_FALSE;
567		mutex_exit(&unitp->umutex);
568		envctrl_led_blink((void *)unitp);
569		mutex_enter(&unitp->umutex);
570	} else {
571		fspval = ENVCTRL_UE250_FSP_ACTIVE;
572		(void) envctrl_set_fsp(unitp, &fspval);
573	}
574
575	mutex_exit(&unitp->umutex);
576
577	envctrl_tempr_poll((void *)unitp);
578
579	/*
580	 * interpose envctrl's abort sequence handler
581	 */
582	if (envctrl_handler) {
583		abort_seq_handler = envctrl_abort_seq_handler;
584	}
585
586	ddi_report_dev(dip);
587
588	return (DDI_SUCCESS);
589
590remhardintr1:
591	ddi_remove_intr(dip, (uint_t)1, unitp->ic_trap_cookie);
592remhardintr:
593	ddi_remove_intr(dip, (uint_t)0, unitp->ic_trap_cookie);
594
595remlock:
596	mutex_destroy(&unitp->umutex);
597
598failed:
599	if (unitp->ctlr_handle)
600		ddi_regs_map_free(&unitp->ctlr_handle);
601
602	cmn_err(CE_WARN, "%s%d: attach failed\n", ddi_get_name(dip), instance);
603
604	return (DDI_FAILURE);
605
606}
607
608static int
609envctrl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
610{
611	int		instance;
612	register struct envctrlunit *unitp;
613
614	instance = ddi_get_instance(dip);
615	unitp = ddi_get_soft_state(envctrlsoft_statep, instance);
616
617	switch (cmd) {
618	case DDI_DETACH:
619		if (envctrl_allow_detach) {
620
621			if (unitp->psksp != NULL) {
622				kstat_delete(unitp->psksp);
623			}
624			if (unitp->fanksp != NULL) {
625				kstat_delete(unitp->fanksp);
626			}
627			if (unitp->enclksp != NULL) {
628				kstat_delete(unitp->enclksp);
629			}
630			if (unitp->tempksp != NULL) {
631				kstat_delete(unitp->tempksp);
632			}
633			if (unitp->diskksp != NULL) {
634				kstat_delete(unitp->diskksp);
635			}
636
637			if (unitp->timeout_id != 0) {
638				(void) untimeout(unitp->timeout_id);
639				unitp->timeout_id = 0;
640			}
641			if (unitp->blink_timeout_id != 0) {
642				(void) untimeout(unitp->blink_timeout_id);
643				unitp->blink_timeout_id = 0;
644			}
645
646			ddi_remove_minor_node(dip, NULL);
647
648			ddi_remove_intr(dip, (uint_t)0, unitp->ic_trap_cookie);
649			ddi_remove_intr(dip, (uint_t)1, unitp->ic_trap_cookie);
650
651			ddi_regs_map_free(&unitp->ctlr_handle);
652
653			mutex_destroy(&unitp->umutex);
654
655			return (DDI_SUCCESS);
656		} else {
657			return (DDI_FAILURE);
658		}
659
660	case DDI_SUSPEND:
661		if (!(unitp = ddi_get_soft_state(envctrlsoft_statep, instance)))
662			return (DDI_FAILURE);
663		mutex_enter(&unitp->umutex);
664		if (unitp->suspended) {
665			cmn_err(CE_WARN, "%s%d: envctrltwo already suspended\n",
666			    ddi_get_name(dip), instance);
667			mutex_exit(&unitp->umutex);
668			return (DDI_FAILURE);
669		}
670		unitp->suspended = 1;
671		mutex_exit(&unitp->umutex);
672		return (DDI_SUCCESS);
673
674	default:
675		cmn_err(CE_WARN, "%s%d: suspend general fault\n",
676		    ddi_get_name(dip), instance);
677		return (DDI_FAILURE);
678	}
679
680
681}
682int
683envctrl_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
684    void **result)
685{
686	dev_t	dev = (dev_t)arg;
687	struct envctrlunit *unitp;
688	int	instance, ret;
689
690	instance = getminor(dev);
691
692#ifdef lint
693	dip = dip;
694#endif
695
696
697	switch (infocmd) {
698		case DDI_INFO_DEVT2DEVINFO:
699			if ((unitp = (struct envctrlunit *)
700			    ddi_get_soft_state(envctrlsoft_statep,
701			    instance)) != NULL) {
702				*result = unitp->dip;
703				ret = DDI_SUCCESS;
704			} else {
705				*result = NULL;
706				ret = DDI_FAILURE;
707			}
708			break;
709		case DDI_INFO_DEVT2INSTANCE:
710			*result = (void *)(uintptr_t)instance;
711			ret = DDI_SUCCESS;
712			break;
713		default:
714			ret = DDI_FAILURE;
715			break;
716	}
717
718	return (ret);
719}
720
721/* ARGSUSED1 */
722static int
723envctrl_open(dev_t *dev, int flag, int otyp, cred_t *cred_p)
724{
725	struct envctrlunit *unitp;
726	int status = 0;
727	register int	instance;
728
729	instance = getminor(*dev);
730	if (instance < 0)
731		return (ENXIO);
732	unitp = (struct envctrlunit *)
733	    ddi_get_soft_state(envctrlsoft_statep, instance);
734
735	if (unitp == NULL)
736		return (ENXIO);
737
738	if (otyp != OTYP_CHR)
739		return (EINVAL);
740
741	mutex_enter(&unitp->umutex);
742
743	if (flag & FWRITE) {
744		if ((unitp->oflag & FWRITE)) {
745			mutex_exit(&unitp->umutex);
746			return (EBUSY);
747		} else {
748			unitp->oflag |= FWRITE;
749		}
750	}
751
752	mutex_exit(&unitp->umutex);
753	return (status);
754}
755
756/*ARGSUSED1*/
757static int
758envctrl_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
759{
760	struct envctrlunit *unitp;
761	register int    instance;
762
763	instance = getminor(dev);
764	if (instance < 0)
765		return (ENXIO);
766	unitp = (struct envctrlunit *)
767	    ddi_get_soft_state(envctrlsoft_statep, instance);
768	if (unitp == NULL)
769		return (ENXIO);
770
771	mutex_enter(&unitp->umutex);
772
773	unitp->oflag = B_FALSE;
774	unitp->current_mode = ENVCTRL_NORMAL_MODE;
775
776	mutex_exit(&unitp->umutex);
777	return (DDI_SUCCESS);
778}
779
780
781/*
782 * standard put procedure for envctrl
783 */
784static int
785envctrl_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
786	int *rvalp)
787{
788	struct envctrlunit *unitp;
789	register int	instance;
790	uint8_t wdval, tempr;
791	struct envctrl_chip fanspeed;
792	struct envctrl_chip ledchip, envcchip;
793	struct envctrl_chip temp, a_fanspeed;
794	int rval = 0, status, tfanspeed;
795
796#ifdef lint
797	cred_p = cred_p;
798	rvalp = rvalp;
799#endif
800	instance = getminor(dev);
801	unitp = (struct envctrlunit *)
802	    ddi_get_soft_state(envctrlsoft_statep, instance);
803
804	if ((cmd == ENVCTRL_IOC_SETFAN2) ||
805	    (cmd == ENVCTRL_IOC_GETFAN2) ||
806	    (cmd == ENVCTRL_IOC_SETMODE) ||
807	    (cmd == ENVCTRL_IOC_GETMODE) ||
808	    (cmd == ENVCTRL_IOC_GETTEMP2) ||
809	    (cmd == ENVCTRL_IOC_SETFSP2) ||
810	    (cmd == ENVCTRL_IOC_GETFSP2) ||
811	    (cmd == ENVCTRL_IOC_RESETTMPR) ||
812	    (cmd == ENVCTRL_IOC_SETDSKLED2) ||
813	    (cmd == ENVCTRL_IOC_GETDSKLED2))
814		if ((caddr_t)arg == NULL)
815			return (EFAULT);
816
817	switch (cmd) {
818	case ENVCTRL_IOC_SETMODE:
819		/* Set mode */
820		if (ddi_copyin((caddr_t)arg, (caddr_t)&wdval, sizeof (uint8_t),
821		    flag)) {
822			rval = EFAULT;
823			break;
824		}
825		if (wdval == ENVCTRL_DIAG_MODE ||
826		    wdval == ENVCTRL_NORMAL_MODE) {
827			mutex_enter(&unitp->umutex);
828			unitp->current_mode = wdval;
829			if (unitp->timeout_id != 0 &&
830			    wdval == ENVCTRL_DIAG_MODE) {
831				(void) untimeout(unitp->timeout_id);
832				unitp->timeout_id =
833				    (timeout(envctrl_tempr_poll,
834				    (caddr_t)unitp, overtemp_timeout_hz));
835			}
836			if (wdval == ENVCTRL_NORMAL_MODE) {
837				/*
838				 * Fans could be blasting, turn them down.
839				 */
840				tempr = 0x0;
841				status = envctrl_write_chip(unitp,
842				    ENVCTRL_PCF8591, EHC_DEV2, 0,
843				    &tempr, 1);
844				if (status == DDI_FAILURE)
845					cmn_err(CE_WARN,
846					    "%s%d: Write to PCF8591 "
847					    "(SETMODE) failed\n",
848					    driver_name, unitp->instance);
849
850				/*
851				 * This delay allows the fans to time to
852				 * change speed
853				 */
854				drv_usecwait(100000);
855				(void) envctrl_check_sys_temperatures(unitp);
856				unitp->current_mode = ENVCTRL_DIAG_MODE;
857				envctrl_fan_fail_service(unitp);
858				unitp->current_mode = ENVCTRL_NORMAL_MODE;
859			}
860			mutex_exit(&unitp->umutex);
861		} else {
862			rval = EINVAL;
863		}
864		break;
865	case ENVCTRL_IOC_GETMODE:
866		wdval = unitp->current_mode;
867		if (ddi_copyout((caddr_t)&wdval, (caddr_t)arg,
868		    sizeof (uint8_t), flag)) {
869			rval = EFAULT;
870		}
871		break;
872	case ENVCTRL_IOC_RESETTMPR:
873		/*
874		 * For diags, cancel the curent temp poll
875		 * and reset it for a new one.
876		 */
877		if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
878			if (unitp->timeout_id != 0) {
879				(void) untimeout(unitp->timeout_id);
880				unitp->timeout_id = 0;
881			}
882			envctrl_tempr_poll((void *)unitp);
883		} else {
884			rval = EINVAL;
885		}
886		break;
887	case ENVCTRL_IOC_GETTEMP2:
888		/* Get the user buffer address */
889
890		if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
891			sizeof (struct envctrl_chip), flag)) {
892			rval = EFAULT;
893			break;
894		}
895		if (((temp.chip_num != ENVCTRL_DEV2) &&
896		    (temp.chip_num != ENVCTRL_DEV7)) ||
897		    (temp.index > EHC_PCF8591_CH_3)) {
898			rval = EINVAL;
899			break;
900		}
901		mutex_enter(&unitp->umutex);
902		status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
903		    temp.chip_num, temp.index, &temp.val, 1);
904		mutex_exit(&unitp->umutex);
905		if (status == DDI_FAILURE) {
906			cmn_err(CE_WARN,
907			    "%s%d: Read from PCF8591 (IOC_GETTEMP) failed",
908			    driver_name, unitp->instance);
909			rval = EINVAL;
910			break;
911		}
912		if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
913			sizeof (struct envctrl_chip), flag)) {
914			rval = EFAULT;
915		}
916		break;
917	case ENVCTRL_IOC_SETTEMP:
918		rval = EINVAL;
919		break;
920	case ENVCTRL_IOC_SETWDT:
921		rval = EINVAL;
922		break;
923	case ENVCTRL_IOC_SETFAN2:
924		/* NOTE: need to sanity check values coming from userland */
925		if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
926			if (ddi_copyin((caddr_t)arg, (caddr_t)&fanspeed,
927				sizeof (struct envctrl_chip), flag)) {
928				rval = EFAULT;
929				break;
930			}
931			if ((fanspeed.type != ENVCTRL_PCF8591) ||
932			    (fanspeed.chip_num != ENVCTRL_DEV2) ||
933			    (fanspeed.index > EHC_PCF8591_CH_3)) {
934				rval = EINVAL;
935				break;
936			}
937			mutex_enter(&unitp->umutex);
938			status = envctrl_set_fanspeed(unitp, &fanspeed);
939			if (status == DDI_FAILURE) {
940				cmn_err(CE_WARN,
941				    "%s%d: Write to PCF8591 "
942				    "(IOC_SETFAN) failed",
943				    driver_name, unitp->instance);
944				rval = EINVAL;
945			}
946			mutex_exit(&unitp->umutex);
947		} else {
948			rval = EINVAL;
949		}
950		break;
951	case ENVCTRL_IOC_GETFAN2:
952		if (ddi_copyin((caddr_t)arg, (caddr_t)&a_fanspeed,
953			sizeof (struct envctrl_chip), flag)) {
954			rval = EFAULT;
955			break;
956		}
957		if ((a_fanspeed.type != ENVCTRL_PCF8591) ||
958		    (a_fanspeed.chip_num != ENVCTRL_DEV2) ||
959		    (a_fanspeed.index != EHC_PCF8591_CH_1)) {
960			rval = EINVAL;
961			break;
962		}
963		mutex_enter(&unitp->umutex);
964		status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
965		    a_fanspeed.chip_num, a_fanspeed.index,
966		    &a_fanspeed.val, 1);
967		mutex_exit(&unitp->umutex);
968		if (status == DDI_FAILURE) {
969			cmn_err(CE_WARN,
970			    "%s%d: Read of PCF8591 (IOC_GETFAN) failed",
971			    driver_name, unitp->instance);
972			rval = EINVAL;
973			break;
974		}
975		/*
976		 * Due to hardware limitation, the actual fan speed
977		 * is always a little less than what it was set to by
978		 * software. Hence, we scale up the read fan speed value
979		 * to more closely match the set value.
980		 */
981		if ((tfanspeed = ((int)a_fanspeed.val * JAV_FAN_SPEED_SF_NUM) /
982		    JAV_FAN_SPEED_SF_DEN) > 255)
983			a_fanspeed.val = 255;
984		else
985			a_fanspeed.val = tfanspeed & 0xFF;
986		unitp->fan_kstats.fanspeed = a_fanspeed.val;
987		if (ddi_copyout((caddr_t)&a_fanspeed, (caddr_t)arg,
988			sizeof (struct envctrl_chip), flag)) {
989			rval = EFAULT;
990		}
991		break;
992	case ENVCTRL_IOC_SETFSP2:
993		if (ddi_copyin((caddr_t)arg, (caddr_t)&envcchip,
994			sizeof (struct envctrl_chip), flag)) {
995			rval = EFAULT;
996			break;
997		}
998		if ((envcchip.type != ENVCTRL_PCF8574A) ||
999		    (envcchip.chip_num != ENVCTRL_DEV6)) {
1000			rval = EINVAL;
1001			break;
1002		}
1003		wdval = envcchip.val;
1004		mutex_enter(&unitp->umutex);
1005		/*
1006		 * If a user is in normal mode and they try
1007		 * to set anything other than a disk fault or
1008		 * a gen fault it is an invalid operation.
1009		 * in diag mode we allow everything to be
1010		 * twiddled.
1011		 */
1012		if (unitp->current_mode == ENVCTRL_NORMAL_MODE) {
1013			if (wdval & ~ENVCTRL_UE250_FSP_USRMASK) {
1014				mutex_exit(&unitp->umutex);
1015				rval = EINVAL;
1016				break;
1017			}
1018		}
1019		if (wdval & ENVCTRL_UE250_FSP_PS_ERR)
1020			power_flt_led_lit = 1;
1021		status = envctrl_set_fsp(unitp, &wdval);
1022		mutex_exit(&unitp->umutex);
1023		if (status == DDI_FAILURE) {
1024			cmn_err(CE_WARN,
1025			    "%s%d: Read of PCF8574A (IOC_SETFSP) failed",
1026			    driver_name, unitp->instance);
1027			rval = EINVAL;
1028		}
1029		break;
1030	case ENVCTRL_IOC_GETFSP2:
1031		if (ddi_copyin((caddr_t)arg, (caddr_t)&envcchip,
1032			sizeof (struct envctrl_chip), flag)) {
1033			rval = EFAULT;
1034			break;
1035		}
1036		if ((envcchip.type != ENVCTRL_PCF8574A) ||
1037		    (envcchip.chip_num != ENVCTRL_DEV6)) {
1038			rval = EINVAL;
1039			break;
1040		}
1041		mutex_enter(&unitp->umutex);
1042		status = envctrl_get_fpm_status(unitp, &wdval);
1043		mutex_exit(&unitp->umutex);
1044		if (status == DDI_FAILURE) {
1045			cmn_err(CE_WARN,
1046			    "%s%d: Read of PCF8574A (IOC_GETFSP) failed",
1047			    driver_name, unitp->instance);
1048			rval = EINVAL;
1049		} else {
1050			envcchip.val = wdval;
1051			if (ddi_copyout((caddr_t)&envcchip, (caddr_t)arg,
1052				sizeof (struct envctrl_chip), flag)) {
1053				rval = EFAULT;
1054			}
1055		}
1056		break;
1057	case ENVCTRL_IOC_SETDSKLED2:
1058		if (ddi_copyin((caddr_t)arg, (caddr_t)&ledchip,
1059			sizeof (struct envctrl_chip), flag)) {
1060			rval = EFAULT;
1061			break;
1062		}
1063		if ((ledchip.type != ENVCTRL_PCF8574A) ||
1064		    (ledchip.chip_num != ENVCTRL_DEV7)) {
1065			rval = EINVAL;
1066			break;
1067		}
1068		mutex_enter(&unitp->umutex);
1069		if (envctrl_set_dskled(unitp, &ledchip)) {
1070			rval = EINVAL;
1071		}
1072		mutex_exit(&unitp->umutex);
1073		break;
1074	case ENVCTRL_IOC_GETDSKLED2:
1075		if (ddi_copyin((caddr_t)arg, (caddr_t)&ledchip,
1076			sizeof (struct envctrl_chip), flag)) {
1077			rval = EFAULT;
1078			break;
1079		}
1080		if ((ledchip.type != ENVCTRL_PCF8574A) ||
1081		    (ledchip.chip_num != ENVCTRL_DEV7)) {
1082			rval = EINVAL;
1083			break;
1084		}
1085		mutex_enter(&unitp->umutex);
1086		if (envctrl_get_dskled(unitp, &ledchip)) {
1087			rval = EINVAL;
1088		} else {
1089			if (ddi_copyout((caddr_t)&ledchip, (caddr_t)arg,
1090				sizeof (struct envctrl_chip), flag)) {
1091				rval = EFAULT;
1092			}
1093		}
1094		mutex_exit(&unitp->umutex);
1095		break;
1096	case ENVCTRL_IOC_SETRAW:
1097		if (unitp->current_mode != ENVCTRL_DIAG_MODE) {
1098			rval = EINVAL;
1099			break;
1100		}
1101		if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
1102			sizeof (struct envctrl_chip), flag)) {
1103			rval = EFAULT;
1104			break;
1105		}
1106		mutex_enter(&unitp->umutex);
1107		status = envctrl_write_chip(unitp, temp.type, temp.chip_num,
1108		    temp.index, &temp.val, 1);
1109		if (status == DDI_FAILURE) {
1110			cmn_err(CE_WARN,
1111			    "%s%d: Write to chip (IOC_SETRAW) failed",
1112			    driver_name, unitp->instance);
1113			rval = EINVAL;
1114		}
1115		mutex_exit(&unitp->umutex);
1116		break;
1117	case ENVCTRL_IOC_GETRAW:
1118		if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
1119			sizeof (struct envctrl_chip), flag)) {
1120			rval = EFAULT;
1121			break;
1122		}
1123		mutex_enter(&unitp->umutex);
1124		status = envctrl_read_chip(unitp, temp.type, temp.chip_num,
1125		    temp.index, &temp.val, 1);
1126		if (status == DDI_FAILURE) {
1127			cmn_err(CE_WARN,
1128			    "%s%d: Read of chip (IOC_GETRAW) failed",
1129			    driver_name, unitp->instance);
1130			rval = EINVAL;
1131		}
1132		mutex_exit(&unitp->umutex);
1133		if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
1134			sizeof (struct envctrl_chip), flag)) {
1135			rval = EFAULT;
1136		}
1137		break;
1138	default:
1139		rval = EINVAL;
1140	}
1141
1142	return (rval);
1143}
1144
1145uint_t
1146envctrl_bus_isr(caddr_t arg)
1147{
1148	struct envctrlunit *unitp = (struct envctrlunit *)(void *)arg;
1149	int ic = DDI_INTR_UNCLAIMED;
1150
1151	mutex_enter(&unitp->umutex);
1152
1153	/*
1154	 * NOT USED
1155	 */
1156
1157	mutex_exit(&unitp->umutex);
1158	return (ic);
1159}
1160
1161uint_t
1162envctrl_dev_isr(caddr_t arg)
1163{
1164	struct envctrlunit *unitp = (struct envctrlunit *)(void *)arg;
1165	uint8_t recv_data;
1166	int ic;
1167	int retrys = 0;
1168	int status;
1169	static int spurious_intr_count = 0;
1170
1171	ic = DDI_INTR_UNCLAIMED;
1172
1173	mutex_enter(&unitp->umutex);
1174
1175
1176	/*
1177	 * First check to see if it is an interrupt for us by
1178	 * looking at the "ganged" interrupt and vector
1179	 * according to the major type
1180	 * 0x70 is the addr of the ganged interrupt controller.
1181	 * Address map for the port byte read is as follows
1182	 * MSB
1183	 * -------------------------
1184	 * |  |  |  |  |  |  |  |  |
1185	 * -------------------------
1186	 *  P7 P6 P5 P4 P3 P2 P1 P0
1187	 * P0 = Spare
1188	 * P1 = Thermal Interrupt
1189	 * P2 = Disk Interrupt
1190	 * P3 = Interrupt clock enable
1191	 * P4 = Fan Fail Interrupt
1192	 * P5 =	Front Panel Interrupt
1193	 * P6 = Power Supply Interrupt
1194	 * P7 = Enable Interrupts
1195	 */
1196
1197	do {
1198		status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
1199		    ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
1200		    &recv_data, 1);
1201
1202		/*
1203		 * This extra read is needed since the first read is discarded
1204		 * and the second read seems to return 0xFF.
1205		 */
1206		if (recv_data == 0xFF) {
1207			status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
1208			    ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
1209			    &recv_data, 1);
1210		}
1211
1212		/*
1213		 * if the i2c bus is hung it is imperative that this
1214		 * be cleared on an interrupt or else it will
1215		 * hang the system with continuous interrupts
1216		 */
1217
1218		if (status == DDI_FAILURE) {
1219			drv_usecwait(1000);
1220			if (retrys < envctrl_max_retries) {
1221				retrys++;
1222			} else {
1223				cmn_err(CE_WARN,
1224				    "%s%d: Read of PCF8574A (INT) failed\n",
1225				    driver_name, unitp->instance);
1226				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
1227				mutex_exit(&unitp->umutex);
1228				ic = DDI_INTR_CLAIMED;
1229				return (ic);
1230			}
1231		}
1232	} while (status != DDI_SUCCESS);
1233
1234	DPRINTF1("Interrupt routine called, interrupt = %X\n", recv_data);
1235	if (!(recv_data & EHC_PCF8574_PORT0)) {
1236		ic = DDI_INTR_CLAIMED;
1237	}
1238
1239	if (!(recv_data & EHC_PCF8574_PORT1)) {
1240		DPRINTF1("Temperature interrupt detected\n");
1241		(void) envctrl_check_sys_temperatures(unitp);
1242
1243		/*
1244		 * Clear the interrupt latches
1245		 */
1246		envctrl_intr_latch_clr(unitp);
1247
1248		ic = DDI_INTR_CLAIMED;
1249	}
1250
1251	if (!(recv_data & EHC_PCF8574_PORT2)) {
1252		DPRINTF1("Disk interrupt detected\n");
1253		envctrl_check_disk_kstats(unitp);
1254		ic = DDI_INTR_CLAIMED;
1255	}
1256
1257	if (!(recv_data & EHC_PCF8574_PORT3)) {
1258		ic = DDI_INTR_CLAIMED;
1259	}
1260
1261	if (!(recv_data & EHC_PCF8574_PORT4)) {
1262		/*
1263		 * Check for a fan fail
1264		 */
1265		DPRINTF1("Fan interrupt detected\n");
1266		envctrl_fan_fail_service(unitp);
1267
1268		/*
1269		 * Clear the interrupt latches
1270		 */
1271		envctrl_intr_latch_clr(unitp);
1272
1273		ic = DDI_INTR_CLAIMED;
1274	}
1275
1276	if (!(recv_data & EHC_PCF8574_PORT5)) {
1277		DPRINTF1("Keyswitch interrupt detected\n");
1278		(void) envctrl_get_fpm_status(unitp, (uint8_t *)NULL);
1279		ic = DDI_INTR_CLAIMED;
1280	}
1281
1282	if (!(recv_data & EHC_PCF8574_PORT6)) {
1283		DPRINTF1("Power supply interrupt detected\n");
1284		envctrl_PS_intr_service(unitp);
1285		ic = DDI_INTR_CLAIMED;
1286	}
1287
1288	if (!(recv_data & EHC_PCF8574_PORT7)) {
1289		ic = DDI_INTR_CLAIMED;
1290	}
1291
1292	/*
1293	 * The interrupt routine got called but the interrupt chip
1294	 * shows no interrupt present. If this happens more than 256
1295	 * times in a row, there is probably some hardware problem so
1296	 * send a warning message to the console.
1297	 */
1298	if ((recv_data == 0xFF)) {
1299		if (spurious_intr_count == 255)
1300			cmn_err(CE_WARN,
1301			    "%s%d: Received 256 spurious interrupts\n",
1302			    driver_name, unitp->instance);
1303		spurious_intr_count++;
1304		ic = DDI_INTR_CLAIMED;
1305	} else
1306		spurious_intr_count = 0;
1307
1308	mutex_exit(&unitp->umutex);
1309	return (ic);
1310
1311}
1312
1313
1314static int
1315envctrl_read_chip(struct envctrlunit *unitp, int type, int chip_num, int port,
1316	uint8_t *data, int num)
1317{
1318	int retrys = 0, autoincr = 0;
1319	int status;
1320
1321	/*
1322	 * If more than one read is requested, set auto-increment bit
1323	 */
1324	if (num > 1)
1325		autoincr = 1;
1326
1327	do {
1328		if (type == ENVCTRL_PCF8574A) {
1329			status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
1330			    ENVCTRL_UE250_PCF8574A_BASE_ADDR | chip_num,
1331			    data, num);
1332		} else if (type == ENVCTRL_PCF8574) {
1333			status = ehc_read_pcf8574((struct ehc_envcunit *)unitp,
1334			    ENVCTRL_UE250_PCF8574_BASE_ADDR | chip_num,
1335			    data, num);
1336		} else if (type == ENVCTRL_PCF8591) {
1337			status = ehc_read_pcf8591((struct ehc_envcunit *)unitp,
1338			    ENVCTRL_UE250_PCF8591_BASE_ADDR | chip_num,
1339			    port, autoincr, 0, 1, data, num);
1340		}
1341		/*
1342		 * If the bus hangs, attempt a recovery
1343		 */
1344		if (status == DDI_FAILURE) {
1345			drv_usecwait(1000);
1346			if (retrys < envctrl_max_retries) {
1347				retrys++;
1348			} else {
1349				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
1350				break;
1351			}
1352		}
1353	} while (status != DDI_SUCCESS);
1354
1355	return (status);
1356}
1357
1358static int
1359envctrl_write_chip(struct envctrlunit *unitp, int type, int chip_num, int port,
1360	uint8_t *data, int num)
1361{
1362	int retrys = 0, autoincr = 0;
1363	int status;
1364
1365	/*
1366	 * Incase some applications mistakenly include the chips base addr
1367	 */
1368	chip_num = chip_num & 0xF;
1369
1370	/*
1371	 * If more than one write is requested, set auto-increment bit
1372	 */
1373	if (num > 1)
1374		autoincr = 1;
1375
1376	do {
1377		if (type == ENVCTRL_PCF8574A) {
1378			status = ehc_write_pcf8574a(
1379			    (struct ehc_envcunit *)unitp,
1380			    ENVCTRL_UE250_PCF8574A_BASE_ADDR | chip_num,
1381			    data, num);
1382		} else if (type == ENVCTRL_PCF8574) {
1383			status = ehc_write_pcf8574((struct ehc_envcunit *)unitp,
1384			    ENVCTRL_UE250_PCF8574_BASE_ADDR | chip_num,
1385			    data, num);
1386		} else if (type == ENVCTRL_PCF8591) {
1387			status = ehc_write_pcf8591((struct ehc_envcunit *)unitp,
1388			    ENVCTRL_UE250_PCF8591_BASE_ADDR | chip_num,
1389			    port, autoincr, 0, 1, data, num);
1390		}
1391
1392		/*
1393		 * If the bus hangs, attempt a recovery
1394		 */
1395		if (status == DDI_FAILURE) {
1396			drv_usecwait(1000);
1397			if (retrys < envctrl_max_retries) {
1398				retrys++;
1399			} else {
1400				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
1401				break;
1402			}
1403		}
1404	} while (status != DDI_SUCCESS);
1405
1406	return (status);
1407}
1408
1409#ifdef GET_CPU_TEMP
1410static int
1411envctrl_get_cpu_temp(struct envctrlunit *unitp, int cpunum)
1412{
1413	uint8_t recv_data;
1414	int status;
1415
1416	ASSERT(MUTEX_HELD(&unitp->umutex));
1417
1418	/*
1419	 * This routine takes in the number of the port that
1420	 * we want to read in the 8591. This should be the
1421	 * location of the CPU thermistor for one of the 2
1422	 * cpu's. It will return a normalized value
1423	 * to the caller.
1424	 */
1425
1426	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV7, cpunum,
1427	    &recv_data, 1);
1428	if (status == DDI_FAILURE) {
1429		cmn_err(CE_WARN, "%s%d: CPU TEMP read failed\n",
1430		    driver_name, unitp->instance);
1431		return (ENVCTRL_UE250_MAX_CPU_TEMP - 10);
1432	}
1433
1434	return (_cpu_temps[recv_data]);
1435}
1436#endif
1437
1438static void
1439envctrl_tempr_poll(void *arg)
1440{
1441	int diag_flag = 0, status;
1442	struct envctrlunit *unitp = (struct envctrlunit *)arg;
1443
1444	mutex_enter(&unitp->umutex);
1445
1446	if (unitp->shutdown == B_TRUE) {
1447		(void) power_down("Fatal System Environmental Control Error");
1448	}
1449
1450	/*
1451	 * Clear the interrupt latches
1452	 */
1453	envctrl_intr_latch_clr(unitp);
1454
1455	envctrl_reset_dflop(unitp);
1456	envctrl_enable_devintrs(unitp);
1457	/*
1458	 * if we are in diag mode and the temp poll thread goes off,
1459	 * this means that the system is too heavily loaded and the 60 second
1460	 * window to execute the test is failing.
1461	 */
1462	if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
1463		diag_flag++;
1464		if (envctrl_debug_flags) {
1465			cmn_err(CE_WARN, "%s%d: "
1466			    "Tempr poll went off while in DIAG MODE\n",
1467			    driver_name, unitp->instance);
1468		}
1469	}
1470	unitp->current_mode = ENVCTRL_NORMAL_MODE;
1471	DPRINTF1("envctrl_tempr_poll(): Checking system temps\n");
1472	status = envctrl_check_sys_temperatures(unitp);
1473	if (status == DDI_FAILURE) {
1474		cmn_err(CE_WARN,
1475		    "%s%d: Failure detected during temperature poll",
1476		    driver_name, unitp->instance);
1477	}
1478
1479	if (diag_flag == 0) {
1480		envctrl_fan_fail_service(unitp);
1481	}
1482
1483	/* Turn of the power fault LED if ps_ok is asserted */
1484	envctrl_ps_probe(unitp);
1485
1486	/* now have this thread sleep for a while */
1487	if ((unitp->fan_failed == B_TRUE) || (unitp->tempr_warning == B_TRUE)) {
1488		/*
1489		 * A thermal warning or fan failure condition exists.
1490		 * Temperature poll thread will run every 10 seconds.
1491		 */
1492		if (unitp->timeout_id != 0)
1493			(void) untimeout(unitp->timeout_id);
1494		unitp->timeout_id = (timeout(envctrl_tempr_poll,
1495		    (caddr_t)unitp, warning_timeout_hz));
1496	} else {
1497		/*
1498		 * No thermal warning or fan failure condition exists.
1499		 * This thread is set to run every 60 seconds.
1500		 */
1501		unitp->timeout_id = (timeout(envctrl_tempr_poll,
1502		    (caddr_t)unitp, overtemp_timeout_hz));
1503	}
1504
1505	mutex_exit(&unitp->umutex);
1506}
1507
1508static void
1509envctrl_led_blink(void *arg)
1510{
1511	uint8_t val, tmpval;
1512	int status;
1513	struct envctrlunit *unitp = (struct envctrlunit *)arg;
1514
1515	mutex_enter(&unitp->umutex);
1516
1517	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
1518	    0, &val, 1);
1519	if (status == DDI_FAILURE) {
1520		cmn_err(CE_WARN, "%s%d: Failed to read FSP LEDs",
1521		    driver_name, unitp->instance);
1522		/* now have this thread sleep for a while */
1523		unitp->blink_timeout_id = (timeout(envctrl_led_blink,
1524		    (caddr_t)unitp, blink_timeout_hz));
1525		mutex_exit(&unitp->umutex);
1526		return;
1527	}
1528
1529	if (unitp->present_led_state == B_TRUE) {
1530		/*
1531		 * Now we need to "or" in fault bits of the FSP
1532		 * module for the mass storage fault led.
1533		 * and set it.
1534		 */
1535		val = (val & ~(EHC_PCF8574_PORT4) | JAV_FSP_MASK);
1536		unitp->present_led_state = B_FALSE;
1537	} else {
1538		val = (val | EHC_PCF8574_PORT4 | JAV_FSP_MASK);
1539		unitp->present_led_state = B_TRUE;
1540	}
1541
1542	/*
1543	 * A static global variable, power_flt_led_lit, is used to keep
1544	 * track of periods when the software has lit the power fault LED.
1545	 * Whenever the power fault LED is lit and this variable is not set,
1546	 * then the power fault LED has been lit by hardware. In this case
1547	 * mask out the power fault LED in the byte. This is a fix for
1548	 * bug 4144872.
1549	 */
1550	tmpval = ~val;
1551	if (tmpval & ENVCTRL_UE250_FSP_PS_ERR) {
1552		if (power_flt_led_lit == 0) {
1553			/*
1554			 * Turn off power fault bit in the FSP byte.
1555			 */
1556			tmpval &= ~(ENVCTRL_UE250_FSP_PS_ERR);
1557		}
1558	}
1559	val = ~tmpval;
1560
1561	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
1562	    0, &val, 1);
1563	if (status == DDI_FAILURE) {
1564		cmn_err(CE_WARN, "%s%d: Failed to blink activity LED",
1565		    driver_name, unitp->instance);
1566		/* now have this thread sleep for a while */
1567		unitp->blink_timeout_id = (timeout(envctrl_led_blink,
1568		    (caddr_t)unitp, blink_timeout_hz));
1569		mutex_exit(&unitp->umutex);
1570		return;
1571	}
1572
1573	/* now have this thread sleep for a while */
1574	unitp->blink_timeout_id = (timeout(envctrl_led_blink,
1575	    (caddr_t)unitp, blink_timeout_hz));
1576
1577	mutex_exit(&unitp->umutex);
1578}
1579
1580static int
1581envctrl_check_sys_temperatures(struct envctrlunit *unitp)
1582{
1583	uint8_t buf[8];
1584	enum levels warning_level, level;
1585	uint8_t fspval;
1586	int status, warning_count = 0;
1587
1588retrytemp1:
1589	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2,
1590	    0, buf, 4);
1591	if (status == DDI_FAILURE) {
1592		cmn_err(CE_WARN, "%s%d: Temperature read failed (PDB)",
1593		    driver_name, unitp->instance);
1594		return (status);
1595	}
1596
1597	warning_level = envctrl_check_tempr_levels(unitp, EHC_DEV2,
1598	    buf, warning_count);
1599	level = warning_level;
1600
1601	if (warning_level != green) {
1602		if (warning_count == 0) {
1603			warning_count++;
1604			drv_usecwait(1000);
1605			goto retrytemp1;
1606		}
1607		if (warning_level == yellow)
1608			unitp->tempr_warning = B_TRUE;
1609		else if (warning_level == red) {
1610				unitp->tempr_warning = B_TRUE;
1611				if (!envctrl_power_off_overide)
1612					unitp->shutdown = B_TRUE;
1613		}
1614	}
1615
1616	warning_count = 0;
1617retrytemp2:
1618	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV7,
1619	    0, buf+4, 4);
1620	if (status == DDI_FAILURE) {
1621		cmn_err(CE_WARN, "%s%d: Temperature read failed (MBD)",
1622		    driver_name, unitp->instance);
1623		return (status);
1624	}
1625
1626	warning_level = envctrl_check_tempr_levels(unitp, EHC_DEV7,
1627	    buf+4, warning_count);
1628
1629	if (warning_level != green) {
1630		if (warning_count == 0) {
1631			warning_count++;
1632			drv_usecwait(1000);
1633			goto retrytemp2;
1634		}
1635		if ((warning_level == yellow) && (unitp->shutdown == B_FALSE))
1636			unitp->tempr_warning = B_TRUE;
1637		else if (warning_level == red) {
1638				unitp->tempr_warning = B_TRUE;
1639				if (!envctrl_power_off_overide)
1640					unitp->shutdown = B_TRUE;
1641		}
1642	} else if ((level == green) && (unitp->tempr_warning == B_TRUE)) {
1643		/*
1644		 * Current tempr. poll shows all levels normal.
1645		 * If the previous poll showed warning levels, we need
1646		 * to clear that status
1647		 */
1648		cmn_err(CE_NOTE,
1649		"TEMPERATURE NORMAL: all sensors back to normal readings");
1650		unitp->tempr_warning = B_FALSE;
1651	}
1652
1653	status = envctrl_get_fpm_status(unitp, &fspval);
1654	if (status == DDI_FAILURE) {
1655		cmn_err(CE_WARN,
1656		    "%s%d: Read of Front Status Panel LEDs failed",
1657		    driver_name, unitp->instance);
1658	}
1659
1660	if ((unitp->tempr_warning == B_TRUE) || (unitp->shutdown == B_TRUE))
1661		fspval |= (ENVCTRL_UE250_FSP_TEMP_ERR |
1662		    ENVCTRL_UE250_FSP_GEN_ERR);
1663	else {
1664		if (envctrl_isother_fault_led(unitp, fspval,
1665		    ENVCTRL_UE250_FSP_TEMP_ERR)) {
1666			fspval &= ~(ENVCTRL_UE250_FSP_TEMP_ERR);
1667		} else {
1668			fspval &= ~(ENVCTRL_UE250_FSP_TEMP_ERR |
1669			    ENVCTRL_UE250_FSP_GEN_ERR);
1670		}
1671	}
1672	status = envctrl_set_fsp(unitp, &fspval);
1673	if (status == DDI_FAILURE) {
1674		cmn_err(CE_WARN,
1675		    "%s%d: Setting of Front Status Panel LEDs failed",
1676		    driver_name, unitp->instance);
1677	}
1678
1679	/*
1680	 * Have this thread run again in about 10 seconds
1681	 */
1682	if (unitp->tempr_warning == B_TRUE) {
1683		if (unitp->timeout_id != 0) {
1684			(void) untimeout(unitp->timeout_id);
1685			unitp->timeout_id = (timeout(envctrl_tempr_poll,
1686			    (caddr_t)unitp, warning_timeout_hz));
1687		}
1688	}
1689
1690	return (status);
1691}
1692
1693static int
1694envctrl_check_tempr_levels(struct envctrlunit *unitp, int chip_num,
1695	uint8_t *data, int count)
1696{
1697	uint_t temp_degree_c;
1698	uint8_t buf[8];
1699	enum levels warning_level = green;
1700	int i, j;
1701	int status;
1702	uint8_t fanspeed;
1703	int tval;
1704
1705	for (i = 0; i < 4; i++) {
1706		if (chip_num == EHC_DEV2) {
1707			if (i == 1) {
1708				tval = ((int)data[i] * JAV_FAN_SPEED_SF_NUM) /
1709				    JAV_FAN_SPEED_SF_DEN;
1710				if (tval > 255)
1711					unitp->fan_kstats.fanspeed = 255;
1712				else
1713					unitp->fan_kstats.fanspeed = tval;
1714				DPRINTF1("device %X, fan = %d %d\n", chip_num,
1715				    unitp->fan_kstats.fanspeed, data[i]);
1716				continue;
1717			} else if (i == 2)
1718				continue;
1719		}
1720		if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
1721		    (i == ENVCTRL_UE250_CPU1_PORT)))
1722			if (unitp->cpu_pr_location[i] == B_FALSE)
1723				continue;
1724
1725		j = 0;
1726		while ((((t_addr[j] & 0xF) != chip_num) || (t_port[j] != i)) &&
1727		    (j < unitp->num_temps_present))
1728			j++;
1729		if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
1730		    (i == ENVCTRL_UE250_CPU1_PORT)))
1731			temp_degree_c = _cpu_temps[data[i]];
1732		else
1733			temp_degree_c = ((int)data[i] * t_scale_num[j]) /
1734			    t_scale_den[j];
1735
1736		/*
1737		 * Javelin hardware will not control fan speeds based on
1738		 * cpu temperature values because the voltages corresponding
1739		 * to the cpu temperatures are based on an inverted scale
1740		 * compared to the ambient temperatures and thus can be
1741		 * fed to the same fan control circuit. As a result, it
1742		 * has been decided that software will control fan speed
1743		 * if cpu temperatures rise.
1744		 */
1745		if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
1746		    (i == ENVCTRL_UE250_CPU1_PORT)) &&
1747		    (unitp->current_mode == ENVCTRL_NORMAL_MODE)) {
1748			if (_cpu_fan_speeds[data[ENVCTRL_UE250_CPU0_PORT]] >
1749			    _cpu_fan_speeds[data[ENVCTRL_UE250_CPU1_PORT]])
1750				fanspeed =
1751				    _cpu_fan_speeds[
1752				    data[ENVCTRL_UE250_CPU0_PORT]];
1753			else
1754				fanspeed =
1755				    _cpu_fan_speeds[
1756				    data[ENVCTRL_UE250_CPU1_PORT]];
1757			status = envctrl_write_chip(unitp, ENVCTRL_PCF8591,
1758			    EHC_DEV2, 0, &fanspeed, 1);
1759			if (status == DDI_FAILURE)
1760				cmn_err(CE_WARN,
1761				    "%s%d: Write to PCF8591 (SETFAN) failed\n",
1762				    driver_name, unitp->instance);
1763			status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
1764			    EHC_DEV2, 0, buf, 4);
1765			if (status == DDI_FAILURE)
1766				cmn_err(CE_WARN,
1767				    "%s%d: Fan speed read failed (PDB)",
1768				    driver_name, unitp->instance);
1769			tval = ((int)buf[1] * JAV_FAN_SPEED_SF_NUM) /
1770			    JAV_FAN_SPEED_SF_DEN;
1771			if (tval > 255)
1772				unitp->fan_kstats.fanspeed = 255;
1773			else
1774				unitp->fan_kstats.fanspeed = tval;
1775		}
1776
1777		DPRINTF1("device %X, temp = %d %d loc = %s\n", chip_num,
1778		    temp_degree_c, data[i], unitp->temp_kstats[j].label);
1779
1780		unitp->temp_kstats[j].value = temp_degree_c;
1781		if ((temp_degree_c >=
1782		    unitp->temp_kstats[j].warning_threshold) ||
1783		    (temp_degree_c < unitp->temp_kstats[j].min)) {
1784			if (warning_level < yellow)
1785				warning_level = yellow;
1786			if (count != 0)
1787				cmn_err(CE_WARN,
1788				    "TEMPERATURE WARNING: %d degrees "
1789				    "celsius at location %s",
1790				    temp_degree_c, unitp->temp_kstats[j].label);
1791		}
1792		if (temp_degree_c >=
1793		    unitp->temp_kstats[j].shutdown_threshold) {
1794			if (warning_level < red)
1795				warning_level = red;
1796			if (count != 0) {
1797				cmn_err(CE_WARN,
1798				    "TEMPERATURE CRITICAL: %d "
1799				    "degrees celsius at location %s",
1800				    temp_degree_c, unitp->temp_kstats[j].label);
1801				if (!envctrl_power_off_overide)
1802					cmn_err(CE_WARN,
1803					    "System shutdown in "
1804					    "10 seconds ...");
1805			}
1806		}
1807	}
1808	return (warning_level);
1809}
1810
1811static void
1812envctrl_update_fanspeed(struct envctrlunit *unitp)
1813{
1814	uint8_t buf[8];
1815	int tval;
1816	int status;
1817
1818	status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2,
1819	    0, buf, 4);
1820	if (status == DDI_FAILURE) {
1821		cmn_err(CE_WARN, "%s%d: Fan speed read failed ",
1822		    driver_name, unitp->instance);
1823	}
1824
1825	tval = ((int)buf[ENVCTRL_PORT1] * JAV_FAN_SPEED_SF_NUM) /
1826	    JAV_FAN_SPEED_SF_DEN;
1827	if (tval > 255)
1828		unitp->fan_kstats.fanspeed = 255;
1829	else
1830		unitp->fan_kstats.fanspeed = tval;
1831}
1832
1833/* called with mutex held */
1834static void
1835envctrl_fan_fail_service(struct envctrlunit *unitp)
1836{
1837	uint8_t recv_data, fpmstat;
1838	int retrys = 0;
1839	int status;
1840
1841	/*
1842	 * The fan fail interrupt is read from address 0x70
1843	 * on the envctrl bus.
1844	 */
1845
1846	ASSERT(MUTEX_HELD(&unitp->umutex));
1847
1848	/*
1849	 * Clear the interrupt latches to handle spurious interrupts
1850	 */
1851	envctrl_intr_latch_clr(unitp);
1852
1853	do {
1854		status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
1855		    ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
1856		    &recv_data, 1);
1857		/*
1858		 * This extra read is needed since the first read is discarded
1859		 * and the second read seems to return 0xFF.
1860		 */
1861		if (recv_data == 0xFF) {
1862			status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
1863			    ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
1864			    &recv_data, 1);
1865		}
1866
1867		if (status == DDI_FAILURE) {
1868			drv_usecwait(1000);
1869			if (retrys < envctrl_max_retries) {
1870				retrys++;
1871			} else {
1872				cmn_err(CE_WARN,
1873				"%s%d: Read of PCF8574A (INTFAN) failed",
1874				    driver_name, unitp->instance);
1875				ehc_init_pcf8584((struct ehc_envcunit *)unitp);
1876				return;
1877			}
1878		}
1879	} while (status != DDI_SUCCESS);
1880
1881	/* If the fan fail interrupt is now absent */
1882	if (recv_data & EHC_PCF8574_PORT4) {
1883		if (unitp->fan_failed == B_TRUE) {
1884			if (unitp->current_mode == ENVCTRL_NORMAL_MODE)
1885				cmn_err(CE_CONT,
1886				    "Fan failure has been cleared\n");
1887			unitp->fan_kstats.fans_ok = B_TRUE;
1888			/*
1889			 * Clear general fault LED if no other faults
1890			 */
1891			status = envctrl_get_fpm_status(unitp, &fpmstat);
1892			if (status == DDI_FAILURE) {
1893				cmn_err(CE_WARN,
1894				    "%s%d: Read of Front Status "
1895				    "Panel LEDs failed",
1896				    driver_name, unitp->instance);
1897			}
1898			if (!(envctrl_isother_fault_led(unitp, fpmstat, 0))) {
1899				fpmstat &= ~(ENVCTRL_UE250_FSP_GEN_ERR);
1900			}
1901			if (unitp->shutdown != B_TRUE) {
1902				status = envctrl_set_fsp(unitp, &fpmstat);
1903				if (status == DDI_FAILURE) {
1904					cmn_err(CE_WARN, "%s%d: "
1905					    "Setting of Front Status "
1906					    "Panel LEDs failed",
1907					    driver_name, unitp->instance);
1908				}
1909			}
1910			/*
1911			 * This should be set after envctrl_isother_fault_led()
1912			 * is called
1913			 */
1914			unitp->fan_failed = B_FALSE;
1915		}
1916	} else {
1917		if (unitp->fan_failed == B_FALSE) {
1918			if (unitp->current_mode == ENVCTRL_NORMAL_MODE)
1919				cmn_err(CE_WARN,
1920				    "Fan failure has been detected");
1921			unitp->fan_failed = B_TRUE;
1922			unitp->fan_kstats.fans_ok = B_FALSE;
1923			/*
1924			 * Set general fault LED
1925			 */
1926			status = envctrl_get_fpm_status(unitp, &fpmstat);
1927			if (status == DDI_FAILURE) {
1928				cmn_err(CE_WARN,
1929				    "%s%d: Read of Front Status "
1930				    "Panel LEDs failed",
1931				    driver_name, unitp->instance);
1932				return;
1933			}
1934			fpmstat |= ENVCTRL_UE250_FSP_GEN_ERR;
1935			status = envctrl_set_fsp(unitp, &fpmstat);
1936			if (status == DDI_FAILURE) {
1937				cmn_err(CE_WARN, "%s%d: "
1938				    "Setting of Front Status Panel LEDs failed",
1939				    driver_name, unitp->instance);
1940			}
1941			/*
1942			 * A fan failure condition exists.
1943			 * Temperature poll thread should run every 10 seconds.
1944			 */
1945			if (unitp->timeout_id != 0) {
1946				(void) untimeout(unitp->timeout_id);
1947				unitp->timeout_id =
1948				    (timeout(envctrl_tempr_poll,
1949				    (caddr_t)unitp, warning_timeout_hz));
1950			}
1951		}
1952	}
1953}
1954
1955/*
1956 * Check for power supply insertion and failure.
1957 * This is a bit tricky, because a power supply insertion will
1958 * cause the ps_ok line to go active as well as PS present in the
1959 * new supply. If we detect an insertion clear
1960 * interrupts, disable interrupts, wait for a couple of seconds
1961 * come back and see if the PSOK bit is set, PS_PRESENT is set
1962 * and the share fail interrupts are gone. If not this is a
1963 * real load share fail event.
1964 * Called with mutex held
1965 */
1966
1967static void
1968envctrl_PS_intr_service(struct envctrlunit *unitp)
1969{
1970
1971	ASSERT(MUTEX_HELD(&unitp->umutex));
1972
1973	if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
1974		return;
1975	}
1976
1977	/*
1978	 * setup a timeout thread to poll the ps after a
1979	 * couple of seconds. This allows for the PS to settle
1980	 * and doesn't report false errors on a hotplug
1981	 */
1982
1983	unitp->pshotplug_id = (timeout(envctrl_pshotplug_poll,
1984	    (caddr_t)unitp, pshotplug_timeout_hz));
1985
1986}
1987
1988static void
1989envctrl_init_bus(struct envctrlunit *unitp)
1990{
1991	ehc_init_pcf8584((struct ehc_envcunit *)unitp);
1992
1993	/*
1994	 * Clear the interrupt latches
1995	 */
1996	envctrl_intr_latch_clr(unitp);
1997
1998	envctrl_reset_dflop(unitp);
1999
2000	envctrl_enable_devintrs(unitp);
2001}
2002
2003/* called with mutex held */
2004static void
2005envctrl_reset_dflop(struct envctrlunit *unitp)
2006{
2007	int status;
2008	uint8_t value;
2009
2010	ASSERT(MUTEX_HELD(&unitp->umutex));
2011
2012	value = ENVCTRL_UE250_DFLOP_INIT0;
2013	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
2014	    0, &value, 1);
2015	if (status == DDI_FAILURE) {
2016		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (DFLOP_INIT0) failed",
2017		    driver_name, unitp->instance);
2018	}
2019
2020	value = ENVCTRL_UE250_DFLOP_INIT1;
2021	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
2022	    0, &value, 1);
2023	if (status == DDI_FAILURE) {
2024		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (DFLOP_INIT1) failed",
2025		    driver_name, unitp->instance);
2026	}
2027}
2028
2029/* called with mutex held */
2030static void
2031envctrl_enable_devintrs(struct envctrlunit *unitp)
2032{
2033	int status;
2034	uint8_t value;
2035
2036	ASSERT(MUTEX_HELD(&unitp->umutex));
2037
2038	value = ENVCTRL_UE250_DEVINTR_INIT0;
2039	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
2040	    0, &value, 1);
2041	if (status == DDI_FAILURE) {
2042		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_INIT0) failed",
2043		    driver_name, unitp->instance);
2044	}
2045
2046	value = ENVCTRL_UE250_DEVINTR_INIT1;
2047	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
2048	    0, &value, 1);
2049	if (status == DDI_FAILURE) {
2050		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_INIT1) failed",
2051		    driver_name, unitp->instance);
2052	}
2053}
2054
2055static void
2056envctrl_intr_latch_clr(struct envctrlunit *unitp)
2057{
2058	int status;
2059	uint8_t value;
2060
2061	ASSERT(MUTEX_HELD(&unitp->umutex));
2062
2063	value = ENVCTRL_UE250_INTR_LATCH_INIT0;
2064	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
2065	    0, &value, 1);
2066	if (status == DDI_FAILURE) {
2067		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_LATCH0) failed",
2068		    driver_name, unitp->instance);
2069	}
2070
2071	value = ENVCTRL_UE250_INTR_LATCH_INIT1;
2072	status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
2073	    0, &value, 1);
2074	if (status == DDI_FAILURE) {
2075		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_LATCH1) failed",
2076		    driver_name, unitp->instance);
2077	}
2078}
2079
2080/* Called with unitp mutex held */
2081static void
2082envctrl_ps_probe(struct envctrlunit *unitp)
2083{
2084
2085	uint8_t recv_data, fpmstat;
2086	int i, j;
2087	int ps_error = 0, ps_present_port, power_ok_port;
2088	int status;
2089
2090
2091	ASSERT(MUTEX_HELD(&unitp->umutex));
2092
2093	unitp->num_ps_present = 0;
2094
2095	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV1,
2096	    0, &recv_data, 1);
2097	if (status == DDI_FAILURE) {
2098		cmn_err(CE_WARN, "%s%d: Read of PCF8574 (PS) failed",
2099		    driver_name, unitp->instance);
2100		return;
2101	}
2102
2103	for (i = 0, j = 0; i < ENVCTRL_UE250_MAXPS; i++) {
2104		unitp->ps_kstats[i].slot = -1;
2105
2106		/*
2107		 * Port 0 = PS0 Present
2108		 * Port 1 = PS1 Present
2109		 * Port 2 = SPARE
2110		 * Port 3 = SPARE
2111		 * Port 4 = PS0 OK
2112		 * Port 5 = PS1 OK
2113		 * Port 6 = SPARE
2114		 * Port 7 = SPARE
2115		 */
2116
2117		/*
2118		 * Port 0 = PS Present
2119		 * Port is pulled LOW "0" to indicate
2120		 * present.
2121		 */
2122
2123		switch (i) {
2124		case 0:
2125			ps_present_port = EHC_PCF8574_PORT0;
2126			power_ok_port = EHC_PCF8574_PORT4;
2127			break;
2128		case 1:
2129			ps_present_port = EHC_PCF8574_PORT1;
2130			power_ok_port = EHC_PCF8574_PORT5;
2131			break;
2132		}
2133
2134		if (!(recv_data & ps_present_port)) {
2135			/* update unit kstat array */
2136			unitp->ps_kstats[j].slot = i;
2137			++unitp->num_ps_present;
2138
2139			if (pspr[i] == 0) {
2140				cmn_err(CE_NOTE,
2141				    "Power Supply %d inserted\n", i);
2142			}
2143			pspr[i] = 1;
2144
2145			if (!(recv_data & power_ok_port)) {
2146				cmn_err(CE_WARN,
2147				    "Power Supply %d NOT okay\n", i);
2148				unitp->ps_kstats[j].ps_ok = B_FALSE;
2149				ps_error++;
2150				psok[i] = 0;
2151			} else {
2152				unitp->ps_kstats[j].ps_ok = B_TRUE;
2153				if (psok[i] == 0)
2154					cmn_err(CE_NOTE,
2155					    "Power Supply %d okay\n", i);
2156				psok[i] = 1;
2157			}
2158
2159			if (!(recv_data & EHC_PCF8574_PORT2)) {
2160				cmn_err(CE_WARN,
2161				    "PS %d Shouln't interrupt\n", i);
2162				ps_error++;
2163			}
2164
2165			if (!(recv_data & EHC_PCF8574_PORT3)) {
2166				cmn_err(CE_WARN,
2167				    "PS %d Shouln't interrupt\n", i);
2168				ps_error++;
2169			}
2170
2171			if (!(recv_data & EHC_PCF8574_PORT6)) {
2172				cmn_err(CE_WARN,
2173				    "PS %d Shouln't interrupt\n", i);
2174				ps_error++;
2175			}
2176
2177			if (!(recv_data & EHC_PCF8574_PORT7)) {
2178				cmn_err(CE_WARN,
2179				    "PS %d Shouln't interrupt\n", i);
2180				ps_error++;
2181			}
2182			j++;
2183		} else {
2184			if (pspr[i] == 1) {
2185				cmn_err(CE_NOTE,
2186				    "Power Supply %d removed\n", i);
2187			}
2188			pspr[i] = 0;
2189		}
2190	}
2191
2192	status = envctrl_get_fpm_status(unitp, &fpmstat);
2193	if (status == DDI_FAILURE) {
2194		cmn_err(CE_WARN, "%s%d: Read of Front Status Panel LEDs failed",
2195		    driver_name, unitp->instance);
2196	}
2197	if (ps_error) {
2198		fpmstat |= (ENVCTRL_UE250_FSP_PS_ERR |
2199		    ENVCTRL_UE250_FSP_GEN_ERR);
2200	} else {
2201		if (envctrl_isother_fault_led(unitp, fpmstat,
2202		    ENVCTRL_UE250_FSP_PS_ERR)) {
2203			fpmstat &= ~(ENVCTRL_UE250_FSP_PS_ERR);
2204		} else {
2205			fpmstat &= ~(ENVCTRL_UE250_FSP_PS_ERR |
2206			    ENVCTRL_UE250_FSP_GEN_ERR);
2207		}
2208	}
2209	status = envctrl_set_fsp(unitp, &fpmstat);
2210	if (status == DDI_FAILURE) {
2211		cmn_err(CE_WARN,
2212		    "%s%d: Setting of Front Status Panel LEDs failed",
2213		    driver_name, unitp->instance);
2214	}
2215
2216	if (ps_error) {
2217		power_flt_led_lit = 1;
2218	} else {
2219		power_flt_led_lit = 0;
2220	}
2221}
2222
2223/*
2224 * consider key switch position when handling an abort sequence
2225 */
2226static void
2227envctrl_abort_seq_handler(char *msg)
2228{
2229	struct envctrlunit *unitp;
2230	int i;
2231	uint8_t secure = 0;
2232
2233	/*
2234	 * Find the instance of the device available on this host.
2235	 * Note that there may be only one, but the instance may
2236	 * not be zero.
2237	 */
2238	for (i = 0; i < MAX_DEVS; i++) {
2239		if (unitp = (struct envctrlunit *)
2240		    ddi_get_soft_state(envctrlsoft_statep, i))
2241			break;
2242	}
2243
2244	ASSERT(unitp);
2245
2246	secure = unitp->encl_kstats.value;
2247
2248	if ((secure & ENVCTRL_UE250_FSP_KEYMASK) ==
2249	    ENVCTRL_UE250_FSP_KEYLOCKED) {
2250			cmn_err(CE_CONT,
2251			    "%s%d: ignoring debug enter sequence\n",
2252			    driver_name, unitp->instance);
2253	} else {
2254		if (envctrl_debug_flags) {
2255			cmn_err(CE_CONT, "%s%d: allowing debug enter\n",
2256			    driver_name, unitp->instance);
2257		}
2258		debug_enter(msg);
2259	}
2260}
2261
2262/*
2263 * get the front Panel module LED and keyswitch status.
2264 * this part is addressed at 0x7C on the i2c bus.
2265 * called with mutex held
2266 */
2267static int
2268envctrl_get_fpm_status(struct envctrlunit *unitp, uint8_t *val)
2269{
2270	uint8_t recv_data;
2271	int status;
2272
2273	ASSERT(MUTEX_HELD(&unitp->umutex));
2274
2275	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
2276	    0, &recv_data, 1);
2277	if (status == DDI_FAILURE) {
2278		cmn_err(CE_WARN, "%s%d: Read from PCF8574A (FSP) failed",
2279		    driver_name, unitp->instance);
2280		return (status);
2281	}
2282
2283	recv_data = ~recv_data;
2284	if (val != (uint8_t *)NULL)
2285		*val = recv_data;
2286
2287	/* Update kstats */
2288	unitp->encl_kstats.value = recv_data;
2289
2290	return (status);
2291}
2292
2293static int
2294envctrl_set_fsp(struct envctrlunit *unitp, uint8_t *val)
2295{
2296	uint8_t value;
2297	int status = DDI_SUCCESS;
2298	uint8_t confirm_val = 0, confirm_val_hold;
2299	int confirm_count = 0, confirm_max = 20;
2300
2301	ASSERT(MUTEX_HELD(&unitp->umutex));
2302
2303	value = ENVCTRL_UE250_FSP_OFF; /* init all values to off */
2304
2305	/*
2306	 * strip off bits that are R/O
2307	 */
2308	value = (~(ENVCTRL_UE250_FSP_KEYMASK | ENVCTRL_UE250_FSP_POMASK) &
2309	    (*val));
2310
2311	confirm_val_hold = value;
2312
2313	value = ~value;
2314
2315	while (confirm_count < confirm_max) {
2316		status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
2317		    0, &value, 1);
2318		if (status == DDI_FAILURE) {
2319			cmn_err(CE_WARN, "%s%d: Write to PCF8574A (FSP) failed",
2320			    driver_name, unitp->instance);
2321			break;
2322		} else {
2323			/*
2324			 * Sometimes the i2c hardware status is not
2325			 * completely dependable as far as reporting
2326			 * a condition where the set does not take
2327			 * place. So we read back the set value to
2328			 * confirm what we set.
2329			 */
2330			status = envctrl_get_fpm_status(unitp, &confirm_val);
2331			confirm_val = ~(ENVCTRL_UE250_FSP_KEYMASK |
2332			    ENVCTRL_UE250_FSP_POMASK) & confirm_val;
2333			if (status == DDI_FAILURE) {
2334				cmn_err(CE_WARN,
2335				"%s%d: Read of PCF8574A (FSP) failed",
2336				    driver_name, unitp->instance);
2337				break;
2338			} else if (confirm_val != confirm_val_hold) {
2339				confirm_count++;
2340				drv_usecwait(1000);
2341				continue;
2342			} else
2343				/*
2344				 * Set was confirmed.
2345				 */
2346				break;
2347		}
2348	}
2349
2350	if (confirm_count == confirm_max)
2351		status = DDI_FAILURE;
2352
2353	return (status);
2354
2355}
2356
2357static int
2358envctrl_get_dskled(struct envctrlunit *unitp, struct envctrl_chip *chip)
2359{
2360	int status;
2361
2362	ASSERT(MUTEX_HELD(&unitp->umutex));
2363
2364	if (chip->chip_num != EHC_DEV7 ||
2365	    chip->type != ENVCTRL_PCF8574A) {
2366		return (DDI_FAILURE);
2367	}
2368
2369	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
2370	    0, &chip->val, 1);
2371	if (status == DDI_FAILURE) {
2372		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
2373		    driver_name, unitp->instance);
2374	}
2375	chip->val = ~chip->val;
2376
2377	return (status);
2378}
2379
2380static int
2381envctrl_set_dskled(struct envctrlunit *unitp, struct envctrl_chip *chip)
2382{
2383	uint8_t val;
2384	int status;
2385	struct envctrl_chip confirm_chip;
2386	uint8_t confirm_val_hold;
2387	int confirm_count = 0, confirm_max = 20;
2388
2389	/*
2390	 * We need to check the type of disk led being set. If it
2391	 * is a 4 slot backplane then the upper 4 bits (7, 6, 5, 4) are
2392	 * invalid.
2393	 */
2394	ASSERT(MUTEX_HELD(&unitp->umutex));
2395
2396
2397	if (chip->chip_num != EHC_DEV7)
2398		return (DDI_FAILURE);
2399
2400	if (chip->type != ENVCTRL_PCF8574A)
2401		return (DDI_FAILURE);
2402
2403	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
2404	    0, &val, 1);
2405	if (status == DDI_FAILURE) {
2406		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (FSP) failed",
2407		    driver_name, unitp->instance);
2408		return (status);
2409	}
2410
2411	val = ~val;
2412	if ((chip->val & 0x3F) == 0) {
2413		if (!(envctrl_isother_fault_led(unitp, val,
2414		    ENVCTRL_UE250_FSP_DISK_ERR))) {
2415			val &= ~(ENVCTRL_UE250_FSP_DISK_ERR);
2416		} else {
2417			val &= ~(ENVCTRL_UE250_FSP_DISK_ERR |
2418			    ENVCTRL_UE250_FSP_GEN_ERR);
2419		}
2420		val = (val & ~(ENVCTRL_UE250_FSP_DISK_ERR |
2421		    ENVCTRL_UE250_FSP_GEN_ERR));
2422	} else {
2423		val = (val | (ENVCTRL_UE250_FSP_DISK_ERR |
2424		    ENVCTRL_UE250_FSP_GEN_ERR));
2425	}
2426
2427	status = envctrl_set_fsp(unitp, &val);
2428	if (status == DDI_FAILURE) {
2429		cmn_err(CE_WARN, "%s%d: Write to PCF8574A (FSP) failed",
2430		    driver_name, unitp->instance);
2431		return (status);
2432	}
2433
2434
2435	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV5,
2436	    0, &val, 1);
2437	if (status == DDI_FAILURE) {
2438		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
2439		    driver_name, unitp->instance);
2440		return (status);
2441	}
2442
2443	envctrl_update_disk_kstats(unitp, val, ~(chip->val));
2444
2445	/*
2446	 * we take the ones compliment of the val passed in
2447	 * because the hardware thinks that a "low" or "0"
2448	 * is the way to indicate a fault. of course software
2449	 * knows that a 1 is a TRUE state or fault. ;-)
2450	 */
2451
2452	confirm_val_hold = chip->val;
2453
2454	chip->val = ~(chip->val);
2455
2456	while (confirm_count < confirm_max) {
2457		status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
2458		    0, &chip->val, 1);
2459		if (status == DDI_FAILURE) {
2460			cmn_err(CE_WARN, "%s%d: Write PCF8574A (DISKFL) failed",
2461			    driver_name, unitp->instance);
2462			return (status);
2463		} else {
2464			/*
2465			 * Sometimes the i2c hardware status is not
2466			 * completely dependable as far as reporting
2467			 * a condition where the set does not take
2468			 * place. So we read back the set value to
2469			 * confirm what we set.
2470			 */
2471			confirm_chip.type = chip->type;
2472			confirm_chip.chip_num = chip->chip_num;
2473			confirm_chip.index = chip->index;
2474			status = envctrl_get_dskled(unitp, &confirm_chip);
2475			if (status != DDI_SUCCESS) {
2476				return (status);
2477			} else if (confirm_chip.val != confirm_val_hold) {
2478				confirm_count++;
2479				drv_usecwait(1000);
2480				continue;
2481			} else
2482				/*
2483				 * Set was confirmed.
2484				 */
2485				break;
2486		}
2487	}
2488
2489	if (confirm_count == confirm_max)
2490		return (DDI_FAILURE);
2491
2492	return (DDI_SUCCESS);
2493}
2494
2495/*
2496 * After setting the fan speed, we read back the fan speed to confirm
2497 * that the new value is within an acceptable range, else we retry.
2498 * We do not confirm the fan speed if the set value is below the
2499 * hardware determined speed (based on system temeratures).
2500 */
2501static int
2502envctrl_set_fanspeed(struct envctrlunit *unitp, struct envctrl_chip *fanspeed)
2503{
2504	int readback_speed, max_speed;
2505	int status;
2506	int confirm_count = 0, confirm_max = 20;
2507	uint8_t fanspeed_hold;
2508
2509	fanspeed_hold = fanspeed->val;
2510	while (confirm_count < confirm_max) {
2511		status = envctrl_write_chip(unitp, ENVCTRL_PCF8591,
2512		    EHC_DEV2, 0, &fanspeed->val, 1);
2513		if (status == DDI_FAILURE) {
2514			envctrl_fan_fail_service(unitp);
2515			cmn_err(CE_WARN,
2516			"%s%d: Set fanspeed failed", driver_name,
2517			    unitp->instance);
2518			return (status);
2519		} else {
2520			drv_usecwait(100000);
2521			envctrl_update_fanspeed(unitp);
2522			readback_speed = unitp->fan_kstats.fanspeed;
2523			if (fanspeed_hold > idle_fanspeed) {
2524				max_speed =
2525				    (fanspeed->val + FAN_DRIFT >
2526				    MAX_FAN_SPEED) ?  MAX_FAN_SPEED :
2527				    (fanspeed->val + FAN_DRIFT);
2528				if ((readback_speed < fanspeed->val -
2529				    FAN_DRIFT) ||
2530				    (readback_speed > max_speed)) {
2531					confirm_count++;
2532					drv_usecwait(1000);
2533					continue;
2534				}
2535			}
2536			break;
2537		}
2538	}
2539
2540	if (confirm_count == confirm_max)
2541		return (DDI_FAILURE);
2542
2543	return (DDI_SUCCESS);
2544}
2545
2546static void
2547envctrl_add_kstats(struct envctrlunit *unitp)
2548{
2549
2550	ASSERT(MUTEX_HELD(&unitp->umutex));
2551
2552	if ((unitp->enclksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
2553	    ENVCTRL_KSTAT_ENCL, "misc", KSTAT_TYPE_RAW,
2554	    sizeof (unitp->encl_kstats),
2555	    KSTAT_FLAG_PERSISTENT)) == NULL) {
2556		cmn_err(CE_WARN, "%s%d: encl raw kstat_create failed",
2557		    driver_name, unitp->instance);
2558		return;
2559	}
2560
2561	unitp->enclksp->ks_update = envctrl_encl_kstat_update;
2562	unitp->enclksp->ks_private = (void *)unitp;
2563	kstat_install(unitp->enclksp);
2564
2565
2566	if ((unitp->fanksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
2567	    ENVCTRL_KSTAT_FANSTAT, "misc", KSTAT_TYPE_RAW,
2568	    sizeof (unitp->fan_kstats),
2569	    KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
2570		cmn_err(CE_WARN, "%s%d: fans kstat_create failed",
2571		    driver_name, unitp->instance);
2572		return;
2573	}
2574
2575	unitp->fanksp->ks_update = envctrl_fanstat_kstat_update;
2576	unitp->fanksp->ks_private = (void *)unitp;
2577	kstat_install(unitp->fanksp);
2578
2579	if ((unitp->psksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
2580	    ENVCTRL_KSTAT_PSNAME2, "misc", KSTAT_TYPE_RAW,
2581	    sizeof (unitp->ps_kstats),
2582	    KSTAT_FLAG_PERSISTENT)) == NULL) {
2583		cmn_err(CE_WARN, "%s%d: ps name kstat_create failed",
2584		    driver_name, unitp->instance);
2585		return;
2586	}
2587
2588	unitp->psksp->ks_update = envctrl_ps_kstat_update;
2589	unitp->psksp->ks_private = (void *)unitp;
2590	kstat_install(unitp->psksp);
2591
2592	if ((unitp->tempksp = kstat_create(ENVCTRL_MODULE_NAME,
2593	    unitp->instance, ENVCTRL_KSTAT_TEMPERATURE, "misc", KSTAT_TYPE_RAW,
2594	    sizeof (unitp->temp_kstats),
2595	    KSTAT_FLAG_PERSISTENT)) == NULL) {
2596		cmn_err(CE_WARN, "%s%d: temp name kstat_create failed",
2597		    driver_name, unitp->instance);
2598		return;
2599	}
2600
2601	unitp->tempksp->ks_update = envctrl_temp_kstat_update;
2602	unitp->tempksp->ks_private = (void *)unitp;
2603	kstat_install(unitp->tempksp);
2604
2605	if ((unitp->diskksp = kstat_create(ENVCTRL_MODULE_NAME,
2606	    unitp->instance, ENVCTRL_KSTAT_DISK, "misc", KSTAT_TYPE_RAW,
2607	    sizeof (unitp->disk_kstats),
2608	    KSTAT_FLAG_PERSISTENT)) == NULL) {
2609		cmn_err(CE_WARN, "%s%d: disk name kstat_create failed",
2610		    driver_name, unitp->instance);
2611		return;
2612	}
2613
2614	unitp->diskksp->ks_update = envctrl_disk_kstat_update;
2615	unitp->diskksp->ks_private = (void *)unitp;
2616	kstat_install(unitp->diskksp);
2617
2618}
2619
2620static int
2621envctrl_ps_kstat_update(kstat_t *ksp, int rw)
2622{
2623	struct envctrlunit *unitp;
2624	char *kstatp;
2625
2626
2627
2628	unitp = (struct envctrlunit *)ksp->ks_private;
2629
2630	mutex_enter(&unitp->umutex);
2631	ASSERT(MUTEX_HELD(&unitp->umutex));
2632
2633	kstatp = (char *)ksp->ks_data;
2634
2635	if (rw == KSTAT_WRITE) {
2636		mutex_exit(&unitp->umutex);
2637		return (EACCES);
2638	} else {
2639
2640		unitp->psksp->ks_ndata = unitp->num_ps_present;
2641		bcopy((caddr_t)&unitp->ps_kstats, kstatp,
2642		    sizeof (unitp->ps_kstats));
2643	}
2644	mutex_exit(&unitp->umutex);
2645	return (DDI_SUCCESS);
2646}
2647
2648static int
2649envctrl_fanstat_kstat_update(kstat_t *ksp, int rw)
2650{
2651	struct envctrlunit *unitp;
2652	char *kstatp;
2653
2654	kstatp = (char *)ksp->ks_data;
2655	unitp = (struct envctrlunit *)ksp->ks_private;
2656
2657	mutex_enter(&unitp->umutex);
2658	ASSERT(MUTEX_HELD(&unitp->umutex));
2659
2660	if (rw == KSTAT_WRITE) {
2661		mutex_exit(&unitp->umutex);
2662		return (EACCES);
2663	} else {
2664		unitp->fanksp->ks_ndata = unitp->num_fans_present;
2665		bcopy((caddr_t)&unitp->fan_kstats, kstatp,
2666		    sizeof (unitp->fan_kstats));
2667	}
2668	mutex_exit(&unitp->umutex);
2669	return (DDI_SUCCESS);
2670}
2671
2672static int
2673envctrl_encl_kstat_update(kstat_t *ksp, int rw)
2674{
2675	struct envctrlunit *unitp;
2676	char *kstatp;
2677	int status;
2678
2679
2680	kstatp = (char *)ksp->ks_data;
2681	unitp = (struct envctrlunit *)ksp->ks_private;
2682
2683	mutex_enter(&unitp->umutex);
2684	ASSERT(MUTEX_HELD(&unitp->umutex));
2685
2686	if (rw == KSTAT_WRITE) {
2687		mutex_exit(&unitp->umutex);
2688		return (EACCES);
2689	} else {
2690
2691		unitp->enclksp->ks_ndata = unitp->num_encl_present;
2692		status = envctrl_get_fpm_status(unitp, (uint8_t *)NULL);
2693		if (status == DDI_SUCCESS)
2694			bcopy((caddr_t)&unitp->encl_kstats, kstatp,
2695			    sizeof (unitp->encl_kstats));
2696	}
2697	mutex_exit(&unitp->umutex);
2698	return (DDI_SUCCESS);
2699}
2700
2701static int
2702envctrl_temp_kstat_update(kstat_t *ksp, int rw)
2703{
2704	struct envctrlunit *unitp;
2705	char *kstatp;
2706
2707	kstatp = (char *)ksp->ks_data;
2708	unitp = (struct envctrlunit *)ksp->ks_private;
2709
2710	mutex_enter(&unitp->umutex);
2711	ASSERT(MUTEX_HELD(&unitp->umutex));
2712
2713	if (rw == KSTAT_WRITE) {
2714		mutex_exit(&unitp->umutex);
2715		return (EACCES);
2716	} else {
2717		unitp->tempksp->ks_ndata = unitp->num_temps_present;
2718		bcopy((caddr_t)unitp->temp_kstats, kstatp,
2719		    sizeof (unitp->temp_kstats));
2720	}
2721	mutex_exit(&unitp->umutex);
2722	return (DDI_SUCCESS);
2723}
2724
2725static int
2726envctrl_disk_kstat_update(kstat_t *ksp, int rw)
2727{
2728	struct envctrlunit *unitp;
2729	char *kstatp;
2730
2731	kstatp = (char *)ksp->ks_data;
2732	unitp = (struct envctrlunit *)ksp->ks_private;
2733
2734	mutex_enter(&unitp->umutex);
2735	ASSERT(MUTEX_HELD(&unitp->umutex));
2736
2737	if (rw == KSTAT_WRITE) {
2738		mutex_exit(&unitp->umutex);
2739		return (EACCES);
2740	} else {
2741		unitp->diskksp->ks_ndata = unitp->num_disks_present;
2742		bcopy((caddr_t)unitp->disk_kstats, kstatp,
2743		    sizeof (unitp->disk_kstats));
2744	}
2745	mutex_exit(&unitp->umutex);
2746	return (DDI_SUCCESS);
2747}
2748
2749static void
2750envctrl_init_encl_kstats(struct envctrlunit *unitp)
2751{
2752	uint8_t val;
2753	int status;
2754
2755	ASSERT(MUTEX_HELD(&unitp->umutex));
2756
2757	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
2758	    0, &val, 1);
2759	if (status == DDI_FAILURE) {
2760		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (FSP) failed",
2761		    driver_name, unitp->instance);
2762		return;
2763	}
2764
2765	unitp->encl_kstats.value = val;
2766}
2767
2768static void
2769envctrl_check_disk_kstats(struct envctrlunit *unitp)
2770{
2771	uint8_t diskpr, diskfl;
2772	int status;
2773
2774	ASSERT(MUTEX_HELD(&unitp->umutex));
2775
2776	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV5,
2777	    0, &diskpr, 1);
2778	if (status == DDI_FAILURE) {
2779		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKPR) failed",
2780		    driver_name, unitp->instance);
2781	}
2782
2783	status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
2784	    0, &diskfl, 1);
2785	if (status == DDI_FAILURE) {
2786		cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
2787		    driver_name, unitp->instance);
2788	}
2789
2790	envctrl_update_disk_kstats(unitp, diskpr, diskfl);
2791
2792}
2793
2794static void
2795envctrl_update_disk_kstats(struct envctrlunit *unitp, uint8_t diskpr,
2796	uint8_t diskfl)
2797{
2798	int i, j, count = 0;
2799
2800	DPRINTF1("diskpr = %X, diskfl = %X\n", diskpr, diskfl);
2801	for (i = 0, j = 1; i < ENVCTRL_UE250_MAX_DISKS; i++, j = j << 1) {
2802		if (!(diskpr & j)) {
2803			if (!(diskfl & j))
2804				unitp->disk_kstats[count].disk_ok = 0;
2805			else
2806				unitp->disk_kstats[count].disk_ok = 1;
2807			unitp->disk_kstats[count].slot = i;
2808			count++;
2809		}
2810	}
2811
2812	unitp->num_disks_present = count;
2813}
2814
2815static void
2816envctrl_probe_cpus(struct envctrlunit *unitp)
2817{
2818	int instance;
2819
2820	/*
2821	 * The cpu search is as follows:
2822	 * If there is only 1 CPU module it is named as
2823	 * SUNW,UltraSPARC. If this is a match we still don't
2824	 * know what slot the cpu module is in therefore
2825	 * we need to check the "upa-portid" property.
2826	 * If we have more than 1 cpu, then they are appended by
2827	 * instance numbers and slot locations. e.g.
2828	 * SUNW,UltraSPARC@1,0 (slot 1). it would have been
2829	 * nice to have the naming consistent for one CPU e.g.
2830	 * SUNW,UltraSPARC@0,0...sigh
2831	 */
2832
2833	for (instance = 0; instance < ENVCTRL_MAX_CPUS; instance++) {
2834		unitp->cpu_pr_location[instance] = B_FALSE;
2835	}
2836
2837	ddi_walk_devs(ddi_root_node(), envctrl_match_cpu, unitp);
2838}
2839
2840static int
2841envctrl_match_cpu(dev_info_t *dip, void *arg)
2842{
2843
2844	int cpu_slot;
2845	char name[32];
2846	char name1[32];
2847	struct envctrlunit *unitp = (struct envctrlunit *)arg;
2848
2849	(void) sprintf(name, "%s", ENVCTRL_ULTRA1CPU_STRING);
2850	(void) sprintf(name1, "%s", ENVCTRL_ULTRA2CPU_STRING);
2851
2852	if ((strcmp(ddi_node_name(dip), name) == 0) ||
2853	    (strcmp(ddi_node_name(dip), name1) == 0)) {
2854		if ((cpu_slot = (int)ddi_getprop(DDI_DEV_T_ANY, dip,
2855		    DDI_PROP_DONTPASS, "upa-portid",
2856		    -1)) == -1) {
2857			cmn_err(CE_WARN, "%s%d: no cpu upa-portid",
2858			    driver_name, unitp->instance);
2859		} else {
2860			unitp->cpu_pr_location[cpu_slot] = B_TRUE;
2861			unitp->num_cpus_present++;
2862		}
2863	}
2864
2865	return (DDI_WALK_CONTINUE);
2866}
2867
2868/*
2869 * This routine returns TRUE if some other error condition
2870 * has set the GEN_ERR FAULT LED. Tp further complicate this
2871 * LED panel we have overloaded the GEN_ERR LED to indicate
2872 * that a fan fault has occurred without having a fan fault
2873 * LED as does all other error conditions. So we just take the
2874 * software state and return true. The whole purpose of this functon
2875 * is to tell us wehther or not we can shut off the GEN_FAULT LED.
2876 * NOTE: this ledval is usually one of the following FSP vals
2877 * EXCEPT in the case of the fan fail.. we pass in a "0".
2878 */
2879
2880static int
2881envctrl_isother_fault_led(struct envctrlunit *unitp, uint8_t fspval,
2882    uint8_t thisled)
2883{
2884	int status = B_FALSE;
2885
2886	if (fspval != 0) {
2887		fspval = (fspval & ~(thisled));
2888	}
2889	if ((unitp->fan_failed == B_TRUE) && thisled != 0) {
2890		status = B_TRUE;
2891	} else if (fspval & ENVCTRL_UE250_FSP_DISK_ERR) {
2892		status = B_TRUE;
2893	} else if (fspval & ENVCTRL_UE250_FSP_PS_ERR) {
2894		status = B_TRUE;
2895	} else if (fspval & ENVCTRL_UE250_FSP_TEMP_ERR) {
2896		status = B_TRUE;
2897	}
2898	return (status);
2899}
2900
2901static void
2902envctrl_pshotplug_poll(void *arg)
2903{
2904	struct envctrlunit *unitp = (struct envctrlunit *)arg;
2905
2906	mutex_enter(&unitp->umutex);
2907
2908	envctrl_ps_probe(unitp);
2909
2910	mutex_exit(&unitp->umutex);
2911}
2912