]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/xen/xenbus/xenbus_probe.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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         xenbus_add_device(dev, bus, type, id);
352         taskqueue_enqueue(taskqueue_thread, &sc->xs_probechildren);
353 out:
354         free(node, M_DEVBUF);
355 }
356
357 static void
358 xenbus_attach_deferred(void *arg)
359 {
360         device_t dev = (device_t) arg;
361         struct xenbus_softc *sc = device_get_softc(dev);
362         int error;
363         
364         error = xenbus_enumerate_bus(dev, "device");
365         if (error)
366                 return;
367         xenbus_probe_children(dev);
368
369         sc->xs_dev = dev;
370         sc->xs_devicewatch.node = "device";
371         sc->xs_devicewatch.callback = xenbus_devices_changed;
372
373         TASK_INIT(&sc->xs_probechildren, 0, xenbus_probe_children_cb, dev);
374
375         register_xenbus_watch(&sc->xs_devicewatch);
376
377         config_intrhook_disestablish(&sc->xs_attachcb);
378 }
379
380 static int
381 xenbus_attach(device_t dev)
382 {
383         struct xenbus_softc *sc = device_get_softc(dev);
384
385         sc->xs_attachcb.ich_func = xenbus_attach_deferred;
386         sc->xs_attachcb.ich_arg = dev;
387         config_intrhook_establish(&sc->xs_attachcb);
388
389         return (0);
390 }
391
392 static int
393 xenbus_suspend(device_t dev)
394 {
395         int error;
396
397         DPRINTK("");
398
399         error = bus_generic_suspend(dev);
400         if (error)
401                 return (error);
402
403         xs_suspend();
404
405         return (0);
406 }
407
408 static int
409 xenbus_resume(device_t dev)
410 {
411         device_t *kids;
412         struct xenbus_device_ivars *ivars;
413         int i, count, error;
414         char *statepath;
415
416         xb_init_comms();
417         xs_resume();
418
419         /*
420          * We must re-examine each device and find the new path for
421          * its backend.
422          */
423         if (device_get_children(dev, &kids, &count) == 0) {
424                 for (i = 0; i < count; i++) {
425                         if (device_get_state(kids[i]) == DS_NOTPRESENT)
426                                 continue;
427
428                         ivars = device_get_ivars(kids[i]);
429
430                         unregister_xenbus_watch(
431                                 &ivars->xd_otherend_watch);
432                         ivars->xd_state = XenbusStateInitialising;
433
434                         /*
435                          * Find the new backend details and
436                          * re-register our watch.
437                          */
438                         free(ivars->xd_otherend_path, M_DEVBUF);
439                         error = xenbus_gather(XBT_NIL, ivars->xd_node,
440                             "backend-id", "%i", &ivars->xd_otherend_id,
441                             "backend", NULL, &ivars->xd_otherend_path,
442                             NULL);
443                         if (error)
444                                 return (error);
445
446                         DEVICE_RESUME(kids[i]);
447
448                         statepath = malloc(strlen(ivars->xd_otherend_path)
449                             + strlen("/state") + 1, M_DEVBUF, M_WAITOK);
450                         sprintf(statepath, "%s/state", ivars->xd_otherend_path);
451
452                         free(ivars->xd_otherend_watch.node, M_DEVBUF);
453                         ivars->xd_otherend_watch.node = statepath;
454                         register_xenbus_watch(
455                                 &ivars->xd_otherend_watch);
456
457 #if 0
458                         /*
459                          * Can't do this yet since we are running in
460                          * the xenwatch thread and if we sleep here,
461                          * we will stop delivering watch notifications
462                          * and the device will never come back online.
463                          */
464                         sx_xlock(&ivars->xd_lock);
465                         while (ivars->xd_state != XenbusStateClosed
466                             && ivars->xd_state != XenbusStateConnected)
467                                 sx_sleep(&ivars->xd_state, &ivars->xd_lock,
468                                     0, "xdresume", 0);
469                         sx_xunlock(&ivars->xd_lock);
470 #endif
471                 }
472                 free(kids, M_TEMP);
473         }
474
475         return (0);
476 }
477
478 static int
479 xenbus_print_child(device_t dev, device_t child)
480 {
481         struct xenbus_device_ivars *ivars = device_get_ivars(child);
482         int     retval = 0;
483
484         retval += bus_print_child_header(dev, child);
485         retval += printf(" at %s", ivars->xd_node);
486         retval += bus_print_child_footer(dev, child);
487
488         return (retval);
489 }
490
491 static int
492 xenbus_read_ivar(device_t dev, device_t child, int index,
493     uintptr_t * result)
494 {
495         struct xenbus_device_ivars *ivars = device_get_ivars(child);
496
497         switch (index) {
498         case XENBUS_IVAR_NODE:
499                 *result = (uintptr_t) ivars->xd_node;
500                 return (0);
501
502         case XENBUS_IVAR_TYPE:
503                 *result = (uintptr_t) ivars->xd_type;
504                 return (0);
505
506         case XENBUS_IVAR_STATE:
507                 *result = (uintptr_t) ivars->xd_state;
508                 return (0);
509
510         case XENBUS_IVAR_OTHEREND_ID:
511                 *result = (uintptr_t) ivars->xd_otherend_id;
512                 return (0);
513
514         case XENBUS_IVAR_OTHEREND_PATH:
515                 *result = (uintptr_t) ivars->xd_otherend_path;
516                 return (0);
517         }
518
519         return (ENOENT);
520 }
521
522 static int
523 xenbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
524 {
525         struct xenbus_device_ivars *ivars = device_get_ivars(child);
526         enum xenbus_state newstate;
527         int currstate;
528         int error;
529
530         switch (index) {
531         case XENBUS_IVAR_STATE:
532                 newstate = (enum xenbus_state) value;
533                 sx_xlock(&ivars->xd_lock);
534                 if (ivars->xd_state == newstate)
535                         goto out;
536
537                 error = xenbus_scanf(XBT_NIL, ivars->xd_node, "state",
538                     NULL, "%d", &currstate);
539                 if (error)
540                         goto out;
541
542                 error = xenbus_printf(XBT_NIL, ivars->xd_node, "state",
543                     "%d", newstate);
544                 if (error) {
545                         if (newstate != XenbusStateClosing) /* Avoid looping */
546                                 xenbus_dev_fatal(dev, error, "writing new state");
547                         goto out;
548                 }
549                 ivars->xd_state = newstate;
550                 wakeup(&ivars->xd_state);
551         out:
552                 sx_xunlock(&ivars->xd_lock);
553                 return (0);
554
555         case XENBUS_IVAR_NODE:
556         case XENBUS_IVAR_TYPE:
557         case XENBUS_IVAR_OTHEREND_ID:
558         case XENBUS_IVAR_OTHEREND_PATH:
559                 /*
560                  * These variables are read-only.
561                  */
562                 return (EINVAL);
563         }
564
565         return (ENOENT);
566 }
567
568 SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen");
569 SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xen_store_evtchn, 0, "");
570 SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, "");
571
572 static device_method_t xenbus_methods[] = { 
573         /* Device interface */ 
574         DEVMETHOD(device_identify,      xenbus_identify),
575         DEVMETHOD(device_probe,         xenbus_probe), 
576         DEVMETHOD(device_attach,        xenbus_attach), 
577         DEVMETHOD(device_detach,        bus_generic_detach), 
578         DEVMETHOD(device_shutdown,      bus_generic_shutdown), 
579         DEVMETHOD(device_suspend,       xenbus_suspend), 
580         DEVMETHOD(device_resume,        xenbus_resume), 
581  
582         /* Bus interface */ 
583         DEVMETHOD(bus_print_child,      xenbus_print_child),
584         DEVMETHOD(bus_read_ivar,        xenbus_read_ivar), 
585         DEVMETHOD(bus_write_ivar,       xenbus_write_ivar), 
586  
587         { 0, 0 } 
588 }; 
589
590 static char driver_name[] = "xenbus";
591 static driver_t xenbus_driver = { 
592         driver_name, 
593         xenbus_methods, 
594         sizeof(struct xenbus_softc),
595 }; 
596 devclass_t xenbus_devclass; 
597  
598 #ifdef XENHVM
599 DRIVER_MODULE(xenbus, xenpci, xenbus_driver, xenbus_devclass, 0, 0);
600 #else
601 DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0);
602 #endif