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 ¤t_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