+ if (!blkdev) {
+ return;
+ }
+
+ aio_context_acquire(blkdev->ctx);
+ blk_set_aio_context(blkdev->blk, qemu_get_aio_context());
+ aio_context_release(blkdev->ctx);
+
+ xendev = blkdev->xendev;
+
+ if (blkdev->event_channel) {
+ Error *local_err = NULL;
+
+ xen_device_unbind_event_channel(xendev, blkdev->event_channel,
+ &local_err);
+ blkdev->event_channel = NULL;
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ }
+
+ if (blkdev->sring) {
+ Error *local_err = NULL;
+
+ xen_device_unmap_grant_refs(xendev, blkdev->sring,
+ blkdev->nr_ring_ref, &local_err);
+ blkdev->sring = NULL;
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ }
+
+ g_free(blkdev->ring_ref);
+ blkdev->ring_ref = NULL;
+}
+
+void xen_block_dataplane_start(struct XenBlkDev *blkdev,
+ const unsigned int ring_ref[],
+ unsigned int nr_ring_ref,
+ unsigned int event_channel,
+ unsigned int protocol,
+ Error **errp)
+{
+ XenDevice *xendev = blkdev->xendev;
+ Error *local_err = NULL;
+ unsigned int ring_size;
+ unsigned int i;
+
+ blkdev->nr_ring_ref = nr_ring_ref;
+ blkdev->ring_ref = g_new(unsigned int, nr_ring_ref);
+
+ for (i = 0; i < nr_ring_ref; i++) {
+ blkdev->ring_ref[i] = ring_ref[i];
+ }
+
+ blkdev->protocol = protocol;
+
+ ring_size = XC_PAGE_SIZE * blkdev->nr_ring_ref;
+ switch (blkdev->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ {
+ blkdev->max_requests = __CONST_RING_SIZE(blkif, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_32:
+ {
+ blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_64:
+ {
+ blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size);
+ break;
+ }
+ default:
+ error_setg(errp, "unknown protocol %u", blkdev->protocol);
+ return;
+ }
+
+ xen_device_set_max_grant_refs(xendev, blkdev->nr_ring_ref,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto stop;
+ }
+
+ blkdev->sring = xen_device_map_grant_refs(xendev,
+ blkdev->ring_ref,
+ blkdev->nr_ring_ref,
+ PROT_READ | PROT_WRITE,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto stop;
+ }
+
+ switch (blkdev->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ {
+ blkif_sring_t *sring_native = blkdev->sring;
+
+ BACK_RING_INIT(&blkdev->rings.native, sring_native, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_32:
+ {
+ blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
+
+ BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32,
+ ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_64:
+ {
+ blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
+
+ BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64,
+ ring_size);
+ break;
+ }
+ }
+
+ blkdev->event_channel =
+ xen_device_bind_event_channel(xendev, event_channel,
+ blk_event, blkdev,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto stop;
+ }
+
+ aio_context_acquire(blkdev->ctx);
+ blk_set_aio_context(blkdev->blk, blkdev->ctx);
+ aio_context_release(blkdev->ctx);
+ return;
+
+stop:
+ xen_block_dataplane_stop(blkdev);