};
static int next_scsi_bus;
+static int scsi_device_init(SCSIDevice *s)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->init) {
+ return sc->init(s);
+ }
+ return 0;
+}
+
+static void scsi_device_destroy(SCSIDevice *s)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->destroy) {
+ sc->destroy(s);
+ }
+}
+
+static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun,
+ uint8_t *buf, void *hba_private)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->alloc_req) {
+ return sc->alloc_req(s, tag, lun, buf, hba_private);
+ }
+
+ return NULL;
+}
+
+static void scsi_device_unit_attention_reported(SCSIDevice *s)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->unit_attention_reported) {
+ sc->unit_attention_reported(s);
+ }
+}
+
/* Create a scsi bus, and attach devices to it. */
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
{
static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
{
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
- SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
SCSIDevice *d;
int rc = -1;
}
}
- dev->info = info;
QTAILQ_INIT(&dev->requests);
- rc = dev->info->init(dev);
+ rc = scsi_device_init(dev);
if (rc == 0) {
dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
dev);
static int scsi_qdev_exit(DeviceState *qdev)
{
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->vmsentry) {
qemu_del_vm_change_state_handler(dev->vmsentry);
}
- if (dev->info->destroy) {
- dev->info->destroy(dev);
- }
+ scsi_device_destroy(dev);
return 0;
}
-void scsi_qdev_register(SCSIDeviceInfo *info)
+void scsi_qdev_register(DeviceInfo *info)
{
- info->qdev.bus_info = &scsi_bus_info;
- info->qdev.init = scsi_qdev_init;
- info->qdev.unplug = qdev_simple_unplug_cb;
- info->qdev.exit = scsi_qdev_exit;
- qdev_register(&info->qdev);
+ info->bus_info = &scsi_bus_info;
+ info->init = scsi_qdev_init;
+ info->unplug = qdev_simple_unplug_cb;
+ info->exit = scsi_qdev_exit;
+ qdev_register_subclass(info, TYPE_SCSI_DEVICE);
}
/* handle legacy '-drive if=scsi,...' cmd line args */
}
if (qdev_init(dev) < 0)
return NULL;
- return DO_UPCAST(SCSIDevice, qdev, dev);
+ return SCSI_DEVICE(dev);
}
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
found_lun0 = false;
n = 0;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == 0) {
stl_be_p(&r->buf, n);
i = found_lun0 ? 8 : 16;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
store_lun(&r->buf[i], dev->lun);
MIN(req->cmd.xfer, sizeof r->buf),
(req->cmd.buf[1] & 1) == 0);
if (r->req.dev->sense_is_ua) {
- if (r->req.dev->info->unit_attention_reported) {
- r->req.dev->info->unit_attention_reported(req->dev);
- }
+ scsi_device_unit_attention_reported(req->dev);
r->req.dev->sense_len = 0;
r->req.dev->sense_is_ua = false;
}
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
hba_private);
} else {
- req = d->info->alloc_req(d, tag, lun, buf, hba_private);
+ req = scsi_device_alloc_req(d, tag, lun, buf, hba_private);
}
}
* Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
*/
if (req->dev->sense_is_ua) {
- if (req->dev->info->unit_attention_reported) {
- req->dev->info->unit_attention_reported(req->dev);
- }
+ scsi_device_unit_attention_reported(req->dev);
req->dev->sense_len = 0;
req->dev->sense_is_ua = false;
}
static char *scsibus_get_fw_dev_path(DeviceState *dev)
{
- SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
+ SCSIDevice *d = SCSI_DEVICE(dev);
char path[100];
snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel,
SCSIDevice *target_dev = NULL;
QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == lun) {
}
return target_dev;
}
+
+static TypeInfo scsi_device_type_info = {
+ .name = TYPE_SCSI_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SCSIDevice),
+ .abstract = true,
+ .class_size = sizeof(SCSIDeviceClass),
+};
+
+static void scsi_register_devices(void)
+{
+ type_register_static(&scsi_device_type_info);
+}
+
+device_init(scsi_register_devices);
DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
DEFINE_PROP_STRING("serial", SCSIDiskState, serial)
-static SCSIDeviceInfo scsi_disk_info[] = {
- {
- .qdev.name = "scsi-hd",
- .qdev.fw_name = "disk",
- .qdev.desc = "virtual SCSI disk",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_hd_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .unit_attention_reported = scsi_disk_unit_attention_reported,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- }
- },{
- .qdev.name = "scsi-cd",
- .qdev.fw_name = "disk",
- .qdev.desc = "virtual SCSI CD-ROM",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_cd_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .unit_attention_reported = scsi_disk_unit_attention_reported,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_hd_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+}
+
+static DeviceInfo scsi_hd_info = {
+ .name = "scsi-hd",
+ .fw_name = "disk",
+ .desc = "virtual SCSI disk",
+ .size = sizeof(SCSIDiskState),
+ .reset = scsi_disk_reset,
+ .class_init = scsi_hd_class_initfn,
+ .props = (Property[]) {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_cd_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+}
+
+static DeviceInfo scsi_cd_info = {
+ .name = "scsi-cd",
+ .fw_name = "disk",
+ .desc = "virtual SCSI CD-ROM",
+ .size = sizeof(SCSIDiskState),
+ .reset = scsi_disk_reset,
+ .class_init = scsi_cd_class_initfn,
+ .props = (Property[]) {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
#ifdef __linux__
- },{
- .qdev.name = "scsi-block",
- .qdev.fw_name = "disk",
- .qdev.desc = "SCSI block device passthrough",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_block_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_block_new_request,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void scsi_block_class_initfn(ObjectClass *klass, void *data)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_block_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_block_new_request;
+}
+
+static DeviceInfo scsi_block_info = {
+ .name = "scsi-block",
+ .fw_name = "disk",
+ .desc = "SCSI block device passthrough",
+ .size = sizeof(SCSIDiskState),
+ .reset = scsi_disk_reset,
+ .class_init = scsi_block_class_initfn,
+ .props = (Property[]) {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
#endif
- },{
- .qdev.name = "scsi-disk", /* legacy -device scsi-disk */
- .qdev.fw_name = "disk",
- .qdev.desc = "virtual SCSI disk or CD-ROM (legacy)",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_disk_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .unit_attention_reported = scsi_disk_unit_attention_reported,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- }
+
+static void scsi_disk_class_initfn(ObjectClass *klass, void *data)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_disk_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+}
+
+static DeviceInfo scsi_disk_info = {
+ .name = "scsi-disk", /* legacy -device scsi-disk */
+ .fw_name = "disk",
+ .desc = "virtual SCSI disk or CD-ROM (legacy)",
+ .size = sizeof(SCSIDiskState),
+ .reset = scsi_disk_reset,
+ .class_init = scsi_disk_class_initfn,
+ .props = (Property[]) {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
}
};
static void scsi_disk_register_devices(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
- scsi_qdev_register(&scsi_disk_info[i]);
- }
+ scsi_qdev_register(&scsi_hd_info);
+ scsi_qdev_register(&scsi_cd_info);
+#ifdef __linux__
+ scsi_qdev_register(&scsi_block_info);
+#endif
+ scsi_qdev_register(&scsi_disk_info);
}
device_init(scsi_disk_register_devices)
static void scsi_generic_reset(DeviceState *dev)
{
- SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
+ SCSIDevice *s = SCSI_DEVICE(dev);
scsi_device_purge_requests(s, SENSE_CODE(RESET));
}
return req;
}
-static SCSIDeviceInfo scsi_generic_info = {
- .qdev.name = "scsi-generic",
- .qdev.fw_name = "disk",
- .qdev.desc = "pass through generic scsi device (/dev/sg*)",
- .qdev.size = sizeof(SCSIDevice),
- .qdev.reset = scsi_generic_reset,
- .init = scsi_generic_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .qdev.props = (Property[]) {
+static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_generic_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+}
+
+static DeviceInfo scsi_generic_info = {
+ .name = "scsi-generic",
+ .fw_name = "disk",
+ .desc = "pass through generic scsi device (/dev/sg*)",
+ .size = sizeof(SCSIDevice),
+ .reset = scsi_generic_reset,
+ .class_init = scsi_generic_class_initfn,
+ .props = (Property[]) {
DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
DEFINE_PROP_END_OF_LIST(),
},
typedef struct SCSIBusInfo SCSIBusInfo;
typedef struct SCSICommand SCSICommand;
typedef struct SCSIDevice SCSIDevice;
-typedef struct SCSIDeviceInfo SCSIDeviceInfo;
typedef struct SCSIRequest SCSIRequest;
typedef struct SCSIReqOps SCSIReqOps;
QTAILQ_ENTRY(SCSIRequest) next;
};
+#define TYPE_SCSI_DEVICE "scsi-device"
+#define SCSI_DEVICE(obj) \
+ OBJECT_CHECK(SCSIDevice, (obj), TYPE_SCSI_DEVICE)
+#define SCSI_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SCSIDeviceClass, (klass), TYPE_SCSI_DEVICE)
+#define SCSI_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SCSIDeviceClass, (obj), TYPE_SCSI_DEVICE)
+
+typedef struct SCSIDeviceClass {
+ DeviceClass parent_class;
+ int (*init)(SCSIDevice *dev);
+ void (*destroy)(SCSIDevice *s);
+ SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
+ uint8_t *buf, void *hba_private);
+ void (*unit_attention_reported)(SCSIDevice *s);
+} SCSIDeviceClass;
+
struct SCSIDevice
{
DeviceState qdev;
QEMUBH *bh;
uint32_t id;
BlockConf conf;
- SCSIDeviceInfo *info;
SCSISense unit_attention;
bool sense_is_ua;
uint8_t sense[SCSI_SENSE_BUF_SIZE];
uint8_t *(*get_buf)(SCSIRequest *req);
};
-typedef int (*scsi_qdev_initfn)(SCSIDevice *dev);
-struct SCSIDeviceInfo {
- DeviceInfo qdev;
- scsi_qdev_initfn init;
- void (*destroy)(SCSIDevice *s);
- SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
- uint8_t *buf, void *hba_private);
- void (*unit_attention_reported)(SCSIDevice *s);
-};
-
struct SCSIBusInfo {
int tcq;
int max_channel, max_target, max_lun;
};
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
-void scsi_qdev_register(SCSIDeviceInfo *info);
+void scsi_qdev_register(DeviceInfo *info);
static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
{