Annotation of sys/dev/ipmi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ipmi.c,v 1.58 2007/05/29 06:36:56 claudio Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2005 Jordan Hargrave
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
! 17: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 19: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
! 20: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 26: * SUCH DAMAGE.
! 27: */
! 28:
! 29: #include <sys/types.h>
! 30: #include <sys/param.h>
! 31: #include <sys/systm.h>
! 32: #include <sys/kernel.h>
! 33: #include <sys/device.h>
! 34: #include <sys/extent.h>
! 35: #include <sys/timeout.h>
! 36: #include <sys/sensors.h>
! 37: #include <sys/malloc.h>
! 38: #include <sys/kthread.h>
! 39:
! 40: #include <machine/bus.h>
! 41: #include <machine/intr.h>
! 42: #include <machine/smbiosvar.h>
! 43:
! 44: #include <dev/isa/isareg.h>
! 45: #include <dev/isa/isavar.h>
! 46:
! 47: #include <dev/ipmivar.h>
! 48:
! 49: #include <uvm/uvm_extern.h>
! 50:
! 51: struct ipmi_sensor {
! 52: u_int8_t *i_sdr;
! 53: int i_num;
! 54: int stype;
! 55: int etype;
! 56: struct ksensor i_sensor;
! 57: SLIST_ENTRY(ipmi_sensor) list;
! 58: };
! 59:
! 60: int ipmi_nintr;
! 61: int ipmi_poll = 1;
! 62: int ipmi_enabled = 0;
! 63:
! 64: #define SENSOR_REFRESH_RATE (5 * hz)
! 65:
! 66: #define SMBIOS_TYPE_IPMI 0x26
! 67:
! 68: #define DEVNAME(s) ((s)->sc_dev.dv_xname)
! 69:
! 70: /*
! 71: * Format of SMBIOS IPMI Flags
! 72: *
! 73: * bit0: interrupt trigger mode (1=level, 0=edge)
! 74: * bit1: interrupt polarity (1=active high, 0=active low)
! 75: * bit2: reserved
! 76: * bit3: address LSB (1=odd,0=even)
! 77: * bit4: interrupt (1=specified, 0=not specified)
! 78: * bit5: reserved
! 79: * bit6/7: register spacing (1,4,2,err)
! 80: */
! 81: #define SMIPMI_FLAG_IRQLVL (1L << 0)
! 82: #define SMIPMI_FLAG_IRQEN (1L << 3)
! 83: #define SMIPMI_FLAG_ODDOFFSET (1L << 4)
! 84: #define SMIPMI_FLAG_IFSPACING(x) (((x)>>6)&0x3)
! 85: #define IPMI_IOSPACING_BYTE 0
! 86: #define IPMI_IOSPACING_WORD 2
! 87: #define IPMI_IOSPACING_DWORD 1
! 88:
! 89: #define IPMI_BTMSG_LEN 0
! 90: #define IPMI_BTMSG_NFLN 1
! 91: #define IPMI_BTMSG_SEQ 2
! 92: #define IPMI_BTMSG_CMD 3
! 93: #define IPMI_BTMSG_CCODE 4
! 94: #define IPMI_BTMSG_DATASND 4
! 95: #define IPMI_BTMSG_DATARCV 5
! 96:
! 97: #define IPMI_MSG_NFLN 0
! 98: #define IPMI_MSG_CMD 1
! 99: #define IPMI_MSG_CCODE 2
! 100: #define IPMI_MSG_DATASND 2
! 101: #define IPMI_MSG_DATARCV 3
! 102:
! 103: #define IPMI_SENSOR_TYPE_TEMP 0x0101
! 104: #define IPMI_SENSOR_TYPE_VOLT 0x0102
! 105: #define IPMI_SENSOR_TYPE_FAN 0x0104
! 106: #define IPMI_SENSOR_TYPE_INTRUSION 0x6F05
! 107: #define IPMI_SENSOR_TYPE_PWRSUPPLY 0x6F08
! 108:
! 109: #define IPMI_NAME_UNICODE 0x00
! 110: #define IPMI_NAME_BCDPLUS 0x01
! 111: #define IPMI_NAME_ASCII6BIT 0x02
! 112: #define IPMI_NAME_ASCII8BIT 0x03
! 113:
! 114: #define IPMI_ENTITY_PWRSUPPLY 0x0A
! 115:
! 116: #define IPMI_INVALID_SENSOR (1L << 5)
! 117:
! 118: #define IPMI_SDR_TYPEFULL 1
! 119: #define IPMI_SDR_TYPECOMPACT 2
! 120:
! 121: #define byteof(x) ((x) >> 3)
! 122: #define bitof(x) (1L << ((x) & 0x7))
! 123: #define TB(b,m) (data[2+byteof(b)] & bitof(b))
! 124:
! 125: #ifdef IPMI_DEBUG
! 126: int ipmi_dbg = 0;
! 127: #define dbg_printf(lvl, fmt...) \
! 128: if (ipmi_dbg >= lvl) \
! 129: printf(fmt);
! 130: #define dbg_dump(lvl, msg, len, buf) \
! 131: if (len && ipmi_dbg >= lvl) \
! 132: dumpb(msg, len, (const u_int8_t *)(buf));
! 133: #else
! 134: #define dbg_printf(lvl, fmt...)
! 135: #define dbg_dump(lvl, msg, len, buf)
! 136: #endif
! 137:
! 138: long signextend(unsigned long, int);
! 139:
! 140: SLIST_HEAD(ipmi_sensors_head, ipmi_sensor);
! 141: struct ipmi_sensors_head ipmi_sensor_list =
! 142: SLIST_HEAD_INITIALIZER(&ipmi_sensor_list);
! 143:
! 144: struct timeout ipmi_timeout;
! 145:
! 146: void dumpb(const char *, int, const u_int8_t *);
! 147:
! 148: int read_sensor(struct ipmi_softc *, struct ipmi_sensor *);
! 149: int add_sdr_sensor(struct ipmi_softc *, u_int8_t *);
! 150: int get_sdr_partial(struct ipmi_softc *, u_int16_t, u_int16_t,
! 151: u_int8_t, u_int8_t, void *, u_int16_t *);
! 152: int get_sdr(struct ipmi_softc *, u_int16_t, u_int16_t *);
! 153:
! 154: int ipmi_sendcmd(struct ipmi_softc *, int, int, int, int, int, const void*);
! 155: int ipmi_recvcmd(struct ipmi_softc *, int, int *, void *);
! 156: void ipmi_delay(struct ipmi_softc *, int);
! 157:
! 158: int ipmi_watchdog(void *, int);
! 159:
! 160: int ipmi_intr(void *);
! 161: int ipmi_match(struct device *, void *, void *);
! 162: void ipmi_attach(struct device *, struct device *, void *);
! 163:
! 164: long ipow(long, int);
! 165: long ipmi_convert(u_int8_t, struct sdrtype1 *, long);
! 166: void ipmi_sensor_name(char *, int, u_int8_t, u_int8_t *);
! 167:
! 168: /* BMC Helper Functions */
! 169: u_int8_t bmc_read(struct ipmi_softc *, int);
! 170: void bmc_write(struct ipmi_softc *, int, u_int8_t);
! 171: int bmc_io_wait(struct ipmi_softc *, int, u_int8_t, u_int8_t, const char *);
! 172: int bmc_io_wait_cold(struct ipmi_softc *, int, u_int8_t, u_int8_t,
! 173: const char *);
! 174: void _bmc_io_wait(void *);
! 175:
! 176: void *bt_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *);
! 177: void *cmn_buildmsg(struct ipmi_softc *, int, int, int, const void *, int *);
! 178:
! 179: int getbits(u_int8_t *, int, int);
! 180: int ipmi_sensor_type(int, int, int);
! 181:
! 182: void ipmi_smbios_probe(struct smbios_ipmi *, struct ipmi_attach_args *);
! 183: void ipmi_refresh_sensors(struct ipmi_softc *sc);
! 184: int ipmi_map_regs(struct ipmi_softc *sc, struct ipmi_attach_args *ia);
! 185: void ipmi_unmap_regs(struct ipmi_softc *sc, struct ipmi_attach_args *ia);
! 186:
! 187: void *scan_sig(long, long, int, int, const void *);
! 188:
! 189: int ipmi_test_threshold(u_int8_t, u_int8_t, u_int8_t, u_int8_t);
! 190: int ipmi_sensor_status(struct ipmi_softc *, struct ipmi_sensor *,
! 191: u_int8_t *);
! 192:
! 193: int add_child_sensors(struct ipmi_softc *, u_int8_t *, int, int, int,
! 194: int, int, int, const char *);
! 195:
! 196: struct ipmi_if kcs_if = {
! 197: "KCS",
! 198: IPMI_IF_KCS_NREGS,
! 199: cmn_buildmsg,
! 200: kcs_sendmsg,
! 201: kcs_recvmsg,
! 202: kcs_reset,
! 203: kcs_probe,
! 204: };
! 205:
! 206: struct ipmi_if smic_if = {
! 207: "SMIC",
! 208: IPMI_IF_SMIC_NREGS,
! 209: cmn_buildmsg,
! 210: smic_sendmsg,
! 211: smic_recvmsg,
! 212: smic_reset,
! 213: smic_probe,
! 214: };
! 215:
! 216: struct ipmi_if bt_if = {
! 217: "BT",
! 218: IPMI_IF_BT_NREGS,
! 219: bt_buildmsg,
! 220: bt_sendmsg,
! 221: bt_recvmsg,
! 222: bt_reset,
! 223: bt_probe,
! 224: };
! 225:
! 226: struct ipmi_if *ipmi_get_if(int);
! 227:
! 228: struct ipmi_if *
! 229: ipmi_get_if(int iftype)
! 230: {
! 231: switch (iftype) {
! 232: case IPMI_IF_KCS:
! 233: return (&kcs_if);
! 234: case IPMI_IF_SMIC:
! 235: return (&smic_if);
! 236: case IPMI_IF_BT:
! 237: return (&bt_if);
! 238: }
! 239:
! 240: return (NULL);
! 241: }
! 242:
! 243: /*
! 244: * BMC Helper Functions
! 245: */
! 246: u_int8_t
! 247: bmc_read(struct ipmi_softc *sc, int offset)
! 248: {
! 249: return (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
! 250: offset * sc->sc_if_iospacing));
! 251: }
! 252:
! 253: void
! 254: bmc_write(struct ipmi_softc *sc, int offset, u_int8_t val)
! 255: {
! 256: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
! 257: offset * sc->sc_if_iospacing, val);
! 258: }
! 259:
! 260: void
! 261: _bmc_io_wait(void *arg)
! 262: {
! 263: struct ipmi_softc *sc = arg;
! 264: struct ipmi_bmc_args *a = sc->sc_iowait_args;
! 265:
! 266: *a->v = bmc_read(sc, a->offset);
! 267: if ((*a->v & a->mask) == a->value) {
! 268: sc->sc_wakeup = 0;
! 269: wakeup(sc);
! 270: return;
! 271: }
! 272:
! 273: if (++sc->sc_retries > sc->sc_max_retries) {
! 274: sc->sc_wakeup = 0;
! 275: wakeup(sc);
! 276: return;
! 277: }
! 278:
! 279: timeout_add(&sc->sc_timeout, 1);
! 280: }
! 281:
! 282: int
! 283: bmc_io_wait(struct ipmi_softc *sc, int offset, u_int8_t mask, u_int8_t value,
! 284: const char *lbl)
! 285: {
! 286: volatile u_int8_t v;
! 287: struct ipmi_bmc_args args;
! 288:
! 289: if (cold)
! 290: return (bmc_io_wait_cold(sc, offset, mask, value, lbl));
! 291:
! 292: sc->sc_retries = 0;
! 293: sc->sc_wakeup = 1;
! 294:
! 295: args.offset = offset;
! 296: args.mask = mask;
! 297: args.value = value;
! 298: args.v = &v;
! 299: sc->sc_iowait_args = &args;
! 300:
! 301: _bmc_io_wait(sc);
! 302:
! 303: while (sc->sc_wakeup)
! 304: tsleep(sc, PWAIT, lbl, 0);
! 305:
! 306: if (sc->sc_retries > sc->sc_max_retries) {
! 307: dbg_printf(1, "%s: bmc_io_wait fails : v=%.2x m=%.2x "
! 308: "b=%.2x %s\n", DEVNAME(sc), v, mask, value, lbl);
! 309: return (-1);
! 310: }
! 311:
! 312: return (v);
! 313: }
! 314:
! 315: int
! 316: bmc_io_wait_cold(struct ipmi_softc *sc, int offset, u_int8_t mask,
! 317: u_int8_t value, const char *lbl)
! 318: {
! 319: volatile u_int8_t v;
! 320: int count = 5000000; /* == 5s XXX can be shorter */
! 321:
! 322: while (count--) {
! 323: v = bmc_read(sc, offset);
! 324: if ((v & mask) == value)
! 325: return v;
! 326:
! 327: delay(1);
! 328: }
! 329:
! 330: dbg_printf(1, "%s: bmc_io_wait_cold fails : *v=%.2x m=%.2x b=%.2x %s\n",
! 331: DEVNAME(sc), v, mask, value, lbl);
! 332: return (-1);
! 333:
! 334: }
! 335:
! 336: #define NETFN_LUN(nf,ln) (((nf) << 2) | ((ln) & 0x3))
! 337:
! 338: /*
! 339: * BT interface
! 340: */
! 341: #define _BT_CTRL_REG 0
! 342: #define BT_CLR_WR_PTR (1L << 0)
! 343: #define BT_CLR_RD_PTR (1L << 1)
! 344: #define BT_HOST2BMC_ATN (1L << 2)
! 345: #define BT_BMC2HOST_ATN (1L << 3)
! 346: #define BT_EVT_ATN (1L << 4)
! 347: #define BT_HOST_BUSY (1L << 6)
! 348: #define BT_BMC_BUSY (1L << 7)
! 349:
! 350: #define BT_READY (BT_HOST_BUSY|BT_HOST2BMC_ATN|BT_BMC2HOST_ATN)
! 351:
! 352: #define _BT_DATAIN_REG 1
! 353: #define _BT_DATAOUT_REG 1
! 354:
! 355: #define _BT_INTMASK_REG 2
! 356: #define BT_IM_HIRQ_PEND (1L << 1)
! 357: #define BT_IM_SCI_EN (1L << 2)
! 358: #define BT_IM_SMI_EN (1L << 3)
! 359: #define BT_IM_NMI2SMI (1L << 4)
! 360:
! 361: int bt_read(struct ipmi_softc *, int);
! 362: int bt_write(struct ipmi_softc *, int, uint8_t);
! 363:
! 364: int
! 365: bt_read(struct ipmi_softc *sc, int reg)
! 366: {
! 367: return bmc_read(sc, reg);
! 368: }
! 369:
! 370: int
! 371: bt_write(struct ipmi_softc *sc, int reg, uint8_t data)
! 372: {
! 373: if (bmc_io_wait(sc, _BT_CTRL_REG, BT_BMC_BUSY, 0, "bt_write") < 0)
! 374: return (-1);
! 375:
! 376: bmc_write(sc, reg, data);
! 377: return (0);
! 378: }
! 379:
! 380: int
! 381: bt_sendmsg(struct ipmi_softc *sc, int len, const u_int8_t *data)
! 382: {
! 383: int i;
! 384:
! 385: bt_write(sc, _BT_CTRL_REG, BT_CLR_WR_PTR);
! 386: for (i = 0; i < len; i++)
! 387: bt_write(sc, _BT_DATAOUT_REG, data[i]);
! 388:
! 389: bt_write(sc, _BT_CTRL_REG, BT_HOST2BMC_ATN);
! 390: if (bmc_io_wait(sc, _BT_CTRL_REG, BT_HOST2BMC_ATN | BT_BMC_BUSY, 0,
! 391: "bt_sendwait") < 0)
! 392: return (-1);
! 393:
! 394: return (0);
! 395: }
! 396:
! 397: int
! 398: bt_recvmsg(struct ipmi_softc *sc, int maxlen, int *rxlen, u_int8_t *data)
! 399: {
! 400: u_int8_t len, v, i;
! 401:
! 402: if (bmc_io_wait(sc, _BT_CTRL_REG, BT_BMC2HOST_ATN, BT_BMC2HOST_ATN,
! 403: "bt_recvwait") < 0)
! 404: return (-1);
! 405:
! 406: bt_write(sc, _BT_CTRL_REG, BT_HOST_BUSY);
! 407: bt_write(sc, _BT_CTRL_REG, BT_BMC2HOST_ATN);
! 408: bt_write(sc, _BT_CTRL_REG, BT_CLR_RD_PTR);
! 409: len = bt_read(sc, _BT_DATAIN_REG);
! 410: for (i = IPMI_BTMSG_NFLN; i <= len; i++) {
! 411: v = bt_read(sc, _BT_DATAIN_REG);
! 412: if (i != IPMI_BTMSG_SEQ)
! 413: *(data++) = v;
! 414: }
! 415: bt_write(sc, _BT_CTRL_REG, BT_HOST_BUSY);
! 416: *rxlen = len - 1;
! 417:
! 418: return (0);
! 419: }
! 420:
! 421: int
! 422: bt_reset(struct ipmi_softc *sc)
! 423: {
! 424: return (-1);
! 425: }
! 426:
! 427: int
! 428: bt_probe(struct ipmi_softc *sc)
! 429: {
! 430: u_int8_t rv;
! 431:
! 432: rv = bmc_read(sc, _BT_CTRL_REG);
! 433: rv &= BT_HOST_BUSY;
! 434: rv |= BT_CLR_WR_PTR|BT_CLR_RD_PTR|BT_BMC2HOST_ATN|BT_HOST2BMC_ATN;
! 435: bmc_write(sc, _BT_CTRL_REG, rv);
! 436:
! 437: rv = bmc_read(sc, _BT_INTMASK_REG);
! 438: rv &= BT_IM_SCI_EN|BT_IM_SMI_EN|BT_IM_NMI2SMI;
! 439: rv |= BT_IM_HIRQ_PEND;
! 440: bmc_write(sc, _BT_INTMASK_REG, rv);
! 441:
! 442: #if 0
! 443: printf("bt_probe: %2x\n", v);
! 444: printf(" WR : %2x\n", v & BT_CLR_WR_PTR);
! 445: printf(" RD : %2x\n", v & BT_CLR_RD_PTR);
! 446: printf(" H2B : %2x\n", v & BT_HOST2BMC_ATN);
! 447: printf(" B2H : %2x\n", v & BT_BMC2HOST_ATN);
! 448: printf(" EVT : %2x\n", v & BT_EVT_ATN);
! 449: printf(" HBSY : %2x\n", v & BT_HOST_BUSY);
! 450: printf(" BBSY : %2x\n", v & BT_BMC_BUSY);
! 451: #endif
! 452: return (0);
! 453: }
! 454:
! 455: /*
! 456: * SMIC interface
! 457: */
! 458: #define _SMIC_DATAIN_REG 0
! 459: #define _SMIC_DATAOUT_REG 0
! 460:
! 461: #define _SMIC_CTRL_REG 1
! 462: #define SMS_CC_GET_STATUS 0x40
! 463: #define SMS_CC_START_TRANSFER 0x41
! 464: #define SMS_CC_NEXT_TRANSFER 0x42
! 465: #define SMS_CC_END_TRANSFER 0x43
! 466: #define SMS_CC_START_RECEIVE 0x44
! 467: #define SMS_CC_NEXT_RECEIVE 0x45
! 468: #define SMS_CC_END_RECEIVE 0x46
! 469: #define SMS_CC_TRANSFER_ABORT 0x47
! 470:
! 471: #define SMS_SC_READY 0xc0
! 472: #define SMS_SC_WRITE_START 0xc1
! 473: #define SMS_SC_WRITE_NEXT 0xc2
! 474: #define SMS_SC_WRITE_END 0xc3
! 475: #define SMS_SC_READ_START 0xc4
! 476: #define SMS_SC_READ_NEXT 0xc5
! 477: #define SMS_SC_READ_END 0xc6
! 478:
! 479: #define _SMIC_FLAG_REG 2
! 480: #define SMIC_BUSY (1L << 0)
! 481: #define SMIC_SMS_ATN (1L << 2)
! 482: #define SMIC_EVT_ATN (1L << 3)
! 483: #define SMIC_SMI (1L << 4)
! 484: #define SMIC_TX_DATA_RDY (1L << 6)
! 485: #define SMIC_RX_DATA_RDY (1L << 7)
! 486:
! 487: int smic_wait(struct ipmi_softc *, u_int8_t, u_int8_t, const char *);
! 488: int smic_write_cmd_data(struct ipmi_softc *, u_int8_t, const u_int8_t *);
! 489: int smic_read_data(struct ipmi_softc *, u_int8_t *);
! 490:
! 491: int
! 492: smic_wait(struct ipmi_softc *sc, u_int8_t mask, u_int8_t val, const char *lbl)
! 493: {
! 494: int v;
! 495:
! 496: /* Wait for expected flag bits */
! 497: v = bmc_io_wait(sc, _SMIC_FLAG_REG, mask, val, "smicwait");
! 498: if (v < 0)
! 499: return (-1);
! 500:
! 501: /* Return current status */
! 502: v = bmc_read(sc, _SMIC_CTRL_REG);
! 503: dbg_printf(99, "smic_wait = %.2x\n", v);
! 504: return (v);
! 505: }
! 506:
! 507: int
! 508: smic_write_cmd_data(struct ipmi_softc *sc, u_int8_t cmd, const u_int8_t *data)
! 509: {
! 510: int sts, v;
! 511:
! 512: dbg_printf(50, "smic_wcd: %.2x %.2x\n", cmd, data ? *data : -1);
! 513: sts = smic_wait(sc, SMIC_TX_DATA_RDY | SMIC_BUSY, SMIC_TX_DATA_RDY,
! 514: "smic_write_cmd_data ready");
! 515: if (sts < 0)
! 516: return (sts);
! 517:
! 518: bmc_write(sc, _SMIC_CTRL_REG, cmd);
! 519: if (data)
! 520: bmc_write(sc, _SMIC_DATAOUT_REG, *data);
! 521:
! 522: /* Toggle BUSY bit, then wait for busy bit to clear */
! 523: v = bmc_read(sc, _SMIC_FLAG_REG);
! 524: bmc_write(sc, _SMIC_FLAG_REG, v | SMIC_BUSY);
! 525:
! 526: return (smic_wait(sc, SMIC_BUSY, 0, "smic_write_cmd_data busy"));
! 527: }
! 528:
! 529: int
! 530: smic_read_data(struct ipmi_softc *sc, u_int8_t *data)
! 531: {
! 532: int sts;
! 533:
! 534: sts = smic_wait(sc, SMIC_RX_DATA_RDY | SMIC_BUSY, SMIC_RX_DATA_RDY,
! 535: "smic_read_data");
! 536: if (sts >= 0) {
! 537: *data = bmc_read(sc, _SMIC_DATAIN_REG);
! 538: dbg_printf(50, "smic_readdata: %.2x\n", *data);
! 539: }
! 540: return (sts);
! 541: }
! 542:
! 543: #define ErrStat(a,b) if (a) printf(b);
! 544:
! 545: int
! 546: smic_sendmsg(struct ipmi_softc *sc, int len, const u_int8_t *data)
! 547: {
! 548: int sts, idx;
! 549:
! 550: sts = smic_write_cmd_data(sc, SMS_CC_START_TRANSFER, &data[0]);
! 551: ErrStat(sts != SMS_SC_WRITE_START, "wstart");
! 552: for (idx = 1; idx < len - 1; idx++) {
! 553: sts = smic_write_cmd_data(sc, SMS_CC_NEXT_TRANSFER,
! 554: &data[idx]);
! 555: ErrStat(sts != SMS_SC_WRITE_NEXT, "write");
! 556: }
! 557: sts = smic_write_cmd_data(sc, SMS_CC_END_TRANSFER, &data[idx]);
! 558: if (sts != SMS_SC_WRITE_END) {
! 559: dbg_printf(50, "smic_sendmsg %d/%d = %.2x\n", idx, len, sts);
! 560: return (-1);
! 561: }
! 562:
! 563: return (0);
! 564: }
! 565:
! 566: int
! 567: smic_recvmsg(struct ipmi_softc *sc, int maxlen, int *len, u_int8_t *data)
! 568: {
! 569: int sts, idx;
! 570:
! 571: *len = 0;
! 572: sts = smic_wait(sc, SMIC_RX_DATA_RDY, SMIC_RX_DATA_RDY, "smic_recvmsg");
! 573: if (sts < 0)
! 574: return (-1);
! 575:
! 576: sts = smic_write_cmd_data(sc, SMS_CC_START_RECEIVE, NULL);
! 577: ErrStat(sts != SMS_SC_READ_START, "rstart");
! 578: for (idx = 0;; ) {
! 579: sts = smic_read_data(sc, &data[idx++]);
! 580: if (sts != SMS_SC_READ_START && sts != SMS_SC_READ_NEXT)
! 581: break;
! 582: smic_write_cmd_data(sc, SMS_CC_NEXT_RECEIVE, NULL);
! 583: }
! 584: ErrStat(sts != SMS_SC_READ_END, "rend");
! 585:
! 586: *len = idx;
! 587:
! 588: sts = smic_write_cmd_data(sc, SMS_CC_END_RECEIVE, NULL);
! 589: if (sts != SMS_SC_READY) {
! 590: dbg_printf(50, "smic_recvmsg %d/%d = %.2x\n", idx, maxlen, sts);
! 591: return (-1);
! 592: }
! 593:
! 594: return (0);
! 595: }
! 596:
! 597: int
! 598: smic_reset(struct ipmi_softc *sc)
! 599: {
! 600: return (-1);
! 601: }
! 602:
! 603: int
! 604: smic_probe(struct ipmi_softc *sc)
! 605: {
! 606: /* Flag register should not be 0xFF on a good system */
! 607: if (bmc_read(sc, _SMIC_FLAG_REG) == 0xFF)
! 608: return (-1);
! 609:
! 610: return (0);
! 611: }
! 612:
! 613: /*
! 614: * KCS interface
! 615: */
! 616: #define _KCS_DATAIN_REGISTER 0
! 617: #define _KCS_DATAOUT_REGISTER 0
! 618: #define KCS_READ_NEXT 0x68
! 619:
! 620: #define _KCS_COMMAND_REGISTER 1
! 621: #define KCS_GET_STATUS 0x60
! 622: #define KCS_WRITE_START 0x61
! 623: #define KCS_WRITE_END 0x62
! 624:
! 625: #define _KCS_STATUS_REGISTER 1
! 626: #define KCS_OBF (1L << 0)
! 627: #define KCS_IBF (1L << 1)
! 628: #define KCS_SMS_ATN (1L << 2)
! 629: #define KCS_CD (1L << 3)
! 630: #define KCS_OEM1 (1L << 4)
! 631: #define KCS_OEM2 (1L << 5)
! 632: #define KCS_STATE_MASK 0xc0
! 633: #define KCS_IDLE_STATE 0x00
! 634: #define KCS_READ_STATE 0x40
! 635: #define KCS_WRITE_STATE 0x80
! 636: #define KCS_ERROR_STATE 0xC0
! 637:
! 638: int kcs_wait(struct ipmi_softc *, u_int8_t, u_int8_t, const char *);
! 639: int kcs_write_cmd(struct ipmi_softc *, u_int8_t);
! 640: int kcs_write_data(struct ipmi_softc *, u_int8_t);
! 641: int kcs_read_data(struct ipmi_softc *, u_int8_t *);
! 642:
! 643: int
! 644: kcs_wait(struct ipmi_softc *sc, u_int8_t mask, u_int8_t value, const char *lbl)
! 645: {
! 646: int v;
! 647:
! 648: v = bmc_io_wait(sc, _KCS_STATUS_REGISTER, mask, value, lbl);
! 649: if (v < 0)
! 650: return (v);
! 651:
! 652: /* Check if output buffer full, read dummy byte */
! 653: if ((v & (KCS_OBF | KCS_STATE_MASK)) == (KCS_OBF | KCS_WRITE_STATE))
! 654: bmc_read(sc, _KCS_DATAIN_REGISTER);
! 655:
! 656: /* Check for error state */
! 657: if ((v & KCS_STATE_MASK) == KCS_ERROR_STATE) {
! 658: bmc_write(sc, _KCS_COMMAND_REGISTER, KCS_GET_STATUS);
! 659: while (bmc_read(sc, _KCS_STATUS_REGISTER) & KCS_IBF)
! 660: ;
! 661: printf("%s: error code: %x\n", DEVNAME(sc),
! 662: bmc_read(sc, _KCS_DATAIN_REGISTER));
! 663: }
! 664:
! 665: return (v & KCS_STATE_MASK);
! 666: }
! 667:
! 668: int
! 669: kcs_write_cmd(struct ipmi_softc *sc, u_int8_t cmd)
! 670: {
! 671: /* ASSERT: IBF and OBF are clear */
! 672: dbg_printf(50, "kcswritecmd: %.2x\n", cmd);
! 673: bmc_write(sc, _KCS_COMMAND_REGISTER, cmd);
! 674:
! 675: return (kcs_wait(sc, KCS_IBF, 0, "write_cmd"));
! 676: }
! 677:
! 678: int
! 679: kcs_write_data(struct ipmi_softc *sc, u_int8_t data)
! 680: {
! 681: /* ASSERT: IBF and OBF are clear */
! 682: dbg_printf(50, "kcswritedata: %.2x\n", data);
! 683: bmc_write(sc, _KCS_DATAOUT_REGISTER, data);
! 684:
! 685: return (kcs_wait(sc, KCS_IBF, 0, "write_data"));
! 686: }
! 687:
! 688: int
! 689: kcs_read_data(struct ipmi_softc *sc, u_int8_t * data)
! 690: {
! 691: int sts;
! 692:
! 693: sts = kcs_wait(sc, KCS_IBF | KCS_OBF, KCS_OBF, "read_data");
! 694: if (sts != KCS_READ_STATE)
! 695: return (sts);
! 696:
! 697: /* ASSERT: OBF is set read data, request next byte */
! 698: *data = bmc_read(sc, _KCS_DATAIN_REGISTER);
! 699: bmc_write(sc, _KCS_DATAOUT_REGISTER, KCS_READ_NEXT);
! 700:
! 701: dbg_printf(50, "kcsreaddata: %.2x\n", *data);
! 702:
! 703: return (sts);
! 704: }
! 705:
! 706: /* Exported KCS functions */
! 707: int
! 708: kcs_sendmsg(struct ipmi_softc *sc, int len, const u_int8_t * data)
! 709: {
! 710: int idx, sts;
! 711:
! 712: /* ASSERT: IBF is clear */
! 713: dbg_dump(50, "kcs sendmsg", len, data);
! 714: sts = kcs_write_cmd(sc, KCS_WRITE_START);
! 715: for (idx = 0; idx < len; idx++) {
! 716: if (idx == len - 1)
! 717: sts = kcs_write_cmd(sc, KCS_WRITE_END);
! 718:
! 719: if (sts != KCS_WRITE_STATE)
! 720: break;
! 721:
! 722: sts = kcs_write_data(sc, data[idx]);
! 723: }
! 724: if (sts != KCS_READ_STATE) {
! 725: dbg_printf(1, "kcs sendmsg = %d/%d <%.2x>\n", idx, len, sts);
! 726: dbg_dump(1, "kcs_sendmsg", len, data);
! 727: return (-1);
! 728: }
! 729:
! 730: return (0);
! 731: }
! 732:
! 733: int
! 734: kcs_recvmsg(struct ipmi_softc *sc, int maxlen, int *rxlen, u_int8_t * data)
! 735: {
! 736: int idx, sts;
! 737:
! 738: for (idx = 0; idx < maxlen; idx++) {
! 739: sts = kcs_read_data(sc, &data[idx]);
! 740: if (sts != KCS_READ_STATE)
! 741: break;
! 742: }
! 743: sts = kcs_wait(sc, KCS_IBF, 0, "recv");
! 744: *rxlen = idx;
! 745: if (sts != KCS_IDLE_STATE) {
! 746: dbg_printf(1, "kcs read = %d/%d <%.2x>\n", idx, maxlen, sts);
! 747: return (-1);
! 748: }
! 749:
! 750: dbg_dump(50, "kcs recvmsg", idx, data);
! 751:
! 752: return (0);
! 753: }
! 754:
! 755: int
! 756: kcs_reset(struct ipmi_softc *sc)
! 757: {
! 758: return (-1);
! 759: }
! 760:
! 761: int
! 762: kcs_probe(struct ipmi_softc *sc)
! 763: {
! 764: u_int8_t v;
! 765:
! 766: v = bmc_read(sc, _KCS_STATUS_REGISTER);
! 767: #if 0
! 768: printf("kcs_probe: %2x\n", v);
! 769: printf(" STS: %2x\n", v & KCS_STATE_MASK);
! 770: printf(" ATN: %2x\n", v & KCS_SMS_ATN);
! 771: printf(" C/D: %2x\n", v & KCS_CD);
! 772: printf(" IBF: %2x\n", v & KCS_IBF);
! 773: printf(" OBF: %2x\n", v & KCS_OBF);
! 774: #endif
! 775: return (0);
! 776: }
! 777:
! 778: /*
! 779: * IPMI code
! 780: */
! 781: #define READ_SMS_BUFFER 0x37
! 782: #define WRITE_I2C 0x50
! 783:
! 784: #define GET_MESSAGE_CMD 0x33
! 785: #define SEND_MESSAGE_CMD 0x34
! 786:
! 787: #define IPMB_CHANNEL_NUMBER 0
! 788:
! 789: #define PUBLIC_BUS 0
! 790:
! 791: #define MIN_I2C_PACKET_SIZE 3
! 792: #define MIN_IMB_PACKET_SIZE 7 /* one byte for cksum */
! 793:
! 794: #define MIN_BTBMC_REQ_SIZE 4
! 795: #define MIN_BTBMC_RSP_SIZE 5
! 796: #define MIN_BMC_REQ_SIZE 2
! 797: #define MIN_BMC_RSP_SIZE 3
! 798:
! 799: #define BMC_SA 0x20 /* BMC/ESM3 */
! 800: #define FPC_SA 0x22 /* front panel */
! 801: #define BP_SA 0xC0 /* Primary Backplane */
! 802: #define BP2_SA 0xC2 /* Secondary Backplane */
! 803: #define PBP_SA 0xC4 /* Peripheral Backplane */
! 804: #define DRAC_SA 0x28 /* DRAC-III */
! 805: #define DRAC3_SA 0x30 /* DRAC-III */
! 806: #define BMC_LUN 0
! 807: #define SMS_LUN 2
! 808:
! 809: struct ipmi_request {
! 810: u_int8_t rsSa;
! 811: u_int8_t rsLun;
! 812: u_int8_t netFn;
! 813: u_int8_t cmd;
! 814: u_int8_t data_len;
! 815: u_int8_t *data;
! 816: };
! 817:
! 818: struct ipmi_response {
! 819: u_int8_t cCode;
! 820: u_int8_t data_len;
! 821: u_int8_t *data;
! 822: };
! 823:
! 824: struct ipmi_bmc_request {
! 825: u_int8_t bmc_nfLn;
! 826: u_int8_t bmc_cmd;
! 827: u_int8_t bmc_data_len;
! 828: u_int8_t bmc_data[1];
! 829: };
! 830:
! 831: struct ipmi_bmc_response {
! 832: u_int8_t bmc_nfLn;
! 833: u_int8_t bmc_cmd;
! 834: u_int8_t bmc_cCode;
! 835: u_int8_t bmc_data_len;
! 836: u_int8_t bmc_data[1];
! 837: };
! 838:
! 839: struct cfattach ipmi_ca = {
! 840: sizeof(struct ipmi_softc), ipmi_match, ipmi_attach
! 841: };
! 842:
! 843: struct cfdriver ipmi_cd = {
! 844: NULL, "ipmi", DV_DULL
! 845: };
! 846:
! 847: /* Scan memory for signature */
! 848: void *
! 849: scan_sig(long start, long end, int skip, int len, const void *data)
! 850: {
! 851: void *va;
! 852:
! 853: while (start < end) {
! 854: va = ISA_HOLE_VADDR(start);
! 855: if (memcmp(va, data, len) == 0)
! 856: return (va);
! 857:
! 858: start += skip;
! 859: }
! 860:
! 861: return (NULL);
! 862: }
! 863:
! 864: void
! 865: dumpb(const char *lbl, int len, const u_int8_t *data)
! 866: {
! 867: int idx;
! 868:
! 869: printf("%s: ", lbl);
! 870: for (idx = 0; idx < len; idx++)
! 871: printf("%.2x ", data[idx]);
! 872:
! 873: printf("\n");
! 874: }
! 875:
! 876: void
! 877: ipmi_smbios_probe(struct smbios_ipmi *pipmi, struct ipmi_attach_args *ia)
! 878: {
! 879:
! 880: dbg_printf(1, "ipmi_smbios_probe: %02x %02x %02x %02x %08llx %02x "
! 881: "%02x\n",
! 882: pipmi->smipmi_if_type,
! 883: pipmi->smipmi_if_rev,
! 884: pipmi->smipmi_i2c_address,
! 885: pipmi->smipmi_nvram_address,
! 886: pipmi->smipmi_base_address,
! 887: pipmi->smipmi_base_flags,
! 888: pipmi->smipmi_irq);
! 889:
! 890: ia->iaa_if_type = pipmi->smipmi_if_type;
! 891: ia->iaa_if_rev = pipmi->smipmi_if_rev;
! 892: ia->iaa_if_irq = (pipmi->smipmi_base_flags & SMIPMI_FLAG_IRQEN) ?
! 893: pipmi->smipmi_irq : -1;
! 894: ia->iaa_if_irqlvl = (pipmi->smipmi_base_flags & SMIPMI_FLAG_IRQLVL) ?
! 895: IST_LEVEL : IST_EDGE;
! 896:
! 897: switch (SMIPMI_FLAG_IFSPACING(pipmi->smipmi_base_flags)) {
! 898: case IPMI_IOSPACING_BYTE:
! 899: ia->iaa_if_iospacing = 1;
! 900: break;
! 901:
! 902: case IPMI_IOSPACING_DWORD:
! 903: ia->iaa_if_iospacing = 4;
! 904: break;
! 905:
! 906: case IPMI_IOSPACING_WORD:
! 907: ia->iaa_if_iospacing = 2;
! 908: break;
! 909:
! 910: default:
! 911: ia->iaa_if_iospacing = 1;
! 912: printf("ipmi: unknown register spacing\n");
! 913: }
! 914:
! 915: /* Calculate base address (PCI BAR format) */
! 916: if (pipmi->smipmi_base_address & 0x1) {
! 917: ia->iaa_if_iotype = 'i';
! 918: ia->iaa_if_iobase = pipmi->smipmi_base_address & ~0x1;
! 919: } else {
! 920: ia->iaa_if_iotype = 'm';
! 921: ia->iaa_if_iobase = pipmi->smipmi_base_address & ~0xF;
! 922: }
! 923: if (pipmi->smipmi_base_flags & SMIPMI_FLAG_ODDOFFSET)
! 924: ia->iaa_if_iobase++;
! 925:
! 926: if (pipmi->smipmi_base_flags == 0x7f) {
! 927: /* IBM 325 eServer workaround */
! 928: ia->iaa_if_iospacing = 1;
! 929: ia->iaa_if_iobase = pipmi->smipmi_base_address;
! 930: ia->iaa_if_iotype = 'i';
! 931: return;
! 932: }
! 933: }
! 934:
! 935: /*
! 936: * bt_buildmsg builds an IPMI message from a nfLun, cmd, and data
! 937: * This is used by BT protocol
! 938: *
! 939: * Returns a buffer to an allocated message, txlen contains length
! 940: * of allocated message
! 941: */
! 942: void *
! 943: bt_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len,
! 944: const void *data, int *txlen)
! 945: {
! 946: u_int8_t *buf;
! 947:
! 948: /* Block transfer needs 4 extra bytes: length/netfn/seq/cmd + data */
! 949: *txlen = len + 4;
! 950: buf = malloc(*txlen, M_DEVBUF, M_NOWAIT|M_CANFAIL);
! 951: if (buf == NULL)
! 952: return (NULL);
! 953:
! 954: buf[IPMI_BTMSG_LEN] = len + 3;
! 955: buf[IPMI_BTMSG_NFLN] = nfLun;
! 956: buf[IPMI_BTMSG_SEQ] = sc->sc_btseq++;
! 957: buf[IPMI_BTMSG_CMD] = cmd;
! 958: if (len && data)
! 959: memcpy(buf + IPMI_BTMSG_DATASND, data, len);
! 960:
! 961: return (buf);
! 962: }
! 963:
! 964: /*
! 965: * cmn_buildmsg builds an IPMI message from a nfLun, cmd, and data
! 966: * This is used by both SMIC and KCS protocols
! 967: *
! 968: * Returns a buffer to an allocated message, txlen contains length
! 969: * of allocated message
! 970: */
! 971: void *
! 972: cmn_buildmsg(struct ipmi_softc *sc, int nfLun, int cmd, int len,
! 973: const void *data, int *txlen)
! 974: {
! 975: u_int8_t *buf;
! 976:
! 977: /* Common needs two extra bytes: nfLun/cmd + data */
! 978: *txlen = len + 2;
! 979: buf = malloc(*txlen, M_DEVBUF, M_NOWAIT|M_CANFAIL);
! 980: if (buf == NULL)
! 981: return (NULL);
! 982:
! 983: buf[IPMI_MSG_NFLN] = nfLun;
! 984: buf[IPMI_MSG_CMD] = cmd;
! 985: if (len && data)
! 986: memcpy(buf + IPMI_MSG_DATASND, data, len);
! 987:
! 988: return (buf);
! 989: }
! 990:
! 991: /* Send an IPMI command */
! 992: int
! 993: ipmi_sendcmd(struct ipmi_softc *sc, int rssa, int rslun, int netfn, int cmd,
! 994: int txlen, const void *data)
! 995: {
! 996: u_int8_t *buf;
! 997: int rc = -1;
! 998:
! 999: dbg_printf(50, "ipmi_sendcmd: rssa=%.2x nfln=%.2x cmd=%.2x len=%.2x\n",
! 1000: rssa, NETFN_LUN(netfn, rslun), cmd, txlen);
! 1001: dbg_dump(10, " send", txlen, data);
! 1002: if (rssa != BMC_SA) {
! 1003: #if 0
! 1004: buf = sc->sc_if->buildmsg(sc, NETFN_LUN(APP_NETFN, BMC_LUN),
! 1005: APP_SEND_MESSAGE, 7 + txlen, NULL, &txlen);
! 1006: pI2C->bus = (sc->if_ver == 0x09) ?
! 1007: PUBLIC_BUS :
! 1008: IPMB_CHANNEL_NUMBER;
! 1009:
! 1010: imbreq->rsSa = rssa;
! 1011: imbreq->nfLn = NETFN_LUN(netfn, rslun);
! 1012: imbreq->cSum1 = -(imbreq->rsSa + imbreq->nfLn);
! 1013: imbreq->rqSa = BMC_SA;
! 1014: imbreq->seqLn = NETFN_LUN(sc->imb_seq++, SMS_LUN);
! 1015: imbreq->cmd = cmd;
! 1016: if (txlen)
! 1017: memcpy(imbreq->data, data, txlen);
! 1018: /* Set message checksum */
! 1019: imbreq->data[txlen] = cksum8(&imbreq->rqSa, txlen + 3);
! 1020: #endif
! 1021: goto done;
! 1022: } else
! 1023: buf = sc->sc_if->buildmsg(sc, NETFN_LUN(netfn, rslun), cmd,
! 1024: txlen, data, &txlen);
! 1025:
! 1026: if (buf == NULL) {
! 1027: printf("%s: sendcmd malloc fails\n", DEVNAME(sc));
! 1028: goto done;
! 1029: }
! 1030: rc = sc->sc_if->sendmsg(sc, txlen, buf);
! 1031: free(buf, M_DEVBUF);
! 1032:
! 1033: ipmi_delay(sc, 5); /* give bmc chance to digest command */
! 1034:
! 1035: done:
! 1036: return (rc);
! 1037: }
! 1038:
! 1039: int
! 1040: ipmi_recvcmd(struct ipmi_softc *sc, int maxlen, int *rxlen, void *data)
! 1041: {
! 1042: u_int8_t *buf, rc = 0;
! 1043: int rawlen;
! 1044:
! 1045: /* Need three extra bytes: netfn/cmd/ccode + data */
! 1046: buf = malloc(maxlen + 3, M_DEVBUF, M_NOWAIT|M_CANFAIL);
! 1047: if (buf == NULL) {
! 1048: printf("%s: ipmi_recvcmd: malloc fails\n", DEVNAME(sc));
! 1049: return (-1);
! 1050: }
! 1051: /* Receive message from interface, copy out result data */
! 1052: if (sc->sc_if->recvmsg(sc, maxlen + 3, &rawlen, buf))
! 1053: return (-1);
! 1054:
! 1055: *rxlen = rawlen - IPMI_MSG_DATARCV;
! 1056: if (*rxlen > 0 && data)
! 1057: memcpy(data, buf + IPMI_MSG_DATARCV, *rxlen);
! 1058:
! 1059: rc = buf[IPMI_MSG_CCODE];
! 1060: #ifdef IPMI_DEBUG
! 1061: if (rc != 0)
! 1062: dbg_printf(1, "ipmi_recvmsg: nfln=%.2x cmd=%.2x err=%.2x\n",
! 1063: buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE]);
! 1064: #endif
! 1065:
! 1066: dbg_printf(50, "ipmi_recvcmd: nfln=%.2x cmd=%.2x err=%.2x len=%.2x\n",
! 1067: buf[IPMI_MSG_NFLN], buf[IPMI_MSG_CMD], buf[IPMI_MSG_CCODE],
! 1068: *rxlen);
! 1069: dbg_dump(10, " recv", *rxlen, data);
! 1070:
! 1071: free(buf, M_DEVBUF);
! 1072:
! 1073: ipmi_delay(sc, 5); /* give bmc chance to digest command */
! 1074:
! 1075: return (rc);
! 1076: }
! 1077:
! 1078: void
! 1079: ipmi_delay(struct ipmi_softc *sc, int period)
! 1080: {
! 1081: /* period is in 10 ms increments */
! 1082: if (cold)
! 1083: delay(period * 10000);
! 1084: else
! 1085: while (tsleep(sc, PWAIT, "ipmicmd", period) != EWOULDBLOCK);
! 1086: }
! 1087:
! 1088: /* Read a partial SDR entry */
! 1089: int
! 1090: get_sdr_partial(struct ipmi_softc *sc, u_int16_t recordId, u_int16_t reserveId,
! 1091: u_int8_t offset, u_int8_t length, void *buffer, u_int16_t *nxtRecordId)
! 1092: {
! 1093: u_int8_t cmd[8 + length];
! 1094: int len;
! 1095:
! 1096: ((u_int16_t *) cmd)[0] = reserveId;
! 1097: ((u_int16_t *) cmd)[1] = recordId;
! 1098: cmd[4] = offset;
! 1099: cmd[5] = length;
! 1100: if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_GET_SDR, 6,
! 1101: cmd)) {
! 1102: printf("%s: sendcmd fails\n", DEVNAME(sc));
! 1103: return (-1);
! 1104: }
! 1105: if (ipmi_recvcmd(sc, 8 + length, &len, cmd)) {
! 1106: printf("%s: getSdrPartial: recvcmd fails\n", DEVNAME(sc));
! 1107: return (-1);
! 1108: }
! 1109: if (nxtRecordId)
! 1110: *nxtRecordId = *(uint16_t *) cmd;
! 1111: memcpy(buffer, cmd + 2, len - 2);
! 1112:
! 1113: return (0);
! 1114: }
! 1115:
! 1116: int maxsdrlen = 0x10;
! 1117:
! 1118: /* Read an entire SDR; pass to add sensor */
! 1119: int
! 1120: get_sdr(struct ipmi_softc *sc, u_int16_t recid, u_int16_t *nxtrec)
! 1121: {
! 1122: u_int16_t resid = 0;
! 1123: int len, sdrlen, offset;
! 1124: u_int8_t *psdr;
! 1125: struct sdrhdr shdr;
! 1126:
! 1127: /* Reserve SDR */
! 1128: if (ipmi_sendcmd(sc, BMC_SA, 0, STORAGE_NETFN, STORAGE_RESERVE_SDR,
! 1129: 0, NULL)) {
! 1130: printf(": reserve send fails\n");
! 1131: return (-1);
! 1132: }
! 1133: if (ipmi_recvcmd(sc, sizeof(resid), &len, &resid)) {
! 1134: printf(": reserve recv fails\n");
! 1135: return (-1);
! 1136: }
! 1137: /* Get SDR Header */
! 1138: if (get_sdr_partial(sc, recid, resid, 0, sizeof shdr, &shdr, nxtrec)) {
! 1139: printf(": get header fails\n");
! 1140: return (-1);
! 1141: }
! 1142: /* Allocate space for entire SDR Length of SDR in header does not
! 1143: * include header length */
! 1144: sdrlen = sizeof(shdr) + shdr.record_length;
! 1145: psdr = malloc(sdrlen, M_DEVBUF, M_NOWAIT|M_CANFAIL);
! 1146: if (psdr == NULL)
! 1147: return -1;
! 1148:
! 1149: memcpy(psdr, &shdr, sizeof(shdr));
! 1150:
! 1151: /* Read SDR Data maxsdrlen bytes at a time */
! 1152: for (offset = sizeof(shdr); offset < sdrlen; offset += maxsdrlen) {
! 1153: len = sdrlen - offset;
! 1154: if (len > maxsdrlen)
! 1155: len = maxsdrlen;
! 1156:
! 1157: if (get_sdr_partial(sc, recid, resid, offset, len,
! 1158: psdr + offset, NULL)) {
! 1159: printf(": get chunk: %d,%d fails\n", offset, len);
! 1160: return (-1);
! 1161: }
! 1162: }
! 1163:
! 1164: /* Add SDR to sensor list, if not wanted, free buffer */
! 1165: if (add_sdr_sensor(sc, psdr) == 0)
! 1166: free(psdr, M_DEVBUF);
! 1167:
! 1168: return (0);
! 1169: }
! 1170:
! 1171: int
! 1172: getbits(u_int8_t *bytes, int bitpos, int bitlen)
! 1173: {
! 1174: int v;
! 1175: int mask;
! 1176:
! 1177: bitpos += bitlen - 1;
! 1178: for (v = 0; bitlen--;) {
! 1179: v <<= 1;
! 1180: mask = 1L << (bitpos & 7);
! 1181: if (bytes[bitpos >> 3] & mask)
! 1182: v |= 1;
! 1183: bitpos--;
! 1184: }
! 1185:
! 1186: return (v);
! 1187: }
! 1188:
! 1189: /* Decode IPMI sensor name */
! 1190: void
! 1191: ipmi_sensor_name(char *name, int len, u_int8_t typelen, u_int8_t *bits)
! 1192: {
! 1193: int i, slen;
! 1194: char bcdplus[] = "0123456789 -.:,_";
! 1195:
! 1196: slen = typelen & 0x1F;
! 1197: switch (typelen >> 6) {
! 1198: case IPMI_NAME_UNICODE:
! 1199: //unicode
! 1200: break;
! 1201:
! 1202: case IPMI_NAME_BCDPLUS:
! 1203: /* Characters are encoded in 4-bit BCDPLUS */
! 1204: if (len < slen * 2 + 1)
! 1205: slen = (len >> 1) - 1;
! 1206: for (i = 0; i < slen; i++) {
! 1207: *(name++) = bcdplus[bits[i] >> 4];
! 1208: *(name++) = bcdplus[bits[i] & 0xF];
! 1209: }
! 1210: break;
! 1211:
! 1212: case IPMI_NAME_ASCII6BIT:
! 1213: /* Characters are encoded in 6-bit ASCII
! 1214: * 0x00 - 0x3F maps to 0x20 - 0x5F */
! 1215: /* XXX: need to calculate max len: slen = 3/4 * len */
! 1216: if (len < slen + 1)
! 1217: slen = len - 1;
! 1218: for (i = 0; i < slen * 8; i += 6)
! 1219: *(name++) = getbits(bits, i, 6) + ' ';
! 1220: break;
! 1221:
! 1222: case IPMI_NAME_ASCII8BIT:
! 1223: /* Characters are 8-bit ascii */
! 1224: if (len < slen + 1)
! 1225: slen = len - 1;
! 1226: while (slen--)
! 1227: *(name++) = *(bits++);
! 1228: break;
! 1229: }
! 1230: *name = 0;
! 1231: }
! 1232:
! 1233: /* Calculate val * 10^exp */
! 1234: long
! 1235: ipow(long val, int exp)
! 1236: {
! 1237: while (exp > 0) {
! 1238: val *= 10;
! 1239: exp--;
! 1240: }
! 1241:
! 1242: while (exp < 0) {
! 1243: val /= 10;
! 1244: exp++;
! 1245: }
! 1246:
! 1247: return (val);
! 1248: }
! 1249:
! 1250: /* Sign extend a n-bit value */
! 1251: long
! 1252: signextend(unsigned long val, int bits)
! 1253: {
! 1254: long msk = (1L << (bits-1))-1;
! 1255:
! 1256: return (-(val & ~msk) | val);
! 1257: }
! 1258:
! 1259: /* Convert IPMI reading from sensor factors */
! 1260: long
! 1261: ipmi_convert(u_int8_t v, struct sdrtype1 *s1, long adj)
! 1262: {
! 1263: short M, B;
! 1264: char K1, K2;
! 1265: long val;
! 1266:
! 1267: /* Calculate linear reading variables */
! 1268: M = signextend((((short)(s1->m_tolerance & 0xC0)) << 2) + s1->m, 10);
! 1269: B = signextend((((short)(s1->b_accuracy & 0xC0)) << 2) + s1->b, 10);
! 1270: K1 = signextend(s1->rbexp & 0xF, 4);
! 1271: K2 = signextend(s1->rbexp >> 4, 4);
! 1272:
! 1273: /* Calculate sensor reading:
! 1274: * y = L((M * v + (B * 10^K1)) * 10^(K2+adj)
! 1275: *
! 1276: * This commutes out to:
! 1277: * y = L(M*v * 10^(K2+adj) + B * 10^(K1+K2+adj)); */
! 1278: val = ipow(M * v, K2 + adj) + ipow(B, K1 + K2 + adj);
! 1279:
! 1280: /* Linearization function: y = f(x) 0 : y = x 1 : y = ln(x) 2 : y =
! 1281: * log10(x) 3 : y = log2(x) 4 : y = e^x 5 : y = 10^x 6 : y = 2^x 7 : y
! 1282: * = 1/x 8 : y = x^2 9 : y = x^3 10 : y = square root(x) 11 : y = cube
! 1283: * root(x) */
! 1284: return (val);
! 1285: }
! 1286:
! 1287: int
! 1288: ipmi_test_threshold(u_int8_t v, u_int8_t valid, u_int8_t hi, u_int8_t lo)
! 1289: {
! 1290: dbg_printf(10, "thresh: %.2x %.2x %.2x %d\n", v, lo, hi,valid);
! 1291: return ((valid & 1 && lo != 0x00 && v <= lo) ||
! 1292: (valid & 8 && hi != 0xFF && v >= hi));
! 1293: }
! 1294:
! 1295: int
! 1296: ipmi_sensor_status(struct ipmi_softc *sc, struct ipmi_sensor *psensor,
! 1297: u_int8_t *reading)
! 1298: {
! 1299: u_int8_t data[32];
! 1300: struct sdrtype1 *s1 = (struct sdrtype1 *)psensor->i_sdr;
! 1301: int rxlen, etype;
! 1302:
! 1303: /* Get reading of sensor */
! 1304: switch (psensor->i_sensor.type) {
! 1305: case SENSOR_TEMP:
! 1306: psensor->i_sensor.value = ipmi_convert(reading[0], s1, 6);
! 1307: psensor->i_sensor.value += 273150000;
! 1308: break;
! 1309:
! 1310: case SENSOR_VOLTS_DC:
! 1311: psensor->i_sensor.value = ipmi_convert(reading[0], s1, 6);
! 1312: break;
! 1313:
! 1314: case SENSOR_FANRPM:
! 1315: psensor->i_sensor.value = ipmi_convert(reading[0], s1, 0);
! 1316: if (((s1->units1>>3)&0x7) == 0x3)
! 1317: psensor->i_sensor.value *= 60; // RPS -> RPM
! 1318: break;
! 1319: default:
! 1320: break;
! 1321: }
! 1322:
! 1323: /* Return Sensor Status */
! 1324: etype = (psensor->etype << 8) + psensor->stype;
! 1325: switch (etype) {
! 1326: case IPMI_SENSOR_TYPE_TEMP:
! 1327: case IPMI_SENSOR_TYPE_VOLT:
! 1328: case IPMI_SENSOR_TYPE_FAN:
! 1329: data[0] = psensor->i_num;
! 1330: if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun,
! 1331: SE_NETFN, SE_GET_SENSOR_THRESHOLD, 1, data) ||
! 1332: ipmi_recvcmd(sc, sizeof(data), &rxlen, data))
! 1333: return (SENSOR_S_UNKNOWN);
! 1334:
! 1335: dbg_printf(25, "recvdata: %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
! 1336: data[0], data[1], data[2], data[3], data[4], data[5],
! 1337: data[6]);
! 1338:
! 1339: if (ipmi_test_threshold(*reading, data[0] >> 2 ,
! 1340: data[6], data[3]))
! 1341: return (SENSOR_S_CRIT);
! 1342:
! 1343: if (ipmi_test_threshold(*reading, data[0] >> 1,
! 1344: data[5], data[2]))
! 1345: return (SENSOR_S_CRIT);
! 1346:
! 1347: if (ipmi_test_threshold(*reading, data[0] ,
! 1348: data[4], data[1]))
! 1349: return (SENSOR_S_WARN);
! 1350:
! 1351: break;
! 1352:
! 1353: case IPMI_SENSOR_TYPE_INTRUSION:
! 1354: psensor->i_sensor.value = (reading[2] & 1) ? 1 : 0;
! 1355: if (reading[2] & 0x1)
! 1356: return (SENSOR_S_CRIT);
! 1357: break;
! 1358:
! 1359: case IPMI_SENSOR_TYPE_PWRSUPPLY:
! 1360: /* Reading: 1 = present+powered, 0 = otherwise */
! 1361: psensor->i_sensor.value = (reading[2] & 1) ? 1 : 0;
! 1362: if (reading[2] & 0x10) {
! 1363: /* XXX: Need sysctl type for Power Supply types
! 1364: * ok: power supply installed && powered
! 1365: * warn: power supply installed && !powered
! 1366: * crit: power supply !installed
! 1367: */
! 1368: return (SENSOR_S_CRIT);
! 1369: }
! 1370: if (reading[2] & 0x08) {
! 1371: /* Power supply AC lost */
! 1372: return (SENSOR_S_WARN);
! 1373: }
! 1374: break;
! 1375: }
! 1376:
! 1377: return (SENSOR_S_OK);
! 1378: }
! 1379:
! 1380: int
! 1381: read_sensor(struct ipmi_softc *sc, struct ipmi_sensor *psensor)
! 1382: {
! 1383: struct sdrtype1 *s1 = (struct sdrtype1 *) psensor->i_sdr;
! 1384: u_int8_t data[8];
! 1385: int rxlen, rv = -1;
! 1386:
! 1387: if (!cold)
! 1388: rw_enter_write(&sc->sc_lock);
! 1389:
! 1390: memset(data, 0, sizeof(data));
! 1391: data[0] = psensor->i_num;
! 1392: if (ipmi_sendcmd(sc, s1->owner_id, s1->owner_lun, SE_NETFN,
! 1393: SE_GET_SENSOR_READING, 1, data))
! 1394: goto done;
! 1395:
! 1396: if (ipmi_recvcmd(sc, sizeof(data), &rxlen, data))
! 1397: goto done;
! 1398:
! 1399: dbg_printf(10, "values=%.2x %.2x %.2x %.2x %s\n",
! 1400: data[0],data[1],data[2],data[3], psensor->i_sensor.desc);
! 1401: psensor->i_sensor.flags &= ~SENSOR_FINVALID;
! 1402: if (data[1] & IPMI_INVALID_SENSOR) {
! 1403: /* Check if sensor is valid */
! 1404: psensor->i_sensor.flags |= SENSOR_FINVALID;
! 1405: }
! 1406: psensor->i_sensor.status = ipmi_sensor_status(sc, psensor, data);
! 1407: rv = 0;
! 1408: done:
! 1409: if (!cold)
! 1410: rw_exit_write(&sc->sc_lock);
! 1411: return (rv);
! 1412: }
! 1413:
! 1414: int
! 1415: ipmi_sensor_type(int type, int ext_type, int entity)
! 1416: {
! 1417: switch (ext_type << 8L | type) {
! 1418: case IPMI_SENSOR_TYPE_TEMP:
! 1419: return (SENSOR_TEMP);
! 1420:
! 1421: case IPMI_SENSOR_TYPE_VOLT:
! 1422: return (SENSOR_VOLTS_DC);
! 1423:
! 1424: case IPMI_SENSOR_TYPE_FAN:
! 1425: return (SENSOR_FANRPM);
! 1426:
! 1427: case IPMI_SENSOR_TYPE_PWRSUPPLY:
! 1428: if (entity == IPMI_ENTITY_PWRSUPPLY)
! 1429: return (SENSOR_INDICATOR);
! 1430: break;
! 1431:
! 1432: case IPMI_SENSOR_TYPE_INTRUSION:
! 1433: return (SENSOR_INDICATOR);
! 1434: }
! 1435:
! 1436: return (-1);
! 1437: }
! 1438:
! 1439: /* Add Sensor to BSD Sysctl interface */
! 1440: int
! 1441: add_sdr_sensor(struct ipmi_softc *sc, u_int8_t *psdr)
! 1442: {
! 1443: int rc;
! 1444: struct sdrtype1 *s1 = (struct sdrtype1 *)psdr;
! 1445: struct sdrtype2 *s2 = (struct sdrtype2 *)psdr;
! 1446: char name[64];
! 1447:
! 1448: switch (s1->sdrhdr.record_type) {
! 1449: case IPMI_SDR_TYPEFULL:
! 1450: ipmi_sensor_name(name, sizeof(name), s1->typelen, s1->name);
! 1451: rc = add_child_sensors(sc, psdr, 1, s1->sensor_num,
! 1452: s1->sensor_type, s1->event_code, 0, s1->entity_id, name);
! 1453: break;
! 1454:
! 1455: case IPMI_SDR_TYPECOMPACT:
! 1456: ipmi_sensor_name(name, sizeof(name), s2->typelen, s2->name);
! 1457: rc = add_child_sensors(sc, psdr, s2->share1 & 0xF,
! 1458: s2->sensor_num, s2->sensor_type, s2->event_code,
! 1459: s2->share2 & 0x7F, s2->entity_id, name);
! 1460: break;
! 1461:
! 1462: default:
! 1463: return (0);
! 1464: }
! 1465:
! 1466: return rc;
! 1467: }
! 1468:
! 1469: int
! 1470: add_child_sensors(struct ipmi_softc *sc, u_int8_t *psdr, int count,
! 1471: int sensor_num, int sensor_type, int ext_type, int sensor_base,
! 1472: int entity, const char *name)
! 1473: {
! 1474: int typ, idx;
! 1475: struct ipmi_sensor *psensor;
! 1476: #ifdef IPMI_DEBUG
! 1477: struct sdrtype1 *s1 = (struct sdrtype1 *)psdr;
! 1478: #endif
! 1479:
! 1480: typ = ipmi_sensor_type(sensor_type, ext_type, entity);
! 1481: if (typ == -1) {
! 1482: dbg_printf(5, "Unknown sensor type:%.2x et:%.2x sn:%.2x "
! 1483: "name:%s\n", sensor_type, ext_type, sensor_num, name);
! 1484: return 0;
! 1485: }
! 1486: for (idx = 0; idx < count; idx++) {
! 1487: psensor = malloc(sizeof(struct ipmi_sensor), M_DEVBUF,
! 1488: M_NOWAIT|M_CANFAIL);
! 1489: if (psensor == NULL)
! 1490: break;
! 1491:
! 1492: memset(psensor, 0, sizeof(struct ipmi_sensor));
! 1493:
! 1494: /* Initialize BSD Sensor info */
! 1495: psensor->i_sdr = psdr;
! 1496: psensor->i_num = sensor_num + idx;
! 1497: psensor->stype = sensor_type;
! 1498: psensor->etype = ext_type;
! 1499: psensor->i_sensor.type = typ;
! 1500: if (count > 1)
! 1501: snprintf(psensor->i_sensor.desc,
! 1502: sizeof(psensor->i_sensor.desc),
! 1503: "%s - %d", name, sensor_base + idx);
! 1504: else
! 1505: strlcpy(psensor->i_sensor.desc, name,
! 1506: sizeof(psensor->i_sensor.desc));
! 1507:
! 1508: dbg_printf(5, "add sensor:%.4x %.2x:%d ent:%.2x:%.2x %s\n",
! 1509: s1->sdrhdr.record_id, s1->sensor_type,
! 1510: typ, s1->entity_id, s1->entity_instance,
! 1511: psensor->i_sensor.desc);
! 1512: if (read_sensor(sc, psensor) == 0) {
! 1513: SLIST_INSERT_HEAD(&ipmi_sensor_list, psensor, list);
! 1514: sensor_attach(&sc->sc_sensordev, &psensor->i_sensor);
! 1515: dbg_printf(5, " reading: %lld [%s]\n",
! 1516: psensor->i_sensor.value,
! 1517: psensor->i_sensor.desc);
! 1518: }
! 1519: }
! 1520:
! 1521: return (1);
! 1522: }
! 1523:
! 1524: /* Interrupt handler */
! 1525: int
! 1526: ipmi_intr(void *arg)
! 1527: {
! 1528: struct ipmi_softc *sc = (struct ipmi_softc *)arg;
! 1529: int v;
! 1530:
! 1531: v = bmc_read(sc, _KCS_STATUS_REGISTER);
! 1532: if (v & KCS_OBF)
! 1533: ++ipmi_nintr;
! 1534:
! 1535: return (0);
! 1536: }
! 1537:
! 1538: /* Handle IPMI Timer - reread sensor values */
! 1539: void
! 1540: ipmi_refresh_sensors(struct ipmi_softc *sc)
! 1541: {
! 1542: if (!ipmi_poll)
! 1543: return;
! 1544:
! 1545: if (SLIST_EMPTY(&ipmi_sensor_list))
! 1546: return;
! 1547:
! 1548: sc->current_sensor = SLIST_NEXT(sc->current_sensor, list);
! 1549: if (sc->current_sensor == NULL)
! 1550: sc->current_sensor = SLIST_FIRST(&ipmi_sensor_list);
! 1551:
! 1552: if (read_sensor(sc, sc->current_sensor)) {
! 1553: dbg_printf(1, "%s: error reading: %s\n", DEVNAME(sc),
! 1554: sc->current_sensor->i_sensor.desc);
! 1555: return;
! 1556: }
! 1557: }
! 1558:
! 1559: int
! 1560: ipmi_map_regs(struct ipmi_softc *sc, struct ipmi_attach_args *ia)
! 1561: {
! 1562: sc->sc_if = ipmi_get_if(ia->iaa_if_type);
! 1563: if (sc->sc_if == NULL)
! 1564: return (-1);
! 1565:
! 1566: if (ia->iaa_if_iotype == 'i')
! 1567: sc->sc_iot = ia->iaa_iot;
! 1568: else
! 1569: sc->sc_iot = ia->iaa_memt;
! 1570:
! 1571: sc->sc_if_rev = ia->iaa_if_rev;
! 1572: sc->sc_if_iospacing = ia->iaa_if_iospacing;
! 1573: if (bus_space_map(sc->sc_iot, ia->iaa_if_iobase,
! 1574: sc->sc_if->nregs * sc->sc_if_iospacing,
! 1575: 0, &sc->sc_ioh)) {
! 1576: printf("%s: bus_space_map(%x %x %x 0 %p) failed\n",
! 1577: DEVNAME(sc),
! 1578: sc->sc_iot, ia->iaa_if_iobase,
! 1579: sc->sc_if->nregs * sc->sc_if_iospacing, &sc->sc_ioh);
! 1580: return (-1);
! 1581: }
! 1582: #if 0
! 1583: if (iaa->if_if_irq != -1)
! 1584: sc->ih = isa_intr_establish(-1, iaa->if_if_irq,
! 1585: iaa->if_irqlvl, IPL_BIO, ipmi_intr, sc, DEVNAME(sc));
! 1586: #endif
! 1587: return (0);
! 1588: }
! 1589:
! 1590: void
! 1591: ipmi_unmap_regs(struct ipmi_softc *sc, struct ipmi_attach_args *ia)
! 1592: {
! 1593: bus_space_unmap(sc->sc_iot, sc->sc_ioh,
! 1594: sc->sc_if->nregs * sc->sc_if_iospacing);
! 1595: }
! 1596:
! 1597: void
! 1598: ipmi_poll_thread(void *arg)
! 1599: {
! 1600: struct ipmi_thread *thread = arg;
! 1601: struct ipmi_softc *sc = thread->sc;
! 1602:
! 1603: while (thread->running) {
! 1604: ipmi_refresh_sensors(sc);
! 1605: tsleep(thread, PWAIT, "ipmi_poll", SENSOR_REFRESH_RATE);
! 1606: }
! 1607: free(thread, M_DEVBUF);
! 1608:
! 1609: kthread_exit(0);
! 1610: }
! 1611:
! 1612: void
! 1613: ipmi_create_thread(void *arg)
! 1614: {
! 1615: struct ipmi_softc *sc = arg;
! 1616:
! 1617: if (kthread_create(ipmi_poll_thread, sc->sc_thread, NULL,
! 1618: DEVNAME(sc)) != 0) {
! 1619: printf("%s: unable to create polling thread, ipmi disabled\n",
! 1620: DEVNAME(sc));
! 1621: return;
! 1622: }
! 1623: }
! 1624:
! 1625: int
! 1626: ipmi_probe(void *aux)
! 1627: {
! 1628: struct ipmi_attach_args *ia = aux;
! 1629: struct dmd_ipmi *pipmi;
! 1630: struct smbtable tbl;
! 1631:
! 1632: tbl.cookie = 0;
! 1633: if (smbios_find_table(SMBIOS_TYPE_IPMIDEV, &tbl))
! 1634: ipmi_smbios_probe(tbl.tblhdr, ia);
! 1635: else {
! 1636: pipmi = (struct dmd_ipmi *)scan_sig(0xC0000L, 0xFFFFFL, 16, 4,
! 1637: "IPMI");
! 1638: /* XXX hack to find Dell PowerEdge 8450 */
! 1639: if (pipmi == NULL) {
! 1640: /* no IPMI found */
! 1641: return (0);
! 1642: }
! 1643:
! 1644: /* we have an IPMI signature, fill in attach arg structure */
! 1645: ia->iaa_if_type = pipmi->dmd_if_type;
! 1646: ia->iaa_if_rev = pipmi->dmd_if_rev;
! 1647: }
! 1648:
! 1649: return (1);
! 1650: }
! 1651:
! 1652: int
! 1653: ipmi_match(struct device *parent, void *match, void *aux)
! 1654: {
! 1655: struct ipmi_softc sc;
! 1656: struct ipmi_attach_args *ia = aux;
! 1657: struct cfdata *cf = match;
! 1658: u_int8_t cmd[32];
! 1659: int len;
! 1660: int rv = 0;
! 1661:
! 1662: if (strcmp(ia->iaa_name, cf->cf_driver->cd_name))
! 1663: return (0);
! 1664:
! 1665: /* XXX local softc is wrong wrong wrong */
! 1666: strlcpy(sc.sc_dev.dv_xname, "ipmi0", sizeof(sc.sc_dev.dv_xname));
! 1667: /* Map registers */
! 1668: if (ipmi_map_regs(&sc, ia) == 0) {
! 1669: sc.sc_if->probe(&sc);
! 1670:
! 1671: /* Identify BMC device early to detect lying bios */
! 1672: if (ipmi_sendcmd(&sc, BMC_SA, 0, APP_NETFN, APP_GET_DEVICE_ID,
! 1673: 0, NULL)) {
! 1674: dbg_printf(1, ": unable to send get device id "
! 1675: "command\n");
! 1676: goto unmap;
! 1677: }
! 1678: if (ipmi_recvcmd(&sc, sizeof(cmd), &len, cmd)) {
! 1679: dbg_printf(1, ": unable to retrieve device id\n");
! 1680: goto unmap;
! 1681: }
! 1682:
! 1683: dbg_dump(1, "bmc data", len, cmd);
! 1684: unmap:
! 1685: rv = 1; /* GETID worked, we got IPMI */
! 1686: ipmi_unmap_regs(&sc, ia);
! 1687: }
! 1688:
! 1689: return (rv);
! 1690: }
! 1691:
! 1692: void
! 1693: ipmi_attach(struct device *parent, struct device *self, void *aux)
! 1694: {
! 1695: struct ipmi_softc *sc = (void *) self;
! 1696: struct ipmi_attach_args *ia = aux;
! 1697: u_int16_t rec;
! 1698:
! 1699: /* Map registers */
! 1700: ipmi_map_regs(sc, ia);
! 1701:
! 1702: /* Scan SDRs, add sensors */
! 1703: for (rec = 0; rec != 0xFFFF;) {
! 1704: if (get_sdr(sc, rec, &rec)) {
! 1705: /* IPMI may have been advertised, but it is stillborn */
! 1706: ipmi_unmap_regs(sc, ia);
! 1707: return;
! 1708: }
! 1709: }
! 1710:
! 1711: sc->sc_thread = malloc(sizeof(struct ipmi_thread), M_DEVBUF,
! 1712: M_NOWAIT|M_CANFAIL);
! 1713: if (sc->sc_thread == NULL) {
! 1714: printf(": unable to allocate thread\n");
! 1715: return;
! 1716: }
! 1717: sc->sc_thread->sc = sc;
! 1718: sc->sc_thread->running = 1;
! 1719:
! 1720: /* initialize sensor list for thread */
! 1721: if (!SLIST_EMPTY(&ipmi_sensor_list))
! 1722: sc->current_sensor = SLIST_FIRST(&ipmi_sensor_list);
! 1723:
! 1724: /* Setup threads */
! 1725: kthread_create_deferred(ipmi_create_thread, sc);
! 1726:
! 1727: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
! 1728: sizeof(sc->sc_sensordev.xname));
! 1729: sensordev_install(&sc->sc_sensordev);
! 1730:
! 1731: printf(": version %d.%d interface %s %sbase 0x%x/%x spacing %d",
! 1732: ia->iaa_if_rev >> 4, ia->iaa_if_rev & 0xF, sc->sc_if->name,
! 1733: ia->iaa_if_iotype == 'i' ? "io" : "mem", ia->iaa_if_iobase,
! 1734: ia->iaa_if_iospacing * sc->sc_if->nregs, ia->iaa_if_iospacing);
! 1735: if (ia->iaa_if_irq != -1)
! 1736: printf(" irq %d", ia->iaa_if_irq);
! 1737: printf("\n");
! 1738:
! 1739: /* setup flag to exclude iic */
! 1740: ipmi_enabled = 1;
! 1741:
! 1742: /* Setup Watchdog timer */
! 1743: sc->sc_wdog_period = 0;
! 1744: wdog_register(sc, ipmi_watchdog);
! 1745:
! 1746: /* lock around read_sensor so that no one messes with the bmc regs */
! 1747: rw_init(&sc->sc_lock, DEVNAME(sc));
! 1748:
! 1749: /* setup ticker */
! 1750: sc->sc_retries = 0;
! 1751: sc->sc_wakeup = 0;
! 1752: sc->sc_max_retries = 50; /* 50 * 1/100 = 0.5 seconds max */
! 1753: timeout_set(&sc->sc_timeout, _bmc_io_wait, sc);
! 1754: }
! 1755:
! 1756: int
! 1757: ipmi_watchdog(void *arg, int period)
! 1758: {
! 1759: struct ipmi_softc *sc = arg;
! 1760: struct ipmi_watchdog wdog;
! 1761: int s, rc, len;
! 1762:
! 1763: if (sc->sc_wdog_period == period) {
! 1764: if (period != 0) {
! 1765: s = splsoftclock();
! 1766: /* tickle the watchdog */
! 1767: rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
! 1768: APP_RESET_WATCHDOG, 0, NULL);
! 1769: rc = ipmi_recvcmd(sc, 0, &len, NULL);
! 1770: splx(s);
! 1771: }
! 1772: return (period);
! 1773: }
! 1774:
! 1775: if (period < 10 && period > 0)
! 1776: period = 10;
! 1777:
! 1778: s = splsoftclock();
! 1779: /* XXX what to do if poking wdog fails? */
! 1780: rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
! 1781: APP_GET_WATCHDOG_TIMER, 0, NULL);
! 1782: rc = ipmi_recvcmd(sc, sizeof(wdog), &len, &wdog);
! 1783:
! 1784: /* Period is 10ths/sec */
! 1785: wdog.wdog_timeout = htole32(period * 10);
! 1786: wdog.wdog_action &= ~IPMI_WDOG_MASK;
! 1787: wdog.wdog_action |= (period == 0) ? IPMI_WDOG_DISABLED :
! 1788: IPMI_WDOG_REBOOT;
! 1789:
! 1790: rc = ipmi_sendcmd(sc, BMC_SA, BMC_LUN, APP_NETFN,
! 1791: APP_SET_WATCHDOG_TIMER, sizeof(wdog), &wdog);
! 1792: rc = ipmi_recvcmd(sc, 0, &len, NULL);
! 1793:
! 1794: splx(s);
! 1795:
! 1796: sc->sc_wdog_period = period;
! 1797: return (period);
! 1798: }
CVSweb