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