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 * 33*db4fcadfSConrad 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 */ 54ff662b5cSJustin T. Gibbs #include <sys/cdefs.h> 55ff662b5cSJustin T. Gibbs __FBSDID("$FreeBSD$"); 56ff662b5cSJustin T. Gibbs 57ff662b5cSJustin T. Gibbs #include <sys/param.h> 58ff662b5cSJustin T. Gibbs #include <sys/bus.h> 59ff662b5cSJustin T. Gibbs #include <sys/kernel.h> 60ff662b5cSJustin T. Gibbs #include <sys/lock.h> 61ff662b5cSJustin T. Gibbs #include <sys/malloc.h> 62ff662b5cSJustin T. Gibbs #include <sys/module.h> 63ff662b5cSJustin T. Gibbs #include <sys/sbuf.h> 64ff662b5cSJustin T. Gibbs #include <sys/sysctl.h> 65ff662b5cSJustin T. Gibbs #include <sys/syslog.h> 66ff662b5cSJustin T. Gibbs #include <sys/systm.h> 67ff662b5cSJustin T. Gibbs #include <sys/sx.h> 68ff662b5cSJustin T. Gibbs #include <sys/taskqueue.h> 69ff662b5cSJustin T. Gibbs 70ff662b5cSJustin T. Gibbs #include <machine/xen/xen-os.h> 71ff662b5cSJustin T. Gibbs #include <machine/stdarg.h> 72ff662b5cSJustin T. Gibbs 73ff662b5cSJustin T. Gibbs #include <xen/gnttab.h> 74ff662b5cSJustin T. Gibbs #include <xen/xenstore/xenstorevar.h> 75ff662b5cSJustin T. Gibbs #include <xen/xenbus/xenbusb.h> 76ff662b5cSJustin T. Gibbs #include <xen/xenbus/xenbusvar.h> 77ff662b5cSJustin T. Gibbs 78ff662b5cSJustin T. Gibbs /*------------------------- Private Functions --------------------------------*/ 79ff662b5cSJustin T. Gibbs /** 80ff662b5cSJustin T. Gibbs * \brief Deallocate XenBus device instance variables. 81ff662b5cSJustin T. Gibbs * 82ff662b5cSJustin T. Gibbs * \param ivars The instance variable block to free. 83ff662b5cSJustin T. Gibbs */ 84ff662b5cSJustin T. Gibbs static void 85ff662b5cSJustin T. Gibbs xenbusb_free_child_ivars(struct xenbus_device_ivars *ivars) 86ff662b5cSJustin T. Gibbs { 87ff662b5cSJustin T. Gibbs if (ivars->xd_otherend_watch.node != NULL) { 88ff662b5cSJustin T. Gibbs xs_unregister_watch(&ivars->xd_otherend_watch); 89ff662b5cSJustin T. Gibbs free(ivars->xd_otherend_watch.node, M_XENBUS); 90ff662b5cSJustin T. Gibbs ivars->xd_otherend_watch.node = NULL; 91ff662b5cSJustin T. Gibbs } 92ff662b5cSJustin T. Gibbs 93283d6f72SJustin T. Gibbs if (ivars->xd_local_watch.node != NULL) { 94283d6f72SJustin T. Gibbs xs_unregister_watch(&ivars->xd_local_watch); 95283d6f72SJustin T. Gibbs ivars->xd_local_watch.node = NULL; 96283d6f72SJustin T. Gibbs } 97283d6f72SJustin T. Gibbs 98ff662b5cSJustin T. Gibbs if (ivars->xd_node != NULL) { 99ff662b5cSJustin T. Gibbs free(ivars->xd_node, M_XENBUS); 100ff662b5cSJustin T. Gibbs ivars->xd_node = NULL; 101ff662b5cSJustin T. Gibbs } 102283d6f72SJustin T. Gibbs ivars->xd_node_len = 0; 103ff662b5cSJustin T. Gibbs 104ff662b5cSJustin T. Gibbs if (ivars->xd_type != NULL) { 105ff662b5cSJustin T. Gibbs free(ivars->xd_type, M_XENBUS); 106ff662b5cSJustin T. Gibbs ivars->xd_type = NULL; 107ff662b5cSJustin T. Gibbs } 108ff662b5cSJustin T. Gibbs 109ff662b5cSJustin T. Gibbs if (ivars->xd_otherend_path != NULL) { 110ff662b5cSJustin T. Gibbs free(ivars->xd_otherend_path, M_XENBUS); 111ff662b5cSJustin T. Gibbs ivars->xd_otherend_path = NULL; 112ff662b5cSJustin T. Gibbs } 113283d6f72SJustin T. Gibbs ivars->xd_otherend_path_len = 0; 114ff662b5cSJustin T. Gibbs 115ff662b5cSJustin T. Gibbs free(ivars, M_XENBUS); 116ff662b5cSJustin T. Gibbs } 117ff662b5cSJustin T. Gibbs 118ff662b5cSJustin T. Gibbs /** 119ff662b5cSJustin T. Gibbs * XenBus watch callback registered against the "state" XenStore 120ff662b5cSJustin T. Gibbs * node of the other-end of a split device connection. 121ff662b5cSJustin T. Gibbs * 122ff662b5cSJustin T. Gibbs * This callback is invoked whenever the state of a device instance's 123ff662b5cSJustin T. Gibbs * peer changes. 124ff662b5cSJustin T. Gibbs * 125ff662b5cSJustin T. Gibbs * \param watch The xs_watch object used to register this callback 126ff662b5cSJustin T. Gibbs * function. 127ff662b5cSJustin T. Gibbs * \param vec An array of pointers to NUL terminated strings containing 128ff662b5cSJustin T. Gibbs * watch event data. The vector should be indexed via the 129ff662b5cSJustin T. Gibbs * xs_watch_type enum in xs_wire.h. 130ff662b5cSJustin T. Gibbs * \param vec_size The number of elements in vec. 131ff662b5cSJustin T. Gibbs */ 132ff662b5cSJustin T. Gibbs static void 133283d6f72SJustin T. Gibbs xenbusb_otherend_watch_cb(struct xs_watch *watch, const char **vec, 134ff662b5cSJustin T. Gibbs unsigned int vec_size __unused) 135ff662b5cSJustin T. Gibbs { 136ff662b5cSJustin T. Gibbs struct xenbus_device_ivars *ivars; 137283d6f72SJustin T. Gibbs device_t child; 138283d6f72SJustin T. Gibbs device_t bus; 139283d6f72SJustin T. Gibbs const char *path; 140ff662b5cSJustin T. Gibbs enum xenbus_state newstate; 141ff662b5cSJustin T. Gibbs 142283d6f72SJustin T. Gibbs ivars = (struct xenbus_device_ivars *)watch->callback_data; 143283d6f72SJustin T. Gibbs child = ivars->xd_dev; 144283d6f72SJustin T. Gibbs bus = device_get_parent(child); 145ff662b5cSJustin T. Gibbs 146283d6f72SJustin T. Gibbs path = vec[XS_WATCH_PATH]; 147283d6f72SJustin T. Gibbs if (ivars->xd_otherend_path == NULL 148283d6f72SJustin T. Gibbs || strncmp(ivars->xd_otherend_path, path, ivars->xd_otherend_path_len)) 149ff662b5cSJustin T. Gibbs return; 150ff662b5cSJustin T. Gibbs 151ff662b5cSJustin T. Gibbs newstate = xenbus_read_driver_state(ivars->xd_otherend_path); 152283d6f72SJustin T. Gibbs XENBUSB_OTHEREND_CHANGED(bus, child, newstate); 153283d6f72SJustin T. Gibbs } 154283d6f72SJustin T. Gibbs 155283d6f72SJustin T. Gibbs /** 156283d6f72SJustin T. Gibbs * XenBus watch callback registered against the XenStore sub-tree 157283d6f72SJustin T. Gibbs * represnting the local half of a split device connection. 158283d6f72SJustin T. Gibbs * 159283d6f72SJustin T. Gibbs * This callback is invoked whenever any XenStore data in the subtree 160283d6f72SJustin T. Gibbs * is modified, either by us or another privledged domain. 161283d6f72SJustin T. Gibbs * 162283d6f72SJustin T. Gibbs * \param watch The xs_watch object used to register this callback 163283d6f72SJustin T. Gibbs * function. 164283d6f72SJustin T. Gibbs * \param vec An array of pointers to NUL terminated strings containing 165283d6f72SJustin T. Gibbs * watch event data. The vector should be indexed via the 166283d6f72SJustin T. Gibbs * xs_watch_type enum in xs_wire.h. 167283d6f72SJustin T. Gibbs * \param vec_size The number of elements in vec. 168283d6f72SJustin T. Gibbs * 169283d6f72SJustin T. Gibbs */ 170283d6f72SJustin T. Gibbs static void 171283d6f72SJustin T. Gibbs xenbusb_local_watch_cb(struct xs_watch *watch, const char **vec, 172283d6f72SJustin T. Gibbs unsigned int vec_size __unused) 173283d6f72SJustin T. Gibbs { 174283d6f72SJustin T. Gibbs struct xenbus_device_ivars *ivars; 175283d6f72SJustin T. Gibbs device_t child; 176283d6f72SJustin T. Gibbs device_t bus; 177283d6f72SJustin T. Gibbs const char *path; 178283d6f72SJustin T. Gibbs 179283d6f72SJustin T. Gibbs ivars = (struct xenbus_device_ivars *)watch->callback_data; 180283d6f72SJustin T. Gibbs child = ivars->xd_dev; 181283d6f72SJustin T. Gibbs bus = device_get_parent(child); 182283d6f72SJustin T. Gibbs 183283d6f72SJustin T. Gibbs path = vec[XS_WATCH_PATH]; 184283d6f72SJustin T. Gibbs if (ivars->xd_node == NULL 185283d6f72SJustin T. Gibbs || strncmp(ivars->xd_node, path, ivars->xd_node_len)) 186283d6f72SJustin T. Gibbs return; 187283d6f72SJustin T. Gibbs 188283d6f72SJustin T. Gibbs XENBUSB_LOCALEND_CHANGED(bus, child, &path[ivars->xd_node_len]); 189ff662b5cSJustin T. Gibbs } 190ff662b5cSJustin T. Gibbs 191ff662b5cSJustin T. Gibbs /** 192ff662b5cSJustin T. Gibbs * Search our internal record of configured devices (not the XenStore) 193ff662b5cSJustin T. Gibbs * to determine if the XenBus device indicated by \a node is known to 194ff662b5cSJustin T. Gibbs * the system. 195ff662b5cSJustin T. Gibbs * 196ff662b5cSJustin T. Gibbs * \param dev The XenBus bus instance to search for device children. 197ff662b5cSJustin T. Gibbs * \param node The XenStore node path for the device to find. 198ff662b5cSJustin T. Gibbs * 199ff662b5cSJustin T. Gibbs * \return The device_t of the found device if any, or NULL. 200ff662b5cSJustin T. Gibbs * 201ff662b5cSJustin T. Gibbs * \note device_t is a pointer type, so it can be compared against 202ff662b5cSJustin T. Gibbs * NULL for validity. 203ff662b5cSJustin T. Gibbs */ 204ff662b5cSJustin T. Gibbs static device_t 205ff662b5cSJustin T. Gibbs xenbusb_device_exists(device_t dev, const char *node) 206ff662b5cSJustin T. Gibbs { 207ff662b5cSJustin T. Gibbs device_t *kids; 208ff662b5cSJustin T. Gibbs device_t result; 209ff662b5cSJustin T. Gibbs struct xenbus_device_ivars *ivars; 210ff662b5cSJustin T. Gibbs int i, count; 211ff662b5cSJustin T. Gibbs 212ff662b5cSJustin T. Gibbs if (device_get_children(dev, &kids, &count)) 213ff662b5cSJustin T. Gibbs return (FALSE); 214ff662b5cSJustin T. Gibbs 215ff662b5cSJustin T. Gibbs result = NULL; 216ff662b5cSJustin T. Gibbs for (i = 0; i < count; i++) { 217ff662b5cSJustin T. Gibbs ivars = device_get_ivars(kids[i]); 218ff662b5cSJustin T. Gibbs if (!strcmp(ivars->xd_node, node)) { 219ff662b5cSJustin T. Gibbs result = kids[i]; 220ff662b5cSJustin T. Gibbs break; 221ff662b5cSJustin T. Gibbs } 222ff662b5cSJustin T. Gibbs } 223ff662b5cSJustin T. Gibbs free(kids, M_TEMP); 224ff662b5cSJustin T. Gibbs 225ff662b5cSJustin T. Gibbs return (result); 226ff662b5cSJustin T. Gibbs } 227ff662b5cSJustin T. Gibbs 228ff662b5cSJustin T. Gibbs static void 229ff662b5cSJustin T. Gibbs xenbusb_delete_child(device_t dev, device_t child) 230ff662b5cSJustin T. Gibbs { 231ff662b5cSJustin T. Gibbs struct xenbus_device_ivars *ivars; 232ff662b5cSJustin T. Gibbs 233ff662b5cSJustin T. Gibbs ivars = device_get_ivars(child); 234ff662b5cSJustin T. Gibbs 235ff662b5cSJustin T. Gibbs /* 236ff662b5cSJustin T. Gibbs * We no longer care about the otherend of the 237283d6f72SJustin T. Gibbs * connection. Cancel the watches now so that we 238ff662b5cSJustin T. Gibbs * don't try to handle an event for a partially 239ff662b5cSJustin T. Gibbs * detached child. 240ff662b5cSJustin T. Gibbs */ 241ff662b5cSJustin T. Gibbs if (ivars->xd_otherend_watch.node != NULL) 242ff662b5cSJustin T. Gibbs xs_unregister_watch(&ivars->xd_otherend_watch); 243283d6f72SJustin T. Gibbs if (ivars->xd_local_watch.node != NULL) 244283d6f72SJustin T. Gibbs xs_unregister_watch(&ivars->xd_local_watch); 245ff662b5cSJustin T. Gibbs 246ff662b5cSJustin T. Gibbs device_delete_child(dev, child); 247ff662b5cSJustin T. Gibbs xenbusb_free_child_ivars(ivars); 248ff662b5cSJustin T. Gibbs } 249ff662b5cSJustin T. Gibbs 250ff662b5cSJustin T. Gibbs /** 251ff662b5cSJustin T. Gibbs * \param dev The NewBus device representing this XenBus bus. 252ff662b5cSJustin T. Gibbs * \param child The NewBus device representing a child of dev%'s XenBus bus. 253ff662b5cSJustin T. Gibbs */ 254ff662b5cSJustin T. Gibbs static void 255ff662b5cSJustin T. Gibbs xenbusb_verify_device(device_t dev, device_t child) 256ff662b5cSJustin T. Gibbs { 257ff662b5cSJustin T. Gibbs if (xs_exists(XST_NIL, xenbus_get_node(child), "") == 0) { 258ff662b5cSJustin T. Gibbs 259ff662b5cSJustin T. Gibbs /* 260ff662b5cSJustin T. Gibbs * Device tree has been removed from Xenbus. 261ff662b5cSJustin T. Gibbs * Tear down the device. 262ff662b5cSJustin T. Gibbs */ 263ff662b5cSJustin T. Gibbs xenbusb_delete_child(dev, child); 264ff662b5cSJustin T. Gibbs } 265ff662b5cSJustin T. Gibbs } 266ff662b5cSJustin T. Gibbs 267ff662b5cSJustin T. Gibbs /** 268ff662b5cSJustin T. Gibbs * \brief Enumerate the devices on a XenBus bus and register them with 269ff662b5cSJustin T. Gibbs * the NewBus device tree. 270ff662b5cSJustin T. Gibbs * 271ff662b5cSJustin T. Gibbs * xenbusb_enumerate_bus() will create entries (in state DS_NOTPRESENT) 272ff662b5cSJustin T. Gibbs * for nodes that appear in the XenStore, but will not invoke probe/attach 273ff662b5cSJustin T. Gibbs * operations on drivers. Probe/Attach processing must be separately 274ff662b5cSJustin T. Gibbs * performed via an invocation of xenbusb_probe_children(). This is usually 275ff662b5cSJustin T. Gibbs * done via the xbs_probe_children task. 276ff662b5cSJustin T. Gibbs * 277ff662b5cSJustin T. Gibbs * \param xbs XenBus Bus device softc of the owner of the bus to enumerate. 278ff662b5cSJustin T. Gibbs * 279ff662b5cSJustin T. Gibbs * \return On success, 0. Otherwise an errno value indicating the 280ff662b5cSJustin T. Gibbs * type of failure. 281ff662b5cSJustin T. Gibbs */ 282ff662b5cSJustin T. Gibbs static int 283ff662b5cSJustin T. Gibbs xenbusb_enumerate_bus(struct xenbusb_softc *xbs) 284ff662b5cSJustin T. Gibbs { 285ff662b5cSJustin T. Gibbs const char **types; 286ff662b5cSJustin T. Gibbs u_int type_idx; 287ff662b5cSJustin T. Gibbs u_int type_count; 288ff662b5cSJustin T. Gibbs int error; 289ff662b5cSJustin T. Gibbs 290ff662b5cSJustin T. Gibbs error = xs_directory(XST_NIL, xbs->xbs_node, "", &type_count, &types); 291ff662b5cSJustin T. Gibbs if (error) 292ff662b5cSJustin T. Gibbs return (error); 293ff662b5cSJustin T. Gibbs 294ff662b5cSJustin T. Gibbs for (type_idx = 0; type_idx < type_count; type_idx++) 295ff662b5cSJustin T. Gibbs XENBUSB_ENUMERATE_TYPE(xbs->xbs_dev, types[type_idx]); 296ff662b5cSJustin T. Gibbs 297ff662b5cSJustin T. Gibbs free(types, M_XENSTORE); 298ff662b5cSJustin T. Gibbs 299ff662b5cSJustin T. Gibbs return (0); 300ff662b5cSJustin T. Gibbs } 301ff662b5cSJustin T. Gibbs 302ff662b5cSJustin T. Gibbs /** 303ff662b5cSJustin T. Gibbs * Handler for all generic XenBus device systcl nodes. 304ff662b5cSJustin T. Gibbs */ 305ff662b5cSJustin T. Gibbs static int 306ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_handler(SYSCTL_HANDLER_ARGS) 307ff662b5cSJustin T. Gibbs { 308ff662b5cSJustin T. Gibbs device_t dev; 309ff662b5cSJustin T. Gibbs const char *value; 310ff662b5cSJustin T. Gibbs 311ff662b5cSJustin T. Gibbs dev = (device_t)arg1; 312ff662b5cSJustin T. Gibbs switch (arg2) { 313ff662b5cSJustin T. Gibbs case XENBUS_IVAR_NODE: 314ff662b5cSJustin T. Gibbs value = xenbus_get_node(dev); 315ff662b5cSJustin T. Gibbs break; 316ff662b5cSJustin T. Gibbs case XENBUS_IVAR_TYPE: 317ff662b5cSJustin T. Gibbs value = xenbus_get_type(dev); 318ff662b5cSJustin T. Gibbs break; 319ff662b5cSJustin T. Gibbs case XENBUS_IVAR_STATE: 320ff662b5cSJustin T. Gibbs value = xenbus_strstate(xenbus_get_state(dev)); 321ff662b5cSJustin T. Gibbs break; 322ff662b5cSJustin T. Gibbs case XENBUS_IVAR_OTHEREND_ID: 323ff662b5cSJustin T. Gibbs return (sysctl_handle_int(oidp, NULL, 324ff662b5cSJustin T. Gibbs xenbus_get_otherend_id(dev), 325ff662b5cSJustin T. Gibbs req)); 326ff662b5cSJustin T. Gibbs /* NOTREACHED */ 327ff662b5cSJustin T. Gibbs case XENBUS_IVAR_OTHEREND_PATH: 328ff662b5cSJustin T. Gibbs value = xenbus_get_otherend_path(dev); 329ff662b5cSJustin T. Gibbs break; 330ff662b5cSJustin T. Gibbs default: 331ff662b5cSJustin T. Gibbs return (EINVAL); 332ff662b5cSJustin T. Gibbs } 333d711ee2cSIan Lepore return (SYSCTL_OUT_STR(req, value)); 334ff662b5cSJustin T. Gibbs } 335ff662b5cSJustin T. Gibbs 336ff662b5cSJustin T. Gibbs /** 337ff662b5cSJustin T. Gibbs * Create read-only systcl nodes for xenbusb device ivar data. 338ff662b5cSJustin T. Gibbs * 339ff662b5cSJustin T. Gibbs * \param dev The XenBus device instance to register with sysctl. 340ff662b5cSJustin T. Gibbs */ 341ff662b5cSJustin T. Gibbs static void 342ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_init(device_t dev) 343ff662b5cSJustin T. Gibbs { 344ff662b5cSJustin T. Gibbs struct sysctl_ctx_list *ctx; 345ff662b5cSJustin T. Gibbs struct sysctl_oid *tree; 346ff662b5cSJustin T. Gibbs 347ff662b5cSJustin T. Gibbs ctx = device_get_sysctl_ctx(dev); 348ff662b5cSJustin T. Gibbs tree = device_get_sysctl_tree(dev); 349ff662b5cSJustin T. Gibbs 350ff662b5cSJustin T. Gibbs SYSCTL_ADD_PROC(ctx, 351ff662b5cSJustin T. Gibbs SYSCTL_CHILDREN(tree), 352ff662b5cSJustin T. Gibbs OID_AUTO, 353ff662b5cSJustin T. Gibbs "xenstore_path", 354f4f04709SMatthew D Fleming CTLTYPE_STRING | CTLFLAG_RD, 355ff662b5cSJustin T. Gibbs dev, 356ff662b5cSJustin T. Gibbs XENBUS_IVAR_NODE, 357ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_handler, 358ff662b5cSJustin T. Gibbs "A", 359ff662b5cSJustin T. Gibbs "XenStore path to device"); 360ff662b5cSJustin T. Gibbs 361ff662b5cSJustin T. Gibbs SYSCTL_ADD_PROC(ctx, 362ff662b5cSJustin T. Gibbs SYSCTL_CHILDREN(tree), 363ff662b5cSJustin T. Gibbs OID_AUTO, 364ff662b5cSJustin T. Gibbs "xenbus_dev_type", 365f4f04709SMatthew D Fleming CTLTYPE_STRING | CTLFLAG_RD, 366ff662b5cSJustin T. Gibbs dev, 367ff662b5cSJustin T. Gibbs XENBUS_IVAR_TYPE, 368ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_handler, 369ff662b5cSJustin T. Gibbs "A", 370ff662b5cSJustin T. Gibbs "XenBus device type"); 371ff662b5cSJustin T. Gibbs 372ff662b5cSJustin T. Gibbs SYSCTL_ADD_PROC(ctx, 373ff662b5cSJustin T. Gibbs SYSCTL_CHILDREN(tree), 374ff662b5cSJustin T. Gibbs OID_AUTO, 375ff662b5cSJustin T. Gibbs "xenbus_connection_state", 376f4f04709SMatthew D Fleming CTLTYPE_STRING | CTLFLAG_RD, 377ff662b5cSJustin T. Gibbs dev, 378ff662b5cSJustin T. Gibbs XENBUS_IVAR_STATE, 379ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_handler, 380ff662b5cSJustin T. Gibbs "A", 381ff662b5cSJustin T. Gibbs "XenBus state of peer connection"); 382ff662b5cSJustin T. Gibbs 383ff662b5cSJustin T. Gibbs SYSCTL_ADD_PROC(ctx, 384ff662b5cSJustin T. Gibbs SYSCTL_CHILDREN(tree), 385ff662b5cSJustin T. Gibbs OID_AUTO, 386ff662b5cSJustin T. Gibbs "xenbus_peer_domid", 387f4f04709SMatthew D Fleming CTLTYPE_INT | CTLFLAG_RD, 388ff662b5cSJustin T. Gibbs dev, 389ff662b5cSJustin T. Gibbs XENBUS_IVAR_OTHEREND_ID, 390ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_handler, 391ff662b5cSJustin T. Gibbs "I", 392ff662b5cSJustin T. Gibbs "Xen domain ID of peer"); 393ff662b5cSJustin T. Gibbs 394ff662b5cSJustin T. Gibbs SYSCTL_ADD_PROC(ctx, 395ff662b5cSJustin T. Gibbs SYSCTL_CHILDREN(tree), 396ff662b5cSJustin T. Gibbs OID_AUTO, 397ff662b5cSJustin T. Gibbs "xenstore_peer_path", 398f4f04709SMatthew D Fleming CTLTYPE_STRING | CTLFLAG_RD, 399ff662b5cSJustin T. Gibbs dev, 400ff662b5cSJustin T. Gibbs XENBUS_IVAR_OTHEREND_PATH, 401ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_handler, 402ff662b5cSJustin T. Gibbs "A", 403ff662b5cSJustin T. Gibbs "XenStore path to peer device"); 404ff662b5cSJustin T. Gibbs } 405ff662b5cSJustin T. Gibbs 406ff662b5cSJustin T. Gibbs /** 407f2dc9238SJustin T. Gibbs * \brief Decrement the number of XenBus child devices in the 408f2dc9238SJustin T. Gibbs * connecting state by one and release the xbs_attch_ch 409f2dc9238SJustin T. Gibbs * interrupt configuration hook if the connecting count 410f2dc9238SJustin T. Gibbs * drops to zero. 411f2dc9238SJustin T. Gibbs * 412f2dc9238SJustin T. Gibbs * \param xbs XenBus Bus device softc of the owner of the bus to enumerate. 413f2dc9238SJustin T. Gibbs */ 414f2dc9238SJustin T. Gibbs static void 415f2dc9238SJustin T. Gibbs xenbusb_release_confighook(struct xenbusb_softc *xbs) 416f2dc9238SJustin T. Gibbs { 417f2dc9238SJustin T. Gibbs mtx_lock(&xbs->xbs_lock); 418f2dc9238SJustin T. Gibbs KASSERT(xbs->xbs_connecting_children > 0, 419f2dc9238SJustin T. Gibbs ("Connecting device count error\n")); 420f2dc9238SJustin T. Gibbs xbs->xbs_connecting_children--; 421f2dc9238SJustin T. Gibbs if (xbs->xbs_connecting_children == 0 422f2dc9238SJustin T. Gibbs && (xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) { 423f2dc9238SJustin T. Gibbs xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE; 424f2dc9238SJustin T. Gibbs mtx_unlock(&xbs->xbs_lock); 425f2dc9238SJustin T. Gibbs config_intrhook_disestablish(&xbs->xbs_attach_ch); 426f2dc9238SJustin T. Gibbs } else { 427f2dc9238SJustin T. Gibbs mtx_unlock(&xbs->xbs_lock); 428f2dc9238SJustin T. Gibbs } 429f2dc9238SJustin T. Gibbs } 430f2dc9238SJustin T. Gibbs 431f2dc9238SJustin T. Gibbs /** 432ff662b5cSJustin T. Gibbs * \brief Verify the existance of attached device instances and perform 433ff662b5cSJustin T. Gibbs * probe/attach processing for newly arrived devices. 434ff662b5cSJustin T. Gibbs * 435ff662b5cSJustin T. Gibbs * \param dev The NewBus device representing this XenBus bus. 436ff662b5cSJustin T. Gibbs * 437ff662b5cSJustin T. Gibbs * \return On success, 0. Otherwise an errno value indicating the 438ff662b5cSJustin T. Gibbs * type of failure. 439ff662b5cSJustin T. Gibbs */ 440ff662b5cSJustin T. Gibbs static int 441ff662b5cSJustin T. Gibbs xenbusb_probe_children(device_t dev) 442ff662b5cSJustin T. Gibbs { 443ff662b5cSJustin T. Gibbs device_t *kids; 444ff662b5cSJustin T. Gibbs struct xenbus_device_ivars *ivars; 445f2dc9238SJustin T. Gibbs int i, count, error; 446ff662b5cSJustin T. Gibbs 447ff662b5cSJustin T. Gibbs if (device_get_children(dev, &kids, &count) == 0) { 448ff662b5cSJustin T. Gibbs for (i = 0; i < count; i++) { 449ff662b5cSJustin T. Gibbs if (device_get_state(kids[i]) != DS_NOTPRESENT) { 450ff662b5cSJustin T. Gibbs /* 451ff662b5cSJustin T. Gibbs * We already know about this one. 452ff662b5cSJustin T. Gibbs * Make sure it's still here. 453ff662b5cSJustin T. Gibbs */ 454ff662b5cSJustin T. Gibbs xenbusb_verify_device(dev, kids[i]); 455ff662b5cSJustin T. Gibbs continue; 456ff662b5cSJustin T. Gibbs } 457ff662b5cSJustin T. Gibbs 458f2dc9238SJustin T. Gibbs error = device_probe_and_attach(kids[i]); 459f2dc9238SJustin T. Gibbs if (error == ENXIO) { 460f2dc9238SJustin T. Gibbs struct xenbusb_softc *xbs; 461f2dc9238SJustin T. Gibbs 462f2dc9238SJustin T. Gibbs /* 463f2dc9238SJustin T. Gibbs * We don't have a PV driver for this device. 464f2dc9238SJustin T. Gibbs * However, an emulated device we do support 465f2dc9238SJustin T. Gibbs * may share this backend. Hide the node from 466f2dc9238SJustin T. Gibbs * XenBus until the next rescan, but leave it's 467f2dc9238SJustin T. Gibbs * state unchanged so we don't inadvertently 468f2dc9238SJustin T. Gibbs * prevent attachment of any emulated device. 469f2dc9238SJustin T. Gibbs */ 470f2dc9238SJustin T. Gibbs xenbusb_delete_child(dev, kids[i]); 471f2dc9238SJustin T. Gibbs 472f2dc9238SJustin T. Gibbs /* 473f2dc9238SJustin T. Gibbs * Since the XenStore state of this device 474f2dc9238SJustin T. Gibbs * still indicates a pending attach, manually 475f2dc9238SJustin T. Gibbs * release it's hold on the boot process. 476f2dc9238SJustin T. Gibbs */ 477f2dc9238SJustin T. Gibbs xbs = device_get_softc(dev); 478f2dc9238SJustin T. Gibbs xenbusb_release_confighook(xbs); 479f2dc9238SJustin T. Gibbs 480f2dc9238SJustin T. Gibbs continue; 481f2dc9238SJustin T. Gibbs } else if (error) { 482ff662b5cSJustin T. Gibbs /* 483ff662b5cSJustin T. Gibbs * Transition device to the closed state 484ff662b5cSJustin T. Gibbs * so the world knows that attachment will 485ff662b5cSJustin T. Gibbs * not occur. 486ff662b5cSJustin T. Gibbs */ 487ff662b5cSJustin T. Gibbs xenbus_set_state(kids[i], XenbusStateClosed); 488ff662b5cSJustin T. Gibbs 489ff662b5cSJustin T. Gibbs /* 490ff662b5cSJustin T. Gibbs * Remove our record of this device. 491ff662b5cSJustin T. Gibbs * So long as it remains in the closed 492ff662b5cSJustin T. Gibbs * state in the XenStore, we will not find 493ff662b5cSJustin T. Gibbs * it again. The state will only change 494ff662b5cSJustin T. Gibbs * if the control domain actively reconfigures 495ff662b5cSJustin T. Gibbs * this device. 496ff662b5cSJustin T. Gibbs */ 497ff662b5cSJustin T. Gibbs xenbusb_delete_child(dev, kids[i]); 498ff662b5cSJustin T. Gibbs 499ff662b5cSJustin T. Gibbs continue; 500ff662b5cSJustin T. Gibbs } 501ff662b5cSJustin T. Gibbs /* 502ff662b5cSJustin T. Gibbs * Augment default newbus provided dynamic sysctl 503ff662b5cSJustin T. Gibbs * variables with the standard ivar contents of 504ff662b5cSJustin T. Gibbs * XenBus devices. 505ff662b5cSJustin T. Gibbs */ 506ff662b5cSJustin T. Gibbs xenbusb_device_sysctl_init(kids[i]); 507ff662b5cSJustin T. Gibbs 508ff662b5cSJustin T. Gibbs /* 509ff662b5cSJustin T. Gibbs * Now that we have a driver managing this device 510ff662b5cSJustin T. Gibbs * that can receive otherend state change events, 511ff662b5cSJustin T. Gibbs * hook up a watch for them. 512ff662b5cSJustin T. Gibbs */ 513ff662b5cSJustin T. Gibbs ivars = device_get_ivars(kids[i]); 514ff662b5cSJustin T. Gibbs xs_register_watch(&ivars->xd_otherend_watch); 515283d6f72SJustin T. Gibbs xs_register_watch(&ivars->xd_local_watch); 516ff662b5cSJustin T. Gibbs } 517ff662b5cSJustin T. Gibbs free(kids, M_TEMP); 518ff662b5cSJustin T. Gibbs } 519ff662b5cSJustin T. Gibbs 520ff662b5cSJustin T. Gibbs return (0); 521ff662b5cSJustin T. Gibbs } 522ff662b5cSJustin T. Gibbs 523ff662b5cSJustin T. Gibbs /** 524ff662b5cSJustin T. Gibbs * \brief Task callback function to perform XenBus probe operations 525ff662b5cSJustin T. Gibbs * from a known safe context. 526ff662b5cSJustin T. Gibbs * 527ff662b5cSJustin T. Gibbs * \param arg The NewBus device_t representing the bus instance to 528ff662b5cSJustin T. Gibbs * on which to perform probe processing. 529ff662b5cSJustin T. Gibbs * \param pending The number of times this task was queued before it could 530ff662b5cSJustin T. Gibbs * be run. 531ff662b5cSJustin T. Gibbs */ 532ff662b5cSJustin T. Gibbs static void 533ff662b5cSJustin T. Gibbs xenbusb_probe_children_cb(void *arg, int pending __unused) 534ff662b5cSJustin T. Gibbs { 535ff662b5cSJustin T. Gibbs device_t dev = (device_t)arg; 536ff662b5cSJustin T. Gibbs 537ff662b5cSJustin T. Gibbs /* 538ff662b5cSJustin T. Gibbs * Hold Giant until the Giant free newbus changes are committed. 539ff662b5cSJustin T. Gibbs */ 540ff662b5cSJustin T. Gibbs mtx_lock(&Giant); 541ff662b5cSJustin T. Gibbs xenbusb_probe_children(dev); 542ff662b5cSJustin T. Gibbs mtx_unlock(&Giant); 543ff662b5cSJustin T. Gibbs } 544ff662b5cSJustin T. Gibbs 545ff662b5cSJustin T. Gibbs /** 546ff662b5cSJustin T. Gibbs * \brief XenStore watch callback for the root node of the XenStore 547ff662b5cSJustin T. Gibbs * subtree representing a XenBus. 548ff662b5cSJustin T. Gibbs * 549ff662b5cSJustin T. Gibbs * This callback performs, or delegates to the xbs_probe_children task, 550ff662b5cSJustin T. Gibbs * all processing necessary to handle dynmaic device arrival and departure 551ff662b5cSJustin T. Gibbs * events from a XenBus. 552ff662b5cSJustin T. Gibbs * 553ff662b5cSJustin T. Gibbs * \param watch The XenStore watch object associated with this callback. 554ff662b5cSJustin T. Gibbs * \param vec The XenStore watch event data. 555ff662b5cSJustin T. Gibbs * \param len The number of fields in the event data stream. 556ff662b5cSJustin T. Gibbs */ 557ff662b5cSJustin T. Gibbs static void 558ff662b5cSJustin T. Gibbs xenbusb_devices_changed(struct xs_watch *watch, const char **vec, 559ff662b5cSJustin T. Gibbs unsigned int len) 560ff662b5cSJustin T. Gibbs { 561ff662b5cSJustin T. Gibbs struct xenbusb_softc *xbs; 562ff662b5cSJustin T. Gibbs device_t dev; 563ff662b5cSJustin T. Gibbs char *node; 564ff662b5cSJustin T. Gibbs char *type; 565ff662b5cSJustin T. Gibbs char *id; 566ff662b5cSJustin T. Gibbs char *p; 567ff662b5cSJustin T. Gibbs u_int component; 568ff662b5cSJustin T. Gibbs 569283d6f72SJustin T. Gibbs xbs = (struct xenbusb_softc *)watch->callback_data; 570ff662b5cSJustin T. Gibbs dev = xbs->xbs_dev; 571ff662b5cSJustin T. Gibbs 572ff662b5cSJustin T. Gibbs if (len <= XS_WATCH_PATH) { 573ff662b5cSJustin T. Gibbs device_printf(dev, "xenbusb_devices_changed: " 574ff662b5cSJustin T. Gibbs "Short Event Data.\n"); 575ff662b5cSJustin T. Gibbs return; 576ff662b5cSJustin T. Gibbs } 577ff662b5cSJustin T. Gibbs 578ff662b5cSJustin T. Gibbs node = strdup(vec[XS_WATCH_PATH], M_XENBUS); 579ff662b5cSJustin T. Gibbs p = strchr(node, '/'); 580ff662b5cSJustin T. Gibbs if (p == NULL) 581ff662b5cSJustin T. Gibbs goto out; 582ff662b5cSJustin T. Gibbs *p = 0; 583ff662b5cSJustin T. Gibbs type = p + 1; 584ff662b5cSJustin T. Gibbs 585ff662b5cSJustin T. Gibbs p = strchr(type, '/'); 586ff662b5cSJustin T. Gibbs if (p == NULL) 587ff662b5cSJustin T. Gibbs goto out; 588ff662b5cSJustin T. Gibbs *p++ = 0; 589ff662b5cSJustin T. Gibbs 590ff662b5cSJustin T. Gibbs /* 591ff662b5cSJustin T. Gibbs * Extract the device ID. A device ID has one or more path 592ff662b5cSJustin T. Gibbs * components separated by the '/' character. 593ff662b5cSJustin T. Gibbs * 594ff662b5cSJustin T. Gibbs * e.g. "<frontend vm id>/<frontend dev id>" for backend devices. 595ff662b5cSJustin T. Gibbs */ 596ff662b5cSJustin T. Gibbs id = p; 597ff662b5cSJustin T. Gibbs for (component = 0; component < xbs->xbs_id_components; component++) { 598ff662b5cSJustin T. Gibbs p = strchr(p, '/'); 599ff662b5cSJustin T. Gibbs if (p == NULL) 600ff662b5cSJustin T. Gibbs break; 601ff662b5cSJustin T. Gibbs p++; 602ff662b5cSJustin T. Gibbs } 603ff662b5cSJustin T. Gibbs if (p != NULL) 604ff662b5cSJustin T. Gibbs *p = 0; 605ff662b5cSJustin T. Gibbs 606ff662b5cSJustin T. Gibbs if (*id != 0 && component >= xbs->xbs_id_components - 1) { 607ff662b5cSJustin T. Gibbs xenbusb_add_device(xbs->xbs_dev, type, id); 608ff662b5cSJustin T. Gibbs taskqueue_enqueue(taskqueue_thread, &xbs->xbs_probe_children); 609ff662b5cSJustin T. Gibbs } 610ff662b5cSJustin T. Gibbs out: 611ff662b5cSJustin T. Gibbs free(node, M_XENBUS); 612ff662b5cSJustin T. Gibbs } 613ff662b5cSJustin T. Gibbs 614ff662b5cSJustin T. Gibbs /** 615ff662b5cSJustin T. Gibbs * \brief Interrupt configuration hook callback associated with xbs_attch_ch. 616ff662b5cSJustin T. Gibbs * 617ff662b5cSJustin T. Gibbs * Since interrupts are always functional at the time of XenBus configuration, 618ff662b5cSJustin T. Gibbs * there is nothing to be done when the callback occurs. This hook is only 619ff662b5cSJustin T. Gibbs * registered to hold up boot processing while XenBus devices come online. 620ff662b5cSJustin T. Gibbs * 621ff662b5cSJustin T. Gibbs * \param arg Unused configuration hook callback argument. 622ff662b5cSJustin T. Gibbs */ 623ff662b5cSJustin T. Gibbs static void 624ff662b5cSJustin T. Gibbs xenbusb_nop_confighook_cb(void *arg __unused) 625ff662b5cSJustin T. Gibbs { 626ff662b5cSJustin T. Gibbs } 627ff662b5cSJustin T. Gibbs 628ff662b5cSJustin T. Gibbs /*--------------------------- Public Functions -------------------------------*/ 629ff662b5cSJustin T. Gibbs /*--------- API comments for these methods can be found in xenbusb.h ---------*/ 630ff662b5cSJustin T. Gibbs void 631ff662b5cSJustin T. Gibbs xenbusb_identify(driver_t *driver __unused, device_t parent) 632ff662b5cSJustin T. Gibbs { 633ff662b5cSJustin T. Gibbs /* 634ff662b5cSJustin T. Gibbs * A single instance of each bus type for which we have a driver 635ff662b5cSJustin T. Gibbs * is always present in a system operating under Xen. 636ff662b5cSJustin T. Gibbs */ 637ff662b5cSJustin T. Gibbs BUS_ADD_CHILD(parent, 0, driver->name, 0); 638ff662b5cSJustin T. Gibbs } 639ff662b5cSJustin T. Gibbs 640ff662b5cSJustin T. Gibbs int 641ff662b5cSJustin T. Gibbs xenbusb_add_device(device_t dev, const char *type, const char *id) 642ff662b5cSJustin T. Gibbs { 643ff662b5cSJustin T. Gibbs struct xenbusb_softc *xbs; 644ff662b5cSJustin T. Gibbs struct sbuf *devpath_sbuf; 645ff662b5cSJustin T. Gibbs char *devpath; 646ff662b5cSJustin T. Gibbs struct xenbus_device_ivars *ivars; 647ff662b5cSJustin T. Gibbs int error; 648ff662b5cSJustin T. Gibbs 649ff662b5cSJustin T. Gibbs xbs = device_get_softc(dev); 650ff662b5cSJustin T. Gibbs devpath_sbuf = sbuf_new_auto(); 651ff662b5cSJustin T. Gibbs sbuf_printf(devpath_sbuf, "%s/%s/%s", xbs->xbs_node, type, id); 652ff662b5cSJustin T. Gibbs sbuf_finish(devpath_sbuf); 653ff662b5cSJustin T. Gibbs devpath = sbuf_data(devpath_sbuf); 654ff662b5cSJustin T. Gibbs 655ff662b5cSJustin T. Gibbs ivars = malloc(sizeof(*ivars), M_XENBUS, M_ZERO|M_WAITOK); 656ff662b5cSJustin T. Gibbs error = ENXIO; 657ff662b5cSJustin T. Gibbs 658ff662b5cSJustin T. Gibbs if (xs_exists(XST_NIL, devpath, "") != 0) { 659ff662b5cSJustin T. Gibbs device_t child; 660ff662b5cSJustin T. Gibbs enum xenbus_state state; 661ff662b5cSJustin T. Gibbs char *statepath; 662ff662b5cSJustin T. Gibbs 663ff662b5cSJustin T. Gibbs child = xenbusb_device_exists(dev, devpath); 664ff662b5cSJustin T. Gibbs if (child != NULL) { 665ff662b5cSJustin T. Gibbs /* 666ff662b5cSJustin T. Gibbs * We are already tracking this node 667ff662b5cSJustin T. Gibbs */ 668ff662b5cSJustin T. Gibbs error = 0; 669ff662b5cSJustin T. Gibbs goto out; 670ff662b5cSJustin T. Gibbs } 671ff662b5cSJustin T. Gibbs 672ff662b5cSJustin T. Gibbs state = xenbus_read_driver_state(devpath); 673ff662b5cSJustin T. Gibbs if (state != XenbusStateInitialising) { 674ff662b5cSJustin T. Gibbs /* 675ff662b5cSJustin T. Gibbs * Device is not new, so ignore it. This can 676ff662b5cSJustin T. Gibbs * happen if a device is going away after 677ff662b5cSJustin T. Gibbs * switching to Closed. 678ff662b5cSJustin T. Gibbs */ 679ff662b5cSJustin T. Gibbs printf("xenbusb_add_device: Device %s ignored. " 680ff662b5cSJustin T. Gibbs "State %d\n", devpath, state); 681ff662b5cSJustin T. Gibbs error = 0; 682ff662b5cSJustin T. Gibbs goto out; 683ff662b5cSJustin T. Gibbs } 684ff662b5cSJustin T. Gibbs 685ff662b5cSJustin T. Gibbs sx_init(&ivars->xd_lock, "xdlock"); 686ff662b5cSJustin T. Gibbs ivars->xd_flags = XDF_CONNECTING; 687ff662b5cSJustin T. Gibbs ivars->xd_node = strdup(devpath, M_XENBUS); 688283d6f72SJustin T. Gibbs ivars->xd_node_len = strlen(devpath); 689ff662b5cSJustin T. Gibbs ivars->xd_type = strdup(type, M_XENBUS); 690ff662b5cSJustin T. Gibbs ivars->xd_state = XenbusStateInitialising; 691ff662b5cSJustin T. Gibbs 692ff662b5cSJustin T. Gibbs error = XENBUSB_GET_OTHEREND_NODE(dev, ivars); 693ff662b5cSJustin T. Gibbs if (error) { 694ff662b5cSJustin T. Gibbs printf("xenbus_update_device: %s no otherend id\n", 695ff662b5cSJustin T. Gibbs devpath); 696ff662b5cSJustin T. Gibbs goto out; 697ff662b5cSJustin T. Gibbs } 698ff662b5cSJustin T. Gibbs 699283d6f72SJustin T. Gibbs statepath = malloc(ivars->xd_otherend_path_len 700ff662b5cSJustin T. Gibbs + strlen("/state") + 1, M_XENBUS, M_WAITOK); 701ff662b5cSJustin T. Gibbs sprintf(statepath, "%s/state", ivars->xd_otherend_path); 702ff662b5cSJustin T. Gibbs ivars->xd_otherend_watch.node = statepath; 703283d6f72SJustin T. Gibbs ivars->xd_otherend_watch.callback = xenbusb_otherend_watch_cb; 704283d6f72SJustin T. Gibbs ivars->xd_otherend_watch.callback_data = (uintptr_t)ivars; 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; 709ff662b5cSJustin T. Gibbs 710ff662b5cSJustin T. Gibbs mtx_lock(&xbs->xbs_lock); 711ff662b5cSJustin T. Gibbs xbs->xbs_connecting_children++; 712ff662b5cSJustin T. Gibbs mtx_unlock(&xbs->xbs_lock); 713ff662b5cSJustin T. Gibbs 714ff662b5cSJustin T. Gibbs child = device_add_child(dev, NULL, -1); 715ff662b5cSJustin T. Gibbs ivars->xd_dev = child; 716ff662b5cSJustin T. Gibbs device_set_ivars(child, ivars); 717ff662b5cSJustin T. Gibbs } 718ff662b5cSJustin T. Gibbs 719ff662b5cSJustin T. Gibbs out: 720ff662b5cSJustin T. Gibbs sbuf_delete(devpath_sbuf); 721ff662b5cSJustin T. Gibbs if (error != 0) 722ff662b5cSJustin T. Gibbs xenbusb_free_child_ivars(ivars); 723ff662b5cSJustin T. Gibbs 724ff662b5cSJustin T. Gibbs return (error); 725ff662b5cSJustin T. Gibbs } 726ff662b5cSJustin T. Gibbs 727ff662b5cSJustin T. Gibbs int 728ff662b5cSJustin T. Gibbs xenbusb_attach(device_t dev, char *bus_node, u_int id_components) 729ff662b5cSJustin T. Gibbs { 730ff662b5cSJustin T. Gibbs struct xenbusb_softc *xbs; 731ff662b5cSJustin T. Gibbs 732ff662b5cSJustin T. Gibbs xbs = device_get_softc(dev); 733ff662b5cSJustin T. Gibbs mtx_init(&xbs->xbs_lock, "xenbusb softc lock", NULL, MTX_DEF); 734ff662b5cSJustin T. Gibbs xbs->xbs_node = bus_node; 735ff662b5cSJustin T. Gibbs xbs->xbs_id_components = id_components; 736ff662b5cSJustin T. Gibbs xbs->xbs_dev = dev; 737ff662b5cSJustin T. Gibbs 738ff662b5cSJustin T. Gibbs /* 739*db4fcadfSConrad Meyer * Since XenBus buses are attached to the XenStore, and 740ff662b5cSJustin T. Gibbs * the XenStore does not probe children until after interrupt 741ff662b5cSJustin T. Gibbs * services are available, this config hook is used solely 742ff662b5cSJustin T. Gibbs * to ensure that the remainder of the boot process (e.g. 743ff662b5cSJustin T. Gibbs * mount root) is deferred until child devices are adequately 744ff662b5cSJustin T. Gibbs * probed. We unblock the boot process as soon as the 745ff662b5cSJustin T. Gibbs * connecting child count in our softc goes to 0. 746ff662b5cSJustin T. Gibbs */ 747ff662b5cSJustin T. Gibbs xbs->xbs_attach_ch.ich_func = xenbusb_nop_confighook_cb; 748ff662b5cSJustin T. Gibbs xbs->xbs_attach_ch.ich_arg = dev; 749ff662b5cSJustin T. Gibbs config_intrhook_establish(&xbs->xbs_attach_ch); 750ff662b5cSJustin T. Gibbs xbs->xbs_flags |= XBS_ATTACH_CH_ACTIVE; 751ff662b5cSJustin T. Gibbs xbs->xbs_connecting_children = 1; 752ff662b5cSJustin T. Gibbs 753ff662b5cSJustin T. Gibbs /* 754ff662b5cSJustin T. Gibbs * The subtree for this bus type may not yet exist 755ff662b5cSJustin T. Gibbs * causing initial enumeration to fail. We still 756ff662b5cSJustin T. Gibbs * want to return success from our attach though 757ff662b5cSJustin T. Gibbs * so that we are ready to handle devices for this 758ff662b5cSJustin T. Gibbs * bus when they are dynamically attached to us 759ff662b5cSJustin T. Gibbs * by a Xen management action. 760ff662b5cSJustin T. Gibbs */ 761ff662b5cSJustin T. Gibbs (void)xenbusb_enumerate_bus(xbs); 762ff662b5cSJustin T. Gibbs xenbusb_probe_children(dev); 763ff662b5cSJustin T. Gibbs 764ff662b5cSJustin T. Gibbs xbs->xbs_device_watch.node = bus_node; 765ff662b5cSJustin T. Gibbs xbs->xbs_device_watch.callback = xenbusb_devices_changed; 766283d6f72SJustin T. Gibbs xbs->xbs_device_watch.callback_data = (uintptr_t)xbs; 767ff662b5cSJustin T. Gibbs 768ff662b5cSJustin T. Gibbs TASK_INIT(&xbs->xbs_probe_children, 0, xenbusb_probe_children_cb, dev); 769ff662b5cSJustin T. Gibbs 770ff662b5cSJustin T. Gibbs xs_register_watch(&xbs->xbs_device_watch); 771ff662b5cSJustin T. Gibbs 772ff662b5cSJustin T. Gibbs xenbusb_release_confighook(xbs); 773ff662b5cSJustin T. Gibbs 774ff662b5cSJustin T. Gibbs return (0); 775ff662b5cSJustin T. Gibbs } 776ff662b5cSJustin T. Gibbs 777ff662b5cSJustin T. Gibbs int 778ff662b5cSJustin T. Gibbs xenbusb_resume(device_t dev) 779ff662b5cSJustin T. Gibbs { 780ff662b5cSJustin T. Gibbs device_t *kids; 781ff662b5cSJustin T. Gibbs struct xenbus_device_ivars *ivars; 782ff662b5cSJustin T. Gibbs int i, count, error; 783ff662b5cSJustin T. Gibbs char *statepath; 784ff662b5cSJustin T. Gibbs 785ff662b5cSJustin T. Gibbs /* 786ff662b5cSJustin T. Gibbs * We must re-examine each device and find the new path for 787ff662b5cSJustin T. Gibbs * its backend. 788ff662b5cSJustin T. Gibbs */ 789ff662b5cSJustin T. Gibbs if (device_get_children(dev, &kids, &count) == 0) { 790ff662b5cSJustin T. Gibbs for (i = 0; i < count; i++) { 791ff662b5cSJustin T. Gibbs if (device_get_state(kids[i]) == DS_NOTPRESENT) 792ff662b5cSJustin T. Gibbs continue; 793ff662b5cSJustin T. Gibbs 794ff662b5cSJustin T. Gibbs ivars = device_get_ivars(kids[i]); 795ff662b5cSJustin T. Gibbs 796ff662b5cSJustin T. Gibbs xs_unregister_watch(&ivars->xd_otherend_watch); 7972ca7463bSJustin T. Gibbs xenbus_set_state(kids[i], XenbusStateInitialising); 798ff662b5cSJustin T. Gibbs 799ff662b5cSJustin T. Gibbs /* 800ff662b5cSJustin T. Gibbs * Find the new backend details and 801ff662b5cSJustin T. Gibbs * re-register our watch. 802ff662b5cSJustin T. Gibbs */ 803ff662b5cSJustin T. Gibbs error = XENBUSB_GET_OTHEREND_NODE(dev, ivars); 804ff662b5cSJustin T. Gibbs if (error) 805ff662b5cSJustin T. Gibbs return (error); 806ff662b5cSJustin T. Gibbs 807283d6f72SJustin T. Gibbs statepath = malloc(ivars->xd_otherend_path_len 808ff662b5cSJustin T. Gibbs + strlen("/state") + 1, M_XENBUS, M_WAITOK); 809ff662b5cSJustin T. Gibbs sprintf(statepath, "%s/state", ivars->xd_otherend_path); 810ff662b5cSJustin T. Gibbs 811ff662b5cSJustin T. Gibbs free(ivars->xd_otherend_watch.node, M_XENBUS); 812ff662b5cSJustin T. Gibbs ivars->xd_otherend_watch.node = statepath; 813ff662b5cSJustin T. Gibbs 8142ca7463bSJustin T. Gibbs DEVICE_RESUME(kids[i]); 8152ca7463bSJustin T. Gibbs 8162ca7463bSJustin T. Gibbs xs_register_watch(&ivars->xd_otherend_watch); 817ff662b5cSJustin T. Gibbs #if 0 818ff662b5cSJustin T. Gibbs /* 819ff662b5cSJustin T. Gibbs * Can't do this yet since we are running in 820ff662b5cSJustin T. Gibbs * the xenwatch thread and if we sleep here, 821ff662b5cSJustin T. Gibbs * we will stop delivering watch notifications 822ff662b5cSJustin T. Gibbs * and the device will never come back online. 823ff662b5cSJustin T. Gibbs */ 824ff662b5cSJustin T. Gibbs sx_xlock(&ivars->xd_lock); 825ff662b5cSJustin T. Gibbs while (ivars->xd_state != XenbusStateClosed 826ff662b5cSJustin T. Gibbs && ivars->xd_state != XenbusStateConnected) 827ff662b5cSJustin T. Gibbs sx_sleep(&ivars->xd_state, &ivars->xd_lock, 828ff662b5cSJustin T. Gibbs 0, "xdresume", 0); 829ff662b5cSJustin T. Gibbs sx_xunlock(&ivars->xd_lock); 830ff662b5cSJustin T. Gibbs #endif 831ff662b5cSJustin T. Gibbs } 832ff662b5cSJustin T. Gibbs free(kids, M_TEMP); 833ff662b5cSJustin T. Gibbs } 834ff662b5cSJustin T. Gibbs 835ff662b5cSJustin T. Gibbs return (0); 836ff662b5cSJustin T. Gibbs } 837ff662b5cSJustin T. Gibbs 838ff662b5cSJustin T. Gibbs int 839ff662b5cSJustin T. Gibbs xenbusb_print_child(device_t dev, device_t child) 840ff662b5cSJustin T. Gibbs { 841ff662b5cSJustin T. Gibbs struct xenbus_device_ivars *ivars = device_get_ivars(child); 842ff662b5cSJustin T. Gibbs int retval = 0; 843ff662b5cSJustin T. Gibbs 844ff662b5cSJustin T. Gibbs retval += bus_print_child_header(dev, child); 845ff662b5cSJustin T. Gibbs retval += printf(" at %s", ivars->xd_node); 846ff662b5cSJustin T. Gibbs retval += bus_print_child_footer(dev, child); 847ff662b5cSJustin T. Gibbs 848ff662b5cSJustin T. Gibbs return (retval); 849ff662b5cSJustin T. Gibbs } 850ff662b5cSJustin T. Gibbs 851ff662b5cSJustin T. Gibbs int 852ff662b5cSJustin T. Gibbs xenbusb_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 853ff662b5cSJustin T. Gibbs { 854ff662b5cSJustin T. Gibbs struct xenbus_device_ivars *ivars = device_get_ivars(child); 855ff662b5cSJustin T. Gibbs 856ff662b5cSJustin T. Gibbs switch (index) { 857ff662b5cSJustin T. Gibbs case XENBUS_IVAR_NODE: 858ff662b5cSJustin T. Gibbs *result = (uintptr_t) ivars->xd_node; 859ff662b5cSJustin T. Gibbs return (0); 860ff662b5cSJustin T. Gibbs 861ff662b5cSJustin T. Gibbs case XENBUS_IVAR_TYPE: 862ff662b5cSJustin T. Gibbs *result = (uintptr_t) ivars->xd_type; 863ff662b5cSJustin T. Gibbs return (0); 864ff662b5cSJustin T. Gibbs 865ff662b5cSJustin T. Gibbs case XENBUS_IVAR_STATE: 866ff662b5cSJustin T. Gibbs *result = (uintptr_t) ivars->xd_state; 867ff662b5cSJustin T. Gibbs return (0); 868ff662b5cSJustin T. Gibbs 869ff662b5cSJustin T. Gibbs case XENBUS_IVAR_OTHEREND_ID: 870ff662b5cSJustin T. Gibbs *result = (uintptr_t) ivars->xd_otherend_id; 871ff662b5cSJustin T. Gibbs return (0); 872ff662b5cSJustin T. Gibbs 873ff662b5cSJustin T. Gibbs case XENBUS_IVAR_OTHEREND_PATH: 874ff662b5cSJustin T. Gibbs *result = (uintptr_t) ivars->xd_otherend_path; 875ff662b5cSJustin T. Gibbs return (0); 876ff662b5cSJustin T. Gibbs } 877ff662b5cSJustin T. Gibbs 878ff662b5cSJustin T. Gibbs return (ENOENT); 879ff662b5cSJustin T. Gibbs } 880ff662b5cSJustin T. Gibbs 881ff662b5cSJustin T. Gibbs int 882ff662b5cSJustin T. Gibbs xenbusb_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 883ff662b5cSJustin T. Gibbs { 884ff662b5cSJustin T. Gibbs struct xenbus_device_ivars *ivars = device_get_ivars(child); 885ff662b5cSJustin T. Gibbs enum xenbus_state newstate; 886ff662b5cSJustin T. Gibbs int currstate; 887ff662b5cSJustin T. Gibbs 888ff662b5cSJustin T. Gibbs switch (index) { 889ff662b5cSJustin T. Gibbs case XENBUS_IVAR_STATE: 890ff662b5cSJustin T. Gibbs { 891ff662b5cSJustin T. Gibbs int error; 892ff662b5cSJustin T. Gibbs 893ff662b5cSJustin T. Gibbs newstate = (enum xenbus_state)value; 894ff662b5cSJustin T. Gibbs sx_xlock(&ivars->xd_lock); 895ff662b5cSJustin T. Gibbs if (ivars->xd_state == newstate) { 896ff662b5cSJustin T. Gibbs error = 0; 897ff662b5cSJustin T. Gibbs goto out; 898ff662b5cSJustin T. Gibbs } 899ff662b5cSJustin T. Gibbs 900ff662b5cSJustin T. Gibbs error = xs_scanf(XST_NIL, ivars->xd_node, "state", 901ff662b5cSJustin T. Gibbs NULL, "%d", &currstate); 902ff662b5cSJustin T. Gibbs if (error) 903ff662b5cSJustin T. Gibbs goto out; 904ff662b5cSJustin T. Gibbs 905ff662b5cSJustin T. Gibbs do { 906ff662b5cSJustin T. Gibbs error = xs_printf(XST_NIL, ivars->xd_node, "state", 907ff662b5cSJustin T. Gibbs "%d", newstate); 908ff662b5cSJustin T. Gibbs } while (error == EAGAIN); 909ff662b5cSJustin T. Gibbs if (error) { 910ff662b5cSJustin T. Gibbs /* 911ff662b5cSJustin T. Gibbs * Avoid looping through xenbus_dev_fatal() 912ff662b5cSJustin T. Gibbs * which calls xenbus_write_ivar to set the 913ff662b5cSJustin T. Gibbs * state to closing. 914ff662b5cSJustin T. Gibbs */ 915ff662b5cSJustin T. Gibbs if (newstate != XenbusStateClosing) 916ff662b5cSJustin T. Gibbs xenbus_dev_fatal(dev, error, 917ff662b5cSJustin T. Gibbs "writing new state"); 918ff662b5cSJustin T. Gibbs goto out; 919ff662b5cSJustin T. Gibbs } 920ff662b5cSJustin T. Gibbs ivars->xd_state = newstate; 921ff662b5cSJustin T. Gibbs 922ff662b5cSJustin T. Gibbs if ((ivars->xd_flags & XDF_CONNECTING) != 0 923ff662b5cSJustin T. Gibbs && (newstate == XenbusStateClosed 924ff662b5cSJustin T. Gibbs || newstate == XenbusStateConnected)) { 925ff662b5cSJustin T. Gibbs struct xenbusb_softc *xbs; 926ff662b5cSJustin T. Gibbs 927ff662b5cSJustin T. Gibbs ivars->xd_flags &= ~XDF_CONNECTING; 928ff662b5cSJustin T. Gibbs xbs = device_get_softc(dev); 929ff662b5cSJustin T. Gibbs xenbusb_release_confighook(xbs); 930ff662b5cSJustin T. Gibbs } 931ff662b5cSJustin T. Gibbs 932ff662b5cSJustin T. Gibbs wakeup(&ivars->xd_state); 933ff662b5cSJustin T. Gibbs out: 934ff662b5cSJustin T. Gibbs sx_xunlock(&ivars->xd_lock); 935ff662b5cSJustin T. Gibbs return (error); 936ff662b5cSJustin T. Gibbs } 937ff662b5cSJustin T. Gibbs 938ff662b5cSJustin T. Gibbs case XENBUS_IVAR_NODE: 939ff662b5cSJustin T. Gibbs case XENBUS_IVAR_TYPE: 940ff662b5cSJustin T. Gibbs case XENBUS_IVAR_OTHEREND_ID: 941ff662b5cSJustin T. Gibbs case XENBUS_IVAR_OTHEREND_PATH: 942ff662b5cSJustin T. Gibbs /* 943ff662b5cSJustin T. Gibbs * These variables are read-only. 944ff662b5cSJustin T. Gibbs */ 945ff662b5cSJustin T. Gibbs return (EINVAL); 946ff662b5cSJustin T. Gibbs } 947ff662b5cSJustin T. Gibbs 948ff662b5cSJustin T. Gibbs return (ENOENT); 949ff662b5cSJustin T. Gibbs } 950283d6f72SJustin T. Gibbs 951283d6f72SJustin T. Gibbs void 952283d6f72SJustin T. Gibbs xenbusb_otherend_changed(device_t bus, device_t child, enum xenbus_state state) 953283d6f72SJustin T. Gibbs { 954283d6f72SJustin T. Gibbs XENBUS_OTHEREND_CHANGED(child, state); 955283d6f72SJustin T. Gibbs } 956283d6f72SJustin T. Gibbs 957283d6f72SJustin T. Gibbs void 958283d6f72SJustin T. Gibbs xenbusb_localend_changed(device_t bus, device_t child, const char *path) 959283d6f72SJustin T. Gibbs { 960283d6f72SJustin T. Gibbs 961283d6f72SJustin T. Gibbs if (strcmp(path, "/state") != 0) { 962283d6f72SJustin T. Gibbs struct xenbus_device_ivars *ivars; 963283d6f72SJustin T. Gibbs 964283d6f72SJustin T. Gibbs ivars = device_get_ivars(child); 965283d6f72SJustin T. Gibbs sx_xlock(&ivars->xd_lock); 966283d6f72SJustin T. Gibbs ivars->xd_state = xenbus_read_driver_state(ivars->xd_node); 967283d6f72SJustin T. Gibbs sx_xunlock(&ivars->xd_lock); 968283d6f72SJustin T. Gibbs } 969283d6f72SJustin T. Gibbs XENBUS_LOCALEND_CHANGED(child, path); 970283d6f72SJustin T. Gibbs } 971