qemu/hw/ipmi/isa_ipmi_bt.c
<<
>>
Prefs
   1/*
   2 * QEMU ISA IPMI BT emulation
   3 *
   4 * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include "qemu/osdep.h"
  25#include "qemu/log.h"
  26#include "qapi/error.h"
  27#include "hw/hw.h"
  28#include "hw/ipmi/ipmi.h"
  29#include "hw/isa/isa.h"
  30
  31/* Control register */
  32#define IPMI_BT_CLR_WR_BIT         0
  33#define IPMI_BT_CLR_RD_BIT         1
  34#define IPMI_BT_H2B_ATN_BIT        2
  35#define IPMI_BT_B2H_ATN_BIT        3
  36#define IPMI_BT_SMS_ATN_BIT        4
  37#define IPMI_BT_HBUSY_BIT          6
  38#define IPMI_BT_BBUSY_BIT          7
  39
  40#define IPMI_BT_GET_CLR_WR(d)      (((d) >> IPMI_BT_CLR_WR_BIT) & 0x1)
  41
  42#define IPMI_BT_GET_CLR_RD(d)      (((d) >> IPMI_BT_CLR_RD_BIT) & 0x1)
  43
  44#define IPMI_BT_GET_H2B_ATN(d)     (((d) >> IPMI_BT_H2B_ATN_BIT) & 0x1)
  45
  46#define IPMI_BT_B2H_ATN_MASK       (1 << IPMI_BT_B2H_ATN_BIT)
  47#define IPMI_BT_GET_B2H_ATN(d)     (((d) >> IPMI_BT_B2H_ATN_BIT) & 0x1)
  48#define IPMI_BT_SET_B2H_ATN(d, v)  ((d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \
  49                                        (!!(v) << IPMI_BT_B2H_ATN_BIT)))
  50
  51#define IPMI_BT_SMS_ATN_MASK       (1 << IPMI_BT_SMS_ATN_BIT)
  52#define IPMI_BT_GET_SMS_ATN(d)     (((d) >> IPMI_BT_SMS_ATN_BIT) & 0x1)
  53#define IPMI_BT_SET_SMS_ATN(d, v)  ((d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \
  54                                        (!!(v) << IPMI_BT_SMS_ATN_BIT)))
  55
  56#define IPMI_BT_HBUSY_MASK         (1 << IPMI_BT_HBUSY_BIT)
  57#define IPMI_BT_GET_HBUSY(d)       (((d) >> IPMI_BT_HBUSY_BIT) & 0x1)
  58#define IPMI_BT_SET_HBUSY(d, v)    ((d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \
  59                                       (!!(v) << IPMI_BT_HBUSY_BIT)))
  60
  61#define IPMI_BT_BBUSY_MASK         (1 << IPMI_BT_BBUSY_BIT)
  62#define IPMI_BT_SET_BBUSY(d, v)    ((d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \
  63                                       (!!(v) << IPMI_BT_BBUSY_BIT)))
  64
  65
  66/* Mask register */
  67#define IPMI_BT_B2H_IRQ_EN_BIT     0
  68#define IPMI_BT_B2H_IRQ_BIT        1
  69
  70#define IPMI_BT_B2H_IRQ_EN_MASK      (1 << IPMI_BT_B2H_IRQ_EN_BIT)
  71#define IPMI_BT_GET_B2H_IRQ_EN(d)    (((d) >> IPMI_BT_B2H_IRQ_EN_BIT) & 0x1)
  72#define IPMI_BT_SET_B2H_IRQ_EN(d, v) ((d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) |\
  73                                        (!!(v) << IPMI_BT_B2H_IRQ_EN_BIT)))
  74
  75#define IPMI_BT_B2H_IRQ_MASK         (1 << IPMI_BT_B2H_IRQ_BIT)
  76#define IPMI_BT_GET_B2H_IRQ(d)       (((d) >> IPMI_BT_B2H_IRQ_BIT) & 0x1)
  77#define IPMI_BT_SET_B2H_IRQ(d, v)    ((d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \
  78                                        (!!(v) << IPMI_BT_B2H_IRQ_BIT)))
  79
  80typedef struct IPMIBT {
  81    IPMIBmc *bmc;
  82
  83    bool do_wake;
  84
  85    qemu_irq irq;
  86
  87    uint32_t io_base;
  88    unsigned long io_length;
  89    MemoryRegion io;
  90
  91    bool obf_irq_set;
  92    bool atn_irq_set;
  93    bool use_irq;
  94    bool irqs_enabled;
  95
  96    uint8_t outmsg[MAX_IPMI_MSG_SIZE];
  97    uint32_t outpos;
  98    uint32_t outlen;
  99
 100    uint8_t inmsg[MAX_IPMI_MSG_SIZE];
 101    uint32_t inlen;
 102
 103    uint8_t control_reg;
 104    uint8_t mask_reg;
 105
 106    /*
 107     * This is a response number that we send with the command to make
 108     * sure that the response matches the command.
 109     */
 110    uint8_t waiting_rsp;
 111    uint8_t waiting_seq;
 112} IPMIBT;
 113
 114#define IPMI_CMD_GET_BT_INTF_CAP        0x36
 115
 116static void ipmi_bt_handle_event(IPMIInterface *ii)
 117{
 118    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 119    IPMIBT *ib = iic->get_backend_data(ii);
 120
 121    if (ib->inlen < 4) {
 122        goto out;
 123    }
 124    /* Note that overruns are handled by handle_command */
 125    if (ib->inmsg[0] != (ib->inlen - 1)) {
 126        /* Length mismatch, just ignore. */
 127        IPMI_BT_SET_BBUSY(ib->control_reg, 1);
 128        ib->inlen = 0;
 129        goto out;
 130    }
 131    if ((ib->inmsg[1] == (IPMI_NETFN_APP << 2)) &&
 132                        (ib->inmsg[3] == IPMI_CMD_GET_BT_INTF_CAP)) {
 133        /* We handle this one ourselves. */
 134        ib->outmsg[0] = 9;
 135        ib->outmsg[1] = ib->inmsg[1] | 0x04;
 136        ib->outmsg[2] = ib->inmsg[2];
 137        ib->outmsg[3] = ib->inmsg[3];
 138        ib->outmsg[4] = 0;
 139        ib->outmsg[5] = 1; /* Only support 1 outstanding request. */
 140        if (sizeof(ib->inmsg) > 0xff) { /* Input buffer size */
 141            ib->outmsg[6] = 0xff;
 142        } else {
 143            ib->outmsg[6] = (unsigned char) sizeof(ib->inmsg);
 144        }
 145        if (sizeof(ib->outmsg) > 0xff) { /* Output buffer size */
 146            ib->outmsg[7] = 0xff;
 147        } else {
 148            ib->outmsg[7] = (unsigned char) sizeof(ib->outmsg);
 149        }
 150        ib->outmsg[8] = 10; /* Max request to response time */
 151        ib->outmsg[9] = 0; /* Don't recommend retries */
 152        ib->outlen = 10;
 153        IPMI_BT_SET_BBUSY(ib->control_reg, 0);
 154        IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
 155        if (ib->use_irq && ib->irqs_enabled &&
 156                !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
 157                IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 158            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 159            qemu_irq_raise(ib->irq);
 160        }
 161        goto out;
 162    }
 163    ib->waiting_seq = ib->inmsg[2];
 164    ib->inmsg[2] = ib->inmsg[1];
 165    {
 166        IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ib->bmc);
 167        bk->handle_command(ib->bmc, ib->inmsg + 2, ib->inlen - 2,
 168                           sizeof(ib->inmsg), ib->waiting_rsp);
 169    }
 170 out:
 171    return;
 172}
 173
 174static void ipmi_bt_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
 175                                unsigned char *rsp, unsigned int rsp_len)
 176{
 177    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 178    IPMIBT *ib = iic->get_backend_data(ii);
 179
 180    if (ib->waiting_rsp == msg_id) {
 181        ib->waiting_rsp++;
 182        if (rsp_len > (sizeof(ib->outmsg) - 2)) {
 183            ib->outmsg[0] = 4;
 184            ib->outmsg[1] = rsp[0];
 185            ib->outmsg[2] = ib->waiting_seq;
 186            ib->outmsg[3] = rsp[1];
 187            ib->outmsg[4] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
 188            ib->outlen = 5;
 189        } else {
 190            ib->outmsg[0] = rsp_len + 1;
 191            ib->outmsg[1] = rsp[0];
 192            ib->outmsg[2] = ib->waiting_seq;
 193            memcpy(ib->outmsg + 3, rsp + 1, rsp_len - 1);
 194            ib->outlen = rsp_len + 2;
 195        }
 196        IPMI_BT_SET_BBUSY(ib->control_reg, 0);
 197        IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
 198        if (ib->use_irq && ib->irqs_enabled &&
 199                !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
 200                IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 201            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 202            qemu_irq_raise(ib->irq);
 203        }
 204    }
 205}
 206
 207
 208static uint64_t ipmi_bt_ioport_read(void *opaque, hwaddr addr, unsigned size)
 209{
 210    IPMIInterface *ii = opaque;
 211    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 212    IPMIBT *ib = iic->get_backend_data(ii);
 213    uint32_t ret = 0xff;
 214
 215    switch (addr & 3) {
 216    case 0:
 217        ret = ib->control_reg;
 218        break;
 219    case 1:
 220        if (ib->outpos < ib->outlen) {
 221            ret = ib->outmsg[ib->outpos];
 222            ib->outpos++;
 223            if (ib->outpos == ib->outlen) {
 224                ib->outpos = 0;
 225                ib->outlen = 0;
 226            }
 227        } else {
 228            ret = 0xff;
 229        }
 230        break;
 231    case 2:
 232        ret = ib->mask_reg;
 233        break;
 234    }
 235    return ret;
 236}
 237
 238static void ipmi_bt_signal(IPMIBT *ib, IPMIInterface *ii)
 239{
 240    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 241
 242    ib->do_wake = 1;
 243    while (ib->do_wake) {
 244        ib->do_wake = 0;
 245        iic->handle_if_event(ii);
 246    }
 247}
 248
 249static void ipmi_bt_ioport_write(void *opaque, hwaddr addr, uint64_t val,
 250                                 unsigned size)
 251{
 252    IPMIInterface *ii = opaque;
 253    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 254    IPMIBT *ib = iic->get_backend_data(ii);
 255
 256    switch (addr & 3) {
 257    case 0:
 258        if (IPMI_BT_GET_CLR_WR(val)) {
 259            ib->inlen = 0;
 260        }
 261        if (IPMI_BT_GET_CLR_RD(val)) {
 262            ib->outpos = 0;
 263        }
 264        if (IPMI_BT_GET_B2H_ATN(val)) {
 265            IPMI_BT_SET_B2H_ATN(ib->control_reg, 0);
 266        }
 267        if (IPMI_BT_GET_SMS_ATN(val)) {
 268            IPMI_BT_SET_SMS_ATN(ib->control_reg, 0);
 269        }
 270        if (IPMI_BT_GET_HBUSY(val)) {
 271            /* Toggle */
 272            IPMI_BT_SET_HBUSY(ib->control_reg,
 273                              !IPMI_BT_GET_HBUSY(ib->control_reg));
 274        }
 275        if (IPMI_BT_GET_H2B_ATN(val)) {
 276            IPMI_BT_SET_BBUSY(ib->control_reg, 1);
 277            ipmi_bt_signal(ib, ii);
 278        }
 279        break;
 280
 281    case 1:
 282        if (ib->inlen < sizeof(ib->inmsg)) {
 283            ib->inmsg[ib->inlen] = val;
 284        }
 285        ib->inlen++;
 286        break;
 287
 288    case 2:
 289        if (IPMI_BT_GET_B2H_IRQ_EN(val) !=
 290                        IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 291            if (IPMI_BT_GET_B2H_IRQ_EN(val)) {
 292                if (IPMI_BT_GET_B2H_ATN(ib->control_reg) ||
 293                        IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
 294                    IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 295                    qemu_irq_raise(ib->irq);
 296                }
 297                IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 1);
 298            } else {
 299                if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 300                    IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 301                    qemu_irq_lower(ib->irq);
 302                }
 303                IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
 304            }
 305        }
 306        if (IPMI_BT_GET_B2H_IRQ(val) && IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 307            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 308            qemu_irq_lower(ib->irq);
 309        }
 310        break;
 311    }
 312}
 313
 314static const MemoryRegionOps ipmi_bt_io_ops = {
 315    .read = ipmi_bt_ioport_read,
 316    .write = ipmi_bt_ioport_write,
 317    .impl = {
 318        .min_access_size = 1,
 319        .max_access_size = 1,
 320    },
 321    .endianness = DEVICE_LITTLE_ENDIAN,
 322};
 323
 324static void ipmi_bt_set_atn(IPMIInterface *ii, int val, int irq)
 325{
 326    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 327    IPMIBT *ib = iic->get_backend_data(ii);
 328
 329    if (!!val == IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
 330        return;
 331    }
 332
 333    IPMI_BT_SET_SMS_ATN(ib->control_reg, val);
 334    if (val) {
 335        if (irq && ib->use_irq && ib->irqs_enabled &&
 336                !IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
 337                IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 338            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 339            qemu_irq_raise(ib->irq);
 340        }
 341    } else {
 342        if (!IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
 343                IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 344            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 345            qemu_irq_lower(ib->irq);
 346        }
 347    }
 348}
 349
 350static void ipmi_bt_handle_reset(IPMIInterface *ii, bool is_cold)
 351{
 352    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 353    IPMIBT *ib = iic->get_backend_data(ii);
 354
 355    if (is_cold) {
 356        /* Disable the BT interrupt on reset */
 357        if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 358            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 359            qemu_irq_lower(ib->irq);
 360        }
 361        IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
 362    }
 363}
 364
 365static void ipmi_bt_set_irq_enable(IPMIInterface *ii, int val)
 366{
 367    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 368    IPMIBT *ib = iic->get_backend_data(ii);
 369
 370    ib->irqs_enabled = val;
 371}
 372
 373static void ipmi_bt_init(IPMIInterface *ii, Error **errp)
 374{
 375    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 376    IPMIBT *ib = iic->get_backend_data(ii);
 377
 378    ib->io_length = 3;
 379
 380    memory_region_init_io(&ib->io, NULL, &ipmi_bt_io_ops, ii, "ipmi-bt", 3);
 381}
 382
 383
 384#define TYPE_ISA_IPMI_BT "isa-ipmi-bt"
 385#define ISA_IPMI_BT(obj) OBJECT_CHECK(ISAIPMIBTDevice, (obj), \
 386                                       TYPE_ISA_IPMI_BT)
 387
 388typedef struct ISAIPMIBTDevice {
 389    ISADevice dev;
 390    int32_t isairq;
 391    IPMIBT bt;
 392    uint32_t uuid;
 393} ISAIPMIBTDevice;
 394
 395static void ipmi_bt_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info)
 396{
 397    ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii);
 398
 399    info->interface_name = "bt";
 400    info->interface_type = IPMI_SMBIOS_BT;
 401    info->ipmi_spec_major_revision = 2;
 402    info->ipmi_spec_minor_revision = 0;
 403    info->base_address = iib->bt.io_base;
 404    info->register_length = iib->bt.io_length;
 405    info->register_spacing = 1;
 406    info->memspace = IPMI_MEMSPACE_IO;
 407    info->irq_type = IPMI_LEVEL_IRQ;
 408    info->interrupt_number = iib->isairq;
 409    info->i2c_slave_address = iib->bt.bmc->slave_addr;
 410    info->uuid = iib->uuid;
 411}
 412
 413static void ipmi_bt_class_init(IPMIInterfaceClass *iic)
 414{
 415    iic->init = ipmi_bt_init;
 416    iic->set_atn = ipmi_bt_set_atn;
 417    iic->handle_rsp = ipmi_bt_handle_rsp;
 418    iic->handle_if_event = ipmi_bt_handle_event;
 419    iic->set_irq_enable = ipmi_bt_set_irq_enable;
 420    iic->reset = ipmi_bt_handle_reset;
 421    iic->get_fwinfo = ipmi_bt_get_fwinfo;
 422}
 423
 424static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
 425{
 426    ISADevice *isadev = ISA_DEVICE(dev);
 427    ISAIPMIBTDevice *iib = ISA_IPMI_BT(dev);
 428    IPMIInterface *ii = IPMI_INTERFACE(dev);
 429    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 430
 431    if (!iib->bt.bmc) {
 432        error_setg(errp, "IPMI device requires a bmc attribute to be set");
 433        return;
 434    }
 435
 436    iib->uuid = ipmi_next_uuid();
 437
 438    iib->bt.bmc->intf = ii;
 439
 440    iic->init(ii, errp);
 441    if (*errp)
 442        return;
 443
 444    if (iib->isairq > 0) {
 445        isa_init_irq(isadev, &iib->bt.irq, iib->isairq);
 446        iib->bt.use_irq = 1;
 447    }
 448
 449    qdev_set_legacy_instance_id(dev, iib->bt.io_base, iib->bt.io_length);
 450
 451    isa_register_ioport(isadev, &iib->bt.io, iib->bt.io_base);
 452}
 453
 454static int ipmi_bt_vmstate_post_load(void *opaque, int version)
 455{
 456    IPMIBT *ib = opaque;
 457
 458    /* Make sure all the values are sane. */
 459    if (ib->outpos >= MAX_IPMI_MSG_SIZE || ib->outlen >= MAX_IPMI_MSG_SIZE ||
 460        ib->outpos >= ib->outlen) {
 461        qemu_log_mask(LOG_GUEST_ERROR,
 462                      "ipmi:bt: vmstate transfer received bad out values: %d %d\n",
 463                      ib->outpos, ib->outlen);
 464        ib->outpos = 0;
 465        ib->outlen = 0;
 466    }
 467
 468    if (ib->inlen >= MAX_IPMI_MSG_SIZE) {
 469        qemu_log_mask(LOG_GUEST_ERROR,
 470                      "ipmi:bt: vmstate transfer received bad in value: %d\n",
 471                      ib->inlen);
 472        ib->inlen = 0;
 473    }
 474
 475    return 0;
 476}
 477
 478const VMStateDescription vmstate_IPMIBT = {
 479    .name = TYPE_IPMI_INTERFACE_PREFIX "bt",
 480    .version_id = 1,
 481    .minimum_version_id = 1,
 482    .post_load = ipmi_bt_vmstate_post_load,
 483    .fields      = (VMStateField[]) {
 484        VMSTATE_BOOL(obf_irq_set, IPMIBT),
 485        VMSTATE_BOOL(atn_irq_set, IPMIBT),
 486        VMSTATE_BOOL(irqs_enabled, IPMIBT),
 487        VMSTATE_UINT32(outpos, IPMIBT),
 488        VMSTATE_UINT32(outlen, IPMIBT),
 489        VMSTATE_UINT8_ARRAY(outmsg, IPMIBT, MAX_IPMI_MSG_SIZE),
 490        VMSTATE_UINT32(inlen, IPMIBT),
 491        VMSTATE_UINT8_ARRAY(inmsg, IPMIBT, MAX_IPMI_MSG_SIZE),
 492        VMSTATE_UINT8(control_reg, IPMIBT),
 493        VMSTATE_UINT8(mask_reg, IPMIBT),
 494        VMSTATE_UINT8(waiting_rsp, IPMIBT),
 495        VMSTATE_UINT8(waiting_seq, IPMIBT),
 496        VMSTATE_END_OF_LIST()
 497    }
 498};
 499
 500static const VMStateDescription vmstate_ISAIPMIBTDevice = {
 501    .name = TYPE_IPMI_INTERFACE_PREFIX "isa-bt",
 502    .version_id = 2,
 503    .minimum_version_id = 2,
 504    /*
 505     * Version 1 had messed up the array transfer, it's not even usable
 506     * because it used VMSTATE_VBUFFER_UINT32, but it did not transfer
 507     * the buffer length, so random things would happen.
 508     */
 509    .fields      = (VMStateField[]) {
 510        VMSTATE_STRUCT(bt, ISAIPMIBTDevice, 1, vmstate_IPMIBT, IPMIBT),
 511        VMSTATE_END_OF_LIST()
 512    }
 513};
 514
 515static void isa_ipmi_bt_init(Object *obj)
 516{
 517    ISAIPMIBTDevice *iib = ISA_IPMI_BT(obj);
 518
 519    ipmi_bmc_find_and_link(obj, (Object **) &iib->bt.bmc);
 520
 521    vmstate_register(NULL, 0, &vmstate_ISAIPMIBTDevice, iib);
 522}
 523
 524static void *isa_ipmi_bt_get_backend_data(IPMIInterface *ii)
 525{
 526    ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii);
 527
 528    return &iib->bt;
 529}
 530
 531static Property ipmi_isa_properties[] = {
 532    DEFINE_PROP_UINT32("ioport", ISAIPMIBTDevice, bt.io_base,  0xe4),
 533    DEFINE_PROP_INT32("irq",   ISAIPMIBTDevice, isairq,  5),
 534    DEFINE_PROP_END_OF_LIST(),
 535};
 536
 537static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data)
 538{
 539    DeviceClass *dc = DEVICE_CLASS(oc);
 540    IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
 541
 542    dc->realize = isa_ipmi_bt_realize;
 543    dc->props = ipmi_isa_properties;
 544
 545    iic->get_backend_data = isa_ipmi_bt_get_backend_data;
 546    ipmi_bt_class_init(iic);
 547}
 548
 549static const TypeInfo isa_ipmi_bt_info = {
 550    .name          = TYPE_ISA_IPMI_BT,
 551    .parent        = TYPE_ISA_DEVICE,
 552    .instance_size = sizeof(ISAIPMIBTDevice),
 553    .instance_init = isa_ipmi_bt_init,
 554    .class_init    = isa_ipmi_bt_class_init,
 555    .interfaces = (InterfaceInfo[]) {
 556        { TYPE_IPMI_INTERFACE },
 557        { }
 558    }
 559};
 560
 561static void ipmi_register_types(void)
 562{
 563    type_register_static(&isa_ipmi_bt_info);
 564}
 565
 566type_init(ipmi_register_types)
 567