2009-08-31 16:24:04 +04:00
|
|
|
#include "hw.h"
|
|
|
|
#include "sysemu.h"
|
2009-10-30 11:54:00 +03:00
|
|
|
#include "scsi.h"
|
2009-08-31 16:24:04 +04:00
|
|
|
#include "block.h"
|
|
|
|
#include "qdev.h"
|
|
|
|
|
|
|
|
static struct BusInfo scsi_bus_info = {
|
|
|
|
.name = "SCSI",
|
|
|
|
.size = sizeof(SCSIBus),
|
|
|
|
.props = (Property[]) {
|
|
|
|
DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
|
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
static int next_scsi_bus;
|
|
|
|
|
|
|
|
/* Create a scsi bus, and attach devices to it. */
|
2009-09-17 00:25:28 +04:00
|
|
|
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
|
|
|
|
scsi_completionfn complete)
|
2009-08-31 16:24:04 +04:00
|
|
|
{
|
2009-09-17 00:25:28 +04:00
|
|
|
qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
|
2009-08-31 16:24:04 +04:00
|
|
|
bus->busnr = next_scsi_bus++;
|
|
|
|
bus->tcq = tcq;
|
|
|
|
bus->ndev = ndev;
|
|
|
|
bus->complete = complete;
|
2009-09-25 23:42:43 +04:00
|
|
|
bus->qbus.allow_hotplug = 1;
|
2009-08-31 16:24:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
|
|
|
{
|
|
|
|
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
|
|
|
|
SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
|
|
|
|
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
|
2009-09-25 23:42:36 +04:00
|
|
|
int rc = -1;
|
2009-08-31 16:24:04 +04:00
|
|
|
|
|
|
|
if (dev->id == -1) {
|
|
|
|
for (dev->id = 0; dev->id < bus->ndev; dev->id++) {
|
|
|
|
if (bus->devs[dev->id] == NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dev->id >= bus->ndev) {
|
|
|
|
qemu_error("bad scsi device id: %d\n", dev->id);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus->devs[dev->id]) {
|
2009-09-25 23:42:36 +04:00
|
|
|
qdev_free(&bus->devs[dev->id]->qdev);
|
2009-08-31 16:24:04 +04:00
|
|
|
}
|
|
|
|
bus->devs[dev->id] = dev;
|
|
|
|
|
|
|
|
dev->info = info;
|
2009-09-25 23:42:36 +04:00
|
|
|
rc = dev->info->init(dev);
|
|
|
|
if (rc != 0) {
|
|
|
|
bus->devs[dev->id] = NULL;
|
|
|
|
}
|
2009-08-31 16:24:04 +04:00
|
|
|
|
|
|
|
err:
|
2009-09-25 23:42:36 +04:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int scsi_qdev_exit(DeviceState *qdev)
|
|
|
|
{
|
|
|
|
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
|
|
|
|
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
|
|
|
|
|
|
|
|
assert(bus->devs[dev->id] != NULL);
|
|
|
|
if (bus->devs[dev->id]->info->destroy) {
|
|
|
|
bus->devs[dev->id]->info->destroy(bus->devs[dev->id]);
|
|
|
|
}
|
|
|
|
bus->devs[dev->id] = NULL;
|
|
|
|
return 0;
|
2009-08-31 16:24:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void scsi_qdev_register(SCSIDeviceInfo *info)
|
|
|
|
{
|
|
|
|
info->qdev.bus_info = &scsi_bus_info;
|
|
|
|
info->qdev.init = scsi_qdev_init;
|
2009-09-25 23:42:43 +04:00
|
|
|
info->qdev.unplug = qdev_simple_unplug_cb;
|
2009-09-25 23:42:36 +04:00
|
|
|
info->qdev.exit = scsi_qdev_exit;
|
2009-08-31 16:24:04 +04:00
|
|
|
qdev_register(&info->qdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle legacy '-drive if=scsi,...' cmd line args */
|
2009-10-07 03:15:57 +04:00
|
|
|
/* FIXME callers should check for failure, but don't */
|
2009-08-31 16:24:04 +04:00
|
|
|
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, DriveInfo *dinfo, int unit)
|
|
|
|
{
|
|
|
|
const char *driver;
|
|
|
|
DeviceState *dev;
|
|
|
|
|
|
|
|
driver = bdrv_is_sg(dinfo->bdrv) ? "scsi-generic" : "scsi-disk";
|
|
|
|
dev = qdev_create(&bus->qbus, driver);
|
|
|
|
qdev_prop_set_uint32(dev, "scsi-id", unit);
|
|
|
|
qdev_prop_set_drive(dev, "drive", dinfo);
|
2009-10-07 03:15:57 +04:00
|
|
|
if (qdev_init(dev) < 0)
|
|
|
|
return NULL;
|
2009-08-31 16:24:04 +04:00
|
|
|
return DO_UPCAST(SCSIDevice, qdev, dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
|
|
|
|
{
|
|
|
|
DriveInfo *dinfo;
|
|
|
|
int unit;
|
|
|
|
|
|
|
|
for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
|
|
|
|
dinfo = drive_get(IF_SCSI, bus->busnr, unit);
|
|
|
|
if (dinfo == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
scsi_bus_legacy_add_drive(bus, dinfo, unit);
|
|
|
|
}
|
|
|
|
}
|