diff options
-rw-r--r-- | block/iscsi.c | 42 | ||||
-rw-r--r-- | hw/i386/kvmvapic.c | 1 | ||||
-rw-r--r-- | hw/i386/pc.c | 19 | ||||
-rw-r--r-- | hw/i386/pc_piix.c | 4 | ||||
-rw-r--r-- | hw/i386/pc_q35.c | 3 | ||||
-rw-r--r-- | hw/misc/ivshmem.c | 118 | ||||
-rw-r--r-- | hw/misc/vfio.c | 1 | ||||
-rw-r--r-- | hw/scsi/megasas.c | 574 | ||||
-rw-r--r-- | hw/scsi/mfi.h | 16 | ||||
-rw-r--r-- | hw/scsi/scsi-bus.c | 71 | ||||
-rw-r--r-- | hw/scsi/scsi-disk.c | 18 | ||||
-rw-r--r-- | hw/scsi/scsi-generic.c | 7 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi-dataplane.c | 3 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 8 | ||||
-rw-r--r-- | include/exec/memory.h | 19 | ||||
-rw-r--r-- | include/hw/i386/pc.h | 2 | ||||
-rw-r--r-- | include/hw/pci/pci_ids.h | 1 | ||||
-rw-r--r-- | include/hw/scsi/scsi.h | 7 | ||||
-rw-r--r-- | memory.c | 10 | ||||
-rw-r--r-- | memory_mapping.c | 3 | ||||
-rw-r--r-- | qemu-options.hx | 3 | ||||
-rw-r--r-- | rules.mak | 5 | ||||
-rwxr-xr-x | scripts/kvm/kvm_stat | 150 | ||||
-rw-r--r-- | target-i386/translate.c | 3 | ||||
-rw-r--r-- | trace-events | 54 | ||||
-rw-r--r-- | ui/Makefile.objs | 5 | ||||
-rw-r--r-- | vl.c | 9 |
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, ¤t_pc, ¤t_cs_base, ¤t_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); @@ -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 @@ -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) @@ -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)); |