blob: d46205868b880cca866728c9db67bf711272aa9c [file] [log] [blame]
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -07001/******************************************************************************
2 * Talks to Xen Store to figure out what devices we have.
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 */
32
33#define DPRINTK(fmt, args...) \
34 pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \
35 __func__, __LINE__, ##args)
36
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>
Alex Zeffertt1107ba82009-01-07 18:07:11 -080043#include <linux/proc_fs.h>
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -070044#include <linux/notifier.h>
45#include <linux/kthread.h>
46#include <linux/mutex.h>
47#include <linux/io.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090048#include <linux/slab.h>
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -070049
50#include <asm/page.h>
51#include <asm/pgtable.h>
52#include <asm/xen/hypervisor.h>
Jeremy Fitzhardinge1ccbf532009-10-06 15:11:14 -070053
54#include <xen/xen.h>
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -070055#include <xen/xenbus.h>
56#include <xen/events.h>
57#include <xen/page.h>
58
Sheng Yangbee6ab52010-05-14 12:39:33 +010059#include <xen/hvm.h>
60
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -070061#include "xenbus_comms.h"
62#include "xenbus_probe.h"
63
Alex Zeffertt1107ba82009-01-07 18:07:11 -080064
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -070065int xen_store_evtchn;
Jeremy Fitzhardinge8e3e9992009-03-21 23:51:26 -070066EXPORT_SYMBOL_GPL(xen_store_evtchn);
Alex Zeffertt1107ba82009-01-07 18:07:11 -080067
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -070068struct xenstore_domain_interface *xen_store_interface;
Jeremy Fitzhardinge8e3e9992009-03-21 23:51:26 -070069EXPORT_SYMBOL_GPL(xen_store_interface);
70
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -070071static unsigned long xen_store_mfn;
72
73static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
74
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -070075/* If something in array of ids matches this device, return it. */
76static const struct xenbus_device_id *
77match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
78{
79 for (; *arr->devicetype != '\0'; arr++) {
80 if (!strcmp(arr->devicetype, dev->devicetype))
81 return arr;
82 }
83 return NULL;
84}
85
86int xenbus_match(struct device *_dev, struct device_driver *_drv)
87{
88 struct xenbus_driver *drv = to_xenbus_driver(_drv);
89
90 if (!drv->ids)
91 return 0;
92
93 return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
94}
Ian Campbell2de06cc2009-02-09 12:05:51 -080095EXPORT_SYMBOL_GPL(xenbus_match);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -070096
Ian Campbell2de06cc2009-02-09 12:05:51 -080097
98int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env)
Mark McLoughlind2f0c522008-04-02 10:54:05 -070099{
100 struct xenbus_device *dev = to_xenbus_device(_dev);
101
102 if (add_uevent_var(env, "MODALIAS=xen:%s", dev->devicetype))
103 return -ENOMEM;
104
105 return 0;
106}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800107EXPORT_SYMBOL_GPL(xenbus_uevent);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700108
109static void free_otherend_details(struct xenbus_device *dev)
110{
111 kfree(dev->otherend);
112 dev->otherend = NULL;
113}
114
115
116static void free_otherend_watch(struct xenbus_device *dev)
117{
118 if (dev->otherend_watch.node) {
119 unregister_xenbus_watch(&dev->otherend_watch);
120 kfree(dev->otherend_watch.node);
121 dev->otherend_watch.node = NULL;
122 }
123}
124
125
Ian Campbell2de06cc2009-02-09 12:05:51 -0800126static int talk_to_otherend(struct xenbus_device *dev)
127{
128 struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
129
130 free_otherend_watch(dev);
131 free_otherend_details(dev);
132
133 return drv->read_otherend_details(dev);
134}
135
136
137
138static int watch_otherend(struct xenbus_device *dev)
139{
140 struct xen_bus_type *bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
141
142 return xenbus_watch_pathfmt(dev, &dev->otherend_watch, bus->otherend_changed,
143 "%s/%s", dev->otherend, "state");
144}
145
146
147int xenbus_read_otherend_details(struct xenbus_device *xendev,
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700148 char *id_node, char *path_node)
149{
150 int err = xenbus_gather(XBT_NIL, xendev->nodename,
151 id_node, "%i", &xendev->otherend_id,
152 path_node, NULL, &xendev->otherend,
153 NULL);
154 if (err) {
155 xenbus_dev_fatal(xendev, err,
156 "reading other end details from %s",
157 xendev->nodename);
158 return err;
159 }
160 if (strlen(xendev->otherend) == 0 ||
161 !xenbus_exists(XBT_NIL, xendev->otherend, "")) {
162 xenbus_dev_fatal(xendev, -ENOENT,
163 "unable to read other end from %s. "
164 "missing or inaccessible.",
165 xendev->nodename);
166 free_otherend_details(xendev);
167 return -ENOENT;
168 }
169
170 return 0;
171}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800172EXPORT_SYMBOL_GPL(xenbus_read_otherend_details);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700173
Ian Campbell2de06cc2009-02-09 12:05:51 -0800174void xenbus_otherend_changed(struct xenbus_watch *watch,
175 const char **vec, unsigned int len,
176 int ignore_on_shutdown)
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700177{
178 struct xenbus_device *dev =
179 container_of(watch, struct xenbus_device, otherend_watch);
180 struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
181 enum xenbus_state state;
182
183 /* Protect us against watches firing on old details when the otherend
184 details change, say immediately after a resume. */
185 if (!dev->otherend ||
186 strncmp(dev->otherend, vec[XS_WATCH_PATH],
187 strlen(dev->otherend))) {
Joe Perches898eb712007-10-18 03:06:30 -0700188 dev_dbg(&dev->dev, "Ignoring watch at %s\n",
189 vec[XS_WATCH_PATH]);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700190 return;
191 }
192
193 state = xenbus_read_driver_state(dev->otherend);
194
Joe Perches898eb712007-10-18 03:06:30 -0700195 dev_dbg(&dev->dev, "state is %d, (%s), %s, %s\n",
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700196 state, xenbus_strstate(state), dev->otherend_watch.node,
197 vec[XS_WATCH_PATH]);
198
199 /*
200 * Ignore xenbus transitions during shutdown. This prevents us doing
201 * work that can fail e.g., when the rootfs is gone.
202 */
203 if (system_state > SYSTEM_RUNNING) {
Ian Campbell2de06cc2009-02-09 12:05:51 -0800204 if (ignore_on_shutdown && (state == XenbusStateClosing))
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700205 xenbus_frontend_closed(dev);
206 return;
207 }
208
209 if (drv->otherend_changed)
210 drv->otherend_changed(dev, state);
211}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800212EXPORT_SYMBOL_GPL(xenbus_otherend_changed);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700213
214int xenbus_dev_probe(struct device *_dev)
215{
216 struct xenbus_device *dev = to_xenbus_device(_dev);
217 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
218 const struct xenbus_device_id *id;
219 int err;
220
221 DPRINTK("%s", dev->nodename);
222
223 if (!drv->probe) {
224 err = -ENODEV;
225 goto fail;
226 }
227
228 id = match_device(drv->ids, dev);
229 if (!id) {
230 err = -ENODEV;
231 goto fail;
232 }
233
234 err = talk_to_otherend(dev);
235 if (err) {
236 dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n",
237 dev->nodename);
238 return err;
239 }
240
241 err = drv->probe(dev, id);
242 if (err)
243 goto fail;
244
245 err = watch_otherend(dev);
246 if (err) {
247 dev_warn(&dev->dev, "watch_otherend on %s failed.\n",
248 dev->nodename);
249 return err;
250 }
251
252 return 0;
253fail:
254 xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
255 xenbus_switch_state(dev, XenbusStateClosed);
256 return -ENODEV;
257}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800258EXPORT_SYMBOL_GPL(xenbus_dev_probe);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700259
260int xenbus_dev_remove(struct device *_dev)
261{
262 struct xenbus_device *dev = to_xenbus_device(_dev);
263 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
264
265 DPRINTK("%s", dev->nodename);
266
267 free_otherend_watch(dev);
268 free_otherend_details(dev);
269
270 if (drv->remove)
271 drv->remove(dev);
272
273 xenbus_switch_state(dev, XenbusStateClosed);
274 return 0;
275}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800276EXPORT_SYMBOL_GPL(xenbus_dev_remove);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700277
Ian Campbell2de06cc2009-02-09 12:05:51 -0800278void xenbus_dev_shutdown(struct device *_dev)
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700279{
280 struct xenbus_device *dev = to_xenbus_device(_dev);
281 unsigned long timeout = 5*HZ;
282
283 DPRINTK("%s", dev->nodename);
284
285 get_device(&dev->dev);
286 if (dev->state != XenbusStateConnected) {
287 printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__,
288 dev->nodename, xenbus_strstate(dev->state));
289 goto out;
290 }
291 xenbus_switch_state(dev, XenbusStateClosing);
292 timeout = wait_for_completion_timeout(&dev->down, timeout);
293 if (!timeout)
294 printk(KERN_INFO "%s: %s timeout closing device\n",
295 __func__, dev->nodename);
296 out:
297 put_device(&dev->dev);
298}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800299EXPORT_SYMBOL_GPL(xenbus_dev_shutdown);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700300
301int xenbus_register_driver_common(struct xenbus_driver *drv,
302 struct xen_bus_type *bus,
303 struct module *owner,
304 const char *mod_name)
305{
306 drv->driver.name = drv->name;
307 drv->driver.bus = &bus->bus;
308 drv->driver.owner = owner;
309 drv->driver.mod_name = mod_name;
310
311 return driver_register(&drv->driver);
312}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800313EXPORT_SYMBOL_GPL(xenbus_register_driver_common);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700314
315void xenbus_unregister_driver(struct xenbus_driver *drv)
316{
317 driver_unregister(&drv->driver);
318}
319EXPORT_SYMBOL_GPL(xenbus_unregister_driver);
320
321struct xb_find_info
322{
323 struct xenbus_device *dev;
324 const char *nodename;
325};
326
327static int cmp_dev(struct device *dev, void *data)
328{
329 struct xenbus_device *xendev = to_xenbus_device(dev);
330 struct xb_find_info *info = data;
331
332 if (!strcmp(xendev->nodename, info->nodename)) {
333 info->dev = xendev;
334 get_device(dev);
335 return 1;
336 }
337 return 0;
338}
339
340struct xenbus_device *xenbus_device_find(const char *nodename,
341 struct bus_type *bus)
342{
343 struct xb_find_info info = { .dev = NULL, .nodename = nodename };
344
345 bus_for_each_dev(bus, NULL, &info, cmp_dev);
346 return info.dev;
347}
348
349static int cleanup_dev(struct device *dev, void *data)
350{
351 struct xenbus_device *xendev = to_xenbus_device(dev);
352 struct xb_find_info *info = data;
353 int len = strlen(info->nodename);
354
355 DPRINTK("%s", info->nodename);
356
357 /* Match the info->nodename path, or any subdirectory of that path. */
358 if (strncmp(xendev->nodename, info->nodename, len))
359 return 0;
360
361 /* If the node name is longer, ensure it really is a subdirectory. */
362 if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/'))
363 return 0;
364
365 info->dev = xendev;
366 get_device(dev);
367 return 1;
368}
369
370static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
371{
372 struct xb_find_info info = { .nodename = path };
373
374 do {
375 info.dev = NULL;
376 bus_for_each_dev(bus, NULL, &info, cleanup_dev);
377 if (info.dev) {
378 device_unregister(&info.dev->dev);
379 put_device(&info.dev->dev);
380 }
381 } while (info.dev);
382}
383
384static void xenbus_dev_release(struct device *dev)
385{
386 if (dev)
387 kfree(to_xenbus_device(dev));
388}
389
390static ssize_t xendev_show_nodename(struct device *dev,
391 struct device_attribute *attr, char *buf)
392{
393 return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
394}
Jeremy Fitzhardingedb05fed2009-11-24 16:41:47 -0800395static DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700396
397static ssize_t xendev_show_devtype(struct device *dev,
398 struct device_attribute *attr, char *buf)
399{
400 return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
401}
Jeremy Fitzhardingedb05fed2009-11-24 16:41:47 -0800402static DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700403
Mark McLoughlind2f0c522008-04-02 10:54:05 -0700404static ssize_t xendev_show_modalias(struct device *dev,
405 struct device_attribute *attr, char *buf)
406{
407 return sprintf(buf, "xen:%s\n", to_xenbus_device(dev)->devicetype);
408}
Jeremy Fitzhardingedb05fed2009-11-24 16:41:47 -0800409static DEVICE_ATTR(modalias, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_modalias, NULL);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700410
411int xenbus_probe_node(struct xen_bus_type *bus,
412 const char *type,
413 const char *nodename)
414{
Kay Sievers2a678cc2009-01-06 10:44:34 -0800415 char devname[XEN_BUS_ID_SIZE];
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700416 int err;
417 struct xenbus_device *xendev;
418 size_t stringlen;
419 char *tmpstring;
420
421 enum xenbus_state state = xenbus_read_driver_state(nodename);
422
423 if (state != XenbusStateInitialising) {
424 /* Device is not new, so ignore it. This can happen if a
425 device is going away after switching to Closed. */
426 return 0;
427 }
428
429 stringlen = strlen(nodename) + 1 + strlen(type) + 1;
430 xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
431 if (!xendev)
432 return -ENOMEM;
433
434 xendev->state = XenbusStateInitialising;
435
436 /* Copy the strings into the extra space. */
437
438 tmpstring = (char *)(xendev + 1);
439 strcpy(tmpstring, nodename);
440 xendev->nodename = tmpstring;
441
442 tmpstring += strlen(tmpstring) + 1;
443 strcpy(tmpstring, type);
444 xendev->devicetype = tmpstring;
445 init_completion(&xendev->down);
446
447 xendev->dev.bus = &bus->bus;
448 xendev->dev.release = xenbus_dev_release;
449
Kay Sievers2a678cc2009-01-06 10:44:34 -0800450 err = bus->get_bus_id(devname, xendev->nodename);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700451 if (err)
452 goto fail;
453
Kay Sievers2a678cc2009-01-06 10:44:34 -0800454 dev_set_name(&xendev->dev, devname);
455
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700456 /* Register with generic device framework. */
457 err = device_register(&xendev->dev);
458 if (err)
459 goto fail;
460
461 err = device_create_file(&xendev->dev, &dev_attr_nodename);
462 if (err)
463 goto fail_unregister;
464
465 err = device_create_file(&xendev->dev, &dev_attr_devtype);
466 if (err)
Mark McLoughlind2f0c522008-04-02 10:54:05 -0700467 goto fail_remove_nodename;
468
469 err = device_create_file(&xendev->dev, &dev_attr_modalias);
470 if (err)
471 goto fail_remove_devtype;
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700472
473 return 0;
Mark McLoughlind2f0c522008-04-02 10:54:05 -0700474fail_remove_devtype:
475 device_remove_file(&xendev->dev, &dev_attr_devtype);
476fail_remove_nodename:
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700477 device_remove_file(&xendev->dev, &dev_attr_nodename);
478fail_unregister:
479 device_unregister(&xendev->dev);
480fail:
481 kfree(xendev);
482 return err;
483}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800484EXPORT_SYMBOL_GPL(xenbus_probe_node);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700485
486static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
487{
488 int err = 0;
489 char **dir;
490 unsigned int dir_n = 0;
491 int i;
492
Ian Campbell2de06cc2009-02-09 12:05:51 -0800493 printk(KERN_CRIT "%s type %s\n", __func__, type);
494
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700495 dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n);
Ian Campbell2de06cc2009-02-09 12:05:51 -0800496 if (IS_ERR(dir)) {
497 printk(KERN_CRIT "%s failed xenbus_directory\n", __func__);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700498 return PTR_ERR(dir);
Ian Campbell2de06cc2009-02-09 12:05:51 -0800499 }
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700500
501 for (i = 0; i < dir_n; i++) {
Ian Campbell2de06cc2009-02-09 12:05:51 -0800502 printk(KERN_CRIT "%s %d/%d %s\n", __func__, i+1,dir_n, dir[i]);
503 err = bus->probe(bus, type, dir[i]);
504 if (err) {
505 printk(KERN_CRIT "%s failed\n", __func__);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700506 break;
Ian Campbell2de06cc2009-02-09 12:05:51 -0800507 }
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700508 }
Ian Campbell2de06cc2009-02-09 12:05:51 -0800509 printk("%s done\n", __func__);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700510 kfree(dir);
511 return err;
512}
513
514int xenbus_probe_devices(struct xen_bus_type *bus)
515{
516 int err = 0;
517 char **dir;
518 unsigned int i, dir_n;
519
Ian Campbell2de06cc2009-02-09 12:05:51 -0800520 printk(KERN_CRIT "%s %s\n", __func__, bus->root);
521
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700522 dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n);
Ian Campbell2de06cc2009-02-09 12:05:51 -0800523 if (IS_ERR(dir)) {
524 printk(KERN_CRIT "%s failed xenbus_directory\n", __func__);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700525 return PTR_ERR(dir);
Ian Campbell2de06cc2009-02-09 12:05:51 -0800526 }
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700527
528 for (i = 0; i < dir_n; i++) {
Ian Campbell2de06cc2009-02-09 12:05:51 -0800529 printk(KERN_CRIT "%s %d/%d %s\n", __func__, i+1,dir_n, dir[i]);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700530 err = xenbus_probe_device_type(bus, dir[i]);
Ian Campbell2de06cc2009-02-09 12:05:51 -0800531 if (err) {
532 printk(KERN_CRIT "%s failed\n", __func__);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700533 break;
Ian Campbell2de06cc2009-02-09 12:05:51 -0800534 }
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700535 }
Ian Campbell2de06cc2009-02-09 12:05:51 -0800536 printk("%s done\n", __func__);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700537 kfree(dir);
538 return err;
539}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800540EXPORT_SYMBOL_GPL(xenbus_probe_devices);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700541
542static unsigned int char_count(const char *str, char c)
543{
544 unsigned int i, ret = 0;
545
546 for (i = 0; str[i]; i++)
547 if (str[i] == c)
548 ret++;
549 return ret;
550}
551
552static int strsep_len(const char *str, char c, unsigned int len)
553{
554 unsigned int i;
555
556 for (i = 0; str[i]; i++)
557 if (str[i] == c) {
558 if (len == 0)
559 return i;
560 len--;
561 }
562 return (len == 0) ? i : -ERANGE;
563}
564
565void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
566{
567 int exists, rootlen;
568 struct xenbus_device *dev;
Kay Sievers2a678cc2009-01-06 10:44:34 -0800569 char type[XEN_BUS_ID_SIZE];
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700570 const char *p, *root;
571
572 if (char_count(node, '/') < 2)
573 return;
574
575 exists = xenbus_exists(XBT_NIL, node, "");
576 if (!exists) {
577 xenbus_cleanup_devices(node, &bus->bus);
578 return;
579 }
580
581 /* backend/<type>/... or device/<type>/... */
582 p = strchr(node, '/') + 1;
Kay Sievers2a678cc2009-01-06 10:44:34 -0800583 snprintf(type, XEN_BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
584 type[XEN_BUS_ID_SIZE-1] = '\0';
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700585
586 rootlen = strsep_len(node, '/', bus->levels);
587 if (rootlen < 0)
588 return;
589 root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
590 if (!root)
591 return;
592
593 dev = xenbus_device_find(root, &bus->bus);
594 if (!dev)
595 xenbus_probe_node(bus, type, root);
596 else
597 put_device(&dev->dev);
598
599 kfree(root);
600}
Jeremy Fitzhardingec6a960c2009-02-09 12:05:53 -0800601EXPORT_SYMBOL_GPL(xenbus_dev_changed);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700602
Ian Campbell2de06cc2009-02-09 12:05:51 -0800603int xenbus_dev_suspend(struct device *dev, pm_message_t state)
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700604{
605 int err = 0;
606 struct xenbus_driver *drv;
Ian Campbell2de06cc2009-02-09 12:05:51 -0800607 struct xenbus_device *xdev = container_of(dev, struct xenbus_device, dev);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700608
Ian Campbell2de06cc2009-02-09 12:05:51 -0800609 DPRINTK("%s", xdev->nodename);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700610
611 if (dev->driver == NULL)
612 return 0;
613 drv = to_xenbus_driver(dev->driver);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700614 if (drv->suspend)
Ian Campbellde5b31b2009-02-09 12:05:50 -0800615 err = drv->suspend(xdev, state);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700616 if (err)
617 printk(KERN_WARNING
Kay Sievers2a678cc2009-01-06 10:44:34 -0800618 "xenbus: suspend %s failed: %i\n", dev_name(dev), err);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700619 return 0;
620}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800621EXPORT_SYMBOL_GPL(xenbus_dev_suspend);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700622
Ian Campbell2de06cc2009-02-09 12:05:51 -0800623int xenbus_dev_resume(struct device *dev)
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700624{
625 int err;
626 struct xenbus_driver *drv;
Ian Campbell2de06cc2009-02-09 12:05:51 -0800627 struct xenbus_device *xdev = container_of(dev, struct xenbus_device, dev);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700628
Ian Campbell2de06cc2009-02-09 12:05:51 -0800629 DPRINTK("%s", xdev->nodename);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700630
631 if (dev->driver == NULL)
632 return 0;
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700633 drv = to_xenbus_driver(dev->driver);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700634 err = talk_to_otherend(xdev);
635 if (err) {
636 printk(KERN_WARNING
637 "xenbus: resume (talk_to_otherend) %s failed: %i\n",
Kay Sievers2a678cc2009-01-06 10:44:34 -0800638 dev_name(dev), err);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700639 return err;
640 }
641
642 xdev->state = XenbusStateInitialising;
643
644 if (drv->resume) {
645 err = drv->resume(xdev);
646 if (err) {
647 printk(KERN_WARNING
648 "xenbus: resume %s failed: %i\n",
Kay Sievers2a678cc2009-01-06 10:44:34 -0800649 dev_name(dev), err);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700650 return err;
651 }
652 }
653
654 err = watch_otherend(xdev);
655 if (err) {
656 printk(KERN_WARNING
657 "xenbus_probe: resume (watch_otherend) %s failed: "
Kay Sievers2a678cc2009-01-06 10:44:34 -0800658 "%d.\n", dev_name(dev), err);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700659 return err;
660 }
661
662 return 0;
663}
Ian Campbell2de06cc2009-02-09 12:05:51 -0800664EXPORT_SYMBOL_GPL(xenbus_dev_resume);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700665
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700666/* A flag to determine if xenstored is 'ready' (i.e. has started) */
667int xenstored_ready = 0;
668
669
670int register_xenstore_notifier(struct notifier_block *nb)
671{
672 int ret = 0;
673
Stefano Stabellinia947f0f2010-10-04 16:10:06 +0100674 if (xenstored_ready > 0)
675 ret = nb->notifier_call(nb, 0, NULL);
676 else
677 blocking_notifier_chain_register(&xenstore_chain, nb);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700678
679 return ret;
680}
681EXPORT_SYMBOL_GPL(register_xenstore_notifier);
682
683void unregister_xenstore_notifier(struct notifier_block *nb)
684{
685 blocking_notifier_chain_unregister(&xenstore_chain, nb);
686}
687EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
688
689void xenbus_probe(struct work_struct *unused)
690{
Stefano Stabellinia947f0f2010-10-04 16:10:06 +0100691 xenstored_ready = 1;
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700692
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700693 /* Notify others that xenstore is up */
694 blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
695}
Stefano Stabellini183d03c2010-05-17 17:08:21 +0100696EXPORT_SYMBOL_GPL(xenbus_probe);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700697
Stefano Stabellini183d03c2010-05-17 17:08:21 +0100698static int __init xenbus_probe_initcall(void)
699{
700 if (!xen_domain())
701 return -ENODEV;
702
703 if (xen_initial_domain() || xen_hvm_domain())
704 return 0;
705
706 xenbus_probe(NULL);
707 return 0;
708}
709
710device_initcall(xenbus_probe_initcall);
711
712static int __init xenbus_init(void)
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700713{
714 int err = 0;
Juan Quintelab37a56d2010-09-02 14:53:56 +0100715 unsigned long page = 0;
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700716
717 DPRINTK("");
718
719 err = -ENODEV;
Jeremy Fitzhardinge6e833582008-08-19 13:16:17 -0700720 if (!xen_domain())
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700721 goto out_error;
722
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700723 /*
724 * Domain0 doesn't have a store_evtchn or store_mfn yet.
725 */
Jeremy Fitzhardinge6e833582008-08-19 13:16:17 -0700726 if (xen_initial_domain()) {
Juan Quintelab37a56d2010-09-02 14:53:56 +0100727 struct evtchn_alloc_unbound alloc_unbound;
728
729 /* Allocate Xenstore page */
730 page = get_zeroed_page(GFP_KERNEL);
731 if (!page)
732 goto out_error;
733
734 xen_store_mfn = xen_start_info->store_mfn =
735 pfn_to_mfn(virt_to_phys((void *)page) >>
736 PAGE_SHIFT);
737
738 /* Next allocate a local port which xenstored can bind to */
739 alloc_unbound.dom = DOMID_SELF;
740 alloc_unbound.remote_dom = 0;
741
742 err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
743 &alloc_unbound);
744 if (err == -ENOSYS)
745 goto out_error;
746
747 BUG_ON(err);
748 xen_store_evtchn = xen_start_info->store_evtchn =
749 alloc_unbound.port;
750
751 xen_store_interface = mfn_to_virt(xen_store_mfn);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700752 } else {
Sheng Yangbee6ab52010-05-14 12:39:33 +0100753 if (xen_hvm_domain()) {
754 uint64_t v = 0;
755 err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
756 if (err)
757 goto out_error;
758 xen_store_evtchn = (int)v;
759 err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
760 if (err)
761 goto out_error;
762 xen_store_mfn = (unsigned long)v;
763 xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE);
764 } else {
765 xen_store_evtchn = xen_start_info->store_evtchn;
766 xen_store_mfn = xen_start_info->store_mfn;
767 xen_store_interface = mfn_to_virt(xen_store_mfn);
Stefano Stabellinia947f0f2010-10-04 16:10:06 +0100768 xenstored_ready = 1;
Sheng Yangbee6ab52010-05-14 12:39:33 +0100769 }
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700770 }
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700771
772 /* Initialize the interface to xenstore. */
773 err = xs_init();
774 if (err) {
775 printk(KERN_WARNING
776 "XENBUS: Error initializing xenstore comms: %i\n", err);
Ian Campbell2de06cc2009-02-09 12:05:51 -0800777 goto out_error;
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700778 }
779
Alex Zeffertt1107ba82009-01-07 18:07:11 -0800780#ifdef CONFIG_XEN_COMPAT_XENFS
781 /*
782 * Create xenfs mountpoint in /proc for compatibility with
783 * utilities that expect to find "xenbus" under "/proc/xen".
784 */
785 proc_mkdir("xen", NULL);
786#endif
787
Ian Campbell2de06cc2009-02-09 12:05:51 -0800788 printk(KERN_CRIT "%s ok\n", __func__);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700789 return 0;
790
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700791 out_error:
Juan Quintelab37a56d2010-09-02 14:53:56 +0100792 if (page != 0)
793 free_page(page);
Ian Campbell2de06cc2009-02-09 12:05:51 -0800794
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700795 return err;
796}
797
Stefano Stabellini183d03c2010-05-17 17:08:21 +0100798postcore_initcall(xenbus_init);
Jeremy Fitzhardinge4bac07c2007-07-17 18:37:06 -0700799
800MODULE_LICENSE("GPL");