The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/xen/xenbus/xenbusb.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /******************************************************************************
    2  * Copyright (C) 2010 Spectra Logic Corporation
    3  * Copyright (C) 2008 Doug Rabson
    4  * Copyright (C) 2005 Rusty Russell, IBM Corporation
    5  * Copyright (C) 2005 Mike Wray, Hewlett-Packard
    6  * Copyright (C) 2005 XenSource Ltd
    7  * 
    8  * This file may be distributed separately from the Linux kernel, or
    9  * incorporated into other software packages, subject to the following license:
   10  * 
   11  * Permission is hereby granted, free of charge, to any person obtaining a copy
   12  * of this source file (the "Software"), to deal in the Software without
   13  * restriction, including without limitation the rights to use, copy, modify,
   14  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   15  * and to permit persons to whom the Software is furnished to do so, subject to
   16  * the following conditions:
   17  * 
   18  * The above copyright notice and this permission notice shall be included in
   19  * all copies or substantial portions of the Software.
   20  * 
   21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   27  * IN THE SOFTWARE.
   28  */
   29 
   30 /**
   31  * \file xenbusb.c
   32  *
   33  * \brief Shared support functions for managing the NewBus busses that contain
   34  *        Xen front and back end device instances.
   35  *
   36  * The NewBus implementation of XenBus attaches a xenbusb_front and xenbusb_back
   37  * child bus to the xenstore device.  This strategy allows the small differences
   38  * in the handling of XenBus operations for front and back devices to be handled
   39  * as overrides in xenbusb_front/back.c.  Front and back specific device
   40  * classes are also provided so device drivers can register for the devices they
   41  * can handle without the need to filter within their probe routines.  The
   42  * net result is a device hierarchy that might look like this:
   43  *
   44  * xenstore0/
   45  *           xenbusb_front0/
   46  *                         xn0
   47  *                         xbd0
   48  *                         xbd1
   49  *           xenbusb_back0/
   50  *                        xbbd0
   51  *                        xnb0
   52  *                        xnb1
   53  */
   54 #include <sys/cdefs.h>
   55 __FBSDID("$FreeBSD: releng/8.2/sys/xen/xenbus/xenbusb.c 215788 2010-11-24 01:03:03Z gibbs $");
   56 
   57 #include <sys/param.h>
   58 #include <sys/bus.h>
   59 #include <sys/kernel.h>
   60 #include <sys/lock.h>
   61 #include <sys/malloc.h>
   62 #include <sys/module.h>
   63 #include <sys/sbuf.h>
   64 #include <sys/sysctl.h>
   65 #include <sys/syslog.h>
   66 #include <sys/systm.h>
   67 #include <sys/sx.h>
   68 #include <sys/taskqueue.h>
   69 
   70 #include <machine/xen/xen-os.h>
   71 #include <machine/stdarg.h>
   72 
   73 #include <xen/gnttab.h>
   74 #include <xen/xenstore/xenstorevar.h>
   75 #include <xen/xenbus/xenbusb.h>
   76 #include <xen/xenbus/xenbusvar.h>
   77 
   78 /*------------------------- Private Functions --------------------------------*/
   79 /**
   80  * \brief Deallocate XenBus device instance variables.
   81  *
   82  * \param ivars  The instance variable block to free.
   83  */
   84 static void
   85 xenbusb_free_child_ivars(struct xenbus_device_ivars *ivars)
   86 {
   87         if (ivars->xd_otherend_watch.node != NULL) {
   88                 xs_unregister_watch(&ivars->xd_otherend_watch);
   89                 free(ivars->xd_otherend_watch.node, M_XENBUS);
   90                 ivars->xd_otherend_watch.node = NULL;
   91         }
   92 
   93         if (ivars->xd_node != NULL) {
   94                 free(ivars->xd_node, M_XENBUS);
   95                 ivars->xd_node = NULL;
   96         }
   97 
   98         if (ivars->xd_type != NULL) {
   99                 free(ivars->xd_type, M_XENBUS);
  100                 ivars->xd_type = NULL;
  101         }
  102 
  103         if (ivars->xd_otherend_path != NULL) {
  104                 free(ivars->xd_otherend_path, M_XENBUS);
  105                 ivars->xd_otherend_path = NULL;
  106         }
  107 
  108         free(ivars, M_XENBUS);
  109 }
  110 
  111 /**
  112  * XenBus watch callback registered against the "state" XenStore
  113  * node of the other-end of a split device connection.
  114  *
  115  * This callback is invoked whenever the state of a device instance's
  116  * peer changes.
  117  *
  118  * \param watch      The xs_watch object used to register this callback
  119  *                   function.
  120  * \param vec        An array of pointers to NUL terminated strings containing
  121  *                   watch event data.  The vector should be indexed via the
  122  *                   xs_watch_type enum in xs_wire.h.
  123  * \param vec_size   The number of elements in vec.
  124  *
  125  * \return  The device_t of the found device if any, or NULL.
  126  *
  127  * \note device_t is a pointer type, so it can be compared against
  128  *       NULL for validity. 
  129  */
  130 static void
  131 xenbusb_otherend_changed(struct xs_watch *watch, const char **vec,
  132     unsigned int vec_size __unused)
  133 {
  134         struct xenbus_device_ivars *ivars;
  135         device_t dev;
  136         enum xenbus_state newstate;
  137 
  138         ivars = (struct xenbus_device_ivars *) watch;
  139         dev = ivars->xd_dev;
  140 
  141         if (!ivars->xd_otherend_path
  142          || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH],
  143                     strlen(ivars->xd_otherend_path)))
  144                 return;
  145 
  146         newstate = xenbus_read_driver_state(ivars->xd_otherend_path);
  147         XENBUS_OTHEREND_CHANGED(dev, newstate);
  148 }
  149 
  150 /**
  151  * Search our internal record of configured devices (not the XenStore)
  152  * to determine if the XenBus device indicated by \a node is known to
  153  * the system.
  154  *
  155  * \param dev   The XenBus bus instance to search for device children.
  156  * \param node  The XenStore node path for the device to find.
  157  *
  158  * \return  The device_t of the found device if any, or NULL.
  159  *
  160  * \note device_t is a pointer type, so it can be compared against
  161  *       NULL for validity. 
  162  */
  163 static device_t
  164 xenbusb_device_exists(device_t dev, const char *node)
  165 {
  166         device_t *kids;
  167         device_t result;
  168         struct xenbus_device_ivars *ivars;
  169         int i, count;
  170 
  171         if (device_get_children(dev, &kids, &count))
  172                 return (FALSE);
  173 
  174         result = NULL;
  175         for (i = 0; i < count; i++) {
  176                 ivars = device_get_ivars(kids[i]);
  177                 if (!strcmp(ivars->xd_node, node)) {
  178                         result = kids[i];
  179                         break;
  180                 }
  181         }
  182         free(kids, M_TEMP);
  183 
  184         return (result);
  185 }
  186 
  187 static void
  188 xenbusb_delete_child(device_t dev, device_t child)
  189 {
  190         struct xenbus_device_ivars *ivars;
  191 
  192         ivars = device_get_ivars(child);
  193 
  194         /*
  195          * We no longer care about the otherend of the
  196          * connection.  Cancel the watch now so that we
  197          * don't try to handle an event for a partially
  198          * detached child.
  199          */
  200         if (ivars->xd_otherend_watch.node != NULL)
  201                 xs_unregister_watch(&ivars->xd_otherend_watch);
  202         
  203         device_delete_child(dev, child);
  204         xenbusb_free_child_ivars(ivars);
  205 }
  206 
  207 /**
  208  * \param dev    The NewBus device representing this XenBus bus.
  209  * \param child  The NewBus device representing a child of dev%'s XenBus bus.
  210  */
  211 static void
  212 xenbusb_verify_device(device_t dev, device_t child)
  213 {
  214         if (xs_exists(XST_NIL, xenbus_get_node(child), "") == 0) {
  215 
  216                 /*
  217                  * Device tree has been removed from Xenbus.
  218                  * Tear down the device.
  219                  */
  220                 xenbusb_delete_child(dev, child);
  221         }
  222 }
  223 
  224 /**
  225  * \brief Enumerate the devices on a XenBus bus and register them with
  226  *        the NewBus device tree.
  227  *
  228  * xenbusb_enumerate_bus() will create entries (in state DS_NOTPRESENT)
  229  * for nodes that appear in the XenStore, but will not invoke probe/attach
  230  * operations on drivers.  Probe/Attach processing must be separately
  231  * performed via an invocation of xenbusb_probe_children().  This is usually
  232  * done via the xbs_probe_children task.
  233  *
  234  * \param xbs  XenBus Bus device softc of the owner of the bus to enumerate.
  235  *
  236  * \return  On success, 0. Otherwise an errno value indicating the
  237  *          type of failure.
  238  */
  239 static int
  240 xenbusb_enumerate_bus(struct xenbusb_softc *xbs)
  241 {
  242         const char **types;
  243         u_int type_idx;
  244         u_int type_count;
  245         int error;
  246 
  247         error = xs_directory(XST_NIL, xbs->xbs_node, "", &type_count, &types);
  248         if (error)
  249                 return (error);
  250 
  251         for (type_idx = 0; type_idx < type_count; type_idx++)
  252                 XENBUSB_ENUMERATE_TYPE(xbs->xbs_dev, types[type_idx]);
  253 
  254         free(types, M_XENSTORE);
  255 
  256         return (0);
  257 }
  258 
  259 /**
  260  * Handler for all generic XenBus device systcl nodes.
  261  */
  262 static int
  263 xenbusb_device_sysctl_handler(SYSCTL_HANDLER_ARGS)  
  264 {
  265         device_t dev;
  266         const char *value;
  267 
  268         dev = (device_t)arg1;
  269         switch (arg2) {
  270         case XENBUS_IVAR_NODE:
  271                 value = xenbus_get_node(dev);
  272                 break;
  273         case XENBUS_IVAR_TYPE:
  274                 value = xenbus_get_type(dev);
  275                 break;
  276         case XENBUS_IVAR_STATE:
  277                 value = xenbus_strstate(xenbus_get_state(dev));
  278                 break;
  279         case XENBUS_IVAR_OTHEREND_ID:
  280                 return (sysctl_handle_int(oidp, NULL,
  281                                           xenbus_get_otherend_id(dev),
  282                                           req));
  283                 /* NOTREACHED */
  284         case XENBUS_IVAR_OTHEREND_PATH:
  285                 value = xenbus_get_otherend_path(dev);
  286                 break;
  287         default:
  288                 return (EINVAL);
  289         }
  290         return (SYSCTL_OUT(req, value, strlen(value)));
  291 }
  292 
  293 /**
  294  * Create read-only systcl nodes for xenbusb device ivar data.
  295  *
  296  * \param dev  The XenBus device instance to register with sysctl.
  297  */
  298 static void
  299 xenbusb_device_sysctl_init(device_t dev)
  300 {
  301         struct sysctl_ctx_list *ctx;
  302         struct sysctl_oid      *tree;
  303 
  304         ctx  = device_get_sysctl_ctx(dev);
  305         tree = device_get_sysctl_tree(dev);
  306 
  307         SYSCTL_ADD_PROC(ctx,
  308                         SYSCTL_CHILDREN(tree),
  309                         OID_AUTO,
  310                         "xenstore_path",
  311                         CTLFLAG_RD,
  312                         dev,
  313                         XENBUS_IVAR_NODE,
  314                         xenbusb_device_sysctl_handler,
  315                         "A",
  316                         "XenStore path to device");
  317 
  318         SYSCTL_ADD_PROC(ctx,
  319                         SYSCTL_CHILDREN(tree),
  320                         OID_AUTO,
  321                         "xenbus_dev_type",
  322                         CTLFLAG_RD,
  323                         dev,
  324                         XENBUS_IVAR_TYPE,
  325                         xenbusb_device_sysctl_handler,
  326                         "A",
  327                         "XenBus device type");
  328 
  329         SYSCTL_ADD_PROC(ctx,
  330                         SYSCTL_CHILDREN(tree),
  331                         OID_AUTO,
  332                         "xenbus_connection_state",
  333                         CTLFLAG_RD,
  334                         dev,
  335                         XENBUS_IVAR_STATE,
  336                         xenbusb_device_sysctl_handler,
  337                         "A",
  338                         "XenBus state of peer connection");
  339 
  340         SYSCTL_ADD_PROC(ctx,
  341                         SYSCTL_CHILDREN(tree),
  342                         OID_AUTO,
  343                         "xenbus_peer_domid",
  344                         CTLFLAG_RD,
  345                         dev,
  346                         XENBUS_IVAR_OTHEREND_ID,
  347                         xenbusb_device_sysctl_handler,
  348                         "I",
  349                         "Xen domain ID of peer");
  350 
  351         SYSCTL_ADD_PROC(ctx,
  352                         SYSCTL_CHILDREN(tree),
  353                         OID_AUTO,
  354                         "xenstore_peer_path",
  355                         CTLFLAG_RD,
  356                         dev,
  357                         XENBUS_IVAR_OTHEREND_PATH,
  358                         xenbusb_device_sysctl_handler,
  359                         "A",
  360                         "XenStore path to peer device");
  361 }
  362 
  363 /**
  364  * \brief Verify the existance of attached device instances and perform
  365  *        probe/attach processing for newly arrived devices.
  366  *
  367  * \param dev  The NewBus device representing this XenBus bus.
  368  *
  369  * \return  On success, 0. Otherwise an errno value indicating the
  370  *          type of failure.
  371  */
  372 static int
  373 xenbusb_probe_children(device_t dev)
  374 {
  375         device_t *kids;
  376         struct xenbus_device_ivars *ivars;
  377         int i, count;
  378 
  379         if (device_get_children(dev, &kids, &count) == 0) {
  380                 for (i = 0; i < count; i++) {
  381                         if (device_get_state(kids[i]) != DS_NOTPRESENT) {
  382                                 /*
  383                                  * We already know about this one.
  384                                  * Make sure it's still here.
  385                                  */
  386                                 xenbusb_verify_device(dev, kids[i]);
  387                                 continue;
  388                         }
  389 
  390                         if (device_probe_and_attach(kids[i])) {
  391                                 /*
  392                                  * Transition device to the closed state
  393                                  * so the world knows that attachment will
  394                                  * not occur.
  395                                  */
  396                                 xenbus_set_state(kids[i], XenbusStateClosed);
  397 
  398                                 /*
  399                                  * Remove our record of this device.
  400                                  * So long as it remains in the closed
  401                                  * state in the XenStore, we will not find
  402                                  * it again.  The state will only change
  403                                  * if the control domain actively reconfigures
  404                                  * this device.
  405                                  */
  406                                 xenbusb_delete_child(dev, kids[i]);
  407 
  408                                 continue;
  409                         }
  410                         /*
  411                          * Augment default newbus provided dynamic sysctl
  412                          * variables with the standard ivar contents of
  413                          * XenBus devices.
  414                          */
  415                         xenbusb_device_sysctl_init(kids[i]);
  416 
  417                         /*
  418                          * Now that we have a driver managing this device
  419                          * that can receive otherend state change events,
  420                          * hook up a watch for them.
  421                          */
  422                         ivars = device_get_ivars(kids[i]);
  423                         xs_register_watch(&ivars->xd_otherend_watch);
  424                 }
  425                 free(kids, M_TEMP);
  426         }
  427 
  428         return (0);
  429 }
  430 
  431 /**
  432  * \brief Task callback function to perform XenBus probe operations
  433  *        from a known safe context.
  434  *
  435  * \param arg      The NewBus device_t representing the bus instance to
  436  *                 on which to perform probe processing.
  437  * \param pending  The number of times this task was queued before it could
  438  *                 be run.
  439  */
  440 static void
  441 xenbusb_probe_children_cb(void *arg, int pending __unused)
  442 {
  443         device_t dev = (device_t)arg;
  444 
  445         /*
  446          * Hold Giant until the Giant free newbus changes are committed.
  447          */
  448         mtx_lock(&Giant);
  449         xenbusb_probe_children(dev);
  450         mtx_unlock(&Giant);
  451 }
  452 
  453 /**
  454  * \brief XenStore watch callback for the root node of the XenStore
  455  *        subtree representing a XenBus.
  456  *
  457  * This callback performs, or delegates to the xbs_probe_children task,
  458  * all processing necessary to handle dynmaic device arrival and departure
  459  * events from a XenBus.
  460  *
  461  * \param watch  The XenStore watch object associated with this callback.
  462  * \param vec    The XenStore watch event data.
  463  * \param len    The number of fields in the event data stream.
  464  */
  465 static void
  466 xenbusb_devices_changed(struct xs_watch *watch, const char **vec,
  467                         unsigned int len)
  468 {
  469         struct xenbusb_softc *xbs;
  470         device_t dev;
  471         char *node;
  472         char *bus;
  473         char *type;
  474         char *id;
  475         char *p;
  476         u_int component;
  477 
  478         xbs = (struct xenbusb_softc *)watch;
  479         dev = xbs->xbs_dev;
  480 
  481         if (len <= XS_WATCH_PATH) {
  482                 device_printf(dev, "xenbusb_devices_changed: "
  483                               "Short Event Data.\n");
  484                 return;
  485         }
  486 
  487         node = strdup(vec[XS_WATCH_PATH], M_XENBUS);
  488         p = strchr(node, '/');
  489         if (p == NULL)
  490                 goto out;
  491         bus = node;
  492         *p = 0;
  493         type = p + 1;
  494 
  495         p = strchr(type, '/');
  496         if (p == NULL)
  497                 goto out;
  498         *p++ = 0;
  499 
  500         /*
  501          * Extract the device ID.  A device ID has one or more path
  502          * components separated by the '/' character.
  503          *
  504          * e.g. "<frontend vm id>/<frontend dev id>" for backend devices.
  505          */
  506         id = p;
  507         for (component = 0; component < xbs->xbs_id_components; component++) {
  508                 p = strchr(p, '/');
  509                 if (p == NULL)
  510                         break;
  511                 p++;
  512         }
  513         if (p != NULL)
  514                 *p = 0;
  515 
  516         if (*id != 0 && component >= xbs->xbs_id_components - 1) {
  517                 xenbusb_add_device(xbs->xbs_dev, type, id);
  518                 taskqueue_enqueue(taskqueue_thread, &xbs->xbs_probe_children);
  519         }
  520 out:
  521         free(node, M_XENBUS);
  522 }
  523 
  524 /**
  525  * \brief Interrupt configuration hook callback associated with xbs_attch_ch.
  526  *
  527  * Since interrupts are always functional at the time of XenBus configuration,
  528  * there is nothing to be done when the callback occurs.  This hook is only
  529  * registered to hold up boot processing while XenBus devices come online.
  530  * 
  531  * \param arg  Unused configuration hook callback argument.
  532  */
  533 static void
  534 xenbusb_nop_confighook_cb(void *arg __unused)
  535 {
  536 }
  537 
  538 /**
  539  * \brief Decrement the number of XenBus child devices in the
  540  *        connecting state by one and release the xbs_attch_ch
  541  *        interrupt configuration hook if the connecting count
  542  *        drops to zero.
  543  *
  544  * \param xbs  XenBus Bus device softc of the owner of the bus to enumerate.
  545  */
  546 static void
  547 xenbusb_release_confighook(struct xenbusb_softc *xbs)
  548 {
  549         mtx_lock(&xbs->xbs_lock);
  550         KASSERT(xbs->xbs_connecting_children > 0,
  551                 ("Connecting device count error\n"));
  552         xbs->xbs_connecting_children--;
  553         if (xbs->xbs_connecting_children == 0
  554          && (xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) {
  555                 xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE;
  556                 mtx_unlock(&xbs->xbs_lock);
  557                 config_intrhook_disestablish(&xbs->xbs_attach_ch);
  558         } else {
  559                 mtx_unlock(&xbs->xbs_lock);
  560         }
  561 }
  562 
  563 /*--------------------------- Public Functions -------------------------------*/
  564 /*--------- API comments for these methods can be found in xenbusb.h ---------*/
  565 void
  566 xenbusb_identify(driver_t *driver __unused, device_t parent)
  567 {
  568         /*
  569          * A single instance of each bus type for which we have a driver
  570          * is always present in a system operating under Xen.
  571          */
  572         BUS_ADD_CHILD(parent, 0, driver->name, 0);
  573 }
  574 
  575 int
  576 xenbusb_add_device(device_t dev, const char *type, const char *id)
  577 {
  578         struct xenbusb_softc *xbs;
  579         struct sbuf *devpath_sbuf;
  580         char *devpath;
  581         struct xenbus_device_ivars *ivars;
  582         int error;
  583 
  584         xbs = device_get_softc(dev);
  585         devpath_sbuf = sbuf_new_auto();
  586         sbuf_printf(devpath_sbuf, "%s/%s/%s", xbs->xbs_node, type, id);
  587         sbuf_finish(devpath_sbuf);
  588         devpath = sbuf_data(devpath_sbuf);
  589 
  590         ivars = malloc(sizeof(*ivars), M_XENBUS, M_ZERO|M_WAITOK);
  591         error = ENXIO;
  592 
  593         if (xs_exists(XST_NIL, devpath, "") != 0) {
  594                 device_t child;
  595                 enum xenbus_state state;
  596                 char *statepath;
  597 
  598                 child = xenbusb_device_exists(dev, devpath);
  599                 if (child != NULL) {
  600                         /*
  601                          * We are already tracking this node
  602                          */
  603                         error = 0;
  604                         goto out;
  605                 }
  606                         
  607                 state = xenbus_read_driver_state(devpath);
  608                 if (state != XenbusStateInitialising) {
  609                         /*
  610                          * Device is not new, so ignore it. This can
  611                          * happen if a device is going away after
  612                          * switching to Closed.
  613                          */
  614                         printf("xenbusb_add_device: Device %s ignored. "
  615                                "State %d\n", devpath, state);
  616                         error = 0;
  617                         goto out;
  618                 }
  619 
  620                 sx_init(&ivars->xd_lock, "xdlock");
  621                 ivars->xd_flags = XDF_CONNECTING;
  622                 ivars->xd_node = strdup(devpath, M_XENBUS);
  623                 ivars->xd_type  = strdup(type, M_XENBUS);
  624                 ivars->xd_state = XenbusStateInitialising;
  625 
  626                 error = XENBUSB_GET_OTHEREND_NODE(dev, ivars);
  627                 if (error) {
  628                         printf("xenbus_update_device: %s no otherend id\n",
  629                             devpath); 
  630                         goto out;
  631                 }
  632 
  633                 statepath = malloc(strlen(ivars->xd_otherend_path)
  634                     + strlen("/state") + 1, M_XENBUS, M_WAITOK);
  635                 sprintf(statepath, "%s/state", ivars->xd_otherend_path);
  636 
  637                 ivars->xd_otherend_watch.node = statepath;
  638                 ivars->xd_otherend_watch.callback = xenbusb_otherend_changed;
  639 
  640                 mtx_lock(&xbs->xbs_lock);
  641                 xbs->xbs_connecting_children++;
  642                 mtx_unlock(&xbs->xbs_lock);
  643 
  644                 child = device_add_child(dev, NULL, -1);
  645                 ivars->xd_dev = child;
  646                 device_set_ivars(child, ivars);
  647         }
  648 
  649 out:
  650         sbuf_delete(devpath_sbuf);
  651         if (error != 0)
  652                 xenbusb_free_child_ivars(ivars);
  653 
  654         return (error);
  655 }
  656 
  657 int
  658 xenbusb_attach(device_t dev, char *bus_node, u_int id_components)
  659 {
  660         struct xenbusb_softc *xbs;
  661 
  662         xbs = device_get_softc(dev);
  663         mtx_init(&xbs->xbs_lock, "xenbusb softc lock", NULL, MTX_DEF);
  664         xbs->xbs_node = bus_node;
  665         xbs->xbs_id_components = id_components;
  666         xbs->xbs_dev = dev;
  667 
  668         /*
  669          * Since XenBus busses are attached to the XenStore, and
  670          * the XenStore does not probe children until after interrupt
  671          * services are available, this config hook is used solely
  672          * to ensure that the remainder of the boot process (e.g.
  673          * mount root) is deferred until child devices are adequately
  674          * probed.  We unblock the boot process as soon as the
  675          * connecting child count in our softc goes to 0.
  676          */
  677         xbs->xbs_attach_ch.ich_func = xenbusb_nop_confighook_cb;
  678         xbs->xbs_attach_ch.ich_arg = dev;
  679         config_intrhook_establish(&xbs->xbs_attach_ch);
  680         xbs->xbs_flags |= XBS_ATTACH_CH_ACTIVE;
  681         xbs->xbs_connecting_children = 1;
  682 
  683         /*
  684          * The subtree for this bus type may not yet exist
  685          * causing initial enumeration to fail.  We still
  686          * want to return success from our attach though
  687          * so that we are ready to handle devices for this
  688          * bus when they are dynamically attached to us
  689          * by a Xen management action.
  690          */
  691         (void)xenbusb_enumerate_bus(xbs);
  692         xenbusb_probe_children(dev);
  693 
  694         xbs->xbs_device_watch.node = bus_node;
  695         xbs->xbs_device_watch.callback = xenbusb_devices_changed;
  696 
  697         TASK_INIT(&xbs->xbs_probe_children, 0, xenbusb_probe_children_cb, dev);
  698 
  699         xs_register_watch(&xbs->xbs_device_watch);
  700 
  701         xenbusb_release_confighook(xbs);
  702 
  703         return (0);
  704 }
  705 
  706 int
  707 xenbusb_resume(device_t dev)
  708 {
  709         device_t *kids;
  710         struct xenbus_device_ivars *ivars;
  711         int i, count, error;
  712         char *statepath;
  713 
  714         /*
  715          * We must re-examine each device and find the new path for
  716          * its backend.
  717          */
  718         if (device_get_children(dev, &kids, &count) == 0) {
  719                 for (i = 0; i < count; i++) {
  720                         if (device_get_state(kids[i]) == DS_NOTPRESENT)
  721                                 continue;
  722 
  723                         ivars = device_get_ivars(kids[i]);
  724 
  725                         xs_unregister_watch(&ivars->xd_otherend_watch);
  726                         ivars->xd_state = XenbusStateInitialising;
  727 
  728                         /*
  729                          * Find the new backend details and
  730                          * re-register our watch.
  731                          */
  732                         error = XENBUSB_GET_OTHEREND_NODE(dev, ivars);
  733                         if (error)
  734                                 return (error);
  735 
  736                         DEVICE_RESUME(kids[i]);
  737 
  738                         statepath = malloc(strlen(ivars->xd_otherend_path)
  739                             + strlen("/state") + 1, M_XENBUS, M_WAITOK);
  740                         sprintf(statepath, "%s/state", ivars->xd_otherend_path);
  741 
  742                         free(ivars->xd_otherend_watch.node, M_XENBUS);
  743                         ivars->xd_otherend_watch.node = statepath;
  744                         xs_register_watch(&ivars->xd_otherend_watch);
  745 
  746 #if 0
  747                         /*
  748                          * Can't do this yet since we are running in
  749                          * the xenwatch thread and if we sleep here,
  750                          * we will stop delivering watch notifications
  751                          * and the device will never come back online.
  752                          */
  753                         sx_xlock(&ivars->xd_lock);
  754                         while (ivars->xd_state != XenbusStateClosed
  755                             && ivars->xd_state != XenbusStateConnected)
  756                                 sx_sleep(&ivars->xd_state, &ivars->xd_lock,
  757                                     0, "xdresume", 0);
  758                         sx_xunlock(&ivars->xd_lock);
  759 #endif
  760                 }
  761                 free(kids, M_TEMP);
  762         }
  763 
  764         return (0);
  765 }
  766 
  767 int
  768 xenbusb_print_child(device_t dev, device_t child)
  769 {
  770         struct xenbus_device_ivars *ivars = device_get_ivars(child);
  771         int     retval = 0;
  772 
  773         retval += bus_print_child_header(dev, child);
  774         retval += printf(" at %s", ivars->xd_node);
  775         retval += bus_print_child_footer(dev, child);
  776 
  777         return (retval);
  778 }
  779 
  780 int
  781 xenbusb_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
  782 {
  783         struct xenbus_device_ivars *ivars = device_get_ivars(child);
  784 
  785         switch (index) {
  786         case XENBUS_IVAR_NODE:
  787                 *result = (uintptr_t) ivars->xd_node;
  788                 return (0);
  789 
  790         case XENBUS_IVAR_TYPE:
  791                 *result = (uintptr_t) ivars->xd_type;
  792                 return (0);
  793 
  794         case XENBUS_IVAR_STATE:
  795                 *result = (uintptr_t) ivars->xd_state;
  796                 return (0);
  797 
  798         case XENBUS_IVAR_OTHEREND_ID:
  799                 *result = (uintptr_t) ivars->xd_otherend_id;
  800                 return (0);
  801 
  802         case XENBUS_IVAR_OTHEREND_PATH:
  803                 *result = (uintptr_t) ivars->xd_otherend_path;
  804                 return (0);
  805         }
  806 
  807         return (ENOENT);
  808 }
  809 
  810 int
  811 xenbusb_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
  812 {
  813         struct xenbus_device_ivars *ivars = device_get_ivars(child);
  814         enum xenbus_state newstate;
  815         int currstate;
  816 
  817         switch (index) {
  818         case XENBUS_IVAR_STATE:
  819         {
  820                 int error;
  821 
  822                 newstate = (enum xenbus_state) value;
  823                 sx_xlock(&ivars->xd_lock);
  824                 if (ivars->xd_state == newstate) {
  825                         error = 0;
  826                         goto out;
  827                 }
  828 
  829                 error = xs_scanf(XST_NIL, ivars->xd_node, "state",
  830                     NULL, "%d", &currstate);
  831                 if (error)
  832                         goto out;
  833 
  834                 do {
  835                         error = xs_printf(XST_NIL, ivars->xd_node, "state",
  836                             "%d", newstate);
  837                 } while (error == EAGAIN);
  838                 if (error) {
  839                         /*
  840                          * Avoid looping through xenbus_dev_fatal()
  841                          * which calls xenbus_write_ivar to set the
  842                          * state to closing.
  843                          */
  844                         if (newstate != XenbusStateClosing)
  845                                 xenbus_dev_fatal(dev, error,
  846                                                  "writing new state");
  847                         goto out;
  848                 }
  849                 ivars->xd_state = newstate;
  850 
  851                 if ((ivars->xd_flags & XDF_CONNECTING) != 0
  852                  && (newstate == XenbusStateClosed
  853                   || newstate == XenbusStateConnected)) {
  854                         struct xenbusb_softc *xbs;
  855 
  856                         ivars->xd_flags &= ~XDF_CONNECTING;
  857                         xbs = device_get_softc(dev);
  858                         xenbusb_release_confighook(xbs);
  859                 }
  860 
  861                 wakeup(&ivars->xd_state);
  862         out:
  863                 sx_xunlock(&ivars->xd_lock);
  864                 return (error);
  865         }
  866 
  867         case XENBUS_IVAR_NODE:
  868         case XENBUS_IVAR_TYPE:
  869         case XENBUS_IVAR_OTHEREND_ID:
  870         case XENBUS_IVAR_OTHEREND_PATH:
  871                 /*
  872                  * These variables are read-only.
  873                  */
  874                 return (EINVAL);
  875         }
  876 
  877         return (ENOENT);
  878 }

Cache object: 328337dbc59398bd13788bb870c67be0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.