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