Home | History | Annotate | Line # | Download | only in xenbus
xenbus_client.c revision 1.4.2.2
      1  1.4.2.2  tron /* $NetBSD: xenbus_client.c,v 1.4.2.2 2006/04/07 12:51:26 tron Exp $ */
      2  1.4.2.2  tron /******************************************************************************
      3  1.4.2.2  tron  * Client-facing interface for the Xenbus driver.  In other words, the
      4  1.4.2.2  tron  * interface between the Xenbus and the device-specific code, be it the
      5  1.4.2.2  tron  * frontend or the backend of that driver.
      6  1.4.2.2  tron  *
      7  1.4.2.2  tron  * Copyright (C) 2005 XenSource Ltd
      8  1.4.2.2  tron  *
      9  1.4.2.2  tron  * This file may be distributed separately from the Linux kernel, or
     10  1.4.2.2  tron  * incorporated into other software packages, subject to the following license:
     11  1.4.2.2  tron  *
     12  1.4.2.2  tron  * Permission is hereby granted, free of charge, to any person obtaining a copy
     13  1.4.2.2  tron  * of this source file (the "Software"), to deal in the Software without
     14  1.4.2.2  tron  * restriction, including without limitation the rights to use, copy, modify,
     15  1.4.2.2  tron  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
     16  1.4.2.2  tron  * and to permit persons to whom the Software is furnished to do so, subject to
     17  1.4.2.2  tron  * the following conditions:
     18  1.4.2.2  tron  *
     19  1.4.2.2  tron  * The above copyright notice and this permission notice shall be included in
     20  1.4.2.2  tron  * all copies or substantial portions of the Software.
     21  1.4.2.2  tron  *
     22  1.4.2.2  tron  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     23  1.4.2.2  tron  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     24  1.4.2.2  tron  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     25  1.4.2.2  tron  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     26  1.4.2.2  tron  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     27  1.4.2.2  tron  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     28  1.4.2.2  tron  * IN THE SOFTWARE.
     29  1.4.2.2  tron  */
     30  1.4.2.2  tron 
     31  1.4.2.2  tron #include <sys/cdefs.h>
     32  1.4.2.2  tron __KERNEL_RCSID(0, "$NetBSD: xenbus_client.c,v 1.4.2.2 2006/04/07 12:51:26 tron Exp $");
     33  1.4.2.2  tron 
     34  1.4.2.2  tron #if 0
     35  1.4.2.2  tron #define DPRINTK(fmt, args...) \
     36  1.4.2.2  tron     printk("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
     37  1.4.2.2  tron #else
     38  1.4.2.2  tron #define DPRINTK(fmt, args...) ((void)0)
     39  1.4.2.2  tron #endif
     40  1.4.2.2  tron 
     41  1.4.2.2  tron #include <sys/types.h>
     42  1.4.2.2  tron #include <sys/null.h>
     43  1.4.2.2  tron #include <sys/errno.h>
     44  1.4.2.2  tron #include <sys/malloc.h>
     45  1.4.2.2  tron #include <sys/systm.h>
     46  1.4.2.2  tron 
     47  1.4.2.2  tron #include <machine/stdarg.h>
     48  1.4.2.2  tron 
     49  1.4.2.2  tron #include <machine/evtchn.h>
     50  1.4.2.2  tron #include <machine/xenbus.h>
     51  1.4.2.2  tron #include <machine/granttables.h>
     52  1.4.2.2  tron 
     53  1.4.2.2  tron 
     54  1.4.2.2  tron int
     55  1.4.2.2  tron xenbus_watch_path(struct xenbus_device *dev, char *path,
     56  1.4.2.2  tron 		      struct xenbus_watch *watch,
     57  1.4.2.2  tron 		      void (*callback)(struct xenbus_watch *,
     58  1.4.2.2  tron 				       const char **, unsigned int))
     59  1.4.2.2  tron {
     60  1.4.2.2  tron 	int err;
     61  1.4.2.2  tron 
     62  1.4.2.2  tron 	watch->node = path;
     63  1.4.2.2  tron 	watch->xbw_callback = callback;
     64  1.4.2.2  tron 
     65  1.4.2.2  tron 	err = register_xenbus_watch(watch);
     66  1.4.2.2  tron 
     67  1.4.2.2  tron 	if (err) {
     68  1.4.2.2  tron 		watch->node = NULL;
     69  1.4.2.2  tron 		watch->xbw_callback = NULL;
     70  1.4.2.2  tron 		xenbus_dev_fatal(dev, err, "adding watch on %s", path);
     71  1.4.2.2  tron 	}
     72  1.4.2.2  tron 	err = 0;
     73  1.4.2.2  tron 
     74  1.4.2.2  tron 	return err;
     75  1.4.2.2  tron }
     76  1.4.2.2  tron 
     77  1.4.2.2  tron int
     78  1.4.2.2  tron xenbus_watch_path2(struct xenbus_device *dev, const char *path,
     79  1.4.2.2  tron 		       const char *path2, struct xenbus_watch *watch,
     80  1.4.2.2  tron 		       void (*callback)(struct xenbus_watch *,
     81  1.4.2.2  tron 					const char **, unsigned int))
     82  1.4.2.2  tron {
     83  1.4.2.2  tron 	int err;
     84  1.4.2.2  tron 	char *state;
     85  1.4.2.2  tron 
     86  1.4.2.2  tron 	DPRINTK("xenbus_watch_path2 path %s path2 %s\n", path, path2);
     87  1.4.2.2  tron 	state =
     88  1.4.2.2  tron 		malloc(strlen(path) + 1 + strlen(path2) + 1, M_DEVBUF,
     89  1.4.2.2  tron 		    M_NOWAIT);
     90  1.4.2.2  tron 	if (!state) {
     91  1.4.2.2  tron 		xenbus_dev_fatal(dev, ENOMEM, "allocating path for watch");
     92  1.4.2.2  tron 		return ENOMEM;
     93  1.4.2.2  tron 	}
     94  1.4.2.2  tron 	strcpy(state, path);
     95  1.4.2.2  tron 	strcat(state, "/");
     96  1.4.2.2  tron 	strcat(state, path2);
     97  1.4.2.2  tron 
     98  1.4.2.2  tron 	err = xenbus_watch_path(dev, state, watch, callback);
     99  1.4.2.2  tron 
    100  1.4.2.2  tron 	if (err) {
    101  1.4.2.2  tron 		free(state, M_DEVBUF);
    102  1.4.2.2  tron 	}
    103  1.4.2.2  tron 	return err;
    104  1.4.2.2  tron }
    105  1.4.2.2  tron 
    106  1.4.2.2  tron 
    107  1.4.2.2  tron int
    108  1.4.2.2  tron xenbus_switch_state(struct xenbus_device *dev,
    109  1.4.2.2  tron 			struct xenbus_transaction *xbt,
    110  1.4.2.2  tron 			XenbusState state)
    111  1.4.2.2  tron {
    112  1.4.2.2  tron 	/* We check whether the state is currently set to the given value, and
    113  1.4.2.2  tron 	   if not, then the state is set.  We don't want to unconditionally
    114  1.4.2.2  tron 	   write the given state, because we don't want to fire watches
    115  1.4.2.2  tron 	   unnecessarily.  Furthermore, if the node has gone, we don't write
    116  1.4.2.2  tron 	   to it, as the device will be tearing down, and we don't want to
    117  1.4.2.2  tron 	   resurrect that directory.
    118  1.4.2.2  tron 	 */
    119  1.4.2.2  tron 
    120  1.4.2.2  tron 	u_long current_state;
    121  1.4.2.2  tron 
    122  1.4.2.2  tron 	int err = xenbus_read_ul(xbt, dev->xbusd_path, "state", &current_state);
    123  1.4.2.2  tron 	if (err)
    124  1.4.2.2  tron 		return 0;
    125  1.4.2.2  tron 
    126  1.4.2.2  tron 	if ((XenbusState)current_state == state)
    127  1.4.2.2  tron 		return 0;
    128  1.4.2.2  tron 
    129  1.4.2.2  tron 	err = xenbus_printf(xbt, dev->xbusd_path, "state", "%d", state);
    130  1.4.2.2  tron 	if (err) {
    131  1.4.2.2  tron 		xenbus_dev_fatal(dev, err, "writing new state");
    132  1.4.2.2  tron 		return err;
    133  1.4.2.2  tron 	}
    134  1.4.2.2  tron 	return 0;
    135  1.4.2.2  tron }
    136  1.4.2.2  tron 
    137  1.4.2.2  tron /**
    138  1.4.2.2  tron  * Return the path to the error node for the given device, or NULL on failure.
    139  1.4.2.2  tron  * If the value returned is non-NULL, then it is the caller's to kfree.
    140  1.4.2.2  tron  */
    141  1.4.2.2  tron static char *
    142  1.4.2.2  tron error_path(struct xenbus_device *dev)
    143  1.4.2.2  tron {
    144  1.4.2.2  tron 	char *path_buffer = malloc(strlen("error/") + strlen(dev->xbusd_path) +
    145  1.4.2.2  tron 				    1, M_DEVBUF, M_NOWAIT);
    146  1.4.2.2  tron 	if (path_buffer == NULL) {
    147  1.4.2.2  tron 		return NULL;
    148  1.4.2.2  tron 	}
    149  1.4.2.2  tron 
    150  1.4.2.2  tron 	strcpy(path_buffer, "error/");
    151  1.4.2.2  tron 	strcpy(path_buffer + strlen("error/"), dev->xbusd_path);
    152  1.4.2.2  tron 
    153  1.4.2.2  tron 	return path_buffer;
    154  1.4.2.2  tron }
    155  1.4.2.2  tron 
    156  1.4.2.2  tron 
    157  1.4.2.2  tron static void
    158  1.4.2.2  tron _dev_error(struct xenbus_device *dev, int err, const char *fmt,
    159  1.4.2.2  tron 		va_list ap)
    160  1.4.2.2  tron {
    161  1.4.2.2  tron 	int ret;
    162  1.4.2.2  tron 	unsigned int len;
    163  1.4.2.2  tron 	char *printf_buffer = NULL, *path_buffer = NULL;
    164  1.4.2.2  tron 
    165  1.4.2.2  tron #define PRINTF_BUFFER_SIZE 4096
    166  1.4.2.2  tron 	printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_NOWAIT);
    167  1.4.2.2  tron 	if (printf_buffer == NULL)
    168  1.4.2.2  tron 		goto fail;
    169  1.4.2.2  tron 
    170  1.4.2.2  tron 	len = sprintf(printf_buffer, "%i ", -err);
    171  1.4.2.2  tron 	ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
    172  1.4.2.2  tron 
    173  1.4.2.2  tron 	KASSERT(len + ret < PRINTF_BUFFER_SIZE);
    174  1.4.2.2  tron 	dev->xbusd_has_error = 1;
    175  1.4.2.2  tron 
    176  1.4.2.2  tron 	path_buffer = error_path(dev);
    177  1.4.2.2  tron 
    178  1.4.2.2  tron 	if (path_buffer == NULL) {
    179  1.4.2.2  tron 		printk("xenbus: failed to write error node for %s (%s)\n",
    180  1.4.2.2  tron 		       dev->xbusd_path, printf_buffer);
    181  1.4.2.2  tron 		goto fail;
    182  1.4.2.2  tron 	}
    183  1.4.2.2  tron 
    184  1.4.2.2  tron 	if (xenbus_write(NULL, path_buffer, "error", printf_buffer) != 0) {
    185  1.4.2.2  tron 		printk("xenbus: failed to write error node for %s (%s)\n",
    186  1.4.2.2  tron 		       dev->xbusd_path, printf_buffer);
    187  1.4.2.2  tron 		goto fail;
    188  1.4.2.2  tron 	}
    189  1.4.2.2  tron 
    190  1.4.2.2  tron fail:
    191  1.4.2.2  tron 	if (printf_buffer)
    192  1.4.2.2  tron 		free(printf_buffer, M_DEVBUF);
    193  1.4.2.2  tron 	if (path_buffer)
    194  1.4.2.2  tron 		free(path_buffer, M_DEVBUF);
    195  1.4.2.2  tron }
    196  1.4.2.2  tron 
    197  1.4.2.2  tron 
    198  1.4.2.2  tron void
    199  1.4.2.2  tron xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,
    200  1.4.2.2  tron 		      ...)
    201  1.4.2.2  tron {
    202  1.4.2.2  tron 	va_list ap;
    203  1.4.2.2  tron 
    204  1.4.2.2  tron 	va_start(ap, fmt);
    205  1.4.2.2  tron 	_dev_error(dev, err, fmt, ap);
    206  1.4.2.2  tron 	va_end(ap);
    207  1.4.2.2  tron }
    208  1.4.2.2  tron 
    209  1.4.2.2  tron 
    210  1.4.2.2  tron void
    211  1.4.2.2  tron xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
    212  1.4.2.2  tron 		      ...)
    213  1.4.2.2  tron {
    214  1.4.2.2  tron 	va_list ap;
    215  1.4.2.2  tron 
    216  1.4.2.2  tron 	va_start(ap, fmt);
    217  1.4.2.2  tron 	_dev_error(dev, err, fmt, ap);
    218  1.4.2.2  tron 	va_end(ap);
    219  1.4.2.2  tron 
    220  1.4.2.2  tron 	xenbus_switch_state(dev, NULL, XenbusStateClosing);
    221  1.4.2.2  tron }
    222  1.4.2.2  tron 
    223  1.4.2.2  tron 
    224  1.4.2.2  tron int
    225  1.4.2.2  tron xenbus_grant_ring(struct xenbus_device *dev, paddr_t ring_pa,
    226  1.4.2.2  tron     grant_ref_t *entryp)
    227  1.4.2.2  tron {
    228  1.4.2.2  tron 	int err = xengnt_grant_access(dev->xbusd_otherend_id, ring_pa,
    229  1.4.2.2  tron 	    0, entryp);
    230  1.4.2.2  tron 	if (err != 0)
    231  1.4.2.2  tron 		xenbus_dev_fatal(dev, err, "granting access to ring page");
    232  1.4.2.2  tron 	return err;
    233  1.4.2.2  tron }
    234  1.4.2.2  tron 
    235  1.4.2.2  tron 
    236  1.4.2.2  tron int
    237  1.4.2.2  tron xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
    238  1.4.2.2  tron {
    239  1.4.2.2  tron 	evtchn_op_t op = {
    240  1.4.2.2  tron 		.cmd = EVTCHNOP_alloc_unbound,
    241  1.4.2.2  tron 		.u.alloc_unbound.dom = DOMID_SELF,
    242  1.4.2.2  tron 		.u.alloc_unbound.remote_dom = dev->xbusd_otherend_id };
    243  1.4.2.2  tron 
    244  1.4.2.2  tron 	int err = HYPERVISOR_event_channel_op(&op);
    245  1.4.2.2  tron 	if (err)
    246  1.4.2.2  tron 		xenbus_dev_fatal(dev, err, "allocating event channel");
    247  1.4.2.2  tron 	else
    248  1.4.2.2  tron 		*port = op.u.alloc_unbound.port;
    249  1.4.2.2  tron 	return err;
    250  1.4.2.2  tron }
    251  1.4.2.2  tron 
    252  1.4.2.2  tron 
    253  1.4.2.2  tron XenbusState
    254  1.4.2.2  tron xenbus_read_driver_state(const char *path)
    255  1.4.2.2  tron {
    256  1.4.2.2  tron 	u_long result;
    257  1.4.2.2  tron 
    258  1.4.2.2  tron 	int err = xenbus_read_ul(NULL, path, "state", &result);
    259  1.4.2.2  tron 	if (err)
    260  1.4.2.2  tron 		result = XenbusStateClosed;
    261  1.4.2.2  tron 
    262  1.4.2.2  tron 	return result;
    263  1.4.2.2  tron }
    264  1.4.2.2  tron 
    265  1.4.2.2  tron 
    266  1.4.2.2  tron /*
    267  1.4.2.2  tron  * Local variables:
    268  1.4.2.2  tron  *  c-file-style: "linux"
    269  1.4.2.2  tron  *  indent-tabs-mode: t
    270  1.4.2.2  tron  *  c-indent-level: 8
    271  1.4.2.2  tron  *  c-basic-offset: 8
    272  1.4.2.2  tron  *  tab-width: 8
    273  1.4.2.2  tron  * End:
    274  1.4.2.2  tron  */
    275