#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qemu/main-loop.h"
+#include "qemu/module.h"
#include "hw/scsi/scsi.h"
-#include <block/scsi.h>
+#include "migration/vmstate.h"
+#include "scsi/constants.h"
#include "hw/pci/msi.h"
#include "vmw_pvscsi.h"
#include "trace.h"
#define PVSCSI_MAX_DEVS (64)
#define PVSCSI_MSIX_NUM_VECTORS (1)
+#define PVSCSI_MAX_SG_ELEM 2048
+
#define PVSCSI_MAX_CMD_DATA_WORDS \
(sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t))
return log;
}
-static int
+static void
pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri)
{
int i;
uint32_t req_ring_size, cmp_ring_size;
m->rs_pa = ri->ringsStatePPN << VMW_PAGE_SHIFT;
- if ((ri->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)
- || (ri->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)) {
- return -1;
- }
req_ring_size = ri->reqRingNumPages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
cmp_ring_size = ri->cmpRingNumPages * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
txr_len_log2 = pvscsi_log2(req_ring_size - 1);
/* Flush ring state page changes */
smp_wmb();
-
- return 0;
}
static int
uint32_t len_log2;
uint32_t ring_size;
- if (ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) {
+ if (!ri->numPages || ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) {
return -1;
}
ring_size = ri->numPages * PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE;
pvscsi_ring_pop_req_descr(PVSCSIRingInfo *mgr)
{
uint32_t ready_ptr = RS_GET_FIELD(mgr, reqProdIdx);
+ uint32_t ring_size = PVSCSI_MAX_NUM_PAGES_REQ_RING
+ * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
- if (ready_ptr != mgr->consumed_ptr) {
+ if (ready_ptr != mgr->consumed_ptr
+ && ready_ptr - mgr->consumed_ptr < ring_size) {
uint32_t next_ready_ptr =
mgr->consumed_ptr++ & mgr->txr_len_mask;
uint32_t next_ready_page =
pvscsi_reset_adapter(PVSCSIState *s)
{
s->resetting++;
- qbus_reset_all_fn(&s->bus);
+ qbus_reset_all(BUS(&s->bus));
s->resetting--;
pvscsi_process_completion_queue(s);
assert(QTAILQ_EMPTY(&s->pending_queue));
static void
pvscsi_convert_sglist(PVSCSIRequest *r)
{
- int chunk_size;
+ uint32_t chunk_size, elmcnt = 0;
uint64_t data_length = r->req.dataLen;
PVSCSISGState sg = r->sg;
- while (data_length) {
- while (!sg.resid) {
+ while (data_length && elmcnt < PVSCSI_MAX_SG_ELEM) {
+ while (!sg.resid && elmcnt++ < PVSCSI_MAX_SG_ELEM) {
pvscsi_get_next_sg_elem(&sg);
trace_pvscsi_convert_sglist(r->req.context, r->sg.dataAddr,
r->sg.resid);
}
- assert(data_length > 0);
- chunk_size = MIN((unsigned) data_length, sg.resid);
+ chunk_size = MIN(data_length, sg.resid);
if (chunk_size) {
qemu_sglist_add(&r->sgl, sg.dataAddr, chunk_size);
}
trace_pvscsi_tx_rings_num_pages("Confirm Ring", rc->cmpRingNumPages);
for (i = 0; i < rc->cmpRingNumPages; i++) {
- trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->reqRingPPNs[i]);
+ trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->cmpRingPPNs[i]);
}
}
trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_RINGS");
- pvscsi_dbg_dump_tx_rings_config(rc);
- if (pvscsi_ring_init_data(&s->rings, rc) < 0) {
+ if (!rc->reqRingNumPages
+ || rc->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
+ || !rc->cmpRingNumPages
+ || rc->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) {
return PVSCSI_COMMAND_PROCESSING_FAILED;
}
+ pvscsi_dbg_dump_tx_rings_config(rc);
+ pvscsi_ring_init_data(&s->rings, rc);
+
s->rings_info_valid = TRUE;
return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
}
trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_RESET_BUS");
s->resetting++;
- qbus_reset_all_fn(&s->bus);
+ qbus_reset_all(BUS(&s->bus));
s->resetting--;
return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
}
.cancel = pvscsi_request_cancelled,
};
-static int
-pvscsi_init(PCIDevice *pci_dev)
+static void
+pvscsi_realizefn(PCIDevice *pci_dev, Error **errp)
{
PVSCSIState *s = PVSCSI(pci_dev);
pvscsi_init_msi(s);
- if (pci_is_express(pci_dev) && pci_bus_is_express(pci_dev->bus)) {
+ if (pci_is_express(pci_dev) && pci_bus_is_express(pci_get_bus(pci_dev))) {
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);
- return -ENOMEM;
- }
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev),
&pvscsi_scsi_info, NULL);
/* override default SCSI bus hotplug-handler, with pvscsi's one */
- qbus_set_hotplug_handler(BUS(&s->bus), DEVICE(s), &error_abort);
+ qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(s), &error_abort);
pvscsi_reset_state(s);
-
- return 0;
}
static void
pvscsi_reset_adapter(s);
}
-static void
+static int
pvscsi_pre_save(void *opaque)
{
PVSCSIState *s = (PVSCSIState *) opaque;
assert(QTAILQ_EMPTY(&s->pending_queue));
assert(QTAILQ_EMPTY(&s->completion_queue));
+
+ return 0;
}
static int
.name = "pvscsi/pcie",
.needed = pvscsi_vmstate_need_pcie_device,
.fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(parent_obj, PVSCSIState),
+ VMSTATE_PCI_DEVICE(parent_obj, PVSCSIState),
VMSTATE_END_OF_LIST()
}
};
PVSCSIClass *pvs_k = PVSCSI_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
- k->init = pvscsi_init;
+ k->realize = pvscsi_realizefn;
k->exit = pvscsi_uninit;
k->vendor_id = PCI_VENDOR_ID_VMWARE;
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;
+ device_class_set_parent_realize(dc, pvscsi_realize,
+ &pvs_k->parent_dc_realize);
dc->reset = pvscsi_reset;
dc->vmsd = &vmstate_pvscsi;
dc->props = pvscsi_properties;
.class_init = pvscsi_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
+ { INTERFACE_PCIE_DEVICE },
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
};