Merge remote branch 'origin/master' into pci

Conflicts:
	Makefile.objs
	hw/virtio.c
diff --git a/.gitignore b/.gitignore
index a43e4d1..3efb4ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@
 config-target.*
 trace.h
 trace.c
+trace-dtrace.h
+trace-dtrace.dtrace
 *-timestamp
 *-softmmu
 *-darwin-user
diff --git a/MAINTAINERS b/MAINTAINERS
index e5165fb..59effc7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1,88 +1,428 @@
 QEMU Maintainers
 ================
 
-Project leaders:
-----------------
+The intention of this file is not to establish who owns what portions of the
+code base, but to provide a set of names that developers can consult when they
+have a question about a particular subset and also to provide a set of names
+to be CC'd when submitting a patch to obtain appropriate review.
 
-Fabrice Bellard
-Paul Brook
+In general, if you have a question about inclusion of a patch, you should
+consult qemu-devel and not any specific individual privately.
 
-CPU cores:
-----------
+Descriptions of section entries:
 
-x86                Fabrice Bellard
-ARM                Paul Brook
-SPARC              Blue Swirl
-MIPS               ?
-PowerPC            Alexander Graf
-M68K               Paul Brook
-SH4                ?
-CRIS               Edgar E. Iglesias
-Alpha              ?
-MicroBlaze         Edgar E. Iglesias
-S390               ?
+	M: Mail patches to: FullName <address@domain>
+	L: Mailing list that is relevant to this area
+	W: Web-page with status/info
+	Q: Patchwork web based patch tracking system site
+	T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit.
+	S: Status, one of the following:
+	   Supported:	Someone is actually paid to look after this.
+	   Maintained:	Someone actually looks after it.
+	   Odd Fixes:	It has a maintainer but they don't have time to do
+			much other than throw the odd patch in. See below..
+	   Orphan:	No current maintainer [but maybe you could take the
+			role as you write your new code].
+	   Obsolete:	Old code. Something tagged obsolete generally means
+			it has been replaced by a better system and you
+			should be using that.
+	F: Files and directories with wildcard patterns.
+	   A trailing slash includes all files and subdirectory files.
+	   F:	drivers/net/	all files in and below drivers/net
+	   F:	drivers/net/*	all files in drivers/net, but not below
+	   F:	*/net/*		all files in "any top level directory"/net
+	   One pattern per line.  Multiple F: lines acceptable.
+	X: Files and directories that are NOT maintained, same rules as F:
+	   Files exclusions are tested before file matches.
+	   Can be useful for excluding a specific subdirectory, for instance:
+	   F:	net/
+	   X:	net/ipv6/
+	   matches all files in and below net excluding net/ipv6/
+	K: Keyword perl extended regex pattern to match content in a
+	   patch or file.  For instance:
+	   K: of_get_profile
+	      matches patches or files that contain "of_get_profile"
+	   K: \b(printk|pr_(info|err))\b
+	      matches patches or files that contain one or more of the words
+	      printk, pr_info or pr_err
+	   One regex pattern per line.  Multiple K: lines acceptable.
 
-Machines (sorted by CPU):
--------------------------
 
-x86
-  pc.c                    Fabrice Bellard (new maintainer needed)
-ARM
-  integratorcp.c          Paul Brook
-  versatilepb.c           Paul Brook
-  Real View               Paul Brook
-  spitz.c                 Andrzej Zaborowski
-  palm.c                  Andrzej Zaborowski
-  nseries.c               Andrzej Zaborowski
-  stellaris.c             Paul Brook
-  gumstix.c               Thorsten Zitterell
-  mainstone.c             Armin Kuster
-  musicpal.c              Jan Kiszka
-SPARC
-  sun4u.c                 Blue Swirl
-  sun4m.c                 Blue Swirl
-MIPS
-  mips_r4k.c              Aurelien Jarno
-  mips_malta.c            Aurelien Jarno
-  mips_jazz.c             Hervé Poussineau
-  mips_mipssim.c          ?
-PowerPC
-  ppc_prep.c              ?
-  ppc_oldworld.c          Alexander Graf
-  ppc_newworld.c          Alexander Graf
-  ppc405_boards.c         Alexander Graf
-M86K
-  mcf5208.c               Paul Brook
-  an5206.c                Paul Brook
-  dummy_m68k.c            Paul Brook
-SH4
-  shix.c                  ?
-  r2d.c                   Magnus Damm
-CRIS
-  etraxfs.c               Edgar E. Iglesias
-  axis_dev88.c            Edgar E. Iglesias
+General Project Administration
+------------------------------
+M: Anthony Liguori <aliguori@us.ibm.com>
+M: Paul Brook <paul@codesourcery.com>
+
+Guest CPU cores (TCG):
+----------------------
 Alpha
+M: qemu-devel@nongnu.org
+S: Orphan
+F: target-alpha/
+
+ARM
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: target-arm/
+
+CRIS
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: target-cris/
+
+M68K
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: target-m68k/
+
 MicroBlaze
-  petalogix_s3adsp1800.c  Edgar E. Iglesias
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: target-microblaze/
+
+MIPS
+M: qemu-devel@nongnu.org
+S: Orphan
+F: target-mips/
+
+PowerPC
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: target-ppc/
+
 S390
-  s390-*.c                Alexander Graf
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: target-s390x/
 
-Generic Subsystems:
--------------------  
+SH4
+M: qemu-devel@nongnu.org
+S: Orphan
+F: target-sh4/
 
-Dynamic translator        Fabrice Bellard
-Main loop                 Fabrice Bellard (new maintainer needed)
-TCG                       Fabrice Bellard
-IDE device                ?
-SCSI device               Paul Brook
-PCI layer                 Michael S. Tsirkin
-USB layer                 ?
-Block layer               ?
-Graphic layer             ?
-Audio device layer        Vassili Karpov (malc)
-Character device layer    ?
-Network device layer      ?
-GDB stub                  ?
-Linux user                ?
-Darwin user               ?
-SLIRP                     ?
+SPARC
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Maintained
+F: target-sparc/
+
+X86
+M: qemu-devel@nongnu.org
+S: Odd Fixes
+F: target-i386/
+
+Guest CPU Cores (KVM):
+----------------------
+
+Overall
+M: Avi Kivity <avi@redhat.com>
+M: Marcelo Tosatti <mtosatti@redhat.com>
+L: kvm@vger.kernel.org
+S: Supported
+F: kvm-*
+F: */kvm.*
+
+PPC
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: target-ppc/kvm.c
+
+S390
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: target-s390x/kvm.c
+
+X86
+M: Avi Kivity <avi@redhat.com>
+M: Marcelo Tosatti <mtosatti@redhat.com>
+L: kvm@vger.kernel.org
+S: Supported
+F: target-i386/kvm.c
+
+ARM Machines
+------------
+Gumstix
+M: qemu-devel@nongnu.org
+S: Orphan
+F: hw/gumstix.c
+
+Integrator CP
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/integratorcp.c
+
+Mainstone
+M: qemu-devel@nongnu.org
+S: Orphan
+F: hw/mainstone.c
+
+Musicpal
+M: Jan Kiszka <jan.kiszka@web.de>
+S: Maintained
+F: hw/musicpal.c
+
+nSeries
+M: Andrzej Zaborowski <balrogg@gmail.com>
+S: Maintained
+F: hw/nseries.c
+
+Palm
+M: Andrzej Zaborowski <balrogg@gmail.com>
+S: Maintained
+F: hw/palm.c
+
+Real View
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/realview*
+
+Spitz
+M: Andrzej Zaborowski <balrogg@gmail.com>
+S: Maintained
+F: hw/spitz.c
+
+Stellaris
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/stellaris.c
+
+Versatile PB
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/versatilepb.c
+
+CRIS Machines
+-------------
+Axis Dev88
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: hw/axis_dev88.c
+
+etraxfs
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: hw/etraxfs.c
+
+M86K Machines
+-------------
+an5206
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/an5206.c
+
+dummy_m68k
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/dummy_m68k.c
+
+mcf5208
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/mcf5208.c
+
+MicroBlaze Machines
+-------------------
+petalogix_s3adsp1800
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: hw/petalogix_s3adsp1800.c
+
+MIPS Machines
+-------------
+Jazz
+M: Hervé Poussineau <hpoussin@reactos.org>
+S: Maintained
+F: hw/mips_jazz.c
+
+Malta
+M: Aurelien Jarno <aurelien@aurel32.net>
+S: Maintained
+F: hw/mips_malta.c
+
+Mipssim
+M: qemu-devel@nongnu.org
+S: Orphan
+F: hw/mips_mipssim.c
+
+R4000
+M: Aurelien Jarno <aurelien@aurel32.net>
+S: Maintained
+F: hw/mips_r4k.c
+
+PowerPC Machines
+----------------
+405
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: hw/ppc405_boards.c
+
+New World
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: hw/ppc_newworld.c
+
+Old World
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: hw/ppc_oldworld.c
+
+Prep
+M: qemu-devel@nongnu.org
+S: Orphan
+F: hw/ppc_prep.c
+
+SH4 Machines
+------------
+R2D
+M: Magnus Damm <magnus.damm@gmail.com>
+S: Maintained
+F: hw/r2d.c
+
+Shix
+M: Magnus Damm <magnus.damm@gmail.com>
+S: Oprhan
+F: hw/shix.c
+
+SPARC Machines
+--------------
+Sun4m
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Maintained
+F: hw/sun4m.c
+
+Sun4u
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Maintained
+F: hw/sun4u.c
+
+S390 Machines
+-------------
+S390 Virtio
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: hw/s390-*.c
+
+X86 Machines
+------------
+PC
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Supported
+F: hw/pc.[ch] hw/pc_piix.c
+
+Devices
+-------
+IDE
+M: Kevin Wolf <kwolf@redhat.com>
+S: Odd Fixes
+F: hw/ide/
+
+PCI
+M: Michael S. Tsirkin <mst@redhat.com>
+S: Supported
+F: hw/pci*
+F: hw/piix*
+
+SCSI
+M: Paul Brook <paul@codesourcery.com>
+M: Kevin Wolf <kwolf@redhat.com>
+S: Odd Fixes
+F: hw/lsi53c895a.c
+F: hw/scsi*
+
+USB
+M: qemu-devel@nongnu.org
+S: Odd Fixes
+F: hw/usb*
+
+vhost
+M: Michael S. Tsirkin <mst@redhat.com>
+S: Supported
+F: hw/vhost*
+
+virtio
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Supported
+F: hw/virtio*
+
+virtio-9p
+M: Venkateswararao Jujjuri (JV) <jvrao@linux.vnet.ibm.com>
+S: Supported
+F: hw/virtio-9p*
+
+virtio-blk
+M: Kevin Wolf <kwolf@redhat.com>
+S: Supported
+F: hw/virtio-blk*
+
+virtio-serial
+M: Amit Shah <amit.shah@redhat.com>
+S: Supported
+F: hw/virtio-serial*
+F: hw/virtio-console*
+
+Subsystems
+----------
+Audio
+M: Vassili Karpov (malc) <av1474@comtv.ru>
+S: Maintained
+F: audio/
+
+Block
+M: Kevin Wolf <kwolf@redhat.com>
+S: Supported
+F: block*
+F: block/
+
+Character Devices
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Maintained
+F: qemu-char.c
+
+GDB stub
+M: qemu-devel@nongnu.org
+S: Odd Fixes
+F: gdbstub*
+F: gdb-xml/
+
+Graphics
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Maintained
+F: ui/
+
+Main loop
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Supported
+F: vl.c
+
+Monitor (QMP/HMP)
+M: Luiz Capitulino <lcapitulino@redhat.com>
+M: Markus Armbruster <armbru@redhat.com>
+S: Supported
+F: monitor.c
+
+Network device layer
+M: Anthony Liguori <aliguori@us.ibm.com>
+M: Mark McLoughlin <markmc@redhat.com>
+S: Maintained
+F: net/
+
+SLIRP
+M: qemu-devel@nongnu.org
+S: Orphan
+F: slirp/
+
+Usermode Emulation
+------------------
+BSD user
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Maintained
+F: bsd-user/
+
+Darwin user
+M: qemu-devel@nongnu.org
+S: Orphan
+F: darwin-user/
+
+Linux user
+M: Riku Voipio <riku.voipio@iki.fi>
+S: Maintained
+F: linux-user/
diff --git a/Makefile b/Makefile
index 2883d27..c80566c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@
 # Makefile for QEMU.
 
 GENERATED_HEADERS = config-host.h trace.h qemu-options.def
+ifeq ($(TRACE_BACKEND),dtrace)
+GENERATED_HEADERS += trace-dtrace.h
+endif
 
 ifneq ($(wildcard config-host.mak),)
 # Put the all: rule here so that config-host.mak can contain dependencies.
@@ -36,18 +39,19 @@
 
 SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
 SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
+SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
 
 config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
 	$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@,"  GEN   $@")
 
+-include $(SUBDIR_DEVICES_MAK_DEP)
+
 %/config-devices.mak: default-configs/%.mak
-	$(call quiet-command,cat $< > $@.tmp, "  GEN   $@")
+	$(call quiet-command,$(SHELL) $(SRC_PATH)/make_device_config.sh $@ $<, "  GEN   $@")
 	@if test -f $@; then \
 	  if cmp -s $@.old $@; then \
-	    if ! cmp -s $@ $@.tmp; then \
-	      mv $@.tmp $@; \
-	      cp -p $@ $@.old; \
-	    fi; \
+	    mv $@.tmp $@; \
+	    cp -p $@ $@.old; \
 	  else \
 	    if test -f $@.old; then \
 	      echo "WARNING: $@ (user modified) out of date.";\
@@ -108,7 +112,11 @@
 
 bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 
+ifeq ($(TRACE_BACKEND),dtrace)
+trace.h: trace.h-timestamp trace-dtrace.h
+else
 trace.h: trace.h-timestamp
+endif
 trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
 	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
 	@cmp -s $@ trace.h || cp $@ trace.h
@@ -120,6 +128,20 @@
 
 trace.o: trace.c $(GENERATED_HEADERS)
 
+trace-dtrace.h: trace-dtrace.dtrace
+	$(call quiet-command,dtrace -o $@ -h -s $<, "  GEN   trace-dtrace.h")
+
+# Normal practice is to name DTrace probe file with a '.d' extension
+# but that gets picked up by QEMU's Makefile as an external dependancy
+# rule file. So we use '.dtrace' instead
+trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
+trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
+	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
+	@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
+
+trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
+	$(call quiet-command,dtrace -o $@ -G -s $<, "  GEN trace-dtrace.o")
+
 simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
 
 version.o: $(SRC_PATH)/version.rc config-host.mak
@@ -129,7 +151,7 @@
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
-qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS)
+qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o: $(GENERATED_HEADERS)
 
 qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
 
@@ -142,12 +164,14 @@
 
 check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
 
-check-qint: check-qint.o qint.o qemu-malloc.o $(trace-obj-y)
-check-qstring: check-qstring.o qstring.o qemu-malloc.o $(trace-obj-y)
-check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o $(trace-obj-y)
-check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o $(trace-obj-y)
-check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o $(trace-obj-y)
-check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o $(trace-obj-y)
+CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y)
+
+check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS)
+check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS)
+check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS)
+check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
+check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
+check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS)
 
 clean:
 # avoid old build problems by removing potentially incorrect old files
@@ -157,6 +181,8 @@
 	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
 	rm -f qemu-img-cmds.h
 	rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
+	rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
+	rm -f trace-dtrace.h trace-dtrace.h-timestamp
 	$(MAKE) -C tests clean
 	for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
 	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
@@ -178,8 +204,9 @@
 common  de-ch  es     fo  fr-ca  hu     ja  mk  nl-be      pt  sl     tr
 
 ifdef INSTALL_BLOBS
-BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
-openbios-sparc32 openbios-sparc64 openbios-ppc \
+BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
+vgabios-stdvga.bin vgabios-vmware.bin \
+ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
 gpxe-eepro100-80861209.rom \
 pxe-e1000.bin \
 pxe-ne2k_pci.bin pxe-pcnet.bin \
diff --git a/Makefile.objs b/Makefile.objs
index c5919af..257623b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -42,6 +42,11 @@
 net-nested-$(CONFIG_VDE) += vde.o
 net-obj-y += $(addprefix net/, $(net-nested-y))
 
+ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS),yy)
+# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
+# only pull in the actual virtio-9p device if we also enabled virtio.
+CONFIG_REALLY_VIRTFS=y
+endif
 fsdev-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o
 fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
 
@@ -102,6 +107,7 @@
 audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 audio-obj-$(CONFIG_SDL) += sdlaudio.o
 audio-obj-$(CONFIG_OSS) += ossaudio.o
+audio-obj-$(CONFIG_SPICE) += spiceaudio.o
 audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
 audio-obj-$(CONFIG_ALSA) += alsaaudio.o
 audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
@@ -158,9 +164,13 @@
 
 hw-obj-y =
 hw-obj-y += vl.o loader.o
-hw-obj-y += virtio.o virtio-console.o
-hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o
-hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
+hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
+hw-obj-y += fw_cfg.o
+# FIXME: Core PCI code and its direct dependencies are required by the
+# QMP query-pci command.
+hw-obj-y += pci.o pci_bridge.o msix.o msi.o
+hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
+hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
 hw-obj-y += watchdog.o
 hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 hw-obj-$(CONFIG_ECC) += ecc.o
@@ -205,15 +215,16 @@
 hw-obj-$(CONFIG_PIIX4) += piix4.o
 
 # PCI watchdog devices
-hw-obj-y += wdt_i6300esb.o
+hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
 
-hw-obj-y += pcie.o pcie_aer.o pcie_port.o
-hw-obj-y += msix.o msi.o
+hw-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
+hw-obj-$(CONFIG_PCI) += msix.o msi.o
 
 # PCI network cards
-hw-obj-y += ne2000.o
-hw-obj-y += eepro100.o
-hw-obj-y += pcnet.o
+hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
+hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
+hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
+hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
 
 hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
 hw-obj-$(CONFIG_LAN9118) += lan9118.o
@@ -230,7 +241,7 @@
 hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
 
 # SCSI layer
-hw-obj-y += lsi53c895a.o
+hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
 hw-obj-$(CONFIG_ESP) += esp.o
 
 hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
@@ -260,7 +271,8 @@
 adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 
-hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o virtio-9p-xattr.o
+hw-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p-debug.o
+hw-obj-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
 hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
 
 ######################################################################
@@ -285,11 +297,15 @@
 ######################################################################
 # trace
 
+ifeq ($(TRACE_BACKEND),dtrace)
+trace-obj-y = trace-dtrace.o
+else
 trace-obj-y = trace.o
 ifeq ($(TRACE_BACKEND),simple)
 trace-obj-y += simpletrace.o
 user-obj-y += qemu-timer-common.o
 endif
+endif
 
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
diff --git a/Makefile.target b/Makefile.target
index 91e6e74..5784844 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -30,6 +30,7 @@
 endif
 
 PROGS=$(QEMU_PROG)
+STPFILES=
 
 ifndef CONFIG_HAIKU
 LIBS+=-lm
@@ -40,7 +41,27 @@
 config-target.h: config-target.h-timestamp
 config-target.h-timestamp: config-target.mak
 
-all: $(PROGS)
+ifdef CONFIG_SYSTEMTAP_TRACE
+stap: $(QEMU_PROG).stp
+
+ifdef CONFIG_USER_ONLY
+TARGET_TYPE=user
+else
+TARGET_TYPE=system
+endif
+
+$(QEMU_PROG).stp:
+	$(call quiet-command,sh $(SRC_PATH)/tracetool \
+		--$(TRACE_BACKEND) \
+		--binary $(bindir)/$(QEMU_PROG) \
+		--target-arch $(TARGET_ARCH) \
+		--target-type $(TARGET_TYPE) \
+		--stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp,"  GEN   $(QEMU_PROG).stp")
+else
+stap:
+endif
+
+all: $(PROGS) stap
 
 # Dummy command so that make thinks it has done something
 	@true
@@ -167,11 +188,11 @@
 obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
-obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
+obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
 obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
 obj-y += vhost_net.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
-obj-$(CONFIG_VIRTFS) += virtio-9p.o
+obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p.o
 obj-y += rwhandler.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
@@ -189,8 +210,8 @@
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 
 # PCI network cards
-obj-y += rtl8139.o
-obj-y += e1000.o
+obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
+obj-$(CONFIG_E1000_PCI) += e1000.o
 
 # Inter-VM PCI shared memory
 obj-$(CONFIG_KVM) += ivshmem.o
@@ -340,6 +361,9 @@
 	rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
 	rm -f *.d */*.d tcg/*.o ide/*.o
 	rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
+ifdef CONFIG_SYSTEMTAP_TRACE
+	rm -f *.stp
+endif
 
 install: all
 ifneq ($(PROGS),)
@@ -348,6 +372,10 @@
 	$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
 endif
 endif
+ifdef CONFIG_SYSTEMTAP_TRACE
+	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
+	$(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
+endif
 
 # Include automatically generated dependency files
 -include $(wildcard *.d */*.d)
diff --git a/QMP/README b/QMP/README
index 80503f2..c95a08c 100644
--- a/QMP/README
+++ b/QMP/README
@@ -19,10 +19,7 @@
 o qmp-commands.txt  QMP supported commands (auto-generated at build-time)
 o qmp-events.txt    List of available asynchronous events
 
-There are also two simple Python scripts available:
-
-o qmp-shell  A shell
-o vm-info    Show some information about the Virtual Machine
+There is also a simple Python script called 'qmp-shell' available.
 
 IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
 section in the qmp-commands.txt file before making any serious use of QMP.
diff --git a/QMP/qmp-shell b/QMP/qmp-shell
index a5b72d1..42dabc8 100755
--- a/QMP/qmp-shell
+++ b/QMP/qmp-shell
@@ -1,8 +1,8 @@
 #!/usr/bin/python
 #
-# Simple QEMU shell on top of QMP
+# Low-level QEMU shell on top of QMP.
 #
-# Copyright (C) 2009 Red Hat Inc.
+# Copyright (C) 2009, 2010 Red Hat Inc.
 #
 # Authors:
 #  Luiz Capitulino <lcapitulino@redhat.com>
@@ -14,60 +14,246 @@
 #
 # Start QEMU with:
 #
-# $ qemu [...] -monitor control,unix:./qmp,server
+# # qemu [...] -qmp unix:./qmp-sock,server
 #
 # Run the shell:
 #
-# $ qmp-shell ./qmp
+# $ qmp-shell ./qmp-sock
 #
 # Commands have the following format:
 #
-# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+#    < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
 #
 # For example:
 #
-# (QEMU) info item=network
+# (QEMU) device_add driver=e1000 id=net1
+# {u'return': {}}
+# (QEMU)
 
 import qmp
 import readline
-from sys import argv,exit
+import sys
 
-def shell_help():
-    print 'bye  exit from the shell'
+class QMPCompleter(list):
+    def complete(self, text, state):
+        for cmd in self:
+            if cmd.startswith(text):
+                if not state:
+                    return cmd
+                else:
+                    state -= 1
 
-def main():
-    if len(argv) != 2:
-        print 'qemu-shell <unix-socket>'
-        exit(1)
+class QMPShellError(Exception):
+    pass
 
-    qemu = qmp.QEMUMonitorProtocol(argv[1])
-    qemu.connect()
-    qemu.send("qmp_capabilities")
+class QMPShellBadPort(QMPShellError):
+    pass
 
-    print 'Connected!'
+# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
+#       _execute_cmd()). Let's design a better one.
+class QMPShell(qmp.QEMUMonitorProtocol):
+    def __init__(self, address):
+        qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
+        self._greeting = None
+        self._completer = None
 
-    while True:
+    def __get_address(self, arg):
+        """
+        Figure out if the argument is in the port:host form, if it's not it's
+        probably a file path.
+        """
+        addr = arg.split(':')
+        if len(addr) == 2:
+            try:
+                port = int(addr[1])
+            except ValueError:
+                raise QMPShellBadPort
+            return ( addr[0], port )
+        # socket path
+        return arg
+
+    def _fill_completion(self):
+        for cmd in self.cmd('query-commands')['return']:
+            self._completer.append(cmd['name'])
+
+    def __completer_setup(self):
+        self._completer = QMPCompleter()
+        self._fill_completion()
+        readline.set_completer(self._completer.complete)
+        readline.parse_and_bind("tab: complete")
+        # XXX: default delimiters conflict with some command names (eg. query-),
+        # clearing everything as it doesn't seem to matter
+        readline.set_completer_delims('')
+
+    def __build_cmd(self, cmdline):
+        """
+        Build a QMP input object from a user provided command-line in the
+        following format:
+    
+            < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+        """
+        cmdargs = cmdline.split()
+        qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
+        for arg in cmdargs[1:]:
+            opt = arg.split('=')
+            try:
+                value = int(opt[1])
+            except ValueError:
+                value = opt[1]
+            qmpcmd['arguments'][opt[0]] = value
+        return qmpcmd
+
+    def _execute_cmd(self, cmdline):
         try:
-            cmd = raw_input('(QEMU) ')
+            qmpcmd = self.__build_cmd(cmdline)
+        except:
+            print 'command format: <command-name> ',
+            print '[arg-name1=arg1] ... [arg-nameN=argN]'
+            return True
+        resp = self.cmd_obj(qmpcmd)
+        if resp is None:
+            print 'Disconnected'
+            return False
+        print resp
+        return True
+
+    def connect(self):
+        self._greeting = qmp.QEMUMonitorProtocol.connect(self)
+        self.__completer_setup()
+
+    def show_banner(self, msg='Welcome to the QMP low-level shell!'):
+        print msg
+        version = self._greeting['QMP']['version']['qemu']
+        print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
+
+    def read_exec_command(self, prompt):
+        """
+        Read and execute a command.
+
+        @return True if execution was ok, return False if disconnected.
+        """
+        try:
+            cmdline = raw_input(prompt)
         except EOFError:
             print
-            break
-        if cmd == '':
-            continue
-        elif cmd == 'bye':
-            break
-        elif cmd == 'help':
-            shell_help()
+            return False
+        if cmdline == '':
+            for ev in self.get_events():
+                print ev
+            self.clear_events()
+            return True
         else:
+            return self._execute_cmd(cmdline)
+
+class HMPShell(QMPShell):
+    def __init__(self, address):
+        QMPShell.__init__(self, address)
+        self.__cpu_index = 0
+
+    def __cmd_completion(self):
+        for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'):
+            if cmd and cmd[0] != '[' and cmd[0] != '\t':
+                name = cmd.split()[0] # drop help text
+                if name == 'info':
+                    continue
+                if name.find('|') != -1:
+                    # Command in the form 'foobar|f' or 'f|foobar', take the
+                    # full name
+                    opt = name.split('|')
+                    if len(opt[0]) == 1:
+                        name = opt[1]
+                    else:
+                        name = opt[0]
+                self._completer.append(name)
+                self._completer.append('help ' + name) # help completion
+
+    def __info_completion(self):
+        for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'):
+            if cmd:
+                self._completer.append('info ' + cmd.split()[1])
+
+    def __other_completion(self):
+        # special cases
+        self._completer.append('help info')
+
+    def _fill_completion(self):
+        self.__cmd_completion()
+        self.__info_completion()
+        self.__other_completion()
+
+    def __cmd_passthrough(self, cmdline, cpu_index = 0):
+        return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments':
+                              { 'command-line': cmdline,
+                                'cpu-index': cpu_index } })
+
+    def _execute_cmd(self, cmdline):
+        if cmdline.split()[0] == "cpu":
+            # trap the cpu command, it requires special setting
             try:
-                resp = qemu.send(cmd)
-                if resp == None:
-                    print 'Disconnected'
-                    break
-                print resp
-            except IndexError:
-                print '-> command format: <command-name> ',
-                print '[arg-name1=arg1] ... [arg-nameN=argN]'
+                idx = int(cmdline.split()[1])
+                if not 'return' in self.__cmd_passthrough('info version', idx):
+                    print 'bad CPU index'
+                    return True
+                self.__cpu_index = idx
+            except ValueError:
+                print 'cpu command takes an integer argument'
+                return True
+        resp = self.__cmd_passthrough(cmdline, self.__cpu_index)
+        if resp is None:
+            print 'Disconnected'
+            return False
+        assert 'return' in resp or 'error' in resp
+        if 'return' in resp:
+            # Success
+            if len(resp['return']) > 0:
+                print resp['return'],
+        else:
+            # Error
+            print '%s: %s' % (resp['error']['class'], resp['error']['desc'])
+        return True
+
+    def show_banner(self):
+        QMPShell.show_banner(self, msg='Welcome to the HMP shell!')
+
+def die(msg):
+    sys.stderr.write('ERROR: %s\n' % msg)
+    sys.exit(1)
+
+def fail_cmdline(option=None):
+    if option:
+        sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
+    sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n')
+    sys.exit(1)
+
+def main():
+    addr = ''
+    try:
+        if len(sys.argv) == 2:
+            qemu = QMPShell(sys.argv[1])
+            addr = sys.argv[1]
+        elif len(sys.argv) == 3:
+            if sys.argv[1] != '-H':
+                fail_cmdline(sys.argv[1])
+            qemu = HMPShell(sys.argv[2])
+            addr = sys.argv[2]
+        else:
+                fail_cmdline()
+    except QMPShellBadPort:
+        die('bad port number in command-line')
+
+    try:
+        qemu.connect()
+    except qmp.QMPConnectError:
+        die('Didn\'t get QMP greeting message')
+    except qmp.QMPCapabilitiesError:
+        die('Could not negotiate capabilities')
+    except qemu.error:
+        die('Could not connect to %s' % addr)
+
+    qemu.show_banner()
+    while qemu.read_exec_command('(QEMU) '):
+        pass
+    qemu.close()
 
 if __name__ == '__main__':
     main()
diff --git a/QMP/qmp.py b/QMP/qmp.py
index 4062f84..14ce8b0 100644
--- a/QMP/qmp.py
+++ b/QMP/qmp.py
@@ -1,6 +1,6 @@
 # QEMU Monitor Protocol Python class
 # 
-# Copyright (C) 2009 Red Hat Inc.
+# Copyright (C) 2009, 2010 Red Hat Inc.
 #
 # Authors:
 #  Luiz Capitulino <lcapitulino@redhat.com>
@@ -8,7 +8,9 @@
 # This work is licensed under the terms of the GNU GPL, version 2.  See
 # the COPYING file in the top-level directory.
 
-import socket, json
+import json
+import errno
+import socket
 
 class QMPError(Exception):
     pass
@@ -16,61 +18,114 @@
 class QMPConnectError(QMPError):
     pass
 
+class QMPCapabilitiesError(QMPError):
+    pass
+
 class QEMUMonitorProtocol:
-    def connect(self):
-        self.sock.connect(self.filename)
-        data = self.__json_read()
-        if data == None:
-            raise QMPConnectError
-        if not data.has_key('QMP'):
-            raise QMPConnectError
-        return data['QMP']['capabilities']
+    def __init__(self, address):
+        """
+        Create a QEMUMonitorProtocol class.
 
-    def close(self):
-        self.sock.close()
+        @param address: QEMU address, can be either a unix socket path (string)
+                        or a tuple in the form ( address, port ) for a TCP
+                        connection
+        @note No connection is established, this is done by the connect() method
+        """
+        self.__events = []
+        self.__address = address
+        self.__sock = self.__get_sock()
+        self.__sockfile = self.__sock.makefile()
 
-    def send_raw(self, line):
-        self.sock.send(str(line))
-        return self.__json_read()
-
-    def send(self, cmdline):
-        cmd = self.__build_cmd(cmdline)
-        self.__json_send(cmd)
-        resp = self.__json_read()
-        if resp == None:
-            return
-        elif resp.has_key('error'):
-            return resp['error']
+    def __get_sock(self):
+        if isinstance(self.__address, tuple):
+            family = socket.AF_INET
         else:
-            return resp['return']
-
-    def __build_cmd(self, cmdline):
-        cmdargs = cmdline.split()
-        qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
-        for arg in cmdargs[1:]:
-            opt = arg.split('=')
-            try:
-                value = int(opt[1])
-            except ValueError:
-                value = opt[1]
-            qmpcmd['arguments'][opt[0]] = value
-        return qmpcmd
-
-    def __json_send(self, cmd):
-        # XXX: We have to send any additional char, otherwise
-        # the Server won't read our input
-        self.sock.send(json.dumps(cmd) + ' ')
+            family = socket.AF_UNIX
+        return socket.socket(family, socket.SOCK_STREAM)
 
     def __json_read(self):
-        try:
-            while True:
-                line = json.loads(self.sockfile.readline())
-                if not 'event' in line:
-                    return line
-        except ValueError:
-            return
+        while True:
+            data = self.__sockfile.readline()
+            if not data:
+                return
+            resp = json.loads(data)
+            if 'event' in resp:
+                self.__events.append(resp)
+                continue
+            return resp
 
-    def __init__(self, filename):
-        self.filename = filename
-        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        self.sockfile = self.sock.makefile()
+    error = socket.error
+
+    def connect(self):
+        """
+        Connect to the QMP Monitor and perform capabilities negotiation.
+
+        @return QMP greeting dict
+        @raise socket.error on socket connection errors
+        @raise QMPConnectError if the greeting is not received
+        @raise QMPCapabilitiesError if fails to negotiate capabilities
+        """
+        self.__sock.connect(self.__address)
+        greeting = self.__json_read()
+        if greeting is None or not greeting.has_key('QMP'):
+            raise QMPConnectError
+        # Greeting seems ok, negotiate capabilities
+        resp = self.cmd('qmp_capabilities')
+        if "return" in resp:
+            return greeting
+        raise QMPCapabilitiesError
+
+    def cmd_obj(self, qmp_cmd):
+        """
+        Send a QMP command to the QMP Monitor.
+
+        @param qmp_cmd: QMP command to be sent as a Python dict
+        @return QMP response as a Python dict or None if the connection has
+                been closed
+        """
+        try:
+            self.__sock.sendall(json.dumps(qmp_cmd))
+        except socket.error, err:
+            if err[0] == errno.EPIPE:
+                return
+            raise socket.error(err)
+        return self.__json_read()
+
+    def cmd(self, name, args=None, id=None):
+        """
+        Build a QMP command and send it to the QMP Monitor.
+
+        @param name: command name (string)
+        @param args: command arguments (dict)
+        @param id: command id (dict, list, string or int)
+        """
+        qmp_cmd = { 'execute': name }
+        if args:
+            qmp_cmd['arguments'] = args
+        if id:
+            qmp_cmd['id'] = id
+        return self.cmd_obj(qmp_cmd)
+
+    def get_events(self):
+        """
+        Get a list of available QMP events.
+        """
+        self.__sock.setblocking(0)
+        try:
+            self.__json_read()
+        except socket.error, err:
+            if err[0] == errno.EAGAIN:
+                # No data available
+                pass
+        self.__sock.setblocking(1)
+        return self.__events
+
+    def clear_events(self):
+        """
+        Clear current list of pending events.
+        """
+        self.__events = []
+
+    def close(self):
+        self.__sock.close()
+        self.__sockfile.close()
diff --git a/QMP/vm-info b/QMP/vm-info
deleted file mode 100755
index be5b038..0000000
--- a/QMP/vm-info
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/python
-#
-# Print Virtual Machine information
-#
-# Usage:
-#
-# Start QEMU with:
-#
-# $ qemu [...] -monitor control,unix:./qmp,server
-#
-# Run vm-info:
-#
-# $ vm-info ./qmp
-#
-# Luiz Capitulino <lcapitulino@redhat.com>
-
-import qmp
-from sys import argv,exit
-
-def main():
-    if len(argv) != 2:
-        print 'vm-info <unix-socket>'
-        exit(1)
-
-    qemu = qmp.QEMUMonitorProtocol(argv[1])
-    qemu.connect()
-    qemu.send("qmp_capabilities")
-
-    for cmd in [ 'version', 'kvm', 'status', 'uuid', 'balloon' ]:
-        print cmd + ': ' + str(qemu.send('query-' + cmd))
-
-if __name__ == '__main__':
-    main()
diff --git a/audio/audio.c b/audio/audio.c
index ad51077..1707446 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -44,6 +44,9 @@
     that we generate the list.
 */
 static struct audio_driver *drvtab[] = {
+#ifdef CONFIG_SPICE
+    &spice_audio_driver,
+#endif
     CONFIG_AUDIO_DRIVERS
     &no_audio_driver,
     &wav_audio_driver
@@ -1093,15 +1096,6 @@
 /*
  * Timer
  */
-static void audio_timer (void *opaque)
-{
-    AudioState *s = opaque;
-
-    audio_run ("timer");
-    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
-}
-
-
 static int audio_is_timer_needed (void)
 {
     HWVoiceIn *hwi = NULL;
@@ -1116,10 +1110,8 @@
     return 0;
 }
 
-static void audio_reset_timer (void)
+static void audio_reset_timer (AudioState *s)
 {
-    AudioState *s = &glob_audio_state;
-
     if (audio_is_timer_needed ()) {
         qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
     }
@@ -1128,6 +1120,12 @@
     }
 }
 
+static void audio_timer (void *opaque)
+{
+    audio_run ("timer");
+    audio_reset_timer (opaque);
+}
+
 /*
  * Public API
  */
@@ -1192,7 +1190,7 @@
                 hw->enabled = 1;
                 if (s->vm_running) {
                     hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
-                    audio_reset_timer ();
+                    audio_reset_timer (s);
                 }
             }
         }
@@ -1237,6 +1235,7 @@
                 hw->enabled = 1;
                 if (s->vm_running) {
                     hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in);
+                    audio_reset_timer (s);
                 }
             }
             sw->total_hw_samples_acquired = hw->total_samples_captured;
@@ -1758,7 +1757,7 @@
     while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
         hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
     }
-    audio_reset_timer ();
+    audio_reset_timer (s);
 }
 
 static void audio_atexit (void)
diff --git a/audio/audio_int.h b/audio/audio_int.h
index d8560b6..d66f2c3 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -209,6 +209,7 @@
 extern struct audio_driver dsound_audio_driver;
 extern struct audio_driver esd_audio_driver;
 extern struct audio_driver pa_audio_driver;
+extern struct audio_driver spice_audio_driver;
 extern struct audio_driver winwave_audio_driver;
 extern struct mixeng_volume nominal_volume;
 
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
new file mode 100644
index 0000000..373e4c4
--- /dev/null
+++ b/audio/spiceaudio.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "ui/qemu-spice.h"
+
+#define AUDIO_CAP "spice"
+#include "audio.h"
+#include "audio_int.h"
+
+#define LINE_IN_SAMPLES 1024
+#define LINE_OUT_SAMPLES 1024
+
+typedef struct SpiceRateCtl {
+    int64_t               start_ticks;
+    int64_t               bytes_sent;
+} SpiceRateCtl;
+
+typedef struct SpiceVoiceOut {
+    HWVoiceOut            hw;
+    SpicePlaybackInstance sin;
+    SpiceRateCtl          rate;
+    int                   active;
+    uint32_t              *frame;
+    uint32_t              *fpos;
+    uint32_t              fsize;
+} SpiceVoiceOut;
+
+typedef struct SpiceVoiceIn {
+    HWVoiceIn             hw;
+    SpiceRecordInstance   sin;
+    SpiceRateCtl          rate;
+    int                   active;
+    uint32_t              samples[LINE_IN_SAMPLES];
+} SpiceVoiceIn;
+
+static const SpicePlaybackInterface playback_sif = {
+    .base.type          = SPICE_INTERFACE_PLAYBACK,
+    .base.description   = "playback",
+    .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
+};
+
+static const SpiceRecordInterface record_sif = {
+    .base.type          = SPICE_INTERFACE_RECORD,
+    .base.description   = "record",
+    .base.major_version = SPICE_INTERFACE_RECORD_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
+};
+
+static void *spice_audio_init (void)
+{
+    if (!using_spice) {
+        return NULL;
+    }
+    return &spice_audio_init;
+}
+
+static void spice_audio_fini (void *opaque)
+{
+    /* nothing */
+}
+
+static void rate_start (SpiceRateCtl *rate)
+{
+    memset (rate, 0, sizeof (*rate));
+    rate->start_ticks = qemu_get_clock (vm_clock);
+}
+
+static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
+{
+    int64_t now;
+    int64_t ticks;
+    int64_t bytes;
+    int64_t samples;
+
+    now = qemu_get_clock (vm_clock);
+    ticks = now - rate->start_ticks;
+    bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
+    samples = (bytes - rate->bytes_sent) >> info->shift;
+    if (samples < 0 || samples > 65536) {
+        fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples);
+        rate_start (rate);
+        samples = 0;
+    }
+    rate->bytes_sent += samples << info->shift;
+    return samples;
+}
+
+/* playback */
+
+static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
+{
+    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+    struct audsettings settings;
+
+    settings.freq       = SPICE_INTERFACE_PLAYBACK_FREQ;
+    settings.nchannels  = SPICE_INTERFACE_PLAYBACK_CHAN;
+    settings.fmt        = AUD_FMT_S16;
+    settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+    audio_pcm_init_info (&hw->info, &settings);
+    hw->samples = LINE_OUT_SAMPLES;
+    out->active = 0;
+
+    out->sin.base.sif = &playback_sif.base;
+    qemu_spice_add_interface (&out->sin.base);
+    return 0;
+}
+
+static void line_out_fini (HWVoiceOut *hw)
+{
+    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+
+    spice_server_remove_interface (&out->sin.base);
+}
+
+static int line_out_run (HWVoiceOut *hw, int live)
+{
+    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+    int rpos, decr;
+    int samples;
+
+    if (!live) {
+        return 0;
+    }
+
+    decr = rate_get_samples (&hw->info, &out->rate);
+    decr = audio_MIN (live, decr);
+
+    samples = decr;
+    rpos = hw->rpos;
+    while (samples) {
+        int left_till_end_samples = hw->samples - rpos;
+        int len = audio_MIN (samples, left_till_end_samples);
+
+        if (!out->frame) {
+            spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
+            out->fpos = out->frame;
+        }
+        if (out->frame) {
+            len = audio_MIN (len, out->fsize);
+            hw->clip (out->fpos, hw->mix_buf + rpos, len);
+            out->fsize -= len;
+            out->fpos  += len;
+            if (out->fsize == 0) {
+                spice_server_playback_put_samples (&out->sin, out->frame);
+                out->frame = out->fpos = NULL;
+            }
+        }
+        rpos = (rpos + len) % hw->samples;
+        samples -= len;
+    }
+    hw->rpos = rpos;
+    return decr;
+}
+
+static int line_out_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
+{
+    SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (out->active) {
+            break;
+        }
+        out->active = 1;
+        rate_start (&out->rate);
+        spice_server_playback_start (&out->sin);
+        break;
+    case VOICE_DISABLE:
+        if (!out->active) {
+            break;
+        }
+        out->active = 0;
+        if (out->frame) {
+            memset (out->fpos, 0, out->fsize << 2);
+            spice_server_playback_put_samples (&out->sin, out->frame);
+            out->frame = out->fpos = NULL;
+        }
+        spice_server_playback_stop (&out->sin);
+        break;
+    }
+    return 0;
+}
+
+/* record */
+
+static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
+{
+    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+    struct audsettings settings;
+
+    settings.freq       = SPICE_INTERFACE_RECORD_FREQ;
+    settings.nchannels  = SPICE_INTERFACE_RECORD_CHAN;
+    settings.fmt        = AUD_FMT_S16;
+    settings.endianness = AUDIO_HOST_ENDIANNESS;
+
+    audio_pcm_init_info (&hw->info, &settings);
+    hw->samples = LINE_IN_SAMPLES;
+    in->active = 0;
+
+    in->sin.base.sif = &record_sif.base;
+    qemu_spice_add_interface (&in->sin.base);
+    return 0;
+}
+
+static void line_in_fini (HWVoiceIn *hw)
+{
+    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+
+    spice_server_remove_interface (&in->sin.base);
+}
+
+static int line_in_run (HWVoiceIn *hw)
+{
+    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+    int num_samples;
+    int ready;
+    int len[2];
+    uint64_t delta_samp;
+    const uint32_t *samples;
+
+    if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
+        return 0;
+    }
+
+    delta_samp = rate_get_samples (&hw->info, &in->rate);
+    num_samples = audio_MIN (num_samples, delta_samp);
+
+    ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
+    samples = in->samples;
+    if (ready == 0) {
+        static const uint32_t silence[LINE_IN_SAMPLES];
+        samples = silence;
+        ready = LINE_IN_SAMPLES;
+    }
+
+    num_samples = audio_MIN (ready, num_samples);
+
+    if (hw->wpos + num_samples > hw->samples) {
+        len[0] = hw->samples - hw->wpos;
+        len[1] = num_samples - len[0];
+    } else {
+        len[0] = num_samples;
+        len[1] = 0;
+    }
+
+    hw->conv (hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume);
+
+    if (len[1]) {
+        hw->conv (hw->conv_buf, samples + len[0], len[1],
+                  &nominal_volume);
+    }
+
+    hw->wpos = (hw->wpos + num_samples) % hw->samples;
+
+    return num_samples;
+}
+
+static int line_in_read (SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
+{
+    SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (in->active) {
+            break;
+        }
+        in->active = 1;
+        rate_start (&in->rate);
+        spice_server_record_start (&in->sin);
+        break;
+    case VOICE_DISABLE:
+        if (!in->active) {
+            break;
+        }
+        in->active = 0;
+        spice_server_record_stop (&in->sin);
+        break;
+    }
+    return 0;
+}
+
+static struct audio_option audio_options[] = {
+    { /* end of list */ },
+};
+
+static struct audio_pcm_ops audio_callbacks = {
+    .init_out = line_out_init,
+    .fini_out = line_out_fini,
+    .run_out  = line_out_run,
+    .write    = line_out_write,
+    .ctl_out  = line_out_ctl,
+
+    .init_in  = line_in_init,
+    .fini_in  = line_in_fini,
+    .run_in   = line_in_run,
+    .read     = line_in_read,
+    .ctl_in   = line_in_ctl,
+};
+
+struct audio_driver spice_audio_driver = {
+    .name           = "spice",
+    .descr          = "spice audio driver",
+    .options        = audio_options,
+    .init           = spice_audio_init,
+    .fini           = spice_audio_fini,
+    .pcm_ops        = &audio_callbacks,
+    .max_voices_out = 1,
+    .max_voices_in  = 1,
+    .voice_size_out = sizeof (SpiceVoiceOut),
+    .voice_size_in  = sizeof (SpiceVoiceIn),
+};
+
+void qemu_spice_audio_init (void)
+{
+    spice_audio_driver.can_be_default = 1;
+}
diff --git a/block-migration.c b/block-migration.c
index 0bfdb73..1475325 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -49,12 +49,14 @@
     int64_t total_sectors;
     int64_t dirty;
     QSIMPLEQ_ENTRY(BlkMigDevState) entry;
+    unsigned long *aio_bitmap;
 } BlkMigDevState;
 
 typedef struct BlkMigBlock {
     uint8_t *buf;
     BlkMigDevState *bmds;
     int64_t sector;
+    int nr_sectors;
     struct iovec iov;
     QEMUIOVector qiov;
     BlockDriverAIOCB *aiocb;
@@ -140,6 +142,52 @@
     return  (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time;
 }
 
+static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
+{
+    int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+    if ((sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) {
+        return !!(bmds->aio_bitmap[chunk / (sizeof(unsigned long) * 8)] &
+            (1UL << (chunk % (sizeof(unsigned long) * 8))));
+    } else {
+        return 0;
+    }
+}
+
+static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num,
+                             int nb_sectors, int set)
+{
+    int64_t start, end;
+    unsigned long val, idx, bit;
+
+    start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
+    end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
+
+    for (; start <= end; start++) {
+        idx = start / (sizeof(unsigned long) * 8);
+        bit = start % (sizeof(unsigned long) * 8);
+        val = bmds->aio_bitmap[idx];
+        if (set) {
+            val |= 1UL << bit;
+        } else {
+            val &= ~(1UL << bit);
+        }
+        bmds->aio_bitmap[idx] = val;
+    }
+}
+
+static void alloc_aio_bitmap(BlkMigDevState *bmds)
+{
+    BlockDriverState *bs = bmds->bs;
+    int64_t bitmap_size;
+
+    bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
+            BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
+    bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
+
+    bmds->aio_bitmap = qemu_mallocz(bitmap_size);
+}
+
 static void blk_mig_read_cb(void *opaque, int ret)
 {
     BlkMigBlock *blk = opaque;
@@ -151,6 +199,7 @@
     add_avg_read_time(blk->time);
 
     QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
+    bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
 
     block_mig_state.submitted--;
     block_mig_state.read_done++;
@@ -194,6 +243,7 @@
     blk->buf = qemu_malloc(BLOCK_SIZE);
     blk->bmds = bmds;
     blk->sector = cur_sector;
+    blk->nr_sectors = nr_sectors;
 
     blk->iov.iov_base = blk->buf;
     blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
@@ -248,6 +298,7 @@
         bmds->total_sectors = sectors;
         bmds->completed_sectors = 0;
         bmds->shared_base = block_mig_state.shared_base;
+        alloc_aio_bitmap(bmds);
 
         block_mig_state.total_sector_sum += sectors;
 
@@ -329,6 +380,9 @@
     int nr_sectors;
 
     for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
+        if (bmds_aio_inflight(bmds, sector)) {
+            qemu_aio_flush();
+        }
         if (bdrv_get_dirty(bmds->bs, sector)) {
 
             if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
@@ -340,6 +394,7 @@
             blk->buf = qemu_malloc(BLOCK_SIZE);
             blk->bmds = bmds;
             blk->sector = sector;
+            blk->nr_sectors = nr_sectors;
 
             if (is_async) {
                 blk->iov.iov_base = blk->buf;
@@ -354,6 +409,7 @@
                     goto error;
                 }
                 block_mig_state.submitted++;
+                bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
             } else {
                 if (bdrv_read(bmds->bs, sector, blk->buf,
                               nr_sectors) < 0) {
@@ -474,6 +530,7 @@
 
     while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
         QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
+        qemu_free(bmds->aio_bitmap);
         qemu_free(bmds);
     }
 
diff --git a/block.c b/block.c
index 985d0b7..63effd8 100644
--- a/block.c
+++ b/block.c
@@ -930,14 +930,14 @@
         bit = start % (sizeof(unsigned long) * 8);
         val = bs->dirty_bitmap[idx];
         if (dirty) {
-            if (!(val & (1 << bit))) {
+            if (!(val & (1UL << bit))) {
                 bs->dirty_count++;
-                val |= 1 << bit;
+                val |= 1UL << bit;
             }
         } else {
-            if (val & (1 << bit)) {
+            if (val & (1UL << bit)) {
                 bs->dirty_count--;
-                val &= ~(1 << bit);
+                val &= ~(1UL << bit);
             }
         }
         bs->dirty_bitmap[idx] = val;
@@ -1453,14 +1453,27 @@
     return bs->device_name;
 }
 
-void bdrv_flush(BlockDriverState *bs)
+int bdrv_flush(BlockDriverState *bs)
 {
     if (bs->open_flags & BDRV_O_NO_FLUSH) {
-        return;
+        return 0;
     }
 
-    if (bs->drv && bs->drv->bdrv_flush)
-        bs->drv->bdrv_flush(bs);
+    if (bs->drv && bs->drv->bdrv_flush) {
+        return bs->drv->bdrv_flush(bs);
+    }
+
+    /*
+     * Some block drivers always operate in either writethrough or unsafe mode
+     * and don't support bdrv_flush therefore. Usually qemu doesn't know how
+     * the server works (because the behaviour is hardcoded or depends on
+     * server-side configuration), so we can't ensure that everything is safe
+     * on disk. Returning an error doesn't work because that would break guests
+     * even if the server operates in writethrough mode.
+     *
+     * Let's hope the user knows what he's doing.
+     */
+    return 0;
 }
 
 void bdrv_flush_all(void)
@@ -2018,12 +2031,49 @@
     return ret;
 }
 
+typedef struct BlockCompleteData {
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+    BlockDriverState *bs;
+    int64_t sector_num;
+    int nb_sectors;
+} BlockCompleteData;
+
+static void block_complete_cb(void *opaque, int ret)
+{
+    BlockCompleteData *b = opaque;
+
+    if (b->bs->dirty_bitmap) {
+        set_dirty_bitmap(b->bs, b->sector_num, b->nb_sectors, 1);
+    }
+    b->cb(b->opaque, ret);
+    qemu_free(b);
+}
+
+static BlockCompleteData *blk_dirty_cb_alloc(BlockDriverState *bs,
+                                             int64_t sector_num,
+                                             int nb_sectors,
+                                             BlockDriverCompletionFunc *cb,
+                                             void *opaque)
+{
+    BlockCompleteData *blkdata = qemu_mallocz(sizeof(BlockCompleteData));
+
+    blkdata->bs = bs;
+    blkdata->cb = cb;
+    blkdata->opaque = opaque;
+    blkdata->sector_num = sector_num;
+    blkdata->nb_sectors = nb_sectors;
+
+    return blkdata;
+}
+
 BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                   QEMUIOVector *qiov, int nb_sectors,
                                   BlockDriverCompletionFunc *cb, void *opaque)
 {
     BlockDriver *drv = bs->drv;
     BlockDriverAIOCB *ret;
+    BlockCompleteData *blk_cb_data;
 
     trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
 
@@ -2035,7 +2085,10 @@
         return NULL;
 
     if (bs->dirty_bitmap) {
-        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+        blk_cb_data = blk_dirty_cb_alloc(bs, sector_num, nb_sectors, cb,
+                                         opaque);
+        cb = &block_complete_cb;
+        opaque = blk_cb_data;
     }
 
     ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
@@ -2672,8 +2725,8 @@
 
     if (bs->dirty_bitmap &&
         (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
-        return bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
-            (1 << (chunk % (sizeof(unsigned long) * 8)));
+        return !!(bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
+            (1UL << (chunk % (sizeof(unsigned long) * 8))));
     } else {
         return 0;
     }
diff --git a/block.h b/block.h
index a4facf2..78ecfac 100644
--- a/block.h
+++ b/block.h
@@ -142,7 +142,7 @@
         BlockDriverCompletionFunc *cb, void *opaque);
 
 /* Ensure contents are flushed to disk.  */
-void bdrv_flush(BlockDriverState *bs);
+int bdrv_flush(BlockDriverState *bs);
 void bdrv_flush_all(void);
 void bdrv_close_all(void);
 
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 4d6ff0a..cd9eb80 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -397,9 +397,9 @@
     }
 }
 
-static void blkdebug_flush(BlockDriverState *bs)
+static int blkdebug_flush(BlockDriverState *bs)
 {
-    bdrv_flush(bs->file);
+    return bdrv_flush(bs->file);
 }
 
 static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
diff --git a/block/blkverify.c b/block/blkverify.c
index b2a12fe..c7522b4 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -116,12 +116,12 @@
     s->test_file = NULL;
 }
 
-static void blkverify_flush(BlockDriverState *bs)
+static int blkverify_flush(BlockDriverState *bs)
 {
     BDRVBlkverifyState *s = bs->opaque;
 
     /* Only flush test file, the raw file is not important */
-    bdrv_flush(s->test_file);
+    return bdrv_flush(s->test_file);
 }
 
 static int64_t blkverify_getlength(BlockDriverState *bs)
@@ -300,8 +300,8 @@
 {
     ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
     if (offset != -1) {
-        blkverify_err(acb, "contents mismatch in sector %lld",
-                      acb->sector_num + (offset / BDRV_SECTOR_SIZE));
+        blkverify_err(acb, "contents mismatch in sector %" PRId64,
+                      acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
     }
 }
 
diff --git a/block/cow.c b/block/cow.c
index eedcc48..4cf543c 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -282,9 +282,9 @@
     return ret;
 }
 
-static void cow_flush(BlockDriverState *bs)
+static int cow_flush(BlockDriverState *bs)
 {
-    bdrv_flush(bs->file);
+    return bdrv_flush(bs->file);
 }
 
 static QEMUOptionParameter cow_create_options[] = {
diff --git a/block/qcow.c b/block/qcow.c
index 816103d..f67d3d3 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -54,7 +54,6 @@
 #define L2_CACHE_SIZE 16
 
 typedef struct BDRVQcowState {
-    BlockDriverState *hd;
     int cluster_bits;
     int cluster_size;
     int cluster_sectors;
@@ -910,9 +909,9 @@
     return 0;
 }
 
-static void qcow_flush(BlockDriverState *bs)
+static int qcow_flush(BlockDriverState *bs)
 {
-    bdrv_flush(bs->file);
+    return bdrv_flush(bs->file);
 }
 
 static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 4f7dc59..b040208 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -188,6 +188,7 @@
     ret = bdrv_pread(bs->file, l2_offset, *l2_table,
         s->l2_size * sizeof(uint64_t));
     if (ret < 0) {
+        qcow2_l2_cache_reset(bs);
         return ret;
     }
 
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 0efb676..a10453c 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -103,6 +103,7 @@
     ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache,
                      s->cluster_size);
     if (ret < 0) {
+        s->refcount_block_cache_offset = 0;
         return ret;
     }
 
diff --git a/block/qcow2.c b/block/qcow2.c
index b816d87..537c479 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1148,9 +1148,9 @@
     return 0;
 }
 
-static void qcow_flush(BlockDriverState *bs)
+static int qcow_flush(BlockDriverState *bs)
 {
-    bdrv_flush(bs->file);
+    return bdrv_flush(bs->file);
 }
 
 static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
diff --git a/block/qcow2.h b/block/qcow2.h
index 2d22e5e..5217bea 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -79,7 +79,6 @@
 } QCowSnapshot;
 
 typedef struct BDRVQcowState {
-    BlockDriverState *hd;
     int cluster_bits;
     int cluster_size;
     int cluster_sectors;
diff --git a/block/raw-posix.c b/block/raw-posix.c
index d0393e0..9286fb8 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -463,7 +463,7 @@
                 count -= ret;
                 sum += ret;
             }
-            /* here, count < 512 because (count & ~sector_mask) == 0 */
+            /* here, count < sector_size because (count & ~sector_mask) == 0 */
             if (count) {
                 ret = raw_pread_aligned(bs, offset, s->aligned_buf,
                                      bs->buffer_alignment);
@@ -734,10 +734,10 @@
     return result;
 }
 
-static void raw_flush(BlockDriverState *bs)
+static int raw_flush(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
-    qemu_fdatasync(s->fd);
+    return qemu_fdatasync(s->fd);
 }
 
 
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 503ed39..06c9710 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -147,10 +147,17 @@
     return ret_count;
 }
 
-static void raw_flush(BlockDriverState *bs)
+static int raw_flush(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
-    FlushFileBuffers(s->hfile);
+    int ret;
+
+    ret = FlushFileBuffers(s->hfile);
+    if (ret != 0) {
+        return -EIO;
+    }
+
+    return 0;
 }
 
 static void raw_close(BlockDriverState *bs)
diff --git a/block/raw.c b/block/raw.c
index 9108779..1980deb 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -39,9 +39,9 @@
 {
 }
 
-static void raw_flush(BlockDriverState *bs)
+static int raw_flush(BlockDriverState *bs)
 {
-    bdrv_flush(bs->file);
+    return bdrv_flush(bs->file);
 }
 
 static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
diff --git a/block/vdi.c b/block/vdi.c
index f72633c..ab8f70f 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -186,7 +186,6 @@
 } VdiHeader;
 
 typedef struct {
-    BlockDriverState *hd;
     /* The block map entries are little endian (even in memory). */
     uint32_t *bmap;
     /* Size of block (bytes). */
@@ -900,10 +899,10 @@
 {
 }
 
-static void vdi_flush(BlockDriverState *bs)
+static int vdi_flush(BlockDriverState *bs)
 {
     logout("\n");
-    bdrv_flush(bs->file);
+    return bdrv_flush(bs->file);
 }
 
 
diff --git a/block/vmdk.c b/block/vmdk.c
index 2d4ba42..8fc9d67 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -61,7 +61,6 @@
 #define L2_CACHE_SIZE 16
 
 typedef struct BDRVVmdkState {
-    BlockDriverState *hd;
     int64_t l1_table_offset;
     int64_t l1_backup_table_offset;
     uint32_t *l1_table;
@@ -823,9 +822,9 @@
     qemu_free(s->l2_cache);
 }
 
-static void vmdk_flush(BlockDriverState *bs)
+static int vmdk_flush(BlockDriverState *bs)
 {
-    bdrv_flush(bs->file);
+    return bdrv_flush(bs->file);
 }
 
 
diff --git a/block/vpc.c b/block/vpc.c
index e50509e..21e2a68 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -110,8 +110,6 @@
 };
 
 typedef struct BDRVVPCState {
-    BlockDriverState *hd;
-
     uint8_t footer_buf[HEADER_SIZE];
     uint64_t free_data_block_offset;
     int max_table_entries;
@@ -439,6 +437,10 @@
     return 0;
 }
 
+static int vpc_flush(BlockDriverState *bs)
+{
+    return bdrv_flush(bs->file);
+}
 
 /*
  * Calculates the number of cylinders, heads and sectors per cylinder
@@ -618,14 +620,15 @@
 };
 
 static BlockDriver bdrv_vpc = {
-    .format_name	= "vpc",
-    .instance_size	= sizeof(BDRVVPCState),
-    .bdrv_probe		= vpc_probe,
-    .bdrv_open		= vpc_open,
-    .bdrv_read		= vpc_read,
-    .bdrv_write		= vpc_write,
-    .bdrv_close		= vpc_close,
-    .bdrv_create	= vpc_create,
+    .format_name    = "vpc",
+    .instance_size  = sizeof(BDRVVPCState),
+    .bdrv_probe     = vpc_probe,
+    .bdrv_open      = vpc_open,
+    .bdrv_read      = vpc_read,
+    .bdrv_write     = vpc_write,
+    .bdrv_flush     = vpc_flush,
+    .bdrv_close     = vpc_close,
+    .bdrv_create    = vpc_create,
 
     .create_options = vpc_create_options,
 };
diff --git a/block_int.h b/block_int.h
index 87e60b8..3c3adb5 100644
--- a/block_int.h
+++ b/block_int.h
@@ -59,7 +59,7 @@
                       const uint8_t *buf, int nb_sectors);
     void (*bdrv_close)(BlockDriverState *bs);
     int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
-    void (*bdrv_flush)(BlockDriverState *bs);
+    int (*bdrv_flush)(BlockDriverState *bs);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
diff --git a/blockdev.c b/blockdev.c
index ff7602b..f6ac439 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -14,6 +14,8 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 #include "sysemu.h"
+#include "hw/qdev.h"
+#include "block_int.h"
 
 static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
 
@@ -314,7 +316,7 @@
     on_write_error = BLOCK_ERR_STOP_ENOSPC;
     if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
         if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
-            fprintf(stderr, "werror is no supported by this format\n");
+            fprintf(stderr, "werror is not supported by this format\n");
             return NULL;
         }
 
@@ -326,8 +328,8 @@
 
     on_read_error = BLOCK_ERR_REPORT;
     if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
-        if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
-            fprintf(stderr, "rerror is no supported by this format\n");
+        if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
+            fprintf(stderr, "rerror is not supported by this format\n");
             return NULL;
         }
 
@@ -597,3 +599,40 @@
     }
     return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
 }
+
+int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *id = qdict_get_str(qdict, "id");
+    BlockDriverState *bs;
+    BlockDriverState **ptr;
+    Property *prop;
+
+    bs = bdrv_find(id);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, id);
+        return -1;
+    }
+
+    /* quiesce block driver; prevent further io */
+    qemu_aio_flush();
+    bdrv_flush(bs);
+    bdrv_close(bs);
+
+    /* clean up guest state from pointing to host resource by
+     * finding and removing DeviceState "drive" property */
+    for (prop = bs->peer->info->props; prop && prop->name; prop++) {
+        if (prop->info->type == PROP_TYPE_DRIVE) {
+            ptr = qdev_get_prop_ptr(bs->peer, prop);
+            if ((*ptr) == bs) {
+                bdrv_detach(bs, bs->peer);
+                *ptr = NULL;
+                break;
+            }
+        }
+    }
+
+    /* clean up host side */
+    drive_uninit(drive_get_by_blockdev(bs));
+
+    return 0;
+}
diff --git a/blockdev.h b/blockdev.h
index 653affc..4cb8ca9 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -32,7 +32,7 @@
 };
 
 #define MAX_IDE_DEVS	2
-#define MAX_SCSI_DEVS	7
+#define MAX_SCSI_DEVS	255
 
 DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
 int drive_get_max_bus(BlockInterfaceType type);
@@ -51,5 +51,6 @@
 int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_change_block(Monitor *mon, const char *device,
                     const char *filename, const char *fmt);
+int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
 #endif
diff --git a/configure b/configure
index 7025d2b..2917874 100755
--- a/configure
+++ b/configure
@@ -929,7 +929,7 @@
 echo "  --disable-docs           disable documentation build"
 echo "  --disable-vhost-net      disable vhost-net acceleration support"
 echo "  --enable-vhost-net       enable vhost-net acceleration support"
-echo "  --trace-backend=B        Trace backend nop simple ust"
+echo "  --trace-backend=B        Trace backend nop simple ust dtrace"
 echo "  --trace-file=NAME        Full PATH,NAME of file to store traces"
 echo "                           Default:trace-<pid>"
 echo "  --disable-spice          disable spice"
@@ -2193,6 +2193,22 @@
     exit 1
   fi
 fi
+
+##########################################
+# For 'dtrace' backend, test if 'dtrace' command is present
+if test "$trace_backend" = "dtrace"; then
+  if ! has 'dtrace' ; then
+    echo
+    echo "Error: dtrace command is not found in PATH $PATH"
+    echo
+    exit 1
+  fi
+  trace_backend_stap="no"
+  if has 'stap' ; then
+    trace_backend_stap="yes"
+  fi
+fi
+
 ##########################################
 # End of CC checks
 # After here, no more $cc or $ld runs
@@ -2633,6 +2649,9 @@
 if test "$trace_backend" = "simple"; then
   trace_file="\"$trace_file-%u\""
 fi
+if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then
+  echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak
+fi
 echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
 
 echo "TOOLS=$tools" >> $config_host_mak
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index e7a4e84..ac48dc1 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -1,7 +1,7 @@
 # Default configuration for arm-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
 CONFIG_ISA_MMIO=y
 CONFIG_NAND=y
 CONFIG_ECC=y
@@ -25,6 +25,5 @@
 CONFIG_LAN9118=y
 CONFIG_SMC91C111=y
 CONFIG_DS1338=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
diff --git a/default-configs/cris-softmmu.mak b/default-configs/cris-softmmu.mak
index e0d2cab..1a479cd 100644
--- a/default-configs/cris-softmmu.mak
+++ b/default-configs/cris-softmmu.mak
@@ -2,5 +2,4 @@
 
 CONFIG_NAND=y
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI02=y
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index ed00471..ce905d2 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -1,6 +1,6 @@
 # Default configuration for i386-softmmu
 
-CONFIG_USB_OHCI=y
+include pci.mak
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VMWARE_VGA=y
@@ -9,7 +9,6 @@
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -22,4 +21,3 @@
 CONFIG_NE2000_ISA=y
 CONFIG_PIIX_PCI=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak
index 69ca3ed..3e2ec37 100644
--- a/default-configs/m68k-softmmu.mak
+++ b/default-configs/m68k-softmmu.mak
@@ -1,5 +1,5 @@
 # Default configuration for m68k-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
diff --git a/default-configs/microblaze-softmmu.mak b/default-configs/microblaze-softmmu.mak
index 6c4f4f2..4399b8b 100644
--- a/default-configs/microblaze-softmmu.mak
+++ b/default-configs/microblaze-softmmu.mak
@@ -1,5 +1,4 @@
 # Default configuration for microblaze-softmmu
 
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 3d0af83..565e611 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for mips-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -24,7 +24,6 @@
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index 0030de4..03bd8eb 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for mips64-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -24,7 +24,6 @@
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index fa2a3ff..4661617 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for mips64el-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -25,7 +25,6 @@
 CONFIG_IDE_VIA=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 238b73a..92fc473 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for mipsel-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -24,7 +24,6 @@
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
new file mode 100644
index 0000000..c74a99f
--- /dev/null
+++ b/default-configs/pci.mak
@@ -0,0 +1,12 @@
+CONFIG_PCI=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_OHCI=y
+CONFIG_NE2000_PCI=y
+CONFIG_EEPRO100_PCI=y
+CONFIG_PCNET_PCI=y
+CONFIG_PCNET_COMMON=y
+CONFIG_LSI_SCSI_PCI=y
+CONFIG_RTL8139_PCI=y
+CONFIG_E1000_PCI=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 940f4bf..f1cb99e 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -1,7 +1,7 @@
 # Default configuration for ppc-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
@@ -31,7 +31,6 @@
 CONFIG_IDE_MACIO=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index e1bc6b8..83cbe97 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -1,7 +1,7 @@
 # Default configuration for ppc64-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
@@ -31,7 +31,6 @@
 CONFIG_IDE_MACIO=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index 8f1cc09..2b52d4a 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -1,7 +1,7 @@
 # Default configuration for ppcemb-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
@@ -31,7 +31,6 @@
 CONFIG_IDE_MACIO=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index e69de29..3005729 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -0,0 +1 @@
+CONFIG_VIRTIO=y
diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak
index 866ed7d..87247a4 100644
--- a/default-configs/sh4-softmmu.mak
+++ b/default-configs/sh4-softmmu.mak
@@ -1,9 +1,8 @@
 # Default configuration for sh4-softmmu
 
-CONFIG_USB_OHCI=y
+include pci.mak
 CONFIG_SERIAL=y
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_IDE_CORE=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak
index e3e08b7..5b8a16e 100644
--- a/default-configs/sh4eb-softmmu.mak
+++ b/default-configs/sh4eb-softmmu.mak
@@ -1,9 +1,8 @@
 # Default configuration for sh4eb-softmmu
 
-CONFIG_USB_OHCI=y
+include pci.mak
 CONFIG_SERIAL=y
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_IDE_CORE=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak
index becf880..b0310c5 100644
--- a/default-configs/sparc-softmmu.mak
+++ b/default-configs/sparc-softmmu.mak
@@ -6,5 +6,5 @@
 CONFIG_M48T59=y
 CONFIG_PTIMER=y
 CONFIG_FDC=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_EMPTY_SLOT=y
+CONFIG_PCNET_COMMON=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index 1cc3f13..ecc3122 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for sparc64-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_M48T59=y
 CONFIG_PTIMER=y
@@ -13,4 +14,3 @@
 CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_CMD646=y
-CONFIG_VIRTIO_PCI=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 5183203..7f22599 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -1,6 +1,6 @@
 # Default configuration for x86_64-softmmu
 
-CONFIG_USB_OHCI=y
+include pci.mak
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VMWARE_VGA=y
@@ -9,7 +9,6 @@
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -22,4 +21,3 @@
 CONFIG_NE2000_ISA=y
 CONFIG_PIIX_PCI=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
diff --git a/hmp-commands.hx b/hmp-commands.hx
index e5585ba..23024ba 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -68,6 +68,24 @@
 ETEXI
 
     {
+        .name       = "drive_del",
+        .args_type  = "id:s",
+        .params     = "device",
+        .help       = "remove host block device",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_drive_del,
+    },
+
+STEXI
+@item drive_del @var{device}
+@findex drive_del
+Remove host block device.  The result is that guest generated IO is no longer
+submitted against the host device underlying the disk.  Once a drive has
+been deleted, the QEMU Block layer returns -EIO which results in IO
+errors in the guest for applications that are reading/writing to the device.
+ETEXI
+
+    {
         .name       = "change",
         .args_type  = "device:B,target:F,arg:s?",
         .params     = "device filename [format]",
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index f549089..173d781 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -52,6 +52,7 @@
 
 typedef struct PIIX4PMState {
     PCIDevice dev;
+    IORange ioport;
     uint16_t pmsts;
     uint16_t pmen;
     uint16_t pmcntrl;
@@ -128,10 +129,16 @@
     pm_update_sci(s);
 }
 
-static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width,
+                            uint64_t val)
 {
-    PIIX4PMState *s = opaque;
-    addr &= 0x3f;
+    PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport);
+
+    if (width != 2) {
+        PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n",
+                      (unsigned)addr, width, (unsigned)val);
+    }
+
     switch(addr) {
     case 0x00:
         {
@@ -184,12 +191,12 @@
     PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val);
 }
 
-static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
+static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width,
+                            uint64_t *data)
 {
-    PIIX4PMState *s = opaque;
+    PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport);
     uint32_t val;
 
-    addr &= 0x3f;
     switch(addr) {
     case 0x00:
         val = get_pmsts(s);
@@ -200,27 +207,6 @@
     case 0x04:
         val = s->pmcntrl;
         break;
-    default:
-        val = 0;
-        break;
-    }
-    PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val);
-    return val;
-}
-
-static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-    //    PIIX4PMState *s = opaque;
-    PIIX4_DPRINTF("PM writel port=0x%04x val=0x%08x\n", addr & 0x3f, val);
-}
-
-static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
-{
-    PIIX4PMState *s = opaque;
-    uint32_t val;
-
-    addr &= 0x3f;
-    switch(addr) {
     case 0x08:
         val = get_pmtmr(s);
         break;
@@ -228,10 +214,15 @@
         val = 0;
         break;
     }
-    PIIX4_DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val);
-    return val;
+    PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val);
+    *data = val;
 }
 
+static const IORangeOps pm_iorange_ops = {
+    .read = pm_ioport_read,
+    .write = pm_ioport_write,
+};
+
 static void apm_ctrl_changed(uint32_t val, void *arg)
 {
     PIIX4PMState *s = arg;
@@ -265,10 +256,8 @@
 
         /* XXX: need to improve memory and ioport allocation */
         PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base);
-        register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
-        register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
-        register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
-        register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
+        iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64);
+        ioport_register(&s->ioport);
     }
 }
 
diff --git a/hw/apic.c b/hw/apic.c
index 63d62c7..5f4a87c 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -437,6 +437,8 @@
         apic = local_apics[i];
 	if (apic && apic->id == dest)
             return i;
+        if (!apic)
+            break;
     }
 
     return -1;
@@ -472,6 +474,8 @@
                         set_bit(deliver_bitmask, i);
                     }
                 }
+            } else {
+                break;
             }
         }
     }
diff --git a/hw/e1000.c b/hw/e1000.c
index b7f585b..57d08cf 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -447,9 +447,10 @@
         // data descriptor
         tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
         tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
-    } else
+    } else {
         // legacy descriptor
         tp->cptse = 0;
+    }
 
     if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
         (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
@@ -685,8 +686,9 @@
                                       (void *)(buf + vlan_offset), size);
             desc.length = cpu_to_le16(size + fcs_len(s));
             desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM;
-        } else // as per intel docs; skip descriptors with null buf addr
+        } else { // as per intel docs; skip descriptors with null buf addr
             DBGOUT(RX, "Null RX descriptor!!\n");
+        }
         cpu_physical_memory_write(base, (void *)&desc, sizeof(desc));
 
         if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
@@ -858,13 +860,14 @@
 #ifdef TARGET_WORDS_BIGENDIAN
     val = bswap32(val);
 #endif
-    if (index < NWRITEOPS && macreg_writeops[index])
+    if (index < NWRITEOPS && macreg_writeops[index]) {
         macreg_writeops[index](s, index, val);
-    else if (index < NREADOPS && macreg_readops[index])
+    } else if (index < NREADOPS && macreg_readops[index]) {
         DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04x\n", index<<2, val);
-    else
+    } else {
         DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n",
                index<<2, val);
+    }
 }
 
 static void
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 1035774..c699d6f 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -808,6 +808,28 @@
     return 0;
 }
 
+static int hda_audio_exit(HDACodecDevice *hda)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    HDAAudioStream *st;
+    int i;
+
+    dprint(a, 1, "%s\n", __FUNCTION__);
+    for (i = 0; i < ARRAY_SIZE(a->st); i++) {
+        st = a->st + i;
+        if (st->node == NULL) {
+            continue;
+        }
+        if (st->output) {
+            AUD_close_out(&a->card, st->voice.out);
+        } else {
+            AUD_close_in(&a->card, st->voice.in);
+        }
+    }
+    AUD_remove_card(&a->card);
+    return 0;
+}
+
 static int hda_audio_post_load(void *opaque, int version)
 {
     HDAAudioState *a = opaque;
@@ -879,6 +901,7 @@
     .qdev.vmsd    = &vmstate_hda_audio,
     .qdev.props   = hda_audio_properties,
     .init         = hda_audio_init_output,
+    .exit         = hda_audio_exit,
     .command      = hda_audio_command,
     .stream       = hda_audio_stream,
 };
@@ -890,6 +913,7 @@
     .qdev.vmsd    = &vmstate_hda_audio,
     .qdev.props   = hda_audio_properties,
     .init         = hda_audio_init_duplex,
+    .exit         = hda_audio_exit,
     .command      = hda_audio_command,
     .stream       = hda_audio_stream,
 };
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index ff80dd5..dfe6091 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -179,12 +179,8 @@
             register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
         }
 
-        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
-        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
-        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
-        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
-        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
-        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
+        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
+        ioport_register(&bm->addr_ioport);
         addr += 8;
     }
 }
diff --git a/hw/ide/core.c b/hw/ide/core.c
index bc3e916..430350f 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -473,11 +473,21 @@
     qemu_sglist_destroy(&s->sg);
 }
 
+static void ide_dma_set_inactive(BMDMAState *bm)
+{
+    bm->status &= ~BM_STATUS_DMAING;
+    bm->dma_cb = NULL;
+    bm->unit = -1;
+    bm->aiocb = NULL;
+}
+
 void ide_dma_error(IDEState *s)
 {
     ide_transfer_stop(s);
     s->error = ABRT_ERR;
     s->status = READY_STAT | ERR_STAT;
+    ide_dma_set_inactive(s->bus->bmdma);
+    s->bus->bmdma->status |= BM_STATUS_INT;
     ide_set_irq(s->bus);
 }
 
@@ -587,11 +597,8 @@
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
     eot:
-        bm->status &= ~BM_STATUS_DMAING;
         bm->status |= BM_STATUS_INT;
-        bm->dma_cb = NULL;
-        bm->unit = -1;
-        bm->aiocb = NULL;
+        ide_dma_set_inactive(bm);
         return;
     }
 
@@ -733,11 +740,8 @@
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
     eot:
-        bm->status &= ~BM_STATUS_DMAING;
         bm->status |= BM_STATUS_INT;
-        bm->dma_cb = NULL;
-        bm->unit = -1;
-        bm->aiocb = NULL;
+        ide_dma_set_inactive(bm);
         return;
     }
 
@@ -811,10 +815,16 @@
 
 static void ide_flush_cache(IDEState *s)
 {
-    if (s->bs) {
-        bdrv_aio_flush(s->bs, ide_flush_cb, s);
-    } else {
+    BlockDriverAIOCB *acb;
+
+    if (s->bs == NULL) {
         ide_flush_cb(s, 0);
+        return;
+    }
+
+    acb = bdrv_aio_flush(s->bs, ide_flush_cb, s);
+    if (acb == NULL) {
+        ide_flush_cb(s, -EIO);
     }
 }
 
@@ -1055,11 +1065,8 @@
         s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
         ide_set_irq(s->bus);
     eot:
-        bm->status &= ~BM_STATUS_DMAING;
         bm->status |= BM_STATUS_INT;
-        bm->dma_cb = NULL;
-        bm->unit = -1;
-        bm->aiocb = NULL;
+        ide_dma_set_inactive(bm);
         return;
     }
 
@@ -2948,12 +2955,10 @@
             printf("aio_cancel\n");
 #endif
             bdrv_aio_cancel(bm->aiocb);
-            bm->aiocb = NULL;
         }
-        bm->status &= ~BM_STATUS_DMAING;
+
         /* cancel DMA request */
-        bm->unit = -1;
-        bm->dma_cb = NULL;
+        ide_dma_set_inactive(bm);
     }
 }
 
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index d652e06..85f4a16 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -8,6 +8,7 @@
  */
 #include <hw/ide.h>
 #include "block_int.h"
+#include "iorange.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -496,6 +497,7 @@
     QEMUIOVector qiov;
     int64_t sector_num;
     uint32_t nsector;
+    IORange addr_ioport;
     QEMUBH *bh;
 };
 
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index ec90f26..ad406ee 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -39,106 +39,75 @@
 #ifdef DEBUG_IDE
     printf("%s: 0x%08x\n", __func__, val);
 #endif
-    if (!(val & BM_CMD_START)) {
-        /*
-         * We can't cancel Scatter Gather DMA in the middle of the
-         * operation or a partial (not full) DMA transfer would reach
-         * the storage so we wait for completion instead (we beahve
-         * like if the DMA was completed by the time the guest trying
-         * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
-         * set).
-         *
-         * In the future we'll be able to safely cancel the I/O if the
-         * whole DMA operation will be submitted to disk with a single
-         * aio operation with preadv/pwritev.
-         */
-        if (bm->aiocb) {
-            qemu_aio_flush();
+
+    /* Ignore writes to SSBM if it keeps the old value */
+    if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
+        if (!(val & BM_CMD_START)) {
+            /*
+             * We can't cancel Scatter Gather DMA in the middle of the
+             * operation or a partial (not full) DMA transfer would reach
+             * the storage so we wait for completion instead (we beahve
+             * like if the DMA was completed by the time the guest trying
+             * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
+             * set).
+             *
+             * In the future we'll be able to safely cancel the I/O if the
+             * whole DMA operation will be submitted to disk with a single
+             * aio operation with preadv/pwritev.
+             */
+            if (bm->aiocb) {
+                qemu_aio_flush();
 #ifdef DEBUG_IDE
-            if (bm->aiocb)
-                printf("ide_dma_cancel: aiocb still pending");
-            if (bm->status & BM_STATUS_DMAING)
-                printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
+                if (bm->aiocb)
+                    printf("ide_dma_cancel: aiocb still pending");
+                if (bm->status & BM_STATUS_DMAING)
+                    printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
 #endif
+            }
+        } else {
+            bm->cur_addr = bm->addr;
+            if (!(bm->status & BM_STATUS_DMAING)) {
+                bm->status |= BM_STATUS_DMAING;
+                /* start dma transfer if possible */
+                if (bm->dma_cb)
+                    bm->dma_cb(bm, 0);
+            }
         }
-        bm->cmd = val & 0x09;
-    } else {
-        if (!(bm->status & BM_STATUS_DMAING)) {
-            bm->status |= BM_STATUS_DMAING;
-            /* start dma transfer if possible */
-            if (bm->dma_cb)
-                bm->dma_cb(bm, 0);
-        }
-        bm->cmd = val & 0x09;
     }
+
+    bm->cmd = val & 0x09;
 }
 
-uint32_t bmdma_addr_readb(void *opaque, uint32_t addr)
+static void bmdma_addr_read(IORange *ioport, uint64_t addr,
+                            unsigned width, uint64_t *data)
 {
-    BMDMAState *bm = opaque;
-    uint32_t val;
-    val = (bm->addr >> ((addr & 3) * 8)) & 0xff;
+    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    uint32_t mask = (1ULL << (width * 8)) - 1;
+
+    *data = (bm->addr >> (addr * 8)) & mask;
 #ifdef DEBUG_IDE
-    printf("%s: 0x%08x\n", __func__, val);
+    printf("%s: 0x%08x\n", __func__, (unsigned)*data);
 #endif
-    return val;
 }
 
-void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void bmdma_addr_write(IORange *ioport, uint64_t addr,
+                             unsigned width, uint64_t data)
 {
-    BMDMAState *bm = opaque;
-    int shift = (addr & 3) * 8;
+    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    int shift = addr * 8;
+    uint32_t mask = (1ULL << (width * 8)) - 1;
+
 #ifdef DEBUG_IDE
-    printf("%s: 0x%08x\n", __func__, val);
+    printf("%s: 0x%08x\n", __func__, (unsigned)data);
 #endif
-    bm->addr &= ~(0xFF << shift);
-    bm->addr |= ((val & 0xFF) << shift) & ~3;
-    bm->cur_addr = bm->addr;
+    bm->addr &= ~(mask << shift);
+    bm->addr |= ((data & mask) << shift) & ~3;
 }
 
-uint32_t bmdma_addr_readw(void *opaque, uint32_t addr)
-{
-    BMDMAState *bm = opaque;
-    uint32_t val;
-    val = (bm->addr >> ((addr & 3) * 8)) & 0xffff;
-#ifdef DEBUG_IDE
-    printf("%s: 0x%08x\n", __func__, val);
-#endif
-    return val;
-}
-
-void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val)
-{
-    BMDMAState *bm = opaque;
-    int shift = (addr & 3) * 8;
-#ifdef DEBUG_IDE
-    printf("%s: 0x%08x\n", __func__, val);
-#endif
-    bm->addr &= ~(0xFFFF << shift);
-    bm->addr |= ((val & 0xFFFF) << shift) & ~3;
-    bm->cur_addr = bm->addr;
-}
-
-uint32_t bmdma_addr_readl(void *opaque, uint32_t addr)
-{
-    BMDMAState *bm = opaque;
-    uint32_t val;
-    val = bm->addr;
-#ifdef DEBUG_IDE
-    printf("%s: 0x%08x\n", __func__, val);
-#endif
-    return val;
-}
-
-void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-    BMDMAState *bm = opaque;
-#ifdef DEBUG_IDE
-    printf("%s: 0x%08x\n", __func__, val);
-#endif
-    bm->addr = val & ~3;
-    bm->cur_addr = bm->addr;
-}
+const IORangeOps bmdma_addr_ioport_ops = {
+    .read = bmdma_addr_read,
+    .write = bmdma_addr_write,
+};
 
 static bool ide_bmdma_current_needed(void *opaque)
 {
diff --git a/hw/ide/pci.h b/hw/ide/pci.h
index d46a95e..b81b26c 100644
--- a/hw/ide/pci.h
+++ b/hw/ide/pci.h
@@ -11,12 +11,7 @@
 } PCIIDEState;
 
 void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val);
-uint32_t bmdma_addr_readb(void *opaque, uint32_t addr);
-void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val);
-uint32_t bmdma_addr_readw(void *opaque, uint32_t addr);
-void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val);
-uint32_t bmdma_addr_readl(void *opaque, uint32_t addr);
-void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val);
+extern const IORangeOps bmdma_addr_ioport_ops;
 void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
 
 extern const VMStateDescription vmstate_ide_pci;
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 07483e8..e02b89a 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -85,12 +85,8 @@
         register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
         register_ioport_read(addr, 4, 1, bmdma_readb, bm);
 
-        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
-        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
-        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
-        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
-        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
-        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
+        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
+        ioport_register(&bm->addr_ioport);
         addr += 8;
     }
 }
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 2001a36..66be0c4 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -87,12 +87,8 @@
         register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
         register_ioport_read(addr, 4, 1, bmdma_readb, bm);
 
-        register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
-        register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
-        register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
-        register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
-        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
-        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
+        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
+        ioport_register(&bm->addr_ioport);
         addr += 8;
     }
 }
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index ccb059d..fe31624 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -19,6 +19,7 @@
 
 #include "hw.h"
 #include "pci.h"
+#include "msi.h"
 #include "qemu-timer.h"
 #include "audiodev.h"
 #include "intel-hda.h"
@@ -55,15 +56,27 @@
     if (dev->cad == -1) {
         dev->cad = bus->next_cad;
     }
-    if (dev->cad > 15)
+    if (dev->cad >= 15) {
         return -1;
+    }
     bus->next_cad = dev->cad + 1;
     return info->init(dev);
 }
 
+static int hda_codec_dev_exit(DeviceState *qdev)
+{
+    HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+
+    if (dev->info->exit) {
+        dev->info->exit(dev);
+    }
+    return 0;
+}
+
 void hda_codec_register(HDACodecDeviceInfo *info)
 {
     info->qdev.init = hda_codec_dev_init;
+    info->qdev.exit = hda_codec_dev_exit;
     info->qdev.bus_info = &hda_codec_bus_info;
     qdev_register(&info->qdev);
 }
@@ -177,6 +190,7 @@
 
     /* properties */
     uint32_t debug;
+    uint32_t msi;
 };
 
 struct IntelHDAReg {
@@ -235,7 +249,7 @@
     if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
         sts |= (1 << 30);
     }
-    if (d->state_sts) {
+    if (d->state_sts & d->wake_en) {
         sts |= (1 << 30);
     }
 
@@ -257,6 +271,7 @@
 
 static void intel_hda_update_irq(IntelHDAState *d)
 {
+    int msi = d->msi && msi_enabled(&d->pci);
     int level;
 
     intel_hda_update_int_sts(d);
@@ -265,8 +280,15 @@
     } else {
         level = 0;
     }
-    dprint(d, 2, "%s: level %d\n", __FUNCTION__, level);
-    qemu_set_irq(d->pci.irq[0], level);
+    dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
+           level, msi ? "msi" : "intx");
+    if (msi) {
+        if (level) {
+            msi_notify(&d->pci, 0);
+        }
+    } else {
+        qemu_set_irq(d->pci.irq[0], level);
+    }
 }
 
 static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
@@ -497,6 +519,11 @@
     }
 }
 
+static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+}
+
 static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
 {
     intel_hda_update_irq(d);
@@ -617,13 +644,15 @@
     [ ICH6_REG_WAKEEN ] = {
         .name     = "WAKEEN",
         .size     = 2,
+        .wmask    = 0x7fff,
         .offset   = offsetof(IntelHDAState, wake_en),
+        .whandler = intel_hda_set_wake_en,
     },
     [ ICH6_REG_STATESTS ] = {
         .name     = "STATESTS",
         .size     = 2,
-        .wmask    = 0x3fff,
-        .wclear   = 0x3fff,
+        .wmask    = 0x7fff,
+        .wclear   = 0x7fff,
         .offset   = offsetof(IntelHDAState, state_sts),
         .whandler = intel_hda_set_state_sts,
     },
@@ -1130,6 +1159,9 @@
                                           intel_hda_mmio_write, d);
     pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
                      intel_hda_map);
+    if (d->msi) {
+        msi_init(&d->pci, 0x50, 1, true, false);
+    }
 
     hda_codec_bus_init(&d->pci.qdev, &d->codecs,
                        intel_hda_response, intel_hda_xfer);
@@ -1137,6 +1169,28 @@
     return 0;
 }
 
+static int intel_hda_exit(PCIDevice *pci)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+    if (d->msi) {
+        msi_uninit(&d->pci);
+    }
+    cpu_unregister_io_memory(d->mmio_addr);
+    return 0;
+}
+
+static void intel_hda_write_config(PCIDevice *pci, uint32_t addr,
+                                   uint32_t val, int len)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+    pci_default_write_config(pci, addr, val, len);
+    if (d->msi) {
+        msi_write_config(pci, addr, val, len);
+    }
+}
+
 static int intel_hda_post_load(void *opaque, int version)
 {
     IntelHDAState* d = opaque;
@@ -1219,8 +1273,11 @@
     .qdev.vmsd    = &vmstate_intel_hda,
     .qdev.reset   = intel_hda_reset,
     .init         = intel_hda_init,
+    .exit         = intel_hda_exit,
+    .config_write = intel_hda_write_config,
     .qdev.props   = (Property[]) {
         DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+        DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index ba290ec..4e44e38 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -32,6 +32,7 @@
 struct HDACodecDeviceInfo {
     DeviceInfo qdev;
     int (*init)(HDACodecDevice *dev);
+    int (*exit)(HDACodecDevice *dev);
     void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
     void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
 };
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 8026071..6be8aa7 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -977,7 +977,7 @@
     } else if (vmsvga_enabled) {
         pci_vmsvga_init(pci_bus);
     } else if (std_vga_enabled) {
-        pci_vga_init(pci_bus, 0, 0);
+        pci_vga_init(pci_bus);
     }
 }
 
diff --git a/hw/multiboot.c b/hw/multiboot.c
index f9097a2..e710bbb 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -171,6 +171,12 @@
         uint64_t elf_low, elf_high;
         int kernel_size;
         fclose(f);
+
+        if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
+            fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
+            exit(1);
+        }
+
         kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
                                &elf_low, &elf_high, 0, ELF_MACHINE, 0);
         if (kernel_size < 0) {
diff --git a/hw/pc.c b/hw/pc.c
index 69b13bf..119c110 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -75,12 +75,12 @@
     uint64_t address;
     uint64_t length;
     uint32_t type;
-};
+} __attribute((__packed__, __aligned__(4)));
 
 struct e820_table {
     uint32_t count;
     struct e820_entry entry[E820_NR_ENTRIES];
-};
+} __attribute((__packed__, __aligned__(4)));
 
 static struct e820_table e820_table;
 
@@ -430,8 +430,8 @@
         /* Bochs BIOS messages */
     case 0x400:
     case 0x401:
-        fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
-        exit(1);
+        /* used to be panic, now unused */
+        break;
     case 0x402:
     case 0x403:
 #ifdef DEBUG_BIOS
@@ -467,19 +467,19 @@
 
 int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
 {
-    int index = e820_table.count;
+    int index = le32_to_cpu(e820_table.count);
     struct e820_entry *entry;
 
     if (index >= E820_NR_ENTRIES)
         return -EBUSY;
-    entry = &e820_table.entry[index];
+    entry = &e820_table.entry[index++];
 
-    entry->address = address;
-    entry->length = length;
-    entry->type = type;
+    entry->address = cpu_to_le64(address);
+    entry->length = cpu_to_le64(length);
+    entry->type = cpu_to_le32(type);
 
-    e820_table.count++;
-    return e820_table.count;
+    e820_table.count = cpu_to_le32(index);
+    return index;
 }
 
 static void *bochs_bios_init(void)
@@ -993,7 +993,7 @@
             fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
     } else if (std_vga_enabled) {
         if (pci_bus) {
-            pci_vga_init(pci_bus, 0, 0);
+            pci_vga_init(pci_bus);
         } else {
             isa_vga_init();
         }
diff --git a/hw/pc.h b/hw/pc.h
index 63b0249..6852790 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -154,8 +154,7 @@
 extern enum vga_retrace_method vga_retrace_method;
 
 int isa_vga_init(void);
-int pci_vga_init(PCIBus *bus,
-                 unsigned long vga_bios_offset, int vga_bios_size);
+int pci_vga_init(PCIBus *bus);
 int isa_vga_mm_init(target_phys_addr_t vram_base,
                     target_phys_addr_t ctrl_base, int it_shift);
 
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 12359a7..7d29d43 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -212,7 +212,7 @@
 }
 
 static QEMUMachine pc_machine = {
-    .name = "pc-0.13",
+    .name = "pc-0.14",
     .alias = "pc",
     .desc = "Standard PC",
     .init = pc_init_pci,
@@ -220,6 +220,29 @@
     .is_default = 1,
 };
 
+static QEMUMachine pc_machine_v0_13 = {
+    .name = "pc-0.13",
+    .desc = "Standard PC",
+    .init = pc_init_pci,
+    .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "virtio-9p-pci",
+            .property = "vectors",
+            .value    = stringify(0),
+        },{
+            .driver   = "VGA",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "vmware-svga",
+            .property = "rombar",
+            .value    = stringify(0),
+        },
+        { /* end of list */ }
+    },
+};
+
 static QEMUMachine pc_machine_v0_12 = {
     .name = "pc-0.12",
     .desc = "Standard PC",
@@ -234,6 +257,14 @@
             .driver   = "virtio-serial-pci",
             .property = "vectors",
             .value    = stringify(0),
+        },{
+            .driver   = "VGA",
+            .property = "rombar",
+            .value    = stringify(0),
+        },{
+            .driver   = "vmware-svga",
+            .property = "rombar",
+            .value    = stringify(0),
         },
         { /* end of list */ }
     }
@@ -331,6 +362,7 @@
 static void pc_machine_init(void)
 {
     qemu_register_machine(&pc_machine);
+    qemu_register_machine(&pc_machine_v0_13);
     qemu_register_machine(&pc_machine_v0_12);
     qemu_register_machine(&pc_machine_v0_11);
     qemu_register_machine(&pc_machine_v0_10);
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
new file mode 100644
index 0000000..3dfbe46
--- /dev/null
+++ b/hw/pcnet-pci.c
@@ -0,0 +1,345 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) PCI emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * 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.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
+ */
+
+#include "pci.h"
+#include "net.h"
+#include "loader.h"
+#include "qemu-timer.h"
+
+#include "pcnet.h"
+
+//#define PCNET_DEBUG
+//#define PCNET_DEBUG_IO
+//#define PCNET_DEBUG_BCR
+//#define PCNET_DEBUG_CSR
+//#define PCNET_DEBUG_RMD
+//#define PCNET_DEBUG_TMD
+//#define PCNET_DEBUG_MATCH
+
+
+typedef struct {
+    PCIDevice pci_dev;
+    PCNetState state;
+} PCIPCNetState;
+
+static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCNetState *s = opaque;
+#ifdef PCNET_DEBUG
+    printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+    /* Check APROMWE bit to enable write access */
+    if (pcnet_bcr_readw(s,2) & 0x100)
+        s->prom[addr & 15] = val;
+}
+
+static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
+{
+    PCNetState *s = opaque;
+    uint32_t val = s->prom[addr & 15];
+#ifdef PCNET_DEBUG
+    printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
+                             pcibus_t addr, pcibus_t size, int type)
+{
+    PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
+
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
+           addr, size);
+#endif
+
+    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
+    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
+
+    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
+    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
+    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
+    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
+}
+
+static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
+           val);
+#endif
+    if (!(addr & 0x10))
+        pcnet_aprom_writeb(d, addr & 0x0f, val);
+}
+
+static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val = -1;
+    if (!(addr & 0x10))
+        val = pcnet_aprom_readb(d, addr & 0x0f);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
+           val & 0xff);
+#endif
+    return val;
+}
+
+static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
+           val);
+#endif
+    if (addr & 0x10)
+        pcnet_ioport_writew(d, addr & 0x0f, val);
+    else {
+        addr &= 0x0f;
+        pcnet_aprom_writeb(d, addr, val & 0xff);
+        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+    }
+}
+
+static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val = -1;
+    if (addr & 0x10)
+        val = pcnet_ioport_readw(d, addr & 0x0f);
+    else {
+        addr &= 0x0f;
+        val = pcnet_aprom_readb(d, addr+1);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr);
+    }
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
+           val & 0xffff);
+#endif
+    return val;
+}
+
+static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
+           val);
+#endif
+    if (addr & 0x10)
+        pcnet_ioport_writel(d, addr & 0x0f, val);
+    else {
+        addr &= 0x0f;
+        pcnet_aprom_writeb(d, addr, val & 0xff);
+        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+        pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
+        pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
+    }
+}
+
+static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val;
+    if (addr & 0x10)
+        val = pcnet_ioport_readl(d, addr & 0x0f);
+    else {
+        addr &= 0x0f;
+        val = pcnet_aprom_readb(d, addr+3);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr+2);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr+1);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr);
+    }
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
+           val);
+#endif
+    return val;
+}
+
+static const VMStateDescription vmstate_pci_pcnet = {
+    .name = "pcnet",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
+        VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* PCI interface */
+
+static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
+    &pcnet_mmio_writeb,
+    &pcnet_mmio_writew,
+    &pcnet_mmio_writel
+};
+
+static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
+    &pcnet_mmio_readb,
+    &pcnet_mmio_readw,
+    &pcnet_mmio_readl
+};
+
+static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
+                            pcibus_t addr, pcibus_t size, int type)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
+           addr, size);
+#endif
+
+    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index);
+}
+
+static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
+                                      uint8_t *buf, int len, int do_bswap)
+{
+    cpu_physical_memory_write(addr, buf, len);
+}
+
+static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
+                                     uint8_t *buf, int len, int do_bswap)
+{
+    cpu_physical_memory_read(addr, buf, len);
+}
+
+static void pci_pcnet_cleanup(VLANClientState *nc)
+{
+    PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    pcnet_common_cleanup(d);
+}
+
+static int pci_pcnet_uninit(PCIDevice *dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
+
+    cpu_unregister_io_memory(d->state.mmio_index);
+    qemu_del_timer(d->state.poll_timer);
+    qemu_free_timer(d->state.poll_timer);
+    qemu_del_vlan_client(&d->state.nic->nc);
+    return 0;
+}
+
+static NetClientInfo net_pci_pcnet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = pcnet_can_receive,
+    .receive = pcnet_receive,
+    .cleanup = pci_pcnet_cleanup,
+};
+
+static int pci_pcnet_init(PCIDevice *pci_dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+    PCNetState *s = &d->state;
+    uint8_t *pci_conf;
+
+#if 0
+    printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
+        sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
+#endif
+
+    pci_conf = pci_dev->config;
+
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
+    pci_set_word(pci_conf + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+    pci_conf[PCI_REVISION_ID] = 0x10;
+    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
+
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+    pci_conf[PCI_MIN_GNT] = 0x06;
+    pci_conf[PCI_MAX_LAT] = 0xff;
+
+    /* Handler for memory-mapped I/O */
+    s->mmio_index =
+      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state);
+
+    pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
+                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
+
+    pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
+                           PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
+
+    s->irq = pci_dev->irq[0];
+    s->phys_mem_read = pci_physical_memory_read;
+    s->phys_mem_write = pci_physical_memory_write;
+
+    if (!pci_dev->qdev.hotplugged) {
+        static int loaded = 0;
+        if (!loaded) {
+            rom_add_option("pxe-pcnet.bin");
+            loaded = 1;
+        }
+    }
+
+    return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
+}
+
+static void pci_reset(DeviceState *dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
+
+    pcnet_h_reset(&d->state);
+}
+
+static PCIDeviceInfo pcnet_info = {
+    .qdev.name  = "pcnet",
+    .qdev.size  = sizeof(PCIPCNetState),
+    .qdev.reset = pci_reset,
+    .qdev.vmsd  = &vmstate_pci_pcnet,
+    .init       = pci_pcnet_init,
+    .exit       = pci_pcnet_uninit,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void pci_pcnet_register_devices(void)
+{
+    pci_qdev_register(&pcnet_info);
+}
+
+device_init(pci_pcnet_register_devices)
diff --git a/hw/pcnet.c b/hw/pcnet.c
index b52935a..37010b8 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -35,9 +35,8 @@
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
  */
 
-#include "pci.h"
+#include "qdev.h"
 #include "net.h"
-#include "loader.h"
 #include "qemu-timer.h"
 #include "qemu_socket.h"
 
@@ -52,11 +51,6 @@
 //#define PCNET_DEBUG_MATCH
 
 
-typedef struct {
-    PCIDevice pci_dev;
-    PCNetState state;
-} PCIPCNetState;
-
 struct qemu_ether_header {
     uint8_t ether_dhost[6];
     uint8_t ether_shost[6];
@@ -704,7 +698,6 @@
 static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
 static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
 static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
-static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
 
 static void pcnet_s_reset(PCNetState *s)
 {
@@ -1048,9 +1041,10 @@
     int crc_err = 0;
     int size = size_;
 
-    if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
+    if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size ||
+        (CSR_LOOP(s) && !s->looptest)) {
         return -1;
-
+    }
 #ifdef PCNET_DEBUG
     printf("pcnet_receive size=%d\n", size);
 #endif
@@ -1537,7 +1531,7 @@
     }
 }
 
-static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
 {
     uint32_t val;
     rap &= 127;
@@ -1594,27 +1588,6 @@
     pcnet_poll_timer(s);
 }
 
-static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCNetState *s = opaque;
-#ifdef PCNET_DEBUG
-    printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
-    /* Check APROMWE bit to enable write access */
-    if (pcnet_bcr_readw(s,2) & 0x100)
-        s->prom[addr & 15] = val;
-}
-
-static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
-{
-    PCNetState *s = opaque;
-    uint32_t val = s->prom[addr & 15];
-#ifdef PCNET_DEBUG
-    printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
-    return val;
-}
-
 void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
 {
     PCNetState *s = opaque;
@@ -1667,7 +1640,7 @@
     return val;
 }
 
-static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
 {
     PCNetState *s = opaque;
     pcnet_poll_timer(s);
@@ -1697,7 +1670,7 @@
     pcnet_update_irq(s);
 }
 
-static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
 {
     PCNetState *s = opaque;
     uint32_t val = -1;
@@ -1726,125 +1699,6 @@
     return val;
 }
 
-static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
-                             pcibus_t addr, pcibus_t size, int type)
-{
-    PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
-
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
-           addr, size);
-#endif
-
-    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
-    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
-
-    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
-    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
-    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
-    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
-}
-
-static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
-           val);
-#endif
-    if (!(addr & 0x10))
-        pcnet_aprom_writeb(d, addr & 0x0f, val);
-}
-
-static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
-{
-    PCNetState *d = opaque;
-    uint32_t val = -1;
-    if (!(addr & 0x10))
-        val = pcnet_aprom_readb(d, addr & 0x0f);
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
-           val & 0xff);
-#endif
-    return val;
-}
-
-static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
-           val);
-#endif
-    if (addr & 0x10)
-        pcnet_ioport_writew(d, addr & 0x0f, val);
-    else {
-        addr &= 0x0f;
-        pcnet_aprom_writeb(d, addr, val & 0xff);
-        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
-    }
-}
-
-static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
-    PCNetState *d = opaque;
-    uint32_t val = -1;
-    if (addr & 0x10)
-        val = pcnet_ioport_readw(d, addr & 0x0f);
-    else {
-        addr &= 0x0f;
-        val = pcnet_aprom_readb(d, addr+1);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr);
-    }
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
-           val & 0xffff);
-#endif
-    return val;
-}
-
-static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
-           val);
-#endif
-    if (addr & 0x10)
-        pcnet_ioport_writel(d, addr & 0x0f, val);
-    else {
-        addr &= 0x0f;
-        pcnet_aprom_writeb(d, addr, val & 0xff);
-        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
-        pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
-        pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
-    }
-}
-
-static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
-    PCNetState *d = opaque;
-    uint32_t val;
-    if (addr & 0x10)
-        val = pcnet_ioport_readl(d, addr & 0x0f);
-    else {
-        addr &= 0x0f;
-        val = pcnet_aprom_readb(d, addr+3);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr+2);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr+1);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr);
-    }
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
-           val);
-#endif
-    return val;
-}
-
 static bool is_version_2(void *opaque, int version_id)
 {
     return version_id == 2;
@@ -1874,18 +1728,6 @@
     }
 };
 
-static const VMStateDescription vmstate_pci_pcnet = {
-    .name = "pcnet",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
-        VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
 void pcnet_common_cleanup(PCNetState *d)
 {
     d->nic = NULL;
@@ -1900,147 +1742,3 @@
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
     return 0;
 }
-
-/* PCI interface */
-
-static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
-    &pcnet_mmio_writeb,
-    &pcnet_mmio_writew,
-    &pcnet_mmio_writel
-};
-
-static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
-    &pcnet_mmio_readb,
-    &pcnet_mmio_readw,
-    &pcnet_mmio_readl
-};
-
-static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
-                            pcibus_t addr, pcibus_t size, int type)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
-
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
-           addr, size);
-#endif
-
-    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index);
-}
-
-static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
-                                      uint8_t *buf, int len, int do_bswap)
-{
-    cpu_physical_memory_write(addr, buf, len);
-}
-
-static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
-                                     uint8_t *buf, int len, int do_bswap)
-{
-    cpu_physical_memory_read(addr, buf, len);
-}
-
-static void pci_pcnet_cleanup(VLANClientState *nc)
-{
-    PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
-
-    pcnet_common_cleanup(d);
-}
-
-static int pci_pcnet_uninit(PCIDevice *dev)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
-
-    cpu_unregister_io_memory(d->state.mmio_index);
-    qemu_del_timer(d->state.poll_timer);
-    qemu_free_timer(d->state.poll_timer);
-    qemu_del_vlan_client(&d->state.nic->nc);
-    return 0;
-}
-
-static NetClientInfo net_pci_pcnet_info = {
-    .type = NET_CLIENT_TYPE_NIC,
-    .size = sizeof(NICState),
-    .can_receive = pcnet_can_receive,
-    .receive = pcnet_receive,
-    .cleanup = pci_pcnet_cleanup,
-};
-
-static int pci_pcnet_init(PCIDevice *pci_dev)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
-    PCNetState *s = &d->state;
-    uint8_t *pci_conf;
-
-#if 0
-    printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
-        sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
-#endif
-
-    pci_conf = pci_dev->config;
-
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
-    pci_set_word(pci_conf + PCI_STATUS,
-                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_conf[PCI_REVISION_ID] = 0x10;
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
-
-    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
-    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
-
-    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
-    pci_conf[PCI_MIN_GNT] = 0x06;
-    pci_conf[PCI_MAX_LAT] = 0xff;
-
-    /* Handler for memory-mapped I/O */
-    s->mmio_index =
-      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state);
-
-    pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
-
-    pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
-
-    s->irq = pci_dev->irq[0];
-    s->phys_mem_read = pci_physical_memory_read;
-    s->phys_mem_write = pci_physical_memory_write;
-
-    if (!pci_dev->qdev.hotplugged) {
-        static int loaded = 0;
-        if (!loaded) {
-            rom_add_option("pxe-pcnet.bin");
-            loaded = 1;
-        }
-    }
-
-    return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
-}
-
-static void pci_reset(DeviceState *dev)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
-
-    pcnet_h_reset(&d->state);
-}
-
-static PCIDeviceInfo pcnet_info = {
-    .qdev.name  = "pcnet",
-    .qdev.size  = sizeof(PCIPCNetState),
-    .qdev.reset = pci_reset,
-    .qdev.vmsd  = &vmstate_pci_pcnet,
-    .init       = pci_pcnet_init,
-    .exit       = pci_pcnet_uninit,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
-};
-
-static void pcnet_register_devices(void)
-{
-    pci_qdev_register(&pcnet_info);
-}
-
-device_init(pcnet_register_devices)
diff --git a/hw/pcnet.h b/hw/pcnet.h
index efacc9f..534bdf9 100644
--- a/hw/pcnet.h
+++ b/hw/pcnet.h
@@ -32,6 +32,9 @@
 void pcnet_h_reset(void *opaque);
 void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
 uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
 int pcnet_can_receive(VLANClientState *nc);
 ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_);
 void pcnet_common_cleanup(PCNetState *d);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 4369337..305b2d4 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -316,7 +316,7 @@
         machine_arch = ARCH_MAC99;
     }
     /* init basic PC hardware */
-    pci_vga_init(pci_bus, 0, 0);
+    pci_vga_init(pci_bus);
 
     escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24],
                                serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index a2f9ddf..5efc93d 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -227,7 +227,7 @@
     }
     pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
     pci_bus = pci_grackle_init(0xfec00000, pic);
-    pci_vga_init(pci_bus, 0, 0);
+    pci_vga_init(pci_bus);
 
     escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
                                serial_hds[1], ESCC_CLOCK, 4);
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index a6915f7..b1f9cc7 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -694,7 +694,7 @@
     cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
 
     /* init basic PC hardware */
-    pci_vga_init(pci_bus, 0, 0);
+    pci_vga_init(pci_bus);
     //    openpic = openpic_init(0x00000000, 0xF0000000, 1);
     //    pit = pit_init(0x40, i8259[0]);
     rtc_init(2000, NULL);
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 5a3fd4b..93f0e9a 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -108,7 +108,7 @@
     int res = 0, unit;
 
     loc_push_none(&loc);
-    for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
+    for (unit = 0; unit < bus->ndev; unit++) {
         dinfo = drive_get(IF_SCSI, bus->busnr, unit);
         if (dinfo == NULL) {
             continue;
@@ -123,16 +123,6 @@
     return res;
 }
 
-void scsi_dev_clear_sense(SCSIDevice *dev)
-{
-    memset(&dev->sense, 0, sizeof(dev->sense));
-}
-
-void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key)
-{
-    dev->sense.key = key;
-}
-
 SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun)
 {
     SCSIRequest *req;
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index a4a3518..1473ecb 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -111,18 +111,20 @@
 #define BLANK 0xa1
 
 /*
- *  Status codes
+ *  SAM Status codes
  */
 
 #define GOOD                 0x00
-#define CHECK_CONDITION      0x01
-#define CONDITION_GOOD       0x02
-#define BUSY                 0x04
-#define INTERMEDIATE_GOOD    0x08
-#define INTERMEDIATE_C_GOOD  0x0a
-#define RESERVATION_CONFLICT 0x0c
-#define COMMAND_TERMINATED   0x11
-#define QUEUE_FULL           0x14
+#define CHECK_CONDITION      0x02
+#define CONDITION_GOOD       0x04
+#define BUSY                 0x08
+#define INTERMEDIATE_GOOD    0x10
+#define INTERMEDIATE_C_GOOD  0x14
+#define RESERVATION_CONFLICT 0x18
+#define COMMAND_TERMINATED   0x22
+#define TASK_SET_FULL        0x28
+#define ACA_ACTIVE           0x30
+#define TASK_ABORTED         0x40
 
 #define STATUS_MASK          0x3e
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 9628b39..6e49404 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -41,10 +41,18 @@
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
 
-#define SCSI_REQ_STATUS_RETRY 0x01
+#define SCSI_REQ_STATUS_RETRY           0x01
+#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
+#define SCSI_REQ_STATUS_RETRY_READ      0x00
+#define SCSI_REQ_STATUS_RETRY_WRITE     0x02
+#define SCSI_REQ_STATUS_RETRY_FLUSH     0x04
 
 typedef struct SCSIDiskState SCSIDiskState;
 
+typedef struct SCSISense {
+    uint8_t key;
+} SCSISense;
+
 typedef struct SCSIDiskReq {
     SCSIRequest req;
     /* ??? We should probably keep track of whether the data transfer is
@@ -68,8 +76,12 @@
     QEMUBH *bh;
     char *version;
     char *serial;
+    SCSISense sense;
 };
 
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
+static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
+
 static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
         uint32_t lun)
 {
@@ -93,10 +105,22 @@
     return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag));
 }
 
-static void scsi_req_set_status(SCSIRequest *req, int status, int sense_code)
+static void scsi_disk_clear_sense(SCSIDiskState *s)
 {
-    req->status = status;
-    scsi_dev_set_sense(req->dev, sense_code);
+    memset(&s->sense, 0, sizeof(s->sense));
+}
+
+static void scsi_disk_set_sense(SCSIDiskState *s, uint8_t key)
+{
+    s->sense.key = key;
+}
+
+static void scsi_req_set_status(SCSIDiskReq *r, int status, int sense_code)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    r->req.status = status;
+    scsi_disk_set_sense(s, sense_code);
 }
 
 /* Helper function for command completion.  */
@@ -104,7 +128,7 @@
 {
     DPRINTF("Command complete tag=0x%x status=%d sense=%d\n",
             r->req.tag, status, sense);
-    scsi_req_set_status(&r->req, status, sense);
+    scsi_req_set_status(r, status, sense);
     scsi_req_complete(&r->req);
     scsi_remove_request(r);
 }
@@ -127,34 +151,30 @@
 static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    int n;
 
     r->req.aiocb = NULL;
 
     if (ret) {
-        DPRINTF("IO error\n");
-        r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
-        scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
-        return;
+        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
+            return;
+        }
     }
+
     DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
 
+    n = r->iov.iov_len / 512;
+    r->sector += n;
+    r->sector_count -= n;
     r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
 }
 
-/* Read more data from scsi device into buffer.  */
-static void scsi_read_data(SCSIDevice *d, uint32_t tag)
+
+static void scsi_read_request(SCSIDiskReq *r)
 {
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-    SCSIDiskReq *r;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     uint32_t n;
 
-    r = scsi_find_request(s, tag);
-    if (!r) {
-        BADF("Bad read tag 0x%x\n", tag);
-        /* ??? This is the wrong error.  */
-        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
-        return;
-    }
     if (r->sector_count == (uint32_t)-1) {
         DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
         r->sector_count = 0;
@@ -167,6 +187,9 @@
         return;
     }
 
+    /* No data transfer may already be in progress */
+    assert(r->req.aiocb == NULL);
+
     n = r->sector_count;
     if (n > SCSI_DMA_BUF_SIZE / 512)
         n = SCSI_DMA_BUF_SIZE / 512;
@@ -175,31 +198,54 @@
     qemu_iovec_init_external(&r->qiov, &r->iov, 1);
     r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
                               scsi_read_complete, r);
-    if (r->req.aiocb == NULL)
-        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
-    r->sector += n;
-    r->sector_count -= n;
+    if (r->req.aiocb == NULL) {
+        scsi_read_complete(r, -EIO);
+    }
 }
 
-static int scsi_handle_write_error(SCSIDiskReq *r, int error)
+/* Read more data from scsi device into buffer.  */
+static void scsi_read_data(SCSIDevice *d, uint32_t tag)
 {
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+    SCSIDiskReq *r;
+
+    r = scsi_find_request(s, tag);
+    if (!r) {
+        BADF("Bad read tag 0x%x\n", tag);
+        /* ??? This is the wrong error.  */
+        scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
+        return;
+    }
+
+    scsi_read_request(r);
+}
+
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
+{
+    int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    BlockErrorAction action = bdrv_get_on_error(s->bs, 0);
+    BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
 
     if (action == BLOCK_ERR_IGNORE) {
-        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0);
+        bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
         return 0;
     }
 
     if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
             || action == BLOCK_ERR_STOP_ANY) {
-        r->status |= SCSI_REQ_STATUS_RETRY;
-        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0);
+
+        type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
+        r->status |= SCSI_REQ_STATUS_RETRY | type;
+
+        bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
         vm_stop(0);
     } else {
+        if (type == SCSI_REQ_STATUS_RETRY_READ) {
+            r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
+        }
         scsi_command_complete(r, CHECK_CONDITION,
                 HARDWARE_ERROR);
-        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0);
+        bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
     }
 
     return 1;
@@ -214,8 +260,9 @@
     r->req.aiocb = NULL;
 
     if (ret) {
-        if (scsi_handle_write_error(r, -ret))
+        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
             return;
+        }
     }
 
     n = r->iov.iov_len / 512;
@@ -239,14 +286,17 @@
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     uint32_t n;
 
+    /* No data transfer may already be in progress */
+    assert(r->req.aiocb == NULL);
+
     n = r->iov.iov_len / 512;
     if (n) {
         qemu_iovec_init_external(&r->qiov, &r->iov, 1);
         r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
                                    scsi_write_complete, r);
-        if (r->req.aiocb == NULL)
-            scsi_command_complete(r, CHECK_CONDITION,
-                                  HARDWARE_ERROR);
+        if (r->req.aiocb == NULL) {
+            scsi_write_complete(r, -EIO);
+        }
     } else {
         /* Invoke completion routine to fetch data from host.  */
         scsi_write_complete(r, 0);
@@ -268,9 +318,6 @@
         return 1;
     }
 
-    if (r->req.aiocb)
-        BADF("Data transfer already in progress\n");
-
     scsi_write_request(r);
 
     return 0;
@@ -288,8 +335,25 @@
     QTAILQ_FOREACH(req, &s->qdev.requests, next) {
         r = DO_UPCAST(SCSIDiskReq, req, req);
         if (r->status & SCSI_REQ_STATUS_RETRY) {
-            r->status &= ~SCSI_REQ_STATUS_RETRY;
-            scsi_write_request(r); 
+            int status = r->status;
+            int ret;
+
+            r->status &=
+                ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
+
+            switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
+            case SCSI_REQ_STATUS_RETRY_READ:
+                scsi_read_request(r);
+                break;
+            case SCSI_REQ_STATUS_RETRY_WRITE:
+                scsi_write_request(r);
+                break;
+            case SCSI_REQ_STATUS_RETRY_FLUSH:
+                ret = scsi_disk_emulate_command(r, r->iov.iov_base);
+                if (ret == 0) {
+                    scsi_command_complete(r, GOOD, NO_SENSE);
+                }
+            }
         }
     }
 }
@@ -351,15 +415,20 @@
 
         switch (page_code) {
         case 0x00: /* Supported page codes, mandatory */
+        {
+            int pages;
             DPRINTF("Inquiry EVPD[Supported pages] "
                     "buffer size %zd\n", req->cmd.xfer);
-            outbuf[buflen++] = 4;    // number of pages
+            pages = buflen++;
             outbuf[buflen++] = 0x00; // list of supported pages (this page)
             outbuf[buflen++] = 0x80; // unit serial number
             outbuf[buflen++] = 0x83; // device identification
-            outbuf[buflen++] = 0xb0; // block device characteristics
+            if (bdrv_get_type_hint(s->bs) != BDRV_TYPE_CDROM) {
+                outbuf[buflen++] = 0xb0; // block device characteristics
+            }
+            outbuf[pages] = buflen - pages - 1; // number of pages
             break;
-
+        }
         case 0x80: /* Device serial number, optional */
         {
             int l = strlen(s->serial);
@@ -387,7 +456,7 @@
             DPRINTF("Inquiry EVPD[Device identification] "
                     "buffer size %zd\n", req->cmd.xfer);
 
-            outbuf[buflen++] = 3 + id_len;
+            outbuf[buflen++] = 4 + id_len;
             outbuf[buflen++] = 0x2; // ASCII
             outbuf[buflen++] = 0;   // not officially assigned
             outbuf[buflen++] = 0;   // reserved
@@ -404,6 +473,11 @@
             unsigned int opt_io_size =
                     s->qdev.conf.opt_io_size / s->qdev.blocksize;
 
+            if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
+                DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
+                        page_code);
+                return -1;
+            }
             /* required VPD size with unmap support */
             outbuf[3] = buflen = 0x3c;
 
@@ -747,11 +821,13 @@
     return toclen;
 }
 
-static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
+static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
 {
+    SCSIRequest *req = &r->req;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     uint64_t nb_sectors;
     int buflen = 0;
+    int ret;
 
     switch (req->cmd.buf[0]) {
     case TEST_UNIT_READY:
@@ -763,7 +839,7 @@
             goto illegal_request;
         memset(outbuf, 0, 4);
         buflen = 4;
-        if (req->dev->sense.key == NOT_READY && req->cmd.xfer >= 18) {
+        if (s->sense.key == NOT_READY && req->cmd.xfer >= 18) {
             memset(outbuf, 0, 18);
             buflen = 18;
             outbuf[7] = 10;
@@ -773,8 +849,8 @@
         }
         outbuf[0] = 0xf0;
         outbuf[1] = 0;
-        outbuf[2] = req->dev->sense.key;
-        scsi_dev_clear_sense(req->dev);
+        outbuf[2] = s->sense.key;
+        scsi_disk_clear_sense(s);
         break;
     case INQUIRY:
         buflen = scsi_disk_emulate_inquiry(req, outbuf);
@@ -842,7 +918,12 @@
         buflen = 8;
 	break;
     case SYNCHRONIZE_CACHE:
-        bdrv_flush(s->bs);
+        ret = bdrv_flush(s->bs);
+        if (ret < 0) {
+            if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
+                return -1;
+            }
+        }
         break;
     case GET_CONFIGURATION:
         memset(outbuf, 0, 8);
@@ -902,16 +983,16 @@
     default:
         goto illegal_request;
     }
-    scsi_req_set_status(req, GOOD, NO_SENSE);
+    scsi_req_set_status(r, GOOD, NO_SENSE);
     return buflen;
 
 not_ready:
-    scsi_req_set_status(req, CHECK_CONDITION, NOT_READY);
-    return 0;
+    scsi_command_complete(r, CHECK_CONDITION, NOT_READY);
+    return -1;
 
 illegal_request:
-    scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST);
-    return 0;
+    scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
+    return -1;
 }
 
 /* Execute a scsi command.  Returns the length of the data expected by the
@@ -923,9 +1004,7 @@
                                  uint8_t *buf, int lun)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-    uint64_t lba;
     uint32_t len;
-    int cmdlen;
     int is_write;
     uint8_t command;
     uint8_t *outbuf;
@@ -944,55 +1023,21 @@
     outbuf = (uint8_t *)r->iov.iov_base;
     is_write = 0;
     DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
-    switch (command >> 5) {
-    case 0:
-        lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
-              (((uint64_t) buf[1] & 0x1f) << 16);
-        len = buf[4];
-        cmdlen = 6;
-        break;
-    case 1:
-    case 2:
-        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
-              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
-        len = buf[8] | (buf[7] << 8);
-        cmdlen = 10;
-        break;
-    case 4:
-        lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
-              ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
-              ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
-              ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
-        len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
-        cmdlen = 16;
-        break;
-    case 5:
-        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
-              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
-        len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
-        cmdlen = 12;
-        break;
-    default:
+
+    if (scsi_req_parse(&r->req, buf) != 0) {
         BADF("Unsupported command length, command %x\n", command);
         goto fail;
     }
 #ifdef DEBUG_SCSI
     {
         int i;
-        for (i = 1; i < cmdlen; i++) {
+        for (i = 1; i < r->req.cmd.len; i++) {
             printf(" 0x%02x", buf[i]);
         }
         printf("\n");
     }
 #endif
 
-    if (scsi_req_parse(&r->req, buf) != 0) {
-        BADF("Unsupported command length, command %x\n", command);
-        goto fail;
-    }
-    assert(r->req.cmd.len == cmdlen);
-    assert(r->req.cmd.lba == lba);
-
     if (lun || buf[1] >> 5) {
         /* Only LUN 0 supported.  */
         DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
@@ -1019,23 +1064,22 @@
     case REPORT_LUNS:
     case VERIFY:
     case REZERO_UNIT:
-        rc = scsi_disk_emulate_command(&r->req, outbuf);
-        if (rc > 0) {
-            r->iov.iov_len = rc;
-        } else {
-            scsi_req_complete(&r->req);
-            scsi_remove_request(r);
+        rc = scsi_disk_emulate_command(r, outbuf);
+        if (rc < 0) {
             return 0;
         }
+
+        r->iov.iov_len = rc;
         break;
     case READ_6:
     case READ_10:
     case READ_12:
     case READ_16:
-        DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len);
-        if (lba > s->max_lba)
+        len = r->req.cmd.xfer / d->blocksize;
+        DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
+        if (r->req.cmd.lba > s->max_lba)
             goto illegal_lba;
-        r->sector = lba * s->cluster_size;
+        r->sector = r->req.cmd.lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         break;
     case WRITE_6:
@@ -1045,42 +1089,45 @@
     case WRITE_VERIFY:
     case WRITE_VERIFY_12:
     case WRITE_VERIFY_16:
+        len = r->req.cmd.xfer / d->blocksize;
         DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
-                (command & 0xe) == 0xe ? "And Verify " : "", lba, len);
-        if (lba > s->max_lba)
+                (command & 0xe) == 0xe ? "And Verify " : "",
+                r->req.cmd.lba, len);
+        if (r->req.cmd.lba > s->max_lba)
             goto illegal_lba;
-        r->sector = lba * s->cluster_size;
+        r->sector = r->req.cmd.lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         is_write = 1;
         break;
     case MODE_SELECT:
-        DPRINTF("Mode Select(6) (len %d)\n", len);
+        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
         /* We don't support mode parameter changes.
            Allow the mode parameter header + block descriptors only. */
-        if (len > 12) {
+        if (r->req.cmd.xfer > 12) {
             goto fail;
         }
         break;
     case MODE_SELECT_10:
-        DPRINTF("Mode Select(10) (len %d)\n", len);
+        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
         /* We don't support mode parameter changes.
            Allow the mode parameter header + block descriptors only. */
-        if (len > 16) {
+        if (r->req.cmd.xfer > 16) {
             goto fail;
         }
         break;
     case SEEK_6:
     case SEEK_10:
-        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, lba);
-        if (lba > s->max_lba) {
+        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
+                r->req.cmd.lba);
+        if (r->req.cmd.lba > s->max_lba) {
             goto illegal_lba;
         }
         break;
     default:
-	DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
+        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
     fail:
         scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
-	return 0;
+        return 0;
     illegal_lba:
         scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
         return 0;
@@ -1152,11 +1199,6 @@
         return -1;
     }
 
-    if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
-        error_report("Device doesn't support drive option rerror");
-        return -1;
-    }
-
     if (!s->serial) {
         /* try to fall back to value set with legacy -drive serial=... */
         dinfo = drive_get_by_blockdev(s->bs);
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 7212091..9be1cca 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -96,17 +96,17 @@
         s->senselen = r->io_header.sb_len_wr;
 
     if (ret != 0)
-        r->req.status = BUSY << 1;
+        r->req.status = BUSY;
     else {
         if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
-            r->req.status = BUSY << 1;
+            r->req.status = BUSY;
             BADF("Driver Timeout\n");
         } else if (r->io_header.status)
             r->req.status = r->io_header.status;
         else if (s->driver_status & SG_ERR_DRIVER_SENSE)
-            r->req.status = CHECK_CONDITION << 1;
+            r->req.status = CHECK_CONDITION;
         else
-            r->req.status = GOOD << 1;
+            r->req.status = GOOD;
     }
     DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
             r, r->req.tag, r->req.status);
@@ -333,7 +333,7 @@
         s->senselen = 7;
         s->driver_status = SG_ERR_DRIVER_SENSE;
         bus = scsi_bus_from_device(d);
-        bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1);
+        bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION);
         return 0;
     }
 
diff --git a/hw/scsi.h b/hw/scsi.h
index cb06d6d..bf02adf 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,6 +3,7 @@
 
 #include "qdev.h"
 #include "block.h"
+#include "blockdev.h"
 #include "block_int.h"
 
 #define SCSI_CMD_BUF_SIZE     16
@@ -25,10 +26,6 @@
     SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
 };
 
-typedef struct SCSISense {
-    uint8_t key;
-} SCSISense;
-
 typedef struct SCSIRequest {
     SCSIBus           *bus;
     SCSIDevice        *dev;
@@ -56,7 +53,6 @@
     QTAILQ_HEAD(, SCSIRequest) requests;
     int blocksize;
     int type;
-    struct SCSISense sense;
 };
 
 /* cdrom.c */
@@ -86,7 +82,7 @@
     int tcq, ndev;
     scsi_completionfn complete;
 
-    SCSIDevice *devs[8];
+    SCSIDevice *devs[MAX_SCSI_DEVS];
 };
 
 void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
@@ -101,9 +97,6 @@
 SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit);
 int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
 
-void scsi_dev_clear_sense(SCSIDevice *dev);
-void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key);
-
 SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
 SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag);
 void scsi_req_free(SCSIRequest *req);
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 45a46d6..5292ac6 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -767,7 +767,7 @@
     pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
                            &pci_bus3);
     isa_mem_base = APB_PCI_IO_BASE;
-    pci_vga_init(pci_bus, 0, 0);
+    pci_vga_init(pci_bus);
 
     // XXX Should be pci_bus3
     pci_ebus_init(pci_bus, -1);
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 70f9263..58c672f 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1142,7 +1142,7 @@
                 break;
 
             default:
-                if (usb_net_stringtable[value & 0xff]) {
+                if (ARRAY_SIZE(usb_net_stringtable) > (value & 0xff)) {
                     ret = set_usb_string(data,
                                     usb_net_stringtable[value & 0xff]);
                     break;
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 2315f70..791ca22 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -52,14 +52,11 @@
 {
     PCIVGAState *d = (PCIVGAState *)pci_dev;
     VGACommonState *s = &d->vga;
-    if (region_num == PCI_ROM_SLOT) {
-        cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
-    } else {
-        cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
-        s->map_addr = addr;
-        s->map_end = addr + s->vram_size;
-        vga_dirty_log_start(s);
-    }
+
+    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
+    s->map_addr = addr;
+    s->map_end = addr + s->vram_size;
+    vga_dirty_log_start(s);
 }
 
 static void pci_vga_write_config(PCIDevice *d,
@@ -95,32 +92,17 @@
      pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
                       PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
 
-     if (s->bios_size) {
-        unsigned int bios_total_size;
-        /* must be a power of two */
-        bios_total_size = 1;
-        while (bios_total_size < s->bios_size)
-            bios_total_size <<= 1;
-        pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
-                         PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
+     if (!dev->rom_bar) {
+         /* compatibility with pc-0.13 and older */
+         vga_init_vbe(s);
      }
 
-    vga_init_vbe(s);
-     /* ROM BIOS */
-     rom_add_vga(VGABIOS_FILENAME);
      return 0;
 }
 
-int pci_vga_init(PCIBus *bus,
-                 unsigned long vga_bios_offset, int vga_bios_size)
+int pci_vga_init(PCIBus *bus)
 {
-    PCIDevice *dev;
-
-    dev = pci_create(bus, -1, "VGA");
-    qdev_prop_set_uint32(&dev->qdev, "bios-offset", vga_bios_offset);
-    qdev_prop_set_uint32(&dev->qdev, "bios-size", vga_bios_size);
-    qdev_init_nofail(&dev->qdev);
-
+    pci_create_simple(bus, -1, "VGA");
     return 0;
 }
 
@@ -130,11 +112,7 @@
     .qdev.vmsd    = &vmstate_vga_pci,
     .init         = pci_vga_initfn,
     .config_write = pci_vga_write_config,
-    .qdev.props   = (Property[]) {
-        DEFINE_PROP_HEX32("bios-offset", PCIVGAState, vga.bios_offset, 0),
-        DEFINE_PROP_HEX32("bios-size",   PCIVGAState, vga.bios_size,   0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+    .romfile      = "vgabios-stdvga.bin",
 };
 
 static void vga_register(void)
diff --git a/hw/vga.c b/hw/vga.c
index 966185e..c057f4f 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1934,8 +1934,6 @@
     s->map_addr = 0;
     s->map_end = 0;
     s->lfb_vram_mapped = 0;
-    s->bios_offset = 0;
-    s->bios_size = 0;
     s->sr_index = 0;
     memset(s->sr, '\0', sizeof(s->sr));
     s->gr_index = 0;
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 6a46a43..bc1327f 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -112,8 +112,6 @@
     uint32_t map_addr;
     uint32_t map_end;
     uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */
-    uint32_t bios_offset;
-    uint32_t bios_size;
     uint32_t latch;
     uint8_t sr_index;
     uint8_t sr[256];
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index dbe20707..e5f9b27 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -273,7 +273,7 @@
 
     acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
     if (!acb) {
-        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+        virtio_blk_flush_complete(req, -EIO);
     }
 }
 
@@ -324,13 +324,13 @@
     MultiReqBuffer *mrb)
 {
     if (req->elem.out_num < 1 || req->elem.in_num < 1) {
-        fprintf(stderr, "virtio-blk missing headers\n");
+        error_report("virtio-blk missing headers");
         exit(1);
     }
 
     if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
         req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
-        fprintf(stderr, "virtio-blk header not in correct element\n");
+        error_report("virtio-blk header not in correct element");
         exit(1);
     }
 
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 7e1688c..1d61f19 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -120,8 +120,8 @@
     if (!n->vhost_started) {
         int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
         if (r < 0) {
-            fprintf(stderr, "unable to start vhost net: %d: "
-                    "falling back on userspace virtio\n", -r);
+            error_report("unable to start vhost net: %d: "
+                         "falling back on userspace virtio", -r);
         } else {
             n->vhost_started = 1;
         }
@@ -271,7 +271,7 @@
     uint8_t on;
 
     if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(on)) {
-        fprintf(stderr, "virtio-net ctrl invalid rx mode command\n");
+        error_report("virtio-net ctrl invalid rx mode command");
         exit(1);
     }
 
@@ -353,7 +353,7 @@
     uint16_t vid;
 
     if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(vid)) {
-        fprintf(stderr, "virtio-net ctrl invalid vlan command\n");
+        error_report("virtio-net ctrl invalid vlan command");
         return VIRTIO_NET_ERR;
     }
 
@@ -381,13 +381,13 @@
 
     while (virtqueue_pop(vq, &elem)) {
         if ((elem.in_num < 1) || (elem.out_num < 1)) {
-            fprintf(stderr, "virtio-net ctrl missing headers\n");
+            error_report("virtio-net ctrl missing headers");
             exit(1);
         }
 
         if (elem.out_sg[0].iov_len < sizeof(ctrl) ||
             elem.in_sg[elem.in_num - 1].iov_len < sizeof(status)) {
-            fprintf(stderr, "virtio-net ctrl header not in correct element\n");
+            error_report("virtio-net ctrl header not in correct element");
             exit(1);
         }
 
@@ -591,21 +591,21 @@
         if (virtqueue_pop(n->rx_vq, &elem) == 0) {
             if (i == 0)
                 return -1;
-            fprintf(stderr, "virtio-net unexpected empty queue: "
+            error_report("virtio-net unexpected empty queue: "
                     "i %zd mergeable %d offset %zd, size %zd, "
-                    "guest hdr len %zd, host hdr len %zd guest features 0x%x\n",
+                    "guest hdr len %zd, host hdr len %zd guest features 0x%x",
                     i, n->mergeable_rx_bufs, offset, size,
                     guest_hdr_len, host_hdr_len, n->vdev.guest_features);
             exit(1);
         }
 
         if (elem.in_num < 1) {
-            fprintf(stderr, "virtio-net receive queue contains no in buffers\n");
+            error_report("virtio-net receive queue contains no in buffers");
             exit(1);
         }
 
         if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) {
-            fprintf(stderr, "virtio-net header not in first element\n");
+            error_report("virtio-net header not in first element");
             exit(1);
         }
 
@@ -630,12 +630,11 @@
          * Otherwise, drop it. */
         if (!n->mergeable_rx_bufs && offset < size) {
 #if 0
-            fprintf(stderr, "virtio-net truncated non-mergeable packet: "
-
-                    "i %zd mergeable %d offset %zd, size %zd, "
-                    "guest hdr len %zd, host hdr len %zd\n",
-                    i, n->mergeable_rx_bufs,
-                    offset, size, guest_hdr_len, host_hdr_len);
+            error_report("virtio-net truncated non-mergeable packet: "
+                         "i %zd mergeable %d offset %zd, size %zd, "
+                         "guest hdr len %zd, host hdr len %zd",
+                         i, n->mergeable_rx_bufs,
+                         offset, size, guest_hdr_len, host_hdr_len);
 #endif
             return size;
         }
@@ -695,7 +694,7 @@
             sizeof(struct virtio_net_hdr);
 
         if (out_num < 1 || out_sg->iov_len != hdr_len) {
-            fprintf(stderr, "virtio-net header not in first element\n");
+            error_report("virtio-net header not in first element");
             exit(1);
         }
 
@@ -981,10 +980,10 @@
     n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
 
     if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) {
-        fprintf(stderr, "virtio-net: "
-                "Unknown option tx=%s, valid options: \"timer\" \"bh\"\n",
-                net->tx);
-        fprintf(stderr, "Defaulting to \"bh\"\n");
+        error_report("virtio-net: "
+                     "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
+                     net->tx);
+        error_report("Defaulting to \"bh\"");
     }
 
     if (net->tx && !strcmp(net->tx, "timer")) {
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 729917d..c65765a 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -254,8 +254,8 @@
         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
         break;
     default:
-        fprintf(stderr, "%s: unexpected address 0x%x value 0x%x\n",
-                __func__, addr, val);
+        error_report("%s: unexpected address 0x%x value 0x%x",
+                     __func__, addr, val);
         break;
     }
 }
@@ -684,12 +684,14 @@
     VirtIODevice *vdev;
 
     vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
+    vdev->nvectors = proxy->nvectors;
     virtio_init_pci(proxy, vdev,
                     PCI_VENDOR_ID_REDHAT_QUMRANET,
                     0x1009,
                     0x2,
                     0x00);
-
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
     return 0;
 }
 #endif
@@ -758,6 +760,7 @@
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_9p_init_pci,
         .qdev.props = (Property[]) {
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
             DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
             DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
             DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 3d25c14..d0f4e1b 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -114,14 +114,12 @@
 # define SVGA_IO_BASE		SVGA_LEGACY_BASE_PORT
 # define SVGA_IO_MUL		1
 # define SVGA_FIFO_SIZE		0x10000
-# define SVGA_MEM_BASE		0xe0000000
 # define SVGA_PCI_DEVICE_ID	PCI_DEVICE_ID_VMWARE_SVGA2
 #else
 # define SVGA_ID		SVGA_ID_1
 # define SVGA_IO_BASE		SVGA_LEGACY_BASE_PORT
 # define SVGA_IO_MUL		4
 # define SVGA_FIFO_SIZE		0x10000
-# define SVGA_MEM_BASE		0xe0000000
 # define SVGA_PCI_DEVICE_ID	PCI_DEVICE_ID_VMWARE_SVGA
 #endif
 
@@ -1219,10 +1217,6 @@
     vga_init(&s->vga);
     vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
 
-    vga_init_vbe(&s->vga);
-
-    rom_add_vga(VGABIOS_FILENAME);
-
     vmsvga_reset(s);
 }
 
@@ -1307,6 +1301,11 @@
 
     vmsvga_init(&s->chip, VGA_RAM_SIZE);
 
+    if (!dev->rom_bar) {
+        /* compatibility with pc-0.13 and older */
+        vga_init_vbe(&s->chip.vga);
+    }
+
     return 0;
 }
 
@@ -1320,6 +1319,7 @@
     .qdev.size    = sizeof(struct pci_vmsvga_state_s),
     .qdev.vmsd    = &vmstate_vmware_vga,
     .init         = pci_vmsvga_initfn,
+    .romfile      = "vgabios-vmware.bin",
 };
 
 static void vmsvga_register(void)
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 134ac33..85a1c85 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -181,6 +181,10 @@
 	ioreq->prot = PROT_WRITE; /* to memory */
 	break;
     case BLKIF_OP_WRITE_BARRIER:
+        if (!ioreq->req.nr_segments) {
+            ioreq->presync = 1;
+            return 0;
+        }
 	if (!syncwrite)
 	    ioreq->presync = ioreq->postsync = 1;
 	/* fall through */
@@ -305,7 +309,7 @@
     int i, rc, len = 0;
     off_t pos;
 
-    if (ioreq_map(ioreq) == -1)
+    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
 	goto err;
     if (ioreq->presync)
 	bdrv_flush(blkdev->bs);
@@ -329,6 +333,8 @@
 	break;
     case BLKIF_OP_WRITE:
     case BLKIF_OP_WRITE_BARRIER:
+        if (!ioreq->req.nr_segments)
+            break;
 	pos = ioreq->start;
 	for (i = 0; i < ioreq->v.niov; i++) {
 	    rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE,
@@ -386,7 +392,7 @@
 {
     struct XenBlkDev *blkdev = ioreq->blkdev;
 
-    if (ioreq_map(ioreq) == -1)
+    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
 	goto err;
 
     ioreq->aio_inflight++;
@@ -403,6 +409,8 @@
     case BLKIF_OP_WRITE:
     case BLKIF_OP_WRITE_BARRIER:
         ioreq->aio_inflight++;
+        if (!ioreq->req.nr_segments)
+            break;
         bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
                         &ioreq->v, ioreq->v.size / BLOCK_SIZE,
                         qemu_aio_complete, ioreq);
diff --git a/ioport.c b/ioport.c
index ec3dc65..aa4188a 100644
--- a/ioport.c
+++ b/ioport.c
@@ -174,6 +174,70 @@
     return 0;
 }
 
+static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
+{
+    IORange *ioport = opaque;
+    uint64_t data;
+
+    ioport->ops->read(ioport, addr - ioport->base, 1, &data);
+    return data;
+}
+
+static uint32_t ioport_readw_thunk(void *opaque, uint32_t addr)
+{
+    IORange *ioport = opaque;
+    uint64_t data;
+
+    ioport->ops->read(ioport, addr - ioport->base, 2, &data);
+    return data;
+}
+
+static uint32_t ioport_readl_thunk(void *opaque, uint32_t addr)
+{
+    IORange *ioport = opaque;
+    uint64_t data;
+
+    ioport->ops->read(ioport, addr - ioport->base, 4, &data);
+    return data;
+}
+
+static void ioport_writeb_thunk(void *opaque, uint32_t addr, uint32_t data)
+{
+    IORange *ioport = opaque;
+
+    ioport->ops->write(ioport, addr - ioport->base, 1, data);
+}
+
+static void ioport_writew_thunk(void *opaque, uint32_t addr, uint32_t data)
+{
+    IORange *ioport = opaque;
+
+    ioport->ops->write(ioport, addr - ioport->base, 2, data);
+}
+
+static void ioport_writel_thunk(void *opaque, uint32_t addr, uint32_t data)
+{
+    IORange *ioport = opaque;
+
+    ioport->ops->write(ioport, addr - ioport->base, 4, data);
+}
+
+void ioport_register(IORange *ioport)
+{
+    register_ioport_read(ioport->base, ioport->len, 1,
+                         ioport_readb_thunk, ioport);
+    register_ioport_read(ioport->base, ioport->len, 2,
+                         ioport_readw_thunk, ioport);
+    register_ioport_read(ioport->base, ioport->len, 4,
+                         ioport_readl_thunk, ioport);
+    register_ioport_write(ioport->base, ioport->len, 1,
+                          ioport_writeb_thunk, ioport);
+    register_ioport_write(ioport->base, ioport->len, 2,
+                          ioport_writew_thunk, ioport);
+    register_ioport_write(ioport->base, ioport->len, 4,
+                          ioport_writel_thunk, ioport);
+}
+
 void isa_unassign_ioport(pio_addr_t start, int length)
 {
     int i;
diff --git a/ioport.h b/ioport.h
index 3d3c8a3..5ae62a3 100644
--- a/ioport.h
+++ b/ioport.h
@@ -25,6 +25,7 @@
 #define IOPORT_H
 
 #include "qemu-common.h"
+#include "iorange.h"
 
 typedef uint32_t pio_addr_t;
 #define FMT_pioaddr     PRIx32
@@ -36,6 +37,7 @@
 typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
 typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
 
+void ioport_register(IORange *iorange);
 int register_ioport_read(pio_addr_t start, int length, int size,
                          IOPortReadFunc *func, void *opaque);
 int register_ioport_write(pio_addr_t start, int length, int size,
diff --git a/iorange.h b/iorange.h
new file mode 100644
index 0000000..9783168
--- /dev/null
+++ b/iorange.h
@@ -0,0 +1,30 @@
+#ifndef IORANGE_H
+#define IORANGE_H
+
+#include <stdint.h>
+
+typedef struct IORange IORange;
+typedef struct IORangeOps IORangeOps;
+
+struct IORangeOps {
+    void (*read)(IORange *iorange, uint64_t offset, unsigned width,
+                 uint64_t *data);
+    void (*write)(IORange *iorange, uint64_t offset, unsigned width,
+                  uint64_t data);
+};
+
+struct IORange {
+    const IORangeOps *ops;
+    uint64_t base;
+    uint64_t len;
+};
+
+static inline void iorange_init(IORange *iorange, const IORangeOps *ops,
+                                uint64_t base, uint64_t len)
+{
+    iorange->ops = ops;
+    iorange->base = base;
+    iorange->len = len;
+}
+
+#endif
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 77683f7..7c62fac 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -3071,11 +3071,11 @@
 };
 
 struct target_ucontext {
-    abi_ulong uc_flags;
-    abi_ulong uc_link;
-    struct target_stack_t uc_stack;
-    struct target_sigcontext sc;
-    uint32_t extramask[TARGET_NSIG_WORDS - 1];
+    abi_ulong tuc_flags;
+    abi_ulong tuc_link;
+    struct target_stack_t tuc_stack;
+    struct target_sigcontext tuc_mcontext;
+    uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
 };
 
 /* Signal frames. */
@@ -3189,7 +3189,7 @@
         goto badframe;
 
     /* Save the mask.  */
-    err |= __put_user(set->sig[0], &frame->uc.sc.oldmask);
+    err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
     if (err)
         goto badframe;
 
@@ -3198,7 +3198,7 @@
             goto badframe;
     }
 
-    setup_sigcontext(&frame->uc.sc, env);
+    setup_sigcontext(&frame->uc.tuc_mcontext, env);
 
     /* Set up to return from userspace. If provided, use a stub
        already in userspace. */
@@ -3261,7 +3261,7 @@
         goto badframe;
 
     /* Restore blocked signals */
-    if (__get_user(target_set.sig[0], &frame->uc.sc.oldmask))
+    if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
         goto badframe;
     for(i = 1; i < TARGET_NSIG_WORDS; i++) {
         if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
@@ -3270,7 +3270,7 @@
     target_to_host_sigset_internal(&set, &target_set);
     sigprocmask(SIG_SETMASK, &set, NULL);
 
-    restore_sigcontext(&frame->uc.sc, env);
+    restore_sigcontext(&frame->uc.tuc_mcontext, env);
     /* We got here through a sigreturn syscall, our path back is via an
        rtb insn so setup r14 for that.  */
     env->regs[14] = env->sregs[SR_PC];
diff --git a/make_device_config.sh b/make_device_config.sh
new file mode 100644
index 0000000..8abadfe
--- /dev/null
+++ b/make_device_config.sh
@@ -0,0 +1,28 @@
+#! /bin/sh
+# Construct a target device config file from a default, pulling in any
+# files from include directives.
+
+dest=$1.tmp
+dep=$1.d
+src=$2
+src_dir=`dirname $src`
+all_includes=
+
+process_includes () {
+  cat $1 | grep '^include' | \
+  while read include file ; do
+    all_includes="$all_includes $src_dir/$file"
+    process_includes $src_dir/$file
+  done
+}
+
+f=$src
+while [ -n "$f" ] ; do
+  f=`awk '/^include / {ORS=" " ; print "'$src_dir'/" $2}' $f`
+  [ $? = 0 ] || exit 1
+  all_includes="$all_includes $f"
+done
+process_includes $src > $dest
+
+cat $src $all_includes | grep -v '^include' > $dest
+echo "$1: $all_includes" > $dep
diff --git a/monitor.c b/monitor.c
index 8cee35d..ec31eac 100644
--- a/monitor.c
+++ b/monitor.c
@@ -491,6 +491,44 @@
     return 0;
 }
 
+static int mon_set_cpu(int cpu_index);
+static void handle_user_command(Monitor *mon, const char *cmdline);
+
+static int do_hmp_passthrough(Monitor *mon, const QDict *params,
+                              QObject **ret_data)
+{
+    int ret = 0;
+    Monitor *old_mon, hmp;
+    CharDriverState mchar;
+
+    memset(&hmp, 0, sizeof(hmp));
+    qemu_chr_init_mem(&mchar);
+    hmp.chr = &mchar;
+
+    old_mon = cur_mon;
+    cur_mon = &hmp;
+
+    if (qdict_haskey(params, "cpu-index")) {
+        ret = mon_set_cpu(qdict_get_int(params, "cpu-index"));
+        if (ret < 0) {
+            cur_mon = old_mon;
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number");
+            goto out;
+        }
+    }
+
+    handle_user_command(&hmp, qdict_get_str(params, "command-line"));
+    cur_mon = old_mon;
+
+    if (qemu_chr_mem_osize(hmp.chr) > 0) {
+        *ret_data = QOBJECT(qemu_chr_mem_to_qs(hmp.chr));
+    }
+
+out:
+    qemu_chr_close_mem(hmp.chr);
+    return ret;
+}
+
 static int compare_cmd(const char *name, const char *list)
 {
     const char *p, *pstart;
diff --git a/pc-bios/optionrom/signrom.sh b/pc-bios/optionrom/signrom.sh
index 975b27d..9dc5c63 100755
--- a/pc-bios/optionrom/signrom.sh
+++ b/pc-bios/optionrom/signrom.sh
@@ -31,14 +31,13 @@
 size=$(( $x * 512 - 1 ))
 
 # now get the checksum
-nums=`od -A n -t u1 -v "$1"`
+nums=`od -A n -t u1 -v -N $size "$1"`
 for i in ${nums}; do
     # add each byte's value to sum
-    sum=`expr $sum + $i`
+    sum=`expr \( $sum + $i \) % 256`
 done
 
-sum=$(( $sum % 256 ))
-sum=$(( 256 - $sum ))
+sum=$(( (256 - $sum) % 256 ))
 sum_octal=$( printf "%o" $sum )
 
 # and write the output file
diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin
index 4fa8f99..424dd0c 100644
--- a/pc-bios/vgabios-cirrus.bin
+++ b/pc-bios/vgabios-cirrus.bin
Binary files differ
diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin
new file mode 100644
index 0000000..5123c5f
--- /dev/null
+++ b/pc-bios/vgabios-stdvga.bin
Binary files differ
diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin
new file mode 100644
index 0000000..5e8c06b
--- /dev/null
+++ b/pc-bios/vgabios-vmware.bin
Binary files differ
diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin
index fa6f815..892a2b5 100644
--- a/pc-bios/vgabios.bin
+++ b/pc-bios/vgabios.bin
Binary files differ
diff --git a/qemu-char.c b/qemu-char.c
index 88997f9..edc9ad6 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2275,6 +2275,70 @@
     return NULL;
 }
 
+/***********************************************************/
+/* Memory chardev */
+typedef struct {
+    size_t outbuf_size;
+    size_t outbuf_capacity;
+    uint8_t *outbuf;
+} MemoryDriver;
+
+static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MemoryDriver *d = chr->opaque;
+
+    /* TODO: the QString implementation has the same code, we should
+     * introduce a generic way to do this in cutils.c */
+    if (d->outbuf_capacity < d->outbuf_size + len) {
+        /* grow outbuf */
+        d->outbuf_capacity += len;
+        d->outbuf_capacity *= 2;
+        d->outbuf = qemu_realloc(d->outbuf, d->outbuf_capacity);
+    }
+
+    memcpy(d->outbuf + d->outbuf_size, buf, len);
+    d->outbuf_size += len;
+
+    return len;
+}
+
+void qemu_chr_init_mem(CharDriverState *chr)
+{
+    MemoryDriver *d;
+
+    d = qemu_malloc(sizeof(*d));
+    d->outbuf_size = 0;
+    d->outbuf_capacity = 4096;
+    d->outbuf = qemu_mallocz(d->outbuf_capacity);
+
+    memset(chr, 0, sizeof(*chr));
+    chr->opaque = d;
+    chr->chr_write = mem_chr_write;
+}
+
+QString *qemu_chr_mem_to_qs(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+    return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
+}
+
+/* NOTE: this driver can not be closed with qemu_chr_close()! */
+void qemu_chr_close_mem(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+
+    qemu_free(d->outbuf);
+    qemu_free(chr->opaque);
+    chr->opaque = NULL;
+    chr->chr_write = NULL;
+}
+
+size_t qemu_chr_mem_osize(const CharDriverState *chr)
+{
+    const MemoryDriver *d = chr->opaque;
+    return d->outbuf_size;
+}
+
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
 {
     char host[65], port[33], width[8], height[8];
diff --git a/qemu-char.h b/qemu-char.h
index 18ad12b..e6ee6c4 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -6,6 +6,7 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 #include "qobject.h"
+#include "qstring.h"
 
 /* character device */
 
@@ -100,6 +101,12 @@
 
 extern int term_escape_char;
 
+/* memory chardev */
+void qemu_chr_init_mem(CharDriverState *chr);
+void qemu_chr_close_mem(CharDriverState *chr);
+QString *qemu_chr_mem_to_qs(CharDriverState *chr);
+size_t qemu_chr_mem_osize(const CharDriverState *chr);
+
 /* async I/O support */
 
 int qemu_set_fd_handler2(int fd,
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 793cf1c..e5f157f 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -761,6 +761,51 @@
 
 Note: This command must be issued before issuing any other command.
 
+EQMP
+
+    {
+        .name       = "human-monitor-command",
+        .args_type  = "command-line:s,cpu-index:i?",
+        .params     = "",
+        .help       = "",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_hmp_passthrough,
+    },
+
+SQMP
+human-monitor-command
+---------------------
+
+Execute a Human Monitor command.
+
+Arguments: 
+
+- command-line: the command name and its arguments, just like the
+                Human Monitor's shell (json-string)
+- cpu-index: select the CPU number to be used by commands which access CPU
+             data, like 'info registers'. The Monitor selects CPU 0 if this
+             argument is not provided (json-int, optional)
+
+Example:
+
+-> { "execute": "human-monitor-command", "arguments": { "command-line": "info kvm" } }
+<- { "return": "kvm support: enabled\r\n" }
+
+Notes:
+
+(1) The Human Monitor is NOT an stable interface, this means that command
+    names, arguments and responses can change or be removed at ANY time.
+    Applications that rely on long term stability guarantees should NOT
+    use this command
+
+(2) Limitations:
+
+    o This command is stateless, this means that commands that depend
+      on state information (such as getfd) might not work
+
+    o Commands that prompt the user for data (eg. 'cont' when the block
+      device is encrypted) don't currently work
+
 3. Query Commands
 =================
 
diff --git a/roms/vgabios b/roms/vgabios
index 6e62666..19ea12c 160000
--- a/roms/vgabios
+++ b/roms/vgabios
@@ -1 +1 @@
-Subproject commit 6e62666cfc19e7fd45dd0d7c3ad62fd8d0b5f67a
+Subproject commit 19ea12c230ded95928ecaef0db47a82231c2e485
diff --git a/simpletrace.h b/simpletrace.h
index 72614ec..2f44ed3 100644
--- a/simpletrace.h
+++ b/simpletrace.h
@@ -29,10 +29,10 @@
 void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4);
 void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5);
 void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);
-void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
-void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
+void st_print_trace(FILE *stream, fprintf_function stream_printf);
+void st_print_trace_events(FILE *stream, fprintf_function stream_printf);
 bool st_change_trace_event_state(const char *tname, bool tstate);
-void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
+void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf);
 void st_set_trace_file_enabled(bool enable);
 bool st_set_trace_file(const char *file);
 void st_flush_trace_buffer(void);
diff --git a/slirp/misc.c b/slirp/misc.c
index 1aeb401..19dbec4 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -264,48 +264,6 @@
     va_end(args);
 }
 
-#ifdef BAD_SPRINTF
-
-#undef vsprintf
-#undef sprintf
-
-/*
- * Some BSD-derived systems have a sprintf which returns char *
- */
-
-int
-vsprintf_len(string, format, args)
-	char *string;
-	const char *format;
-	va_list args;
-{
-	vsprintf(string, format, args);
-	return strlen(string);
-}
-
-int
-#ifdef __STDC__
-sprintf_len(char *string, const char *format, ...)
-#else
-sprintf_len(va_alist) va_dcl
-#endif
-{
-	va_list args;
-#ifdef __STDC__
-	va_start(args, format);
-#else
-	char *string;
-	char *format;
-	va_start(args);
-	string = va_arg(args, char *);
-	format = va_arg(args, char *);
-#endif
-	vsprintf(string, format, args);
-	return strlen(string);
-}
-
-#endif
-
 void
 u_sleep(int usec)
 {
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 462292d..dfd977a 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -237,20 +237,6 @@
 void if_start(struct ttys *);
 #endif
 
-#ifdef BAD_SPRINTF
-# define vsprintf vsprintf_len
-# define sprintf sprintf_len
- extern int vsprintf_len(char *, const char *, va_list);
- extern int sprintf_len(char *, const char *, ...);
-#endif
-
-#ifdef DECLARE_SPRINTF
-# ifndef BAD_SPRINTF
- extern int vsprintf(char *, const char *, va_list);
-# endif
- extern int vfprintf(FILE *, const char *, va_list);
-#endif
-
 #ifndef HAVE_STRERROR
  extern char *strerror(int error);
 #endif
diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h
index f19c703..18db45c 100644
--- a/slirp/slirp_config.h
+++ b/slirp/slirp_config.h
@@ -85,9 +85,6 @@
 /* Define if the machine is big endian */
 //#undef HOST_WORDS_BIGENDIAN
 
-/* Define if your sprintf returns char * instead of int */
-#undef BAD_SPRINTF
-
 /* Define if you have readv */
 #undef HAVE_READV
 
@@ -97,9 +94,6 @@
 #define DECLARE_IOVEC
 #endif
 
-/* Define if a declaration of sprintf/fprintf is needed */
-#undef DECLARE_SPRINTF
-
 /* Define if you have a POSIX.1 sys/wait.h */
 #undef HAVE_SYS_WAIT_H
 
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 2440d65..06e40f3 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -681,6 +681,7 @@
 #endif
     uint64_t system_time_msr;
     uint64_t wall_clock_msr;
+    uint64_t async_pf_en_msr;
 
     uint64_t tsc;
 
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 650a719..165045e 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -73,7 +73,7 @@
 };
 
 static const char *kvm_feature_name[] = {
-    "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, NULL, NULL, NULL, NULL,
+    "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, "kvm_asyncpf", NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ae0a034..7dfc357 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -162,6 +162,9 @@
 #ifdef KVM_CAP_PV_MMU
         { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
 #endif
+#ifdef KVM_CAP_ASYNC_PF
+        { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
+#endif
         { -1, -1 }
 };
 
@@ -838,6 +841,9 @@
         kvm_msr_entry_set(&msrs[n++], MSR_KVM_SYSTEM_TIME,
                           env->system_time_msr);
         kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
+#ifdef KVM_CAP_ASYNC_PF
+        kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr);
+#endif
     }
 #ifdef KVM_CAP_MCE
     if (env->mcg_cap) {
@@ -1064,6 +1070,9 @@
 #endif
     msrs[n++].index = MSR_KVM_SYSTEM_TIME;
     msrs[n++].index = MSR_KVM_WALL_CLOCK;
+#ifdef KVM_CAP_ASYNC_PF
+    msrs[n++].index = MSR_KVM_ASYNC_PF_EN;
+#endif
 
 #ifdef KVM_CAP_MCE
     if (env->mcg_cap) {
@@ -1135,6 +1144,11 @@
             }
 #endif
             break;
+#ifdef KVM_CAP_ASYNC_PF
+        case MSR_KVM_ASYNC_PF_EN:
+            env->async_pf_en_msr = msrs[i].data;
+            break;
+#endif
         }
     }
 
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 5f8376c..d78eceb 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -373,6 +373,24 @@
     return 0;
 }
 
+static bool async_pf_msr_needed(void *opaque)
+{
+    CPUState *cpu = opaque;
+
+    return cpu->async_pf_en_msr != 0;
+}
+
+static const VMStateDescription vmstate_async_pf_msr = {
+    .name = "cpu/async_pf_msr",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(async_pf_en_msr, CPUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_cpu = {
     .name = "cpu",
     .version_id = CPU_SAVE_VERSION,
@@ -475,6 +493,14 @@
         VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12),
         VMSTATE_END_OF_LIST()
         /* The above list is not sorted /wrt version numbers, watch out! */
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_async_pf_msr,
+            .needed = async_pf_msr_needed,
+        } , {
+            /* empty */
+        }
     }
 };
 
diff --git a/trace-events b/trace-events
index 947f8b0..da03d4b 100644
--- a/trace-events
+++ b/trace-events
@@ -189,3 +189,6 @@
 disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x"
 disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
 disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
+
+# vl.c
+disable vm_state_notify(int running, int reason) "running %d reason %d"
diff --git a/tracetool b/tracetool
index 7010858..fce491c 100755
--- a/tracetool
+++ b/tracetool
@@ -20,10 +20,19 @@
   --nop     Tracing disabled
   --simple  Simple built-in backend
   --ust     LTTng User Space Tracing backend
+  --dtrace  DTrace/SystemTAP backend
 
 Output formats:
-  -h    Generate .h file
-  -c    Generate .c file
+  -h     Generate .h file
+  -c     Generate .c file
+  -d     Generate .d file (DTrace only)
+  --stap Generate .stp file (DTrace with SystemTAP only)
+
+Options:
+  --binary      [path]  Full path to QEMU binary
+  --target-arch [arch]  QEMU emulator target arch
+  --target-type [type]  QEMU emulator target type ('system' or 'user')
+
 EOF
     exit 1
 }
@@ -46,8 +55,9 @@
 # Get the argument name list of a trace event
 get_argnames()
 {
-    local nfields field name
+    local nfields field name sep
     nfields=0
+    sep="$2"
     for field in $(get_args "$1"); do
         nfields=$((nfields + 1))
 
@@ -58,7 +68,7 @@
         name=${field%,}
         test "$field" = "$name" && continue
 
-        printf "%s" "$name, "
+        printf "%s%s " $name $sep
     done
 
     # Last argument name
@@ -73,7 +83,7 @@
 {
     local name argc
     argc=0
-    for name in $(get_argnames "$1"); do
+    for name in $(get_argnames "$1", ","); do
         argc=$((argc + 1))
     done
     echo $argc
@@ -154,7 +164,7 @@
 cast_args_to_uint64_t()
 {
     local arg
-    for arg in $(get_argnames "$1"); do
+    for arg in $(get_argnames "$1", ","); do
         printf "%s" "(uint64_t)(uintptr_t)$arg"
     done
 }
@@ -247,7 +257,7 @@
     local name args argnames
     name=$(get_name "$1")
     args=$(get_args "$1")
-    argnames=$(get_argnames "$1")
+    argnames=$(get_argnames "$1", ",")
 
     cat <<EOF
 DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
@@ -274,7 +284,7 @@
     local name args argnames fmt
     name=$(get_name "$1")
     args=$(get_args "$1")
-    argnames=$(get_argnames "$1")
+    argnames=$(get_argnames "$1", ",")
     fmt=$(get_fmt "$1")
 
     cat <<EOF
@@ -306,6 +316,138 @@
     echo "}"
 }
 
+linetoh_begin_dtrace()
+{
+    cat <<EOF
+#include "trace-dtrace.h"
+EOF
+}
+
+linetoh_dtrace()
+{
+    local name args argnames state nameupper
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    argnames=$(get_argnames "$1", ",")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+
+    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
+
+    # Define an empty function for the trace event
+    cat <<EOF
+static inline void trace_$name($args) {
+    if (QEMU_${nameupper}_ENABLED()) {
+        QEMU_${nameupper}($argnames);
+    }
+}
+EOF
+}
+
+linetoh_end_dtrace()
+{
+    return
+}
+
+linetoc_begin_dtrace()
+{
+    return
+}
+
+linetoc_dtrace()
+{
+    # No need for function definitions in dtrace backend
+    return
+}
+
+linetoc_end_dtrace()
+{
+    return
+}
+
+linetod_begin_dtrace()
+{
+    cat <<EOF
+provider qemu {
+EOF
+}
+
+linetod_dtrace()
+{
+    local name args state
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+
+    # DTrace provider syntax expects foo() for empty
+    # params, not foo(void)
+    if [ "$args" = "void" ]; then
+       args=""
+    fi
+
+    # Define prototype for probe arguments
+    cat <<EOF
+        probe $name($args);
+EOF
+}
+
+linetod_end_dtrace()
+{
+    cat <<EOF
+};
+EOF
+}
+
+linetostap_begin_dtrace()
+{
+    return
+}
+
+linetostap_dtrace()
+{
+    local i arg name args arglist state
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    arglist=$(get_argnames "$1", "")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+
+    # Define prototype for probe arguments
+    cat <<EOF
+probe qemu.$targettype.$targetarch.$name = process("$binary").mark("$name")
+{
+EOF
+
+    i=1
+    for arg in $arglist
+    do
+        # 'limit' is a reserved keyword
+        if [ "$arg" = "limit" ]; then
+          arg="_limit"
+        fi
+        cat <<EOF
+  $arg = \$arg$i;
+EOF
+	i="$((i+1))"
+    done
+
+    cat <<EOF
+}
+EOF
+}
+
+linetostap_end_dtrace()
+{
+    return
+}
+
 # Process stdin by calling begin, line, and end functions for the backend
 convert()
 {
@@ -324,9 +466,10 @@
         disable=${str%%disable *}
         echo
         if test -z "$disable"; then
-            # Pass the disabled state as an arg to lineto$1_simple().
-            # For all other cases, call lineto$1_nop()
-            if [ $backend = "simple" ]; then
+            # Pass the disabled state as an arg for the simple
+            # or DTrace backends which handle it dynamically.
+            # For all other backends, call lineto$1_nop()
+            if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
                 "$process_line" "$str"
             else
                 "lineto$1_nop" "${str##disable }"
@@ -360,18 +503,71 @@
     convert c
 }
 
-# Choose backend
-case "$1" in
-"--nop" | "--simple" | "--ust") backend="${1#--}" ;;
-*) usage ;;
-esac
-shift
+tracetod()
+{
+    if [ $backend != "dtrace" ]; then
+       echo "DTrace probe generator not applicable to $backend backend"
+       exit 1
+    fi
+    echo "/* This file is autogenerated by tracetool, do not edit. */"
+    convert d
+}
 
-case "$1" in
-"-h") tracetoh ;;
-"-c") tracetoc ;;
-"--check-backend") exit 0 ;; # used by ./configure to test for backend
-*) usage ;;
-esac
+tracetostap()
+{
+    if [ $backend != "dtrace" ]; then
+       echo "SystemTAP tapset generator not applicable to $backend backend"
+       exit 1
+    fi
+    if [ -z "$binary" ]; then
+       echo "--binary is required for SystemTAP tapset generator"
+       exit 1
+    fi
+    if [ -z "$targettype" ]; then
+       echo "--target-type is required for SystemTAP tapset generator"
+       exit 1
+    fi
+    if [ -z "$targetarch" ]; then
+       echo "--target-arch is required for SystemTAP tapset generator"
+       exit 1
+    fi
+    echo "/* This file is autogenerated by tracetool, do not edit. */"
+    convert stap
+}
+
+
+backend=
+output=
+binary=
+targettype=
+targetarch=
+
+
+until [ -z "$1" ]
+do
+  case "$1" in
+    "--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
+
+    "--binary") shift ; binary="$1" ;;
+    "--target-arch") shift ; targetarch="$1" ;;
+    "--target-type") shift ; targettype="$1" ;;
+
+    "-h" | "-c" | "-d") output="${1#-}" ;;
+    "--stap") output="${1#--}" ;;
+
+    "--check-backend") exit 0 ;; # used by ./configure to test for backend
+
+    *)
+      usage;;
+  esac
+  shift
+done
+
+if [ "$backend" = "" -o "$output" = "" ]; then
+  usage
+fi
+
+gen="traceto$output"
+"$gen"
 
 exit 0
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index 063c7dc..0e3ad9b 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -29,6 +29,7 @@
 
 void qemu_spice_init(void);
 void qemu_spice_input_init(void);
+void qemu_spice_audio_init(void);
 void qemu_spice_display_init(DisplayState *ds);
 int qemu_spice_add_interface(SpiceBaseInstance *sin);
 
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 6a1cf17..d13bdc2 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -95,7 +95,7 @@
         on_read = watch_read;
     }
     if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) {
-        on_read = watch_write;
+        on_write = watch_write;
     }
     qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
 }
@@ -240,7 +240,7 @@
     char *x509_key_file = NULL,
         *x509_cert_file = NULL,
         *x509_cacert_file = NULL;
-    int port, tls_port, len, addr_flags, streaming_video;
+    int port, tls_port, len, addr_flags;
     spice_image_compression_t compression;
     spice_wan_compression_t wan_compr;
 
@@ -344,7 +344,7 @@
 
     str = qemu_opt_get(opts, "streaming-video");
     if (str) {
-        streaming_video = parse_stream_video(str);
+        int streaming_video = parse_stream_video(str);
         spice_server_set_streaming_video(spice_server, streaming_video);
     }
 
@@ -361,6 +361,7 @@
     using_spice = 1;
 
     qemu_spice_input_init();
+    qemu_spice_audio_init();
 
     qemu_free(x509_key_file);
     qemu_free(x509_cert_file);
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 7b4f5c1..020b423 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -64,10 +64,10 @@
 
 /*
  * Called from spice server thread context (via interface_get_command).
- * We do *not* hold the global qemu mutex here, so extra care is needed
- * when calling qemu functions.  Qemu interfaces used:
- *    - pflib (is re-entrant).
- *    - qemu_malloc (underlying glibc malloc is re-entrant).
+ *
+ * We must aquire the global qemu mutex here to make sure the
+ * DisplayState (+DisplaySurface) we are accessing doesn't change
+ * underneath us.
  */
 SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
 {
@@ -78,11 +78,12 @@
     uint8_t *src, *dst;
     int by, bw, bh;
 
+    qemu_mutex_lock_iothread();
     if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+        qemu_mutex_unlock_iothread();
         return NULL;
     };
 
-    pthread_mutex_lock(&ssd->lock);
     dprint(2, "%s: lr %d -> %d,  tb -> %d -> %d\n", __FUNCTION__,
            ssd->dirty.left, ssd->dirty.right,
            ssd->dirty.top, ssd->dirty.bottom);
@@ -140,7 +141,7 @@
     cmd->data = (intptr_t)drawable;
 
     memset(&ssd->dirty, 0, sizeof(ssd->dirty));
-    pthread_mutex_unlock(&ssd->lock);
+    qemu_mutex_unlock_iothread();
     return update;
 }
 
@@ -184,14 +185,19 @@
     surface.type       = 0;
     surface.mem        = (intptr_t)ssd->buf;
     surface.group_id   = MEMSLOT_GROUP_HOST;
+
+    qemu_mutex_unlock_iothread();
     ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
+    qemu_mutex_lock_iothread();
 }
 
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
 {
     dprint(1, "%s:\n", __FUNCTION__);
 
+    qemu_mutex_unlock_iothread();
     ssd->worker->destroy_primary_surface(ssd->worker, 0);
+    qemu_mutex_lock_iothread();
 }
 
 void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
@@ -201,7 +207,9 @@
     if (running) {
         ssd->worker->start(ssd->worker);
     } else {
+        qemu_mutex_unlock_iothread();
         ssd->worker->stop(ssd->worker);
+        qemu_mutex_lock_iothread();
     }
     ssd->running = running;
 }
@@ -219,31 +227,25 @@
     update_area.top = y;
     update_area.bottom = y + h;
 
-    pthread_mutex_lock(&ssd->lock);
     if (qemu_spice_rect_is_empty(&ssd->dirty)) {
         ssd->notify++;
     }
     qemu_spice_rect_union(&ssd->dirty, &update_area);
-    pthread_mutex_unlock(&ssd->lock);
 }
 
 void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
 {
     dprint(1, "%s:\n", __FUNCTION__);
 
-    pthread_mutex_lock(&ssd->lock);
     memset(&ssd->dirty, 0, sizeof(ssd->dirty));
     qemu_pf_conv_put(ssd->conv);
     ssd->conv = NULL;
-    pthread_mutex_unlock(&ssd->lock);
 
     qemu_spice_destroy_host_primary(ssd);
     qemu_spice_create_host_primary(ssd);
 
-    pthread_mutex_lock(&ssd->lock);
     memset(&ssd->dirty, 0, sizeof(ssd->dirty));
     ssd->notify++;
-    pthread_mutex_unlock(&ssd->lock);
 }
 
 void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
@@ -398,7 +400,6 @@
     sdpy.ds = ds;
     sdpy.bufsize = (16 * 1024 * 1024);
     sdpy.buf = qemu_malloc(sdpy.bufsize);
-    pthread_mutex_init(&sdpy.lock, NULL);
     register_displaychangelistener(ds, &display_listener);
 
     sdpy.qxl.base.sif = &dpy_interface.base;
diff --git a/ui/spice-display.h b/ui/spice-display.h
index e17671c..aef0464 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -40,7 +40,6 @@
     uint32_t unique;
     QemuPfConv *conv;
 
-    pthread_mutex_t lock;
     QXLRect dirty;
     int notify;
     int running;
diff --git a/usb-linux.c b/usb-linux.c
index c3c38ec..ccf7073 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -62,8 +62,8 @@
     uint16_t wLength;
 };
 
-typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
-                        int vendor_id, int product_id,
+typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
+                        int class_id, int vendor_id, int product_id,
                         const char *product_name, int speed);
 
 //#define DEBUG
@@ -141,6 +141,7 @@
     /* Host side address */
     int bus_num;
     int addr;
+    int devpath;
     struct USBAutoFilter match;
 
     QTAILQ_ENTRY(USBHostDevice) next;
@@ -151,6 +152,8 @@
 static int usb_host_close(USBHostDevice *dev);
 static int parse_filter(const char *spec, struct USBAutoFilter *f);
 static void usb_host_auto_check(void *unused);
+static int usb_host_read_file(char *line, size_t line_size,
+                            const char *device_file, const char *device_name);
 
 static int is_isoc(USBHostDevice *s, int ep)
 {
@@ -774,14 +777,29 @@
     }
 }
 
-/* returns 1 on problem encountered or 0 for success */
-static int usb_linux_update_endp_table(USBHostDevice *s)
+static int usb_linux_get_configuration(USBHostDevice *s)
 {
-    uint8_t *descriptors;
-    uint8_t devep, type, configuration, alt_interface;
+    uint8_t configuration;
     struct usb_ctrltransfer ct;
-    int interface, ret, length, i;
+    int ret;
 
+    if (usb_fs_type == USB_FS_SYS) {
+        char device_name[32], line[1024];
+        int configuration;
+
+        sprintf(device_name, "%d-%d", s->bus_num, s->devpath);
+
+        if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
+                                device_name)) {
+            goto usbdevfs;
+        }
+        if (sscanf(line, "%d", &configuration) != 1) {
+            goto usbdevfs;
+        }
+        return configuration;
+    }
+
+usbdevfs:
     ct.bRequestType = USB_DIR_IN;
     ct.bRequest = USB_REQ_GET_CONFIGURATION;
     ct.wValue = 0;
@@ -792,15 +810,31 @@
 
     ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
     if (ret < 0) {
-        perror("usb_linux_update_endp_table");
-        return 1;
+        perror("usb_linux_get_configuration");
+        return -1;
     }
 
     /* in address state */
     if (configuration == 0) {
-        return 1;
+        return -1;
     }
 
+    return configuration;
+}
+
+/* returns 1 on problem encountered or 0 for success */
+static int usb_linux_update_endp_table(USBHostDevice *s)
+{
+    uint8_t *descriptors;
+    uint8_t devep, type, configuration, alt_interface;
+    struct usb_ctrltransfer ct;
+    int interface, ret, length, i;
+
+    i = usb_linux_get_configuration(s);
+    if (i < 0)
+        return 1;
+    configuration = i;
+
     /* get the desired configuration, interface, and endpoint descriptors
      * from device description */
     descriptors = &s->descr[18];
@@ -885,7 +919,7 @@
 }
 
 static int usb_host_open(USBHostDevice *dev, int bus_num,
-                         int addr, const char *prod_name)
+                         int addr, int devpath, const char *prod_name)
 {
     int fd = -1, ret;
     struct usbdevfs_connectinfo ci;
@@ -911,6 +945,7 @@
 
     dev->bus_num = bus_num;
     dev->addr = addr;
+    dev->devpath = devpath;
     dev->fd = fd;
 
     /* read the device description */
@@ -1173,7 +1208,7 @@
         if (line[0] == 'T' && line[1] == ':') {
             if (device_count && (vendor_id || product_id)) {
                 /* New device.  Add the previously discovered device.  */
-                ret = func(opaque, bus_num, addr, class_id, vendor_id,
+                ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
                            product_id, product_name, speed);
                 if (ret) {
                     goto the_end;
@@ -1226,7 +1261,7 @@
     }
     if (device_count && (vendor_id || product_id)) {
         /* Add the last device.  */
-        ret = func(opaque, bus_num, addr, class_id, vendor_id,
+        ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
                    product_id, product_name, speed);
     }
  the_end:
@@ -1275,7 +1310,7 @@
 {
     DIR *dir = NULL;
     char line[1024];
-    int bus_num, addr, speed, class_id, product_id, vendor_id;
+    int bus_num, addr, devpath, speed, class_id, product_id, vendor_id;
     int ret = 0;
     char product_name[512];
     struct dirent *de;
@@ -1292,7 +1327,9 @@
             if (!strncmp(de->d_name, "usb", 3)) {
                 tmpstr += 3;
             }
-            bus_num = atoi(tmpstr);
+            if (sscanf(tmpstr, "%d-%d", &bus_num, &devpath) < 1) {
+                goto the_end;
+            }
 
             if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
                 goto the_end;
@@ -1343,7 +1380,7 @@
                 speed = USB_SPEED_FULL;
             }
 
-            ret = func(opaque, bus_num, addr, class_id, vendor_id,
+            ret = func(opaque, bus_num, addr, devpath, class_id, vendor_id,
                        product_id, product_name, speed);
             if (ret) {
                 goto the_end;
@@ -1434,7 +1471,7 @@
 
 static QEMUTimer *usb_auto_timer;
 
-static int usb_host_auto_scan(void *opaque, int bus_num, int addr,
+static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
                               int class_id, int vendor_id, int product_id,
                               const char *product_name, int speed)
 {
@@ -1470,7 +1507,7 @@
         }
         DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
 
-        usb_host_open(s, bus_num, addr, product_name);
+        usb_host_open(s, bus_num, addr, devpath, product_name);
     }
 
     return 0;
@@ -1630,7 +1667,7 @@
 }
 
 static int usb_host_info_device(void *opaque, int bus_num, int addr,
-                                int class_id,
+                                int devpath, int class_id,
                                 int vendor_id, int product_id,
                                 const char *product_name,
                                 int speed)
diff --git a/vl.c b/vl.c
index 135fdeb..2cd263e 100644
--- a/vl.c
+++ b/vl.c
@@ -158,6 +158,7 @@
 
 #include "slirp/libslirp.h"
 
+#include "trace.h"
 #include "qemu-queue.h"
 #include "cpus.h"
 #include "arch_init.h"
@@ -1074,6 +1075,8 @@
 {
     VMChangeStateEntry *e;
 
+    trace_vm_state_notify(running, reason);
+
     for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
         e->cb(e->opaque, running, reason);
     }
@@ -1249,16 +1252,17 @@
         IOHandlerRecord *pioh;
 
         QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
+            if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
+                ioh->fd_read(ioh->opaque);
+            }
+            if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
+                ioh->fd_write(ioh->opaque);
+            }
+
+            /* Do this last in case read/write handlers marked it for deletion */
             if (ioh->deleted) {
                 QLIST_REMOVE(ioh, next);
                 qemu_free(ioh);
-                continue;
-            }
-            if (ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
-                ioh->fd_read(ioh->opaque);
-            }
-            if (ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
-                ioh->fd_write(ioh->opaque);
             }
         }
     }