pci-hotplug.c 8.9 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

M
Mark McLoughlin 已提交
57 58 59 60 61 62 63 64 65
    opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", NULL);
    if (!opts) {
        monitor_printf(mon, "parsing network options '%s' failed\n",
                       opts_str ? opts_str : "");
        return NULL;
    }

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

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

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
static int scsi_hot_add(DeviceState *adapter, DriveInfo *dinfo, int printinfo)
{
    SCSIBus *scsibus;
    SCSIDevice *scsidev;

    scsibus = DO_UPCAST(SCSIBus, qbus, QLIST_FIRST(&adapter->child_bus));
    if (!scsibus || strcmp(scsibus->qbus.info->name, "SCSI") != 0) {
        qemu_error("Device is not a SCSI adapter\n");
        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 已提交
97
    dinfo->unit = scsidev->id;
98 99 100 101 102 103

    if (printinfo)
        qemu_error("OK bus %d, unit %d\n", scsibus->busnr, scsidev->id);
    return 0;
}

104
void drive_hot_add(Monitor *mon, const QDict *qdict)
105 106 107
{
    int dom, pci_bus;
    unsigned slot;
G
Gerd Hoffmann 已提交
108
    int type, bus;
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 125
    bus = drive_get_max_bus (type);

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

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

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

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

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

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

200 201
    switch (type) {
    case IF_SCSI:
202
        dev = pci_create(bus, devfn, "lsi53c895a");
203 204
        if (qdev_init(&dev->qdev) < 0)
            dev = NULL;
205
        if (dev && dinfo) {
206 207 208 209
            if (scsi_hot_add(&dev->qdev, dinfo, 0) != 0) {
                qdev_unplug(&dev->qdev);
                dev = NULL;
            }
210
        }
211 212
        break;
    case IF_VIRTIO:
213 214 215 216
        if (!dinfo) {
            monitor_printf(mon, "virtio requires a backing file/device.\n");
            return NULL;
        }
217
        dev = pci_create(bus, devfn, "virtio-blk-pci");
G
Gerd Hoffmann 已提交
218
        qdev_prop_set_drive(&dev->qdev, "drive", dinfo);
219 220
        if (qdev_init(&dev->qdev) < 0)
            dev = NULL;
221
        break;
222 223
    default:
        dev = NULL;
224
    }
225
    return dev;
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 256 257
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 }
 */
void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
258 259
{
    PCIDevice *dev = NULL;
260 261 262
    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");
263

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

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

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

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

    if (dev) {
284 285 286 287
        *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));
288
    } else
A
aliguori 已提交
289
        monitor_printf(mon, "failed to add %s\n", opts);
290 291 292
}
#endif

A
aliguori 已提交
293
void pci_device_hot_remove(Monitor *mon, const char *pci_addr)
294 295 296 297 298
{
    PCIDevice *d;
    int dom, bus;
    unsigned slot;

299
    if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) {
300 301 302
        return;
    }

303
    d = pci_find_device(pci_find_root_bus(0), bus, slot, 0);
304
    if (!d) {
A
aliguori 已提交
305
        monitor_printf(mon, "slot %d empty\n", slot);
306 307
        return;
    }
G
Gerd Hoffmann 已提交
308
    qdev_unplug(&d->qdev);
309 310
}

311 312
void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
                              QObject **ret_data)
313
{
314
    pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr"));
315
}