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