1 /******************************************************************************
2 * Copyright (C) 2010 Spectra Logic Corporation
3 * Copyright (C) 2008 Doug Rabson
4 * Copyright (C) 2005 Rusty Russell, IBM Corporation
5 * Copyright (C) 2005 Mike Wray, Hewlett-Packard
6 * Copyright (C) 2005 XenSource Ltd
7 *
8 * This file may be distributed separately from the Linux kernel, or
9 * incorporated into other software packages, subject to the following license:
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this source file (the "Software"), to deal in the Software without
13 * restriction, including without limitation the rights to use, copy, modify,
14 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
15 * and to permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 * IN THE SOFTWARE.
28 */
29
30 /**
31 * \file xenbusb.c
32 *
33 * \brief Shared support functions for managing the NewBus busses that contain
34 * Xen front and back end device instances.
35 *
36 * The NewBus implementation of XenBus attaches a xenbusb_front and xenbusb_back
37 * child bus to the xenstore device. This strategy allows the small differences
38 * in the handling of XenBus operations for front and back devices to be handled
39 * as overrides in xenbusb_front/back.c. Front and back specific device
40 * classes are also provided so device drivers can register for the devices they
41 * can handle without the need to filter within their probe routines. The
42 * net result is a device hierarchy that might look like this:
43 *
44 * xenstore0/
45 * xenbusb_front0/
46 * xn0
47 * xbd0
48 * xbd1
49 * xenbusb_back0/
50 * xbbd0
51 * xnb0
52 * xnb1
53 */
54 #include <sys/cdefs.h>
55 __FBSDID("$FreeBSD: releng/8.2/sys/xen/xenbus/xenbusb.c 215788 2010-11-24 01:03:03Z gibbs $");
56
57 #include <sys/param.h>
58 #include <sys/bus.h>
59 #include <sys/kernel.h>
60 #include <sys/lock.h>
61 #include <sys/malloc.h>
62 #include <sys/module.h>
63 #include <sys/sbuf.h>
64 #include <sys/sysctl.h>
65 #include <sys/syslog.h>
66 #include <sys/systm.h>
67 #include <sys/sx.h>
68 #include <sys/taskqueue.h>
69
70 #include <machine/xen/xen-os.h>
71 #include <machine/stdarg.h>
72
73 #include <xen/gnttab.h>
74 #include <xen/xenstore/xenstorevar.h>
75 #include <xen/xenbus/xenbusb.h>
76 #include <xen/xenbus/xenbusvar.h>
77
78 /*------------------------- Private Functions --------------------------------*/
79 /**
80 * \brief Deallocate XenBus device instance variables.
81 *
82 * \param ivars The instance variable block to free.
83 */
84 static void
85 xenbusb_free_child_ivars(struct xenbus_device_ivars *ivars)
86 {
87 if (ivars->xd_otherend_watch.node != NULL) {
88 xs_unregister_watch(&ivars->xd_otherend_watch);
89 free(ivars->xd_otherend_watch.node, M_XENBUS);
90 ivars->xd_otherend_watch.node = NULL;
91 }
92
93 if (ivars->xd_node != NULL) {
94 free(ivars->xd_node, M_XENBUS);
95 ivars->xd_node = NULL;
96 }
97
98 if (ivars->xd_type != NULL) {
99 free(ivars->xd_type, M_XENBUS);
100 ivars->xd_type = NULL;
101 }
102
103 if (ivars->xd_otherend_path != NULL) {
104 free(ivars->xd_otherend_path, M_XENBUS);
105 ivars->xd_otherend_path = NULL;
106 }
107
108 free(ivars, M_XENBUS);
109 }
110
111 /**
112 * XenBus watch callback registered against the "state" XenStore
113 * node of the other-end of a split device connection.
114 *
115 * This callback is invoked whenever the state of a device instance's
116 * peer changes.
117 *
118 * \param watch The xs_watch object used to register this callback
119 * function.
120 * \param vec An array of pointers to NUL terminated strings containing
121 * watch event data. The vector should be indexed via the
122 * xs_watch_type enum in xs_wire.h.
123 * \param vec_size The number of elements in vec.
124 *
125 * \return The device_t of the found device if any, or NULL.
126 *
127 * \note device_t is a pointer type, so it can be compared against
128 * NULL for validity.
129 */
130 static void
131 xenbusb_otherend_changed(struct xs_watch *watch, const char **vec,
132 unsigned int vec_size __unused)
133 {
134 struct xenbus_device_ivars *ivars;
135 device_t dev;
136 enum xenbus_state newstate;
137
138 ivars = (struct xenbus_device_ivars *) watch;
139 dev = ivars->xd_dev;
140
141 if (!ivars->xd_otherend_path
142 || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH],
143 strlen(ivars->xd_otherend_path)))
144 return;
145
146 newstate = xenbus_read_driver_state(ivars->xd_otherend_path);
147 XENBUS_OTHEREND_CHANGED(dev, newstate);
148 }
149
150 /**
151 * Search our internal record of configured devices (not the XenStore)
152 * to determine if the XenBus device indicated by \a node is known to
153 * the system.
154 *
155 * \param dev The XenBus bus instance to search for device children.
156 * \param node The XenStore node path for the device to find.
157 *
158 * \return The device_t of the found device if any, or NULL.
159 *
160 * \note device_t is a pointer type, so it can be compared against
161 * NULL for validity.
162 */
163 static device_t
164 xenbusb_device_exists(device_t dev, const char *node)
165 {
166 device_t *kids;
167 device_t result;
168 struct xenbus_device_ivars *ivars;
169 int i, count;
170
171 if (device_get_children(dev, &kids, &count))
172 return (FALSE);
173
174 result = NULL;
175 for (i = 0; i < count; i++) {
176 ivars = device_get_ivars(kids[i]);
177 if (!strcmp(ivars->xd_node, node)) {
178 result = kids[i];
179 break;
180 }
181 }
182 free(kids, M_TEMP);
183
184 return (result);
185 }
186
187 static void
188 xenbusb_delete_child(device_t dev, device_t child)
189 {
190 struct xenbus_device_ivars *ivars;
191
192 ivars = device_get_ivars(child);
193
194 /*
195 * We no longer care about the otherend of the
196 * connection. Cancel the watch now so that we
197 * don't try to handle an event for a partially
198 * detached child.
199 */
200 if (ivars->xd_otherend_watch.node != NULL)
201 xs_unregister_watch(&ivars->xd_otherend_watch);
202
203 device_delete_child(dev, child);
204 xenbusb_free_child_ivars(ivars);
205 }
206
207 /**
208 * \param dev The NewBus device representing this XenBus bus.
209 * \param child The NewBus device representing a child of dev%'s XenBus bus.
210 */
211 static void
212 xenbusb_verify_device(device_t dev, device_t child)
213 {
214 if (xs_exists(XST_NIL, xenbus_get_node(child), "") == 0) {
215
216 /*
217 * Device tree has been removed from Xenbus.
218 * Tear down the device.
219 */
220 xenbusb_delete_child(dev, child);
221 }
222 }
223
224 /**
225 * \brief Enumerate the devices on a XenBus bus and register them with
226 * the NewBus device tree.
227 *
228 * xenbusb_enumerate_bus() will create entries (in state DS_NOTPRESENT)
229 * for nodes that appear in the XenStore, but will not invoke probe/attach
230 * operations on drivers. Probe/Attach processing must be separately
231 * performed via an invocation of xenbusb_probe_children(). This is usually
232 * done via the xbs_probe_children task.
233 *
234 * \param xbs XenBus Bus device softc of the owner of the bus to enumerate.
235 *
236 * \return On success, 0. Otherwise an errno value indicating the
237 * type of failure.
238 */
239 static int
240 xenbusb_enumerate_bus(struct xenbusb_softc *xbs)
241 {
242 const char **types;
243 u_int type_idx;
244 u_int type_count;
245 int error;
246
247 error = xs_directory(XST_NIL, xbs->xbs_node, "", &type_count, &types);
248 if (error)
249 return (error);
250
251 for (type_idx = 0; type_idx < type_count; type_idx++)
252 XENBUSB_ENUMERATE_TYPE(xbs->xbs_dev, types[type_idx]);
253
254 free(types, M_XENSTORE);
255
256 return (0);
257 }
258
259 /**
260 * Handler for all generic XenBus device systcl nodes.
261 */
262 static int
263 xenbusb_device_sysctl_handler(SYSCTL_HANDLER_ARGS)
264 {
265 device_t dev;
266 const char *value;
267
268 dev = (device_t)arg1;
269 switch (arg2) {
270 case XENBUS_IVAR_NODE:
271 value = xenbus_get_node(dev);
272 break;
273 case XENBUS_IVAR_TYPE:
274 value = xenbus_get_type(dev);
275 break;
276 case XENBUS_IVAR_STATE:
277 value = xenbus_strstate(xenbus_get_state(dev));
278 break;
279 case XENBUS_IVAR_OTHEREND_ID:
280 return (sysctl_handle_int(oidp, NULL,
281 xenbus_get_otherend_id(dev),
282 req));
283 /* NOTREACHED */
284 case XENBUS_IVAR_OTHEREND_PATH:
285 value = xenbus_get_otherend_path(dev);
286 break;
287 default:
288 return (EINVAL);
289 }
290 return (SYSCTL_OUT(req, value, strlen(value)));
291 }
292
293 /**
294 * Create read-only systcl nodes for xenbusb device ivar data.
295 *
296 * \param dev The XenBus device instance to register with sysctl.
297 */
298 static void
299 xenbusb_device_sysctl_init(device_t dev)
300 {
301 struct sysctl_ctx_list *ctx;
302 struct sysctl_oid *tree;
303
304 ctx = device_get_sysctl_ctx(dev);
305 tree = device_get_sysctl_tree(dev);
306
307 SYSCTL_ADD_PROC(ctx,
308 SYSCTL_CHILDREN(tree),
309 OID_AUTO,
310 "xenstore_path",
311 CTLFLAG_RD,
312 dev,
313 XENBUS_IVAR_NODE,
314 xenbusb_device_sysctl_handler,
315 "A",
316 "XenStore path to device");
317
318 SYSCTL_ADD_PROC(ctx,
319 SYSCTL_CHILDREN(tree),
320 OID_AUTO,
321 "xenbus_dev_type",
322 CTLFLAG_RD,
323 dev,
324 XENBUS_IVAR_TYPE,
325 xenbusb_device_sysctl_handler,
326 "A",
327 "XenBus device type");
328
329 SYSCTL_ADD_PROC(ctx,
330 SYSCTL_CHILDREN(tree),
331 OID_AUTO,
332 "xenbus_connection_state",
333 CTLFLAG_RD,
334 dev,
335 XENBUS_IVAR_STATE,
336 xenbusb_device_sysctl_handler,
337 "A",
338 "XenBus state of peer connection");
339
340 SYSCTL_ADD_PROC(ctx,
341 SYSCTL_CHILDREN(tree),
342 OID_AUTO,
343 "xenbus_peer_domid",
344 CTLFLAG_RD,
345 dev,
346 XENBUS_IVAR_OTHEREND_ID,
347 xenbusb_device_sysctl_handler,
348 "I",
349 "Xen domain ID of peer");
350
351 SYSCTL_ADD_PROC(ctx,
352 SYSCTL_CHILDREN(tree),
353 OID_AUTO,
354 "xenstore_peer_path",
355 CTLFLAG_RD,
356 dev,
357 XENBUS_IVAR_OTHEREND_PATH,
358 xenbusb_device_sysctl_handler,
359 "A",
360 "XenStore path to peer device");
361 }
362
363 /**
364 * \brief Verify the existance of attached device instances and perform
365 * probe/attach processing for newly arrived devices.
366 *
367 * \param dev The NewBus device representing this XenBus bus.
368 *
369 * \return On success, 0. Otherwise an errno value indicating the
370 * type of failure.
371 */
372 static int
373 xenbusb_probe_children(device_t dev)
374 {
375 device_t *kids;
376 struct xenbus_device_ivars *ivars;
377 int i, count;
378
379 if (device_get_children(dev, &kids, &count) == 0) {
380 for (i = 0; i < count; i++) {
381 if (device_get_state(kids[i]) != DS_NOTPRESENT) {
382 /*
383 * We already know about this one.
384 * Make sure it's still here.
385 */
386 xenbusb_verify_device(dev, kids[i]);
387 continue;
388 }
389
390 if (device_probe_and_attach(kids[i])) {
391 /*
392 * Transition device to the closed state
393 * so the world knows that attachment will
394 * not occur.
395 */
396 xenbus_set_state(kids[i], XenbusStateClosed);
397
398 /*
399 * Remove our record of this device.
400 * So long as it remains in the closed
401 * state in the XenStore, we will not find
402 * it again. The state will only change
403 * if the control domain actively reconfigures
404 * this device.
405 */
406 xenbusb_delete_child(dev, kids[i]);
407
408 continue;
409 }
410 /*
411 * Augment default newbus provided dynamic sysctl
412 * variables with the standard ivar contents of
413 * XenBus devices.
414 */
415 xenbusb_device_sysctl_init(kids[i]);
416
417 /*
418 * Now that we have a driver managing this device
419 * that can receive otherend state change events,
420 * hook up a watch for them.
421 */
422 ivars = device_get_ivars(kids[i]);
423 xs_register_watch(&ivars->xd_otherend_watch);
424 }
425 free(kids, M_TEMP);
426 }
427
428 return (0);
429 }
430
431 /**
432 * \brief Task callback function to perform XenBus probe operations
433 * from a known safe context.
434 *
435 * \param arg The NewBus device_t representing the bus instance to
436 * on which to perform probe processing.
437 * \param pending The number of times this task was queued before it could
438 * be run.
439 */
440 static void
441 xenbusb_probe_children_cb(void *arg, int pending __unused)
442 {
443 device_t dev = (device_t)arg;
444
445 /*
446 * Hold Giant until the Giant free newbus changes are committed.
447 */
448 mtx_lock(&Giant);
449 xenbusb_probe_children(dev);
450 mtx_unlock(&Giant);
451 }
452
453 /**
454 * \brief XenStore watch callback for the root node of the XenStore
455 * subtree representing a XenBus.
456 *
457 * This callback performs, or delegates to the xbs_probe_children task,
458 * all processing necessary to handle dynmaic device arrival and departure
459 * events from a XenBus.
460 *
461 * \param watch The XenStore watch object associated with this callback.
462 * \param vec The XenStore watch event data.
463 * \param len The number of fields in the event data stream.
464 */
465 static void
466 xenbusb_devices_changed(struct xs_watch *watch, const char **vec,
467 unsigned int len)
468 {
469 struct xenbusb_softc *xbs;
470 device_t dev;
471 char *node;
472 char *bus;
473 char *type;
474 char *id;
475 char *p;
476 u_int component;
477
478 xbs = (struct xenbusb_softc *)watch;
479 dev = xbs->xbs_dev;
480
481 if (len <= XS_WATCH_PATH) {
482 device_printf(dev, "xenbusb_devices_changed: "
483 "Short Event Data.\n");
484 return;
485 }
486
487 node = strdup(vec[XS_WATCH_PATH], M_XENBUS);
488 p = strchr(node, '/');
489 if (p == NULL)
490 goto out;
491 bus = node;
492 *p = 0;
493 type = p + 1;
494
495 p = strchr(type, '/');
496 if (p == NULL)
497 goto out;
498 *p++ = 0;
499
500 /*
501 * Extract the device ID. A device ID has one or more path
502 * components separated by the '/' character.
503 *
504 * e.g. "<frontend vm id>/<frontend dev id>" for backend devices.
505 */
506 id = p;
507 for (component = 0; component < xbs->xbs_id_components; component++) {
508 p = strchr(p, '/');
509 if (p == NULL)
510 break;
511 p++;
512 }
513 if (p != NULL)
514 *p = 0;
515
516 if (*id != 0 && component >= xbs->xbs_id_components - 1) {
517 xenbusb_add_device(xbs->xbs_dev, type, id);
518 taskqueue_enqueue(taskqueue_thread, &xbs->xbs_probe_children);
519 }
520 out:
521 free(node, M_XENBUS);
522 }
523
524 /**
525 * \brief Interrupt configuration hook callback associated with xbs_attch_ch.
526 *
527 * Since interrupts are always functional at the time of XenBus configuration,
528 * there is nothing to be done when the callback occurs. This hook is only
529 * registered to hold up boot processing while XenBus devices come online.
530 *
531 * \param arg Unused configuration hook callback argument.
532 */
533 static void
534 xenbusb_nop_confighook_cb(void *arg __unused)
535 {
536 }
537
538 /**
539 * \brief Decrement the number of XenBus child devices in the
540 * connecting state by one and release the xbs_attch_ch
541 * interrupt configuration hook if the connecting count
542 * drops to zero.
543 *
544 * \param xbs XenBus Bus device softc of the owner of the bus to enumerate.
545 */
546 static void
547 xenbusb_release_confighook(struct xenbusb_softc *xbs)
548 {
549 mtx_lock(&xbs->xbs_lock);
550 KASSERT(xbs->xbs_connecting_children > 0,
551 ("Connecting device count error\n"));
552 xbs->xbs_connecting_children--;
553 if (xbs->xbs_connecting_children == 0
554 && (xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) {
555 xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE;
556 mtx_unlock(&xbs->xbs_lock);
557 config_intrhook_disestablish(&xbs->xbs_attach_ch);
558 } else {
559 mtx_unlock(&xbs->xbs_lock);
560 }
561 }
562
563 /*--------------------------- Public Functions -------------------------------*/
564 /*--------- API comments for these methods can be found in xenbusb.h ---------*/
565 void
566 xenbusb_identify(driver_t *driver __unused, device_t parent)
567 {
568 /*
569 * A single instance of each bus type for which we have a driver
570 * is always present in a system operating under Xen.
571 */
572 BUS_ADD_CHILD(parent, 0, driver->name, 0);
573 }
574
575 int
576 xenbusb_add_device(device_t dev, const char *type, const char *id)
577 {
578 struct xenbusb_softc *xbs;
579 struct sbuf *devpath_sbuf;
580 char *devpath;
581 struct xenbus_device_ivars *ivars;
582 int error;
583
584 xbs = device_get_softc(dev);
585 devpath_sbuf = sbuf_new_auto();
586 sbuf_printf(devpath_sbuf, "%s/%s/%s", xbs->xbs_node, type, id);
587 sbuf_finish(devpath_sbuf);
588 devpath = sbuf_data(devpath_sbuf);
589
590 ivars = malloc(sizeof(*ivars), M_XENBUS, M_ZERO|M_WAITOK);
591 error = ENXIO;
592
593 if (xs_exists(XST_NIL, devpath, "") != 0) {
594 device_t child;
595 enum xenbus_state state;
596 char *statepath;
597
598 child = xenbusb_device_exists(dev, devpath);
599 if (child != NULL) {
600 /*
601 * We are already tracking this node
602 */
603 error = 0;
604 goto out;
605 }
606
607 state = xenbus_read_driver_state(devpath);
608 if (state != XenbusStateInitialising) {
609 /*
610 * Device is not new, so ignore it. This can
611 * happen if a device is going away after
612 * switching to Closed.
613 */
614 printf("xenbusb_add_device: Device %s ignored. "
615 "State %d\n", devpath, state);
616 error = 0;
617 goto out;
618 }
619
620 sx_init(&ivars->xd_lock, "xdlock");
621 ivars->xd_flags = XDF_CONNECTING;
622 ivars->xd_node = strdup(devpath, M_XENBUS);
623 ivars->xd_type = strdup(type, M_XENBUS);
624 ivars->xd_state = XenbusStateInitialising;
625
626 error = XENBUSB_GET_OTHEREND_NODE(dev, ivars);
627 if (error) {
628 printf("xenbus_update_device: %s no otherend id\n",
629 devpath);
630 goto out;
631 }
632
633 statepath = malloc(strlen(ivars->xd_otherend_path)
634 + strlen("/state") + 1, M_XENBUS, M_WAITOK);
635 sprintf(statepath, "%s/state", ivars->xd_otherend_path);
636
637 ivars->xd_otherend_watch.node = statepath;
638 ivars->xd_otherend_watch.callback = xenbusb_otherend_changed;
639
640 mtx_lock(&xbs->xbs_lock);
641 xbs->xbs_connecting_children++;
642 mtx_unlock(&xbs->xbs_lock);
643
644 child = device_add_child(dev, NULL, -1);
645 ivars->xd_dev = child;
646 device_set_ivars(child, ivars);
647 }
648
649 out:
650 sbuf_delete(devpath_sbuf);
651 if (error != 0)
652 xenbusb_free_child_ivars(ivars);
653
654 return (error);
655 }
656
657 int
658 xenbusb_attach(device_t dev, char *bus_node, u_int id_components)
659 {
660 struct xenbusb_softc *xbs;
661
662 xbs = device_get_softc(dev);
663 mtx_init(&xbs->xbs_lock, "xenbusb softc lock", NULL, MTX_DEF);
664 xbs->xbs_node = bus_node;
665 xbs->xbs_id_components = id_components;
666 xbs->xbs_dev = dev;
667
668 /*
669 * Since XenBus busses are attached to the XenStore, and
670 * the XenStore does not probe children until after interrupt
671 * services are available, this config hook is used solely
672 * to ensure that the remainder of the boot process (e.g.
673 * mount root) is deferred until child devices are adequately
674 * probed. We unblock the boot process as soon as the
675 * connecting child count in our softc goes to 0.
676 */
677 xbs->xbs_attach_ch.ich_func = xenbusb_nop_confighook_cb;
678 xbs->xbs_attach_ch.ich_arg = dev;
679 config_intrhook_establish(&xbs->xbs_attach_ch);
680 xbs->xbs_flags |= XBS_ATTACH_CH_ACTIVE;
681 xbs->xbs_connecting_children = 1;
682
683 /*
684 * The subtree for this bus type may not yet exist
685 * causing initial enumeration to fail. We still
686 * want to return success from our attach though
687 * so that we are ready to handle devices for this
688 * bus when they are dynamically attached to us
689 * by a Xen management action.
690 */
691 (void)xenbusb_enumerate_bus(xbs);
692 xenbusb_probe_children(dev);
693
694 xbs->xbs_device_watch.node = bus_node;
695 xbs->xbs_device_watch.callback = xenbusb_devices_changed;
696
697 TASK_INIT(&xbs->xbs_probe_children, 0, xenbusb_probe_children_cb, dev);
698
699 xs_register_watch(&xbs->xbs_device_watch);
700
701 xenbusb_release_confighook(xbs);
702
703 return (0);
704 }
705
706 int
707 xenbusb_resume(device_t dev)
708 {
709 device_t *kids;
710 struct xenbus_device_ivars *ivars;
711 int i, count, error;
712 char *statepath;
713
714 /*
715 * We must re-examine each device and find the new path for
716 * its backend.
717 */
718 if (device_get_children(dev, &kids, &count) == 0) {
719 for (i = 0; i < count; i++) {
720 if (device_get_state(kids[i]) == DS_NOTPRESENT)
721 continue;
722
723 ivars = device_get_ivars(kids[i]);
724
725 xs_unregister_watch(&ivars->xd_otherend_watch);
726 ivars->xd_state = XenbusStateInitialising;
727
728 /*
729 * Find the new backend details and
730 * re-register our watch.
731 */
732 error = XENBUSB_GET_OTHEREND_NODE(dev, ivars);
733 if (error)
734 return (error);
735
736 DEVICE_RESUME(kids[i]);
737
738 statepath = malloc(strlen(ivars->xd_otherend_path)
739 + strlen("/state") + 1, M_XENBUS, M_WAITOK);
740 sprintf(statepath, "%s/state", ivars->xd_otherend_path);
741
742 free(ivars->xd_otherend_watch.node, M_XENBUS);
743 ivars->xd_otherend_watch.node = statepath;
744 xs_register_watch(&ivars->xd_otherend_watch);
745
746 #if 0
747 /*
748 * Can't do this yet since we are running in
749 * the xenwatch thread and if we sleep here,
750 * we will stop delivering watch notifications
751 * and the device will never come back online.
752 */
753 sx_xlock(&ivars->xd_lock);
754 while (ivars->xd_state != XenbusStateClosed
755 && ivars->xd_state != XenbusStateConnected)
756 sx_sleep(&ivars->xd_state, &ivars->xd_lock,
757 0, "xdresume", 0);
758 sx_xunlock(&ivars->xd_lock);
759 #endif
760 }
761 free(kids, M_TEMP);
762 }
763
764 return (0);
765 }
766
767 int
768 xenbusb_print_child(device_t dev, device_t child)
769 {
770 struct xenbus_device_ivars *ivars = device_get_ivars(child);
771 int retval = 0;
772
773 retval += bus_print_child_header(dev, child);
774 retval += printf(" at %s", ivars->xd_node);
775 retval += bus_print_child_footer(dev, child);
776
777 return (retval);
778 }
779
780 int
781 xenbusb_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
782 {
783 struct xenbus_device_ivars *ivars = device_get_ivars(child);
784
785 switch (index) {
786 case XENBUS_IVAR_NODE:
787 *result = (uintptr_t) ivars->xd_node;
788 return (0);
789
790 case XENBUS_IVAR_TYPE:
791 *result = (uintptr_t) ivars->xd_type;
792 return (0);
793
794 case XENBUS_IVAR_STATE:
795 *result = (uintptr_t) ivars->xd_state;
796 return (0);
797
798 case XENBUS_IVAR_OTHEREND_ID:
799 *result = (uintptr_t) ivars->xd_otherend_id;
800 return (0);
801
802 case XENBUS_IVAR_OTHEREND_PATH:
803 *result = (uintptr_t) ivars->xd_otherend_path;
804 return (0);
805 }
806
807 return (ENOENT);
808 }
809
810 int
811 xenbusb_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
812 {
813 struct xenbus_device_ivars *ivars = device_get_ivars(child);
814 enum xenbus_state newstate;
815 int currstate;
816
817 switch (index) {
818 case XENBUS_IVAR_STATE:
819 {
820 int error;
821
822 newstate = (enum xenbus_state) value;
823 sx_xlock(&ivars->xd_lock);
824 if (ivars->xd_state == newstate) {
825 error = 0;
826 goto out;
827 }
828
829 error = xs_scanf(XST_NIL, ivars->xd_node, "state",
830 NULL, "%d", &currstate);
831 if (error)
832 goto out;
833
834 do {
835 error = xs_printf(XST_NIL, ivars->xd_node, "state",
836 "%d", newstate);
837 } while (error == EAGAIN);
838 if (error) {
839 /*
840 * Avoid looping through xenbus_dev_fatal()
841 * which calls xenbus_write_ivar to set the
842 * state to closing.
843 */
844 if (newstate != XenbusStateClosing)
845 xenbus_dev_fatal(dev, error,
846 "writing new state");
847 goto out;
848 }
849 ivars->xd_state = newstate;
850
851 if ((ivars->xd_flags & XDF_CONNECTING) != 0
852 && (newstate == XenbusStateClosed
853 || newstate == XenbusStateConnected)) {
854 struct xenbusb_softc *xbs;
855
856 ivars->xd_flags &= ~XDF_CONNECTING;
857 xbs = device_get_softc(dev);
858 xenbusb_release_confighook(xbs);
859 }
860
861 wakeup(&ivars->xd_state);
862 out:
863 sx_xunlock(&ivars->xd_lock);
864 return (error);
865 }
866
867 case XENBUS_IVAR_NODE:
868 case XENBUS_IVAR_TYPE:
869 case XENBUS_IVAR_OTHEREND_ID:
870 case XENBUS_IVAR_OTHEREND_PATH:
871 /*
872 * These variables are read-only.
873 */
874 return (EINVAL);
875 }
876
877 return (ENOENT);
878 }
Cache object: 328337dbc59398bd13788bb870c67be0
|