xen-vtx-unstable

view linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 9ead08216805 f59e0163540e
children e7c7196fa329 8ca0f98ba8e2
line source
1 /* Xenbus code for blkif tap
3 A Warfield.
5 Hastily modified from the oroginal backend code:
7 Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
24 #include <stdarg.h>
25 #include <linux/module.h>
26 #include <asm-xen/xenbus.h>
27 #include "common.h"
29 struct backend_info
30 {
31 struct xenbus_device *dev;
33 /* our communications channel */
34 blkif_t *blkif;
36 long int frontend_id;
38 /* watch back end for changes */
39 struct xenbus_watch backend_watch;
41 /* watch front end for changes */
42 struct xenbus_watch watch;
43 char *frontpath;
44 };
46 static int blkback_remove(struct xenbus_device *dev)
47 {
48 struct backend_info *be = dev->data;
50 if (be->watch.node)
51 unregister_xenbus_watch(&be->watch);
52 unregister_xenbus_watch(&be->backend_watch);
53 if (be->blkif)
54 blkif_put(be->blkif);
55 if (be->frontpath)
56 kfree(be->frontpath);
57 kfree(be);
58 return 0;
59 }
61 /* Front end tells us frame. */
62 static void frontend_changed(struct xenbus_watch *watch, const char *node)
63 {
64 unsigned long ring_ref;
65 unsigned int evtchn;
66 int err;
67 struct backend_info *be
68 = container_of(watch, struct backend_info, watch);
70 /* If other end is gone, delete ourself. */
71 if (node && !xenbus_exists(be->frontpath, "")) {
72 xenbus_rm(be->dev->nodename, "");
73 device_unregister(&be->dev->dev);
74 return;
75 }
76 if (be->blkif == NULL || be->blkif->status == CONNECTED)
77 return;
79 err = xenbus_gather(be->frontpath, "ring-ref", "%lu", &ring_ref,
80 "event-channel", "%u", &evtchn, NULL);
81 if (err) {
82 xenbus_dev_error(be->dev, err,
83 "reading %s/ring-ref and event-channel",
84 be->frontpath);
85 return;
86 }
88 /* Map the shared frame, irq etc. */
89 err = blkif_map(be->blkif, ring_ref, evtchn);
90 if (err) {
91 xenbus_dev_error(be->dev, err, "mapping ring-ref %lu port %u",
92 ring_ref, evtchn);
93 goto abort;
94 }
96 xenbus_dev_ok(be->dev);
98 return;
100 abort:
101 xenbus_transaction_end(1);
102 }
104 /*
105 Setup supplies physical device.
106 We provide event channel and device details to front end.
107 Frontend supplies shared frame and event channel.
108 */
109 static void backend_changed(struct xenbus_watch *watch, const char *node)
110 {
111 int err;
112 char *p;
113 long int handle;
114 struct backend_info *be
115 = container_of(watch, struct backend_info, backend_watch);
116 struct xenbus_device *dev = be->dev;
118 if (be->blkif == NULL) {
119 /* Front end dir is a number, which is used as the handle. */
120 p = strrchr(be->frontpath, '/') + 1;
121 handle = simple_strtoul(p, NULL, 0);
123 be->blkif = alloc_blkif(be->frontend_id);
124 if (IS_ERR(be->blkif)) {
125 err = PTR_ERR(be->blkif);
126 be->blkif = NULL;
127 xenbus_dev_error(dev, err, "creating block interface");
128 return;
129 }
131 /* Pass in NULL node to skip exist test. */
132 frontend_changed(&be->watch, NULL);
133 }
134 }
136 static int blkback_probe(struct xenbus_device *dev,
137 const struct xenbus_device_id *id)
138 {
139 struct backend_info *be;
140 char *frontend;
141 int err;
143 be = kmalloc(sizeof(*be), GFP_KERNEL);
144 if (!be) {
145 xenbus_dev_error(dev, -ENOMEM, "allocating backend structure");
146 return -ENOMEM;
147 }
148 memset(be, 0, sizeof(*be));
150 frontend = NULL;
151 err = xenbus_gather(dev->nodename,
152 "frontend-id", "%li", &be->frontend_id,
153 "frontend", NULL, &frontend,
154 NULL);
155 if (XENBUS_EXIST_ERR(err))
156 goto free_be;
157 if (err < 0) {
158 xenbus_dev_error(dev, err,
159 "reading %s/frontend or frontend-id",
160 dev->nodename);
161 goto free_be;
162 }
163 if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
164 /* If we can't get a frontend path and a frontend-id,
165 * then our bus-id is no longer valid and we need to
166 * destroy the backend device.
167 */
168 err = -ENOENT;
169 goto free_be;
170 }
172 be->dev = dev;
173 be->backend_watch.node = dev->nodename;
174 be->backend_watch.callback = backend_changed;
175 err = register_xenbus_watch(&be->backend_watch);
176 if (err) {
177 be->backend_watch.node = NULL;
178 xenbus_dev_error(dev, err, "adding backend watch on %s",
179 dev->nodename);
180 goto free_be;
181 }
183 be->frontpath = frontend;
184 be->watch.node = be->frontpath;
185 be->watch.callback = frontend_changed;
186 err = register_xenbus_watch(&be->watch);
187 if (err) {
188 be->watch.node = NULL;
189 xenbus_dev_error(dev, err,
190 "adding frontend watch on %s",
191 be->frontpath);
192 goto free_be;
193 }
195 dev->data = be;
197 backend_changed(&be->backend_watch, dev->nodename);
198 return 0;
200 free_be:
201 if (be->backend_watch.node)
202 unregister_xenbus_watch(&be->backend_watch);
203 if (frontend)
204 kfree(frontend);
205 kfree(be);
206 return err;
207 }
209 static struct xenbus_device_id blkback_ids[] = {
210 { "vbd" },
211 { "" }
212 };
214 static struct xenbus_driver blkback = {
215 .name = "vbd",
216 .owner = THIS_MODULE,
217 .ids = blkback_ids,
218 .probe = blkback_probe,
219 .remove = blkback_remove,
220 };
222 void blkif_xenbus_init(void)
223 {
224 xenbus_register_backend(&blkback);
225 }