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