aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/iscsi.c42
-rw-r--r--hw/i386/kvmvapic.c1
-rw-r--r--hw/i386/pc.c19
-rw-r--r--hw/i386/pc_piix.c4
-rw-r--r--hw/i386/pc_q35.c3
-rw-r--r--hw/misc/ivshmem.c118
-rw-r--r--hw/misc/vfio.c1
-rw-r--r--hw/scsi/megasas.c574
-rw-r--r--hw/scsi/mfi.h16
-rw-r--r--hw/scsi/scsi-bus.c71
-rw-r--r--hw/scsi/scsi-disk.c18
-rw-r--r--hw/scsi/scsi-generic.c7
-rw-r--r--hw/scsi/virtio-scsi-dataplane.c3
-rw-r--r--hw/scsi/virtio-scsi.c8
-rw-r--r--include/exec/memory.h19
-rw-r--r--include/hw/i386/pc.h2
-rw-r--r--include/hw/pci/pci_ids.h1
-rw-r--r--include/hw/scsi/scsi.h7
-rw-r--r--memory.c10
-rw-r--r--memory_mapping.c3
-rw-r--r--qemu-options.hx3
-rw-r--r--rules.mak5
-rwxr-xr-xscripts/kvm/kvm_stat150
-rw-r--r--target-i386/translate.c3
-rw-r--r--trace-events54
-rw-r--r--ui/Makefile.objs5
-rw-r--r--vl.c9
27 files changed, 824 insertions, 332 deletions
diff --git a/block/iscsi.c b/block/iscsi.c
index 233f462..3485d62 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -1219,6 +1219,40 @@ static void iscsi_attach_aio_context(BlockDriverState *bs,
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
}
+static bool iscsi_is_write_protected(IscsiLun *iscsilun)
+{
+ struct scsi_task *task;
+ struct scsi_mode_sense *ms = NULL;
+ bool wrprotected = false;
+
+ task = iscsi_modesense6_sync(iscsilun->iscsi, iscsilun->lun,
+ 1, SCSI_MODESENSE_PC_CURRENT,
+ 0x3F, 0, 255);
+ if (task == NULL) {
+ error_report("iSCSI: Failed to send MODE_SENSE(6) command: %s",
+ iscsi_get_error(iscsilun->iscsi));
+ goto out;
+ }
+
+ if (task->status != SCSI_STATUS_GOOD) {
+ error_report("iSCSI: Failed MODE_SENSE(6), LUN assumed writable");
+ goto out;
+ }
+ ms = scsi_datain_unmarshall(task);
+ if (!ms) {
+ error_report("iSCSI: Failed to unmarshall MODE_SENSE(6) data: %s",
+ iscsi_get_error(iscsilun->iscsi));
+ goto out;
+ }
+ wrprotected = ms->device_specific_parameter & 0x80;
+
+out:
+ if (task) {
+ scsi_free_scsi_task(task);
+ }
+ return wrprotected;
+}
+
/*
* We support iscsi url's on the form
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
@@ -1339,6 +1373,14 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
scsi_free_scsi_task(task);
task = NULL;
+ /* Check the write protect flag of the LUN if we want to write */
+ if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
+ iscsi_is_write_protected(iscsilun)) {
+ error_setg(errp, "Cannot open a write protected LUN as read-write");
+ ret = -EACCES;
+ goto out;
+ }
+
iscsi_readcapacity_sync(iscsilun, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 2dc362b..c6d34b2 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -405,7 +405,6 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
}
if (!kvm_enabled()) {
- cpu_restore_state(cs, cs->mem_io_pc);
cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
&current_flags);
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 61aba9f..889e888 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1688,6 +1688,20 @@ static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v,
pcms->max_ram_below_4g = value;
}
+static bool pc_machine_get_vmport(Object *obj, Error **errp)
+{
+ PCMachineState *pcms = PC_MACHINE(obj);
+
+ return pcms->vmport;
+}
+
+static void pc_machine_set_vmport(Object *obj, bool value, Error **errp)
+{
+ PCMachineState *pcms = PC_MACHINE(obj);
+
+ pcms->vmport = value;
+}
+
static void pc_machine_initfn(Object *obj)
{
PCMachineState *pcms = PC_MACHINE(obj);
@@ -1700,6 +1714,11 @@ static void pc_machine_initfn(Object *obj)
pc_machine_get_max_ram_below_4g,
pc_machine_set_max_ram_below_4g,
NULL, NULL, NULL);
+ pcms->vmport = !xen_enabled();
+ object_property_add_bool(obj, PC_MACHINE_VMPORT,
+ pc_machine_get_vmport,
+ pc_machine_set_vmport,
+ NULL);
}
static void pc_machine_class_init(ObjectClass *oc, void *data)
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 91a20cb..1cda5dd 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -234,8 +234,8 @@ static void pc_init1(MachineState *machine,
pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
/* init basic PC hardware */
- pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled(),
- 0x4);
+ pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy,
+ !pc_machine->vmport, 0x4);
pc_nic_init(isa_bus, pci_bus);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index e225c6d..4d9e3cd 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -242,7 +242,8 @@ static void pc_q35_init(MachineState *machine)
pc_register_ferr_irq(gsi[13]);
/* init basic PC hardware */
- pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false, 0xff0104);
+ pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy,
+ !pc_machine->vmport, 0xff0104);
/* connect pm stuff to lpc */
ich9_lpc_pm_init(lpc);
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index bd9d718..5d272c8 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -24,10 +24,12 @@
#include "migration/migration.h"
#include "qapi/qmp/qerror.h"
#include "qemu/event_notifier.h"
+#include "qemu/fifo8.h"
#include "sysemu/char.h"
#include <sys/mman.h>
#include <sys/types.h>
+#include <limits.h>
#define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET
#define PCI_DEVICE_ID_IVSHMEM 0x1110
@@ -73,6 +75,7 @@ typedef struct IVShmemState {
CharDriverState **eventfd_chr;
CharDriverState *server_chr;
+ Fifo8 incoming_fifo;
MemoryRegion ivshmem_mmio;
/* We might need to register the BAR before we actually have the memory.
@@ -130,7 +133,7 @@ static void ivshmem_update_irq(IVShmemState *s, int val)
/* don't print ISR resets */
if (isr) {
IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
- isr ? 1 : 0, s->intrstatus, s->intrmask);
+ isr ? 1 : 0, s->intrstatus, s->intrmask);
}
pci_set_irq(d, (isr != 0));
@@ -297,8 +300,8 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *
chr = qemu_chr_open_eventfd(eventfd);
if (chr == NULL) {
- fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
- exit(-1);
+ error_report("creating eventfd for eventfd %d failed", eventfd);
+ exit(1);
}
qemu_chr_fe_claim_no_fail(chr);
@@ -325,16 +328,15 @@ static int check_shm_size(IVShmemState *s, int fd) {
struct stat buf;
if (fstat(fd, &buf) < 0) {
- fprintf(stderr, "ivshmem: exiting: fstat on fd %d failed: %s\n",
- fd, strerror(errno));
+ error_report("exiting: fstat on fd %d failed: %s",
+ fd, strerror(errno));
return -1;
}
if (s->ivshmem_size > buf.st_size) {
- fprintf(stderr,
- "IVSHMEM ERROR: Requested memory size greater"
- " than shared object size (%" PRIu64 " > %" PRIu64")\n",
- s->ivshmem_size, (uint64_t)buf.st_size);
+ error_report("Requested memory size greater"
+ " than shared object size (%" PRIu64 " > %" PRIu64")",
+ s->ivshmem_size, (uint64_t)buf.st_size);
return -1;
} else {
return 0;
@@ -387,6 +389,9 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
return;
}
+ if (posn < 0 || posn >= s->nb_peers) {
+ return;
+ }
guest_curr_max = s->peers[posn].nb_eventfds;
@@ -405,14 +410,24 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
/* this function increase the dynamic storage need to store data about other
* guests */
-static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
+static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
+{
int j, old_nb_alloc;
+ /* check for integer overflow */
+ if (new_min_size >= INT_MAX / sizeof(Peer) - 1 || new_min_size <= 0) {
+ return -1;
+ }
+
old_nb_alloc = s->nb_peers;
- while (new_min_size >= s->nb_peers)
- s->nb_peers = s->nb_peers * 2;
+ if (new_min_size >= s->nb_peers) {
+ /* +1 because #new_min_size is used as last array index */
+ s->nb_peers = new_min_size + 1;
+ } else {
+ return 0;
+ }
IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
@@ -422,23 +437,57 @@ static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
s->peers[j].eventfds = NULL;
s->peers[j].nb_eventfds = 0;
}
+
+ return 0;
}
-static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
+static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
{
IVShmemState *s = opaque;
int incoming_fd, tmp_fd;
int guest_max_eventfd;
long incoming_posn;
- memcpy(&incoming_posn, buf, sizeof(long));
+ if (fifo8_is_empty(&s->incoming_fifo) && size == sizeof(incoming_posn)) {
+ memcpy(&incoming_posn, buf, size);
+ } else {
+ const uint8_t *p;
+ uint32_t num;
+
+ IVSHMEM_DPRINTF("short read of %d bytes\n", size);
+ num = MAX(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
+ fifo8_push_all(&s->incoming_fifo, buf, num);
+ if (fifo8_num_used(&s->incoming_fifo) < sizeof(incoming_posn)) {
+ return;
+ }
+ size -= num;
+ buf += num;
+ p = fifo8_pop_buf(&s->incoming_fifo, sizeof(incoming_posn), &num);
+ g_assert(num == sizeof(incoming_posn));
+ memcpy(&incoming_posn, p, sizeof(incoming_posn));
+ if (size > 0) {
+ fifo8_push_all(&s->incoming_fifo, buf, size);
+ }
+ }
+
+ if (incoming_posn < -1) {
+ IVSHMEM_DPRINTF("invalid incoming_posn %ld\n", incoming_posn);
+ return;
+ }
+
/* pick off s->server_chr->msgfd and store it, posn should accompany msg */
tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
/* make sure we have enough space for this guest */
if (incoming_posn >= s->nb_peers) {
- increase_dynamic_storage(s, incoming_posn);
+ if (increase_dynamic_storage(s, incoming_posn) < 0) {
+ error_report("increase_dynamic_storage() failed");
+ if (tmp_fd != -1) {
+ close(tmp_fd);
+ }
+ return;
+ }
}
if (tmp_fd == -1) {
@@ -460,8 +509,8 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
incoming_fd = dup(tmp_fd);
if (incoming_fd == -1) {
- fprintf(stderr, "could not allocate file descriptor %s\n",
- strerror(errno));
+ error_report("could not allocate file descriptor %s", strerror(errno));
+ close(tmp_fd);
return;
}
@@ -473,7 +522,7 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
s->max_peer = 0;
if (check_shm_size(s, incoming_fd) == -1) {
- exit(-1);
+ exit(1);
}
/* mmap the region and map into the BAR2 */
@@ -484,7 +533,7 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
vmstate_register_ram(&s->ivshmem, DEVICE(s));
IVSHMEM_DPRINTF("guest h/w addr = %p, size = %" PRIu64 "\n",
- map_ptr, s->ivshmem_size);
+ map_ptr, s->ivshmem_size);
memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
@@ -505,7 +554,7 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
/* this is an eventfd for a particular guest VM */
IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
- guest_max_eventfd, incoming_fd);
+ guest_max_eventfd, incoming_fd);
event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd],
incoming_fd);
@@ -567,13 +616,13 @@ static uint64_t ivshmem_get_size(IVShmemState * s) {
value <<= 30;
break;
default:
- fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg);
+ error_report("invalid ram size: %s", s->sizearg);
exit(1);
}
/* BARs must be a power of 2 */
if (!is_power_of_two(value)) {
- fprintf(stderr, "ivshmem: size must be power of 2\n");
+ error_report("size must be power of 2");
exit(1);
}
@@ -625,7 +674,7 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
}
if (proxy->role_val == IVSHMEM_PEER) {
- fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n");
+ error_report("'peer' devices are not migratable");
return -EINVAL;
}
@@ -663,13 +712,15 @@ static int pci_ivshmem_init(PCIDevice *dev)
s->ivshmem_size = ivshmem_get_size(s);
}
+ fifo8_create(&s->incoming_fifo, sizeof(long));
+
register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
dev);
/* IRQFD requires MSI */
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
!ivshmem_has_feature(s, IVSHMEM_MSI)) {
- fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n");
+ error_report("ioeventfd/irqfd requires MSI");
exit(1);
}
@@ -680,7 +731,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
} else if (strncmp(s->role, "master", 7) == 0) {
s->role_val = IVSHMEM_MASTER;
} else {
- fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n");
+ error_report("'role' must be 'peer' or 'master'");
exit(1);
}
} else {
@@ -720,12 +771,12 @@ static int pci_ivshmem_init(PCIDevice *dev)
* to the ivshmem server to receive the memory region */
if (s->shmobj != NULL) {
- fprintf(stderr, "WARNING: do not specify both 'chardev' "
- "and 'shm' with ivshmem\n");
+ error_report("WARNING: do not specify both 'chardev' "
+ "and 'shm' with ivshmem");
}
IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
- s->server_chr->filename);
+ s->server_chr->filename);
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
ivshmem_setup_msi(s);
@@ -749,7 +800,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
int fd;
if (s->shmobj == NULL) {
- fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
+ error_report("Must specify 'chardev' or 'shm' to ivshmem");
exit(1);
}
@@ -761,18 +812,18 @@ static int pci_ivshmem_init(PCIDevice *dev)
S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
/* truncate file to length PCI device's memory */
if (ftruncate(fd, s->ivshmem_size) != 0) {
- fprintf(stderr, "ivshmem: could not truncate shared file\n");
+ error_report("could not truncate shared file");
}
} else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
- fprintf(stderr, "ivshmem: could not open shared file\n");
- exit(-1);
+ error_report("could not open shared file");
+ exit(1);
}
if (check_shm_size(s, fd) == -1) {
- exit(-1);
+ exit(1);
}
create_shared_memory_BAR(s, fd);
@@ -796,6 +847,7 @@ static void pci_ivshmem_uninit(PCIDevice *dev)
memory_region_del_subregion(&s->bar, &s->ivshmem);
vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
unregister_savevm(DEVICE(dev), "ivshmem", s);
+ fifo8_destroy(&s->incoming_fifo);
}
static Property ivshmem_properties[] = {
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
index b5e7981..fd318a1 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -2911,6 +2911,7 @@ static int vfio_mmap_bar(VFIODevice *vdev, VFIOBAR *bar,
}
memory_region_init_ram_ptr(submem, OBJECT(vdev), name, size, *map);
+ memory_region_set_skip_dump(submem);
} else {
empty_region:
/* Create a zero sized sub-region to make cleanup easy. */
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 36a04f3..604252a 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -31,9 +31,11 @@
#include "mfi.h"
-#define MEGASAS_VERSION "1.70"
+#define MEGASAS_VERSION_GEN1 "1.70"
+#define MEGASAS_VERSION_GEN2 "1.80"
#define MEGASAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */
#define MEGASAS_DEFAULT_FRAMES 1000 /* Windows requires this */
+#define MEGASAS_GEN2_DEFAULT_FRAMES 1008 /* Windows requires this */
#define MEGASAS_MAX_SGE 128 /* Firmware limit */
#define MEGASAS_DEFAULT_SGE 80
#define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */
@@ -91,6 +93,8 @@ typedef struct MegasasState {
int intr_mask;
int doorbell;
int busy;
+ int diag;
+ int adp_reset;
MegasasCmd *event_cmd;
int event_locale;
@@ -111,14 +115,30 @@ typedef struct MegasasState {
uint64_t producer_pa;
MegasasCmd frames[MEGASAS_MAX_FRAMES];
-
+ DECLARE_BITMAP(frame_map, MEGASAS_MAX_FRAMES);
SCSIBus bus;
} MegasasState;
-#define TYPE_MEGASAS "megasas"
+typedef struct MegasasBaseClass {
+ PCIDeviceClass parent_class;
+ const char *product_name;
+ const char *product_version;
+ int mmio_bar;
+ int ioport_bar;
+ int osts;
+} MegasasBaseClass;
+
+#define TYPE_MEGASAS_BASE "megasas-base"
+#define TYPE_MEGASAS_GEN1 "megasas"
+#define TYPE_MEGASAS_GEN2 "megasas-gen2"
#define MEGASAS(obj) \
- OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS)
+ OBJECT_CHECK(MegasasState, (obj), TYPE_MEGASAS_BASE)
+
+#define MEGASAS_DEVICE_CLASS(oc) \
+ OBJECT_CLASS_CHECK(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE)
+#define MEGASAS_DEVICE_GET_CLASS(oc) \
+ OBJECT_GET_CLASS(MegasasBaseClass, (oc), TYPE_MEGASAS_BASE)
#define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF
@@ -443,34 +463,20 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s,
return cmd;
}
-static MegasasCmd *megasas_next_frame(MegasasState *s,
- hwaddr frame)
+static void megasas_unmap_frame(MegasasState *s, MegasasCmd *cmd)
{
- MegasasCmd *cmd = NULL;
- int num = 0, index;
+ PCIDevice *p = PCI_DEVICE(s);
- cmd = megasas_lookup_frame(s, frame);
- if (cmd) {
- trace_megasas_qf_found(cmd->index, cmd->pa);
- return cmd;
- }
- index = s->reply_queue_head;
- num = 0;
- while (num < s->fw_cmds) {
- if (!s->frames[index].pa) {
- cmd = &s->frames[index];
- break;
- }
- index = megasas_next_index(s, index, s->fw_cmds);
- num++;
- }
- if (!cmd) {
- trace_megasas_qf_failed(frame);
- }
- trace_megasas_qf_new(index, cmd);
- return cmd;
+ pci_dma_unmap(p, cmd->frame, cmd->pa_size, 0, 0);
+ cmd->frame = NULL;
+ cmd->pa = 0;
+ clear_bit(cmd->index, s->frame_map);
}
+/*
+ * This absolutely needs to be locked if
+ * qemu ever goes multithreaded.
+ */
static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
hwaddr frame, uint64_t context, int count)
{
@@ -478,37 +484,50 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
MegasasCmd *cmd = NULL;
int frame_size = MFI_FRAME_SIZE * 16;
hwaddr frame_size_p = frame_size;
+ unsigned long index;
- cmd = megasas_next_frame(s, frame);
- /* All frames busy */
- if (!cmd) {
+ index = 0;
+ while (index < s->fw_cmds) {
+ index = find_next_zero_bit(s->frame_map, s->fw_cmds, index);
+ if (!s->frames[index].pa)
+ break;
+ /* Busy frame found */
+ trace_megasas_qf_mapped(index);
+ }
+ if (index >= s->fw_cmds) {
+ /* All frames busy */
+ trace_megasas_qf_busy(frame);
return NULL;
}
- if (!cmd->pa) {
- cmd->pa = frame;
- /* Map all possible frames */
- cmd->frame = pci_dma_map(pcid, frame, &frame_size_p, 0);
- if (frame_size_p != frame_size) {
- trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame);
- if (cmd->frame) {
- pci_dma_unmap(pcid, cmd->frame, frame_size_p, 0, 0);
- cmd->frame = NULL;
- cmd->pa = 0;
- }
- s->event_count++;
- return NULL;
- }
- cmd->pa_size = frame_size_p;
- cmd->context = context;
- if (!megasas_use_queue64(s)) {
- cmd->context &= (uint64_t)0xFFFFFFFF;
+ cmd = &s->frames[index];
+ set_bit(index, s->frame_map);
+ trace_megasas_qf_new(index, frame);
+
+ cmd->pa = frame;
+ /* Map all possible frames */
+ cmd->frame = pci_dma_map(pcid, frame, &frame_size_p, 0);
+ if (frame_size_p != frame_size) {
+ trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame);
+ if (cmd->frame) {
+ megasas_unmap_frame(s, cmd);
}
+ s->event_count++;
+ return NULL;
+ }
+ cmd->pa_size = frame_size_p;
+ cmd->context = context;
+ if (!megasas_use_queue64(s)) {
+ cmd->context &= (uint64_t)0xFFFFFFFF;
}
cmd->count = count;
s->busy++;
+ if (s->consumer_pa) {
+ s->reply_queue_tail = ldl_le_phys(&address_space_memory,
+ s->consumer_pa);
+ }
trace_megasas_qf_enqueue(cmd->index, cmd->count, cmd->context,
- s->reply_queue_head, s->busy);
+ s->reply_queue_head, s->reply_queue_tail, s->busy);
return cmd;
}
@@ -520,39 +539,47 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context)
/* Decrement busy count */
s->busy--;
-
if (s->reply_queue_pa) {
/*
* Put command on the reply queue.
* Context is opaque, but emulation is running in
* little endian. So convert it.
*/
- tail = s->reply_queue_head;
if (megasas_use_queue64(s)) {
- queue_offset = tail * sizeof(uint64_t);
+ queue_offset = s->reply_queue_head * sizeof(uint64_t);
stq_le_phys(&address_space_memory,
s->reply_queue_pa + queue_offset, context);
} else {
- queue_offset = tail * sizeof(uint32_t);
+ queue_offset = s->reply_queue_head * sizeof(uint32_t);
stl_le_phys(&address_space_memory,
s->reply_queue_pa + queue_offset, context);
}
- s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds);
- trace_megasas_qf_complete(context, tail, queue_offset,
- s->busy, s->doorbell);
+ s->reply_queue_tail = ldl_le_phys(&address_space_memory,
+ s->consumer_pa);
+ trace_megasas_qf_complete(context, s->reply_queue_head,
+ s->reply_queue_tail, s->busy);
}
if (megasas_intr_enabled(s)) {
+ /* Update reply queue pointer */
+ s->reply_queue_tail = ldl_le_phys(&address_space_memory,
+ s->consumer_pa);
+ tail = s->reply_queue_head;
+ s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds);
+ trace_megasas_qf_update(s->reply_queue_head, s->reply_queue_tail,
+ s->busy);
+ stl_le_phys(&address_space_memory,
+ s->producer_pa, s->reply_queue_head);
/* Notify HBA */
- s->doorbell++;
- if (s->doorbell == 1) {
- if (msix_enabled(pci_dev)) {
- trace_megasas_msix_raise(0);
- msix_notify(pci_dev, 0);
- } else if (msi_enabled(pci_dev)) {
- trace_megasas_msi_raise(0);
- msi_notify(pci_dev, 0);
- } else {
+ if (msix_enabled(pci_dev)) {
+ trace_megasas_msix_raise(0);
+ msix_notify(pci_dev, 0);
+ } else if (msi_enabled(pci_dev)) {
+ trace_megasas_msi_raise(0);
+ msi_notify(pci_dev, 0);
+ } else {
+ s->doorbell++;
+ if (s->doorbell == 1) {
trace_megasas_irq_raise();
pci_irq_assert(pci_dev);
}
@@ -564,18 +591,16 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context)
static void megasas_reset_frames(MegasasState *s)
{
- PCIDevice *pcid = PCI_DEVICE(s);
int i;
MegasasCmd *cmd;
for (i = 0; i < s->fw_cmds; i++) {
cmd = &s->frames[i];
if (cmd->pa) {
- pci_dma_unmap(pcid, cmd->frame, cmd->pa_size, 0, 0);
- cmd->frame = NULL;
- cmd->pa = 0;
+ megasas_unmap_frame(s, cmd);
}
}
+ bitmap_zero(s->frame_map, MEGASAS_MAX_FRAMES);
}
static void megasas_abort_command(MegasasCmd *cmd)
@@ -590,16 +615,19 @@ static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd)
{
PCIDevice *pcid = PCI_DEVICE(s);
uint32_t pa_hi, pa_lo;
- hwaddr iq_pa, initq_size;
- struct mfi_init_qinfo *initq;
+ hwaddr iq_pa, initq_size = sizeof(struct mfi_init_qinfo);
+ struct mfi_init_qinfo *initq = NULL;
uint32_t flags;
int ret = MFI_STAT_OK;
+ if (s->reply_queue_pa) {
+ trace_megasas_initq_mapped(s->reply_queue_pa);
+ goto out;
+ }
pa_lo = le32_to_cpu(cmd->frame->init.qinfo_new_addr_lo);
pa_hi = le32_to_cpu(cmd->frame->init.qinfo_new_addr_hi);
iq_pa = (((uint64_t) pa_hi << 32) | pa_lo);
trace_megasas_init_firmware((uint64_t)iq_pa);
- initq_size = sizeof(*initq);
initq = pci_dma_map(pcid, iq_pa, &initq_size, 0);
if (!initq || initq_size != sizeof(*initq)) {
trace_megasas_initq_map_failed(cmd->index);
@@ -686,11 +714,12 @@ static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size)
static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
{
PCIDevice *pci_dev = PCI_DEVICE(s);
+ PCIDeviceClass *pci_class = PCI_DEVICE_GET_CLASS(pci_dev);
+ MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s);
struct mfi_ctrl_info info;
size_t dcmd_size = sizeof(info);
BusChild *kid;
- int num_ld_disks = 0;
- uint16_t sdev_id;
+ int num_pd_disks = 0;
memset(&info, 0x0, cmd->iov_size);
if (cmd->iov_size < dcmd_size) {
@@ -699,10 +728,10 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
return MFI_STAT_INVALID_PARAMETER;
}
- info.pci.vendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
- info.pci.device = cpu_to_le16(PCI_DEVICE_ID_LSI_SAS1078);
- info.pci.subvendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
- info.pci.subdevice = cpu_to_le16(0x1013);
+ info.pci.vendor = cpu_to_le16(pci_class->vendor_id);
+ info.pci.device = cpu_to_le16(pci_class->device_id);
+ info.pci.subvendor = cpu_to_le16(pci_class->subsystem_vendor_id);
+ info.pci.subdevice = cpu_to_le16(pci_class->subsystem_id);
/*
* For some reason the firmware supports
@@ -719,20 +748,22 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
info.device.port_count = 8;
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+ uint16_t pd_id;
- if (num_ld_disks < 8) {
- sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
- info.device.port_addr[num_ld_disks] =
- cpu_to_le64(megasas_get_sata_addr(sdev_id));
+ if (num_pd_disks < 8) {
+ pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
+ info.device.port_addr[num_pd_disks] =
+ cpu_to_le64(megasas_get_sata_addr(pd_id));
}
- num_ld_disks++;
+ num_pd_disks++;
}
- memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
+ memcpy(info.product_name, base_class->product_name, 24);
snprintf(info.serial_number, 32, "%s", s->hba_serial);
snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
memcpy(info.image_component[0].name, "APP", 3);
- memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
+ snprintf(info.image_component[0].version, 10, "%s-QEMU",
+ base_class->product_version);
memcpy(info.image_component[0].build_date, "Apr 1 2014", 11);
memcpy(info.image_component[0].build_time, "12:34:56", 8);
info.image_component_count = 1;
@@ -751,13 +782,14 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
info.max_arms = 32;
info.max_spans = 8;
info.max_arrays = MEGASAS_MAX_ARRAYS;
- info.max_lds = s->fw_luns;
+ info.max_lds = MFI_MAX_LD;
info.max_cmds = cpu_to_le16(s->fw_cmds);
info.max_sg_elements = cpu_to_le16(s->fw_sge);
info.max_request_size = cpu_to_le32(MEGASAS_MAX_SECTORS);
- info.lds_present = cpu_to_le16(num_ld_disks);
- info.pd_present = cpu_to_le16(num_ld_disks);
- info.pd_disks_present = cpu_to_le16(num_ld_disks);
+ if (!megasas_is_jbod(s))
+ info.lds_present = cpu_to_le16(num_pd_disks);
+ info.pd_present = cpu_to_le16(num_pd_disks);
+ info.pd_disks_present = cpu_to_le16(num_pd_disks);
info.hw_present = cpu_to_le32(MFI_INFO_HW_NVRAM |
MFI_INFO_HW_MEM |
MFI_INFO_HW_FLASH);
@@ -916,7 +948,6 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
size_t dcmd_size = sizeof(info);
BusChild *kid;
uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks;
- uint16_t sdev_id;
memset(&info, 0, dcmd_size);
offset = 8;
@@ -928,22 +959,25 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
}
max_pd_disks = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address);
- if (max_pd_disks > s->fw_luns) {
- max_pd_disks = s->fw_luns;
+ if (max_pd_disks > MFI_MAX_SYS_PDS) {
+ max_pd_disks = MFI_MAX_SYS_PDS;
}
-
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+ uint16_t pd_id;
+
+ if (num_pd_disks >= max_pd_disks)
+ break;
- sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
- info.addr[num_pd_disks].device_id = cpu_to_le16(sdev_id);
+ pd_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
+ info.addr[num_pd_disks].device_id = cpu_to_le16(pd_id);
info.addr[num_pd_disks].encl_device_id = 0xFFFF;
info.addr[num_pd_disks].encl_index = 0;
- info.addr[num_pd_disks].slot_number = (sdev->id & 0xFF);
+ info.addr[num_pd_disks].slot_number = sdev->id & 0xFF;
info.addr[num_pd_disks].scsi_dev_type = sdev->type;
info.addr[num_pd_disks].connect_port_bitmap = 0x1;
info.addr[num_pd_disks].sas_addr[0] =
- cpu_to_le64(megasas_get_sata_addr(sdev_id));
+ cpu_to_le64(megasas_get_sata_addr(pd_id));
num_pd_disks++;
offset += sizeof(struct mfi_pd_address);
}
@@ -978,7 +1012,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
struct mfi_pd_info *info = cmd->iov_buf;
size_t dcmd_size = sizeof(struct mfi_pd_info);
uint64_t pd_size;
- uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF);
+ uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
uint8_t cmdbuf[6];
SCSIRequest *req;
size_t len, resid;
@@ -1034,7 +1068,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
info->fw_state = cpu_to_le16(MFI_PD_STATE_OFFLINE);
}
- info->ref.v.device_id = cpu_to_le16(sdev_id);
+ info->ref.v.device_id = cpu_to_le16(pd_id);
info->state.ddf.pd_type = cpu_to_le16(MFI_PD_DDF_TYPE_IN_VD|
MFI_PD_DDF_TYPE_INTF_SAS);
blk_get_geometry(sdev->conf.blk, &pd_size);
@@ -1045,7 +1079,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
info->slot_number = (sdev->id & 0xFF);
info->path_info.count = 1;
info->path_info.sas_addr[0] =
- cpu_to_le64(megasas_get_sata_addr(sdev_id));
+ cpu_to_le64(megasas_get_sata_addr(pd_id));
info->connected_port_bitmap = 0x1;
info->device_speed = 1;
info->link_speed = 1;
@@ -1060,6 +1094,7 @@ static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd)
{
size_t dcmd_size = sizeof(struct mfi_pd_info);
uint16_t pd_id;
+ uint8_t target_id, lun_id;
SCSIDevice *sdev = NULL;
int retval = MFI_STAT_DEVICE_NOT_FOUND;
@@ -1069,7 +1104,9 @@ static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd)
/* mbox0 has the ID */
pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
- sdev = scsi_device_find(&s->bus, 0, pd_id, 0);
+ target_id = (pd_id >> 8) & 0xFF;
+ lun_id = pd_id & 0xFF;
+ sdev = scsi_device_find(&s->bus, 0, target_id, lun_id);
trace_megasas_dcmd_pd_get_info(cmd->index, pd_id);
if (sdev) {
@@ -1084,20 +1121,24 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
{
struct mfi_ld_list info;
size_t dcmd_size = sizeof(info), resid;
- uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns;
+ uint32_t num_ld_disks = 0, max_ld_disks;
uint64_t ld_size;
BusChild *kid;
memset(&info, 0, dcmd_size);
- if (cmd->iov_size < dcmd_size) {
+ if (cmd->iov_size > dcmd_size) {
trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
dcmd_size);
return MFI_STAT_INVALID_PARAMETER;
}
+ max_ld_disks = (cmd->iov_size - 8) / 16;
if (megasas_is_jbod(s)) {
max_ld_disks = 0;
}
+ if (max_ld_disks > MFI_MAX_LD) {
+ max_ld_disks = MFI_MAX_LD;
+ }
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
@@ -1107,7 +1148,6 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
/* Logical device size is in blocks */
blk_get_geometry(sdev->conf.blk, &ld_size);
info.ld_list[num_ld_disks].ld.v.target_id = sdev->id;
- info.ld_list[num_ld_disks].ld.v.lun_id = sdev->lun;
info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size);
num_ld_disks++;
@@ -1123,15 +1163,49 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd)
{
uint16_t flags;
+ struct mfi_ld_targetid_list info;
+ size_t dcmd_size = sizeof(info), resid;
+ uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns;
+ BusChild *kid;
/* mbox0 contains flags */
flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
trace_megasas_dcmd_ld_list_query(cmd->index, flags);
- if (flags == MR_LD_QUERY_TYPE_ALL ||
- flags == MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) {
- return megasas_dcmd_ld_get_list(s, cmd);
+ if (flags != MR_LD_QUERY_TYPE_ALL &&
+ flags != MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) {
+ max_ld_disks = 0;
}
+ memset(&info, 0, dcmd_size);
+ if (cmd->iov_size < 12) {
+ trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
+ dcmd_size);
+ return MFI_STAT_INVALID_PARAMETER;
+ }
+ dcmd_size = sizeof(uint32_t) * 2 + 3;
+ max_ld_disks = cmd->iov_size - dcmd_size;
+ if (megasas_is_jbod(s)) {
+ max_ld_disks = 0;
+ }
+ if (max_ld_disks > MFI_MAX_LD) {
+ max_ld_disks = MFI_MAX_LD;
+ }
+ QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+ SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+
+ if (num_ld_disks >= max_ld_disks) {
+ break;
+ }
+ info.targetid[num_ld_disks] = sdev->lun;
+ num_ld_disks++;
+ dcmd_size++;
+ }
+ info.ld_count = cpu_to_le32(num_ld_disks);
+ info.size = dcmd_size;
+ trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks);
+
+ resid = dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
+ cmd->iov_size = dcmd_size - resid;
return MFI_STAT_OK;
}
@@ -1143,7 +1217,7 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
uint8_t cdb[6];
SCSIRequest *req;
ssize_t len, resid;
- uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF);
+ uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
uint64_t ld_size;
if (!cmd->iov_buf) {
@@ -1259,7 +1333,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
- uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
+ uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (sdev->lun & 0xFF);
struct mfi_array *array;
struct mfi_ld_config *ld;
uint64_t pd_size;
@@ -1285,7 +1359,7 @@ static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
array_offset += sizeof(struct mfi_array);
ld = (struct mfi_ld_config *)(data + ld_offset);
memset(ld, 0, sizeof(struct mfi_ld_config));
- ld->properties.ld.v.target_id = (sdev->id & 0xFF);
+ ld->properties.ld.v.target_id = sdev->id;
ld->properties.default_cache_policy = MR_LD_CACHE_READ_AHEAD |
MR_LD_CACHE_READ_ADAPTIVE;
ld->properties.current_cache_policy = MR_LD_CACHE_READ_AHEAD |
@@ -1347,9 +1421,23 @@ static int megasas_ctrl_shutdown(MegasasState *s, MegasasCmd *cmd)
return MFI_STAT_OK;
}
+/* Some implementations use CLUSTER RESET LD to simulate a device reset */
static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd)
{
- return MFI_STAT_INVALID_DCMD;
+ uint16_t target_id;
+ int i;
+
+ /* mbox0 contains the device index */
+ target_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
+ trace_megasas_dcmd_reset_ld(cmd->index, target_id);
+ for (i = 0; i < s->fw_cmds; i++) {
+ MegasasCmd *tmp_cmd = &s->frames[i];
+ if (tmp_cmd->req && tmp_cmd->req->dev->id == target_id) {
+ SCSIDevice *d = tmp_cmd->req->dev;
+ qdev_reset_all(&d->qdev);
+ }
+ }
+ return MFI_STAT_OK;
}
static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd)
@@ -1566,16 +1654,23 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
bool is_logical)
{
uint8_t *cdb;
- int len;
bool is_write;
struct SCSIDevice *sdev = NULL;
cdb = cmd->frame->pass.cdb;
- if (cmd->frame->header.target_id < s->fw_luns) {
- sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
- cmd->frame->header.lun_id);
+ if (is_logical) {
+ if (cmd->frame->header.target_id >= MFI_MAX_LD ||
+ cmd->frame->header.lun_id != 0) {
+ trace_megasas_scsi_target_not_present(
+ mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
+ cmd->frame->header.target_id, cmd->frame->header.lun_id);
+ return MFI_STAT_DEVICE_NOT_FOUND;
+ }
}
+ sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
+ cmd->frame->header.lun_id);
+
cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len);
trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd],
is_logical, cmd->frame->header.target_id,
@@ -1619,16 +1714,16 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
}
is_write = (cmd->req->cmd.mode == SCSI_XFER_TO_DEV);
- len = megasas_enqueue_req(cmd, is_write);
- if (len > 0) {
+ if (cmd->iov_size) {
if (is_write) {
- trace_megasas_scsi_write_start(cmd->index, len);
+ trace_megasas_scsi_write_start(cmd->index, cmd->iov_size);
} else {
- trace_megasas_scsi_read_start(cmd->index, len);
+ trace_megasas_scsi_read_start(cmd->index, cmd->iov_size);
}
} else {
trace_megasas_scsi_nodata(cmd->index);
}
+ megasas_enqueue_req(cmd, is_write);
return MFI_STAT_INVALID_STATUS;
}
@@ -1646,7 +1741,8 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd)
lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi);
lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo;
- if (cmd->frame->header.target_id < s->fw_luns) {
+ if (cmd->frame->header.target_id < MFI_MAX_LD &&
+ cmd->frame->header.lun_id == 0) {
sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
cmd->frame->header.lun_id);
}
@@ -1797,6 +1893,7 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
cmd->req = NULL;
}
cmd->frame->header.cmd_status = cmd_status;
+ megasas_unmap_frame(cmd->state, cmd);
megasas_complete_frame(cmd->state, cmd->context);
}
@@ -1900,6 +1997,7 @@ static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr,
} else {
megasas_frame_set_cmd_status(frame_addr, frame_status);
}
+ megasas_unmap_frame(s, cmd);
megasas_complete_frame(s, cmd->context);
}
}
@@ -1908,38 +2006,55 @@ static uint64_t megasas_mmio_read(void *opaque, hwaddr addr,
unsigned size)
{
MegasasState *s = opaque;
+ PCIDevice *pci_dev = PCI_DEVICE(s);
+ MegasasBaseClass *base_class = MEGASAS_DEVICE_GET_CLASS(s);
uint32_t retval = 0;
switch (addr) {
case MFI_IDB:
retval = 0;
+ trace_megasas_mmio_readl("MFI_IDB", retval);
break;
case MFI_OMSG0:
case MFI_OSP0:
- retval = (megasas_use_msix(s) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) |
+ retval = (msix_present(pci_dev) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) |
(s->fw_state & MFI_FWSTATE_MASK) |
((s->fw_sge & 0xff) << 16) |
(s->fw_cmds & 0xFFFF);
+ trace_megasas_mmio_readl(addr == MFI_OMSG0 ? "MFI_OMSG0" : "MFI_OSP0",
+ retval);
break;
case MFI_OSTS:
if (megasas_intr_enabled(s) && s->doorbell) {
- retval = MFI_1078_RM | 1;
+ retval = base_class->osts;
}
+ trace_megasas_mmio_readl("MFI_OSTS", retval);
break;
case MFI_OMSK:
retval = s->intr_mask;
+ trace_megasas_mmio_readl("MFI_OMSK", retval);
break;
case MFI_ODCR0:
- retval = s->doorbell;
+ retval = s->doorbell ? 1 : 0;
+ trace_megasas_mmio_readl("MFI_ODCR0", retval);
+ break;
+ case MFI_DIAG:
+ retval = s->diag;
+ trace_megasas_mmio_readl("MFI_DIAG", retval);
+ break;
+ case MFI_OSP1:
+ retval = 15;
+ trace_megasas_mmio_readl("MFI_OSP1", retval);
break;
default:
trace_megasas_mmio_invalid_readl(addr);
break;
}
- trace_megasas_mmio_readl(addr, retval);
return retval;
}
+static int adp_reset_seq[] = {0x00, 0x04, 0x0b, 0x02, 0x07, 0x0d};
+
static void megasas_mmio_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
@@ -1949,9 +2064,9 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
uint32_t frame_count;
int i;
- trace_megasas_mmio_writel(addr, val);
switch (addr) {
case MFI_IDB:
+ trace_megasas_mmio_writel("MFI_IDB", val);
if (val & MFI_FWINIT_ABORT) {
/* Abort all pending cmds */
for (i = 0; i < s->fw_cmds; i++) {
@@ -1965,8 +2080,13 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
if (val & MFI_FWINIT_MFIMODE) {
/* discard MFIs */
}
+ if (val & MFI_FWINIT_STOP_ADP) {
+ /* Terminal error, stop processing */
+ s->fw_state = MFI_FWSTATE_FAULT;
+ }
break;
case MFI_OMSK:
+ trace_megasas_mmio_writel("MFI_OMSK", val);
s->intr_mask = val;
if (!megasas_intr_enabled(s) &&
!msi_enabled(pci_dev) &&
@@ -1984,29 +2104,34 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
}
} else {
trace_megasas_intr_disabled();
+ megasas_soft_reset(s);
}
break;
case MFI_ODCR0:
+ trace_megasas_mmio_writel("MFI_ODCR0", val);
s->doorbell = 0;
- if (s->producer_pa && megasas_intr_enabled(s)) {
- /* Update reply queue pointer */
- trace_megasas_qf_update(s->reply_queue_head, s->busy);
- stl_le_phys(&address_space_memory,
- s->producer_pa, s->reply_queue_head);
- if (!msix_enabled(pci_dev)) {
+ if (megasas_intr_enabled(s)) {
+ if (!msix_enabled(pci_dev) && !msi_enabled(pci_dev)) {
trace_megasas_irq_lower();
pci_irq_deassert(pci_dev);
}
}
break;
case MFI_IQPH:
+ trace_megasas_mmio_writel("MFI_IQPH", val);
/* Received high 32 bits of a 64 bit MFI frame address */
s->frame_hi = val;
break;
case MFI_IQPL:
+ trace_megasas_mmio_writel("MFI_IQPL", val);
/* Received low 32 bits of a 64 bit MFI frame address */
+ /* Fallthrough */
case MFI_IQP:
- /* Received 32 bit MFI frame address */
+ if (addr == MFI_IQP) {
+ trace_megasas_mmio_writel("MFI_IQP", val);
+ /* Received 64 bit MFI frame address */
+ s->frame_hi = 0;
+ }
frame_addr = (val & ~0x1F);
/* Add possible 64 bit offset */
frame_addr |= ((uint64_t)s->frame_hi << 32);
@@ -2014,6 +2139,30 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
frame_count = (val >> 1) & 0xF;
megasas_handle_frame(s, frame_addr, frame_count);
break;
+ case MFI_SEQ:
+ trace_megasas_mmio_writel("MFI_SEQ", val);
+ /* Magic sequence to start ADP reset */
+ if (adp_reset_seq[s->adp_reset] == val) {
+ s->adp_reset++;
+ } else {
+ s->adp_reset = 0;
+ s->diag = 0;
+ }
+ if (s->adp_reset == 6) {
+ s->diag = MFI_DIAG_WRITE_ENABLE;
+ }
+ break;
+ case MFI_DIAG:
+ trace_megasas_mmio_writel("MFI_DIAG", val);
+ /* ADP reset */
+ if ((s->diag & MFI_DIAG_WRITE_ENABLE) &&
+ (val & MFI_DIAG_RESET_ADP)) {
+ s->diag |= MFI_DIAG_RESET_ADP;
+ megasas_soft_reset(s);
+ s->adp_reset = 0;
+ s->diag = 0;
+ }
+ break;
default:
trace_megasas_mmio_invalid_writel(addr, val);
break;
@@ -2072,11 +2221,26 @@ static void megasas_soft_reset(MegasasState *s)
int i;
MegasasCmd *cmd;
- trace_megasas_reset();
+ trace_megasas_reset(s->fw_state);
for (i = 0; i < s->fw_cmds; i++) {
cmd = &s->frames[i];
megasas_abort_command(cmd);
}
+ if (s->fw_state == MFI_FWSTATE_READY) {
+ BusChild *kid;
+
+ /*
+ * The EFI firmware doesn't handle UA,
+ * so we need to clear the Power On/Reset UA
+ * after the initial reset.
+ */
+ QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+ SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+
+ sdev->unit_attention = SENSE_CODE(NO_SENSE);
+ scsi_device_unit_attention_reported(sdev);
+ }
+ }
megasas_reset_frames(s);
s->reply_queue_len = s->fw_cmds;
s->reply_queue_pa = 0;
@@ -2098,7 +2262,7 @@ static void megasas_scsi_reset(DeviceState *dev)
megasas_soft_reset(s);
}
-static const VMStateDescription vmstate_megasas = {
+static const VMStateDescription vmstate_megasas_gen1 = {
.name = "megasas",
.version_id = 0,
.minimum_version_id = 0,
@@ -2116,6 +2280,25 @@ static const VMStateDescription vmstate_megasas = {
}
};
+static const VMStateDescription vmstate_megasas_gen2 = {
+ .name = "megasas-gen2",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCIE_DEVICE(parent_obj, MegasasState),
+ VMSTATE_MSIX(parent_obj, MegasasState),
+
+ VMSTATE_INT32(fw_state, MegasasState),
+ VMSTATE_INT32(intr_mask, MegasasState),
+ VMSTATE_INT32(doorbell, MegasasState),
+ VMSTATE_UINT64(reply_queue_pa, MegasasState),
+ VMSTATE_UINT64(consumer_pa, MegasasState),
+ VMSTATE_UINT64(producer_pa, MegasasState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void megasas_scsi_uninit(PCIDevice *d)
{
MegasasState *s = MEGASAS(d);
@@ -2143,6 +2326,7 @@ static int megasas_scsi_init(PCIDevice *dev)
{
DeviceState *d = DEVICE(dev);
MegasasState *s = MEGASAS(dev);
+ MegasasBaseClass *b = MEGASAS_DEVICE_GET_CLASS(s);
uint8_t *pci_conf;
int i, bar_type;
Error *err = NULL;
@@ -2166,20 +2350,25 @@ static int megasas_scsi_init(PCIDevice *dev)
s->flags &= ~MEGASAS_MASK_USE_MSI;
}
if (megasas_use_msix(s) &&
- msix_init(dev, 15, &s->mmio_io, 0, 0x2000,
- &s->mmio_io, 0, 0x3800, 0x68)) {
+ msix_init(dev, 15, &s->mmio_io, b->mmio_bar, 0x2000,
+ &s->mmio_io, b->mmio_bar, 0x3800, 0x68)) {
s->flags &= ~MEGASAS_MASK_USE_MSIX;
}
+ if (pci_is_express(dev)) {
+ pcie_endpoint_cap_init(dev, 0xa0);
+ }
bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64;
- pci_register_bar(dev, 0, bar_type, &s->mmio_io);
- pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
+ pci_register_bar(dev, b->ioport_bar,
+ PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
+ pci_register_bar(dev, b->mmio_bar, bar_type, &s->mmio_io);
pci_register_bar(dev, 3, bar_type, &s->queue_io);
if (megasas_use_msix(s)) {
msix_vector_use(dev, 0);
}
+ s->fw_state = MFI_FWSTATE_READY;
if (!s->sas_addr) {
s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) |
IEEE_COMPANY_LOCALLY_ASSIGNED) << 36;
@@ -2202,8 +2391,12 @@ static int megasas_scsi_init(PCIDevice *dev)
}
trace_megasas_init(s->fw_sge, s->fw_cmds,
megasas_is_jbod(s) ? "jbod" : "raid");
- s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ?
- MAX_SCSI_DEVS : MFI_MAX_LD;
+
+ if (megasas_is_jbod(s)) {
+ s->fw_luns = MFI_MAX_SYS_PDS;
+ } else {
+ s->fw_luns = MFI_MAX_LD;
+ }
s->producer_pa = 0;
s->consumer_pa = 0;
for (i = 0; i < s->fw_cmds; i++) {
@@ -2232,7 +2425,7 @@ megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len)
msi_write_config(pci, addr, val, len);
}
-static Property megasas_properties[] = {
+static Property megasas_properties_gen1[] = {
DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
MEGASAS_DEFAULT_SGE),
DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
@@ -2248,36 +2441,119 @@ static Property megasas_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static Property megasas_properties_gen2[] = {
+ DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
+ MEGASAS_DEFAULT_SGE),
+ DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
+ MEGASAS_GEN2_DEFAULT_FRAMES),
+ DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
+ DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0),
+ DEFINE_PROP_BIT("use_msi", MegasasState, flags,
+ MEGASAS_FLAG_USE_MSI, true),
+ DEFINE_PROP_BIT("use_msix", MegasasState, flags,
+ MEGASAS_FLAG_USE_MSIX, true),
+ DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
+ MEGASAS_FLAG_USE_JBOD, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+typedef struct MegasasInfo {
+ const char *name;
+ const char *desc;
+ const char *product_name;
+ const char *product_version;
+ uint16_t device_id;
+ uint16_t subsystem_id;
+ int ioport_bar;
+ int mmio_bar;
+ bool is_express;
+ int osts;
+ const VMStateDescription *vmsd;
+ Property *props;
+} MegasasInfo;
+
+static struct MegasasInfo megasas_devices[] = {
+ {
+ .name = TYPE_MEGASAS_GEN1,
+ .desc = "LSI MegaRAID SAS 1078",
+ .product_name = "LSI MegaRAID SAS 8708EM2",
+ .product_version = MEGASAS_VERSION_GEN1,
+ .device_id = PCI_DEVICE_ID_LSI_SAS1078,
+ .subsystem_id = 0x1013,
+ .ioport_bar = 2,
+ .mmio_bar = 0,
+ .osts = MFI_1078_RM | 1,
+ .is_express = false,
+ .vmsd = &vmstate_megasas_gen1,
+ .props = megasas_properties_gen1,
+ },{
+ .name = TYPE_MEGASAS_GEN2,
+ .desc = "LSI MegaRAID SAS 2108",
+ .product_name = "LSI MegaRAID SAS 9260-8i",
+ .product_version = MEGASAS_VERSION_GEN2,
+ .device_id = PCI_DEVICE_ID_LSI_SAS0079,
+ .subsystem_id = 0x9261,
+ .ioport_bar = 0,
+ .mmio_bar = 1,
+ .osts = MFI_GEN2_RM,
+ .is_express = true,
+ .vmsd = &vmstate_megasas_gen2,
+ .props = megasas_properties_gen2,
+ }
+};
+
static void megasas_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
+ MegasasBaseClass *e = MEGASAS_DEVICE_CLASS(oc);
+ const MegasasInfo *info = data;
pc->init = megasas_scsi_init;
pc->exit = megasas_scsi_uninit;
pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
- pc->device_id = PCI_DEVICE_ID_LSI_SAS1078;
+ pc->device_id = info->device_id;
pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
- pc->subsystem_id = 0x1013;
+ pc->subsystem_id = info->subsystem_id;
pc->class_id = PCI_CLASS_STORAGE_RAID;
- dc->props = megasas_properties;
+ pc->is_express = info->is_express;
+ e->mmio_bar = info->mmio_bar;
+ e->ioport_bar = info->ioport_bar;
+ e->osts = info->osts;
+ e->product_name = info->product_name;
+ e->product_version = info->product_version;
+ dc->props = info->props;
dc->reset = megasas_scsi_reset;
- dc->vmsd = &vmstate_megasas;
+ dc->vmsd = info->vmsd;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->desc = "LSI MegaRAID SAS 1078";
+ dc->desc = info->desc;
pc->config_write = megasas_write_config;
}
static const TypeInfo megasas_info = {
- .name = TYPE_MEGASAS,
+ .name = TYPE_MEGASAS_BASE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(MegasasState),
- .class_init = megasas_class_init,
+ .class_size = sizeof(MegasasBaseClass),
+ .abstract = true,
};
static void megasas_register_types(void)
{
+ int i;
+
type_register_static(&megasas_info);
+ for (i = 0; i < ARRAY_SIZE(megasas_devices); i++) {
+ const MegasasInfo *info = &megasas_devices[i];
+ TypeInfo type_info = {};
+
+ type_info.name = info->name;
+ type_info.parent = TYPE_MEGASAS_BASE;
+ type_info.class_data = (void *)info;
+ type_info.class_init = megasas_class_init;
+
+ type_register(&type_info);
+ }
}
type_init(megasas_register_types)
diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h
index a3034f6..29d4177 100644
--- a/hw/scsi/mfi.h
+++ b/hw/scsi/mfi.h
@@ -60,6 +60,7 @@
#define MFI_ODR0 0x9c /* outbound doorbell register0 */
#define MFI_ODCR0 0xa0 /* outbound doorbell clear register0 */
#define MFI_OSP0 0xb0 /* outbound scratch pad0 */
+#define MFI_OSP1 0xb4 /* outbound scratch pad1 */
#define MFI_IQPL 0xc0 /* Inbound queue port (low bytes) */
#define MFI_IQPH 0xc4 /* Inbound queue port (high bytes) */
#define MFI_DIAG 0xf8 /* Host diag */
@@ -116,6 +117,12 @@
#define MFI_FWINIT_STOP_ADP 0x00000020 /* Move to operational, stop */
#define MFI_FWINIT_ADP_RESET 0x00000040 /* Reset ADP */
+/*
+ * Control bits for the DIAG register
+ */
+#define MFI_DIAG_WRITE_ENABLE 0x00000080
+#define MFI_DIAG_RESET_ADP 0x00000004
+
/* MFI Commands */
typedef enum {
MFI_CMD_INIT = 0x00,
@@ -1094,7 +1101,7 @@ struct mfi_pd_list {
union mfi_ld_ref {
struct {
uint8_t target_id;
- uint8_t lun_id;
+ uint8_t reserved;
uint16_t seq;
} v;
uint32_t ref;
@@ -1111,6 +1118,13 @@ struct mfi_ld_list {
} ld_list[MFI_MAX_LD];
} QEMU_PACKED;
+struct mfi_ld_targetid_list {
+ uint32_t size;
+ uint32_t ld_count;
+ uint8_t pad[3];
+ uint8_t targetid[MFI_MAX_LD];
+} QEMU_PACKED;
+
enum mfi_ld_access {
MFI_LD_ACCESS_RW = 0,
MFI_LD_ACCSSS_RO = 2,
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index af7707c..24f7b74 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -51,14 +51,6 @@ static void scsi_device_realize(SCSIDevice *s, Error **errp)
}
}
-static void scsi_device_unrealize(SCSIDevice *s, Error **errp)
-{
- SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
- if (sc->unrealize) {
- sc->unrealize(s, errp);
- }
-}
-
int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
void *hba_private)
{
@@ -84,7 +76,7 @@ static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t
return NULL;
}
-static void scsi_device_unit_attention_reported(SCSIDevice *s)
+void scsi_device_unit_attention_reported(SCSIDevice *s)
{
SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
if (sc->unit_attention_reported) {
@@ -218,7 +210,9 @@ static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp)
if (dev->vmsentry) {
qemu_del_vm_change_state_handler(dev->vmsentry);
}
- scsi_device_unrealize(dev, errp);
+
+ scsi_device_purge_requests(dev, SENSE_CODE(NO_SENSE));
+ blockdev_mark_auto_del(dev->conf.blk);
}
/* handle legacy '-drive if=scsi,...' cmd line args */
@@ -826,7 +820,7 @@ static int ata_passthrough_xfer_unit(SCSIDevice *dev, uint8_t *buf)
return xfer_unit;
}
-static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf)
+static int ata_passthrough_12_xfer(SCSIDevice *dev, uint8_t *buf)
{
int length = buf[2] & 0x3;
int xfer;
@@ -849,7 +843,7 @@ static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf)
return xfer * unit;
}
-static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
+static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf)
{
int extend = buf[1] & 0x1;
int length = buf[2] & 0x3;
@@ -875,16 +869,16 @@ static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
return xfer * unit;
}
-uint32_t scsi_data_cdb_length(uint8_t *buf)
+uint32_t scsi_data_cdb_xfer(uint8_t *buf)
{
if ((buf[0] >> 5) == 0 && buf[4] == 0) {
return 256;
} else {
- return scsi_cdb_length(buf);
+ return scsi_cdb_xfer(buf);
}
}
-uint32_t scsi_cdb_length(uint8_t *buf)
+uint32_t scsi_cdb_xfer(uint8_t *buf)
{
switch (buf[0] >> 5) {
case 0:
@@ -905,9 +899,9 @@ uint32_t scsi_cdb_length(uint8_t *buf)
}
}
-static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
{
- cmd->xfer = scsi_cdb_length(buf);
+ cmd->xfer = scsi_cdb_xfer(buf);
switch (buf[0]) {
case TEST_UNIT_READY:
case REWIND:
@@ -1038,17 +1032,17 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
/* BLANK command of MMC */
cmd->xfer = 0;
} else {
- cmd->xfer = ata_passthrough_12_xfer_size(dev, buf);
+ cmd->xfer = ata_passthrough_12_xfer(dev, buf);
}
break;
case ATA_PASSTHROUGH_16:
- cmd->xfer = ata_passthrough_16_xfer_size(dev, buf);
+ cmd->xfer = ata_passthrough_16_xfer(dev, buf);
break;
}
return 0;
}
-static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+static int scsi_req_stream_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
{
switch (buf[0]) {
/* stream commands */
@@ -1103,12 +1097,12 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu
break;
/* generic commands */
default:
- return scsi_req_length(cmd, dev, buf);
+ return scsi_req_xfer(cmd, dev, buf);
}
return 0;
}
-static int scsi_req_medium_changer_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+static int scsi_req_medium_changer_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
{
switch (buf[0]) {
/* medium changer commands */
@@ -1125,7 +1119,7 @@ static int scsi_req_medium_changer_length(SCSICommand *cmd, SCSIDevice *dev, uin
/* generic commands */
default:
- return scsi_req_length(cmd, dev, buf);
+ return scsi_req_xfer(cmd, dev, buf);
}
return 0;
}
@@ -1214,38 +1208,45 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd)
return lba;
}
-int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
-{
- int rc;
+int scsi_cdb_length(uint8_t *buf) {
+ int cdb_len;
- cmd->lba = -1;
switch (buf[0] >> 5) {
case 0:
- cmd->len = 6;
+ cdb_len = 6;
break;
case 1:
case 2:
- cmd->len = 10;
+ cdb_len = 10;
break;
case 4:
- cmd->len = 16;
+ cdb_len = 16;
break;
case 5:
- cmd->len = 12;
+ cdb_len = 12;
break;
default:
- return -1;
+ cdb_len = -1;
}
+ return cdb_len;
+}
+
+int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
+{
+ int rc;
+
+ cmd->lba = -1;
+ cmd->len = scsi_cdb_length(buf);
switch (dev->type) {
case TYPE_TAPE:
- rc = scsi_req_stream_length(cmd, dev, buf);
+ rc = scsi_req_stream_xfer(cmd, dev, buf);
break;
case TYPE_MEDIUM_CHANGER:
- rc = scsi_req_medium_changer_length(cmd, dev, buf);
+ rc = scsi_req_medium_changer_xfer(cmd, dev, buf);
break;
default:
- rc = scsi_req_length(cmd, dev, buf);
+ rc = scsi_req_xfer(cmd, dev, buf);
break;
}
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 010eefd..2f75d7d 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -1666,7 +1666,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
{
SCSIRequest *req = &r->req;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
- uint32_t nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
+ uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf);
WriteSameCBData *data;
uint8_t *buf;
int i;
@@ -2061,7 +2061,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
- len = scsi_data_cdb_length(r->req.cmd.buf);
+ len = scsi_data_cdb_xfer(r->req.cmd.buf);
switch (command) {
case READ_6:
case READ_10:
@@ -2138,14 +2138,6 @@ static void scsi_disk_reset(DeviceState *dev)
s->tray_open = 0;
}
-static void scsi_unrealize(SCSIDevice *dev, Error **errp)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-
- scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
- blockdev_mark_auto_del(s->qdev.conf.blk);
-}
-
static void scsi_disk_resize_cb(void *opaque)
{
SCSIDiskState *s = opaque;
@@ -2396,7 +2388,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
{
int i;
- for (i = 1; i < req->cmd.len; i++) {
+ for (i = 1; i < scsi_cdb_length(buf); i++) {
printf(" 0x%02x", buf[i]);
}
printf("\n");
@@ -2612,7 +2604,6 @@ static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->realize = scsi_hd_realize;
- sc->unrealize = scsi_unrealize;
sc->alloc_req = scsi_new_request;
sc->unit_attention_reported = scsi_disk_unit_attention_reported;
dc->fw_name = "disk";
@@ -2643,7 +2634,6 @@ static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->realize = scsi_cd_realize;
- sc->unrealize = scsi_unrealize;
sc->alloc_req = scsi_new_request;
sc->unit_attention_reported = scsi_disk_unit_attention_reported;
dc->fw_name = "disk";
@@ -2672,7 +2662,6 @@ static void scsi_block_class_initfn(ObjectClass *klass, void *data)
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->realize = scsi_block_realize;
- sc->unrealize = scsi_unrealize;
sc->alloc_req = scsi_block_new_request;
sc->parse_cdb = scsi_block_parse_cdb;
dc->fw_name = "disk";
@@ -2710,7 +2699,6 @@ static void scsi_disk_class_initfn(ObjectClass *klass, void *data)
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->realize = scsi_disk_realize;
- sc->unrealize = scsi_unrealize;
sc->alloc_req = scsi_new_request;
sc->unit_attention_reported = scsi_disk_unit_attention_reported;
dc->fw_name = "disk";
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index f2e53af..6b9e4e1 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -368,12 +368,6 @@ static void scsi_generic_reset(DeviceState *dev)
scsi_device_purge_requests(s, SENSE_CODE(RESET));
}
-static void scsi_unrealize(SCSIDevice *s, Error **errp)
-{
- scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
- blockdev_mark_auto_del(s->conf.blk);
-}
-
static void scsi_generic_realize(SCSIDevice *s, Error **errp)
{
int rc;
@@ -478,7 +472,6 @@ static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
sc->realize = scsi_generic_realize;
- sc->unrealize = scsi_unrealize;
sc->alloc_req = scsi_new_request;
sc->parse_cdb = scsi_generic_parse_cdb;
dc->fw_name = "disk";
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 3097d54..9651e6f 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -241,9 +241,10 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s)
}
}
- aio_context_release(s->ctx);
s->dataplane_starting = false;
s->dataplane_started = true;
+ aio_context_release(s->ctx);
+ return;
fail_vrings:
virtio_scsi_clear_aio(s);
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 7d40ecc..fdcacfd 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -804,10 +804,12 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI,
sizeof(VirtIOSCSIConfig));
- if (s->conf.num_queues <= 0 || s->conf.num_queues > VIRTIO_PCI_QUEUE_MAX) {
- error_setg(errp, "Invalid number of queues (= %" PRId32 "), "
+ if (s->conf.num_queues == 0 ||
+ s->conf.num_queues > VIRTIO_PCI_QUEUE_MAX - 2) {
+ error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
"must be a positive integer less than %d.",
- s->conf.num_queues, VIRTIO_PCI_QUEUE_MAX);
+ s->conf.num_queues, VIRTIO_PCI_QUEUE_MAX - 2);
+ virtio_cleanup(vdev);
return;
}
s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *));
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 072aad2..74a58b4 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -150,6 +150,7 @@ struct MemoryRegion {
bool terminates;
bool romd_mode;
bool ram;
+ bool skip_dump;
bool readonly; /* For RAM regions */
bool enabled;
bool rom_device;
@@ -457,6 +458,24 @@ uint64_t memory_region_size(MemoryRegion *mr);
bool memory_region_is_ram(MemoryRegion *mr);
/**
+ * memory_region_is_skip_dump: check whether a memory region should not be
+ * dumped
+ *
+ * Returns %true is a memory region should not be dumped(e.g. VFIO BAR MMAP).
+ *
+ * @mr: the memory region being queried
+ */
+bool memory_region_is_skip_dump(MemoryRegion *mr);
+
+/**
+ * memory_region_set_skip_dump: Set skip_dump flag, dump will ignore this memory
+ * region
+ *
+ * @mr: the memory region being queried
+ */
+void memory_region_set_skip_dump(MemoryRegion *mr);
+
+/**
* memory_region_is_romd: check whether a memory region is in ROMD mode
*
* Returns %true if a memory region is a ROM device and currently set to allow
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index c4ee520..2545268 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -35,11 +35,13 @@ struct PCMachineState {
HotplugHandler *acpi_dev;
uint64_t max_ram_below_4g;
+ bool vmport;
};
#define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"
#define PC_MACHINE_MEMHP_REGION_SIZE "hotplug-memory-region-size"
#define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g"
+#define PC_MACHINE_VMPORT "vmport"
/**
* PCMachineClass:
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index e597070..321d622 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -56,6 +56,7 @@
#define PCI_DEVICE_ID_LSI_53C810 0x0001
#define PCI_DEVICE_ID_LSI_53C895A 0x0012
#define PCI_DEVICE_ID_LSI_SAS1078 0x0060
+#define PCI_DEVICE_ID_LSI_SAS0079 0x0079
#define PCI_VENDOR_ID_DEC 0x1011
#define PCI_DEVICE_ID_DEC_21154 0x0026
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index 6bc841a..cdaf0f8 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -84,7 +84,6 @@ struct SCSIRequest {
typedef struct SCSIDeviceClass {
DeviceClass parent_class;
void (*realize)(SCSIDevice *dev, Error **errp);
- void (*unrealize)(SCSIDevice *dev, Error **errp);
int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
void *hba_private);
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
@@ -239,8 +238,9 @@ extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
#define SENSE_CODE(x) sense_code_ ## x
-uint32_t scsi_data_cdb_length(uint8_t *buf);
-uint32_t scsi_cdb_length(uint8_t *buf);
+uint32_t scsi_data_cdb_xfer(uint8_t *buf);
+uint32_t scsi_cdb_xfer(uint8_t *buf);
+int scsi_cdb_length(uint8_t *buf);
int scsi_sense_valid(SCSISense sense);
int scsi_build_sense(uint8_t *in_buf, int in_len,
uint8_t *buf, int len, bool fixed);
@@ -271,6 +271,7 @@ void scsi_req_retry(SCSIRequest *req);
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense);
void scsi_device_report_change(SCSIDevice *dev, SCSISense sense);
+void scsi_device_unit_attention_reported(SCSIDevice *dev);
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
diff --git a/memory.c b/memory.c
index 30f77b2..0f4fdc7 100644
--- a/memory.c
+++ b/memory.c
@@ -1185,6 +1185,11 @@ void memory_region_init_ram_ptr(MemoryRegion *mr,
mr->ram_addr = qemu_ram_alloc_from_ptr(size, ptr, mr, &error_abort);
}
+void memory_region_set_skip_dump(MemoryRegion *mr)
+{
+ mr->skip_dump = true;
+}
+
void memory_region_init_alias(MemoryRegion *mr,
Object *owner,
const char *name,
@@ -1306,6 +1311,11 @@ bool memory_region_is_ram(MemoryRegion *mr)
return mr->ram;
}
+bool memory_region_is_skip_dump(MemoryRegion *mr)
+{
+ return mr->skip_dump;
+}
+
bool memory_region_is_logging(MemoryRegion *mr)
{
return mr->dirty_log_mask;
diff --git a/memory_mapping.c b/memory_mapping.c
index 87a6ed5..7b69801 100644
--- a/memory_mapping.c
+++ b/memory_mapping.c
@@ -203,7 +203,8 @@ static void guest_phys_blocks_region_add(MemoryListener *listener,
GuestPhysBlock *predecessor;
/* we only care about RAM */
- if (!memory_region_is_ram(section->mr)) {
+ if (!memory_region_is_ram(section->mr) ||
+ memory_region_is_skip_dump(section->mr)) {
return;
}
diff --git a/qemu-options.hx b/qemu-options.hx
index 1e7d5b8..da9851d 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -33,6 +33,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
" property accel=accel1[:accel2[:...]] selects accelerator\n"
" supported accelerators are kvm, xen, tcg (default: tcg)\n"
" kernel_irqchip=on|off controls accelerated irqchip support\n"
+ " vmport=on|off controls emulation of vmport (default: on)\n"
" kvm_shadow_mem=size of KVM shadow MMU\n"
" dump-guest-core=on|off include guest memory in a core dump (default=on)\n"
" mem-merge=on|off controls memory merge support (default: on)\n"
@@ -51,6 +52,8 @@ than one accelerator specified, the next one is used if the previous one fails
to initialize.
@item kernel_irqchip=on|off
Enables in-kernel irqchip support for the chosen accelerator when available.
+@item vmport=on|off
+Enables emulation of VMWare IO port, for vmmouse etc. (enabled by default)
@item kvm_shadow_mem=size
Defines the size of the KVM shadow MMU.
@item dump-guest-core=on|off
diff --git a/rules.mak b/rules.mak
index cf76b88..f500fef 100644
--- a/rules.mak
+++ b/rules.mak
@@ -362,4 +362,9 @@ define unnest-vars
# Include all the .d files
$(eval -include $(addsuffix *.d, $(sort $(dir $($v)))))
$(eval $v := $(filter-out %/,$($v))))
+
+ # For all %.mo objects that are directly added into -y, expand them to %.mo-objs
+ $(foreach v,$2,
+ $(eval $v := $(foreach o,$($v),$(if $($o-objs),$($o-objs),$o))))
+
endef
diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat
index d7e97e7..7b1437c 100755
--- a/scripts/kvm/kvm_stat
+++ b/scripts/kvm/kvm_stat
@@ -12,7 +12,7 @@
# the COPYING file in the top-level directory.
import curses
-import sys, os, time, optparse
+import sys, os, time, optparse, ctypes
class DebugfsProvider(object):
def __init__(self):
@@ -141,61 +141,97 @@ svm_exit_reasons = {
0x400: 'NPF',
}
-s390_exit_reasons = {
- 0x000: 'UNKNOWN',
- 0x001: 'EXCEPTION',
- 0x002: 'IO',
- 0x003: 'HYPERCALL',
- 0x004: 'DEBUG',
- 0x005: 'HLT',
- 0x006: 'MMIO',
- 0x007: 'IRQ_WINDOW_OPEN',
- 0x008: 'SHUTDOWN',
- 0x009: 'FAIL_ENTRY',
- 0x010: 'INTR',
- 0x011: 'SET_TPR',
- 0x012: 'TPR_ACCESS',
- 0x013: 'S390_SIEIC',
- 0x014: 'S390_RESET',
- 0x015: 'DCR',
- 0x016: 'NMI',
- 0x017: 'INTERNAL_ERROR',
- 0x018: 'OSI',
- 0x019: 'PAPR_HCALL',
+# From include/uapi/linux/kvm.h, KVM_EXIT_xxx
+userspace_exit_reasons = {
+ 0: 'UNKNOWN',
+ 1: 'EXCEPTION',
+ 2: 'IO',
+ 3: 'HYPERCALL',
+ 4: 'DEBUG',
+ 5: 'HLT',
+ 6: 'MMIO',
+ 7: 'IRQ_WINDOW_OPEN',
+ 8: 'SHUTDOWN',
+ 9: 'FAIL_ENTRY',
+ 10: 'INTR',
+ 11: 'SET_TPR',
+ 12: 'TPR_ACCESS',
+ 13: 'S390_SIEIC',
+ 14: 'S390_RESET',
+ 15: 'DCR',
+ 16: 'NMI',
+ 17: 'INTERNAL_ERROR',
+ 18: 'OSI',
+ 19: 'PAPR_HCALL',
+ 20: 'S390_UCONTROL',
+ 21: 'WATCHDOG',
+ 22: 'S390_TSCH',
+ 23: 'EPR',
}
-vendor_exit_reasons = {
+x86_exit_reasons = {
'vmx': vmx_exit_reasons,
'svm': svm_exit_reasons,
- 'IBM/S390': s390_exit_reasons,
}
-syscall_numbers = {
- 'IBM/S390': 331,
-}
-
-sc_perf_evt_open = 298
-
+sc_perf_evt_open = None
exit_reasons = None
-for line in file('/proc/cpuinfo').readlines():
- if line.startswith('flags') or line.startswith('vendor_id'):
- for flag in line.split():
- if flag in vendor_exit_reasons:
- exit_reasons = vendor_exit_reasons[flag]
- if flag in syscall_numbers:
- sc_perf_evt_open = syscall_numbers[flag]
-filters = {
- 'kvm_exit': ('exit_reason', exit_reasons)
+ioctl_numbers = {
+ 'SET_FILTER' : 0x40082406,
+ 'ENABLE' : 0x00002400,
+ 'DISABLE' : 0x00002401,
}
+def x86_init(flag):
+ globals().update({
+ 'sc_perf_evt_open' : 298,
+ 'exit_reasons' : x86_exit_reasons[flag],
+ })
+
+def s390_init():
+ globals().update({
+ 'sc_perf_evt_open' : 331
+ })
+
+def ppc_init():
+ globals().update({
+ 'sc_perf_evt_open' : 319,
+ 'ioctl_numbers' : {
+ 'SET_FILTER' : 0x80002406 | (ctypes.sizeof(ctypes.c_char_p) << 16),
+ 'ENABLE' : 0x20002400,
+ 'DISABLE' : 0x20002401,
+ }
+ })
+
+def detect_platform():
+ if os.uname()[4].startswith('ppc'):
+ ppc_init()
+ return
+
+ for line in file('/proc/cpuinfo').readlines():
+ if line.startswith('flags'):
+ for flag in line.split():
+ if flag in x86_exit_reasons:
+ x86_init(flag)
+ return
+ elif line.startswith('vendor_id'):
+ for flag in line.split():
+ if flag == 'IBM/S390':
+ s390_init()
+ return
+
+detect_platform()
+
def invert(d):
return dict((x[1], x[0]) for x in d.iteritems())
-for f in filters:
- filters[f] = (filters[f][0], invert(filters[f][1]))
+filters = {}
+filters['kvm_userspace_exit'] = ('reason', invert(userspace_exit_reasons))
+if exit_reasons:
+ filters['kvm_exit'] = ('exit_reason', invert(exit_reasons))
-import ctypes, struct, array
+import struct, array
libc = ctypes.CDLL('libc.so.6')
syscall = libc.syscall
@@ -285,14 +321,14 @@ class Event(object):
raise Exception('perf_event_open failed')
if filter:
import fcntl
- fcntl.ioctl(fd, 0x40082406, filter)
+ fcntl.ioctl(fd, ioctl_numbers['SET_FILTER'], filter)
self.fd = fd
def enable(self):
import fcntl
- fcntl.ioctl(self.fd, 0x00002400, 0)
+ fcntl.ioctl(self.fd, ioctl_numbers['ENABLE'], 0)
def disable(self):
import fcntl
- fcntl.ioctl(self.fd, 0x00002401, 0)
+ fcntl.ioctl(self.fd, ioctl_numbers['DISABLE'], 0)
class TracepointProvider(object):
def __init__(self):
@@ -311,18 +347,30 @@ class TracepointProvider(object):
self.select(fields)
def fields(self):
return self._fields
+
+ def _online_cpus(self):
+ l = []
+ pattern = r'cpu([0-9]+)'
+ basedir = '/sys/devices/system/cpu'
+ for entry in os.listdir(basedir):
+ match = re.match(pattern, entry)
+ if not match:
+ continue
+ path = os.path.join(basedir, entry, 'online')
+ if os.path.exists(path) and open(path).read().strip() != '1':
+ continue
+ l.append(int(match.group(1)))
+ return l
+
def _setup(self, _fields):
self._fields = _fields
- cpure = r'cpu([0-9]+)'
- self.cpus = [int(re.match(cpure, x).group(1))
- for x in os.listdir('/sys/devices/system/cpu')
- if re.match(cpure, x)]
+ cpus = self._online_cpus()
import resource
- nfiles = len(self.cpus) * 1000
+ nfiles = len(cpus) * 1000
resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles))
events = []
self.group_leaders = []
- for cpu in self.cpus:
+ for cpu in cpus:
group = Group(cpu)
for name in _fields:
tracepoint = name
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 418173e..782f7d2 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7987,7 +7987,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
if (bp->pc == pc_ptr &&
!((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
gen_debug(dc, pc_ptr - dc->cs_base);
- break;
+ goto done_generating;
}
}
}
@@ -8038,6 +8038,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
}
if (tb->cflags & CF_LAST_IO)
gen_io_end();
+done_generating:
gen_tb_end(tb, num_insns);
*tcg_ctx.gen_opc_ptr = INDEX_op_end;
/* we don't forget to fill the last values */
diff --git a/trace-events b/trace-events
index 6c3a400..b5722ea 100644
--- a/trace-events
+++ b/trace-events
@@ -697,35 +697,36 @@ lm32_uart_irq_state(int level) "irq state %d"
megasas_init_firmware(uint64_t pa) "pa %" PRIx64 " "
megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at %" PRIx64 " len %d head %" PRIx64 " tail %" PRIx64 " flags %x"
megasas_initq_map_failed(int frame) "scmd %d: failed to map queue"
+megasas_initq_mapped(uint64_t pa) "queue already mapped at %" PRIx64 ""
megasas_initq_mismatch(int queue_len, int fw_cmds) "queue size %d max fw cmds %d"
-megasas_qf_found(unsigned int index, uint64_t pa) "found mapped frame %x pa %" PRIx64 ""
-megasas_qf_new(unsigned int index, void *cmd) "return new frame %x cmd %p"
-megasas_qf_failed(unsigned long pa) "all frames busy for frame %lx"
-megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int tail, int busy) "enqueue frame %x count %d context %" PRIx64 " tail %x busy %d"
-megasas_qf_update(unsigned int head, unsigned int busy) "update reply queue head %x busy %d"
+megasas_qf_mapped(unsigned int index) "skip mapped frame %x"
+megasas_qf_new(unsigned int index, uint64_t frame) "frame %x addr %" PRIx64 ""
+megasas_qf_busy(unsigned long pa) "all frames busy for frame %lx"
+megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int head, unsigned int tail, int busy) "frame %x count %d context %" PRIx64 " head %x tail %x busy %d"
+megasas_qf_update(unsigned int head, unsigned int tail, unsigned int busy) "head %x tail %x busy %d"
megasas_qf_map_failed(int cmd, unsigned long frame) "scmd %d: frame %lu"
megasas_qf_complete_noirq(uint64_t context) "context %" PRIx64 " "
-megasas_qf_complete(uint64_t context, unsigned int tail, unsigned int offset, int busy, unsigned int doorbell) "context %" PRIx64 " tail %x offset %d busy %d doorbell %x"
+megasas_qf_complete(uint64_t context, unsigned int head, unsigned int tail, int busy) "context %" PRIx64 " head %x tail %x busy %d"
megasas_frame_busy(uint64_t addr) "frame %" PRIx64 " busy"
-megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: Unhandled MFI cmd %x"
+megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: MFI cmd %x"
megasas_handle_scsi(const char *frame, int bus, int dev, int lun, void *sdev, unsigned long size) "%s dev %x/%x/%x sdev %p xfer %lu"
-megasas_scsi_target_not_present(const char *frame, int bus, int dev, int lun) "%s dev %x/%x/%x target not present"
+megasas_scsi_target_not_present(const char *frame, int bus, int dev, int lun) "%s dev %x/%x/%x"
megasas_scsi_invalid_cdb_len(const char *frame, int bus, int dev, int lun, int len) "%s dev %x/%x/%x invalid cdb len %d"
megasas_iov_read_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
megasas_iov_write_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
megasas_iov_read_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
megasas_iov_write_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes"
-megasas_scsi_req_alloc_failed(const char *frame, int dev, int lun) "%s dev %x/%x req allocation failed"
+megasas_scsi_req_alloc_failed(const char *frame, int dev, int lun) "%s dev %x/%x"
megasas_scsi_read_start(int cmd, int len) "scmd %d: transfer %d bytes of data"
megasas_scsi_write_start(int cmd, int len) "scmd %d: transfer %d bytes of data"
megasas_scsi_nodata(int cmd) "scmd %d: no data to be transferred"
-megasas_scsi_complete(int cmd, uint32_t status, int len, int xfer) "scmd %d: finished with status %x, len %u/%u"
-megasas_command_complete(int cmd, uint32_t status, uint32_t resid) "scmd %d: command completed, status %x, residual %d"
+megasas_scsi_complete(int cmd, uint32_t status, int len, int xfer) "scmd %d: status %x, len %u/%u"
+megasas_command_complete(int cmd, uint32_t status, uint32_t resid) "scmd %d: status %x, residual %d"
megasas_handle_io(int cmd, const char *frame, int dev, int lun, unsigned long lba, unsigned long count) "scmd %d: %s dev %x/%x lba %lx count %lu"
megasas_io_target_not_present(int cmd, const char *frame, int dev, int lun) "scmd %d: %s dev 1/%x/%x LUN not present"
megasas_io_read_start(int cmd, unsigned long lba, unsigned long count, unsigned long len) "scmd %d: start LBA %lx %lu blocks (%lu bytes)"
megasas_io_write_start(int cmd, unsigned long lba, unsigned long count, unsigned long len) "scmd %d: start LBA %lx %lu blocks (%lu bytes)"
-megasas_io_complete(int cmd, uint32_t len) "scmd %d: %d bytes completed"
+megasas_io_complete(int cmd, uint32_t len) "scmd %d: %d bytes"
megasas_iovec_sgl_overflow(int cmd, int index, int limit) "scmd %d: iovec count %d limit %d"
megasas_iovec_sgl_underflow(int cmd, int index) "scmd %d: iovec count %d"
megasas_iovec_sgl_invalid(int cmd, int index, uint64_t pa, uint32_t len) "scmd %d: element %d pa %" PRIx64 " len %u"
@@ -733,28 +734,29 @@ megasas_iovec_overflow(int cmd, int len, int limit) "scmd %d: len %d limit %d"
megasas_iovec_underflow(int cmd, int len, int limit) "scmd %d: len %d limit %d"
megasas_handle_dcmd(int cmd, int opcode) "scmd %d: MFI DCMD opcode %x"
megasas_finish_dcmd(int cmd, int size) "scmd %d: MFI DCMD wrote %d bytes"
-megasas_dcmd_req_alloc_failed(int cmd, const char *desc) "scmd %d: %s alloc failed"
+megasas_dcmd_req_alloc_failed(int cmd, const char *desc) "scmd %d: %s"
megasas_dcmd_internal_submit(int cmd, const char *desc, int dev) "scmd %d: %s to dev %d"
-megasas_dcmd_internal_finish(int cmd, int opcode, int lun) "scmd %d: DCMD finish internal cmd %x lun %d"
-megasas_dcmd_internal_invalid(int cmd, int opcode) "scmd %d: Invalid internal DCMD %x"
+megasas_dcmd_internal_finish(int cmd, int opcode, int lun) "scmd %d: cmd %x lun %d"
+megasas_dcmd_internal_invalid(int cmd, int opcode) "scmd %d: DCMD %x"
megasas_dcmd_unhandled(int cmd, int opcode, int len) "scmd %d: opcode %x, len %d"
megasas_dcmd_zero_sge(int cmd) "scmd %d: zero DCMD sge count"
-megasas_dcmd_invalid_sge(int cmd, int count) "scmd %d: invalid DCMD sge count %d"
-megasas_dcmd_invalid_xfer_len(int cmd, unsigned long size, unsigned long max) "scmd %d: invalid xfer len %ld, max %ld"
+megasas_dcmd_invalid_sge(int cmd, int count) "scmd %d: DCMD sge count %d"
+megasas_dcmd_invalid_xfer_len(int cmd, unsigned long size, unsigned long max) "scmd %d: xfer len %ld, max %ld"
megasas_dcmd_enter(int cmd, const char *dcmd, int len) "scmd %d: DCMD %s len %d"
-megasas_dcmd_dummy(int cmd, unsigned long size) "scmd %d: DCMD dummy xfer len %ld"
+megasas_dcmd_dummy(int cmd, unsigned long size) "scmd %d: xfer len %ld"
megasas_dcmd_set_fw_time(int cmd, unsigned long time) "scmd %d: Set FW time %lx"
megasas_dcmd_pd_get_list(int cmd, int num, int max, int offset) "scmd %d: DCMD PD get list: %d / %d PDs, size %d"
megasas_dcmd_ld_get_list(int cmd, int num, int max) "scmd %d: DCMD LD get list: found %d / %d LDs"
-megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: DCMD LD get info for dev %d"
-megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: DCMD PD get info for dev %d"
-megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: DCMD PD list query flags %x"
-megasas_dcmd_ld_list_query(int cmd, int flags) "scmd %d: DCMD LD list query flags %x"
+megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: dev %d"
+megasas_dcmd_ld_list_query(int cmd, int flags) "scmd %d: query flags %x"
+megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: dev %d"
+megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: query flags %x"
+megasas_dcmd_reset_ld(int cmd, int target_id) "scmd %d: dev %d"
megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld"
-megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: aborting frame %x"
+megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: frame %x"
megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 ""
megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x"
-megasas_reset(void) "Reset"
+megasas_reset(int fw_state) "firmware state %x"
megasas_init(int sges, int cmds, const char *mode) "Using %d sges, %d cmds, %s mode"
megasas_msix_raise(int vector) "vector %d"
megasas_msi_raise(int vector) "vector %d"
@@ -764,9 +766,9 @@ megasas_intr_enabled(void) "Interrupts enabled"
megasas_intr_disabled(void) "Interrupts disabled"
megasas_msix_enabled(int vector) "vector %d"
megasas_msi_enabled(int vector) "vector %d"
-megasas_mmio_readl(unsigned long addr, uint32_t val) "addr 0x%lx: 0x%x"
+megasas_mmio_readl(const char *reg, uint32_t val) "reg %s: 0x%x"
megasas_mmio_invalid_readl(unsigned long addr) "addr 0x%lx"
-megasas_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
+megasas_mmio_writel(const char *reg, uint32_t val) "reg %s: 0x%x"
megasas_mmio_invalid_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
# hw/audio/milkymist-ac97.c
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 6afb52a..801cba2 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -10,12 +10,13 @@ vnc-obj-y += vnc-jobs.o
common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o
common-obj-y += input.o input-keymap.o input-legacy.o
common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o
-common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o sdl2.o
+common-obj-$(CONFIG_SDL) += sdl.mo x_keymap.o
common-obj-$(CONFIG_COCOA) += cocoa.o
common-obj-$(CONFIG_CURSES) += curses.o
common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o
-$(obj)/sdl.o $(obj)/sdl_zoom.o $(obj)/sdl2.o: QEMU_CFLAGS += $(SDL_CFLAGS)
+sdl.mo-objs := sdl.o sdl_zoom.o sdl2.o
+sdl.mo-cflags := $(SDL_CFLAGS)
gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
diff --git a/vl.c b/vl.c
index f6b3546..f070c90 100644
--- a/vl.c
+++ b/vl.c
@@ -376,6 +376,10 @@ static QemuOptsList qemu_machine_opts = {
.name = PC_MACHINE_MAX_RAM_BELOW_4G,
.type = QEMU_OPT_SIZE,
.help = "maximum ram below the 4G boundary (32bit boundary)",
+ }, {
+ .name = PC_MACHINE_VMPORT,
+ .type = QEMU_OPT_BOOL,
+ .help = "Enable vmport (pc & q35)",
},{
.name = "iommu",
.type = QEMU_OPT_BOOL,
@@ -3746,6 +3750,11 @@ int main(int argc, char **argv, char **envp)
configure_msg(opts);
break;
case QEMU_OPTION_dump_vmstate:
+ if (vmstate_dump_file) {
+ fprintf(stderr, "qemu: only one '-dump-vmstate' "
+ "option may be given\n");
+ exit(1);
+ }
vmstate_dump_file = fopen(optarg, "w");
if (vmstate_dump_file == NULL) {
fprintf(stderr, "open %s: %s\n", optarg, strerror(errno));