ia64/linux-2.6.18-xen.hg

view drivers/xen/scsiback/interface.c @ 562:66faefe721eb

pvSCSI backend driver

Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jun 02 09:58:27 2008 +0100 (2008-06-02)
parents
children 920abc7b20ac
line source
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 */
33 #include <scsi/scsi.h>
34 #include <scsi/scsi_host.h>
35 #include <scsi/scsi_device.h>
36 #include "common.h"
38 #include <xen/evtchn.h>
39 #include <linux/kthread.h>
42 static kmem_cache_t *scsiback_cachep;
44 struct vscsibk_info *vscsibk_info_alloc(domid_t domid)
45 {
46 struct vscsibk_info *info;
48 info = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL);
49 if (!info)
50 return ERR_PTR(-ENOMEM);
52 memset(info, 0, sizeof(*info));
53 info->domid = domid;
54 spin_lock_init(&info->ring_lock);
55 atomic_set(&info->refcnt, 1);
56 init_waitqueue_head(&info->wq);
57 init_waitqueue_head(&info->waiting_to_free);
59 return info;
60 }
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;
68 gnttab_set_map_op(&op, (unsigned long)info->ring_area->addr,
69 GNTMAP_host_map, ring_ref,
70 info->domid);
72 err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
73 BUG_ON(err);
75 if (op.status) {
76 printk(KERN_ERR "scsiback: Grant table operation failure !\n");
77 return op.status;
78 }
80 info->shmem_ref = ring_ref;
81 info->shmem_handle = op.handle;
83 return 0;
84 }
86 static void unmap_frontend_page(struct vscsibk_info *info)
87 {
88 struct gnttab_unmap_grant_ref op;
89 int err;
91 gnttab_set_unmap_op(&op, (unsigned long)info->ring_area->addr,
92 GNTMAP_host_map, info->shmem_handle);
94 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
95 BUG_ON(err);
97 }
99 int scsiback_init_sring(struct vscsibk_info *info,
100 unsigned long ring_ref, unsigned int evtchn)
101 {
102 struct vscsiif_sring *sring;
103 int err;
105 if (info->irq) {
106 printk(KERN_ERR "scsiback: Already connected through?\n");
107 return 0;
108 }
110 info->ring_area = alloc_vm_area(PAGE_SIZE);
111 if (!info)
112 return -ENOMEM;
114 err = map_frontend_page(info, ring_ref);
115 if (err)
116 goto free_vm;
118 sring = (struct vscsiif_sring *) info->ring_area->addr;
119 BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
121 err = bind_interdomain_evtchn_to_irqhandler(
122 info->domid, evtchn,
123 scsiback_intr, 0, "vscsiif-backend", info);
125 if (err < 0)
126 goto unmap_page;
128 info->irq = err;
130 return 0;
132 unmap_page:
133 unmap_frontend_page(info);
134 free_vm:
135 free_vm_area(info->ring_area);
137 return err;
138 }
140 void scsiback_disconnect(struct vscsibk_info *info)
141 {
142 if (info->kthread) {
143 kthread_stop(info->kthread);
144 info->kthread = NULL;
145 }
147 atomic_dec(&info->refcnt);
148 wait_event(info->waiting_to_free, atomic_read(&info->refcnt) == 0);
149 atomic_inc(&info->refcnt);
151 if (info->irq) {
152 unbind_from_irqhandler(info->irq, info);
153 info->irq = 0;
154 }
156 if (info->ring.sring) {
157 unmap_frontend_page(info);
158 free_vm_area(info->ring_area);
159 info->ring.sring = NULL;
160 }
161 }
163 void scsiback_free(struct vscsibk_info *info)
164 {
165 if (atomic_dec_and_test(&info->refcnt))
166 kmem_cache_free(scsiback_cachep, info);
167 }
169 int __init scsiback_interface_init(void)
170 {
171 scsiback_cachep = kmem_cache_create("vscsiif_cache",
172 sizeof(struct vscsibk_info), 0, 0, NULL, NULL);
173 if (!scsiback_cachep) {
174 printk(KERN_ERR "scsiback: can't init scsi cache\n");
175 return -ENOMEM;
176 }
178 return 0;
179 }
181 void __exit scsiback_interface_exit(void)
182 {
183 kmem_cache_destroy(scsiback_cachep);
184 }