Index: sys/conf/majors
===================================================================
RCS file: /cvsroot/src/sys/conf/majors,v
retrieving revision 1.86
diff -p -u -r1.86 majors
--- sys/conf/majors 5 May 2019 17:24:00 -0000 1.86
+++ sys/conf/majors 6 May 2019 05:57:10 -0000
@@ -85,4 +85,4 @@ device-major spi char 347 spi
# Major 351 is reserved for sys/modules/examples
# Major 352 is reserved for external/cddl/osnet/dev/fbt/fbt.c
# Major 353 is reserved for external/cddl/osnet/dev/sdt/sdt.c
-# Major 354 is reserved for IPMI userland driver
+device-major ipmi char 354 ipmi
Index: sys/dev/ipmi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ipmi.c,v
retrieving revision 1.3
diff -p -u -r1.3 ipmi.c
--- sys/dev/ipmi.c 28 Dec 2018 12:44:15 -0000 1.3
+++ sys/dev/ipmi.c 6 May 2019 05:57:10 -0000
@@ -1,6 +1,30 @@
/* $NetBSD: ipmi.c,v 1.3 2018/12/28 12:44:15 mlelstv Exp $ */
/*
+ * 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.
+ *
+ */
+/*
* Copyright (c) 2006 Manuel Bouyer.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,14 +90,42 @@ __KERNEL_RCSID(0, "$NetBSD: ipmi.c,v 1.3
#include <sys/kthread.h>
#include <sys/bus.h>
#include <sys/intr.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/conf.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
+#include <sys/ipmi.h>
#include <dev/ipmivar.h>
#include <uvm/uvm_extern.h>
+#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))
+
struct ipmi_sensor {
uint8_t *i_sdr;
int i_num;
@@ -344,6 +396,8 @@ bmc_io_wait_spin(struct ipmi_softc *sc,
}
#define NETFN_LUN(nf,ln) (((nf) << 2) | ((ln) & 0x3))
+#define GET_NETFN(m) (((m) >> 2)
+#define GET_LUN(m) ((m) & 0x03)
/*
* BT interface
@@ -1014,7 +1068,7 @@ ipmi_recvcmd(struct ipmi_softc *sc, int
return -1;
}
- *rxlen = rawlen - IPMI_MSG_DATARCV;
+ *rxlen = rawlen >= IPMI_MSG_DATARCV ? rawlen - IPMI_MSG_DATARCV : 0;
if (*rxlen > 0 && data)
memcpy(data, buf + IPMI_MSG_DATARCV, *rxlen);
@@ -2037,13 +2091,20 @@ ipmi_thread(void *cookie)
mutex_enter(&sc->sc_poll_mtx);
while (sc->sc_thread_running) {
- ipmi_refresh_sensors(sc);
- cv_timedwait(&sc->sc_poll_cv, &sc->sc_poll_mtx,
- SENSOR_REFRESH_RATE);
+ while (sc->sc_mode == IPMI_MODE_COMMAND)
+ cv_wait(&sc->sc_mode_cv, &sc->sc_poll_mtx);
+ sc->sc_mode = IPMI_MODE_ENVSYS;
+
if (sc->sc_tickle_due) {
ipmi_dotickle(sc);
sc->sc_tickle_due = false;
}
+ 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);
}
mutex_exit(&sc->sc_poll_mtx);
self->dv_flags &= ~DVF_ATTACH_INPROGRESS;
@@ -2067,6 +2128,7 @@ ipmi_attach(device_t parent, device_t se
mutex_init(&sc->sc_poll_mtx, MUTEX_DEFAULT, IPL_SOFTCLOCK);
cv_init(&sc->sc_poll_cv, "ipmipoll");
+ cv_init(&sc->sc_mode_cv, "ipmimode");
if (kthread_create(PRI_NONE, 0, NULL, ipmi_thread, self,
&sc->sc_kthread, "%s", device_xname(self)) != 0) {
@@ -2121,6 +2183,7 @@ ipmi_detach(device_t self, int flags)
ipmi_unmap_regs(sc);
+ cv_destroy(&sc->sc_mode_cv);
cv_destroy(&sc->sc_poll_cv);
mutex_destroy(&sc->sc_poll_mtx);
cv_destroy(&sc->sc_cmd_sleep);
@@ -2247,3 +2310,208 @@ ipmi_suspend(device_t dev, const pmf_qua
return false;
return true;
}
+
+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;
+}
Index: sys/dev/ipmivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ipmivar.h,v
retrieving revision 1.2
diff -p -u -r1.2 ipmivar.h
--- sys/dev/ipmivar.h 28 Dec 2018 12:44:15 -0000 1.2
+++ sys/dev/ipmivar.h 6 May 2019 05:57:10 -0000
@@ -92,6 +92,7 @@ struct ipmi_softc {
kmutex_t sc_poll_mtx;
kcondvar_t sc_poll_cv;
+ kcondvar_t sc_mode_cv;
kmutex_t sc_cmd_mtx;
kmutex_t sc_sleep_mtx;
@@ -107,8 +108,24 @@ struct ipmi_softc {
envsys_data_t *sc_sensor;
int sc_nsensors; /* total number of sensors */
- char sc_buf[64];
+ char sc_buf[1024 + 3]; /* IPMI_MAX_RX + 3 */
bool sc_buf_rsvd;
+
+ /* request busy */
+ int sc_mode;
+#define IPMI_MODE_IDLE 0
+#define IPMI_MODE_COMMAND 1
+#define IPMI_MODE_ENVSYS 2
+ bool sc_sent;
+
+ /* dummy */
+ int sc_address;
+ int sc_lun;
+
+ /* saved from last SEND_COMMAND */
+ int sc_msgid;
+ int sc_netfn;
+ int sc_cmd;
};
struct ipmi_device_id {
Index: sys/sys/ipmi.h
===================================================================
RCS file: sys/sys/ipmi.h
diff -N sys/sys/ipmi.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/sys/ipmi.h 6 May 2019 05:57:10 -0000
@@ -0,0 +1,105 @@
+/* $NetBSD: $ */
+
+/*-
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_IPMI_H_
+#define _SYS_IPMI_H_
+
+#define IPMI_MAX_ADDR_SIZE 0x20
+#define IPMI_MAX_RX 1024
+#define IPMI_BMC_SLAVE_ADDR 0x20
+#define IPMI_BMC_CHANNEL 0x0f
+#define IPMI_BMC_SMS_LUN 0x02
+
+#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c
+#define IPMI_IPMB_ADDR_TYPE 0x01
+#define IPMI_IPMB_BROADCAST_ADDR_TYPE 0x41
+
+struct ipmi_msg {
+ unsigned char netfn;
+ unsigned char cmd;
+ unsigned short data_len;
+ unsigned char *data;
+};
+
+struct ipmi_req {
+ unsigned char *addr;
+ unsigned int addr_len;
+ long msgid;
+ struct ipmi_msg msg;
+};
+
+struct ipmi_recv {
+ int recv_type;
+#define IPMI_RESPONSE_RECV_TYPE 1
+#define IPMI_ASYNC_EVENT_RECV_TYPE 2
+#define IPMI_CMD_RECV_TYPE 3
+ unsigned char *addr;
+ unsigned int addr_len;
+ long msgid;
+ struct ipmi_msg msg;
+};
+
+struct ipmi_cmdspec {
+ unsigned char netfn;
+ unsigned char cmd;
+};
+
+struct ipmi_addr {
+ int addr_type;
+ short channel;
+ unsigned char data[IPMI_MAX_ADDR_SIZE];
+};
+
+struct ipmi_system_interface_addr {
+ int addr_type;
+ short channel;
+ unsigned char lun;
+};
+
+struct ipmi_ipmb_addr {
+ int addr_type;
+ short channel;
+ unsigned char slave_addr;
+ unsigned char lun;
+};
+
+#define IPMICTL_RECEIVE_MSG_TRUNC _IOWR('i', 11, struct ipmi_recv)
+#define IPMICTL_RECEIVE_MSG _IOWR('i', 12, struct ipmi_recv)
+#define IPMICTL_SEND_COMMAND _IOW('i', 13, struct ipmi_req)
+#define IPMICTL_REGISTER_FOR_CMD _IOW('i', 14, struct ipmi_cmdspec)
+#define IPMICTL_UNREGISTER_FOR_CMD _IOW('i', 15, struct ipmi_cmdspec)
+#define IPMICTL_SET_GETS_EVENTS_CMD _IOW('i', 16, int)
+#define IPMICTL_SET_MY_ADDRESS_CMD _IOW('i', 17, unsigned int)
+#define IPMICTL_GET_MY_ADDRESS_CMD _IOR('i', 18, unsigned int)
+#define IPMICTL_SET_MY_LUN_CMD _IOW('i', 19, unsigned int)
+#define IPMICTL_GET_MY_LUN_CMD _IOR('i', 20, unsigned int)
+
+#endif /* !_SYS_IPMI_H_ */
Index: sys/sys/Makefile
===================================================================
RCS file: /cvsroot/src/sys/sys/Makefile,v
retrieving revision 1.169
diff -p -u -r1.169 Makefile
--- sys/sys/Makefile 23 Feb 2019 03:10:06 -0000 1.169
+++ sys/sys/Makefile 6 May 2019 05:57:10 -0000
@@ -23,7 +23,7 @@ INCS= acct.h agpio.h aio.h ansi.h aout_m
fcntl.h fd_set.h fdio.h featuretest.h file.h filedesc.h filio.h \
flashio.h float_ieee754.h fstypes.h gcq.h gmon.h gpio.h hash.h \
idtype.h ieee754.h intr.h intrio.h inttypes.h ioccom.h ioctl.h \
- ioctl_compat.h iostat.h ipc.h \
+ ioctl_compat.h iostat.h ipc.h ipmi.h \
joystick.h \
kcore.h kcov.h kcpuset.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \
localcount.h localedef.h lock.h lockf.h lua.h lwp.h lwpctl.h \
Index: distrib/sets/lists/comp/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/comp/mi,v
retrieving revision 1.2272
diff -p -u -r1.2272 mi
--- distrib/sets/lists/comp/mi 27 Apr 2019 23:04:31 -0000 1.2272
+++ distrib/sets/lists/comp/mi 6 May 2019 05:57:15 -0000
@@ -3016,6 +3016,7 @@
./usr/include/sys/ioctl_compat.h comp-c-include
./usr/include/sys/iostat.h comp-c-include
./usr/include/sys/ipc.h comp-c-include
+./usr/include/sys/ipmi.h comp-c-include
./usr/include/sys/joystick.h comp-c-include
./usr/include/sys/kcore.h comp-c-include
./usr/include/sys/kcov.h comp-c-include