summaryrefslogtreecommitdiffstats
path: root/qemu/hw/scsi/vmw_pvscsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/hw/scsi/vmw_pvscsi.c')
-rw-r--r--qemu/hw/scsi/vmw_pvscsi.c98
1 files changed, 92 insertions, 6 deletions
diff --git a/qemu/hw/scsi/vmw_pvscsi.c b/qemu/hw/scsi/vmw_pvscsi.c
index 9c71f31fe..e690b4ec0 100644
--- a/qemu/hw/scsi/vmw_pvscsi.c
+++ b/qemu/hw/scsi/vmw_pvscsi.c
@@ -25,6 +25,8 @@
*
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/scsi/scsi.h"
#include <block/scsi.h>
#include "hw/pci/msi.h"
@@ -32,7 +34,6 @@
#include "trace.h"
-#define PVSCSI_MSI_OFFSET (0x50)
#define PVSCSI_USE_64BIT (true)
#define PVSCSI_PER_VECTOR_MASK (false)
@@ -49,9 +50,33 @@
(stl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \
(m)->rs_pa + offsetof(struct PVSCSIRingsState, field), val))
+typedef struct PVSCSIClass {
+ PCIDeviceClass parent_class;
+ DeviceRealize parent_dc_realize;
+} PVSCSIClass;
+
#define TYPE_PVSCSI "pvscsi"
#define PVSCSI(obj) OBJECT_CHECK(PVSCSIState, (obj), TYPE_PVSCSI)
+#define PVSCSI_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PVSCSIClass, (klass), TYPE_PVSCSI)
+#define PVSCSI_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PVSCSIClass, (obj), TYPE_PVSCSI)
+
+/* Compatability flags for migration */
+#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT 0
+#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION \
+ (1 << PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT)
+#define PVSCSI_COMPAT_DISABLE_PCIE_BIT 1
+#define PVSCSI_COMPAT_DISABLE_PCIE \
+ (1 << PVSCSI_COMPAT_DISABLE_PCIE_BIT)
+
+#define PVSCSI_USE_OLD_PCI_CONFIGURATION(s) \
+ ((s)->compat_flags & PVSCSI_COMPAT_OLD_PCI_CONFIGURATION)
+#define PVSCSI_MSI_OFFSET(s) \
+ (PVSCSI_USE_OLD_PCI_CONFIGURATION(s) ? 0x50 : 0x7c)
+#define PVSCSI_EXP_EP_OFFSET (0x40)
+
typedef struct PVSCSIRingInfo {
uint64_t rs_pa;
uint32_t txr_len_mask;
@@ -100,6 +125,8 @@ typedef struct {
PVSCSIRingInfo rings; /* Data transfer rings manager */
uint32_t resetting; /* Reset in progress */
+
+ uint32_t compat_flags;
} PVSCSIState;
typedef struct PVSCSIRequest {
@@ -1019,7 +1046,7 @@ pvscsi_init_msi(PVSCSIState *s)
int res;
PCIDevice *d = PCI_DEVICE(s);
- res = msi_init(d, PVSCSI_MSI_OFFSET, PVSCSI_MSIX_NUM_VECTORS,
+ res = msi_init(d, PVSCSI_MSI_OFFSET(s), PVSCSI_MSIX_NUM_VECTORS,
PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK);
if (res < 0) {
trace_pvscsi_init_msi_fail(res);
@@ -1069,9 +1096,16 @@ pvscsi_init(PCIDevice *pci_dev)
trace_pvscsi_state("init");
- /* PCI subsystem ID */
- pci_dev->config[PCI_SUBSYSTEM_ID] = 0x00;
- pci_dev->config[PCI_SUBSYSTEM_ID + 1] = 0x10;
+ /* PCI subsystem ID, subsystem vendor ID, revision */
+ if (PVSCSI_USE_OLD_PCI_CONFIGURATION(s)) {
+ pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, 0x1000);
+ } else {
+ pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
+ PCI_VENDOR_ID_VMWARE);
+ pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
+ PCI_DEVICE_ID_VMWARE_PVSCSI);
+ pci_config_set_revision(pci_dev->config, 0x2);
+ }
/* PCI latency timer = 255 */
pci_dev->config[PCI_LATENCY_TIMER] = 0xff;
@@ -1085,6 +1119,10 @@ pvscsi_init(PCIDevice *pci_dev)
pvscsi_init_msi(s);
+ if (pci_is_express(pci_dev) && pci_bus_is_express(pci_dev->bus)) {
+ pcie_endpoint_cap_init(pci_dev, PVSCSI_EXP_EP_OFFSET);
+ }
+
s->completion_worker = qemu_bh_new(pvscsi_process_completion_queue, s);
if (!s->completion_worker) {
pvscsi_cleanup_msi(s);
@@ -1139,6 +1177,27 @@ pvscsi_post_load(void *opaque, int version_id)
return 0;
}
+static bool pvscsi_vmstate_need_pcie_device(void *opaque)
+{
+ PVSCSIState *s = PVSCSI(opaque);
+
+ return !(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE);
+}
+
+static bool pvscsi_vmstate_test_pci_device(void *opaque, int version_id)
+{
+ return !pvscsi_vmstate_need_pcie_device(opaque);
+}
+
+static const VMStateDescription vmstate_pvscsi_pcie_device = {
+ .name = "pvscsi/pcie",
+ .needed = pvscsi_vmstate_need_pcie_device,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCIE_DEVICE(parent_obj, PVSCSIState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_pvscsi = {
.name = "pvscsi",
.version_id = 0,
@@ -1146,7 +1205,9 @@ static const VMStateDescription vmstate_pvscsi = {
.pre_save = pvscsi_pre_save,
.post_load = pvscsi_post_load,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, PVSCSIState),
+ VMSTATE_STRUCT_TEST(parent_obj, PVSCSIState,
+ pvscsi_vmstate_test_pci_device, 0,
+ vmstate_pci_device, PCIDevice),
VMSTATE_UINT8(msi_used, PVSCSIState),
VMSTATE_UINT32(resetting, PVSCSIState),
VMSTATE_UINT64(reg_interrupt_status, PVSCSIState),
@@ -1171,18 +1232,40 @@ static const VMStateDescription vmstate_pvscsi = {
VMSTATE_UINT64(rings.filled_cmp_ptr, PVSCSIState),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription*[]) {
+ &vmstate_pvscsi_pcie_device,
+ NULL
}
};
static Property pvscsi_properties[] = {
DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1),
+ DEFINE_PROP_BIT("x-old-pci-configuration", PVSCSIState, compat_flags,
+ PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT, false),
+ DEFINE_PROP_BIT("x-disable-pcie", PVSCSIState, compat_flags,
+ PVSCSI_COMPAT_DISABLE_PCIE_BIT, false),
DEFINE_PROP_END_OF_LIST(),
};
+static void pvscsi_realize(DeviceState *qdev, Error **errp)
+{
+ PVSCSIClass *pvs_c = PVSCSI_DEVICE_GET_CLASS(qdev);
+ PCIDevice *pci_dev = PCI_DEVICE(qdev);
+ PVSCSIState *s = PVSCSI(qdev);
+
+ if (!(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE)) {
+ pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
+ }
+
+ pvs_c->parent_dc_realize(qdev, errp);
+}
+
static void pvscsi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ PVSCSIClass *pvs_k = PVSCSI_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
k->init = pvscsi_init;
@@ -1191,6 +1274,8 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI;
k->class_id = PCI_CLASS_STORAGE_SCSI;
k->subsystem_id = 0x1000;
+ pvs_k->parent_dc_realize = dc->realize;
+ dc->realize = pvscsi_realize;
dc->reset = pvscsi_reset;
dc->vmsd = &vmstate_pvscsi;
dc->props = pvscsi_properties;
@@ -1202,6 +1287,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
static const TypeInfo pvscsi_info = {
.name = TYPE_PVSCSI,
.parent = TYPE_PCI_DEVICE,
+ .class_size = sizeof(PVSCSIClass),
.instance_size = sizeof(PVSCSIState),
.class_init = pvscsi_class_init,
.interfaces = (InterfaceInfo[]) {