kvm: external module: include <linux/time.h>
[qemu-kvm/fedora.git] / hw / device-hotplug.c
blob5e2f2f022ea7dc79aac902881d1804fa55258d4c
1 #include "hw.h"
2 #include "boards.h"
3 #include "pci.h"
4 #include "net.h"
5 #include "sysemu.h"
6 #include "pc.h"
7 #include "console.h"
8 #include "block_int.h"
10 #define PCI_BASE_CLASS_STORAGE 0x01
11 #define PCI_BASE_CLASS_NETWORK 0x02
13 static PCIDevice *qemu_system_hot_add_nic(const char *opts, int bus_nr)
15 int ret;
16 char buf[4096];
17 PCIBus *pci_bus;
19 pci_bus = pci_find_bus (bus_nr);
20 if (!pci_bus) {
21 term_printf ("Can't find pci_bus %d\n", bus_nr);
22 return NULL;
25 memset (buf, 0, sizeof (buf));
27 strcpy (buf, "nic,");
28 strncat (buf, opts, sizeof (buf) - strlen (buf) - 1);
30 ret = net_client_init (buf);
31 if (ret < 0 || !nd_table[ret].model)
32 return NULL;
33 return pci_nic_init (pci_bus, &nd_table[ret], -1);
36 static int add_init_drive(const char *opts)
38 int drive_opt_idx, drive_idx;
39 int ret = -1;
41 drive_opt_idx = drive_add(NULL, "%s", opts);
42 if (!drive_opt_idx)
43 return ret;
45 drive_idx = drive_init(&drives_opt[drive_opt_idx], 0, current_machine);
46 if (drive_idx == -1) {
47 drive_remove(drive_opt_idx);
48 return ret;
51 return drive_idx;
54 void drive_hot_add(int pcibus, const char *devfn_string, const char *opts)
56 int drive_idx, type, bus;
57 int devfn;
58 int success = 0;
59 PCIDevice *dev;
61 devfn = strtoul(devfn_string, NULL, 0);
63 dev = pci_find_device(pcibus, PCI_SLOT(devfn));
64 if (!dev) {
65 term_printf("no pci device with devfn %d (slot %d)\n", devfn,
66 PCI_SLOT(devfn));
67 return;
70 drive_idx = add_init_drive(opts);
71 if (drive_idx < 0)
72 return;
73 type = drives_table[drive_idx].type;
74 bus = drive_get_max_bus (type);
76 switch (type) {
77 case IF_SCSI:
78 success = 1;
79 lsi_scsi_attach (dev, drives_table[drive_idx].bdrv,
80 drives_table[drive_idx].unit);
81 break;
82 default:
83 term_printf("Can't hot-add drive to type %d\n", type);
86 if (success)
87 term_printf("OK bus %d, unit %d\n", drives_table[drive_idx].bus,
88 drives_table[drive_idx].unit);
89 return;
92 static PCIDevice *qemu_system_hot_add_storage(const char *opts, int bus_nr)
94 void *opaque = NULL;
95 PCIBus *pci_bus;
96 int type = -1, drive_idx = -1;
97 char buf[128];
99 pci_bus = pci_find_bus(bus_nr);
100 if (!pci_bus) {
101 term_printf("Can't find pci_bus %d\n", bus_nr);
102 return NULL;
105 if (get_param_value(buf, sizeof(buf), "if", opts)) {
106 if (!strcmp(buf, "scsi"))
107 type = IF_SCSI;
108 else if (!strcmp(buf, "virtio")) {
109 type = IF_VIRTIO;
111 } else {
112 term_printf("no if= specified\n");
113 return NULL;
116 if (get_param_value(buf, sizeof(buf), "file", opts)) {
117 drive_idx = add_init_drive(opts);
118 if (drive_idx < 0)
119 return NULL;
120 } else if (type == IF_VIRTIO) {
121 term_printf("virtio requires a backing file/device.\n");
122 return NULL;
125 switch (type) {
126 case IF_SCSI:
127 opaque = lsi_scsi_init (pci_bus, -1);
128 if (opaque && drive_idx >= 0)
129 lsi_scsi_attach (opaque, drives_table[drive_idx].bdrv,
130 drives_table[drive_idx].unit);
131 break;
132 case IF_VIRTIO:
133 opaque = virtio_blk_init (pci_bus, 0x1AF4, 0x1001,
134 drives_table[drive_idx].bdrv);
135 break;
136 default:
137 term_printf ("type %s not a hotpluggable PCI device.\n", buf);
140 return opaque;
143 #if defined(TARGET_I386) || defined(TARGET_X86_64)
144 void device_hot_add(int pcibus, const char *type, const char *opts)
146 PCIDevice *dev = NULL;
148 if (strcmp(type, "nic") == 0)
149 dev = qemu_system_hot_add_nic(opts, pcibus);
150 else if (strcmp(type, "storage") == 0)
151 dev = qemu_system_hot_add_storage(opts, pcibus);
152 else
153 term_printf("invalid type: %s\n", type);
155 if (dev) {
156 qemu_system_device_hot_add(pcibus, PCI_SLOT(dev->devfn), 1);
157 term_printf("OK bus %d, slot %d, function %d (devfn %d)\n",
158 pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
159 PCI_FUNC(dev->devfn), dev->devfn);
160 } else
161 term_printf("failed to add %s\n", opts);
164 void device_hot_remove(int pcibus, int slot)
166 PCIDevice *d = pci_find_device(pcibus, slot);
168 if (!d) {
169 term_printf("invalid slot %d\n", slot);
170 return;
173 qemu_system_device_hot_add(pcibus, slot, 0);
175 #endif
177 static void destroy_nic(int slot)
179 int i;
181 for (i = 0; i < MAX_NICS; i++)
182 if (nd_table[i].used &&
183 PCI_SLOT(nd_table[i].devfn) == slot)
184 net_client_uninit(&nd_table[i]);
187 static void destroy_bdrvs(int slot)
189 int i;
190 struct BlockDriverState *bs;
192 for (i = 0; i <= MAX_DRIVES; i++) {
193 bs = drives_table[i].bdrv;
194 if (bs && (PCI_SLOT(bs->devfn) == slot)) {
195 drive_uninit(bs);
196 bdrv_delete(bs);
202 * OS has executed _EJ0 method, we now can remove the device
204 void device_hot_remove_success(int pcibus, int slot)
206 PCIDevice *d = pci_find_device(pcibus, slot);
207 int class_code;
209 if (!d) {
210 term_printf("invalid slot %d\n", slot);
211 return;
214 class_code = d->config_read(d, PCI_CLASS_DEVICE+1, 1);
216 pci_unregister_device(d);
218 switch(class_code) {
219 case PCI_BASE_CLASS_STORAGE:
220 destroy_bdrvs(slot);
221 break;
222 case PCI_BASE_CLASS_NETWORK:
223 destroy_nic(slot);
224 break;