Update: merged 3 changes from Jonathan Matthew. Other things remain. See [1] for details.
- Don't check threashold in this driver; fix false positive warnings. - Handle disabled sensors, but allow them to supply readings if they want. - Make command taskq MP-safe. Masao [1] https://github.com/uebayasi/openbsd-ipmi Index: sys/arch/amd64/amd64/conf.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/conf.c,v retrieving revision 1.52 diff -u -p -r1.52 conf.c --- sys/arch/amd64/amd64/conf.c 13 Nov 2015 07:52:20 -0000 1.52 +++ sys/arch/amd64/amd64/conf.c 18 Dec 2015 12:07:54 -0000 @@ -182,6 +182,7 @@ cdev_decl(pci); #include "vscsi.h" #include "pppx.h" #include "fuse.h" +#include "ipmi.h" struct cdevsw cdevsw[] = { @@ -291,6 +292,7 @@ struct cdevsw cdevsw[] = cdev_pppx_init(NPPPX,pppx), /* 91: pppx */ cdev_fuse_init(NFUSE,fuse), /* 92: fuse */ cdev_tun_init(NTUN,tap), /* 93: Ethernet network tunnel */ + cdev_ipmi_init(NIPMI,ipmi), /* 94: ipmi */ }; int nchrdev = nitems(cdevsw); Index: sys/dev/ipmi.c =================================================================== RCS file: /cvs/src/sys/dev/ipmi.c,v retrieving revision 1.77 diff -u -p -r1.77 ipmi.c --- sys/dev/ipmi.c 8 Sep 2015 11:58:58 -0000 1.77 +++ sys/dev/ipmi.c 18 Dec 2015 12:07:54 -0000 @@ -31,20 +31,21 @@ #include <sys/systm.h> #include <sys/kernel.h> #include <sys/device.h> +#include <sys/ioctl.h> #include <sys/extent.h> -#include <sys/timeout.h> #include <sys/sensors.h> #include <sys/malloc.h> #include <sys/kthread.h> +#include <sys/task.h> #include <machine/bus.h> -#include <machine/intr.h> #include <machine/smbiosvar.h> #include <dev/isa/isareg.h> #include <dev/isa/isavar.h> #include <dev/ipmivar.h> +#include <dev/ipmi_linux.h> struct ipmi_sensor { u_int8_t *i_sdr; @@ -55,8 +56,12 @@ struct ipmi_sensor { SLIST_ENTRY(ipmi_sensor) list; }; -int ipmi_nintr; -int ipmi_poll = 1; +struct ipmi_stats { + int ncmds; + int ntickles; + int nioctls; +} ipmi_stats; + int ipmi_enabled = 0; #define SENSOR_REFRESH_RATE (5 * hz) @@ -112,6 +117,7 @@ int ipmi_enabled = 0; #define IPMI_ENTITY_PWRSUPPLY 0x0A #define IPMI_INVALID_SENSOR (1L << 5) +#define IPMI_DISABLED_SENSOR (1L << 6) #define IPMI_SDR_TYPEFULL 1 #define IPMI_SDR_TYPECOMPACT 2 @@ -139,8 +145,6 @@ SLIST_HEAD(ipmi_sensors_head, ipmi_senso struct ipmi_sensors_head ipmi_sensor_list = SLIST_HEAD_INITIALIZER(ipmi_sensor_list); -struct timeout ipmi_timeout; - void dumpb(const char *, int, const u_int8_t *); int read_sensor(struct ipmi_softc *, struct ipmi_sensor *); @@ -149,16 +153,25 @@ int get_sdr_partial(struct ipmi_softc *, u_int8_t, u_int8_t, void *, u_int16_t *); int get_sdr(struct ipmi_softc *, u_int16_t, u_int16_t *); -int ipmi_sendcmd(struct ipmi_softc *, int, int, int, int, int, const void*); -int ipmi_recvcmd(struct ipmi_softc *, int, int *, void *); -void ipmi_delay(struct ipmi_softc *, int); +int ipmi_sendcmd(struct ipmi_cmd *); +int ipmi_recvcmd(struct ipmi_cmd *); +void ipmi_cmd(struct ipmi_cmd *); +void ipmi_cmd_poll(struct ipmi_cmd *); +void ipmi_cmd_wait(struct ipmi_cmd *); +void ipmi_cmd_wait_cb(void *); int ipmi_watchdog(void *, int); +void ipmi_watchdog_tickle(void *); +void ipmi_watchdog_set(void *); -int ipmi_intr(void *); int ipmi_match(struct device *, void *, void *); void ipmi_attach(struct device *, struct device *, void *); int ipmi_activate(struct device *, int); +struct ipmi_softc *ipmilookup(dev_t dev); + +int ipmiopen(dev_t, int, int, struct proc *); +int ipmiclose(dev_t, int, int, struct proc *); +int ipmiioctl(dev_t, u_long, caddr_t, int, struct proc *); long ipow(long, int); long ipmi_convert(u_int8_t, struct sdrtype1 *, long); @@ -167,13 +180,10 @@ void ipmi_sensor_name(char *, int, u_int /* BMC Helper Functions */ u_int8_t bmc_read(struct ipmi_softc *, int); void bmc_write(struct ipmi_softc *, int, u_int8_t); -int bmc_io_wait(struct ipmi_softc *, int, u_int8_t, u_int8_t, const char *); -int bmc_io_wait_cold(struct ipmi_softc *, int, u_int8_t, u_int8_t, - const char *); -void _bmc_io_wait(void *); +int bmc_io_wait(struct ipmi_softc *); -void *bt_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *); -void *cmn_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *); +void bt_buildmsg(struct ipmi_cmd *); +void cmn_buildmsg(struct ipmi_cmd *); int getbits(u_int8_t *, int, int); int ipmi_sensor_type(int, int, int); @@ -185,7 +195,6 @@ void ipmi_unmap_regs(struct ipmi_softc * void *scan_sig(long, long, int, int, const void *); -int ipmi_test_threshold(u_int8_t, u_int8_t, u_int8_t, u_int8_t, int); int ipmi_sensor_status(struct ipmi_softc *, struct ipmi_sensor *, u_int8_t *); @@ -200,6 +209,8 @@ struct ipmi_if kcs_if = { kcs_recvmsg, kcs_reset, kcs_probe, + IPMI_MSG_DATASND, + IPMI_MSG_DATARCV, }; struct ipmi_if smic_if = { @@ -210,6 +221,8 @@ struct ipmi_if smic_if = { smic_recvmsg, smic_reset, smic_probe, + IPMI_MSG_DATASND, + IPMI_MSG_DATARCV, }; struct ipmi_if bt_if = { @@ -220,6 +233,8 @@ struct ipmi_if bt_if = { bt_recvmsg, bt_reset, bt_probe, + IPMI_BTMSG_DATASND, + IPMI_BTMSG_DATARCV, }; struct ipmi_if *ipmi_get_if(int); @@ -256,78 +271,23 @@ bmc_write(struct ipmi_softc *sc, int off offset * sc->sc_if_iospacing, val); } -void -_bmc_io_wait(void *arg) -{ - struct ipmi_softc *sc = arg; - struct ipmi_bmc_args *a = sc->sc_iowait_args; - - *a->v = bmc_read(sc, a->offset); - if ((*a->v & a->mask) == a->value) { - sc->sc_wakeup = 0; - wakeup(sc); - return; - } - - if (++sc->sc_retries > sc->sc_max_retries) { - sc->sc_wakeup = 0; - wakeup(sc); - return; - } - - timeout_add(&sc->sc_timeout, 1); -} - int -bmc_io_wait(struct ipmi_softc *sc, int offset, u_int8_t mask, u_int8_t value, - const char *lbl) -{ - volatile u_int8_t v; - struct ipmi_bmc_args args; - - if (cold || sc->sc_poll) - return (bmc_io_wait_cold(sc, offset, mask, value, lbl)); - - sc->sc_retries = 0; - sc->sc_wakeup = 1; - - args.offset = offset; - args.mask = mask; - args.value = value; - args.v = &v; - sc->sc_iowait_args = &args; - - _bmc_io_wait(sc); - - while (sc->sc_wakeup) - tsleep(sc, PWAIT, lbl, 0); - - if (sc->sc_retries > sc->sc_max_retries) { - dbg_printf(1, "%s: bmc_io_wait fails : v=%.2x m=%.2x " - "b=%.2x %s\n", DEVNAME(sc), v, mask, value, lbl); - return (-1); - } - - return (v); -} - -int -bmc_io_wait_cold(struct ipmi_softc *sc, int offset, u_int8_t mask, - u_int8_t value, const char *lbl) +bmc_io_wait(struct ipmi_softc *sc) { + struct ipmi_iowait *a = sc->sc_cmd_iowait; volatile u_int8_t v; int count = 5000000; /* == 5s XXX can be shorter */ while (count--) { - v = bmc_read(sc, offset); - if ((v & mask) == value) + v = bmc_read(sc, a->offset); + if ((v & a->mask) == a->value) return v; delay(1); } - dbg_printf(1, "%s: bmc_io_wait_cold fails : *v=%.2x m=%.2x b=%.2x %s\n", - DEVNAME(sc), v, mask, value, lbl); + dbg_printf(1, "%s: bmc_io_wait fails : *v=%.2x m=%.2x b=%.2x %s\n", + DEVNAME(sc), v, a->mask, a->value, a->lbl); return (-1); } @@ -369,7 +329,13 @@ bt_read(struct ipmi_softc *sc, int reg) int bt_write(struct ipmi_softc *sc, int reg, uint8_t data) { - if (bmc_io_wait(sc, _BT_CTRL_REG, BT_BMC_BUSY, 0, "bt_write") < 0) + struct ipmi_iowait *a = sc->sc_cmd_iowait; + + a->offset = _BT_CTRL_REG; + a->mask = BT_BMC_BUSY; + a->value = 0; + a->lbl = "bt_write"; + if (bmc_io_wait(sc) < 0) return (-1); bmc_write(sc, reg, data); @@ -377,42 +343,52 @@ bt_write(struct ipmi_softc *sc, int reg, } int -bt_sendmsg(struct ipmi_softc *sc, int len, const u_int8_t *data) +bt_sendmsg(struct ipmi_cmd *c) { + struct ipmi_softc *sc = c->c_sc; + struct ipmi_iowait *a = sc->sc_cmd_iowait; 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]); + for (i = 0; i < c->c_txlen; i++) + bt_write(sc, _BT_DATAOUT_REG, sc->sc_buf[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, - "bt_sendwait") < 0) + a->offset = _BT_CTRL_REG; + a->mask = BT_HOST2BMC_ATN | BT_BMC_BUSY; + a->value = 0; + a->lbl = "bt_sendwait"; + if (bmc_io_wait(sc) < 0) return (-1); return (0); } int -bt_recvmsg(struct ipmi_softc *sc, int maxlen, int *rxlen, u_int8_t *data) +bt_recvmsg(struct ipmi_cmd *c) { - u_int8_t len, v, i; - - if (bmc_io_wait(sc, _BT_CTRL_REG, BT_BMC2HOST_ATN, BT_BMC2HOST_ATN, - "bt_recvwait") < 0) + struct ipmi_softc *sc = c->c_sc; + struct ipmi_iowait *a = sc->sc_cmd_iowait; + u_int8_t len, v, i, j; + + a->offset = _BT_CTRL_REG; + a->mask = BT_BMC2HOST_ATN; + a->value = BT_BMC2HOST_ATN; + a->lbl = "bt_recvwait"; + if (bmc_io_wait(sc) < 0) return (-1); 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++) { + for (i = IPMI_BTMSG_NFLN, j = 0; i <= len; i++) { v = bt_read(sc, _BT_DATAIN_REG); if (i != IPMI_BTMSG_SEQ) - *(data++) = v; + *(sc->sc_buf + j++) = v; } bt_write(sc, _BT_CTRL_REG, BT_HOST_BUSY); - *rxlen = len - 1; + c->c_rxlen = len - 1; return (0); } @@ -490,10 +466,15 @@ int smic_read_data(struct ipmi_softc *, int smic_wait(struct ipmi_softc *sc, u_int8_t mask, u_int8_t val, const char *lbl) { + struct ipmi_iowait *a = sc->sc_cmd_iowait; int v; /* Wait for expected flag bits */ - v = bmc_io_wait(sc, _SMIC_FLAG_REG, mask, val, "smicwait"); + a->offset = _SMIC_FLAG_REG; + a->mask = mask; + a->value = val; + a->lbl = "smicwait"; + v = bmc_io_wait(sc); if (v < 0) return (-1); @@ -542,20 +523,21 @@ smic_read_data(struct ipmi_softc *sc, u_ #define ErrStat(a,b) if (a) printf(b); int -smic_sendmsg(struct ipmi_softc *sc, int len, const u_int8_t *data) +smic_sendmsg(struct ipmi_cmd *c) { + struct ipmi_softc *sc = c->c_sc; int sts, idx; - sts = smic_write_cmd_data(sc, SMS_CC_START_TRANSFER, &data[0]); + sts = smic_write_cmd_data(sc, SMS_CC_START_TRANSFER, &sc->sc_buf[0]); ErrStat(sts != SMS_SC_WRITE_START, "wstart"); - for (idx = 1; idx < len - 1; idx++) { + for (idx = 1; idx < c->c_txlen - 1; idx++) { sts = smic_write_cmd_data(sc, SMS_CC_NEXT_TRANSFER, - &data[idx]); + &sc->sc_buf[idx]); ErrStat(sts != SMS_SC_WRITE_NEXT, "write"); } - sts = smic_write_cmd_data(sc, SMS_CC_END_TRANSFER, &data[idx]); + sts = smic_write_cmd_data(sc, SMS_CC_END_TRANSFER, &sc->sc_buf[idx]); if (sts != SMS_SC_WRITE_END) { - dbg_printf(50, "smic_sendmsg %d/%d = %.2x\n", idx, len, sts); + dbg_printf(50, "smic_sendmsg %d/%d = %.2x\n", idx, c->c_txlen, sts); return (-1); } @@ -563,11 +545,12 @@ smic_sendmsg(struct ipmi_softc *sc, int } int -smic_recvmsg(struct ipmi_softc *sc, int maxlen, int *len, u_int8_t *data) +smic_recvmsg(struct ipmi_cmd *c) { + struct ipmi_softc *sc = c->c_sc; int sts, idx; - *len = 0; + c->c_rxlen = 0; sts = smic_wait(sc, SMIC_RX_DATA_RDY, SMIC_RX_DATA_RDY, "smic_recvmsg"); if (sts < 0) return (-1); @@ -575,18 +558,18 @@ smic_recvmsg(struct ipmi_softc *sc, int sts = smic_write_cmd_data(sc, SMS_CC_START_RECEIVE, NULL); ErrStat(sts != SMS_SC_READ_START, "rstart"); for (idx = 0;; ) { - sts = smic_read_data(sc, &data[idx++]); + sts = smic_read_data(sc, &sc->sc_buf[idx++]); if (sts != SMS_SC_READ_START && sts != SMS_SC_READ_NEXT) break; smic_write_cmd_data(sc, SMS_CC_NEXT_RECEIVE, NULL); } ErrStat(sts != SMS_SC_READ_END, "rend"); - *len = idx; + c->c_rxlen = idx; sts = smic_write_cmd_data(sc, SMS_CC_END_RECEIVE, NULL); if (sts != SMS_SC_READY) { - dbg_printf(50, "smic_recvmsg %d/%d = %.2x\n", idx, maxlen, sts); + dbg_printf(50, "smic_recvmsg %d/%d = %.2x\n", idx, c->c_maxrxlen, sts); return (-1); } @@ -642,9 +625,14 @@ int kcs_read_data(struct ipmi_softc *, u int kcs_wait(struct ipmi_softc *sc, u_int8_t mask, u_int8_t value, const char *lbl) { + struct ipmi_iowait *a = sc->sc_cmd_iowait; int v; - v = bmc_io_wait(sc, _KCS_STATUS_REGISTER, mask, value, lbl); + a->offset = _KCS_STATUS_REGISTER; + a->mask = mask; + a->value = value; + a->lbl = lbl; + v = bmc_io_wait(sc); if (v < 0) return (v); @@ -704,25 +692,26 @@ kcs_read_data(struct ipmi_softc *sc, u_i /* Exported KCS functions */ int -kcs_sendmsg(struct ipmi_softc *sc, int len, const u_int8_t * data) +kcs_sendmsg(struct ipmi_cmd *c) { + struct ipmi_softc *sc = c->c_sc; int idx, sts; /* ASSERT: IBF is clear */ - dbg_dump(50, "kcs sendmsg", len, data); + dbg_dump(50, "kcs sendmsg", c->c_txlen, sc->sc_buf); sts = kcs_write_cmd(sc, KCS_WRITE_START); - for (idx = 0; idx < len; idx++) { - if (idx == len - 1) + for (idx = 0; idx < c->c_txlen; idx++) { + if (idx == c->c_txlen - 1) sts = kcs_write_cmd(sc, KCS_WRITE_END); if (sts != KCS_WRITE_STATE) break; - sts = kcs_write_data(sc, data[idx]); + sts = kcs_write_data(sc, sc->sc_buf[idx]); } if (sts != KCS_READ_STATE) { - dbg_printf(1, "kcs sendmsg = %d/%d <%.2x>\n", idx, len, sts); - dbg_dump(1, "kcs_sendmsg", len, data); + dbg_printf(1, "kcs sendmsg = %d/%d <%.2x>\n", idx, c->c_txlen, sts); + dbg_dump(1, "kcs_sendmsg", c->c_txlen, sc->sc_buf); return (-1); } @@ -730,23 +719,24 @@ kcs_sendmsg(struct ipmi_softc *sc, int l } int -kcs_recvmsg(struct ipmi_softc *sc, int maxlen, int *rxlen, u_int8_t * data) +kcs_recvmsg(struct ipmi_cmd *c) { + struct ipmi_softc *sc = c->c_sc; int idx, sts; - for (idx = 0; idx < maxlen; idx++) { - sts = kcs_read_data(sc, &data[idx]); + for (idx = 0; idx < c->c_maxrxlen; idx++) { + sts = kcs_read_data(sc, &sc->sc_buf[idx]); if (sts != KCS_READ_STATE) break; } sts = kcs_wait(sc, KCS_IBF, 0, "recv"); - *rxlen = idx; + c->c_rxlen = idx; if (sts != KCS_IDLE_STATE) { - dbg_printf(1, "kcs recvmsg = %d/%d <%.2x>\n", idx, maxlen, sts); + dbg_printf(1, "kcs recvmsg = %d/%d <%.2x>\n", idx, c->c_maxrxlen, sts); return (-1); } - dbg_dump(50, "kcs recvmsg", idx, data); + dbg_dump(50, "kcs recvmsg", idx, sc->sc_buf); return (0); } @@ -935,74 +925,54 @@ ipmi_smbios_probe(struct smbios_ipmi *pi /* * 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 */ -void * -bt_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len, - const void *data, int *txlen) +void +bt_buildmsg(struct ipmi_cmd *c) { - u_int8_t *buf; + struct ipmi_softc *sc = c->c_sc; + u_int8_t *buf = sc->sc_buf; + int nfLun = NETFN_LUN(c->c_netfn, c->c_rslun); /* Block transfer needs 4 extra bytes: length/netfn/seq/cmd + data */ - *txlen = len + 4; - buf = malloc(*txlen, M_DEVBUF, M_NOWAIT); - if (buf == NULL) - return (NULL); - - buf[IPMI_BTMSG_LEN] = len + 3; + buf[IPMI_BTMSG_LEN] = c->c_txlen + (IPMI_BTMSG_DATASND - 1); 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); - - return (buf); + buf[IPMI_BTMSG_CMD] = c->c_cmd; + if (c->c_txlen && c->c_data) + memcpy(buf + IPMI_BTMSG_DATASND, c->c_data, c->c_txlen); } /* * 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 */ -void * -cmn_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len, - const void *data, int *txlen) +void +cmn_buildmsg(struct ipmi_cmd *c) { - u_int8_t *buf; + struct ipmi_softc *sc = c->c_sc; + u_int8_t *buf = sc->sc_buf; + int nfLun = NETFN_LUN(c->c_netfn, c->c_rslun); /* Common needs two extra bytes: nfLun/cmd + data */ - *txlen = len + 2; - buf = malloc(*txlen, M_DEVBUF, M_NOWAIT); - if (buf == NULL) - return (NULL); - buf[IPMI_MSG_NFLN] = nfLun; - buf[IPMI_MSG_CMD] = cmd; - if (len && data) - memcpy(buf + IPMI_MSG_DATASND, data, len); - - return (buf); + buf[IPMI_MSG_CMD] = c->c_cmd; + if (c->c_txlen && c->c_data) + memcpy(buf + IPMI_MSG_DATASND, c->c_data, c->c_txlen); } /* Send an IPMI command */ int -ipmi_sendcmd(struct ipmi_softc *sc, int rssa, int rslun, int netfn, int cmd, - int txlen, const void *data) +ipmi_sendcmd(struct ipmi_cmd *c) { - u_int8_t *buf; + struct ipmi_softc *sc = c->c_sc; int rc = -1; dbg_printf(50, "ipmi_sendcmd: rssa=%.2x nfln=%.2x cmd=%.2x len=%.2x\n", - rssa, NETFN_LUN(netfn, rslun), cmd, txlen); - dbg_dump(10, " send", txlen, data); - if (rssa != BMC_SA) { + c->c_rssa, NETFN_LUN(c->c_netfn, c->c_rslun), c->c_cmd, c->c_txlen); + dbg_dump(10, " send", c->c_txlen, c->c_data); + if (c->c_rssa != BMC_SA) { #if 0 - buf = sc->sc_if->buildmsg(sc, NETFN_LUN(APP_NETFN, BMC_LUN), - APP_SEND_MESSAGE, 7 + txlen, NULL, &txlen); + sc->sc_if->buildmsg(c); pI2C->bus = (sc->if_ver == 0x09) ? PUBLIC_BUS : IPMB_CHANNEL_NUMBER; @@ -1020,44 +990,32 @@ ipmi_sendcmd(struct ipmi_softc *sc, int #endif goto done; } else - buf = sc->sc_if->buildmsg(sc, NETFN_LUN(netfn, rslun), cmd, - txlen, data, &txlen); - - if (buf == NULL) { - printf("%s: sendcmd malloc fails\n", DEVNAME(sc)); - goto done; - } - rc = sc->sc_if->sendmsg(sc, txlen, buf); - free(buf, M_DEVBUF, txlen); + sc->sc_if->buildmsg(c); - ipmi_delay(sc, 5); /* give bmc chance to digest command */ + c->c_txlen += sc->sc_if->datasnd; + rc = sc->sc_if->sendmsg(c); done: return (rc); } +/* Receive an IPMI command */ int -ipmi_recvcmd(struct ipmi_softc *sc, int maxlen, int *rxlen, void *data) +ipmi_recvcmd(struct ipmi_cmd *c) { - u_int8_t *buf, rc = 0; - int rawlen; + struct ipmi_softc *sc = c->c_sc; + u_int8_t *buf = sc->sc_buf, rc = 0; - /* Need three extra bytes: netfn/cmd/ccode + data */ - buf = malloc(maxlen + 3, M_DEVBUF, M_NOWAIT); - if (buf == NULL) { - printf("%s: ipmi_recvcmd: malloc fails\n", DEVNAME(sc)); - return (-1); - } /* Receive message from interface, copy out result data */ - if (sc->sc_if->recvmsg(sc, maxlen + 3, &rawlen, buf) || - rawlen < IPMI_MSG_DATARCV) { - free(buf, M_DEVBUF, maxlen + 3); + c->c_maxrxlen += sc->sc_if->datarcv; + if (sc->sc_if->recvmsg(c) || + c->c_rxlen < sc->sc_if->datarcv) { return (-1); } - *rxlen = rawlen - IPMI_MSG_DATARCV; - if (*rxlen > 0 && data) - memcpy(data, buf + IPMI_MSG_DATARCV, *rxlen); + c->c_rxlen -= sc->sc_if->datarcv; + if (c->c_rxlen > 0 && c->c_data) + memcpy(c->c_data, buf + sc->sc_if->datarcv, c->c_rxlen); rc = buf[IPMI_MSG_CCODE]; #ifdef IPMI_DEBUG @@ -1068,25 +1026,65 @@ ipmi_recvcmd(struct ipmi_softc *sc, int dbg_printf(50, "ipmi_recvcmd: nfln=%.2x cmd=%.2x err=%.2x len=%.2x\n", buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE], - *rxlen); - dbg_dump(10, " recv", *rxlen, data); - - free(buf, M_DEVBUF, maxlen + 3); - - ipmi_delay(sc, 5); /* give bmc chance to digest command */ + c->c_rxlen); + dbg_dump(10, " recv", c->c_rxlen, c->c_data); return (rc); } void -ipmi_delay(struct ipmi_softc *sc, int period) +ipmi_cmd(struct ipmi_cmd *c) { - /* period is in 10 ms increments */ - if (cold || sc->sc_poll) - delay(period * 10000); + if (cold || panicstr != NULL) + ipmi_cmd_poll(c); else - while (tsleep(sc, PWAIT, "ipmicmd", period) != EWOULDBLOCK) - continue; + ipmi_cmd_wait(c); +} + +void +ipmi_cmd_poll(struct ipmi_cmd *c) +{ + struct ipmi_iowait iowait; + + mtx_enter(&c->c_sc->sc_cmd_mtx); + + c->c_sc->sc_cmd = c; + c->c_sc->sc_cmd_iowait = &iowait; + if (ipmi_sendcmd(c)) { + panic("%s: sendcmd fails", DEVNAME(c->c_sc)); + } + c->c_ccode = ipmi_recvcmd(c); + c->c_sc->sc_cmd = NULL; + c->c_sc->sc_cmd_iowait = NULL; + + ipmi_stats.ncmds++; + + mtx_leave(&c->c_sc->sc_cmd_mtx); +} + +void +ipmi_cmd_wait(struct ipmi_cmd *c) +{ + struct task t; + int res; + + task_set(&t, ipmi_cmd_wait_cb, c); + res = task_add(c->c_sc->sc_cmd_taskq, &t); + KASSERT(res == 1); + + tsleep(c, PWAIT, "ipmicmd", 0); + + res = task_del(c->c_sc->sc_cmd_taskq, &t); + KASSERT(res == 0); +} + +void +ipmi_cmd_wait_cb(void *arg) +{ + struct ipmi_cmd *c = arg; + + ipmi_cmd_poll(c); + wakeup(c); } /* Read a partial SDR entry */ @@ -1101,18 +1099,24 @@ get_sdr_partial(struct ipmi_softc *sc, u ((u_int16_t *) cmd)[1] = recordId; cmd[4] = offset; cmd[5] = length; - if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_GET_SDR, 6, - cmd)) { - printf("%s: sendcmd fails\n", DEVNAME(sc)); - return (-1); - } - if (ipmi_recvcmd(sc, 8 + length, &len, cmd)) { - printf("%s: getSdrPartial: recvcmd fails\n", DEVNAME(sc)); - return (-1); - } + + struct ipmi_cmd c; + c.c_sc = sc; + c.c_rssa = BMC_SA; + c.c_rslun = BMC_LUN; + c.c_netfn = STORAGE_NETFN; + c.c_cmd = STORAGE_GET_SDR; + c.c_txlen = 6; + c.c_maxrxlen = 8 + length; + c.c_rxlen = 0; + c.c_data = cmd; + ipmi_cmd(&c); + len = c.c_rxlen; + if (nxtRecordId) *nxtRecordId = *(uint16_t *) cmd; - memcpy(buffer, cmd + 2, len - 2); + if (len > 2) + memcpy(buffer, cmd + 2, len - 2); return (0); } @@ -1129,15 +1133,18 @@ get_sdr(struct ipmi_softc *sc, u_int16_t struct sdrhdr shdr; /* Reserve SDR */ - if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_RESERVE_SDR, - 0, NULL)) { - printf("%s: reserve send fails\n", DEVNAME(sc)); - return (1); - } - if (ipmi_recvcmd(sc, sizeof(resid), &len, &resid)) { - printf("%s: reserve recv fails\n", DEVNAME(sc)); - return (1); - } + struct ipmi_cmd c; + c.c_sc = sc; + c.c_rssa = BMC_SA; + c.c_rslun = BMC_LUN; + c.c_netfn = STORAGE_NETFN; + c.c_cmd = STORAGE_RESERVE_SDR; + c.c_txlen = 0; + c.c_maxrxlen = sizeof(resid); + c.c_rxlen = 0; + c.c_data = &resid; + ipmi_cmd(&c); + /* Get SDR Header */ if (get_sdr_partial(sc, recid, resid, 0, sizeof shdr, &shdr, nxtrec)) { printf("%s: get header fails\n", DEVNAME(sc)); @@ -1291,26 +1298,11 @@ ipmi_convert(u_int8_t v, struct sdrtype1 } int -ipmi_test_threshold(u_int8_t v, u_int8_t valid, u_int8_t hi, u_int8_t lo, - int sign) -{ - dbg_printf(10, "thresh: %.2x %.2x %.2x %d %d\n", v, lo, hi,valid, sign); - if (sign) - return ((valid & 1 && lo != 0x00 && (int8_t)v <= (int8_t)lo) || - (valid & 8 && hi != 0xFF && (int8_t)v >= (int8_t)hi)); - - return ((valid & 1 && lo != 0x00 && v <= lo) || - (valid & 8 && hi != 0xFF && v >= hi)); -} - -int ipmi_sensor_status(struct ipmi_softc *sc, struct ipmi_sensor *psensor, u_int8_t *reading) { - u_int8_t data[32]; struct sdrtype1 *s1 = (struct sdrtype1 *)psensor->i_sdr; - int rxlen, etype; - int sign = s1->units1 >> 7 & 1; + int etype; /* Get reading of sensor */ switch (psensor->i_sensor.type) { @@ -1338,28 +1330,12 @@ ipmi_sensor_status(struct ipmi_softc *sc case IPMI_SENSOR_TYPE_TEMP: case IPMI_SENSOR_TYPE_VOLT: case IPMI_SENSOR_TYPE_FAN: - data[0] = psensor->i_num; - if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun, - SE_NETFN, SE_GET_SENSOR_THRESHOLD, 1, data) || - ipmi_recvcmd(sc, sizeof(data), &rxlen, data)) - return (SENSOR_S_UNKNOWN); - - dbg_printf(25, "recvdata: %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", - data[0], data[1], data[2], data[3], data[4], data[5], - data[6]); - - if (ipmi_test_threshold(*reading, data[0] >> 2 , - data[6], data[3], sign)) + if (reading[2] & ((1 << 5) | (1 << 2))) return (SENSOR_S_CRIT); - - if (ipmi_test_threshold(*reading, data[0] >> 1, - data[5], data[2], sign)) + else if (reading[2] & ((1 << 4) | (1 << 1))) return (SENSOR_S_CRIT); - - if (ipmi_test_threshold(*reading, data[0] , - data[4], data[1], sign)) + else if (reading[2] & ((1 << 3) | (1 << 0))) return (SENSOR_S_WARN); - break; case IPMI_SENSOR_TYPE_INTRUSION: @@ -1394,32 +1370,31 @@ read_sensor(struct ipmi_softc *sc, struc { struct sdrtype1 *s1 = (struct sdrtype1 *) psensor->i_sdr; u_int8_t data[8]; - int rxlen, rv = -1; - - if (!cold) - rw_enter_write(&sc->sc_lock); + int rv = -1; memset(data, 0, sizeof(data)); data[0] = psensor->i_num; - if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun, SE_NETFN, - SE_GET_SENSOR_READING, 1, data)) - goto done; - if (ipmi_recvcmd(sc, sizeof(data), &rxlen, data)) - goto done; + struct ipmi_cmd c; + c.c_sc = sc; + c.c_rssa = s1->owner_id; + c.c_rslun = s1->owner_lun; + c.c_netfn = SE_NETFN; + c.c_cmd = SE_GET_SENSOR_READING; + c.c_txlen = 1; + c.c_maxrxlen = sizeof(data); + c.c_rxlen = 0; + c.c_data = data; + ipmi_cmd(&c); dbg_printf(10, "values=%.2x %.2x %.2x %.2x %s\n", data[0],data[1],data[2],data[3], psensor->i_sensor.desc); psensor->i_sensor.flags &= ~SENSOR_FINVALID; - if (data[1] & IPMI_INVALID_SENSOR) { - /* Check if sensor is valid */ + if ((data[1] & IPMI_INVALID_SENSOR) || + ((data[1] & IPMI_DISABLED_SENSOR) == 0 && data[0] == 0)) psensor->i_sensor.flags |= SENSOR_FINVALID; - } psensor->i_sensor.status = ipmi_sensor_status(sc, psensor, data); rv = 0; -done: - if (!cold) - rw_exit_write(&sc->sc_lock); return (rv); } @@ -1530,27 +1505,10 @@ add_child_sensors(struct ipmi_softc *sc, return (1); } -/* Interrupt handler */ -int -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; - - return (0); -} - /* Handle IPMI Timer - reread sensor values */ void ipmi_refresh_sensors(struct ipmi_softc *sc) { - if (!ipmi_poll) - return; - if (SLIST_EMPTY(&ipmi_sensor_list)) return; @@ -1588,11 +1546,6 @@ ipmi_map_regs(struct ipmi_softc *sc, str sc->sc_if->nregs * sc->sc_if_iospacing, &sc->sc_ioh); return (-1); } -#if 0 - if (iaa->if_if_irq != -1) - sc->ih = isa_intr_establish(-1, iaa->if_if_irq, - iaa->if_irqlvl, IPL_BIO, ipmi_intr, sc, DEVNAME(sc)); -#endif return (0); } @@ -1607,7 +1560,7 @@ void ipmi_poll_thread(void *arg) { struct ipmi_thread *thread = arg; - struct ipmi_softc *sc = thread->sc; + struct ipmi_softc *sc = thread->sc; u_int16_t rec; /* Scan SDRs, add sensors */ @@ -1687,7 +1640,6 @@ ipmi_match(struct device *parent, void * struct ipmi_attach_args *ia = aux; struct cfdata *cf = match; u_int8_t cmd[32]; - int len; int rv = 0; if (strcmp(ia->iaa_name, cf->cf_driver->cd_name)) @@ -1695,24 +1647,26 @@ ipmi_match(struct device *parent, void * /* XXX local softc is wrong wrong wrong */ strlcpy(sc.sc_dev.dv_xname, "ipmi0", sizeof(sc.sc_dev.dv_xname)); + mtx_init(&sc.sc_cmd_mtx, IPL_NONE); + /* Map registers */ if (ipmi_map_regs(&sc, ia) == 0) { sc.sc_if->probe(&sc); /* Identify BMC device early to detect lying bios */ - if (ipmi_sendcmd(&sc, BMC_SA, 0, APP_NETFN, APP_GET_DEVICE_ID, - 0, NULL)) { - dbg_printf(1, ": unable to send get device id " - "command\n"); - goto unmap; - } - if (ipmi_recvcmd(&sc, sizeof(cmd), &len, cmd)) { - dbg_printf(1, ": unable to retrieve device id\n"); - goto unmap; - } + struct ipmi_cmd c; + c.c_sc = ≻ + c.c_rssa = BMC_SA; + c.c_rslun = BMC_LUN; + c.c_netfn = APP_NETFN; + c.c_cmd = APP_GET_DEVICE_ID; + c.c_txlen = 0; + c.c_maxrxlen = sizeof(cmd); + c.c_rxlen = 0; + c.c_data = cmd; + ipmi_cmd(&c); - dbg_dump(1, "bmc data", len, cmd); -unmap: + dbg_dump(1, "bmc data", c.c_rxlen, cmd); rv = 1; /* GETID worked, we got IPMI */ ipmi_unmap_regs(&sc); } @@ -1725,6 +1679,8 @@ ipmi_attach(struct device *parent, struc { struct ipmi_softc *sc = (void *) self; struct ipmi_attach_args *ia = aux; + struct ipmi_cmd *c = &sc->sc_ioctl.cmd; + int i; /* Map registers */ ipmi_map_regs(sc, ia); @@ -1753,16 +1709,27 @@ ipmi_attach(struct device *parent, struc /* Setup Watchdog timer */ sc->sc_wdog_period = 0; + for (i = 0; i < IPMI_WDOG_TICKLE_NTASKS; i++) + task_set(&sc->sc_wdog_tickle_tasks[i], ipmi_watchdog_tickle, sc); + sc->sc_wdog_tickle_cnt = 0; wdog_register(ipmi_watchdog, sc); - /* lock around read_sensor so that no one messes with the bmc regs */ - rw_init(&sc->sc_lock, DEVNAME(sc)); + rw_init(&sc->sc_ioctl.lock, DEVNAME(sc)); + sc->sc_ioctl.req.msgid = -1; - /* setup ticker */ - sc->sc_retries = 0; - sc->sc_wakeup = 0; - sc->sc_max_retries = 50; /* 50 * 1/100 = 0.5 seconds max */ - timeout_set(&sc->sc_timeout, _bmc_io_wait, sc); + c->c_sc = sc; + c->c_rssa = -1; + c->c_rslun = -1; + c->c_netfn = -1; + c->c_cmd = -1; + c->c_txlen = -1; + c->c_rxlen = -1; + c->c_ccode = -1; + + sc->sc_cmd = NULL; + sc->sc_cmd_iowait = NULL; + sc->sc_cmd_taskq = taskq_create("ipmicmd", 1, IPL_NONE, TASKQ_MPSAFE); + mtx_init(&sc->sc_cmd_mtx, IPL_NONE); } int @@ -1777,52 +1744,251 @@ ipmi_activate(struct device *self, int a return (0); } +struct ipmi_softc * +ipmilookup(dev_t dev) +{ + return (struct ipmi_softc *)device_lookup(&ipmi_cd, minor(dev)); +} + +int +ipmiopen(dev_t dev, int flags, int mode, struct proc *p) +{ + return (0); +} + +int +ipmiclose(dev_t dev, int flags, int mode, struct proc *p) +{ + return (0); +} + +int +ipmiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *proc) +{ + struct ipmi_softc *sc = ipmilookup(dev); + struct ipmi_req *req = (struct ipmi_req *)data; + struct ipmi_recv *recv = (struct ipmi_recv *)data; + struct ipmi_cmd *c = &sc->sc_ioctl.cmd; + int len; + u_char ccode; + int rc = 0; + uint8_t buf[IPMI_MAX_RX]; + + if (sc == NULL) + return (ENXIO); + +#ifdef IPMICTL_SEND_COMMAND_32 + switch (cmd) { + case IPMICTL_SEND_COMMAND_32: + case IPMICTL_RECEIVE_MSG_TRUNC_32: + case IPMICTL_RECEIVE_MSG_32: + break; + } +#endif + + rw_enter_write(&sc->sc_ioctl.lock); + + c->c_maxrxlen = sizeof(buf); + c->c_data = buf; + + switch (cmd) { +#ifdef IPMICTL_SEND_COMMAND_32 + case IPMICTL_SEND_COMMAND_32: +#endif + case IPMICTL_SEND_COMMAND: + if (req->msgid == -1) { + rc = EINVAL; // XXX + goto reset; + } + if (sc->sc_ioctl.req.msgid != -1) { + rc = EBUSY; + goto reset; + } + len = req->msg.data_len; + if (len > c->c_maxrxlen) { + rc = E2BIG; // XXX + goto reset; + } + sc->sc_ioctl.req = *req; + rc = copyin(req->msg.data, c->c_data, len); + if (rc != 0) + goto reset; + + /* Execute a command synchronously. */ + /* c_sc is constant */ + /* c_rssa is set by IPMICTL_SET_MY_ADDRESS_CMD */ + /* c_rslun is set by IPMICTL_SET_MY_LUN_CMD */ + c->c_netfn = req->msg.netfn; + c->c_cmd = req->msg.cmd; + c->c_txlen = req->msg.data_len; + /* c_maxrxlen is constant */ + c->c_rxlen = 0; + /* c_data is constant */ + c->c_ccode = -1; + ipmi_cmd(c); + + /* c_sc is constant */ + /* c_rssa is set by IPMICTL_SET_MY_ADDRESS_CMD */ + /* c_rslun is set by IPMICTL_SET_MY_LUN_CMD */ + c->c_netfn = -1; + c->c_cmd = -1; + c->c_txlen = -1; + /* c_maxrxlen is constant */ + /* c_rxlen is saved for IPMICTL_RECEIVE_MSG */ + /* c_data is constant */ + /* c_ccode is saved for IPMICTL_RECEIVE_MSG */ + break; +#ifdef IPMICTL_SEND_COMMAND_32 + case IPMICTL_RECEIVE_MSG_TRUNC_32: + case IPMICTL_RECEIVE_MSG_32: +#endif + case IPMICTL_RECEIVE_MSG_TRUNC: + case IPMICTL_RECEIVE_MSG: + if (sc->sc_ioctl.req.msgid == -1) { + rc = EINVAL; + goto reset; + } + if (c->c_ccode == -1) { + rc = EAGAIN; + goto reset; + } + ccode = c->c_ccode & 0xff; + rc = copyout(&ccode, recv->msg.data, 1); + + /* Return a command result. */ + recv->recv_type = IPMI_RESPONSE_RECV_TYPE; + recv->msgid = sc->sc_ioctl.req.msgid; + recv->msg.netfn = sc->sc_ioctl.req.msg.netfn; + recv->msg.cmd = sc->sc_ioctl.req.msg.cmd; + recv->msg.data_len = c->c_rxlen + 1; + + rc = copyout(c->c_data, recv->msg.data + 1, c->c_rxlen); + goto reset; + case IPMICTL_SET_MY_ADDRESS_CMD: + c->c_rssa = *(int *)data; + break; + case IPMICTL_GET_MY_ADDRESS_CMD: + *(int *)data = c->c_rssa; + break; + case IPMICTL_SET_MY_LUN_CMD: + c->c_rslun = *(int *)data; + break; + case IPMICTL_GET_MY_LUN_CMD: + *(int *)data = c->c_rslun; + break; + case IPMICTL_SET_GETS_EVENTS_CMD: + break; + case IPMICTL_REGISTER_FOR_CMD: + case IPMICTL_UNREGISTER_FOR_CMD: + rc = EOPNOTSUPP; + goto done; + default: + break; + } +done: + rw_exit_write(&sc->sc_ioctl.lock); + ipmi_stats.nioctls++; + return (rc); +reset: + sc->sc_ioctl.req.msgid = -1; + + /* c_sc is constant */ + /* c_rssa is set by IPMICTL_SET_MY_ADDRESS_CMD */ + /* c_rslun is set by IPMICTL_SET_MY_LUN_CMD */ + c->c_netfn = -1; + c->c_cmd = -1; + c->c_txlen = -1; + /* c_maxrxlen is constant */ + c->c_rxlen = -1; + /* c_data is constant */ + c->c_ccode = -1; + + goto done; +} + +#define MIN_PERIOD 10 + int ipmi_watchdog(void *arg, int period) { struct ipmi_softc *sc = arg; - uint8_t wdog[IPMI_GET_WDOG_MAX]; - int s, rc, len; if (sc->sc_wdog_period == period) { if (period != 0) { - s = splsoftclock(); - sc->sc_poll = 1; - /* tickle the watchdog */ - rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN, - APP_RESET_WATCHDOG, 0, NULL); - rc = ipmi_recvcmd(sc, 0, &len, NULL); - sc->sc_poll = 0; - splx(s); + struct task *t; + int res; + + t = &sc->sc_wdog_tickle_tasks[ + sc->sc_wdog_tickle_cnt++ % IPMI_WDOG_TICKLE_NTASKS]; + res = task_del(systq, t); + KASSERT(res == 0); + res = task_add(systq, t); + KASSERT(res == 1); } return (period); } + if (period < MIN_PERIOD && period > 0) + period = MIN_PERIOD; + sc->sc_wdog_period = period; + ipmi_watchdog_set(sc); + return (period); +} + +void +ipmi_watchdog_tickle(void *arg) +{ + struct ipmi_softc *sc = arg; + struct ipmi_cmd c; - if (period < 10 && period > 0) - period = 10; + c.c_sc = sc; + c.c_rssa = BMC_SA; + c.c_rslun = BMC_LUN; + c.c_netfn = APP_NETFN; + c.c_cmd = APP_RESET_WATCHDOG; + c.c_txlen = 0; + c.c_maxrxlen = 0; + c.c_rxlen = 0; + c.c_data = NULL; + ipmi_cmd(&c); - s = splsoftclock(); - sc->sc_poll = 1; - /* XXX what to do if poking wdog fails? */ - rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN, - APP_GET_WATCHDOG_TIMER, 0, NULL); - rc = ipmi_recvcmd(sc, IPMI_GET_WDOG_MAX, &len, wdog); + ipmi_stats.ntickles++; +} - /* Period is 10ths/sec */ - uint16_t timo = htole16(period * 10); +void +ipmi_watchdog_set(void *arg) +{ + struct ipmi_softc *sc = arg; + uint8_t wdog[IPMI_GET_WDOG_MAX]; + struct ipmi_cmd c; + c.c_sc = sc; + c.c_rssa = BMC_SA; + c.c_rslun = BMC_LUN; + c.c_netfn = APP_NETFN; + c.c_cmd = APP_GET_WATCHDOG_TIMER; + c.c_txlen = 0; + c.c_maxrxlen = IPMI_GET_WDOG_MAX; + c.c_rxlen = 0; + c.c_data = wdog; + ipmi_cmd(&c); + + wdog[IPMI_SET_WDOG_TIMER] &= ~IPMI_WDOG_TIMER_DONTSTOP; + wdog[IPMI_SET_WDOG_TIMER] |= (sc->sc_wdog_period == 0) ? + 0 : IPMI_WDOG_TIMER_DONTSTOP; + wdog[IPMI_SET_WDOG_ACTION] &= ~IPMI_WDOG_ACTION_ACTION_MASK; + wdog[IPMI_SET_WDOG_ACTION] |= (sc->sc_wdog_period == 0) ? + IPMI_WDOG_ACTION_ACTION_DISABLED : IPMI_WDOG_ACTION_ACTION_REBOOT; + /* Period is 10ths/sec */ + uint16_t timo = htole16(sc->sc_wdog_period * 10); memcpy(&wdog[IPMI_SET_WDOG_TIMOL], &timo, 2); - wdog[IPMI_SET_WDOG_ACTION] &= ~IPMI_WDOG_MASK; - wdog[IPMI_SET_WDOG_ACTION] |= (period == 0) ? IPMI_WDOG_DISABLED : - IPMI_WDOG_REBOOT; - - rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN, - APP_SET_WATCHDOG_TIMER, IPMI_SET_WDOG_MAX, wdog); - rc = ipmi_recvcmd(sc, 0, &len, NULL); - sc->sc_poll = 0; - splx(s); + c.c_cmd = APP_SET_WATCHDOG_TIMER; + c.c_txlen = IPMI_SET_WDOG_MAX; + c.c_maxrxlen = 0; + c.c_rxlen = 0; + c.c_data = wdog; + ipmi_cmd(&c); - sc->sc_wdog_period = period; - return (period); + printf("%s: watchdog %sabled\n", DEVNAME(sc), + (sc->sc_wdog_period == 0) ? "dis" : "en"); } Index: sys/dev/ipmivar.h =================================================================== RCS file: /cvs/src/sys/dev/ipmivar.h,v retrieving revision 1.19 diff -u -p -r1.19 ipmivar.h --- sys/dev/ipmivar.h 7 Jan 2015 07:49:18 -0000 1.19 +++ sys/dev/ipmivar.h 18 Dec 2015 12:07:54 -0000 @@ -30,9 +30,11 @@ #ifndef _IPMIVAR_H_ #define _IPMIVAR_H_ -#include <sys/timeout.h> #include <sys/rwlock.h> #include <sys/sensors.h> +#include <sys/task.h> + +#include <dev/ipmi_linux.h> #define IPMI_IF_KCS 1 #define IPMI_IF_SMIC 2 @@ -44,12 +46,14 @@ struct ipmi_thread; struct ipmi_softc; +struct ipmi_cmd; -struct ipmi_bmc_args{ +struct ipmi_iowait { int offset; u_int8_t mask; u_int8_t value; volatile u_int8_t *v; + const char *lbl; }; struct ipmi_attach_args { @@ -69,12 +73,29 @@ struct ipmi_attach_args { struct ipmi_if { const char *name; int nregs; - void *(*buildmsg)(struct ipmi_softc *, int, int, int, - const void *, int *); - int (*sendmsg)(struct ipmi_softc *, int, const u_int8_t *); - int (*recvmsg)(struct ipmi_softc *, int, int *, u_int8_t *); + void (*buildmsg)(struct ipmi_cmd *); + int (*sendmsg)(struct ipmi_cmd *); + int (*recvmsg)(struct ipmi_cmd *); int (*reset)(struct ipmi_softc *); int (*probe)(struct ipmi_softc *); + int datasnd; + int datarcv; +}; + +struct ipmi_cmd { + struct ipmi_softc *c_sc; + + int c_rssa; + int c_rslun; + int c_netfn; + int c_cmd; + + int c_txlen; + int c_maxrxlen; + int c_rxlen; + + void *c_data; + u_int c_ccode; }; struct ipmi_softc { @@ -89,24 +110,26 @@ struct ipmi_softc { bus_space_handle_t sc_ioh; int sc_btseq; + u_int8_t sc_buf[IPMI_MAX_RX + 16]; + struct ipmi_cmd *sc_cmd; + struct ipmi_iowait *sc_cmd_iowait; + struct taskq *sc_cmd_taskq; + struct mutex sc_cmd_mtx; + + struct ipmi_ioctl { + struct rwlock lock; + struct ipmi_req req; + struct ipmi_cmd cmd; + } sc_ioctl; int sc_wdog_period; +#define IPMI_WDOG_TICKLE_NTASKS 2 + struct task sc_wdog_tickle_tasks[IPMI_WDOG_TICKLE_NTASKS]; + int sc_wdog_tickle_cnt; struct ipmi_thread *sc_thread; - - struct timeout sc_timeout; - int sc_max_retries; - int sc_retries; - int sc_wakeup; - - struct rwlock sc_lock; - - struct ipmi_bmc_args *sc_iowait_args; - struct ipmi_sensor *current_sensor; struct ksensordev sc_sensordev; - - int sc_poll; }; struct ipmi_thread { @@ -114,11 +137,15 @@ struct ipmi_thread { volatile int running; }; -#define IPMI_WDOG_MASK 0x03 -#define IPMI_WDOG_DISABLED 0x00 -#define IPMI_WDOG_REBOOT 0x01 -#define IPMI_WDOG_PWROFF 0x02 -#define IPMI_WDOG_PWRCYCLE 0x03 +#define IPMI_WDOG_TIMER_DONTLOG 0x80 +#define IPMI_WDOG_TIMER_DONTSTOP 0x40 +#define IPMI_WDOG_TIMER_USE_MASK 0x07 + +#define IPMI_WDOG_ACTION_ACTION_MASK 0x03 +#define IPMI_WDOG_ACTION_ACTION_DISABLED 0x00 +#define IPMI_WDOG_ACTION_ACTION_REBOOT 0x01 +#define IPMI_WDOG_ACTION_ACTION_PWROFF 0x02 +#define IPMI_WDOG_ACTION_ACTION_PWRCYCLE 0x03 #define IPMI_WDOG_PRE_DISABLED 0x00 #define IPMI_WDOG_PRE_SMI 0x01 @@ -148,18 +175,18 @@ void ipmi_poll_thread(void *); int kcs_probe(struct ipmi_softc *); int kcs_reset(struct ipmi_softc *); -int kcs_sendmsg(struct ipmi_softc *, int, const u_int8_t *); -int kcs_recvmsg(struct ipmi_softc *, int, int *len, u_int8_t *); +int kcs_sendmsg(struct ipmi_cmd *); +int kcs_recvmsg(struct ipmi_cmd *); int bt_probe(struct ipmi_softc *); int bt_reset(struct ipmi_softc *); -int bt_sendmsg(struct ipmi_softc *, int, const u_int8_t *); -int bt_recvmsg(struct ipmi_softc *, int, int *, u_int8_t *); +int bt_sendmsg(struct ipmi_cmd *); +int bt_recvmsg(struct ipmi_cmd *); int smic_probe(struct ipmi_softc *); int smic_reset(struct ipmi_softc *); -int smic_sendmsg(struct ipmi_softc *, int, const u_int8_t *); -int smic_recvmsg(struct ipmi_softc *, int, int *, u_int8_t *); +int smic_sendmsg(struct ipmi_cmd *); +int smic_recvmsg(struct ipmi_cmd *); struct dmd_ipmi { u_int8_t dmd_sig[4]; /* Signature 'IPMI' */ Index: sys/sys/conf.h =================================================================== RCS file: /cvs/src/sys/sys/conf.h,v retrieving revision 1.135 diff -u -p -r1.135 conf.h --- sys/sys/conf.h 23 Oct 2015 15:10:52 -0000 1.135 +++ sys/sys/conf.h 18 Dec 2015 12:07:54 -0000 @@ -465,6 +465,13 @@ extern struct cdevsw cdevsw[]; (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \ (dev_type_mmap((*))) enodev, 0, D_CLONE, dev_init(c,n,kqfilter) } +/* open, close, read, write, poll, ioctl, nokqfilter */ +#define cdev_ipmi_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ + (dev_type_mmap((*))) enodev, 0 } + #endif /* @@ -596,6 +603,7 @@ cdev_decl(hotplug); cdev_decl(gpio); cdev_decl(amdmsr); cdev_decl(fuse); +cdev_decl(ipmi); #endif
