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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)2633db86aabSstevel _info(struct modinfo *modinfop)
2643db86aabSstevel {
2653db86aabSstevel return (mod_info(&envctrlmodlinkage, modinfop));
2663db86aabSstevel }
2673db86aabSstevel
2683db86aabSstevel static int
envctrl_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
envctrl_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
envctrl_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)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
envctrl_open(dev_t * dev,int flag,int otyp,cred_t * cred_p)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
envctrl_close(dev_t dev,int flag,int otyp,cred_t * cred_p)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
envctrl_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rvalp)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
envctrl_bus_isr(caddr_t arg)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
envctrl_dev_isr(caddr_t arg)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
envctrl_read_chip(struct envctrlunit * unitp,int type,int chip_num,int port,uint8_t * data,int num)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
envctrl_write_chip(struct envctrlunit * unitp,int type,int chip_num,int port,uint8_t * data,int num)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
envctrl_get_cpu_temp(struct envctrlunit * unitp,int cpunum)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
envctrl_tempr_poll(void * arg)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
envctrl_led_blink(void * arg)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
envctrl_check_sys_temperatures(struct envctrlunit * unitp)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
envctrl_check_tempr_levels(struct envctrlunit * unitp,int chip_num,uint8_t * data,int count)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
envctrl_update_fanspeed(struct envctrlunit * unitp)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
envctrl_fan_fail_service(struct envctrlunit * unitp)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
envctrl_PS_intr_service(struct envctrlunit * unitp)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
envctrl_init_bus(struct envctrlunit * unitp)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
envctrl_reset_dflop(struct envctrlunit * unitp)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
envctrl_enable_devintrs(struct envctrlunit * unitp)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
envctrl_intr_latch_clr(struct envctrlunit * unitp)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
envctrl_ps_probe(struct envctrlunit * unitp)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
envctrl_abort_seq_handler(char * msg)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
envctrl_get_fpm_status(struct envctrlunit * unitp,uint8_t * val)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
envctrl_set_fsp(struct envctrlunit * unitp,uint8_t * val)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
envctrl_get_dskled(struct envctrlunit * unitp,struct envctrl_chip * chip)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
envctrl_set_dskled(struct envctrlunit * unitp,struct envctrl_chip * chip)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
envctrl_set_fanspeed(struct envctrlunit * unitp,struct envctrl_chip * fanspeed)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
envctrl_add_kstats(struct envctrlunit * unitp)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
envctrl_ps_kstat_update(kstat_t * ksp,int rw)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
envctrl_fanstat_kstat_update(kstat_t * ksp,int rw)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
envctrl_encl_kstat_update(kstat_t * ksp,int rw)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
envctrl_temp_kstat_update(kstat_t * ksp,int rw)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
envctrl_disk_kstat_update(kstat_t * ksp,int rw)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
envctrl_init_encl_kstats(struct envctrlunit * unitp)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
envctrl_check_disk_kstats(struct envctrlunit * unitp)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
envctrl_update_disk_kstats(struct envctrlunit * unitp,uint8_t diskpr,uint8_t diskfl)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
envctrl_probe_cpus(struct envctrlunit * unitp)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
envctrl_match_cpu(dev_info_t * dip,void * arg)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
envctrl_isother_fault_led(struct envctrlunit * unitp,uint8_t fspval,uint8_t thisled)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
envctrl_pshotplug_poll(void * arg)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