#include <sys/param.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/errno.h>
#include <sys/file.h>
#include <sys/termio.h>
#include <sys/termios.h>
#include <sys/cmn_err.h>
#include <sys/stream.h>
#include <sys/strsun.h>
#include <sys/stropts.h>
#include <sys/strtty.h>
#include <sys/debug.h>
#include <sys/eucioctl.h>
#include <sys/cred.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/kmem.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/obpdefs.h>
#include <sys/conf.h>
#include <sys/modctl.h>
#include <sys/stat.h>
#include <sys/open.h>
#include <sys/uio.h>
#include <sys/envctrl_gen.h>
#include <sys/envctrl_ue250.h>
#include <javelin/sys/envctrltwo.h>
#include <io/envctrl_targets.c>
#include <sys/priv_names.h>
static int envctrl_open(dev_t *, int, int, cred_t *);
static int envctrl_close(dev_t, int, int, cred_t *);
static int envctrl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
static uint_t envctrl_bus_isr(caddr_t);
static uint_t envctrl_dev_isr(caddr_t);
static int envctrl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
static int envctrl_attach(dev_info_t *, ddi_attach_cmd_t);
static int envctrl_detach(dev_info_t *, ddi_detach_cmd_t);
#ifdef GET_CPU_TEMP
static int envctrl_get_cpu_temp(struct envctrlunit *, int);
#endif
static void envctrl_fan_fail_service(struct envctrlunit *);
static void envctrl_PS_intr_service(struct envctrlunit *);
static void envctrl_ps_probe(struct envctrlunit *);
static void envctrl_tempr_poll(void *);
static void envctrl_pshotplug_poll(void *);
static void envctrl_led_blink(void *);
static void envctrl_init_bus(struct envctrlunit *);
static void envctrl_reset_dflop(struct envctrlunit *);
static void envctrl_enable_devintrs(struct envctrlunit *);
static void envctrl_intr_latch_clr(struct envctrlunit *);
static void envctrl_abort_seq_handler(char *msg);
static int envctrl_get_fpm_status(struct envctrlunit *, uint8_t *);
static int envctrl_set_fsp(struct envctrlunit *, uint8_t *);
static int envctrl_set_dskled(struct envctrlunit *,
struct envctrl_chip *);
static int envctrl_get_dskled(struct envctrlunit *,
struct envctrl_chip *);
static int envctrl_set_fanspeed(struct envctrlunit *,
struct envctrl_chip *);
static void envctrl_probe_cpus(struct envctrlunit *);
static int envctrl_match_cpu(dev_info_t *, void *);
static int envctrl_isother_fault_led(struct envctrlunit *,
uint8_t, uint8_t);
static int envctrl_check_sys_temperatures(struct envctrlunit *);
static void envctrl_check_disk_kstats(struct envctrlunit *);
static void envctrl_update_disk_kstats(struct envctrlunit *,
uint8_t, uint8_t);
static int envctrl_read_chip(struct envctrlunit *, int, int, int,
uint8_t *, int);
static int envctrl_write_chip(struct envctrlunit *, int, int, int,
uint8_t *, int);
static int envctrl_check_tempr_levels(struct envctrlunit *,
int, uint8_t *, int);
static void envctrl_update_fanspeed(struct envctrlunit *);
static void envctrl_add_kstats(struct envctrlunit *);
static int envctrl_ps_kstat_update(kstat_t *, int);
static int envctrl_fanstat_kstat_update(kstat_t *, int);
static int envctrl_encl_kstat_update(kstat_t *, int);
static int envctrl_temp_kstat_update(kstat_t *, int);
static int envctrl_disk_kstat_update(kstat_t *, int);
static void envctrl_init_encl_kstats(struct envctrlunit *);
extern void power_down(const char *);
extern int prom_getprop();
extern int prom_getproplen();
extern void prom_printf(const char *fmt, ...);
extern void (*abort_seq_handler)();
static void *envctrlsoft_statep;
static char driver_name[] = "envctrltwo";
static uchar_t _cpu_temps[256];
static uchar_t _cpu_fan_speeds[256];
static int psok[2] = {-1, -1};
static int pspr[2] = {-1, -1};
static uint8_t idle_fanspeed;
static int power_flt_led_lit = 0;
extern void pci_thermal_rem_intr(dev_info_t *, uint_t);
static int envctrl_debug_flags = 0;
static int envctrl_power_off_overide = 0;
static int envctrl_max_retries = 200;
static int envctrl_allow_detach = 0;
static int envctrl_numcpus = 1;
static int envctrl_handler = 1;
static clock_t overtemp_timeout_hz;
static clock_t blink_timeout_hz;
static clock_t pshotplug_timeout_hz;
static clock_t warning_timeout_hz;
enum levels {green, yellow, red};
#define DPRINTF1 if (envctrl_debug_flags && (envctrl_debug_flags & 0x1)) printf
#define DPRINTF2 if (envctrl_debug_flags && (envctrl_debug_flags & 0x2)) printf
#define DPRINTF3 if (envctrl_debug_flags && (envctrl_debug_flags & 0x4)) printf
#define JAV_FAN_SPEED_SF_NUM 107
#define JAV_FAN_SPEED_SF_DEN 100
#define JAV_MAX_TEMP_SENSORS 6
#define JAV_FSP_MASK 0xC0
#define FAN_DRIFT 25
#define MAX_FAN_SPEED 255
#define MAX_DEVS 16
#define ENVCTRL_UE250_INTR_LATCH_INIT0 0xFE
#define ENVCTRL_UE250_INTR_LATCH_INIT1 0xFF
static int t_scale_num[8];
static int t_scale_den[8];
static uint8_t t_addr[8];
static uint8_t t_port[8];
static int sensor_types[] = { ENVCTRL_UE250_CPU0_SENSOR,
ENVCTRL_UE250_CPU1_SENSOR, ENVCTRL_UE250_MB0_SENSOR,
ENVCTRL_UE250_MB1_SENSOR, ENVCTRL_UE250_PDB_SENSOR,
ENVCTRL_UE250_SCSI_SENSOR };
static struct cb_ops envctrl_cb_ops = {
envctrl_open,
envctrl_close,
nodev,
nodev,
nodev,
nodev,
nodev,
envctrl_ioctl,
nodev,
nodev,
nodev,
nochpoll,
ddi_prop_op,
NULL,
(int)(D_NEW | D_MP)
};
struct dev_ops envctrltwo_ops = {
DEVO_REV,
0,
envctrl_getinfo,
nulldev,
nulldev,
envctrl_attach,
envctrl_detach,
nodev,
&envctrl_cb_ops,
(struct bus_ops *)NULL,
nulldev,
ddi_quiesce_not_supported,
};
extern struct mod_ops mod_driverops;
static struct modldrv envctrlmodldrv = {
&mod_driverops,
"I2C ENVCTRLTWO_driver",
&envctrltwo_ops,
};
static struct modlinkage envctrlmodlinkage = {
MODREV_1,
&envctrlmodldrv,
0
};
int
_init(void)
{
register int error;
if ((error = mod_install(&envctrlmodlinkage)) == 0) {
(void) ddi_soft_state_init(&envctrlsoft_statep,
sizeof (struct envctrlunit), 1);
}
return (error);
}
int
_fini(void)
{
register int error;
if ((error = mod_remove(&envctrlmodlinkage)) == 0)
ddi_soft_state_fini(&envctrlsoft_statep);
return (error);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&envctrlmodlinkage, modinfop));
}
static int
envctrl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
register int instance;
char name[16];
uint8_t fspval;
register struct envctrlunit *unitp;
struct ddi_device_acc_attr attr;
uchar_t *creg_prop;
uint_t len, tblsz;
int i, j, k, status;
uint8_t fanspeed;
status = len = tblsz = 0;
attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
instance = ddi_get_instance(dip);
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
if (!(unitp = ddi_get_soft_state(envctrlsoft_statep, instance)))
return (DDI_FAILURE);
mutex_enter(&unitp->umutex);
if (!unitp->suspended) {
mutex_exit(&unitp->umutex);
return (DDI_FAILURE);
}
unitp->suspended = 0;
unitp->initting = B_TRUE;
envctrl_init_bus(unitp);
unitp->initting = B_FALSE;
envctrl_ps_probe(unitp);
envctrl_probe_cpus(unitp);
mutex_exit(&unitp->umutex);
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
overtemp_timeout_hz = drv_usectohz(ENVCTRL_UE250_OVERTEMP_TIMEOUT_USEC);
blink_timeout_hz = drv_usectohz(ENVCTRL_UE250_BLINK_TIMEOUT_USEC);
pshotplug_timeout_hz =
drv_usectohz(ENVCTRL_UE250_BLINK_TIMEOUT_USEC * 2);
warning_timeout_hz =
drv_usectohz(ENVCTRL_UE250_OVERTEMP_TIMEOUT_USEC / 6);
if (ddi_soft_state_zalloc(envctrlsoft_statep, instance) != 0) {
cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n",
ddi_get_name(dip), instance);
goto failed;
}
unitp = ddi_get_soft_state(envctrlsoft_statep, instance);
if (ddi_regs_map_setup(dip, 0, (caddr_t *)&unitp->bus_ctl_regs, 0,
sizeof (struct ehc_pcd8584_regs), &attr,
&unitp->ctlr_handle) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s%d: failed to map in bus_control regs\n",
ddi_get_name(dip), instance);
return (DDI_FAILURE);
}
pci_thermal_rem_intr(dip, (uint_t)0);
if (ddi_get_iblock_cookie(dip, 1,
&unitp->ic_trap_cookie) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s%d: ddi_get_iblock_cookie FAILED \n",
ddi_get_name(dip), instance);
goto failed;
}
mutex_init(&unitp->umutex, NULL, MUTEX_DRIVER,
(void *)unitp->ic_trap_cookie);
if (ddi_add_intr(dip, 0, &unitp->ic_trap_cookie, NULL, envctrl_bus_isr,
(caddr_t)unitp) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s%d: failed to add hard intr \n",
ddi_get_name(dip), instance);
goto remlock;
}
if (ddi_add_intr(dip, 1, &unitp->ic_trap_cookie, NULL, envctrl_dev_isr,
(caddr_t)unitp) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s%d: failed to add hard intr \n",
ddi_get_name(dip), instance);
goto remhardintr;
}
(void) sprintf(name, "envctrltwo%d", instance);
if (ddi_create_priv_minor_node(dip, name, S_IFCHR, instance,
DDI_PSEUDO, 0, PRIV_SYS_CONFIG, PRIV_SYS_CONFIG, 0666) ==
DDI_FAILURE) {
goto remhardintr1;
}
mutex_enter(&unitp->umutex);
unitp->activity_led_blink = B_TRUE;
unitp->shutdown = B_FALSE;
unitp->num_ps_present = 0;
unitp->num_encl_present = 1;
unitp->current_mode = ENVCTRL_NORMAL_MODE;
if (envctrl_numcpus > 1) {
unitp->num_cpus_present = envctrl_numcpus;
}
envctrl_probe_cpus(unitp);
if ((unitp->cpu_pr_location[ENVCTRL_CPU0] == B_FALSE) ||
(unitp->cpu_pr_location[ENVCTRL_CPU1] == B_FALSE))
unitp->num_temps_present = 5;
else
unitp->num_temps_present = 6;
unitp->num_fans_present = 1;
unitp->dip = dip;
mutex_exit(&unitp->umutex);
if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
"cpu-temp-factors", &creg_prop, &len) != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN,
"%s%d: Unable to read cpu-temp-factors property",
ddi_get_name(dip), instance);
return (DDI_NOT_WELL_FORMED);
}
tblsz = (sizeof (_cpu_temps) / sizeof (uchar_t));
if (len <= tblsz && status == DDI_PROP_SUCCESS) {
for (i = 0; i < len; i++) {
_cpu_temps[i+2] = creg_prop[i];
}
}
_cpu_temps[0] = _cpu_temps[1] = _cpu_temps[2];
ddi_prop_free((void *)creg_prop);
if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
"cpu-fan-speeds", &creg_prop, &len) != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN,
"%s%d: Unable to read cpu-fan-speeds property",
ddi_get_name(dip), instance);
return (DDI_NOT_WELL_FORMED);
}
tblsz = (sizeof (_cpu_fan_speeds) / sizeof (uchar_t));
if (len <= tblsz && status == DDI_PROP_SUCCESS) {
for (i = 0; i < len; i++) {
_cpu_fan_speeds[i+2] = creg_prop[i];
}
}
_cpu_fan_speeds[0] = _cpu_fan_speeds[1] = _cpu_fan_speeds[2];
ddi_prop_free((void *)creg_prop);
if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
"thermisters", &creg_prop, &len) != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN,
"%s%d: Unable to read thermisters property",
ddi_get_name(dip), instance);
return (DDI_NOT_WELL_FORMED);
}
mutex_enter(&unitp->umutex);
j = 0; k = 0;
for (i = 0; i < JAV_MAX_TEMP_SENSORS; i++) {
unitp->temp_kstats[k].type = sensor_types[i];
t_addr[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
creg_prop[j+2] << 8 | creg_prop[j+3];
j += 4;
t_port[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
creg_prop[j+2] << 8 | creg_prop[j+3];
j += 4;
unitp->temp_kstats[k].min =
creg_prop[j] << 24 | creg_prop[j+1] << 16 |
creg_prop[j+2] << 8 | creg_prop[j+3];
j += 4;
unitp->temp_kstats[k].warning_threshold =
creg_prop[j] << 24 | creg_prop[j+1] << 16 |
creg_prop[j+2] << 8 | creg_prop[j+3];
j += 4;
unitp->temp_kstats[k].shutdown_threshold =
creg_prop[j] << 24 | creg_prop[j+1] << 16 |
creg_prop[j+2] << 8 | creg_prop[j+3];
j += 4;
t_scale_num[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
creg_prop[j+2] << 8 | creg_prop[j+3];
j += 4;
t_scale_den[k] = creg_prop[j] << 24 | creg_prop[j+1] << 16 |
creg_prop[j+2] << 8 | creg_prop[j+3];
j += 4;
bcopy((caddr_t)&creg_prop[j], unitp->temp_kstats[k].label,
(size_t)sizeof (&creg_prop[j]));
while (creg_prop[j] != '\0') j++;
j++;
if (t_addr[k] == ENVCTRL_UE250_CPU_TEMP_DEV) {
if (((t_port[k] == ENVCTRL_UE250_CPU0_PORT) &&
(unitp->cpu_pr_location[ENVCTRL_CPU0] ==
B_FALSE)) ||
((t_port[k] == ENVCTRL_UE250_CPU1_PORT) &&
(unitp->cpu_pr_location[ENVCTRL_CPU1] == B_FALSE)))
#ifdef lint
k = k;
#else
;
#endif
else
k++;
} else
k++;
}
ddi_prop_free((void *)creg_prop);
unitp->initting = B_TRUE;
envctrl_init_bus(unitp);
DPRINTF1("envctrl_attach(): Completed initialization of PCF8584");
unitp->initting = B_FALSE;
drv_usecwait(1000);
unitp->timeout_id = 0;
unitp->blink_timeout_id = 0;
unitp->fan_failed = 0;
unitp->fan_kstats.fans_ok = B_TRUE;
unitp->tempr_warning = 0;
envctrl_ps_probe(unitp);
unitp->initting = B_TRUE;
envctrl_fan_fail_service(unitp);
unitp->initting = B_FALSE;
fanspeed = 0x0;
status = envctrl_write_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2, 0,
&fanspeed, 1);
if (status == DDI_FAILURE)
cmn_err(CE_WARN, "%s%d: Write to PCF8591 (SETFAN) failed\n",
ddi_get_name(dip), instance);
envctrl_add_kstats(unitp);
envctrl_init_encl_kstats(unitp);
envctrl_check_disk_kstats(unitp);
envctrl_update_fanspeed(unitp);
idle_fanspeed = unitp->fan_kstats.fanspeed;
if (unitp->activity_led_blink == B_TRUE) {
unitp->present_led_state = B_FALSE;
mutex_exit(&unitp->umutex);
envctrl_led_blink((void *)unitp);
mutex_enter(&unitp->umutex);
} else {
fspval = ENVCTRL_UE250_FSP_ACTIVE;
(void) envctrl_set_fsp(unitp, &fspval);
}
mutex_exit(&unitp->umutex);
envctrl_tempr_poll((void *)unitp);
if (envctrl_handler) {
abort_seq_handler = envctrl_abort_seq_handler;
}
ddi_report_dev(dip);
return (DDI_SUCCESS);
remhardintr1:
ddi_remove_intr(dip, (uint_t)1, unitp->ic_trap_cookie);
remhardintr:
ddi_remove_intr(dip, (uint_t)0, unitp->ic_trap_cookie);
remlock:
mutex_destroy(&unitp->umutex);
failed:
if (unitp->ctlr_handle)
ddi_regs_map_free(&unitp->ctlr_handle);
cmn_err(CE_WARN, "%s%d: attach failed\n", ddi_get_name(dip), instance);
return (DDI_FAILURE);
}
static int
envctrl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
int instance;
register struct envctrlunit *unitp;
instance = ddi_get_instance(dip);
unitp = ddi_get_soft_state(envctrlsoft_statep, instance);
switch (cmd) {
case DDI_DETACH:
if (envctrl_allow_detach) {
if (unitp->psksp != NULL) {
kstat_delete(unitp->psksp);
}
if (unitp->fanksp != NULL) {
kstat_delete(unitp->fanksp);
}
if (unitp->enclksp != NULL) {
kstat_delete(unitp->enclksp);
}
if (unitp->tempksp != NULL) {
kstat_delete(unitp->tempksp);
}
if (unitp->diskksp != NULL) {
kstat_delete(unitp->diskksp);
}
if (unitp->timeout_id != 0) {
(void) untimeout(unitp->timeout_id);
unitp->timeout_id = 0;
}
if (unitp->blink_timeout_id != 0) {
(void) untimeout(unitp->blink_timeout_id);
unitp->blink_timeout_id = 0;
}
ddi_remove_minor_node(dip, NULL);
ddi_remove_intr(dip, (uint_t)0, unitp->ic_trap_cookie);
ddi_remove_intr(dip, (uint_t)1, unitp->ic_trap_cookie);
ddi_regs_map_free(&unitp->ctlr_handle);
mutex_destroy(&unitp->umutex);
return (DDI_SUCCESS);
} else {
return (DDI_FAILURE);
}
case DDI_SUSPEND:
if (!(unitp = ddi_get_soft_state(envctrlsoft_statep, instance)))
return (DDI_FAILURE);
mutex_enter(&unitp->umutex);
if (unitp->suspended) {
cmn_err(CE_WARN, "%s%d: envctrltwo already suspended\n",
ddi_get_name(dip), instance);
mutex_exit(&unitp->umutex);
return (DDI_FAILURE);
}
unitp->suspended = 1;
mutex_exit(&unitp->umutex);
return (DDI_SUCCESS);
default:
cmn_err(CE_WARN, "%s%d: suspend general fault\n",
ddi_get_name(dip), instance);
return (DDI_FAILURE);
}
}
int
envctrl_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
void **result)
{
dev_t dev = (dev_t)arg;
struct envctrlunit *unitp;
int instance, ret;
instance = getminor(dev);
#ifdef lint
dip = dip;
#endif
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
if ((unitp = (struct envctrlunit *)
ddi_get_soft_state(envctrlsoft_statep,
instance)) != NULL) {
*result = unitp->dip;
ret = DDI_SUCCESS;
} else {
*result = NULL;
ret = DDI_FAILURE;
}
break;
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)(uintptr_t)instance;
ret = DDI_SUCCESS;
break;
default:
ret = DDI_FAILURE;
break;
}
return (ret);
}
static int
envctrl_open(dev_t *dev, int flag, int otyp, cred_t *cred_p)
{
struct envctrlunit *unitp;
int status = 0;
register int instance;
instance = getminor(*dev);
if (instance < 0)
return (ENXIO);
unitp = (struct envctrlunit *)
ddi_get_soft_state(envctrlsoft_statep, instance);
if (unitp == NULL)
return (ENXIO);
if (otyp != OTYP_CHR)
return (EINVAL);
mutex_enter(&unitp->umutex);
if (flag & FWRITE) {
if ((unitp->oflag & FWRITE)) {
mutex_exit(&unitp->umutex);
return (EBUSY);
} else {
unitp->oflag |= FWRITE;
}
}
mutex_exit(&unitp->umutex);
return (status);
}
static int
envctrl_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
{
struct envctrlunit *unitp;
register int instance;
instance = getminor(dev);
if (instance < 0)
return (ENXIO);
unitp = (struct envctrlunit *)
ddi_get_soft_state(envctrlsoft_statep, instance);
if (unitp == NULL)
return (ENXIO);
mutex_enter(&unitp->umutex);
unitp->oflag = B_FALSE;
unitp->current_mode = ENVCTRL_NORMAL_MODE;
mutex_exit(&unitp->umutex);
return (DDI_SUCCESS);
}
static int
envctrl_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
int *rvalp)
{
struct envctrlunit *unitp;
register int instance;
uint8_t wdval, tempr;
struct envctrl_chip fanspeed;
struct envctrl_chip ledchip, envcchip;
struct envctrl_chip temp, a_fanspeed;
int rval = 0, status, tfanspeed;
#ifdef lint
cred_p = cred_p;
rvalp = rvalp;
#endif
instance = getminor(dev);
unitp = (struct envctrlunit *)
ddi_get_soft_state(envctrlsoft_statep, instance);
if ((cmd == ENVCTRL_IOC_SETFAN2) ||
(cmd == ENVCTRL_IOC_GETFAN2) ||
(cmd == ENVCTRL_IOC_SETMODE) ||
(cmd == ENVCTRL_IOC_GETMODE) ||
(cmd == ENVCTRL_IOC_GETTEMP2) ||
(cmd == ENVCTRL_IOC_SETFSP2) ||
(cmd == ENVCTRL_IOC_GETFSP2) ||
(cmd == ENVCTRL_IOC_RESETTMPR) ||
(cmd == ENVCTRL_IOC_SETDSKLED2) ||
(cmd == ENVCTRL_IOC_GETDSKLED2))
if ((caddr_t)arg == NULL)
return (EFAULT);
switch (cmd) {
case ENVCTRL_IOC_SETMODE:
if (ddi_copyin((caddr_t)arg, (caddr_t)&wdval, sizeof (uint8_t),
flag)) {
rval = EFAULT;
break;
}
if (wdval == ENVCTRL_DIAG_MODE ||
wdval == ENVCTRL_NORMAL_MODE) {
mutex_enter(&unitp->umutex);
unitp->current_mode = wdval;
if (unitp->timeout_id != 0 &&
wdval == ENVCTRL_DIAG_MODE) {
(void) untimeout(unitp->timeout_id);
unitp->timeout_id =
(timeout(envctrl_tempr_poll,
(caddr_t)unitp, overtemp_timeout_hz));
}
if (wdval == ENVCTRL_NORMAL_MODE) {
tempr = 0x0;
status = envctrl_write_chip(unitp,
ENVCTRL_PCF8591, EHC_DEV2, 0,
&tempr, 1);
if (status == DDI_FAILURE)
cmn_err(CE_WARN,
"%s%d: Write to PCF8591 "
"(SETMODE) failed\n",
driver_name, unitp->instance);
drv_usecwait(100000);
(void) envctrl_check_sys_temperatures(unitp);
unitp->current_mode = ENVCTRL_DIAG_MODE;
envctrl_fan_fail_service(unitp);
unitp->current_mode = ENVCTRL_NORMAL_MODE;
}
mutex_exit(&unitp->umutex);
} else {
rval = EINVAL;
}
break;
case ENVCTRL_IOC_GETMODE:
wdval = unitp->current_mode;
if (ddi_copyout((caddr_t)&wdval, (caddr_t)arg,
sizeof (uint8_t), flag)) {
rval = EFAULT;
}
break;
case ENVCTRL_IOC_RESETTMPR:
if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
if (unitp->timeout_id != 0) {
(void) untimeout(unitp->timeout_id);
unitp->timeout_id = 0;
}
envctrl_tempr_poll((void *)unitp);
} else {
rval = EINVAL;
}
break;
case ENVCTRL_IOC_GETTEMP2:
if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
break;
}
if (((temp.chip_num != ENVCTRL_DEV2) &&
(temp.chip_num != ENVCTRL_DEV7)) ||
(temp.index > EHC_PCF8591_CH_3)) {
rval = EINVAL;
break;
}
mutex_enter(&unitp->umutex);
status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
temp.chip_num, temp.index, &temp.val, 1);
mutex_exit(&unitp->umutex);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Read from PCF8591 (IOC_GETTEMP) failed",
driver_name, unitp->instance);
rval = EINVAL;
break;
}
if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
}
break;
case ENVCTRL_IOC_SETTEMP:
rval = EINVAL;
break;
case ENVCTRL_IOC_SETWDT:
rval = EINVAL;
break;
case ENVCTRL_IOC_SETFAN2:
if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
if (ddi_copyin((caddr_t)arg, (caddr_t)&fanspeed,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
break;
}
if ((fanspeed.type != ENVCTRL_PCF8591) ||
(fanspeed.chip_num != ENVCTRL_DEV2) ||
(fanspeed.index > EHC_PCF8591_CH_3)) {
rval = EINVAL;
break;
}
mutex_enter(&unitp->umutex);
status = envctrl_set_fanspeed(unitp, &fanspeed);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Write to PCF8591 "
"(IOC_SETFAN) failed",
driver_name, unitp->instance);
rval = EINVAL;
}
mutex_exit(&unitp->umutex);
} else {
rval = EINVAL;
}
break;
case ENVCTRL_IOC_GETFAN2:
if (ddi_copyin((caddr_t)arg, (caddr_t)&a_fanspeed,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
break;
}
if ((a_fanspeed.type != ENVCTRL_PCF8591) ||
(a_fanspeed.chip_num != ENVCTRL_DEV2) ||
(a_fanspeed.index != EHC_PCF8591_CH_1)) {
rval = EINVAL;
break;
}
mutex_enter(&unitp->umutex);
status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
a_fanspeed.chip_num, a_fanspeed.index,
&a_fanspeed.val, 1);
mutex_exit(&unitp->umutex);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Read of PCF8591 (IOC_GETFAN) failed",
driver_name, unitp->instance);
rval = EINVAL;
break;
}
if ((tfanspeed = ((int)a_fanspeed.val * JAV_FAN_SPEED_SF_NUM) /
JAV_FAN_SPEED_SF_DEN) > 255)
a_fanspeed.val = 255;
else
a_fanspeed.val = tfanspeed & 0xFF;
unitp->fan_kstats.fanspeed = a_fanspeed.val;
if (ddi_copyout((caddr_t)&a_fanspeed, (caddr_t)arg,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
}
break;
case ENVCTRL_IOC_SETFSP2:
if (ddi_copyin((caddr_t)arg, (caddr_t)&envcchip,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
break;
}
if ((envcchip.type != ENVCTRL_PCF8574A) ||
(envcchip.chip_num != ENVCTRL_DEV6)) {
rval = EINVAL;
break;
}
wdval = envcchip.val;
mutex_enter(&unitp->umutex);
if (unitp->current_mode == ENVCTRL_NORMAL_MODE) {
if (wdval & ~ENVCTRL_UE250_FSP_USRMASK) {
mutex_exit(&unitp->umutex);
rval = EINVAL;
break;
}
}
if (wdval & ENVCTRL_UE250_FSP_PS_ERR)
power_flt_led_lit = 1;
status = envctrl_set_fsp(unitp, &wdval);
mutex_exit(&unitp->umutex);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Read of PCF8574A (IOC_SETFSP) failed",
driver_name, unitp->instance);
rval = EINVAL;
}
break;
case ENVCTRL_IOC_GETFSP2:
if (ddi_copyin((caddr_t)arg, (caddr_t)&envcchip,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
break;
}
if ((envcchip.type != ENVCTRL_PCF8574A) ||
(envcchip.chip_num != ENVCTRL_DEV6)) {
rval = EINVAL;
break;
}
mutex_enter(&unitp->umutex);
status = envctrl_get_fpm_status(unitp, &wdval);
mutex_exit(&unitp->umutex);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Read of PCF8574A (IOC_GETFSP) failed",
driver_name, unitp->instance);
rval = EINVAL;
} else {
envcchip.val = wdval;
if (ddi_copyout((caddr_t)&envcchip, (caddr_t)arg,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
}
}
break;
case ENVCTRL_IOC_SETDSKLED2:
if (ddi_copyin((caddr_t)arg, (caddr_t)&ledchip,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
break;
}
if ((ledchip.type != ENVCTRL_PCF8574A) ||
(ledchip.chip_num != ENVCTRL_DEV7)) {
rval = EINVAL;
break;
}
mutex_enter(&unitp->umutex);
if (envctrl_set_dskled(unitp, &ledchip)) {
rval = EINVAL;
}
mutex_exit(&unitp->umutex);
break;
case ENVCTRL_IOC_GETDSKLED2:
if (ddi_copyin((caddr_t)arg, (caddr_t)&ledchip,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
break;
}
if ((ledchip.type != ENVCTRL_PCF8574A) ||
(ledchip.chip_num != ENVCTRL_DEV7)) {
rval = EINVAL;
break;
}
mutex_enter(&unitp->umutex);
if (envctrl_get_dskled(unitp, &ledchip)) {
rval = EINVAL;
} else {
if (ddi_copyout((caddr_t)&ledchip, (caddr_t)arg,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
}
}
mutex_exit(&unitp->umutex);
break;
case ENVCTRL_IOC_SETRAW:
if (unitp->current_mode != ENVCTRL_DIAG_MODE) {
rval = EINVAL;
break;
}
if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
break;
}
mutex_enter(&unitp->umutex);
status = envctrl_write_chip(unitp, temp.type, temp.chip_num,
temp.index, &temp.val, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Write to chip (IOC_SETRAW) failed",
driver_name, unitp->instance);
rval = EINVAL;
}
mutex_exit(&unitp->umutex);
break;
case ENVCTRL_IOC_GETRAW:
if (ddi_copyin((caddr_t)arg, (caddr_t)&temp,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
break;
}
mutex_enter(&unitp->umutex);
status = envctrl_read_chip(unitp, temp.type, temp.chip_num,
temp.index, &temp.val, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Read of chip (IOC_GETRAW) failed",
driver_name, unitp->instance);
rval = EINVAL;
}
mutex_exit(&unitp->umutex);
if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
sizeof (struct envctrl_chip), flag)) {
rval = EFAULT;
}
break;
default:
rval = EINVAL;
}
return (rval);
}
uint_t
envctrl_bus_isr(caddr_t arg)
{
struct envctrlunit *unitp = (struct envctrlunit *)(void *)arg;
int ic = DDI_INTR_UNCLAIMED;
mutex_enter(&unitp->umutex);
mutex_exit(&unitp->umutex);
return (ic);
}
uint_t
envctrl_dev_isr(caddr_t arg)
{
struct envctrlunit *unitp = (struct envctrlunit *)(void *)arg;
uint8_t recv_data;
int ic;
int retrys = 0;
int status;
static int spurious_intr_count = 0;
ic = DDI_INTR_UNCLAIMED;
mutex_enter(&unitp->umutex);
do {
status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
&recv_data, 1);
if (recv_data == 0xFF) {
status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
&recv_data, 1);
}
if (status == DDI_FAILURE) {
drv_usecwait(1000);
if (retrys < envctrl_max_retries) {
retrys++;
} else {
cmn_err(CE_WARN,
"%s%d: Read of PCF8574A (INT) failed\n",
driver_name, unitp->instance);
ehc_init_pcf8584((struct ehc_envcunit *)unitp);
mutex_exit(&unitp->umutex);
ic = DDI_INTR_CLAIMED;
return (ic);
}
}
} while (status != DDI_SUCCESS);
DPRINTF1("Interrupt routine called, interrupt = %X\n", recv_data);
if (!(recv_data & EHC_PCF8574_PORT0)) {
ic = DDI_INTR_CLAIMED;
}
if (!(recv_data & EHC_PCF8574_PORT1)) {
DPRINTF1("Temperature interrupt detected\n");
(void) envctrl_check_sys_temperatures(unitp);
envctrl_intr_latch_clr(unitp);
ic = DDI_INTR_CLAIMED;
}
if (!(recv_data & EHC_PCF8574_PORT2)) {
DPRINTF1("Disk interrupt detected\n");
envctrl_check_disk_kstats(unitp);
ic = DDI_INTR_CLAIMED;
}
if (!(recv_data & EHC_PCF8574_PORT3)) {
ic = DDI_INTR_CLAIMED;
}
if (!(recv_data & EHC_PCF8574_PORT4)) {
DPRINTF1("Fan interrupt detected\n");
envctrl_fan_fail_service(unitp);
envctrl_intr_latch_clr(unitp);
ic = DDI_INTR_CLAIMED;
}
if (!(recv_data & EHC_PCF8574_PORT5)) {
DPRINTF1("Keyswitch interrupt detected\n");
(void) envctrl_get_fpm_status(unitp, (uint8_t *)NULL);
ic = DDI_INTR_CLAIMED;
}
if (!(recv_data & EHC_PCF8574_PORT6)) {
DPRINTF1("Power supply interrupt detected\n");
envctrl_PS_intr_service(unitp);
ic = DDI_INTR_CLAIMED;
}
if (!(recv_data & EHC_PCF8574_PORT7)) {
ic = DDI_INTR_CLAIMED;
}
if ((recv_data == 0xFF)) {
if (spurious_intr_count == 255)
cmn_err(CE_WARN,
"%s%d: Received 256 spurious interrupts\n",
driver_name, unitp->instance);
spurious_intr_count++;
ic = DDI_INTR_CLAIMED;
} else
spurious_intr_count = 0;
mutex_exit(&unitp->umutex);
return (ic);
}
static int
envctrl_read_chip(struct envctrlunit *unitp, int type, int chip_num, int port,
uint8_t *data, int num)
{
int retrys = 0, autoincr = 0;
int status;
if (num > 1)
autoincr = 1;
do {
if (type == ENVCTRL_PCF8574A) {
status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8574A_BASE_ADDR | chip_num,
data, num);
} else if (type == ENVCTRL_PCF8574) {
status = ehc_read_pcf8574((struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8574_BASE_ADDR | chip_num,
data, num);
} else if (type == ENVCTRL_PCF8591) {
status = ehc_read_pcf8591((struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8591_BASE_ADDR | chip_num,
port, autoincr, 0, 1, data, num);
}
if (status == DDI_FAILURE) {
drv_usecwait(1000);
if (retrys < envctrl_max_retries) {
retrys++;
} else {
ehc_init_pcf8584((struct ehc_envcunit *)unitp);
break;
}
}
} while (status != DDI_SUCCESS);
return (status);
}
static int
envctrl_write_chip(struct envctrlunit *unitp, int type, int chip_num, int port,
uint8_t *data, int num)
{
int retrys = 0, autoincr = 0;
int status;
chip_num = chip_num & 0xF;
if (num > 1)
autoincr = 1;
do {
if (type == ENVCTRL_PCF8574A) {
status = ehc_write_pcf8574a(
(struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8574A_BASE_ADDR | chip_num,
data, num);
} else if (type == ENVCTRL_PCF8574) {
status = ehc_write_pcf8574((struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8574_BASE_ADDR | chip_num,
data, num);
} else if (type == ENVCTRL_PCF8591) {
status = ehc_write_pcf8591((struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8591_BASE_ADDR | chip_num,
port, autoincr, 0, 1, data, num);
}
if (status == DDI_FAILURE) {
drv_usecwait(1000);
if (retrys < envctrl_max_retries) {
retrys++;
} else {
ehc_init_pcf8584((struct ehc_envcunit *)unitp);
break;
}
}
} while (status != DDI_SUCCESS);
return (status);
}
#ifdef GET_CPU_TEMP
static int
envctrl_get_cpu_temp(struct envctrlunit *unitp, int cpunum)
{
uint8_t recv_data;
int status;
ASSERT(MUTEX_HELD(&unitp->umutex));
status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV7, cpunum,
&recv_data, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: CPU TEMP read failed\n",
driver_name, unitp->instance);
return (ENVCTRL_UE250_MAX_CPU_TEMP - 10);
}
return (_cpu_temps[recv_data]);
}
#endif
static void
envctrl_tempr_poll(void *arg)
{
int diag_flag = 0, status;
struct envctrlunit *unitp = (struct envctrlunit *)arg;
mutex_enter(&unitp->umutex);
if (unitp->shutdown == B_TRUE) {
(void) power_down("Fatal System Environmental Control Error");
}
envctrl_intr_latch_clr(unitp);
envctrl_reset_dflop(unitp);
envctrl_enable_devintrs(unitp);
if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
diag_flag++;
if (envctrl_debug_flags) {
cmn_err(CE_WARN, "%s%d: "
"Tempr poll went off while in DIAG MODE\n",
driver_name, unitp->instance);
}
}
unitp->current_mode = ENVCTRL_NORMAL_MODE;
DPRINTF1("envctrl_tempr_poll(): Checking system temps\n");
status = envctrl_check_sys_temperatures(unitp);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Failure detected during temperature poll",
driver_name, unitp->instance);
}
if (diag_flag == 0) {
envctrl_fan_fail_service(unitp);
}
envctrl_ps_probe(unitp);
if ((unitp->fan_failed == B_TRUE) || (unitp->tempr_warning == B_TRUE)) {
if (unitp->timeout_id != 0)
(void) untimeout(unitp->timeout_id);
unitp->timeout_id = (timeout(envctrl_tempr_poll,
(caddr_t)unitp, warning_timeout_hz));
} else {
unitp->timeout_id = (timeout(envctrl_tempr_poll,
(caddr_t)unitp, overtemp_timeout_hz));
}
mutex_exit(&unitp->umutex);
}
static void
envctrl_led_blink(void *arg)
{
uint8_t val, tmpval;
int status;
struct envctrlunit *unitp = (struct envctrlunit *)arg;
mutex_enter(&unitp->umutex);
status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
0, &val, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Failed to read FSP LEDs",
driver_name, unitp->instance);
unitp->blink_timeout_id = (timeout(envctrl_led_blink,
(caddr_t)unitp, blink_timeout_hz));
mutex_exit(&unitp->umutex);
return;
}
if (unitp->present_led_state == B_TRUE) {
val = (val & ~(EHC_PCF8574_PORT4) | JAV_FSP_MASK);
unitp->present_led_state = B_FALSE;
} else {
val = (val | EHC_PCF8574_PORT4 | JAV_FSP_MASK);
unitp->present_led_state = B_TRUE;
}
tmpval = ~val;
if (tmpval & ENVCTRL_UE250_FSP_PS_ERR) {
if (power_flt_led_lit == 0) {
tmpval &= ~(ENVCTRL_UE250_FSP_PS_ERR);
}
}
val = ~tmpval;
status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
0, &val, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Failed to blink activity LED",
driver_name, unitp->instance);
unitp->blink_timeout_id = (timeout(envctrl_led_blink,
(caddr_t)unitp, blink_timeout_hz));
mutex_exit(&unitp->umutex);
return;
}
unitp->blink_timeout_id = (timeout(envctrl_led_blink,
(caddr_t)unitp, blink_timeout_hz));
mutex_exit(&unitp->umutex);
}
static int
envctrl_check_sys_temperatures(struct envctrlunit *unitp)
{
uint8_t buf[8];
enum levels warning_level, level;
uint8_t fspval;
int status, warning_count = 0;
retrytemp1:
status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2,
0, buf, 4);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Temperature read failed (PDB)",
driver_name, unitp->instance);
return (status);
}
warning_level = envctrl_check_tempr_levels(unitp, EHC_DEV2,
buf, warning_count);
level = warning_level;
if (warning_level != green) {
if (warning_count == 0) {
warning_count++;
drv_usecwait(1000);
goto retrytemp1;
}
if (warning_level == yellow)
unitp->tempr_warning = B_TRUE;
else if (warning_level == red) {
unitp->tempr_warning = B_TRUE;
if (!envctrl_power_off_overide)
unitp->shutdown = B_TRUE;
}
}
warning_count = 0;
retrytemp2:
status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV7,
0, buf+4, 4);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Temperature read failed (MBD)",
driver_name, unitp->instance);
return (status);
}
warning_level = envctrl_check_tempr_levels(unitp, EHC_DEV7,
buf+4, warning_count);
if (warning_level != green) {
if (warning_count == 0) {
warning_count++;
drv_usecwait(1000);
goto retrytemp2;
}
if ((warning_level == yellow) && (unitp->shutdown == B_FALSE))
unitp->tempr_warning = B_TRUE;
else if (warning_level == red) {
unitp->tempr_warning = B_TRUE;
if (!envctrl_power_off_overide)
unitp->shutdown = B_TRUE;
}
} else if ((level == green) && (unitp->tempr_warning == B_TRUE)) {
cmn_err(CE_NOTE,
"TEMPERATURE NORMAL: all sensors back to normal readings");
unitp->tempr_warning = B_FALSE;
}
status = envctrl_get_fpm_status(unitp, &fspval);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Read of Front Status Panel LEDs failed",
driver_name, unitp->instance);
}
if ((unitp->tempr_warning == B_TRUE) || (unitp->shutdown == B_TRUE))
fspval |= (ENVCTRL_UE250_FSP_TEMP_ERR |
ENVCTRL_UE250_FSP_GEN_ERR);
else {
if (envctrl_isother_fault_led(unitp, fspval,
ENVCTRL_UE250_FSP_TEMP_ERR)) {
fspval &= ~(ENVCTRL_UE250_FSP_TEMP_ERR);
} else {
fspval &= ~(ENVCTRL_UE250_FSP_TEMP_ERR |
ENVCTRL_UE250_FSP_GEN_ERR);
}
}
status = envctrl_set_fsp(unitp, &fspval);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Setting of Front Status Panel LEDs failed",
driver_name, unitp->instance);
}
if (unitp->tempr_warning == B_TRUE) {
if (unitp->timeout_id != 0) {
(void) untimeout(unitp->timeout_id);
unitp->timeout_id = (timeout(envctrl_tempr_poll,
(caddr_t)unitp, warning_timeout_hz));
}
}
return (status);
}
static int
envctrl_check_tempr_levels(struct envctrlunit *unitp, int chip_num,
uint8_t *data, int count)
{
uint_t temp_degree_c;
uint8_t buf[8];
enum levels warning_level = green;
int i, j;
int status;
uint8_t fanspeed;
int tval;
for (i = 0; i < 4; i++) {
if (chip_num == EHC_DEV2) {
if (i == 1) {
tval = ((int)data[i] * JAV_FAN_SPEED_SF_NUM) /
JAV_FAN_SPEED_SF_DEN;
if (tval > 255)
unitp->fan_kstats.fanspeed = 255;
else
unitp->fan_kstats.fanspeed = tval;
DPRINTF1("device %X, fan = %d %d\n", chip_num,
unitp->fan_kstats.fanspeed, data[i]);
continue;
} else if (i == 2)
continue;
}
if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
(i == ENVCTRL_UE250_CPU1_PORT)))
if (unitp->cpu_pr_location[i] == B_FALSE)
continue;
j = 0;
while ((((t_addr[j] & 0xF) != chip_num) || (t_port[j] != i)) &&
(j < unitp->num_temps_present))
j++;
if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
(i == ENVCTRL_UE250_CPU1_PORT)))
temp_degree_c = _cpu_temps[data[i]];
else
temp_degree_c = ((int)data[i] * t_scale_num[j]) /
t_scale_den[j];
if ((chip_num == EHC_DEV7) && ((i == ENVCTRL_UE250_CPU0_PORT) ||
(i == ENVCTRL_UE250_CPU1_PORT)) &&
(unitp->current_mode == ENVCTRL_NORMAL_MODE)) {
if (_cpu_fan_speeds[data[ENVCTRL_UE250_CPU0_PORT]] >
_cpu_fan_speeds[data[ENVCTRL_UE250_CPU1_PORT]])
fanspeed =
_cpu_fan_speeds[
data[ENVCTRL_UE250_CPU0_PORT]];
else
fanspeed =
_cpu_fan_speeds[
data[ENVCTRL_UE250_CPU1_PORT]];
status = envctrl_write_chip(unitp, ENVCTRL_PCF8591,
EHC_DEV2, 0, &fanspeed, 1);
if (status == DDI_FAILURE)
cmn_err(CE_WARN,
"%s%d: Write to PCF8591 (SETFAN) failed\n",
driver_name, unitp->instance);
status = envctrl_read_chip(unitp, ENVCTRL_PCF8591,
EHC_DEV2, 0, buf, 4);
if (status == DDI_FAILURE)
cmn_err(CE_WARN,
"%s%d: Fan speed read failed (PDB)",
driver_name, unitp->instance);
tval = ((int)buf[1] * JAV_FAN_SPEED_SF_NUM) /
JAV_FAN_SPEED_SF_DEN;
if (tval > 255)
unitp->fan_kstats.fanspeed = 255;
else
unitp->fan_kstats.fanspeed = tval;
}
DPRINTF1("device %X, temp = %d %d loc = %s\n", chip_num,
temp_degree_c, data[i], unitp->temp_kstats[j].label);
unitp->temp_kstats[j].value = temp_degree_c;
if ((temp_degree_c >=
unitp->temp_kstats[j].warning_threshold) ||
(temp_degree_c < unitp->temp_kstats[j].min)) {
if (warning_level < yellow)
warning_level = yellow;
if (count != 0)
cmn_err(CE_WARN,
"TEMPERATURE WARNING: %d degrees "
"celsius at location %s",
temp_degree_c, unitp->temp_kstats[j].label);
}
if (temp_degree_c >=
unitp->temp_kstats[j].shutdown_threshold) {
if (warning_level < red)
warning_level = red;
if (count != 0) {
cmn_err(CE_WARN,
"TEMPERATURE CRITICAL: %d "
"degrees celsius at location %s",
temp_degree_c, unitp->temp_kstats[j].label);
if (!envctrl_power_off_overide)
cmn_err(CE_WARN,
"System shutdown in "
"10 seconds ...");
}
}
}
return (warning_level);
}
static void
envctrl_update_fanspeed(struct envctrlunit *unitp)
{
uint8_t buf[8];
int tval;
int status;
status = envctrl_read_chip(unitp, ENVCTRL_PCF8591, EHC_DEV2,
0, buf, 4);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Fan speed read failed ",
driver_name, unitp->instance);
}
tval = ((int)buf[ENVCTRL_PORT1] * JAV_FAN_SPEED_SF_NUM) /
JAV_FAN_SPEED_SF_DEN;
if (tval > 255)
unitp->fan_kstats.fanspeed = 255;
else
unitp->fan_kstats.fanspeed = tval;
}
static void
envctrl_fan_fail_service(struct envctrlunit *unitp)
{
uint8_t recv_data, fpmstat;
int retrys = 0;
int status;
ASSERT(MUTEX_HELD(&unitp->umutex));
envctrl_intr_latch_clr(unitp);
do {
status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
&recv_data, 1);
if (recv_data == 0xFF) {
status = ehc_read_pcf8574a((struct ehc_envcunit *)unitp,
ENVCTRL_UE250_PCF8574A_BASE_ADDR | EHC_DEV0,
&recv_data, 1);
}
if (status == DDI_FAILURE) {
drv_usecwait(1000);
if (retrys < envctrl_max_retries) {
retrys++;
} else {
cmn_err(CE_WARN,
"%s%d: Read of PCF8574A (INTFAN) failed",
driver_name, unitp->instance);
ehc_init_pcf8584((struct ehc_envcunit *)unitp);
return;
}
}
} while (status != DDI_SUCCESS);
if (recv_data & EHC_PCF8574_PORT4) {
if (unitp->fan_failed == B_TRUE) {
if (unitp->current_mode == ENVCTRL_NORMAL_MODE)
cmn_err(CE_CONT,
"Fan failure has been cleared\n");
unitp->fan_kstats.fans_ok = B_TRUE;
status = envctrl_get_fpm_status(unitp, &fpmstat);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Read of Front Status "
"Panel LEDs failed",
driver_name, unitp->instance);
}
if (!(envctrl_isother_fault_led(unitp, fpmstat, 0))) {
fpmstat &= ~(ENVCTRL_UE250_FSP_GEN_ERR);
}
if (unitp->shutdown != B_TRUE) {
status = envctrl_set_fsp(unitp, &fpmstat);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: "
"Setting of Front Status "
"Panel LEDs failed",
driver_name, unitp->instance);
}
}
unitp->fan_failed = B_FALSE;
}
} else {
if (unitp->fan_failed == B_FALSE) {
if (unitp->current_mode == ENVCTRL_NORMAL_MODE)
cmn_err(CE_WARN,
"Fan failure has been detected");
unitp->fan_failed = B_TRUE;
unitp->fan_kstats.fans_ok = B_FALSE;
status = envctrl_get_fpm_status(unitp, &fpmstat);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Read of Front Status "
"Panel LEDs failed",
driver_name, unitp->instance);
return;
}
fpmstat |= ENVCTRL_UE250_FSP_GEN_ERR;
status = envctrl_set_fsp(unitp, &fpmstat);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: "
"Setting of Front Status Panel LEDs failed",
driver_name, unitp->instance);
}
if (unitp->timeout_id != 0) {
(void) untimeout(unitp->timeout_id);
unitp->timeout_id =
(timeout(envctrl_tempr_poll,
(caddr_t)unitp, warning_timeout_hz));
}
}
}
}
static void
envctrl_PS_intr_service(struct envctrlunit *unitp)
{
ASSERT(MUTEX_HELD(&unitp->umutex));
if (unitp->current_mode == ENVCTRL_DIAG_MODE) {
return;
}
unitp->pshotplug_id = (timeout(envctrl_pshotplug_poll,
(caddr_t)unitp, pshotplug_timeout_hz));
}
static void
envctrl_init_bus(struct envctrlunit *unitp)
{
ehc_init_pcf8584((struct ehc_envcunit *)unitp);
envctrl_intr_latch_clr(unitp);
envctrl_reset_dflop(unitp);
envctrl_enable_devintrs(unitp);
}
static void
envctrl_reset_dflop(struct envctrlunit *unitp)
{
int status;
uint8_t value;
ASSERT(MUTEX_HELD(&unitp->umutex));
value = ENVCTRL_UE250_DFLOP_INIT0;
status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
0, &value, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Write to PCF8574A (DFLOP_INIT0) failed",
driver_name, unitp->instance);
}
value = ENVCTRL_UE250_DFLOP_INIT1;
status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
0, &value, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Write to PCF8574A (DFLOP_INIT1) failed",
driver_name, unitp->instance);
}
}
static void
envctrl_enable_devintrs(struct envctrlunit *unitp)
{
int status;
uint8_t value;
ASSERT(MUTEX_HELD(&unitp->umutex));
value = ENVCTRL_UE250_DEVINTR_INIT0;
status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
0, &value, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_INIT0) failed",
driver_name, unitp->instance);
}
value = ENVCTRL_UE250_DEVINTR_INIT1;
status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
0, &value, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_INIT1) failed",
driver_name, unitp->instance);
}
}
static void
envctrl_intr_latch_clr(struct envctrlunit *unitp)
{
int status;
uint8_t value;
ASSERT(MUTEX_HELD(&unitp->umutex));
value = ENVCTRL_UE250_INTR_LATCH_INIT0;
status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
0, &value, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_LATCH0) failed",
driver_name, unitp->instance);
}
value = ENVCTRL_UE250_INTR_LATCH_INIT1;
status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV0,
0, &value, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Write to PCF8574A (INTR_LATCH1) failed",
driver_name, unitp->instance);
}
}
static void
envctrl_ps_probe(struct envctrlunit *unitp)
{
uint8_t recv_data, fpmstat;
int i, j;
int ps_error = 0, ps_present_port, power_ok_port;
int status;
ASSERT(MUTEX_HELD(&unitp->umutex));
unitp->num_ps_present = 0;
status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV1,
0, &recv_data, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Read of PCF8574 (PS) failed",
driver_name, unitp->instance);
return;
}
for (i = 0, j = 0; i < ENVCTRL_UE250_MAXPS; i++) {
unitp->ps_kstats[i].slot = -1;
switch (i) {
case 0:
ps_present_port = EHC_PCF8574_PORT0;
power_ok_port = EHC_PCF8574_PORT4;
break;
case 1:
ps_present_port = EHC_PCF8574_PORT1;
power_ok_port = EHC_PCF8574_PORT5;
break;
}
if (!(recv_data & ps_present_port)) {
unitp->ps_kstats[j].slot = i;
++unitp->num_ps_present;
if (pspr[i] == 0) {
cmn_err(CE_NOTE,
"Power Supply %d inserted\n", i);
}
pspr[i] = 1;
if (!(recv_data & power_ok_port)) {
cmn_err(CE_WARN,
"Power Supply %d NOT okay\n", i);
unitp->ps_kstats[j].ps_ok = B_FALSE;
ps_error++;
psok[i] = 0;
} else {
unitp->ps_kstats[j].ps_ok = B_TRUE;
if (psok[i] == 0)
cmn_err(CE_NOTE,
"Power Supply %d okay\n", i);
psok[i] = 1;
}
if (!(recv_data & EHC_PCF8574_PORT2)) {
cmn_err(CE_WARN,
"PS %d Shouln't interrupt\n", i);
ps_error++;
}
if (!(recv_data & EHC_PCF8574_PORT3)) {
cmn_err(CE_WARN,
"PS %d Shouln't interrupt\n", i);
ps_error++;
}
if (!(recv_data & EHC_PCF8574_PORT6)) {
cmn_err(CE_WARN,
"PS %d Shouln't interrupt\n", i);
ps_error++;
}
if (!(recv_data & EHC_PCF8574_PORT7)) {
cmn_err(CE_WARN,
"PS %d Shouln't interrupt\n", i);
ps_error++;
}
j++;
} else {
if (pspr[i] == 1) {
cmn_err(CE_NOTE,
"Power Supply %d removed\n", i);
}
pspr[i] = 0;
}
}
status = envctrl_get_fpm_status(unitp, &fpmstat);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Read of Front Status Panel LEDs failed",
driver_name, unitp->instance);
}
if (ps_error) {
fpmstat |= (ENVCTRL_UE250_FSP_PS_ERR |
ENVCTRL_UE250_FSP_GEN_ERR);
} else {
if (envctrl_isother_fault_led(unitp, fpmstat,
ENVCTRL_UE250_FSP_PS_ERR)) {
fpmstat &= ~(ENVCTRL_UE250_FSP_PS_ERR);
} else {
fpmstat &= ~(ENVCTRL_UE250_FSP_PS_ERR |
ENVCTRL_UE250_FSP_GEN_ERR);
}
}
status = envctrl_set_fsp(unitp, &fpmstat);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Setting of Front Status Panel LEDs failed",
driver_name, unitp->instance);
}
if (ps_error) {
power_flt_led_lit = 1;
} else {
power_flt_led_lit = 0;
}
}
static void
envctrl_abort_seq_handler(char *msg)
{
struct envctrlunit *unitp;
int i;
uint8_t secure = 0;
for (i = 0; i < MAX_DEVS; i++) {
if (unitp = (struct envctrlunit *)
ddi_get_soft_state(envctrlsoft_statep, i))
break;
}
ASSERT(unitp);
secure = unitp->encl_kstats.value;
if ((secure & ENVCTRL_UE250_FSP_KEYMASK) ==
ENVCTRL_UE250_FSP_KEYLOCKED) {
cmn_err(CE_CONT,
"%s%d: ignoring debug enter sequence\n",
driver_name, unitp->instance);
} else {
if (envctrl_debug_flags) {
cmn_err(CE_CONT, "%s%d: allowing debug enter\n",
driver_name, unitp->instance);
}
debug_enter(msg);
}
}
static int
envctrl_get_fpm_status(struct envctrlunit *unitp, uint8_t *val)
{
uint8_t recv_data;
int status;
ASSERT(MUTEX_HELD(&unitp->umutex));
status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
0, &recv_data, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Read from PCF8574A (FSP) failed",
driver_name, unitp->instance);
return (status);
}
recv_data = ~recv_data;
if (val != (uint8_t *)NULL)
*val = recv_data;
unitp->encl_kstats.value = recv_data;
return (status);
}
static int
envctrl_set_fsp(struct envctrlunit *unitp, uint8_t *val)
{
uint8_t value;
int status = DDI_SUCCESS;
uint8_t confirm_val = 0, confirm_val_hold;
int confirm_count = 0, confirm_max = 20;
ASSERT(MUTEX_HELD(&unitp->umutex));
value = ENVCTRL_UE250_FSP_OFF;
value = (~(ENVCTRL_UE250_FSP_KEYMASK | ENVCTRL_UE250_FSP_POMASK) &
(*val));
confirm_val_hold = value;
value = ~value;
while (confirm_count < confirm_max) {
status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
0, &value, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Write to PCF8574A (FSP) failed",
driver_name, unitp->instance);
break;
} else {
status = envctrl_get_fpm_status(unitp, &confirm_val);
confirm_val = ~(ENVCTRL_UE250_FSP_KEYMASK |
ENVCTRL_UE250_FSP_POMASK) & confirm_val;
if (status == DDI_FAILURE) {
cmn_err(CE_WARN,
"%s%d: Read of PCF8574A (FSP) failed",
driver_name, unitp->instance);
break;
} else if (confirm_val != confirm_val_hold) {
confirm_count++;
drv_usecwait(1000);
continue;
} else
break;
}
}
if (confirm_count == confirm_max)
status = DDI_FAILURE;
return (status);
}
static int
envctrl_get_dskled(struct envctrlunit *unitp, struct envctrl_chip *chip)
{
int status;
ASSERT(MUTEX_HELD(&unitp->umutex));
if (chip->chip_num != EHC_DEV7 ||
chip->type != ENVCTRL_PCF8574A) {
return (DDI_FAILURE);
}
status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
0, &chip->val, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
driver_name, unitp->instance);
}
chip->val = ~chip->val;
return (status);
}
static int
envctrl_set_dskled(struct envctrlunit *unitp, struct envctrl_chip *chip)
{
uint8_t val;
int status;
struct envctrl_chip confirm_chip;
uint8_t confirm_val_hold;
int confirm_count = 0, confirm_max = 20;
ASSERT(MUTEX_HELD(&unitp->umutex));
if (chip->chip_num != EHC_DEV7)
return (DDI_FAILURE);
if (chip->type != ENVCTRL_PCF8574A)
return (DDI_FAILURE);
status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
0, &val, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Read of PCF8574A (FSP) failed",
driver_name, unitp->instance);
return (status);
}
val = ~val;
if ((chip->val & 0x3F) == 0) {
if (!(envctrl_isother_fault_led(unitp, val,
ENVCTRL_UE250_FSP_DISK_ERR))) {
val &= ~(ENVCTRL_UE250_FSP_DISK_ERR);
} else {
val &= ~(ENVCTRL_UE250_FSP_DISK_ERR |
ENVCTRL_UE250_FSP_GEN_ERR);
}
val = (val & ~(ENVCTRL_UE250_FSP_DISK_ERR |
ENVCTRL_UE250_FSP_GEN_ERR));
} else {
val = (val | (ENVCTRL_UE250_FSP_DISK_ERR |
ENVCTRL_UE250_FSP_GEN_ERR));
}
status = envctrl_set_fsp(unitp, &val);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Write to PCF8574A (FSP) failed",
driver_name, unitp->instance);
return (status);
}
status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV5,
0, &val, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
driver_name, unitp->instance);
return (status);
}
envctrl_update_disk_kstats(unitp, val, ~(chip->val));
confirm_val_hold = chip->val;
chip->val = ~(chip->val);
while (confirm_count < confirm_max) {
status = envctrl_write_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
0, &chip->val, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Write PCF8574A (DISKFL) failed",
driver_name, unitp->instance);
return (status);
} else {
confirm_chip.type = chip->type;
confirm_chip.chip_num = chip->chip_num;
confirm_chip.index = chip->index;
status = envctrl_get_dskled(unitp, &confirm_chip);
if (status != DDI_SUCCESS) {
return (status);
} else if (confirm_chip.val != confirm_val_hold) {
confirm_count++;
drv_usecwait(1000);
continue;
} else
break;
}
}
if (confirm_count == confirm_max)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
static int
envctrl_set_fanspeed(struct envctrlunit *unitp, struct envctrl_chip *fanspeed)
{
int readback_speed, max_speed;
int status;
int confirm_count = 0, confirm_max = 20;
uint8_t fanspeed_hold;
fanspeed_hold = fanspeed->val;
while (confirm_count < confirm_max) {
status = envctrl_write_chip(unitp, ENVCTRL_PCF8591,
EHC_DEV2, 0, &fanspeed->val, 1);
if (status == DDI_FAILURE) {
envctrl_fan_fail_service(unitp);
cmn_err(CE_WARN,
"%s%d: Set fanspeed failed", driver_name,
unitp->instance);
return (status);
} else {
drv_usecwait(100000);
envctrl_update_fanspeed(unitp);
readback_speed = unitp->fan_kstats.fanspeed;
if (fanspeed_hold > idle_fanspeed) {
max_speed =
(fanspeed->val + FAN_DRIFT >
MAX_FAN_SPEED) ? MAX_FAN_SPEED :
(fanspeed->val + FAN_DRIFT);
if ((readback_speed < fanspeed->val -
FAN_DRIFT) ||
(readback_speed > max_speed)) {
confirm_count++;
drv_usecwait(1000);
continue;
}
}
break;
}
}
if (confirm_count == confirm_max)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
static void
envctrl_add_kstats(struct envctrlunit *unitp)
{
ASSERT(MUTEX_HELD(&unitp->umutex));
if ((unitp->enclksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
ENVCTRL_KSTAT_ENCL, "misc", KSTAT_TYPE_RAW,
sizeof (unitp->encl_kstats),
KSTAT_FLAG_PERSISTENT)) == NULL) {
cmn_err(CE_WARN, "%s%d: encl raw kstat_create failed",
driver_name, unitp->instance);
return;
}
unitp->enclksp->ks_update = envctrl_encl_kstat_update;
unitp->enclksp->ks_private = (void *)unitp;
kstat_install(unitp->enclksp);
if ((unitp->fanksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
ENVCTRL_KSTAT_FANSTAT, "misc", KSTAT_TYPE_RAW,
sizeof (unitp->fan_kstats),
KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
cmn_err(CE_WARN, "%s%d: fans kstat_create failed",
driver_name, unitp->instance);
return;
}
unitp->fanksp->ks_update = envctrl_fanstat_kstat_update;
unitp->fanksp->ks_private = (void *)unitp;
kstat_install(unitp->fanksp);
if ((unitp->psksp = kstat_create(ENVCTRL_MODULE_NAME, unitp->instance,
ENVCTRL_KSTAT_PSNAME2, "misc", KSTAT_TYPE_RAW,
sizeof (unitp->ps_kstats),
KSTAT_FLAG_PERSISTENT)) == NULL) {
cmn_err(CE_WARN, "%s%d: ps name kstat_create failed",
driver_name, unitp->instance);
return;
}
unitp->psksp->ks_update = envctrl_ps_kstat_update;
unitp->psksp->ks_private = (void *)unitp;
kstat_install(unitp->psksp);
if ((unitp->tempksp = kstat_create(ENVCTRL_MODULE_NAME,
unitp->instance, ENVCTRL_KSTAT_TEMPERATURE, "misc", KSTAT_TYPE_RAW,
sizeof (unitp->temp_kstats),
KSTAT_FLAG_PERSISTENT)) == NULL) {
cmn_err(CE_WARN, "%s%d: temp name kstat_create failed",
driver_name, unitp->instance);
return;
}
unitp->tempksp->ks_update = envctrl_temp_kstat_update;
unitp->tempksp->ks_private = (void *)unitp;
kstat_install(unitp->tempksp);
if ((unitp->diskksp = kstat_create(ENVCTRL_MODULE_NAME,
unitp->instance, ENVCTRL_KSTAT_DISK, "misc", KSTAT_TYPE_RAW,
sizeof (unitp->disk_kstats),
KSTAT_FLAG_PERSISTENT)) == NULL) {
cmn_err(CE_WARN, "%s%d: disk name kstat_create failed",
driver_name, unitp->instance);
return;
}
unitp->diskksp->ks_update = envctrl_disk_kstat_update;
unitp->diskksp->ks_private = (void *)unitp;
kstat_install(unitp->diskksp);
}
static int
envctrl_ps_kstat_update(kstat_t *ksp, int rw)
{
struct envctrlunit *unitp;
char *kstatp;
unitp = (struct envctrlunit *)ksp->ks_private;
mutex_enter(&unitp->umutex);
ASSERT(MUTEX_HELD(&unitp->umutex));
kstatp = (char *)ksp->ks_data;
if (rw == KSTAT_WRITE) {
mutex_exit(&unitp->umutex);
return (EACCES);
} else {
unitp->psksp->ks_ndata = unitp->num_ps_present;
bcopy((caddr_t)&unitp->ps_kstats, kstatp,
sizeof (unitp->ps_kstats));
}
mutex_exit(&unitp->umutex);
return (DDI_SUCCESS);
}
static int
envctrl_fanstat_kstat_update(kstat_t *ksp, int rw)
{
struct envctrlunit *unitp;
char *kstatp;
kstatp = (char *)ksp->ks_data;
unitp = (struct envctrlunit *)ksp->ks_private;
mutex_enter(&unitp->umutex);
ASSERT(MUTEX_HELD(&unitp->umutex));
if (rw == KSTAT_WRITE) {
mutex_exit(&unitp->umutex);
return (EACCES);
} else {
unitp->fanksp->ks_ndata = unitp->num_fans_present;
bcopy((caddr_t)&unitp->fan_kstats, kstatp,
sizeof (unitp->fan_kstats));
}
mutex_exit(&unitp->umutex);
return (DDI_SUCCESS);
}
static int
envctrl_encl_kstat_update(kstat_t *ksp, int rw)
{
struct envctrlunit *unitp;
char *kstatp;
int status;
kstatp = (char *)ksp->ks_data;
unitp = (struct envctrlunit *)ksp->ks_private;
mutex_enter(&unitp->umutex);
ASSERT(MUTEX_HELD(&unitp->umutex));
if (rw == KSTAT_WRITE) {
mutex_exit(&unitp->umutex);
return (EACCES);
} else {
unitp->enclksp->ks_ndata = unitp->num_encl_present;
status = envctrl_get_fpm_status(unitp, (uint8_t *)NULL);
if (status == DDI_SUCCESS)
bcopy((caddr_t)&unitp->encl_kstats, kstatp,
sizeof (unitp->encl_kstats));
}
mutex_exit(&unitp->umutex);
return (DDI_SUCCESS);
}
static int
envctrl_temp_kstat_update(kstat_t *ksp, int rw)
{
struct envctrlunit *unitp;
char *kstatp;
kstatp = (char *)ksp->ks_data;
unitp = (struct envctrlunit *)ksp->ks_private;
mutex_enter(&unitp->umutex);
ASSERT(MUTEX_HELD(&unitp->umutex));
if (rw == KSTAT_WRITE) {
mutex_exit(&unitp->umutex);
return (EACCES);
} else {
unitp->tempksp->ks_ndata = unitp->num_temps_present;
bcopy((caddr_t)unitp->temp_kstats, kstatp,
sizeof (unitp->temp_kstats));
}
mutex_exit(&unitp->umutex);
return (DDI_SUCCESS);
}
static int
envctrl_disk_kstat_update(kstat_t *ksp, int rw)
{
struct envctrlunit *unitp;
char *kstatp;
kstatp = (char *)ksp->ks_data;
unitp = (struct envctrlunit *)ksp->ks_private;
mutex_enter(&unitp->umutex);
ASSERT(MUTEX_HELD(&unitp->umutex));
if (rw == KSTAT_WRITE) {
mutex_exit(&unitp->umutex);
return (EACCES);
} else {
unitp->diskksp->ks_ndata = unitp->num_disks_present;
bcopy((caddr_t)unitp->disk_kstats, kstatp,
sizeof (unitp->disk_kstats));
}
mutex_exit(&unitp->umutex);
return (DDI_SUCCESS);
}
static void
envctrl_init_encl_kstats(struct envctrlunit *unitp)
{
uint8_t val;
int status;
ASSERT(MUTEX_HELD(&unitp->umutex));
status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV6,
0, &val, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Read of PCF8574A (FSP) failed",
driver_name, unitp->instance);
return;
}
unitp->encl_kstats.value = val;
}
static void
envctrl_check_disk_kstats(struct envctrlunit *unitp)
{
uint8_t diskpr, diskfl;
int status;
ASSERT(MUTEX_HELD(&unitp->umutex));
status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV5,
0, &diskpr, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKPR) failed",
driver_name, unitp->instance);
}
status = envctrl_read_chip(unitp, ENVCTRL_PCF8574A, EHC_DEV7,
0, &diskfl, 1);
if (status == DDI_FAILURE) {
cmn_err(CE_WARN, "%s%d: Read of PCF8574A (DISKFL) failed",
driver_name, unitp->instance);
}
envctrl_update_disk_kstats(unitp, diskpr, diskfl);
}
static void
envctrl_update_disk_kstats(struct envctrlunit *unitp, uint8_t diskpr,
uint8_t diskfl)
{
int i, j, count = 0;
DPRINTF1("diskpr = %X, diskfl = %X\n", diskpr, diskfl);
for (i = 0, j = 1; i < ENVCTRL_UE250_MAX_DISKS; i++, j = j << 1) {
if (!(diskpr & j)) {
if (!(diskfl & j))
unitp->disk_kstats[count].disk_ok = 0;
else
unitp->disk_kstats[count].disk_ok = 1;
unitp->disk_kstats[count].slot = i;
count++;
}
}
unitp->num_disks_present = count;
}
static void
envctrl_probe_cpus(struct envctrlunit *unitp)
{
int instance;
for (instance = 0; instance < ENVCTRL_MAX_CPUS; instance++) {
unitp->cpu_pr_location[instance] = B_FALSE;
}
ddi_walk_devs(ddi_root_node(), envctrl_match_cpu, unitp);
}
static int
envctrl_match_cpu(dev_info_t *dip, void *arg)
{
int cpu_slot;
char name[32];
char name1[32];
struct envctrlunit *unitp = (struct envctrlunit *)arg;
(void) sprintf(name, "%s", ENVCTRL_ULTRA1CPU_STRING);
(void) sprintf(name1, "%s", ENVCTRL_ULTRA2CPU_STRING);
if ((strcmp(ddi_node_name(dip), name) == 0) ||
(strcmp(ddi_node_name(dip), name1) == 0)) {
if ((cpu_slot = (int)ddi_getprop(DDI_DEV_T_ANY, dip,
DDI_PROP_DONTPASS, "upa-portid",
-1)) == -1) {
cmn_err(CE_WARN, "%s%d: no cpu upa-portid",
driver_name, unitp->instance);
} else {
unitp->cpu_pr_location[cpu_slot] = B_TRUE;
unitp->num_cpus_present++;
}
}
return (DDI_WALK_CONTINUE);
}
static int
envctrl_isother_fault_led(struct envctrlunit *unitp, uint8_t fspval,
uint8_t thisled)
{
int status = B_FALSE;
if (fspval != 0) {
fspval = (fspval & ~(thisled));
}
if ((unitp->fan_failed == B_TRUE) && thisled != 0) {
status = B_TRUE;
} else if (fspval & ENVCTRL_UE250_FSP_DISK_ERR) {
status = B_TRUE;
} else if (fspval & ENVCTRL_UE250_FSP_PS_ERR) {
status = B_TRUE;
} else if (fspval & ENVCTRL_UE250_FSP_TEMP_ERR) {
status = B_TRUE;
}
return (status);
}
static void
envctrl_pshotplug_poll(void *arg)
{
struct envctrlunit *unitp = (struct envctrlunit *)arg;
mutex_enter(&unitp->umutex);
envctrl_ps_probe(unitp);
mutex_exit(&unitp->umutex);
}