xref: /freebsd/sys/xen/xenbus/xenbusb.c (revision 5b56413d04e608379c9a306373554a8e4d321bc0)
1ff662b5cSJustin T. Gibbs /******************************************************************************
2ff662b5cSJustin T. Gibbs  * Copyright (C) 2010 Spectra Logic Corporation
3ff662b5cSJustin T. Gibbs  * Copyright (C) 2008 Doug Rabson
4ff662b5cSJustin T. Gibbs  * Copyright (C) 2005 Rusty Russell, IBM Corporation
5ff662b5cSJustin T. Gibbs  * Copyright (C) 2005 Mike Wray, Hewlett-Packard
6ff662b5cSJustin T. Gibbs  * Copyright (C) 2005 XenSource Ltd
7ff662b5cSJustin T. Gibbs  *
8ff662b5cSJustin T. Gibbs  * This file may be distributed separately from the Linux kernel, or
9ff662b5cSJustin T. Gibbs  * incorporated into other software packages, subject to the following license:
10ff662b5cSJustin T. Gibbs  *
11ff662b5cSJustin T. Gibbs  * Permission is hereby granted, free of charge, to any person obtaining a copy
12ff662b5cSJustin T. Gibbs  * of this source file (the "Software"), to deal in the Software without
13ff662b5cSJustin T. Gibbs  * restriction, including without limitation the rights to use, copy, modify,
14ff662b5cSJustin T. Gibbs  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
15ff662b5cSJustin T. Gibbs  * and to permit persons to whom the Software is furnished to do so, subject to
16ff662b5cSJustin T. Gibbs  * the following conditions:
17ff662b5cSJustin T. Gibbs  *
18ff662b5cSJustin T. Gibbs  * The above copyright notice and this permission notice shall be included in
19ff662b5cSJustin T. Gibbs  * all copies or substantial portions of the Software.
20ff662b5cSJustin T. Gibbs  *
21ff662b5cSJustin T. Gibbs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22ff662b5cSJustin T. Gibbs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23ff662b5cSJustin T. Gibbs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24ff662b5cSJustin T. Gibbs  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25ff662b5cSJustin T. Gibbs  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26ff662b5cSJustin T. Gibbs  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27ff662b5cSJustin T. Gibbs  * IN THE SOFTWARE.
28ff662b5cSJustin T. Gibbs  */
29ff662b5cSJustin T. Gibbs 
30ff662b5cSJustin T. Gibbs /**
31ff662b5cSJustin T. Gibbs  * \file xenbusb.c
32ff662b5cSJustin T. Gibbs  *
33db4fcadfSConrad Meyer  * \brief Shared support functions for managing the NewBus buses that contain
34ff662b5cSJustin T. Gibbs  *        Xen front and back end device instances.
35ff662b5cSJustin T. Gibbs  *
36ff662b5cSJustin T. Gibbs  * The NewBus implementation of XenBus attaches a xenbusb_front and xenbusb_back
37ff662b5cSJustin T. Gibbs  * child bus to the xenstore device.  This strategy allows the small differences
38ff662b5cSJustin T. Gibbs  * in the handling of XenBus operations for front and back devices to be handled
39ff662b5cSJustin T. Gibbs  * as overrides in xenbusb_front/back.c.  Front and back specific device
40ff662b5cSJustin T. Gibbs  * classes are also provided so device drivers can register for the devices they
41ff662b5cSJustin T. Gibbs  * can handle without the need to filter within their probe routines.  The
42ff662b5cSJustin T. Gibbs  * net result is a device hierarchy that might look like this:
43ff662b5cSJustin T. Gibbs  *
44ff662b5cSJustin T. Gibbs  * xenstore0/
45ff662b5cSJustin T. Gibbs  *           xenbusb_front0/
46ff662b5cSJustin T. Gibbs  *                         xn0
47ff662b5cSJustin T. Gibbs  *                         xbd0
48ff662b5cSJustin T. Gibbs  *                         xbd1
49ff662b5cSJustin T. Gibbs  *           xenbusb_back0/
50ff662b5cSJustin T. Gibbs  *                        xbbd0
51ff662b5cSJustin T. Gibbs  *                        xnb0
52ff662b5cSJustin T. Gibbs  *                        xnb1
53ff662b5cSJustin T. Gibbs  */
54fdafd315SWarner Losh 
55ff662b5cSJustin T. Gibbs #include <sys/param.h>
56ff662b5cSJustin T. Gibbs #include <sys/bus.h>
57ff662b5cSJustin T. Gibbs #include <sys/kernel.h>
58ff662b5cSJustin T. Gibbs #include <sys/lock.h>
59ff662b5cSJustin T. Gibbs #include <sys/malloc.h>
60ff662b5cSJustin T. Gibbs #include <sys/module.h>
61ff662b5cSJustin T. Gibbs #include <sys/sbuf.h>
62ff662b5cSJustin T. Gibbs #include <sys/sysctl.h>
63ff662b5cSJustin T. Gibbs #include <sys/syslog.h>
64ff662b5cSJustin T. Gibbs #include <sys/systm.h>
65ff662b5cSJustin T. Gibbs #include <sys/sx.h>
66ff662b5cSJustin T. Gibbs #include <sys/taskqueue.h>
67ff662b5cSJustin T. Gibbs 
68ff662b5cSJustin T. Gibbs #include <machine/stdarg.h>
69ff662b5cSJustin T. Gibbs 
70ff5272caSJulien Grall #include <xen/xen-os.h>
71ff662b5cSJustin T. Gibbs #include <xen/gnttab.h>
72ff662b5cSJustin T. Gibbs #include <xen/xenstore/xenstorevar.h>
73ff662b5cSJustin T. Gibbs #include <xen/xenbus/xenbusb.h>
74ff662b5cSJustin T. Gibbs #include <xen/xenbus/xenbusvar.h>
75ff662b5cSJustin T. Gibbs 
76ff662b5cSJustin T. Gibbs /*------------------------- Private Functions --------------------------------*/
77ff662b5cSJustin T. Gibbs /**
78ff662b5cSJustin T. Gibbs  * \brief Deallocate XenBus device instance variables.
79ff662b5cSJustin T. Gibbs  *
80ff662b5cSJustin T. Gibbs  * \param ivars  The instance variable block to free.
81ff662b5cSJustin T. Gibbs  */
82ff662b5cSJustin T. Gibbs static void
83ff662b5cSJustin T. Gibbs xenbusb_free_child_ivars(struct xenbus_device_ivars *ivars)
84ff662b5cSJustin T. Gibbs {
85ff662b5cSJustin T. Gibbs 	if (ivars->xd_otherend_watch.node != NULL) {
86ff662b5cSJustin T. Gibbs 		xs_unregister_watch(&ivars->xd_otherend_watch);
87ff662b5cSJustin T. Gibbs 		free(ivars->xd_otherend_watch.node, M_XENBUS);
88ff662b5cSJustin T. Gibbs 		ivars->xd_otherend_watch.node = NULL;
89ff662b5cSJustin T. Gibbs 	}
90ff662b5cSJustin T. Gibbs 
91283d6f72SJustin T. Gibbs 	if (ivars->xd_local_watch.node != NULL) {
92283d6f72SJustin T. Gibbs 		xs_unregister_watch(&ivars->xd_local_watch);
93283d6f72SJustin T. Gibbs 		ivars->xd_local_watch.node = NULL;
94283d6f72SJustin T. Gibbs 	}
95283d6f72SJustin T. Gibbs 
96ff662b5cSJustin T. Gibbs 	if (ivars->xd_node != NULL) {
97ff662b5cSJustin T. Gibbs 		free(ivars->xd_node, M_XENBUS);
98ff662b5cSJustin T. Gibbs 		ivars->xd_node = NULL;
99ff662b5cSJustin T. Gibbs 	}
100283d6f72SJustin T. Gibbs 	ivars->xd_node_len = 0;
101ff662b5cSJustin T. Gibbs 
102ff662b5cSJustin T. Gibbs 	if (ivars->xd_type != NULL) {
103ff662b5cSJustin T. Gibbs 		free(ivars->xd_type, M_XENBUS);
104ff662b5cSJustin T. Gibbs 		ivars->xd_type = NULL;
105ff662b5cSJustin T. Gibbs 	}
106ff662b5cSJustin T. Gibbs 
107ff662b5cSJustin T. Gibbs 	if (ivars->xd_otherend_path != NULL) {
108ff662b5cSJustin T. Gibbs 		free(ivars->xd_otherend_path, M_XENBUS);
109ff662b5cSJustin T. Gibbs 		ivars->xd_otherend_path = NULL;
110ff662b5cSJustin T. Gibbs 	}
111283d6f72SJustin T. Gibbs 	ivars->xd_otherend_path_len = 0;
112ff662b5cSJustin T. Gibbs 
113ff662b5cSJustin T. Gibbs 	free(ivars, M_XENBUS);
114ff662b5cSJustin T. Gibbs }
115ff662b5cSJustin T. Gibbs 
116ff662b5cSJustin T. Gibbs /**
117ff662b5cSJustin T. Gibbs  * XenBus watch callback registered against the "state" XenStore
118ff662b5cSJustin T. Gibbs  * node of the other-end of a split device connection.
119ff662b5cSJustin T. Gibbs  *
120ff662b5cSJustin T. Gibbs  * This callback is invoked whenever the state of a device instance's
121ff662b5cSJustin T. Gibbs  * peer changes.
122ff662b5cSJustin T. Gibbs  *
123ff662b5cSJustin T. Gibbs  * \param watch      The xs_watch object used to register this callback
124ff662b5cSJustin T. Gibbs  *                   function.
125ff662b5cSJustin T. Gibbs  * \param vec        An array of pointers to NUL terminated strings containing
126ff662b5cSJustin T. Gibbs  *                   watch event data.  The vector should be indexed via the
127ff662b5cSJustin T. Gibbs  *                   xs_watch_type enum in xs_wire.h.
128ff662b5cSJustin T. Gibbs  * \param vec_size   The number of elements in vec.
129ff662b5cSJustin T. Gibbs  */
130ff662b5cSJustin T. Gibbs static void
131283d6f72SJustin T. Gibbs xenbusb_otherend_watch_cb(struct xs_watch *watch, const char **vec,
132ff662b5cSJustin T. Gibbs     unsigned int vec_size __unused)
133ff662b5cSJustin T. Gibbs {
134ff662b5cSJustin T. Gibbs 	struct xenbus_device_ivars *ivars;
135283d6f72SJustin T. Gibbs 	device_t child;
136283d6f72SJustin T. Gibbs 	device_t bus;
137283d6f72SJustin T. Gibbs 	const char *path;
138ff662b5cSJustin T. Gibbs 	enum xenbus_state newstate;
139ff662b5cSJustin T. Gibbs 
140283d6f72SJustin T. Gibbs 	ivars = (struct xenbus_device_ivars *)watch->callback_data;
141283d6f72SJustin T. Gibbs 	child = ivars->xd_dev;
142283d6f72SJustin T. Gibbs 	bus = device_get_parent(child);
143ff662b5cSJustin T. Gibbs 
144283d6f72SJustin T. Gibbs 	path = vec[XS_WATCH_PATH];
145283d6f72SJustin T. Gibbs 	if (ivars->xd_otherend_path == NULL
146283d6f72SJustin T. Gibbs 	 || strncmp(ivars->xd_otherend_path, path, ivars->xd_otherend_path_len))
147ff662b5cSJustin T. Gibbs 		return;
148ff662b5cSJustin T. Gibbs 
149ff662b5cSJustin T. Gibbs 	newstate = xenbus_read_driver_state(ivars->xd_otherend_path);
150283d6f72SJustin T. Gibbs 	XENBUSB_OTHEREND_CHANGED(bus, child, newstate);
151283d6f72SJustin T. Gibbs }
152283d6f72SJustin T. Gibbs 
153283d6f72SJustin T. Gibbs /**
154283d6f72SJustin T. Gibbs  * XenBus watch callback registered against the XenStore sub-tree
155283d6f72SJustin T. Gibbs  * represnting the local half of a split device connection.
156283d6f72SJustin T. Gibbs  *
157283d6f72SJustin T. Gibbs  * This callback is invoked whenever any XenStore data in the subtree
158283d6f72SJustin T. Gibbs  * is modified, either by us or another privledged domain.
159283d6f72SJustin T. Gibbs  *
160283d6f72SJustin T. Gibbs  * \param watch      The xs_watch object used to register this callback
161283d6f72SJustin T. Gibbs  *                   function.
162283d6f72SJustin T. Gibbs  * \param vec        An array of pointers to NUL terminated strings containing
163283d6f72SJustin T. Gibbs  *                   watch event data.  The vector should be indexed via the
164283d6f72SJustin T. Gibbs  *                   xs_watch_type enum in xs_wire.h.
165283d6f72SJustin T. Gibbs  * \param vec_size   The number of elements in vec.
166283d6f72SJustin T. Gibbs  *
167283d6f72SJustin T. Gibbs  */
168283d6f72SJustin T. Gibbs static void
169283d6f72SJustin T. Gibbs xenbusb_local_watch_cb(struct xs_watch *watch, const char **vec,
170283d6f72SJustin T. Gibbs     unsigned int vec_size __unused)
171283d6f72SJustin T. Gibbs {
172283d6f72SJustin T. Gibbs 	struct xenbus_device_ivars *ivars;
173283d6f72SJustin T. Gibbs 	device_t child;
174283d6f72SJustin T. Gibbs 	device_t bus;
175283d6f72SJustin T. Gibbs 	const char *path;
176283d6f72SJustin T. Gibbs 
177283d6f72SJustin T. Gibbs 	ivars = (struct xenbus_device_ivars *)watch->callback_data;
178283d6f72SJustin T. Gibbs 	child = ivars->xd_dev;
179283d6f72SJustin T. Gibbs 	bus = device_get_parent(child);
180283d6f72SJustin T. Gibbs 
181283d6f72SJustin T. Gibbs 	path = vec[XS_WATCH_PATH];
182283d6f72SJustin T. Gibbs 	if (ivars->xd_node == NULL
183283d6f72SJustin T. Gibbs 	 || strncmp(ivars->xd_node, path, ivars->xd_node_len))
184283d6f72SJustin T. Gibbs 		return;
185283d6f72SJustin T. Gibbs 
186283d6f72SJustin T. Gibbs 	XENBUSB_LOCALEND_CHANGED(bus, child, &path[ivars->xd_node_len]);
187ff662b5cSJustin T. Gibbs }
188ff662b5cSJustin T. Gibbs 
189ff662b5cSJustin T. Gibbs /**
190ff662b5cSJustin T. Gibbs  * Search our internal record of configured devices (not the XenStore)
191ff662b5cSJustin T. Gibbs  * to determine if the XenBus device indicated by \a node is known to
192ff662b5cSJustin T. Gibbs  * the system.
193ff662b5cSJustin T. Gibbs  *
194ff662b5cSJustin T. Gibbs  * \param dev   The XenBus bus instance to search for device children.
195ff662b5cSJustin T. Gibbs  * \param node  The XenStore node path for the device to find.
196ff662b5cSJustin T. Gibbs  *
197ff662b5cSJustin T. Gibbs  * \return  The device_t of the found device if any, or NULL.
198ff662b5cSJustin T. Gibbs  *
199ff662b5cSJustin T. Gibbs  * \note device_t is a pointer type, so it can be compared against
200ff662b5cSJustin T. Gibbs  *       NULL for validity.
201ff662b5cSJustin T. Gibbs  */
202ff662b5cSJustin T. Gibbs static device_t
203ff662b5cSJustin T. Gibbs xenbusb_device_exists(device_t dev, const char *node)
204ff662b5cSJustin T. Gibbs {
205ff662b5cSJustin T. Gibbs 	device_t *kids;
206ff662b5cSJustin T. Gibbs 	device_t result;
207ff662b5cSJustin T. Gibbs 	struct xenbus_device_ivars *ivars;
208ff662b5cSJustin T. Gibbs 	int i, count;
209ff662b5cSJustin T. Gibbs 
210ff662b5cSJustin T. Gibbs 	if (device_get_children(dev, &kids, &count))
211ff662b5cSJustin T. Gibbs 		return (FALSE);
212ff662b5cSJustin T. Gibbs 
213ff662b5cSJustin T. Gibbs 	result = NULL;
214ff662b5cSJustin T. Gibbs 	for (i = 0; i < count; i++) {
215ff662b5cSJustin T. Gibbs 		ivars = device_get_ivars(kids[i]);
216ff662b5cSJustin T. Gibbs 		if (!strcmp(ivars->xd_node, node)) {
217ff662b5cSJustin T. Gibbs 			result = kids[i];
218ff662b5cSJustin T. Gibbs 			break;
219ff662b5cSJustin T. Gibbs 		}
220ff662b5cSJustin T. Gibbs 	}
221ff662b5cSJustin T. Gibbs 	free(kids, M_TEMP);
222ff662b5cSJustin T. Gibbs 
223ff662b5cSJustin T. Gibbs 	return (result);
224ff662b5cSJustin T. Gibbs }
225ff662b5cSJustin T. Gibbs 
226ff662b5cSJustin T. Gibbs static void
227ff662b5cSJustin T. Gibbs xenbusb_delete_child(device_t dev, device_t child)
228ff662b5cSJustin T. Gibbs {
229ff662b5cSJustin T. Gibbs 	struct xenbus_device_ivars *ivars;
230ff662b5cSJustin T. Gibbs 
231ff662b5cSJustin T. Gibbs 	ivars = device_get_ivars(child);
232ff662b5cSJustin T. Gibbs 
233ff662b5cSJustin T. Gibbs 	/*
234ff662b5cSJustin T. Gibbs 	 * We no longer care about the otherend of the
235283d6f72SJustin T. Gibbs 	 * connection.  Cancel the watches now so that we
236ff662b5cSJustin T. Gibbs 	 * don't try to handle an event for a partially
237ff662b5cSJustin T. Gibbs 	 * detached child.
238ff662b5cSJustin T. Gibbs 	 */
239ff662b5cSJustin T. Gibbs 	if (ivars->xd_otherend_watch.node != NULL)
240ff662b5cSJustin T. Gibbs 		xs_unregister_watch(&ivars->xd_otherend_watch);
241283d6f72SJustin T. Gibbs 	if (ivars->xd_local_watch.node != NULL)
242283d6f72SJustin T. Gibbs 		xs_unregister_watch(&ivars->xd_local_watch);
243ff662b5cSJustin T. Gibbs 
244ff662b5cSJustin T. Gibbs 	device_delete_child(dev, child);
245ff662b5cSJustin T. Gibbs 	xenbusb_free_child_ivars(ivars);
246ff662b5cSJustin T. Gibbs }
247ff662b5cSJustin T. Gibbs 
248ff662b5cSJustin T. Gibbs /**
249ff662b5cSJustin T. Gibbs  * \param dev    The NewBus device representing this XenBus bus.
250ff662b5cSJustin T. Gibbs  * \param child	 The NewBus device representing a child of dev%'s XenBus bus.
251ff662b5cSJustin T. Gibbs  */
252ff662b5cSJustin T. Gibbs static void
253ff662b5cSJustin T. Gibbs xenbusb_verify_device(device_t dev, device_t child)
254ff662b5cSJustin T. Gibbs {
255f3d54dedSRoger Pau Monné 	if (xs_exists(XST_NIL, xenbus_get_node(child), "state") == 0) {
256ff662b5cSJustin T. Gibbs 		/*
257ff662b5cSJustin T. Gibbs 		 * Device tree has been removed from Xenbus.
258ff662b5cSJustin T. Gibbs 		 * Tear down the device.
259ff662b5cSJustin T. Gibbs 		 */
260ff662b5cSJustin T. Gibbs 		xenbusb_delete_child(dev, child);
261ff662b5cSJustin T. Gibbs 	}
262ff662b5cSJustin T. Gibbs }
263ff662b5cSJustin T. Gibbs 
264ff662b5cSJustin T. Gibbs /**
265ff662b5cSJustin T. Gibbs  * \brief Enumerate the devices on a XenBus bus and register them with
266ff662b5cSJustin T. Gibbs  *        the NewBus device tree.
267ff662b5cSJustin T. Gibbs  *
268ff662b5cSJustin T. Gibbs  * xenbusb_enumerate_bus() will create entries (in state DS_NOTPRESENT)
269ff662b5cSJustin T. Gibbs  * for nodes that appear in the XenStore, but will not invoke probe/attach
270ff662b5cSJustin T. Gibbs  * operations on drivers.  Probe/Attach processing must be separately
271ff662b5cSJustin T. Gibbs  * performed via an invocation of xenbusb_probe_children().  This is usually
272ff662b5cSJustin T. Gibbs  * done via the xbs_probe_children task.
273ff662b5cSJustin T. Gibbs  *
274ff662b5cSJustin T. Gibbs  * \param xbs  XenBus Bus device softc of the owner of the bus to enumerate.
275ff662b5cSJustin T. Gibbs  *
276ff662b5cSJustin T. Gibbs  * \return  On success, 0. Otherwise an errno value indicating the
277ff662b5cSJustin T. Gibbs  *          type of failure.
278ff662b5cSJustin T. Gibbs  */
279ff662b5cSJustin T. Gibbs static int
280ff662b5cSJustin T. Gibbs xenbusb_enumerate_bus(struct xenbusb_softc *xbs)
281ff662b5cSJustin T. Gibbs {
282ff662b5cSJustin T. Gibbs 	const char **types;
283ff662b5cSJustin T. Gibbs 	u_int type_idx;
284ff662b5cSJustin T. Gibbs 	u_int type_count;
285ff662b5cSJustin T. Gibbs 	int error;
286ff662b5cSJustin T. Gibbs 
287ff662b5cSJustin T. Gibbs 	error = xs_directory(XST_NIL, xbs->xbs_node, "", &type_count, &types);
288ff662b5cSJustin T. Gibbs 	if (error)
289ff662b5cSJustin T. Gibbs 		return (error);
290ff662b5cSJustin T. Gibbs 
291ff662b5cSJustin T. Gibbs 	for (type_idx = 0; type_idx < type_count; type_idx++)
292ff662b5cSJustin T. Gibbs 		XENBUSB_ENUMERATE_TYPE(xbs->xbs_dev, types[type_idx]);
293ff662b5cSJustin T. Gibbs 
294ff662b5cSJustin T. Gibbs 	free(types, M_XENSTORE);
295ff662b5cSJustin T. Gibbs 
296ff662b5cSJustin T. Gibbs 	return (0);
297ff662b5cSJustin T. Gibbs }
298ff662b5cSJustin T. Gibbs 
299ff662b5cSJustin T. Gibbs /**
300ff662b5cSJustin T. Gibbs  * Handler for all generic XenBus device systcl nodes.
301ff662b5cSJustin T. Gibbs  */
302ff662b5cSJustin T. Gibbs static int
303ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_handler(SYSCTL_HANDLER_ARGS)
304ff662b5cSJustin T. Gibbs {
305ff662b5cSJustin T. Gibbs 	device_t dev;
306ff662b5cSJustin T. Gibbs         const char *value;
307ff662b5cSJustin T. Gibbs 
308ff662b5cSJustin T. Gibbs 	dev = (device_t)arg1;
309ff662b5cSJustin T. Gibbs         switch (arg2) {
310ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_NODE:
311ff662b5cSJustin T. Gibbs 		value = xenbus_get_node(dev);
312ff662b5cSJustin T. Gibbs 		break;
313ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_TYPE:
314ff662b5cSJustin T. Gibbs 		value = xenbus_get_type(dev);
315ff662b5cSJustin T. Gibbs 		break;
316ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_STATE:
317ff662b5cSJustin T. Gibbs 		value = xenbus_strstate(xenbus_get_state(dev));
318ff662b5cSJustin T. Gibbs 		break;
319ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_OTHEREND_ID:
320ff662b5cSJustin T. Gibbs 		return (sysctl_handle_int(oidp, NULL,
321ff662b5cSJustin T. Gibbs 					  xenbus_get_otherend_id(dev),
322ff662b5cSJustin T. Gibbs 					  req));
323ff662b5cSJustin T. Gibbs 		/* NOTREACHED */
324ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_OTHEREND_PATH:
325ff662b5cSJustin T. Gibbs 		value = xenbus_get_otherend_path(dev);
326ff662b5cSJustin T. Gibbs                 break;
327ff662b5cSJustin T. Gibbs 	default:
328ff662b5cSJustin T. Gibbs 		return (EINVAL);
329ff662b5cSJustin T. Gibbs 	}
330d711ee2cSIan Lepore 	return (SYSCTL_OUT_STR(req, value));
331ff662b5cSJustin T. Gibbs }
332ff662b5cSJustin T. Gibbs 
333ff662b5cSJustin T. Gibbs /**
334ff662b5cSJustin T. Gibbs  * Create read-only systcl nodes for xenbusb device ivar data.
335ff662b5cSJustin T. Gibbs  *
336ff662b5cSJustin T. Gibbs  * \param dev  The XenBus device instance to register with sysctl.
337ff662b5cSJustin T. Gibbs  */
338ff662b5cSJustin T. Gibbs static void
339ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_init(device_t dev)
340ff662b5cSJustin T. Gibbs {
341ff662b5cSJustin T. Gibbs 	struct sysctl_ctx_list *ctx;
342ff662b5cSJustin T. Gibbs 	struct sysctl_oid      *tree;
343ff662b5cSJustin T. Gibbs 
344ff662b5cSJustin T. Gibbs 	ctx  = device_get_sysctl_ctx(dev);
345ff662b5cSJustin T. Gibbs 	tree = device_get_sysctl_tree(dev);
346ff662b5cSJustin T. Gibbs 
347ff662b5cSJustin T. Gibbs         SYSCTL_ADD_PROC(ctx,
348ff662b5cSJustin T. Gibbs 			SYSCTL_CHILDREN(tree),
349ff662b5cSJustin T. Gibbs 			OID_AUTO,
350ff662b5cSJustin T. Gibbs 			"xenstore_path",
35141fc1ce1SPawel Biernacki 			CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
352ff662b5cSJustin T. Gibbs 			dev,
353ff662b5cSJustin T. Gibbs 			XENBUS_IVAR_NODE,
354ff662b5cSJustin T. Gibbs 			xenbusb_device_sysctl_handler,
355ff662b5cSJustin T. Gibbs 			"A",
356ff662b5cSJustin T. Gibbs 			"XenStore path to device");
357ff662b5cSJustin T. Gibbs 
358ff662b5cSJustin T. Gibbs         SYSCTL_ADD_PROC(ctx,
359ff662b5cSJustin T. Gibbs 			SYSCTL_CHILDREN(tree),
360ff662b5cSJustin T. Gibbs 			OID_AUTO,
361ff662b5cSJustin T. Gibbs 			"xenbus_dev_type",
36241fc1ce1SPawel Biernacki 			CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
363ff662b5cSJustin T. Gibbs 			dev,
364ff662b5cSJustin T. Gibbs 			XENBUS_IVAR_TYPE,
365ff662b5cSJustin T. Gibbs 			xenbusb_device_sysctl_handler,
366ff662b5cSJustin T. Gibbs 			"A",
367ff662b5cSJustin T. Gibbs 			"XenBus device type");
368ff662b5cSJustin T. Gibbs 
369ff662b5cSJustin T. Gibbs         SYSCTL_ADD_PROC(ctx,
370ff662b5cSJustin T. Gibbs 			SYSCTL_CHILDREN(tree),
371ff662b5cSJustin T. Gibbs 			OID_AUTO,
372ff662b5cSJustin T. Gibbs 			"xenbus_connection_state",
37341fc1ce1SPawel Biernacki 			CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
374ff662b5cSJustin T. Gibbs 			dev,
375ff662b5cSJustin T. Gibbs 			XENBUS_IVAR_STATE,
376ff662b5cSJustin T. Gibbs 			xenbusb_device_sysctl_handler,
377ff662b5cSJustin T. Gibbs 			"A",
378ff662b5cSJustin T. Gibbs 			"XenBus state of peer connection");
379ff662b5cSJustin T. Gibbs 
380ff662b5cSJustin T. Gibbs         SYSCTL_ADD_PROC(ctx,
381ff662b5cSJustin T. Gibbs 			SYSCTL_CHILDREN(tree),
382ff662b5cSJustin T. Gibbs 			OID_AUTO,
383ff662b5cSJustin T. Gibbs 			"xenbus_peer_domid",
38441fc1ce1SPawel Biernacki 			CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
385ff662b5cSJustin T. Gibbs 			dev,
386ff662b5cSJustin T. Gibbs 			XENBUS_IVAR_OTHEREND_ID,
387ff662b5cSJustin T. Gibbs 			xenbusb_device_sysctl_handler,
388ff662b5cSJustin T. Gibbs 			"I",
389ff662b5cSJustin T. Gibbs 			"Xen domain ID of peer");
390ff662b5cSJustin T. Gibbs 
391ff662b5cSJustin T. Gibbs         SYSCTL_ADD_PROC(ctx,
392ff662b5cSJustin T. Gibbs 			SYSCTL_CHILDREN(tree),
393ff662b5cSJustin T. Gibbs 			OID_AUTO,
394ff662b5cSJustin T. Gibbs 			"xenstore_peer_path",
39541fc1ce1SPawel Biernacki 			CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
396ff662b5cSJustin T. Gibbs 			dev,
397ff662b5cSJustin T. Gibbs 			XENBUS_IVAR_OTHEREND_PATH,
398ff662b5cSJustin T. Gibbs 			xenbusb_device_sysctl_handler,
399ff662b5cSJustin T. Gibbs 			"A",
400ff662b5cSJustin T. Gibbs 			"XenStore path to peer device");
401ff662b5cSJustin T. Gibbs }
402ff662b5cSJustin T. Gibbs 
403ff662b5cSJustin T. Gibbs /**
404f2dc9238SJustin T. Gibbs  * \brief Decrement the number of XenBus child devices in the
405f2dc9238SJustin T. Gibbs  *        connecting state by one and release the xbs_attch_ch
406f2dc9238SJustin T. Gibbs  *        interrupt configuration hook if the connecting count
407f2dc9238SJustin T. Gibbs  *        drops to zero.
408f2dc9238SJustin T. Gibbs  *
409f2dc9238SJustin T. Gibbs  * \param xbs  XenBus Bus device softc of the owner of the bus to enumerate.
410f2dc9238SJustin T. Gibbs  */
411f2dc9238SJustin T. Gibbs static void
412f2dc9238SJustin T. Gibbs xenbusb_release_confighook(struct xenbusb_softc *xbs)
413f2dc9238SJustin T. Gibbs {
414f2dc9238SJustin T. Gibbs 	mtx_lock(&xbs->xbs_lock);
415f2dc9238SJustin T. Gibbs 	KASSERT(xbs->xbs_connecting_children > 0,
416f2dc9238SJustin T. Gibbs 		("Connecting device count error\n"));
417f2dc9238SJustin T. Gibbs 	xbs->xbs_connecting_children--;
418f2dc9238SJustin T. Gibbs 	if (xbs->xbs_connecting_children == 0
419f2dc9238SJustin T. Gibbs 	 && (xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) {
420f2dc9238SJustin T. Gibbs 		xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE;
421f2dc9238SJustin T. Gibbs 		mtx_unlock(&xbs->xbs_lock);
422f2dc9238SJustin T. Gibbs 		config_intrhook_disestablish(&xbs->xbs_attach_ch);
423f2dc9238SJustin T. Gibbs 	} else {
424f2dc9238SJustin T. Gibbs 		mtx_unlock(&xbs->xbs_lock);
425f2dc9238SJustin T. Gibbs 	}
426f2dc9238SJustin T. Gibbs }
427f2dc9238SJustin T. Gibbs 
428f2dc9238SJustin T. Gibbs /**
429bc9432d0SGordon Bergling  * \brief Verify the existence of attached device instances and perform
430ff662b5cSJustin T. Gibbs  *        probe/attach processing for newly arrived devices.
431ff662b5cSJustin T. Gibbs  *
432ff662b5cSJustin T. Gibbs  * \param dev  The NewBus device representing this XenBus bus.
433ff662b5cSJustin T. Gibbs  *
434ff662b5cSJustin T. Gibbs  * \return  On success, 0. Otherwise an errno value indicating the
435ff662b5cSJustin T. Gibbs  *          type of failure.
436ff662b5cSJustin T. Gibbs  */
437ff662b5cSJustin T. Gibbs static int
438ff662b5cSJustin T. Gibbs xenbusb_probe_children(device_t dev)
439ff662b5cSJustin T. Gibbs {
440ff662b5cSJustin T. Gibbs 	device_t *kids;
441ff662b5cSJustin T. Gibbs 	struct xenbus_device_ivars *ivars;
442f2dc9238SJustin T. Gibbs 	int i, count, error;
443ff662b5cSJustin T. Gibbs 
444ff662b5cSJustin T. Gibbs 	if (device_get_children(dev, &kids, &count) == 0) {
445ff662b5cSJustin T. Gibbs 		for (i = 0; i < count; i++) {
446ff662b5cSJustin T. Gibbs 			if (device_get_state(kids[i]) != DS_NOTPRESENT) {
447ff662b5cSJustin T. Gibbs 				/*
448ff662b5cSJustin T. Gibbs 				 * We already know about this one.
449ff662b5cSJustin T. Gibbs 				 * Make sure it's still here.
450ff662b5cSJustin T. Gibbs 				 */
451ff662b5cSJustin T. Gibbs 				xenbusb_verify_device(dev, kids[i]);
452ff662b5cSJustin T. Gibbs 				continue;
453ff662b5cSJustin T. Gibbs 			}
454ff662b5cSJustin T. Gibbs 
455f2dc9238SJustin T. Gibbs 			error = device_probe_and_attach(kids[i]);
456f2dc9238SJustin T. Gibbs 			if (error == ENXIO) {
457f2dc9238SJustin T. Gibbs 				struct xenbusb_softc *xbs;
458f2dc9238SJustin T. Gibbs 
459f2dc9238SJustin T. Gibbs 				/*
460f2dc9238SJustin T. Gibbs 				 * We don't have a PV driver for this device.
461f2dc9238SJustin T. Gibbs 				 * However, an emulated device we do support
462f2dc9238SJustin T. Gibbs 				 * may share this backend.  Hide the node from
463f2dc9238SJustin T. Gibbs 				 * XenBus until the next rescan, but leave it's
464f2dc9238SJustin T. Gibbs 				 * state unchanged so we don't inadvertently
465f2dc9238SJustin T. Gibbs 				 * prevent attachment of any emulated device.
466f2dc9238SJustin T. Gibbs 				 */
467f2dc9238SJustin T. Gibbs 				xenbusb_delete_child(dev, kids[i]);
468f2dc9238SJustin T. Gibbs 
469f2dc9238SJustin T. Gibbs 				/*
470f2dc9238SJustin T. Gibbs 				 * Since the XenStore state of this device
471f2dc9238SJustin T. Gibbs 				 * still indicates a pending attach, manually
472f2dc9238SJustin T. Gibbs 				 * release it's hold on the boot process.
473f2dc9238SJustin T. Gibbs 				 */
474f2dc9238SJustin T. Gibbs 				xbs = device_get_softc(dev);
475f2dc9238SJustin T. Gibbs 				xenbusb_release_confighook(xbs);
476f2dc9238SJustin T. Gibbs 
477f2dc9238SJustin T. Gibbs 				continue;
478f2dc9238SJustin T. Gibbs 			} else if (error) {
479ff662b5cSJustin T. Gibbs 				/*
480ff662b5cSJustin T. Gibbs 				 * Transition device to the closed state
481ff662b5cSJustin T. Gibbs 				 * so the world knows that attachment will
482ff662b5cSJustin T. Gibbs 				 * not occur.
483ff662b5cSJustin T. Gibbs 				 */
484ff662b5cSJustin T. Gibbs 				xenbus_set_state(kids[i], XenbusStateClosed);
485ff662b5cSJustin T. Gibbs 
486ff662b5cSJustin T. Gibbs 				/*
487ff662b5cSJustin T. Gibbs 				 * Remove our record of this device.
488ff662b5cSJustin T. Gibbs 				 * So long as it remains in the closed
489ff662b5cSJustin T. Gibbs 				 * state in the XenStore, we will not find
490ff662b5cSJustin T. Gibbs 				 * it again.  The state will only change
491ff662b5cSJustin T. Gibbs 				 * if the control domain actively reconfigures
492ff662b5cSJustin T. Gibbs 				 * this device.
493ff662b5cSJustin T. Gibbs 				 */
494ff662b5cSJustin T. Gibbs 				xenbusb_delete_child(dev, kids[i]);
495ff662b5cSJustin T. Gibbs 
496ff662b5cSJustin T. Gibbs 				continue;
497ff662b5cSJustin T. Gibbs 			}
498ff662b5cSJustin T. Gibbs 			/*
499ff662b5cSJustin T. Gibbs 			 * Augment default newbus provided dynamic sysctl
500ff662b5cSJustin T. Gibbs 			 * variables with the standard ivar contents of
501ff662b5cSJustin T. Gibbs 			 * XenBus devices.
502ff662b5cSJustin T. Gibbs 			 */
503ff662b5cSJustin T. Gibbs 			xenbusb_device_sysctl_init(kids[i]);
504ff662b5cSJustin T. Gibbs 
505ff662b5cSJustin T. Gibbs 			/*
506ff662b5cSJustin T. Gibbs 			 * Now that we have a driver managing this device
507ff662b5cSJustin T. Gibbs 			 * that can receive otherend state change events,
508ff662b5cSJustin T. Gibbs 			 * hook up a watch for them.
509ff662b5cSJustin T. Gibbs 			 */
510ff662b5cSJustin T. Gibbs 			ivars = device_get_ivars(kids[i]);
511ff662b5cSJustin T. Gibbs 			xs_register_watch(&ivars->xd_otherend_watch);
512283d6f72SJustin T. Gibbs 			xs_register_watch(&ivars->xd_local_watch);
513ff662b5cSJustin T. Gibbs 		}
514ff662b5cSJustin T. Gibbs 		free(kids, M_TEMP);
515ff662b5cSJustin T. Gibbs 	}
516ff662b5cSJustin T. Gibbs 
517ff662b5cSJustin T. Gibbs 	return (0);
518ff662b5cSJustin T. Gibbs }
519ff662b5cSJustin T. Gibbs 
520ff662b5cSJustin T. Gibbs /**
521ff662b5cSJustin T. Gibbs  * \brief Task callback function to perform XenBus probe operations
522ff662b5cSJustin T. Gibbs  *        from a known safe context.
523ff662b5cSJustin T. Gibbs  *
524ff662b5cSJustin T. Gibbs  * \param arg      The NewBus device_t representing the bus instance to
525ff662b5cSJustin T. Gibbs  *                 on which to perform probe processing.
526ff662b5cSJustin T. Gibbs  * \param pending  The number of times this task was queued before it could
527ff662b5cSJustin T. Gibbs  *                 be run.
528ff662b5cSJustin T. Gibbs  */
529ff662b5cSJustin T. Gibbs static void
530ff662b5cSJustin T. Gibbs xenbusb_probe_children_cb(void *arg, int pending __unused)
531ff662b5cSJustin T. Gibbs {
532ff662b5cSJustin T. Gibbs 	device_t dev = (device_t)arg;
533ff662b5cSJustin T. Gibbs 
534c6df6f53SWarner Losh 	bus_topo_lock();
535ff662b5cSJustin T. Gibbs 	xenbusb_probe_children(dev);
536c6df6f53SWarner Losh 	bus_topo_unlock();
537ff662b5cSJustin T. Gibbs }
538ff662b5cSJustin T. Gibbs 
539ff662b5cSJustin T. Gibbs /**
540ff662b5cSJustin T. Gibbs  * \brief XenStore watch callback for the root node of the XenStore
541ff662b5cSJustin T. Gibbs  *        subtree representing a XenBus.
542ff662b5cSJustin T. Gibbs  *
543ff662b5cSJustin T. Gibbs  * This callback performs, or delegates to the xbs_probe_children task,
544ff662b5cSJustin T. Gibbs  * all processing necessary to handle dynmaic device arrival and departure
545ff662b5cSJustin T. Gibbs  * events from a XenBus.
546ff662b5cSJustin T. Gibbs  *
547ff662b5cSJustin T. Gibbs  * \param watch  The XenStore watch object associated with this callback.
548ff662b5cSJustin T. Gibbs  * \param vec    The XenStore watch event data.
549ff662b5cSJustin T. Gibbs  * \param len	 The number of fields in the event data stream.
550ff662b5cSJustin T. Gibbs  */
551ff662b5cSJustin T. Gibbs static void
552ff662b5cSJustin T. Gibbs xenbusb_devices_changed(struct xs_watch *watch, const char **vec,
553ff662b5cSJustin T. Gibbs 			unsigned int len)
554ff662b5cSJustin T. Gibbs {
555ff662b5cSJustin T. Gibbs 	struct xenbusb_softc *xbs;
556ff662b5cSJustin T. Gibbs 	device_t dev;
557ff662b5cSJustin T. Gibbs 	char *node;
558ff662b5cSJustin T. Gibbs 	char *type;
559ff662b5cSJustin T. Gibbs 	char *id;
560ff662b5cSJustin T. Gibbs 	char *p;
561ff662b5cSJustin T. Gibbs 	u_int component;
562ff662b5cSJustin T. Gibbs 
563283d6f72SJustin T. Gibbs 	xbs = (struct xenbusb_softc *)watch->callback_data;
564ff662b5cSJustin T. Gibbs 	dev = xbs->xbs_dev;
565ff662b5cSJustin T. Gibbs 
566ff662b5cSJustin T. Gibbs 	if (len <= XS_WATCH_PATH) {
567ff662b5cSJustin T. Gibbs 		device_printf(dev, "xenbusb_devices_changed: "
568ff662b5cSJustin T. Gibbs 			      "Short Event Data.\n");
569ff662b5cSJustin T. Gibbs 		return;
570ff662b5cSJustin T. Gibbs 	}
571ff662b5cSJustin T. Gibbs 
572ff662b5cSJustin T. Gibbs 	node = strdup(vec[XS_WATCH_PATH], M_XENBUS);
573ff662b5cSJustin T. Gibbs 	p = strchr(node, '/');
574ff662b5cSJustin T. Gibbs 	if (p == NULL)
575ff662b5cSJustin T. Gibbs 		goto out;
576ff662b5cSJustin T. Gibbs 	*p = 0;
577ff662b5cSJustin T. Gibbs 	type = p + 1;
578ff662b5cSJustin T. Gibbs 
579ff662b5cSJustin T. Gibbs 	p = strchr(type, '/');
580ff662b5cSJustin T. Gibbs 	if (p == NULL)
581ff662b5cSJustin T. Gibbs 		goto out;
582ff662b5cSJustin T. Gibbs 	*p++ = 0;
583ff662b5cSJustin T. Gibbs 
584ff662b5cSJustin T. Gibbs 	/*
585ff662b5cSJustin T. Gibbs 	 * Extract the device ID.  A device ID has one or more path
586ff662b5cSJustin T. Gibbs 	 * components separated by the '/' character.
587ff662b5cSJustin T. Gibbs 	 *
588ff662b5cSJustin T. Gibbs 	 * e.g. "<frontend vm id>/<frontend dev id>" for backend devices.
589ff662b5cSJustin T. Gibbs 	 */
590ff662b5cSJustin T. Gibbs 	id = p;
591ff662b5cSJustin T. Gibbs 	for (component = 0; component < xbs->xbs_id_components; component++) {
592ff662b5cSJustin T. Gibbs 		p = strchr(p, '/');
593ff662b5cSJustin T. Gibbs 		if (p == NULL)
594ff662b5cSJustin T. Gibbs 			break;
595ff662b5cSJustin T. Gibbs 		p++;
596ff662b5cSJustin T. Gibbs 	}
597ff662b5cSJustin T. Gibbs 	if (p != NULL)
598ff662b5cSJustin T. Gibbs 		*p = 0;
599ff662b5cSJustin T. Gibbs 
600ff662b5cSJustin T. Gibbs 	if (*id != 0 && component >= xbs->xbs_id_components - 1) {
601ff662b5cSJustin T. Gibbs 		xenbusb_add_device(xbs->xbs_dev, type, id);
602ff662b5cSJustin T. Gibbs 		taskqueue_enqueue(taskqueue_thread, &xbs->xbs_probe_children);
603ff662b5cSJustin T. Gibbs 	}
604ff662b5cSJustin T. Gibbs out:
605ff662b5cSJustin T. Gibbs 	free(node, M_XENBUS);
606ff662b5cSJustin T. Gibbs }
607ff662b5cSJustin T. Gibbs 
608ff662b5cSJustin T. Gibbs /**
609ff662b5cSJustin T. Gibbs  * \brief Interrupt configuration hook callback associated with xbs_attch_ch.
610ff662b5cSJustin T. Gibbs  *
611ff662b5cSJustin T. Gibbs  * Since interrupts are always functional at the time of XenBus configuration,
612ff662b5cSJustin T. Gibbs  * there is nothing to be done when the callback occurs.  This hook is only
613ff662b5cSJustin T. Gibbs  * registered to hold up boot processing while XenBus devices come online.
614ff662b5cSJustin T. Gibbs  *
615ff662b5cSJustin T. Gibbs  * \param arg  Unused configuration hook callback argument.
616ff662b5cSJustin T. Gibbs  */
617ff662b5cSJustin T. Gibbs static void
618ff662b5cSJustin T. Gibbs xenbusb_nop_confighook_cb(void *arg __unused)
619ff662b5cSJustin T. Gibbs {
620ff662b5cSJustin T. Gibbs }
621ff662b5cSJustin T. Gibbs 
622ff662b5cSJustin T. Gibbs /*--------------------------- Public Functions -------------------------------*/
623ff662b5cSJustin T. Gibbs /*--------- API comments for these methods can be found in xenbusb.h ---------*/
624ff662b5cSJustin T. Gibbs void
625d48760ffSElliott Mitchell xenbusb_identify(driver_t *driver, device_t parent)
626ff662b5cSJustin T. Gibbs {
627ff662b5cSJustin T. Gibbs 	/*
628ff662b5cSJustin T. Gibbs 	 * A single instance of each bus type for which we have a driver
629ff662b5cSJustin T. Gibbs 	 * is always present in a system operating under Xen.
630ff662b5cSJustin T. Gibbs 	 */
631ff662b5cSJustin T. Gibbs 	BUS_ADD_CHILD(parent, 0, driver->name, 0);
632ff662b5cSJustin T. Gibbs }
633ff662b5cSJustin T. Gibbs 
634ff662b5cSJustin T. Gibbs int
635ff662b5cSJustin T. Gibbs xenbusb_add_device(device_t dev, const char *type, const char *id)
636ff662b5cSJustin T. Gibbs {
637ff662b5cSJustin T. Gibbs 	struct xenbusb_softc *xbs;
638ff662b5cSJustin T. Gibbs 	struct sbuf *devpath_sbuf;
639ff662b5cSJustin T. Gibbs 	char *devpath;
640ff662b5cSJustin T. Gibbs 	struct xenbus_device_ivars *ivars;
641ff662b5cSJustin T. Gibbs 	int error;
642ff662b5cSJustin T. Gibbs 
643ff662b5cSJustin T. Gibbs 	xbs = device_get_softc(dev);
644ff662b5cSJustin T. Gibbs 	devpath_sbuf = sbuf_new_auto();
645ff662b5cSJustin T. Gibbs 	sbuf_printf(devpath_sbuf, "%s/%s/%s", xbs->xbs_node, type, id);
646ff662b5cSJustin T. Gibbs 	sbuf_finish(devpath_sbuf);
647ff662b5cSJustin T. Gibbs 	devpath = sbuf_data(devpath_sbuf);
648ff662b5cSJustin T. Gibbs 
649ff662b5cSJustin T. Gibbs 	ivars = malloc(sizeof(*ivars), M_XENBUS, M_ZERO|M_WAITOK);
650ff662b5cSJustin T. Gibbs 	error = ENXIO;
651ff662b5cSJustin T. Gibbs 
652ff662b5cSJustin T. Gibbs 	if (xs_exists(XST_NIL, devpath, "") != 0) {
653ff662b5cSJustin T. Gibbs 		device_t child;
654ff662b5cSJustin T. Gibbs 		enum xenbus_state state;
655ff662b5cSJustin T. Gibbs 		char *statepath;
656ff662b5cSJustin T. Gibbs 
657ff662b5cSJustin T. Gibbs 		child = xenbusb_device_exists(dev, devpath);
658ff662b5cSJustin T. Gibbs 		if (child != NULL) {
659ff662b5cSJustin T. Gibbs 			/*
660ff662b5cSJustin T. Gibbs 			 * We are already tracking this node
661ff662b5cSJustin T. Gibbs 			 */
662ff662b5cSJustin T. Gibbs 			error = 0;
663ff662b5cSJustin T. Gibbs 			goto out;
664ff662b5cSJustin T. Gibbs 		}
665ff662b5cSJustin T. Gibbs 
666ff662b5cSJustin T. Gibbs 		state = xenbus_read_driver_state(devpath);
667ff662b5cSJustin T. Gibbs 		if (state != XenbusStateInitialising) {
668ff662b5cSJustin T. Gibbs 			/*
669ff662b5cSJustin T. Gibbs 			 * Device is not new, so ignore it. This can
670ff662b5cSJustin T. Gibbs 			 * happen if a device is going away after
671ff662b5cSJustin T. Gibbs 			 * switching to Closed.
672ff662b5cSJustin T. Gibbs 			 */
673ff662b5cSJustin T. Gibbs 			printf("xenbusb_add_device: Device %s ignored. "
674ff662b5cSJustin T. Gibbs 			       "State %d\n", devpath, state);
675ff662b5cSJustin T. Gibbs 			error = 0;
676ff662b5cSJustin T. Gibbs 			goto out;
677ff662b5cSJustin T. Gibbs 		}
678ff662b5cSJustin T. Gibbs 
679ff662b5cSJustin T. Gibbs 		sx_init(&ivars->xd_lock, "xdlock");
680ff662b5cSJustin T. Gibbs 		ivars->xd_flags = XDF_CONNECTING;
681ff662b5cSJustin T. Gibbs 		ivars->xd_node = strdup(devpath, M_XENBUS);
682283d6f72SJustin T. Gibbs 		ivars->xd_node_len = strlen(devpath);
683ff662b5cSJustin T. Gibbs 		ivars->xd_type  = strdup(type, M_XENBUS);
684ff662b5cSJustin T. Gibbs 		ivars->xd_state = XenbusStateInitialising;
685ff662b5cSJustin T. Gibbs 
686ff662b5cSJustin T. Gibbs 		error = XENBUSB_GET_OTHEREND_NODE(dev, ivars);
687ff662b5cSJustin T. Gibbs 		if (error) {
688ff662b5cSJustin T. Gibbs 			printf("xenbus_update_device: %s no otherend id\n",
689ff662b5cSJustin T. Gibbs 			    devpath);
690ff662b5cSJustin T. Gibbs 			goto out;
691ff662b5cSJustin T. Gibbs 		}
692ff662b5cSJustin T. Gibbs 
693283d6f72SJustin T. Gibbs 		statepath = malloc(ivars->xd_otherend_path_len
694ff662b5cSJustin T. Gibbs 		    + strlen("/state") + 1, M_XENBUS, M_WAITOK);
695ff662b5cSJustin T. Gibbs 		sprintf(statepath, "%s/state", ivars->xd_otherend_path);
696ff662b5cSJustin T. Gibbs 		ivars->xd_otherend_watch.node = statepath;
697283d6f72SJustin T. Gibbs 		ivars->xd_otherend_watch.callback = xenbusb_otherend_watch_cb;
698283d6f72SJustin T. Gibbs 		ivars->xd_otherend_watch.callback_data = (uintptr_t)ivars;
6994e4e43dcSRoger Pau Monné 		/*
7004e4e43dcSRoger Pau Monné 		 * Other end state node watch, limit to one pending event
7014e4e43dcSRoger Pau Monné 		 * to prevent frontends from queuing too many events that
7024e4e43dcSRoger Pau Monné 		 * could cause resource starvation.
7034e4e43dcSRoger Pau Monné 		 */
7044e4e43dcSRoger Pau Monné 		ivars->xd_otherend_watch.max_pending = 1;
705283d6f72SJustin T. Gibbs 
706283d6f72SJustin T. Gibbs 		ivars->xd_local_watch.node = ivars->xd_node;
707283d6f72SJustin T. Gibbs 		ivars->xd_local_watch.callback = xenbusb_local_watch_cb;
708283d6f72SJustin T. Gibbs 		ivars->xd_local_watch.callback_data = (uintptr_t)ivars;
7094e4e43dcSRoger Pau Monné 		/*
7104e4e43dcSRoger Pau Monné 		 * Watch our local path, only writable by us or a privileged
7114e4e43dcSRoger Pau Monné 		 * domain, no need to limit.
7124e4e43dcSRoger Pau Monné 		 */
7134e4e43dcSRoger Pau Monné 		ivars->xd_local_watch.max_pending = 0;
714ff662b5cSJustin T. Gibbs 
715ff662b5cSJustin T. Gibbs 		mtx_lock(&xbs->xbs_lock);
716ff662b5cSJustin T. Gibbs 		xbs->xbs_connecting_children++;
717ff662b5cSJustin T. Gibbs 		mtx_unlock(&xbs->xbs_lock);
718ff662b5cSJustin T. Gibbs 
719*5b56413dSWarner Losh 		child = device_add_child(dev, NULL, DEVICE_UNIT_ANY);
720ff662b5cSJustin T. Gibbs 		ivars->xd_dev = child;
721ff662b5cSJustin T. Gibbs 		device_set_ivars(child, ivars);
722ff662b5cSJustin T. Gibbs 	}
723ff662b5cSJustin T. Gibbs 
724ff662b5cSJustin T. Gibbs out:
725ff662b5cSJustin T. Gibbs 	sbuf_delete(devpath_sbuf);
726ff662b5cSJustin T. Gibbs 	if (error != 0)
727ff662b5cSJustin T. Gibbs 		xenbusb_free_child_ivars(ivars);
728ff662b5cSJustin T. Gibbs 
729ff662b5cSJustin T. Gibbs 	return (error);
730ff662b5cSJustin T. Gibbs }
731ff662b5cSJustin T. Gibbs 
732ff662b5cSJustin T. Gibbs int
733ff662b5cSJustin T. Gibbs xenbusb_attach(device_t dev, char *bus_node, u_int id_components)
734ff662b5cSJustin T. Gibbs {
735ff662b5cSJustin T. Gibbs 	struct xenbusb_softc *xbs;
736ff662b5cSJustin T. Gibbs 
737ff662b5cSJustin T. Gibbs 	xbs = device_get_softc(dev);
738ff662b5cSJustin T. Gibbs 	mtx_init(&xbs->xbs_lock, "xenbusb softc lock", NULL, MTX_DEF);
739ff662b5cSJustin T. Gibbs 	xbs->xbs_node = bus_node;
740ff662b5cSJustin T. Gibbs 	xbs->xbs_id_components = id_components;
741ff662b5cSJustin T. Gibbs 	xbs->xbs_dev = dev;
742ff662b5cSJustin T. Gibbs 
743ff662b5cSJustin T. Gibbs 	/*
744db4fcadfSConrad Meyer 	 * Since XenBus buses are attached to the XenStore, and
745ff662b5cSJustin T. Gibbs 	 * the XenStore does not probe children until after interrupt
746ff662b5cSJustin T. Gibbs 	 * services are available, this config hook is used solely
747ff662b5cSJustin T. Gibbs 	 * to ensure that the remainder of the boot process (e.g.
748ff662b5cSJustin T. Gibbs 	 * mount root) is deferred until child devices are adequately
749ff662b5cSJustin T. Gibbs 	 * probed.  We unblock the boot process as soon as the
750ff662b5cSJustin T. Gibbs 	 * connecting child count in our softc goes to 0.
751ff662b5cSJustin T. Gibbs 	 */
752ff662b5cSJustin T. Gibbs 	xbs->xbs_attach_ch.ich_func = xenbusb_nop_confighook_cb;
753ff662b5cSJustin T. Gibbs 	xbs->xbs_attach_ch.ich_arg = dev;
754ff662b5cSJustin T. Gibbs 	config_intrhook_establish(&xbs->xbs_attach_ch);
755ff662b5cSJustin T. Gibbs 	xbs->xbs_flags |= XBS_ATTACH_CH_ACTIVE;
756ff662b5cSJustin T. Gibbs 	xbs->xbs_connecting_children = 1;
757ff662b5cSJustin T. Gibbs 
758ff662b5cSJustin T. Gibbs 	/*
759ff662b5cSJustin T. Gibbs 	 * The subtree for this bus type may not yet exist
760ff662b5cSJustin T. Gibbs 	 * causing initial enumeration to fail.  We still
761ff662b5cSJustin T. Gibbs 	 * want to return success from our attach though
762ff662b5cSJustin T. Gibbs 	 * so that we are ready to handle devices for this
763ff662b5cSJustin T. Gibbs 	 * bus when they are dynamically attached to us
764ff662b5cSJustin T. Gibbs 	 * by a Xen management action.
765ff662b5cSJustin T. Gibbs 	 */
766ff662b5cSJustin T. Gibbs 	(void)xenbusb_enumerate_bus(xbs);
767ff662b5cSJustin T. Gibbs 	xenbusb_probe_children(dev);
768ff662b5cSJustin T. Gibbs 
769ff662b5cSJustin T. Gibbs 	xbs->xbs_device_watch.node = bus_node;
770ff662b5cSJustin T. Gibbs 	xbs->xbs_device_watch.callback = xenbusb_devices_changed;
771283d6f72SJustin T. Gibbs 	xbs->xbs_device_watch.callback_data = (uintptr_t)xbs;
7724e4e43dcSRoger Pau Monné 	/*
7734e4e43dcSRoger Pau Monné 	 * Allow for unlimited pending watches, as those are local paths
7744e4e43dcSRoger Pau Monné 	 * either controlled by the guest or only writable by privileged
7754e4e43dcSRoger Pau Monné 	 * domains.
7764e4e43dcSRoger Pau Monné 	 */
7774e4e43dcSRoger Pau Monné 	xbs->xbs_device_watch.max_pending = 0;
778ff662b5cSJustin T. Gibbs 
779ff662b5cSJustin T. Gibbs 	TASK_INIT(&xbs->xbs_probe_children, 0, xenbusb_probe_children_cb, dev);
780ff662b5cSJustin T. Gibbs 
781ff662b5cSJustin T. Gibbs 	xs_register_watch(&xbs->xbs_device_watch);
782ff662b5cSJustin T. Gibbs 
783ff662b5cSJustin T. Gibbs 	xenbusb_release_confighook(xbs);
784ff662b5cSJustin T. Gibbs 
785ff662b5cSJustin T. Gibbs 	return (0);
786ff662b5cSJustin T. Gibbs }
787ff662b5cSJustin T. Gibbs 
788ff662b5cSJustin T. Gibbs int
789ff662b5cSJustin T. Gibbs xenbusb_resume(device_t dev)
790ff662b5cSJustin T. Gibbs {
791ff662b5cSJustin T. Gibbs 	device_t *kids;
792ff662b5cSJustin T. Gibbs 	struct xenbus_device_ivars *ivars;
793ff662b5cSJustin T. Gibbs 	int i, count, error;
794ff662b5cSJustin T. Gibbs 	char *statepath;
795ff662b5cSJustin T. Gibbs 
796ff662b5cSJustin T. Gibbs 	/*
797ff662b5cSJustin T. Gibbs 	 * We must re-examine each device and find the new path for
798ff662b5cSJustin T. Gibbs 	 * its backend.
799ff662b5cSJustin T. Gibbs 	 */
800ff662b5cSJustin T. Gibbs 	if (device_get_children(dev, &kids, &count) == 0) {
801ff662b5cSJustin T. Gibbs 		for (i = 0; i < count; i++) {
802ff662b5cSJustin T. Gibbs 			if (device_get_state(kids[i]) == DS_NOTPRESENT)
803ff662b5cSJustin T. Gibbs 				continue;
804ff662b5cSJustin T. Gibbs 
8058dee0e9bSRoger Pau Monné 			if (xen_suspend_cancelled) {
8068dee0e9bSRoger Pau Monné 				DEVICE_RESUME(kids[i]);
8078dee0e9bSRoger Pau Monné 				continue;
8088dee0e9bSRoger Pau Monné 			}
8098dee0e9bSRoger Pau Monné 
810ff662b5cSJustin T. Gibbs 			ivars = device_get_ivars(kids[i]);
811ff662b5cSJustin T. Gibbs 
812ff662b5cSJustin T. Gibbs 			xs_unregister_watch(&ivars->xd_otherend_watch);
8132ca7463bSJustin T. Gibbs 			xenbus_set_state(kids[i], XenbusStateInitialising);
814ff662b5cSJustin T. Gibbs 
815ff662b5cSJustin T. Gibbs 			/*
816ff662b5cSJustin T. Gibbs 			 * Find the new backend details and
817ff662b5cSJustin T. Gibbs 			 * re-register our watch.
818ff662b5cSJustin T. Gibbs 			 */
819ff662b5cSJustin T. Gibbs 			error = XENBUSB_GET_OTHEREND_NODE(dev, ivars);
820ff662b5cSJustin T. Gibbs 			if (error)
821ff662b5cSJustin T. Gibbs 				return (error);
822ff662b5cSJustin T. Gibbs 
823283d6f72SJustin T. Gibbs 			statepath = malloc(ivars->xd_otherend_path_len
824ff662b5cSJustin T. Gibbs 			    + strlen("/state") + 1, M_XENBUS, M_WAITOK);
825ff662b5cSJustin T. Gibbs 			sprintf(statepath, "%s/state", ivars->xd_otherend_path);
826ff662b5cSJustin T. Gibbs 
827ff662b5cSJustin T. Gibbs 			free(ivars->xd_otherend_watch.node, M_XENBUS);
828ff662b5cSJustin T. Gibbs 			ivars->xd_otherend_watch.node = statepath;
829ff662b5cSJustin T. Gibbs 
8302ca7463bSJustin T. Gibbs 			DEVICE_RESUME(kids[i]);
8312ca7463bSJustin T. Gibbs 
8322ca7463bSJustin T. Gibbs 			xs_register_watch(&ivars->xd_otherend_watch);
833ff662b5cSJustin T. Gibbs #if 0
834ff662b5cSJustin T. Gibbs 			/*
835ff662b5cSJustin T. Gibbs 			 * Can't do this yet since we are running in
836ff662b5cSJustin T. Gibbs 			 * the xenwatch thread and if we sleep here,
837ff662b5cSJustin T. Gibbs 			 * we will stop delivering watch notifications
838ff662b5cSJustin T. Gibbs 			 * and the device will never come back online.
839ff662b5cSJustin T. Gibbs 			 */
840ff662b5cSJustin T. Gibbs 			sx_xlock(&ivars->xd_lock);
841ff662b5cSJustin T. Gibbs 			while (ivars->xd_state != XenbusStateClosed
842ff662b5cSJustin T. Gibbs 			    && ivars->xd_state != XenbusStateConnected)
843ff662b5cSJustin T. Gibbs 				sx_sleep(&ivars->xd_state, &ivars->xd_lock,
844ff662b5cSJustin T. Gibbs 				    0, "xdresume", 0);
845ff662b5cSJustin T. Gibbs 			sx_xunlock(&ivars->xd_lock);
846ff662b5cSJustin T. Gibbs #endif
847ff662b5cSJustin T. Gibbs 		}
848ff662b5cSJustin T. Gibbs 		free(kids, M_TEMP);
849ff662b5cSJustin T. Gibbs 	}
850ff662b5cSJustin T. Gibbs 
851ff662b5cSJustin T. Gibbs 	return (0);
852ff662b5cSJustin T. Gibbs }
853ff662b5cSJustin T. Gibbs 
854ff662b5cSJustin T. Gibbs int
855ff662b5cSJustin T. Gibbs xenbusb_print_child(device_t dev, device_t child)
856ff662b5cSJustin T. Gibbs {
857ff662b5cSJustin T. Gibbs 	struct xenbus_device_ivars *ivars = device_get_ivars(child);
858ff662b5cSJustin T. Gibbs 	int	retval = 0;
859ff662b5cSJustin T. Gibbs 
860ff662b5cSJustin T. Gibbs 	retval += bus_print_child_header(dev, child);
861ff662b5cSJustin T. Gibbs 	retval += printf(" at %s", ivars->xd_node);
862ff662b5cSJustin T. Gibbs 	retval += bus_print_child_footer(dev, child);
863ff662b5cSJustin T. Gibbs 
864ff662b5cSJustin T. Gibbs 	return (retval);
865ff662b5cSJustin T. Gibbs }
866ff662b5cSJustin T. Gibbs 
867ff662b5cSJustin T. Gibbs int
868ff662b5cSJustin T. Gibbs xenbusb_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
869ff662b5cSJustin T. Gibbs {
870ff662b5cSJustin T. Gibbs 	struct xenbus_device_ivars *ivars = device_get_ivars(child);
871ff662b5cSJustin T. Gibbs 
872ff662b5cSJustin T. Gibbs 	switch (index) {
873ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_NODE:
874ff662b5cSJustin T. Gibbs 		*result = (uintptr_t) ivars->xd_node;
875ff662b5cSJustin T. Gibbs 		return (0);
876ff662b5cSJustin T. Gibbs 
877ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_TYPE:
878ff662b5cSJustin T. Gibbs 		*result = (uintptr_t) ivars->xd_type;
879ff662b5cSJustin T. Gibbs 		return (0);
880ff662b5cSJustin T. Gibbs 
881ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_STATE:
882ff662b5cSJustin T. Gibbs 		*result = (uintptr_t) ivars->xd_state;
883ff662b5cSJustin T. Gibbs 		return (0);
884ff662b5cSJustin T. Gibbs 
885ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_OTHEREND_ID:
886ff662b5cSJustin T. Gibbs 		*result = (uintptr_t) ivars->xd_otherend_id;
887ff662b5cSJustin T. Gibbs 		return (0);
888ff662b5cSJustin T. Gibbs 
889ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_OTHEREND_PATH:
890ff662b5cSJustin T. Gibbs 		*result = (uintptr_t) ivars->xd_otherend_path;
891ff662b5cSJustin T. Gibbs 		return (0);
892ff662b5cSJustin T. Gibbs 	}
893ff662b5cSJustin T. Gibbs 
894ff662b5cSJustin T. Gibbs 	return (ENOENT);
895ff662b5cSJustin T. Gibbs }
896ff662b5cSJustin T. Gibbs 
897ff662b5cSJustin T. Gibbs int
898ff662b5cSJustin T. Gibbs xenbusb_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
899ff662b5cSJustin T. Gibbs {
900ff662b5cSJustin T. Gibbs 	struct xenbus_device_ivars *ivars = device_get_ivars(child);
901ff662b5cSJustin T. Gibbs 	enum xenbus_state newstate;
902ff662b5cSJustin T. Gibbs 	int currstate;
903ff662b5cSJustin T. Gibbs 
904ff662b5cSJustin T. Gibbs 	switch (index) {
905ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_STATE:
906ff662b5cSJustin T. Gibbs 	{
907ff662b5cSJustin T. Gibbs 		int error;
908f3d54dedSRoger Pau Monné 		struct xs_transaction xst;
909ff662b5cSJustin T. Gibbs 
910ff662b5cSJustin T. Gibbs 		newstate = (enum xenbus_state)value;
911ff662b5cSJustin T. Gibbs 		sx_xlock(&ivars->xd_lock);
912ff662b5cSJustin T. Gibbs 		if (ivars->xd_state == newstate) {
913ff662b5cSJustin T. Gibbs 			error = 0;
914ff662b5cSJustin T. Gibbs 			goto out;
915ff662b5cSJustin T. Gibbs 		}
916ff662b5cSJustin T. Gibbs 
917f3d54dedSRoger Pau Monné 		do {
918f3d54dedSRoger Pau Monné 			error = xs_transaction_start(&xst);
919f3d54dedSRoger Pau Monné 			if (error != 0)
920f3d54dedSRoger Pau Monné 				goto out;
921f3d54dedSRoger Pau Monné 
922f3d54dedSRoger Pau Monné 			do {
923f3d54dedSRoger Pau Monné 				error = xs_scanf(xst, ivars->xd_node, "state",
924ff662b5cSJustin T. Gibbs 				    NULL, "%d", &currstate);
925f3d54dedSRoger Pau Monné 			} while (error == EAGAIN);
926ff662b5cSJustin T. Gibbs 			if (error)
927ff662b5cSJustin T. Gibbs 				goto out;
928ff662b5cSJustin T. Gibbs 
929ff662b5cSJustin T. Gibbs 			do {
930f3d54dedSRoger Pau Monné 				error = xs_printf(xst, ivars->xd_node, "state",
931ff662b5cSJustin T. Gibbs 				    "%d", newstate);
932ff662b5cSJustin T. Gibbs 			} while (error == EAGAIN);
933ff662b5cSJustin T. Gibbs 			if (error) {
934ff662b5cSJustin T. Gibbs 				/*
935ff662b5cSJustin T. Gibbs 				 * Avoid looping through xenbus_dev_fatal()
936ff662b5cSJustin T. Gibbs 				 * which calls xenbus_write_ivar to set the
937ff662b5cSJustin T. Gibbs 				 * state to closing.
938ff662b5cSJustin T. Gibbs 				 */
939ff662b5cSJustin T. Gibbs 				if (newstate != XenbusStateClosing)
940ff662b5cSJustin T. Gibbs 					xenbus_dev_fatal(dev, error,
941ff662b5cSJustin T. Gibbs 					    "writing new state");
942ff662b5cSJustin T. Gibbs 				goto out;
943ff662b5cSJustin T. Gibbs 			}
944f3d54dedSRoger Pau Monné 		} while (xs_transaction_end(xst, 0));
945ff662b5cSJustin T. Gibbs 		ivars->xd_state = newstate;
946ff662b5cSJustin T. Gibbs 
947f3d54dedSRoger Pau Monné 		if ((ivars->xd_flags & XDF_CONNECTING) != 0 &&
948f3d54dedSRoger Pau Monné 		    (newstate == XenbusStateClosed ||
949f3d54dedSRoger Pau Monné 		    newstate == XenbusStateConnected)) {
950ff662b5cSJustin T. Gibbs 			struct xenbusb_softc *xbs;
951ff662b5cSJustin T. Gibbs 
952ff662b5cSJustin T. Gibbs 			ivars->xd_flags &= ~XDF_CONNECTING;
953ff662b5cSJustin T. Gibbs 			xbs = device_get_softc(dev);
954ff662b5cSJustin T. Gibbs 			xenbusb_release_confighook(xbs);
955ff662b5cSJustin T. Gibbs 		}
956ff662b5cSJustin T. Gibbs 
957ff662b5cSJustin T. Gibbs 		wakeup(&ivars->xd_state);
958ff662b5cSJustin T. Gibbs 	out:
959f3d54dedSRoger Pau Monné 		if (error != 0)
960f3d54dedSRoger Pau Monné 			xs_transaction_end(xst, 1);
961ff662b5cSJustin T. Gibbs 		sx_xunlock(&ivars->xd_lock);
962f3d54dedSRoger Pau Monné 		/*
963f3d54dedSRoger Pau Monné 		 * Shallow ENOENT errors, as returning an error here will
964f3d54dedSRoger Pau Monné 		 * trigger a panic.  ENOENT is fine to ignore, because it means
965f3d54dedSRoger Pau Monné 		 * the toolstack has removed the state node as part of
966f3d54dedSRoger Pau Monné 		 * destroying the device, and so we have to shut down the
967f3d54dedSRoger Pau Monné 		 * device without recreating it or else the node would be
968f3d54dedSRoger Pau Monné 		 * leaked.
969f3d54dedSRoger Pau Monné 		 */
970f3d54dedSRoger Pau Monné 		return (error == ENOENT ? 0 : error);
971ff662b5cSJustin T. Gibbs 	}
972ff662b5cSJustin T. Gibbs 
973ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_NODE:
974ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_TYPE:
975ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_OTHEREND_ID:
976ff662b5cSJustin T. Gibbs 	case XENBUS_IVAR_OTHEREND_PATH:
977ff662b5cSJustin T. Gibbs 		/*
978ff662b5cSJustin T. Gibbs 		 * These variables are read-only.
979ff662b5cSJustin T. Gibbs 		 */
980ff662b5cSJustin T. Gibbs 		return (EINVAL);
981ff662b5cSJustin T. Gibbs 	}
982ff662b5cSJustin T. Gibbs 
983ff662b5cSJustin T. Gibbs 	return (ENOENT);
984ff662b5cSJustin T. Gibbs }
985283d6f72SJustin T. Gibbs 
986283d6f72SJustin T. Gibbs void
987283d6f72SJustin T. Gibbs xenbusb_otherend_changed(device_t bus, device_t child, enum xenbus_state state)
988283d6f72SJustin T. Gibbs {
989283d6f72SJustin T. Gibbs 	XENBUS_OTHEREND_CHANGED(child, state);
990283d6f72SJustin T. Gibbs }
991283d6f72SJustin T. Gibbs 
992283d6f72SJustin T. Gibbs void
993283d6f72SJustin T. Gibbs xenbusb_localend_changed(device_t bus, device_t child, const char *path)
994283d6f72SJustin T. Gibbs {
995283d6f72SJustin T. Gibbs 
996283d6f72SJustin T. Gibbs 	if (strcmp(path, "/state") != 0) {
997283d6f72SJustin T. Gibbs 		struct xenbus_device_ivars *ivars;
998283d6f72SJustin T. Gibbs 
999283d6f72SJustin T. Gibbs 		ivars = device_get_ivars(child);
1000283d6f72SJustin T. Gibbs 		sx_xlock(&ivars->xd_lock);
1001283d6f72SJustin T. Gibbs 		ivars->xd_state = xenbus_read_driver_state(ivars->xd_node);
1002283d6f72SJustin T. Gibbs 		sx_xunlock(&ivars->xd_lock);
1003283d6f72SJustin T. Gibbs 	}
1004283d6f72SJustin T. Gibbs 	XENBUS_LOCALEND_CHANGED(child, path);
1005283d6f72SJustin T. Gibbs }
1006