ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe_backend.c @ 13665:140afd7a5462

merge with xen-unstable.hg
author awilliam@xenbuild2.aw
date Sat Jan 27 14:07:19 2007 -0700 (2007-01-27)
parents c242b6d6a64a
children 32f532e6c054
line source
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 *
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 #define DPRINTK(fmt, args...) \
34 pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \
35 __FUNCTION__, __LINE__, ##args)
37 #include <linux/kernel.h>
38 #include <linux/err.h>
39 #include <linux/string.h>
40 #include <linux/ctype.h>
41 #include <linux/fcntl.h>
42 #include <linux/mm.h>
43 #include <linux/notifier.h>
44 #include <linux/kthread.h>
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 #include <xen/hvm.h>
57 #include "xenbus_comms.h"
58 #include "xenbus_probe.h"
60 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
61 #include <xen/platform-compat.h>
62 #endif
64 static int xenbus_uevent_backend(struct device *dev, char **envp,
65 int num_envp, char *buffer, int buffer_size);
66 static int xenbus_probe_backend(const char *type, const char *domid);
68 extern int read_otherend_details(struct xenbus_device *xendev,
69 char *id_node, char *path_node);
71 static int read_frontend_details(struct xenbus_device *xendev)
72 {
73 return read_otherend_details(xendev, "frontend-id", "frontend");
74 }
76 /* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
77 static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
78 {
79 int domid, err;
80 const char *devid, *type, *frontend;
81 unsigned int typelen;
83 type = strchr(nodename, '/');
84 if (!type)
85 return -EINVAL;
86 type++;
87 typelen = strcspn(type, "/");
88 if (!typelen || type[typelen] != '/')
89 return -EINVAL;
91 devid = strrchr(nodename, '/') + 1;
93 err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
94 "frontend", NULL, &frontend,
95 NULL);
96 if (err)
97 return err;
98 if (strlen(frontend) == 0)
99 err = -ERANGE;
100 if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
101 err = -ENOENT;
102 kfree(frontend);
104 if (err)
105 return err;
107 if (snprintf(bus_id, BUS_ID_SIZE,
108 "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
109 return -ENOSPC;
110 return 0;
111 }
113 static struct xen_bus_type xenbus_backend = {
114 .root = "backend",
115 .levels = 3, /* backend/type/<frontend>/<id> */
116 .get_bus_id = backend_bus_id,
117 .probe = xenbus_probe_backend,
118 .bus = {
119 .name = "xen-backend",
120 .match = xenbus_match,
121 .probe = xenbus_dev_probe,
122 .remove = xenbus_dev_remove,
123 // .shutdown = xenbus_dev_shutdown,
124 .uevent = xenbus_uevent_backend,
125 },
126 .dev = {
127 .bus_id = "xen-backend",
128 },
129 };
131 static int xenbus_uevent_backend(struct device *dev, char **envp,
132 int num_envp, char *buffer, int buffer_size)
133 {
134 struct xenbus_device *xdev;
135 struct xenbus_driver *drv;
136 int i = 0;
137 int length = 0;
139 DPRINTK("");
141 if (dev == NULL)
142 return -ENODEV;
144 xdev = to_xenbus_device(dev);
145 if (xdev == NULL)
146 return -ENODEV;
148 /* stuff we want to pass to /sbin/hotplug */
149 add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
150 "XENBUS_TYPE=%s", xdev->devicetype);
152 add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
153 "XENBUS_PATH=%s", xdev->nodename);
155 add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
156 "XENBUS_BASE_PATH=%s", xenbus_backend.root);
158 /* terminate, set to next free slot, shrink available space */
159 envp[i] = NULL;
160 envp = &envp[i];
161 num_envp -= i;
162 buffer = &buffer[length];
163 buffer_size -= length;
165 if (dev->driver) {
166 drv = to_xenbus_driver(dev->driver);
167 if (drv && drv->uevent)
168 return drv->uevent(xdev, envp, num_envp, buffer,
169 buffer_size);
170 }
172 return 0;
173 }
175 int xenbus_register_backend(struct xenbus_driver *drv)
176 {
177 drv->read_otherend_details = read_frontend_details;
179 return xenbus_register_driver_common(drv, &xenbus_backend);
180 }
181 EXPORT_SYMBOL_GPL(xenbus_register_backend);
183 /* backend/<typename>/<frontend-uuid>/<name> */
184 static int xenbus_probe_backend_unit(const char *dir,
185 const char *type,
186 const char *name)
187 {
188 char *nodename;
189 int err;
191 nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
192 if (!nodename)
193 return -ENOMEM;
195 DPRINTK("%s\n", nodename);
197 err = xenbus_probe_node(&xenbus_backend, type, nodename);
198 kfree(nodename);
199 return err;
200 }
202 /* backend/<typename>/<frontend-domid> */
203 static int xenbus_probe_backend(const char *type, const char *domid)
204 {
205 char *nodename;
206 int err = 0;
207 char **dir;
208 unsigned int i, dir_n = 0;
210 DPRINTK("");
212 nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_backend.root, type, domid);
213 if (!nodename)
214 return -ENOMEM;
216 dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
217 if (IS_ERR(dir)) {
218 kfree(nodename);
219 return PTR_ERR(dir);
220 }
222 for (i = 0; i < dir_n; i++) {
223 err = xenbus_probe_backend_unit(nodename, type, dir[i]);
224 if (err)
225 break;
226 }
227 kfree(dir);
228 kfree(nodename);
229 return err;
230 }
232 static void backend_changed(struct xenbus_watch *watch,
233 const char **vec, unsigned int len)
234 {
235 DPRINTK("");
237 dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
238 }
240 static struct xenbus_watch be_watch = {
241 .node = "backend",
242 .callback = backend_changed,
243 };
245 void xenbus_backend_suspend(int (*fn)(struct device *, void *))
246 {
247 DPRINTK("");
248 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
249 }
251 void xenbus_backend_resume(int (*fn)(struct device *, void *))
252 {
253 DPRINTK("");
254 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
255 }
257 void xenbus_backend_probe_and_watch(void)
258 {
259 xenbus_probe_devices(&xenbus_backend);
260 register_xenbus_watch(&be_watch);
261 }
263 void xenbus_backend_bus_register(void)
264 {
265 bus_register(&xenbus_backend.bus);
266 }
268 void xenbus_backend_device_register(void)
269 {
270 device_register(&xenbus_backend.dev);
271 }