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