Index: ioemu/hw/ide.c
===================================================================
--- ioemu.orig/hw/ide.c	2007-05-03 15:03:18.000000000 +0100
+++ ioemu/hw/ide.c	2007-05-03 15:06:48.000000000 +0100
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 #include "vl.h"
+#include <pthread.h>
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -390,6 +391,89 @@
     int type; /* see IDE_TYPE_xxx */
 } PCIIDEState;
 
+#define DMA_MULTI_THREAD
+
+#ifdef DMA_MULTI_THREAD
+
+static pthread_t ide_dma_thread;
+static int file_pipes[2];
+
+static void ide_dma_loop(BMDMAState *bm);
+static void dma_thread_loop(BMDMAState *bm);
+
+extern int suspend_requested;
+static void *dma_thread_func(void* opaque)
+{
+    BMDMAState* req;
+    fd_set fds;
+    int rv, nfds = file_pipes[0] + 1;
+    struct timeval tm;
+
+    while (1) {
+
+        /* Wait at most a second for the pipe to become readable */
+        FD_ZERO(&fds);
+        FD_SET(file_pipes[0], &fds);
+        tm.tv_sec = 1;
+        tm.tv_usec = 0;
+        rv = select(nfds, &fds, NULL, NULL, &tm);
+        
+        if (rv != 0) {
+            if (read(file_pipes[0], &req, sizeof(req)) == 0)
+                return NULL;
+            dma_thread_loop(req);
+        } else {
+            if (suspend_requested)  {
+                /* Need to tidy up the DMA thread so that we don't end up 
+                 * finishing operations after the domain's ioreqs are 
+                 * drained and its state saved */
+                return NULL;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static void dma_create_thread(void)
+{
+    int rt;
+    pthread_attr_t a;
+
+    if (pipe(file_pipes) != 0) {
+        fprintf(stderr, "create pipe failed\n");
+        exit(1);
+    }
+
+    if ((rt = pthread_attr_init(&a))
+        || (rt = pthread_attr_setdetachstate(&a, PTHREAD_CREATE_JOINABLE))) {
+        fprintf(stderr, "Oops, dma thread attr setup failed, errno=%d\n", rt);
+        exit(1);
+    }    
+    
+    if ((rt = pthread_create(&ide_dma_thread, &a, dma_thread_func, NULL))) {
+        fprintf(stderr, "Oops, dma thread creation failed, errno=%d\n", rt);
+        exit(1);
+    }
+}
+
+void ide_stop_dma_thread(void)
+{
+    int rc;
+    /* Make sure the IDE DMA thread is stopped */
+    if ( (rc = pthread_join(ide_dma_thread, NULL)) != 0 )
+    {
+        fprintf(stderr, "Oops, error collecting IDE DMA thread (%s)\n", 
+                strerror(rc));
+    }
+}
+
+#else
+void ide_stop_dma_thread(void)
+{
+}
+#endif /* DMA_MULTI_THREAD */
+
 static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb);
 
 static void padstr(char *str, const char *src, int len)
@@ -695,7 +779,9 @@
     }
     if (s->io_buffer_index >= s->io_buffer_size && s->nsector == 0) {
         s->status = READY_STAT | SEEK_STAT;
+#ifndef DMA_MULTI_THREAD
         ide_set_irq(s);
+#endif /* !DMA_MULTI_THREAD */
 #ifdef DEBUG_IDE_ATAPI
         printf("dma status=0x%x\n", s->status);
 #endif
@@ -795,7 +881,11 @@
                             qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
                 } else 
 #endif
+#ifndef DMA_MULTI_THREAD
                     ide_set_irq(s);
+#else  /* !DMA_MULTI_THREAD */
+                    ;
+#endif /* DMA_MULTI_THREAD */
                 return 0;
             }
             if (n > MAX_MULT_SECTORS)
@@ -1046,7 +1136,9 @@
     if (s->packet_transfer_size <= 0) {
         s->status = READY_STAT;
         s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+#ifndef DMA_MULTI_THREAD
         ide_set_irq(s);
+#endif /* !DMA_MULTI_THREAD */
 #ifdef DEBUG_IDE_ATAPI
         printf("dma status=0x%x\n", s->status);
 #endif
@@ -2103,9 +2195,30 @@
     }
 }
 
+static void ide_dma_finish(BMDMAState *bm)
+{
+    IDEState *s = bm->ide_if;
+
+    bm->status &= ~BM_STATUS_DMAING;
+    bm->status |= BM_STATUS_INT;
+    bm->dma_cb = NULL;
+    bm->ide_if = NULL;
+#ifdef DMA_MULTI_THREAD
+    ide_set_irq(s);
+#endif /* DMA_MULTI_THREAD */
+}
+
 /* XXX: full callback usage to prepare non blocking I/Os support -
    error handling */
+#ifdef DMA_MULTI_THREAD
+static void ide_dma_loop(BMDMAState *bm)
+{
+    write(file_pipes[1], &bm, sizeof(bm));
+}
+static void dma_thread_loop(BMDMAState *bm)
+#else  /* DMA_MULTI_THREAD */
 static void ide_dma_loop(BMDMAState *bm)
+#endif /* !DMA_MULTI_THREAD */
 {
     struct {
         uint32_t addr;
@@ -2141,10 +2254,7 @@
     }
     /* end of transfer */
  the_end:
-    bm->status &= ~BM_STATUS_DMAING;
-    bm->status |= BM_STATUS_INT;
-    bm->dma_cb = NULL;
-    bm->ide_if = NULL;
+    ide_dma_finish(bm);
 }
 
 static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb)
@@ -2370,6 +2480,9 @@
               cmd646_set_irq, d, 0);
     ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
               cmd646_set_irq, d, 1);
+#ifdef DMA_MULTI_THREAD    
+    dma_create_thread();
+#endif /* DMA_MULTI_THREAD */
 }
 
 static void pci_ide_save(QEMUFile* f, void *opaque)
@@ -2522,6 +2635,10 @@
 
     register_savevm("ide_pci", 0, 1, generic_pci_save, generic_pci_load, d);
     register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d);
+
+#ifdef DMA_MULTI_THREAD    
+    dma_create_thread();
+#endif //DMA_MULTI_THREAD    
 }
 
 /***********************************************************/
Index: ioemu/target-i386-dm/helper2.c
===================================================================
--- ioemu.orig/target-i386-dm/helper2.c	2007-05-03 15:03:18.000000000 +0100
+++ ioemu/target-i386-dm/helper2.c	2007-05-03 15:06:41.000000000 +0100
@@ -556,6 +556,9 @@
     handle_buffered_io(env);
     main_loop_wait(1); /* For the select() on events */
 
+    /* Stop the IDE thread */
+    ide_stop_dma_thread();
+
     /* Save the device state */
     sprintf(qemu_file, "/tmp/xen.qemu-dm.%d", domid);
     if (qemu_savevm(qemu_file) < 0)
Index: ioemu/vl.h
===================================================================
--- ioemu.orig/vl.h	2007-05-03 15:03:18.000000000 +0100
+++ ioemu/vl.h	2007-05-03 15:06:42.000000000 +0100
@@ -797,6 +797,7 @@
 void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn);
 int pmac_ide_init (BlockDriverState **hd_table,
                    SetIRQFunc *set_irq, void *irq_opaque, int irq);
+void ide_stop_dma_thread(void);
 
 /* cdrom.c */
 int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
