ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c @ 6422:e24fd7012ffb

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 10:09:39 2005 +0000 (2005-08-25)
parents 2f20c2fce2c5 be5c24f2709c
children 4abd299ef2f6
line source
1 /* Xenbus code for blkif backend
2 Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <stdarg.h>
19 #include <linux/module.h>
20 #include <asm-xen/xenbus.h>
21 #include "common.h"
23 struct backend_info
24 {
25 struct xenbus_device *dev;
27 /* our communications channel */
28 blkif_t *blkif;
30 long int frontend_id;
31 long int pdev;
32 long int readonly;
34 /* watch back end for changes */
35 struct xenbus_watch backend_watch;
37 /* watch front end for changes */
38 struct xenbus_watch watch;
39 char *frontpath;
40 };
42 static int blkback_remove(struct xenbus_device *dev)
43 {
44 struct backend_info *be = dev->data;
46 if (be->watch.node)
47 unregister_xenbus_watch(&be->watch);
48 unregister_xenbus_watch(&be->backend_watch);
49 if (be->blkif)
50 blkif_put(be->blkif);
51 if (be->frontpath)
52 kfree(be->frontpath);
53 kfree(be);
54 return 0;
55 }
57 /* Front end tells us frame. */
58 static void frontend_changed(struct xenbus_watch *watch, const char *node)
59 {
60 unsigned long ring_ref;
61 unsigned int evtchn;
62 int err;
63 struct backend_info *be
64 = container_of(watch, struct backend_info, watch);
66 /* If other end is gone, delete ourself. */
67 if (node && !xenbus_exists(be->frontpath, "")) {
68 xenbus_rm(be->dev->nodename, "");
69 device_unregister(&be->dev->dev);
70 return;
71 }
72 if (be->blkif == NULL || be->blkif->status == CONNECTED)
73 return;
75 err = xenbus_gather(be->frontpath, "ring-ref", "%lu", &ring_ref,
76 "event-channel", "%u", &evtchn, NULL);
77 if (err) {
78 xenbus_dev_error(be->dev, err,
79 "reading %s/ring-ref and event-channel",
80 be->frontpath);
81 return;
82 }
84 /* Supply the information about the device the frontend needs */
85 err = xenbus_transaction_start(be->dev->nodename);
86 if (err) {
87 xenbus_dev_error(be->dev, err, "starting transaction");
88 return;
89 }
91 err = xenbus_printf(be->dev->nodename, "sectors", "%lu",
92 vbd_size(&be->blkif->vbd));
93 if (err) {
94 xenbus_dev_error(be->dev, err, "writing %s/sectors",
95 be->dev->nodename);
96 goto abort;
97 }
99 /* FIXME: use a typename instead */
100 err = xenbus_printf(be->dev->nodename, "info", "%u",
101 vbd_info(&be->blkif->vbd));
102 if (err) {
103 xenbus_dev_error(be->dev, err, "writing %s/info",
104 be->dev->nodename);
105 goto abort;
106 }
107 err = xenbus_printf(be->dev->nodename, "sector-size", "%lu",
108 vbd_secsize(&be->blkif->vbd));
109 if (err) {
110 xenbus_dev_error(be->dev, err, "writing %s/sector-size",
111 be->dev->nodename);
112 goto abort;
113 }
115 /* Map the shared frame, irq etc. */
116 err = blkif_map(be->blkif, ring_ref, evtchn);
117 if (err) {
118 xenbus_dev_error(be->dev, err, "mapping ring-ref %lu port %u",
119 ring_ref, evtchn);
120 goto abort;
121 }
123 xenbus_transaction_end(0);
124 xenbus_dev_ok(be->dev);
126 return;
128 abort:
129 xenbus_transaction_end(1);
130 }
132 /*
133 Setup supplies physical device.
134 We provide event channel and device details to front end.
135 Frontend supplies shared frame and event channel.
136 */
137 static void backend_changed(struct xenbus_watch *watch, const char *node)
138 {
139 int err;
140 char *p;
141 long int handle, pdev;
142 struct backend_info *be
143 = container_of(watch, struct backend_info, backend_watch);
144 struct xenbus_device *dev = be->dev;
146 err = xenbus_scanf(dev->nodename, "physical-device", "%li", &pdev);
147 if (XENBUS_EXIST_ERR(err))
148 return;
149 if (err < 0) {
150 xenbus_dev_error(dev, err, "reading physical-device");
151 return;
152 }
153 if (be->pdev && be->pdev != pdev) {
154 printk(KERN_WARNING
155 "changing physical-device not supported\n");
156 return;
157 }
158 be->pdev = pdev;
160 /* If there's a read-only node, we're read only. */
161 p = xenbus_read(dev->nodename, "read-only", NULL);
162 if (!IS_ERR(p)) {
163 be->readonly = 1;
164 kfree(p);
165 }
167 if (be->blkif == NULL) {
168 /* Front end dir is a number, which is used as the handle. */
169 p = strrchr(be->frontpath, '/') + 1;
170 handle = simple_strtoul(p, NULL, 0);
172 be->blkif = alloc_blkif(be->frontend_id);
173 if (IS_ERR(be->blkif)) {
174 err = PTR_ERR(be->blkif);
175 be->blkif = NULL;
176 xenbus_dev_error(dev, err, "creating block interface");
177 return;
178 }
180 err = vbd_create(be->blkif, handle, be->pdev, be->readonly);
181 if (err) {
182 xenbus_dev_error(dev, err, "creating vbd structure");
183 return;
184 }
186 /* Pass in NULL node to skip exist test. */
187 frontend_changed(&be->watch, NULL);
188 }
189 }
191 static int blkback_probe(struct xenbus_device *dev,
192 const struct xenbus_device_id *id)
193 {
194 struct backend_info *be;
195 char *frontend;
196 int err;
198 be = kmalloc(sizeof(*be), GFP_KERNEL);
199 if (!be) {
200 xenbus_dev_error(dev, -ENOMEM, "allocating backend structure");
201 return -ENOMEM;
202 }
203 memset(be, 0, sizeof(*be));
205 frontend = NULL;
206 err = xenbus_gather(dev->nodename,
207 "frontend-id", "%li", &be->frontend_id,
208 "frontend", NULL, &frontend,
209 NULL);
210 if (XENBUS_EXIST_ERR(err))
211 goto free_be;
212 if (err < 0) {
213 xenbus_dev_error(dev, err,
214 "reading %s/frontend or frontend-id",
215 dev->nodename);
216 goto free_be;
217 }
218 if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
219 /* If we can't get a frontend path and a frontend-id,
220 * then our bus-id is no longer valid and we need to
221 * destroy the backend device.
222 */
223 err = -ENOENT;
224 goto free_be;
225 }
227 be->dev = dev;
228 be->backend_watch.node = dev->nodename;
229 be->backend_watch.callback = backend_changed;
230 err = register_xenbus_watch(&be->backend_watch);
231 if (err) {
232 be->backend_watch.node = NULL;
233 xenbus_dev_error(dev, err, "adding backend watch on %s",
234 dev->nodename);
235 goto free_be;
236 }
238 be->frontpath = frontend;
239 be->watch.node = be->frontpath;
240 be->watch.callback = frontend_changed;
241 err = register_xenbus_watch(&be->watch);
242 if (err) {
243 be->watch.node = NULL;
244 xenbus_dev_error(dev, err,
245 "adding frontend watch on %s",
246 be->frontpath);
247 goto free_be;
248 }
250 dev->data = be;
252 backend_changed(&be->backend_watch, dev->nodename);
253 return 0;
255 free_be:
256 if (be->backend_watch.node)
257 unregister_xenbus_watch(&be->backend_watch);
258 if (frontend)
259 kfree(frontend);
260 kfree(be);
261 return err;
262 }
264 static struct xenbus_device_id blkback_ids[] = {
265 { "vbd" },
266 { "" }
267 };
269 static struct xenbus_driver blkback = {
270 .name = "vbd",
271 .owner = THIS_MODULE,
272 .ids = blkback_ids,
273 .probe = blkback_probe,
274 .remove = blkback_remove,
275 };
277 void blkif_xenbus_init(void)
278 {
279 xenbus_register_backend(&blkback);
280 }