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
|