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