Statistics
| Branch: | Revision:

root / hw / xen_backend.c @ 72cf2d4f

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