Deleted Added
full compact
xenbusb.c (196403) xenbusb.c (201758)
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>
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: head/sys/xen/xenbus/xenbus_probe.c 196403 2009-08-20 19:17:53Z jhb $");
39__FBSDID("$FreeBSD: head/sys/xen/xenbus/xenbus_probe.c 201758 2010-01-07 21:01:37Z mbr $");
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
60struct 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
67struct 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. */
79char *
80kasprintf(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
98static void
99xenbus_identify(driver_t *driver, device_t parent)
100{
101
102 BUS_ADD_CHILD(parent, 0, "xenbus", 0);
103}
104
105static int
106xenbus_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
130static enum xenbus_state
131xenbus_otherend_state(struct xenbus_device_ivars *ivars)
132{
133
134 return (xenbus_read_driver_state(ivars->xd_otherend_path));
135}
136
137static void
138xenbus_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
157static int
158xenbus_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
180static int
181xenbus_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
244static int
245xenbus_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
262static int
263xenbus_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
280static int
281xenbus_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
317static void
318xenbus_probe_children_cb(void *arg, int pending)
319{
320 device_t dev = (device_t) arg;
321
322 xenbus_probe_children(dev);
323}
324
325static void
326xenbus_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
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
60struct 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
67struct 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. */
79char *
80kasprintf(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
98static void
99xenbus_identify(driver_t *driver, device_t parent)
100{
101
102 BUS_ADD_CHILD(parent, 0, "xenbus", 0);
103}
104
105static int
106xenbus_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
130static enum xenbus_state
131xenbus_otherend_state(struct xenbus_device_ivars *ivars)
132{
133
134 return (xenbus_read_driver_state(ivars->xd_otherend_path));
135}
136
137static void
138xenbus_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
157static int
158xenbus_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
180static int
181xenbus_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
244static int
245xenbus_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
262static int
263xenbus_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
280static int
281xenbus_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
317static void
318xenbus_probe_children_cb(void *arg, int pending)
319{
320 device_t dev = (device_t) arg;
321
322 xenbus_probe_children(dev);
323}
324
325static void
326xenbus_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);;
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);
353out:
354 free(node, M_DEVBUF);
355}
356
357static void
358xenbus_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
380static int
381xenbus_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
392static int
393xenbus_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
408static int
409xenbus_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
478static int
479xenbus_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
491static int
492xenbus_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
522static int
523xenbus_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
568SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen");
569SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xen_store_evtchn, 0, "");
570SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, "");
571
572static 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
590static char driver_name[] = "xenbus";
591static driver_t xenbus_driver = {
592 driver_name,
593 xenbus_methods,
594 sizeof(struct xenbus_softc),
595};
596devclass_t xenbus_devclass;
597
598#ifdef XENHVM
599DRIVER_MODULE(xenbus, xenpci, xenbus_driver, xenbus_devclass, 0, 0);
600#else
601DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0);
602#endif
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);
353out:
354 free(node, M_DEVBUF);
355}
356
357static void
358xenbus_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
380static int
381xenbus_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
392static int
393xenbus_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
408static int
409xenbus_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
478static int
479xenbus_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
491static int
492xenbus_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
522static int
523xenbus_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
568SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen");
569SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xen_store_evtchn, 0, "");
570SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, "");
571
572static 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
590static char driver_name[] = "xenbus";
591static driver_t xenbus_driver = {
592 driver_name,
593 xenbus_methods,
594 sizeof(struct xenbus_softc),
595};
596devclass_t xenbus_devclass;
597
598#ifdef XENHVM
599DRIVER_MODULE(xenbus, xenpci, xenbus_driver, xenbus_devclass, 0, 0);
600#else
601DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0);
602#endif