- 2.6.17 port work build breaks, but the patch set is relativly stable
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / blktap / interface.c
1 /******************************************************************************
2  * arch/xen/drivers/blkif/backend/interface.c
3  * 
4  * Block-device interface management.
5  * 
6  * Copyright (c) 2004, Keir Fraser
7  */
8
9 #include "common.h"
10 #include <xen/evtchn.h>
11
12 static kmem_cache_t *blkif_cachep;
13
14 blkif_t *alloc_blkif(domid_t domid)
15 {
16         blkif_t *blkif;
17
18         blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
19         if (!blkif)
20                 return ERR_PTR(-ENOMEM);
21
22         memset(blkif, 0, sizeof(*blkif));
23         blkif->domid = domid;
24         blkif->status = DISCONNECTED;
25         spin_lock_init(&blkif->blk_ring_lock);
26         atomic_set(&blkif->refcnt, 1);
27
28         return blkif;
29 }
30
31 static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
32 {
33         struct gnttab_map_grant_ref op;
34         int ret;
35
36         op.host_addr = (unsigned long)blkif->blk_ring_area->addr;
37         op.flags     = GNTMAP_host_map;
38         op.ref       = shared_page;
39         op.dom       = blkif->domid;
40
41         lock_vm_area(blkif->blk_ring_area);
42         ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
43         unlock_vm_area(blkif->blk_ring_area);
44         BUG_ON(ret);
45
46         if (op.status) {
47                 DPRINTK(" Grant table operation failure !\n");
48                 return op.status;
49         }
50
51         blkif->shmem_ref    = shared_page;
52         blkif->shmem_handle = op.handle;
53
54         return 0;
55 }
56
57 static void unmap_frontend_page(blkif_t *blkif)
58 {
59         struct gnttab_unmap_grant_ref op;
60         int ret;
61
62         op.host_addr    = (unsigned long)blkif->blk_ring_area->addr;
63         op.handle       = blkif->shmem_handle;
64         op.dev_bus_addr = 0;
65
66         lock_vm_area(blkif->blk_ring_area);
67         ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
68         unlock_vm_area(blkif->blk_ring_area);
69         BUG_ON(ret);
70 }
71
72 int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
73 {
74         blkif_sring_t *sring;
75         int err;
76         evtchn_op_t op = {
77                 .cmd = EVTCHNOP_bind_interdomain,
78                 .u.bind_interdomain.remote_dom  = blkif->domid,
79                 .u.bind_interdomain.remote_port = evtchn };
80
81         if ((blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
82                 return -ENOMEM;
83
84         err = map_frontend_page(blkif, shared_page);
85         if (err) {
86                 free_vm_area(blkif->blk_ring_area);
87                 return err;
88         }
89
90         err = HYPERVISOR_event_channel_op(&op);
91         if (err) {
92                 unmap_frontend_page(blkif);
93                 free_vm_area(blkif->blk_ring_area);
94                 return err;
95         }
96
97         blkif->evtchn = op.u.bind_interdomain.local_port;
98
99         sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
100         BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
101
102         blkif->irq = bind_evtchn_to_irqhandler(
103                 blkif->evtchn, blkif_be_int, 0, "blkif-backend", blkif);
104
105         blkif->status = CONNECTED;
106
107         return 0;
108 }
109
110 static void free_blkif(void *arg)
111 {
112         blkif_t *blkif = (blkif_t *)arg;
113
114         if (blkif->irq)
115                 unbind_from_irqhandler(blkif->irq, blkif);
116
117         if (blkif->blk_ring.sring) {
118                 unmap_frontend_page(blkif);
119                 free_vm_area(blkif->blk_ring_area);
120                 blkif->blk_ring.sring = NULL;
121         }
122
123         kmem_cache_free(blkif_cachep, blkif);
124 }
125
126 void free_blkif_callback(blkif_t *blkif)
127 {
128         INIT_WORK(&blkif->free_work, free_blkif, (void *)blkif);
129         schedule_work(&blkif->free_work);
130 }
131
132 void __init blkif_interface_init(void)
133 {
134         blkif_cachep = kmem_cache_create(
135                 "blkif_cache", sizeof(blkif_t), 0, 0, NULL, NULL);
136 }
137
138 /*
139  * Local variables:
140  *  c-file-style: "linux"
141  *  indent-tabs-mode: t
142  *  c-indent-level: 8
143  *  c-basic-offset: 8
144  *  tab-width: 8
145  * End:
146  */