]> git.proxmox.com Git - mirror_qemu.git/blame - hw/scsi-bus.c
Make qdev_init() destroy the device on failure
[mirror_qemu.git] / hw / scsi-bus.c
CommitLineData
d52affa7
GH
1#include "hw.h"
2#include "sysemu.h"
3#include "scsi-disk.h"
4#include "block.h"
5#include "qdev.h"
6
7static struct BusInfo scsi_bus_info = {
8 .name = "SCSI",
9 .size = sizeof(SCSIBus),
10 .props = (Property[]) {
11 DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
12 DEFINE_PROP_END_OF_LIST(),
13 },
14};
15static int next_scsi_bus;
16
17/* Create a scsi bus, and attach devices to it. */
ca9c39fa
GH
18void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
19 scsi_completionfn complete)
d52affa7 20{
ca9c39fa 21 qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
d52affa7
GH
22 bus->busnr = next_scsi_bus++;
23 bus->tcq = tcq;
24 bus->ndev = ndev;
25 bus->complete = complete;
cb23117b 26 bus->qbus.allow_hotplug = 1;
d52affa7
GH
27}
28
29static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
30{
31 SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
32 SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
33 SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
01985dcf 34 int rc = -1;
d52affa7
GH
35
36 if (dev->id == -1) {
37 for (dev->id = 0; dev->id < bus->ndev; dev->id++) {
38 if (bus->devs[dev->id] == NULL)
39 break;
40 }
41 }
42 if (dev->id >= bus->ndev) {
43 qemu_error("bad scsi device id: %d\n", dev->id);
44 goto err;
45 }
46
47 if (bus->devs[dev->id]) {
01985dcf 48 qdev_free(&bus->devs[dev->id]->qdev);
d52affa7
GH
49 }
50 bus->devs[dev->id] = dev;
51
52 dev->info = info;
01985dcf
GH
53 rc = dev->info->init(dev);
54 if (rc != 0) {
55 bus->devs[dev->id] = NULL;
56 }
d52affa7
GH
57
58err:
01985dcf
GH
59 return rc;
60}
61
62static int scsi_qdev_exit(DeviceState *qdev)
63{
64 SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
65 SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
66
67 assert(bus->devs[dev->id] != NULL);
68 if (bus->devs[dev->id]->info->destroy) {
69 bus->devs[dev->id]->info->destroy(bus->devs[dev->id]);
70 }
71 bus->devs[dev->id] = NULL;
72 return 0;
d52affa7
GH
73}
74
75void scsi_qdev_register(SCSIDeviceInfo *info)
76{
77 info->qdev.bus_info = &scsi_bus_info;
78 info->qdev.init = scsi_qdev_init;
cb23117b 79 info->qdev.unplug = qdev_simple_unplug_cb;
01985dcf 80 info->qdev.exit = scsi_qdev_exit;
d52affa7
GH
81 qdev_register(&info->qdev);
82}
83
84/* handle legacy '-drive if=scsi,...' cmd line args */
85SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, DriveInfo *dinfo, int unit)
86{
87 const char *driver;
88 DeviceState *dev;
89
90 driver = bdrv_is_sg(dinfo->bdrv) ? "scsi-generic" : "scsi-disk";
91 dev = qdev_create(&bus->qbus, driver);
92 qdev_prop_set_uint32(dev, "scsi-id", unit);
93 qdev_prop_set_drive(dev, "drive", dinfo);
94 qdev_init(dev);
95 return DO_UPCAST(SCSIDevice, qdev, dev);
96}
97
98void scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
99{
100 DriveInfo *dinfo;
101 int unit;
102
103 for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
104 dinfo = drive_get(IF_SCSI, bus->busnr, unit);
105 if (dinfo == NULL) {
106 continue;
107 }
108 scsi_bus_legacy_add_drive(bus, dinfo, unit);
109 }
110}