scsi: convert to QEMU Object Model
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
d148211c6d
commit
b9eea3e6a4
@ -23,6 +23,42 @@ static struct BusInfo scsi_bus_info = {
|
||||
};
|
||||
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)
|
||||
{
|
||||
@ -81,8 +117,7 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
|
||||
|
||||
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;
|
||||
@ -126,9 +161,8 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -140,24 +174,22 @@ err:
|
||||
|
||||
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 */
|
||||
@ -182,7 +214,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
|
||||
}
|
||||
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)
|
||||
@ -278,7 +310,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
|
||||
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) {
|
||||
@ -300,7 +332,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
|
||||
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);
|
||||
@ -398,9 +430,7 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
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;
|
||||
}
|
||||
@ -507,7 +537,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -597,9 +627,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
|
||||
* 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;
|
||||
}
|
||||
@ -1367,7 +1395,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
|
||||
|
||||
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,
|
||||
@ -1382,7 +1410,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
|
||||
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) {
|
||||
@ -1393,3 +1421,18 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int 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);
|
||||
|
159
hw/scsi-disk.c
159
hw/scsi-disk.c
@ -1712,75 +1712,108 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
|
||||
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)
|
||||
|
@ -357,7 +357,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
|
||||
|
||||
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));
|
||||
}
|
||||
@ -457,16 +457,23 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||
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(),
|
||||
},
|
||||
|
31
hw/scsi.h
31
hw/scsi.h
@ -13,7 +13,6 @@ typedef struct SCSIBus SCSIBus;
|
||||
typedef struct SCSIBusInfo SCSIBusInfo;
|
||||
typedef struct SCSICommand SCSICommand;
|
||||
typedef struct SCSIDevice SCSIDevice;
|
||||
typedef struct SCSIDeviceInfo SCSIDeviceInfo;
|
||||
typedef struct SCSIRequest SCSIRequest;
|
||||
typedef struct SCSIReqOps SCSIReqOps;
|
||||
|
||||
@ -58,6 +57,23 @@ struct SCSIRequest {
|
||||
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;
|
||||
@ -65,7 +81,6 @@ struct SCSIDevice
|
||||
QEMUBH *bh;
|
||||
uint32_t id;
|
||||
BlockConf conf;
|
||||
SCSIDeviceInfo *info;
|
||||
SCSISense unit_attention;
|
||||
bool sense_is_ua;
|
||||
uint8_t sense[SCSI_SENSE_BUF_SIZE];
|
||||
@ -93,16 +108,6 @@ struct SCSIReqOps {
|
||||
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;
|
||||
@ -120,7 +125,7 @@ struct SCSIBus {
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user