1*ff662b5cSJustin T. Gibbs /****************************************************************************** 2*ff662b5cSJustin T. Gibbs * Talks to Xen Store to figure out what devices we have. 3*ff662b5cSJustin T. Gibbs * 4*ff662b5cSJustin T. Gibbs * Copyright (C) 2009, 2010 Spectra Logic Corporation 5*ff662b5cSJustin T. Gibbs * Copyright (C) 2008 Doug Rabson 6*ff662b5cSJustin T. Gibbs * Copyright (C) 2005 Rusty Russell, IBM Corporation 7*ff662b5cSJustin T. Gibbs * Copyright (C) 2005 Mike Wray, Hewlett-Packard 8*ff662b5cSJustin T. Gibbs * Copyright (C) 2005 XenSource Ltd 9*ff662b5cSJustin T. Gibbs * 10*ff662b5cSJustin T. Gibbs * This file may be distributed separately from the Linux kernel, or 11*ff662b5cSJustin T. Gibbs * incorporated into other software packages, subject to the following license: 12*ff662b5cSJustin T. Gibbs * 13*ff662b5cSJustin T. Gibbs * Permission is hereby granted, free of charge, to any person obtaining a copy 14*ff662b5cSJustin T. Gibbs * of this source file (the "Software"), to deal in the Software without 15*ff662b5cSJustin T. Gibbs * restriction, including without limitation the rights to use, copy, modify, 16*ff662b5cSJustin T. Gibbs * merge, publish, distribute, sublicense, and/or sell copies of the Software, 17*ff662b5cSJustin T. Gibbs * and to permit persons to whom the Software is furnished to do so, subject to 18*ff662b5cSJustin T. Gibbs * the following conditions: 19*ff662b5cSJustin T. Gibbs * 20*ff662b5cSJustin T. Gibbs * The above copyright notice and this permission notice shall be included in 21*ff662b5cSJustin T. Gibbs * all copies or substantial portions of the Software. 22*ff662b5cSJustin T. Gibbs * 23*ff662b5cSJustin T. Gibbs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24*ff662b5cSJustin T. Gibbs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25*ff662b5cSJustin T. Gibbs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26*ff662b5cSJustin T. Gibbs * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27*ff662b5cSJustin T. Gibbs * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28*ff662b5cSJustin T. Gibbs * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 29*ff662b5cSJustin T. Gibbs * IN THE SOFTWARE. 30*ff662b5cSJustin T. Gibbs */ 31*ff662b5cSJustin T. Gibbs 32*ff662b5cSJustin T. Gibbs /** 33*ff662b5cSJustin T. Gibbs * \file xenbusb_back.c 34*ff662b5cSJustin T. Gibbs * 35*ff662b5cSJustin T. Gibbs * XenBus management of the NewBus bus containing the backend instances of 36*ff662b5cSJustin T. Gibbs * Xen split devices. 37*ff662b5cSJustin T. Gibbs */ 38*ff662b5cSJustin T. Gibbs #include <sys/cdefs.h> 39*ff662b5cSJustin T. Gibbs __FBSDID("$FreeBSD$"); 40*ff662b5cSJustin T. Gibbs 41*ff662b5cSJustin T. Gibbs #include <sys/param.h> 42*ff662b5cSJustin T. Gibbs #include <sys/bus.h> 43*ff662b5cSJustin T. Gibbs #include <sys/kernel.h> 44*ff662b5cSJustin T. Gibbs #include <sys/lock.h> 45*ff662b5cSJustin T. Gibbs #include <sys/malloc.h> 46*ff662b5cSJustin T. Gibbs #include <sys/module.h> 47*ff662b5cSJustin T. Gibbs #include <sys/sbuf.h> 48*ff662b5cSJustin T. Gibbs #include <sys/sysctl.h> 49*ff662b5cSJustin T. Gibbs #include <sys/syslog.h> 50*ff662b5cSJustin T. Gibbs #include <sys/systm.h> 51*ff662b5cSJustin T. Gibbs #include <sys/sx.h> 52*ff662b5cSJustin T. Gibbs #include <sys/taskqueue.h> 53*ff662b5cSJustin T. Gibbs 54*ff662b5cSJustin T. Gibbs #include <machine/xen/xen-os.h> 55*ff662b5cSJustin T. Gibbs #include <machine/stdarg.h> 56*ff662b5cSJustin T. Gibbs 57*ff662b5cSJustin T. Gibbs #include <xen/gnttab.h> 58*ff662b5cSJustin T. Gibbs #include <xen/xenbus/xenbusvar.h> 59*ff662b5cSJustin T. Gibbs #include <xen/xenbus/xenbusb.h> 60*ff662b5cSJustin T. Gibbs 61*ff662b5cSJustin T. Gibbs 62*ff662b5cSJustin T. Gibbs /*------------------ Private Device Attachment Functions --------------------*/ 63*ff662b5cSJustin T. Gibbs /** 64*ff662b5cSJustin T. Gibbs * \brief Probe for the existance of the XenBus back bus. 65*ff662b5cSJustin T. Gibbs * 66*ff662b5cSJustin T. Gibbs * \param dev NewBus device_t for this XenBus back bus instance. 67*ff662b5cSJustin T. Gibbs * 68*ff662b5cSJustin T. Gibbs * \return Always returns 0 indicating success. 69*ff662b5cSJustin T. Gibbs */ 70*ff662b5cSJustin T. Gibbs static int 71*ff662b5cSJustin T. Gibbs xenbusb_back_probe(device_t dev) 72*ff662b5cSJustin T. Gibbs { 73*ff662b5cSJustin T. Gibbs device_set_desc(dev, "Xen Backend Devices"); 74*ff662b5cSJustin T. Gibbs 75*ff662b5cSJustin T. Gibbs return (0); 76*ff662b5cSJustin T. Gibbs } 77*ff662b5cSJustin T. Gibbs 78*ff662b5cSJustin T. Gibbs /** 79*ff662b5cSJustin T. Gibbs * \brief Attach the XenBus back bus. 80*ff662b5cSJustin T. Gibbs * 81*ff662b5cSJustin T. Gibbs * \param dev NewBus device_t for this XenBus back bus instance. 82*ff662b5cSJustin T. Gibbs * 83*ff662b5cSJustin T. Gibbs * \return On success, 0. Otherwise an errno value indicating the 84*ff662b5cSJustin T. Gibbs * type of failure. 85*ff662b5cSJustin T. Gibbs */ 86*ff662b5cSJustin T. Gibbs static int 87*ff662b5cSJustin T. Gibbs xenbusb_back_attach(device_t dev) 88*ff662b5cSJustin T. Gibbs { 89*ff662b5cSJustin T. Gibbs struct xenbusb_softc *xbs; 90*ff662b5cSJustin T. Gibbs int error; 91*ff662b5cSJustin T. Gibbs 92*ff662b5cSJustin T. Gibbs xbs = device_get_softc(dev); 93*ff662b5cSJustin T. Gibbs error = xenbusb_attach(dev, "backend", /*id_components*/2); 94*ff662b5cSJustin T. Gibbs 95*ff662b5cSJustin T. Gibbs /* 96*ff662b5cSJustin T. Gibbs * Backend devices operate to serve other domains, 97*ff662b5cSJustin T. Gibbs * so there is no need to hold up boot processing 98*ff662b5cSJustin T. Gibbs * while connections to foreign domains are made. 99*ff662b5cSJustin T. Gibbs */ 100*ff662b5cSJustin T. Gibbs mtx_lock(&xbs->xbs_lock); 101*ff662b5cSJustin T. Gibbs if ((xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) { 102*ff662b5cSJustin T. Gibbs xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE; 103*ff662b5cSJustin T. Gibbs mtx_unlock(&xbs->xbs_lock); 104*ff662b5cSJustin T. Gibbs config_intrhook_disestablish(&xbs->xbs_attach_ch); 105*ff662b5cSJustin T. Gibbs } else { 106*ff662b5cSJustin T. Gibbs mtx_unlock(&xbs->xbs_lock); 107*ff662b5cSJustin T. Gibbs } 108*ff662b5cSJustin T. Gibbs 109*ff662b5cSJustin T. Gibbs return (error); 110*ff662b5cSJustin T. Gibbs } 111*ff662b5cSJustin T. Gibbs 112*ff662b5cSJustin T. Gibbs /** 113*ff662b5cSJustin T. Gibbs * \brief Enumerate all devices of the given type on this bus. 114*ff662b5cSJustin T. Gibbs * 115*ff662b5cSJustin T. Gibbs * \param dev NewBus device_t for this XenBus backend bus instance. 116*ff662b5cSJustin T. Gibbs * \param type String indicating the device sub-tree (e.g. "vfb", "vif") 117*ff662b5cSJustin T. Gibbs * to enumerate. 118*ff662b5cSJustin T. Gibbs * 119*ff662b5cSJustin T. Gibbs * \return On success, 0. Otherwise an errno value indicating the 120*ff662b5cSJustin T. Gibbs * type of failure. 121*ff662b5cSJustin T. Gibbs * 122*ff662b5cSJustin T. Gibbs * Devices that are found are entered into the NewBus hierarchy via 123*ff662b5cSJustin T. Gibbs * xenbusb_add_device(). xenbusb_add_device() ignores duplicate detects 124*ff662b5cSJustin T. Gibbs * and ignores duplicate devices, so it can be called unconditionally 125*ff662b5cSJustin T. Gibbs * for any device found in the XenStore. 126*ff662b5cSJustin T. Gibbs * 127*ff662b5cSJustin T. Gibbs * The backend XenStore hierarchy has the following format: 128*ff662b5cSJustin T. Gibbs * 129*ff662b5cSJustin T. Gibbs * backend/<device type>/<frontend vm id>/<device id> 130*ff662b5cSJustin T. Gibbs * 131*ff662b5cSJustin T. Gibbs */ 132*ff662b5cSJustin T. Gibbs static int 133*ff662b5cSJustin T. Gibbs xenbusb_back_enumerate_type(device_t dev, const char *type) 134*ff662b5cSJustin T. Gibbs { 135*ff662b5cSJustin T. Gibbs struct xenbusb_softc *xbs; 136*ff662b5cSJustin T. Gibbs const char **vms; 137*ff662b5cSJustin T. Gibbs u_int vm_idx; 138*ff662b5cSJustin T. Gibbs u_int vm_count; 139*ff662b5cSJustin T. Gibbs int error; 140*ff662b5cSJustin T. Gibbs 141*ff662b5cSJustin T. Gibbs xbs = device_get_softc(dev); 142*ff662b5cSJustin T. Gibbs error = xs_directory(XST_NIL, xbs->xbs_node, type, &vm_count, &vms); 143*ff662b5cSJustin T. Gibbs if (error) 144*ff662b5cSJustin T. Gibbs return (error); 145*ff662b5cSJustin T. Gibbs for (vm_idx = 0; vm_idx < vm_count; vm_idx++) { 146*ff662b5cSJustin T. Gibbs struct sbuf *vm_path; 147*ff662b5cSJustin T. Gibbs const char *vm; 148*ff662b5cSJustin T. Gibbs const char **devs; 149*ff662b5cSJustin T. Gibbs u_int dev_idx; 150*ff662b5cSJustin T. Gibbs u_int dev_count; 151*ff662b5cSJustin T. Gibbs 152*ff662b5cSJustin T. Gibbs vm = vms[vm_idx]; 153*ff662b5cSJustin T. Gibbs 154*ff662b5cSJustin T. Gibbs vm_path = xs_join(type, vm); 155*ff662b5cSJustin T. Gibbs error = xs_directory(XST_NIL, xbs->xbs_node, sbuf_data(vm_path), 156*ff662b5cSJustin T. Gibbs &dev_count, &devs); 157*ff662b5cSJustin T. Gibbs sbuf_delete(vm_path); 158*ff662b5cSJustin T. Gibbs if (error) 159*ff662b5cSJustin T. Gibbs break; 160*ff662b5cSJustin T. Gibbs 161*ff662b5cSJustin T. Gibbs for (dev_idx = 0; dev_idx < dev_count; dev_idx++) { 162*ff662b5cSJustin T. Gibbs const char *dev_num; 163*ff662b5cSJustin T. Gibbs struct sbuf *id; 164*ff662b5cSJustin T. Gibbs 165*ff662b5cSJustin T. Gibbs dev_num = devs[dev_idx]; 166*ff662b5cSJustin T. Gibbs id = xs_join(vm, dev_num); 167*ff662b5cSJustin T. Gibbs xenbusb_add_device(dev, type, sbuf_data(id)); 168*ff662b5cSJustin T. Gibbs sbuf_delete(id); 169*ff662b5cSJustin T. Gibbs } 170*ff662b5cSJustin T. Gibbs free(devs, M_XENSTORE); 171*ff662b5cSJustin T. Gibbs } 172*ff662b5cSJustin T. Gibbs 173*ff662b5cSJustin T. Gibbs free(vms, M_XENSTORE); 174*ff662b5cSJustin T. Gibbs 175*ff662b5cSJustin T. Gibbs return (0); 176*ff662b5cSJustin T. Gibbs } 177*ff662b5cSJustin T. Gibbs 178*ff662b5cSJustin T. Gibbs /** 179*ff662b5cSJustin T. Gibbs * \brief Determine and store the XenStore path for the other end of 180*ff662b5cSJustin T. Gibbs * a split device whose local end is represented by ivars. 181*ff662b5cSJustin T. Gibbs * 182*ff662b5cSJustin T. Gibbs * \param dev NewBus device_t for this XenBus backend bus instance. 183*ff662b5cSJustin T. Gibbs * \param ivars Instance variables from the XenBus child device for 184*ff662b5cSJustin T. Gibbs * which to perform this function. 185*ff662b5cSJustin T. Gibbs * 186*ff662b5cSJustin T. Gibbs * \return On success, 0. Otherwise an errno value indicating the 187*ff662b5cSJustin T. Gibbs * type of failure. 188*ff662b5cSJustin T. Gibbs * 189*ff662b5cSJustin T. Gibbs * If successful, the xd_otherend_path field of the child's instance 190*ff662b5cSJustin T. Gibbs * variables will be updated. 191*ff662b5cSJustin T. Gibbs * 192*ff662b5cSJustin T. Gibbs */ 193*ff662b5cSJustin T. Gibbs static int 194*ff662b5cSJustin T. Gibbs xenbusb_back_get_otherend_node(device_t dev, struct xenbus_device_ivars *ivars) 195*ff662b5cSJustin T. Gibbs { 196*ff662b5cSJustin T. Gibbs char *otherend_path; 197*ff662b5cSJustin T. Gibbs int error; 198*ff662b5cSJustin T. Gibbs 199*ff662b5cSJustin T. Gibbs if (ivars->xd_otherend_path != NULL) { 200*ff662b5cSJustin T. Gibbs free(ivars->xd_otherend_path, M_XENBUS); 201*ff662b5cSJustin T. Gibbs ivars->xd_otherend_path = NULL; 202*ff662b5cSJustin T. Gibbs } 203*ff662b5cSJustin T. Gibbs 204*ff662b5cSJustin T. Gibbs error = xs_gather(XST_NIL, ivars->xd_node, 205*ff662b5cSJustin T. Gibbs "frontend-id", "%i", &ivars->xd_otherend_id, 206*ff662b5cSJustin T. Gibbs "frontend", NULL, &otherend_path, 207*ff662b5cSJustin T. Gibbs NULL); 208*ff662b5cSJustin T. Gibbs 209*ff662b5cSJustin T. Gibbs if (error == 0) { 210*ff662b5cSJustin T. Gibbs ivars->xd_otherend_path = strdup(otherend_path, M_XENBUS); 211*ff662b5cSJustin T. Gibbs free(otherend_path, M_XENSTORE); 212*ff662b5cSJustin T. Gibbs } 213*ff662b5cSJustin T. Gibbs return (error); 214*ff662b5cSJustin T. Gibbs } 215*ff662b5cSJustin T. Gibbs 216*ff662b5cSJustin T. Gibbs /** 217*ff662b5cSJustin T. Gibbs * \brief Backend XenBus child instance variable write access method. 218*ff662b5cSJustin T. Gibbs * 219*ff662b5cSJustin T. Gibbs * \param dev The NewBus device representing this XenBus bus. 220*ff662b5cSJustin T. Gibbs * \param child The NewBus device representing a child of dev%'s XenBus bus. 221*ff662b5cSJustin T. Gibbs * \param index The index of the instance variable to access. 222*ff662b5cSJustin T. Gibbs * \param value The new value to set in the instance variable accessed. 223*ff662b5cSJustin T. Gibbs * 224*ff662b5cSJustin T. Gibbs * \return On success, 0. Otherwise an errno value indicating the 225*ff662b5cSJustin T. Gibbs * type of failure. 226*ff662b5cSJustin T. Gibbs * 227*ff662b5cSJustin T. Gibbs * Xenbus_back overrides this method so that it can trap state transitions 228*ff662b5cSJustin T. Gibbs * of local backend devices and clean up their XenStore entries as necessary 229*ff662b5cSJustin T. Gibbs * during device instance teardown. 230*ff662b5cSJustin T. Gibbs */ 231*ff662b5cSJustin T. Gibbs static int 232*ff662b5cSJustin T. Gibbs xenbusb_back_write_ivar(device_t dev, device_t child, int index, 233*ff662b5cSJustin T. Gibbs uintptr_t value) 234*ff662b5cSJustin T. Gibbs { 235*ff662b5cSJustin T. Gibbs int error; 236*ff662b5cSJustin T. Gibbs 237*ff662b5cSJustin T. Gibbs error = xenbusb_write_ivar(dev, child, index, value); 238*ff662b5cSJustin T. Gibbs 239*ff662b5cSJustin T. Gibbs if (index == XENBUS_IVAR_STATE 240*ff662b5cSJustin T. Gibbs && (enum xenbus_state)value == XenbusStateClosed 241*ff662b5cSJustin T. Gibbs && xenbus_dev_is_online(child) == 0) { 242*ff662b5cSJustin T. Gibbs 243*ff662b5cSJustin T. Gibbs /* 244*ff662b5cSJustin T. Gibbs * Cleanup the hotplug entry in the XenStore if 245*ff662b5cSJustin T. Gibbs * present. The control domain expects any userland 246*ff662b5cSJustin T. Gibbs * component associated with this device to destroy 247*ff662b5cSJustin T. Gibbs * this node in order to signify it is safe to 248*ff662b5cSJustin T. Gibbs * teardown the device. However, not all backends 249*ff662b5cSJustin T. Gibbs * rely on userland components, and those that 250*ff662b5cSJustin T. Gibbs * do should either use a communication channel 251*ff662b5cSJustin T. Gibbs * other than the XenStore, or ensure the hotplug 252*ff662b5cSJustin T. Gibbs * data is already cleaned up. 253*ff662b5cSJustin T. Gibbs * 254*ff662b5cSJustin T. Gibbs * This removal ensures that no matter what path 255*ff662b5cSJustin T. Gibbs * is taken to mark a back-end closed, the control 256*ff662b5cSJustin T. Gibbs * domain will understand that it is closed. 257*ff662b5cSJustin T. Gibbs */ 258*ff662b5cSJustin T. Gibbs xs_rm(XST_NIL, xenbus_get_node(child), "hotplug-status"); 259*ff662b5cSJustin T. Gibbs } 260*ff662b5cSJustin T. Gibbs 261*ff662b5cSJustin T. Gibbs return (error); 262*ff662b5cSJustin T. Gibbs } 263*ff662b5cSJustin T. Gibbs 264*ff662b5cSJustin T. Gibbs /*-------------------- Private Device Attachment Data -----------------------*/ 265*ff662b5cSJustin T. Gibbs static device_method_t xenbusb_back_methods[] = { 266*ff662b5cSJustin T. Gibbs /* Device interface */ 267*ff662b5cSJustin T. Gibbs DEVMETHOD(device_identify, xenbusb_identify), 268*ff662b5cSJustin T. Gibbs DEVMETHOD(device_probe, xenbusb_back_probe), 269*ff662b5cSJustin T. Gibbs DEVMETHOD(device_attach, xenbusb_back_attach), 270*ff662b5cSJustin T. Gibbs DEVMETHOD(device_detach, bus_generic_detach), 271*ff662b5cSJustin T. Gibbs DEVMETHOD(device_shutdown, bus_generic_shutdown), 272*ff662b5cSJustin T. Gibbs DEVMETHOD(device_suspend, bus_generic_suspend), 273*ff662b5cSJustin T. Gibbs DEVMETHOD(device_resume, bus_generic_resume), 274*ff662b5cSJustin T. Gibbs 275*ff662b5cSJustin T. Gibbs /* Bus Interface */ 276*ff662b5cSJustin T. Gibbs DEVMETHOD(bus_print_child, xenbusb_print_child), 277*ff662b5cSJustin T. Gibbs DEVMETHOD(bus_read_ivar, xenbusb_read_ivar), 278*ff662b5cSJustin T. Gibbs DEVMETHOD(bus_write_ivar, xenbusb_back_write_ivar), 279*ff662b5cSJustin T. Gibbs DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 280*ff662b5cSJustin T. Gibbs DEVMETHOD(bus_release_resource, bus_generic_release_resource), 281*ff662b5cSJustin T. Gibbs DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 282*ff662b5cSJustin T. Gibbs DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 283*ff662b5cSJustin T. Gibbs 284*ff662b5cSJustin T. Gibbs /* XenBus Bus Interface */ 285*ff662b5cSJustin T. Gibbs DEVMETHOD(xenbusb_enumerate_type, xenbusb_back_enumerate_type), 286*ff662b5cSJustin T. Gibbs DEVMETHOD(xenbusb_get_otherend_node, xenbusb_back_get_otherend_node), 287*ff662b5cSJustin T. Gibbs { 0, 0 } 288*ff662b5cSJustin T. Gibbs }; 289*ff662b5cSJustin T. Gibbs 290*ff662b5cSJustin T. Gibbs DEFINE_CLASS_0(xenbusb_back, xenbusb_back_driver, xenbusb_back_methods, 291*ff662b5cSJustin T. Gibbs sizeof(struct xenbusb_softc)); 292*ff662b5cSJustin T. Gibbs devclass_t xenbusb_back_devclass; 293*ff662b5cSJustin T. Gibbs 294*ff662b5cSJustin T. Gibbs DRIVER_MODULE(xenbusb_back, xenstore, xenbusb_back_driver, 295*ff662b5cSJustin T. Gibbs xenbusb_back_devclass, 0, 0); 296