- patches.rt/0001-sched-count-of-queued-RT-tasks.patch: Delete.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / xenbus / xenbus_probe_backend.c
1 /******************************************************************************
2  * Talks to Xen Store to figure out what devices we have (backend half).
3  *
4  * Copyright (C) 2005 Rusty Russell, IBM Corporation
5  * Copyright (C) 2005 Mike Wray, Hewlett-Packard
6  * Copyright (C) 2005, 2006 XenSource Ltd
7  * Copyright (C) 2007 Solarflare Communications, Inc.
8  * 
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License version 2
11  * as published by the Free Software Foundation; or, when distributed
12  * separately from the Linux kernel or incorporated into other
13  * software packages, subject to the following license:
14  * 
15  * Permission is hereby granted, free of charge, to any person obtaining a copy
16  * of this source file (the "Software"), to deal in the Software without
17  * restriction, including without limitation the rights to use, copy, modify,
18  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
19  * and to permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  * 
22  * The above copyright notice and this permission notice shall be included in
23  * all copies or substantial portions of the Software.
24  * 
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31  * IN THE SOFTWARE.
32  */
33
34 #define DPRINTK(fmt, args...)                           \
35         pr_debug("xenbus_probe (%s:%d) " fmt ".\n",     \
36                  __FUNCTION__, __LINE__, ##args)
37
38 #include <linux/kernel.h>
39 #include <linux/err.h>
40 #include <linux/string.h>
41 #include <linux/ctype.h>
42 #include <linux/fcntl.h>
43 #include <linux/mm.h>
44 #include <linux/notifier.h>
45
46 #include <asm/io.h>
47 #include <asm/page.h>
48 #include <asm/maddr.h>
49 #include <asm/pgtable.h>
50 #include <asm/hypervisor.h>
51 #include <xen/xenbus.h>
52 #include <xen/xen_proc.h>
53 #include <xen/evtchn.h>
54 #include <xen/features.h>
55
56 #include "xenbus_comms.h"
57 #include "xenbus_probe.h"
58
59 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
60 #include <xen/platform-compat.h>
61 #endif
62
63 static int xenbus_uevent_backend(struct device *dev, struct kobj_uevent_env *env);
64 static int xenbus_probe_backend(const char *type, const char *domid);
65
66 extern int read_otherend_details(struct xenbus_device *xendev,
67                                  char *id_node, char *path_node);
68
69 static int read_frontend_details(struct xenbus_device *xendev)
70 {
71         return read_otherend_details(xendev, "frontend-id", "frontend");
72 }
73
74 /* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
75 static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
76 {
77         int domid, err;
78         const char *devid, *type, *frontend;
79         unsigned int typelen;
80
81         type = strchr(nodename, '/');
82         if (!type)
83                 return -EINVAL;
84         type++;
85         typelen = strcspn(type, "/");
86         if (!typelen || type[typelen] != '/')
87                 return -EINVAL;
88
89         devid = strrchr(nodename, '/') + 1;
90
91         err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
92                             "frontend", NULL, &frontend,
93                             NULL);
94         if (err)
95                 return err;
96         if (strlen(frontend) == 0)
97                 err = -ERANGE;
98         if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
99                 err = -ENOENT;
100         kfree(frontend);
101
102         if (err)
103                 return err;
104
105         if (snprintf(bus_id, BUS_ID_SIZE,
106                      "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
107                 return -ENOSPC;
108         return 0;
109 }
110
111 static struct xen_bus_type xenbus_backend = {
112         .root = "backend",
113         .levels = 3,            /* backend/type/<frontend>/<id> */
114         .get_bus_id = backend_bus_id,
115         .probe = xenbus_probe_backend,
116         .error = -ENODEV,
117         .bus = {
118                 .name     = "xen-backend",
119                 .match    = xenbus_match,
120                 .probe    = xenbus_dev_probe,
121                 .remove   = xenbus_dev_remove,
122 //              .shutdown = xenbus_dev_shutdown,
123                 .uevent   = xenbus_uevent_backend,
124         },
125         .dev = {
126                 .bus_id = "xen-backend",
127         },
128 };
129
130 static int xenbus_uevent_backend(struct device *dev, struct kobj_uevent_env *env)
131 {
132         struct xenbus_device *xdev;
133         struct xenbus_driver *drv;
134
135         DPRINTK("");
136
137         if (dev == NULL)
138                 return -ENODEV;
139
140         xdev = to_xenbus_device(dev);
141         if (xdev == NULL)
142                 return -ENODEV;
143
144         /* stuff we want to pass to /sbin/hotplug */
145         add_uevent_var(env, "XENBUS_TYPE=%s", xdev->devicetype);
146
147         add_uevent_var(env, "XENBUS_PATH=%s", xdev->nodename);
148
149         add_uevent_var(env, "XENBUS_BASE_PATH=%s", xenbus_backend.root);
150
151         if (dev->driver) {
152                 drv = to_xenbus_driver(dev->driver);
153                 if (drv && drv->uevent)
154                         return drv->uevent(xdev, env);
155         }
156
157         return 0;
158 }
159
160 int __xenbus_register_backend(struct xenbus_driver *drv,
161                                struct module *owner, const char *mod_name)
162 {
163         drv->read_otherend_details = read_frontend_details;
164
165         return xenbus_register_driver_common(drv, &xenbus_backend,
166                                              owner, mod_name);
167 }
168 EXPORT_SYMBOL_GPL(__xenbus_register_backend);
169
170 /* backend/<typename>/<frontend-uuid>/<name> */
171 static int xenbus_probe_backend_unit(const char *dir,
172                                      const char *type,
173                                      const char *name)
174 {
175         char *nodename;
176         int err;
177
178         nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
179         if (!nodename)
180                 return -ENOMEM;
181
182         DPRINTK("%s\n", nodename);
183
184         err = xenbus_probe_node(&xenbus_backend, type, nodename);
185         kfree(nodename);
186         return err;
187 }
188
189 /* backend/<typename>/<frontend-domid> */
190 static int xenbus_probe_backend(const char *type, const char *domid)
191 {
192         char *nodename;
193         int err = 0;
194         char **dir;
195         unsigned int i, dir_n = 0;
196
197         DPRINTK("");
198
199         nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_backend.root, type, domid);
200         if (!nodename)
201                 return -ENOMEM;
202
203         dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
204         if (IS_ERR(dir)) {
205                 kfree(nodename);
206                 return PTR_ERR(dir);
207         }
208
209         for (i = 0; i < dir_n; i++) {
210                 err = xenbus_probe_backend_unit(nodename, type, dir[i]);
211                 if (err)
212                         break;
213         }
214         kfree(dir);
215         kfree(nodename);
216         return err;
217 }
218
219 static void backend_changed(struct xenbus_watch *watch,
220                             const char **vec, unsigned int len)
221 {
222         DPRINTK("");
223
224         xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
225 }
226
227 static struct xenbus_watch be_watch = {
228         .node = "backend",
229         .callback = backend_changed,
230 };
231
232 void xenbus_backend_suspend(int (*fn)(struct device *, void *))
233 {
234         DPRINTK("");
235         if (!xenbus_backend.error)
236                 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
237 }
238
239 void xenbus_backend_resume(int (*fn)(struct device *, void *))
240 {
241         DPRINTK("");
242         if (!xenbus_backend.error)
243                 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
244 }
245
246 void xenbus_backend_probe_and_watch(void)
247 {
248         xenbus_probe_devices(&xenbus_backend);
249         register_xenbus_watch(&be_watch);
250 }
251
252 void xenbus_backend_bus_register(void)
253 {
254         xenbus_backend.error = bus_register(&xenbus_backend.bus);
255         if (xenbus_backend.error)
256                 printk(KERN_WARNING
257                        "XENBUS: Error registering backend bus: %i\n",
258                        xenbus_backend.error);
259 }
260
261 void xenbus_backend_device_register(void)
262 {
263         if (xenbus_backend.error)
264                 return;
265
266         xenbus_backend.error = device_register(&xenbus_backend.dev);
267         if (xenbus_backend.error) {
268                 bus_unregister(&xenbus_backend.bus);
269                 printk(KERN_WARNING
270                        "XENBUS: Error registering backend device: %i\n",
271                        xenbus_backend.error);
272         }
273 }
274
275 int xenbus_for_each_backend(void *arg, int (*fn)(struct device *, void *))
276 {
277         return bus_for_each_dev(&xenbus_backend.bus, NULL, arg, fn);
278 }
279 EXPORT_SYMBOL_GPL(xenbus_for_each_backend);