Compare commits
126 Commits
machine-ne
...
python-nex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad904f6689 | ||
|
|
5810314e98 | ||
|
|
9ee660e7c1 | ||
|
|
2a2be359c4 | ||
|
|
c4c8146cfd | ||
|
|
41da212c9c | ||
|
|
df4dc10284 | ||
|
|
27e38392ca | ||
|
|
26aa3d9aec | ||
|
|
5502b66fc7 | ||
|
|
ff5667ed53 | ||
|
|
211ad3b412 | ||
|
|
8d9329719c | ||
|
|
c110425d16 | ||
|
|
a803633660 | ||
|
|
a3fd781f65 | ||
|
|
b62b7ed0fc | ||
|
|
d3f5433c7b | ||
|
|
772a73692e | ||
|
|
4d8bc7334b | ||
|
|
6069537f43 | ||
|
|
c51700273a | ||
|
|
9d1c444921 | ||
|
|
1f8ad88935 | ||
|
|
1715d6b59c | ||
|
|
8ad9087c4a | ||
|
|
3aa35fcffc | ||
|
|
5ef5475868 | ||
|
|
a1422723f7 | ||
|
|
bb535bb67e | ||
|
|
524d18d8bd | ||
|
|
2b44178d87 | ||
|
|
4dc3b15188 | ||
|
|
f2f3beb004 | ||
|
|
0347ab8469 | ||
|
|
99aa6bf29b | ||
|
|
b599fef28e | ||
|
|
ca5c1457d6 | ||
|
|
88556edd74 | ||
|
|
b5684cd8c6 | ||
|
|
e0b1a8a14e | ||
|
|
525f4b65c7 | ||
|
|
53d8e91d64 | ||
|
|
ef2974cc27 | ||
|
|
19c69829d6 | ||
|
|
2c98a6c1ca | ||
|
|
7d57754690 | ||
|
|
6286b41986 | ||
|
|
6fda014e1a | ||
|
|
7f579e272f | ||
|
|
a8fbbf1db7 | ||
|
|
ce4a445388 | ||
|
|
cc6a9f8dc9 | ||
|
|
248b920df9 | ||
|
|
51af0ec9fa | ||
|
|
6c5e740247 | ||
|
|
01c36195d6 | ||
|
|
ceb7054fd4 | ||
|
|
2f84a92ec6 | ||
|
|
6c86462220 | ||
|
|
7ec6a36491 | ||
|
|
7437866bfc | ||
|
|
d321e6d58e | ||
|
|
262a69f428 | ||
|
|
825bfa0052 | ||
|
|
4c44a007b5 | ||
|
|
128b52e8d1 | ||
|
|
8e1fe1753a | ||
|
|
40bf8e9aed | ||
|
|
5e95381260 | ||
|
|
6c69dfb67e | ||
|
|
05cb8ed546 | ||
|
|
ebedb37c8d | ||
|
|
9ee24e98d3 | ||
|
|
288cb9490b | ||
|
|
b62e39b469 | ||
|
|
8297be80f7 | ||
|
|
2ab4b13563 | ||
|
|
55d527a94d | ||
|
|
9e5d2c5273 | ||
|
|
4be75077b9 | ||
|
|
67548f0965 | ||
|
|
343562e8fa | ||
|
|
f357f564be | ||
|
|
2747e71672 | ||
|
|
5ea69c2e36 | ||
|
|
89de4b9138 | ||
|
|
ed4f86e8b6 | ||
|
|
80cac47e95 | ||
|
|
a16878d224 | ||
|
|
3fdfb8b6a5 | ||
|
|
d72bc7f6f8 | ||
|
|
4bb95b82df | ||
|
|
ddb98b5a9f | ||
|
|
1d268dece4 | ||
|
|
7a5bd53d09 | ||
|
|
08e2c9f19c | ||
|
|
1ead6b4e24 | ||
|
|
a3760467c6 | ||
|
|
e5b5728cd3 | ||
|
|
37b6045c45 | ||
|
|
14b207487f | ||
|
|
a485b23425 | ||
|
|
5efa3c0448 | ||
|
|
2875135807 | ||
|
|
b07fbce634 | ||
|
|
5c0919d020 | ||
|
|
aa406feadf | ||
|
|
ae35eea7e4 | ||
|
|
80e1960621 | ||
|
|
c6a8242915 | ||
|
|
c6a56c8e99 | ||
|
|
11e06ce1ed | ||
|
|
ae34fce5f9 | ||
|
|
794939e81d | ||
|
|
ac8d9f2e4c | ||
|
|
797285c8db | ||
|
|
5fa0feecaa | ||
|
|
e4baa9f00b | ||
|
|
0e168d3551 | ||
|
|
82a13ff821 | ||
|
|
1787efc3d2 | ||
|
|
335ca2f2f0 | ||
|
|
3eee2611dd | ||
|
|
4c93950659 | ||
|
|
955f5c7ba1 |
23
MAINTAINERS
23
MAINTAINERS
@@ -790,6 +790,7 @@ M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Supported
|
||||
F: hw/char/sclp*.[hc]
|
||||
F: hw/char/terminal3270.c
|
||||
F: hw/s390x/
|
||||
F: include/hw/s390x/
|
||||
F: pc-bios/s390-ccw/
|
||||
@@ -970,7 +971,9 @@ SCSI
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
S: Supported
|
||||
F: include/hw/scsi/*
|
||||
F: include/scsi/*
|
||||
F: hw/scsi/*
|
||||
F: util/scsi*
|
||||
F: tests/virtio-scsi-test.c
|
||||
T: git git://github.com/bonzini/qemu.git scsi-next
|
||||
|
||||
@@ -1103,11 +1106,12 @@ F: hw/block/nvme*
|
||||
F: tests/nvme-test.c
|
||||
|
||||
megasas
|
||||
M: Hannes Reinecke <hare@suse.de>
|
||||
M: Hannes Reinecke <hare@suse.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: hw/scsi/megasas.c
|
||||
F: hw/scsi/mfi.h
|
||||
F: tests/megasas-test.c
|
||||
|
||||
Network packet abstractions
|
||||
M: Dmitry Fleytman <dmitry@daynix.com>
|
||||
@@ -1131,7 +1135,7 @@ F: tests/rocker/
|
||||
F: docs/specs/rocker.txt
|
||||
|
||||
NVDIMM
|
||||
M: Xiao Guangrong <guangrong.xiao@linux.intel.com>
|
||||
M: Xiao Guangrong <xiaoguangrong.eric@gmail.com>
|
||||
S: Maintained
|
||||
F: hw/acpi/nvdimm.c
|
||||
F: hw/mem/nvdimm.c
|
||||
@@ -1215,6 +1219,13 @@ F: migration/block*
|
||||
F: include/block/aio.h
|
||||
T: git git://github.com/stefanha/qemu.git block
|
||||
|
||||
Block SCSI subsystem
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: include/scsi/*
|
||||
F: scsi/*
|
||||
|
||||
Block Jobs
|
||||
M: Jeff Cody <jcody@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
@@ -1392,6 +1403,14 @@ S: Maintained
|
||||
F: include/sysemu/cryptodev*.h
|
||||
F: backends/cryptodev*.c
|
||||
|
||||
Python scripts
|
||||
M: Eduardo Habkost <ehabkost@redhat.com>
|
||||
M: Cleber Rosa <crosa@redhat.com>
|
||||
S: Odd fixes
|
||||
F: scripts/qmp/*
|
||||
F: scripts/*.py
|
||||
F: tests/*.py
|
||||
|
||||
QAPI
|
||||
M: Markus Armbruster <armbru@redhat.com>
|
||||
M: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||
|
||||
7
Makefile
7
Makefile
@@ -335,7 +335,7 @@ subdir-dtc:dtc/libfdt dtc/tests
|
||||
dtc/%:
|
||||
mkdir -p $@
|
||||
|
||||
$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(chardev-obj-y) \
|
||||
$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) \
|
||||
$(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
|
||||
|
||||
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
|
||||
@@ -355,12 +355,11 @@ Makefile: $(version-obj-y)
|
||||
######################################################################
|
||||
# Build libraries
|
||||
|
||||
libqemustub.a: $(stub-obj-y)
|
||||
libqemuutil.a: $(util-obj-y) $(trace-obj-y)
|
||||
libqemuutil.a: $(util-obj-y) $(trace-obj-y) $(stub-obj-y)
|
||||
|
||||
######################################################################
|
||||
|
||||
COMMON_LDADDS = libqemuutil.a libqemustub.a
|
||||
COMMON_LDADDS = libqemuutil.a
|
||||
|
||||
qemu-img.o: qemu-img-cmds.h
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ chardev-obj-y = chardev/
|
||||
|
||||
block-obj-y += nbd/
|
||||
block-obj-y += block.o blockjob.o
|
||||
block-obj-y += block/
|
||||
block-obj-y += block/ scsi/
|
||||
block-obj-y += qemu-io-cmds.o
|
||||
block-obj-$(CONFIG_REPLICATION) += replication.o
|
||||
|
||||
@@ -155,6 +155,7 @@ trace-events-subdirs += hw/acpi
|
||||
trace-events-subdirs += hw/arm
|
||||
trace-events-subdirs += hw/alpha
|
||||
trace-events-subdirs += hw/xen
|
||||
trace-events-subdirs += hw/ide
|
||||
trace-events-subdirs += ui
|
||||
trace-events-subdirs += audio
|
||||
trace-events-subdirs += net
|
||||
|
||||
@@ -101,7 +101,6 @@ obj-y += fpu/softfloat.o
|
||||
obj-y += target/$(TARGET_BASE_ARCH)/
|
||||
obj-y += disas.o
|
||||
obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
|
||||
obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o
|
||||
|
||||
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decContext.o
|
||||
obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decNumber.o
|
||||
@@ -193,7 +192,7 @@ all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
|
||||
|
||||
$(QEMU_PROG_BUILD): config-devices.mak
|
||||
|
||||
COMMON_LDADDS = ../libqemuutil.a ../libqemustub.a
|
||||
COMMON_LDADDS = ../libqemuutil.a
|
||||
|
||||
# build either PROG or PROGW
|
||||
$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
|
||||
|
||||
@@ -79,7 +79,6 @@ struct KVMState
|
||||
int coalesced_mmio;
|
||||
struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
|
||||
bool coalesced_flush_in_progress;
|
||||
int broken_set_mem_region;
|
||||
int vcpu_events;
|
||||
int robust_singlestep;
|
||||
int debugregs;
|
||||
@@ -127,6 +126,7 @@ static bool kvm_immediate_exit;
|
||||
static const KVMCapabilityInfo kvm_required_capabilites[] = {
|
||||
KVM_CAP_INFO(USER_MEMORY),
|
||||
KVM_CAP_INFO(DESTROY_MEMORY_REGION_WORKS),
|
||||
KVM_CAP_INFO(JOIN_MEMORY_REGIONS_WORKS),
|
||||
KVM_CAP_LAST_INFO
|
||||
};
|
||||
|
||||
@@ -172,7 +172,7 @@ static KVMSlot *kvm_alloc_slot(KVMMemoryListener *kml)
|
||||
|
||||
static KVMSlot *kvm_lookup_matching_slot(KVMMemoryListener *kml,
|
||||
hwaddr start_addr,
|
||||
hwaddr end_addr)
|
||||
hwaddr size)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
int i;
|
||||
@@ -180,8 +180,7 @@ static KVMSlot *kvm_lookup_matching_slot(KVMMemoryListener *kml,
|
||||
for (i = 0; i < s->nr_slots; i++) {
|
||||
KVMSlot *mem = &kml->slots[i];
|
||||
|
||||
if (start_addr == mem->start_addr &&
|
||||
end_addr == mem->start_addr + mem->memory_size) {
|
||||
if (start_addr == mem->start_addr && size == mem->memory_size) {
|
||||
return mem;
|
||||
}
|
||||
}
|
||||
@@ -190,31 +189,33 @@ static KVMSlot *kvm_lookup_matching_slot(KVMMemoryListener *kml,
|
||||
}
|
||||
|
||||
/*
|
||||
* Find overlapping slot with lowest start address
|
||||
* Calculate and align the start address and the size of the section.
|
||||
* Return the size. If the size is 0, the aligned section is empty.
|
||||
*/
|
||||
static KVMSlot *kvm_lookup_overlapping_slot(KVMMemoryListener *kml,
|
||||
hwaddr start_addr,
|
||||
hwaddr end_addr)
|
||||
static hwaddr kvm_align_section(MemoryRegionSection *section,
|
||||
hwaddr *start)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
KVMSlot *found = NULL;
|
||||
int i;
|
||||
hwaddr size = int128_get64(section->size);
|
||||
hwaddr delta;
|
||||
|
||||
for (i = 0; i < s->nr_slots; i++) {
|
||||
KVMSlot *mem = &kml->slots[i];
|
||||
*start = section->offset_within_address_space;
|
||||
|
||||
if (mem->memory_size == 0 ||
|
||||
(found && found->start_addr < mem->start_addr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (end_addr > mem->start_addr &&
|
||||
start_addr < mem->start_addr + mem->memory_size) {
|
||||
found = mem;
|
||||
}
|
||||
/* kvm works in page size chunks, but the function may be called
|
||||
with sub-page size and unaligned start address. Pad the start
|
||||
address to next and truncate size to previous page boundary. */
|
||||
delta = qemu_real_host_page_size - (*start & ~qemu_real_host_page_mask);
|
||||
delta &= ~qemu_real_host_page_mask;
|
||||
*start += delta;
|
||||
if (delta > size) {
|
||||
return 0;
|
||||
}
|
||||
size -= delta;
|
||||
size &= qemu_real_host_page_mask;
|
||||
if (*start & ~qemu_real_host_page_mask) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return found;
|
||||
return size;
|
||||
}
|
||||
|
||||
int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
|
||||
@@ -382,15 +383,21 @@ static int kvm_slot_update_flags(KVMMemoryListener *kml, KVMSlot *mem,
|
||||
static int kvm_section_update_flags(KVMMemoryListener *kml,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
hwaddr phys_addr = section->offset_within_address_space;
|
||||
ram_addr_t size = int128_get64(section->size);
|
||||
KVMSlot *mem = kvm_lookup_matching_slot(kml, phys_addr, phys_addr + size);
|
||||
hwaddr start_addr, size;
|
||||
KVMSlot *mem;
|
||||
|
||||
if (mem == NULL) {
|
||||
size = kvm_align_section(section, &start_addr);
|
||||
if (!size) {
|
||||
return 0;
|
||||
} else {
|
||||
return kvm_slot_update_flags(kml, mem, section->mr);
|
||||
}
|
||||
|
||||
mem = kvm_lookup_matching_slot(kml, start_addr, size);
|
||||
if (!mem) {
|
||||
fprintf(stderr, "%s: error finding slot\n", __func__);
|
||||
abort();
|
||||
}
|
||||
|
||||
return kvm_slot_update_flags(kml, mem, section->mr);
|
||||
}
|
||||
|
||||
static void kvm_log_start(MemoryListener *listener,
|
||||
@@ -454,18 +461,16 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
unsigned long size, allocated_size = 0;
|
||||
struct kvm_dirty_log d = {};
|
||||
KVMSlot *mem;
|
||||
int ret = 0;
|
||||
hwaddr start_addr = section->offset_within_address_space;
|
||||
hwaddr end_addr = start_addr + int128_get64(section->size);
|
||||
hwaddr start_addr, size;
|
||||
|
||||
d.dirty_bitmap = NULL;
|
||||
while (start_addr < end_addr) {
|
||||
mem = kvm_lookup_overlapping_slot(kml, start_addr, end_addr);
|
||||
if (mem == NULL) {
|
||||
break;
|
||||
size = kvm_align_section(section, &start_addr);
|
||||
if (size) {
|
||||
mem = kvm_lookup_matching_slot(kml, start_addr, size);
|
||||
if (!mem) {
|
||||
fprintf(stderr, "%s: error finding slot\n", __func__);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* XXX bad kernel interface alert
|
||||
@@ -482,27 +487,20 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
|
||||
*/
|
||||
size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
|
||||
/*HOST_LONG_BITS*/ 64) / 8;
|
||||
if (!d.dirty_bitmap) {
|
||||
d.dirty_bitmap = g_malloc(size);
|
||||
} else if (size > allocated_size) {
|
||||
d.dirty_bitmap = g_realloc(d.dirty_bitmap, size);
|
||||
}
|
||||
allocated_size = size;
|
||||
memset(d.dirty_bitmap, 0, allocated_size);
|
||||
d.dirty_bitmap = g_malloc0(size);
|
||||
|
||||
d.slot = mem->slot | (kml->as_id << 16);
|
||||
if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
|
||||
DPRINTF("ioctl failed %d\n", errno);
|
||||
ret = -1;
|
||||
break;
|
||||
g_free(d.dirty_bitmap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kvm_get_dirty_pages_log_range(section, d.dirty_bitmap);
|
||||
start_addr = mem->start_addr + mem->memory_size;
|
||||
g_free(d.dirty_bitmap);
|
||||
}
|
||||
g_free(d.dirty_bitmap);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvm_coalesce_mmio_region(MemoryListener *listener,
|
||||
@@ -696,30 +694,12 @@ kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list)
|
||||
static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
MemoryRegionSection *section, bool add)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
KVMSlot *mem, old;
|
||||
KVMSlot *mem;
|
||||
int err;
|
||||
MemoryRegion *mr = section->mr;
|
||||
bool writeable = !mr->readonly && !mr->rom_device;
|
||||
hwaddr start_addr = section->offset_within_address_space;
|
||||
ram_addr_t size = int128_get64(section->size);
|
||||
void *ram = NULL;
|
||||
unsigned delta;
|
||||
|
||||
/* kvm works in page size chunks, but the function may be called
|
||||
with sub-page size and unaligned start address. Pad the start
|
||||
address to next and truncate size to previous page boundary. */
|
||||
delta = qemu_real_host_page_size - (start_addr & ~qemu_real_host_page_mask);
|
||||
delta &= ~qemu_real_host_page_mask;
|
||||
if (delta > size) {
|
||||
return;
|
||||
}
|
||||
start_addr += delta;
|
||||
size -= delta;
|
||||
size &= qemu_real_host_page_mask;
|
||||
if (!size || (start_addr & ~qemu_real_host_page_mask)) {
|
||||
return;
|
||||
}
|
||||
hwaddr start_addr, size;
|
||||
void *ram;
|
||||
|
||||
if (!memory_region_is_ram(mr)) {
|
||||
if (writeable || !kvm_readonly_mem_allowed) {
|
||||
@@ -731,30 +711,25 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
}
|
||||
}
|
||||
|
||||
ram = memory_region_get_ram_ptr(mr) + section->offset_within_region + delta;
|
||||
size = kvm_align_section(section, &start_addr);
|
||||
if (!size) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
mem = kvm_lookup_overlapping_slot(kml, start_addr, start_addr + size);
|
||||
ram = memory_region_get_ram_ptr(mr) + section->offset_within_region +
|
||||
(section->offset_within_address_space - start_addr);
|
||||
|
||||
mem = kvm_lookup_matching_slot(kml, start_addr, size);
|
||||
if (!add) {
|
||||
if (!mem) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (add && start_addr >= mem->start_addr &&
|
||||
(start_addr + size <= mem->start_addr + mem->memory_size) &&
|
||||
(ram - start_addr == mem->ram - mem->start_addr)) {
|
||||
/* The new slot fits into the existing one and comes with
|
||||
* identical parameters - update flags and done. */
|
||||
kvm_slot_update_flags(kml, mem, mr);
|
||||
g_assert(!memory_region_is_ram(mr) && !writeable && !mr->romd_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
old = *mem;
|
||||
|
||||
if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
|
||||
kvm_physical_sync_dirty_bitmap(kml, section);
|
||||
}
|
||||
|
||||
/* unregister the overlapping slot */
|
||||
/* unregister the slot */
|
||||
mem->memory_size = 0;
|
||||
err = kvm_set_user_memory_region(kml, mem);
|
||||
if (err) {
|
||||
@@ -762,84 +737,16 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
||||
__func__, strerror(-err));
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Workaround for older KVM versions: we can't join slots, even not by
|
||||
* unregistering the previous ones and then registering the larger
|
||||
* slot. We have to maintain the existing fragmentation. Sigh.
|
||||
*
|
||||
* This workaround assumes that the new slot starts at the same
|
||||
* address as the first existing one. If not or if some overlapping
|
||||
* slot comes around later, we will fail (not seen in practice so far)
|
||||
* - and actually require a recent KVM version. */
|
||||
if (s->broken_set_mem_region &&
|
||||
old.start_addr == start_addr && old.memory_size < size && add) {
|
||||
mem = kvm_alloc_slot(kml);
|
||||
mem->memory_size = old.memory_size;
|
||||
mem->start_addr = old.start_addr;
|
||||
mem->ram = old.ram;
|
||||
mem->flags = kvm_mem_flags(mr);
|
||||
|
||||
err = kvm_set_user_memory_region(kml, mem);
|
||||
if (err) {
|
||||
fprintf(stderr, "%s: error updating slot: %s\n", __func__,
|
||||
strerror(-err));
|
||||
abort();
|
||||
}
|
||||
|
||||
start_addr += old.memory_size;
|
||||
ram += old.memory_size;
|
||||
size -= old.memory_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* register prefix slot */
|
||||
if (old.start_addr < start_addr) {
|
||||
mem = kvm_alloc_slot(kml);
|
||||
mem->memory_size = start_addr - old.start_addr;
|
||||
mem->start_addr = old.start_addr;
|
||||
mem->ram = old.ram;
|
||||
mem->flags = kvm_mem_flags(mr);
|
||||
|
||||
err = kvm_set_user_memory_region(kml, mem);
|
||||
if (err) {
|
||||
fprintf(stderr, "%s: error registering prefix slot: %s\n",
|
||||
__func__, strerror(-err));
|
||||
#ifdef TARGET_PPC
|
||||
fprintf(stderr, "%s: This is probably because your kernel's " \
|
||||
"PAGE_SIZE is too big. Please try to use 4k " \
|
||||
"PAGE_SIZE!\n", __func__);
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* register suffix slot */
|
||||
if (old.start_addr + old.memory_size > start_addr + size) {
|
||||
ram_addr_t size_delta;
|
||||
|
||||
mem = kvm_alloc_slot(kml);
|
||||
mem->start_addr = start_addr + size;
|
||||
size_delta = mem->start_addr - old.start_addr;
|
||||
mem->memory_size = old.memory_size - size_delta;
|
||||
mem->ram = old.ram + size_delta;
|
||||
mem->flags = kvm_mem_flags(mr);
|
||||
|
||||
err = kvm_set_user_memory_region(kml, mem);
|
||||
if (err) {
|
||||
fprintf(stderr, "%s: error registering suffix slot: %s\n",
|
||||
__func__, strerror(-err));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* in case the KVM bug workaround already "consumed" the new slot */
|
||||
if (!size) {
|
||||
return;
|
||||
}
|
||||
if (!add) {
|
||||
|
||||
if (mem) {
|
||||
/* update the slot */
|
||||
kvm_slot_update_flags(kml, mem, mr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* register the new slot */
|
||||
mem = kvm_alloc_slot(kml);
|
||||
mem->memory_size = size;
|
||||
mem->start_addr = start_addr;
|
||||
@@ -1629,10 +1536,9 @@ static int kvm_init(MachineState *ms)
|
||||
|
||||
while (nc->name) {
|
||||
if (nc->num > soft_vcpus_limit) {
|
||||
fprintf(stderr,
|
||||
"Warning: Number of %s cpus requested (%d) exceeds "
|
||||
"the recommended cpus supported by KVM (%d)\n",
|
||||
nc->name, nc->num, soft_vcpus_limit);
|
||||
warn_report("Number of %s cpus requested (%d) exceeds "
|
||||
"the recommended cpus supported by KVM (%d)",
|
||||
nc->name, nc->num, soft_vcpus_limit);
|
||||
|
||||
if (nc->num > hard_vcpus_limit) {
|
||||
fprintf(stderr, "Number of %s cpus requested (%d) exceeds "
|
||||
@@ -1692,12 +1598,6 @@ static int kvm_init(MachineState *ms)
|
||||
|
||||
s->coalesced_mmio = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO);
|
||||
|
||||
s->broken_set_mem_region = 1;
|
||||
ret = kvm_check_extension(s, KVM_CAP_JOIN_MEMORY_REGIONS_WORKS);
|
||||
if (ret > 0) {
|
||||
s->broken_set_mem_region = 0;
|
||||
}
|
||||
|
||||
#ifdef KVM_CAP_VCPU_EVENTS
|
||||
s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS);
|
||||
#endif
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o
|
||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
||||
obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o
|
||||
|
||||
@@ -34,15 +34,20 @@
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/uuid.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "crypto/secret.h"
|
||||
#include "scsi/utils.h"
|
||||
|
||||
/* Conflict between scsi/utils.h and libiscsi! :( */
|
||||
#define SCSI_XFER_NONE ISCSI_XFER_NONE
|
||||
#include <iscsi/iscsi.h>
|
||||
#include <iscsi/scsi-lowlevel.h>
|
||||
#undef SCSI_XFER_NONE
|
||||
QEMU_BUILD_BUG_ON((int)SCSI_XFER_NONE != (int)ISCSI_XFER_NONE);
|
||||
|
||||
#ifdef __linux__
|
||||
#include <scsi/sg.h>
|
||||
@@ -209,47 +214,9 @@ static inline unsigned exp_random(double mean)
|
||||
|
||||
static int iscsi_translate_sense(struct scsi_sense *sense)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (sense->key) {
|
||||
case SCSI_SENSE_NOT_READY:
|
||||
return -EBUSY;
|
||||
case SCSI_SENSE_DATA_PROTECTION:
|
||||
return -EACCES;
|
||||
case SCSI_SENSE_COMMAND_ABORTED:
|
||||
return -ECANCELED;
|
||||
case SCSI_SENSE_ILLEGAL_REQUEST:
|
||||
/* Parse ASCQ */
|
||||
break;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
switch (sense->ascq) {
|
||||
case SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR:
|
||||
case SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE:
|
||||
case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB:
|
||||
case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE:
|
||||
ret = -ENOSPC;
|
||||
break;
|
||||
case SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED:
|
||||
ret = -ENOTSUP;
|
||||
break;
|
||||
case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT:
|
||||
case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED:
|
||||
case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN:
|
||||
ret = -ENOMEDIUM;
|
||||
break;
|
||||
case SCSI_SENSE_ASCQ_WRITE_PROTECTED:
|
||||
ret = -EACCES;
|
||||
break;
|
||||
default:
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return - scsi_sense_to_errno(sense->key,
|
||||
(sense->ascq & 0xFF00) >> 8,
|
||||
sense->ascq & 0xFF);
|
||||
}
|
||||
|
||||
/* Called (via iscsi_service) with QemuMutex held. */
|
||||
|
||||
@@ -301,10 +301,11 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
}
|
||||
|
||||
if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) {
|
||||
error_report("WARNING: a program lacking bitmap support "
|
||||
"modified this file, so all bitmaps are now "
|
||||
"considered inconsistent. Some clusters may be "
|
||||
"leaked, run 'qemu-img check -r' on the image "
|
||||
warn_report("a program lacking bitmap support "
|
||||
"modified this file, so all bitmaps are now "
|
||||
"considered inconsistent");
|
||||
error_printf("Some clusters may be leaked, "
|
||||
"run 'qemu-img check -r' on the image "
|
||||
"file to fix.");
|
||||
if (need_update_header != NULL) {
|
||||
/* Updating is needed to drop invalid bitmap extension. */
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#ifndef S_IWGRP
|
||||
#define S_IWGRP 0
|
||||
@@ -1226,8 +1227,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
switch (s->fat_type) {
|
||||
case 32:
|
||||
fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. "
|
||||
"You are welcome to do so!\n");
|
||||
warn_report("FAT32 has not been tested. You are welcome to do so!");
|
||||
break;
|
||||
case 16:
|
||||
case 12:
|
||||
@@ -3028,7 +3028,8 @@ DLOG(checkpoint());
|
||||
if (memcmp(direntries + k,
|
||||
array_get(&(s->directory), dir_index + k),
|
||||
sizeof(direntry_t))) {
|
||||
fprintf(stderr, "Warning: tried to write to write-protected file\n");
|
||||
warn_report("tried to write to write-protected "
|
||||
"file");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
2
configure
vendored
2
configure
vendored
@@ -2025,7 +2025,7 @@ if test "$seccomp" != "no" ; then
|
||||
arm|aarch64)
|
||||
libseccomp_minver="2.2.3"
|
||||
;;
|
||||
ppc|ppc64)
|
||||
ppc|ppc64|s390x)
|
||||
libseccomp_minver="2.3.0"
|
||||
;;
|
||||
*)
|
||||
|
||||
@@ -43,4 +43,4 @@ CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_IVSHMEM_DEVICE=$(CONFIG_IVSHMEM)
|
||||
CONFIG_ROCKER=y
|
||||
CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX))
|
||||
CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
|
||||
|
||||
@@ -43,7 +43,7 @@ CONFIG_XILINX_ETHLITE=y
|
||||
CONFIG_PREP=y
|
||||
CONFIG_MAC=y
|
||||
CONFIG_E500=y
|
||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
||||
CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM))
|
||||
CONFIG_PLATFORM_BUS=y
|
||||
CONFIG_ETSEC=y
|
||||
CONFIG_LIBDECNUMBER=y
|
||||
|
||||
@@ -48,7 +48,7 @@ CONFIG_POWERNV=y
|
||||
CONFIG_PREP=y
|
||||
CONFIG_MAC=y
|
||||
CONFIG_E500=y
|
||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
||||
CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM))
|
||||
CONFIG_PLATFORM_BUS=y
|
||||
CONFIG_ETSEC=y
|
||||
CONFIG_LIBDECNUMBER=y
|
||||
@@ -56,7 +56,7 @@ CONFIG_SM501=y
|
||||
# For pSeries
|
||||
CONFIG_XICS=$(CONFIG_PSERIES)
|
||||
CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
|
||||
CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
|
||||
CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM))
|
||||
# For PReP
|
||||
CONFIG_SERIAL_ISA=y
|
||||
CONFIG_MC146818RTC=y
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CONFIG_PCI=y
|
||||
CONFIG_VIRTIO_PCI=$(CONFIG_PCI)
|
||||
CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX))
|
||||
CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_TERMINAL3270=y
|
||||
|
||||
@@ -12,6 +12,7 @@ CONFIG_FDC=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_CMD646=y
|
||||
CONFIG_PCI_APB=y
|
||||
CONFIG_SUNHME=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
|
||||
@@ -232,15 +232,15 @@ The utility code that is used by all binaries is built into a
|
||||
static archive called libqemuutil.a, which is then linked to all the
|
||||
binaries. In order to provide hooks that are only needed by some of the
|
||||
binaries, code in libqemuutil.a may depend on other functions that are
|
||||
not fully implemented by all QEMU binaries. To deal with this there is a
|
||||
second library called libqemustub.a which provides dummy stubs for all
|
||||
these functions. These will get lazy linked into the binary if the real
|
||||
implementation is not present. In this way, the libqemustub.a static
|
||||
library can be thought of as a portable implementation of the weak
|
||||
symbols concept. All binaries should link to both libqemuutil.a and
|
||||
libqemustub.a. e.g.
|
||||
not fully implemented by all QEMU binaries. Dummy stubs for all these
|
||||
functions are also provided by this library, and will only be linked
|
||||
into the binary if the real implementation is not present. In a way,
|
||||
the stubs can be thought of as a portable implementation of the weak
|
||||
symbols concept.
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.o ..snip.. libqemuutil.a libqemustub.a
|
||||
All binaries should link to libqemuutil.a, e.g.:
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.o ..snip.. libqemuutil.a
|
||||
|
||||
|
||||
Windows platform portability
|
||||
|
||||
1
dump.c
1
dump.c
@@ -15,7 +15,6 @@
|
||||
#include "qemu/cutils.h"
|
||||
#include "elf.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/cpu-all.h"
|
||||
#include "exec/hwaddr.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
1
exec.c
1
exec.c
@@ -56,7 +56,6 @@
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#include "exec/cpu-all.h"
|
||||
#include "qemu/rcu_queue.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "translate-all.h"
|
||||
|
||||
64
hw/9pfs/9p.c
64
hw/9pfs/9p.c
@@ -803,12 +803,12 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
|
||||
static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *path,
|
||||
const char *basename,
|
||||
const struct stat *stbuf,
|
||||
V9fsStat *v9stat)
|
||||
{
|
||||
int err;
|
||||
const char *str;
|
||||
|
||||
memset(v9stat, 0, sizeof(*v9stat));
|
||||
|
||||
@@ -829,7 +829,7 @@ static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
|
||||
v9fs_string_free(&v9stat->extension);
|
||||
|
||||
if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
|
||||
err = v9fs_co_readlink(pdu, name, &v9stat->extension);
|
||||
err = v9fs_co_readlink(pdu, path, &v9stat->extension);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
@@ -842,14 +842,7 @@ static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
|
||||
"HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
|
||||
}
|
||||
|
||||
str = strrchr(name->data, '/');
|
||||
if (str) {
|
||||
str += 1;
|
||||
} else {
|
||||
str = name->data;
|
||||
}
|
||||
|
||||
v9fs_string_sprintf(&v9stat->name, "%s", str);
|
||||
v9fs_string_sprintf(&v9stat->name, "%s", basename);
|
||||
|
||||
v9stat->size = 61 +
|
||||
v9fs_string_size(&v9stat->name) +
|
||||
@@ -1056,6 +1049,7 @@ static void coroutine_fn v9fs_stat(void *opaque)
|
||||
struct stat stbuf;
|
||||
V9fsFidState *fidp;
|
||||
V9fsPDU *pdu = opaque;
|
||||
char *basename;
|
||||
|
||||
err = pdu_unmarshal(pdu, offset, "d", &fid);
|
||||
if (err < 0) {
|
||||
@@ -1072,7 +1066,9 @@ static void coroutine_fn v9fs_stat(void *opaque)
|
||||
if (err < 0) {
|
||||
goto out;
|
||||
}
|
||||
err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
|
||||
basename = g_path_get_basename(fidp->path.data);
|
||||
err = stat_to_v9stat(pdu, &fidp->path, basename, &stbuf, &v9stat);
|
||||
g_free(basename);
|
||||
if (err < 0) {
|
||||
goto out;
|
||||
}
|
||||
@@ -1748,22 +1744,31 @@ static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu,
|
||||
if (err < 0) {
|
||||
break;
|
||||
}
|
||||
err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
|
||||
err = stat_to_v9stat(pdu, &path, dent->d_name, &stbuf, &v9stat);
|
||||
if (err < 0) {
|
||||
break;
|
||||
}
|
||||
/* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
|
||||
len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
|
||||
if ((count + v9stat.size + 2) > max_count) {
|
||||
v9fs_readdir_unlock(&fidp->fs.dir);
|
||||
|
||||
v9fs_readdir_unlock(&fidp->fs.dir);
|
||||
|
||||
if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
|
||||
/* Ran out of buffer. Set dir back to old position and return */
|
||||
v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
|
||||
v9fs_stat_free(&v9stat);
|
||||
v9fs_path_free(&path);
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
|
||||
len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
|
||||
|
||||
v9fs_readdir_unlock(&fidp->fs.dir);
|
||||
|
||||
if (len < 0) {
|
||||
v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
|
||||
v9fs_stat_free(&v9stat);
|
||||
v9fs_path_free(&path);
|
||||
return len;
|
||||
}
|
||||
count += len;
|
||||
v9fs_stat_free(&v9stat);
|
||||
v9fs_path_free(&path);
|
||||
@@ -2557,13 +2562,11 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
|
||||
int32_t newdirfid,
|
||||
V9fsString *name)
|
||||
{
|
||||
char *end;
|
||||
int err = 0;
|
||||
V9fsPath new_path;
|
||||
V9fsFidState *tfidp;
|
||||
V9fsState *s = pdu->s;
|
||||
V9fsFidState *dirfidp = NULL;
|
||||
char *old_name, *new_name;
|
||||
|
||||
v9fs_path_init(&new_path);
|
||||
if (newdirfid != -1) {
|
||||
@@ -2581,18 +2584,15 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
old_name = fidp->path.data;
|
||||
end = strrchr(old_name, '/');
|
||||
if (end) {
|
||||
end++;
|
||||
} else {
|
||||
end = old_name;
|
||||
}
|
||||
new_name = g_malloc0(end - old_name + name->size + 1);
|
||||
strncat(new_name, old_name, end - old_name);
|
||||
strncat(new_name + (end - old_name), name->data, name->size);
|
||||
err = v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
|
||||
g_free(new_name);
|
||||
char *dir_name = g_path_get_dirname(fidp->path.data);
|
||||
V9fsPath dir_path;
|
||||
|
||||
v9fs_path_init(&dir_path);
|
||||
v9fs_path_sprintf(&dir_path, "%s", dir_name);
|
||||
g_free(dir_name);
|
||||
|
||||
err = v9fs_co_name_to_path(pdu, &dir_path, name->data, &new_path);
|
||||
v9fs_path_free(&dir_path);
|
||||
if (err < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "qapi/opts-visitor.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi-event.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
struct acpi_table_header {
|
||||
uint16_t _length; /* our length, not actual part of the hdr */
|
||||
@@ -183,10 +184,9 @@ static void acpi_table_install(const char unsigned *blob, size_t bloblen,
|
||||
}
|
||||
|
||||
if (has_header && le32_to_cpu(ext_hdr->length) != acpi_payload_size) {
|
||||
fprintf(stderr,
|
||||
"warning: ACPI table has wrong length, header says "
|
||||
"%" PRIu32 ", actual size %zu bytes\n",
|
||||
le32_to_cpu(ext_hdr->length), acpi_payload_size);
|
||||
warn_report("ACPI table has wrong length, header says "
|
||||
"%" PRIu32 ", actual size %zu bytes",
|
||||
le32_to_cpu(ext_hdr->length), acpi_payload_size);
|
||||
}
|
||||
ext_hdr->length = cpu_to_le32(acpi_payload_size);
|
||||
|
||||
@@ -221,7 +221,7 @@ static void acpi_table_install(const char unsigned *blob, size_t bloblen,
|
||||
}
|
||||
|
||||
if (!has_header && changed_fields == 0) {
|
||||
fprintf(stderr, "warning: ACPI table: no headers are specified\n");
|
||||
warn_report("ACPI table: no headers are specified");
|
||||
}
|
||||
|
||||
/* recalculate checksum */
|
||||
|
||||
@@ -479,8 +479,8 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
|
||||
/* Not fatal, we just won't provide virtio. This will
|
||||
* happen with older device tree blobs.
|
||||
*/
|
||||
fprintf(stderr, "QEMU: warning: couldn't find interrupt controller in "
|
||||
"dtb; will not include virtio-mmio devices in the dtb.\n");
|
||||
warn_report("couldn't find interrupt controller in "
|
||||
"dtb; will not include virtio-mmio devices in the dtb");
|
||||
} else {
|
||||
int i;
|
||||
const hwaddr *map = daughterboard->motherboard_map;
|
||||
|
||||
@@ -517,7 +517,7 @@ static Property floppy_drive_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static int floppy_drive_init(DeviceState *qdev)
|
||||
static void floppy_drive_realize(DeviceState *qdev, Error **errp)
|
||||
{
|
||||
FloppyDrive *dev = FLOPPY_DRIVE(qdev);
|
||||
FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
|
||||
@@ -535,15 +535,15 @@ static int floppy_drive_init(DeviceState *qdev)
|
||||
}
|
||||
|
||||
if (dev->unit >= MAX_FD) {
|
||||
error_report("Can't create floppy unit %d, bus supports only %d units",
|
||||
dev->unit, MAX_FD);
|
||||
return -1;
|
||||
error_setg(errp, "Can't create floppy unit %d, bus supports "
|
||||
"only %d units", dev->unit, MAX_FD);
|
||||
return;
|
||||
}
|
||||
|
||||
drive = get_drv(bus->fdc, dev->unit);
|
||||
if (drive->blk) {
|
||||
error_report("Floppy unit %d is in use", dev->unit);
|
||||
return -1;
|
||||
error_setg(errp, "Floppy unit %d is in use", dev->unit);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev->conf.blk) {
|
||||
@@ -557,8 +557,9 @@ static int floppy_drive_init(DeviceState *qdev)
|
||||
if (dev->conf.logical_block_size != 512 ||
|
||||
dev->conf.physical_block_size != 512)
|
||||
{
|
||||
error_report("Physical and logical block size must be 512 for floppy");
|
||||
return -1;
|
||||
error_setg(errp, "Physical and logical block size must "
|
||||
"be 512 for floppy");
|
||||
return;
|
||||
}
|
||||
|
||||
/* rerror/werror aren't supported by fdc and therefore not even registered
|
||||
@@ -570,20 +571,20 @@ static int floppy_drive_init(DeviceState *qdev)
|
||||
blkconf_apply_backend_options(&dev->conf, blk_is_read_only(dev->conf.blk),
|
||||
false, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return -1;
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 'enospc' is the default for -drive, 'report' is what blk_new() gives us
|
||||
* for empty drives. */
|
||||
if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
|
||||
blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
|
||||
error_report("fdc doesn't support drive option werror");
|
||||
return -1;
|
||||
error_setg(errp, "fdc doesn't support drive option werror");
|
||||
return;
|
||||
}
|
||||
if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
|
||||
error_report("fdc doesn't support drive option rerror");
|
||||
return -1;
|
||||
error_setg(errp, "fdc doesn't support drive option rerror");
|
||||
return;
|
||||
}
|
||||
|
||||
drive->conf = &dev->conf;
|
||||
@@ -599,14 +600,12 @@ static int floppy_drive_init(DeviceState *qdev)
|
||||
dev->type = drive->drive;
|
||||
|
||||
fd_revalidate(drive);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void floppy_drive_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *k = DEVICE_CLASS(klass);
|
||||
k->init = floppy_drive_init;
|
||||
k->realize = floppy_drive_realize;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
|
||||
k->bus_type = TYPE_FLOPPY_BUS;
|
||||
k->props = floppy_drive_properties;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/virtio/virtio-blk.h"
|
||||
#include "dataplane/virtio-blk.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#ifdef __linux__
|
||||
# include <scsi/sg.h>
|
||||
#endif
|
||||
|
||||
@@ -1232,7 +1232,7 @@ static int blk_connect(struct XenDevice *xendev)
|
||||
return -1;
|
||||
}
|
||||
|
||||
domids = g_malloc0_n(blkdev->nr_ring_ref, sizeof(uint32_t));
|
||||
domids = g_new0(uint32_t, blkdev->nr_ring_ref);
|
||||
for (i = 0; i < blkdev->nr_ring_ref; i++) {
|
||||
domids[i] = blkdev->xendev.dom;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,48 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
|
||||
|
||||
static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res);
|
||||
|
||||
static void
|
||||
virtio_gpu_ctrl_hdr_bswap(struct virtio_gpu_ctrl_hdr *hdr)
|
||||
{
|
||||
le32_to_cpus(&hdr->type);
|
||||
le32_to_cpus(&hdr->flags);
|
||||
le64_to_cpus(&hdr->fence_id);
|
||||
le32_to_cpus(&hdr->ctx_id);
|
||||
le32_to_cpus(&hdr->padding);
|
||||
}
|
||||
|
||||
static void virtio_gpu_bswap_32(void *ptr,
|
||||
size_t size)
|
||||
{
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
|
||||
size_t i;
|
||||
struct virtio_gpu_ctrl_hdr *hdr = (struct virtio_gpu_ctrl_hdr *) ptr;
|
||||
|
||||
virtio_gpu_ctrl_hdr_bswap(hdr);
|
||||
|
||||
i = sizeof(struct virtio_gpu_ctrl_hdr);
|
||||
while (i < size) {
|
||||
le32_to_cpus((uint32_t *)(ptr + i));
|
||||
i = i + sizeof(uint32_t);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
virtio_gpu_t2d_bswap(struct virtio_gpu_transfer_to_host_2d *t2d)
|
||||
{
|
||||
virtio_gpu_ctrl_hdr_bswap(&t2d->hdr);
|
||||
le32_to_cpus(&t2d->r.x);
|
||||
le32_to_cpus(&t2d->r.y);
|
||||
le32_to_cpus(&t2d->r.width);
|
||||
le32_to_cpus(&t2d->r.height);
|
||||
le64_to_cpus(&t2d->offset);
|
||||
le32_to_cpus(&t2d->resource_id);
|
||||
le32_to_cpus(&t2d->padding);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIRGL
|
||||
#include <virglrenderer.h>
|
||||
#define VIRGL(_g, _virgl, _simple, ...) \
|
||||
@@ -205,6 +247,7 @@ void virtio_gpu_ctrl_response(VirtIOGPU *g,
|
||||
resp->fence_id = cmd->cmd_hdr.fence_id;
|
||||
resp->ctx_id = cmd->cmd_hdr.ctx_id;
|
||||
}
|
||||
virtio_gpu_ctrl_hdr_bswap(resp);
|
||||
s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len);
|
||||
if (s != resp_len) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
@@ -236,8 +279,8 @@ virtio_gpu_fill_display_info(VirtIOGPU *g,
|
||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||
if (g->enabled_output_bitmask & (1 << i)) {
|
||||
dpy_info->pmodes[i].enabled = 1;
|
||||
dpy_info->pmodes[i].r.width = g->req_state[i].width;
|
||||
dpy_info->pmodes[i].r.height = g->req_state[i].height;
|
||||
dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width);
|
||||
dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,6 +330,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
|
||||
struct virtio_gpu_resource_create_2d c2d;
|
||||
|
||||
VIRTIO_GPU_FILL_CMD(c2d);
|
||||
virtio_gpu_bswap_32(&c2d, sizeof(c2d));
|
||||
trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
|
||||
c2d.width, c2d.height);
|
||||
|
||||
@@ -360,6 +404,7 @@ static void virtio_gpu_resource_unref(VirtIOGPU *g,
|
||||
struct virtio_gpu_resource_unref unref;
|
||||
|
||||
VIRTIO_GPU_FILL_CMD(unref);
|
||||
virtio_gpu_bswap_32(&unref, sizeof(unref));
|
||||
trace_virtio_gpu_cmd_res_unref(unref.resource_id);
|
||||
|
||||
res = virtio_gpu_find_resource(g, unref.resource_id);
|
||||
@@ -383,6 +428,7 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
|
||||
struct virtio_gpu_transfer_to_host_2d t2d;
|
||||
|
||||
VIRTIO_GPU_FILL_CMD(t2d);
|
||||
virtio_gpu_t2d_bswap(&t2d);
|
||||
trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
|
||||
|
||||
res = virtio_gpu_find_resource(g, t2d.resource_id);
|
||||
@@ -439,6 +485,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
|
||||
int i;
|
||||
|
||||
VIRTIO_GPU_FILL_CMD(rf);
|
||||
virtio_gpu_bswap_32(&rf, sizeof(rf));
|
||||
trace_virtio_gpu_cmd_res_flush(rf.resource_id,
|
||||
rf.r.width, rf.r.height, rf.r.x, rf.r.y);
|
||||
|
||||
@@ -511,6 +558,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
|
||||
struct virtio_gpu_set_scanout ss;
|
||||
|
||||
VIRTIO_GPU_FILL_CMD(ss);
|
||||
virtio_gpu_bswap_32(&ss, sizeof(ss));
|
||||
trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
|
||||
ss.r.width, ss.r.height, ss.r.x, ss.r.y);
|
||||
|
||||
@@ -633,13 +681,15 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
|
||||
*addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries);
|
||||
}
|
||||
for (i = 0; i < ab->nr_entries; i++) {
|
||||
hwaddr len = ents[i].length;
|
||||
(*iov)[i].iov_len = ents[i].length;
|
||||
(*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1);
|
||||
uint64_t a = le64_to_cpu(ents[i].addr);
|
||||
uint32_t l = le32_to_cpu(ents[i].length);
|
||||
hwaddr len = l;
|
||||
(*iov)[i].iov_len = l;
|
||||
(*iov)[i].iov_base = cpu_physical_memory_map(a, &len, 1);
|
||||
if (addr) {
|
||||
(*addr)[i] = ents[i].addr;
|
||||
(*addr)[i] = a;
|
||||
}
|
||||
if (!(*iov)[i].iov_base || len != ents[i].length) {
|
||||
if (!(*iov)[i].iov_base || len != l) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
|
||||
" resource %d element %d\n",
|
||||
__func__, ab->resource_id, i);
|
||||
@@ -686,6 +736,7 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g,
|
||||
int ret;
|
||||
|
||||
VIRTIO_GPU_FILL_CMD(ab);
|
||||
virtio_gpu_bswap_32(&ab, sizeof(ab));
|
||||
trace_virtio_gpu_cmd_res_back_attach(ab.resource_id);
|
||||
|
||||
res = virtio_gpu_find_resource(g, ab.resource_id);
|
||||
@@ -718,6 +769,7 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g,
|
||||
struct virtio_gpu_resource_detach_backing detach;
|
||||
|
||||
VIRTIO_GPU_FILL_CMD(detach);
|
||||
virtio_gpu_bswap_32(&detach, sizeof(detach));
|
||||
trace_virtio_gpu_cmd_res_back_detach(detach.resource_id);
|
||||
|
||||
res = virtio_gpu_find_resource(g, detach.resource_id);
|
||||
@@ -734,6 +786,7 @@ static void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
|
||||
struct virtio_gpu_ctrl_command *cmd)
|
||||
{
|
||||
VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
|
||||
virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr);
|
||||
|
||||
switch (cmd->cmd_hdr.type) {
|
||||
case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
|
||||
@@ -879,6 +932,7 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
|
||||
"%s: cursor size incorrect %zu vs %zu\n",
|
||||
__func__, s, sizeof(cursor_info));
|
||||
} else {
|
||||
virtio_gpu_bswap_32(&cursor_info, sizeof(cursor_info));
|
||||
update_cursor(g, &cursor_info);
|
||||
}
|
||||
virtqueue_push(vq, elem, 0);
|
||||
@@ -1135,7 +1189,7 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||
}
|
||||
|
||||
g->config_size = sizeof(struct virtio_gpu_config);
|
||||
g->virtio_config.num_scanouts = g->conf.max_outputs;
|
||||
g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs);
|
||||
virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
|
||||
g->config_size);
|
||||
|
||||
|
||||
@@ -2766,17 +2766,22 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
|
||||
ACPI_BUILD_ALIGN_SIZE);
|
||||
if (tables_blob->len > legacy_table_size) {
|
||||
/* Should happen only with PCI bridges and -M pc-i440fx-2.0. */
|
||||
warn_report("migration may not work.");
|
||||
warn_report("ACPI table size %u exceeds %d bytes,"
|
||||
" migration may not work",
|
||||
tables_blob->len, legacy_table_size);
|
||||
error_printf("Try removing CPUs, NUMA nodes, memory slots"
|
||||
" or PCI bridges.");
|
||||
}
|
||||
g_array_set_size(tables_blob, legacy_table_size);
|
||||
} else {
|
||||
/* Make sure we have a buffer in case we need to resize the tables. */
|
||||
if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
|
||||
/* As of QEMU 2.1, this fires with 160 VCPUs and 255 memory slots. */
|
||||
warn_report("ACPI tables are larger than 64k.");
|
||||
warn_report("migration may not work.");
|
||||
warn_report("please remove CPUs, NUMA nodes, "
|
||||
"memory slots or PCI bridges.");
|
||||
warn_report("ACPI table size %u exceeds %d bytes,"
|
||||
" migration may not work",
|
||||
tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
|
||||
error_printf("Try removing CPUs, NUMA nodes, memory slots"
|
||||
" or PCI bridges.");
|
||||
}
|
||||
acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
|
||||
}
|
||||
|
||||
@@ -221,15 +221,34 @@ int load_multiboot(FWCfgState *fw_cfg,
|
||||
uint32_t mh_header_addr = ldl_p(header+i+12);
|
||||
uint32_t mh_load_end_addr = ldl_p(header+i+20);
|
||||
uint32_t mh_bss_end_addr = ldl_p(header+i+24);
|
||||
|
||||
mh_load_addr = ldl_p(header+i+16);
|
||||
if (mh_header_addr < mh_load_addr) {
|
||||
fprintf(stderr, "invalid mh_load_addr address\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
|
||||
uint32_t mb_load_size = 0;
|
||||
mh_entry_addr = ldl_p(header+i+28);
|
||||
|
||||
if (mh_load_end_addr) {
|
||||
if (mh_bss_end_addr < mh_load_addr) {
|
||||
fprintf(stderr, "invalid mh_bss_end_addr address\n");
|
||||
exit(1);
|
||||
}
|
||||
mb_kernel_size = mh_bss_end_addr - mh_load_addr;
|
||||
|
||||
if (mh_load_end_addr < mh_load_addr) {
|
||||
fprintf(stderr, "invalid mh_load_end_addr address\n");
|
||||
exit(1);
|
||||
}
|
||||
mb_load_size = mh_load_end_addr - mh_load_addr;
|
||||
} else {
|
||||
if (kernel_file_size < mb_kernel_text_offset) {
|
||||
fprintf(stderr, "invalid kernel_file_size\n");
|
||||
exit(1);
|
||||
}
|
||||
mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
|
||||
mb_load_size = mb_kernel_size;
|
||||
}
|
||||
|
||||
@@ -384,7 +384,7 @@ ISADevice *pc_find_fdc0(void)
|
||||
warn_report("multiple floppy disk controllers with "
|
||||
"iobase=0x3f0 have been found");
|
||||
error_printf("the one being picked for CMOS setup might not reflect "
|
||||
"your intent\n");
|
||||
"your intent");
|
||||
}
|
||||
|
||||
return state.floppy;
|
||||
@@ -1278,7 +1278,7 @@ void pc_acpi_init(const char *default_dsdt)
|
||||
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt);
|
||||
if (filename == NULL) {
|
||||
fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt);
|
||||
warn_report("failed to find %s", default_dsdt);
|
||||
} else {
|
||||
QemuOpts *opts = qemu_opts_create(qemu_find_opts("acpi"), NULL, 0,
|
||||
&error_abort);
|
||||
@@ -2066,9 +2066,8 @@ static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v,
|
||||
}
|
||||
|
||||
if (value < (1ULL << 20)) {
|
||||
warn_report("small max_ram_below_4g(%"PRIu64
|
||||
") less than 1M. BIOS may not work..",
|
||||
value);
|
||||
warn_report("Only %" PRIu64 " bytes of RAM below the 4GiB boundary,"
|
||||
"BIOS may not work with less than 1MiB", value);
|
||||
}
|
||||
|
||||
pcms->max_ram_below_4g = value;
|
||||
|
||||
@@ -101,9 +101,11 @@ static void pc_q35_init(MachineState *machine)
|
||||
lowmem = pcms->max_ram_below_4g;
|
||||
if (machine->ram_size - lowmem > lowmem &&
|
||||
lowmem & ((1ULL << 30) - 1)) {
|
||||
warn_report("Large machine and max_ram_below_4g(%"PRIu64
|
||||
") not a multiple of 1G; possible bad performance.",
|
||||
pcms->max_ram_below_4g);
|
||||
warn_report("There is possibly poor performance as the ram size "
|
||||
" (0x%" PRIx64 ") is more then twice the size of"
|
||||
" max-ram-below-4g (%"PRIu64") and"
|
||||
" max-ram-below-4g is not a multiple of 1G.",
|
||||
(uint64_t)machine->ram_size, pcms->max_ram_below_4g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#include <sys/resource.h>
|
||||
|
||||
@@ -125,8 +126,8 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
|
||||
rlimit_as.rlim_cur = rlimit_as.rlim_max;
|
||||
|
||||
if (rlimit_as.rlim_max != RLIM_INFINITY) {
|
||||
fprintf(stderr, "Warning: QEMU's maximum size of virtual"
|
||||
" memory is not infinity.\n");
|
||||
warn_report("QEMU's maximum size of virtual"
|
||||
" memory is not infinity");
|
||||
}
|
||||
if (rlimit_as.rlim_max < MCACHE_MAX_SIZE + NON_MCACHE_MEMORY_SIZE) {
|
||||
mapcache->max_mcache_size = rlimit_as.rlim_max -
|
||||
|
||||
244
hw/ide/ahci.c
244
hw/ide/ahci.c
@@ -34,15 +34,7 @@
|
||||
#include "hw/ide/pci.h"
|
||||
#include "hw/ide/ahci_internal.h"
|
||||
|
||||
#define DEBUG_AHCI 0
|
||||
|
||||
#define DPRINTF(port, fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_AHCI) { \
|
||||
fprintf(stderr, "ahci: %s: [%d] ", __func__, port); \
|
||||
fprintf(stderr, fmt, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#include "trace.h"
|
||||
|
||||
static void check_cmd(AHCIState *s, int port);
|
||||
static int handle_cmd(AHCIState *s, int port, uint8_t slot);
|
||||
@@ -55,6 +47,27 @@ static bool ahci_map_fis_address(AHCIDevice *ad);
|
||||
static void ahci_unmap_clb_address(AHCIDevice *ad);
|
||||
static void ahci_unmap_fis_address(AHCIDevice *ad);
|
||||
|
||||
static const char *AHCIPortIRQ_lookup[AHCI_PORT_IRQ__COUNT] = {
|
||||
[AHCI_PORT_IRQ_BIT_DHRS] = "DHRS",
|
||||
[AHCI_PORT_IRQ_BIT_PSS] = "PSS",
|
||||
[AHCI_PORT_IRQ_BIT_DSS] = "DSS",
|
||||
[AHCI_PORT_IRQ_BIT_SDBS] = "SDBS",
|
||||
[AHCI_PORT_IRQ_BIT_UFS] = "UFS",
|
||||
[AHCI_PORT_IRQ_BIT_DPS] = "DPS",
|
||||
[AHCI_PORT_IRQ_BIT_PCS] = "PCS",
|
||||
[AHCI_PORT_IRQ_BIT_DMPS] = "DMPS",
|
||||
[8 ... 21] = "RESERVED",
|
||||
[AHCI_PORT_IRQ_BIT_PRCS] = "PRCS",
|
||||
[AHCI_PORT_IRQ_BIT_IPMS] = "IPMS",
|
||||
[AHCI_PORT_IRQ_BIT_OFS] = "OFS",
|
||||
[25] = "RESERVED",
|
||||
[AHCI_PORT_IRQ_BIT_INFS] = "INFS",
|
||||
[AHCI_PORT_IRQ_BIT_IFS] = "IFS",
|
||||
[AHCI_PORT_IRQ_BIT_HBDS] = "HBDS",
|
||||
[AHCI_PORT_IRQ_BIT_HBFS] = "HBFS",
|
||||
[AHCI_PORT_IRQ_BIT_TFES] = "TFES",
|
||||
[AHCI_PORT_IRQ_BIT_CPDS] = "CPDS"
|
||||
};
|
||||
|
||||
static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
|
||||
{
|
||||
@@ -114,9 +127,9 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
|
||||
default:
|
||||
val = 0;
|
||||
}
|
||||
DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
|
||||
return val;
|
||||
|
||||
trace_ahci_port_read(s, port, offset, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
||||
@@ -125,7 +138,7 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
||||
PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
|
||||
TYPE_PCI_DEVICE);
|
||||
|
||||
DPRINTF(0, "raise irq\n");
|
||||
trace_ahci_irq_raise(s);
|
||||
|
||||
if (pci_dev && msi_enabled(pci_dev)) {
|
||||
msi_notify(pci_dev, 0);
|
||||
@@ -140,7 +153,7 @@ static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
|
||||
PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
|
||||
TYPE_PCI_DEVICE);
|
||||
|
||||
DPRINTF(0, "lower irq\n");
|
||||
trace_ahci_irq_lower(s);
|
||||
|
||||
if (!pci_dev || !msi_enabled(pci_dev)) {
|
||||
qemu_irq_lower(s->irq);
|
||||
@@ -150,8 +163,7 @@ static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
|
||||
static void ahci_check_irq(AHCIState *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
|
||||
uint32_t old_irq = s->control_regs.irqstatus;
|
||||
|
||||
s->control_regs.irqstatus = 0;
|
||||
for (i = 0; i < s->ports; i++) {
|
||||
@@ -160,7 +172,7 @@ static void ahci_check_irq(AHCIState *s)
|
||||
s->control_regs.irqstatus |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
trace_ahci_check_irq(s, old_irq, s->control_regs.irqstatus);
|
||||
if (s->control_regs.irqstatus &&
|
||||
(s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
|
||||
ahci_irq_raise(s, NULL);
|
||||
@@ -170,12 +182,18 @@ static void ahci_check_irq(AHCIState *s)
|
||||
}
|
||||
|
||||
static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d,
|
||||
int irq_type)
|
||||
enum AHCIPortIRQ irqbit)
|
||||
{
|
||||
DPRINTF(d->port_no, "trigger irq %#x -> %x\n",
|
||||
irq_type, d->port_regs.irq_mask & irq_type);
|
||||
g_assert(irqbit >= 0 && irqbit < 32);
|
||||
uint32_t irq = 1U << irqbit;
|
||||
uint32_t irqstat = d->port_regs.irq_stat | irq;
|
||||
|
||||
d->port_regs.irq_stat |= irq_type;
|
||||
trace_ahci_trigger_irq(s, d->port_no,
|
||||
AHCIPortIRQ_lookup[irqbit], irq,
|
||||
d->port_regs.irq_stat, irqstat,
|
||||
irqstat & d->port_regs.irq_mask);
|
||||
|
||||
d->port_regs.irq_stat = irqstat;
|
||||
ahci_check_irq(s);
|
||||
}
|
||||
|
||||
@@ -240,7 +258,7 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
|
||||
{
|
||||
AHCIPortRegs *pr = &s->dev[port].port_regs;
|
||||
|
||||
DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
|
||||
trace_ahci_port_write(s, port, offset, val);
|
||||
switch (offset) {
|
||||
case PORT_LST_ADDR:
|
||||
pr->lst_addr = val;
|
||||
@@ -341,8 +359,6 @@ static uint64_t ahci_mem_read_32(void *opaque, hwaddr addr)
|
||||
val = s->control_regs.version;
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
|
||||
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
|
||||
(addr < (AHCI_PORT_REGS_START_ADDR +
|
||||
(s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
|
||||
@@ -350,6 +366,7 @@ static uint64_t ahci_mem_read_32(void *opaque, hwaddr addr)
|
||||
addr & AHCI_PORT_ADDR_OFFSET_MASK);
|
||||
}
|
||||
|
||||
trace_ahci_mem_read_32(s, addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -379,8 +396,7 @@ static uint64_t ahci_mem_read(void *opaque, hwaddr addr, unsigned size)
|
||||
val = (hi << 32 | lo) >> (ofst * 8);
|
||||
}
|
||||
|
||||
DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
|
||||
addr, val, size);
|
||||
trace_ahci_mem_read(opaque, size, addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -390,8 +406,7 @@ static void ahci_mem_write(void *opaque, hwaddr addr,
|
||||
{
|
||||
AHCIState *s = opaque;
|
||||
|
||||
DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
|
||||
addr, val, size);
|
||||
trace_ahci_mem_write(s, size, addr, val);
|
||||
|
||||
/* Only aligned reads are allowed on AHCI */
|
||||
if (addr & 3) {
|
||||
@@ -401,15 +416,12 @@ static void ahci_mem_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
|
||||
if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
|
||||
DPRINTF(-1, "(addr 0x%08X), val 0x%08"PRIX64"\n", (unsigned) addr, val);
|
||||
|
||||
switch (addr) {
|
||||
case HOST_CAP: /* R/WO, RO */
|
||||
/* FIXME handle R/WO */
|
||||
break;
|
||||
case HOST_CTL: /* R/W */
|
||||
if (val & HOST_CTL_RESET) {
|
||||
DPRINTF(-1, "HBA Reset\n");
|
||||
ahci_reset(s);
|
||||
} else {
|
||||
s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
|
||||
@@ -427,7 +439,7 @@ static void ahci_mem_write(void *opaque, hwaddr addr,
|
||||
/* FIXME report write? */
|
||||
break;
|
||||
default:
|
||||
DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr);
|
||||
trace_ahci_mem_write_unknown(s, size, addr, val);
|
||||
}
|
||||
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
|
||||
(addr < (AHCI_PORT_REGS_START_ADDR +
|
||||
@@ -559,7 +571,8 @@ static void ahci_set_signature(AHCIDevice *ad, uint32_t sig)
|
||||
s->sector = sig >> 8 & 0xFF;
|
||||
s->nsector = sig & 0xFF;
|
||||
|
||||
DPRINTF(ad->port_no, "set hcyl:lcyl:sect:nsect = 0x%08x\n", sig);
|
||||
trace_ahci_set_signature(ad->hba, ad->port_no, s->nsector, s->sector,
|
||||
s->lcyl, s->hcyl, sig);
|
||||
}
|
||||
|
||||
static void ahci_reset_port(AHCIState *s, int port)
|
||||
@@ -569,7 +582,7 @@ static void ahci_reset_port(AHCIState *s, int port)
|
||||
IDEState *ide_state = &d->port.ifs[0];
|
||||
int i;
|
||||
|
||||
DPRINTF(port, "reset port\n");
|
||||
trace_ahci_reset_port(s, port);
|
||||
|
||||
ide_bus_reset(&d->port);
|
||||
ide_state->ncq_queues = AHCI_MAX_CMDS;
|
||||
@@ -622,20 +635,21 @@ static void ahci_reset_port(AHCIState *s, int port)
|
||||
ahci_init_d2h(d);
|
||||
}
|
||||
|
||||
static void debug_print_fis(uint8_t *fis, int cmd_len)
|
||||
/* Buffer pretty output based on a raw FIS structure. */
|
||||
static char *ahci_pretty_buffer_fis(uint8_t *fis, int cmd_len)
|
||||
{
|
||||
#if DEBUG_AHCI
|
||||
int i;
|
||||
GString *s = g_string_new("FIS:");
|
||||
|
||||
fprintf(stderr, "fis:");
|
||||
for (i = 0; i < cmd_len; i++) {
|
||||
if ((i & 0xf) == 0) {
|
||||
fprintf(stderr, "\n%02x:",i);
|
||||
g_string_append_printf(s, "\n0x%02x: ", i);
|
||||
}
|
||||
fprintf(stderr, "%02x ",fis[i]);
|
||||
g_string_append_printf(s, "%02x ", fis[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
g_string_append_c(s, '\n');
|
||||
|
||||
return g_string_free(s, FALSE);
|
||||
}
|
||||
|
||||
static bool ahci_map_fis_address(AHCIDevice *ad)
|
||||
@@ -655,7 +669,7 @@ static bool ahci_map_fis_address(AHCIDevice *ad)
|
||||
static void ahci_unmap_fis_address(AHCIDevice *ad)
|
||||
{
|
||||
if (ad->res_fis == NULL) {
|
||||
DPRINTF(ad->port_no, "Attempt to unmap NULL FIS address\n");
|
||||
trace_ahci_unmap_fis_address_null(ad->hba, ad->port_no);
|
||||
return;
|
||||
}
|
||||
ad->port_regs.cmd &= ~PORT_CMD_FIS_ON;
|
||||
@@ -682,7 +696,7 @@ static bool ahci_map_clb_address(AHCIDevice *ad)
|
||||
static void ahci_unmap_clb_address(AHCIDevice *ad)
|
||||
{
|
||||
if (ad->lst == NULL) {
|
||||
DPRINTF(ad->port_no, "Attempt to unmap NULL CLB address\n");
|
||||
trace_ahci_unmap_clb_address_null(ad->hba, ad->port_no);
|
||||
return;
|
||||
}
|
||||
ad->port_regs.cmd &= ~PORT_CMD_LIST_ON;
|
||||
@@ -723,7 +737,7 @@ static void ahci_write_fis_sdb(AHCIState *s, NCQTransferState *ncq_tfs)
|
||||
|
||||
/* Trigger IRQ if interrupt bit is set (which currently, it always is) */
|
||||
if (sdb_fis->flags & 0x40) {
|
||||
ahci_trigger_irq(s, ad, PORT_IRQ_SDB_FIS);
|
||||
ahci_trigger_irq(s, ad, AHCI_PORT_IRQ_BIT_SDBS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,10 +780,10 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
|
||||
ad->port.ifs[0].status;
|
||||
|
||||
if (pio_fis[2] & ERR_STAT) {
|
||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
|
||||
ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_TFES);
|
||||
}
|
||||
|
||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS);
|
||||
ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_PSS);
|
||||
}
|
||||
|
||||
static bool ahci_write_fis_d2h(AHCIDevice *ad)
|
||||
@@ -809,10 +823,10 @@ static bool ahci_write_fis_d2h(AHCIDevice *ad)
|
||||
ad->port.ifs[0].status;
|
||||
|
||||
if (d2h_fis[2] & ERR_STAT) {
|
||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
|
||||
ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_TFES);
|
||||
}
|
||||
|
||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
|
||||
ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_DHRS);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -854,20 +868,22 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
|
||||
IDEBus *bus = &ad->port;
|
||||
BusState *qbus = BUS(bus);
|
||||
|
||||
trace_ahci_populate_sglist(ad->hba, ad->port_no);
|
||||
|
||||
if (!prdtl) {
|
||||
DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
|
||||
trace_ahci_populate_sglist_no_prdtl(ad->hba, ad->port_no, opts);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* map PRDT */
|
||||
if (!(prdt = dma_memory_map(ad->hba->as, prdt_addr, &prdt_len,
|
||||
DMA_DIRECTION_TO_DEVICE))){
|
||||
DPRINTF(ad->port_no, "map failed\n");
|
||||
trace_ahci_populate_sglist_no_map(ad->hba, ad->port_no);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (prdt_len < real_prdt_len) {
|
||||
DPRINTF(ad->port_no, "mapped less than expected\n");
|
||||
trace_ahci_populate_sglist_short_map(ad->hba, ad->port_no);
|
||||
r = -1;
|
||||
goto out;
|
||||
}
|
||||
@@ -886,9 +902,8 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
|
||||
sum += tbl_entry_size;
|
||||
}
|
||||
if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
|
||||
DPRINTF(ad->port_no, "%s: Incorrect offset! "
|
||||
"off_idx: %d, off_pos: %"PRId64"\n",
|
||||
__func__, off_idx, off_pos);
|
||||
trace_ahci_populate_sglist_bad_offset(ad->hba, ad->port_no,
|
||||
off_idx, off_pos);
|
||||
r = -1;
|
||||
goto out;
|
||||
}
|
||||
@@ -934,8 +949,8 @@ static void ncq_finish(NCQTransferState *ncq_tfs)
|
||||
|
||||
ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs);
|
||||
|
||||
DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
|
||||
ncq_tfs->tag);
|
||||
trace_ncq_finish(ncq_tfs->drive->hba, ncq_tfs->drive->port_no,
|
||||
ncq_tfs->tag);
|
||||
|
||||
block_acct_done(blk_get_stats(ncq_tfs->drive->port.ifs[0].blk),
|
||||
&ncq_tfs->acct);
|
||||
@@ -999,12 +1014,8 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs)
|
||||
|
||||
switch (ncq_tfs->cmd) {
|
||||
case READ_FPDMA_QUEUED:
|
||||
DPRINTF(port, "NCQ reading %d sectors from LBA %"PRId64", tag %d\n",
|
||||
ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag);
|
||||
|
||||
DPRINTF(port, "tag %d aio read %"PRId64"\n",
|
||||
ncq_tfs->tag, ncq_tfs->lba);
|
||||
|
||||
trace_execute_ncq_command_read(ad->hba, port, ncq_tfs->tag,
|
||||
ncq_tfs->sector_count, ncq_tfs->lba);
|
||||
dma_acct_start(ide_state->blk, &ncq_tfs->acct,
|
||||
&ncq_tfs->sglist, BLOCK_ACCT_READ);
|
||||
ncq_tfs->aiocb = dma_blk_read(ide_state->blk, &ncq_tfs->sglist,
|
||||
@@ -1013,12 +1024,8 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs)
|
||||
ncq_cb, ncq_tfs);
|
||||
break;
|
||||
case WRITE_FPDMA_QUEUED:
|
||||
DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n",
|
||||
ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag);
|
||||
|
||||
DPRINTF(port, "tag %d aio write %"PRId64"\n",
|
||||
ncq_tfs->tag, ncq_tfs->lba);
|
||||
|
||||
trace_execute_ncq_command_read(ad->hba, port, ncq_tfs->tag,
|
||||
ncq_tfs->sector_count, ncq_tfs->lba);
|
||||
dma_acct_start(ide_state->blk, &ncq_tfs->acct,
|
||||
&ncq_tfs->sglist, BLOCK_ACCT_WRITE);
|
||||
ncq_tfs->aiocb = dma_blk_write(ide_state->blk, &ncq_tfs->sglist,
|
||||
@@ -1027,8 +1034,8 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs)
|
||||
ncq_cb, ncq_tfs);
|
||||
break;
|
||||
default:
|
||||
DPRINTF(port, "error: unsupported NCQ command (0x%02x) received\n",
|
||||
ncq_tfs->cmd);
|
||||
trace_execute_ncq_command_unsup(ad->hba, port,
|
||||
ncq_tfs->tag, ncq_tfs->cmd);
|
||||
ncq_err(ncq_tfs);
|
||||
}
|
||||
}
|
||||
@@ -1038,7 +1045,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
|
||||
uint8_t slot)
|
||||
{
|
||||
AHCIDevice *ad = &s->dev[port];
|
||||
IDEState *ide_state = &ad->port.ifs[0];
|
||||
NCQFrame *ncq_fis = (NCQFrame*)cmd_fis;
|
||||
uint8_t tag = ncq_fis->tag >> 3;
|
||||
NCQTransferState *ncq_tfs = &ad->ncq_tfs[tag];
|
||||
@@ -1066,21 +1072,20 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
|
||||
|
||||
/* Sanity-check the NCQ packet */
|
||||
if (tag != slot) {
|
||||
DPRINTF(port, "Warn: NCQ slot (%d) did not match the given tag (%d)\n",
|
||||
slot, tag);
|
||||
trace_process_ncq_command_mismatch(s, port, tag, slot);
|
||||
}
|
||||
|
||||
if (ncq_fis->aux0 || ncq_fis->aux1 || ncq_fis->aux2 || ncq_fis->aux3) {
|
||||
DPRINTF(port, "Warn: Attempt to use NCQ auxiliary fields.\n");
|
||||
trace_process_ncq_command_aux(s, port, tag);
|
||||
}
|
||||
if (ncq_fis->prio || ncq_fis->icc) {
|
||||
DPRINTF(port, "Warn: Unsupported attempt to use PRIO/ICC fields\n");
|
||||
trace_process_ncq_command_prioicc(s, port, tag);
|
||||
}
|
||||
if (ncq_fis->fua & NCQ_FIS_FUA_MASK) {
|
||||
DPRINTF(port, "Warn: Unsupported attempt to use Force Unit Access\n");
|
||||
trace_process_ncq_command_fua(s, port, tag);
|
||||
}
|
||||
if (ncq_fis->tag & NCQ_FIS_RARC_MASK) {
|
||||
DPRINTF(port, "Warn: Unsupported attempt to use Rebuild Assist\n");
|
||||
trace_process_ncq_command_rarc(s, port, tag);
|
||||
}
|
||||
|
||||
ncq_tfs->sector_count = ((ncq_fis->sector_count_high << 8) |
|
||||
@@ -1096,19 +1101,17 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
|
||||
"is smaller than the requested size (0x%zx)",
|
||||
ncq_tfs->sglist.size, size);
|
||||
ncq_err(ncq_tfs);
|
||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_OVERFLOW);
|
||||
ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_OFS);
|
||||
return;
|
||||
} else if (ncq_tfs->sglist.size != size) {
|
||||
DPRINTF(port, "Warn: PRDTL (0x%zx)"
|
||||
" does not match requested size (0x%zx)",
|
||||
ncq_tfs->sglist.size, size);
|
||||
trace_process_ncq_command_large(s, port, tag,
|
||||
ncq_tfs->sglist.size, size);
|
||||
}
|
||||
|
||||
DPRINTF(port, "NCQ transfer LBA from %"PRId64" to %"PRId64", "
|
||||
"drive max %"PRId64"\n",
|
||||
ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 1,
|
||||
ide_state->nb_sectors - 1);
|
||||
|
||||
trace_process_ncq_command(s, port, tag,
|
||||
ncq_fis->command,
|
||||
ncq_tfs->lba,
|
||||
ncq_tfs->lba + ncq_tfs->sector_count - 1);
|
||||
execute_ncq_command(ncq_tfs);
|
||||
}
|
||||
|
||||
@@ -1129,16 +1132,14 @@ static void handle_reg_h2d_fis(AHCIState *s, int port,
|
||||
uint16_t opts = le16_to_cpu(cmd->opts);
|
||||
|
||||
if (cmd_fis[1] & 0x0F) {
|
||||
DPRINTF(port, "Port Multiplier not supported."
|
||||
" cmd_fis[0]=%02x cmd_fis[1]=%02x cmd_fis[2]=%02x\n",
|
||||
cmd_fis[0], cmd_fis[1], cmd_fis[2]);
|
||||
trace_handle_reg_h2d_fis_pmp(s, port, cmd_fis[1],
|
||||
cmd_fis[2], cmd_fis[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_fis[1] & 0x70) {
|
||||
DPRINTF(port, "Reserved flags set in H2D Register FIS."
|
||||
" cmd_fis[0]=%02x cmd_fis[1]=%02x cmd_fis[2]=%02x\n",
|
||||
cmd_fis[0], cmd_fis[1], cmd_fis[2]);
|
||||
trace_handle_reg_h2d_fis_res(s, port, cmd_fis[1],
|
||||
cmd_fis[2], cmd_fis[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1192,7 +1193,11 @@ static void handle_reg_h2d_fis(AHCIState *s, int port,
|
||||
* table to ide_state->io_buffer */
|
||||
if (opts & AHCI_CMD_ATAPI) {
|
||||
memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10);
|
||||
debug_print_fis(ide_state->io_buffer, 0x10);
|
||||
if (trace_event_get_state_backends(TRACE_HANDLE_REG_H2D_FIS_DUMP)) {
|
||||
char *pretty_fis = ahci_pretty_buffer_fis(ide_state->io_buffer, 0x10);
|
||||
trace_handle_reg_h2d_fis_dump(s, port, pretty_fis);
|
||||
g_free(pretty_fis);
|
||||
}
|
||||
s->dev[port].done_atapi_packet = false;
|
||||
/* XXX send PIO setup FIS */
|
||||
}
|
||||
@@ -1216,12 +1221,12 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot)
|
||||
|
||||
if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
|
||||
/* Engine currently busy, try again later */
|
||||
DPRINTF(port, "engine busy\n");
|
||||
trace_handle_cmd_busy(s, port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!s->dev[port].lst) {
|
||||
DPRINTF(port, "error: lst not given but cmd handled");
|
||||
trace_handle_cmd_nolist(s, port);
|
||||
return -1;
|
||||
}
|
||||
cmd = get_cmd_header(s, port, slot);
|
||||
@@ -1231,7 +1236,7 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot)
|
||||
/* The device we are working for */
|
||||
ide_state = &s->dev[port].port.ifs[0];
|
||||
if (!ide_state->blk) {
|
||||
DPRINTF(port, "error: guest accessed unused port");
|
||||
trace_handle_cmd_badport(s, port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1240,25 +1245,25 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot)
|
||||
cmd_fis = dma_memory_map(s->as, tbl_addr, &cmd_len,
|
||||
DMA_DIRECTION_FROM_DEVICE);
|
||||
if (!cmd_fis) {
|
||||
DPRINTF(port, "error: guest passed us an invalid cmd fis\n");
|
||||
trace_handle_cmd_badfis(s, port);
|
||||
return -1;
|
||||
} else if (cmd_len != 0x80) {
|
||||
ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_HBUS_ERR);
|
||||
DPRINTF(port, "error: dma_memory_map failed: "
|
||||
"(len(%02"PRIx64") != 0x80)\n",
|
||||
cmd_len);
|
||||
ahci_trigger_irq(s, &s->dev[port], AHCI_PORT_IRQ_BIT_HBFS);
|
||||
trace_handle_cmd_badmap(s, port, cmd_len);
|
||||
goto out;
|
||||
}
|
||||
debug_print_fis(cmd_fis, 0x80);
|
||||
|
||||
if (trace_event_get_state_backends(TRACE_HANDLE_CMD_FIS_DUMP)) {
|
||||
char *pretty_fis = ahci_pretty_buffer_fis(cmd_fis, 0x80);
|
||||
trace_handle_cmd_fis_dump(s, port, pretty_fis);
|
||||
g_free(pretty_fis);
|
||||
}
|
||||
switch (cmd_fis[0]) {
|
||||
case SATA_FIS_TYPE_REGISTER_H2D:
|
||||
handle_reg_h2d_fis(s, port, slot, cmd_fis);
|
||||
break;
|
||||
default:
|
||||
DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
|
||||
"cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
|
||||
cmd_fis[2]);
|
||||
trace_handle_cmd_unhandled_fis(s, port,
|
||||
cmd_fis[0], cmd_fis[1], cmd_fis[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1299,9 +1304,9 @@ static void ahci_start_transfer(IDEDMA *dma)
|
||||
has_sglist = 1;
|
||||
}
|
||||
|
||||
DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n",
|
||||
is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata",
|
||||
has_sglist ? "" : "o");
|
||||
trace_ahci_start_transfer(ad->hba, ad->port_no, is_write ? "writ" : "read",
|
||||
size, is_atapi ? "atapi" : "ata",
|
||||
has_sglist ? "" : "o");
|
||||
|
||||
if (has_sglist && size) {
|
||||
if (is_write) {
|
||||
@@ -1330,7 +1335,7 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s,
|
||||
BlockCompletionFunc *dma_cb)
|
||||
{
|
||||
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
||||
DPRINTF(ad->port_no, "\n");
|
||||
trace_ahci_start_dma(ad->hba, ad->port_no);
|
||||
s->io_buffer_offset = 0;
|
||||
dma_cb(s, 0);
|
||||
}
|
||||
@@ -1368,12 +1373,12 @@ static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit)
|
||||
|
||||
if (ahci_populate_sglist(ad, &s->sg, ad->cur_cmd,
|
||||
limit, s->io_buffer_offset) == -1) {
|
||||
DPRINTF(ad->port_no, "ahci_dma_prepare_buf failed.\n");
|
||||
trace_ahci_dma_prepare_buf_fail(ad->hba, ad->port_no);
|
||||
return -1;
|
||||
}
|
||||
s->io_buffer_size = s->sg.size;
|
||||
|
||||
DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
|
||||
trace_ahci_dma_prepare_buf(ad->hba, ad->port_no, limit, s->io_buffer_size);
|
||||
return s->io_buffer_size;
|
||||
}
|
||||
|
||||
@@ -1409,11 +1414,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
|
||||
|
||||
/* free sglist, update byte count */
|
||||
dma_buf_commit(s, l);
|
||||
|
||||
s->io_buffer_index += l;
|
||||
|
||||
DPRINTF(ad->port_no, "len=%#x\n", l);
|
||||
|
||||
trace_ahci_dma_rw_buf(ad->hba, ad->port_no, l);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1421,7 +1424,7 @@ static void ahci_cmd_done(IDEDMA *dma)
|
||||
{
|
||||
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
||||
|
||||
DPRINTF(ad->port_no, "cmd done\n");
|
||||
trace_ahci_cmd_done(ad->hba, ad->port_no);
|
||||
|
||||
/* update d2h status */
|
||||
ahci_write_fis_d2h(ad);
|
||||
@@ -1495,6 +1498,7 @@ void ahci_uninit(AHCIState *s)
|
||||
|
||||
ide_exit(s);
|
||||
}
|
||||
object_unparent(OBJECT(&ad->port));
|
||||
}
|
||||
|
||||
g_free(s->dev);
|
||||
@@ -1505,6 +1509,8 @@ void ahci_reset(AHCIState *s)
|
||||
AHCIPortRegs *pr;
|
||||
int i;
|
||||
|
||||
trace_ahci_reset(s);
|
||||
|
||||
s->control_regs.irqstatus = 0;
|
||||
/* AHCI Enable (AE)
|
||||
* The implementation of this bit is dependent upon the value of the
|
||||
@@ -1755,6 +1761,7 @@ static uint64_t allwinner_ahci_mem_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
AllwinnerAHCIState *a = opaque;
|
||||
AHCIState *s = &(SYSBUS_AHCI(a)->ahci);
|
||||
uint64_t val = a->regs[addr/4];
|
||||
|
||||
switch (addr / 4) {
|
||||
@@ -1765,8 +1772,7 @@ static uint64_t allwinner_ahci_mem_read(void *opaque, hwaddr addr,
|
||||
val &= ~(0x1 << 24);
|
||||
break;
|
||||
}
|
||||
DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
|
||||
addr, val, size);
|
||||
trace_allwinner_ahci_mem_read(s, a, addr, val, size);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -1774,9 +1780,9 @@ static void allwinner_ahci_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
AllwinnerAHCIState *a = opaque;
|
||||
AHCIState *s = &(SYSBUS_AHCI(a)->ahci);
|
||||
|
||||
DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n",
|
||||
addr, val, size);
|
||||
trace_allwinner_ahci_mem_write(s, a, addr, val, size);
|
||||
a->regs[addr/4] = val;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,31 @@
|
||||
#define PORT_CMD_ISSUE 0x38 /* command issue */
|
||||
#define PORT_RESERVED 0x3c /* reserved */
|
||||
|
||||
/* Port interrupt bit descriptors */
|
||||
enum AHCIPortIRQ {
|
||||
AHCI_PORT_IRQ_BIT_DHRS = 0,
|
||||
AHCI_PORT_IRQ_BIT_PSS = 1,
|
||||
AHCI_PORT_IRQ_BIT_DSS = 2,
|
||||
AHCI_PORT_IRQ_BIT_SDBS = 3,
|
||||
AHCI_PORT_IRQ_BIT_UFS = 4,
|
||||
AHCI_PORT_IRQ_BIT_DPS = 5,
|
||||
AHCI_PORT_IRQ_BIT_PCS = 6,
|
||||
AHCI_PORT_IRQ_BIT_DMPS = 7,
|
||||
/* RESERVED */
|
||||
AHCI_PORT_IRQ_BIT_PRCS = 22,
|
||||
AHCI_PORT_IRQ_BIT_IPMS = 23,
|
||||
AHCI_PORT_IRQ_BIT_OFS = 24,
|
||||
/* RESERVED */
|
||||
AHCI_PORT_IRQ_BIT_INFS = 26,
|
||||
AHCI_PORT_IRQ_BIT_IFS = 27,
|
||||
AHCI_PORT_IRQ_BIT_HBDS = 28,
|
||||
AHCI_PORT_IRQ_BIT_HBFS = 29,
|
||||
AHCI_PORT_IRQ_BIT_TFES = 30,
|
||||
AHCI_PORT_IRQ_BIT_CPDS = 31,
|
||||
AHCI_PORT_IRQ__COUNT = 32
|
||||
};
|
||||
|
||||
|
||||
/* PORT_IRQ_{STAT,MASK} bits */
|
||||
#define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */
|
||||
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
|
||||
@@ -98,18 +123,19 @@
|
||||
#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
|
||||
#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */
|
||||
#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */
|
||||
/* reserved */
|
||||
#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */
|
||||
#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */
|
||||
|
||||
#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */
|
||||
#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */
|
||||
#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */
|
||||
#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */
|
||||
#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */
|
||||
#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */
|
||||
#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */
|
||||
#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */
|
||||
#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
|
||||
/* reserved */
|
||||
#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */
|
||||
#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */
|
||||
#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */
|
||||
#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */
|
||||
#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */
|
||||
#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */
|
||||
#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */
|
||||
#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
|
||||
|
||||
#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \
|
||||
PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "hw/ide/internal.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define ATAPI_SECTOR_BITS (2 + BDRV_SECTOR_BITS)
|
||||
#define ATAPI_SECTOR_SIZE (1 << ATAPI_SECTOR_BITS)
|
||||
@@ -116,9 +117,7 @@ cd_read_sector_sync(IDEState *s)
|
||||
block_acct_start(blk_get_stats(s->blk), &s->acct,
|
||||
ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ);
|
||||
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("cd_read_sector_sync: lba=%d\n", s->lba);
|
||||
#endif
|
||||
trace_cd_read_sector_sync(s->lba);
|
||||
|
||||
switch (s->cd_sector_size) {
|
||||
case 2048:
|
||||
@@ -152,9 +151,7 @@ static void cd_read_sector_cb(void *opaque, int ret)
|
||||
{
|
||||
IDEState *s = opaque;
|
||||
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("cd_read_sector_cb: lba=%d ret=%d\n", s->lba, ret);
|
||||
#endif
|
||||
trace_cd_read_sector_cb(s->lba, ret);
|
||||
|
||||
if (ret < 0) {
|
||||
block_acct_failed(blk_get_stats(s->blk), &s->acct);
|
||||
@@ -188,9 +185,7 @@ static int cd_read_sector(IDEState *s)
|
||||
s->iov.iov_len = ATAPI_SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&s->qiov, &s->iov, 1);
|
||||
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("cd_read_sector: lba=%d\n", s->lba);
|
||||
#endif
|
||||
trace_cd_read_sector(s->lba);
|
||||
|
||||
block_acct_start(blk_get_stats(s->blk), &s->acct,
|
||||
ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ);
|
||||
@@ -213,9 +208,7 @@ void ide_atapi_cmd_ok(IDEState *s)
|
||||
|
||||
void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc)
|
||||
{
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc);
|
||||
#endif
|
||||
trace_ide_atapi_cmd_error(s, sense_key, asc);
|
||||
s->error = sense_key << 4;
|
||||
s->status = READY_STAT | ERR_STAT;
|
||||
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
|
||||
@@ -252,19 +245,14 @@ static uint16_t atapi_byte_count_limit(IDEState *s)
|
||||
void ide_atapi_cmd_reply_end(IDEState *s)
|
||||
{
|
||||
int byte_count_limit, size, ret;
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("reply: tx_size=%d elem_tx_size=%d index=%d\n",
|
||||
s->packet_transfer_size,
|
||||
s->elementary_transfer_size,
|
||||
s->io_buffer_index);
|
||||
#endif
|
||||
trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size,
|
||||
s->elementary_transfer_size,
|
||||
s->io_buffer_index);
|
||||
if (s->packet_transfer_size <= 0) {
|
||||
/* end of transfer */
|
||||
ide_atapi_cmd_ok(s);
|
||||
ide_set_irq(s->bus);
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("end of transfer, status=0x%x\n", s->status);
|
||||
#endif
|
||||
trace_ide_atapi_cmd_reply_end_eot(s, s->status);
|
||||
} else {
|
||||
/* see if a new sector must be read */
|
||||
if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
|
||||
@@ -300,9 +288,7 @@ void ide_atapi_cmd_reply_end(IDEState *s)
|
||||
/* a new transfer is needed */
|
||||
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
|
||||
byte_count_limit = atapi_byte_count_limit(s);
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("byte_count_limit=%d\n", byte_count_limit);
|
||||
#endif
|
||||
trace_ide_atapi_cmd_reply_end_bcl(s, byte_count_limit);
|
||||
size = s->packet_transfer_size;
|
||||
if (size > byte_count_limit) {
|
||||
/* byte count limit must be even if this case */
|
||||
@@ -324,9 +310,7 @@ void ide_atapi_cmd_reply_end(IDEState *s)
|
||||
ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
|
||||
size, ide_atapi_cmd_reply_end);
|
||||
ide_set_irq(s->bus);
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("status=0x%x\n", s->status);
|
||||
#endif
|
||||
trace_ide_atapi_cmd_reply_end_new(s, s->status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,9 +352,7 @@ static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
|
||||
|
||||
static void ide_atapi_cmd_check_status(IDEState *s)
|
||||
{
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("atapi_cmd_check_status\n");
|
||||
#endif
|
||||
trace_ide_atapi_cmd_check_status(s);
|
||||
s->error = MC_ERR | (UNIT_ATTENTION << 4);
|
||||
s->status = ERR_STAT;
|
||||
s->nsector = 0;
|
||||
@@ -434,10 +416,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
|
||||
s->io_buffer_size = n * 2048;
|
||||
data_offset = 0;
|
||||
}
|
||||
#ifdef DEBUG_AIO
|
||||
printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
|
||||
#endif
|
||||
|
||||
trace_ide_atapi_cmd_read_dma_cb_aio(s, s->lba, n);
|
||||
s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset);
|
||||
s->bus->dma->iov.iov_len = n * ATAPI_SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1);
|
||||
@@ -477,10 +456,8 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
|
||||
static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
|
||||
int sector_size)
|
||||
{
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio",
|
||||
lba, nb_sectors);
|
||||
#endif
|
||||
trace_ide_atapi_cmd_read(s, s->atapi_dma ? "dma" : "pio",
|
||||
lba, nb_sectors);
|
||||
if (s->atapi_dma) {
|
||||
ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size);
|
||||
} else {
|
||||
@@ -1330,16 +1307,18 @@ void ide_atapi_cmd(IDEState *s)
|
||||
uint8_t *buf = s->io_buffer;
|
||||
const struct AtapiCmd *cmd = &atapi_cmd_table[s->io_buffer[0]];
|
||||
|
||||
#ifdef DEBUG_IDE_ATAPI
|
||||
{
|
||||
trace_ide_atapi_cmd(s, s->io_buffer[0]);
|
||||
|
||||
if (trace_event_get_state_backends(TRACE_IDE_ATAPI_CMD_PACKET)) {
|
||||
/* Each pretty-printed byte needs two bytes and a space; */
|
||||
char *ppacket = g_malloc(ATAPI_PACKET_SIZE * 3 + 1);
|
||||
int i;
|
||||
printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8));
|
||||
for(i = 0; i < ATAPI_PACKET_SIZE; i++) {
|
||||
printf(" %02x", buf[i]);
|
||||
for (i = 0; i < ATAPI_PACKET_SIZE; i++) {
|
||||
sprintf(ppacket + (i * 3), "%02x ", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
trace_ide_atapi_cmd_packet(s, s->lcyl | (s->hcyl << 8), ppacket);
|
||||
g_free(ppacket);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If there's a UNIT_ATTENTION condition pending, only command flagged with
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
#include "hw/ide/pci.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* CMD646 specific */
|
||||
#define CFR 0x50
|
||||
@@ -195,9 +196,8 @@ static uint64_t bmdma_read(void *opaque, hwaddr addr,
|
||||
val = 0xff;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_IDE
|
||||
printf("bmdma: readb " TARGET_FMT_plx " : 0x%02x\n", addr, val);
|
||||
#endif
|
||||
|
||||
trace_bmdma_read_cmd646(addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -211,9 +211,7 @@ static void bmdma_write(void *opaque, hwaddr addr,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IDE
|
||||
printf("bmdma: writeb " TARGET_FMT_plx " : 0x%" PRIx64 "\n", addr, val);
|
||||
#endif
|
||||
trace_bmdma_write_cmd646(addr, val);
|
||||
switch(addr & 3) {
|
||||
case 0:
|
||||
bmdma_cmd_writeb(bm, val);
|
||||
|
||||
192
hw/ide/core.c
192
hw/ide/core.c
@@ -34,8 +34,10 @@
|
||||
#include "hw/block/block.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#include "hw/ide/internal.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* These values were based on a Seagate ST3500418AS but have been modified
|
||||
to make more sense in QEMU */
|
||||
@@ -57,6 +59,21 @@ static const int smart_attributes[][12] = {
|
||||
{ 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
|
||||
};
|
||||
|
||||
const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT] = {
|
||||
[IDE_DMA_READ] = "DMA READ",
|
||||
[IDE_DMA_WRITE] = "DMA WRITE",
|
||||
[IDE_DMA_TRIM] = "DMA TRIM",
|
||||
[IDE_DMA_ATAPI] = "DMA ATAPI"
|
||||
};
|
||||
|
||||
static const char *IDE_DMA_CMD_str(enum ide_dma_cmd enval)
|
||||
{
|
||||
if (enval >= IDE_DMA__BEGIN && enval < IDE_DMA__COUNT) {
|
||||
return IDE_DMA_CMD_lookup[enval];
|
||||
}
|
||||
return "DMA UNKNOWN CMD";
|
||||
}
|
||||
|
||||
static void ide_dummy_transfer_stop(IDEState *s);
|
||||
|
||||
static void padstr(char *str, const char *src, int len)
|
||||
@@ -656,10 +673,7 @@ void ide_cancel_dma_sync(IDEState *s)
|
||||
* write requests) pending and we can avoid to drain. */
|
||||
QLIST_FOREACH(req, &s->buffered_requests, list) {
|
||||
if (!req->orphaned) {
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: invoking cb %p of buffered request %p with"
|
||||
" -ECANCELED\n", __func__, req->original_cb, req);
|
||||
#endif
|
||||
trace_ide_cancel_dma_sync_buffered(req->original_cb, req);
|
||||
req->original_cb(req->original_opaque, -ECANCELED);
|
||||
}
|
||||
req->orphaned = true;
|
||||
@@ -678,9 +692,7 @@ void ide_cancel_dma_sync(IDEState *s)
|
||||
* aio operation with preadv/pwritev.
|
||||
*/
|
||||
if (s->bus->dma->aiocb) {
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: draining all remaining requests", __func__);
|
||||
#endif
|
||||
trace_ide_cancel_dma_sync_remaining();
|
||||
blk_drain(s->blk);
|
||||
assert(s->bus->dma->aiocb == NULL);
|
||||
}
|
||||
@@ -741,9 +753,7 @@ static void ide_sector_read(IDEState *s)
|
||||
n = s->req_nb_sectors;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_IDE)
|
||||
printf("sector=%" PRId64 "\n", sector_num);
|
||||
#endif
|
||||
trace_ide_sector_read(sector_num, n);
|
||||
|
||||
if (!ide_sect_range_ok(s, sector_num, n)) {
|
||||
ide_rw_error(s);
|
||||
@@ -866,10 +876,7 @@ static void ide_dma_cb(void *opaque, int ret)
|
||||
goto eot;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_AIO
|
||||
printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, cmd_cmd=%d\n",
|
||||
sector_num, n, s->dma_cmd);
|
||||
#endif
|
||||
trace_ide_dma_cb(s, sector_num, n, IDE_DMA_CMD_str(s->dma_cmd));
|
||||
|
||||
if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
|
||||
!ide_sect_range_ok(s, sector_num, n)) {
|
||||
@@ -1005,14 +1012,14 @@ static void ide_sector_write(IDEState *s)
|
||||
|
||||
s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
|
||||
sector_num = ide_get_sector(s);
|
||||
#if defined(DEBUG_IDE)
|
||||
printf("sector=%" PRId64 "\n", sector_num);
|
||||
#endif
|
||||
|
||||
n = s->nsector;
|
||||
if (n > s->req_nb_sectors) {
|
||||
n = s->req_nb_sectors;
|
||||
}
|
||||
|
||||
trace_ide_sector_write(sector_num, n);
|
||||
|
||||
if (!ide_sect_range_ok(s, sector_num, n)) {
|
||||
ide_rw_error(s);
|
||||
block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
|
||||
@@ -1191,60 +1198,83 @@ static void ide_clear_hob(IDEBus *bus)
|
||||
bus->ifs[1].select &= ~(1 << 7);
|
||||
}
|
||||
|
||||
/* IOport [W]rite [R]egisters */
|
||||
enum ATA_IOPORT_WR {
|
||||
ATA_IOPORT_WR_DATA = 0,
|
||||
ATA_IOPORT_WR_FEATURES = 1,
|
||||
ATA_IOPORT_WR_SECTOR_COUNT = 2,
|
||||
ATA_IOPORT_WR_SECTOR_NUMBER = 3,
|
||||
ATA_IOPORT_WR_CYLINDER_LOW = 4,
|
||||
ATA_IOPORT_WR_CYLINDER_HIGH = 5,
|
||||
ATA_IOPORT_WR_DEVICE_HEAD = 6,
|
||||
ATA_IOPORT_WR_COMMAND = 7,
|
||||
ATA_IOPORT_WR_NUM_REGISTERS,
|
||||
};
|
||||
|
||||
const char *ATA_IOPORT_WR_lookup[ATA_IOPORT_WR_NUM_REGISTERS] = {
|
||||
[ATA_IOPORT_WR_DATA] = "Data",
|
||||
[ATA_IOPORT_WR_FEATURES] = "Features",
|
||||
[ATA_IOPORT_WR_SECTOR_COUNT] = "Sector Count",
|
||||
[ATA_IOPORT_WR_SECTOR_NUMBER] = "Sector Number",
|
||||
[ATA_IOPORT_WR_CYLINDER_LOW] = "Cylinder Low",
|
||||
[ATA_IOPORT_WR_CYLINDER_HIGH] = "Cylinder High",
|
||||
[ATA_IOPORT_WR_DEVICE_HEAD] = "Device/Head",
|
||||
[ATA_IOPORT_WR_COMMAND] = "Command"
|
||||
};
|
||||
|
||||
void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
IDEBus *bus = opaque;
|
||||
IDEState *s = idebus_active_if(bus);
|
||||
int reg_num = addr & 7;
|
||||
|
||||
#ifdef DEBUG_IDE
|
||||
printf("IDE: write addr=0x%x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
|
||||
addr &= 7;
|
||||
trace_ide_ioport_write(addr, ATA_IOPORT_WR_lookup[reg_num], val, bus, s);
|
||||
|
||||
/* ignore writes to command block while busy with previous command */
|
||||
if (addr != 7 && (idebus_active_if(bus)->status & (BUSY_STAT|DRQ_STAT)))
|
||||
if (reg_num != 7 && (s->status & (BUSY_STAT|DRQ_STAT))) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
switch (reg_num) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
ide_clear_hob(bus);
|
||||
case ATA_IOPORT_WR_FEATURES:
|
||||
ide_clear_hob(bus);
|
||||
/* NOTE: data is written to the two drives */
|
||||
bus->ifs[0].hob_feature = bus->ifs[0].feature;
|
||||
bus->ifs[1].hob_feature = bus->ifs[1].feature;
|
||||
bus->ifs[0].hob_feature = bus->ifs[0].feature;
|
||||
bus->ifs[1].hob_feature = bus->ifs[1].feature;
|
||||
bus->ifs[0].feature = val;
|
||||
bus->ifs[1].feature = val;
|
||||
break;
|
||||
case 2:
|
||||
case ATA_IOPORT_WR_SECTOR_COUNT:
|
||||
ide_clear_hob(bus);
|
||||
bus->ifs[0].hob_nsector = bus->ifs[0].nsector;
|
||||
bus->ifs[1].hob_nsector = bus->ifs[1].nsector;
|
||||
bus->ifs[0].nsector = val;
|
||||
bus->ifs[1].nsector = val;
|
||||
break;
|
||||
case 3:
|
||||
case ATA_IOPORT_WR_SECTOR_NUMBER:
|
||||
ide_clear_hob(bus);
|
||||
bus->ifs[0].hob_sector = bus->ifs[0].sector;
|
||||
bus->ifs[1].hob_sector = bus->ifs[1].sector;
|
||||
bus->ifs[0].sector = val;
|
||||
bus->ifs[1].sector = val;
|
||||
break;
|
||||
case 4:
|
||||
case ATA_IOPORT_WR_CYLINDER_LOW:
|
||||
ide_clear_hob(bus);
|
||||
bus->ifs[0].hob_lcyl = bus->ifs[0].lcyl;
|
||||
bus->ifs[1].hob_lcyl = bus->ifs[1].lcyl;
|
||||
bus->ifs[0].lcyl = val;
|
||||
bus->ifs[1].lcyl = val;
|
||||
break;
|
||||
case 5:
|
||||
case ATA_IOPORT_WR_CYLINDER_HIGH:
|
||||
ide_clear_hob(bus);
|
||||
bus->ifs[0].hob_hcyl = bus->ifs[0].hcyl;
|
||||
bus->ifs[1].hob_hcyl = bus->ifs[1].hcyl;
|
||||
bus->ifs[0].hcyl = val;
|
||||
bus->ifs[1].hcyl = val;
|
||||
break;
|
||||
case 6:
|
||||
case ATA_IOPORT_WR_DEVICE_HEAD:
|
||||
/* FIXME: HOB readback uses bit 7 */
|
||||
bus->ifs[0].select = (val & ~0x10) | 0xa0;
|
||||
bus->ifs[1].select = (val | 0x10) | 0xa0;
|
||||
@@ -1252,7 +1282,7 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
bus->unit = (val >> 4) & 1;
|
||||
break;
|
||||
default:
|
||||
case 7:
|
||||
case ATA_IOPORT_WR_COMMAND:
|
||||
/* command */
|
||||
ide_exec_cmd(bus, val);
|
||||
break;
|
||||
@@ -1261,9 +1291,7 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
|
||||
static void ide_reset(IDEState *s)
|
||||
{
|
||||
#ifdef DEBUG_IDE
|
||||
printf("ide: reset\n");
|
||||
#endif
|
||||
trace_ide_reset(s);
|
||||
|
||||
if (s->pio_aiocb) {
|
||||
blk_aio_cancel(s->pio_aiocb);
|
||||
@@ -2021,10 +2049,9 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
|
||||
IDEState *s;
|
||||
bool complete;
|
||||
|
||||
#if defined(DEBUG_IDE)
|
||||
printf("ide: CMD=%02x\n", val);
|
||||
#endif
|
||||
s = idebus_active_if(bus);
|
||||
trace_ide_exec_cmd(bus, s, val);
|
||||
|
||||
/* ignore commands to non existent slave */
|
||||
if (s != bus->ifs && !s->blk) {
|
||||
return;
|
||||
@@ -2062,22 +2089,46 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
||||
/* IOport [R]ead [R]egisters */
|
||||
enum ATA_IOPORT_RR {
|
||||
ATA_IOPORT_RR_DATA = 0,
|
||||
ATA_IOPORT_RR_ERROR = 1,
|
||||
ATA_IOPORT_RR_SECTOR_COUNT = 2,
|
||||
ATA_IOPORT_RR_SECTOR_NUMBER = 3,
|
||||
ATA_IOPORT_RR_CYLINDER_LOW = 4,
|
||||
ATA_IOPORT_RR_CYLINDER_HIGH = 5,
|
||||
ATA_IOPORT_RR_DEVICE_HEAD = 6,
|
||||
ATA_IOPORT_RR_STATUS = 7,
|
||||
ATA_IOPORT_RR_NUM_REGISTERS,
|
||||
};
|
||||
|
||||
const char *ATA_IOPORT_RR_lookup[ATA_IOPORT_RR_NUM_REGISTERS] = {
|
||||
[ATA_IOPORT_RR_DATA] = "Data",
|
||||
[ATA_IOPORT_RR_ERROR] = "Error",
|
||||
[ATA_IOPORT_RR_SECTOR_COUNT] = "Sector Count",
|
||||
[ATA_IOPORT_RR_SECTOR_NUMBER] = "Sector Number",
|
||||
[ATA_IOPORT_RR_CYLINDER_LOW] = "Cylinder Low",
|
||||
[ATA_IOPORT_RR_CYLINDER_HIGH] = "Cylinder High",
|
||||
[ATA_IOPORT_RR_DEVICE_HEAD] = "Device/Head",
|
||||
[ATA_IOPORT_RR_STATUS] = "Status"
|
||||
};
|
||||
|
||||
uint32_t ide_ioport_read(void *opaque, uint32_t addr)
|
||||
{
|
||||
IDEBus *bus = opaque;
|
||||
IDEState *s = idebus_active_if(bus);
|
||||
uint32_t addr;
|
||||
uint32_t reg_num;
|
||||
int ret, hob;
|
||||
|
||||
addr = addr1 & 7;
|
||||
reg_num = addr & 7;
|
||||
/* FIXME: HOB readback uses bit 7, but it's always set right now */
|
||||
//hob = s->select & (1 << 7);
|
||||
hob = 0;
|
||||
switch(addr) {
|
||||
case 0:
|
||||
switch (reg_num) {
|
||||
case ATA_IOPORT_RR_DATA:
|
||||
ret = 0xff;
|
||||
break;
|
||||
case 1:
|
||||
case ATA_IOPORT_RR_ERROR:
|
||||
if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
|
||||
(s != bus->ifs && !s->blk)) {
|
||||
ret = 0;
|
||||
@@ -2087,7 +2138,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
||||
ret = s->hob_feature;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case ATA_IOPORT_RR_SECTOR_COUNT:
|
||||
if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
|
||||
ret = 0;
|
||||
} else if (!hob) {
|
||||
@@ -2096,7 +2147,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
||||
ret = s->hob_nsector;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case ATA_IOPORT_RR_SECTOR_NUMBER:
|
||||
if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
|
||||
ret = 0;
|
||||
} else if (!hob) {
|
||||
@@ -2105,7 +2156,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
||||
ret = s->hob_sector;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case ATA_IOPORT_RR_CYLINDER_LOW:
|
||||
if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
|
||||
ret = 0;
|
||||
} else if (!hob) {
|
||||
@@ -2114,7 +2165,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
||||
ret = s->hob_lcyl;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case ATA_IOPORT_RR_CYLINDER_HIGH:
|
||||
if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
|
||||
ret = 0;
|
||||
} else if (!hob) {
|
||||
@@ -2123,7 +2174,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
||||
ret = s->hob_hcyl;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
case ATA_IOPORT_RR_DEVICE_HEAD:
|
||||
if (!bus->ifs[0].blk && !bus->ifs[1].blk) {
|
||||
ret = 0;
|
||||
} else {
|
||||
@@ -2131,7 +2182,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case 7:
|
||||
case ATA_IOPORT_RR_STATUS:
|
||||
if ((!bus->ifs[0].blk && !bus->ifs[1].blk) ||
|
||||
(s != bus->ifs && !s->blk)) {
|
||||
ret = 0;
|
||||
@@ -2141,9 +2192,8 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
|
||||
qemu_irq_lower(bus->irq);
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_IDE
|
||||
printf("ide: read addr=0x%x val=%02x\n", addr1, ret);
|
||||
#endif
|
||||
|
||||
trace_ide_ioport_read(addr, ATA_IOPORT_RR_lookup[reg_num], ret, bus, s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2159,9 +2209,8 @@ uint32_t ide_status_read(void *opaque, uint32_t addr)
|
||||
} else {
|
||||
ret = s->status;
|
||||
}
|
||||
#ifdef DEBUG_IDE
|
||||
printf("ide: read status addr=0x%x val=%02x\n", addr, ret);
|
||||
#endif
|
||||
|
||||
trace_ide_status_read(addr, ret, bus, s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2171,9 +2220,8 @@ void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
IDEState *s;
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG_IDE
|
||||
printf("ide: write control addr=0x%x val=%02x\n", addr, val);
|
||||
#endif
|
||||
trace_ide_cmd_write(addr, val, bus);
|
||||
|
||||
/* common for both drives */
|
||||
if (!(bus->cmd & IDE_CMD_RESET) &&
|
||||
(val & IDE_CMD_RESET)) {
|
||||
@@ -2224,6 +2272,8 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
IDEState *s = idebus_active_if(bus);
|
||||
uint8_t *p;
|
||||
|
||||
trace_ide_data_writew(addr, val, bus, s);
|
||||
|
||||
/* PIO data access allowed only when DRQ bit is set. The result of a write
|
||||
* during PIO out is indeterminate, just ignore it. */
|
||||
if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
|
||||
@@ -2269,6 +2319,8 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
|
||||
trace_ide_data_readw(addr, ret, bus, s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2278,6 +2330,8 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
IDEState *s = idebus_active_if(bus);
|
||||
uint8_t *p;
|
||||
|
||||
trace_ide_data_writel(addr, val, bus, s);
|
||||
|
||||
/* PIO data access allowed only when DRQ bit is set. The result of a write
|
||||
* during PIO out is indeterminate, just ignore it. */
|
||||
if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
|
||||
@@ -2308,7 +2362,8 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
||||
/* PIO data access allowed only when DRQ bit is set. The result of a read
|
||||
* during PIO in is indeterminate, return 0 and don't move forward. */
|
||||
if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
@@ -2323,6 +2378,9 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
|
||||
out:
|
||||
trace_ide_data_readl(addr, ret, bus, s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2346,9 +2404,7 @@ void ide_bus_reset(IDEBus *bus)
|
||||
|
||||
/* pending async DMA */
|
||||
if (bus->dma->aiocb) {
|
||||
#ifdef DEBUG_AIO
|
||||
printf("aio_cancel\n");
|
||||
#endif
|
||||
trace_ide_bus_reset_aio();
|
||||
blk_aio_cancel(bus->dma->aiocb);
|
||||
bus->dma->aiocb = NULL;
|
||||
}
|
||||
@@ -2406,7 +2462,7 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
|
||||
const char *version, const char *serial, const char *model,
|
||||
uint64_t wwn,
|
||||
uint32_t cylinders, uint32_t heads, uint32_t secs,
|
||||
int chs_trans)
|
||||
int chs_trans, Error **errp)
|
||||
{
|
||||
uint64_t nb_sectors;
|
||||
|
||||
@@ -2431,11 +2487,11 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
|
||||
blk_set_guest_block_size(blk, 2048);
|
||||
} else {
|
||||
if (!blk_is_inserted(s->blk)) {
|
||||
error_report("Device needs media, but drive is empty");
|
||||
error_setg(errp, "Device needs media, but drive is empty");
|
||||
return -1;
|
||||
}
|
||||
if (blk_is_read_only(blk)) {
|
||||
error_report("Can't use a read-only drive");
|
||||
error_setg(errp, "Can't use a read-only drive");
|
||||
return -1;
|
||||
}
|
||||
blk_set_dev_ops(blk, &ide_hd_block_ops, s);
|
||||
|
||||
@@ -575,12 +575,15 @@ PCMCIACardState *dscm1xxxx_init(DriveInfo *dinfo)
|
||||
static void dscm1xxxx_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc);
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
pcc->cis = dscm1xxxx_cis;
|
||||
pcc->cis_len = sizeof(dscm1xxxx_cis);
|
||||
|
||||
pcc->attach = dscm1xxxx_attach;
|
||||
pcc->detach = dscm1xxxx_detach;
|
||||
/* Reason: Needs to be wired-up in code, see dscm1xxxx_init() */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo dscm1xxxx_type_info = {
|
||||
|
||||
17
hw/ide/pci.c
17
hw/ide/pci.c
@@ -31,6 +31,7 @@
|
||||
#include "sysemu/dma.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/ide/pci.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define BMDMA_PAGE_SIZE 4096
|
||||
|
||||
@@ -196,9 +197,7 @@ static void bmdma_reset(IDEDMA *dma)
|
||||
{
|
||||
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
|
||||
|
||||
#ifdef DEBUG_IDE
|
||||
printf("ide: dma_reset\n");
|
||||
#endif
|
||||
trace_bmdma_reset();
|
||||
bmdma_cancel(bm);
|
||||
bm->cmd = 0;
|
||||
bm->status = 0;
|
||||
@@ -227,9 +226,7 @@ static void bmdma_irq(void *opaque, int n, int level)
|
||||
|
||||
void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
|
||||
{
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: 0x%08x\n", __func__, val);
|
||||
#endif
|
||||
trace_bmdma_cmd_writeb(val);
|
||||
|
||||
/* Ignore writes to SSBM if it keeps the old value */
|
||||
if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
|
||||
@@ -258,9 +255,7 @@ static uint64_t bmdma_addr_read(void *opaque, hwaddr addr,
|
||||
uint64_t data;
|
||||
|
||||
data = (bm->addr >> (addr * 8)) & mask;
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: 0x%08x\n", __func__, (unsigned)data);
|
||||
#endif
|
||||
trace_bmdma_addr_read(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -271,9 +266,7 @@ static void bmdma_addr_write(void *opaque, hwaddr addr,
|
||||
int shift = addr * 8;
|
||||
uint32_t mask = (1ULL << (width * 8)) - 1;
|
||||
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: 0x%08x\n", __func__, (unsigned)data);
|
||||
#endif
|
||||
trace_bmdma_addr_write(data);
|
||||
bm->addr &= ~(mask << shift);
|
||||
bm->addr |= ((data & mask) << shift) & ~3;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
#include "hw/ide/pci.h"
|
||||
#include "trace.h"
|
||||
|
||||
static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
@@ -54,9 +55,8 @@ static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size)
|
||||
val = 0xff;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_IDE
|
||||
printf("bmdma: readb 0x%02x : 0x%02x\n", (uint8_t)addr, val);
|
||||
#endif
|
||||
|
||||
trace_bmdma_read(addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -69,9 +69,8 @@ static void bmdma_write(void *opaque, hwaddr addr,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IDE
|
||||
printf("bmdma: writeb 0x%02x : 0x%02x\n", (uint8_t)addr, (uint8_t)val);
|
||||
#endif
|
||||
trace_bmdma_write(addr, val);
|
||||
|
||||
switch(addr & 3) {
|
||||
case 0:
|
||||
bmdma_cmd_writeb(bm, val);
|
||||
|
||||
@@ -80,7 +80,7 @@ static char *idebus_get_fw_dev_path(DeviceState *dev)
|
||||
return g_strdup(path);
|
||||
}
|
||||
|
||||
static int ide_qdev_init(DeviceState *qdev)
|
||||
static void ide_qdev_realize(DeviceState *qdev, Error **errp)
|
||||
{
|
||||
IDEDevice *dev = IDE_DEVICE(qdev);
|
||||
IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
|
||||
@@ -91,34 +91,31 @@ static int ide_qdev_init(DeviceState *qdev)
|
||||
}
|
||||
|
||||
if (dev->unit >= bus->max_units) {
|
||||
error_report("Can't create IDE unit %d, bus supports only %d units",
|
||||
error_setg(errp, "Can't create IDE unit %d, bus supports only %d units",
|
||||
dev->unit, bus->max_units);
|
||||
goto err;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev->unit) {
|
||||
case 0:
|
||||
if (bus->master) {
|
||||
error_report("IDE unit %d is in use", dev->unit);
|
||||
goto err;
|
||||
error_setg(errp, "IDE unit %d is in use", dev->unit);
|
||||
return;
|
||||
}
|
||||
bus->master = dev;
|
||||
break;
|
||||
case 1:
|
||||
if (bus->slave) {
|
||||
error_report("IDE unit %d is in use", dev->unit);
|
||||
goto err;
|
||||
error_setg(errp, "IDE unit %d is in use", dev->unit);
|
||||
return;
|
||||
}
|
||||
bus->slave = dev;
|
||||
break;
|
||||
default:
|
||||
error_report("Invalid IDE unit %d", dev->unit);
|
||||
goto err;
|
||||
error_setg(errp, "Invalid IDE unit %d", dev->unit);
|
||||
return;
|
||||
}
|
||||
return dc->init(dev);
|
||||
|
||||
err:
|
||||
return -1;
|
||||
dc->realize(dev, errp);
|
||||
}
|
||||
|
||||
IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
|
||||
@@ -159,7 +156,7 @@ typedef struct IDEDrive {
|
||||
IDEDevice dev;
|
||||
} IDEDrive;
|
||||
|
||||
static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
|
||||
static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
|
||||
{
|
||||
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
|
||||
IDEState *s = bus->ifs + dev->unit;
|
||||
@@ -168,8 +165,8 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
|
||||
|
||||
if (!dev->conf.blk) {
|
||||
if (kind != IDE_CD) {
|
||||
error_report("No drive specified");
|
||||
return -1;
|
||||
error_setg(errp, "No drive specified");
|
||||
return;
|
||||
} else {
|
||||
/* Anonymous BlockBackend for an empty drive */
|
||||
dev->conf.blk = blk_new(0, BLK_PERM_ALL);
|
||||
@@ -182,36 +179,36 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
|
||||
dev->conf.discard_granularity = 512;
|
||||
} else if (dev->conf.discard_granularity &&
|
||||
dev->conf.discard_granularity != 512) {
|
||||
error_report("discard_granularity must be 512 for ide");
|
||||
return -1;
|
||||
error_setg(errp, "discard_granularity must be 512 for ide");
|
||||
return;
|
||||
}
|
||||
|
||||
blkconf_blocksizes(&dev->conf);
|
||||
if (dev->conf.logical_block_size != 512) {
|
||||
error_report("logical_block_size must be 512 for IDE");
|
||||
return -1;
|
||||
error_setg(errp, "logical_block_size must be 512 for IDE");
|
||||
return;
|
||||
}
|
||||
|
||||
blkconf_serial(&dev->conf, &dev->serial);
|
||||
if (kind != IDE_CD) {
|
||||
blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255, &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
return -1;
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
blkconf_apply_backend_options(&dev->conf, kind == IDE_CD, kind != IDE_CD,
|
||||
&err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
return -1;
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ide_init_drive(s, dev->conf.blk, kind,
|
||||
dev->version, dev->serial, dev->model, dev->wwn,
|
||||
dev->conf.cyls, dev->conf.heads, dev->conf.secs,
|
||||
dev->chs_trans) < 0) {
|
||||
return -1;
|
||||
dev->chs_trans, errp) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev->version) {
|
||||
@@ -223,8 +220,6 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
|
||||
|
||||
add_boot_device_path(dev->conf.bootindex, &dev->qdev,
|
||||
dev->unit ? "/disk@1" : "/disk@0");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ide_dev_get_bootindex(Object *obj, Visitor *v, const char *name,
|
||||
@@ -270,17 +265,17 @@ static void ide_dev_instance_init(Object *obj)
|
||||
object_property_set_int(obj, -1, "bootindex", NULL);
|
||||
}
|
||||
|
||||
static int ide_hd_initfn(IDEDevice *dev)
|
||||
static void ide_hd_realize(IDEDevice *dev, Error **errp)
|
||||
{
|
||||
return ide_dev_initfn(dev, IDE_HD);
|
||||
ide_dev_initfn(dev, IDE_HD, errp);
|
||||
}
|
||||
|
||||
static int ide_cd_initfn(IDEDevice *dev)
|
||||
static void ide_cd_realize(IDEDevice *dev, Error **errp)
|
||||
{
|
||||
return ide_dev_initfn(dev, IDE_CD);
|
||||
ide_dev_initfn(dev, IDE_CD, errp);
|
||||
}
|
||||
|
||||
static int ide_drive_initfn(IDEDevice *dev)
|
||||
static void ide_drive_realize(IDEDevice *dev, Error **errp)
|
||||
{
|
||||
DriveInfo *dinfo = NULL;
|
||||
|
||||
@@ -288,7 +283,7 @@ static int ide_drive_initfn(IDEDevice *dev)
|
||||
dinfo = blk_legacy_dinfo(dev->conf.blk);
|
||||
}
|
||||
|
||||
return ide_dev_initfn(dev, dinfo && dinfo->media_cd ? IDE_CD : IDE_HD);
|
||||
ide_dev_initfn(dev, dinfo && dinfo->media_cd ? IDE_CD : IDE_HD, errp);
|
||||
}
|
||||
|
||||
#define DEFINE_IDE_DEV_PROPERTIES() \
|
||||
@@ -311,10 +306,11 @@ static void ide_hd_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
|
||||
k->init = ide_hd_initfn;
|
||||
|
||||
k->realize = ide_hd_realize;
|
||||
dc->fw_name = "drive";
|
||||
dc->desc = "virtual IDE disk";
|
||||
dc->props = ide_hd_properties;
|
||||
dc->desc = "virtual IDE disk";
|
||||
dc->props = ide_hd_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo ide_hd_info = {
|
||||
@@ -333,10 +329,11 @@ static void ide_cd_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
|
||||
k->init = ide_cd_initfn;
|
||||
|
||||
k->realize = ide_cd_realize;
|
||||
dc->fw_name = "drive";
|
||||
dc->desc = "virtual IDE CD-ROM";
|
||||
dc->props = ide_cd_properties;
|
||||
dc->desc = "virtual IDE CD-ROM";
|
||||
dc->props = ide_cd_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo ide_cd_info = {
|
||||
@@ -355,10 +352,11 @@ static void ide_drive_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
|
||||
k->init = ide_drive_initfn;
|
||||
|
||||
k->realize = ide_drive_realize;
|
||||
dc->fw_name = "drive";
|
||||
dc->desc = "virtual IDE disk or CD-ROM (legacy)";
|
||||
dc->props = ide_drive_properties;
|
||||
dc->desc = "virtual IDE disk or CD-ROM (legacy)";
|
||||
dc->props = ide_drive_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo ide_drive_info = {
|
||||
@@ -371,7 +369,7 @@ static const TypeInfo ide_drive_info = {
|
||||
static void ide_device_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *k = DEVICE_CLASS(klass);
|
||||
k->init = ide_qdev_init;
|
||||
k->realize = ide_qdev_realize;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
|
||||
k->bus_type = TYPE_IDE_BUS;
|
||||
k->props = ide_props;
|
||||
|
||||
111
hw/ide/trace-events
Normal file
111
hw/ide/trace-events
Normal file
@@ -0,0 +1,111 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# hw/ide/core.c
|
||||
# portio
|
||||
ide_ioport_read(uint32_t addr, const char *reg, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (%s); val 0x%02"PRIx32"; bus %p IDEState %p"
|
||||
ide_ioport_write(uint32_t addr, const char *reg, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (%s); val 0x%02"PRIx32"; bus %p IDEState %p"
|
||||
ide_status_read(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Alt Status); val 0x%02"PRIx32"; bus %p; IDEState %p"
|
||||
ide_cmd_write(uint32_t addr, uint32_t val, void *bus) "IDE PIO wr @ 0x%"PRIx32" (Device Control); val 0x%02"PRIx32"; bus %p"
|
||||
# Warning: verbose
|
||||
ide_data_readw(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Data: Word); val 0x%04"PRIx32"; bus %p; IDEState %p"
|
||||
ide_data_writew(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (Data: Word); val 0x%04"PRIx32"; bus %p; IDEState %p"
|
||||
ide_data_readl(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Data: Long); val 0x%08"PRIx32"; bus %p; IDEState %p"
|
||||
ide_data_writel(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (Data: Long); val 0x%08"PRIx32"; bus %p; IDEState %p"
|
||||
# misc
|
||||
ide_exec_cmd(void *bus, void *state, uint32_t cmd) "IDE exec cmd: bus %p; state %p; cmd 0x%02x"
|
||||
ide_cancel_dma_sync_buffered(void *fn, void *req) "invoking cb %p of buffered request %p with -ECANCELED"
|
||||
ide_cancel_dma_sync_remaining(void) "draining all remaining requests"
|
||||
ide_sector_read(int64_t sector_num, int nsectors) "sector=%"PRId64" nsectors=%d"
|
||||
ide_sector_write(int64_t sector_num, int nsectors) "sector=%"PRId64" nsectors=%d"
|
||||
ide_reset(void *s) "IDEstate %p"
|
||||
ide_bus_reset_aio(void) "aio_cancel"
|
||||
ide_dma_cb(void *s, int64_t sector_num, int n, const char *dma) "IDEState %p; sector_num=%"PRId64" n=%d cmd=%s"
|
||||
|
||||
# BMDMA HBAs:
|
||||
|
||||
# hw/ide/cmd646.c
|
||||
bmdma_read_cmd646(uint64_t addr, uint32_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x"
|
||||
bmdma_write_cmd646(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64
|
||||
|
||||
# hw/ide/pci.c
|
||||
bmdma_reset(void) ""
|
||||
bmdma_cmd_writeb(uint32_t val) "val: 0x%08x"
|
||||
bmdma_addr_read(uint64_t data) "data: 0x%016"PRIx64
|
||||
bmdma_addr_write(uint64_t data) "data: 0x%016"PRIx64
|
||||
|
||||
# hw/ide/piix.c
|
||||
bmdma_read(uint64_t addr, uint8_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x"
|
||||
bmdma_write(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64
|
||||
|
||||
# hw/ide/via.c
|
||||
bmdma_read_via(uint64_t addr, uint32_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x"
|
||||
bmdma_write_via(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64
|
||||
|
||||
# hw/ide/atapi.c
|
||||
cd_read_sector_sync(int lba) "lba=%d"
|
||||
cd_read_sector_cb(int lba, int ret) "lba=%d ret=%d"
|
||||
cd_read_sector(int lba) "lba=%d"
|
||||
ide_atapi_cmd_error(void *s, int sense_key, int asc) "IDEState: %p; sense=0x%x asc=0x%x"
|
||||
ide_atapi_cmd_reply_end(void *s, int tx_size, int elem_tx_size, int32_t index) "IDEState %p; reply: tx_size=%d elem_tx_size=%d index=%"PRId32
|
||||
ide_atapi_cmd_reply_end_eot(void *s, int status) "IDEState: %p; end of transfer, status=0x%x"
|
||||
ide_atapi_cmd_reply_end_bcl(void *s, int bcl) "IDEState: %p; byte_count_limit=%d"
|
||||
ide_atapi_cmd_reply_end_new(void *s, int status) "IDEState: %p; new transfer started, status=0x%x"
|
||||
ide_atapi_cmd_check_status(void *s) "IDEState: %p"
|
||||
ide_atapi_cmd_read(void *s, const char *method, int lba, int nb_sectors) "IDEState: %p; read %s: LBA=%d nb_sectors=%d"
|
||||
ide_atapi_cmd(void *s, uint8_t cmd) "IDEState: %p; cmd: 0x%02x"
|
||||
ide_atapi_cmd_read_dma_cb_aio(void *s, int lba, int n) "IDEState: %p; aio read: lba=%d n=%d"
|
||||
# Warning: Verbose
|
||||
ide_atapi_cmd_packet(void *s, uint16_t limit, const char *packet) "IDEState: %p; limit=0x%x packet: %s"
|
||||
|
||||
# hw/ide/ahci.c
|
||||
ahci_port_read(void *s, int port, int offset, uint32_t ret) "ahci(%p)[%d]: port read @ 0x%x: 0x%08x"
|
||||
ahci_irq_raise(void *s) "ahci(%p): raise irq"
|
||||
ahci_irq_lower(void *s) "ahci(%p): lower irq"
|
||||
ahci_check_irq(void *s, uint32_t old, uint32_t new) "ahci(%p): check irq 0x%08x --> 0x%08x"
|
||||
ahci_trigger_irq(void *s, int port, const char *name, uint32_t val, uint32_t old, uint32_t new, uint32_t effective) "ahci(%p)[%d]: trigger irq +%s (0x%08x); irqstat: 0x%08x --> 0x%08x; effective: 0x%08x"
|
||||
ahci_port_write(void *s, int port, int offset, uint32_t val) "ahci(%p)[%d]: port write @ 0x%x: 0x%08x"
|
||||
ahci_mem_read_32(void *s, uint64_t addr, uint32_t val) "ahci(%p): mem read @ 0x%"PRIx64": 0x%08x"
|
||||
ahci_mem_read(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): read%u @ 0x%"PRIx64": 0x%016"PRIx64
|
||||
ahci_mem_write(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u @ 0x%"PRIx64": 0x%016"PRIx64
|
||||
ahci_mem_write_unknown(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u to unknown register 0x%"PRIx64": 0x%016"PRIx64
|
||||
ahci_set_signature(void *s, int port, uint8_t nsector, uint8_t sector, uint8_t lcyl, uint8_t hcyl, uint32_t sig) "ahci(%p)[%d]: set signature sector:0x%02x nsector:0x%02x lcyl:0x%02x hcyl:0x%02x (cumulatively: 0x%08x)"
|
||||
ahci_reset_port(void *s, int port) "ahci(%p)[%d]: reset port"
|
||||
ahci_unmap_fis_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL FIS address"
|
||||
ahci_unmap_clb_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL CLB address"
|
||||
ahci_populate_sglist(void *s, int port) "ahci(%p)[%d]"
|
||||
ahci_populate_sglist_no_prdtl(void *s, int port, uint16_t opts) "ahci(%p)[%d]: no sg list given by guest: 0x%04x"
|
||||
ahci_populate_sglist_no_map(void *s, int port) "ahci(%p)[%d]: DMA mapping failed"
|
||||
ahci_populate_sglist_short_map(void *s, int port) "ahci(%p)[%d]: mapped less than expected"
|
||||
ahci_populate_sglist_bad_offset(void *s, int port, int off_idx, int64_t off_pos) "ahci(%p)[%d]: Incorrect offset! off_idx: %d, off_pos: %"PRId64
|
||||
ncq_finish(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: NCQ transfer finished"
|
||||
execute_ncq_command_read(void *s, int port, uint8_t tag, int count, int64_t lba) "ahci(%p)[%d][tag:%d]: NCQ reading %d sectors from LBA %"PRId64
|
||||
execute_ncq_command_write(void *s, int port, uint8_t tag, int count, int64_t lba) "ahci(%p)[%d][tag:%d]: NCQ writing %d sectors to LBA %"PRId64
|
||||
execute_ncq_command_unsup(void *s, int port, uint8_t tag, uint8_t cmd) "ahci(%p)[%d][tag:%d]: error: unsupported NCQ command (0x%02x) received"
|
||||
process_ncq_command_mismatch(void *s, int port, uint8_t tag, uint8_t slot) "ahci(%p)[%d][tag:%d]: Warning: NCQ slot (%d) did not match the given tag"
|
||||
process_ncq_command_aux(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: Warn: Attempt to use NCQ auxiliary fields"
|
||||
process_ncq_command_prioicc(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: Warn: Unsupported attempt to use PRIO/ICC fields"
|
||||
process_ncq_command_fua(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: Warn: Unsupported attempt to use Force Unit Access"
|
||||
process_ncq_command_rarc(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: Warn: Unsupported attempt to use Rebuild Assist"
|
||||
process_ncq_command_large(void *s, int port, uint8_t tag, size_t prdtl, size_t size) "ahci(%p)[%d][tag:%d]: Warn: PRDTL (0x%zx) does not match requested size (0x%zx)"
|
||||
process_ncq_command(void *s, int port, uint8_t tag, uint8_t cmd, uint64_t lba, uint64_t end) "ahci(%p)[%d][tag:%d]: NCQ op 0x%02x on sectors [%"PRId64",%"PRId64"]"
|
||||
handle_reg_h2d_fis_pmp(void *s, int port, char b0, char b1, char b2) "ahci(%p)[%d]: Port Multiplier not supported, FIS: 0x%02x-%02x-%02x"
|
||||
handle_reg_h2d_fis_res(void *s, int port, char b0, char b1, char b2) "ahci(%p)[%d]: Reserved flags set in H2D Register FIS, FIS: 0x%02x-%02x-%02x"
|
||||
handle_cmd_busy(void *s, int port) "ahci(%p)[%d]: engine busy"
|
||||
handle_cmd_nolist(void *s, int port) "ahci(%p)[%d]: handle_cmd called without s->dev[port].lst"
|
||||
handle_cmd_badport(void *s, int port) "ahci(%p)[%d]: guest accessed unused port"
|
||||
handle_cmd_badfis(void *s, int port) "ahci(%p)[%d]: guest provided an invalid cmd FIS"
|
||||
handle_cmd_badmap(void *s, int port, uint64_t len) "ahci(%p)[%d]: dma_memory_map failed, 0x%02"PRIx64" != 0x80"
|
||||
handle_cmd_unhandled_fis(void *s, int port, uint8_t b0, uint8_t b1, uint8_t b2) "ahci(%p)[%d]: unhandled FIS type. cmd_fis: 0x%02x-%02x-%02x"
|
||||
ahci_start_transfer(void *s, int port, const char *rw, uint32_t size, const char *tgt, const char *sgl) "ahci(%p)[%d]: %sing %d bytes on %s w/%s sglist"
|
||||
ahci_start_dma(void *s, int port) "ahci(%p)[%d]: start dma"
|
||||
ahci_dma_prepare_buf(void *s, int port, int32_t io_buffer_size, int32_t limit) "ahci(%p)[%d]: prepare buf limit=%"PRId32" prepared=%"PRId32
|
||||
ahci_dma_prepare_buf_fail(void *s, int port) "ahci(%p)[%d]: sglist population failed"
|
||||
ahci_dma_rw_buf(void *s, int port, int l) "ahci(%p)[%d] len=0x%x"
|
||||
ahci_cmd_done(void *s, int port) "ahci(%p)[%d]: cmd done"
|
||||
ahci_reset(void *s) "ahci(%p): HBA reset"
|
||||
allwinner_ahci_mem_read(void *s, void *a, uint64_t addr, uint64_t val, unsigned size) "ahci(%p): read a=%p addr=0x%"HWADDR_PRIx" val=0x%"PRIx64", size=%d"
|
||||
allwinner_ahci_mem_write(void *s, void *a, uint64_t addr, uint64_t val, unsigned size) "ahci(%p): write a=%p addr=0x%"HWADDR_PRIx" val=0x%"PRIx64", size=%d"
|
||||
|
||||
# Warning: Verbose
|
||||
handle_reg_h2d_fis_dump(void *s, int port, const char *fis) "ahci(%p)[%d]: %s"
|
||||
handle_cmd_fis_dump(void *s, int port, const char *fis) "ahci(%p)[%d]: %s"
|
||||
10
hw/ide/via.c
10
hw/ide/via.c
@@ -33,6 +33,7 @@
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
#include "hw/ide/pci.h"
|
||||
#include "trace.h"
|
||||
|
||||
static uint64_t bmdma_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
@@ -55,9 +56,8 @@ static uint64_t bmdma_read(void *opaque, hwaddr addr,
|
||||
val = 0xff;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_IDE
|
||||
printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
|
||||
#endif
|
||||
|
||||
trace_bmdma_read_via(addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -70,9 +70,7 @@ static void bmdma_write(void *opaque, hwaddr addr,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IDE
|
||||
printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
|
||||
#endif
|
||||
trace_bmdma_write_via(addr, val);
|
||||
switch (addr & 3) {
|
||||
case 0:
|
||||
bmdma_cmd_writeb(bm, val);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
obj-y += mips_r4k.o mips_malta.o mips_mipssim.o
|
||||
obj-y += addr.o cputimer.o mips_int.o
|
||||
obj-y += addr.o mips_int.o
|
||||
obj-$(CONFIG_JAZZ) += mips_jazz.o
|
||||
obj-$(CONFIG_FULONG) += mips_fulong2e.o
|
||||
obj-y += gt64xxx_pci.o
|
||||
|
||||
@@ -71,7 +71,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
|
||||
bool itu_present = false;
|
||||
|
||||
for (i = 0; i < s->num_vp; i++) {
|
||||
cpu = cpu_mips_init(s->cpu_model);
|
||||
cpu = MIPS_CPU(cpu_generic_init(TYPE_MIPS_CPU, s->cpu_model));
|
||||
|
||||
/* Init internal devices */
|
||||
cpu_mips_irq_init_cpu(cpu);
|
||||
|
||||
@@ -280,7 +280,7 @@ static void mips_fulong2e_init(MachineState *machine)
|
||||
if (cpu_model == NULL) {
|
||||
cpu_model = "Loongson-2E";
|
||||
}
|
||||
cpu = cpu_mips_init(cpu_model);
|
||||
cpu = MIPS_CPU(cpu_generic_init(TYPE_MIPS_CPU, cpu_model));
|
||||
env = &cpu->env;
|
||||
|
||||
qemu_register_reset(main_cpu_reset, cpu);
|
||||
|
||||
@@ -151,7 +151,7 @@ static void mips_jazz_init(MachineState *machine,
|
||||
if (cpu_model == NULL) {
|
||||
cpu_model = "R4000";
|
||||
}
|
||||
cpu = cpu_mips_init(cpu_model);
|
||||
cpu = MIPS_CPU(cpu_generic_init(TYPE_MIPS_CPU, cpu_model));
|
||||
env = &cpu->env;
|
||||
qemu_register_reset(main_cpu_reset, cpu);
|
||||
|
||||
|
||||
@@ -216,8 +216,8 @@ static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
|
||||
}
|
||||
|
||||
if (ram_size) {
|
||||
fprintf(stderr, "Warning: SPD cannot represent final %dMB"
|
||||
" of SDRAM\n", (int)ram_size);
|
||||
warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB"
|
||||
" of SDRAM", ram_size);
|
||||
}
|
||||
|
||||
/* fill in SPD memory information */
|
||||
@@ -931,7 +931,7 @@ static void create_cpu_without_cps(const char *cpu_model,
|
||||
int i;
|
||||
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
cpu = cpu_mips_init(cpu_model);
|
||||
cpu = MIPS_CPU(cpu_generic_init(TYPE_MIPS_CPU, cpu_model));
|
||||
|
||||
/* Init internal devices */
|
||||
cpu_mips_irq_init_cpu(cpu);
|
||||
|
||||
@@ -163,7 +163,7 @@ mips_mipssim_init(MachineState *machine)
|
||||
cpu_model = "24Kf";
|
||||
#endif
|
||||
}
|
||||
cpu = cpu_mips_init(cpu_model);
|
||||
cpu = MIPS_CPU(cpu_generic_init(TYPE_MIPS_CPU, cpu_model));
|
||||
env = &cpu->env;
|
||||
|
||||
reset_info = g_malloc0(sizeof(ResetData));
|
||||
|
||||
@@ -193,7 +193,7 @@ void mips_r4k_init(MachineState *machine)
|
||||
cpu_model = "24Kf";
|
||||
#endif
|
||||
}
|
||||
cpu = cpu_mips_init(cpu_model);
|
||||
cpu = MIPS_CPU(cpu_generic_init(TYPE_MIPS_CPU, cpu_model));
|
||||
env = &cpu->env;
|
||||
|
||||
reset_info = g_malloc0(sizeof(ResetData));
|
||||
@@ -249,9 +249,8 @@ void mips_r4k_init(MachineState *machine)
|
||||
fprintf(stderr, "qemu: Error registering flash memory.\n");
|
||||
}
|
||||
} else if (!qtest_enabled()) {
|
||||
/* not fatal */
|
||||
fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
|
||||
bios_name);
|
||||
/* not fatal */
|
||||
warn_report("could not load MIPS bios '%s'", bios_name);
|
||||
}
|
||||
g_free(filename);
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp)
|
||||
s->iobase + APPLESMC_ERR_PORT);
|
||||
|
||||
if (!s->osk || (strlen(s->osk) != 64)) {
|
||||
fprintf(stderr, "WARNING: Using AppleSMC with invalid key\n");
|
||||
warn_report("Using AppleSMC with invalid key");
|
||||
s->osk = default_osk;
|
||||
}
|
||||
|
||||
|
||||
@@ -653,7 +653,7 @@ static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
|
||||
} while (n < sizeof(msg));
|
||||
|
||||
*pfd = qemu_chr_fe_get_msgfd(&s->server_chr);
|
||||
return msg;
|
||||
return le64_to_cpu(msg);
|
||||
}
|
||||
|
||||
static void ivshmem_recv_setup(IVShmemState *s, Error **errp)
|
||||
|
||||
@@ -26,6 +26,7 @@ common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
|
||||
common-obj-$(CONFIG_CADENCE) += cadence_gem.o
|
||||
common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
|
||||
common-obj-$(CONFIG_LANCE) += lance.o
|
||||
common-obj-$(CONFIG_SUNHME) += sunhme.o
|
||||
common-obj-$(CONFIG_FTGMAC100) += ftgmac100.o
|
||||
common-obj-$(CONFIG_SUNGEM) += sungem.o
|
||||
|
||||
|
||||
978
hw/net/sunhme.c
Normal file
978
hw/net/sunhme.c
Normal file
@@ -0,0 +1,978 @@
|
||||
/*
|
||||
* QEMU Sun Happy Meal Ethernet emulation
|
||||
*
|
||||
* Copyright (c) 2017 Mark Cave-Ayland
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/net/mii.h"
|
||||
#include "net/net.h"
|
||||
#include "net/checksum.h"
|
||||
#include "net/eth.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define HME_REG_SIZE 0x8000
|
||||
|
||||
#define HME_SEB_REG_SIZE 0x2000
|
||||
|
||||
#define HME_SEBI_RESET 0x0
|
||||
#define HME_SEB_RESET_ETX 0x1
|
||||
#define HME_SEB_RESET_ERX 0x2
|
||||
|
||||
#define HME_SEBI_STAT 0x100
|
||||
#define HME_SEBI_STAT_LINUXBUG 0x108
|
||||
#define HME_SEB_STAT_RXTOHOST 0x10000
|
||||
#define HME_SEB_STAT_MIFIRQ 0x800000
|
||||
#define HME_SEB_STAT_HOSTTOTX 0x1000000
|
||||
#define HME_SEB_STAT_TXALL 0x2000000
|
||||
|
||||
#define HME_SEBI_IMASK 0x104
|
||||
#define HME_SEBI_IMASK_LINUXBUG 0x10c
|
||||
|
||||
#define HME_ETX_REG_SIZE 0x2000
|
||||
|
||||
#define HME_ETXI_PENDING 0x0
|
||||
|
||||
#define HME_ETXI_RING 0x8
|
||||
#define HME_ETXI_RING_ADDR 0xffffff00
|
||||
#define HME_ETXI_RING_OFFSET 0xff
|
||||
|
||||
#define HME_ETXI_RSIZE 0x2c
|
||||
|
||||
#define HME_ERX_REG_SIZE 0x2000
|
||||
|
||||
#define HME_ERXI_CFG 0x0
|
||||
#define HME_ERX_CFG_RINGSIZE 0x600
|
||||
#define HME_ERX_CFG_RINGSIZE_SHIFT 9
|
||||
#define HME_ERX_CFG_BYTEOFFSET 0x38
|
||||
#define HME_ERX_CFG_BYTEOFFSET_SHIFT 3
|
||||
#define HME_ERX_CFG_CSUMSTART 0x7f0000
|
||||
#define HME_ERX_CFG_CSUMSHIFT 16
|
||||
|
||||
#define HME_ERXI_RING 0x4
|
||||
#define HME_ERXI_RING_ADDR 0xffffff00
|
||||
#define HME_ERXI_RING_OFFSET 0xff
|
||||
|
||||
#define HME_MAC_REG_SIZE 0x1000
|
||||
|
||||
#define HME_MACI_TXCFG 0x20c
|
||||
#define HME_MAC_TXCFG_ENABLE 0x1
|
||||
|
||||
#define HME_MACI_RXCFG 0x30c
|
||||
#define HME_MAC_RXCFG_ENABLE 0x1
|
||||
#define HME_MAC_RXCFG_PMISC 0x40
|
||||
#define HME_MAC_RXCFG_HENABLE 0x800
|
||||
|
||||
#define HME_MACI_MACADDR2 0x318
|
||||
#define HME_MACI_MACADDR1 0x31c
|
||||
#define HME_MACI_MACADDR0 0x320
|
||||
|
||||
#define HME_MACI_HASHTAB3 0x340
|
||||
#define HME_MACI_HASHTAB2 0x344
|
||||
#define HME_MACI_HASHTAB1 0x348
|
||||
#define HME_MACI_HASHTAB0 0x34c
|
||||
|
||||
#define HME_MIF_REG_SIZE 0x20
|
||||
|
||||
#define HME_MIFI_FO 0xc
|
||||
#define HME_MIF_FO_ST 0xc0000000
|
||||
#define HME_MIF_FO_ST_SHIFT 30
|
||||
#define HME_MIF_FO_OPC 0x30000000
|
||||
#define HME_MIF_FO_OPC_SHIFT 28
|
||||
#define HME_MIF_FO_PHYAD 0x0f800000
|
||||
#define HME_MIF_FO_PHYAD_SHIFT 23
|
||||
#define HME_MIF_FO_REGAD 0x007c0000
|
||||
#define HME_MIF_FO_REGAD_SHIFT 18
|
||||
#define HME_MIF_FO_TAMSB 0x20000
|
||||
#define HME_MIF_FO_TALSB 0x10000
|
||||
#define HME_MIF_FO_DATA 0xffff
|
||||
|
||||
#define HME_MIFI_CFG 0x10
|
||||
#define HME_MIF_CFG_MDI0 0x100
|
||||
#define HME_MIF_CFG_MDI1 0x200
|
||||
|
||||
#define HME_MIFI_IMASK 0x14
|
||||
|
||||
#define HME_MIFI_STAT 0x18
|
||||
|
||||
|
||||
/* Wired HME PHY addresses */
|
||||
#define HME_PHYAD_INTERNAL 1
|
||||
#define HME_PHYAD_EXTERNAL 0
|
||||
|
||||
#define MII_COMMAND_START 0x1
|
||||
#define MII_COMMAND_READ 0x2
|
||||
#define MII_COMMAND_WRITE 0x1
|
||||
|
||||
#define TYPE_SUNHME "sunhme"
|
||||
#define SUNHME(obj) OBJECT_CHECK(SunHMEState, (obj), TYPE_SUNHME)
|
||||
|
||||
/* Maximum size of buffer */
|
||||
#define HME_FIFO_SIZE 0x800
|
||||
|
||||
/* Size of TX/RX descriptor */
|
||||
#define HME_DESC_SIZE 0x8
|
||||
|
||||
#define HME_XD_OWN 0x80000000
|
||||
#define HME_XD_OFL 0x40000000
|
||||
#define HME_XD_SOP 0x40000000
|
||||
#define HME_XD_EOP 0x20000000
|
||||
#define HME_XD_RXLENMSK 0x3fff0000
|
||||
#define HME_XD_RXLENSHIFT 16
|
||||
#define HME_XD_RXCKSUM 0xffff
|
||||
#define HME_XD_TXLENMSK 0x00001fff
|
||||
#define HME_XD_TXCKSUM 0x10000000
|
||||
#define HME_XD_TXCSSTUFF 0xff00000
|
||||
#define HME_XD_TXCSSTUFFSHIFT 20
|
||||
#define HME_XD_TXCSSTART 0xfc000
|
||||
#define HME_XD_TXCSSTARTSHIFT 14
|
||||
|
||||
#define HME_MII_REGS_SIZE 0x20
|
||||
|
||||
typedef struct SunHMEState {
|
||||
/*< private >*/
|
||||
PCIDevice parent_obj;
|
||||
|
||||
NICState *nic;
|
||||
NICConf conf;
|
||||
|
||||
MemoryRegion hme;
|
||||
MemoryRegion sebreg;
|
||||
MemoryRegion etxreg;
|
||||
MemoryRegion erxreg;
|
||||
MemoryRegion macreg;
|
||||
MemoryRegion mifreg;
|
||||
|
||||
uint32_t sebregs[HME_SEB_REG_SIZE >> 2];
|
||||
uint32_t etxregs[HME_ETX_REG_SIZE >> 2];
|
||||
uint32_t erxregs[HME_ERX_REG_SIZE >> 2];
|
||||
uint32_t macregs[HME_MAC_REG_SIZE >> 2];
|
||||
uint32_t mifregs[HME_MIF_REG_SIZE >> 2];
|
||||
|
||||
uint16_t miiregs[HME_MII_REGS_SIZE];
|
||||
} SunHMEState;
|
||||
|
||||
static Property sunhme_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(SunHMEState, conf),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void sunhme_reset_tx(SunHMEState *s)
|
||||
{
|
||||
/* Indicate TX reset complete */
|
||||
s->sebregs[HME_SEBI_RESET] &= ~HME_SEB_RESET_ETX;
|
||||
}
|
||||
|
||||
static void sunhme_reset_rx(SunHMEState *s)
|
||||
{
|
||||
/* Indicate RX reset complete */
|
||||
s->sebregs[HME_SEBI_RESET] &= ~HME_SEB_RESET_ERX;
|
||||
}
|
||||
|
||||
static void sunhme_update_irq(SunHMEState *s)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(s);
|
||||
int level;
|
||||
|
||||
/* MIF interrupt mask (16-bit) */
|
||||
uint32_t mifmask = ~(s->mifregs[HME_MIFI_IMASK >> 2]) & 0xffff;
|
||||
uint32_t mif = s->mifregs[HME_MIFI_STAT >> 2] & mifmask;
|
||||
|
||||
/* Main SEB interrupt mask (include MIF status from above) */
|
||||
uint32_t sebmask = ~(s->sebregs[HME_SEBI_IMASK >> 2]) &
|
||||
~HME_SEB_STAT_MIFIRQ;
|
||||
uint32_t seb = s->sebregs[HME_SEBI_STAT >> 2] & sebmask;
|
||||
if (mif) {
|
||||
seb |= HME_SEB_STAT_MIFIRQ;
|
||||
}
|
||||
|
||||
level = (seb ? 1 : 0);
|
||||
pci_set_irq(d, level);
|
||||
}
|
||||
|
||||
static void sunhme_seb_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
|
||||
trace_sunhme_seb_write(addr, val);
|
||||
|
||||
/* Handly buggy Linux drivers before 4.13 which have
|
||||
the wrong offsets for HME_SEBI_STAT and HME_SEBI_IMASK */
|
||||
switch (addr) {
|
||||
case HME_SEBI_STAT_LINUXBUG:
|
||||
addr = HME_SEBI_STAT;
|
||||
break;
|
||||
case HME_SEBI_IMASK_LINUXBUG:
|
||||
addr = HME_SEBI_IMASK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case HME_SEBI_RESET:
|
||||
if (val & HME_SEB_RESET_ETX) {
|
||||
sunhme_reset_tx(s);
|
||||
}
|
||||
if (val & HME_SEB_RESET_ERX) {
|
||||
sunhme_reset_rx(s);
|
||||
}
|
||||
val = s->sebregs[HME_SEBI_RESET >> 2];
|
||||
break;
|
||||
}
|
||||
|
||||
s->sebregs[addr >> 2] = val;
|
||||
}
|
||||
|
||||
static uint64_t sunhme_seb_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
uint64_t val;
|
||||
|
||||
/* Handly buggy Linux drivers before 4.13 which have
|
||||
the wrong offsets for HME_SEBI_STAT and HME_SEBI_IMASK */
|
||||
switch (addr) {
|
||||
case HME_SEBI_STAT_LINUXBUG:
|
||||
addr = HME_SEBI_STAT;
|
||||
break;
|
||||
case HME_SEBI_IMASK_LINUXBUG:
|
||||
addr = HME_SEBI_IMASK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
val = s->sebregs[addr >> 2];
|
||||
|
||||
switch (addr) {
|
||||
case HME_SEBI_STAT:
|
||||
/* Autoclear status (except MIF) */
|
||||
s->sebregs[HME_SEBI_STAT >> 2] &= HME_SEB_STAT_MIFIRQ;
|
||||
sunhme_update_irq(s);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_sunhme_seb_read(addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sunhme_seb_ops = {
|
||||
.read = sunhme_seb_read,
|
||||
.write = sunhme_seb_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void sunhme_transmit(SunHMEState *s);
|
||||
|
||||
static void sunhme_etx_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
|
||||
trace_sunhme_etx_write(addr, val);
|
||||
|
||||
switch (addr) {
|
||||
case HME_ETXI_PENDING:
|
||||
if (val) {
|
||||
sunhme_transmit(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
s->etxregs[addr >> 2] = val;
|
||||
}
|
||||
|
||||
static uint64_t sunhme_etx_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
uint64_t val;
|
||||
|
||||
val = s->etxregs[addr >> 2];
|
||||
|
||||
trace_sunhme_etx_read(addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sunhme_etx_ops = {
|
||||
.read = sunhme_etx_read,
|
||||
.write = sunhme_etx_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void sunhme_erx_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
|
||||
trace_sunhme_erx_write(addr, val);
|
||||
|
||||
s->erxregs[addr >> 2] = val;
|
||||
}
|
||||
|
||||
static uint64_t sunhme_erx_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
uint64_t val;
|
||||
|
||||
val = s->erxregs[addr >> 2];
|
||||
|
||||
trace_sunhme_erx_read(addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sunhme_erx_ops = {
|
||||
.read = sunhme_erx_read,
|
||||
.write = sunhme_erx_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void sunhme_mac_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
|
||||
trace_sunhme_mac_write(addr, val);
|
||||
|
||||
s->macregs[addr >> 2] = val;
|
||||
}
|
||||
|
||||
static uint64_t sunhme_mac_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
uint64_t val;
|
||||
|
||||
val = s->macregs[addr >> 2];
|
||||
|
||||
trace_sunhme_mac_read(addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sunhme_mac_ops = {
|
||||
.read = sunhme_mac_read,
|
||||
.write = sunhme_mac_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void sunhme_mii_write(SunHMEState *s, uint8_t reg, uint16_t data)
|
||||
{
|
||||
trace_sunhme_mii_write(reg, data);
|
||||
|
||||
switch (reg) {
|
||||
case MII_BMCR:
|
||||
if (data & MII_BMCR_RESET) {
|
||||
/* Autoclear reset bit, enable auto negotiation */
|
||||
data &= ~MII_BMCR_RESET;
|
||||
data |= MII_BMCR_AUTOEN;
|
||||
}
|
||||
if (data & MII_BMCR_ANRESTART) {
|
||||
/* Autoclear auto negotiation restart */
|
||||
data &= ~MII_BMCR_ANRESTART;
|
||||
|
||||
/* Indicate negotiation complete */
|
||||
s->miiregs[MII_BMSR] |= MII_BMSR_AN_COMP;
|
||||
|
||||
if (!qemu_get_queue(s->nic)->link_down) {
|
||||
s->miiregs[MII_ANLPAR] |= MII_ANLPAR_TXFD;
|
||||
s->miiregs[MII_BMSR] |= MII_BMSR_LINK_ST;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
s->miiregs[reg] = data;
|
||||
}
|
||||
|
||||
static uint16_t sunhme_mii_read(SunHMEState *s, uint8_t reg)
|
||||
{
|
||||
uint16_t data = s->miiregs[reg];
|
||||
|
||||
trace_sunhme_mii_read(reg, data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void sunhme_mif_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
uint8_t cmd, reg;
|
||||
uint16_t data;
|
||||
|
||||
trace_sunhme_mif_write(addr, val);
|
||||
|
||||
switch (addr) {
|
||||
case HME_MIFI_CFG:
|
||||
/* Mask the read-only bits */
|
||||
val &= ~(HME_MIF_CFG_MDI0 | HME_MIF_CFG_MDI1);
|
||||
val |= s->mifregs[HME_MIFI_CFG >> 2] &
|
||||
(HME_MIF_CFG_MDI0 | HME_MIF_CFG_MDI1);
|
||||
break;
|
||||
case HME_MIFI_FO:
|
||||
/* Detect start of MII command */
|
||||
if ((val & HME_MIF_FO_ST) >> HME_MIF_FO_ST_SHIFT
|
||||
!= MII_COMMAND_START) {
|
||||
val |= HME_MIF_FO_TALSB;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Internal phy only */
|
||||
if ((val & HME_MIF_FO_PHYAD) >> HME_MIF_FO_PHYAD_SHIFT
|
||||
!= HME_PHYAD_INTERNAL) {
|
||||
val |= HME_MIF_FO_TALSB;
|
||||
break;
|
||||
}
|
||||
|
||||
cmd = (val & HME_MIF_FO_OPC) >> HME_MIF_FO_OPC_SHIFT;
|
||||
reg = (val & HME_MIF_FO_REGAD) >> HME_MIF_FO_REGAD_SHIFT;
|
||||
data = (val & HME_MIF_FO_DATA);
|
||||
|
||||
switch (cmd) {
|
||||
case MII_COMMAND_WRITE:
|
||||
sunhme_mii_write(s, reg, data);
|
||||
break;
|
||||
|
||||
case MII_COMMAND_READ:
|
||||
val &= ~HME_MIF_FO_DATA;
|
||||
val |= sunhme_mii_read(s, reg);
|
||||
break;
|
||||
}
|
||||
|
||||
val |= HME_MIF_FO_TALSB;
|
||||
break;
|
||||
}
|
||||
|
||||
s->mifregs[addr >> 2] = val;
|
||||
}
|
||||
|
||||
static uint64_t sunhme_mif_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
SunHMEState *s = SUNHME(opaque);
|
||||
uint64_t val;
|
||||
|
||||
val = s->mifregs[addr >> 2];
|
||||
|
||||
switch (addr) {
|
||||
case HME_MIFI_STAT:
|
||||
/* Autoclear MIF interrupt status */
|
||||
s->mifregs[HME_MIFI_STAT >> 2] = 0;
|
||||
sunhme_update_irq(s);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_sunhme_mif_read(addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sunhme_mif_ops = {
|
||||
.read = sunhme_mif_read,
|
||||
.write = sunhme_mif_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void sunhme_transmit_frame(SunHMEState *s, uint8_t *buf, int size)
|
||||
{
|
||||
qemu_send_packet(qemu_get_queue(s->nic), buf, size);
|
||||
}
|
||||
|
||||
static inline int sunhme_get_tx_ring_count(SunHMEState *s)
|
||||
{
|
||||
return (s->etxregs[HME_ETXI_RSIZE >> 2] + 1) << 4;
|
||||
}
|
||||
|
||||
static inline int sunhme_get_tx_ring_nr(SunHMEState *s)
|
||||
{
|
||||
return s->etxregs[HME_ETXI_RING >> 2] & HME_ETXI_RING_OFFSET;
|
||||
}
|
||||
|
||||
static inline void sunhme_set_tx_ring_nr(SunHMEState *s, int i)
|
||||
{
|
||||
uint32_t ring = s->etxregs[HME_ETXI_RING >> 2] & ~HME_ETXI_RING_OFFSET;
|
||||
ring |= i & HME_ETXI_RING_OFFSET;
|
||||
|
||||
s->etxregs[HME_ETXI_RING >> 2] = ring;
|
||||
}
|
||||
|
||||
static void sunhme_transmit(SunHMEState *s)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(s);
|
||||
dma_addr_t tb, addr;
|
||||
uint32_t intstatus, status, buffer, sum = 0;
|
||||
int cr, nr, len, xmit_pos, csum_offset = 0, csum_stuff_offset = 0;
|
||||
uint16_t csum = 0;
|
||||
uint8_t xmit_buffer[HME_FIFO_SIZE];
|
||||
|
||||
tb = s->etxregs[HME_ETXI_RING >> 2] & HME_ETXI_RING_ADDR;
|
||||
nr = sunhme_get_tx_ring_count(s);
|
||||
cr = sunhme_get_tx_ring_nr(s);
|
||||
|
||||
pci_dma_read(d, tb + cr * HME_DESC_SIZE, &status, 4);
|
||||
pci_dma_read(d, tb + cr * HME_DESC_SIZE + 4, &buffer, 4);
|
||||
|
||||
xmit_pos = 0;
|
||||
while (status & HME_XD_OWN) {
|
||||
trace_sunhme_tx_desc(buffer, status, cr, nr);
|
||||
|
||||
/* Copy data into transmit buffer */
|
||||
addr = buffer;
|
||||
len = status & HME_XD_TXLENMSK;
|
||||
|
||||
if (xmit_pos + len > HME_FIFO_SIZE) {
|
||||
len = HME_FIFO_SIZE - xmit_pos;
|
||||
}
|
||||
|
||||
pci_dma_read(d, addr, &xmit_buffer[xmit_pos], len);
|
||||
xmit_pos += len;
|
||||
|
||||
/* Detect start of packet for TX checksum */
|
||||
if (status & HME_XD_SOP) {
|
||||
sum = 0;
|
||||
csum_offset = (status & HME_XD_TXCSSTART) >> HME_XD_TXCSSTARTSHIFT;
|
||||
csum_stuff_offset = (status & HME_XD_TXCSSTUFF) >>
|
||||
HME_XD_TXCSSTUFFSHIFT;
|
||||
}
|
||||
|
||||
if (status & HME_XD_TXCKSUM) {
|
||||
/* Only start calculation from csum_offset */
|
||||
if (xmit_pos - len <= csum_offset && xmit_pos > csum_offset) {
|
||||
sum += net_checksum_add(xmit_pos - csum_offset,
|
||||
xmit_buffer + csum_offset);
|
||||
trace_sunhme_tx_xsum_add(csum_offset, xmit_pos - csum_offset);
|
||||
} else {
|
||||
sum += net_checksum_add(len, xmit_buffer + xmit_pos - len);
|
||||
trace_sunhme_tx_xsum_add(xmit_pos - len, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Detect end of packet for TX checksum */
|
||||
if (status & HME_XD_EOP) {
|
||||
/* Stuff the checksum if required */
|
||||
if (status & HME_XD_TXCKSUM) {
|
||||
csum = net_checksum_finish(sum);
|
||||
stw_be_p(xmit_buffer + csum_stuff_offset, csum);
|
||||
trace_sunhme_tx_xsum_stuff(csum, csum_stuff_offset);
|
||||
}
|
||||
|
||||
if (s->macregs[HME_MACI_TXCFG >> 2] & HME_MAC_TXCFG_ENABLE) {
|
||||
sunhme_transmit_frame(s, xmit_buffer, xmit_pos);
|
||||
trace_sunhme_tx_done(xmit_pos);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update status */
|
||||
status &= ~HME_XD_OWN;
|
||||
pci_dma_write(d, tb + cr * HME_DESC_SIZE, &status, 4);
|
||||
|
||||
/* Move onto next descriptor */
|
||||
cr++;
|
||||
if (cr >= nr) {
|
||||
cr = 0;
|
||||
}
|
||||
sunhme_set_tx_ring_nr(s, cr);
|
||||
|
||||
pci_dma_read(d, tb + cr * HME_DESC_SIZE, &status, 4);
|
||||
pci_dma_read(d, tb + cr * HME_DESC_SIZE + 4, &buffer, 4);
|
||||
|
||||
/* Indicate TX complete */
|
||||
intstatus = s->sebregs[HME_SEBI_STAT >> 2];
|
||||
intstatus |= HME_SEB_STAT_HOSTTOTX;
|
||||
s->sebregs[HME_SEBI_STAT >> 2] = intstatus;
|
||||
|
||||
/* Autoclear TX pending */
|
||||
s->etxregs[HME_ETXI_PENDING >> 2] = 0;
|
||||
|
||||
sunhme_update_irq(s);
|
||||
}
|
||||
|
||||
/* TX FIFO now clear */
|
||||
intstatus = s->sebregs[HME_SEBI_STAT >> 2];
|
||||
intstatus |= HME_SEB_STAT_TXALL;
|
||||
s->sebregs[HME_SEBI_STAT >> 2] = intstatus;
|
||||
sunhme_update_irq(s);
|
||||
}
|
||||
|
||||
static int sunhme_can_receive(NetClientState *nc)
|
||||
{
|
||||
SunHMEState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
return s->macregs[HME_MAC_RXCFG_ENABLE >> 2] & HME_MAC_RXCFG_ENABLE;
|
||||
}
|
||||
|
||||
static void sunhme_link_status_changed(NetClientState *nc)
|
||||
{
|
||||
SunHMEState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
if (nc->link_down) {
|
||||
s->miiregs[MII_ANLPAR] &= ~MII_ANLPAR_TXFD;
|
||||
s->miiregs[MII_BMSR] &= ~MII_BMSR_LINK_ST;
|
||||
} else {
|
||||
s->miiregs[MII_ANLPAR] |= MII_ANLPAR_TXFD;
|
||||
s->miiregs[MII_BMSR] |= MII_BMSR_LINK_ST;
|
||||
}
|
||||
|
||||
/* Exact bits unknown */
|
||||
s->mifregs[HME_MIFI_STAT >> 2] = 0xffff;
|
||||
sunhme_update_irq(s);
|
||||
}
|
||||
|
||||
static inline int sunhme_get_rx_ring_count(SunHMEState *s)
|
||||
{
|
||||
uint32_t rings = (s->erxregs[HME_ERXI_CFG >> 2] & HME_ERX_CFG_RINGSIZE)
|
||||
>> HME_ERX_CFG_RINGSIZE_SHIFT;
|
||||
|
||||
switch (rings) {
|
||||
case 0:
|
||||
return 32;
|
||||
case 1:
|
||||
return 64;
|
||||
case 2:
|
||||
return 128;
|
||||
case 3:
|
||||
return 256;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int sunhme_get_rx_ring_nr(SunHMEState *s)
|
||||
{
|
||||
return s->erxregs[HME_ERXI_RING >> 2] & HME_ERXI_RING_OFFSET;
|
||||
}
|
||||
|
||||
static inline void sunhme_set_rx_ring_nr(SunHMEState *s, int i)
|
||||
{
|
||||
uint32_t ring = s->erxregs[HME_ERXI_RING >> 2] & ~HME_ERXI_RING_OFFSET;
|
||||
ring |= i & HME_ERXI_RING_OFFSET;
|
||||
|
||||
s->erxregs[HME_ERXI_RING >> 2] = ring;
|
||||
}
|
||||
|
||||
#define POLYNOMIAL_LE 0xedb88320
|
||||
static uint32_t sunhme_crc32_le(const uint8_t *p, int len)
|
||||
{
|
||||
uint32_t crc;
|
||||
int carry, i, j;
|
||||
uint8_t b;
|
||||
|
||||
crc = 0xffffffff;
|
||||
for (i = 0; i < len; i++) {
|
||||
b = *p++;
|
||||
for (j = 0; j < 8; j++) {
|
||||
carry = (crc & 0x1) ^ (b & 0x01);
|
||||
crc >>= 1;
|
||||
b >>= 1;
|
||||
if (carry) {
|
||||
crc = crc ^ POLYNOMIAL_LE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
#define MIN_BUF_SIZE 60
|
||||
|
||||
static ssize_t sunhme_receive(NetClientState *nc, const uint8_t *buf,
|
||||
size_t size)
|
||||
{
|
||||
SunHMEState *s = qemu_get_nic_opaque(nc);
|
||||
PCIDevice *d = PCI_DEVICE(s);
|
||||
dma_addr_t rb, addr;
|
||||
uint32_t intstatus, status, buffer, buffersize, sum;
|
||||
uint16_t csum;
|
||||
uint8_t buf1[60];
|
||||
int nr, cr, len, rxoffset, csum_offset;
|
||||
|
||||
trace_sunhme_rx_incoming(size);
|
||||
|
||||
/* Do nothing if MAC RX disabled */
|
||||
if (!(s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_ENABLE)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
trace_sunhme_rx_filter_destmac(buf[0], buf[1], buf[2],
|
||||
buf[3], buf[4], buf[5]);
|
||||
|
||||
/* Check destination MAC address */
|
||||
if (!(s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_PMISC)) {
|
||||
/* Try and match local MAC address */
|
||||
if (((s->macregs[HME_MACI_MACADDR0 >> 2] & 0xff00) >> 8) == buf[0] &&
|
||||
(s->macregs[HME_MACI_MACADDR0 >> 2] & 0xff) == buf[1] &&
|
||||
((s->macregs[HME_MACI_MACADDR1 >> 2] & 0xff00) >> 8) == buf[2] &&
|
||||
(s->macregs[HME_MACI_MACADDR1 >> 2] & 0xff) == buf[3] &&
|
||||
((s->macregs[HME_MACI_MACADDR2 >> 2] & 0xff00) >> 8) == buf[4] &&
|
||||
(s->macregs[HME_MACI_MACADDR2 >> 2] & 0xff) == buf[5]) {
|
||||
/* Matched local MAC address */
|
||||
trace_sunhme_rx_filter_local_match();
|
||||
} else if (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff &&
|
||||
buf[3] == 0xff && buf[4] == 0xff && buf[5] == 0xff) {
|
||||
/* Matched broadcast address */
|
||||
trace_sunhme_rx_filter_bcast_match();
|
||||
} else if (s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_HENABLE) {
|
||||
/* Didn't match local address, check hash filter */
|
||||
int mcast_idx = sunhme_crc32_le(buf, 6) >> 26;
|
||||
if (!(s->macregs[(HME_MACI_HASHTAB0 >> 2) - (mcast_idx >> 4)] &
|
||||
(1 << (mcast_idx & 0xf)))) {
|
||||
/* Didn't match hash filter */
|
||||
trace_sunhme_rx_filter_hash_nomatch();
|
||||
trace_sunhme_rx_filter_reject();
|
||||
return 0;
|
||||
} else {
|
||||
trace_sunhme_rx_filter_hash_match();
|
||||
}
|
||||
} else {
|
||||
/* Not for us */
|
||||
trace_sunhme_rx_filter_reject();
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
trace_sunhme_rx_filter_promisc_match();
|
||||
}
|
||||
|
||||
trace_sunhme_rx_filter_accept();
|
||||
|
||||
/* If too small buffer, then expand it */
|
||||
if (size < MIN_BUF_SIZE) {
|
||||
memcpy(buf1, buf, size);
|
||||
memset(buf1 + size, 0, MIN_BUF_SIZE - size);
|
||||
buf = buf1;
|
||||
size = MIN_BUF_SIZE;
|
||||
}
|
||||
|
||||
rb = s->erxregs[HME_ERXI_RING >> 2] & HME_ERXI_RING_ADDR;
|
||||
nr = sunhme_get_rx_ring_count(s);
|
||||
cr = sunhme_get_rx_ring_nr(s);
|
||||
|
||||
pci_dma_read(d, rb + cr * HME_DESC_SIZE, &status, 4);
|
||||
pci_dma_read(d, rb + cr * HME_DESC_SIZE + 4, &buffer, 4);
|
||||
|
||||
rxoffset = (s->erxregs[HME_ERXI_CFG >> 2] & HME_ERX_CFG_BYTEOFFSET) >>
|
||||
HME_ERX_CFG_BYTEOFFSET_SHIFT;
|
||||
|
||||
addr = buffer + rxoffset;
|
||||
buffersize = (status & HME_XD_RXLENMSK) >> HME_XD_RXLENSHIFT;
|
||||
|
||||
/* Detect receive overflow */
|
||||
len = size;
|
||||
if (size > buffersize) {
|
||||
status |= HME_XD_OFL;
|
||||
len = buffersize;
|
||||
}
|
||||
|
||||
pci_dma_write(d, addr, buf, len);
|
||||
|
||||
trace_sunhme_rx_desc(buffer, rxoffset, status, len, cr, nr);
|
||||
|
||||
/* Calculate the receive checksum */
|
||||
csum_offset = (s->erxregs[HME_ERXI_CFG >> 2] & HME_ERX_CFG_CSUMSTART) >>
|
||||
HME_ERX_CFG_CSUMSHIFT << 1;
|
||||
sum = 0;
|
||||
sum += net_checksum_add(len - csum_offset, (uint8_t *)buf + csum_offset);
|
||||
csum = net_checksum_finish(sum);
|
||||
|
||||
trace_sunhme_rx_xsum_calc(csum);
|
||||
|
||||
/* Update status */
|
||||
status &= ~HME_XD_OWN;
|
||||
status &= ~HME_XD_RXLENMSK;
|
||||
status |= len << HME_XD_RXLENSHIFT;
|
||||
status &= ~HME_XD_RXCKSUM;
|
||||
status |= csum;
|
||||
|
||||
pci_dma_write(d, rb + cr * HME_DESC_SIZE, &status, 4);
|
||||
|
||||
cr++;
|
||||
if (cr >= nr) {
|
||||
cr = 0;
|
||||
}
|
||||
|
||||
sunhme_set_rx_ring_nr(s, cr);
|
||||
|
||||
/* Indicate RX complete */
|
||||
intstatus = s->sebregs[HME_SEBI_STAT >> 2];
|
||||
intstatus |= HME_SEB_STAT_RXTOHOST;
|
||||
s->sebregs[HME_SEBI_STAT >> 2] = intstatus;
|
||||
|
||||
sunhme_update_irq(s);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static NetClientInfo net_sunhme_info = {
|
||||
.type = NET_CLIENT_DRIVER_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = sunhme_can_receive,
|
||||
.receive = sunhme_receive,
|
||||
.link_status_changed = sunhme_link_status_changed,
|
||||
};
|
||||
|
||||
static void sunhme_realize(PCIDevice *pci_dev, Error **errp)
|
||||
{
|
||||
SunHMEState *s = SUNHME(pci_dev);
|
||||
DeviceState *d = DEVICE(pci_dev);
|
||||
uint8_t *pci_conf;
|
||||
|
||||
pci_conf = pci_dev->config;
|
||||
pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
|
||||
|
||||
memory_region_init(&s->hme, OBJECT(pci_dev), "sunhme", HME_REG_SIZE);
|
||||
pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->hme);
|
||||
|
||||
memory_region_init_io(&s->sebreg, OBJECT(pci_dev), &sunhme_seb_ops, s,
|
||||
"sunhme.seb", HME_SEB_REG_SIZE);
|
||||
memory_region_add_subregion(&s->hme, 0, &s->sebreg);
|
||||
|
||||
memory_region_init_io(&s->etxreg, OBJECT(pci_dev), &sunhme_etx_ops, s,
|
||||
"sunhme.etx", HME_ETX_REG_SIZE);
|
||||
memory_region_add_subregion(&s->hme, 0x2000, &s->etxreg);
|
||||
|
||||
memory_region_init_io(&s->erxreg, OBJECT(pci_dev), &sunhme_erx_ops, s,
|
||||
"sunhme.erx", HME_ERX_REG_SIZE);
|
||||
memory_region_add_subregion(&s->hme, 0x4000, &s->erxreg);
|
||||
|
||||
memory_region_init_io(&s->macreg, OBJECT(pci_dev), &sunhme_mac_ops, s,
|
||||
"sunhme.mac", HME_MAC_REG_SIZE);
|
||||
memory_region_add_subregion(&s->hme, 0x6000, &s->macreg);
|
||||
|
||||
memory_region_init_io(&s->mifreg, OBJECT(pci_dev), &sunhme_mif_ops, s,
|
||||
"sunhme.mif", HME_MIF_REG_SIZE);
|
||||
memory_region_add_subregion(&s->hme, 0x7000, &s->mifreg);
|
||||
|
||||
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||
s->nic = qemu_new_nic(&net_sunhme_info, &s->conf,
|
||||
object_get_typename(OBJECT(d)), d->id, s);
|
||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
||||
}
|
||||
|
||||
static void sunhme_instance_init(Object *obj)
|
||||
{
|
||||
SunHMEState *s = SUNHME(obj);
|
||||
|
||||
device_add_bootindex_property(obj, &s->conf.bootindex,
|
||||
"bootindex", "/ethernet-phy@0",
|
||||
DEVICE(obj), NULL);
|
||||
}
|
||||
|
||||
static void sunhme_reset(DeviceState *ds)
|
||||
{
|
||||
SunHMEState *s = SUNHME(ds);
|
||||
|
||||
/* Configure internal transceiver */
|
||||
s->mifregs[HME_MIFI_CFG >> 2] |= HME_MIF_CFG_MDI0;
|
||||
|
||||
/* Advetise auto, 100Mbps FD */
|
||||
s->miiregs[MII_ANAR] = MII_ANAR_TXFD;
|
||||
s->miiregs[MII_BMSR] = MII_BMSR_AUTONEG | MII_BMSR_100TX_FD |
|
||||
MII_BMSR_AN_COMP;
|
||||
|
||||
if (!qemu_get_queue(s->nic)->link_down) {
|
||||
s->miiregs[MII_ANLPAR] |= MII_ANLPAR_TXFD;
|
||||
s->miiregs[MII_BMSR] |= MII_BMSR_LINK_ST;
|
||||
}
|
||||
|
||||
/* Set manufacturer */
|
||||
s->miiregs[MII_PHYID1] = DP83840_PHYID1;
|
||||
s->miiregs[MII_PHYID2] = DP83840_PHYID2;
|
||||
|
||||
/* Configure default interrupt mask */
|
||||
s->mifregs[HME_MIFI_IMASK >> 2] = 0xffff;
|
||||
s->sebregs[HME_SEBI_IMASK >> 2] = 0xff7fffff;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_hme = {
|
||||
.name = "sunhme",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(parent_obj, SunHMEState),
|
||||
VMSTATE_MACADDR(conf.macaddr, SunHMEState),
|
||||
VMSTATE_UINT32_ARRAY(sebregs, SunHMEState, (HME_SEB_REG_SIZE >> 2)),
|
||||
VMSTATE_UINT32_ARRAY(etxregs, SunHMEState, (HME_ETX_REG_SIZE >> 2)),
|
||||
VMSTATE_UINT32_ARRAY(erxregs, SunHMEState, (HME_ERX_REG_SIZE >> 2)),
|
||||
VMSTATE_UINT32_ARRAY(macregs, SunHMEState, (HME_MAC_REG_SIZE >> 2)),
|
||||
VMSTATE_UINT32_ARRAY(mifregs, SunHMEState, (HME_MIF_REG_SIZE >> 2)),
|
||||
VMSTATE_UINT16_ARRAY(miiregs, SunHMEState, HME_MII_REGS_SIZE),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void sunhme_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = sunhme_realize;
|
||||
k->vendor_id = PCI_VENDOR_ID_SUN;
|
||||
k->device_id = PCI_DEVICE_ID_SUN_HME;
|
||||
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
|
||||
dc->vmsd = &vmstate_hme;
|
||||
dc->reset = sunhme_reset;
|
||||
dc->props = sunhme_properties;
|
||||
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo sunhme_info = {
|
||||
.name = TYPE_SUNHME,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.class_init = sunhme_class_init,
|
||||
.instance_size = sizeof(SunHMEState),
|
||||
.instance_init = sunhme_instance_init,
|
||||
};
|
||||
|
||||
static void sunhme_register_types(void)
|
||||
{
|
||||
type_register_static(&sunhme_info);
|
||||
}
|
||||
|
||||
type_init(sunhme_register_types)
|
||||
@@ -322,3 +322,32 @@ sungem_mmio_mif_write(uint64_t addr, uint64_t val) "MMIO mif write to 0x%"PRIx64
|
||||
sungem_mmio_mif_read(uint64_t addr, uint64_t val) "MMIO mif read from 0x%"PRIx64" val=0x%"PRIx64
|
||||
sungem_mmio_pcs_write(uint64_t addr, uint64_t val) "MMIO pcs write to 0x%"PRIx64" val=0x%"PRIx64
|
||||
sungem_mmio_pcs_read(uint64_t addr, uint64_t val) "MMIO pcs read from 0x%"PRIx64" val=0x%"PRIx64
|
||||
|
||||
# hw/net/sunhme.c
|
||||
sunhme_seb_write(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_seb_read(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_etx_write(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_etx_read(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_erx_write(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_erx_read(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_mac_write(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_mac_read(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_mii_write(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_mii_read(uint8_t addr, uint16_t value) "addr 0x%x value 0x%x"
|
||||
sunhme_mif_write(uint8_t addr, uint16_t value) "addr 0x%x value 0x%x"
|
||||
sunhme_mif_read(uint64_t addr, uint64_t value) "addr 0x%"PRIx64" value 0x%"PRIx64
|
||||
sunhme_tx_desc(uint64_t buffer, uint32_t status, int cr, int nr) "addr 0x%"PRIx64" status 0x%"PRIx32 " (ring %d/%d)"
|
||||
sunhme_tx_xsum_add(int offset, int len) "adding xsum at offset %d, len %d"
|
||||
sunhme_tx_xsum_stuff(uint16_t xsum, int offset) "stuffing xsum 0x%x at offset %d"
|
||||
sunhme_tx_done(int len) "successfully transmitted frame with len %d"
|
||||
sunhme_rx_incoming(size_t len) "received incoming frame with len %zu"
|
||||
sunhme_rx_filter_destmac(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "received frame for MAC: %02x:%02x:%02x:%02x:%02x:%02x"
|
||||
sunhme_rx_filter_local_match(void) "incoming frame matches local MAC address"
|
||||
sunhme_rx_filter_bcast_match(void) "incoming frame matches broadcast MAC address"
|
||||
sunhme_rx_filter_hash_nomatch(void) "incoming MAC address not in hash table"
|
||||
sunhme_rx_filter_hash_match(void) "incoming MAC address found in hash table"
|
||||
sunhme_rx_filter_promisc_match(void) "incoming frame accepted due to promiscuous mode"
|
||||
sunhme_rx_filter_reject(void) "rejecting incoming frame"
|
||||
sunhme_rx_filter_accept(void) "accepting incoming frame"
|
||||
sunhme_rx_desc(uint32_t addr, int offset, uint32_t status, int len, int cr, int nr) "addr 0x%"PRIx32"(+0x%x) status 0x%"PRIx32 " len %d (ring %d/%d)"
|
||||
sunhme_rx_xsum_calc(uint16_t xsum) "calculated incoming xsum as 0x%x"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
obj-y += s390-virtio.o
|
||||
obj-y += s390-virtio-hcall.o
|
||||
obj-y += sclp.o
|
||||
obj-y += event-facility.o
|
||||
|
||||
@@ -793,7 +793,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
|
||||
CCW1 ccw;
|
||||
|
||||
if (!ccw_addr) {
|
||||
return -EIO;
|
||||
return -EINVAL; /* channel-program check */
|
||||
}
|
||||
/* Check doubleword aligned and 31 or 24 (fmt 0) bit addressable. */
|
||||
if (ccw_addr & (sch->ccw_fmt_1 ? 0x80000007 : 0xff000007)) {
|
||||
@@ -980,22 +980,6 @@ static void sch_handle_start_func_virtual(SubchDev *sch)
|
||||
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
|
||||
s->cpa = sch->channel_prog + 8;
|
||||
break;
|
||||
case -EFAULT:
|
||||
/* memory problem, generate channel data check */
|
||||
s->ctrl &= ~SCSW_ACTL_START_PEND;
|
||||
s->cstat = SCSW_CSTAT_DATA_CHECK;
|
||||
s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
|
||||
s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
|
||||
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
|
||||
s->cpa = sch->channel_prog + 8;
|
||||
break;
|
||||
case -EBUSY:
|
||||
/* subchannel busy, generate deferred cc 1 */
|
||||
s->flags &= ~SCSW_FLAGS_MASK_CC;
|
||||
s->flags |= (1 << 8);
|
||||
s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
|
||||
s->ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
|
||||
break;
|
||||
case -EINPROGRESS:
|
||||
/* channel program has been suspended */
|
||||
s->ctrl &= ~SCSW_ACTL_START_PEND;
|
||||
@@ -1276,16 +1260,16 @@ int css_do_xsch(SubchDev *sch)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (s->ctrl & SCSW_CTRL_MASK_STCTL) {
|
||||
ret = -EINPROGRESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) ||
|
||||
((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) ||
|
||||
(!(s->ctrl &
|
||||
(SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) ||
|
||||
(s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) {
|
||||
ret = -EINPROGRESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (s->ctrl & SCSW_CTRL_MASK_STCTL) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -199,8 +199,8 @@ static S390PCIBusDevice *s390_pci_find_dev_by_uid(S390pciState *s, uint16_t uid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s,
|
||||
const char *target)
|
||||
S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s,
|
||||
const char *target)
|
||||
{
|
||||
S390PCIBusDevice *pbdev;
|
||||
|
||||
@@ -397,6 +397,17 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void s390_pci_iommu_replay(IOMMUMemoryRegion *iommu,
|
||||
IOMMUNotifier *notifier)
|
||||
{
|
||||
/* It's impossible to plug a pci device on s390x that already has iommu
|
||||
* mappings which need to be replayed, that is due to the "one iommu per
|
||||
* zpci device" construct. But when we support migration of vfio-pci
|
||||
* devices in future, we need to revisit this.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus,
|
||||
int devfn)
|
||||
{
|
||||
@@ -465,19 +476,13 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
{
|
||||
S390PCIBusDevice *pbdev = opaque;
|
||||
uint32_t idx = data >> ZPCI_MSI_VEC_BITS;
|
||||
uint32_t vec = data & ZPCI_MSI_VEC_MASK;
|
||||
uint64_t ind_bit;
|
||||
uint32_t sum_bit;
|
||||
uint32_t e = 0;
|
||||
|
||||
DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, idx, vec);
|
||||
|
||||
if (!pbdev) {
|
||||
e |= (vec << ERR_EVENT_MVN_OFFSET);
|
||||
s390_pci_generate_error_event(ERR_EVENT_NOMSI, idx, 0, addr, e);
|
||||
return;
|
||||
}
|
||||
assert(pbdev);
|
||||
DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data,
|
||||
pbdev->idx, vec);
|
||||
|
||||
if (pbdev->state != ZPCI_FS_ENABLED) {
|
||||
return;
|
||||
@@ -1051,6 +1056,7 @@ static void s390_iommu_memory_region_class_init(ObjectClass *klass, void *data)
|
||||
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
|
||||
|
||||
imrc->translate = s390_translate_iommu;
|
||||
imrc->replay = s390_pci_iommu_replay;
|
||||
}
|
||||
|
||||
static const TypeInfo s390_iommu_memory_region_info = {
|
||||
|
||||
@@ -322,6 +322,8 @@ void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid,
|
||||
S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx);
|
||||
S390PCIBusDevice *s390_pci_find_dev_by_fh(S390pciState *s, uint32_t fh);
|
||||
S390PCIBusDevice *s390_pci_find_dev_by_fid(S390pciState *s, uint32_t fid);
|
||||
S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s,
|
||||
const char *target);
|
||||
S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s,
|
||||
S390PCIBusDevice *pbdev);
|
||||
|
||||
|
||||
@@ -413,29 +413,6 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_msix_table_msg_data(S390PCIBusDevice *pbdev, uint64_t offset,
|
||||
uint64_t *data, uint8_t len)
|
||||
{
|
||||
uint32_t val;
|
||||
uint8_t *msg_data;
|
||||
|
||||
if (offset % PCI_MSIX_ENTRY_SIZE != 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (len != 4) {
|
||||
DPRINTF("access msix table msg data but len is %d\n", len);
|
||||
return;
|
||||
}
|
||||
|
||||
msg_data = (uint8_t *)data - offset % PCI_MSIX_ENTRY_SIZE +
|
||||
PCI_MSIX_ENTRY_VECTOR_CTRL;
|
||||
val = pci_get_long(msg_data) |
|
||||
((pbdev->fh & FH_MASK_INDEX) << ZPCI_MSI_VEC_BITS);
|
||||
pci_set_long(msg_data, val);
|
||||
DPRINTF("update msix msg_data to 0x%" PRIx64 "\n", *data);
|
||||
}
|
||||
|
||||
static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias)
|
||||
{
|
||||
if (pbdev->msix.available && pbdev->msix.table_bar == pcias &&
|
||||
@@ -508,7 +485,6 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
|
||||
if (trap_msix(pbdev, offset, pcias)) {
|
||||
offset = offset - pbdev->msix.table_offset;
|
||||
mr = &pbdev->pdev->msix_table_mmio;
|
||||
update_msix_table_msg_data(pbdev, offset, &data, len);
|
||||
} else {
|
||||
mr = pbdev->pdev->io_regions[pcias].memory;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,8 @@ S390pciState *s390_get_phb(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx)
|
||||
S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s,
|
||||
const char *target)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* virtio ccw machine
|
||||
*
|
||||
* Copyright 2012 IBM Corp.
|
||||
* Copyright (c) 2009 Alexander Graf <agraf@suse.de>
|
||||
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
@@ -15,13 +16,14 @@
|
||||
#include "cpu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "s390-virtio.h"
|
||||
#include "hw/s390x/s390-virtio-hcall.h"
|
||||
#include "hw/s390x/sclp.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "hw/s390x/ioinst.h"
|
||||
#include "hw/s390x/css.h"
|
||||
#include "virtio-ccw.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "s390-pci-bus.h"
|
||||
#include "hw/s390x/storage-keys.h"
|
||||
#include "hw/s390x/storage-attributes.h"
|
||||
@@ -31,6 +33,67 @@
|
||||
#include "hw/s390x/css-bridge.h"
|
||||
#include "migration/register.h"
|
||||
#include "cpu_models.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "hw/nmi.h"
|
||||
|
||||
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
|
||||
{
|
||||
static MachineState *ms;
|
||||
|
||||
if (!ms) {
|
||||
ms = MACHINE(qdev_get_machine());
|
||||
g_assert(ms->possible_cpus);
|
||||
}
|
||||
|
||||
/* CPU address corresponds to the core_id and the index */
|
||||
if (cpu_addr >= ms->possible_cpus->len) {
|
||||
return NULL;
|
||||
}
|
||||
return S390_CPU(ms->possible_cpus->cpus[cpu_addr].cpu);
|
||||
}
|
||||
|
||||
static void s390_init_cpus(MachineState *machine)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
const char *typename;
|
||||
gchar **model_pieces;
|
||||
ObjectClass *oc;
|
||||
CPUClass *cc;
|
||||
int i;
|
||||
|
||||
if (machine->cpu_model == NULL) {
|
||||
machine->cpu_model = s390_default_cpu_model_name();
|
||||
}
|
||||
if (tcg_enabled() && max_cpus > 1) {
|
||||
error_report("Number of SMP CPUs requested (%d) exceeds max CPUs "
|
||||
"supported by TCG (1) on s390x", max_cpus);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* initialize possible_cpus */
|
||||
mc->possible_cpu_arch_ids(machine);
|
||||
|
||||
model_pieces = g_strsplit(machine->cpu_model, ",", 2);
|
||||
if (!model_pieces[0]) {
|
||||
error_report("Invalid/empty CPU model name");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
oc = cpu_class_by_name(TYPE_S390_CPU, model_pieces[0]);
|
||||
if (!oc) {
|
||||
error_report("Unable to find CPU definition: %s", model_pieces[0]);
|
||||
exit(1);
|
||||
}
|
||||
typename = object_class_get_name(oc);
|
||||
cc = CPU_CLASS(oc);
|
||||
/* after parsing, properties will be applied to all *typename* instances */
|
||||
cc->parse_features(typename, model_pieces[1], &error_fatal);
|
||||
g_strfreev(model_pieces);
|
||||
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
s390x_new_cpu(typename, i, &error_fatal);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const reset_dev_types[] = {
|
||||
TYPE_VIRTUAL_CSS_BRIDGE,
|
||||
@@ -94,7 +157,7 @@ static void virtio_ccw_register_hcalls(void)
|
||||
virtio_ccw_hcall_early_printk);
|
||||
}
|
||||
|
||||
void s390_memory_init(ram_addr_t mem_size)
|
||||
static void s390_memory_init(ram_addr_t mem_size)
|
||||
{
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
@@ -109,11 +172,105 @@ void s390_memory_init(ram_addr_t mem_size)
|
||||
s390_stattrib_init();
|
||||
}
|
||||
|
||||
#define S390_TOD_CLOCK_VALUE_MISSING 0x00
|
||||
#define S390_TOD_CLOCK_VALUE_PRESENT 0x01
|
||||
|
||||
static void gtod_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
uint64_t tod_low;
|
||||
uint8_t tod_high;
|
||||
int r;
|
||||
|
||||
r = s390_get_clock(&tod_high, &tod_low);
|
||||
if (r) {
|
||||
warn_report("Unable to get guest clock for migration: %s",
|
||||
strerror(-r));
|
||||
error_printf("Guest clock will not be migrated "
|
||||
"which could cause the guest to hang.");
|
||||
qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT);
|
||||
qemu_put_byte(f, tod_high);
|
||||
qemu_put_be64(f, tod_low);
|
||||
}
|
||||
|
||||
static int gtod_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
uint64_t tod_low;
|
||||
uint8_t tod_high;
|
||||
int r;
|
||||
|
||||
if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) {
|
||||
warn_report("Guest clock was not migrated. This could "
|
||||
"cause the guest to hang.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tod_high = qemu_get_byte(f);
|
||||
tod_low = qemu_get_be64(f);
|
||||
|
||||
r = s390_set_clock(&tod_high, &tod_low);
|
||||
if (r) {
|
||||
warn_report("Unable to set guest clock for migration: %s",
|
||||
strerror(-r));
|
||||
error_printf("Guest clock will not be restored "
|
||||
"which could cause the guest to hang.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SaveVMHandlers savevm_gtod = {
|
||||
.save_state = gtod_save,
|
||||
.load_state = gtod_load,
|
||||
};
|
||||
|
||||
static void s390_init_ipl_dev(const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *firmware,
|
||||
const char *netboot_fw, bool enforce_bios)
|
||||
{
|
||||
Object *new = object_new(TYPE_S390_IPL);
|
||||
DeviceState *dev = DEVICE(new);
|
||||
|
||||
if (kernel_filename) {
|
||||
qdev_prop_set_string(dev, "kernel", kernel_filename);
|
||||
}
|
||||
if (initrd_filename) {
|
||||
qdev_prop_set_string(dev, "initrd", initrd_filename);
|
||||
}
|
||||
qdev_prop_set_string(dev, "cmdline", kernel_cmdline);
|
||||
qdev_prop_set_string(dev, "firmware", firmware);
|
||||
qdev_prop_set_string(dev, "netboot_fw", netboot_fw);
|
||||
qdev_prop_set_bit(dev, "enforce_bios", enforce_bios);
|
||||
object_property_add_child(qdev_get_machine(), TYPE_S390_IPL,
|
||||
new, NULL);
|
||||
object_unref(new);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
|
||||
static void s390_create_virtio_net(BusState *bus, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
NICInfo *nd = &nd_table[i];
|
||||
DeviceState *dev;
|
||||
|
||||
if (!nd->model) {
|
||||
nd->model = g_strdup("virtio");
|
||||
}
|
||||
|
||||
qemu_check_nic_model(nd, "virtio");
|
||||
|
||||
dev = qdev_create(bus, name);
|
||||
qdev_set_nic_properties(dev, nd);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void ccw_init(MachineState *machine)
|
||||
{
|
||||
int ret;
|
||||
@@ -167,14 +324,24 @@ static void ccw_init(MachineState *machine)
|
||||
static void s390_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
gchar *name;
|
||||
MachineState *ms = MACHINE(hotplug_dev);
|
||||
S390CPU *cpu = S390_CPU(dev);
|
||||
CPUState *cs = CPU(dev);
|
||||
|
||||
name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num);
|
||||
object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name,
|
||||
errp);
|
||||
g_free(name);
|
||||
g_assert(!ms->possible_cpus->cpus[cpu->env.core_id].cpu);
|
||||
ms->possible_cpus->cpus[cpu->env.core_id].cpu = OBJECT(dev);
|
||||
}
|
||||
|
||||
static void s390_machine_reset(void)
|
||||
{
|
||||
S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0));
|
||||
|
||||
s390_cmma_reset();
|
||||
qemu_devices_reset();
|
||||
s390_crypto_reset();
|
||||
|
||||
/* all cpus are stopped - configure and start the ipl cpu only */
|
||||
s390_ipl_prepare_cpu(ipl_cpu);
|
||||
s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu);
|
||||
}
|
||||
|
||||
static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
|
||||
@@ -185,6 +352,45 @@ static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
error_setg(errp, "CPU hot unplug not supported on this machine");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static CpuInstanceProperties s390_cpu_index_to_props(MachineState *machine,
|
||||
unsigned cpu_index)
|
||||
{
|
||||
g_assert(machine->possible_cpus && cpu_index < machine->possible_cpus->len);
|
||||
|
||||
return machine->possible_cpus->cpus[cpu_index].props;
|
||||
}
|
||||
|
||||
static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ms->possible_cpus) {
|
||||
g_assert(ms->possible_cpus && ms->possible_cpus->len == max_cpus);
|
||||
return ms->possible_cpus;
|
||||
}
|
||||
|
||||
ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
|
||||
sizeof(CPUArchId) * max_cpus);
|
||||
ms->possible_cpus->len = max_cpus;
|
||||
for (i = 0; i < ms->possible_cpus->len; i++) {
|
||||
ms->possible_cpus->cpus[i].vcpus_count = 1;
|
||||
ms->possible_cpus->cpus[i].arch_id = i;
|
||||
ms->possible_cpus->cpus[i].props.has_core_id = true;
|
||||
ms->possible_cpus->cpus[i].props.core_id = i;
|
||||
}
|
||||
|
||||
return ms->possible_cpus;
|
||||
}
|
||||
|
||||
static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
|
||||
DeviceState *dev)
|
||||
{
|
||||
@@ -197,8 +403,21 @@ static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
|
||||
static void s390_hot_add_cpu(const int64_t id, Error **errp)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
ObjectClass *oc;
|
||||
|
||||
s390x_new_cpu(machine->cpu_model, id, errp);
|
||||
g_assert(machine->possible_cpus->cpus[0].cpu);
|
||||
oc = OBJECT_CLASS(CPU_GET_CLASS(machine->possible_cpus->cpus[0].cpu));
|
||||
|
||||
s390x_new_cpu(object_class_get_name(oc), id, errp);
|
||||
}
|
||||
|
||||
static void s390_nmi(NMIState *n, int cpu_index, Error **errp)
|
||||
{
|
||||
CPUState *cs = qemu_get_cpu(cpu_index);
|
||||
|
||||
if (s390_cpu_restart(S390_CPU(cs))) {
|
||||
error_setg(errp, QERR_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
||||
@@ -223,8 +442,12 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
||||
mc->no_sdcard = 1;
|
||||
mc->use_sclp = 1;
|
||||
mc->max_cpus = 248;
|
||||
mc->has_hotpluggable_cpus = true;
|
||||
mc->get_hotplug_handler = s390_get_hotplug_handler;
|
||||
mc->cpu_index_to_instance_props = s390_cpu_index_to_props;
|
||||
mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids;
|
||||
hc->plug = s390_machine_device_plug;
|
||||
hc->unplug_request = s390_machine_device_unplug_request;
|
||||
nc->nmi_monitor_handler = s390_nmi;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/s390x/s390-virtio.h"
|
||||
#include "hw/s390x/s390-virtio-hcall.h"
|
||||
|
||||
#define MAX_DIAG_SUBCODES 255
|
||||
|
||||
|
||||
21
hw/s390x/s390-virtio-hcall.h
Normal file
21
hw/s390x/s390-virtio-hcall.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Support for virtio hypercalls on s390x
|
||||
*
|
||||
* Copyright 2012 IBM Corp.
|
||||
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_S390_VIRTIO_HCALL_H
|
||||
#define HW_S390_VIRTIO_HCALL_H
|
||||
|
||||
#include "standard-headers/asm-s390/kvm_virtio.h"
|
||||
#include "standard-headers/asm-s390/virtio-ccw.h"
|
||||
|
||||
typedef int (*s390_virtio_fn)(const uint64_t *args);
|
||||
void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn);
|
||||
int s390_virtio_hypercall(CPUS390XState *env);
|
||||
#endif /* HW_S390_VIRTIO_HCALL_H */
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* QEMU S390 virtio target
|
||||
*
|
||||
* Copyright (c) 2009 Alexander Graf <agraf@suse.de>
|
||||
* Copyright IBM Corp 2012
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Contributions after 2012-10-29 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*
|
||||
* You should have received a copy of the GNU (Lesser) General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/qtest.h"
|
||||
|
||||
#include "hw/s390x/sclp.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "hw/s390x/s390-virtio.h"
|
||||
#include "hw/s390x/storage-keys.h"
|
||||
#include "hw/s390x/ipl.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define MAX_BLK_DEVS 10
|
||||
|
||||
#define S390_TOD_CLOCK_VALUE_MISSING 0x00
|
||||
#define S390_TOD_CLOCK_VALUE_PRESENT 0x01
|
||||
|
||||
static S390CPU **cpu_states;
|
||||
|
||||
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
|
||||
{
|
||||
if (cpu_addr >= max_cpus) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Fast lookup via CPU ID */
|
||||
return cpu_states[cpu_addr];
|
||||
}
|
||||
|
||||
void s390_init_ipl_dev(const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
const char *firmware,
|
||||
const char *netboot_fw,
|
||||
bool enforce_bios)
|
||||
{
|
||||
Object *new = object_new(TYPE_S390_IPL);
|
||||
DeviceState *dev = DEVICE(new);
|
||||
|
||||
if (kernel_filename) {
|
||||
qdev_prop_set_string(dev, "kernel", kernel_filename);
|
||||
}
|
||||
if (initrd_filename) {
|
||||
qdev_prop_set_string(dev, "initrd", initrd_filename);
|
||||
}
|
||||
qdev_prop_set_string(dev, "cmdline", kernel_cmdline);
|
||||
qdev_prop_set_string(dev, "firmware", firmware);
|
||||
qdev_prop_set_string(dev, "netboot_fw", netboot_fw);
|
||||
qdev_prop_set_bit(dev, "enforce_bios", enforce_bios);
|
||||
object_property_add_child(qdev_get_machine(), TYPE_S390_IPL,
|
||||
new, NULL);
|
||||
object_unref(new);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
|
||||
void s390_init_cpus(MachineState *machine)
|
||||
{
|
||||
int i;
|
||||
gchar *name;
|
||||
|
||||
if (machine->cpu_model == NULL) {
|
||||
machine->cpu_model = s390_default_cpu_model_name();
|
||||
}
|
||||
|
||||
cpu_states = g_new0(S390CPU *, max_cpus);
|
||||
|
||||
for (i = 0; i < max_cpus; i++) {
|
||||
name = g_strdup_printf("cpu[%i]", i);
|
||||
object_property_add_link(OBJECT(machine), name, TYPE_S390_CPU,
|
||||
(Object **) &cpu_states[i],
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
s390x_new_cpu(machine->cpu_model, i, &error_fatal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void s390_create_virtio_net(BusState *bus, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
NICInfo *nd = &nd_table[i];
|
||||
DeviceState *dev;
|
||||
|
||||
if (!nd->model) {
|
||||
nd->model = g_strdup("virtio");
|
||||
}
|
||||
|
||||
qemu_check_nic_model(nd, "virtio");
|
||||
|
||||
dev = qdev_create(bus, name);
|
||||
qdev_set_nic_properties(dev, nd);
|
||||
qdev_init_nofail(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void gtod_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
uint64_t tod_low;
|
||||
uint8_t tod_high;
|
||||
int r;
|
||||
|
||||
r = s390_get_clock(&tod_high, &tod_low);
|
||||
if (r) {
|
||||
fprintf(stderr, "WARNING: Unable to get guest clock for migration. "
|
||||
"Error code %d. Guest clock will not be migrated "
|
||||
"which could cause the guest to hang.\n", r);
|
||||
qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT);
|
||||
qemu_put_byte(f, tod_high);
|
||||
qemu_put_be64(f, tod_low);
|
||||
}
|
||||
|
||||
int gtod_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
uint64_t tod_low;
|
||||
uint8_t tod_high;
|
||||
int r;
|
||||
|
||||
if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) {
|
||||
fprintf(stderr, "WARNING: Guest clock was not migrated. This could "
|
||||
"cause the guest to hang.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tod_high = qemu_get_byte(f);
|
||||
tod_low = qemu_get_be64(f);
|
||||
|
||||
r = s390_set_clock(&tod_high, &tod_low);
|
||||
if (r) {
|
||||
fprintf(stderr, "WARNING: Unable to set guest clock value. "
|
||||
"s390_get_clock returned error %d. This could cause "
|
||||
"the guest to hang.\n", r);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void s390_nmi(NMIState *n, int cpu_index, Error **errp)
|
||||
{
|
||||
CPUState *cs = qemu_get_cpu(cpu_index);
|
||||
|
||||
if (s390_cpu_restart(S390_CPU(cs))) {
|
||||
error_setg(errp, QERR_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
void s390_machine_reset(void)
|
||||
{
|
||||
S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0));
|
||||
|
||||
s390_cmma_reset();
|
||||
qemu_devices_reset();
|
||||
s390_crypto_reset();
|
||||
|
||||
/* all cpus are stopped - configure and start the ipl cpu only */
|
||||
s390_ipl_prepare_cpu(ipl_cpu);
|
||||
s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Virtio interfaces for s390
|
||||
*
|
||||
* Copyright 2012 IBM Corp.
|
||||
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_S390_VIRTIO_H
|
||||
#define HW_S390_VIRTIO_H
|
||||
|
||||
#include "hw/nmi.h"
|
||||
#include "standard-headers/asm-s390/kvm_virtio.h"
|
||||
#include "standard-headers/asm-s390/virtio-ccw.h"
|
||||
|
||||
typedef int (*s390_virtio_fn)(const uint64_t *args);
|
||||
void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn);
|
||||
|
||||
void s390_init_cpus(MachineState *machine);
|
||||
void s390_init_ipl_dev(const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
const char *firmware,
|
||||
const char *netboot_fw,
|
||||
bool enforce_bios);
|
||||
void s390_create_virtio_net(BusState *bus, const char *name);
|
||||
void s390_nmi(NMIState *n, int cpu_index, Error **errp);
|
||||
void s390_machine_reset(void);
|
||||
void s390_memory_init(ram_addr_t mem_size);
|
||||
void gtod_save(QEMUFile *f, void *opaque);
|
||||
int gtod_load(QEMUFile *f, void *opaque, int version_id);
|
||||
#endif
|
||||
@@ -34,16 +34,21 @@ static inline SCLPDevice *get_sclp_device(void)
|
||||
return sclp;
|
||||
}
|
||||
|
||||
static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int count)
|
||||
static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
uint8_t features[SCCB_CPU_FEATURE_LEN] = { 0 };
|
||||
int i;
|
||||
|
||||
s390_get_feat_block(S390_FEAT_TYPE_SCLP_CPU, features);
|
||||
for (i = 0; i < count; i++) {
|
||||
entry[i].address = i;
|
||||
entry[i].type = 0;
|
||||
memcpy(entry[i].features, features, sizeof(entry[i].features));
|
||||
for (i = 0, *count = 0; i < ms->possible_cpus->len; i++) {
|
||||
if (!ms->possible_cpus->cpus[i].cpu) {
|
||||
continue;
|
||||
}
|
||||
entry[*count].address = ms->possible_cpus->cpus[i].arch_id;
|
||||
entry[*count].type = 0;
|
||||
memcpy(entry[*count].features, features, sizeof(features));
|
||||
(*count)++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,17 +58,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
|
||||
ReadInfo *read_info = (ReadInfo *) sccb;
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
||||
CPUState *cpu;
|
||||
int cpu_count = 0;
|
||||
int cpu_count;
|
||||
int rnsize, rnmax;
|
||||
int slots = MIN(machine->ram_slots, s390_get_memslot_count());
|
||||
IplParameterBlock *ipib = s390_ipl_get_iplb();
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu_count++;
|
||||
}
|
||||
|
||||
/* CPU information */
|
||||
prepare_cpu_entries(sclp, read_info->entries, &cpu_count);
|
||||
read_info->entries_cpu = cpu_to_be16(cpu_count);
|
||||
read_info->offset_cpu = cpu_to_be16(offsetof(ReadInfo, entries));
|
||||
read_info->highest_cpu = cpu_to_be16(max_cpus);
|
||||
@@ -76,8 +77,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
|
||||
s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT,
|
||||
read_info->conf_char_ext);
|
||||
|
||||
prepare_cpu_entries(sclp, read_info->entries, cpu_count);
|
||||
|
||||
read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
|
||||
SCLP_HAS_IOA_RECONFIG);
|
||||
|
||||
@@ -333,13 +332,9 @@ static void unassign_storage(SCLPDevice *sclp, SCCB *sccb)
|
||||
static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb)
|
||||
{
|
||||
ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb;
|
||||
CPUState *cpu;
|
||||
int cpu_count = 0;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu_count++;
|
||||
}
|
||||
int cpu_count;
|
||||
|
||||
prepare_cpu_entries(sclp, cpu_info->entries, &cpu_count);
|
||||
cpu_info->nr_configured = cpu_to_be16(cpu_count);
|
||||
cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries));
|
||||
cpu_info->nr_standby = cpu_to_be16(0);
|
||||
@@ -348,7 +343,6 @@ static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb)
|
||||
cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured
|
||||
+ cpu_info->nr_configured*sizeof(CPUEntry));
|
||||
|
||||
prepare_cpu_entries(sclp, cpu_info->entries, cpu_count);
|
||||
|
||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
|
||||
}
|
||||
|
||||
@@ -487,7 +487,6 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
virtio_bus_get_vdev_config(&dev->bus, vdev->config);
|
||||
/* XXX config space endianness */
|
||||
cpu_physical_memory_write(ccw.cda, vdev->config, len);
|
||||
sch->curr_status.scsw.count = ccw.count - len;
|
||||
ret = 0;
|
||||
@@ -510,7 +509,6 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
len = hw_len;
|
||||
/* XXX config space endianness */
|
||||
memcpy(vdev->config, config, len);
|
||||
cpu_physical_memory_unmap(config, hw_len, 0, hw_len);
|
||||
virtio_bus_set_vdev_config(&dev->bus, vdev->config);
|
||||
@@ -1007,6 +1005,15 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void virtio_ccw_gpu_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
VirtIOGPUCcw *dev = VIRTIO_GPU_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
/* DeviceState to VirtioCcwDevice. Note: used on datapath,
|
||||
* be careful and test performance if you change this.
|
||||
*/
|
||||
@@ -1616,6 +1623,45 @@ static const TypeInfo virtio_ccw_crypto = {
|
||||
.class_init = virtio_ccw_crypto_class_init,
|
||||
};
|
||||
|
||||
static Property virtio_ccw_gpu_properties[] = {
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
|
||||
VIRTIO_CCW_MAX_REV),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void virtio_ccw_gpu_instance_init(Object *obj)
|
||||
{
|
||||
VirtIOGPUCcw *dev = VIRTIO_GPU_CCW(obj);
|
||||
VirtioCcwDevice *ccw_dev = VIRTIO_CCW_DEVICE(obj);
|
||||
|
||||
ccw_dev->force_revision_1 = true;
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_GPU);
|
||||
}
|
||||
|
||||
static void virtio_ccw_gpu_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
k->realize = virtio_ccw_gpu_realize;
|
||||
k->exit = virtio_ccw_exit;
|
||||
dc->reset = virtio_ccw_reset;
|
||||
dc->props = virtio_ccw_gpu_properties;
|
||||
dc->hotpluggable = false;
|
||||
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_ccw_gpu = {
|
||||
.name = TYPE_VIRTIO_GPU_CCW,
|
||||
.parent = TYPE_VIRTIO_CCW_DEVICE,
|
||||
.instance_size = sizeof(VirtIOGPUCcw),
|
||||
.instance_init = virtio_ccw_gpu_instance_init,
|
||||
.class_init = virtio_ccw_gpu_class_init,
|
||||
};
|
||||
|
||||
static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
|
||||
@@ -1815,6 +1861,7 @@ static void virtio_ccw_register(void)
|
||||
type_register_static(&vhost_vsock_ccw_info);
|
||||
#endif
|
||||
type_register_static(&virtio_ccw_crypto);
|
||||
type_register_static(&virtio_ccw_gpu);
|
||||
}
|
||||
|
||||
type_init(virtio_ccw_register)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#ifdef CONFIG_VHOST_VSOCK
|
||||
#include "hw/virtio/vhost-vsock.h"
|
||||
#endif /* CONFIG_VHOST_VSOCK */
|
||||
#include "hw/virtio/virtio-gpu.h"
|
||||
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "hw/s390x/css.h"
|
||||
@@ -223,4 +224,13 @@ typedef struct VHostVSockCCWState {
|
||||
|
||||
#endif /* CONFIG_VHOST_VSOCK */
|
||||
|
||||
#define TYPE_VIRTIO_GPU_CCW "virtio-gpu-ccw"
|
||||
#define VIRTIO_GPU_CCW(obj) \
|
||||
OBJECT_CHECK(VirtIOGPUCcw, (obj), TYPE_VIRTIO_GPU_CCW)
|
||||
|
||||
typedef struct VirtIOGPUCcw {
|
||||
VirtioCcwDevice parent_obj;
|
||||
VirtIOGPU vdev;
|
||||
} VirtIOGPUCcw;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -593,7 +593,7 @@ const VMStateDescription vmstate_esp = {
|
||||
};
|
||||
|
||||
#define TYPE_ESP "esp"
|
||||
#define ESP(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP)
|
||||
#define ESP_STATE(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP)
|
||||
|
||||
typedef struct {
|
||||
/*< private >*/
|
||||
@@ -644,7 +644,7 @@ void esp_init(hwaddr espaddr, int it_shift,
|
||||
ESPState *esp;
|
||||
|
||||
dev = qdev_create(NULL, TYPE_ESP);
|
||||
sysbus = ESP(dev);
|
||||
sysbus = ESP_STATE(dev);
|
||||
esp = &sysbus->esp;
|
||||
esp->dma_memory_read = dma_memory_read;
|
||||
esp->dma_memory_write = dma_memory_write;
|
||||
@@ -672,7 +672,7 @@ static const struct SCSIBusInfo esp_scsi_info = {
|
||||
|
||||
static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
|
||||
{
|
||||
SysBusESPState *sysbus = ESP(opaque);
|
||||
SysBusESPState *sysbus = ESP_STATE(opaque);
|
||||
ESPState *s = &sysbus->esp;
|
||||
|
||||
switch (irq) {
|
||||
@@ -688,7 +688,7 @@ static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
|
||||
static void sysbus_esp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
SysBusESPState *sysbus = ESP(dev);
|
||||
SysBusESPState *sysbus = ESP_STATE(dev);
|
||||
ESPState *s = &sysbus->esp;
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
@@ -706,7 +706,7 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
static void sysbus_esp_hard_reset(DeviceState *dev)
|
||||
{
|
||||
SysBusESPState *sysbus = ESP(dev);
|
||||
SysBusESPState *sysbus = ESP_STATE(dev);
|
||||
esp_hard_reset(&sysbus->esp);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "hw/pci/msix.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
#include "mfi.h"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "hw/pci/msi.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include "mptsas.h"
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "hw/pci/msi.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
#include "mptsas.h"
|
||||
@@ -1236,11 +1236,9 @@ static void *mptsas_load_request(QEMUFile *f, SCSIRequest *sreq)
|
||||
n = qemu_get_be32(f);
|
||||
/* TODO: add a way for SCSIBusInfo's load_request to fail,
|
||||
* and fail migration instead of asserting here.
|
||||
* When we do, we might be able to re-enable NDEBUG below.
|
||||
* This is just one thing (there are probably more) that must be
|
||||
* fixed before we can allow NDEBUG compilation.
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#error building with NDEBUG is not supported
|
||||
#endif
|
||||
assert(n >= 0);
|
||||
|
||||
pci_dma_sglist_init(&req->qsg, pci, n);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
@@ -516,8 +516,10 @@ static size_t scsi_sense_len(SCSIRequest *req)
|
||||
static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
{
|
||||
SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
|
||||
int fixed_sense = (req->cmd.buf[1] & 1) == 0;
|
||||
|
||||
if (req->lun != 0) {
|
||||
if (req->lun != 0 &&
|
||||
buf[0] != INQUIRY && buf[0] != REQUEST_SENSE) {
|
||||
scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
|
||||
scsi_req_complete(req, CHECK_CONDITION);
|
||||
return 0;
|
||||
@@ -535,9 +537,28 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
|
||||
break;
|
||||
case REQUEST_SENSE:
|
||||
scsi_target_alloc_buf(&r->req, scsi_sense_len(req));
|
||||
r->len = scsi_device_get_sense(r->req.dev, r->buf,
|
||||
MIN(req->cmd.xfer, r->buf_len),
|
||||
(req->cmd.buf[1] & 1) == 0);
|
||||
if (req->lun != 0) {
|
||||
const struct SCSISense sense = SENSE_CODE(LUN_NOT_SUPPORTED);
|
||||
|
||||
if (fixed_sense) {
|
||||
r->buf[0] = 0x70;
|
||||
r->buf[2] = sense.key;
|
||||
r->buf[10] = 10;
|
||||
r->buf[12] = sense.asc;
|
||||
r->buf[13] = sense.ascq;
|
||||
r->len = MIN(req->cmd.xfer, SCSI_SENSE_LEN);
|
||||
} else {
|
||||
r->buf[0] = 0x72;
|
||||
r->buf[1] = sense.key;
|
||||
r->buf[2] = sense.asc;
|
||||
r->buf[3] = sense.ascq;
|
||||
r->len = 8;
|
||||
}
|
||||
} else {
|
||||
r->len = scsi_device_get_sense(r->req.dev, r->buf,
|
||||
MIN(req->cmd.xfer, r->buf_len),
|
||||
fixed_sense);
|
||||
}
|
||||
if (r->req.dev->sense_is_ua) {
|
||||
scsi_device_unit_attention_reported(req->dev);
|
||||
r->req.dev->sense_len = 0;
|
||||
@@ -769,7 +790,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
|
||||
ret = scsi_convert_sense(req->sense, req->sense_len, buf, len, true);
|
||||
|
||||
/*
|
||||
* FIXME: clearing unit attention conditions upon autosense should be done
|
||||
@@ -790,20 +811,14 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
|
||||
|
||||
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
|
||||
{
|
||||
return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
|
||||
return scsi_convert_sense(dev->sense, dev->sense_len, buf, len, fixed);
|
||||
}
|
||||
|
||||
void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
|
||||
{
|
||||
trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
|
||||
sense.key, sense.asc, sense.ascq);
|
||||
memset(req->sense, 0, 18);
|
||||
req->sense[0] = 0x70;
|
||||
req->sense[2] = sense.key;
|
||||
req->sense[7] = 10;
|
||||
req->sense[12] = sense.asc;
|
||||
req->sense[13] = sense.ascq;
|
||||
req->sense_len = 18;
|
||||
req->sense_len = scsi_build_sense(req->sense, sense);
|
||||
}
|
||||
|
||||
static void scsi_req_enqueue_internal(SCSIRequest *req)
|
||||
@@ -935,36 +950,6 @@ static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf)
|
||||
return xfer * unit;
|
||||
}
|
||||
|
||||
uint32_t scsi_data_cdb_xfer(uint8_t *buf)
|
||||
{
|
||||
if ((buf[0] >> 5) == 0 && buf[4] == 0) {
|
||||
return 256;
|
||||
} else {
|
||||
return scsi_cdb_xfer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t scsi_cdb_xfer(uint8_t *buf)
|
||||
{
|
||||
switch (buf[0] >> 5) {
|
||||
case 0:
|
||||
return buf[4];
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
return lduw_be_p(&buf[7]);
|
||||
break;
|
||||
case 4:
|
||||
return ldl_be_p(&buf[10]) & 0xffffffffULL;
|
||||
break;
|
||||
case 5:
|
||||
return ldl_be_p(&buf[6]) & 0xffffffffULL;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
{
|
||||
cmd->xfer = scsi_cdb_xfer(buf);
|
||||
@@ -1277,53 +1262,6 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t scsi_cmd_lba(SCSICommand *cmd)
|
||||
{
|
||||
uint8_t *buf = cmd->buf;
|
||||
uint64_t lba;
|
||||
|
||||
switch (buf[0] >> 5) {
|
||||
case 0:
|
||||
lba = ldl_be_p(&buf[0]) & 0x1fffff;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 5:
|
||||
lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
|
||||
break;
|
||||
case 4:
|
||||
lba = ldq_be_p(&buf[2]);
|
||||
break;
|
||||
default:
|
||||
lba = -1;
|
||||
|
||||
}
|
||||
return lba;
|
||||
}
|
||||
|
||||
int scsi_cdb_length(uint8_t *buf) {
|
||||
int cdb_len;
|
||||
|
||||
switch (buf[0] >> 5) {
|
||||
case 0:
|
||||
cdb_len = 6;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
cdb_len = 10;
|
||||
break;
|
||||
case 4:
|
||||
cdb_len = 16;
|
||||
break;
|
||||
case 5:
|
||||
cdb_len = 12;
|
||||
break;
|
||||
default:
|
||||
cdb_len = -1;
|
||||
}
|
||||
return cdb_len;
|
||||
}
|
||||
|
||||
int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
|
||||
{
|
||||
int rc;
|
||||
@@ -1370,326 +1308,6 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Predefined sense codes
|
||||
*/
|
||||
|
||||
/* No sense data available */
|
||||
const struct SCSISense sense_code_NO_SENSE = {
|
||||
.key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
|
||||
};
|
||||
|
||||
/* LUN not ready, Manual intervention required */
|
||||
const struct SCSISense sense_code_LUN_NOT_READY = {
|
||||
.key = NOT_READY, .asc = 0x04, .ascq = 0x03
|
||||
};
|
||||
|
||||
/* LUN not ready, Medium not present */
|
||||
const struct SCSISense sense_code_NO_MEDIUM = {
|
||||
.key = NOT_READY, .asc = 0x3a, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* LUN not ready, medium removal prevented */
|
||||
const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
|
||||
.key = NOT_READY, .asc = 0x53, .ascq = 0x02
|
||||
};
|
||||
|
||||
/* Hardware error, internal target failure */
|
||||
const struct SCSISense sense_code_TARGET_FAILURE = {
|
||||
.key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Illegal request, invalid command operation code */
|
||||
const struct SCSISense sense_code_INVALID_OPCODE = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Illegal request, LBA out of range */
|
||||
const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Illegal request, Invalid field in CDB */
|
||||
const struct SCSISense sense_code_INVALID_FIELD = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Illegal request, Invalid field in parameter list */
|
||||
const struct SCSISense sense_code_INVALID_PARAM = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Illegal request, Parameter list length error */
|
||||
const struct SCSISense sense_code_INVALID_PARAM_LEN = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Illegal request, LUN not supported */
|
||||
const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Illegal request, Saving parameters not supported */
|
||||
const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Illegal request, Incompatible medium installed */
|
||||
const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Illegal request, medium removal prevented */
|
||||
const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
|
||||
};
|
||||
|
||||
/* Illegal request, Invalid Transfer Tag */
|
||||
const struct SCSISense sense_code_INVALID_TAG = {
|
||||
.key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
|
||||
};
|
||||
|
||||
/* Command aborted, I/O process terminated */
|
||||
const struct SCSISense sense_code_IO_ERROR = {
|
||||
.key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
|
||||
};
|
||||
|
||||
/* Command aborted, I_T Nexus loss occurred */
|
||||
const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
|
||||
.key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
|
||||
};
|
||||
|
||||
/* Command aborted, Logical Unit failure */
|
||||
const struct SCSISense sense_code_LUN_FAILURE = {
|
||||
.key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
|
||||
};
|
||||
|
||||
/* Command aborted, Overlapped Commands Attempted */
|
||||
const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
|
||||
.key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Unit attention, Capacity data has changed */
|
||||
const struct SCSISense sense_code_CAPACITY_CHANGED = {
|
||||
.key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
|
||||
};
|
||||
|
||||
/* Unit attention, Power on, reset or bus device reset occurred */
|
||||
const struct SCSISense sense_code_RESET = {
|
||||
.key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Unit attention, No medium */
|
||||
const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
|
||||
.key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Unit attention, Medium may have changed */
|
||||
const struct SCSISense sense_code_MEDIUM_CHANGED = {
|
||||
.key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Unit attention, Reported LUNs data has changed */
|
||||
const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
|
||||
.key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
|
||||
};
|
||||
|
||||
/* Unit attention, Device internal reset */
|
||||
const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
|
||||
.key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
|
||||
};
|
||||
|
||||
/* Data Protection, Write Protected */
|
||||
const struct SCSISense sense_code_WRITE_PROTECTED = {
|
||||
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
|
||||
};
|
||||
|
||||
/* Data Protection, Space Allocation Failed Write Protect */
|
||||
const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
|
||||
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
|
||||
};
|
||||
|
||||
/*
|
||||
* scsi_build_sense
|
||||
*
|
||||
* Convert between fixed and descriptor sense buffers
|
||||
*/
|
||||
int scsi_build_sense(uint8_t *in_buf, int in_len,
|
||||
uint8_t *buf, int len, bool fixed)
|
||||
{
|
||||
bool fixed_in;
|
||||
SCSISense sense;
|
||||
if (!fixed && len < 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_len == 0) {
|
||||
sense.key = NO_SENSE;
|
||||
sense.asc = 0;
|
||||
sense.ascq = 0;
|
||||
} else {
|
||||
fixed_in = (in_buf[0] & 2) == 0;
|
||||
|
||||
if (fixed == fixed_in) {
|
||||
memcpy(buf, in_buf, MIN(len, in_len));
|
||||
return MIN(len, in_len);
|
||||
}
|
||||
|
||||
if (fixed_in) {
|
||||
sense.key = in_buf[2];
|
||||
sense.asc = in_buf[12];
|
||||
sense.ascq = in_buf[13];
|
||||
} else {
|
||||
sense.key = in_buf[1];
|
||||
sense.asc = in_buf[2];
|
||||
sense.ascq = in_buf[3];
|
||||
}
|
||||
}
|
||||
|
||||
memset(buf, 0, len);
|
||||
if (fixed) {
|
||||
/* Return fixed format sense buffer */
|
||||
buf[0] = 0x70;
|
||||
buf[2] = sense.key;
|
||||
buf[7] = 10;
|
||||
buf[12] = sense.asc;
|
||||
buf[13] = sense.ascq;
|
||||
return MIN(len, SCSI_SENSE_LEN);
|
||||
} else {
|
||||
/* Return descriptor format sense buffer */
|
||||
buf[0] = 0x72;
|
||||
buf[1] = sense.key;
|
||||
buf[2] = sense.asc;
|
||||
buf[3] = sense.ascq;
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
const char *scsi_command_name(uint8_t cmd)
|
||||
{
|
||||
static const char *names[] = {
|
||||
[ TEST_UNIT_READY ] = "TEST_UNIT_READY",
|
||||
[ REWIND ] = "REWIND",
|
||||
[ REQUEST_SENSE ] = "REQUEST_SENSE",
|
||||
[ FORMAT_UNIT ] = "FORMAT_UNIT",
|
||||
[ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS",
|
||||
[ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
|
||||
/* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
|
||||
[ READ_6 ] = "READ_6",
|
||||
[ WRITE_6 ] = "WRITE_6",
|
||||
[ SET_CAPACITY ] = "SET_CAPACITY",
|
||||
[ READ_REVERSE ] = "READ_REVERSE",
|
||||
[ WRITE_FILEMARKS ] = "WRITE_FILEMARKS",
|
||||
[ SPACE ] = "SPACE",
|
||||
[ INQUIRY ] = "INQUIRY",
|
||||
[ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA",
|
||||
[ MAINTENANCE_IN ] = "MAINTENANCE_IN",
|
||||
[ MAINTENANCE_OUT ] = "MAINTENANCE_OUT",
|
||||
[ MODE_SELECT ] = "MODE_SELECT",
|
||||
[ RESERVE ] = "RESERVE",
|
||||
[ RELEASE ] = "RELEASE",
|
||||
[ COPY ] = "COPY",
|
||||
[ ERASE ] = "ERASE",
|
||||
[ MODE_SENSE ] = "MODE_SENSE",
|
||||
[ START_STOP ] = "START_STOP/LOAD_UNLOAD",
|
||||
/* LOAD_UNLOAD and START_STOP use the same operation code */
|
||||
[ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC",
|
||||
[ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC",
|
||||
[ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL",
|
||||
[ READ_CAPACITY_10 ] = "READ_CAPACITY_10",
|
||||
[ READ_10 ] = "READ_10",
|
||||
[ WRITE_10 ] = "WRITE_10",
|
||||
[ SEEK_10 ] = "SEEK_10/POSITION_TO_ELEMENT",
|
||||
/* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
|
||||
[ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10",
|
||||
[ VERIFY_10 ] = "VERIFY_10",
|
||||
[ SEARCH_HIGH ] = "SEARCH_HIGH",
|
||||
[ SEARCH_EQUAL ] = "SEARCH_EQUAL",
|
||||
[ SEARCH_LOW ] = "SEARCH_LOW",
|
||||
[ SET_LIMITS ] = "SET_LIMITS",
|
||||
[ PRE_FETCH ] = "PRE_FETCH/READ_POSITION",
|
||||
/* READ_POSITION and PRE_FETCH use the same operation code */
|
||||
[ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE",
|
||||
[ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE",
|
||||
[ READ_DEFECT_DATA ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
|
||||
/* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
|
||||
[ MEDIUM_SCAN ] = "MEDIUM_SCAN",
|
||||
[ COMPARE ] = "COMPARE",
|
||||
[ COPY_VERIFY ] = "COPY_VERIFY",
|
||||
[ WRITE_BUFFER ] = "WRITE_BUFFER",
|
||||
[ READ_BUFFER ] = "READ_BUFFER",
|
||||
[ UPDATE_BLOCK ] = "UPDATE_BLOCK",
|
||||
[ READ_LONG_10 ] = "READ_LONG_10",
|
||||
[ WRITE_LONG_10 ] = "WRITE_LONG_10",
|
||||
[ CHANGE_DEFINITION ] = "CHANGE_DEFINITION",
|
||||
[ WRITE_SAME_10 ] = "WRITE_SAME_10",
|
||||
[ UNMAP ] = "UNMAP",
|
||||
[ READ_TOC ] = "READ_TOC",
|
||||
[ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT",
|
||||
[ SANITIZE ] = "SANITIZE",
|
||||
[ GET_CONFIGURATION ] = "GET_CONFIGURATION",
|
||||
[ LOG_SELECT ] = "LOG_SELECT",
|
||||
[ LOG_SENSE ] = "LOG_SENSE",
|
||||
[ MODE_SELECT_10 ] = "MODE_SELECT_10",
|
||||
[ RESERVE_10 ] = "RESERVE_10",
|
||||
[ RELEASE_10 ] = "RELEASE_10",
|
||||
[ MODE_SENSE_10 ] = "MODE_SENSE_10",
|
||||
[ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN",
|
||||
[ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT",
|
||||
[ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16",
|
||||
[ EXTENDED_COPY ] = "EXTENDED_COPY",
|
||||
[ ATA_PASSTHROUGH_16 ] = "ATA_PASSTHROUGH_16",
|
||||
[ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN",
|
||||
[ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT",
|
||||
[ READ_16 ] = "READ_16",
|
||||
[ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE",
|
||||
[ WRITE_16 ] = "WRITE_16",
|
||||
[ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
|
||||
[ VERIFY_16 ] = "VERIFY_16",
|
||||
[ PRE_FETCH_16 ] = "PRE_FETCH_16",
|
||||
[ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
|
||||
/* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
|
||||
[ LOCATE_16 ] = "LOCATE_16",
|
||||
[ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16",
|
||||
/* ERASE_16 and WRITE_SAME_16 use the same operation code */
|
||||
[ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
|
||||
[ WRITE_LONG_16 ] = "WRITE_LONG_16",
|
||||
[ REPORT_LUNS ] = "REPORT_LUNS",
|
||||
[ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12",
|
||||
[ MOVE_MEDIUM ] = "MOVE_MEDIUM",
|
||||
[ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM",
|
||||
[ READ_12 ] = "READ_12",
|
||||
[ WRITE_12 ] = "WRITE_12",
|
||||
[ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE",
|
||||
/* ERASE_12 and GET_PERFORMANCE use the same operation code */
|
||||
[ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12",
|
||||
[ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
|
||||
[ VERIFY_12 ] = "VERIFY_12",
|
||||
[ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12",
|
||||
[ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12",
|
||||
[ SEARCH_LOW_12 ] = "SEARCH_LOW_12",
|
||||
[ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS",
|
||||
[ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING",
|
||||
/* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
|
||||
[ READ_CD ] = "READ_CD",
|
||||
[ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12",
|
||||
[ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE",
|
||||
[ RESERVE_TRACK ] = "RESERVE_TRACK",
|
||||
[ SEND_CUE_SHEET ] = "SEND_CUE_SHEET",
|
||||
[ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE",
|
||||
[ SET_CD_SPEED ] = "SET_CD_SPEED",
|
||||
[ SET_READ_AHEAD ] = "SET_READ_AHEAD",
|
||||
[ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE",
|
||||
[ MECHANISM_STATUS ] = "MECHANISM_STATUS",
|
||||
[ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
|
||||
[ READ_DISC_INFORMATION ] = "READ_DISC_INFORMATION",
|
||||
};
|
||||
|
||||
if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
|
||||
return "*UNKNOWN*";
|
||||
return names[cmd];
|
||||
}
|
||||
|
||||
SCSIRequest *scsi_req_ref(SCSIRequest *req)
|
||||
{
|
||||
assert(req->refcount > 0);
|
||||
|
||||
@@ -32,7 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
@@ -106,7 +106,7 @@ typedef struct SCSIDiskState
|
||||
bool tray_locked;
|
||||
} SCSIDiskState;
|
||||
|
||||
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed);
|
||||
static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed);
|
||||
|
||||
static void scsi_free_request(SCSIRequest *req)
|
||||
{
|
||||
@@ -184,19 +184,10 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret < 0 || (r->status && *r->status)) {
|
||||
return scsi_handle_rw_error(r, -ret, acct_failed);
|
||||
}
|
||||
|
||||
if (r->status && *r->status) {
|
||||
if (acct_failed) {
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
|
||||
}
|
||||
scsi_req_complete(&r->req, *r->status);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -422,13 +413,13 @@ static void scsi_read_data(SCSIRequest *req)
|
||||
}
|
||||
|
||||
/*
|
||||
* scsi_handle_rw_error has two return values. 0 means that the error
|
||||
* must be ignored, 1 means that the error has been processed and the
|
||||
* scsi_handle_rw_error has two return values. False means that the error
|
||||
* must be ignored, true means that the error has been processed and the
|
||||
* caller should not do anything else for this request. Note that
|
||||
* scsi_handle_rw_error always manages its reference counts, independent
|
||||
* of the return value.
|
||||
*/
|
||||
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
|
||||
static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
|
||||
{
|
||||
bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV);
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||
@@ -440,6 +431,11 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
|
||||
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
|
||||
}
|
||||
switch (error) {
|
||||
case 0:
|
||||
/* The command has run, no need to fake sense. */
|
||||
assert(r->status && *r->status);
|
||||
scsi_req_complete(&r->req, *r->status);
|
||||
break;
|
||||
case ENOMEDIUM:
|
||||
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
|
||||
break;
|
||||
@@ -457,6 +453,18 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!error) {
|
||||
assert(r->status && *r->status);
|
||||
error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
|
||||
|
||||
if (error == ECANCELED || error == EAGAIN || error == ENOTCONN ||
|
||||
error == 0) {
|
||||
/* These errors are handled by guest. */
|
||||
scsi_req_complete(&r->req, *r->status);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
blk_error_action(s->qdev.conf.blk, action, is_read, error);
|
||||
if (action == BLOCK_ERROR_ACTION_STOP) {
|
||||
scsi_req_retry(&r->req);
|
||||
@@ -1978,8 +1986,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
||||
break;
|
||||
case REQUEST_SENSE:
|
||||
/* Just return "NO SENSE". */
|
||||
buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
|
||||
(req->cmd.buf[1] & 1) == 0);
|
||||
buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen,
|
||||
(req->cmd.buf[1] & 1) == 0);
|
||||
if (buflen < 0) {
|
||||
goto illegal_request;
|
||||
}
|
||||
@@ -2972,6 +2980,7 @@ static const TypeInfo scsi_cd_info = {
|
||||
|
||||
#ifdef __linux__
|
||||
static Property scsi_block_properties[] = {
|
||||
DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \
|
||||
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -34,15 +34,7 @@ do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
|
||||
do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
|
||||
|
||||
#include <scsi/sg.h>
|
||||
#include "block/scsi.h"
|
||||
|
||||
#define SG_ERR_DRIVER_TIMEOUT 0x06
|
||||
#define SG_ERR_DRIVER_SENSE 0x08
|
||||
|
||||
#define SG_ERR_DID_OK 0x00
|
||||
#define SG_ERR_DID_NO_CONNECT 0x01
|
||||
#define SG_ERR_DID_BUS_BUSY 0x02
|
||||
#define SG_ERR_DID_TIME_OUT 0x03
|
||||
#include "scsi/constants.h"
|
||||
|
||||
#ifndef MAX_UINT
|
||||
#define MAX_UINT ((unsigned int)-1)
|
||||
@@ -89,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req)
|
||||
static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
|
||||
{
|
||||
int status;
|
||||
SCSISense sense;
|
||||
|
||||
assert(r->req.aiocb == NULL);
|
||||
|
||||
@@ -96,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
|
||||
scsi_req_cancel_complete(&r->req);
|
||||
goto done;
|
||||
}
|
||||
if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
|
||||
r->req.sense_len = r->io_header.sb_len_wr;
|
||||
status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
|
||||
if (status == CHECK_CONDITION) {
|
||||
if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
|
||||
r->req.sense_len = r->io_header.sb_len_wr;
|
||||
} else {
|
||||
scsi_req_build_sense(&r->req, sense);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
switch (ret) {
|
||||
case -EDOM:
|
||||
status = TASK_SET_FULL;
|
||||
break;
|
||||
case -ENOMEM:
|
||||
status = CHECK_CONDITION;
|
||||
scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
|
||||
break;
|
||||
default:
|
||||
status = CHECK_CONDITION;
|
||||
scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
|
||||
r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
|
||||
r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
|
||||
(r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
|
||||
status = BUSY;
|
||||
BADF("Driver Timeout\n");
|
||||
} else if (r->io_header.host_status) {
|
||||
status = CHECK_CONDITION;
|
||||
scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
|
||||
} else if (r->io_header.status) {
|
||||
status = r->io_header.status;
|
||||
} else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
|
||||
status = CHECK_CONDITION;
|
||||
} else {
|
||||
status = GOOD;
|
||||
}
|
||||
}
|
||||
DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
|
||||
r, r->req.tag, status);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "cpu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "srp.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "qemu/iov.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
|
||||
@@ -867,10 +867,10 @@ void virtio_scsi_common_realize(DeviceState *dev,
|
||||
s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
|
||||
s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
|
||||
|
||||
s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, ctrl);
|
||||
s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, evt);
|
||||
s->ctrl_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, ctrl);
|
||||
s->event_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, evt);
|
||||
for (i = 0; i < s->conf.num_queues; i++) {
|
||||
s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, cmd);
|
||||
s->cmd_vqs[i] = virtio_add_queue(vdev, s->conf.virtqueue_size, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,6 +917,8 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
|
||||
|
||||
static Property virtio_scsi_properties[] = {
|
||||
DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1),
|
||||
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
|
||||
parent_obj.conf.virtqueue_size, 128),
|
||||
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
|
||||
0xFFFF),
|
||||
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "vmw_pvscsi.h"
|
||||
#include "trace.h"
|
||||
|
||||
@@ -427,7 +427,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
unsigned int i;
|
||||
uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
|
||||
PCIBus *pci_bus, *pci_busA, *pci_busB;
|
||||
PCIDevice *ebus;
|
||||
PCIDevice *ebus, *pci_dev;
|
||||
ISABus *isa_bus;
|
||||
SysBusDevice *s;
|
||||
qemu_irq *ivec_irqs, *pbm_irqs;
|
||||
@@ -435,6 +435,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
DriveInfo *fd[MAX_FD];
|
||||
DeviceState *dev;
|
||||
FWCfgState *fw_cfg;
|
||||
NICInfo *nd;
|
||||
int onboard_nic_idx;
|
||||
|
||||
/* init CPUs */
|
||||
cpu = sparc64_cpu_devinit(machine->cpu_model, hwdef->default_cpu_model,
|
||||
@@ -464,8 +466,23 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
serial_hds_isa_init(isa_bus, i, MAX_SERIAL_PORTS);
|
||||
parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
|
||||
|
||||
for(i = 0; i < nb_nics; i++)
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
|
||||
onboard_nic_idx = -1;
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
nd = &nd_table[i];
|
||||
|
||||
if (onboard_nic_idx == -1 &&
|
||||
(!nd->model || strcmp(nd->model, "sunhme") == 0)) {
|
||||
pci_dev = pci_create(pci_bus, -1, "sunhme");
|
||||
dev = &pci_dev->qdev;
|
||||
qdev_set_nic_properties(dev, nd);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
onboard_nic_idx = i;
|
||||
} else {
|
||||
pci_nic_init_nofail(nd, pci_bus, "ne2k_pci", NULL);
|
||||
}
|
||||
}
|
||||
onboard_nic_idx = MAX(onboard_nic_idx, 0);
|
||||
|
||||
ide_drive_get(hd, ARRAY_SIZE(hd));
|
||||
|
||||
@@ -510,7 +527,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
/* XXX: need an option to load a NVRAM image */
|
||||
0,
|
||||
graphic_width, graphic_height, graphic_depth,
|
||||
(uint8_t *)&nd_table[0].macaddr);
|
||||
(uint8_t *)&nd_table[onboard_nic_idx].macaddr);
|
||||
|
||||
dev = qdev_create(NULL, TYPE_FW_CFG_IO);
|
||||
qdev_prop_set_bit(dev, "dma_enabled", false);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "hw/usb.h"
|
||||
#include "hw/usb/desc.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "hw/usb/ehci-regs.h"
|
||||
#include "hw/usb/hcd-ehci.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define FRAME_TIMER_FREQ 1000
|
||||
#define FRAME_TIMER_NS (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ)
|
||||
@@ -348,7 +349,7 @@ static void ehci_trace_sitd(EHCIState *s, hwaddr addr,
|
||||
static void ehci_trace_guest_bug(EHCIState *s, const char *message)
|
||||
{
|
||||
trace_usb_ehci_guest_bug(message);
|
||||
fprintf(stderr, "ehci warning: %s\n", message);
|
||||
warn_report("%s", message);
|
||||
}
|
||||
|
||||
static inline bool ehci_enabled(EHCIState *s)
|
||||
@@ -1728,7 +1729,7 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
|
||||
/* siTD is not active, nothing to do */;
|
||||
} else {
|
||||
/* TODO: split transfers are not implemented */
|
||||
fprintf(stderr, "WARNING: Skipping active siTD\n");
|
||||
warn_report("Skipping active siTD");
|
||||
}
|
||||
|
||||
ehci_set_fetch_addr(ehci, async, sitd.next);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi-event.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
@@ -292,7 +293,7 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
|
||||
s->stats_vq_offset = offset;
|
||||
|
||||
if (qemu_gettimeofday(&tv) < 0) {
|
||||
fprintf(stderr, "warning: %s: failed to get time of day\n", __func__);
|
||||
warn_report("%s: failed to get time of day", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@@ -1025,11 +1025,9 @@ void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz)
|
||||
|
||||
/* TODO: teach all callers that this can fail, and return failure instead
|
||||
* of asserting here.
|
||||
* When we do, we might be able to re-enable NDEBUG below.
|
||||
* This is just one thing (there are probably more) that must be
|
||||
* fixed before we can allow NDEBUG compilation.
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#error building with NDEBUG is not supported
|
||||
#endif
|
||||
assert(ARRAY_SIZE(data.in_addr) >= data.in_num);
|
||||
assert(ARRAY_SIZE(data.out_addr) >= data.out_num);
|
||||
|
||||
|
||||
@@ -180,6 +180,7 @@ typedef struct XenPTMSI {
|
||||
uint32_t addr_hi; /* guest message upper address */
|
||||
uint16_t data; /* guest message data */
|
||||
uint32_t ctrl_offset; /* saved control offset */
|
||||
uint32_t mask; /* guest mask bits */
|
||||
int pirq; /* guest pirq corresponding */
|
||||
bool initialized; /* when guest MSI is initialized */
|
||||
bool mapped; /* when pirq is mapped */
|
||||
|
||||
@@ -1315,6 +1315,22 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xen_pt_mask_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||
uint32_t *val, uint32_t dev_value,
|
||||
uint32_t valid_mask)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = xen_pt_long_reg_write(s, cfg_entry, val, dev_value, valid_mask);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
s->msi->mask = *val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MSI Capability Structure reg static information table */
|
||||
static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||
/* Next Pointer reg */
|
||||
@@ -1393,7 +1409,7 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||
.emu_mask = 0xFFFFFFFF,
|
||||
.init = xen_pt_mask_reg_init,
|
||||
.u.dw.read = xen_pt_long_reg_read,
|
||||
.u.dw.write = xen_pt_long_reg_write,
|
||||
.u.dw.write = xen_pt_mask_reg_write,
|
||||
},
|
||||
/* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
|
||||
{
|
||||
@@ -1404,7 +1420,7 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||
.emu_mask = 0xFFFFFFFF,
|
||||
.init = xen_pt_mask_reg_init,
|
||||
.u.dw.read = xen_pt_long_reg_read,
|
||||
.u.dw.write = xen_pt_long_reg_write,
|
||||
.u.dw.write = xen_pt_mask_reg_write,
|
||||
},
|
||||
/* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define XEN_PT_GFLAGS_SHIFT_DM 9
|
||||
#define XEN_PT_GFLAGSSHIFT_DELIV_MODE 12
|
||||
#define XEN_PT_GFLAGSSHIFT_TRG_MODE 15
|
||||
#define XEN_PT_GFLAGSSHIFT_UNMASKED 16
|
||||
|
||||
#define latch(fld) latch[PCI_MSIX_ENTRY_##fld / sizeof(uint32_t)]
|
||||
|
||||
@@ -155,7 +156,8 @@ static int msi_msix_update(XenPCIPassthroughState *s,
|
||||
int pirq,
|
||||
bool is_msix,
|
||||
int msix_entry,
|
||||
int *old_pirq)
|
||||
int *old_pirq,
|
||||
bool masked)
|
||||
{
|
||||
PCIDevice *d = &s->dev;
|
||||
uint8_t gvec = msi_vector(data);
|
||||
@@ -171,6 +173,8 @@ static int msi_msix_update(XenPCIPassthroughState *s,
|
||||
table_addr = s->msix->mmio_base_addr;
|
||||
}
|
||||
|
||||
gflags |= masked ? 0 : (1u << XEN_PT_GFLAGSSHIFT_UNMASKED);
|
||||
|
||||
rc = xc_domain_update_msi_irq(xen_xc, xen_domid, gvec,
|
||||
pirq, gflags, table_addr);
|
||||
|
||||
@@ -273,8 +277,10 @@ int xen_pt_msi_setup(XenPCIPassthroughState *s)
|
||||
int xen_pt_msi_update(XenPCIPassthroughState *s)
|
||||
{
|
||||
XenPTMSI *msi = s->msi;
|
||||
|
||||
/* Current MSI emulation in QEMU only supports 1 vector */
|
||||
return msi_msix_update(s, msi_addr64(msi), msi->data, msi->pirq,
|
||||
false, 0, &msi->pirq);
|
||||
false, 0, &msi->pirq, msi->mask & 1);
|
||||
}
|
||||
|
||||
void xen_pt_msi_disable(XenPCIPassthroughState *s)
|
||||
@@ -355,7 +361,8 @@ static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr,
|
||||
}
|
||||
|
||||
rc = msi_msix_update(s, entry->addr, entry->data, pirq, true,
|
||||
entry_nr, &entry->pirq);
|
||||
entry_nr, &entry->pirq,
|
||||
vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT);
|
||||
|
||||
if (!rc) {
|
||||
entry->updated = false;
|
||||
|
||||
@@ -371,6 +371,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
|
||||
|
||||
#define PC_COMPAT_2_10 \
|
||||
HW_COMPAT_2_10 \
|
||||
{\
|
||||
.driver = TYPE_X86_CPU,\
|
||||
.property = "x-hv-max-vps",\
|
||||
.value = "0x40",\
|
||||
},
|
||||
|
||||
#define PC_COMPAT_2_9 \
|
||||
HW_COMPAT_2_9 \
|
||||
|
||||
@@ -11,12 +11,10 @@
|
||||
#include "sysemu/dma.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "block/scsi.h"
|
||||
#include "scsi/constants.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
/* debug IDE devices */
|
||||
//#define DEBUG_IDE
|
||||
//#define DEBUG_IDE_ATAPI
|
||||
//#define DEBUG_AIO
|
||||
#define USE_DMA_CDROM
|
||||
|
||||
typedef struct IDEBus IDEBus;
|
||||
@@ -335,12 +333,16 @@ struct unreported_events {
|
||||
};
|
||||
|
||||
enum ide_dma_cmd {
|
||||
IDE_DMA_READ,
|
||||
IDE_DMA__BEGIN = 0,
|
||||
IDE_DMA_READ = IDE_DMA__BEGIN,
|
||||
IDE_DMA_WRITE,
|
||||
IDE_DMA_TRIM,
|
||||
IDE_DMA_ATAPI,
|
||||
IDE_DMA__COUNT
|
||||
};
|
||||
|
||||
extern const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT];
|
||||
|
||||
#define ide_cmd_is_read(s) \
|
||||
((s)->dma_cmd == IDE_DMA_READ)
|
||||
|
||||
@@ -495,7 +497,7 @@ struct IDEBus {
|
||||
|
||||
typedef struct IDEDeviceClass {
|
||||
DeviceClass parent_class;
|
||||
int (*init)(IDEDevice *dev);
|
||||
void (*realize)(IDEDevice *dev, Error **errp);
|
||||
} IDEDeviceClass;
|
||||
|
||||
struct IDEDevice {
|
||||
@@ -605,7 +607,7 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
|
||||
const char *version, const char *serial, const char *model,
|
||||
uint64_t wwn,
|
||||
uint32_t cylinders, uint32_t heads, uint32_t secs,
|
||||
int chs_trans);
|
||||
int chs_trans, Error **errp);
|
||||
void ide_init2(IDEBus *bus, qemu_irq irq);
|
||||
void ide_exit(IDEState *s);
|
||||
void ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2);
|
||||
|
||||
@@ -104,6 +104,10 @@
|
||||
#define RTL8211E_PHYID1 0x001c
|
||||
#define RTL8211E_PHYID2 0xc915
|
||||
|
||||
/* National Semiconductor DP83840 */
|
||||
#define DP83840_PHYID1 0x2000
|
||||
#define DP83840_PHYID2 0x5c01
|
||||
|
||||
/* National Semiconductor DP83848 */
|
||||
#define DP83848_PHYID1 0x2000
|
||||
#define DP83848_PHYID2 0x5c90
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
|
||||
#define PCI_VENDOR_ID_SUN 0x108e
|
||||
#define PCI_DEVICE_ID_SUN_EBUS 0x1000
|
||||
#define PCI_DEVICE_ID_SUN_HME 0x1001
|
||||
#define PCI_DEVICE_ID_SUN_SIMBA 0x5000
|
||||
#define PCI_DEVICE_ID_SUN_SABRE 0xa000
|
||||
|
||||
|
||||
@@ -56,4 +56,6 @@ bool gs_allowed(void);
|
||||
*/
|
||||
bool css_migration_enabled(void);
|
||||
|
||||
void subsystem_reset(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "target/s390x/cpu-qom.h"
|
||||
|
||||
#define SCLP_CMD_CODE_MASK 0xffff00ff
|
||||
|
||||
@@ -242,5 +243,6 @@ sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void);
|
||||
sclpMemoryHotplugDev *get_sclp_memory_hotplug_dev(void);
|
||||
void sclp_service_interrupt(uint32_t sccb);
|
||||
void raise_irq_cpu_hotplug(void);
|
||||
int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,45 +4,20 @@
|
||||
#include "hw/qdev.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "scsi/utils.h"
|
||||
#include "qemu/notify.h"
|
||||
|
||||
#define MAX_SCSI_DEVS 255
|
||||
|
||||
#define SCSI_CMD_BUF_SIZE 16
|
||||
#define SCSI_SENSE_LEN 18
|
||||
#define SCSI_SENSE_LEN_SCANNER 32
|
||||
#define SCSI_INQUIRY_LEN 36
|
||||
|
||||
typedef struct SCSIBus SCSIBus;
|
||||
typedef struct SCSIBusInfo SCSIBusInfo;
|
||||
typedef struct SCSICommand SCSICommand;
|
||||
typedef struct SCSIDevice SCSIDevice;
|
||||
typedef struct SCSIRequest SCSIRequest;
|
||||
typedef struct SCSIReqOps SCSIReqOps;
|
||||
|
||||
enum SCSIXferMode {
|
||||
SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */
|
||||
SCSI_XFER_FROM_DEV, /* READ, INQUIRY, MODE_SENSE, ... */
|
||||
SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */
|
||||
};
|
||||
|
||||
typedef struct SCSISense {
|
||||
uint8_t key;
|
||||
uint8_t asc;
|
||||
uint8_t ascq;
|
||||
} SCSISense;
|
||||
|
||||
#define SCSI_SENSE_BUF_SIZE_OLD 96
|
||||
#define SCSI_SENSE_BUF_SIZE 252
|
||||
|
||||
struct SCSICommand {
|
||||
uint8_t buf[SCSI_CMD_BUF_SIZE];
|
||||
int len;
|
||||
size_t xfer;
|
||||
uint64_t lba;
|
||||
enum SCSIXferMode mode;
|
||||
};
|
||||
|
||||
struct SCSIRequest {
|
||||
SCSIBus *bus;
|
||||
SCSIDevice *dev;
|
||||
@@ -180,73 +155,6 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
|
||||
void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated);
|
||||
void scsi_legacy_handle_cmdline(void);
|
||||
|
||||
/*
|
||||
* Predefined sense codes
|
||||
*/
|
||||
|
||||
/* No sense data available */
|
||||
extern const struct SCSISense sense_code_NO_SENSE;
|
||||
/* LUN not ready, Manual intervention required */
|
||||
extern const struct SCSISense sense_code_LUN_NOT_READY;
|
||||
/* LUN not ready, Medium not present */
|
||||
extern const struct SCSISense sense_code_NO_MEDIUM;
|
||||
/* LUN not ready, medium removal prevented */
|
||||
extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
|
||||
/* Hardware error, internal target failure */
|
||||
extern const struct SCSISense sense_code_TARGET_FAILURE;
|
||||
/* Illegal request, invalid command operation code */
|
||||
extern const struct SCSISense sense_code_INVALID_OPCODE;
|
||||
/* Illegal request, LBA out of range */
|
||||
extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
|
||||
/* Illegal request, Invalid field in CDB */
|
||||
extern const struct SCSISense sense_code_INVALID_FIELD;
|
||||
/* Illegal request, Invalid field in parameter list */
|
||||
extern const struct SCSISense sense_code_INVALID_PARAM;
|
||||
/* Illegal request, Parameter list length error */
|
||||
extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
|
||||
/* Illegal request, LUN not supported */
|
||||
extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
|
||||
/* Illegal request, Saving parameters not supported */
|
||||
extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
|
||||
/* Illegal request, Incompatible format */
|
||||
extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
|
||||
/* Illegal request, medium removal prevented */
|
||||
extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
|
||||
/* Illegal request, Invalid Transfer Tag */
|
||||
extern const struct SCSISense sense_code_INVALID_TAG;
|
||||
/* Command aborted, I/O process terminated */
|
||||
extern const struct SCSISense sense_code_IO_ERROR;
|
||||
/* Command aborted, I_T Nexus loss occurred */
|
||||
extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
|
||||
/* Command aborted, Logical Unit failure */
|
||||
extern const struct SCSISense sense_code_LUN_FAILURE;
|
||||
/* Command aborted, Overlapped Commands Attempted */
|
||||
extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
|
||||
/* LUN not ready, Capacity data has changed */
|
||||
extern const struct SCSISense sense_code_CAPACITY_CHANGED;
|
||||
/* LUN not ready, Medium not present */
|
||||
extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
|
||||
/* Unit attention, Power on, reset or bus device reset occurred */
|
||||
extern const struct SCSISense sense_code_RESET;
|
||||
/* Unit attention, Medium may have changed*/
|
||||
extern const struct SCSISense sense_code_MEDIUM_CHANGED;
|
||||
/* Unit attention, Reported LUNs data has changed */
|
||||
extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
|
||||
/* Unit attention, Device internal reset */
|
||||
extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
|
||||
/* Data Protection, Write Protected */
|
||||
extern const struct SCSISense sense_code_WRITE_PROTECTED;
|
||||
/* Data Protection, Space Allocation Failed Write Protect */
|
||||
extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
|
||||
|
||||
#define SENSE_CODE(x) sense_code_ ## x
|
||||
|
||||
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_build_sense(uint8_t *in_buf, int in_len,
|
||||
uint8_t *buf, int len, bool fixed);
|
||||
|
||||
SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
|
||||
uint32_t tag, uint32_t lun, void *hba_private);
|
||||
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#define VIRTIO_SCSI(obj) \
|
||||
OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI)
|
||||
|
||||
#define VIRTIO_SCSI_VQ_SIZE 128
|
||||
#define VIRTIO_SCSI_MAX_CHANNEL 0
|
||||
#define VIRTIO_SCSI_MAX_TARGET 255
|
||||
#define VIRTIO_SCSI_MAX_LUN 16383
|
||||
@@ -48,6 +47,7 @@ typedef struct virtio_scsi_config VirtIOSCSIConfig;
|
||||
|
||||
struct VirtIOSCSIConf {
|
||||
uint32_t num_queues;
|
||||
uint32_t virtqueue_size;
|
||||
uint32_t max_sectors;
|
||||
uint32_t cmd_per_lun;
|
||||
#ifdef CONFIG_VHOST_SCSI
|
||||
|
||||
@@ -107,6 +107,22 @@ extern int daemon(int, int);
|
||||
#include "glib-compat.h"
|
||||
#include "qemu/typedefs.h"
|
||||
|
||||
/*
|
||||
* We have a lot of unaudited code that may fail in strange ways, or
|
||||
* even be a security risk during migration, if you disable assertions
|
||||
* at compile-time. You may comment out these safety checks if you
|
||||
* absolutely want to disable assertion overhead, but it is not
|
||||
* supported upstream so the risk is all yours. Meanwhile, please
|
||||
* submit patches to remove any side-effects inside an assertion, or
|
||||
* fixing error handling that should use Error instead of assert.
|
||||
*/
|
||||
#ifdef NDEBUG
|
||||
#error building with NDEBUG is not supported
|
||||
#endif
|
||||
#ifdef G_DISABLE_ASSERT
|
||||
#error building with G_DISABLE_ASSERT is not supported
|
||||
#endif
|
||||
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
|
||||
@@ -388,10 +388,10 @@ struct CPUState {
|
||||
DECLARE_BITMAP(trace_dstate, CPU_TRACE_DSTATE_MAX_EVENTS);
|
||||
|
||||
/* TODO Move common fields from CPUArchState here. */
|
||||
int cpu_index; /* used by alpha TCG */
|
||||
uint32_t halted; /* used by alpha, cris, ppc TCG */
|
||||
int cpu_index;
|
||||
uint32_t halted;
|
||||
uint32_t can_do_io;
|
||||
int32_t exception_index; /* used by m68k TCG */
|
||||
int32_t exception_index;
|
||||
|
||||
/* shared by kvm, hax and hvf */
|
||||
bool vcpu_dirty;
|
||||
|
||||
@@ -150,8 +150,6 @@
|
||||
#define READ_CD 0xbe
|
||||
#define SEND_DVD_STRUCTURE 0xbf
|
||||
|
||||
const char *scsi_command_name(uint8_t cmd);
|
||||
|
||||
/*
|
||||
* SERVICE ACTION IN subcodes
|
||||
*/
|
||||
124
include/scsi/utils.h
Normal file
124
include/scsi/utils.h
Normal file
@@ -0,0 +1,124 @@
|
||||
#ifndef SCSI_UTILS_H
|
||||
#define SCSI_UTILS_H 1
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
#include <scsi/sg.h>
|
||||
#endif
|
||||
|
||||
#define SCSI_CMD_BUF_SIZE 16
|
||||
#define SCSI_SENSE_LEN 18
|
||||
#define SCSI_SENSE_LEN_SCANNER 32
|
||||
#define SCSI_INQUIRY_LEN 36
|
||||
|
||||
enum SCSIXferMode {
|
||||
SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */
|
||||
SCSI_XFER_FROM_DEV, /* READ, INQUIRY, MODE_SENSE, ... */
|
||||
SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */
|
||||
};
|
||||
|
||||
typedef struct SCSICommand {
|
||||
uint8_t buf[SCSI_CMD_BUF_SIZE];
|
||||
int len;
|
||||
size_t xfer;
|
||||
uint64_t lba;
|
||||
enum SCSIXferMode mode;
|
||||
} SCSICommand;
|
||||
|
||||
typedef struct SCSISense {
|
||||
uint8_t key;
|
||||
uint8_t asc;
|
||||
uint8_t ascq;
|
||||
} SCSISense;
|
||||
|
||||
int scsi_build_sense(uint8_t *buf, SCSISense sense);
|
||||
|
||||
/*
|
||||
* Predefined sense codes
|
||||
*/
|
||||
|
||||
/* No sense data available */
|
||||
extern const struct SCSISense sense_code_NO_SENSE;
|
||||
/* LUN not ready, Manual intervention required */
|
||||
extern const struct SCSISense sense_code_LUN_NOT_READY;
|
||||
/* LUN not ready, Medium not present */
|
||||
extern const struct SCSISense sense_code_NO_MEDIUM;
|
||||
/* LUN not ready, medium removal prevented */
|
||||
extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
|
||||
/* Hardware error, internal target failure */
|
||||
extern const struct SCSISense sense_code_TARGET_FAILURE;
|
||||
/* Illegal request, invalid command operation code */
|
||||
extern const struct SCSISense sense_code_INVALID_OPCODE;
|
||||
/* Illegal request, LBA out of range */
|
||||
extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
|
||||
/* Illegal request, Invalid field in CDB */
|
||||
extern const struct SCSISense sense_code_INVALID_FIELD;
|
||||
/* Illegal request, Invalid field in parameter list */
|
||||
extern const struct SCSISense sense_code_INVALID_PARAM;
|
||||
/* Illegal request, Parameter list length error */
|
||||
extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
|
||||
/* Illegal request, LUN not supported */
|
||||
extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
|
||||
/* Illegal request, Saving parameters not supported */
|
||||
extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
|
||||
/* Illegal request, Incompatible format */
|
||||
extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
|
||||
/* Illegal request, medium removal prevented */
|
||||
extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
|
||||
/* Illegal request, Invalid Transfer Tag */
|
||||
extern const struct SCSISense sense_code_INVALID_TAG;
|
||||
/* Command aborted, I/O process terminated */
|
||||
extern const struct SCSISense sense_code_IO_ERROR;
|
||||
/* Command aborted, I_T Nexus loss occurred */
|
||||
extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
|
||||
/* Command aborted, Logical Unit failure */
|
||||
extern const struct SCSISense sense_code_LUN_FAILURE;
|
||||
/* Command aborted, Overlapped Commands Attempted */
|
||||
extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
|
||||
/* LUN not ready, Capacity data has changed */
|
||||
extern const struct SCSISense sense_code_CAPACITY_CHANGED;
|
||||
/* LUN not ready, Medium not present */
|
||||
extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
|
||||
/* Unit attention, Power on, reset or bus device reset occurred */
|
||||
extern const struct SCSISense sense_code_RESET;
|
||||
/* Unit attention, Medium may have changed*/
|
||||
extern const struct SCSISense sense_code_MEDIUM_CHANGED;
|
||||
/* Unit attention, Reported LUNs data has changed */
|
||||
extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
|
||||
/* Unit attention, Device internal reset */
|
||||
extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
|
||||
/* Data Protection, Write Protected */
|
||||
extern const struct SCSISense sense_code_WRITE_PROTECTED;
|
||||
/* Data Protection, Space Allocation Failed Write Protect */
|
||||
extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
|
||||
|
||||
#define SENSE_CODE(x) sense_code_ ## x
|
||||
|
||||
int scsi_sense_to_errno(int key, int asc, int ascq);
|
||||
int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size);
|
||||
|
||||
int scsi_convert_sense(uint8_t *in_buf, int in_len,
|
||||
uint8_t *buf, int len, bool fixed);
|
||||
const char *scsi_command_name(uint8_t cmd);
|
||||
|
||||
uint64_t scsi_cmd_lba(SCSICommand *cmd);
|
||||
uint32_t scsi_data_cdb_xfer(uint8_t *buf);
|
||||
uint32_t scsi_cdb_xfer(uint8_t *buf);
|
||||
int scsi_cdb_length(uint8_t *buf);
|
||||
|
||||
/* Linux SG_IO interface. */
|
||||
#ifdef CONFIG_LINUX
|
||||
#define SG_ERR_DRIVER_TIMEOUT 0x06
|
||||
#define SG_ERR_DRIVER_SENSE 0x08
|
||||
|
||||
#define SG_ERR_DID_OK 0x00
|
||||
#define SG_ERR_DID_NO_CONNECT 0x01
|
||||
#define SG_ERR_DID_BUS_BUSY 0x02
|
||||
#define SG_ERR_DID_TIME_OUT 0x03
|
||||
|
||||
#define SG_ERR_DRIVER_SENSE 0x08
|
||||
|
||||
int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
|
||||
SCSISense *sense);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
22
memory.c
22
memory.c
@@ -2701,10 +2701,10 @@ typedef struct MemoryRegionList MemoryRegionList;
|
||||
|
||||
struct MemoryRegionList {
|
||||
const MemoryRegion *mr;
|
||||
QTAILQ_ENTRY(MemoryRegionList) queue;
|
||||
QTAILQ_ENTRY(MemoryRegionList) mrqueue;
|
||||
};
|
||||
|
||||
typedef QTAILQ_HEAD(queue, MemoryRegionList) MemoryRegionListHead;
|
||||
typedef QTAILQ_HEAD(mrqueue, MemoryRegionList) MemoryRegionListHead;
|
||||
|
||||
#define MR_SIZE(size) (int128_nz(size) ? (hwaddr)int128_get64( \
|
||||
int128_sub((size), int128_one())) : 0)
|
||||
@@ -2746,7 +2746,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
|
||||
bool found = false;
|
||||
|
||||
/* check if the alias is already in the queue */
|
||||
QTAILQ_FOREACH(ml, alias_print_queue, queue) {
|
||||
QTAILQ_FOREACH(ml, alias_print_queue, mrqueue) {
|
||||
if (ml->mr == mr->alias) {
|
||||
found = true;
|
||||
}
|
||||
@@ -2755,7 +2755,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
|
||||
if (!found) {
|
||||
ml = g_new(MemoryRegionList, 1);
|
||||
ml->mr = mr->alias;
|
||||
QTAILQ_INSERT_TAIL(alias_print_queue, ml, queue);
|
||||
QTAILQ_INSERT_TAIL(alias_print_queue, ml, mrqueue);
|
||||
}
|
||||
mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx
|
||||
" (prio %d, %s): alias %s @%s " TARGET_FMT_plx
|
||||
@@ -2783,26 +2783,26 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
|
||||
QTAILQ_FOREACH(submr, &mr->subregions, subregions_link) {
|
||||
new_ml = g_new(MemoryRegionList, 1);
|
||||
new_ml->mr = submr;
|
||||
QTAILQ_FOREACH(ml, &submr_print_queue, queue) {
|
||||
QTAILQ_FOREACH(ml, &submr_print_queue, mrqueue) {
|
||||
if (new_ml->mr->addr < ml->mr->addr ||
|
||||
(new_ml->mr->addr == ml->mr->addr &&
|
||||
new_ml->mr->priority > ml->mr->priority)) {
|
||||
QTAILQ_INSERT_BEFORE(ml, new_ml, queue);
|
||||
QTAILQ_INSERT_BEFORE(ml, new_ml, mrqueue);
|
||||
new_ml = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (new_ml) {
|
||||
QTAILQ_INSERT_TAIL(&submr_print_queue, new_ml, queue);
|
||||
QTAILQ_INSERT_TAIL(&submr_print_queue, new_ml, mrqueue);
|
||||
}
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(ml, &submr_print_queue, queue) {
|
||||
QTAILQ_FOREACH(ml, &submr_print_queue, mrqueue) {
|
||||
mtree_print_mr(mon_printf, f, ml->mr, level + 1, cur_start,
|
||||
alias_print_queue);
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, queue, next_ml) {
|
||||
QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, mrqueue, next_ml) {
|
||||
g_free(ml);
|
||||
}
|
||||
}
|
||||
@@ -2872,13 +2872,13 @@ void mtree_info(fprintf_function mon_printf, void *f, bool flatview)
|
||||
}
|
||||
|
||||
/* print aliased regions */
|
||||
QTAILQ_FOREACH(ml, &ml_head, queue) {
|
||||
QTAILQ_FOREACH(ml, &ml_head, mrqueue) {
|
||||
mon_printf(f, "memory-region: %s\n", memory_region_name(ml->mr));
|
||||
mtree_print_mr(mon_printf, f, ml->mr, 1, 0, &ml_head);
|
||||
mon_printf(f, "\n");
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH_SAFE(ml, &ml_head, queue, ml2) {
|
||||
QTAILQ_FOREACH_SAFE(ml, &ml_head, mrqueue, ml2) {
|
||||
g_free(ml);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user