[BACK]Return to ipmi.c CVS log [TXT][DIR] Up to [local] / sys / dev

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