xenbus_probe.c revision 1.2.2.1 1 /* $NetBSD: xenbus_probe.c,v 1.2.2.1 2006/04/19 02:34:08 elad Exp $ */
2 /******************************************************************************
3 * Talks to Xen Store to figure out what devices we have.
4 *
5 * Copyright (C) 2005 Rusty Russell, IBM Corporation
6 * Copyright (C) 2005 Mike Wray, Hewlett-Packard
7 * Copyright (C) 2005 XenSource Ltd
8 *
9 * This file may be distributed separately from the Linux kernel, or
10 * incorporated into other software packages, subject to the following license:
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this source file (the "Software"), to deal in the Software without
14 * restriction, including without limitation the rights to use, copy, modify,
15 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16 * and to permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * IN THE SOFTWARE.
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: xenbus_probe.c,v 1.2.2.1 2006/04/19 02:34:08 elad Exp $");
33
34 #if 0
35 #define DPRINTK(fmt, args...) \
36 printf("xenbus_probe (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
37 #else
38 #define DPRINTK(fmt, args...) ((void)0)
39 #endif
40
41 #include <sys/types.h>
42 #include <sys/null.h>
43 #include <sys/errno.h>
44 #include <sys/malloc.h>
45 #include <sys/systm.h>
46 #include <sys/param.h>
47 #include <sys/kthread.h>
48 #include <uvm/uvm.h>
49
50 #include <machine/stdarg.h>
51
52 #include <machine/hypervisor.h>
53 #include <machine/xenbus.h>
54 #include <machine/evtchn.h>
55
56 #include "xenbus_comms.h"
57
58 extern struct semaphore xenwatch_mutex;
59
60 #define streq(a, b) (strcmp((a), (b)) == 0)
61
62 static int xenbus_match(struct device *, struct cfdata *, void *);
63 static void xenbus_attach(struct device *, struct device *, void *);
64 static int xenbus_print(void *, const char *);
65
66 static void xenbus_kthread_create(void *);
67 static void xenbus_probe_init(void *);
68
69 static struct xenbus_device *xenbus_lookup_device_path(const char *);
70
71 CFATTACH_DECL(xenbus, sizeof(struct device), xenbus_match, xenbus_attach,
72 NULL, NULL);
73
74 struct device *xenbus_sc;
75
76 SLIST_HEAD(, xenbus_device) xenbus_device_list;
77
78 int
79 xenbus_match(struct device *parent, struct cfdata *match, void *aux)
80 {
81 struct xenbus_attach_args *xa = (struct xenbus_attach_args *)aux;
82
83 if (strcmp(xa->xa_device, "xenbus") == 0)
84 return 1;
85 return 0;
86 }
87
88 static void
89 xenbus_attach(struct device *parent, struct device *self, void *aux)
90 {
91 aprint_normal(": Xen Virtual Bus Interface\n");
92 xenbus_sc = self;
93 xb_init_comms(self);
94 config_pending_incr();
95 kthread_create(xenbus_kthread_create, NULL);
96 }
97
98 void
99 xenbus_kthread_create(void *unused)
100 {
101 struct proc *p;
102 int err;
103 err = kthread_create1(xenbus_probe_init, NULL, &p, "xenbus_probe");
104 if (err)
105 printf("kthread_create1(xenbus_probe): %d\n", err);
106 }
107
108
109 #if 0
110 static char *kasprintf(const char *fmt, ...);
111
112 static struct notifier_block *xenstore_chain;
113
114 /* If something in array of ids matches this device, return it. */
115 static const struct xenbus_device_id *
116 match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
117 {
118 for (; !streq(arr->devicetype, ""); arr++) {
119 if (streq(arr->devicetype, dev->devicetype))
120 return arr;
121 }
122 return NULL;
123 }
124
125 static int xenbus_match_device(struct device *_dev, struct device_driver *_drv)
126 {
127 struct xenbus_driver *drv = to_xenbus_driver(_drv);
128
129 if (!drv->ids)
130 return 0;
131
132 return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
133 }
134 #endif
135
136 struct xen_bus_type
137 {
138 const char *root;
139 unsigned int levels;
140 };
141
142 #if 0
143 /* device/<type>/<id> => <type>-<id> */
144 static int
145 frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
146 {
147 nodename = strchr(nodename, '/');
148 if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
149 printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
150 return EINVAL;
151 }
152
153 strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
154 if (!strchr(bus_id, '/')) {
155 printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
156 return EINVAL;
157 }
158 *strchr(bus_id, '/') = '-';
159 return 0;
160 }
161 #endif
162
163 static int
164 read_otherend_details(struct xenbus_device *xendev,
165 const char *id_node, const char *path_node)
166 {
167 int err;
168 char *val, *ep;
169
170 err = xenbus_read(NULL, xendev->xbusd_path, id_node, NULL, &val);
171 if (err) {
172 printf("reading other end details %s from %s\n",
173 id_node, xendev->xbusd_path);
174 xenbus_dev_fatal(xendev, err,
175 "reading other end details %s from %s",
176 id_node, xendev->xbusd_path);
177 return err;
178 }
179 xendev->xbusd_otherend_id = strtoul(val, &ep, 10);
180 if (val[0] == '\0' || *ep != '\0') {
181 printf("reading other end details %s from %s: %s is not a number\n", id_node, xendev->xbusd_path, val);
182 xenbus_dev_fatal(xendev, err,
183 "reading other end details %s from %s: %s is not a number",
184 id_node, xendev->xbusd_path, val);
185 free(val, M_DEVBUF);
186 return EFTYPE;
187 }
188 free(val, M_DEVBUF);
189 err = xenbus_read(NULL, xendev->xbusd_path, path_node, NULL, &val);
190 if (err) {
191 printf("reading other end details %s from %s (%d)\n",
192 path_node, xendev->xbusd_path, err);
193 xenbus_dev_fatal(xendev, err,
194 "reading other end details %s from %s",
195 path_node, xendev->xbusd_path);
196 return err;
197 }
198 DPRINTK("read_otherend_details: read %s/%s returned %s\n",
199 xendev->xbusd_path, path_node, val);
200 xendev->xbusd_otherend = val;
201
202 if (strlen(xendev->xbusd_otherend) == 0 ||
203 !xenbus_exists(NULL, xendev->xbusd_otherend, "")) {
204 printf("missing other end from %s\n", xendev->xbusd_path);
205 xenbus_dev_fatal(xendev, -ENOENT, "missing other end from %s",
206 xendev->xbusd_path);
207 free(xendev->xbusd_otherend, M_DEVBUF);
208 xendev->xbusd_otherend = NULL;
209 return ENOENT;
210 }
211
212 return 0;
213 }
214
215 static int
216 read_backend_details(struct xenbus_device *xendev)
217 {
218 return read_otherend_details(xendev, "backend-id", "backend");
219 }
220
221
222 #if 0 //#ifdef DOM0OPS
223 static int
224 read_frontend_details(struct xenbus_device *xendev)
225 {
226 return read_otherend_details(xendev, "frontend-id", "frontend");
227 }
228 #endif
229
230 #if unused
231 static void
232 free_otherend_details(struct xenbus_device *dev)
233 {
234 free(dev->xbusd_otherend, M_DEVBUF);
235 dev->xbusd_otherend = NULL;
236 }
237 #endif
238
239
240 static void
241 free_otherend_watch(struct xenbus_device *dev)
242 {
243 if (dev->xbusd_otherend_watch.node) {
244 unregister_xenbus_watch(&dev->xbusd_otherend_watch);
245 free(dev->xbusd_otherend_watch.node, M_DEVBUF);
246 dev->xbusd_otherend_watch.node = NULL;
247 }
248 }
249
250 #if 0
251
252 /* Bus type for frontend drivers. */
253 static int xenbus_probe_frontend(const char *type, const char *name);
254 #endif
255 static struct xen_bus_type xenbus_frontend = {
256 .root = "device",
257 .levels = 2, /* device/type/<id> */
258 };
259
260 #if 0
261 /* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
262 static int
263 backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
264 {
265 int domid, err;
266 const char *devid, *type, *frontend;
267 unsigned int typelen;
268
269 type = strchr(nodename, '/');
270 if (!type)
271 return EINVAL;
272 type++;
273 typelen = strcspn(type, "/");
274 if (!typelen || type[typelen] != '/')
275 return EINVAL;
276
277 devid = strrchr(nodename, '/') + 1;
278
279 err = xenbus_gather(NULL, nodename, "frontend-id", "%i", &domid,
280 "frontend", NULL, &frontend,
281 NULL);
282 if (err)
283 return err;
284 if (strlen(frontend) == 0)
285 err = ERANGE;
286
287 if (!err && !xenbus_exists(NULL, frontend, ""))
288 err = ENOENT;
289
290 if (err) {
291 free(frontend, M_DEVBUF);
292 return err;
293 }
294
295 if (snprintf(bus_id, BUS_ID_SIZE,
296 "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
297 return ENOSPC;
298 return 0;
299 }
300
301 static int
302 xenbus_hotplug_backend(struct device *dev, char **envp,
303 int num_envp, char *buffer, int buffer_size)
304 {
305 struct xenbus_device *xdev;
306 struct xenbus_driver *drv = NULL;
307 int i = 0;
308 int length = 0;
309 char *basepath_end;
310 char *frontend_id;
311
312 DPRINTK("");
313
314 if (dev == NULL)
315 return ENODEV;
316
317 xdev = to_xenbus_device(dev);
318 if (xdev == NULL)
319 return ENODEV;
320
321 if (dev->driver)
322 drv = to_xenbus_driver(dev->driver);
323
324 /* stuff we want to pass to /sbin/hotplug */
325 add_hotplug_env_var(envp, num_envp, &i,
326 buffer, buffer_size, &length,
327 "XENBUS_TYPE=%s", xdev->devicetype);
328
329 add_hotplug_env_var(envp, num_envp, &i,
330 buffer, buffer_size, &length,
331 "XENBUS_PATH=%s", xdev->xbusd_path);
332
333 add_hotplug_env_var(envp, num_envp, &i,
334 buffer, buffer_size, &length,
335 "XENBUS_BASE_PATH=%s", xdev->xbusd_path);
336
337 basepath_end = strrchr(envp[i - 1], '/');
338 length -= strlen(basepath_end);
339 *basepath_end = '\0';
340 basepath_end = strrchr(envp[i - 1], '/');
341 length -= strlen(basepath_end);
342 *basepath_end = '\0';
343
344 basepath_end++;
345 frontend_id = kmalloc(strlen(basepath_end) + 1, GFP_KERNEL);
346 strcpy(frontend_id, basepath_end);
347 add_hotplug_env_var(envp, num_envp, &i,
348 buffer, buffer_size, &length,
349 "XENBUS_FRONTEND_ID=%s", frontend_id);
350 free(frontend_id, M_DEVBUF);
351
352 /* terminate, set to next free slot, shrink available space */
353 envp[i] = NULL;
354 envp = &envp[i];
355 num_envp -= i;
356 buffer = &buffer[length];
357 buffer_size -= length;
358
359 if (drv && drv->hotplug)
360 return drv->hotplug(xdev, envp, num_envp, buffer,
361 buffer_size);
362
363 return 0;
364 }
365
366 static int xenbus_probe_backend(const char *type, const char *domid);
367 #endif
368
369 static struct xen_bus_type xenbus_backend = {
370 .root = "backend",
371 .levels = 3, /* backend/type/<frontend>/<id> */
372 };
373
374 static void
375 otherend_changed(struct xenbus_watch *watch,
376 const char **vec, unsigned int len)
377 {
378 struct xenbus_device *xdev = watch->xbw_dev;
379 XenbusState state;
380
381 /* Protect us against watches firing on old details when the otherend
382 details change, say immediately after a resume. */
383 if (!xdev->xbusd_otherend ||
384 strncmp(xdev->xbusd_otherend, vec[XS_WATCH_PATH],
385 strlen(xdev->xbusd_otherend))) {
386 DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]);
387 return;
388 }
389
390 state = xenbus_read_driver_state(xdev->xbusd_otherend);
391
392 DPRINTK("state is %d, %s, %s",
393 state, xdev->xbusd_otherend_watch.node, vec[XS_WATCH_PATH]);
394 if (state == XenbusStateClosed) {
395 int error;
396 error = config_detach(xdev->xbusd_dev, DETACH_FORCE);
397 if (error) {
398 printf("could not detach %s: %d\n",
399 xdev->xbusd_dev->dv_xname, error);
400 return;
401 }
402 xenbus_free_device(xdev);
403 return;
404 }
405 if (xdev->xbusd_otherend_changed)
406 xdev->xbusd_otherend_changed(xdev->xbusd_dev, state);
407 }
408
409 static int
410 talk_to_otherend(struct xenbus_device *dev)
411 {
412 free_otherend_watch(dev);
413
414 return xenbus_watch_path2(dev, dev->xbusd_otherend, "state",
415 &dev->xbusd_otherend_watch,
416 otherend_changed);
417 }
418
419 #if 0
420
421 static int
422 xenbus_dev_probe(struct device *_dev)
423 {
424 struct xenbus_device *dev = to_xenbus_device(_dev);
425 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
426 const struct xenbus_device_id *id;
427 int err;
428
429 DPRINTK("");
430
431 err = talk_to_otherend(dev);
432 if (err) {
433 printk(KERN_WARNING
434 "xenbus_probe: talk_to_otherend on %s failed.\n",
435 dev->xbusd_path);
436 return err;
437 }
438
439 if (!drv->probe) {
440 err = ENODEV;
441 goto fail;
442 }
443
444 id = match_device(drv->ids, dev);
445 if (!id) {
446 err = ENODEV;
447 goto fail;
448 }
449
450 err = drv->probe(dev, id);
451 if (err)
452 goto fail;
453
454 return 0;
455 fail:
456 xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->xbusd_path);
457 xenbus_switch_state(dev, NULL, XenbusStateClosed);
458 return ENODEV;
459
460 }
461
462 static int
463 xenbus_dev_remove(struct device *_dev)
464 {
465 struct xenbus_device *dev = to_xenbus_device(_dev);
466 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
467
468 DPRINTK("");
469
470 free_otherend_watch(dev);
471 free_otherend_details(dev);
472
473 if (drv->remove)
474 drv->remove(dev);
475
476 xenbus_switch_state(dev, NULL, XenbusStateClosed);
477 return 0;
478 }
479
480 static int
481 xenbus_register_driver_common(struct xenbus_driver *drv,
482 struct xen_bus_type *bus)
483 {
484 int ret;
485
486 drv->driver.name = drv->name;
487 drv->driver.bus = &bus->bus;
488 drv->driver.owner = drv->owner;
489 drv->driver.probe = xenbus_dev_probe;
490 drv->driver.remove = xenbus_dev_remove;
491
492 down(&xenwatch_mutex);
493 ret = driver_register(&drv->driver);
494 up(&xenwatch_mutex);
495 return ret;
496 }
497
498 int
499 xenbus_register_frontend(struct xenbus_driver *drv)
500 {
501 drv->read_otherend_details = read_backend_details;
502
503 return xenbus_register_driver_common(drv, &xenbus_frontend);
504 }
505
506 int
507 xenbus_register_backend(struct xenbus_driver *drv)
508 {
509 drv->read_otherend_details = read_frontend_details;
510
511 return xenbus_register_driver_common(drv, &xenbus_backend);
512 }
513
514 void
515 xenbus_unregister_driver(struct xenbus_driver *drv)
516 {
517 driver_unregister(&drv->driver);
518 }
519
520 struct xb_find_info
521 {
522 struct xenbus_device *dev;
523 const char *nodename;
524 };
525
526 static int
527 cmp_dev(struct device *dev, void *data)
528 {
529 struct xenbus_device *xendev = to_xenbus_device(dev);
530 struct xb_find_info *info = data;
531
532 if (streq(xendev->xbusd_path, info->nodename)) {
533 info->dev = xendev;
534 get_device(dev);
535 return 1;
536 }
537 return 0;
538 }
539
540 struct xenbus_device *
541 xenbus_device_find(const char *nodename, struct bus_type *bus)
542 {
543 struct xb_find_info info = { .dev = NULL, .nodename = nodename };
544
545 bus_for_each_dev(bus, NULL, &info, cmp_dev);
546 return info.dev;
547 }
548
549 static int
550 cleanup_dev(struct device *dev, void *data)
551 {
552 struct xenbus_device *xendev = to_xenbus_device(dev);
553 struct xb_find_info *info = data;
554 int len = strlen(info->nodename);
555
556 DPRINTK("%s", info->nodename);
557
558 if (!strncmp(xendev->xbusd_path, info->nodename, len)) {
559 info->dev = xendev;
560 get_device(dev);
561 return 1;
562 }
563 return 0;
564 }
565
566 static void
567 xenbus_cleanup_devices(const char *path, struct bus_type *bus)
568 {
569 struct xb_find_info info = { .nodename = path };
570
571 do {
572 info.dev = NULL;
573 bus_for_each_dev(bus, NULL, &info, cleanup_dev);
574 if (info.dev) {
575 device_unregister(&info.dev->dev);
576 put_device(&info.dev->dev);
577 }
578 } while (info.dev);
579 }
580
581 static void
582 xenbus_dev_free(struct xenbus_device *xendev)
583 {
584 free(xendev, M_DEVBUF);
585 }
586
587 static void
588 xenbus_dev_release(struct device *dev)
589 {
590 if (dev) {
591 xenbus_dev_free(to_xenbus_device(dev));
592 }
593 }
594
595 /* Simplified asprintf. */
596 static char *kasprintf(const char *fmt, ...)
597 {
598 va_list ap;
599 unsigned int len;
600 char *p, dummy[1];
601
602 va_start(ap, fmt);
603 /* FIXME: vsnprintf has a bug, NULL should work */
604 len = vsnprintf(dummy, 0, fmt, ap);
605 va_end(ap);
606
607 p = malloc(len + 1, M_DEVBUF, M_NOWAIT);
608 if (!p)
609 return NULL;
610 va_start(ap, fmt);
611 vsprintf(p, fmt, ap);
612 va_end(ap);
613 return p;
614 }
615 #endif
616
617 #if 0
618 static ssize_t
619 xendev_show_nodename(struct device *dev, char *buf)
620 {
621 return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
622 }
623 // XXX implement
624 DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
625
626 static ssize_t
627 xendev_show_devtype(struct device *dev, char *buf)
628 {
629 return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
630 }
631 DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
632
633
634 static int
635 xenbus_probe_node(struct xen_bus_type *bus,
636 const char *type,
637 const char *nodename)
638 {
639 #define CHECK_FAIL \
640 do { \
641 if (err) \
642 goto fail; \
643 } \
644 while (0) \
645
646
647 struct xenbus_device *xendev;
648 size_t stringlen;
649 char *tmpstring;
650
651 XenbusState state = xenbus_read_driver_state(nodename);
652
653 printf("xenbus_probe_node %s %s %s %d\n", bus->root, type, nodename, state);
654 if (state != XenbusStateInitialising) {
655 /* Device is not new, so ignore it. This can happen if a
656 device is going away after switching to Closed. */
657 return 0;
658 }
659
660
661 stringlen = strlen(nodename) + 1 + strlen(type) + 1;
662 xendev = malloc(sizeof(*xendev) + stringlen, M_DEVBUF, M_NOWAIT);
663 if (!xendev)
664 return ENOMEM;
665 memset(xendev, 0, sizeof(*xendev));
666
667 /* Copy the strings into the extra space. */
668
669 tmpstring = (char *)(xendev + 1);
670 strcpy(tmpstring, nodename);
671 xendev->nodename = tmpstring;
672
673 tmpstring += strlen(tmpstring) + 1;
674 strcpy(tmpstring, type);
675 xendev->devicetype = tmpstring;
676
677 #if 0
678 xendev->dev.parent = &bus->dev;
679 xendev->dev.bus = &bus->bus;
680 xendev->dev.release = xenbus_dev_release;
681
682 err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
683 CHECK_FAIL;
684
685 /* Register with generic device framework. */
686 err = device_register(&xendev->dev);
687 CHECK_FAIL;
688
689 device_create_file(&xendev->dev, &dev_attr_nodename);
690 device_create_file(&xendev->dev, &dev_attr_devtype);
691
692 #endif
693 return 0;
694
695 #undef CHECK_FAIL
696 #if 0
697 fail:
698 xenbus_dev_free(xendev);
699 return err;
700 #endif
701 }
702 #endif
703
704 #if 0
705 /* device/<typename>/<name> */
706 static int
707 xenbus_probe_frontend(const char *type, const char *name)
708 {
709 char *nodename;
710 int err;
711
712 nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name);
713 if (!nodename)
714 return ENOMEM;
715
716 DPRINTK("%s", nodename);
717
718 err = xenbus_probe_node(&xenbus_frontend, type, nodename);
719 free(nodename, M_DEVBUF);
720 return err;
721 }
722
723 /* backend/<typename>/<frontend-uuid>/<name> */
724 static int
725 xenbus_probe_backend_unit(const char *dir,
726 const char *type,
727 const char *name)
728 {
729 char *nodename;
730 int err;
731
732 nodename = kasprintf("%s/%s", dir, name);
733 if (!nodename)
734 return ENOMEM;
735
736 DPRINTK("%s", nodename);
737
738 err = xenbus_probe_node(&xenbus_backend, type, nodename);
739 free(nodename, M_DEVBUF);
740 return err;
741 }
742
743 /* backend/<typename>/<frontend-domid> */
744 static int
745 xenbus_probe_backend(const char *type, const char *domid)
746 {
747 char *nodename;
748 int err;
749 char **dir;
750 unsigned int i, dir_n = 0;
751
752 DPRINTK("");
753
754 nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, domid);
755 if (!nodename)
756 return ENOMEM;
757
758 err = xenbus_directory(NULL, nodename, "", &dir_n, &dir);
759 DPRINTK("xenbus_probe_backend err %d dir_n %d", err, dir_n);
760 if (err) {
761 free(nodename, M_DEVBUF);
762 return err;
763 }
764
765 for (i = 0; i < dir_n; i++) {
766 err = xenbus_probe_backend_unit(nodename, type, dir[i]);
767 if (err)
768 break;
769 }
770 free(dir, M_DEVBUF);
771 free(nodename, M_DEVBUF);
772 return err;
773 }
774 #endif
775
776 static struct xenbus_device *
777 xenbus_lookup_device_path(const char *path)
778 {
779 struct xenbus_device *xbusd;
780
781 SLIST_FOREACH(xbusd, &xenbus_device_list, xbusd_entries) {
782 if (strcmp(xbusd->xbusd_path, path) == 0)
783 return xbusd;
784 }
785 return NULL;
786 }
787
788 static int
789 xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
790 {
791 int err;
792 char **dir;
793 unsigned int dir_n = 0;
794 int i;
795 struct xenbus_device *xbusd;
796 struct xenbusdev_attach_args xa;
797 char *ep;
798
799 DPRINTK("probe %s type %s", bus->root, type);
800 err = xenbus_directory(NULL, bus->root, type, &dir_n, &dir);
801 DPRINTK("directory err %d dir_n %d", err, dir_n);
802 if (err)
803 return err;
804
805 for (i = 0; i < dir_n; i++) {
806 int msize;
807 /*
808 * add size of path to size of xenbus_device. xenbus_device
809 * already has room for one char in xbusd_path.
810 */
811 msize = sizeof(*xbusd) + strlen(bus->root) + strlen(type)
812 + strlen(dir[i]) + 2;
813 xbusd = malloc(msize, M_DEVBUF, M_WAITOK | M_ZERO);
814 if (xbusd == NULL)
815 panic("can't malloc xbusd");
816
817 snprintf(__UNCONST(xbusd->xbusd_path),
818 msize - sizeof(*xbusd) + 1, "%s/%s/%s",
819 bus->root, type, dir[i]);
820 if (xenbus_lookup_device_path(xbusd->xbusd_path) != NULL) {
821 /* device already registered */
822 free(xbusd, M_DEVBUF);
823 continue;
824 }
825
826 xbusd->xbusd_otherend_watch.xbw_dev = xbusd;
827 DPRINTK("xenbus_probe_device_type probe %s\n",
828 xbusd->xbusd_path);
829 xa.xa_xbusd = xbusd;
830 xa.xa_type = type;
831 xa.xa_id = strtoul(dir[i], &ep, 0);
832 if (dir[i][0] == '\0' || *ep != '\0') {
833 printf("xenbus device type %s: id %s is not a number\n",
834 type, dir[i]);
835 err = EFTYPE;
836 free(xbusd, M_DEVBUF);
837 break;
838 }
839 err = read_backend_details(xbusd);
840 if (err != 0) {
841 printf("xenbus: can't get backend details "
842 "for %s (%d)\n", xbusd->xbusd_path, err);
843 break;
844 }
845 xbusd->xbusd_dev = config_found_ia(xenbus_sc, "xenbus", &xa,
846 xenbus_print);
847 if (xbusd->xbusd_dev == NULL)
848 free(xbusd, M_DEVBUF);
849 else {
850 SLIST_INSERT_HEAD(&xenbus_device_list,
851 xbusd, xbusd_entries);
852 talk_to_otherend(xbusd);
853 }
854 }
855 free(dir, M_DEVBUF);
856 return err;
857 }
858
859 static int
860 xenbus_print(void *aux, const char *pnp)
861 {
862 struct xenbusdev_attach_args *xa = aux;
863
864 if (pnp) {
865 if (strcmp(xa->xa_type, "vbd") == 0)
866 aprint_normal("xbd");
867 else if (strcmp(xa->xa_type, "vif") == 0)
868 aprint_normal("xennet");
869 else
870 aprint_normal("unknown type %s", xa->xa_type);
871 aprint_normal(" at %s", pnp);
872 }
873 aprint_normal(" id %d", xa->xa_id);
874 return(UNCONF);
875 }
876
877 static int
878 xenbus_probe_devices(struct xen_bus_type *bus)
879 {
880 int err;
881 char **dir;
882 unsigned int i, dir_n;
883
884 DPRINTK("probe %s", bus->root);
885 err = xenbus_directory(NULL, bus->root, "", &dir_n, &dir);
886 DPRINTK("directory err %d dir_n %d", err, dir_n);
887 if (err)
888 return err;
889
890 for (i = 0; i < dir_n; i++) {
891 err = xenbus_probe_device_type(bus, dir[i]);
892 if (err)
893 break;
894 }
895 free(dir, M_DEVBUF);
896 return err;
897 }
898
899 int
900 xenbus_free_device(struct xenbus_device *xbusd)
901 {
902 KASSERT(xenbus_lookup_device_path(xbusd->xbusd_path) == xbusd);
903 SLIST_REMOVE(&xenbus_device_list, xbusd, xenbus_device, xbusd_entries);
904 free_otherend_watch(xbusd);
905 free(xbusd->xbusd_otherend, M_DEVBUF);
906 xenbus_switch_state(xbusd, NULL, XenbusStateClosed);
907 free(xbusd, M_DEVBUF);
908 return 0;
909 }
910
911 #if 0
912 static unsigned int
913 char_count(const char *str, char c)
914 {
915 unsigned int i, ret = 0;
916
917 for (i = 0; str[i]; i++)
918 if (str[i] == c)
919 ret++;
920 return ret;
921 }
922
923 static int
924 strsep_len(const char *str, char c, unsigned int len)
925 {
926 unsigned int i;
927
928 for (i = 0; str[i]; i++)
929 if (str[i] == c) {
930 if (len == 0)
931 return i;
932 len--;
933 }
934 return (len == 0) ? i : -ERANGE;
935 }
936
937 static void
938 dev_changed(const char *node, struct xen_bus_type *bus)
939 {
940 int exists, rootlen;
941 struct xenbus_device *dev;
942 char type[BUS_ID_SIZE];
943 const char *p, *root;
944
945 if (char_count(node, '/') < 2)
946 return;
947
948 exists = xenbus_exists(NULL, node, "");
949 if (!exists) {
950 xenbus_cleanup_devices(node, &bus->bus);
951 return;
952 }
953
954 /* backend/<type>/... or device/<type>/... */
955 p = strchr(node, '/') + 1;
956 snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
957 type[BUS_ID_SIZE-1] = '\0';
958
959 rootlen = strsep_len(node, '/', bus->levels);
960 if (rootlen < 0)
961 return;
962 root = kasprintf("%.*s", rootlen, node);
963 if (!root)
964 return;
965
966 dev = xenbus_device_find(root, &bus->bus);
967 if (!dev)
968 xenbus_probe_node(bus, type, root);
969 else
970 put_device(&dev->dev);
971
972 free(root, M_DEVBUF);
973 }
974 #endif
975
976 static void
977 frontend_changed(struct xenbus_watch *watch,
978 const char **vec, unsigned int len)
979 {
980 DPRINTK("");
981 //printf("frontend_changed %s\n", vec[XS_WATCH_PATH]);
982 xenbus_probe_devices(&xenbus_frontend);
983 }
984
985 static void
986 backend_changed(struct xenbus_watch *watch,
987 const char **vec, unsigned int len)
988 {
989 DPRINTK("");
990
991 printf("backend_changed %s\n", vec[XS_WATCH_PATH]);
992 //dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
993 }
994
995
996 /* We watch for devices appearing and vanishing. */
997 static struct xenbus_watch fe_watch;
998
999 static struct xenbus_watch be_watch;
1000
1001 #if 0
1002 static int suspend_dev(struct device *dev, void *data)
1003 {
1004 int err = 0;
1005 struct xenbus_driver *drv;
1006 struct xenbus_device *xdev;
1007
1008 DPRINTK("");
1009
1010 if (dev->driver == NULL)
1011 return 0;
1012 drv = to_xenbus_driver(dev->driver);
1013 xdev = container_of(dev, struct xenbus_device, dev);
1014 if (drv->suspend)
1015 err = drv->suspend(xdev);
1016 if (err)
1017 printk(KERN_WARNING
1018 "xenbus: suspend %s failed: %i\n", dev->bus_id, err);
1019 return 0;
1020 }
1021
1022 static int
1023 resume_dev(struct device *dev, void *data)
1024 {
1025 int err;
1026 struct xenbus_driver *drv;
1027 struct xenbus_device *xdev;
1028
1029 DPRINTK("");
1030
1031 if (dev->driver == NULL)
1032 return 0;
1033 drv = to_xenbus_driver(dev->driver);
1034 xdev = container_of(dev, struct xenbus_device, dev);
1035
1036 err = talk_to_otherend(xdev);
1037 if (err) {
1038 printk(KERN_WARNING
1039 "xenbus: resume (talk_to_otherend) %s failed: %i\n",
1040 dev->bus_id, err);
1041 return err;
1042 }
1043
1044 if (drv->resume)
1045 err = drv->resume(xdev);
1046 if (err)
1047 printk(KERN_WARNING
1048 "xenbus: resume %s failed: %i\n", dev->bus_id, err);
1049 return err;
1050 }
1051
1052 void
1053 xenbus_suspend(void)
1054 {
1055 DPRINTK("");
1056
1057 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
1058 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
1059 xs_suspend();
1060 }
1061
1062 void xenbus_resume(struct device *dev)
1063 {
1064 xb_init_comms(dev);
1065 xs_resume();
1066 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
1067 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
1068 }
1069 #endif
1070
1071
1072 /* A flag to determine if xenstored is 'ready' (i.e. has started) */
1073 int xenstored_ready = 0;
1074
1075
1076 #if 0
1077 int
1078 register_xenstore_notifier(struct notifier_block *nb)
1079 {
1080 int ret = 0;
1081
1082 if (xenstored_ready > 0)
1083 ret = nb->notifier_call(nb, 0, NULL);
1084 else
1085 notifier_chain_register(&xenstore_chain, nb);
1086
1087 return ret;
1088 }
1089
1090 void unregister_xenstore_notifier(struct notifier_block *nb)
1091 {
1092 notifier_chain_unregister(&xenstore_chain, nb);
1093 }
1094 #endif
1095
1096
1097
1098 void
1099 xenbus_probe(void *unused)
1100 {
1101 KASSERT((xenstored_ready > 0));
1102
1103 /* Enumerate devices in xenstore. */
1104 xenbus_probe_devices(&xenbus_frontend);
1105 xenbus_probe_devices(&xenbus_backend);
1106
1107 /* Watch for changes. */
1108 fe_watch.node = malloc(strlen("device" + 1), M_DEVBUF, M_NOWAIT);
1109 strcpy(fe_watch.node, "device");
1110 fe_watch.xbw_callback = frontend_changed;
1111 register_xenbus_watch(&fe_watch);
1112 be_watch.node = malloc(strlen("backend" + 1), M_DEVBUF, M_NOWAIT);
1113 strcpy(be_watch.node, "backend");
1114 be_watch.xbw_callback = backend_changed;
1115 register_xenbus_watch(&be_watch);
1116
1117 /* Notify others that xenstore is up */
1118 //notifier_call_chain(&xenstore_chain, 0, NULL);
1119 }
1120
1121 static void
1122 xenbus_probe_init(void *unused)
1123 {
1124 int err = 0, dom0;
1125
1126 DPRINTK("");
1127
1128 SLIST_INIT(&xenbus_device_list);
1129
1130 /*
1131 ** Domain0 doesn't have a store_evtchn or store_mfn yet.
1132 */
1133 dom0 = (xen_start_info.store_evtchn == 0);
1134 if (dom0) {
1135 #if defined(DOM0OPS)
1136 vaddr_t page;
1137 paddr_t ma;
1138 evtchn_op_t op = { 0 };
1139 int ret;
1140
1141 /* Allocate page. */
1142 page = uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
1143 UVM_KMF_ZERO | UVM_KMF_WIRED);
1144 if (!page)
1145 panic("can't get xenstore page");
1146
1147 (void)pmap_extract_ma(pmap_kernel(), page, &ma);
1148 xen_start_info.store_mfn = ma >> PAGE_SHIFT;
1149 xenstore_interface = (void *)page;
1150
1151 /* Next allocate a local port which xenstored can bind to */
1152 op.cmd = EVTCHNOP_alloc_unbound;
1153 op.u.alloc_unbound.dom = DOMID_SELF;
1154 op.u.alloc_unbound.remote_dom = 0;
1155
1156 ret = HYPERVISOR_event_channel_op(&op);
1157 if (ret)
1158 panic("can't register xenstore event");
1159 xen_start_info.store_evtchn = op.u.alloc_unbound.port;
1160
1161 /* And finally publish the above info in /kern/xen */
1162 xenbus_kernfs_init();
1163 #else /* DOM0OPS */
1164 return ; /* can't get a working xenstore in this case */
1165 #endif /* DOM0OPS */
1166 }
1167
1168 /* Initialize the interface to xenstore. */
1169 err = xs_init();
1170 if (err) {
1171 printf("XENBUS: Error initializing xenstore comms: %i\n", err);
1172 kthread_exit(err);
1173 }
1174
1175 if (!dom0) {
1176 xenstored_ready = 1;
1177 xenbus_probe(NULL);
1178 }
1179
1180 DPRINTK("done");
1181 config_pending_decr();
1182 kthread_exit(0);
1183 }
1184
1185 /*
1186 * Local variables:
1187 * c-file-style: "linux"
1188 * indent-tabs-mode: t
1189 * c-indent-level: 8
1190 * c-basic-offset: 8
1191 * tab-width: 8
1192 * End:
1193 */
1194