diff --git a/hw/block/xen_blkif.h b/hw/block/xen_blkif.h
index c68487cb..04dce2f 100644
--- a/hw/block/xen_blkif.h
+++ b/hw/block/xen_blkif.h
@@ -18,40 +18,97 @@ struct blkif_common_response {
 
 /* i386 protocol version */
 #pragma pack(push, 4)
-struct blkif_x86_32_request {
-	uint8_t        operation;    /* BLKIF_OP_???                         */
+struct blkif_x86_32_request_direct {
 	uint8_t        nr_segments;  /* number of segments                   */
 	blkif_vdev_t   handle;       /* only for read/write requests         */
 	uint64_t       id;           /* private guest value, echoed in resp  */
 	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
 	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-};
+} __attribute__((__packed__));
+
+struct blkif_x86_32_request_indirect {
+	uint8_t        operation;
+	uint16_t       nr_segments;
+	uint64_t       id;
+	blkif_sector_t sector_number;
+	blkif_vdev_t   handle;
+	uint16_t       _pad2;
+	grant_ref_t    indirect_grefs[BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST];
+	uint64_t       _pad3;         /* make it 64 byte aligned */
+} __attribute__((__packed__));
+
+struct blkif_x86_32_request {
+	uint8_t 	   operation;
+	union  {
+		struct blkif_x86_32_request_direct direct;
+		struct blkif_x86_32_request_indirect indirect;
+	} u;
+} __attribute__((__packed__));
+
 struct blkif_x86_32_response {
 	uint64_t        id;              /* copied from request */
 	uint8_t         operation;       /* copied from request */
 	int16_t         status;          /* BLKIF_RSP_???       */
-};
+} __attribute__((__packed__));
+
 typedef struct blkif_x86_32_request blkif_x86_32_request_t;
+typedef struct blkif_x86_32_request_direct blkif_x86_32_request_direct_t;
+typedef struct blkif_x86_32_request_indirect blkif_x86_32_request_indirect_t;
 typedef struct blkif_x86_32_response blkif_x86_32_response_t;
 #pragma pack(pop)
 
 /* x86_64 protocol version */
-struct blkif_x86_64_request {
-	uint8_t        operation;    /* BLKIF_OP_???                         */
+struct blkif_x86_64_request_direct {
 	uint8_t        nr_segments;  /* number of segments                   */
 	blkif_vdev_t   handle;       /* only for read/write requests         */
-	uint64_t       __attribute__((__aligned__(8))) id;
+	uint32_t       _pad1;	     /* offsetof(blkif_request,u.rw.id) == 8 */
+	uint64_t       id;           /* private guest value, echoed in resp  */
 	blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
 	struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-};
+} __attribute__((__packed__));
+
+struct blkif_x86_64_request_indirect {
+	uint8_t        operation;
+	uint16_t       nr_segments;
+	uint32_t       _pad1;  
+	uint64_t       id;
+	blkif_sector_t sector_number;
+	blkif_vdev_t   handle;
+	uint16_t       _pad2;
+	grant_ref_t    indirect_grefs[BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST];
+	uint32_t      _pad3;         /* make it 64 byte aligned */
+} __attribute__((__packed__));
+
+struct blkif_x86_64_request {
+	uint8_t        operation;    /* BLKIF_OP_???                         */
+	union {
+		struct blkif_x86_64_request_direct direct;
+		struct blkif_x86_64_request_indirect indirect;
+	} u;
+} __attribute__((__packed__));
+
 struct blkif_x86_64_response {
-	uint64_t       __attribute__((__aligned__(8))) id;
+	uint64_t        id;              /* copied from request */
 	uint8_t         operation;       /* copied from request */
 	int16_t         status;          /* BLKIF_RSP_???       */
 };
+
 typedef struct blkif_x86_64_request blkif_x86_64_request_t;
+typedef struct blkif_x86_64_request_direct blkif_x86_64_request_direct_t;
+typedef struct blkif_x86_64_request_indirect blkif_x86_64_request_indirect_t;
 typedef struct blkif_x86_64_response blkif_x86_64_response_t;
 
+struct blkif_request_local {
+	uint8_t 	   operation;
+ 	union {
+		struct blkif_request direct;
+		struct blkif_request_indirect indirect;
+	} u;
+} __attribute__((__packed__));
+typedef struct blkif_request blkif_request_direct_t;
+typedef struct blkif_request_indirect blkif_request_indirect_t;
+typedef struct blkif_request_local blkif_request_local_t;
+
 DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response);
 DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response);
 DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response);
@@ -70,16 +127,27 @@ enum blkif_protocol {
 	BLKIF_PROTOCOL_X86_64 = 3,
 };
 
-static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
+#define XEN_PAGE_SIZE 4096
+#define XEN_PAGES_PER_SEGMENT 1
+#define XEN_PAGES_PER_INDIRECT_FRAME \
+      (XEN_PAGE_SIZE/sizeof(struct blkif_request_segment))
+#define SEGS_PER_INDIRECT_FRAME \
+      (XEN_PAGES_PER_INDIRECT_FRAME / XEN_PAGES_PER_SEGMENT)
+#define MAX_INDIRECT_PAGES \
+      ((MAX_INDIRECT_SEGMENTS + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
+#define INDIRECT_PAGES(_segs) DIV_ROUND_UP(_segs, XEN_PAGES_PER_INDIRECT_FRAME)
+
+static inline void blkif_get_x86_32_req_direct(blkif_request_direct_t *dst, 
+										       blkif_x86_32_request_direct_t *src,
+										       uint8_t operation)
 {
 	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
 
-	dst->operation = src->operation;
 	dst->nr_segments = src->nr_segments;
 	dst->handle = src->handle;
 	dst->id = src->id;
 	dst->sector_number = src->sector_number;
-	if (src->operation == BLKIF_OP_DISCARD) {
+	if (operation == BLKIF_OP_DISCARD) {
 		struct blkif_request_discard *s = (void *)src;
 		struct blkif_request_discard *d = (void *)dst;
 		d->nr_sectors = s->nr_sectors;
@@ -93,16 +161,43 @@ static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_reque
 		dst->seg[i] = src->seg[i];
 }
 
-static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
+static inline void blkif_get_x86_32_req_indirect(blkif_request_indirect_t *dst, 
+									             blkif_x86_32_request_indirect_t *src)
 {
-	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+	int i, n;
+
+	dst->operation = src->operation;
+	dst->nr_segments = src->nr_segments;
+	dst->handle = src->handle;
+	dst->id = src->id;
+	dst->sector_number = src->sector_number;
+	n = INDIRECT_PAGES(dst->nr_segments);
+	for (i = 0; i < n; i++)
+		dst->indirect_grefs[i] = src->indirect_grefs[i];
+}
 
+static inline void blkif_get_x86_32_req_local(blkif_request_local_t *dst, 
+											  blkif_x86_32_request_t *src) 
+{
 	dst->operation = src->operation;
+	if (dst->operation == BLKIF_OP_INDIRECT) {
+		blkif_get_x86_32_req_indirect(&dst->u.indirect, &src->u.indirect);
+	} else {
+		blkif_get_x86_32_req_direct(&dst->u.direct, &src->u.direct, dst->operation);
+	}
+}
+
+static inline void blkif_get_x86_64_req_direct(blkif_request_direct_t *dst, 
+											   blkif_x86_64_request_direct_t *src,
+										       uint8_t operation)
+{
+	int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
 	dst->nr_segments = src->nr_segments;
 	dst->handle = src->handle;
 	dst->id = src->id;
 	dst->sector_number = src->sector_number;
-	if (src->operation == BLKIF_OP_DISCARD) {
+	if (operation == BLKIF_OP_DISCARD) {
 		struct blkif_request_discard *s = (void *)src;
 		struct blkif_request_discard *d = (void *)dst;
 		d->nr_sectors = s->nr_sectors;
@@ -116,4 +211,30 @@ static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_reque
 		dst->seg[i] = src->seg[i];
 }
 
+static inline void blkif_get_x86_64_req_indirect(blkif_request_indirect_t *dst, 
+									             blkif_x86_64_request_indirect_t *src)
+{
+	int i, n;
+
+	dst->operation = src->operation;
+	dst->nr_segments = src->nr_segments;
+	dst->handle = src->handle;
+	dst->id = src->id;
+	dst->sector_number = src->sector_number;
+	n = INDIRECT_PAGES(dst->nr_segments);
+	for (i = 0; i < n; i++)
+		dst->indirect_grefs[i] = src->indirect_grefs[i];
+}
+
+static inline void blkif_get_x86_64_req_local(blkif_request_local_t *dst, 
+											  blkif_x86_64_request_t *src) 
+{
+	dst->operation = src->operation;
+	if (dst->operation == BLKIF_OP_INDIRECT) {
+		blkif_get_x86_64_req_indirect(&dst->u.indirect, &src->u.indirect);
+	} else {
+		blkif_get_x86_64_req_direct(&dst->u.direct, &src->u.direct, dst->operation);
+	}
+}
+
 #endif /* __XEN_BLKIF_H__ */
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 37e14d1..e497cde 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -52,7 +52,6 @@ static int max_requests = 32;
 /* ------------------------------------------------------------- */
 
 #define BLOCK_SIZE  512
-#define IOCB_COUNT  (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2)
 
 struct PersistentGrant {
     void *page;
@@ -69,8 +68,8 @@ struct PersistentRegion {
 typedef struct PersistentRegion PersistentRegion;
 
 struct ioreq {
-    blkif_request_t     req;
-    int16_t             status;
+    blkif_request_local_t   req;
+    int16_t                 status;
 
     /* parsed request */
     off_t               start;
@@ -80,19 +79,22 @@ struct ioreq {
     uint8_t             mapped;
 
     /* grant mapping */
-    uint32_t            domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-    uint32_t            refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    uint32_t            domids[MAX_INDIRECT_SEGMENTS];
+    uint32_t            refs[MAX_INDIRECT_SEGMENTS];
     int                 prot;
-    void                *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    void                *page[MAX_INDIRECT_SEGMENTS];
     void                *pages;
     int                 num_unmap;
 
+    /* indirect request */
+    struct blkif_request_segment seg[MAX_INDIRECT_SEGMENTS];
+
     /* aio status */
     int                 aio_inflight;
     int                 aio_errors;
 
     struct XenBlkDev    *blkdev;
-    QLIST_ENTRY(ioreq)   list;
+    QLIST_ENTRY(ioreq)  list;
     BlockAcctCookie     acct;
 };
 
@@ -131,6 +133,9 @@ struct XenBlkDev {
     unsigned int        persistent_gnt_count;
     unsigned int        max_grants;
 
+    /* Indirect descriptors */
+    gboolean            feature_indirect;
+
     /* qemu block driver */
     DriveInfo           *dinfo;
     BlockBackend        *blk;
@@ -216,7 +221,11 @@ static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
         ioreq = g_malloc0(sizeof(*ioreq));
         ioreq->blkdev = blkdev;
         blkdev->requests_total++;
-        qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+        if (blkdev->feature_indirect) {
+            qemu_iovec_init(&ioreq->v, MAX_INDIRECT_SEGMENTS);
+        } else {
+            qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+        }
     } else {
         /* get one from freelist */
         ioreq = QLIST_FIRST(&blkdev->freelist);
@@ -254,6 +263,57 @@ static void ioreq_release(struct ioreq *ioreq, bool finish)
     }
 }
 
+static void ioreq_get_operation_and_nr_segments(struct ioreq *ioreq, 
+                                                uint8_t *operation, 
+                                                uint16_t *nseg)
+{
+    if (ioreq->req.operation == BLKIF_OP_INDIRECT) {
+        *operation = ioreq->req.u.indirect.operation;
+        *nseg = ioreq->req.u.indirect.nr_segments;
+    } else {
+        *operation = ioreq->req.operation;
+        *nseg = ioreq->req.u.direct.nr_segments;
+    }
+}
+
+static int ioreq_parse_indirect(struct XenBlkDev *blkdev,
+                                blkif_request_indirect_t *req, uint32_t domid,
+                                struct blkif_request_segment *seg) 
+{
+    void *pages;
+    struct blkif_request_segment *segments = NULL;
+    int i, j, nr_indirect_grefs;
+
+    nr_indirect_grefs = INDIRECT_PAGES(req->nr_segments);
+
+    pages = xc_gnttab_map_domain_grant_refs(blkdev->xendev.gnttabdev, 
+                                            nr_indirect_grefs, domid, 
+                                            req->indirect_grefs,
+                                            PROT_READ);
+    
+    if (pages == NULL) {
+        xen_be_printf(&blkdev->xendev, 0, "can't map indirect grant refs %s\n", 
+                      strerror(errno));
+        return -1;
+    }
+
+    for (i = 0, j = 0; j < req->nr_segments; j++) {
+        i = j % SEGS_PER_INDIRECT_FRAME;
+        if (i == 0) {
+            segments = pages + i/SEGS_PER_INDIRECT_FRAME * XC_PAGE_SIZE;
+        }
+        seg[j].gref = segments[i].gref;
+        seg[j].first_sect = segments[i].first_sect;
+        seg[j].last_sect = segments[i].last_sect;
+    }
+
+    if (xc_gnttab_munmap(blkdev->xendev.gnttabdev, pages, nr_indirect_grefs)) {
+        xen_be_printf(&blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+                      strerror(errno));
+    }
+
+    return 0;
+}
 /*
  * translate request into iovec + start offset
  * do sanity checks along the way
@@ -261,21 +321,21 @@ static void ioreq_release(struct ioreq *ioreq, bool finish)
 static int ioreq_parse(struct ioreq *ioreq)
 {
     struct XenBlkDev *blkdev = ioreq->blkdev;
+    uint8_t operation;
+    uint16_t nseg;
     uintptr_t mem;
     size_t len;
-    int i;
+    int i, r;
 
-    xen_be_printf(&blkdev->xendev, 3,
-                  "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
-                  ioreq->req.operation, ioreq->req.nr_segments,
-                  ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
-    switch (ioreq->req.operation) {
+    ioreq_get_operation_and_nr_segments(ioreq, &operation, &nseg);
+
+    switch (operation) {
     case BLKIF_OP_READ:
         ioreq->prot = PROT_WRITE; /* to memory */
         break;
     case BLKIF_OP_FLUSH_DISKCACHE:
         ioreq->presync = 1;
-        if (!ioreq->req.nr_segments) {
+        if (!nseg) {
             return 0;
         }
         /* fall through */
@@ -286,35 +346,53 @@ static int ioreq_parse(struct ioreq *ioreq)
         return 0;
     default:
         xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
-                      ioreq->req.operation);
+                      operation);
         goto err;
     };
 
-    if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
+    if (operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
         xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n");
         goto err;
     }
 
-    ioreq->start = ioreq->req.sector_number * blkdev->file_blk;
-    for (i = 0; i < ioreq->req.nr_segments; i++) {
-        if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+    if (ioreq->req.operation == BLKIF_OP_INDIRECT) {
+        if (nseg > MAX_INDIRECT_SEGMENTS) {
             xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
             goto err;
         }
-        if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
+        r = ioreq_parse_indirect(ioreq->blkdev, &ioreq->req.u.indirect, 
+                                 blkdev->xendev.dom, ioreq->seg);
+        if (r != 0) {
+            xen_be_printf(&blkdev->xendev, 0, 
+                                  "error: failed to map indirect segments\n");
+            goto err;
+        }
+        ioreq->start = ioreq->req.u.indirect.sector_number * blkdev->file_blk;
+    } else {
+        if (nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+            xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
+            goto err;
+        }
+        memcpy(ioreq->seg, ioreq->req.u.direct.seg, sizeof(struct blkif_request_segment)*nseg);
+        ioreq->start = ioreq->req.u.direct.sector_number * blkdev->file_blk;
+    }
+
+    for (i = 0; i < nseg; i++) {
+
+        if (ioreq->seg[i].first_sect > ioreq->seg[i].last_sect) {
             xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n");
             goto err;
         }
-        if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
+        if (ioreq->seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
             xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n");
             goto err;
         }
 
         ioreq->domids[i] = blkdev->xendev.dom;
-        ioreq->refs[i]   = ioreq->req.seg[i].gref;
+        ioreq->refs[i]   = ioreq->seg[i].gref;
 
-        mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
-        len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
+        mem = ioreq->seg[i].first_sect * blkdev->file_blk;
+        len = (ioreq->seg[i].last_sect - ioreq->seg[i].first_sect + 1) * blkdev->file_blk;
         qemu_iovec_add(&ioreq->v, (void*)mem, len);
     }
     if (ioreq->start + ioreq->v.size > blkdev->file_size) {
@@ -365,9 +443,9 @@ static void ioreq_unmap(struct ioreq *ioreq)
 static int ioreq_map(struct ioreq *ioreq)
 {
     XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
-    uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-    uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-    void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    uint32_t domids[MAX_INDIRECT_SEGMENTS];
+    uint32_t refs[MAX_INDIRECT_SEGMENTS];
+    void *page[MAX_INDIRECT_SEGMENTS];
     int i, j, new_maps = 0;
     PersistentGrant *grant;
     PersistentRegion *region;
@@ -505,10 +583,14 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
 static void qemu_aio_complete(void *opaque, int ret)
 {
     struct ioreq *ioreq = opaque;
+    uint8_t operation;    
+    uint16_t nseg;
+
+    ioreq_get_operation_and_nr_segments(ioreq, &operation, &nseg);
 
     if (ret != 0) {
         xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n",
-                      ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
+                      operation ? "read" : "write");
         ioreq->aio_errors++;
     }
 
@@ -531,10 +613,10 @@ static void qemu_aio_complete(void *opaque, int ret)
     ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
     ioreq_unmap(ioreq);
     ioreq_finish(ioreq);
-    switch (ioreq->req.operation) {
+    switch (operation) {
     case BLKIF_OP_WRITE:
     case BLKIF_OP_FLUSH_DISKCACHE:
-        if (!ioreq->req.nr_segments) {
+        if (!nseg) {
             break;
         }
     case BLKIF_OP_READ:
@@ -550,8 +632,12 @@ static void qemu_aio_complete(void *opaque, int ret)
 static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
 {
     struct XenBlkDev *blkdev = ioreq->blkdev;
+    uint8_t operation;    
+    uint16_t nseg;
 
-    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
+    ioreq_get_operation_and_nr_segments(ioreq, &operation, &nseg);
+
+    if (nseg && ioreq_map(ioreq) == -1) {
         goto err_no_map;
     }
 
@@ -561,7 +647,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
         return 0;
     }
 
-    switch (ioreq->req.operation) {
+    switch (operation) {
     case BLKIF_OP_READ:
         block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
                          ioreq->v.size, BLOCK_ACCT_READ);
@@ -572,7 +658,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
         break;
     case BLKIF_OP_WRITE:
     case BLKIF_OP_FLUSH_DISKCACHE:
-        if (!ioreq->req.nr_segments) {
+        if (!nseg) {
             break;
         }
 
@@ -617,8 +703,13 @@ static int blk_send_response_one(struct ioreq *ioreq)
     blkif_response_t  resp;
     void              *dst;
 
-    resp.id        = ioreq->req.id;
-    resp.operation = ioreq->req.operation;
+    if (ioreq->req.operation == BLKIF_OP_INDIRECT) {
+        resp.id        = ioreq->req.u.indirect.id;
+        resp.operation = ioreq->req.u.indirect.operation;
+    } else {        
+        resp.id        = ioreq->req.u.direct.id;
+        resp.operation = ioreq->req.operation;
+    }   
     resp.status    = ioreq->status;
 
     /* Place on the response ring for the relevant domain. */
@@ -683,11 +774,11 @@ static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_I
                sizeof(ioreq->req));
         break;
     case BLKIF_PROTOCOL_X86_32:
-        blkif_get_x86_32_req(&ioreq->req,
+        blkif_get_x86_32_req_local(&ioreq->req,
                              RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc));
         break;
     case BLKIF_PROTOCOL_X86_64:
-        blkif_get_x86_64_req(&ioreq->req,
+        blkif_get_x86_64_req_local(&ioreq->req,
                              RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc));
         break;
     }
@@ -756,6 +847,7 @@ static void blk_bh(void *opaque)
 static void blk_alloc(struct XenDevice *xendev)
 {
     struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    int max_segments = BLKIF_MAX_SEGMENTS_PER_REQUEST;
 
     QLIST_INIT(&blkdev->inflight);
     QLIST_INIT(&blkdev->finished);
@@ -764,8 +856,15 @@ static void blk_alloc(struct XenDevice *xendev)
     if (xen_mode != XEN_EMULATE) {
         batch_maps = 1;
     }
+    blkdev->feature_indirect = true;
+
+    if (blkdev->feature_indirect) {
+        max_segments = MAX_INDIRECT_SEGMENTS;
+    }
+
+    if (blkdev->feature_indirect)
     if (xc_gnttab_set_max_grants(xendev->gnttabdev,
-            MAX_GRANTS(max_requests, BLKIF_MAX_SEGMENTS_PER_REQUEST)) < 0) {
+            MAX_GRANTS(max_requests, max_segments)) < 0) {
         xen_be_printf(xendev, 0, "xc_gnttab_set_max_grants failed: %s\n",
                       strerror(errno));
     }
@@ -855,6 +954,10 @@ static int blk_init(struct XenDevice *xendev)
     xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1);
     xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1);
     xenstore_write_be_int(&blkdev->xendev, "info", info);
+    if (blkdev->feature_indirect) {
+        xenstore_write_be_int(&blkdev->xendev, "feature-max-indirect-segments", 
+                              MAX_INDIRECT_SEGMENTS);
+    }
 
     blk_parse_discard(blkdev);
 
@@ -1008,7 +1111,11 @@ static int blk_connect(struct XenDevice *xendev)
 
     if (blkdev->feature_persistent) {
         /* Init persistent grants */
-        blkdev->max_grants = max_requests * BLKIF_MAX_SEGMENTS_PER_REQUEST;
+        if (blkdev->feature_indirect) {
+            blkdev->max_grants = max_requests * MAX_INDIRECT_SEGMENTS;
+        } else {
+            blkdev->max_grants = max_requests * BLKIF_MAX_SEGMENTS_PER_REQUEST;
+        }
         blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp,
                                              NULL, NULL,
                                              batch_maps ?
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
index 3b4125e..6836f98 100644
--- a/include/hw/xen/xen_backend.h
+++ b/include/hw/xen/xen_backend.h
@@ -15,6 +15,8 @@ struct XenDevice;
 #define DEVOPS_FLAG_NEED_GNTDEV   1
 /* don't expect frontend doing correct state transitions (aka console quirk) */
 #define DEVOPS_FLAG_IGNORE_STATE  2
+/* */
+#define MAX_INDIRECT_SEGMENTS 32
 
 struct XenDevOps {
     size_t    size;
