Statistics
| Branch: | Revision:

root / hw / xen_backend.c @ 98846d73

History | View | Annotate | Download (18.5 kB)

1 d94f9486 aliguori
/*
2 d94f9486 aliguori
 *  xen backend driver infrastructure
3 d94f9486 aliguori
 *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
4 d94f9486 aliguori
 *
5 d94f9486 aliguori
 *  This program is free software; you can redistribute it and/or modify
6 d94f9486 aliguori
 *  it under the terms of the GNU General Public License as published by
7 d94f9486 aliguori
 *  the Free Software Foundation; under version 2 of the License.
8 d94f9486 aliguori
 *
9 d94f9486 aliguori
 *  This program is distributed in the hope that it will be useful,
10 d94f9486 aliguori
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 d94f9486 aliguori
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 d94f9486 aliguori
 *  GNU General Public License for more details.
13 d94f9486 aliguori
 *
14 d94f9486 aliguori
 *  You should have received a copy of the GNU General Public License along
15 d94f9486 aliguori
 *  with this program; if not, write to the Free Software Foundation, Inc.,
16 d94f9486 aliguori
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 d94f9486 aliguori
 */
18 d94f9486 aliguori
19 d94f9486 aliguori
/*
20 d94f9486 aliguori
 * TODO: add some xenbus / xenstore concepts overview here.
21 d94f9486 aliguori
 */
22 d94f9486 aliguori
23 d94f9486 aliguori
#include <stdio.h>
24 d94f9486 aliguori
#include <stdlib.h>
25 d94f9486 aliguori
#include <stdarg.h>
26 d94f9486 aliguori
#include <string.h>
27 d94f9486 aliguori
#include <unistd.h>
28 d94f9486 aliguori
#include <fcntl.h>
29 d94f9486 aliguori
#include <inttypes.h>
30 d94f9486 aliguori
#include <sys/types.h>
31 d94f9486 aliguori
#include <sys/stat.h>
32 d94f9486 aliguori
#include <sys/mman.h>
33 d94f9486 aliguori
#include <sys/signal.h>
34 d94f9486 aliguori
35 d94f9486 aliguori
#include <xs.h>
36 d94f9486 aliguori
#include <xenctrl.h>
37 d94f9486 aliguori
#include <xen/grant_table.h>
38 d94f9486 aliguori
39 d94f9486 aliguori
#include "hw.h"
40 d94f9486 aliguori
#include "qemu-char.h"
41 2567f579 Blue Swirl
#include "qemu-log.h"
42 d94f9486 aliguori
#include "xen_backend.h"
43 d94f9486 aliguori
44 d94f9486 aliguori
/* ------------------------------------------------------------- */
45 d94f9486 aliguori
46 d94f9486 aliguori
/* public */
47 d94f9486 aliguori
int xen_xc;
48 d94f9486 aliguori
struct xs_handle *xenstore = NULL;
49 2c8b24a3 aliguori
const char *xen_protocol;
50 d94f9486 aliguori
51 d94f9486 aliguori
/* private */
52 d94f9486 aliguori
static TAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = TAILQ_HEAD_INITIALIZER(xendevs);
53 d94f9486 aliguori
static int debug = 0;
54 d94f9486 aliguori
55 d94f9486 aliguori
/* ------------------------------------------------------------- */
56 d94f9486 aliguori
57 d94f9486 aliguori
int xenstore_write_str(const char *base, const char *node, const char *val)
58 d94f9486 aliguori
{
59 d94f9486 aliguori
    char abspath[XEN_BUFSIZE];
60 d94f9486 aliguori
61 d94f9486 aliguori
    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
62 d94f9486 aliguori
    if (!xs_write(xenstore, 0, abspath, val, strlen(val)))
63 d94f9486 aliguori
        return -1;
64 d94f9486 aliguori
    return 0;
65 d94f9486 aliguori
}
66 d94f9486 aliguori
67 d94f9486 aliguori
char *xenstore_read_str(const char *base, const char *node)
68 d94f9486 aliguori
{
69 d94f9486 aliguori
    char abspath[XEN_BUFSIZE];
70 d94f9486 aliguori
    unsigned int len;
71 d94f9486 aliguori
    char *str, *ret = NULL;
72 d94f9486 aliguori
73 d94f9486 aliguori
    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
74 d94f9486 aliguori
    str = xs_read(xenstore, 0, abspath, &len);
75 d94f9486 aliguori
    if (str != NULL) {
76 d94f9486 aliguori
        /* move to qemu-allocated memory to make sure
77 d94f9486 aliguori
         * callers can savely qemu_free() stuff. */
78 d94f9486 aliguori
        ret = qemu_strdup(str);
79 d94f9486 aliguori
        free(str);
80 d94f9486 aliguori
    }
81 d94f9486 aliguori
    return ret;
82 d94f9486 aliguori
}
83 d94f9486 aliguori
84 d94f9486 aliguori
int xenstore_write_int(const char *base, const char *node, int ival)
85 d94f9486 aliguori
{
86 d94f9486 aliguori
    char val[32];
87 d94f9486 aliguori
88 d94f9486 aliguori
    snprintf(val, sizeof(val), "%d", ival);
89 d94f9486 aliguori
    return xenstore_write_str(base, node, val);
90 d94f9486 aliguori
}
91 d94f9486 aliguori
92 d94f9486 aliguori
int xenstore_read_int(const char *base, const char *node, int *ival)
93 d94f9486 aliguori
{
94 d94f9486 aliguori
    char *val;
95 d94f9486 aliguori
    int rc = -1;
96 d94f9486 aliguori
97 d94f9486 aliguori
    val = xenstore_read_str(base, node);
98 d94f9486 aliguori
    if (val && 1 == sscanf(val, "%d", ival))
99 d94f9486 aliguori
        rc = 0;
100 d94f9486 aliguori
    qemu_free(val);
101 d94f9486 aliguori
    return rc;
102 d94f9486 aliguori
}
103 d94f9486 aliguori
104 d94f9486 aliguori
int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
105 d94f9486 aliguori
{
106 d94f9486 aliguori
    return xenstore_write_str(xendev->be, node, val);
107 d94f9486 aliguori
}
108 d94f9486 aliguori
109 d94f9486 aliguori
int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
110 d94f9486 aliguori
{
111 d94f9486 aliguori
    return xenstore_write_int(xendev->be, node, ival);
112 d94f9486 aliguori
}
113 d94f9486 aliguori
114 d94f9486 aliguori
char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
115 d94f9486 aliguori
{
116 d94f9486 aliguori
    return xenstore_read_str(xendev->be, node);
117 d94f9486 aliguori
}
118 d94f9486 aliguori
119 d94f9486 aliguori
int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
120 d94f9486 aliguori
{
121 d94f9486 aliguori
    return xenstore_read_int(xendev->be, node, ival);
122 d94f9486 aliguori
}
123 d94f9486 aliguori
124 d94f9486 aliguori
char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
125 d94f9486 aliguori
{
126 d94f9486 aliguori
    return xenstore_read_str(xendev->fe, node);
127 d94f9486 aliguori
}
128 d94f9486 aliguori
129 d94f9486 aliguori
int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
130 d94f9486 aliguori
{
131 d94f9486 aliguori
    return xenstore_read_int(xendev->fe, node, ival);
132 d94f9486 aliguori
}
133 d94f9486 aliguori
134 d94f9486 aliguori
/* ------------------------------------------------------------- */
135 d94f9486 aliguori
136 d94f9486 aliguori
const char *xenbus_strstate(enum xenbus_state state)
137 d94f9486 aliguori
{
138 d94f9486 aliguori
        static const char *const name[] = {
139 d94f9486 aliguori
                [ XenbusStateUnknown      ] = "Unknown",
140 d94f9486 aliguori
                [ XenbusStateInitialising ] = "Initialising",
141 d94f9486 aliguori
                [ XenbusStateInitWait     ] = "InitWait",
142 d94f9486 aliguori
                [ XenbusStateInitialised  ] = "Initialised",
143 d94f9486 aliguori
                [ XenbusStateConnected    ] = "Connected",
144 d94f9486 aliguori
                [ XenbusStateClosing      ] = "Closing",
145 d94f9486 aliguori
                [ XenbusStateClosed          ] = "Closed",
146 d94f9486 aliguori
        };
147 d94f9486 aliguori
        return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
148 d94f9486 aliguori
}
149 d94f9486 aliguori
150 d94f9486 aliguori
int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
151 d94f9486 aliguori
{
152 d94f9486 aliguori
    int rc;
153 d94f9486 aliguori
154 d94f9486 aliguori
    rc = xenstore_write_be_int(xendev, "state", state);
155 d94f9486 aliguori
    if (rc < 0)
156 d94f9486 aliguori
        return rc;
157 d94f9486 aliguori
    xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
158 d94f9486 aliguori
                  xenbus_strstate(xendev->be_state), xenbus_strstate(state));
159 d94f9486 aliguori
    xendev->be_state = state;
160 d94f9486 aliguori
    return 0;
161 d94f9486 aliguori
}
162 d94f9486 aliguori
163 d94f9486 aliguori
/* ------------------------------------------------------------- */
164 d94f9486 aliguori
165 d94f9486 aliguori
struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
166 d94f9486 aliguori
{
167 d94f9486 aliguori
    struct XenDevice *xendev;
168 d94f9486 aliguori
169 d94f9486 aliguori
    TAILQ_FOREACH(xendev, &xendevs, next) {
170 d94f9486 aliguori
        if (xendev->dom != dom)
171 d94f9486 aliguori
            continue;
172 d94f9486 aliguori
        if (xendev->dev != dev)
173 d94f9486 aliguori
            continue;
174 d94f9486 aliguori
        if (strcmp(xendev->type, type) != 0)
175 d94f9486 aliguori
            continue;
176 d94f9486 aliguori
        return xendev;
177 d94f9486 aliguori
    }
178 d94f9486 aliguori
    return NULL;
179 d94f9486 aliguori
}
180 d94f9486 aliguori
181 d94f9486 aliguori
/*
182 d94f9486 aliguori
 * get xen backend device, allocate a new one if it doesn't exist.
183 d94f9486 aliguori
 */
184 d94f9486 aliguori
static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
185 d94f9486 aliguori
                                           struct XenDevOps *ops)
186 d94f9486 aliguori
{
187 d94f9486 aliguori
    struct XenDevice *xendev;
188 d94f9486 aliguori
    char *dom0;
189 d94f9486 aliguori
190 d94f9486 aliguori
    xendev = xen_be_find_xendev(type, dom, dev);
191 d94f9486 aliguori
    if (xendev)
192 d94f9486 aliguori
        return xendev;
193 d94f9486 aliguori
194 d94f9486 aliguori
    /* init new xendev */
195 d94f9486 aliguori
    xendev = qemu_mallocz(ops->size);
196 d94f9486 aliguori
    xendev->type  = type;
197 d94f9486 aliguori
    xendev->dom   = dom;
198 d94f9486 aliguori
    xendev->dev   = dev;
199 d94f9486 aliguori
    xendev->ops   = ops;
200 d94f9486 aliguori
201 d94f9486 aliguori
    dom0 = xs_get_domain_path(xenstore, 0);
202 d94f9486 aliguori
    snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
203 d94f9486 aliguori
             dom0, xendev->type, xendev->dom, xendev->dev);
204 d94f9486 aliguori
    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
205 d94f9486 aliguori
             xendev->type, xendev->dev);
206 d94f9486 aliguori
    free(dom0);
207 d94f9486 aliguori
208 d94f9486 aliguori
    xendev->debug      = debug;
209 d94f9486 aliguori
    xendev->local_port = -1;
210 d94f9486 aliguori
211 d94f9486 aliguori
    xendev->evtchndev = xc_evtchn_open();
212 d94f9486 aliguori
    if (xendev->evtchndev < 0) {
213 d94f9486 aliguori
        xen_be_printf(NULL, 0, "can't open evtchn device\n");
214 d94f9486 aliguori
        qemu_free(xendev);
215 d94f9486 aliguori
        return NULL;
216 d94f9486 aliguori
    }
217 d94f9486 aliguori
    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
218 d94f9486 aliguori
219 d94f9486 aliguori
    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
220 d94f9486 aliguori
        xendev->gnttabdev = xc_gnttab_open();
221 d94f9486 aliguori
        if (xendev->gnttabdev < 0) {
222 d94f9486 aliguori
            xen_be_printf(NULL, 0, "can't open gnttab device\n");
223 d94f9486 aliguori
            xc_evtchn_close(xendev->evtchndev);
224 d94f9486 aliguori
            qemu_free(xendev);
225 d94f9486 aliguori
            return NULL;
226 d94f9486 aliguori
        }
227 d94f9486 aliguori
    } else {
228 d94f9486 aliguori
        xendev->gnttabdev = -1;
229 d94f9486 aliguori
    }
230 d94f9486 aliguori
231 d94f9486 aliguori
    TAILQ_INSERT_TAIL(&xendevs, xendev, next);
232 d94f9486 aliguori
233 d94f9486 aliguori
    if (xendev->ops->alloc)
234 d94f9486 aliguori
        xendev->ops->alloc(xendev);
235 d94f9486 aliguori
236 d94f9486 aliguori
    return xendev;
237 d94f9486 aliguori
}
238 d94f9486 aliguori
239 d94f9486 aliguori
/*
240 d94f9486 aliguori
 * release xen backend device.
241 d94f9486 aliguori
 */
242 d94f9486 aliguori
static struct XenDevice *xen_be_del_xendev(int dom, int dev)
243 d94f9486 aliguori
{
244 d94f9486 aliguori
    struct XenDevice *xendev, *xnext;
245 d94f9486 aliguori
246 d94f9486 aliguori
    /*
247 d94f9486 aliguori
     * This is pretty much like TAILQ_FOREACH(xendev, &xendevs, next) but
248 d94f9486 aliguori
     * we save the next pointer in xnext because we might free xendev.
249 d94f9486 aliguori
     */
250 d94f9486 aliguori
    xnext = xendevs.tqh_first;
251 d94f9486 aliguori
    while (xnext) {
252 d94f9486 aliguori
        xendev = xnext;
253 d94f9486 aliguori
        xnext = xendev->next.tqe_next;
254 d94f9486 aliguori
255 d94f9486 aliguori
        if (xendev->dom != dom)
256 d94f9486 aliguori
            continue;
257 d94f9486 aliguori
        if (xendev->dev != dev && dev != -1)
258 d94f9486 aliguori
            continue;
259 d94f9486 aliguori
260 d94f9486 aliguori
        if (xendev->ops->free)
261 d94f9486 aliguori
            xendev->ops->free(xendev);
262 d94f9486 aliguori
263 d94f9486 aliguori
        if (xendev->fe) {
264 d94f9486 aliguori
            char token[XEN_BUFSIZE];
265 d94f9486 aliguori
            snprintf(token, sizeof(token), "fe:%p", xendev);
266 d94f9486 aliguori
            xs_unwatch(xenstore, xendev->fe, token);
267 d94f9486 aliguori
            qemu_free(xendev->fe);
268 d94f9486 aliguori
        }
269 d94f9486 aliguori
270 d94f9486 aliguori
        if (xendev->evtchndev >= 0)
271 d94f9486 aliguori
            xc_evtchn_close(xendev->evtchndev);
272 d94f9486 aliguori
        if (xendev->gnttabdev >= 0)
273 d94f9486 aliguori
            xc_gnttab_close(xendev->gnttabdev);
274 d94f9486 aliguori
275 d94f9486 aliguori
        TAILQ_REMOVE(&xendevs, xendev, next);
276 d94f9486 aliguori
        qemu_free(xendev);
277 d94f9486 aliguori
    }
278 d94f9486 aliguori
    return NULL;
279 d94f9486 aliguori
}
280 d94f9486 aliguori
281 d94f9486 aliguori
/*
282 d94f9486 aliguori
 * Sync internal data structures on xenstore updates.
283 d94f9486 aliguori
 * Node specifies the changed field.  node = NULL means
284 d94f9486 aliguori
 * update all fields (used for initialization).
285 d94f9486 aliguori
 */
286 d94f9486 aliguori
static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
287 d94f9486 aliguori
{
288 d94f9486 aliguori
    if (node == NULL  ||  strcmp(node, "online") == 0) {
289 d94f9486 aliguori
        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1)
290 d94f9486 aliguori
            xendev->online = 0;
291 d94f9486 aliguori
    }
292 d94f9486 aliguori
293 d94f9486 aliguori
    if (node) {
294 d94f9486 aliguori
        xen_be_printf(xendev, 2, "backend update: %s\n", node);
295 d94f9486 aliguori
        if (xendev->ops->backend_changed)
296 d94f9486 aliguori
            xendev->ops->backend_changed(xendev, node);
297 d94f9486 aliguori
    }
298 d94f9486 aliguori
}
299 d94f9486 aliguori
300 d94f9486 aliguori
static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
301 d94f9486 aliguori
{
302 d94f9486 aliguori
    int fe_state;
303 d94f9486 aliguori
304 d94f9486 aliguori
    if (node == NULL  ||  strcmp(node, "state") == 0) {
305 d94f9486 aliguori
        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1)
306 d94f9486 aliguori
            fe_state = XenbusStateUnknown;
307 d94f9486 aliguori
        if (xendev->fe_state != fe_state)
308 d94f9486 aliguori
            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
309 d94f9486 aliguori
                          xenbus_strstate(xendev->fe_state),
310 d94f9486 aliguori
                          xenbus_strstate(fe_state));
311 d94f9486 aliguori
        xendev->fe_state = fe_state;
312 d94f9486 aliguori
    }
313 d94f9486 aliguori
    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
314 d94f9486 aliguori
        qemu_free(xendev->protocol);
315 d94f9486 aliguori
        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
316 d94f9486 aliguori
        if (xendev->protocol)
317 d94f9486 aliguori
            xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
318 d94f9486 aliguori
    }
319 d94f9486 aliguori
320 d94f9486 aliguori
    if (node) {
321 d94f9486 aliguori
        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
322 d94f9486 aliguori
        if (xendev->ops->frontend_changed)
323 d94f9486 aliguori
            xendev->ops->frontend_changed(xendev, node);
324 d94f9486 aliguori
    }
325 d94f9486 aliguori
}
326 d94f9486 aliguori
327 d94f9486 aliguori
/* ------------------------------------------------------------- */
328 d94f9486 aliguori
/* Check for possible state transitions and perform them.        */
329 d94f9486 aliguori
330 d94f9486 aliguori
/*
331 d94f9486 aliguori
 * Initial xendev setup.  Read frontend path, register watch for it.
332 d94f9486 aliguori
 * Should succeed once xend finished setting up the backend device.
333 d94f9486 aliguori
 *
334 d94f9486 aliguori
 * Also sets initial state (-> Initializing) when done.  Which
335 d94f9486 aliguori
 * only affects the xendev->be_state variable as xenbus should
336 d94f9486 aliguori
 * already be put into that state by xend.
337 d94f9486 aliguori
 */
338 d94f9486 aliguori
static int xen_be_try_setup(struct XenDevice *xendev)
339 d94f9486 aliguori
{
340 d94f9486 aliguori
    char token[XEN_BUFSIZE];
341 d94f9486 aliguori
    int be_state;
342 d94f9486 aliguori
343 d94f9486 aliguori
    if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
344 d94f9486 aliguori
        xen_be_printf(xendev, 0, "reading backend state failed\n");
345 d94f9486 aliguori
        return -1;
346 d94f9486 aliguori
    }
347 d94f9486 aliguori
348 d94f9486 aliguori
    if (be_state != XenbusStateInitialising) {
349 d94f9486 aliguori
        xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
350 d94f9486 aliguori
                      xenbus_strstate(be_state));
351 d94f9486 aliguori
        return -1;
352 d94f9486 aliguori
    }
353 d94f9486 aliguori
354 d94f9486 aliguori
    xendev->fe = xenstore_read_be_str(xendev, "frontend");
355 d94f9486 aliguori
    if (xendev->fe == NULL) {
356 d94f9486 aliguori
        xen_be_printf(xendev, 0, "reading frontend path failed\n");
357 d94f9486 aliguori
        return -1;
358 d94f9486 aliguori
    }
359 d94f9486 aliguori
360 d94f9486 aliguori
    /* setup frontend watch */
361 d94f9486 aliguori
    snprintf(token, sizeof(token), "fe:%p", xendev);
362 d94f9486 aliguori
    if (!xs_watch(xenstore, xendev->fe, token)) {
363 d94f9486 aliguori
        xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
364 d94f9486 aliguori
                      xendev->fe);
365 d94f9486 aliguori
        return -1;
366 d94f9486 aliguori
    }
367 d94f9486 aliguori
    xen_be_set_state(xendev, XenbusStateInitialising);
368 d94f9486 aliguori
369 d94f9486 aliguori
    xen_be_backend_changed(xendev, NULL);
370 d94f9486 aliguori
    xen_be_frontend_changed(xendev, NULL);
371 d94f9486 aliguori
    return 0;
372 d94f9486 aliguori
}
373 d94f9486 aliguori
374 d94f9486 aliguori
/*
375 d94f9486 aliguori
 * Try initialize xendev.  Prepare everything the backend can do
376 d94f9486 aliguori
 * without synchronizing with the frontend.  Fakes hotplug-status.  No
377 d94f9486 aliguori
 * hotplug involved here because this is about userspace drivers, thus
378 d94f9486 aliguori
 * there are kernel backend devices which could invoke hotplug.
379 d94f9486 aliguori
 *
380 d94f9486 aliguori
 * Goes to InitWait on success.
381 d94f9486 aliguori
 */
382 d94f9486 aliguori
static int xen_be_try_init(struct XenDevice *xendev)
383 d94f9486 aliguori
{
384 d94f9486 aliguori
    int rc = 0;
385 d94f9486 aliguori
386 d94f9486 aliguori
    if (!xendev->online) {
387 d94f9486 aliguori
        xen_be_printf(xendev, 1, "not online\n");
388 d94f9486 aliguori
        return -1;
389 d94f9486 aliguori
    }
390 d94f9486 aliguori
391 d94f9486 aliguori
    if (xendev->ops->init)
392 d94f9486 aliguori
        rc = xendev->ops->init(xendev);
393 d94f9486 aliguori
    if (rc != 0) {
394 d94f9486 aliguori
        xen_be_printf(xendev, 1, "init() failed\n");
395 d94f9486 aliguori
        return rc;
396 d94f9486 aliguori
    }
397 d94f9486 aliguori
398 d94f9486 aliguori
    xenstore_write_be_str(xendev, "hotplug-status", "connected");
399 d94f9486 aliguori
    xen_be_set_state(xendev, XenbusStateInitWait);
400 d94f9486 aliguori
    return 0;
401 d94f9486 aliguori
}
402 d94f9486 aliguori
403 d94f9486 aliguori
/*
404 d94f9486 aliguori
 * Try to connect xendev.  Depends on the frontend being ready
405 d94f9486 aliguori
 * for it (shared ring and evtchn info in xenstore, state being
406 d94f9486 aliguori
 * Initialised or Connected).
407 d94f9486 aliguori
 *
408 d94f9486 aliguori
 * Goes to Connected on success.
409 d94f9486 aliguori
 */
410 d94f9486 aliguori
static int xen_be_try_connect(struct XenDevice *xendev)
411 d94f9486 aliguori
{
412 d94f9486 aliguori
    int rc = 0;
413 d94f9486 aliguori
414 d94f9486 aliguori
    if (xendev->fe_state != XenbusStateInitialised  &&
415 d94f9486 aliguori
        xendev->fe_state != XenbusStateConnected) {
416 d94f9486 aliguori
        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
417 d94f9486 aliguori
            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
418 d94f9486 aliguori
        } else {
419 d94f9486 aliguori
            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
420 d94f9486 aliguori
            return -1;
421 d94f9486 aliguori
        }
422 d94f9486 aliguori
    }
423 d94f9486 aliguori
424 d94f9486 aliguori
    if (xendev->ops->connect)
425 d94f9486 aliguori
        rc = xendev->ops->connect(xendev);
426 d94f9486 aliguori
    if (rc != 0) {
427 d94f9486 aliguori
        xen_be_printf(xendev, 0, "connect() failed\n");
428 d94f9486 aliguori
        return rc;
429 d94f9486 aliguori
    }
430 d94f9486 aliguori
431 d94f9486 aliguori
    xen_be_set_state(xendev, XenbusStateConnected);
432 d94f9486 aliguori
    return 0;
433 d94f9486 aliguori
}
434 d94f9486 aliguori
435 d94f9486 aliguori
/*
436 d94f9486 aliguori
 * Teardown connection.
437 d94f9486 aliguori
 *
438 d94f9486 aliguori
 * Goes to Closed when done.
439 d94f9486 aliguori
 */
440 d94f9486 aliguori
static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
441 d94f9486 aliguori
{
442 d94f9486 aliguori
    if (xendev->be_state != XenbusStateClosing &&
443 d94f9486 aliguori
        xendev->be_state != XenbusStateClosed  &&
444 d94f9486 aliguori
        xendev->ops->disconnect)
445 d94f9486 aliguori
        xendev->ops->disconnect(xendev);
446 d94f9486 aliguori
    if (xendev->be_state != state)
447 d94f9486 aliguori
        xen_be_set_state(xendev, state);
448 d94f9486 aliguori
}
449 d94f9486 aliguori
450 d94f9486 aliguori
/*
451 d94f9486 aliguori
 * Try to reset xendev, for reconnection by another frontend instance.
452 d94f9486 aliguori
 */
453 d94f9486 aliguori
static int xen_be_try_reset(struct XenDevice *xendev)
454 d94f9486 aliguori
{
455 d94f9486 aliguori
    if (xendev->fe_state != XenbusStateInitialising)
456 d94f9486 aliguori
        return -1;
457 d94f9486 aliguori
458 d94f9486 aliguori
    xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
459 d94f9486 aliguori
    xen_be_set_state(xendev, XenbusStateInitialising);
460 d94f9486 aliguori
    return 0;
461 d94f9486 aliguori
}
462 d94f9486 aliguori
463 d94f9486 aliguori
/*
464 d94f9486 aliguori
 * state change dispatcher function
465 d94f9486 aliguori
 */
466 d94f9486 aliguori
void xen_be_check_state(struct XenDevice *xendev)
467 d94f9486 aliguori
{
468 d94f9486 aliguori
    int rc = 0;
469 d94f9486 aliguori
470 d94f9486 aliguori
    /* frontend may request shutdown from almost anywhere */
471 d94f9486 aliguori
    if (xendev->fe_state == XenbusStateClosing ||
472 d94f9486 aliguori
        xendev->fe_state == XenbusStateClosed) {
473 d94f9486 aliguori
        xen_be_disconnect(xendev, xendev->fe_state);
474 d94f9486 aliguori
        return;
475 d94f9486 aliguori
    }
476 d94f9486 aliguori
477 d94f9486 aliguori
    /* check for possible backend state transitions */
478 d94f9486 aliguori
    for (;;) {
479 d94f9486 aliguori
        switch (xendev->be_state) {
480 d94f9486 aliguori
        case XenbusStateUnknown:
481 d94f9486 aliguori
            rc = xen_be_try_setup(xendev);
482 d94f9486 aliguori
            break;
483 d94f9486 aliguori
        case XenbusStateInitialising:
484 d94f9486 aliguori
            rc = xen_be_try_init(xendev);
485 d94f9486 aliguori
            break;
486 d94f9486 aliguori
        case XenbusStateInitWait:
487 d94f9486 aliguori
            rc = xen_be_try_connect(xendev);
488 d94f9486 aliguori
            break;
489 d94f9486 aliguori
        case XenbusStateClosed:
490 d94f9486 aliguori
            rc = xen_be_try_reset(xendev);
491 d94f9486 aliguori
            break;
492 d94f9486 aliguori
        default:
493 d94f9486 aliguori
            rc = -1;
494 d94f9486 aliguori
        }
495 d94f9486 aliguori
        if (rc != 0)
496 d94f9486 aliguori
            break;
497 d94f9486 aliguori
    }
498 d94f9486 aliguori
}
499 d94f9486 aliguori
500 d94f9486 aliguori
/* ------------------------------------------------------------- */
501 d94f9486 aliguori
502 d94f9486 aliguori
static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
503 d94f9486 aliguori
{
504 d94f9486 aliguori
    struct XenDevice *xendev;
505 d94f9486 aliguori
    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
506 d94f9486 aliguori
    char **dev = NULL, *dom0;
507 d94f9486 aliguori
    unsigned int cdev, j;
508 d94f9486 aliguori
509 d94f9486 aliguori
    /* setup watch */
510 d94f9486 aliguori
    dom0 = xs_get_domain_path(xenstore, 0);
511 d94f9486 aliguori
    snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
512 d94f9486 aliguori
    snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
513 d94f9486 aliguori
    free(dom0);
514 d94f9486 aliguori
    if (!xs_watch(xenstore, path, token)) {
515 d94f9486 aliguori
        xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
516 d94f9486 aliguori
        return -1;
517 d94f9486 aliguori
    }
518 d94f9486 aliguori
519 d94f9486 aliguori
    /* look for backends */
520 d94f9486 aliguori
    dev = xs_directory(xenstore, 0, path, &cdev);
521 d94f9486 aliguori
    if (!dev)
522 d94f9486 aliguori
        return 0;
523 d94f9486 aliguori
    for (j = 0; j < cdev; j++) {
524 d94f9486 aliguori
        xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
525 d94f9486 aliguori
        if (xendev == NULL)
526 d94f9486 aliguori
            continue;
527 d94f9486 aliguori
        xen_be_check_state(xendev);
528 d94f9486 aliguori
    }
529 d94f9486 aliguori
    free(dev);
530 d94f9486 aliguori
    return 0;
531 d94f9486 aliguori
}
532 d94f9486 aliguori
533 d94f9486 aliguori
static void xenstore_update_be(char *watch, char *type, int dom,
534 d94f9486 aliguori
                               struct XenDevOps *ops)
535 d94f9486 aliguori
{
536 d94f9486 aliguori
    struct XenDevice *xendev;
537 d94f9486 aliguori
    char path[XEN_BUFSIZE], *dom0;
538 d94f9486 aliguori
    unsigned int len, dev;
539 d94f9486 aliguori
540 d94f9486 aliguori
    dom0 = xs_get_domain_path(xenstore, 0);
541 d94f9486 aliguori
    len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
542 d94f9486 aliguori
    free(dom0);
543 d94f9486 aliguori
    if (strncmp(path, watch, len) != 0)
544 d94f9486 aliguori
        return;
545 d94f9486 aliguori
    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
546 d94f9486 aliguori
        strcpy(path, "");
547 d94f9486 aliguori
        if (sscanf(watch+len, "/%u", &dev) != 1)
548 d94f9486 aliguori
            dev = -1;
549 d94f9486 aliguori
    }
550 d94f9486 aliguori
    if (dev == -1)
551 d94f9486 aliguori
        return;
552 d94f9486 aliguori
553 d94f9486 aliguori
    if (0) {
554 d94f9486 aliguori
        /* FIXME: detect devices being deleted from xenstore ... */
555 d94f9486 aliguori
        xen_be_del_xendev(dom, dev);
556 d94f9486 aliguori
    }
557 d94f9486 aliguori
558 d94f9486 aliguori
    xendev = xen_be_get_xendev(type, dom, dev, ops);
559 d94f9486 aliguori
    if (xendev != NULL) {
560 d94f9486 aliguori
        xen_be_backend_changed(xendev, path);
561 d94f9486 aliguori
        xen_be_check_state(xendev);
562 d94f9486 aliguori
    }
563 d94f9486 aliguori
}
564 d94f9486 aliguori
565 d94f9486 aliguori
static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
566 d94f9486 aliguori
{
567 d94f9486 aliguori
    char *node;
568 d94f9486 aliguori
    unsigned int len;
569 d94f9486 aliguori
570 d94f9486 aliguori
    len = strlen(xendev->fe);
571 d94f9486 aliguori
    if (strncmp(xendev->fe, watch, len) != 0)
572 d94f9486 aliguori
        return;
573 d94f9486 aliguori
    if (watch[len] != '/')
574 d94f9486 aliguori
        return;
575 d94f9486 aliguori
    node = watch + len + 1;
576 d94f9486 aliguori
577 d94f9486 aliguori
    xen_be_frontend_changed(xendev, node);
578 d94f9486 aliguori
    xen_be_check_state(xendev);
579 d94f9486 aliguori
}
580 d94f9486 aliguori
581 d94f9486 aliguori
static void xenstore_update(void *unused)
582 d94f9486 aliguori
{
583 d94f9486 aliguori
    char **vec = NULL;
584 d94f9486 aliguori
    intptr_t type, ops, ptr;
585 d94f9486 aliguori
    unsigned int dom, count;
586 d94f9486 aliguori
587 d94f9486 aliguori
    vec = xs_read_watch(xenstore, &count);
588 d94f9486 aliguori
    if (vec == NULL)
589 d94f9486 aliguori
        goto cleanup;
590 d94f9486 aliguori
591 d94f9486 aliguori
    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
592 d94f9486 aliguori
               &type, &dom, &ops) == 3)
593 d94f9486 aliguori
        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
594 d94f9486 aliguori
    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1)
595 d94f9486 aliguori
        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
596 d94f9486 aliguori
597 d94f9486 aliguori
cleanup:
598 d94f9486 aliguori
    qemu_free(vec);
599 d94f9486 aliguori
}
600 d94f9486 aliguori
601 d94f9486 aliguori
static void xen_be_evtchn_event(void *opaque)
602 d94f9486 aliguori
{
603 d94f9486 aliguori
    struct XenDevice *xendev = opaque;
604 d94f9486 aliguori
    evtchn_port_t port;
605 d94f9486 aliguori
606 d94f9486 aliguori
    port = xc_evtchn_pending(xendev->evtchndev);
607 d94f9486 aliguori
    if (port != xendev->local_port) {
608 d94f9486 aliguori
        xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
609 d94f9486 aliguori
                      port, xendev->local_port);
610 d94f9486 aliguori
        return;
611 d94f9486 aliguori
    }
612 d94f9486 aliguori
    xc_evtchn_unmask(xendev->evtchndev, port);
613 d94f9486 aliguori
614 d94f9486 aliguori
    if (xendev->ops->event)
615 d94f9486 aliguori
        xendev->ops->event(xendev);
616 d94f9486 aliguori
}
617 d94f9486 aliguori
618 d94f9486 aliguori
/* -------------------------------------------------------------------- */
619 d94f9486 aliguori
620 d94f9486 aliguori
int xen_be_init(void)
621 d94f9486 aliguori
{
622 d94f9486 aliguori
    xenstore = xs_daemon_open();
623 d94f9486 aliguori
    if (!xenstore) {
624 d94f9486 aliguori
        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
625 d94f9486 aliguori
        return -1;
626 d94f9486 aliguori
    }
627 d94f9486 aliguori
628 d94f9486 aliguori
    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0)
629 d94f9486 aliguori
        goto err;
630 d94f9486 aliguori
631 d94f9486 aliguori
    xen_xc = xc_interface_open();
632 d94f9486 aliguori
    if (xen_xc == -1) {
633 d94f9486 aliguori
        xen_be_printf(NULL, 0, "can't open xen interface\n");
634 d94f9486 aliguori
        goto err;
635 d94f9486 aliguori
    }
636 d94f9486 aliguori
    return 0;
637 d94f9486 aliguori
638 d94f9486 aliguori
err:
639 d94f9486 aliguori
    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
640 d94f9486 aliguori
    xs_daemon_close(xenstore);
641 d94f9486 aliguori
    xenstore = NULL;
642 d94f9486 aliguori
643 d94f9486 aliguori
    return -1;
644 d94f9486 aliguori
}
645 d94f9486 aliguori
646 d94f9486 aliguori
int xen_be_register(const char *type, struct XenDevOps *ops)
647 d94f9486 aliguori
{
648 d94f9486 aliguori
    return xenstore_scan(type, xen_domid, ops);
649 d94f9486 aliguori
}
650 d94f9486 aliguori
651 d94f9486 aliguori
int xen_be_bind_evtchn(struct XenDevice *xendev)
652 d94f9486 aliguori
{
653 d94f9486 aliguori
    if (xendev->local_port != -1)
654 d94f9486 aliguori
        return 0;
655 d94f9486 aliguori
    xendev->local_port = xc_evtchn_bind_interdomain
656 d94f9486 aliguori
        (xendev->evtchndev, xendev->dom, xendev->remote_port);
657 d94f9486 aliguori
    if (xendev->local_port == -1) {
658 d94f9486 aliguori
        xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
659 d94f9486 aliguori
        return -1;
660 d94f9486 aliguori
    }
661 d94f9486 aliguori
    xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
662 d94f9486 aliguori
    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
663 d94f9486 aliguori
                        xen_be_evtchn_event, NULL, xendev);
664 d94f9486 aliguori
    return 0;
665 d94f9486 aliguori
}
666 d94f9486 aliguori
667 d94f9486 aliguori
void xen_be_unbind_evtchn(struct XenDevice *xendev)
668 d94f9486 aliguori
{
669 d94f9486 aliguori
    if (xendev->local_port == -1)
670 d94f9486 aliguori
        return;
671 d94f9486 aliguori
    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
672 d94f9486 aliguori
    xc_evtchn_unbind(xendev->evtchndev, xendev->local_port);
673 d94f9486 aliguori
    xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
674 d94f9486 aliguori
    xendev->local_port = -1;
675 d94f9486 aliguori
}
676 d94f9486 aliguori
677 d94f9486 aliguori
int xen_be_send_notify(struct XenDevice *xendev)
678 d94f9486 aliguori
{
679 d94f9486 aliguori
    return xc_evtchn_notify(xendev->evtchndev, xendev->local_port);
680 d94f9486 aliguori
}
681 d94f9486 aliguori
682 d94f9486 aliguori
/*
683 d94f9486 aliguori
 * msg_level:
684 d94f9486 aliguori
 *  0 == errors (stderr + logfile).
685 d94f9486 aliguori
 *  1 == informative debug messages (logfile only).
686 d94f9486 aliguori
 *  2 == noisy debug messages (logfile only).
687 d94f9486 aliguori
 *  3 == will flood your log (logfile only).
688 d94f9486 aliguori
 */
689 d94f9486 aliguori
void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
690 d94f9486 aliguori
{
691 d94f9486 aliguori
    va_list args;
692 d94f9486 aliguori
693 d94f9486 aliguori
    if (xendev) {
694 d94f9486 aliguori
        if (msg_level > xendev->debug)
695 d94f9486 aliguori
            return;
696 d94f9486 aliguori
        qemu_log("xen be: %s: ", xendev->name);
697 d94f9486 aliguori
        if (msg_level == 0)
698 d94f9486 aliguori
            fprintf(stderr, "xen be: %s: ", xendev->name);
699 d94f9486 aliguori
    } else {
700 d94f9486 aliguori
        if (msg_level > debug)
701 d94f9486 aliguori
            return;
702 d94f9486 aliguori
        qemu_log("xen be core: ");
703 d94f9486 aliguori
        if (msg_level == 0)
704 d94f9486 aliguori
            fprintf(stderr, "xen be core: ");
705 d94f9486 aliguori
    }
706 d94f9486 aliguori
    va_start(args, fmt);
707 d94f9486 aliguori
    qemu_log_vprintf(fmt, args);
708 d94f9486 aliguori
    va_end(args);
709 d94f9486 aliguori
    if (msg_level == 0) {
710 d94f9486 aliguori
        va_start(args, fmt);
711 d94f9486 aliguori
        vfprintf(stderr, fmt, args);
712 d94f9486 aliguori
        va_end(args);
713 d94f9486 aliguori
    }
714 d94f9486 aliguori
    qemu_log_flush();
715 d94f9486 aliguori
}