Kill redundant declarion of perror()
[qemu-kvm/fedora.git] / hw / device-hotplug.c
blobd8f0fccf4b699128e3e0385367c72608d09ee473
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"
9 #include "device-assignment.h"
10 #include "config.h"
11 #include "virtio-blk.h"
13 #define PCI_BASE_CLASS_STORAGE 0x01
14 #define PCI_BASE_CLASS_NETWORK 0x02
16 static PCIDevice *qemu_system_hot_add_nic(const char *opts, int bus_nr)
18 int ret;
19 PCIBus *pci_bus;
21 pci_bus = pci_find_bus (bus_nr);
22 if (!pci_bus) {
23 term_printf ("Can't find pci_bus %d\n", bus_nr);
24 return NULL;
27 ret = net_client_init ("nic", opts);
28 if (ret < 0 || !nd_table[ret].model)
29 return NULL;
30 return pci_nic_init (pci_bus, &nd_table[ret], -1, "rtl8139");
33 #ifdef USE_KVM_DEVICE_ASSIGNMENT
34 static PCIDevice *qemu_system_hot_assign_device(const char *opts, int bus_nr)
36 PCIBus *pci_bus;
37 AssignedDevInfo *adev;
38 PCIDevice *ret;
40 pci_bus = pci_find_bus(bus_nr);
41 if (!pci_bus) {
42 term_printf ("Can't find pci_bus %d\n", bus_nr);
43 return NULL;
45 adev = add_assigned_device(opts);
46 if (adev == NULL) {
47 term_printf ("Error adding device; check syntax\n");
48 return NULL;
51 ret = init_assigned_device(adev, pci_bus);
52 if (ret == NULL) {
53 term_printf("Failed to assign device\n");
54 free_assigned_device(adev);
55 return NULL;
58 term_printf("Registered host PCI device %02x:%02x.%1x "
59 "(\"%s\") as guest device %02x:%02x.%1x\n",
60 adev->bus, adev->dev, adev->func, adev->name,
61 pci_bus_num(pci_bus), (ret->devfn >> 3) & 0x1f,
62 adev->func);
64 return ret;
67 #endif /* USE_KVM_DEVICE_ASSIGNMENT */
69 static int add_init_drive(const char *opts)
71 int drive_opt_idx, drive_idx;
72 int ret = -1;
74 drive_opt_idx = drive_add(NULL, "%s", opts);
75 if (!drive_opt_idx)
76 return ret;
78 drive_idx = drive_init(&drives_opt[drive_opt_idx], 0, current_machine);
79 if (drive_idx == -1) {
80 drive_remove(drive_opt_idx);
81 return ret;
84 return drive_idx;
87 void drive_hot_add(int pcibus, const char *devfn_string, const char *opts)
89 int drive_idx, type, bus;
90 int devfn;
91 int success = 0;
92 PCIDevice *dev;
94 devfn = strtoul(devfn_string, NULL, 0);
96 dev = pci_find_device(pcibus, PCI_SLOT(devfn));
97 if (!dev) {
98 term_printf("no pci device with devfn %d (slot %d)\n", devfn,
99 PCI_SLOT(devfn));
100 return;
103 drive_idx = add_init_drive(opts);
104 if (drive_idx < 0)
105 return;
106 type = drives_table[drive_idx].type;
107 bus = drive_get_max_bus (type);
109 switch (type) {
110 case IF_SCSI:
111 success = 1;
112 lsi_scsi_attach (dev, drives_table[drive_idx].bdrv,
113 drives_table[drive_idx].unit);
114 break;
115 default:
116 term_printf("Can't hot-add drive to type %d\n", type);
119 if (success)
120 term_printf("OK bus %d, unit %d\n", drives_table[drive_idx].bus,
121 drives_table[drive_idx].unit);
122 return;
125 static PCIDevice *qemu_system_hot_add_storage(const char *opts, int bus_nr)
127 void *opaque = NULL;
128 PCIBus *pci_bus;
129 int type = -1, drive_idx = -1;
130 char buf[128];
132 pci_bus = pci_find_bus(bus_nr);
133 if (!pci_bus) {
134 term_printf("Can't find pci_bus %d\n", bus_nr);
135 return NULL;
138 if (get_param_value(buf, sizeof(buf), "if", opts)) {
139 if (!strcmp(buf, "scsi"))
140 type = IF_SCSI;
141 else if (!strcmp(buf, "virtio")) {
142 type = IF_VIRTIO;
144 } else {
145 term_printf("no if= specified\n");
146 return NULL;
149 if (get_param_value(buf, sizeof(buf), "file", opts)) {
150 drive_idx = add_init_drive(opts);
151 if (drive_idx < 0)
152 return NULL;
153 } else if (type == IF_VIRTIO) {
154 term_printf("virtio requires a backing file/device.\n");
155 return NULL;
158 switch (type) {
159 case IF_SCSI:
160 opaque = lsi_scsi_init (pci_bus, -1);
161 if (opaque && drive_idx >= 0)
162 lsi_scsi_attach (opaque, drives_table[drive_idx].bdrv,
163 drives_table[drive_idx].unit);
164 break;
165 case IF_VIRTIO:
166 opaque = virtio_blk_init(pci_bus, drives_table[drive_idx].bdrv);
167 break;
168 default:
169 term_printf ("type %s not a hotpluggable PCI device.\n", buf);
172 return opaque;
175 #if defined(TARGET_I386) || defined(TARGET_X86_64)
176 void device_hot_add(int pcibus, const char *type, const char *opts)
178 PCIDevice *dev = NULL;
180 if (strcmp(type, "nic") == 0)
181 dev = qemu_system_hot_add_nic(opts, pcibus);
182 else if (strcmp(type, "storage") == 0)
183 dev = qemu_system_hot_add_storage(opts, pcibus);
184 #ifdef USE_KVM_DEVICE_ASSIGNMENT
185 else if (strcmp(type, "host") == 0)
186 dev = qemu_system_hot_assign_device(opts, pcibus);
187 #endif /* USE_KVM_DEVICE_ASSIGNMENT */
188 else
189 term_printf("invalid type: %s\n", type);
191 if (dev) {
192 qemu_system_device_hot_add(pcibus, PCI_SLOT(dev->devfn), 1);
193 term_printf("OK bus %d, slot %d, function %d (devfn %d)\n",
194 pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
195 PCI_FUNC(dev->devfn), dev->devfn);
196 } else
197 term_printf("failed to add %s\n", opts);
200 void device_hot_remove(int pcibus, int slot)
202 PCIDevice *d = pci_find_device(pcibus, slot);
204 if (!d) {
205 term_printf("invalid slot %d\n", slot);
206 return;
209 qemu_system_device_hot_add(pcibus, slot, 0);
211 #endif
213 static void destroy_nic(int slot)
215 int i;
217 for (i = 0; i < MAX_NICS; i++)
218 if (nd_table[i].used &&
219 PCI_SLOT(nd_table[i].devfn) == slot)
220 net_client_uninit(&nd_table[i]);
223 static void destroy_bdrvs(int slot)
225 int i;
226 struct BlockDriverState *bs;
228 for (i = 0; i <= MAX_DRIVES; i++) {
229 bs = drives_table[i].bdrv;
230 if (bs && (PCI_SLOT(bs->devfn) == slot)) {
231 drive_uninit(bs);
232 bdrv_delete(bs);
238 * OS has executed _EJ0 method, we now can remove the device
240 void device_hot_remove_success(int pcibus, int slot)
242 PCIDevice *d = pci_find_device(pcibus, slot);
243 int class_code;
245 if (!d) {
246 term_printf("invalid slot %d\n", slot);
247 return;
250 class_code = d->config_read(d, PCI_CLASS_DEVICE+1, 1);
252 pci_unregister_device(d);
254 switch(class_code) {
255 case PCI_BASE_CLASS_STORAGE:
256 destroy_bdrvs(slot);
257 break;
258 case PCI_BASE_CLASS_NETWORK:
259 destroy_nic(slot);
260 break;