144743Smarkm/****************************************************************************** 244743Smarkm * Talks to Xen Store to figure out what devices we have. 344743Smarkm * 444743Smarkm * Copyright (C) 2009, 2010 Spectra Logic Corporation 544743Smarkm * Copyright (C) 2008 Doug Rabson 644743Smarkm * Copyright (C) 2005 Rusty Russell, IBM Corporation 744743Smarkm * Copyright (C) 2005 Mike Wray, Hewlett-Packard 844743Smarkm * Copyright (C) 2005 XenSource Ltd 944743Smarkm * 1044743Smarkm * This file may be distributed separately from the Linux kernel, or 1144743Smarkm * incorporated into other software packages, subject to the following license: 1244743Smarkm * 1344743Smarkm * Permission is hereby granted, free of charge, to any person obtaining a copy 1444743Smarkm * of this source file (the "Software"), to deal in the Software without 1544743Smarkm * restriction, including without limitation the rights to use, copy, modify, 1644743Smarkm * merge, publish, distribute, sublicense, and/or sell copies of the Software, 1744743Smarkm * and to permit persons to whom the Software is furnished to do so, subject to 1844743Smarkm * the following conditions: 1944743Smarkm * 2044743Smarkm * The above copyright notice and this permission notice shall be included in 2144743Smarkm * all copies or substantial portions of the Software. 2244743Smarkm * 2344743Smarkm * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2444743Smarkm * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2544743Smarkm * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2644743Smarkm * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2744743Smarkm * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2844743Smarkm * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2944743Smarkm * IN THE SOFTWARE. 3044743Smarkm */ 3144743Smarkm 3244743Smarkm/** 3344743Smarkm * \file xenbusb_back.c 3444743Smarkm * 3544743Smarkm * XenBus management of the NewBus bus containing the backend instances of 3644743Smarkm * Xen split devices. 3744743Smarkm */ 3844743Smarkm#include <sys/cdefs.h> 3944743Smarkm__FBSDID("$FreeBSD$"); 4044743Smarkm 4144743Smarkm#include <sys/param.h> 4244743Smarkm#include <sys/bus.h> 4344743Smarkm#include <sys/kernel.h> 4444743Smarkm#include <sys/lock.h> 4544743Smarkm#include <sys/malloc.h> 4644743Smarkm#include <sys/module.h> 4744743Smarkm#include <sys/sbuf.h> 4844743Smarkm#include <sys/sysctl.h> 4944743Smarkm#include <sys/syslog.h> 5044743Smarkm#include <sys/systm.h> 5144743Smarkm#include <sys/sx.h> 5244743Smarkm#include <sys/taskqueue.h> 5344743Smarkm 5444743Smarkm#include <machine/xen/xen-os.h> 5544743Smarkm#include <machine/stdarg.h> 5644743Smarkm 5744743Smarkm#include <xen/gnttab.h> 5844743Smarkm#include <xen/xenbus/xenbusvar.h> 5944743Smarkm#include <xen/xenbus/xenbusb.h> 6044743Smarkm 6144743Smarkm 6244743Smarkm/*------------------ Private Device Attachment Functions --------------------*/ 6344743Smarkm/** 6444743Smarkm * \brief Probe for the existance of the XenBus back bus. 6544743Smarkm * 6644743Smarkm * \param dev NewBus device_t for this XenBus back bus instance. 6744743Smarkm * 6844743Smarkm * \return Always returns 0 indicating success. 6944743Smarkm */ 7044743Smarkmstatic int 7144743Smarkmxenbusb_back_probe(device_t dev) 7244743Smarkm{ 7344743Smarkm device_set_desc(dev, "Xen Backend Devices"); 7444743Smarkm 7544743Smarkm return (0); 7644743Smarkm} 7744743Smarkm 7844743Smarkm/** 7944743Smarkm * \brief Attach the XenBus back bus. 8044743Smarkm * 8144743Smarkm * \param dev NewBus device_t for this XenBus back bus instance. 8244743Smarkm * 8344743Smarkm * \return On success, 0. Otherwise an errno value indicating the 8444743Smarkm * type of failure. 8544743Smarkm */ 8644743Smarkmstatic int 8744743Smarkmxenbusb_back_attach(device_t dev) 8844743Smarkm{ 8944743Smarkm struct xenbusb_softc *xbs; 9044743Smarkm int error; 9144743Smarkm 9244743Smarkm xbs = device_get_softc(dev); 9344743Smarkm error = xenbusb_attach(dev, "backend", /*id_components*/2); 9444743Smarkm 9544743Smarkm /* 9644743Smarkm * Backend devices operate to serve other domains, 9744743Smarkm * so there is no need to hold up boot processing 9844743Smarkm * while connections to foreign domains are made. 9944743Smarkm */ 10044743Smarkm mtx_lock(&xbs->xbs_lock); 10144743Smarkm if ((xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) { 10244743Smarkm xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE; 10344743Smarkm mtx_unlock(&xbs->xbs_lock); 10444743Smarkm config_intrhook_disestablish(&xbs->xbs_attach_ch); 10544743Smarkm } else { 10644743Smarkm mtx_unlock(&xbs->xbs_lock); 10744743Smarkm } 10844743Smarkm 10944743Smarkm return (error); 11044743Smarkm} 11144743Smarkm 11244743Smarkm/** 11344743Smarkm * \brief Enumerate all devices of the given type on this bus. 11444743Smarkm * 11544743Smarkm * \param dev NewBus device_t for this XenBus backend bus instance. 11644743Smarkm * \param type String indicating the device sub-tree (e.g. "vfb", "vif") 11744743Smarkm * to enumerate. 11844743Smarkm * 11944743Smarkm * \return On success, 0. Otherwise an errno value indicating the 12044743Smarkm * type of failure. 12144743Smarkm * 12244743Smarkm * Devices that are found are entered into the NewBus hierarchy via 12344743Smarkm * xenbusb_add_device(). xenbusb_add_device() ignores duplicate detects 12444743Smarkm * and ignores duplicate devices, so it can be called unconditionally 12544743Smarkm * for any device found in the XenStore. 12644743Smarkm * 12744743Smarkm * The backend XenStore hierarchy has the following format: 12844743Smarkm * 12944743Smarkm * backend/<device type>/<frontend vm id>/<device id> 13044743Smarkm * 13144743Smarkm */ 13244743Smarkmstatic int 13344743Smarkmxenbusb_back_enumerate_type(device_t dev, const char *type) 13444743Smarkm{ 13544743Smarkm struct xenbusb_softc *xbs; 13644743Smarkm const char **vms; 13744743Smarkm u_int vm_idx; 13844743Smarkm u_int vm_count; 13944743Smarkm int error; 14044743Smarkm 14144743Smarkm xbs = device_get_softc(dev); 14244743Smarkm error = xs_directory(XST_NIL, xbs->xbs_node, type, &vm_count, &vms); 14344743Smarkm if (error) 14444743Smarkm return (error); 14544743Smarkm for (vm_idx = 0; vm_idx < vm_count; vm_idx++) { 14644743Smarkm struct sbuf *vm_path; 14744743Smarkm const char *vm; 14844743Smarkm const char **devs; 14944743Smarkm u_int dev_idx; 15044743Smarkm u_int dev_count; 15144743Smarkm 15244743Smarkm vm = vms[vm_idx]; 15344743Smarkm 15444743Smarkm vm_path = xs_join(type, vm); 15544743Smarkm error = xs_directory(XST_NIL, xbs->xbs_node, sbuf_data(vm_path), 15644743Smarkm &dev_count, &devs); 15744743Smarkm sbuf_delete(vm_path); 15844743Smarkm if (error) 15944743Smarkm break; 16044743Smarkm 16144743Smarkm for (dev_idx = 0; dev_idx < dev_count; dev_idx++) { 16244743Smarkm const char *dev_num; 16344743Smarkm struct sbuf *id; 16444743Smarkm 16544743Smarkm dev_num = devs[dev_idx]; 16644743Smarkm id = xs_join(vm, dev_num); 16744743Smarkm xenbusb_add_device(dev, type, sbuf_data(id)); 16844743Smarkm sbuf_delete(id); 16944743Smarkm } 17044743Smarkm free(devs, M_XENSTORE); 17144743Smarkm } 17244743Smarkm 17344743Smarkm free(vms, M_XENSTORE); 17444743Smarkm 17544743Smarkm return (0); 17644743Smarkm} 17744743Smarkm 17844743Smarkm/** 17944743Smarkm * \brief Determine and store the XenStore path for the other end of 18044743Smarkm * a split device whose local end is represented by ivars. 18144743Smarkm * 18244743Smarkm * \param dev NewBus device_t for this XenBus backend bus instance. 18344743Smarkm * \param ivars Instance variables from the XenBus child device for 18444743Smarkm * which to perform this function. 18544743Smarkm * 18644743Smarkm * \return On success, 0. Otherwise an errno value indicating the 18744743Smarkm * type of failure. 18844743Smarkm * 18944743Smarkm * If successful, the xd_otherend_path field of the child's instance 19044743Smarkm * variables will be updated. 19144743Smarkm * 19244743Smarkm */ 19344743Smarkmstatic int 19444743Smarkmxenbusb_back_get_otherend_node(device_t dev, struct xenbus_device_ivars *ivars) 19544743Smarkm{ 19644743Smarkm char *otherend_path; 19744743Smarkm int error; 19844743Smarkm 19944743Smarkm if (ivars->xd_otherend_path != NULL) { 20044743Smarkm free(ivars->xd_otherend_path, M_XENBUS); 20144743Smarkm ivars->xd_otherend_path = NULL; 20244743Smarkm } 20344743Smarkm 20444743Smarkm error = xs_gather(XST_NIL, ivars->xd_node, 20544743Smarkm "frontend-id", "%i", &ivars->xd_otherend_id, 20644743Smarkm "frontend", NULL, &otherend_path, 20744743Smarkm NULL); 20844743Smarkm 20944743Smarkm if (error == 0) { 21044743Smarkm ivars->xd_otherend_path = strdup(otherend_path, M_XENBUS); 21144743Smarkm ivars->xd_otherend_path_len = strlen(otherend_path); 21244743Smarkm free(otherend_path, M_XENSTORE); 21344743Smarkm } 21444743Smarkm return (error); 21544743Smarkm} 21644743Smarkm 21744743Smarkm/** 21844743Smarkm * \brief Backend XenBus method implementing responses to peer state changes. 21944743Smarkm * 22044743Smarkm * \param bus The XenBus bus parent of child. 22144743Smarkm * \param child The XenBus child whose peer stat has changed. 22244743Smarkm * \param state The current state of the peer. 22344743Smarkm */ 22444743Smarkmstatic void 22544743Smarkmxenbusb_back_otherend_changed(device_t bus, device_t child, 22644743Smarkm enum xenbus_state peer_state) 22744743Smarkm{ 22844743Smarkm /* Perform default processing of state. */ 22944743Smarkm xenbusb_otherend_changed(bus, child, peer_state); 23044743Smarkm 23144743Smarkm /* 23244743Smarkm * "Online" devices are never fully detached in the 23344743Smarkm * newbus sense. Only the front<->back connection is 23444743Smarkm * torn down. If the front returns to the initialising 23544743Smarkm * state after closing a previous connection, signal 23644743Smarkm * our willingness to reconnect and that all necessary 23744743Smarkm * XenStore data for feature negotiation is present. 23844743Smarkm */ 23944743Smarkm if (peer_state == XenbusStateInitialising 24044743Smarkm && xenbus_dev_is_online(child) != 0 24144743Smarkm && xenbus_get_state(child) == XenbusStateClosed) 24244743Smarkm xenbus_set_state(child, XenbusStateInitWait); 24344743Smarkm} 24444743Smarkm 24544743Smarkm/** 24644743Smarkm * \brief Backend XenBus method implementing responses to local 24744743Smarkm * XenStore changes. 24844743Smarkm * 24944743Smarkm * \param bus The XenBus bus parent of child. 25044743Smarkm * \param child The XenBus child whose peer stat has changed. 25144743Smarkm * \param_path The tree relative sub-path to the modified node. The empty 25244743Smarkm * string indicates the root of the tree was destroyed. 25344743Smarkm */ 25444743Smarkmstatic void 25544743Smarkmxenbusb_back_localend_changed(device_t bus, device_t child, const char *path) 25644743Smarkm{ 25744743Smarkm 25844743Smarkm xenbusb_localend_changed(bus, child, path); 25944743Smarkm 26044743Smarkm if (strcmp(path, "/state") != 0 26144743Smarkm && strcmp(path, "/online") != 0) 26244743Smarkm return; 26344743Smarkm 26444743Smarkm if (xenbus_get_state(child) != XenbusStateClosed 26544743Smarkm || xenbus_dev_is_online(child) != 0) 26644743Smarkm return; 26744743Smarkm 26844743Smarkm /* 26944743Smarkm * Cleanup the hotplug entry in the XenStore if 27044743Smarkm * present. The control domain expects any userland 27144743Smarkm * component associated with this device to destroy 27244743Smarkm * this node in order to signify it is safe to 27344743Smarkm * teardown the device. However, not all backends 27444743Smarkm * rely on userland components, and those that 27544743Smarkm * do should either use a communication channel 27644743Smarkm * other than the XenStore, or ensure the hotplug 27744743Smarkm * data is already cleaned up. 27844743Smarkm * 27944743Smarkm * This removal ensures that no matter what path 28044743Smarkm * is taken to mark a back-end closed, the control 28144743Smarkm * domain will understand that it is closed. 28244743Smarkm */ 28344743Smarkm xs_rm(XST_NIL, xenbus_get_node(child), "hotplug-status"); 28444743Smarkm} 28544743Smarkm 28644743Smarkm/*-------------------- Private Device Attachment Data -----------------------*/ 28744743Smarkmstatic device_method_t xenbusb_back_methods[] = { 28844743Smarkm /* Device interface */ 28944743Smarkm DEVMETHOD(device_identify, xenbusb_identify), 29044743Smarkm DEVMETHOD(device_probe, xenbusb_back_probe), 29144743Smarkm DEVMETHOD(device_attach, xenbusb_back_attach), 29244743Smarkm DEVMETHOD(device_detach, bus_generic_detach), 29344743Smarkm DEVMETHOD(device_shutdown, bus_generic_shutdown), 29444743Smarkm DEVMETHOD(device_suspend, bus_generic_suspend), 29544743Smarkm DEVMETHOD(device_resume, xenbusb_resume), 29644743Smarkm 29744743Smarkm /* Bus Interface */ 29844743Smarkm DEVMETHOD(bus_print_child, xenbusb_print_child), 29944743Smarkm DEVMETHOD(bus_read_ivar, xenbusb_read_ivar), 30044743Smarkm DEVMETHOD(bus_write_ivar, xenbusb_write_ivar), 30144743Smarkm DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 30244743Smarkm DEVMETHOD(bus_release_resource, bus_generic_release_resource), 30344743Smarkm DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 30444743Smarkm DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 30544743Smarkm 30644743Smarkm /* XenBus Bus Interface */ 30744743Smarkm DEVMETHOD(xenbusb_enumerate_type, xenbusb_back_enumerate_type), 30844743Smarkm DEVMETHOD(xenbusb_get_otherend_node, xenbusb_back_get_otherend_node), 30944743Smarkm DEVMETHOD(xenbusb_otherend_changed, xenbusb_back_otherend_changed), 31044743Smarkm DEVMETHOD(xenbusb_localend_changed, xenbusb_back_localend_changed), 31144743Smarkm { 0, 0 } 31244743Smarkm}; 31344743Smarkm 31444743SmarkmDEFINE_CLASS_0(xenbusb_back, xenbusb_back_driver, xenbusb_back_methods, 31544743Smarkm sizeof(struct xenbusb_softc)); 31644743Smarkmdevclass_t xenbusb_back_devclass; 31744743Smarkm 31844743SmarkmDRIVER_MODULE(xenbusb_back, xenstore, xenbusb_back_driver, 31944743Smarkm xenbusb_back_devclass, 0, 0); 32044743Smarkm