]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/xen/xenbus/xenbus_probe.c
Copy head to stable/8 as part of 8.0 Release cycle.
[FreeBSD/stable/8.git] / sys / xen / xenbus / xenbus_probe.c
1 /******************************************************************************
2  * Talks to Xen Store to figure out what devices we have.
3  *
4  * Copyright (C) 2008 Doug Rabson
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 #if 0
32 #define DPRINTK(fmt, args...) \
33     printf("xenbus_probe (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
34 #else
35 #define DPRINTK(fmt, args...) ((void)0)
36 #endif
37
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <sys/param.h>
42 #include <sys/bus.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/module.h>
47 #include <sys/sysctl.h>
48 #include <sys/syslog.h>
49 #include <sys/systm.h>
50 #include <sys/sx.h>
51 #include <sys/taskqueue.h>
52
53 #include <machine/xen/xen-os.h>
54 #include <machine/stdarg.h>
55
56 #include <xen/gnttab.h>
57 #include <xen/xenbus/xenbusvar.h>
58 #include <xen/xenbus/xenbus_comms.h>
59
60 struct xenbus_softc {
61         struct xenbus_watch xs_devicewatch;
62         struct task     xs_probechildren;
63         struct intr_config_hook xs_attachcb;
64         device_t        xs_dev;
65 };
66
67 struct xenbus_device_ivars {
68         struct xenbus_watch xd_otherend_watch; /* must be first */
69         struct sx       xd_lock;
70         device_t        xd_dev;
71         char            *xd_node;       /* node name in xenstore */
72         char            *xd_type;       /* xen device type */
73         enum xenbus_state xd_state;
74         int             xd_otherend_id;
75         char            *xd_otherend_path;
76 };
77
78 /* Simplified asprintf. */
79 char *
80 kasprintf(const char *fmt, ...)
81 {
82         va_list ap;
83         unsigned int len;
84         char *p, dummy[1];
85
86         va_start(ap, fmt);
87         /* FIXME: vsnprintf has a bug, NULL should work */
88         len = vsnprintf(dummy, 0, fmt, ap);
89         va_end(ap);
90
91         p = malloc(len + 1, M_DEVBUF, M_WAITOK);
92         va_start(ap, fmt);
93         vsprintf(p, fmt, ap);
94         va_end(ap);
95         return p;
96 }
97
98 static void
99 xenbus_identify(driver_t *driver, device_t parent)
100 {
101
102         BUS_ADD_CHILD(parent, 0, "xenbus", 0);
103 }
104
105 static int 
106 xenbus_probe(device_t dev)
107 {
108         int err = 0;
109
110         DPRINTK("");
111
112         /* Initialize the interface to xenstore. */
113         err = xs_init(); 
114         if (err) {
115                 log(LOG_WARNING,
116                     "XENBUS: Error initializing xenstore comms: %i\n", err);
117                 return (ENXIO);
118         }
119         err = gnttab_init();
120         if (err) {
121                 log(LOG_WARNING,
122                     "XENBUS: Error initializing grant table: %i\n", err);
123                 return (ENXIO);
124         }
125         device_set_desc(dev, "Xen Devices");
126
127         return (0);
128 }
129
130 static enum xenbus_state
131 xenbus_otherend_state(struct xenbus_device_ivars *ivars)
132 {
133
134         return (xenbus_read_driver_state(ivars->xd_otherend_path));
135 }
136
137 static void
138 xenbus_backend_changed(struct xenbus_watch *watch, const char **vec,
139     unsigned int len)
140 {
141         struct xenbus_device_ivars *ivars;
142         device_t dev;
143         enum xenbus_state newstate;
144
145         ivars = (struct xenbus_device_ivars *) watch;
146         dev = ivars->xd_dev;
147
148         if (!ivars->xd_otherend_path
149             || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH],
150                 strlen(ivars->xd_otherend_path)))
151                 return;
152
153         newstate = xenbus_otherend_state(ivars);
154         XENBUS_BACKEND_CHANGED(dev, newstate);
155 }
156
157 static int
158 xenbus_device_exists(device_t dev, const char *node)
159 {
160         device_t *kids;
161         struct xenbus_device_ivars *ivars;
162         int i, count, result;
163
164         if (device_get_children(dev, &kids, &count))
165                 return (FALSE);
166
167         result = FALSE;
168         for (i = 0; i < count; i++) {
169                 ivars = device_get_ivars(kids[i]);
170                 if (!strcmp(ivars->xd_node, node)) {
171                         result = TRUE;
172                         break;
173                 }
174         }
175         free(kids, M_TEMP);
176
177         return (result);
178 }
179
180 static int
181 xenbus_add_device(device_t dev, const char *bus,
182     const char *type, const char *id)
183 {
184         device_t child;
185         struct xenbus_device_ivars *ivars;
186         enum xenbus_state state;
187         char *statepath;
188         int error;
189
190         ivars = malloc(sizeof(struct xenbus_device_ivars),
191             M_DEVBUF, M_ZERO|M_WAITOK);
192         ivars->xd_node = kasprintf("%s/%s/%s", bus, type, id);
193
194         if (xenbus_device_exists(dev, ivars->xd_node)) {
195                 /*
196                  * We are already tracking this node
197                  */
198                 free(ivars->xd_node, M_DEVBUF);
199                 free(ivars, M_DEVBUF);
200                 return (0);
201         }
202
203         state = xenbus_read_driver_state(ivars->xd_node);
204
205         if (state != XenbusStateInitialising) {
206                 /*
207                  * Device is not new, so ignore it. This can
208                  * happen if a device is going away after
209                  * switching to Closed.
210                  */
211                 free(ivars->xd_node, M_DEVBUF);
212                 free(ivars, M_DEVBUF);
213                 return (0);
214         }
215
216         /*
217          * Find the backend details
218          */
219         error = xenbus_gather(XBT_NIL, ivars->xd_node,
220             "backend-id", "%i", &ivars->xd_otherend_id,
221             "backend", NULL, &ivars->xd_otherend_path,
222             NULL);
223         if (error)
224                 return (error);
225
226         sx_init(&ivars->xd_lock, "xdlock");
227         ivars->xd_type = strdup(type, M_DEVBUF);
228         ivars->xd_state = XenbusStateInitialising;
229
230         statepath = malloc(strlen(ivars->xd_otherend_path)
231             + strlen("/state") + 1, M_DEVBUF, M_WAITOK);
232         sprintf(statepath, "%s/state", ivars->xd_otherend_path);
233
234         ivars->xd_otherend_watch.node = statepath;
235         ivars->xd_otherend_watch.callback = xenbus_backend_changed;
236
237         child = device_add_child(dev, NULL, -1);
238         ivars->xd_dev = child;
239         device_set_ivars(child, ivars);
240
241         return (0);
242 }
243
244 static int
245 xenbus_enumerate_type(device_t dev, const char *bus, const char *type)
246 {
247         char **dir;
248         unsigned int i, count;
249         int error;
250
251         error = xenbus_directory(XBT_NIL, bus, type, &count, &dir);
252         if (error)
253                 return (error);
254         for (i = 0; i < count; i++)
255                 xenbus_add_device(dev, bus, type, dir[i]);
256
257         free(dir, M_DEVBUF);
258
259         return (0);
260 }
261
262 static int
263 xenbus_enumerate_bus(device_t dev, const char *bus)
264 {
265         char **dir;
266         unsigned int i, count;
267         int error;
268
269         error = xenbus_directory(XBT_NIL, bus, "", &count, &dir);
270         if (error)
271                 return (error);
272         for (i = 0; i < count; i++) {
273                 xenbus_enumerate_type(dev, bus, dir[i]);
274         }
275         free(dir, M_DEVBUF);
276
277         return (0);
278 }
279
280 static int
281 xenbus_probe_children(device_t dev)
282 {
283         device_t *kids;
284         struct xenbus_device_ivars *ivars;
285         int i, count;
286
287         /*
288          * Probe any new devices and register watches for any that
289          * attach successfully. Since part of the protocol which
290          * establishes a connection with the other end is interrupt
291          * driven, we sleep until the device reaches a stable state
292          * (closed or connected).
293          */
294         if (device_get_children(dev, &kids, &count) == 0) {
295                 for (i = 0; i < count; i++) {
296                         if (device_get_state(kids[i]) != DS_NOTPRESENT)
297                                 continue;
298
299                         if (device_probe_and_attach(kids[i]))
300                                 continue;
301                         ivars = device_get_ivars(kids[i]);
302                         register_xenbus_watch(
303                                 &ivars->xd_otherend_watch);
304                         sx_xlock(&ivars->xd_lock);
305                         while (ivars->xd_state != XenbusStateClosed
306                             && ivars->xd_state != XenbusStateConnected)
307                                 sx_sleep(&ivars->xd_state, &ivars->xd_lock,
308                                     0, "xdattach", 0);
309                         sx_xunlock(&ivars->xd_lock);
310                 }
311                 free(kids, M_TEMP);
312         }
313
314         return (0);
315 }
316
317 static void
318 xenbus_probe_children_cb(void *arg, int pending)
319 {
320         device_t dev = (device_t) arg;
321
322         xenbus_probe_children(dev);
323 }
324
325 static void
326 xenbus_devices_changed(struct xenbus_watch *watch,
327     const char **vec, unsigned int len)
328 {
329         struct xenbus_softc *sc = (struct xenbus_softc *) watch;
330         device_t dev = sc->xs_dev;
331         char *node, *bus, *type, *id, *p;
332
333         node = strdup(vec[XS_WATCH_PATH], M_DEVBUF);;
334         p = strchr(node, '/');
335         if (!p)
336                 goto out;
337         bus = node;
338         *p = 0;
339         type = p + 1;
340
341         p = strchr(type, '/');
342         if (!p)
343                 goto out;
344         *p = 0;
345         id = p + 1;
346
347         p = strchr(id, '/');
348         if (p)
349                 *p = 0;
350
351         newbus_xlock();
352         xenbus_add_device(dev, bus, type, id);
353         newbus_xunlock();
354         taskqueue_enqueue(taskqueue_thread, &sc->xs_probechildren);
355 out:
356         free(node, M_DEVBUF);
357 }
358
359 static void
360 xenbus_attach_deferred(void *arg)
361 {
362         device_t dev = (device_t) arg;
363         struct xenbus_softc *sc = device_get_softc(dev);
364         int error;
365         
366         newbus_xlock();
367         error = xenbus_enumerate_bus(dev, "device");
368         newbus_xunlock();
369         if (error)
370                 return;
371         xenbus_probe_children(dev);
372
373         sc->xs_dev = dev;
374         sc->xs_devicewatch.node = "device";
375         sc->xs_devicewatch.callback = xenbus_devices_changed;
376
377         TASK_INIT(&sc->xs_probechildren, 0, xenbus_probe_children_cb, dev);
378
379         register_xenbus_watch(&sc->xs_devicewatch);
380
381         config_intrhook_disestablish(&sc->xs_attachcb);
382 }
383
384 static int
385 xenbus_attach(device_t dev)
386 {
387         struct xenbus_softc *sc = device_get_softc(dev);
388
389         sc->xs_attachcb.ich_func = xenbus_attach_deferred;
390         sc->xs_attachcb.ich_arg = dev;
391         config_intrhook_establish(&sc->xs_attachcb);
392
393         return (0);
394 }
395
396 static int
397 xenbus_suspend(device_t dev)
398 {
399         int error;
400
401         DPRINTK("");
402
403         error = bus_generic_suspend(dev);
404         if (error)
405                 return (error);
406
407         xs_suspend();
408
409         return (0);
410 }
411
412 static int
413 xenbus_resume(device_t dev)
414 {
415         device_t *kids;
416         struct xenbus_device_ivars *ivars;
417         int i, count, error;
418         char *statepath;
419
420         xb_init_comms();
421         xs_resume();
422
423         /*
424          * We must re-examine each device and find the new path for
425          * its backend.
426          */
427         if (device_get_children(dev, &kids, &count) == 0) {
428                 for (i = 0; i < count; i++) {
429                         if (device_get_state(kids[i]) == DS_NOTPRESENT)
430                                 continue;
431
432                         ivars = device_get_ivars(kids[i]);
433
434                         unregister_xenbus_watch(
435                                 &ivars->xd_otherend_watch);
436                         ivars->xd_state = XenbusStateInitialising;
437
438                         /*
439                          * Find the new backend details and
440                          * re-register our watch.
441                          */
442                         free(ivars->xd_otherend_path, M_DEVBUF);
443                         error = xenbus_gather(XBT_NIL, ivars->xd_node,
444                             "backend-id", "%i", &ivars->xd_otherend_id,
445                             "backend", NULL, &ivars->xd_otherend_path,
446                             NULL);
447                         if (error)
448                                 return (error);
449
450                         DEVICE_RESUME(kids[i]);
451
452                         statepath = malloc(strlen(ivars->xd_otherend_path)
453                             + strlen("/state") + 1, M_DEVBUF, M_WAITOK);
454                         sprintf(statepath, "%s/state", ivars->xd_otherend_path);
455
456                         free(ivars->xd_otherend_watch.node, M_DEVBUF);
457                         ivars->xd_otherend_watch.node = statepath;
458                         register_xenbus_watch(
459                                 &ivars->xd_otherend_watch);
460
461 #if 0
462                         /*
463                          * Can't do this yet since we are running in
464                          * the xenwatch thread and if we sleep here,
465                          * we will stop delivering watch notifications
466                          * and the device will never come back online.
467                          */
468                         sx_xlock(&ivars->xd_lock);
469                         while (ivars->xd_state != XenbusStateClosed
470                             && ivars->xd_state != XenbusStateConnected)
471                                 sx_sleep(&ivars->xd_state, &ivars->xd_lock,
472                                     0, "xdresume", 0);
473                         sx_xunlock(&ivars->xd_lock);
474 #endif
475                 }
476                 free(kids, M_TEMP);
477         }
478
479         return (0);
480 }
481
482 static int
483 xenbus_print_child(device_t dev, device_t child)
484 {
485         struct xenbus_device_ivars *ivars = device_get_ivars(child);
486         int     retval = 0;
487
488         retval += bus_print_child_header(dev, child);
489         retval += printf(" at %s", ivars->xd_node);
490         retval += bus_print_child_footer(dev, child);
491
492         return (retval);
493 }
494
495 static int
496 xenbus_read_ivar(device_t dev, device_t child, int index,
497     uintptr_t * result)
498 {
499         struct xenbus_device_ivars *ivars = device_get_ivars(child);
500
501         switch (index) {
502         case XENBUS_IVAR_NODE:
503                 *result = (uintptr_t) ivars->xd_node;
504                 return (0);
505
506         case XENBUS_IVAR_TYPE:
507                 *result = (uintptr_t) ivars->xd_type;
508                 return (0);
509
510         case XENBUS_IVAR_STATE:
511                 *result = (uintptr_t) ivars->xd_state;
512                 return (0);
513
514         case XENBUS_IVAR_OTHEREND_ID:
515                 *result = (uintptr_t) ivars->xd_otherend_id;
516                 return (0);
517
518         case XENBUS_IVAR_OTHEREND_PATH:
519                 *result = (uintptr_t) ivars->xd_otherend_path;
520                 return (0);
521         }
522
523         return (ENOENT);
524 }
525
526 static int
527 xenbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
528 {
529         struct xenbus_device_ivars *ivars = device_get_ivars(child);
530         enum xenbus_state newstate;
531         int currstate;
532         int error;
533
534         switch (index) {
535         case XENBUS_IVAR_STATE:
536                 newstate = (enum xenbus_state) value;
537                 sx_xlock(&ivars->xd_lock);
538                 if (ivars->xd_state == newstate)
539                         goto out;
540
541                 error = xenbus_scanf(XBT_NIL, ivars->xd_node, "state",
542                     NULL, "%d", &currstate);
543                 if (error)
544                         goto out;
545
546                 error = xenbus_printf(XBT_NIL, ivars->xd_node, "state",
547                     "%d", newstate);
548                 if (error) {
549                         if (newstate != XenbusStateClosing) /* Avoid looping */
550                                 xenbus_dev_fatal(dev, error, "writing new state");
551                         goto out;
552                 }
553                 ivars->xd_state = newstate;
554                 wakeup(&ivars->xd_state);
555         out:
556                 sx_xunlock(&ivars->xd_lock);
557                 return (0);
558
559         case XENBUS_IVAR_NODE:
560         case XENBUS_IVAR_TYPE:
561         case XENBUS_IVAR_OTHEREND_ID:
562         case XENBUS_IVAR_OTHEREND_PATH:
563                 /*
564                  * These variables are read-only.
565                  */
566                 return (EINVAL);
567         }
568
569         return (ENOENT);
570 }
571
572 SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen");
573 SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xen_store_evtchn, 0, "");
574 SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, "");
575
576 static device_method_t xenbus_methods[] = { 
577         /* Device interface */ 
578         DEVMETHOD(device_identify,      xenbus_identify),
579         DEVMETHOD(device_probe,         xenbus_probe), 
580         DEVMETHOD(device_attach,        xenbus_attach), 
581         DEVMETHOD(device_detach,        bus_generic_detach), 
582         DEVMETHOD(device_shutdown,      bus_generic_shutdown), 
583         DEVMETHOD(device_suspend,       xenbus_suspend), 
584         DEVMETHOD(device_resume,        xenbus_resume), 
585  
586         /* Bus interface */ 
587         DEVMETHOD(bus_print_child,      xenbus_print_child),
588         DEVMETHOD(bus_read_ivar,        xenbus_read_ivar), 
589         DEVMETHOD(bus_write_ivar,       xenbus_write_ivar), 
590  
591         { 0, 0 } 
592 }; 
593
594 static char driver_name[] = "xenbus";
595 static driver_t xenbus_driver = { 
596         driver_name, 
597         xenbus_methods, 
598         sizeof(struct xenbus_softc),
599 }; 
600 devclass_t xenbus_devclass; 
601  
602 #ifdef XENHVM
603 DRIVER_MODULE(xenbus, xenpci, xenbus_driver, xenbus_devclass, 0, 0);
604 #else
605 DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0);
606 #endif