xref: /netbsd-src/sys/arch/xen/xenbus/xenbus_client.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /* $NetBSD: xenbus_client.c,v 1.10 2009/04/28 05:44:43 cegger 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.10 2009/04/28 05:44:43 cegger Exp $");
33 
34 #if 0
35 #define DPRINTK(fmt, args...) \
36     printk("xenbus_client (%s:%d) " fmt ".\n", __func__, __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 <xen/xen.h>
50 #include <xen/hypervisor.h>
51 #include <xen/evtchn.h>
52 #include <xen/xenbus.h>
53 #include <xen/granttables.h>
54 
55 
56 int
57 xenbus_watch_path(struct xenbus_device *dev, char *path,
58 		      struct xenbus_watch *watch,
59 		      void (*callback)(struct xenbus_watch *,
60 				       const char **, unsigned int))
61 {
62 	int err;
63 
64 	watch->node = path;
65 	watch->xbw_callback = callback;
66 
67 	err = register_xenbus_watch(watch);
68 
69 	if (err) {
70 		watch->node = NULL;
71 		watch->xbw_callback = NULL;
72 		xenbus_dev_fatal(dev, err, "adding watch on %s", path);
73 	}
74 	err = 0;
75 
76 	return err;
77 }
78 
79 int
80 xenbus_watch_path2(struct xenbus_device *dev, const char *path,
81 		       const char *path2, struct xenbus_watch *watch,
82 		       void (*callback)(struct xenbus_watch *,
83 					const char **, unsigned int))
84 {
85 	int err;
86 	char *state;
87 
88 	DPRINTK("xenbus_watch_path2 path %s path2 %s\n", path, path2);
89 	state =
90 		malloc(strlen(path) + 1 + strlen(path2) + 1, M_DEVBUF,
91 		    M_NOWAIT);
92 	if (!state) {
93 		xenbus_dev_fatal(dev, ENOMEM, "allocating path for watch");
94 		return ENOMEM;
95 	}
96 	strcpy(state, path);
97 	strcat(state, "/");
98 	strcat(state, path2);
99 
100 	err = xenbus_watch_path(dev, state, watch, callback);
101 
102 	if (err) {
103 		free(state, M_DEVBUF);
104 	}
105 	return err;
106 }
107 
108 
109 int
110 xenbus_switch_state(struct xenbus_device *dev,
111 			struct xenbus_transaction *xbt,
112 			XenbusState state)
113 {
114 	/* We check whether the state is currently set to the given value, and
115 	   if not, then the state is set.  We don't want to unconditionally
116 	   write the given state, because we don't want to fire watches
117 	   unnecessarily.  Furthermore, if the node has gone, we don't write
118 	   to it, as the device will be tearing down, and we don't want to
119 	   resurrect that directory.
120 	 */
121 
122 	u_long current_state;
123 
124 	int err = xenbus_read_ul(xbt, dev->xbusd_path, "state",
125 	    &current_state, 10);
126 	if (err)
127 		return 0;
128 
129 	if ((XenbusState)current_state == state)
130 		return 0;
131 
132 	err = xenbus_printf(xbt, dev->xbusd_path, "state", "%d", state);
133 	if (err) {
134 		xenbus_dev_fatal(dev, err, "writing new state");
135 		return err;
136 	}
137 	return 0;
138 }
139 
140 /**
141  * Return the path to the error node for the given device, or NULL on failure.
142  * If the value returned is non-NULL, then it is the caller's to kfree.
143  */
144 static char *
145 error_path(struct xenbus_device *dev)
146 {
147 	char *path_buffer = malloc(strlen("error/") + strlen(dev->xbusd_path) +
148 				    1, M_DEVBUF, M_NOWAIT);
149 	if (path_buffer == NULL) {
150 		return NULL;
151 	}
152 
153 	strcpy(path_buffer, "error/");
154 	strcpy(path_buffer + strlen("error/"), dev->xbusd_path);
155 
156 	return path_buffer;
157 }
158 
159 
160 static void
161 _dev_error(struct xenbus_device *dev, int err, const char *fmt,
162 		va_list ap)
163 {
164 	int ret;
165 	unsigned int len;
166 	char *printf_buffer = NULL, *path_buffer = NULL;
167 
168 #define PRINTF_BUFFER_SIZE 4096
169 	printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_NOWAIT);
170 	if (printf_buffer == NULL)
171 		goto fail;
172 
173 	len = snprintf(printf_buffer, PRINTF_BUFFER_SIZE, "%i ", -err);
174 	ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
175 
176 	KASSERT(len + ret < PRINTF_BUFFER_SIZE);
177 	dev->xbusd_has_error = 1;
178 
179 	path_buffer = error_path(dev);
180 
181 	if (path_buffer == NULL) {
182 		printk("xenbus: failed to write error node for %s (%s)\n",
183 		       dev->xbusd_path, printf_buffer);
184 		goto fail;
185 	}
186 
187 	if (xenbus_write(NULL, path_buffer, "error", printf_buffer) != 0) {
188 		printk("xenbus: failed to write error node for %s (%s)\n",
189 		       dev->xbusd_path, printf_buffer);
190 		goto fail;
191 	}
192 
193 fail:
194 	if (printf_buffer)
195 		free(printf_buffer, M_DEVBUF);
196 	if (path_buffer)
197 		free(path_buffer, M_DEVBUF);
198 }
199 
200 
201 void
202 xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,
203 		      ...)
204 {
205 	va_list ap;
206 
207 	va_start(ap, fmt);
208 	_dev_error(dev, err, fmt, ap);
209 	va_end(ap);
210 }
211 
212 
213 void
214 xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
215 		      ...)
216 {
217 	va_list ap;
218 
219 	va_start(ap, fmt);
220 	_dev_error(dev, err, fmt, ap);
221 	va_end(ap);
222 
223 	xenbus_switch_state(dev, NULL, XenbusStateClosing);
224 }
225 
226 
227 int
228 xenbus_grant_ring(struct xenbus_device *dev, paddr_t ring_pa,
229     grant_ref_t *entryp)
230 {
231 	int err = xengnt_grant_access(dev->xbusd_otherend_id, ring_pa,
232 	    0, entryp);
233 	if (err != 0)
234 		xenbus_dev_fatal(dev, err, "granting access to ring page");
235 	return err;
236 }
237 
238 
239 int
240 xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
241 {
242 	evtchn_op_t op = {
243 		.cmd = EVTCHNOP_alloc_unbound,
244 		.u.alloc_unbound = {
245 			.dom = DOMID_SELF,
246 			.remote_dom = dev->xbusd_otherend_id,
247 			.port = 0
248 		}
249 	};
250 
251 	int err = HYPERVISOR_event_channel_op(&op);
252 	if (err)
253 		xenbus_dev_fatal(dev, err, "allocating event channel");
254 	else
255 		*port = op.u.alloc_unbound.port;
256 	return err;
257 }
258 
259 
260 XenbusState
261 xenbus_read_driver_state(const char *path)
262 {
263 	u_long result;
264 
265 	int err = xenbus_read_ul(NULL, path, "state", &result, 10);
266 	if (err)
267 		result = XenbusStateClosed;
268 
269 	return result;
270 }
271 
272 
273 /*
274  * Local variables:
275  *  c-file-style: "linux"
276  *  indent-tabs-mode: t
277  *  c-indent-level: 8
278  *  c-basic-offset: 8
279  *  tab-width: 8
280  * End:
281  */
282