From ac0fa1d012235bbcbe3e62693b30ca499b984e5d Mon Sep 17 00:00:00 2001 From: hannken Date: Mon, 14 Feb 2011 08:50:38 +0000 Subject: Initial implementation of ibmhawk(4) driver for sensors behind the IBM Hawk on-board Integrated Systems Management Processor found on some eServers. Tested on an IBM eServer x335. --- sys/dev/i2c/files.i2c | 7 +- sys/dev/i2c/ibmhawk.c | 386 +++++++++++++++++++++++++++++++++++++++++++++++ sys/dev/i2c/ibmhawkreg.h | 86 +++++++++++ sys/dev/i2c/ibmhawkvar.h | 51 +++++++ 4 files changed, 529 insertions(+), 1 deletion(-) create mode 100644 sys/dev/i2c/ibmhawk.c create mode 100644 sys/dev/i2c/ibmhawkreg.h create mode 100644 sys/dev/i2c/ibmhawkvar.h (limited to 'sys/dev') diff --git a/sys/dev/i2c/files.i2c b/sys/dev/i2c/files.i2c index 1c8cb19d464..6a7e074f363 100644 --- a/sys/dev/i2c/files.i2c +++ b/sys/dev/i2c/files.i2c @@ -1,4 +1,4 @@ -# $NetBSD: files.i2c,v 1.32 2011/01/21 19:11:47 jakllsch Exp $ +# $NetBSD: files.i2c,v 1.33 2011/02/14 08:50:39 hannken Exp $ defflag opt_i2cbus.h I2C_SCAN define i2cbus { } @@ -145,3 +145,8 @@ file dev/i2c/smscmon.c smscmon device g760a: sysmon_envsys attach g760a at iic file dev/i2c/g760a.c g760a + +# IBM Hawk Integrated Systems Management Processor +device ibmhawk: sysmon_envsys +attach ibmhawk at iic +file dev/i2c/ibmhawk.c ibmhawk diff --git a/sys/dev/i2c/ibmhawk.c b/sys/dev/i2c/ibmhawk.c new file mode 100644 index 00000000000..409bca75260 --- /dev/null +++ b/sys/dev/i2c/ibmhawk.c @@ -0,0 +1,386 @@ +/* $NetBSD: ibmhawk.c,v 1.1 2011/02/14 08:50:39 hannken Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Juergen Hannken-Illjes. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if !defined(IBMHAWK_DEBUG) /* Set to 2 for verbose debug. */ +#if defined(DEBUG) +#define IBMHAWK_DEBUG 1 +#else +#define IBMHAWK_DEBUG 0 +#endif +#endif + +/* + * Known sensors. + */ +static struct ibmhawk_sensordesc { + const char *desc; + uint32_t units; + int offset; +} ibmhawk_sensors[] = { + { "Ambient temperature", ENVSYS_STEMP, IBMHAWK_T_AMBIENT }, + { "CPU 1 temperature", ENVSYS_STEMP, IBMHAWK_T_CPU }, + { "CPU 2 temperature", ENVSYS_STEMP, IBMHAWK_T_CPU+1 }, + { "12 Voltage sensor", ENVSYS_SVOLTS_DC, IBMHAWK_V_VOLTAGE }, + { "5 Voltage sensor", ENVSYS_SVOLTS_DC, IBMHAWK_V_VOLTAGE+1 }, + { "3.3 Voltage sensor", ENVSYS_SVOLTS_DC, IBMHAWK_V_VOLTAGE+2 }, + { "2.5 Voltage sensor", ENVSYS_SVOLTS_DC, IBMHAWK_V_VOLTAGE+3 }, + { "1.5 Voltage sensor", ENVSYS_SVOLTS_DC, IBMHAWK_V_VOLTAGE+4 }, + { "1.25 Voltage sensor", ENVSYS_SVOLTS_DC, IBMHAWK_V_VOLTAGE+5 }, + { "VRM 1", ENVSYS_SVOLTS_DC, IBMHAWK_V_VOLTAGE+6 }, + { "Fan 1", ENVSYS_SFANRPM, IBMHAWK_F_FAN }, + { "Fan 2", ENVSYS_SFANRPM, IBMHAWK_F_FAN+1 }, + { "Fan 3", ENVSYS_SFANRPM, IBMHAWK_F_FAN+2 }, + { "Fan 4", ENVSYS_SFANRPM, IBMHAWK_F_FAN+3 }, + { "Fan 5", ENVSYS_SFANRPM, IBMHAWK_F_FAN+4 }, + { "Fan 6", ENVSYS_SFANRPM, IBMHAWK_F_FAN+5 }, +}; +static const int ibmhawk_num_sensors = + (sizeof(ibmhawk_sensors)/sizeof(ibmhawk_sensors[0])); + +static int ibmhawk_match(device_t, cfdata_t, void *); +static void ibmhawk_attach(device_t, device_t, void *); +static int ibmhawk_detach(device_t, int); +static uint8_t ibmhawk_cksum(uint8_t *); +static int ibmhawk_request(struct ibmhawk_softc *, + uint8_t, ibmhawk_response_t *); +static uint32_t ibmhawk_normalize(int, uint32_t); +static void ibmhawk_set(struct ibmhawk_softc *, int, int, bool, bool); +static void ibmhawk_refreshall(struct ibmhawk_softc *, bool); +static void ibmhawk_refresh(struct sysmon_envsys *, envsys_data_t *); +static void ibmhawk_get_limits(struct sysmon_envsys *, envsys_data_t *, + sysmon_envsys_lim_t *, uint32_t *); + +CFATTACH_DECL_NEW(ibmhawk, sizeof(struct ibmhawk_softc), + ibmhawk_match, ibmhawk_attach, ibmhawk_detach, NULL); + +static int +ibmhawk_match(device_t parent, cfdata_t match, void *aux) +{ + struct i2c_attach_args *ia = aux; + ibmhawk_response_t resp; + static struct ibmhawk_softc sc; + + sc.sc_tag = ia->ia_tag; + sc.sc_addr = ia->ia_addr; + if (ibmhawk_request(&sc, IHR_EQUIP, &resp)) + return 0; + return 1; +} + +static void +ibmhawk_attach(device_t parent, device_t self, void *aux) +{ + struct ibmhawk_softc *sc = device_private(self); + struct i2c_attach_args *ia = aux; + ibmhawk_response_t resp; + int i; + + sc->sc_dev = self; + sc->sc_tag = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); + if (ibmhawk_request(sc, IHR_NAME, &resp)) { + aprint_normal(": communication failed\n"); + return; + } + aprint_normal(": IBM Hawk \"%.16s\"\n", resp.ihr_name); + if (ibmhawk_request(sc, IHR_EQUIP, &resp)) { + aprint_error_dev(sc->sc_dev, "equip query failed\n"); + return; + } + sc->sc_numcpus = min(resp.ihr_numcpus, IBMHAWK_MAX_CPU); + sc->sc_numfans = min(resp.ihr_numfans, IBMHAWK_MAX_FAN); +#if IBMHAWK_DEBUG > 0 + aprint_normal_dev(sc->sc_dev, "monitoring %d/%d cpu(s) %d/%d fan(s)\n", + sc->sc_numcpus, resp.ihr_numcpus, sc->sc_numfans, resp.ihr_numfans); +#endif + /* Request and set sensor thresholds. */ + if (ibmhawk_request(sc, IHR_TEMP_THR, &resp)) { + aprint_error_dev(sc->sc_dev, "temp threshold query failed\n"); + return; + } + for (i = 0; i < sc->sc_numcpus; i++) + sc->sc_sensordata[IBMHAWK_T_CPU+i].ihs_warnmax = + resp.ihr_t_warn_thr; + if (ibmhawk_request(sc, IHR_VOLT_THR, &resp)) { + aprint_error_dev(sc->sc_dev, "volt threshold query failed\n"); + return; + } + for (i = 0; i < IBMHAWK_MAX_VOLTAGE; i++) { + sc->sc_sensordata[IBMHAWK_V_VOLTAGE+i].ihs_warnmax = + bswap16(resp.ihr_v_voltage_thr[i*2]); + sc->sc_sensordata[IBMHAWK_V_VOLTAGE+i].ihs_warnmin = + bswap16(resp.ihr_v_voltage_thr[i*2+1]); + } + if ((sc->sc_sme = sysmon_envsys_create()) == NULL) { + aprint_error_dev(sc->sc_dev, "sysmon_envsys_create failed\n"); + return; + } + ibmhawk_refreshall(sc, true); + sc->sc_sme->sme_name = device_xname(sc->sc_dev); + sc->sc_sme->sme_cookie = sc; + sc->sc_sme->sme_refresh = ibmhawk_refresh; + sc->sc_sme->sme_get_limits = ibmhawk_get_limits; + if (sysmon_envsys_register(sc->sc_sme)) { + aprint_error_dev(sc->sc_dev, "sysmon_envsys_register failed\n"); + sysmon_envsys_destroy(sc->sc_sme); + sc->sc_sme = NULL; + return; + } +} + +static int +ibmhawk_detach(device_t self, int flags) +{ + struct ibmhawk_softc *sc = device_private(self); + + if (sc->sc_sme) + sysmon_envsys_destroy(sc->sc_sme); + return 0; +} + + +/* + * Compute the message checksum. + */ +static uint8_t +ibmhawk_cksum(uint8_t *buf) +{ + int len = *buf++; + int s = 0; + + while (--len > 0) + s += *buf++; + return -s; +} + +/* + * Request information from the management processor. + * The response will be zeroed on error. + * Request and response have the form . + */ +static int +ibmhawk_request(struct ibmhawk_softc *sc, uint8_t request, + ibmhawk_response_t *response) +{ + int i, error, retries;; + uint8_t buf[sizeof(ibmhawk_response_t)+3], dummy; + + error = EIO; /* Fail until we have a valid response. */ + retries = 0; + + if (iic_acquire_bus(sc->sc_tag, 0)) + return error; + +again: + memset(response, 0, sizeof(*response)); + + /* Build and send the request. */ + buf[0] = 2; + buf[1] = request; + buf[2] = ibmhawk_cksum(buf); +#if IBMHAWK_DEBUG > 1 + printf("["); + for (i = 0; i < 3; i++) + printf(" %02x", buf[i]); + printf(" ]"); +#endif + for (i = 0; i < 3; i++) + if (iic_smbus_send_byte(sc->sc_tag, sc->sc_addr, buf[i], 0)) + goto bad; + + /* Receive and check the response. */ +#if IBMHAWK_DEBUG > 1 + printf(" => ["); +#endif + if (iic_smbus_receive_byte(sc->sc_tag, sc->sc_addr, &buf[0], 0)) + goto bad; + if (buf[0] == 0 || buf[0] == 255) + goto bad; + for (i = 1; i < buf[0]+1; i++) + if (iic_smbus_receive_byte(sc->sc_tag, sc->sc_addr, + (i < sizeof buf ? &buf[i] : &dummy), 0)) + goto bad; + if (buf[0] >= sizeof(buf) || buf[1] != request || + ibmhawk_cksum(buf) != buf[buf[0]]) + goto bad; + if (buf[0] > 2) + memcpy(response, buf+2, buf[0]-2); + error = 0; + +bad: +#if IBMHAWK_DEBUG > 1 + for (i = 0; i < min(buf[0]+1, sizeof buf); i++) + printf(" %02x", buf[i]); + printf(" ] => %d\n", error); +#endif + if (error != 0 && retries++ < 3) + goto again; + + iic_release_bus(sc->sc_tag, 0); + return error; +} + +static uint32_t +ibmhawk_normalize(int value, uint32_t units) +{ + + if (value == 0) + return 0; + + switch (units) { + case ENVSYS_STEMP: + return 273150000+1000000*value; + case ENVSYS_SVOLTS_DC: + return 10000*value; + default: + return value; + } +} + +static void +ibmhawk_set(struct ibmhawk_softc *sc, + int offset, int value, bool valid, bool create) +{ + int i; + struct ibmhawk_sensordesc *sp; + struct ibmhawk_sensordata *sd; + envsys_data_t *dp; + + sd = &sc->sc_sensordata[offset]; + dp = &sd->ihs_edata; + sp = NULL; + if (create) { + for (i = 0; i < ibmhawk_num_sensors; i++) + if (ibmhawk_sensors[i].offset == offset) { + sp = ibmhawk_sensors+i; + break; + } + if (sp == NULL) { +#if IBMHAWK_DEBUG > 0 + aprint_error_dev(sc->sc_dev, + "offset %d: no sensor found\n", offset); +#endif + return; + } + strlcpy(dp->desc, sp->desc, sizeof(dp->desc)); + dp->units = sp->units; + if (sd->ihs_warnmin != 0 || sd->ihs_warnmax != 0) { + sd->ihs_warnmin = + ibmhawk_normalize(sd->ihs_warnmin, dp->units); + sd->ihs_warnmax = + ibmhawk_normalize(sd->ihs_warnmax, dp->units); + dp->flags |= ENVSYS_FMONLIMITS; + } + if (sysmon_envsys_sensor_attach(sc->sc_sme, dp)) + aprint_error_dev(sc->sc_dev, + "failed to attach \"%s\"\n", dp->desc); + } + + dp->value_cur = ibmhawk_normalize(value, dp->units); + if (!valid) + dp->state = ENVSYS_SINVALID; + else if (sd->ihs_warnmin != 0 && value < sd->ihs_warnmin) + dp->state = ENVSYS_SWARNUNDER; + else if (sd->ihs_warnmax != 0 && value > sd->ihs_warnmax) + dp->state = ENVSYS_SWARNOVER; + else + dp->state = ENVSYS_SVALID; +} + +static void +ibmhawk_refreshall(struct ibmhawk_softc *sc, bool create) +{ + int i; + bool valid; + ibmhawk_response_t resp; + + valid = (ibmhawk_request(sc, IHR_TEMP, &resp) == 0); + ibmhawk_set(sc, IBMHAWK_T_AMBIENT, resp.ihr_t_ambient, valid, create); + for (i = 0; i < sc->sc_numcpus; i++) + ibmhawk_set(sc, IBMHAWK_T_CPU+i, + resp.ihr_t_cpu[i], valid, create); + + valid = (ibmhawk_request(sc, IHR_FANRPM, &resp) == 0); + for (i = 0; i < sc->sc_numfans; i++) + ibmhawk_set(sc, IBMHAWK_F_FAN+i, + bswap16(resp.ihr_fanrpm[i]), valid, create); + + valid = (ibmhawk_request(sc, IHR_VOLT, &resp) == 0); + for (i = 0; i < IBMHAWK_MAX_VOLTAGE; i++) + ibmhawk_set(sc, IBMHAWK_V_VOLTAGE+i, + bswap16(resp.ihr_v_voltage[i]), valid, create); +} + +static void +ibmhawk_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) +{ + struct ibmhawk_softc *sc = sme->sme_cookie; + + /* No more than two refreshes per second. */ + if (hardclock_ticks-sc->sc_refresh < hz/2) + return; +#if IBMHAWK_DEBUG > 1 + aprint_normal_dev(sc->sc_dev, "refresh \"%s\" delta %d\n", + edata->desc, hardclock_ticks-sc->sc_refresh); +#endif + sc->sc_refresh = hardclock_ticks; + ibmhawk_refreshall(sc, false); +} + +static void +ibmhawk_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, + sysmon_envsys_lim_t *limits, uint32_t *props) +{ + struct ibmhawk_sensordata *sd = (struct ibmhawk_sensordata *)edata; + + if (sd->ihs_warnmin != 0) { + limits->sel_warnmin = sd->ihs_warnmin; + *props |= PROP_WARNMIN; + } + if (sd->ihs_warnmax != 0) { + limits->sel_warnmax = sd->ihs_warnmax; + *props |= PROP_WARNMAX; + } +} diff --git a/sys/dev/i2c/ibmhawkreg.h b/sys/dev/i2c/ibmhawkreg.h new file mode 100644 index 00000000000..e3cbf7960bf --- /dev/null +++ b/sys/dev/i2c/ibmhawkreg.h @@ -0,0 +1,86 @@ +/* $NetBSD: ibmhawkreg.h,v 1.1 2011/02/14 08:50:39 hannken Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Juergen Hannken-Illjes. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define IBMHAWK_MAX_CPU 2 +#define IBMHAWK_MAX_VOLTAGE 7 +#define IBMHAWK_MAX_FAN 6 + +typedef union ibmhawk_response { + struct { + uint8_t unknown1; + uint8_t numcpus; + uint8_t unknown2[5]; + uint8_t numfans; + } resp_equip; +#define IHR_EQUIP 0x51 +#define ihr_numcpus resp_equip.numcpus +#define ihr_numfans resp_equip.numfans + struct { + uint8_t unknown[4]; + uint16_t rpm[IBMHAWK_MAX_FAN]; + } resp_fan; +#define IHR_FANRPM 0xa2 +#define ihr_fanrpm resp_fan.rpm + struct { + char name[16]; + } resp_name; +#define IHR_NAME 0x14 +#define ihr_name resp_name.name + struct { + uint8_t unknown1[4]; + uint8_t ambient; + uint8_t cpu[IBMHAWK_MAX_CPU]; + uint8_t unknown2[2]; + } resp_temp; +#define IHR_TEMP 0xa4 +#define ihr_t_ambient resp_temp.ambient +#define ihr_t_cpu resp_temp.cpu + struct { + uint8_t warn_reset; + uint8_t warn; + uint8_t soft; + uint8_t hard; + } resp_temp_thresh; +#define IHR_TEMP_THR 0xe0 +#define ihr_t_warn_thr resp_temp_thresh.warn +#define ihr_t_soft_thr resp_temp_thresh.soft + struct { + uint8_t unknown[2]; + uint16_t voltage[IBMHAWK_MAX_VOLTAGE]; + } resp_volt; +#define IHR_VOLT 0xa6 +#define ihr_v_voltage resp_volt.voltage + struct { + uint16_t voltage[IBMHAWK_MAX_VOLTAGE*2]; + } resp_volt_thresh; +#define IHR_VOLT_THR 0xea +#define ihr_v_voltage_thr resp_volt_thresh.voltage +} ibmhawk_response_t __packed; diff --git a/sys/dev/i2c/ibmhawkvar.h b/sys/dev/i2c/ibmhawkvar.h new file mode 100644 index 00000000000..62f923d0a47 --- /dev/null +++ b/sys/dev/i2c/ibmhawkvar.h @@ -0,0 +1,51 @@ +/* $NetBSD: ibmhawkvar.h,v 1.1 2011/02/14 08:50:39 hannken Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Juergen Hannken-Illjes. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define IBMHAWK_T_AMBIENT 0 +#define IBMHAWK_T_CPU 1 +#define IBMHAWK_V_VOLTAGE (IBMHAWK_T_CPU+IBMHAWK_MAX_CPU) +#define IBMHAWK_F_FAN (IBMHAWK_V_VOLTAGE+IBMHAWK_MAX_VOLTAGE) +#define IBMHAWK_MAX_SENSOR (IBMHAWK_F_FAN+IBMHAWK_MAX_FAN) + +struct ibmhawk_softc { + device_t sc_dev; + i2c_tag_t sc_tag; + i2c_addr_t sc_addr; + int sc_numcpus; + int sc_numfans; + int sc_refresh; + struct sysmon_envsys *sc_sme; + struct ibmhawk_sensordata { + envsys_data_t ihs_edata; + uint32_t ihs_warnmin; + uint32_t ihs_warnmax; + } sc_sensordata[IBMHAWK_MAX_SENSOR]; +}; -- cgit