2020-08-17 11:34:36 +03:00
|
|
|
/* $NetBSD: ipmi.c,v 1.5 2020/08/17 08:34:36 nonaka Exp $ */
|
2008-11-19 16:12:05 +03:00
|
|
|
|
2019-05-18 11:38:00 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2019 Michael van Elst
|
|
|
|
*
|
|
|
|
* 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 AUTHOR ``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 AUTHOR 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.
|
|
|
|
*
|
|
|
|
*/
|
2006-10-01 22:37:54 +04:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2006 Manuel Bouyer.
|
|
|
|
*
|
|
|
|
* 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 AUTHOR ``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 AUTHOR 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2005 Jordan Hargrave
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* 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 AUTHORS 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 AUTHORS 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 <sys/cdefs.h>
|
2020-08-17 11:34:36 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: ipmi.c,v 1.5 2020/08/17 08:34:36 nonaka Exp $");
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/device.h>
|
|
|
|
#include <sys/extent.h>
|
|
|
|
#include <sys/callout.h>
|
|
|
|
#include <sys/envsys.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/kthread.h>
|
2008-01-04 21:38:31 +03:00
|
|
|
#include <sys/bus.h>
|
|
|
|
#include <sys/intr.h>
|
2019-05-18 11:38:00 +03:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
#include <sys/conf.h>
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
#include <dev/isa/isareg.h>
|
|
|
|
#include <dev/isa/isavar.h>
|
|
|
|
|
2019-05-18 11:38:00 +03:00
|
|
|
#include <sys/ipmi.h>
|
2018-12-25 14:56:13 +03:00
|
|
|
#include <dev/ipmivar.h>
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
#include <uvm/uvm_extern.h>
|
|
|
|
|
2019-05-18 11:38:00 +03:00
|
|
|
#include "ioconf.h"
|
|
|
|
|
|
|
|
static dev_type_open(ipmi_open);
|
|
|
|
static dev_type_close(ipmi_close);
|
|
|
|
static dev_type_ioctl(ipmi_ioctl);
|
|
|
|
static dev_type_poll(ipmi_poll);
|
|
|
|
|
|
|
|
const struct cdevsw ipmi_cdevsw = {
|
|
|
|
.d_open = ipmi_open,
|
|
|
|
.d_close = ipmi_close,
|
|
|
|
.d_read = noread,
|
|
|
|
.d_write = nowrite,
|
|
|
|
.d_ioctl = ipmi_ioctl,
|
|
|
|
.d_stop = nostop,
|
|
|
|
.d_tty = notty,
|
|
|
|
.d_poll = ipmi_poll,
|
|
|
|
.d_mmap = nommap,
|
|
|
|
.d_kqfilter = nokqfilter,
|
|
|
|
.d_discard = nodiscard,
|
|
|
|
.d_flag = D_OTHER
|
|
|
|
};
|
|
|
|
|
|
|
|
#define IPMIUNIT(n) (minor(n))
|
|
|
|
|
2006-10-01 22:37:54 +04:00
|
|
|
struct ipmi_sensor {
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t *i_sdr;
|
2006-10-01 22:37:54 +04:00
|
|
|
int i_num;
|
|
|
|
int i_stype;
|
|
|
|
int i_etype;
|
|
|
|
char i_envdesc[64];
|
|
|
|
int i_envtype; /* envsys compatible type */
|
|
|
|
int i_envnum; /* envsys index */
|
2010-04-10 23:02:39 +04:00
|
|
|
sysmon_envsys_lim_t i_limits, i_deflims;
|
|
|
|
uint32_t i_props, i_defprops;
|
2006-10-01 22:37:54 +04:00
|
|
|
SLIST_ENTRY(ipmi_sensor) i_list;
|
2012-02-02 23:42:57 +04:00
|
|
|
int32_t i_prevval; /* feed rnd source on change */
|
2006-10-01 22:37:54 +04:00
|
|
|
};
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
#if 0
|
|
|
|
static int ipmi_nintr;
|
|
|
|
#endif
|
|
|
|
static int ipmi_dbg = 0;
|
|
|
|
static int ipmi_enabled = 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2012-02-02 23:42:57 +04:00
|
|
|
#define SENSOR_REFRESH_RATE (hz / 2)
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
#define IPMI_BTMSG_LEN 0
|
|
|
|
#define IPMI_BTMSG_NFLN 1
|
|
|
|
#define IPMI_BTMSG_SEQ 2
|
|
|
|
#define IPMI_BTMSG_CMD 3
|
|
|
|
#define IPMI_BTMSG_CCODE 4
|
|
|
|
#define IPMI_BTMSG_DATASND 4
|
|
|
|
#define IPMI_BTMSG_DATARCV 5
|
|
|
|
|
|
|
|
#define IPMI_MSG_NFLN 0
|
|
|
|
#define IPMI_MSG_CMD 1
|
|
|
|
#define IPMI_MSG_CCODE 2
|
|
|
|
#define IPMI_MSG_DATASND 2
|
|
|
|
#define IPMI_MSG_DATARCV 3
|
|
|
|
|
|
|
|
#define IPMI_SENSOR_TYPE_TEMP 0x0101
|
|
|
|
#define IPMI_SENSOR_TYPE_VOLT 0x0102
|
|
|
|
#define IPMI_SENSOR_TYPE_FAN 0x0104
|
|
|
|
#define IPMI_SENSOR_TYPE_INTRUSION 0x6F05
|
|
|
|
#define IPMI_SENSOR_TYPE_PWRSUPPLY 0x6F08
|
|
|
|
|
|
|
|
#define IPMI_NAME_UNICODE 0x00
|
|
|
|
#define IPMI_NAME_BCDPLUS 0x01
|
|
|
|
#define IPMI_NAME_ASCII6BIT 0x02
|
|
|
|
#define IPMI_NAME_ASCII8BIT 0x03
|
|
|
|
|
|
|
|
#define IPMI_ENTITY_PWRSUPPLY 0x0A
|
|
|
|
|
2013-08-12 19:40:34 +04:00
|
|
|
#define IPMI_SENSOR_SCANNING_ENABLED (1L << 6)
|
|
|
|
#define IPMI_SENSOR_UNAVAILABLE (1L << 5)
|
|
|
|
#define IPMI_INVALID_SENSOR_P(x) \
|
|
|
|
(((x) & (IPMI_SENSOR_SCANNING_ENABLED|IPMI_SENSOR_UNAVAILABLE)) \
|
|
|
|
!= IPMI_SENSOR_SCANNING_ENABLED)
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
#define IPMI_SDR_TYPEFULL 1
|
|
|
|
#define IPMI_SDR_TYPECOMPACT 2
|
|
|
|
|
|
|
|
#define byteof(x) ((x) >> 3)
|
|
|
|
#define bitof(x) (1L << ((x) & 0x7))
|
|
|
|
#define TB(b,m) (data[2+byteof(b)] & bitof(b))
|
|
|
|
|
|
|
|
#define dbg_printf(lvl, fmt...) \
|
|
|
|
if (ipmi_dbg >= lvl) \
|
|
|
|
printf(fmt);
|
|
|
|
#define dbg_dump(lvl, msg, len, buf) \
|
|
|
|
if (len && ipmi_dbg >= lvl) \
|
2008-04-16 20:06:51 +04:00
|
|
|
dumpb(msg, len, (const uint8_t *)(buf));
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static long signextend(unsigned long, int);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
SLIST_HEAD(ipmi_sensors_head, ipmi_sensor);
|
2018-12-25 14:56:13 +03:00
|
|
|
static struct ipmi_sensors_head ipmi_sensor_list =
|
2006-10-01 22:37:54 +04:00
|
|
|
SLIST_HEAD_INITIALIZER(&ipmi_sensor_list);
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void dumpb(const char *, int, const uint8_t *);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int read_sensor(struct ipmi_softc *, struct ipmi_sensor *);
|
|
|
|
static int add_sdr_sensor(struct ipmi_softc *, uint8_t *);
|
|
|
|
static int get_sdr_partial(struct ipmi_softc *, uint16_t, uint16_t,
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t, uint8_t, void *, uint16_t *);
|
2018-12-25 14:56:13 +03:00
|
|
|
static int get_sdr(struct ipmi_softc *, uint16_t, uint16_t *);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static char *ipmi_buf_acquire(struct ipmi_softc *, size_t);
|
|
|
|
static void ipmi_buf_release(struct ipmi_softc *, char *);
|
|
|
|
static int ipmi_sendcmd(struct ipmi_softc *, int, int, int, int, int, const void*);
|
|
|
|
static int ipmi_recvcmd(struct ipmi_softc *, int, int *, void *);
|
|
|
|
static void ipmi_delay(struct ipmi_softc *, int);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-28 15:44:15 +03:00
|
|
|
static int ipmi_get_device_id(struct ipmi_softc *, struct ipmi_device_id *);
|
2018-12-25 14:56:13 +03:00
|
|
|
static int ipmi_watchdog_setmode(struct sysmon_wdog *);
|
|
|
|
static int ipmi_watchdog_tickle(struct sysmon_wdog *);
|
|
|
|
static void ipmi_dotickle(struct ipmi_softc *);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
#if 0
|
|
|
|
static int ipmi_intr(void *);
|
|
|
|
#endif
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int ipmi_match(device_t, cfdata_t, void *);
|
|
|
|
static void ipmi_attach(device_t, device_t, void *);
|
|
|
|
static int ipmi_detach(device_t, int);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static long ipmi_convert(uint8_t, struct sdrtype1 *, long);
|
|
|
|
static void ipmi_sensor_name(char *, int, uint8_t, uint8_t *);
|
2010-07-18 01:34:39 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
/* BMC Helper Functions */
|
|
|
|
static uint8_t bmc_read(struct ipmi_softc *, int);
|
|
|
|
static void bmc_write(struct ipmi_softc *, int, uint8_t);
|
|
|
|
static int bmc_io_wait(struct ipmi_softc *, int, uint8_t, uint8_t, const char *);
|
|
|
|
static int bmc_io_wait_spin(struct ipmi_softc *, int, uint8_t, uint8_t);
|
|
|
|
static int bmc_io_wait_sleep(struct ipmi_softc *, int, uint8_t, uint8_t);
|
|
|
|
|
|
|
|
static void *bt_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *);
|
|
|
|
static void *cmn_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *);
|
|
|
|
|
|
|
|
static int getbits(uint8_t *, int, int);
|
|
|
|
static int ipmi_sensor_type(int, int, int);
|
|
|
|
|
|
|
|
static void ipmi_refresh_sensors(struct ipmi_softc *);
|
|
|
|
static int ipmi_map_regs(struct ipmi_softc *, struct ipmi_attach_args *);
|
|
|
|
static void ipmi_unmap_regs(struct ipmi_softc *);
|
|
|
|
|
|
|
|
static int32_t ipmi_convert_sensor(uint8_t *, struct ipmi_sensor *);
|
|
|
|
static void ipmi_set_limits(struct sysmon_envsys *, envsys_data_t *,
|
|
|
|
sysmon_envsys_lim_t *, uint32_t *);
|
|
|
|
static void ipmi_get_limits(struct sysmon_envsys *, envsys_data_t *,
|
|
|
|
sysmon_envsys_lim_t *, uint32_t *);
|
|
|
|
static void ipmi_get_sensor_limits(struct ipmi_softc *, struct ipmi_sensor *,
|
|
|
|
sysmon_envsys_lim_t *, uint32_t *);
|
|
|
|
static int ipmi_sensor_status(struct ipmi_softc *, struct ipmi_sensor *,
|
|
|
|
envsys_data_t *, uint8_t *);
|
|
|
|
|
|
|
|
static int add_child_sensors(struct ipmi_softc *, uint8_t *, int, int, int,
|
|
|
|
int, int, int, const char *);
|
|
|
|
|
|
|
|
static bool ipmi_suspend(device_t, const pmf_qual_t *);
|
|
|
|
|
|
|
|
static int kcs_probe(struct ipmi_softc *);
|
|
|
|
static int kcs_reset(struct ipmi_softc *);
|
|
|
|
static int kcs_sendmsg(struct ipmi_softc *, int, const uint8_t *);
|
|
|
|
static int kcs_recvmsg(struct ipmi_softc *, int, int *len, uint8_t *);
|
|
|
|
|
|
|
|
static int bt_probe(struct ipmi_softc *);
|
|
|
|
static int bt_reset(struct ipmi_softc *);
|
|
|
|
static int bt_sendmsg(struct ipmi_softc *, int, const uint8_t *);
|
|
|
|
static int bt_recvmsg(struct ipmi_softc *, int, int *, uint8_t *);
|
|
|
|
|
|
|
|
static int smic_probe(struct ipmi_softc *);
|
|
|
|
static int smic_reset(struct ipmi_softc *);
|
|
|
|
static int smic_sendmsg(struct ipmi_softc *, int, const uint8_t *);
|
|
|
|
static int smic_recvmsg(struct ipmi_softc *, int, int *, uint8_t *);
|
|
|
|
|
|
|
|
static struct ipmi_if kcs_if = {
|
2006-10-01 22:37:54 +04:00
|
|
|
"KCS",
|
|
|
|
IPMI_IF_KCS_NREGS,
|
|
|
|
cmn_buildmsg,
|
|
|
|
kcs_sendmsg,
|
|
|
|
kcs_recvmsg,
|
|
|
|
kcs_reset,
|
|
|
|
kcs_probe,
|
|
|
|
};
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static struct ipmi_if smic_if = {
|
2006-10-01 22:37:54 +04:00
|
|
|
"SMIC",
|
|
|
|
IPMI_IF_SMIC_NREGS,
|
|
|
|
cmn_buildmsg,
|
|
|
|
smic_sendmsg,
|
|
|
|
smic_recvmsg,
|
|
|
|
smic_reset,
|
|
|
|
smic_probe,
|
|
|
|
};
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static struct ipmi_if bt_if = {
|
2006-10-01 22:37:54 +04:00
|
|
|
"BT",
|
|
|
|
IPMI_IF_BT_NREGS,
|
|
|
|
bt_buildmsg,
|
|
|
|
bt_sendmsg,
|
|
|
|
bt_recvmsg,
|
|
|
|
bt_reset,
|
|
|
|
bt_probe,
|
|
|
|
};
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static struct ipmi_if *ipmi_get_if(int);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static struct ipmi_if *
|
2006-10-01 22:37:54 +04:00
|
|
|
ipmi_get_if(int iftype)
|
|
|
|
{
|
|
|
|
switch (iftype) {
|
|
|
|
case IPMI_IF_KCS:
|
2017-06-22 00:55:07 +03:00
|
|
|
return &kcs_if;
|
2006-10-01 22:37:54 +04:00
|
|
|
case IPMI_IF_SMIC:
|
2017-06-22 00:55:07 +03:00
|
|
|
return &smic_if;
|
2006-10-01 22:37:54 +04:00
|
|
|
case IPMI_IF_BT:
|
2017-06-22 00:55:07 +03:00
|
|
|
return &bt_if;
|
|
|
|
default:
|
|
|
|
return NULL;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BMC Helper Functions
|
|
|
|
*/
|
2018-12-25 14:56:13 +03:00
|
|
|
static uint8_t
|
2006-10-01 22:37:54 +04:00
|
|
|
bmc_read(struct ipmi_softc *sc, int offset)
|
|
|
|
{
|
2017-06-22 00:55:07 +03:00
|
|
|
return bus_space_read_1(sc->sc_iot, sc->sc_ioh,
|
|
|
|
offset * sc->sc_if_iospacing);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2008-04-16 20:06:51 +04:00
|
|
|
bmc_write(struct ipmi_softc *sc, int offset, uint8_t val)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
bus_space_write_1(sc->sc_iot, sc->sc_ioh,
|
|
|
|
offset * sc->sc_if_iospacing, val);
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2009-07-20 23:11:30 +04:00
|
|
|
bmc_io_wait_sleep(struct ipmi_softc *sc, int offset, uint8_t mask,
|
|
|
|
uint8_t value)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2009-07-20 23:11:30 +04:00
|
|
|
int retries;
|
|
|
|
uint8_t v;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
KASSERT(mutex_owned(&sc->sc_cmd_mtx));
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
for (retries = 0; retries < sc->sc_max_retries; retries++) {
|
|
|
|
v = bmc_read(sc, offset);
|
|
|
|
if ((v & mask) == value)
|
|
|
|
return v;
|
2010-08-01 12:16:14 +04:00
|
|
|
mutex_enter(&sc->sc_sleep_mtx);
|
|
|
|
cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_sleep_mtx, 1);
|
|
|
|
mutex_exit(&sc->sc_sleep_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
2009-07-20 23:11:30 +04:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
bmc_io_wait(struct ipmi_softc *sc, int offset, uint8_t mask, uint8_t value,
|
2006-10-01 22:37:54 +04:00
|
|
|
const char *lbl)
|
|
|
|
{
|
2009-07-20 23:11:30 +04:00
|
|
|
int v;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
v = bmc_io_wait_spin(sc, offset, mask, value);
|
|
|
|
if (cold || v != -1)
|
|
|
|
return v;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
return bmc_io_wait_sleep(sc, offset, mask, value);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-09-23 14:17:06 +04:00
|
|
|
bmc_io_wait_spin(struct ipmi_softc *sc, int offset, uint8_t mask,
|
2009-07-20 23:11:30 +04:00
|
|
|
uint8_t value)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2009-07-20 23:11:30 +04:00
|
|
|
uint8_t v;
|
2010-08-01 12:16:14 +04:00
|
|
|
int count = cold ? 15000 : 500;
|
2008-11-04 01:44:42 +03:00
|
|
|
/* ~us */
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
while (count--) {
|
|
|
|
v = bmc_read(sc, offset);
|
|
|
|
if ((v & mask) == value)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
delay(1);
|
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#define NETFN_LUN(nf,ln) (((nf) << 2) | ((ln) & 0x3))
|
2019-05-18 11:38:00 +03:00
|
|
|
#define GET_NETFN(m) (((m) >> 2)
|
|
|
|
#define GET_LUN(m) ((m) & 0x03)
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* BT interface
|
|
|
|
*/
|
|
|
|
#define _BT_CTRL_REG 0
|
|
|
|
#define BT_CLR_WR_PTR (1L << 0)
|
|
|
|
#define BT_CLR_RD_PTR (1L << 1)
|
|
|
|
#define BT_HOST2BMC_ATN (1L << 2)
|
|
|
|
#define BT_BMC2HOST_ATN (1L << 3)
|
|
|
|
#define BT_EVT_ATN (1L << 4)
|
|
|
|
#define BT_HOST_BUSY (1L << 6)
|
|
|
|
#define BT_BMC_BUSY (1L << 7)
|
|
|
|
|
|
|
|
#define BT_READY (BT_HOST_BUSY|BT_HOST2BMC_ATN|BT_BMC2HOST_ATN)
|
|
|
|
|
|
|
|
#define _BT_DATAIN_REG 1
|
|
|
|
#define _BT_DATAOUT_REG 1
|
|
|
|
|
|
|
|
#define _BT_INTMASK_REG 2
|
|
|
|
#define BT_IM_HIRQ_PEND (1L << 1)
|
|
|
|
#define BT_IM_SCI_EN (1L << 2)
|
|
|
|
#define BT_IM_SMI_EN (1L << 3)
|
|
|
|
#define BT_IM_NMI2SMI (1L << 4)
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int bt_read(struct ipmi_softc *, int);
|
|
|
|
static int bt_write(struct ipmi_softc *, int, uint8_t);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
bt_read(struct ipmi_softc *sc, int reg)
|
|
|
|
{
|
|
|
|
return bmc_read(sc, reg);
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
bt_write(struct ipmi_softc *sc, int reg, uint8_t data)
|
|
|
|
{
|
2017-06-22 00:55:07 +03:00
|
|
|
if (bmc_io_wait(sc, _BT_CTRL_REG, BT_BMC_BUSY, 0, __func__) < 0)
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
bmc_write(sc, reg, data);
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
bt_sendmsg(struct ipmi_softc *sc, int len, const uint8_t *data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
bt_write(sc, _BT_CTRL_REG, BT_CLR_WR_PTR);
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
bt_write(sc, _BT_DATAOUT_REG, data[i]);
|
|
|
|
|
|
|
|
bt_write(sc, _BT_CTRL_REG, BT_HOST2BMC_ATN);
|
|
|
|
if (bmc_io_wait(sc, _BT_CTRL_REG, BT_HOST2BMC_ATN | BT_BMC_BUSY, 0,
|
2017-06-22 00:55:07 +03:00
|
|
|
__func__) < 0)
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2013-03-19 10:34:28 +04:00
|
|
|
bt_recvmsg(struct ipmi_softc *sc, int maxlen, int *rxlen, uint8_t *data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t len, v, i;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
if (bmc_io_wait(sc, _BT_CTRL_REG, BT_BMC2HOST_ATN, BT_BMC2HOST_ATN,
|
2017-06-22 00:55:07 +03:00
|
|
|
__func__) < 0)
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
bt_write(sc, _BT_CTRL_REG, BT_HOST_BUSY);
|
|
|
|
bt_write(sc, _BT_CTRL_REG, BT_BMC2HOST_ATN);
|
|
|
|
bt_write(sc, _BT_CTRL_REG, BT_CLR_RD_PTR);
|
|
|
|
len = bt_read(sc, _BT_DATAIN_REG);
|
|
|
|
for (i = IPMI_BTMSG_NFLN; i <= len; i++) {
|
|
|
|
v = bt_read(sc, _BT_DATAIN_REG);
|
|
|
|
if (i != IPMI_BTMSG_SEQ)
|
|
|
|
*(data++) = v;
|
|
|
|
}
|
|
|
|
bt_write(sc, _BT_CTRL_REG, BT_HOST_BUSY);
|
|
|
|
*rxlen = len - 1;
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-11-16 04:32:37 +03:00
|
|
|
bt_reset(struct ipmi_softc *sc)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
bt_probe(struct ipmi_softc *sc)
|
|
|
|
{
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t rv;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
rv = bmc_read(sc, _BT_CTRL_REG);
|
|
|
|
rv &= BT_HOST_BUSY;
|
|
|
|
rv |= BT_CLR_WR_PTR|BT_CLR_RD_PTR|BT_BMC2HOST_ATN|BT_HOST2BMC_ATN;
|
|
|
|
bmc_write(sc, _BT_CTRL_REG, rv);
|
|
|
|
|
|
|
|
rv = bmc_read(sc, _BT_INTMASK_REG);
|
|
|
|
rv &= BT_IM_SCI_EN|BT_IM_SMI_EN|BT_IM_NMI2SMI;
|
|
|
|
rv |= BT_IM_HIRQ_PEND;
|
|
|
|
bmc_write(sc, _BT_INTMASK_REG, rv);
|
|
|
|
|
|
|
|
#if 0
|
2017-06-22 00:55:07 +03:00
|
|
|
printf("%s: %2x\n", __func__, v);
|
2006-10-01 22:37:54 +04:00
|
|
|
printf(" WR : %2x\n", v & BT_CLR_WR_PTR);
|
|
|
|
printf(" RD : %2x\n", v & BT_CLR_RD_PTR);
|
|
|
|
printf(" H2B : %2x\n", v & BT_HOST2BMC_ATN);
|
|
|
|
printf(" B2H : %2x\n", v & BT_BMC2HOST_ATN);
|
|
|
|
printf(" EVT : %2x\n", v & BT_EVT_ATN);
|
|
|
|
printf(" HBSY : %2x\n", v & BT_HOST_BUSY);
|
|
|
|
printf(" BBSY : %2x\n", v & BT_BMC_BUSY);
|
|
|
|
#endif
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SMIC interface
|
|
|
|
*/
|
|
|
|
#define _SMIC_DATAIN_REG 0
|
|
|
|
#define _SMIC_DATAOUT_REG 0
|
|
|
|
|
|
|
|
#define _SMIC_CTRL_REG 1
|
|
|
|
#define SMS_CC_GET_STATUS 0x40
|
|
|
|
#define SMS_CC_START_TRANSFER 0x41
|
|
|
|
#define SMS_CC_NEXT_TRANSFER 0x42
|
|
|
|
#define SMS_CC_END_TRANSFER 0x43
|
|
|
|
#define SMS_CC_START_RECEIVE 0x44
|
|
|
|
#define SMS_CC_NEXT_RECEIVE 0x45
|
|
|
|
#define SMS_CC_END_RECEIVE 0x46
|
|
|
|
#define SMS_CC_TRANSFER_ABORT 0x47
|
|
|
|
|
|
|
|
#define SMS_SC_READY 0xc0
|
|
|
|
#define SMS_SC_WRITE_START 0xc1
|
|
|
|
#define SMS_SC_WRITE_NEXT 0xc2
|
|
|
|
#define SMS_SC_WRITE_END 0xc3
|
|
|
|
#define SMS_SC_READ_START 0xc4
|
|
|
|
#define SMS_SC_READ_NEXT 0xc5
|
|
|
|
#define SMS_SC_READ_END 0xc6
|
|
|
|
|
|
|
|
#define _SMIC_FLAG_REG 2
|
|
|
|
#define SMIC_BUSY (1L << 0)
|
|
|
|
#define SMIC_SMS_ATN (1L << 2)
|
|
|
|
#define SMIC_EVT_ATN (1L << 3)
|
|
|
|
#define SMIC_SMI (1L << 4)
|
|
|
|
#define SMIC_TX_DATA_RDY (1L << 6)
|
|
|
|
#define SMIC_RX_DATA_RDY (1L << 7)
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int smic_wait(struct ipmi_softc *, uint8_t, uint8_t, const char *);
|
|
|
|
static int smic_write_cmd_data(struct ipmi_softc *, uint8_t, const uint8_t *);
|
|
|
|
static int smic_read_data(struct ipmi_softc *, uint8_t *);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2013-03-19 10:34:28 +04:00
|
|
|
smic_wait(struct ipmi_softc *sc, uint8_t mask, uint8_t val, const char *lbl)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int v;
|
|
|
|
|
|
|
|
/* Wait for expected flag bits */
|
2017-06-22 00:55:07 +03:00
|
|
|
v = bmc_io_wait(sc, _SMIC_FLAG_REG, mask, val, __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (v < 0)
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* Return current status */
|
|
|
|
v = bmc_read(sc, _SMIC_CTRL_REG);
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(99, "%s(%s) = %#.2x\n", __func__, lbl, v);
|
|
|
|
return v;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
smic_write_cmd_data(struct ipmi_softc *sc, uint8_t cmd, const uint8_t *data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int sts, v;
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(50, "%s: %#.2x %#.2x\n", __func__, cmd, data ? *data : -1);
|
2006-10-01 22:37:54 +04:00
|
|
|
sts = smic_wait(sc, SMIC_TX_DATA_RDY | SMIC_BUSY, SMIC_TX_DATA_RDY,
|
|
|
|
"smic_write_cmd_data ready");
|
|
|
|
if (sts < 0)
|
2017-06-22 00:55:07 +03:00
|
|
|
return sts;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
bmc_write(sc, _SMIC_CTRL_REG, cmd);
|
|
|
|
if (data)
|
|
|
|
bmc_write(sc, _SMIC_DATAOUT_REG, *data);
|
|
|
|
|
|
|
|
/* Toggle BUSY bit, then wait for busy bit to clear */
|
|
|
|
v = bmc_read(sc, _SMIC_FLAG_REG);
|
|
|
|
bmc_write(sc, _SMIC_FLAG_REG, v | SMIC_BUSY);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return smic_wait(sc, SMIC_BUSY, 0, __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
smic_read_data(struct ipmi_softc *sc, uint8_t *data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int sts;
|
|
|
|
|
|
|
|
sts = smic_wait(sc, SMIC_RX_DATA_RDY | SMIC_BUSY, SMIC_RX_DATA_RDY,
|
2017-06-22 00:55:07 +03:00
|
|
|
__func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (sts >= 0) {
|
|
|
|
*data = bmc_read(sc, _SMIC_DATAIN_REG);
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(50, "%s: %#.2x\n", __func__, *data);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
2017-06-22 00:55:07 +03:00
|
|
|
return sts;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
#define ErrStat(a, ...) if (a) printf(__VA_ARGS__);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
smic_sendmsg(struct ipmi_softc *sc, int len, const uint8_t *data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int sts, idx;
|
|
|
|
|
|
|
|
sts = smic_write_cmd_data(sc, SMS_CC_START_TRANSFER, &data[0]);
|
2017-06-22 00:55:07 +03:00
|
|
|
ErrStat(sts != SMS_SC_WRITE_START, "%s: wstart", __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
for (idx = 1; idx < len - 1; idx++) {
|
|
|
|
sts = smic_write_cmd_data(sc, SMS_CC_NEXT_TRANSFER,
|
|
|
|
&data[idx]);
|
2017-06-22 00:55:07 +03:00
|
|
|
ErrStat(sts != SMS_SC_WRITE_NEXT, "%s: write", __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
sts = smic_write_cmd_data(sc, SMS_CC_END_TRANSFER, &data[idx]);
|
|
|
|
if (sts != SMS_SC_WRITE_END) {
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(50, "%s: %d/%d = %#.2x\n", __func__, idx, len, sts);
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
smic_recvmsg(struct ipmi_softc *sc, int maxlen, int *len, uint8_t *data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int sts, idx;
|
|
|
|
|
|
|
|
*len = 0;
|
2017-06-22 00:55:07 +03:00
|
|
|
sts = smic_wait(sc, SMIC_RX_DATA_RDY, SMIC_RX_DATA_RDY, __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (sts < 0)
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
sts = smic_write_cmd_data(sc, SMS_CC_START_RECEIVE, NULL);
|
2017-06-22 00:55:07 +03:00
|
|
|
ErrStat(sts != SMS_SC_READ_START, "%s: rstart", __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
for (idx = 0;; ) {
|
|
|
|
sts = smic_read_data(sc, &data[idx++]);
|
|
|
|
if (sts != SMS_SC_READ_START && sts != SMS_SC_READ_NEXT)
|
|
|
|
break;
|
|
|
|
smic_write_cmd_data(sc, SMS_CC_NEXT_RECEIVE, NULL);
|
|
|
|
}
|
2017-06-22 00:55:07 +03:00
|
|
|
ErrStat(sts != SMS_SC_READ_END, "%s: rend", __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
*len = idx;
|
|
|
|
|
|
|
|
sts = smic_write_cmd_data(sc, SMS_CC_END_RECEIVE, NULL);
|
|
|
|
if (sts != SMS_SC_READY) {
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(50, "%s: %d/%d = %#.2x\n",
|
|
|
|
__func__, idx, maxlen, sts);
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-11-16 04:32:37 +03:00
|
|
|
smic_reset(struct ipmi_softc *sc)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
smic_probe(struct ipmi_softc *sc)
|
|
|
|
{
|
|
|
|
/* Flag register should not be 0xFF on a good system */
|
|
|
|
if (bmc_read(sc, _SMIC_FLAG_REG) == 0xFF)
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* KCS interface
|
|
|
|
*/
|
|
|
|
#define _KCS_DATAIN_REGISTER 0
|
|
|
|
#define _KCS_DATAOUT_REGISTER 0
|
|
|
|
#define KCS_READ_NEXT 0x68
|
|
|
|
|
|
|
|
#define _KCS_COMMAND_REGISTER 1
|
|
|
|
#define KCS_GET_STATUS 0x60
|
|
|
|
#define KCS_WRITE_START 0x61
|
|
|
|
#define KCS_WRITE_END 0x62
|
|
|
|
|
|
|
|
#define _KCS_STATUS_REGISTER 1
|
|
|
|
#define KCS_OBF (1L << 0)
|
|
|
|
#define KCS_IBF (1L << 1)
|
|
|
|
#define KCS_SMS_ATN (1L << 2)
|
|
|
|
#define KCS_CD (1L << 3)
|
|
|
|
#define KCS_OEM1 (1L << 4)
|
|
|
|
#define KCS_OEM2 (1L << 5)
|
|
|
|
#define KCS_STATE_MASK 0xc0
|
|
|
|
#define KCS_IDLE_STATE 0x00
|
|
|
|
#define KCS_READ_STATE 0x40
|
|
|
|
#define KCS_WRITE_STATE 0x80
|
|
|
|
#define KCS_ERROR_STATE 0xC0
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int kcs_wait(struct ipmi_softc *, uint8_t, uint8_t, const char *);
|
|
|
|
static int kcs_write_cmd(struct ipmi_softc *, uint8_t);
|
|
|
|
static int kcs_write_data(struct ipmi_softc *, uint8_t);
|
|
|
|
static int kcs_read_data(struct ipmi_softc *, uint8_t *);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
kcs_wait(struct ipmi_softc *sc, uint8_t mask, uint8_t value, const char *lbl)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int v;
|
|
|
|
|
|
|
|
v = bmc_io_wait(sc, _KCS_STATUS_REGISTER, mask, value, lbl);
|
|
|
|
if (v < 0)
|
2017-06-22 00:55:07 +03:00
|
|
|
return v;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* Check if output buffer full, read dummy byte */
|
|
|
|
if ((v & (KCS_OBF | KCS_STATE_MASK)) == (KCS_OBF | KCS_WRITE_STATE))
|
|
|
|
bmc_read(sc, _KCS_DATAIN_REGISTER);
|
|
|
|
|
|
|
|
/* Check for error state */
|
|
|
|
if ((v & KCS_STATE_MASK) == KCS_ERROR_STATE) {
|
|
|
|
bmc_write(sc, _KCS_COMMAND_REGISTER, KCS_GET_STATUS);
|
|
|
|
while (bmc_read(sc, _KCS_STATUS_REGISTER) & KCS_IBF)
|
|
|
|
;
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev, "error code: %#x\n",
|
2006-10-01 22:37:54 +04:00
|
|
|
bmc_read(sc, _KCS_DATAIN_REGISTER));
|
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return v & KCS_STATE_MASK;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
kcs_write_cmd(struct ipmi_softc *sc, uint8_t cmd)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
/* ASSERT: IBF and OBF are clear */
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(50, "%s: %#.2x\n", __func__, cmd);
|
2006-10-01 22:37:54 +04:00
|
|
|
bmc_write(sc, _KCS_COMMAND_REGISTER, cmd);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return kcs_wait(sc, KCS_IBF, 0, "write_cmd");
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
kcs_write_data(struct ipmi_softc *sc, uint8_t data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
/* ASSERT: IBF and OBF are clear */
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(50, "%s: %#.2x\n", __func__, data);
|
2006-10-01 22:37:54 +04:00
|
|
|
bmc_write(sc, _KCS_DATAOUT_REGISTER, data);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return kcs_wait(sc, KCS_IBF, 0, "write_data");
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
kcs_read_data(struct ipmi_softc *sc, uint8_t * data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int sts;
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
sts = kcs_wait(sc, KCS_IBF | KCS_OBF, KCS_OBF, __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (sts != KCS_READ_STATE)
|
2017-06-22 00:55:07 +03:00
|
|
|
return sts;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* ASSERT: OBF is set read data, request next byte */
|
|
|
|
*data = bmc_read(sc, _KCS_DATAIN_REGISTER);
|
|
|
|
bmc_write(sc, _KCS_DATAOUT_REGISTER, KCS_READ_NEXT);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(50, "%s: %#.2x\n", __func__, *data);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return sts;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Exported KCS functions */
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
kcs_sendmsg(struct ipmi_softc *sc, int len, const uint8_t * data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int idx, sts;
|
|
|
|
|
|
|
|
/* ASSERT: IBF is clear */
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_dump(50, __func__, len, data);
|
2006-10-01 22:37:54 +04:00
|
|
|
sts = kcs_write_cmd(sc, KCS_WRITE_START);
|
|
|
|
for (idx = 0; idx < len; idx++) {
|
|
|
|
if (idx == len - 1)
|
|
|
|
sts = kcs_write_cmd(sc, KCS_WRITE_END);
|
|
|
|
|
|
|
|
if (sts != KCS_WRITE_STATE)
|
|
|
|
break;
|
|
|
|
|
|
|
|
sts = kcs_write_data(sc, data[idx]);
|
|
|
|
}
|
|
|
|
if (sts != KCS_READ_STATE) {
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(1, "%s: %d/%d <%#.2x>\n", __func__, idx, len, sts);
|
|
|
|
dbg_dump(1, __func__, len, data);
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
kcs_recvmsg(struct ipmi_softc *sc, int maxlen, int *rxlen, uint8_t * data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int idx, sts;
|
|
|
|
|
|
|
|
for (idx = 0; idx < maxlen; idx++) {
|
|
|
|
sts = kcs_read_data(sc, &data[idx]);
|
|
|
|
if (sts != KCS_READ_STATE)
|
|
|
|
break;
|
|
|
|
}
|
2017-06-22 00:55:07 +03:00
|
|
|
sts = kcs_wait(sc, KCS_IBF, 0, __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
*rxlen = idx;
|
|
|
|
if (sts != KCS_IDLE_STATE) {
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(1, "%s: %d/%d <%#.2x>\n",
|
|
|
|
__func__, idx, maxlen, sts);
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_dump(50, __func__, idx, data);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-11-16 04:32:37 +03:00
|
|
|
kcs_reset(struct ipmi_softc *sc)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
kcs_probe(struct ipmi_softc *sc)
|
|
|
|
{
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t v;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
v = bmc_read(sc, _KCS_STATUS_REGISTER);
|
|
|
|
#if 0
|
2017-06-22 00:55:07 +03:00
|
|
|
printf("%s: %2x\n", __func__, v);
|
2006-10-01 22:37:54 +04:00
|
|
|
printf(" STS: %2x\n", v & KCS_STATE_MASK);
|
|
|
|
printf(" ATN: %2x\n", v & KCS_SMS_ATN);
|
|
|
|
printf(" C/D: %2x\n", v & KCS_CD);
|
|
|
|
printf(" IBF: %2x\n", v & KCS_IBF);
|
|
|
|
printf(" OBF: %2x\n", v & KCS_OBF);
|
2013-10-18 00:58:55 +04:00
|
|
|
#else
|
|
|
|
__USE(v);
|
2006-10-01 22:37:54 +04:00
|
|
|
#endif
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IPMI code
|
|
|
|
*/
|
|
|
|
#define READ_SMS_BUFFER 0x37
|
|
|
|
#define WRITE_I2C 0x50
|
|
|
|
|
|
|
|
#define GET_MESSAGE_CMD 0x33
|
|
|
|
#define SEND_MESSAGE_CMD 0x34
|
|
|
|
|
|
|
|
#define IPMB_CHANNEL_NUMBER 0
|
|
|
|
|
|
|
|
#define PUBLIC_BUS 0
|
|
|
|
|
|
|
|
#define MIN_I2C_PACKET_SIZE 3
|
|
|
|
#define MIN_IMB_PACKET_SIZE 7 /* one byte for cksum */
|
|
|
|
|
|
|
|
#define MIN_BTBMC_REQ_SIZE 4
|
|
|
|
#define MIN_BTBMC_RSP_SIZE 5
|
|
|
|
#define MIN_BMC_REQ_SIZE 2
|
|
|
|
#define MIN_BMC_RSP_SIZE 3
|
|
|
|
|
|
|
|
#define BMC_SA 0x20 /* BMC/ESM3 */
|
|
|
|
#define FPC_SA 0x22 /* front panel */
|
|
|
|
#define BP_SA 0xC0 /* Primary Backplane */
|
|
|
|
#define BP2_SA 0xC2 /* Secondary Backplane */
|
|
|
|
#define PBP_SA 0xC4 /* Peripheral Backplane */
|
|
|
|
#define DRAC_SA 0x28 /* DRAC-III */
|
|
|
|
#define DRAC3_SA 0x30 /* DRAC-III */
|
|
|
|
#define BMC_LUN 0
|
|
|
|
#define SMS_LUN 2
|
|
|
|
|
|
|
|
struct ipmi_request {
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t rsSa;
|
|
|
|
uint8_t rsLun;
|
|
|
|
uint8_t netFn;
|
|
|
|
uint8_t cmd;
|
|
|
|
uint8_t data_len;
|
|
|
|
uint8_t *data;
|
2006-10-01 22:37:54 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ipmi_response {
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t cCode;
|
|
|
|
uint8_t data_len;
|
|
|
|
uint8_t *data;
|
2006-10-01 22:37:54 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ipmi_bmc_request {
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t bmc_nfLn;
|
|
|
|
uint8_t bmc_cmd;
|
|
|
|
uint8_t bmc_data_len;
|
|
|
|
uint8_t bmc_data[1];
|
2006-10-01 22:37:54 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ipmi_bmc_response {
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t bmc_nfLn;
|
|
|
|
uint8_t bmc_cmd;
|
|
|
|
uint8_t bmc_cCode;
|
|
|
|
uint8_t bmc_data_len;
|
|
|
|
uint8_t bmc_data[1];
|
2006-10-01 22:37:54 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-11-19 16:12:05 +03:00
|
|
|
CFATTACH_DECL2_NEW(ipmi, sizeof(struct ipmi_softc),
|
2009-04-07 21:53:45 +04:00
|
|
|
ipmi_match, ipmi_attach, ipmi_detach, NULL, NULL, NULL);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2008-04-16 20:06:51 +04:00
|
|
|
dumpb(const char *lbl, int len, const uint8_t *data)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
printf("%s: ", lbl);
|
|
|
|
for (idx = 0; idx < len; idx++)
|
|
|
|
printf("%.2x ", data[idx]);
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bt_buildmsg builds an IPMI message from a nfLun, cmd, and data
|
|
|
|
* This is used by BT protocol
|
|
|
|
*
|
|
|
|
* Returns a buffer to an allocated message, txlen contains length
|
|
|
|
* of allocated message
|
|
|
|
*/
|
2018-12-25 14:56:13 +03:00
|
|
|
static void *
|
2006-10-01 22:37:54 +04:00
|
|
|
bt_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len,
|
|
|
|
const void *data, int *txlen)
|
|
|
|
{
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t *buf;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* Block transfer needs 4 extra bytes: length/netfn/seq/cmd + data */
|
|
|
|
*txlen = len + 4;
|
2009-07-20 23:11:30 +04:00
|
|
|
buf = ipmi_buf_acquire(sc, *txlen);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (buf == NULL)
|
2017-06-22 00:55:07 +03:00
|
|
|
return NULL;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
buf[IPMI_BTMSG_LEN] = len + 3;
|
|
|
|
buf[IPMI_BTMSG_NFLN] = nfLun;
|
|
|
|
buf[IPMI_BTMSG_SEQ] = sc->sc_btseq++;
|
|
|
|
buf[IPMI_BTMSG_CMD] = cmd;
|
|
|
|
if (len && data)
|
|
|
|
memcpy(buf + IPMI_BTMSG_DATASND, data, len);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return buf;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cmn_buildmsg builds an IPMI message from a nfLun, cmd, and data
|
|
|
|
* This is used by both SMIC and KCS protocols
|
|
|
|
*
|
|
|
|
* Returns a buffer to an allocated message, txlen contains length
|
|
|
|
* of allocated message
|
|
|
|
*/
|
2018-12-25 14:56:13 +03:00
|
|
|
static void *
|
2006-11-16 04:32:37 +03:00
|
|
|
cmn_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len,
|
2006-10-01 22:37:54 +04:00
|
|
|
const void *data, int *txlen)
|
|
|
|
{
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t *buf;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* Common needs two extra bytes: nfLun/cmd + data */
|
|
|
|
*txlen = len + 2;
|
2009-07-20 23:11:30 +04:00
|
|
|
buf = ipmi_buf_acquire(sc, *txlen);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (buf == NULL)
|
2017-06-22 00:55:07 +03:00
|
|
|
return NULL;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
buf[IPMI_MSG_NFLN] = nfLun;
|
|
|
|
buf[IPMI_MSG_CMD] = cmd;
|
|
|
|
if (len && data)
|
|
|
|
memcpy(buf + IPMI_MSG_DATASND, data, len);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return buf;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
/*
|
|
|
|
* ipmi_sendcmd: caller must hold sc_cmd_mtx.
|
|
|
|
*
|
|
|
|
* Send an IPMI command
|
|
|
|
*/
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
ipmi_sendcmd(struct ipmi_softc *sc, int rssa, int rslun, int netfn, int cmd,
|
|
|
|
int txlen, const void *data)
|
|
|
|
{
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t *buf;
|
2006-10-01 22:37:54 +04:00
|
|
|
int rc = -1;
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(50, "%s: rssa=%#.2x nfln=%#.2x cmd=%#.2x len=%#.2x\n",
|
|
|
|
__func__, rssa, NETFN_LUN(netfn, rslun), cmd, txlen);
|
|
|
|
dbg_dump(10, __func__, txlen, data);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (rssa != BMC_SA) {
|
|
|
|
#if 0
|
|
|
|
buf = sc->sc_if->buildmsg(sc, NETFN_LUN(APP_NETFN, BMC_LUN),
|
|
|
|
APP_SEND_MESSAGE, 7 + txlen, NULL, &txlen);
|
|
|
|
pI2C->bus = (sc->if_ver == 0x09) ?
|
|
|
|
PUBLIC_BUS :
|
|
|
|
IPMB_CHANNEL_NUMBER;
|
|
|
|
|
|
|
|
imbreq->rsSa = rssa;
|
|
|
|
imbreq->nfLn = NETFN_LUN(netfn, rslun);
|
|
|
|
imbreq->cSum1 = -(imbreq->rsSa + imbreq->nfLn);
|
|
|
|
imbreq->rqSa = BMC_SA;
|
|
|
|
imbreq->seqLn = NETFN_LUN(sc->imb_seq++, SMS_LUN);
|
|
|
|
imbreq->cmd = cmd;
|
|
|
|
if (txlen)
|
|
|
|
memcpy(imbreq->data, data, txlen);
|
|
|
|
/* Set message checksum */
|
|
|
|
imbreq->data[txlen] = cksum8(&imbreq->rqSa, txlen + 3);
|
|
|
|
#endif
|
|
|
|
goto done;
|
|
|
|
} else
|
|
|
|
buf = sc->sc_if->buildmsg(sc, NETFN_LUN(netfn, rslun), cmd,
|
|
|
|
txlen, data, &txlen);
|
|
|
|
|
|
|
|
if (buf == NULL) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev, "sendcmd buffer busy\n");
|
2006-10-01 22:37:54 +04:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
rc = sc->sc_if->sendmsg(sc, txlen, buf);
|
2009-07-20 23:11:30 +04:00
|
|
|
ipmi_buf_release(sc, buf);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2008-09-23 14:17:06 +04:00
|
|
|
ipmi_delay(sc, 50); /* give bmc chance to digest command */
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
done:
|
2017-06-22 00:55:07 +03:00
|
|
|
return rc;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2009-07-20 23:11:30 +04:00
|
|
|
ipmi_buf_release(struct ipmi_softc *sc, char *buf)
|
|
|
|
{
|
|
|
|
KASSERT(sc->sc_buf_rsvd);
|
|
|
|
KASSERT(sc->sc_buf == buf);
|
|
|
|
sc->sc_buf_rsvd = false;
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static char *
|
2009-07-20 23:11:30 +04:00
|
|
|
ipmi_buf_acquire(struct ipmi_softc *sc, size_t len)
|
|
|
|
{
|
|
|
|
KASSERT(len <= sizeof(sc->sc_buf));
|
|
|
|
|
|
|
|
if (sc->sc_buf_rsvd || len > sizeof(sc->sc_buf))
|
|
|
|
return NULL;
|
|
|
|
sc->sc_buf_rsvd = true;
|
|
|
|
return sc->sc_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ipmi_recvcmd: caller must hold sc_cmd_mtx.
|
|
|
|
*/
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
ipmi_recvcmd(struct ipmi_softc *sc, int maxlen, int *rxlen, void *data)
|
|
|
|
{
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t *buf, rc = 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
int rawlen;
|
|
|
|
|
|
|
|
/* Need three extra bytes: netfn/cmd/ccode + data */
|
2009-07-20 23:11:30 +04:00
|
|
|
buf = ipmi_buf_acquire(sc, maxlen + 3);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (buf == NULL) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev, "%s: malloc fails\n", __func__);
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
/* Receive message from interface, copy out result data */
|
2010-01-31 14:39:55 +03:00
|
|
|
if (sc->sc_if->recvmsg(sc, maxlen + 3, &rawlen, buf)) {
|
|
|
|
ipmi_buf_release(sc, buf);
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2010-01-31 14:39:55 +03:00
|
|
|
}
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2019-05-18 11:38:00 +03:00
|
|
|
*rxlen = rawlen >= IPMI_MSG_DATARCV ? rawlen - IPMI_MSG_DATARCV : 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
if (*rxlen > 0 && data)
|
|
|
|
memcpy(data, buf + IPMI_MSG_DATARCV, *rxlen);
|
|
|
|
|
|
|
|
if ((rc = buf[IPMI_MSG_CCODE]) != 0)
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(1, "%s: nfln=%#.2x cmd=%#.2x err=%#.2x\n", __func__,
|
2006-10-01 22:37:54 +04:00
|
|
|
buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE]);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(50, "%s: nfln=%#.2x cmd=%#.2x err=%#.2x len=%#.2x\n",
|
|
|
|
__func__, buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD],
|
|
|
|
buf[IPMI_MSG_CCODE], *rxlen);
|
|
|
|
dbg_dump(10, __func__, *rxlen, data);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
ipmi_buf_release(sc, buf);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return rc;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
/*
|
|
|
|
* ipmi_delay: caller must hold sc_cmd_mtx.
|
|
|
|
*/
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2008-09-23 14:17:06 +04:00
|
|
|
ipmi_delay(struct ipmi_softc *sc, int ms)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2017-06-22 00:55:07 +03:00
|
|
|
if (cold) {
|
2008-09-23 14:17:06 +04:00
|
|
|
delay(ms * 1000);
|
2017-06-22 00:55:07 +03:00
|
|
|
return;
|
2010-08-01 12:16:14 +04:00
|
|
|
}
|
2017-06-22 00:55:07 +03:00
|
|
|
mutex_enter(&sc->sc_sleep_mtx);
|
|
|
|
cv_timedwait(&sc->sc_cmd_sleep, &sc->sc_sleep_mtx, mstohz(ms));
|
|
|
|
mutex_exit(&sc->sc_sleep_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read a partial SDR entry */
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
get_sdr_partial(struct ipmi_softc *sc, uint16_t recordId, uint16_t reserveId,
|
|
|
|
uint8_t offset, uint8_t length, void *buffer, uint16_t *nxtRecordId)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t cmd[256 + 8];
|
2006-10-01 22:37:54 +04:00
|
|
|
int len;
|
|
|
|
|
2008-04-16 20:06:51 +04:00
|
|
|
((uint16_t *) cmd)[0] = reserveId;
|
|
|
|
((uint16_t *) cmd)[1] = recordId;
|
2006-10-01 22:37:54 +04:00
|
|
|
cmd[4] = offset;
|
|
|
|
cmd[5] = length;
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_GET_SDR, 6,
|
|
|
|
cmd)) {
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev, "%s: sendcmd fails\n", __func__);
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
if (ipmi_recvcmd(sc, 8 + length, &len, cmd)) {
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev, "%s: recvcmd fails\n", __func__);
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (nxtRecordId)
|
|
|
|
*nxtRecordId = *(uint16_t *) cmd;
|
|
|
|
memcpy(buffer, cmd + 2, len - 2);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int maxsdrlen = 0x10;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* Read an entire SDR; pass to add sensor */
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
get_sdr(struct ipmi_softc *sc, uint16_t recid, uint16_t *nxtrec)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2008-04-16 20:06:51 +04:00
|
|
|
uint16_t resid = 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
int len, sdrlen, offset;
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t *psdr;
|
2006-10-01 22:37:54 +04:00
|
|
|
struct sdrhdr shdr;
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
/* Reserve SDR */
|
|
|
|
if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_RESERVE_SDR,
|
|
|
|
0, NULL)) {
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev, "reserve send fails\n");
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
if (ipmi_recvcmd(sc, sizeof(resid), &len, &resid)) {
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev, "reserve recv fails\n");
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
/* Get SDR Header */
|
|
|
|
if (get_sdr_partial(sc, recid, resid, 0, sizeof shdr, &shdr, nxtrec)) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev, "get header fails\n");
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
/* Allocate space for entire SDR Length of SDR in header does not
|
|
|
|
* include header length */
|
|
|
|
sdrlen = sizeof(shdr) + shdr.record_length;
|
2018-10-14 20:37:40 +03:00
|
|
|
psdr = malloc(sdrlen, M_DEVBUF, M_WAITOK);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (psdr == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
memcpy(psdr, &shdr, sizeof(shdr));
|
|
|
|
|
|
|
|
/* Read SDR Data maxsdrlen bytes at a time */
|
|
|
|
for (offset = sizeof(shdr); offset < sdrlen; offset += maxsdrlen) {
|
|
|
|
len = sdrlen - offset;
|
|
|
|
if (len > maxsdrlen)
|
|
|
|
len = maxsdrlen;
|
|
|
|
|
|
|
|
if (get_sdr_partial(sc, recid, resid, offset, len,
|
|
|
|
psdr + offset, NULL)) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev,
|
|
|
|
"get chunk : %d,%d fails\n", offset, len);
|
2014-09-21 20:40:53 +04:00
|
|
|
free(psdr, M_DEVBUF);
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add SDR to sensor list, if not wanted, free buffer */
|
|
|
|
if (add_sdr_sensor(sc, psdr) == 0)
|
|
|
|
free(psdr, M_DEVBUF);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
getbits(uint8_t *bytes, int bitpos, int bitlen)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int v;
|
|
|
|
int mask;
|
|
|
|
|
|
|
|
bitpos += bitlen - 1;
|
|
|
|
for (v = 0; bitlen--;) {
|
|
|
|
v <<= 1;
|
|
|
|
mask = 1L << (bitpos & 7);
|
|
|
|
if (bytes[bitpos >> 3] & mask)
|
|
|
|
v |= 1;
|
|
|
|
bitpos--;
|
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return v;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Decode IPMI sensor name */
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2008-04-16 20:06:51 +04:00
|
|
|
ipmi_sensor_name(char *name, int len, uint8_t typelen, uint8_t *bits)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int i, slen;
|
|
|
|
char bcdplus[] = "0123456789 -.:,_";
|
|
|
|
|
|
|
|
slen = typelen & 0x1F;
|
|
|
|
switch (typelen >> 6) {
|
|
|
|
case IPMI_NAME_UNICODE:
|
|
|
|
//unicode
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPMI_NAME_BCDPLUS:
|
|
|
|
/* Characters are encoded in 4-bit BCDPLUS */
|
|
|
|
if (len < slen * 2 + 1)
|
|
|
|
slen = (len >> 1) - 1;
|
|
|
|
for (i = 0; i < slen; i++) {
|
|
|
|
*(name++) = bcdplus[bits[i] >> 4];
|
|
|
|
*(name++) = bcdplus[bits[i] & 0xF];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPMI_NAME_ASCII6BIT:
|
|
|
|
/* Characters are encoded in 6-bit ASCII
|
|
|
|
* 0x00 - 0x3F maps to 0x20 - 0x5F */
|
|
|
|
/* XXX: need to calculate max len: slen = 3/4 * len */
|
|
|
|
if (len < slen + 1)
|
|
|
|
slen = len - 1;
|
|
|
|
for (i = 0; i < slen * 8; i += 6)
|
|
|
|
*(name++) = getbits(bits, i, 6) + ' ';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPMI_NAME_ASCII8BIT:
|
|
|
|
/* Characters are 8-bit ascii */
|
|
|
|
if (len < slen + 1)
|
|
|
|
slen = len - 1;
|
|
|
|
while (slen--)
|
|
|
|
*(name++) = *(bits++);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*name = 0;
|
|
|
|
}
|
|
|
|
|
2010-08-01 12:16:14 +04:00
|
|
|
/* Sign extend a n-bit value */
|
2018-12-25 14:56:13 +03:00
|
|
|
static long
|
2010-08-01 12:16:14 +04:00
|
|
|
signextend(unsigned long val, int bits)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2010-08-01 12:16:14 +04:00
|
|
|
long msk = (1L << (bits-1))-1;
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return -(val & ~msk) | val;
|
2010-08-01 12:16:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* fixpoint arithmetic */
|
|
|
|
#define FIX2INT(x) ((int64_t)((x) >> 32))
|
2015-08-28 17:06:01 +03:00
|
|
|
#define INT2FIX(x) ((int64_t)((uint64_t)(x) << 32))
|
2010-08-01 12:16:14 +04:00
|
|
|
|
|
|
|
#define FIX2 0x0000000200000000ll /* 2.0 */
|
|
|
|
#define FIX3 0x0000000300000000ll /* 3.0 */
|
|
|
|
#define FIXE 0x00000002b7e15163ll /* 2.71828182845904523536 */
|
|
|
|
#define FIX10 0x0000000a00000000ll /* 10.0 */
|
|
|
|
#define FIXMONE 0xffffffff00000000ll /* -1.0 */
|
|
|
|
#define FIXHALF 0x0000000080000000ll /* 0.5 */
|
|
|
|
#define FIXTHIRD 0x0000000055555555ll /* 0.33333333333333333333 */
|
|
|
|
|
|
|
|
#define FIX1LOG2 0x0000000171547653ll /* 1.0/log(2) */
|
|
|
|
#define FIX1LOGE 0x0000000100000000ll /* 1.0/log(2.71828182845904523536) */
|
|
|
|
#define FIX1LOG10 0x000000006F2DEC55ll /* 1.0/log(10) */
|
|
|
|
|
|
|
|
#define FIX1E 0x000000005E2D58D9ll /* 1.0/2.71828182845904523536 */
|
|
|
|
|
|
|
|
static int64_t fixlog_a[] = {
|
|
|
|
0x0000000100000000ll /* 1.0/1.0 */,
|
|
|
|
0xffffffff80000000ll /* -1.0/2.0 */,
|
|
|
|
0x0000000055555555ll /* 1.0/3.0 */,
|
|
|
|
0xffffffffc0000000ll /* -1.0/4.0 */,
|
|
|
|
0x0000000033333333ll /* 1.0/5.0 */,
|
|
|
|
0x000000002aaaaaabll /* -1.0/6.0 */,
|
|
|
|
0x0000000024924925ll /* 1.0/7.0 */,
|
|
|
|
0x0000000020000000ll /* -1.0/8.0 */,
|
|
|
|
0x000000001c71c71cll /* 1.0/9.0 */
|
2016-07-07 09:55:38 +03:00
|
|
|
};
|
2010-08-01 12:16:14 +04:00
|
|
|
|
|
|
|
static int64_t fixexp_a[] = {
|
|
|
|
0x0000000100000000ll /* 1.0/1.0 */,
|
|
|
|
0x0000000100000000ll /* 1.0/1.0 */,
|
|
|
|
0x0000000080000000ll /* 1.0/2.0 */,
|
|
|
|
0x000000002aaaaaabll /* 1.0/6.0 */,
|
|
|
|
0x000000000aaaaaabll /* 1.0/24.0 */,
|
|
|
|
0x0000000002222222ll /* 1.0/120.0 */,
|
|
|
|
0x00000000005b05b0ll /* 1.0/720.0 */,
|
|
|
|
0x00000000000d00d0ll /* 1.0/5040.0 */,
|
|
|
|
0x000000000001a01all /* 1.0/40320.0 */
|
2016-07-07 09:55:38 +03:00
|
|
|
};
|
2010-08-01 12:16:14 +04:00
|
|
|
|
|
|
|
static int64_t
|
|
|
|
fixmul(int64_t x, int64_t y)
|
|
|
|
{
|
|
|
|
int64_t z;
|
2016-07-07 09:55:38 +03:00
|
|
|
int64_t a,b,c,d;
|
2010-08-01 12:16:14 +04:00
|
|
|
int neg;
|
|
|
|
|
|
|
|
neg = 0;
|
|
|
|
if (x < 0) {
|
|
|
|
x = -x;
|
|
|
|
neg = !neg;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
2010-08-01 12:16:14 +04:00
|
|
|
if (y < 0) {
|
|
|
|
y = -y;
|
|
|
|
neg = !neg;
|
|
|
|
}
|
|
|
|
|
|
|
|
a = FIX2INT(x);
|
|
|
|
b = x - INT2FIX(a);
|
|
|
|
c = FIX2INT(y);
|
|
|
|
d = y - INT2FIX(c);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2010-08-01 12:16:14 +04:00
|
|
|
z = INT2FIX(a*c) + a * d + b * c + (b/2 * d/2 >> 30);
|
|
|
|
|
|
|
|
return neg ? -z : z;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t
|
|
|
|
poly(int64_t x0, int64_t x, int64_t a[], int n)
|
|
|
|
{
|
|
|
|
int64_t z;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
z = fixmul(x0, a[0]);
|
|
|
|
for (i=1; i<n; ++i) {
|
|
|
|
x0 = fixmul(x0, x);
|
|
|
|
z = fixmul(x0, a[i]) + z;
|
|
|
|
}
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t
|
|
|
|
logx(int64_t x, int64_t y)
|
|
|
|
{
|
2016-07-07 09:55:38 +03:00
|
|
|
int64_t z;
|
2010-08-01 12:16:14 +04:00
|
|
|
|
|
|
|
if (x <= INT2FIX(0)) {
|
|
|
|
z = INT2FIX(-99999);
|
|
|
|
goto done;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2010-08-01 12:16:14 +04:00
|
|
|
z = INT2FIX(0);
|
|
|
|
while (x >= FIXE) {
|
|
|
|
x = fixmul(x, FIX1E);
|
|
|
|
z += INT2FIX(1);
|
|
|
|
}
|
|
|
|
while (x < INT2FIX(1)) {
|
|
|
|
x = fixmul(x, FIXE);
|
|
|
|
z -= INT2FIX(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
x -= INT2FIX(1);
|
|
|
|
z += poly(x, x, fixlog_a, sizeof(fixlog_a)/sizeof(fixlog_a[0]));
|
|
|
|
z = fixmul(z, y);
|
|
|
|
|
|
|
|
done:
|
|
|
|
return z;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2010-08-01 12:16:14 +04:00
|
|
|
static int64_t
|
|
|
|
powx(int64_t x, int64_t y)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2010-08-01 12:16:14 +04:00
|
|
|
int64_t k;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2010-08-01 12:16:14 +04:00
|
|
|
if (x == INT2FIX(0))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
x = logx(x,y);
|
|
|
|
|
|
|
|
if (x < INT2FIX(0)) {
|
|
|
|
x = INT2FIX(0) - x;
|
|
|
|
k = -FIX2INT(x);
|
|
|
|
x = INT2FIX(-k) - x;
|
|
|
|
} else {
|
|
|
|
k = FIX2INT(x);
|
|
|
|
x = x - INT2FIX(k);
|
|
|
|
}
|
|
|
|
|
|
|
|
x = poly(INT2FIX(1), x, fixexp_a, sizeof(fixexp_a)/sizeof(fixexp_a[0]));
|
|
|
|
|
|
|
|
while (k < 0) {
|
|
|
|
x = fixmul(x, FIX1E);
|
|
|
|
++k;
|
|
|
|
}
|
|
|
|
while (k > 0) {
|
|
|
|
x = fixmul(x, FIXE);
|
|
|
|
--k;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
return x;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert IPMI reading from sensor factors */
|
2018-12-25 14:56:13 +03:00
|
|
|
static long
|
2008-04-16 20:06:51 +04:00
|
|
|
ipmi_convert(uint8_t v, struct sdrtype1 *s1, long adj)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2010-08-01 12:16:14 +04:00
|
|
|
int64_t M, B;
|
2006-10-01 22:37:54 +04:00
|
|
|
char K1, K2;
|
2012-04-04 21:44:31 +04:00
|
|
|
int64_t val, v1, v2, vs;
|
|
|
|
int sign = (s1->units1 >> 6) & 0x3;
|
|
|
|
|
|
|
|
vs = (sign == 0x1 || sign == 0x2) ? (int8_t)v : v;
|
|
|
|
if ((vs < 0) && (sign == 0x1))
|
|
|
|
vs++;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* Calculate linear reading variables */
|
|
|
|
M = signextend((((short)(s1->m_tolerance & 0xC0)) << 2) + s1->m, 10);
|
|
|
|
B = signextend((((short)(s1->b_accuracy & 0xC0)) << 2) + s1->b, 10);
|
|
|
|
K1 = signextend(s1->rbexp & 0xF, 4);
|
|
|
|
K2 = signextend(s1->rbexp >> 4, 4);
|
|
|
|
|
|
|
|
/* Calculate sensor reading:
|
|
|
|
* y = L((M * v + (B * 10^K1)) * 10^(K2+adj)
|
|
|
|
*
|
|
|
|
* This commutes out to:
|
|
|
|
* y = L(M*v * 10^(K2+adj) + B * 10^(K1+K2+adj)); */
|
2010-08-01 12:16:14 +04:00
|
|
|
v1 = powx(FIX10, INT2FIX(K2 + adj));
|
|
|
|
v2 = powx(FIX10, INT2FIX(K1 + K2 + adj));
|
2012-04-04 21:44:31 +04:00
|
|
|
val = M * vs * v1 + B * v2;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* Linearization function: y = f(x) 0 : y = x 1 : y = ln(x) 2 : y =
|
|
|
|
* log10(x) 3 : y = log2(x) 4 : y = e^x 5 : y = 10^x 6 : y = 2^x 7 : y
|
|
|
|
* = 1/x 8 : y = x^2 9 : y = x^3 10 : y = square root(x) 11 : y = cube
|
|
|
|
* root(x) */
|
2010-08-01 12:16:14 +04:00
|
|
|
switch (s1->linear & 0x7f) {
|
|
|
|
case 0: break;
|
|
|
|
case 1: val = logx(val,FIX1LOGE); break;
|
|
|
|
case 2: val = logx(val,FIX1LOG10); break;
|
|
|
|
case 3: val = logx(val,FIX1LOG2); break;
|
|
|
|
case 4: val = powx(FIXE,val); break;
|
|
|
|
case 5: val = powx(FIX10,val); break;
|
|
|
|
case 6: val = powx(FIX2,val); break;
|
|
|
|
case 7: val = powx(val,FIXMONE); break;
|
|
|
|
case 8: val = powx(val,FIX2); break;
|
|
|
|
case 9: val = powx(val,FIX3); break;
|
|
|
|
case 10: val = powx(val,FIXHALF); break;
|
|
|
|
case 11: val = powx(val,FIXTHIRD); break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FIX2INT(val);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int32_t
|
2009-06-29 16:30:09 +04:00
|
|
|
ipmi_convert_sensor(uint8_t *reading, struct ipmi_sensor *psensor)
|
2008-09-08 07:05:38 +04:00
|
|
|
{
|
2006-10-01 22:37:54 +04:00
|
|
|
struct sdrtype1 *s1 = (struct sdrtype1 *)psensor->i_sdr;
|
2009-06-29 16:30:09 +04:00
|
|
|
int32_t val;
|
|
|
|
|
|
|
|
switch (psensor->i_envtype) {
|
2006-10-01 22:37:54 +04:00
|
|
|
case ENVSYS_STEMP:
|
2009-06-29 16:30:09 +04:00
|
|
|
val = ipmi_convert(reading[0], s1, 6) + 273150000;
|
2006-10-01 22:37:54 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ENVSYS_SVOLTS_DC:
|
2009-06-29 16:30:09 +04:00
|
|
|
val = ipmi_convert(reading[0], s1, 6);
|
2006-10-01 22:37:54 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ENVSYS_SFANRPM:
|
2009-06-29 16:30:09 +04:00
|
|
|
val = ipmi_convert(reading[0], s1, 0);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (((s1->units1>>3)&0x7) == 0x3)
|
2009-06-29 16:30:09 +04:00
|
|
|
val *= 60; /* RPS -> RPM */
|
2006-10-01 22:37:54 +04:00
|
|
|
break;
|
|
|
|
default:
|
2009-06-29 16:30:09 +04:00
|
|
|
val = 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
break;
|
|
|
|
}
|
2009-06-29 16:30:09 +04:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2009-07-11 09:03:11 +04:00
|
|
|
ipmi_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
|
2010-02-15 02:07:59 +03:00
|
|
|
sysmon_envsys_lim_t *limits, uint32_t *props)
|
2009-07-11 09:03:11 +04:00
|
|
|
{
|
|
|
|
struct ipmi_sensor *ipmi_s;
|
|
|
|
|
|
|
|
/* Find the ipmi_sensor corresponding to this edata */
|
|
|
|
SLIST_FOREACH(ipmi_s, &ipmi_sensor_list, i_list) {
|
|
|
|
if (ipmi_s->i_envnum == edata->sensor) {
|
2010-04-10 23:02:39 +04:00
|
|
|
if (limits == NULL) {
|
|
|
|
limits = &ipmi_s->i_deflims;
|
|
|
|
props = &ipmi_s->i_defprops;
|
|
|
|
}
|
2010-02-15 02:07:59 +03:00
|
|
|
*props |= PROP_DRIVER_LIMITS;
|
2009-07-11 09:03:11 +04:00
|
|
|
ipmi_s->i_limits = *limits;
|
2010-02-15 02:07:59 +03:00
|
|
|
ipmi_s->i_props = *props;
|
2009-07-11 09:03:11 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2009-06-29 16:30:09 +04:00
|
|
|
ipmi_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
|
2010-02-15 02:07:59 +03:00
|
|
|
sysmon_envsys_lim_t *limits, uint32_t *props)
|
2009-06-29 16:30:09 +04:00
|
|
|
{
|
|
|
|
struct ipmi_sensor *ipmi_s;
|
|
|
|
struct ipmi_softc *sc = sme->sme_cookie;
|
|
|
|
|
|
|
|
/* Find the ipmi_sensor corresponding to this edata */
|
|
|
|
SLIST_FOREACH(ipmi_s, &ipmi_sensor_list, i_list) {
|
|
|
|
if (ipmi_s->i_envnum == edata->sensor) {
|
2010-02-15 02:07:59 +03:00
|
|
|
ipmi_get_sensor_limits(sc, ipmi_s, limits, props);
|
2009-07-11 09:03:11 +04:00
|
|
|
ipmi_s->i_limits = *limits;
|
2010-02-15 02:07:59 +03:00
|
|
|
ipmi_s->i_props = *props;
|
2010-04-10 23:02:39 +04:00
|
|
|
if (ipmi_s->i_defprops == 0) {
|
|
|
|
ipmi_s->i_defprops = *props;
|
|
|
|
ipmi_s->i_deflims = *limits;
|
|
|
|
}
|
2009-06-29 16:30:09 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2009-06-29 16:30:09 +04:00
|
|
|
ipmi_get_sensor_limits(struct ipmi_softc *sc, struct ipmi_sensor *psensor,
|
2010-02-15 02:07:59 +03:00
|
|
|
sysmon_envsys_lim_t *limits, uint32_t *props)
|
2009-06-29 16:30:09 +04:00
|
|
|
{
|
|
|
|
struct sdrtype1 *s1 = (struct sdrtype1 *)psensor->i_sdr;
|
2009-07-20 23:11:30 +04:00
|
|
|
bool failure;
|
2009-06-29 16:30:09 +04:00
|
|
|
int rxlen;
|
|
|
|
uint8_t data[32];
|
2010-08-01 19:42:19 +04:00
|
|
|
uint32_t prop_critmax, prop_warnmax, prop_critmin, prop_warnmin;
|
|
|
|
int32_t *pcritmax, *pwarnmax, *pcritmin, *pwarnmin;
|
2009-06-29 16:30:09 +04:00
|
|
|
|
2010-08-01 12:16:14 +04:00
|
|
|
*props &= ~(PROP_CRITMIN | PROP_CRITMAX | PROP_WARNMIN | PROP_WARNMAX);
|
2009-06-29 16:30:09 +04:00
|
|
|
data[0] = psensor->i_num;
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
|
|
|
failure =
|
|
|
|
ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun,
|
2009-06-29 16:30:09 +04:00
|
|
|
SE_NETFN, SE_GET_SENSOR_THRESHOLD, 1, data) ||
|
2009-07-20 23:11:30 +04:00
|
|
|
ipmi_recvcmd(sc, sizeof(data), &rxlen, data);
|
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
|
|
|
if (failure)
|
2009-07-11 09:03:11 +04:00
|
|
|
return;
|
2009-06-29 16:30:09 +04:00
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(25, "%s: %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x\n",
|
|
|
|
__func__, data[0], data[1], data[2], data[3], data[4], data[5],
|
|
|
|
data[6]);
|
2009-06-29 16:30:09 +04:00
|
|
|
|
2010-08-01 19:42:19 +04:00
|
|
|
switch (s1->linear & 0x7f) {
|
|
|
|
case 7: /* 1/x sensor, exchange upper and lower limits */
|
|
|
|
prop_critmax = PROP_CRITMIN;
|
|
|
|
prop_warnmax = PROP_WARNMIN;
|
|
|
|
prop_critmin = PROP_CRITMAX;
|
|
|
|
prop_warnmin = PROP_WARNMAX;
|
|
|
|
pcritmax = &limits->sel_critmin;
|
|
|
|
pwarnmax = &limits->sel_warnmin;
|
|
|
|
pcritmin = &limits->sel_critmax;
|
|
|
|
pwarnmin = &limits->sel_warnmax;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
prop_critmax = PROP_CRITMAX;
|
|
|
|
prop_warnmax = PROP_WARNMAX;
|
|
|
|
prop_critmin = PROP_CRITMIN;
|
|
|
|
prop_warnmin = PROP_WARNMIN;
|
|
|
|
pcritmax = &limits->sel_critmax;
|
|
|
|
pwarnmax = &limits->sel_warnmax;
|
|
|
|
pcritmin = &limits->sel_critmin;
|
|
|
|
pwarnmin = &limits->sel_warnmin;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-07-09 19:50:26 +04:00
|
|
|
if (data[0] & 0x20 && data[6] != 0xff) {
|
2010-08-01 19:42:19 +04:00
|
|
|
*pcritmax = ipmi_convert_sensor(&data[6], psensor);
|
|
|
|
*props |= prop_critmax;
|
2009-06-29 16:30:09 +04:00
|
|
|
}
|
2009-07-09 19:50:26 +04:00
|
|
|
if (data[0] & 0x10 && data[5] != 0xff) {
|
2010-08-01 19:42:19 +04:00
|
|
|
*pcritmax = ipmi_convert_sensor(&data[5], psensor);
|
|
|
|
*props |= prop_critmax;
|
2009-06-29 16:30:09 +04:00
|
|
|
}
|
2009-07-09 19:50:26 +04:00
|
|
|
if (data[0] & 0x08 && data[4] != 0xff) {
|
2010-08-01 19:42:19 +04:00
|
|
|
*pwarnmax = ipmi_convert_sensor(&data[4], psensor);
|
|
|
|
*props |= prop_warnmax;
|
2009-06-29 16:30:09 +04:00
|
|
|
}
|
2009-07-09 19:50:26 +04:00
|
|
|
if (data[0] & 0x04 && data[3] != 0x00) {
|
2010-08-01 19:42:19 +04:00
|
|
|
*pcritmin = ipmi_convert_sensor(&data[3], psensor);
|
|
|
|
*props |= prop_critmin;
|
2009-06-29 16:30:09 +04:00
|
|
|
}
|
2009-07-09 19:50:26 +04:00
|
|
|
if (data[0] & 0x02 && data[2] != 0x00) {
|
2010-08-01 19:42:19 +04:00
|
|
|
*pcritmin = ipmi_convert_sensor(&data[2], psensor);
|
|
|
|
*props |= prop_critmin;
|
2009-06-29 16:30:09 +04:00
|
|
|
}
|
2009-07-09 19:50:26 +04:00
|
|
|
if (data[0] & 0x01 && data[1] != 0x00) {
|
2010-08-01 19:42:19 +04:00
|
|
|
*pwarnmin = ipmi_convert_sensor(&data[1], psensor);
|
|
|
|
*props |= prop_warnmin;
|
2009-06-29 16:30:09 +04:00
|
|
|
}
|
2009-07-11 09:03:11 +04:00
|
|
|
return;
|
2009-06-29 16:30:09 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2009-06-29 16:30:09 +04:00
|
|
|
ipmi_sensor_status(struct ipmi_softc *sc, struct ipmi_sensor *psensor,
|
|
|
|
envsys_data_t *edata, uint8_t *reading)
|
|
|
|
{
|
|
|
|
int etype;
|
|
|
|
|
|
|
|
/* Get reading of sensor */
|
|
|
|
edata->value_cur = ipmi_convert_sensor(reading, psensor);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* Return Sensor Status */
|
|
|
|
etype = (psensor->i_etype << 8) + psensor->i_stype;
|
|
|
|
switch (etype) {
|
|
|
|
case IPMI_SENSOR_TYPE_TEMP:
|
|
|
|
case IPMI_SENSOR_TYPE_VOLT:
|
|
|
|
case IPMI_SENSOR_TYPE_FAN:
|
2010-02-15 02:07:59 +03:00
|
|
|
if (psensor->i_props & PROP_CRITMAX &&
|
2009-07-11 09:03:11 +04:00
|
|
|
edata->value_cur > psensor->i_limits.sel_critmax)
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
return ENVSYS_SCRITOVER;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2010-02-15 02:07:59 +03:00
|
|
|
if (psensor->i_props & PROP_WARNMAX &&
|
2009-07-11 09:03:11 +04:00
|
|
|
edata->value_cur > psensor->i_limits.sel_warnmax)
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
return ENVSYS_SWARNOVER;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2010-02-15 02:07:59 +03:00
|
|
|
if (psensor->i_props & PROP_CRITMIN &&
|
2009-07-11 09:03:11 +04:00
|
|
|
edata->value_cur < psensor->i_limits.sel_critmin)
|
2008-09-08 07:05:38 +04:00
|
|
|
return ENVSYS_SCRITUNDER;
|
|
|
|
|
2020-08-17 11:34:36 +03:00
|
|
|
if (psensor->i_props & PROP_WARNMIN &&
|
|
|
|
edata->value_cur < psensor->i_limits.sel_warnmin)
|
|
|
|
return ENVSYS_SWARNUNDER;
|
|
|
|
|
2006-10-01 22:37:54 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IPMI_SENSOR_TYPE_INTRUSION:
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
edata->value_cur = (reading[2] & 1) ? 0 : 1;
|
2006-10-01 22:37:54 +04:00
|
|
|
if (reading[2] & 0x1)
|
2007-07-02 19:29:47 +04:00
|
|
|
return ENVSYS_SCRITICAL;
|
2006-10-01 22:37:54 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IPMI_SENSOR_TYPE_PWRSUPPLY:
|
|
|
|
/* Reading: 1 = present+powered, 0 = otherwise */
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
edata->value_cur = (reading[2] & 1) ? 0 : 1;
|
2006-10-01 22:37:54 +04:00
|
|
|
if (reading[2] & 0x10) {
|
|
|
|
/* XXX: Need envsys type for Power Supply types
|
|
|
|
* ok: power supply installed && powered
|
|
|
|
* warn: power supply installed && !powered
|
|
|
|
* crit: power supply !installed
|
|
|
|
*/
|
2007-07-02 19:29:47 +04:00
|
|
|
return ENVSYS_SCRITICAL;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
if (reading[2] & 0x08) {
|
|
|
|
/* Power supply AC lost */
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
return ENVSYS_SWARNOVER;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
return ENVSYS_SVALID;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
read_sensor(struct ipmi_softc *sc, struct ipmi_sensor *psensor)
|
|
|
|
{
|
|
|
|
struct sdrtype1 *s1 = (struct sdrtype1 *) psensor->i_sdr;
|
2008-04-16 20:06:51 +04:00
|
|
|
uint8_t data[8];
|
2009-07-20 23:11:30 +04:00
|
|
|
int rxlen;
|
2007-11-16 11:00:11 +03:00
|
|
|
envsys_data_t *edata = &sc->sc_sensor[psensor->i_envnum];
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
memset(data, 0, sizeof(data));
|
|
|
|
data[0] = psensor->i_num;
|
2009-07-20 23:11:30 +04:00
|
|
|
|
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun, SE_NETFN,
|
|
|
|
SE_GET_SENSOR_READING, 1, data))
|
2009-07-20 23:11:30 +04:00
|
|
|
goto err;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
if (ipmi_recvcmd(sc, sizeof(data), &rxlen, data))
|
2009-07-20 23:11:30 +04:00
|
|
|
goto err;
|
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(10, "m=%u, m_tolerance=%u, b=%u, b_accuracy=%u, "
|
|
|
|
"rbexp=%u, linear=%d\n", s1->m, s1->m_tolerance, s1->b,
|
|
|
|
s1->b_accuracy, s1->rbexp, s1->linear);
|
|
|
|
dbg_printf(10, "values=%#.2x %#.2x %#.2x %#.2x %s\n",
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
data[0],data[1],data[2],data[3], edata->desc);
|
2013-08-12 19:40:34 +04:00
|
|
|
if (IPMI_INVALID_SENSOR_P(data[1])) {
|
2006-10-01 22:37:54 +04:00
|
|
|
/* Check if sensor is valid */
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
edata->state = ENVSYS_SINVALID;
|
2006-10-01 22:37:54 +04:00
|
|
|
} else {
|
2007-07-04 21:36:17 +04:00
|
|
|
edata->state = ipmi_sensor_status(sc, psensor, edata, data);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
2009-07-20 23:11:30 +04:00
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
ipmi_sensor_type(int type, int ext_type, int entity)
|
|
|
|
{
|
|
|
|
switch (ext_type << 8L | type) {
|
|
|
|
case IPMI_SENSOR_TYPE_TEMP:
|
2017-06-22 00:55:07 +03:00
|
|
|
return ENVSYS_STEMP;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
case IPMI_SENSOR_TYPE_VOLT:
|
2017-06-22 00:55:07 +03:00
|
|
|
return ENVSYS_SVOLTS_DC;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
case IPMI_SENSOR_TYPE_FAN:
|
2017-06-22 00:55:07 +03:00
|
|
|
return ENVSYS_SFANRPM;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
case IPMI_SENSOR_TYPE_PWRSUPPLY:
|
|
|
|
if (entity == IPMI_ENTITY_PWRSUPPLY)
|
2017-06-22 00:55:07 +03:00
|
|
|
return ENVSYS_INDICATOR;
|
2006-10-01 22:37:54 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IPMI_SENSOR_TYPE_INTRUSION:
|
2017-06-22 00:55:07 +03:00
|
|
|
return ENVSYS_INDICATOR;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add Sensor to BSD Sysctl interface */
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
add_sdr_sensor(struct ipmi_softc *sc, uint8_t *psdr)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct sdrtype1 *s1 = (struct sdrtype1 *)psdr;
|
|
|
|
struct sdrtype2 *s2 = (struct sdrtype2 *)psdr;
|
|
|
|
char name[64];
|
|
|
|
|
|
|
|
switch (s1->sdrhdr.record_type) {
|
|
|
|
case IPMI_SDR_TYPEFULL:
|
|
|
|
ipmi_sensor_name(name, sizeof(name), s1->typelen, s1->name);
|
|
|
|
rc = add_child_sensors(sc, psdr, 1, s1->sensor_num,
|
|
|
|
s1->sensor_type, s1->event_code, 0, s1->entity_id, name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPMI_SDR_TYPECOMPACT:
|
|
|
|
ipmi_sensor_name(name, sizeof(name), s2->typelen, s2->name);
|
|
|
|
rc = add_child_sensors(sc, psdr, s2->share1 & 0xF,
|
|
|
|
s2->sensor_num, s2->sensor_type, s2->event_code,
|
|
|
|
s2->share2 & 0x7F, s2->entity_id, name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-08-13 22:32:22 +04:00
|
|
|
static int
|
|
|
|
ipmi_is_dupname(char *name)
|
|
|
|
{
|
|
|
|
struct ipmi_sensor *ipmi_s;
|
|
|
|
|
|
|
|
SLIST_FOREACH(ipmi_s, &ipmi_sensor_list, i_list) {
|
|
|
|
if (strcmp(ipmi_s->i_envdesc, name) == 0) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-04-16 20:06:51 +04:00
|
|
|
add_child_sensors(struct ipmi_softc *sc, uint8_t *psdr, int count,
|
2006-10-01 22:37:54 +04:00
|
|
|
int sensor_num, int sensor_type, int ext_type, int sensor_base,
|
|
|
|
int entity, const char *name)
|
|
|
|
{
|
2007-08-13 22:32:22 +04:00
|
|
|
int typ, idx, dupcnt, c;
|
|
|
|
char *e;
|
2006-10-01 22:37:54 +04:00
|
|
|
struct ipmi_sensor *psensor;
|
|
|
|
struct sdrtype1 *s1 = (struct sdrtype1 *)psdr;
|
2014-08-10 20:44:32 +04:00
|
|
|
|
2006-10-01 22:37:54 +04:00
|
|
|
typ = ipmi_sensor_type(sensor_type, ext_type, entity);
|
|
|
|
if (typ == -1) {
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(5, "Unknown sensor type:%#.2x et:%#.2x sn:%#.2x "
|
2006-10-01 22:37:54 +04:00
|
|
|
"name:%s\n", sensor_type, ext_type, sensor_num, name);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-08-13 22:32:22 +04:00
|
|
|
dupcnt = 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
sc->sc_nsensors += count;
|
|
|
|
for (idx = 0; idx < count; idx++) {
|
|
|
|
psensor = malloc(sizeof(struct ipmi_sensor), M_DEVBUF,
|
2018-10-14 20:37:40 +03:00
|
|
|
M_WAITOK);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (psensor == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
memset(psensor, 0, sizeof(struct ipmi_sensor));
|
|
|
|
|
|
|
|
/* Initialize BSD Sensor info */
|
|
|
|
psensor->i_sdr = psdr;
|
|
|
|
psensor->i_num = sensor_num + idx;
|
|
|
|
psensor->i_stype = sensor_type;
|
|
|
|
psensor->i_etype = ext_type;
|
|
|
|
psensor->i_envtype = typ;
|
|
|
|
if (count > 1)
|
|
|
|
snprintf(psensor->i_envdesc,
|
|
|
|
sizeof(psensor->i_envdesc),
|
|
|
|
"%s - %d", name, sensor_base + idx);
|
|
|
|
else
|
|
|
|
strlcpy(psensor->i_envdesc, name,
|
|
|
|
sizeof(psensor->i_envdesc));
|
|
|
|
|
2007-08-13 22:32:22 +04:00
|
|
|
/*
|
|
|
|
* Check for duplicates. If there are duplicates,
|
|
|
|
* make sure there is space in the name (if not,
|
|
|
|
* truncate to make space) for a count (1-99) to
|
|
|
|
* add to make the name unique. If we run the
|
|
|
|
* counter out, just accept the duplicate (@name99)
|
|
|
|
* for now.
|
|
|
|
*/
|
|
|
|
if (ipmi_is_dupname(psensor->i_envdesc)) {
|
|
|
|
if (strlen(psensor->i_envdesc) >=
|
|
|
|
sizeof(psensor->i_envdesc) - 3) {
|
|
|
|
e = psensor->i_envdesc +
|
|
|
|
sizeof(psensor->i_envdesc) - 3;
|
|
|
|
} else {
|
|
|
|
e = psensor->i_envdesc +
|
|
|
|
strlen(psensor->i_envdesc);
|
|
|
|
}
|
|
|
|
c = psensor->i_envdesc +
|
|
|
|
sizeof(psensor->i_envdesc) - e;
|
|
|
|
do {
|
|
|
|
dupcnt++;
|
|
|
|
snprintf(e, c, "%d", dupcnt);
|
|
|
|
} while (dupcnt < 100 &&
|
|
|
|
ipmi_is_dupname(psensor->i_envdesc));
|
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(5, "%s: %#.4x %#.2x:%d ent:%#.2x:%#.2x %s\n",
|
|
|
|
__func__,
|
2006-10-01 22:37:54 +04:00
|
|
|
s1->sdrhdr.record_id, s1->sensor_type,
|
|
|
|
typ, s1->entity_id, s1->entity_instance,
|
|
|
|
psensor->i_envdesc);
|
|
|
|
SLIST_INSERT_HEAD(&ipmi_sensor_list, psensor, i_list);
|
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
#if 0
|
2006-10-01 22:37:54 +04:00
|
|
|
/* Interrupt handler */
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
ipmi_intr(void *arg)
|
|
|
|
{
|
|
|
|
struct ipmi_softc *sc = (struct ipmi_softc *)arg;
|
|
|
|
int v;
|
|
|
|
|
|
|
|
v = bmc_read(sc, _KCS_STATUS_REGISTER);
|
|
|
|
if (v & KCS_OBF)
|
|
|
|
++ipmi_nintr;
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
2018-12-25 14:56:13 +03:00
|
|
|
#endif
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* Handle IPMI Timer - reread sensor values */
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2006-10-01 22:37:54 +04:00
|
|
|
ipmi_refresh_sensors(struct ipmi_softc *sc)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (SLIST_EMPTY(&ipmi_sensor_list))
|
|
|
|
return;
|
|
|
|
|
|
|
|
sc->current_sensor = SLIST_NEXT(sc->current_sensor, i_list);
|
|
|
|
if (sc->current_sensor == NULL)
|
|
|
|
sc->current_sensor = SLIST_FIRST(&ipmi_sensor_list);
|
|
|
|
|
|
|
|
if (read_sensor(sc, sc->current_sensor)) {
|
2017-06-22 00:55:07 +03:00
|
|
|
dbg_printf(1, "%s: error reading\n", __func__);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
ipmi_map_regs(struct ipmi_softc *sc, struct ipmi_attach_args *ia)
|
|
|
|
{
|
2018-12-17 19:26:03 +03:00
|
|
|
int error;
|
|
|
|
|
2006-10-01 22:37:54 +04:00
|
|
|
sc->sc_if = ipmi_get_if(ia->iaa_if_type);
|
|
|
|
if (sc->sc_if == NULL)
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
if (ia->iaa_if_iotype == 'i')
|
|
|
|
sc->sc_iot = ia->iaa_iot;
|
|
|
|
else
|
|
|
|
sc->sc_iot = ia->iaa_memt;
|
|
|
|
|
|
|
|
sc->sc_if_rev = ia->iaa_if_rev;
|
|
|
|
sc->sc_if_iospacing = ia->iaa_if_iospacing;
|
2018-12-17 19:26:03 +03:00
|
|
|
if ((error = bus_space_map(sc->sc_iot, ia->iaa_if_iobase,
|
|
|
|
sc->sc_if->nregs * sc->sc_if_iospacing, 0, &sc->sc_ioh)) != 0) {
|
|
|
|
const char *xname = sc->sc_dev ? device_xname(sc->sc_dev) :
|
|
|
|
"ipmi0";
|
2018-12-25 14:56:13 +03:00
|
|
|
aprint_error("%s: %s:bus_space_map(..., %" PRIx64 ", %x"
|
|
|
|
", 0, %p) type %c failed %d\n",
|
2018-12-26 09:45:58 +03:00
|
|
|
xname, __func__, (uint64_t)ia->iaa_if_iobase,
|
2018-12-17 19:26:03 +03:00
|
|
|
sc->sc_if->nregs * sc->sc_if_iospacing, &sc->sc_ioh,
|
|
|
|
ia->iaa_if_iotype, error);
|
2017-06-22 00:55:07 +03:00
|
|
|
return -1;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
if (iaa->if_if_irq != -1)
|
|
|
|
sc->ih = isa_intr_establish(-1, iaa->if_if_irq,
|
2008-11-19 16:12:05 +03:00
|
|
|
iaa->if_irqlvl, IPL_BIO, ipmi_intr, sc,
|
|
|
|
device_xname(sc->sc_dev);
|
2006-10-01 22:37:54 +04:00
|
|
|
#endif
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2009-04-07 21:53:45 +04:00
|
|
|
ipmi_unmap_regs(struct ipmi_softc *sc)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
|
|
|
bus_space_unmap(sc->sc_iot, sc->sc_ioh,
|
|
|
|
sc->sc_if->nregs * sc->sc_if_iospacing);
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2008-10-30 23:28:02 +03:00
|
|
|
ipmi_match(device_t parent, cfdata_t cf, void *aux)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2008-11-03 15:25:53 +03:00
|
|
|
struct ipmi_softc sc;
|
2006-10-01 22:37:54 +04:00
|
|
|
struct ipmi_attach_args *ia = aux;
|
|
|
|
int rv = 0;
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
memset(&sc, 0, sizeof(sc));
|
|
|
|
|
2006-10-01 22:37:54 +04:00
|
|
|
/* Map registers */
|
2008-11-03 15:33:08 +03:00
|
|
|
if (ipmi_map_regs(&sc, ia) != 0)
|
2008-11-03 15:19:06 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2008-11-03 15:19:06 +03:00
|
|
|
sc.sc_if->probe(&sc);
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_init(&sc.sc_cmd_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
|
2010-08-11 15:31:45 +04:00
|
|
|
cv_init(&sc.sc_cmd_sleep, "ipmimtch");
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-28 15:44:15 +03:00
|
|
|
if (ipmi_get_device_id(&sc, NULL) == 0)
|
|
|
|
rv = 1;
|
|
|
|
|
2009-07-20 23:25:07 +04:00
|
|
|
cv_destroy(&sc.sc_cmd_sleep);
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_destroy(&sc.sc_cmd_mtx);
|
2009-04-07 21:53:45 +04:00
|
|
|
ipmi_unmap_regs(&sc);
|
2008-11-03 15:19:06 +03:00
|
|
|
|
|
|
|
return rv;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2008-09-23 14:17:06 +04:00
|
|
|
static void
|
2009-04-24 21:42:03 +04:00
|
|
|
ipmi_thread(void *cookie)
|
2006-10-01 22:37:54 +04:00
|
|
|
{
|
2009-04-24 21:42:03 +04:00
|
|
|
device_t self = cookie;
|
2008-10-30 23:28:02 +03:00
|
|
|
struct ipmi_softc *sc = device_private(self);
|
2008-09-23 14:17:06 +04:00
|
|
|
struct ipmi_attach_args *ia = &sc->sc_ia;
|
2008-04-16 20:06:51 +04:00
|
|
|
uint16_t rec;
|
2006-10-01 22:37:54 +04:00
|
|
|
struct ipmi_sensor *ipmi_s;
|
2018-12-28 15:44:15 +03:00
|
|
|
struct ipmi_device_id id;
|
2006-10-01 22:37:54 +04:00
|
|
|
int i;
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
sc->sc_thread_running = true;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2008-09-23 14:17:06 +04:00
|
|
|
/* setup ticker */
|
2008-12-20 19:52:41 +03:00
|
|
|
sc->sc_max_retries = hz * 90; /* 90 seconds max */
|
2008-09-23 14:17:06 +04:00
|
|
|
|
2006-10-01 22:37:54 +04:00
|
|
|
/* Map registers */
|
|
|
|
ipmi_map_regs(sc, ia);
|
|
|
|
|
2018-12-28 15:44:15 +03:00
|
|
|
memset(&id, 0, sizeof(id));
|
|
|
|
if (ipmi_get_device_id(sc, &id))
|
|
|
|
aprint_error_dev(self, "Failed to re-query device ID\n");
|
|
|
|
|
2006-10-01 22:37:54 +04:00
|
|
|
/* Scan SDRs, add sensors to list */
|
|
|
|
for (rec = 0; rec != 0xFFFF;)
|
|
|
|
if (get_sdr(sc, rec, &rec))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* allocate and fill sensor arrays */
|
2007-11-16 11:00:11 +03:00
|
|
|
sc->sc_sensor =
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
malloc(sizeof(envsys_data_t) * sc->sc_nsensors,
|
2009-04-24 21:42:03 +04:00
|
|
|
M_DEVBUF, M_WAITOK | M_ZERO);
|
2007-11-16 11:00:11 +03:00
|
|
|
if (sc->sc_sensor == NULL) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(self, "can't allocate envsys_data_t\n");
|
2009-04-24 21:42:03 +04:00
|
|
|
kthread_exit(0);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
|
2007-11-16 11:00:11 +03:00
|
|
|
sc->sc_envsys = sysmon_envsys_create();
|
2009-06-29 16:30:09 +04:00
|
|
|
sc->sc_envsys->sme_cookie = sc;
|
|
|
|
sc->sc_envsys->sme_get_limits = ipmi_get_limits;
|
2009-07-11 09:03:11 +04:00
|
|
|
sc->sc_envsys->sme_set_limits = ipmi_set_limits;
|
2007-11-16 11:00:11 +03:00
|
|
|
|
2010-08-01 12:16:14 +04:00
|
|
|
i = 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
SLIST_FOREACH(ipmi_s, &ipmi_sensor_list, i_list) {
|
2010-02-15 02:07:59 +03:00
|
|
|
ipmi_s->i_props = 0;
|
2010-08-01 12:16:14 +04:00
|
|
|
ipmi_s->i_envnum = -1;
|
2007-11-16 11:00:11 +03:00
|
|
|
sc->sc_sensor[i].units = ipmi_s->i_envtype;
|
|
|
|
sc->sc_sensor[i].state = ENVSYS_SINVALID;
|
2014-08-10 20:44:32 +04:00
|
|
|
sc->sc_sensor[i].flags |= ENVSYS_FHAS_ENTROPY;
|
2007-07-02 19:29:47 +04:00
|
|
|
/*
|
2009-06-02 00:08:44 +04:00
|
|
|
* Monitor threshold limits in the sensors.
|
2007-07-02 19:29:47 +04:00
|
|
|
*/
|
2009-06-29 16:30:09 +04:00
|
|
|
switch (sc->sc_sensor[i].units) {
|
|
|
|
case ENVSYS_STEMP:
|
|
|
|
case ENVSYS_SVOLTS_DC:
|
|
|
|
case ENVSYS_SFANRPM:
|
|
|
|
sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sc->sc_sensor[i].flags |= ENVSYS_FMONCRITICAL;
|
|
|
|
}
|
2007-11-16 11:00:11 +03:00
|
|
|
(void)strlcpy(sc->sc_sensor[i].desc, ipmi_s->i_envdesc,
|
|
|
|
sizeof(sc->sc_sensor[i].desc));
|
2010-08-01 12:16:14 +04:00
|
|
|
++i;
|
|
|
|
|
2007-11-16 11:00:11 +03:00
|
|
|
if (sysmon_envsys_sensor_attach(sc->sc_envsys,
|
2010-08-01 12:16:14 +04:00
|
|
|
&sc->sc_sensor[i-1]))
|
2007-11-16 11:00:11 +03:00
|
|
|
continue;
|
2010-08-01 12:16:14 +04:00
|
|
|
|
|
|
|
/* get reference number from envsys */
|
|
|
|
ipmi_s->i_envnum = sc->sc_sensor[i-1].sensor;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
Imported envsys 2, a brief description of the new features:
(Part 2: drivers)
* Support for detachable sensors.
* Cleaned up the API for simplicity and efficiency.
* Ability to send capacity/critical/warning events to powerd(8).
* Adapted all the code to the new locking order.
* Compatibility with the old envsys API: the ENVSYS_GTREINFO
and ENVSYS_GTREDATA ioctl(2)s are supported.
* Added support for a 'dictionary based communication channel' between
sysmon_power(9) and powerd(8), that means there is no 32 bytes event
size restriction anymore.
* Binary compatibility with old envstat(8) and powerd(8) via COMPAT_40.
* All drivers with the n^2 gtredata bug were fixed, PR kern/36226.
Tested by:
blymn: smsc(4).
bouyer: ipmi(4), mfi(4).
kefren: ug(4).
njoly: viaenv(4), adt7463.c.
riz: owtemp(4).
xtraeme: acpiacad(4), acpibat(4), acpitz(4), aiboost(4), it(4), lm(4).
2007-07-01 11:37:12 +04:00
|
|
|
|
2008-11-19 16:12:05 +03:00
|
|
|
sc->sc_envsys->sme_name = device_xname(sc->sc_dev);
|
2007-11-16 11:00:11 +03:00
|
|
|
sc->sc_envsys->sme_flags = SME_DISABLE_REFRESH;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2007-11-16 11:00:11 +03:00
|
|
|
if (sysmon_envsys_register(sc->sc_envsys)) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(self, "unable to register with sysmon\n");
|
2007-11-16 11:00:11 +03:00
|
|
|
sysmon_envsys_destroy(sc->sc_envsys);
|
|
|
|
}
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
/* initialize sensor list for thread */
|
|
|
|
if (!SLIST_EMPTY(&ipmi_sensor_list))
|
|
|
|
sc->current_sensor = SLIST_FIRST(&ipmi_sensor_list);
|
|
|
|
|
2008-09-23 14:17:06 +04:00
|
|
|
aprint_verbose_dev(self, "version %d.%d interface %s %sbase "
|
2018-12-25 14:56:13 +03:00
|
|
|
"0x%" PRIx64 "/%#x spacing %d\n",
|
2006-10-01 22:37:54 +04:00
|
|
|
ia->iaa_if_rev >> 4, ia->iaa_if_rev & 0xF, sc->sc_if->name,
|
2018-12-26 09:45:58 +03:00
|
|
|
ia->iaa_if_iotype == 'i' ? "io" : "mem",
|
|
|
|
(uint64_t)ia->iaa_if_iobase,
|
2006-10-01 22:37:54 +04:00
|
|
|
ia->iaa_if_iospacing * sc->sc_if->nregs, ia->iaa_if_iospacing);
|
|
|
|
if (ia->iaa_if_irq != -1)
|
2009-04-24 21:42:03 +04:00
|
|
|
aprint_verbose_dev(self, " irq %d\n", ia->iaa_if_irq);
|
2006-10-01 22:37:54 +04:00
|
|
|
|
2018-12-28 15:44:15 +03:00
|
|
|
if (id.deviceid != 0) {
|
|
|
|
aprint_normal_dev(self, "ID %u.%u IPMI %x.%x%s%s\n",
|
|
|
|
id.deviceid, (id.revision & 0xf),
|
|
|
|
(id.version & 0xf), (id.version >> 4) & 0xf,
|
|
|
|
(id.fwrev1 & 0x80) ? " Initializing" : " Available",
|
|
|
|
(id.revision & 0x80) ? " +SDRs" : "");
|
|
|
|
if (id.additional != 0)
|
|
|
|
aprint_verbose_dev(self, "Additional%s%s%s%s%s%s%s%s\n",
|
|
|
|
(id.additional & 0x80) ? " Chassis" : "",
|
|
|
|
(id.additional & 0x40) ? " Bridge" : "",
|
|
|
|
(id.additional & 0x20) ? " IPMBGen" : "",
|
|
|
|
(id.additional & 0x10) ? " IPMBRcv" : "",
|
|
|
|
(id.additional & 0x08) ? " FRU" : "",
|
|
|
|
(id.additional & 0x04) ? " SEL" : "",
|
|
|
|
(id.additional & 0x02) ? " SDR" : "",
|
|
|
|
(id.additional & 0x01) ? " Sensor" : "");
|
|
|
|
aprint_verbose_dev(self, "Manufacturer %05x Product %04x\n",
|
|
|
|
(id.manufacturer[2] & 0xf) << 16
|
|
|
|
| id.manufacturer[1] << 8
|
|
|
|
| id.manufacturer[0],
|
|
|
|
id.product[1] << 8
|
|
|
|
| id.manufacturer[0]);
|
|
|
|
aprint_verbose_dev(self, "Firmware %u.%x\n",
|
|
|
|
(id.fwrev1 & 0x7f), id.fwrev2);
|
|
|
|
}
|
|
|
|
|
2006-10-01 22:37:54 +04:00
|
|
|
/* setup flag to exclude iic */
|
|
|
|
ipmi_enabled = 1;
|
|
|
|
|
|
|
|
/* Setup Watchdog timer */
|
2008-11-19 16:12:05 +03:00
|
|
|
sc->sc_wdog.smw_name = device_xname(sc->sc_dev);
|
2006-10-01 22:37:54 +04:00
|
|
|
sc->sc_wdog.smw_cookie = sc;
|
|
|
|
sc->sc_wdog.smw_setmode = ipmi_watchdog_setmode;
|
|
|
|
sc->sc_wdog.smw_tickle = ipmi_watchdog_tickle;
|
|
|
|
sysmon_wdog_register(&sc->sc_wdog);
|
|
|
|
|
2010-07-18 01:34:39 +04:00
|
|
|
/* Set up a power handler so we can possibly sleep */
|
|
|
|
if (!pmf_device_register(self, ipmi_suspend, NULL))
|
|
|
|
aprint_error_dev(self, "couldn't establish a power handler\n");
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_enter(&sc->sc_poll_mtx);
|
2009-04-24 21:42:03 +04:00
|
|
|
while (sc->sc_thread_running) {
|
2019-05-18 11:38:00 +03:00
|
|
|
while (sc->sc_mode == IPMI_MODE_COMMAND)
|
|
|
|
cv_wait(&sc->sc_mode_cv, &sc->sc_poll_mtx);
|
|
|
|
sc->sc_mode = IPMI_MODE_ENVSYS;
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
if (sc->sc_tickle_due) {
|
|
|
|
ipmi_dotickle(sc);
|
|
|
|
sc->sc_tickle_due = false;
|
|
|
|
}
|
2019-05-18 11:38:00 +03:00
|
|
|
ipmi_refresh_sensors(sc);
|
|
|
|
|
|
|
|
sc->sc_mode = IPMI_MODE_IDLE;
|
|
|
|
cv_broadcast(&sc->sc_mode_cv);
|
|
|
|
cv_timedwait(&sc->sc_poll_cv, &sc->sc_poll_mtx,
|
|
|
|
SENSOR_REFRESH_RATE);
|
2007-07-10 00:51:58 +04:00
|
|
|
}
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_exit(&sc->sc_poll_mtx);
|
2018-12-01 04:56:30 +03:00
|
|
|
self->dv_flags &= ~DVF_ATTACH_INPROGRESS;
|
2009-04-24 21:42:03 +04:00
|
|
|
kthread_exit(0);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2008-10-30 23:28:02 +03:00
|
|
|
ipmi_attach(device_t parent, device_t self, void *aux)
|
2008-09-23 14:17:06 +04:00
|
|
|
{
|
2008-10-30 23:28:02 +03:00
|
|
|
struct ipmi_softc *sc = device_private(self);
|
2008-09-23 14:17:06 +04:00
|
|
|
|
|
|
|
sc->sc_ia = *(struct ipmi_attach_args *)aux;
|
2008-10-30 23:28:02 +03:00
|
|
|
sc->sc_dev = self;
|
2012-01-10 19:23:11 +04:00
|
|
|
aprint_naive("\n");
|
2008-09-23 14:17:06 +04:00
|
|
|
aprint_normal("\n");
|
2009-04-24 21:42:03 +04:00
|
|
|
|
2010-08-01 12:16:14 +04:00
|
|
|
/* lock around read_sensor so that no one messes with the bmc regs */
|
|
|
|
mutex_init(&sc->sc_cmd_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
|
|
|
|
mutex_init(&sc->sc_sleep_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
|
|
|
|
cv_init(&sc->sc_cmd_sleep, "ipmicmd");
|
|
|
|
|
|
|
|
mutex_init(&sc->sc_poll_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
|
2010-08-11 15:31:45 +04:00
|
|
|
cv_init(&sc->sc_poll_cv, "ipmipoll");
|
2019-05-18 11:38:00 +03:00
|
|
|
cv_init(&sc->sc_mode_cv, "ipmimode");
|
2010-08-01 12:16:14 +04:00
|
|
|
|
2009-04-24 21:42:03 +04:00
|
|
|
if (kthread_create(PRI_NONE, 0, NULL, ipmi_thread, self,
|
2017-06-22 16:32:47 +03:00
|
|
|
&sc->sc_kthread, "%s", device_xname(self)) != 0) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(self, "unable to create thread, disabled\n");
|
2018-12-01 04:56:30 +03:00
|
|
|
} else
|
|
|
|
self->dv_flags |= DVF_ATTACH_INPROGRESS;
|
2008-09-23 14:17:06 +04:00
|
|
|
}
|
|
|
|
|
2009-04-07 21:53:45 +04:00
|
|
|
static int
|
|
|
|
ipmi_detach(device_t self, int flags)
|
|
|
|
{
|
2009-04-08 01:47:58 +04:00
|
|
|
struct ipmi_sensor *i;
|
2009-04-07 21:53:45 +04:00
|
|
|
int rc;
|
|
|
|
struct ipmi_softc *sc = device_private(self);
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_enter(&sc->sc_poll_mtx);
|
|
|
|
sc->sc_thread_running = false;
|
|
|
|
cv_signal(&sc->sc_poll_cv);
|
|
|
|
mutex_exit(&sc->sc_poll_mtx);
|
2009-04-07 21:53:45 +04:00
|
|
|
|
|
|
|
if ((rc = sysmon_wdog_unregister(&sc->sc_wdog)) != 0) {
|
|
|
|
if (rc == ERESTART)
|
|
|
|
rc = EINTR;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cancel any pending countdown */
|
|
|
|
sc->sc_wdog.smw_mode &= ~WDOG_MODE_MASK;
|
|
|
|
sc->sc_wdog.smw_mode |= WDOG_MODE_DISARMED;
|
|
|
|
sc->sc_wdog.smw_period = WDOG_PERIOD_DEFAULT;
|
|
|
|
|
|
|
|
if ((rc = ipmi_watchdog_setmode(&sc->sc_wdog)) != 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
ipmi_enabled = 0;
|
|
|
|
|
|
|
|
if (sc->sc_envsys != NULL) {
|
2009-04-08 01:00:30 +04:00
|
|
|
/* _unregister also destroys */
|
|
|
|
sysmon_envsys_unregister(sc->sc_envsys);
|
2009-04-07 21:53:45 +04:00
|
|
|
sc->sc_envsys = NULL;
|
|
|
|
}
|
|
|
|
|
2009-04-08 01:47:58 +04:00
|
|
|
while ((i = SLIST_FIRST(&ipmi_sensor_list)) != NULL) {
|
|
|
|
SLIST_REMOVE_HEAD(&ipmi_sensor_list, i_list);
|
|
|
|
free(i, M_DEVBUF);
|
|
|
|
}
|
|
|
|
|
2009-04-07 21:53:45 +04:00
|
|
|
if (sc->sc_sensor != NULL) {
|
|
|
|
free(sc->sc_sensor, M_DEVBUF);
|
|
|
|
sc->sc_sensor = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ipmi_unmap_regs(sc);
|
|
|
|
|
2019-05-18 11:38:00 +03:00
|
|
|
cv_destroy(&sc->sc_mode_cv);
|
2009-07-20 23:11:30 +04:00
|
|
|
cv_destroy(&sc->sc_poll_cv);
|
|
|
|
mutex_destroy(&sc->sc_poll_mtx);
|
|
|
|
cv_destroy(&sc->sc_cmd_sleep);
|
2010-08-01 12:16:14 +04:00
|
|
|
mutex_destroy(&sc->sc_sleep_mtx);
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_destroy(&sc->sc_cmd_mtx);
|
2009-04-07 21:53:45 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-28 15:44:15 +03:00
|
|
|
static int
|
|
|
|
ipmi_get_device_id(struct ipmi_softc *sc, struct ipmi_device_id *res)
|
|
|
|
{
|
|
|
|
uint8_t buf[32];
|
|
|
|
int len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
|
|
|
/* Identify BMC device early to detect lying bios */
|
|
|
|
rc = ipmi_sendcmd(sc, BMC_SA, 0, APP_NETFN, APP_GET_DEVICE_ID, 0, NULL);
|
|
|
|
if (rc) {
|
|
|
|
dbg_printf(1, ": unable to send get device id "
|
|
|
|
"command\n");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
rc = ipmi_recvcmd(sc, sizeof(buf), &len, buf);
|
|
|
|
if (rc) {
|
|
|
|
dbg_printf(1, ": unable to retrieve device id\n");
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
|
|
|
|
|
|
|
if (rc == 0 && res != NULL)
|
|
|
|
memcpy(res, buf, MIN(sizeof(*res), len));
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
ipmi_watchdog_setmode(struct sysmon_wdog *smwdog)
|
|
|
|
{
|
|
|
|
struct ipmi_softc *sc = smwdog->smw_cookie;
|
|
|
|
struct ipmi_get_watchdog gwdog;
|
|
|
|
struct ipmi_set_watchdog swdog;
|
2009-07-20 23:11:30 +04:00
|
|
|
int rc, len;
|
2006-10-01 22:37:54 +04:00
|
|
|
|
|
|
|
if (smwdog->smw_period < 10)
|
|
|
|
return EINVAL;
|
|
|
|
if (smwdog->smw_period == WDOG_PERIOD_DEFAULT)
|
|
|
|
sc->sc_wdog.smw_period = 10;
|
|
|
|
else
|
|
|
|
sc->sc_wdog.smw_period = smwdog->smw_period;
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
/* see if we can properly task to the watchdog */
|
|
|
|
rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
|
|
|
|
APP_GET_WATCHDOG_TIMER, 0, NULL);
|
|
|
|
rc = ipmi_recvcmd(sc, sizeof(gwdog), &len, &gwdog);
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (rc) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev,
|
|
|
|
"APP_GET_WATCHDOG_TIMER returned %#x\n", rc);
|
2006-10-01 22:37:54 +04:00
|
|
|
return EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&swdog, 0, sizeof(swdog));
|
|
|
|
/* Period is 10ths/sec */
|
2009-07-20 23:11:30 +04:00
|
|
|
swdog.wdog_timeout = htole16(sc->sc_wdog.smw_period * 10);
|
|
|
|
if ((smwdog->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED)
|
|
|
|
swdog.wdog_action = IPMI_WDOG_ACT_DISABLED;
|
|
|
|
else
|
|
|
|
swdog.wdog_action = IPMI_WDOG_ACT_RESET;
|
2006-10-01 22:37:54 +04:00
|
|
|
swdog.wdog_use = IPMI_WDOG_USE_USE_OS;
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
|
|
|
if ((rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
|
|
|
|
APP_SET_WATCHDOG_TIMER, sizeof(swdog), &swdog)) == 0)
|
|
|
|
rc = ipmi_recvcmd(sc, 0, &len, NULL);
|
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
if (rc) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev,
|
|
|
|
"APP_SET_WATCHDOG_TIMER returned %#x\n", rc);
|
2006-10-01 22:37:54 +04:00
|
|
|
return EIO;
|
|
|
|
}
|
|
|
|
|
2017-06-22 00:55:07 +03:00
|
|
|
return 0;
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static int
|
2006-10-01 22:37:54 +04:00
|
|
|
ipmi_watchdog_tickle(struct sysmon_wdog *smwdog)
|
|
|
|
{
|
|
|
|
struct ipmi_softc *sc = smwdog->smw_cookie;
|
|
|
|
|
2009-07-20 23:11:30 +04:00
|
|
|
mutex_enter(&sc->sc_poll_mtx);
|
|
|
|
sc->sc_tickle_due = true;
|
|
|
|
cv_signal(&sc->sc_poll_cv);
|
|
|
|
mutex_exit(&sc->sc_poll_mtx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static void
|
2009-07-20 23:11:30 +04:00
|
|
|
ipmi_dotickle(struct ipmi_softc *sc)
|
|
|
|
{
|
|
|
|
int rc, len;
|
|
|
|
|
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
2006-10-01 22:37:54 +04:00
|
|
|
/* tickle the watchdog */
|
2009-07-20 23:11:30 +04:00
|
|
|
if ((rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
|
|
|
|
APP_RESET_WATCHDOG, 0, NULL)) == 0)
|
|
|
|
rc = ipmi_recvcmd(sc, 0, &len, NULL);
|
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
|
|
|
if (rc != 0) {
|
2017-06-22 00:55:07 +03:00
|
|
|
aprint_error_dev(sc->sc_dev, "watchdog tickle returned %#x\n",
|
|
|
|
rc);
|
2006-10-01 22:37:54 +04:00
|
|
|
}
|
|
|
|
}
|
2010-07-18 01:34:39 +04:00
|
|
|
|
2018-12-25 14:56:13 +03:00
|
|
|
static bool
|
2010-07-18 01:34:39 +04:00
|
|
|
ipmi_suspend(device_t dev, const pmf_qual_t *qual)
|
|
|
|
{
|
|
|
|
struct ipmi_softc *sc = device_private(dev);
|
|
|
|
|
|
|
|
/* Don't allow suspend if watchdog is armed */
|
|
|
|
if ((sc->sc_wdog.smw_mode & WDOG_MODE_MASK) != WDOG_MODE_DISARMED)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
2019-05-18 11:38:00 +03:00
|
|
|
|
|
|
|
static int
|
|
|
|
ipmi_open(dev_t dev, int flag, int fmt, lwp_t *l)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipmi_close(dev_t dev, int flag, int fmt, lwp_t *l)
|
|
|
|
{
|
|
|
|
struct ipmi_softc *sc;
|
|
|
|
int unit;
|
|
|
|
|
|
|
|
unit = IPMIUNIT(dev);
|
|
|
|
if ((sc = device_lookup_private(&ipmi_cd, unit)) == NULL)
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
mutex_enter(&sc->sc_poll_mtx);
|
|
|
|
if (sc->sc_mode == IPMI_MODE_COMMAND) {
|
|
|
|
sc->sc_mode = IPMI_MODE_IDLE;
|
|
|
|
cv_broadcast(&sc->sc_mode_cv);
|
|
|
|
}
|
|
|
|
mutex_exit(&sc->sc_poll_mtx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipmi_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
|
|
|
|
{
|
|
|
|
struct ipmi_softc *sc;
|
|
|
|
int unit, error = 0, len;
|
|
|
|
struct ipmi_req *req;
|
|
|
|
struct ipmi_recv *recv;
|
|
|
|
struct ipmi_addr addr;
|
|
|
|
unsigned char ccode, *buf = NULL;
|
|
|
|
|
|
|
|
unit = IPMIUNIT(dev);
|
|
|
|
if ((sc = device_lookup_private(&ipmi_cd, unit)) == NULL)
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case IPMICTL_SEND_COMMAND:
|
|
|
|
mutex_enter(&sc->sc_poll_mtx);
|
|
|
|
while (sc->sc_mode == IPMI_MODE_ENVSYS) {
|
|
|
|
error = cv_wait_sig(&sc->sc_mode_cv, &sc->sc_poll_mtx);
|
|
|
|
if (error == EINTR) {
|
|
|
|
mutex_exit(&sc->sc_poll_mtx);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sc->sc_mode = IPMI_MODE_COMMAND;
|
|
|
|
mutex_exit(&sc->sc_poll_mtx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case IPMICTL_SEND_COMMAND:
|
|
|
|
req = data;
|
|
|
|
buf = malloc(IPMI_MAX_RX, M_DEVBUF, M_WAITOK);
|
|
|
|
|
|
|
|
len = req->msg.data_len;
|
|
|
|
if (len < 0 || len > IPMI_MAX_RX) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear pending result */
|
|
|
|
if (sc->sc_sent)
|
|
|
|
(void)ipmi_recvcmd(sc, IPMI_MAX_RX, &len, buf);
|
|
|
|
|
|
|
|
/* XXX */
|
|
|
|
error = copyin(req->addr, &addr, sizeof(addr));
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
|
|
|
|
error = copyin(req->msg.data, buf, len);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* save for receive */
|
|
|
|
sc->sc_msgid = req->msgid;
|
|
|
|
sc->sc_netfn = req->msg.netfn;
|
|
|
|
sc->sc_cmd = req->msg.cmd;
|
|
|
|
|
|
|
|
if (ipmi_sendcmd(sc, BMC_SA, 0, req->msg.netfn,
|
|
|
|
req->msg.cmd, len, buf)) {
|
|
|
|
error = EIO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
sc->sc_sent = true;
|
|
|
|
break;
|
|
|
|
case IPMICTL_RECEIVE_MSG_TRUNC:
|
|
|
|
case IPMICTL_RECEIVE_MSG:
|
|
|
|
recv = data;
|
|
|
|
buf = malloc(IPMI_MAX_RX, M_DEVBUF, M_WAITOK);
|
|
|
|
|
|
|
|
if (recv->msg.data_len < 1) {
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX */
|
|
|
|
error = copyin(recv->addr, &addr, sizeof(addr));
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
if (!sc->sc_sent) {
|
|
|
|
error = EIO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
error = ipmi_recvcmd(sc, IPMI_MAX_RX, &len, buf);
|
|
|
|
if (error < 0) {
|
|
|
|
error = EIO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ccode = (unsigned char)error;
|
|
|
|
sc->sc_sent = false;
|
|
|
|
|
|
|
|
if (len > recv->msg.data_len - 1) {
|
|
|
|
if (cmd == IPMICTL_RECEIVE_MSG) {
|
|
|
|
error = EMSGSIZE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
len = recv->msg.data_len - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr.channel = IPMI_BMC_CHANNEL;
|
|
|
|
|
|
|
|
recv->recv_type = IPMI_RESPONSE_RECV_TYPE;
|
|
|
|
recv->msgid = sc->sc_msgid;
|
|
|
|
recv->msg.netfn = sc->sc_netfn;
|
|
|
|
recv->msg.cmd = sc->sc_cmd;
|
|
|
|
recv->msg.data_len = len+1;
|
|
|
|
|
|
|
|
error = copyout(&addr, recv->addr, sizeof(addr));
|
|
|
|
if (error == 0)
|
|
|
|
error = copyout(&ccode, recv->msg.data, 1);
|
|
|
|
if (error == 0)
|
|
|
|
error = copyout(buf, recv->msg.data+1, len);
|
|
|
|
break;
|
|
|
|
case IPMICTL_SET_MY_ADDRESS_CMD:
|
|
|
|
sc->sc_address = *(int *)data;
|
|
|
|
break;
|
|
|
|
case IPMICTL_GET_MY_ADDRESS_CMD:
|
|
|
|
*(int *)data = sc->sc_address;
|
|
|
|
break;
|
|
|
|
case IPMICTL_SET_MY_LUN_CMD:
|
|
|
|
sc->sc_lun = *(int *)data & 0x3;
|
|
|
|
break;
|
|
|
|
case IPMICTL_GET_MY_LUN_CMD:
|
|
|
|
*(int *)data = sc->sc_lun;
|
|
|
|
break;
|
|
|
|
case IPMICTL_SET_GETS_EVENTS_CMD:
|
|
|
|
break;
|
|
|
|
case IPMICTL_REGISTER_FOR_CMD:
|
|
|
|
case IPMICTL_UNREGISTER_FOR_CMD:
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error = ENODEV;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buf)
|
|
|
|
free(buf, M_DEVBUF);
|
|
|
|
|
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case IPMICTL_RECEIVE_MSG:
|
|
|
|
case IPMICTL_RECEIVE_MSG_TRUNC:
|
|
|
|
mutex_enter(&sc->sc_poll_mtx);
|
|
|
|
sc->sc_mode = IPMI_MODE_IDLE;
|
|
|
|
cv_broadcast(&sc->sc_mode_cv);
|
|
|
|
mutex_exit(&sc->sc_poll_mtx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipmi_poll(dev_t dev, int events, lwp_t *l)
|
|
|
|
{
|
|
|
|
struct ipmi_softc *sc;
|
|
|
|
int unit, revents = 0;
|
|
|
|
|
|
|
|
unit = IPMIUNIT(dev);
|
|
|
|
if ((sc = device_lookup_private(&ipmi_cd, unit)) == NULL)
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
mutex_enter(&sc->sc_cmd_mtx);
|
|
|
|
if (events & (POLLIN | POLLRDNORM)) {
|
|
|
|
if (sc->sc_sent)
|
|
|
|
revents |= events & (POLLIN | POLLRDNORM);
|
|
|
|
}
|
|
|
|
mutex_exit(&sc->sc_cmd_mtx);
|
|
|
|
|
|
|
|
return revents;
|
|
|
|
}
|