iPXE
xenbus.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdio.h>
00027 #include <errno.h>
00028 #include <ipxe/malloc.h>
00029 #include <ipxe/device.h>
00030 #include <ipxe/timer.h>
00031 #include <ipxe/nap.h>
00032 #include <ipxe/xen.h>
00033 #include <ipxe/xenstore.h>
00034 #include <ipxe/xenbus.h>
00035 
00036 /** @file
00037  *
00038  * Xen device bus
00039  *
00040  */
00041 
00042 /* Disambiguate the various error causes */
00043 #define ETIMEDOUT_UNKNOWN                                               \
00044         __einfo_error ( EINFO_ETIMEDOUT_UNKNOWN )
00045 #define EINFO_ETIMEDOUT_UNKNOWN                                         \
00046         __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateUnknown,          \
00047                           "Unknown" )
00048 #define ETIMEDOUT_INITIALISING                                          \
00049         __einfo_error ( EINFO_ETIMEDOUT_INITIALISING )
00050 #define EINFO_ETIMEDOUT_INITIALISING                                    \
00051         __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateInitialising,     \
00052                           "Initialising" )
00053 #define ETIMEDOUT_INITWAIT                                              \
00054         __einfo_error ( EINFO_ETIMEDOUT_INITWAIT )
00055 #define EINFO_ETIMEDOUT_INITWAIT                                        \
00056         __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateInitWait,         \
00057                           "InitWait" )
00058 #define ETIMEDOUT_INITIALISED                                           \
00059         __einfo_error ( EINFO_ETIMEDOUT_INITIALISED )
00060 #define EINFO_ETIMEDOUT_INITIALISED                                     \
00061         __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateInitialised,      \
00062                           "Initialised" )
00063 #define ETIMEDOUT_CONNECTED                                             \
00064         __einfo_error ( EINFO_ETIMEDOUT_CONNECTED )
00065 #define EINFO_ETIMEDOUT_CONNECTED                                       \
00066         __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateConnected,        \
00067                           "Connected" )
00068 #define ETIMEDOUT_CLOSING                                               \
00069         __einfo_error ( EINFO_ETIMEDOUT_CLOSING )
00070 #define EINFO_ETIMEDOUT_CLOSING                                         \
00071         __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateClosing,          \
00072                           "Closing" )
00073 #define ETIMEDOUT_CLOSED                                                \
00074         __einfo_error ( EINFO_ETIMEDOUT_CLOSED )
00075 #define EINFO_ETIMEDOUT_CLOSED                                          \
00076         __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateClosed,           \
00077                           "Closed" )
00078 #define ETIMEDOUT_RECONFIGURING                                         \
00079         __einfo_error ( EINFO_ETIMEDOUT_RECONFIGURING )
00080 #define EINFO_ETIMEDOUT_RECONFIGURING                                   \
00081         __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateReconfiguring,    \
00082                           "Reconfiguring" )
00083 #define ETIMEDOUT_RECONFIGURED                                          \
00084         __einfo_error ( EINFO_ETIMEDOUT_RECONFIGURED )
00085 #define EINFO_ETIMEDOUT_RECONFIGURED                                    \
00086         __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateReconfigured,     \
00087                           "Reconfigured" )
00088 #define ETIMEDOUT_STATE( state )                                        \
00089         EUNIQ ( EINFO_ETIMEDOUT, (state), ETIMEDOUT_UNKNOWN,            \
00090                 ETIMEDOUT_INITIALISING, ETIMEDOUT_INITWAIT,             \
00091                 ETIMEDOUT_INITIALISED, ETIMEDOUT_CONNECTED,             \
00092                 ETIMEDOUT_CLOSING, ETIMEDOUT_CLOSED,                    \
00093                 ETIMEDOUT_RECONFIGURING, ETIMEDOUT_RECONFIGURED )
00094 
00095 /** Maximum time to wait for backend to reach a given state, in ticks */
00096 #define XENBUS_BACKEND_TIMEOUT ( 5 * TICKS_PER_SEC )
00097 
00098 /**
00099  * Set device state
00100  *
00101  * @v xendev            Xen device
00102  * @v state             New state
00103  * @ret rc              Return status code
00104  */
00105 int xenbus_set_state ( struct xen_device *xendev, int state ) {
00106         int rc;
00107 
00108         /* Attempt to set state */
00109         if ( ( rc = xenstore_write_num ( xendev->xen, state, xendev->key,
00110                                          "state", NULL ) ) != 0 ) {
00111                 DBGC ( xendev, "XENBUS %s could not set state=\"%d\": %s\n",
00112                        xendev->key, state, strerror ( rc ) );
00113                 return rc;
00114         }
00115 
00116         return 0;
00117 }
00118 
00119 /**
00120  * Get backend state
00121  *
00122  * @v xendev            Xen device
00123  * @ret state           Backend state, or negative error
00124  */
00125 int xenbus_backend_state ( struct xen_device *xendev ) {
00126         unsigned long state;
00127         int rc;
00128 
00129         /* Attempt to get backend state */
00130         if ( ( rc = xenstore_read_num ( xendev->xen, &state, xendev->backend,
00131                                         "state", NULL ) ) != 0 ) {
00132                 DBGC ( xendev, "XENBUS %s could not read %s/state: %s\n",
00133                        xendev->key, xendev->backend, strerror ( rc ) );
00134                 return rc;
00135         }
00136 
00137         return state;
00138 }
00139 
00140 /**
00141  * Wait for backend to reach a given state
00142  *
00143  * @v xendev            Xen device
00144  * @v state             Desired backend state
00145  * @ret rc              Return status code
00146  */
00147 int xenbus_backend_wait ( struct xen_device *xendev, int state ) {
00148         unsigned long started = currticks();
00149         unsigned long elapsed;
00150         unsigned int attempts = 0;
00151         int current_state;
00152         int rc;
00153 
00154         /* Wait for backend to reach this state */
00155         do {
00156 
00157                 /* Get current backend state */
00158                 current_state = xenbus_backend_state ( xendev );
00159                 if ( current_state < 0 ) {
00160                         rc = current_state;
00161                         return rc;
00162                 }
00163                 if ( current_state == state )
00164                         return 0;
00165 
00166                 /* Allow time for backend to react */
00167                 cpu_nap();
00168 
00169                 /* XenStore is a very slow interface; any fixed delay
00170                  * time would be dwarfed by the XenStore access time.
00171                  * We therefore use wall clock to time out this
00172                  * operation.
00173                  */
00174                 elapsed = ( currticks() - started );
00175                 attempts++;
00176 
00177         } while ( elapsed < XENBUS_BACKEND_TIMEOUT );
00178 
00179         /* Construct status code from current backend state */
00180         rc = -ETIMEDOUT_STATE ( current_state );
00181         DBGC ( xendev, "XENBUS %s timed out after %d attempts waiting for "
00182                "%s/state=\"%d\": %s\n", xendev->key, attempts, xendev->backend,
00183                state, strerror ( rc ) );
00184 
00185         return rc;
00186 }
00187 
00188 /**
00189  * Find driver for Xen device
00190  *
00191  * @v type              Device type
00192  * @ret driver          Driver, or NULL
00193  */
00194 static struct xen_driver * xenbus_find_driver ( const char *type ) {
00195         struct xen_driver *xendrv;
00196 
00197         for_each_table_entry ( xendrv, XEN_DRIVERS ) {
00198                 if ( strcmp ( xendrv->type, type ) == 0 )
00199                         return xendrv;
00200         }
00201         return NULL;
00202 }
00203 
00204 /**
00205  * Probe Xen device
00206  *
00207  * @v xen               Xen hypervisor
00208  * @v parent            Parent device
00209  * @v instance          Device instance
00210  * @v driver            Device driver
00211  * @ret rc              Return status code
00212  */
00213 static int xenbus_probe_device ( struct xen_hypervisor *xen,
00214                                  struct device *parent, const char *instance,
00215                                  struct xen_driver *driver ) {
00216         const char *type = driver->type;
00217         struct xen_device *xendev;
00218         size_t key_len;
00219         int rc;
00220 
00221         /* Allocate and initialise structure */
00222         key_len = ( 7 /* "device/" */ + strlen ( type ) + 1 /* "/" */ +
00223                     strlen ( instance ) + 1 /* NUL */ );
00224         xendev = zalloc ( sizeof ( *xendev ) + key_len );
00225         if ( ! xendev ) {
00226                 rc = -ENOMEM;
00227                 goto err_alloc;
00228         }
00229         snprintf ( xendev->dev.name, sizeof ( xendev->dev.name ), "%s/%s",
00230                    type, instance );
00231         xendev->dev.desc.bus_type = BUS_TYPE_XEN;
00232         INIT_LIST_HEAD ( &xendev->dev.children );
00233         list_add_tail ( &xendev->dev.siblings, &parent->children );
00234         xendev->dev.parent = parent;
00235         xendev->xen = xen;
00236         xendev->key = ( ( void * ) ( xendev + 1 ) );
00237         snprintf ( xendev->key, key_len, "device/%s/%s", type, instance );
00238         xendev->driver = driver;
00239         xendev->dev.driver_name = driver->name;
00240         DBGC ( xendev, "XENBUS %s has driver \"%s\"\n", xendev->key,
00241                xendev->driver->name );
00242 
00243         /* Read backend key */
00244         if ( ( rc = xenstore_read ( xen, &xendev->backend, xendev->key,
00245                                     "backend", NULL ) ) != 0 ) {
00246                 DBGC ( xendev, "XENBUS %s could not read backend: %s\n",
00247                        xendev->key, strerror ( rc ) );
00248                 goto err_read_backend;
00249         }
00250 
00251         /* Read backend domain ID */
00252         if ( ( rc = xenstore_read_num ( xen, &xendev->backend_id, xendev->key,
00253                                         "backend-id", NULL ) ) != 0 ) {
00254                 DBGC ( xendev, "XENBUS %s could not read backend-id: %s\n",
00255                        xendev->key, strerror ( rc ) );
00256                 goto err_read_backend_id;
00257         }
00258         DBGC ( xendev, "XENBUS %s backend=\"%s\" in domain %ld\n",
00259                xendev->key, xendev->backend, xendev->backend_id );
00260 
00261         /* Probe driver */
00262         if ( ( rc = xendev->driver->probe ( xendev ) ) != 0 ) {
00263                 DBGC ( xendev, "XENBUS could not probe %s: %s\n",
00264                        xendev->key, strerror ( rc ) );
00265                 goto err_probe;
00266         }
00267 
00268         return 0;
00269 
00270         xendev->driver->remove ( xendev );
00271  err_probe:
00272  err_read_backend_id:
00273         free ( xendev->backend );
00274  err_read_backend:
00275         list_del ( &xendev->dev.siblings );
00276         free ( xendev );
00277  err_alloc:
00278         return rc;
00279 }
00280 
00281 /**
00282  * Remove Xen device
00283  *
00284  * @v xendev            Xen device
00285  */
00286 static void xenbus_remove_device ( struct xen_device *xendev ) {
00287 
00288         /* Remove device */
00289         xendev->driver->remove ( xendev );
00290         free ( xendev->backend );
00291         list_del ( &xendev->dev.siblings );
00292         free ( xendev );
00293 }
00294 
00295 /**
00296  * Probe Xen devices of a given type
00297  *
00298  * @v xen               Xen hypervisor
00299  * @v parent            Parent device
00300  * @v type              Device type
00301  * @ret rc              Return status code
00302  */
00303 static int xenbus_probe_type ( struct xen_hypervisor *xen,
00304                                struct device *parent, const char *type ) {
00305         struct xen_driver *driver;
00306         char *children;
00307         char *child;
00308         size_t len;
00309         int rc;
00310 
00311         /* Look for a driver */
00312         driver = xenbus_find_driver ( type );
00313         if ( ! driver ) {
00314                 DBGC ( xen, "XENBUS has no driver for \"%s\" devices\n", type );
00315                 /* Not a fatal error */
00316                 rc = 0;
00317                 goto err_no_driver;
00318         }
00319 
00320         /* Get children of this key */
00321         if ( ( rc = xenstore_directory ( xen, &children, &len, "device",
00322                                          type, NULL ) ) != 0 ) {
00323                 DBGC ( xen, "XENBUS could not list \"%s\" devices: %s\n",
00324                        type, strerror ( rc ) );
00325                 goto err_directory;
00326         }
00327 
00328         /* Probe each child */
00329         for ( child = children ; child < ( children + len ) ;
00330               child += ( strlen ( child ) + 1 /* NUL */ ) ) {
00331                 if ( ( rc = xenbus_probe_device ( xen, parent, child,
00332                                                   driver ) ) != 0 )
00333                         goto err_probe_device;
00334         }
00335 
00336         free ( children );
00337         return 0;
00338 
00339  err_probe_device:
00340         free ( children );
00341  err_directory:
00342  err_no_driver:
00343         return rc;
00344 }
00345 
00346 /**
00347  * Probe Xen bus
00348  *
00349  * @v xen               Xen hypervisor
00350  * @v parent            Parent device
00351  * @ret rc              Return status code
00352  */
00353 int xenbus_probe ( struct xen_hypervisor *xen, struct device *parent ) {
00354         char *types;
00355         char *type;
00356         size_t len;
00357         int rc;
00358 
00359         /* Get children of "device" key */
00360         if ( ( rc = xenstore_directory ( xen, &types, &len, "device",
00361                                          NULL ) ) != 0 ) {
00362                 DBGC ( xen, "XENBUS could not list device types: %s\n",
00363                        strerror ( rc ) );
00364                 goto err_directory;
00365         }
00366 
00367         /* Probe each child type */
00368         for ( type = types ; type < ( types + len ) ;
00369               type += ( strlen ( type ) + 1 /* NUL */ ) ) {
00370                 if ( ( rc = xenbus_probe_type ( xen, parent, type ) ) != 0 )
00371                         goto err_probe_type;
00372         }
00373 
00374         free ( types );
00375         return 0;
00376 
00377         xenbus_remove ( xen, parent );
00378  err_probe_type:
00379         free ( types );
00380  err_directory:
00381         return rc;
00382 }
00383 
00384 /**
00385  * Remove Xen bus
00386  *
00387  * @v xen               Xen hypervisor
00388  * @v parent            Parent device
00389  */
00390 void xenbus_remove ( struct xen_hypervisor *xen __unused,
00391                      struct device *parent ) {
00392         struct xen_device *xendev;
00393         struct xen_device *tmp;
00394 
00395         /* Remove devices */
00396         list_for_each_entry_safe ( xendev, tmp, &parent->children,
00397                                    dev.siblings ) {
00398                 xenbus_remove_device ( xendev );
00399         }
00400 }