pci-hotplug.c 9.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
 * QEMU PCI hotplug support
 *
 * Copyright (c) 2004 Fabrice Bellard
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "hw.h"
#include "boards.h"
#include "pci.h"
#include "net.h"
#include "sysemu.h"
#include "pc.h"
A
aliguori 已提交
31
#include "monitor.h"
32
#include "block_int.h"
G
Gerd Hoffmann 已提交
33
#include "scsi.h"
34
#include "virtio-blk.h"
M
Mark McLoughlin 已提交
35
#include "qemu-config.h"
36
#include "qemu-objects.h"
37

38
#if defined(TARGET_I386)
39
static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
M
Mark McLoughlin 已提交
40 41
                                       const char *devaddr,
                                       const char *opts_str)
42
{
M
Mark McLoughlin 已提交
43
    QemuOpts *opts;
44 45 46 47 48 49 50 51 52 53 54 55
    PCIBus *bus;
    int ret, devfn;

    bus = pci_get_bus_devfn(&devfn, devaddr);
    if (!bus) {
        monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
        return NULL;
    }
    if (!((BusState*)bus)->allow_hotplug) {
        monitor_printf(mon, "PCI bus doesn't support hotplug\n");
        return NULL;
    }
56

57
    opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", 0);
M
Mark McLoughlin 已提交
58 59 60 61 62 63
    if (!opts) {
        return NULL;
    }

    qemu_opt_set(opts, "type", "nic");

M
Mark McLoughlin 已提交
64
    ret = net_client_init(mon, opts, 0);
65
    if (ret < 0)
66
        return NULL;
67 68 69 70
    if (nd_table[ret].devaddr) {
        monitor_printf(mon, "Parameter addr not supported\n");
        return NULL;
    }
71
    return pci_nic_init(&nd_table[ret], "rtl8139", devaddr);
72 73
}

74 75
static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
                        DriveInfo *dinfo, int printinfo)
76 77 78 79 80 81
{
    SCSIBus *scsibus;
    SCSIDevice *scsidev;

    scsibus = DO_UPCAST(SCSIBus, qbus, QLIST_FIRST(&adapter->child_bus));
    if (!scsibus || strcmp(scsibus->qbus.info->name, "SCSI") != 0) {
82
        error_report("Device is not a SCSI adapter");
83 84 85 86 87 88 89 90 91 92 93 94 95
        return -1;
    }

    /*
     * drive_init() tries to find a default for dinfo->unit.  Doesn't
     * work at all for hotplug though as we assign the device to a
     * specific bus instead of the first bus with spare scsi ids.
     *
     * Ditch the calculated value and reload from option string (if
     * specified).
     */
    dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
    scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo, dinfo->unit);
G
Gerd Hoffmann 已提交
96
    dinfo->unit = scsidev->id;
97 98

    if (printinfo)
99 100
        monitor_printf(mon, "OK bus %d, unit %d\n",
                       scsibus->busnr, scsidev->id);
101 102 103
    return 0;
}

104
void drive_hot_add(Monitor *mon, const QDict *qdict)
105 106 107
{
    int dom, pci_bus;
    unsigned slot;
108
    int type;
109
    PCIDevice *dev;
G
Gerd Hoffmann 已提交
110
    DriveInfo *dinfo = NULL;
111 112
    const char *pci_addr = qdict_get_str(qdict, "pci_addr");
    const char *opts = qdict_get_str(qdict, "opts");
113

G
Gerd Hoffmann 已提交
114 115
    dinfo = add_init_drive(opts);
    if (!dinfo)
G
Gerd Hoffmann 已提交
116
        goto err;
G
Gerd Hoffmann 已提交
117
    if (dinfo->devaddr) {
118
        monitor_printf(mon, "Parameter addr not supported\n");
G
Gerd Hoffmann 已提交
119
        goto err;
120
    }
G
Gerd Hoffmann 已提交
121
    type = dinfo->type;
122 123 124

    switch (type) {
    case IF_SCSI:
G
Gerd Hoffmann 已提交
125 126 127
        if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) {
            goto err;
        }
128
        dev = pci_find_device(pci_find_root_bus(0), pci_bus, slot, 0);
G
Gerd Hoffmann 已提交
129 130 131 132
        if (!dev) {
            monitor_printf(mon, "no pci device with address %s\n", pci_addr);
            goto err;
        }
133
        if (scsi_hot_add(mon, &dev->qdev, dinfo, 1) != 0) {
134 135
            goto err;
        }
136
        break;
G
Gerd Hoffmann 已提交
137 138 139
    case IF_NONE:
        monitor_printf(mon, "OK\n");
        break;
140
    default:
A
aliguori 已提交
141
        monitor_printf(mon, "Can't hot-add drive to type %d\n", type);
G
Gerd Hoffmann 已提交
142
        goto err;
143
    }
G
Gerd Hoffmann 已提交
144
    return;
145

G
Gerd Hoffmann 已提交
146 147 148
err:
    if (dinfo)
        drive_uninit(dinfo);
149 150 151
    return;
}

152 153
static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
                                           const char *devaddr,
A
aliguori 已提交
154
                                           const char *opts)
155
{
156
    PCIDevice *dev;
157
    DriveInfo *dinfo = NULL;
G
Gerd Hoffmann 已提交
158
    int type = -1;
159
    char buf[128];
160 161
    PCIBus *bus;
    int devfn;
162 163 164 165 166 167

    if (get_param_value(buf, sizeof(buf), "if", opts)) {
        if (!strcmp(buf, "scsi"))
            type = IF_SCSI;
        else if (!strcmp(buf, "virtio")) {
            type = IF_VIRTIO;
168 169
        } else {
            monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf);
170
            return NULL;
171 172
        }
    } else {
A
aliguori 已提交
173
        monitor_printf(mon, "no if= specified\n");
174
        return NULL;
175 176 177
    }

    if (get_param_value(buf, sizeof(buf), "file", opts)) {
G
Gerd Hoffmann 已提交
178 179
        dinfo = add_init_drive(opts);
        if (!dinfo)
180
            return NULL;
G
Gerd Hoffmann 已提交
181
        if (dinfo->devaddr) {
182 183 184
            monitor_printf(mon, "Parameter addr not supported\n");
            return NULL;
        }
185 186
    } else {
        dinfo = NULL;
187 188
    }

189 190 191 192 193
    bus = pci_get_bus_devfn(&devfn, devaddr);
    if (!bus) {
        monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
        return NULL;
    }
194 195 196 197
    if (!((BusState*)bus)->allow_hotplug) {
        monitor_printf(mon, "PCI bus doesn't support hotplug\n");
        return NULL;
    }
198

199 200
    switch (type) {
    case IF_SCSI:
201
        dev = pci_create(bus, devfn, "lsi53c895a");
202 203
        if (qdev_init(&dev->qdev) < 0)
            dev = NULL;
204
        if (dev && dinfo) {
205
            if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) {
206 207 208
                qdev_unplug(&dev->qdev);
                dev = NULL;
            }
209
        }
210 211
        break;
    case IF_VIRTIO:
212 213 214 215
        if (!dinfo) {
            monitor_printf(mon, "virtio requires a backing file/device.\n");
            return NULL;
        }
216
        dev = pci_create(bus, devfn, "virtio-blk-pci");
G
Gerd Hoffmann 已提交
217
        qdev_prop_set_drive(&dev->qdev, "drive", dinfo);
218 219
        if (qdev_init(&dev->qdev) < 0)
            dev = NULL;
220
        break;
221 222
    default:
        dev = NULL;
223
    }
224
    return dev;
225 226
}

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
void pci_device_hot_add_print(Monitor *mon, const QObject *data)
{
    QDict *qdict;

    assert(qobject_type(data) == QTYPE_QDICT);
    qdict = qobject_to_qdict(data);

    monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
                   (int) qdict_get_int(qdict, "domain"),
                   (int) qdict_get_int(qdict, "bus"),
                   (int) qdict_get_int(qdict, "slot"),
                   (int) qdict_get_int(qdict, "function"));

}

/**
 * pci_device_hot_add(): Hot add a PCI device
 *
 * Return a QDict with the following device information:
 *
 * - "domain": domain number
 * - "bus": bus number
 * - "slot": slot number
 * - "function": function number
 *
 * Example:
 *
 * { "domain": 0, "bus": 0, "slot": 5, "function": 0 }
 */
256
int pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
257 258
{
    PCIDevice *dev = NULL;
259 260 261
    const char *pci_addr = qdict_get_str(qdict, "pci_addr");
    const char *type = qdict_get_str(qdict, "type");
    const char *opts = qdict_get_try_str(qdict, "opts");
262

263 264 265
    /* strip legacy tag */
    if (!strncmp(pci_addr, "pci_addr=", 9)) {
        pci_addr += 9;
266 267
    }

268 269 270 271
    if (!opts) {
        opts = "";
    }

272 273
    if (!strcmp(pci_addr, "auto"))
        pci_addr = NULL;
274

275
    if (strcmp(type, "nic") == 0) {
276
        dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
277
    } else if (strcmp(type, "storage") == 0) {
278
        dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
279
    } else {
A
aliguori 已提交
280
        monitor_printf(mon, "invalid type: %s\n", type);
281 282
        return -1;
    }
283 284

    if (dev) {
285 286 287 288
        *ret_data =
        qobject_from_jsonf("{ 'domain': 0, 'bus': %d, 'slot': %d, "
                           "'function': %d }", pci_bus_num(dev->bus),
                           PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
289
    } else {
A
aliguori 已提交
290
        monitor_printf(mon, "failed to add %s\n", opts);
291 292 293 294
        return -1;
    }

    return 0;
295 296 297
}
#endif

298
int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
299 300 301 302 303
{
    PCIDevice *d;
    int dom, bus;
    unsigned slot;

304
    if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) {
305
        return -1;
306 307
    }

308
    d = pci_find_device(pci_find_root_bus(0), bus, slot, 0);
309
    if (!d) {
A
aliguori 已提交
310
        monitor_printf(mon, "slot %d empty\n", slot);
311
        return -1;
312
    }
313
    return qdev_unplug(&d->qdev);
314 315
}

316 317
int do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
                             QObject **ret_data)
318
{
319
    return pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr"));
320
}