Added patch headers.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / scsiback / interface.c
1 /*
2  * interface management.
3  *
4  * Copyright (c) 2008, FUJITSU Limited
5  *
6  * Based on the blkback driver code.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version 2
10  * as published by the Free Software Foundation; or, when distributed
11  * separately from the Linux kernel or incorporated into other
12  * software packages, subject to the following license:
13  * 
14  * Permission is hereby granted, free of charge, to any person obtaining a copy
15  * of this source file (the "Software"), to deal in the Software without
16  * restriction, including without limitation the rights to use, copy, modify,
17  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18  * and to permit persons to whom the Software is furnished to do so, subject to
19  * the following conditions:
20  * 
21  * The above copyright notice and this permission notice shall be included in
22  * all copies or substantial portions of the Software.
23  * 
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * IN THE SOFTWARE.
31  */
32
33 #include <scsi/scsi.h>
34 #include <scsi/scsi_host.h>
35 #include <scsi/scsi_device.h>
36 #include "common.h"
37
38 #include <xen/evtchn.h>
39 #include <linux/kthread.h>
40 #include <linux/delay.h>
41
42
43 static struct kmem_cache *scsiback_cachep;
44
45 struct vscsibk_info *vscsibk_info_alloc(domid_t domid)
46 {
47         struct vscsibk_info *info;
48
49         info = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL|__GFP_ZERO);
50         if (!info)
51                 return ERR_PTR(-ENOMEM);
52
53         info->domid = domid;
54         spin_lock_init(&info->ring_lock);
55         atomic_set(&info->nr_unreplied_reqs, 0);
56         init_waitqueue_head(&info->wq);
57         init_waitqueue_head(&info->waiting_to_free);
58
59         return info;
60 }
61
62 static int map_frontend_page( struct vscsibk_info *info,
63                                 unsigned long ring_ref)
64 {
65         struct gnttab_map_grant_ref op;
66         int err;
67
68         gnttab_set_map_op(&op, (unsigned long)info->ring_area->addr,
69                                 GNTMAP_host_map, ring_ref,
70                                 info->domid);
71
72     do {
73             err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
74             BUG_ON(err);
75         msleep(10);
76     } while(op.status == GNTST_eagain);
77
78         if (op.status) {
79                 printk(KERN_ERR "scsiback: Grant table operation failure !\n");
80                 return op.status;
81         }
82
83         info->shmem_ref    = ring_ref;
84         info->shmem_handle = op.handle;
85
86         return (GNTST_okay);
87 }
88
89 static void unmap_frontend_page(struct vscsibk_info *info)
90 {
91         struct gnttab_unmap_grant_ref op;
92         int err;
93
94         gnttab_set_unmap_op(&op, (unsigned long)info->ring_area->addr,
95                                 GNTMAP_host_map, info->shmem_handle);
96
97         err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
98         BUG_ON(err);
99
100 }
101
102 int scsiback_init_sring(struct vscsibk_info *info,
103                 unsigned long ring_ref, unsigned int evtchn)
104 {
105         struct vscsiif_sring *sring;
106         int err;
107
108         if (info->irq) {
109                 printk(KERN_ERR "scsiback: Already connected through?\n");
110                 return -1;
111         }
112
113         info->ring_area = alloc_vm_area(PAGE_SIZE);
114         if (!info)
115                 return -ENOMEM;
116
117         err = map_frontend_page(info, ring_ref);
118         if (err)
119                 goto free_vm;
120
121         sring = (struct vscsiif_sring *) info->ring_area->addr;
122         BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
123
124         err = bind_interdomain_evtchn_to_irqhandler(
125                         info->domid, evtchn,
126                         scsiback_intr, 0, "vscsiif-backend", info);
127
128         if (err < 0)
129                 goto unmap_page;
130                 
131         info->irq = err;
132
133         return 0;
134
135 unmap_page:
136         unmap_frontend_page(info);
137 free_vm:
138         free_vm_area(info->ring_area);
139
140         return err;
141 }
142
143 void scsiback_disconnect(struct vscsibk_info *info)
144 {
145         if (info->kthread) {
146                 kthread_stop(info->kthread);
147                 info->kthread = NULL;
148         }
149
150         wait_event(info->waiting_to_free, 
151                 atomic_read(&info->nr_unreplied_reqs) == 0);
152
153         if (info->irq) {
154                 unbind_from_irqhandler(info->irq, info);
155                 info->irq = 0;
156         }
157
158         if (info->ring.sring) {
159                 unmap_frontend_page(info);
160                 free_vm_area(info->ring_area);
161                 info->ring.sring = NULL;
162         }
163 }
164
165 void scsiback_free(struct vscsibk_info *info)
166 {
167         kmem_cache_free(scsiback_cachep, info);
168 }
169
170 int __init scsiback_interface_init(void)
171 {
172         scsiback_cachep = kmem_cache_create("vscsiif_cache",
173                 sizeof(struct vscsibk_info), 0, 0, NULL);
174         if (!scsiback_cachep) {
175                 printk(KERN_ERR "scsiback: can't init scsi cache\n");
176                 return -ENOMEM;
177         }
178         
179         return 0;
180 }
181
182 void scsiback_interface_exit(void)
183 {
184         kmem_cache_destroy(scsiback_cachep);
185 }