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