From 881d588a98bf0dce98ddb65c15aa0854c0ac41ed Mon Sep 17 00:00:00 2001 From: Dmitry Fleytman Date: Fri, 19 Apr 2013 10:05:46 +0300 Subject: scsi: VMWare PVSCSI paravirtual device implementation Signed-off-by: Dmitry Fleytman Signed-off-by: Yan Vugenfirer [ Rename files to vmw_pvscsi, fix setting of hostStatus in pvscsi_request_cancelled - Paolo ] Signed-off-by: Paolo Bonzini --- include/hw/pci/pci.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 05315c0475..2c138b185f 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -59,6 +59,7 @@ #define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 #define PCI_DEVICE_ID_VMWARE_NET 0x0720 #define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 +#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 #define PCI_DEVICE_ID_VMWARE_IDE 0x1729 #define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0 -- cgit v1.2.3-55-g7522 From af60314291af3cabda18d27f928b0e0ff899cc76 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 3 Apr 2013 09:15:11 +0000 Subject: vhost: Add vhost_commit callback for SeaBIOS ROM region re-mapping This patch follows MST's recommendation to move checks for vhost_verify_ring_mappings() -> cpu_physical_memory_map() operations from MemoryListener->region_[add,del]() -> vhost_set_memory() into final MemoryListener->commit() -> vhost_commit() callback. It addresses the case where virtio-scsi vq ioport RAM re-mapping to read-only SeaBIOS ROM triggers a cpu_physical_memory_map() NIL MemoryRegionSection pointer failure. Also save vhost_dev->mem_changed_[start,end]_addr values in vhost_set_memory() for final ranges_overlap checks. (Thanks Paolo!) Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Asias He Signed-off-by: Nicholas Bellinger Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/virtio/vhost.c | 53 +++++++++++++++++++++++++++++++++-------------- include/hw/virtio/vhost.h | 3 +++ 2 files changed, 41 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 636fad0f74..40feab42a0 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -382,8 +382,6 @@ static void vhost_set_memory(MemoryListener *listener, bool log_dirty = memory_region_is_logging(section->mr); int s = offsetof(struct vhost_memory, regions) + (dev->mem->nregions + 1) * sizeof dev->mem->regions[0]; - uint64_t log_size; - int r; void *ram; dev->mem = g_realloc(dev->mem, s); @@ -416,12 +414,47 @@ static void vhost_set_memory(MemoryListener *listener, /* Remove old mapping for this memory, if any. */ vhost_dev_unassign_memory(dev, start_addr, size); } + dev->mem_changed_start_addr = MIN(dev->mem_changed_start_addr, start_addr); + dev->mem_changed_end_addr = MAX(dev->mem_changed_end_addr, start_addr + size - 1); + dev->memory_changed = true; +} + +static bool vhost_section(MemoryRegionSection *section) +{ + return memory_region_is_ram(section->mr); +} + +static void vhost_begin(MemoryListener *listener) +{ + struct vhost_dev *dev = container_of(listener, struct vhost_dev, + memory_listener); + dev->mem_changed_end_addr = 0; + dev->mem_changed_start_addr = -1; +} +static void vhost_commit(MemoryListener *listener) +{ + struct vhost_dev *dev = container_of(listener, struct vhost_dev, + memory_listener); + hwaddr start_addr = 0; + ram_addr_t size = 0; + uint64_t log_size; + int r; + + if (!dev->memory_changed) { + return; + } if (!dev->started) { return; } + if (dev->mem_changed_start_addr > dev->mem_changed_end_addr) { + return; + } if (dev->started) { + start_addr = dev->mem_changed_start_addr; + size = dev->mem_changed_end_addr - dev->mem_changed_start_addr + 1; + r = vhost_verify_ring_mappings(dev, start_addr, size); assert(r >= 0); } @@ -429,6 +462,7 @@ static void vhost_set_memory(MemoryListener *listener, if (!dev->log_enabled) { r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem); assert(r >= 0); + dev->memory_changed = false; return; } log_size = vhost_get_log_size(dev); @@ -445,19 +479,7 @@ static void vhost_set_memory(MemoryListener *listener, if (dev->log_size > log_size + VHOST_LOG_BUFFER) { vhost_dev_log_resize(dev, log_size); } -} - -static bool vhost_section(MemoryRegionSection *section) -{ - return memory_region_is_ram(section->mr); -} - -static void vhost_begin(MemoryListener *listener) -{ -} - -static void vhost_commit(MemoryListener *listener) -{ + dev->memory_changed = false; } static void vhost_region_add(MemoryListener *listener, @@ -842,6 +864,7 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, hdev->log_size = 0; hdev->log_enabled = false; hdev->started = false; + hdev->memory_changed = false; memory_listener_register(&hdev->memory_listener, &address_space_memory); hdev->force = force; return 0; diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index b373be0387..de24746c7e 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -45,6 +45,9 @@ struct vhost_dev { vhost_log_chunk_t *log; unsigned long long log_size; bool force; + bool memory_changed; + hwaddr mem_changed_start_addr; + hwaddr mem_changed_end_addr; }; int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, -- cgit v1.2.3-55-g7522 From 292c8e50d540735c601886acc13eb0c117ee94f8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 29 Mar 2013 01:08:15 +0000 Subject: virtio-scsi: create VirtIOSCSICommon This patch refactors existing virtio-scsi code into VirtIOSCSICommon in order to allow virtio_scsi_init_common() to be used by both internal virtio_scsi_init() and external vhost-scsi-pci code. Cc: Michael S. Tsirkin Cc: Asias He Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 2 +- hw/s390x/virtio-ccw.c | 2 +- hw/scsi/virtio-scsi.c | 212 ++++++++++++++-------------------------- hw/virtio/virtio-pci.c | 5 +- include/hw/virtio/virtio-scsi.h | 133 ++++++++++++++++++++++++- include/qemu/osdep.h | 4 + 6 files changed, 210 insertions(+), 148 deletions(-) (limited to 'include') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index ca0e301f7b..8f29b5e92a 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -560,7 +560,7 @@ static const TypeInfo virtio_s390_device_info = { }; static Property s390_virtio_scsi_properties[] = { - DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIS390, vdev.conf), + DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIS390, vdev.parent_obj.conf), DEFINE_VIRTIO_SCSI_FEATURES(VirtIOS390Device, host_features), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index e9e7509c2f..52325263ab 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -873,7 +873,7 @@ static const TypeInfo virtio_ccw_balloon = { static Property virtio_ccw_scsi_properties[] = { DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.conf), + DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf), DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index ead7cda13d..051daeac55 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -19,118 +19,6 @@ #include #include -#define VIRTIO_SCSI_VQ_SIZE 128 -#define VIRTIO_SCSI_CDB_SIZE 32 -#define VIRTIO_SCSI_SENSE_SIZE 96 -#define VIRTIO_SCSI_MAX_CHANNEL 0 -#define VIRTIO_SCSI_MAX_TARGET 255 -#define VIRTIO_SCSI_MAX_LUN 16383 - -/* Response codes */ -#define VIRTIO_SCSI_S_OK 0 -#define VIRTIO_SCSI_S_OVERRUN 1 -#define VIRTIO_SCSI_S_ABORTED 2 -#define VIRTIO_SCSI_S_BAD_TARGET 3 -#define VIRTIO_SCSI_S_RESET 4 -#define VIRTIO_SCSI_S_BUSY 5 -#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6 -#define VIRTIO_SCSI_S_TARGET_FAILURE 7 -#define VIRTIO_SCSI_S_NEXUS_FAILURE 8 -#define VIRTIO_SCSI_S_FAILURE 9 -#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10 -#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11 -#define VIRTIO_SCSI_S_INCORRECT_LUN 12 - -/* Controlq type codes. */ -#define VIRTIO_SCSI_T_TMF 0 -#define VIRTIO_SCSI_T_AN_QUERY 1 -#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2 - -/* Valid TMF subtypes. */ -#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0 -#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1 -#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2 -#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3 -#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4 -#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5 -#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6 -#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7 - -/* Events. */ -#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000 -#define VIRTIO_SCSI_T_NO_EVENT 0 -#define VIRTIO_SCSI_T_TRANSPORT_RESET 1 -#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 -#define VIRTIO_SCSI_T_PARAM_CHANGE 3 - -/* Reasons for transport reset event */ -#define VIRTIO_SCSI_EVT_RESET_HARD 0 -#define VIRTIO_SCSI_EVT_RESET_RESCAN 1 -#define VIRTIO_SCSI_EVT_RESET_REMOVED 2 - -/* SCSI command request, followed by data-out */ -typedef struct { - uint8_t lun[8]; /* Logical Unit Number */ - uint64_t tag; /* Command identifier */ - uint8_t task_attr; /* Task attribute */ - uint8_t prio; - uint8_t crn; - uint8_t cdb[]; -} QEMU_PACKED VirtIOSCSICmdReq; - -/* Response, followed by sense data and data-in */ -typedef struct { - uint32_t sense_len; /* Sense data length */ - uint32_t resid; /* Residual bytes in data buffer */ - uint16_t status_qualifier; /* Status qualifier */ - uint8_t status; /* Command completion status */ - uint8_t response; /* Response values */ - uint8_t sense[]; -} QEMU_PACKED VirtIOSCSICmdResp; - -/* Task Management Request */ -typedef struct { - uint32_t type; - uint32_t subtype; - uint8_t lun[8]; - uint64_t tag; -} QEMU_PACKED VirtIOSCSICtrlTMFReq; - -typedef struct { - uint8_t response; -} QEMU_PACKED VirtIOSCSICtrlTMFResp; - -/* Asynchronous notification query/subscription */ -typedef struct { - uint32_t type; - uint8_t lun[8]; - uint32_t event_requested; -} QEMU_PACKED VirtIOSCSICtrlANReq; - -typedef struct { - uint32_t event_actual; - uint8_t response; -} QEMU_PACKED VirtIOSCSICtrlANResp; - -typedef struct { - uint32_t event; - uint8_t lun[8]; - uint32_t reason; -} QEMU_PACKED VirtIOSCSIEvent; - -typedef struct { - uint32_t num_queues; - uint32_t seg_max; - uint32_t max_sectors; - uint32_t cmd_per_lun; - uint32_t event_info_size; - uint32_t sense_size; - uint32_t cdb_size; - uint16_t max_channel; - uint16_t max_target; - uint32_t max_lun; -} QEMU_PACKED VirtIOSCSIConfig; - typedef struct VirtIOSCSIReq { VirtIOSCSI *dev; VirtQueue *vq; @@ -237,9 +125,10 @@ static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq) static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq) { VirtIOSCSIReq *req = sreq->hba_private; + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(req->dev); uint32_t n = virtio_queue_get_id(req->vq) - 2; - assert(n < req->dev->conf.num_queues); + assert(n < vs->conf.num_queues); qemu_put_be32s(f, &n); qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); } @@ -248,14 +137,15 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) { SCSIBus *bus = sreq->bus; VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); VirtIOSCSIReq *req; uint32_t n; req = g_malloc(sizeof(*req)); qemu_get_be32s(f, &n); - assert(n < s->conf.num_queues); + assert(n < vs->conf.num_queues); qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); - virtio_scsi_parse_req(s, s->cmd_vqs[n], req); + virtio_scsi_parse_req(s, vs->cmd_vqs[n], req); scsi_req_ref(sreq); req->sreq = sreq; @@ -457,7 +347,10 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) { + /* use non-QOM casts in the data path */ VirtIOSCSI *s = (VirtIOSCSI *)vdev; + VirtIOSCSICommon *vs = &s->parent_obj; + VirtIOSCSIReq *req; int n; @@ -470,8 +363,8 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) out_size = req->elem.out_sg[0].iov_len; in_size = req->elem.in_sg[0].iov_len; - if (out_size < sizeof(VirtIOSCSICmdReq) + s->cdb_size || - in_size < sizeof(VirtIOSCSICmdResp) + s->sense_size) { + if (out_size < sizeof(VirtIOSCSICmdReq) + vs->cdb_size || + in_size < sizeof(VirtIOSCSICmdResp) + vs->sense_size) { virtio_scsi_bad_req(); } @@ -513,7 +406,7 @@ static void virtio_scsi_get_config(VirtIODevice *vdev, uint8_t *config) { VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; - VirtIOSCSI *s = (VirtIOSCSI *)vdev; + VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev); stl_raw(&scsiconf->num_queues, s->conf.num_queues); stl_raw(&scsiconf->seg_max, 128 - 2); @@ -531,7 +424,7 @@ static void virtio_scsi_set_config(VirtIODevice *vdev, const uint8_t *config) { VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; - VirtIOSCSI *s = (VirtIOSCSI *)vdev; + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 || (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) { @@ -539,8 +432,8 @@ static void virtio_scsi_set_config(VirtIODevice *vdev, exit(1); } - s->sense_size = ldl_raw(&scsiconf->sense_size); - s->cdb_size = ldl_raw(&scsiconf->cdb_size); + vs->sense_size = ldl_raw(&scsiconf->sense_size); + vs->cdb_size = ldl_raw(&scsiconf->cdb_size); } static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, @@ -551,14 +444,15 @@ static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, static void virtio_scsi_reset(VirtIODevice *vdev) { - VirtIOSCSI *s = (VirtIOSCSI *)vdev; + VirtIOSCSI *s = VIRTIO_SCSI(vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); s->resetting++; qbus_reset_all(&s->bus.qbus); s->resetting--; - s->sense_size = VIRTIO_SCSI_SENSE_SIZE; - s->cdb_size = VIRTIO_SCSI_CDB_SIZE; + vs->sense_size = VIRTIO_SCSI_SENSE_SIZE; + vs->cdb_size = VIRTIO_SCSI_CDB_SIZE; s->events_dropped = false; } @@ -586,7 +480,8 @@ static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, uint32_t event, uint32_t reason) { - VirtIOSCSIReq *req = virtio_scsi_pop_req(s, s->event_vq); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + VirtIOSCSIReq *req = virtio_scsi_pop_req(s, vs->event_vq); VirtIOSCSIEvent *evt; VirtIODevice *vdev = VIRTIO_DEVICE(s); int in_size; @@ -692,23 +587,19 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = { .load_request = virtio_scsi_load_request, }; -static int virtio_scsi_device_init(VirtIODevice *vdev) +int virtio_scsi_common_init(VirtIOSCSICommon *s) { - DeviceState *qdev = DEVICE(vdev); - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - static int virtio_scsi_id; + VirtIODevice *vdev = VIRTIO_DEVICE(s); int i; virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI, sizeof(VirtIOSCSIConfig)); s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *)); + s->sense_size = VIRTIO_SCSI_SENSE_SIZE; + s->cdb_size = VIRTIO_SCSI_CDB_SIZE; - /* TODO set up vdev function pointers */ vdev->get_config = virtio_scsi_get_config; - vdev->set_config = virtio_scsi_set_config; - vdev->get_features = virtio_scsi_get_features; - vdev->reset = virtio_scsi_reset; s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, virtio_scsi_handle_ctrl); @@ -719,6 +610,26 @@ static int virtio_scsi_device_init(VirtIODevice *vdev) virtio_scsi_handle_cmd); } + return 0; +} + +static int virtio_scsi_device_init(VirtIODevice *vdev) +{ + DeviceState *qdev = DEVICE(vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + VirtIOSCSI *s = VIRTIO_SCSI(vdev); + static int virtio_scsi_id; + int ret; + + ret = virtio_scsi_common_init(vs); + if (ret < 0) { + return ret; + } + + vdev->get_features = virtio_scsi_get_features; + vdev->set_config = virtio_scsi_set_config; + vdev->reset = virtio_scsi_reset; + scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info); if (!qdev->hotplugged) { scsi_bus_legacy_handle_cmdline(&s->bus); @@ -730,22 +641,36 @@ static int virtio_scsi_device_init(VirtIODevice *vdev) return 0; } +int virtio_scsi_common_exit(VirtIOSCSICommon *vs) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vs); + + g_free(vs->cmd_vqs); + virtio_common_cleanup(vdev); + return 0; +} + static int virtio_scsi_device_exit(DeviceState *qdev) { VirtIOSCSI *s = VIRTIO_SCSI(qdev); - VirtIODevice *vdev = VIRTIO_DEVICE(qdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev); unregister_savevm(qdev, "virtio-scsi", s); - g_free(s->cmd_vqs); - virtio_common_cleanup(vdev); - return 0; + return virtio_scsi_common_exit(vs); } static Property virtio_scsi_properties[] = { - DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, conf), + DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, parent_obj.conf), DEFINE_PROP_END_OF_LIST(), }; +static void virtio_scsi_common_class_init(ObjectClass *klass, void *data) +{ + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + vdc->get_config = virtio_scsi_get_config; +} + static void virtio_scsi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -753,21 +678,28 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) dc->exit = virtio_scsi_device_exit; dc->props = virtio_scsi_properties; vdc->init = virtio_scsi_device_init; - vdc->get_config = virtio_scsi_get_config; vdc->set_config = virtio_scsi_set_config; vdc->get_features = virtio_scsi_get_features; vdc->reset = virtio_scsi_reset; } +static const TypeInfo virtio_scsi_common_info = { + .name = TYPE_VIRTIO_SCSI_COMMON, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOSCSICommon), + .class_init = virtio_scsi_common_class_init, +}; + static const TypeInfo virtio_scsi_info = { .name = TYPE_VIRTIO_SCSI, - .parent = TYPE_VIRTIO_DEVICE, + .parent = TYPE_VIRTIO_SCSI_COMMON, .instance_size = sizeof(VirtIOSCSI), .class_init = virtio_scsi_class_init, }; static void virtio_register_types(void) { + type_register_static(&virtio_scsi_common_info); type_register_static(&virtio_scsi_info); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index e2d1693547..b362cc851a 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1236,7 +1236,7 @@ static Property virtio_scsi_pci_properties[] = { DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED), DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.conf), + DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.parent_obj.conf), DEFINE_PROP_END_OF_LIST(), }; @@ -1244,9 +1244,10 @@ static int virtio_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev) { VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev); DeviceState *vdev = DEVICE(&dev->vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { - vpci_dev->nvectors = dev->vdev.conf.num_queues + 3; + vpci_dev->nvectors = vs->conf.num_queues + 3; } qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index ccd7b0669c..4a961b9c5a 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -18,6 +18,10 @@ #include "hw/pci/pci.h" #include "hw/scsi/scsi.h" +#define TYPE_VIRTIO_SCSI_COMMON "virtio-scsi-common" +#define VIRTIO_SCSI_COMMON(obj) \ + OBJECT_CHECK(VirtIOSCSICommon, (obj), TYPE_VIRTIO_SCSI_COMMON) + #define TYPE_VIRTIO_SCSI "virtio-scsi-device" #define VIRTIO_SCSI(obj) \ OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI) @@ -31,24 +35,141 @@ #define VIRTIO_SCSI_F_HOTPLUG 1 #define VIRTIO_SCSI_F_CHANGE 2 +#define VIRTIO_SCSI_VQ_SIZE 128 +#define VIRTIO_SCSI_CDB_SIZE 32 +#define VIRTIO_SCSI_SENSE_SIZE 96 +#define VIRTIO_SCSI_MAX_CHANNEL 0 +#define VIRTIO_SCSI_MAX_TARGET 255 +#define VIRTIO_SCSI_MAX_LUN 16383 + +/* Response codes */ +#define VIRTIO_SCSI_S_OK 0 +#define VIRTIO_SCSI_S_OVERRUN 1 +#define VIRTIO_SCSI_S_ABORTED 2 +#define VIRTIO_SCSI_S_BAD_TARGET 3 +#define VIRTIO_SCSI_S_RESET 4 +#define VIRTIO_SCSI_S_BUSY 5 +#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6 +#define VIRTIO_SCSI_S_TARGET_FAILURE 7 +#define VIRTIO_SCSI_S_NEXUS_FAILURE 8 +#define VIRTIO_SCSI_S_FAILURE 9 +#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10 +#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11 +#define VIRTIO_SCSI_S_INCORRECT_LUN 12 + +/* Controlq type codes. */ +#define VIRTIO_SCSI_T_TMF 0 +#define VIRTIO_SCSI_T_AN_QUERY 1 +#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2 + +/* Valid TMF subtypes. */ +#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0 +#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1 +#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2 +#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3 +#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4 +#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5 +#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6 +#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7 + +/* Events. */ +#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000 +#define VIRTIO_SCSI_T_NO_EVENT 0 +#define VIRTIO_SCSI_T_TRANSPORT_RESET 1 +#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 +#define VIRTIO_SCSI_T_PARAM_CHANGE 3 + +/* Reasons for transport reset event */ +#define VIRTIO_SCSI_EVT_RESET_HARD 0 +#define VIRTIO_SCSI_EVT_RESET_RESCAN 1 +#define VIRTIO_SCSI_EVT_RESET_REMOVED 2 + +/* SCSI command request, followed by data-out */ +typedef struct { + uint8_t lun[8]; /* Logical Unit Number */ + uint64_t tag; /* Command identifier */ + uint8_t task_attr; /* Task attribute */ + uint8_t prio; + uint8_t crn; + uint8_t cdb[]; +} QEMU_PACKED VirtIOSCSICmdReq; + +/* Response, followed by sense data and data-in */ +typedef struct { + uint32_t sense_len; /* Sense data length */ + uint32_t resid; /* Residual bytes in data buffer */ + uint16_t status_qualifier; /* Status qualifier */ + uint8_t status; /* Command completion status */ + uint8_t response; /* Response values */ + uint8_t sense[]; +} QEMU_PACKED VirtIOSCSICmdResp; + +/* Task Management Request */ +typedef struct { + uint32_t type; + uint32_t subtype; + uint8_t lun[8]; + uint64_t tag; +} QEMU_PACKED VirtIOSCSICtrlTMFReq; + +typedef struct { + uint8_t response; +} QEMU_PACKED VirtIOSCSICtrlTMFResp; + +/* Asynchronous notification query/subscription */ +typedef struct { + uint32_t type; + uint8_t lun[8]; + uint32_t event_requested; +} QEMU_PACKED VirtIOSCSICtrlANReq; + +typedef struct { + uint32_t event_actual; + uint8_t response; +} QEMU_PACKED VirtIOSCSICtrlANResp; + +typedef struct { + uint32_t event; + uint8_t lun[8]; + uint32_t reason; +} QEMU_PACKED VirtIOSCSIEvent; + +typedef struct { + uint32_t num_queues; + uint32_t seg_max; + uint32_t max_sectors; + uint32_t cmd_per_lun; + uint32_t event_info_size; + uint32_t sense_size; + uint32_t cdb_size; + uint16_t max_channel; + uint16_t max_target; + uint32_t max_lun; +} QEMU_PACKED VirtIOSCSIConfig; + struct VirtIOSCSIConf { uint32_t num_queues; uint32_t max_sectors; uint32_t cmd_per_lun; }; -typedef struct VirtIOSCSI { +typedef struct VirtIOSCSICommon { VirtIODevice parent_obj; VirtIOSCSIConf conf; - SCSIBus bus; uint32_t sense_size; uint32_t cdb_size; - int resetting; - bool events_dropped; VirtQueue *ctrl_vq; VirtQueue *event_vq; VirtQueue **cmd_vqs; +} VirtIOSCSICommon; + +typedef struct { + VirtIOSCSICommon parent_obj; + + SCSIBus bus; + int resetting; + bool events_dropped; } VirtIOSCSI; #define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field) \ @@ -63,4 +184,8 @@ typedef struct VirtIOSCSI { DEFINE_PROP_BIT("param_change", _state, _feature_field, \ VIRTIO_SCSI_F_CHANGE, true) +int virtio_scsi_common_init(VirtIOSCSICommon *vs); +int virtio_scsi_common_exit(VirtIOSCSICommon *vs); + + #endif /* _QEMU_VIRTIO_SCSI_H */ diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index df244006c7..8b465fdf2f 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -67,6 +67,10 @@ typedef signed int int_fast16_t; #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#ifndef ROUND_UP +#define ROUND_UP(n,d) (((n) + (d) - 1) & -(d)) +#endif + #ifndef DIV_ROUND_UP #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #endif -- cgit v1.2.3-55-g7522 From 5e9be92d775208cf6cc9bf9a592853888046239e Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 29 Mar 2013 01:08:16 +0000 Subject: vhost-scsi: new device supporting the tcm_vhost Linux kernel module The WWPN specified in configfs is passed to "-device vhost-scsi-pci". The tgpt field of the SET_ENDPOINT ioctl is obsolete now, so it is not available from the QEMU command-line. Instead, I hardcode it to zero. Changes in Patch-v2: - Add vhost_scsi_get_features() in order to determine feature bits supports by host kernel (mst + nab) - Re-enable usage of DEFINE_VIRTIO_COMMON_FEATURES, and allow EVENT_IDX to be disabled by host in vhost_scsi_get_features() - Drop unused hotplug bit in DEFINE_VHOST_SCSI_PROPERTIES Changes in Patch-v1: - Set event_idx=off by default (nab, thanks asias) - Disable hotplug feature bit for v3.9 tcm_vhost kernel code, need to re-enable in v3.10 (nab) - Update to latest qemu.git/master HEAD Changes in WIP-V3: - Drop ioeventfd vhost_scsi_properties (asias, thanks stefanha) - Add CONFIG_VHOST_SCSI (asias, thanks stefanha) - Add hotplug feature bit Changes in WIP-V2: - Add backend guest masking support (nab) - Bump ABI_VERSION to 1 (nab) - Set up set_guest_notifiers (asias) - Set up vs->dev.vq_index (asias) - Drop vs->vs.vdev.{set,clear}_vhost_endpoint (asias) - Drop VIRTIO_CONFIG_S_DRIVER check in vhost_scsi_set_status (asias) Howto: Use the latest seabios, at least commit b44a7be17b git clone git://git.seabios.org/seabios.git make cp out/bios.bin /usr/share/qemu/bios.bin qemu -device vhost-scsi-pci,wwpn=naa.6001405bd4e8476d,event_idx=off ... Cc: Michael S. Tsirkin Signed-off-by: Nicholas Bellinger Signed-off-by: Asias He [ Rebase on top of VirtIOSCSICommon patch, fix bugs in feature negotiation and irqfd masking - Paolo ] Signed-off-by: Paolo Bonzini --- configure | 10 ++ hw/scsi/Makefile.objs | 6 +- hw/scsi/vhost-scsi.c | 288 ++++++++++++++++++++++++++++++++++++++++ include/hw/virtio/vhost-scsi.h | 73 ++++++++++ include/hw/virtio/virtio-scsi.h | 2 + 5 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 hw/scsi/vhost-scsi.c create mode 100644 include/hw/virtio/vhost-scsi.h (limited to 'include') diff --git a/configure b/configure index ed49f919c8..51a6c5621c 100755 --- a/configure +++ b/configure @@ -179,6 +179,7 @@ libattr="" xfs="" vhost_net="no" +vhost_scsi="no" kvm="no" gprof="no" debug_tcg="no" @@ -543,6 +544,7 @@ Haiku) usb="linux" kvm="yes" vhost_net="yes" + vhost_scsi="yes" if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then audio_possible_drivers="$audio_possible_drivers fmod" fi @@ -870,6 +872,10 @@ for opt do ;; --enable-vhost-net) vhost_net="yes" ;; + --disable-vhost-scsi) vhost_scsi="no" + ;; + --enable-vhost-scsi) vhost_scsi="yes" + ;; --disable-glx) glx="no" ;; --enable-glx) glx="yes" @@ -3553,6 +3559,7 @@ echo "sigev_thread_id $sigev_thread_id" echo "uuid support $uuid" echo "libcap-ng support $cap_ng" echo "vhost-net support $vhost_net" +echo "vhost-scsi support $vhost_scsi" echo "Trace backend $trace_backend" echo "Trace output file $trace_file-" echo "spice support $spice ($spice_protocol_version/$spice_server_version)" @@ -3836,6 +3843,9 @@ fi if test "$virtfs" = "yes" ; then echo "CONFIG_VIRTFS=y" >> $config_host_mak fi +if test "$vhost_scsi" = "yes" ; then + echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak +fi if test "$blobs" = "yes" ; then echo "INSTALL_BLOBS=yes" >> $config_host_mak fi diff --git a/hw/scsi/Makefile.objs b/hw/scsi/Makefile.objs index eaec6c87ef..121ddc5cf4 100644 --- a/hw/scsi/Makefile.objs +++ b/hw/scsi/Makefile.objs @@ -6,4 +6,8 @@ common-obj-$(CONFIG_VMW_PVSCSI_SCSI_PCI) += vmw_pvscsi.o common-obj-$(CONFIG_ESP) += esp.o common-obj-$(CONFIG_ESP_PCI) += esp-pci.o obj-$(CONFIG_PSERIES) += spapr_vscsi.o -obj-$(CONFIG_VIRTIO) += virtio-scsi.o + +ifeq ($(CONFIG_VIRTIO),y) +obj-y += virtio-scsi.o +obj-$(CONFIG_VHOST_SCSI) += vhost-scsi.o +endif diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c new file mode 100644 index 0000000000..3dd1a0f2ed --- /dev/null +++ b/hw/scsi/vhost-scsi.c @@ -0,0 +1,288 @@ +/* + * vhost_scsi host device + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi + * + * Changes for QEMU mainline + tcm_vhost kernel upstream: + * Nicholas Bellinger + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include +#include "config.h" +#include "qemu/queue.h" +#include "monitor/monitor.h" +#include "migration/migration.h" +#include "hw/virtio/vhost-scsi.h" +#include "hw/virtio/vhost.h" +#include "hw/virtio/virtio-scsi.h" + +static int vhost_scsi_set_endpoint(VHostSCSI *s) +{ + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + struct vhost_scsi_target backend; + int ret; + + memset(&backend, 0, sizeof(backend)); + pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn); + ret = ioctl(s->dev.control, VHOST_SCSI_SET_ENDPOINT, &backend); + if (ret < 0) { + return -errno; + } + return 0; +} + +static void vhost_scsi_clear_endpoint(VHostSCSI *s) +{ + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + struct vhost_scsi_target backend; + + memset(&backend, 0, sizeof(backend)); + pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn); + ioctl(s->dev.control, VHOST_SCSI_CLEAR_ENDPOINT, &backend); +} + +static int vhost_scsi_start(VHostSCSI *s) +{ + int ret, abi_version, i; + VirtIODevice *vdev = VIRTIO_DEVICE(s); + + if (!vdev->binding->set_guest_notifiers) { + error_report("binding does not support guest notifiers"); + return -ENOSYS; + } + + ret = ioctl(s->dev.control, VHOST_SCSI_GET_ABI_VERSION, &abi_version); + if (ret < 0) { + return -errno; + } + if (abi_version > VHOST_SCSI_ABI_VERSION) { + error_report("vhost-scsi: The running tcm_vhost kernel abi_version:" + " %d is greater than vhost_scsi userspace supports: %d, please" + " upgrade your version of QEMU\n", abi_version, + VHOST_SCSI_ABI_VERSION); + return -ENOSYS; + } + + ret = vhost_dev_enable_notifiers(&s->dev, vdev); + if (ret < 0) { + return ret; + } + + s->dev.acked_features = vdev->guest_features; + ret = vhost_dev_start(&s->dev, vdev); + if (ret < 0) { + error_report("Error start vhost dev"); + goto err_notifiers; + } + + ret = vhost_scsi_set_endpoint(s); + if (ret < 0) { + error_report("Error set vhost-scsi endpoint"); + goto err_vhost_stop; + } + + ret = vdev->binding->set_guest_notifiers(vdev->binding_opaque, s->dev.nvqs, true); + if (ret < 0) { + error_report("Error binding guest notifier"); + goto err_endpoint; + } + + /* guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < s->dev.nvqs; i++) { + vhost_virtqueue_mask(&s->dev, vdev, i, false); + } + + return ret; + +err_endpoint: + vhost_scsi_clear_endpoint(s); +err_vhost_stop: + vhost_dev_stop(&s->dev, vdev); +err_notifiers: + vhost_dev_disable_notifiers(&s->dev, vdev); + return ret; +} + +static void vhost_scsi_stop(VHostSCSI *s) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(s); + int ret = 0; + + if (!vdev->binding->set_guest_notifiers) { + ret = vdev->binding->set_guest_notifiers(vdev->binding_opaque, + s->dev.nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d\n", ret); + } + } + assert(ret >= 0); + + vhost_scsi_clear_endpoint(s); + vhost_dev_stop(&s->dev, vdev); + vhost_dev_disable_notifiers(&s->dev, vdev); +} + +static uint32_t vhost_scsi_get_features(VirtIODevice *vdev, + uint32_t features) +{ + VHostSCSI *s = VHOST_SCSI(vdev); + + /* Clear features not supported by host kernel. */ + if (!(s->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) { + features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY); + } + if (!(s->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) { + features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC); + } + if (!(s->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) { + features &= ~(1 << VIRTIO_RING_F_EVENT_IDX); + } + if (!(s->dev.features & (1 << VIRTIO_SCSI_F_HOTPLUG))) { + features &= ~(1 << VIRTIO_SCSI_F_HOTPLUG); + } + + return features; +} + +static void vhost_scsi_set_config(VirtIODevice *vdev, + const uint8_t *config) +{ + VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + + if ((uint32_t) ldl_raw(&scsiconf->sense_size) != vs->sense_size || + (uint32_t) ldl_raw(&scsiconf->cdb_size) != vs->cdb_size) { + error_report("vhost-scsi does not support changing the sense data and CDB sizes"); + exit(1); + } +} + +static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) +{ + VHostSCSI *s = (VHostSCSI *)vdev; + bool start = (val & VIRTIO_CONFIG_S_DRIVER_OK); + + if (s->dev.started == start) { + return; + } + + if (start) { + int ret; + + ret = vhost_scsi_start(s); + if (ret < 0) { + error_report("virtio-scsi: unable to start vhost: %s\n", + strerror(-ret)); + + /* There is no userspace virtio-scsi fallback so exit */ + exit(1); + } + } else { + vhost_scsi_stop(s); + } +} + +static int vhost_scsi_init(VirtIODevice *vdev) +{ + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + VHostSCSI *s = VHOST_SCSI(vdev); + int vhostfd = -1; + int ret; + + if (!vs->conf.wwpn) { + error_report("vhost-scsi: missing wwpn\n"); + return -EINVAL; + } + + if (vs->conf.vhostfd) { + vhostfd = monitor_handle_fd_param(cur_mon, vs->conf.vhostfd); + if (vhostfd == -1) { + error_report("vhost-scsi: unable to parse vhostfd\n"); + return -EINVAL; + } + } + + ret = virtio_scsi_common_init(vs); + if (ret < 0) { + return ret; + } + + vdev->get_features = vhost_scsi_get_features; + vdev->set_config = vhost_scsi_set_config; + vdev->set_status = vhost_scsi_set_status; + + s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; + s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs); + s->dev.vq_index = 0; + + ret = vhost_dev_init(&s->dev, vhostfd, "/dev/vhost-scsi", true); + if (ret < 0) { + error_report("vhost-scsi: vhost initialization failed: %s\n", + strerror(-ret)); + return ret; + } + s->dev.backend_features = 0; + + error_setg(&s->migration_blocker, + "vhost-scsi does not support migration"); + migrate_add_blocker(s->migration_blocker); + + return 0; +} + +static int vhost_scsi_exit(DeviceState *qdev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(qdev); + VHostSCSI *s = VHOST_SCSI(qdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev); + + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); + + /* This will stop vhost backend. */ + vhost_scsi_set_status(vdev, 0); + + g_free(s->dev.vqs); + return virtio_scsi_common_exit(vs); +} + +static Property vhost_scsi_properties[] = { + DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSI, parent_obj.conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_scsi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + dc->exit = vhost_scsi_exit; + dc->props = vhost_scsi_properties; + vdc->init = vhost_scsi_init; + vdc->get_features = vhost_scsi_get_features; + vdc->set_config = vhost_scsi_set_config; + vdc->set_status = vhost_scsi_set_status; +} + +static const TypeInfo vhost_scsi_info = { + .name = TYPE_VHOST_SCSI, + .parent = TYPE_VIRTIO_SCSI_COMMON, + .instance_size = sizeof(VHostSCSI), + .class_init = vhost_scsi_class_init, +}; + +static void virtio_register_types(void) +{ + type_register_static(&vhost_scsi_info); +} + +type_init(virtio_register_types) diff --git a/include/hw/virtio/vhost-scsi.h b/include/hw/virtio/vhost-scsi.h new file mode 100644 index 0000000000..85cc031281 --- /dev/null +++ b/include/hw/virtio/vhost-scsi.h @@ -0,0 +1,73 @@ +/* + * vhost_scsi host device + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef VHOST_SCSI_H +#define VHOST_SCSI_H + +#include "qemu-common.h" +#include "hw/qdev.h" +#include "hw/virtio/virtio-scsi.h" +#include "hw/virtio/vhost.h" + +/* + * Used by QEMU userspace to ensure a consistent vhost-scsi ABI. + * + * ABI Rev 0: July 2012 version starting point for v3.6-rc merge candidate + + * RFC-v2 vhost-scsi userspace. Add GET_ABI_VERSION ioctl usage + * ABI Rev 1: January 2013. Ignore vhost_tpgt filed in struct vhost_scsi_target. + * All the targets under vhost_wwpn can be seen and used by guest. + */ + +#define VHOST_SCSI_ABI_VERSION 1 + +/* TODO #include properly */ +/* For VHOST_SCSI_SET_ENDPOINT/VHOST_SCSI_CLEAR_ENDPOINT ioctl */ +struct vhost_scsi_target { + int abi_version; + char vhost_wwpn[224]; + unsigned short vhost_tpgt; + unsigned short reserved; +}; + +enum vhost_scsi_vq_list { + VHOST_SCSI_VQ_CONTROL = 0, + VHOST_SCSI_VQ_EVENT = 1, + VHOST_SCSI_VQ_NUM_FIXED = 2, +}; + +#define VHOST_VIRTIO 0xAF +#define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target) +#define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target) +#define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, int) + +#define TYPE_VHOST_SCSI "vhost-scsi" +#define VHOST_SCSI(obj) \ + OBJECT_CHECK(VHostSCSI, (obj), TYPE_VHOST_SCSI) + +typedef struct VHostSCSI { + VirtIOSCSICommon parent_obj; + + Error *migration_blocker; + + struct vhost_dev dev; +} VHostSCSI; + +#define DEFINE_VHOST_SCSI_PROPERTIES(_state, _conf_field) \ + DEFINE_PROP_STRING("vhostfd", _state, _conf_field.vhostfd), \ + DEFINE_PROP_STRING("wwpn", _state, _conf_field.wwpn), \ + DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \ + DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF), \ + DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128) + + +#endif diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 4a961b9c5a..4db346b546 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -151,6 +151,8 @@ struct VirtIOSCSIConf { uint32_t num_queues; uint32_t max_sectors; uint32_t cmd_per_lun; + char *vhostfd; + char *wwpn; }; typedef struct VirtIOSCSICommon { -- cgit v1.2.3-55-g7522