summaryrefslogtreecommitdiffstats
path: root/sys/xen/xenbus
diff options
context:
space:
mode:
Diffstat (limited to 'sys/xen/xenbus')
-rw-r--r--sys/xen/xenbus/init.txt14
-rw-r--r--sys/xen/xenbus/xenbus.c (renamed from sys/xen/xenbus/xenbus_client.c)141
-rw-r--r--sys/xen/xenbus/xenbus_comms.c226
-rw-r--r--sys/xen/xenbus/xenbus_comms.h48
-rw-r--r--sys/xen/xenbus/xenbus_dev.c229
-rw-r--r--sys/xen/xenbus/xenbus_if.m14
-rw-r--r--sys/xen/xenbus/xenbus_probe.c602
-rw-r--r--sys/xen/xenbus/xenbus_probe_backend.c308
-rw-r--r--sys/xen/xenbus/xenbus_xs.c935
-rw-r--r--sys/xen/xenbus/xenbusb.c878
-rw-r--r--sys/xen/xenbus/xenbusb.h272
-rw-r--r--sys/xen/xenbus/xenbusb_back.c295
-rw-r--r--sys/xen/xenbus/xenbusb_front.c195
-rw-r--r--sys/xen/xenbus/xenbusb_if.m78
-rw-r--r--sys/xen/xenbus/xenbusvar.h325
15 files changed, 1990 insertions, 2570 deletions
diff --git a/sys/xen/xenbus/init.txt b/sys/xen/xenbus/init.txt
deleted file mode 100644
index 4249549..0000000
--- a/sys/xen/xenbus/init.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-- frontend driver initializes static xenbus_driver with _ids, _probe, _remove,
-_resume, _otherend_changed
-
- - initialization calls xenbus_register_frontend(xenbus_driver)
-
- - xenbus_register_frontend sets read_otherend details to read_backend_details
- then calls xenbus_register_driver_common(xenbus_driver, xenbus_frontend)
-
- - xenbus_register_driver_common sets underlying driver name to xenbus_driver name
- underlying driver bus to xenbus_frontend's bus, driver's probe to xenbus_dev_probe
- driver's remove to xenbus_dev_remove then calls driver_register
-
diff --git a/sys/xen/xenbus/xenbus_client.c b/sys/xen/xenbus/xenbus.c
index 740d664..c3e5fee 100644
--- a/sys/xen/xenbus/xenbus_client.c
+++ b/sys/xen/xenbus/xenbus.c
@@ -1,8 +1,4 @@
/******************************************************************************
- * Client-facing interface for the Xenbus driver. In other words, the
- * interface between the Xenbus and the device-specific code, be it the
- * frontend or the backend of that driver.
- *
* Copyright (C) 2005 XenSource Ltd
*
* This file may be distributed separately from the Linux kernel, or
@@ -27,6 +23,14 @@
* IN THE SOFTWARE.
*/
+/**
+ * \file xenbus.c
+ *
+ * \brief Client-facing interface for the Xenbus driver.
+ *
+ * In other words, the interface between the Xenbus and the device-specific
+ * code, be it the frontend or the backend of that driver.
+ */
#if 0
#define DPRINTK(fmt, args...) \
@@ -39,9 +43,12 @@
__FBSDID("$FreeBSD$");
#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
#include <sys/types.h>
#include <sys/malloc.h>
#include <sys/libkern.h>
+#include <sys/sbuf.h>
#include <machine/xen/xen-os.h>
#include <xen/hypervisor.h>
@@ -50,6 +57,34 @@ __FBSDID("$FreeBSD$");
#include <xen/xenbus/xenbusvar.h>
#include <machine/stdarg.h>
+MALLOC_DEFINE(M_XENBUS, "xenbus", "XenBus Support");
+
+/*------------------------- Private Functions --------------------------------*/
+/**
+ * \brief Construct the error path corresponding to the given XenBus
+ * device.
+ *
+ * \param dev The XenBus device for which we are constructing an error path.
+ *
+ * \return On success, the contructed error path. Otherwise NULL.
+ *
+ * It is the caller's responsibility to free any returned error path
+ * node using the M_XENBUS malloc type.
+ */
+static char *
+error_path(device_t dev)
+{
+ char *path_buffer = malloc(strlen("error/")
+ + strlen(xenbus_get_node(dev)) + 1,M_XENBUS, M_WAITOK);
+
+ strcpy(path_buffer, "error/");
+ strcpy(path_buffer + strlen("error/"), xenbus_get_node(dev));
+
+ return (path_buffer);
+}
+
+/*--------------------------- Public Functions -------------------------------*/
+/*-------- API comments for these methods can be found in xenbusvar.h --------*/
const char *
xenbus_strstate(XenbusState state)
{
@@ -67,15 +102,15 @@ xenbus_strstate(XenbusState state)
}
int
-xenbus_watch_path(device_t dev, char *path, struct xenbus_watch *watch,
- void (*callback)(struct xenbus_watch *, const char **, unsigned int))
+xenbus_watch_path(device_t dev, char *path, struct xs_watch *watch,
+ xs_watch_cb_t *callback)
{
int error;
watch->node = path;
watch->callback = callback;
- error = register_xenbus_watch(watch);
+ error = xs_register_watch(watch);
if (error) {
watch->node = NULL;
@@ -88,12 +123,12 @@ xenbus_watch_path(device_t dev, char *path, struct xenbus_watch *watch,
int
xenbus_watch_path2(device_t dev, const char *path,
- const char *path2, struct xenbus_watch *watch,
- void (*callback)(struct xenbus_watch *, const char **, unsigned int))
+ const char *path2, struct xs_watch *watch,
+ xs_watch_cb_t *callback)
{
int error;
char *state = malloc(strlen(path) + 1 + strlen(path2) + 1,
- M_DEVBUF, M_WAITOK);
+ M_XENBUS, M_WAITOK);
strcpy(state, path);
strcat(state, "/");
@@ -101,46 +136,27 @@ xenbus_watch_path2(device_t dev, const char *path,
error = xenbus_watch_path(dev, state, watch, callback);
if (error) {
- free(state, M_DEVBUF);
+ free(state,M_XENBUS);
}
return (error);
}
-/**
- * Return the path to the error node for the given device, or NULL on failure.
- * If the value returned is non-NULL, then it is the caller's to kfree.
- */
-static char *
-error_path(device_t dev)
-{
- char *path_buffer = malloc(strlen("error/")
- + strlen(xenbus_get_node(dev)) + 1, M_DEVBUF, M_WAITOK);
-
- strcpy(path_buffer, "error/");
- strcpy(path_buffer + strlen("error/"), xenbus_get_node(dev));
-
- return (path_buffer);
-}
-
-
-static void
-_dev_error(device_t dev, int err, const char *fmt, va_list ap)
+void
+xenbus_dev_verror(device_t dev, int err, const char *fmt, va_list ap)
{
int ret;
unsigned int len;
char *printf_buffer = NULL, *path_buffer = NULL;
#define PRINTF_BUFFER_SIZE 4096
- printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_WAITOK);
+ printf_buffer = malloc(PRINTF_BUFFER_SIZE,M_XENBUS, M_WAITOK);
len = sprintf(printf_buffer, "%i ", err);
ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
KASSERT(len + ret <= PRINTF_BUFFER_SIZE-1, ("xenbus error message too big"));
-#if 0
- dev_err(&dev->dev, "%s\n", printf_buffer);
-#endif
+ device_printf(dev, "Error %s\n", printf_buffer);
path_buffer = error_path(dev);
if (path_buffer == NULL) {
@@ -149,7 +165,7 @@ _dev_error(device_t dev, int err, const char *fmt, va_list ap)
goto fail;
}
- if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
+ if (xs_write(XST_NIL, path_buffer, "error", printf_buffer) != 0) {
printf("xenbus: failed to write error node for %s (%s)\n",
xenbus_get_node(dev), printf_buffer);
goto fail;
@@ -157,9 +173,9 @@ _dev_error(device_t dev, int err, const char *fmt, va_list ap)
fail:
if (printf_buffer)
- free(printf_buffer, M_DEVBUF);
+ free(printf_buffer,M_XENBUS);
if (path_buffer)
- free(path_buffer, M_DEVBUF);
+ free(path_buffer,M_XENBUS);
}
void
@@ -168,41 +184,45 @@ xenbus_dev_error(device_t dev, int err, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- _dev_error(dev, err, fmt, ap);
+ xenbus_dev_verror(dev, err, fmt, ap);
va_end(ap);
}
void
+xenbus_dev_vfatal(device_t dev, int err, const char *fmt, va_list ap)
+{
+ xenbus_dev_verror(dev, err, fmt, ap);
+ device_printf(dev, "Fatal error. Transitioning to Closing State\n");
+ xenbus_set_state(dev, XenbusStateClosing);
+}
+
+void
xenbus_dev_fatal(device_t dev, int err, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- _dev_error(dev, err, fmt, ap);
+ xenbus_dev_vfatal(dev, err, fmt, ap);
va_end(ap);
-
- xenbus_set_state(dev, XenbusStateClosing);
}
int
-xenbus_grant_ring(device_t dev, unsigned long ring_mfn, int *refp)
+xenbus_grant_ring(device_t dev, unsigned long ring_mfn, grant_ref_t *refp)
{
int error;
- grant_ref_t ref;
error = gnttab_grant_foreign_access(
- xenbus_get_otherend_id(dev), ring_mfn, 0, &ref);
+ xenbus_get_otherend_id(dev), ring_mfn, 0, refp);
if (error) {
xenbus_dev_fatal(dev, error, "granting access to ring page");
return (error);
}
- *refp = ref;
return (0);
}
int
-xenbus_alloc_evtchn(device_t dev, int *port)
+xenbus_alloc_evtchn(device_t dev, evtchn_port_t *port)
{
struct evtchn_alloc_unbound alloc_unbound;
int err;
@@ -222,7 +242,7 @@ xenbus_alloc_evtchn(device_t dev, int *port)
}
int
-xenbus_free_evtchn(device_t dev, int port)
+xenbus_free_evtchn(device_t dev, evtchn_port_t port)
{
struct evtchn_close close;
int err;
@@ -240,12 +260,29 @@ xenbus_free_evtchn(device_t dev, int port)
XenbusState
xenbus_read_driver_state(const char *path)
{
- XenbusState result;
+ XenbusState result;
+ int error;
+
+ error = xs_gather(XST_NIL, path, "state", "%d", &result, NULL);
+ if (error)
+ result = XenbusStateClosed;
+
+ return (result);
+}
+
+int
+xenbus_dev_is_online(device_t dev)
+{
+ const char *path;
int error;
+ int value;
- error = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
- if (error)
- result = XenbusStateClosed;
+ path = xenbus_get_node(dev);
+ error = xs_gather(XST_NIL, path, "online", "%d", &value, NULL);
+ if (error != 0) {
+ /* Default to not online. */
+ value = 0;
+ }
- return (result);
+ return (value);
}
diff --git a/sys/xen/xenbus/xenbus_comms.c b/sys/xen/xenbus/xenbus_comms.c
deleted file mode 100644
index 2f03955..0000000
--- a/sys/xen/xenbus/xenbus_comms.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/******************************************************************************
- * xenbus_comms.c
- *
- * Low level code to talks to Xen Store: ringbuffer and event channel.
- *
- * Copyright (C) 2005 Rusty Russell, IBM Corporation
- *
- * This file may be distributed separately from the Linux kernel, or
- * incorporated into other software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/sx.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/syslog.h>
-
-#include <machine/xen/xen-os.h>
-#include <xen/hypervisor.h>
-
-#include <xen/xen_intr.h>
-#include <xen/evtchn.h>
-#include <xen/interface/io/xs_wire.h>
-#include <xen/xenbus/xenbus_comms.h>
-
-static unsigned int xenstore_irq;
-
-static inline struct xenstore_domain_interface *
-xenstore_domain_interface(void)
-{
-
- return (struct xenstore_domain_interface *)xen_store;
-}
-
-static void
-xb_intr(void * arg __attribute__((unused)))
-{
-
- wakeup(xen_store);
-}
-
-static int
-xb_check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
-{
-
- return ((prod - cons) <= XENSTORE_RING_SIZE);
-}
-
-static void *
-xb_get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod,
- char *buf, uint32_t *len)
-{
-
- *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
- if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
- *len = XENSTORE_RING_SIZE - (prod - cons);
- return (buf + MASK_XENSTORE_IDX(prod));
-}
-
-static const void *
-xb_get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod,
- const char *buf, uint32_t *len)
-{
-
- *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
- if ((prod - cons) < *len)
- *len = prod - cons;
- return (buf + MASK_XENSTORE_IDX(cons));
-}
-
-int
-xb_write(const void *tdata, unsigned len, struct lock_object *lock)
-{
- struct xenstore_domain_interface *intf = xenstore_domain_interface();
- XENSTORE_RING_IDX cons, prod;
- const char *data = (const char *)tdata;
- int error;
-
- while (len != 0) {
- void *dst;
- unsigned int avail;
-
- while ((intf->req_prod - intf->req_cons)
- == XENSTORE_RING_SIZE) {
- error = _sleep(intf,
- lock,
- PCATCH, "xbwrite", hz/10);
- if (error && error != EWOULDBLOCK)
- return (error);
- }
-
- /* Read indexes, then verify. */
- cons = intf->req_cons;
- prod = intf->req_prod;
- mb();
- if (!xb_check_indexes(cons, prod)) {
- intf->req_cons = intf->req_prod = 0;
- return (EIO);
- }
-
- dst = xb_get_output_chunk(cons, prod, intf->req, &avail);
- if (avail == 0)
- continue;
- if (avail > len)
- avail = len;
- mb();
-
- memcpy(dst, data, avail);
- data += avail;
- len -= avail;
-
- /* Other side must not see new header until data is there. */
- wmb();
- intf->req_prod += avail;
-
- /* This implies mb() before other side sees interrupt. */
- notify_remote_via_evtchn(xen_store_evtchn);
- }
-
- return (0);
-}
-
-int
-xb_read(void *tdata, unsigned len, struct lock_object *lock)
-{
- struct xenstore_domain_interface *intf = xenstore_domain_interface();
- XENSTORE_RING_IDX cons, prod;
- char *data = (char *)tdata;
- int error;
-
- while (len != 0) {
- unsigned int avail;
- const char *src;
-
- while (intf->rsp_cons == intf->rsp_prod) {
- error = _sleep(intf, lock,
- PCATCH, "xbread", hz/10);
- if (error && error != EWOULDBLOCK)
- return (error);
- }
-
- /* Read indexes, then verify. */
- cons = intf->rsp_cons;
- prod = intf->rsp_prod;
- if (!xb_check_indexes(cons, prod)) {
- intf->rsp_cons = intf->rsp_prod = 0;
- return (EIO);
- }
-
- src = xb_get_input_chunk(cons, prod, intf->rsp, &avail);
- if (avail == 0)
- continue;
- if (avail > len)
- avail = len;
-
- /* We must read header before we read data. */
- rmb();
-
- memcpy(data, src, avail);
- data += avail;
- len -= avail;
-
- /* Other side must not see free space until we've copied out */
- mb();
- intf->rsp_cons += avail;
-
- /* Implies mb(): they will see new header. */
- notify_remote_via_evtchn(xen_store_evtchn);
- }
-
- return (0);
-}
-
-/* Set up interrupt handler off store event channel. */
-int
-xb_init_comms(void)
-{
- struct xenstore_domain_interface *intf = xenstore_domain_interface();
- int error;
-
- if (intf->rsp_prod != intf->rsp_cons) {
- log(LOG_WARNING, "XENBUS response ring is not quiescent "
- "(%08x:%08x): fixing up\n",
- intf->rsp_cons, intf->rsp_prod);
- intf->rsp_cons = intf->rsp_prod;
- }
-
- if (xenstore_irq)
- unbind_from_irqhandler(xenstore_irq);
-
- error = bind_caller_port_to_irqhandler(
- xen_store_evtchn, "xenbus",
- xb_intr, NULL, INTR_TYPE_NET, &xenstore_irq);
- if (error) {
- log(LOG_WARNING, "XENBUS request irq failed %i\n", error);
- return (error);
- }
-
- return (0);
-}
diff --git a/sys/xen/xenbus/xenbus_comms.h b/sys/xen/xenbus/xenbus_comms.h
deleted file mode 100644
index fa47331..0000000
--- a/sys/xen/xenbus/xenbus_comms.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Private include for xenbus communications.
- *
- * Copyright (C) 2005 Rusty Russell, IBM Corporation
- *
- * This file may be distributed separately from the Linux kernel, or
- * incorporated into other software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * $FreeBSD$
- */
-
-#ifndef _XENBUS_COMMS_H
-#define _XENBUS_COMMS_H
-
-struct sx;
-extern int xen_store_evtchn;
-extern char *xen_store;
-
-int xs_init(void);
-int xb_init_comms(void);
-
-/* Low level routines. */
-int xb_write(const void *data, unsigned len, struct lock_object *);
-int xb_read(void *data, unsigned len, struct lock_object *);
-extern int xenbus_running;
-
-char *kasprintf(const char *fmt, ...);
-
-
-#endif /* _XENBUS_COMMS_H */
diff --git a/sys/xen/xenbus/xenbus_dev.c b/sys/xen/xenbus/xenbus_dev.c
deleted file mode 100644
index ac3f103..0000000
--- a/sys/xen/xenbus/xenbus_dev.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * xenbus_dev.c
- *
- * Driver giving user-space access to the kernel's xenbus connection
- * to xenstore.
- *
- * Copyright (c) 2005, Christian Limpach
- * Copyright (c) 2005, Rusty Russell, IBM Corporation
- *
- * This file may be distributed separately from the Linux kernel, or
- * incorporated into other software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/cdefs.h>
-#include <sys/errno.h>
-#include <sys/uio.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/proc.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/conf.h>
-
-#include <machine/xen/xen-os.h>
-#include <xen/hypervisor.h>
-#include <xen/xenbus/xenbusvar.h>
-#include <xen/xenbus/xenbus_comms.h>
-
-struct xenbus_dev_transaction {
- LIST_ENTRY(xenbus_dev_transaction) list;
- struct xenbus_transaction handle;
-};
-
-struct xenbus_dev_data {
- /* In-progress transaction. */
- LIST_HEAD(xdd_list_head, xenbus_dev_transaction) transactions;
-
- /* Partial request. */
- unsigned int len;
- union {
- struct xsd_sockmsg msg;
- char buffer[PAGE_SIZE];
- } u;
-
- /* Response queue. */
-#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
- char read_buffer[PAGE_SIZE];
- unsigned int read_cons, read_prod;
-};
-
-static int
-xenbus_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
-{
- int error;
- struct xenbus_dev_data *u = dev->si_drv1;
-
- while (u->read_prod == u->read_cons) {
- error = tsleep(u, PCATCH, "xbdread", hz/10);
- if (error && error != EWOULDBLOCK)
- return (error);
- }
-
- while (uio->uio_resid > 0) {
- if (u->read_cons == u->read_prod)
- break;
- error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
- 1, uio);
- if (error)
- return (error);
- u->read_cons++;
- }
- return (0);
-}
-
-static void
-queue_reply(struct xenbus_dev_data *u, char *data, unsigned int len)
-{
- int i;
-
- for (i = 0; i < len; i++, u->read_prod++)
- u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
-
- KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer),
- ("xenstore reply too big"));
-
- wakeup(u);
-}
-
-static int
-xenbus_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
-{
- int error;
- struct xenbus_dev_data *u = dev->si_drv1;
- struct xenbus_dev_transaction *trans;
- void *reply;
- int len = uio->uio_resid;
-
- if ((len + u->len) > sizeof(u->u.buffer))
- return (EINVAL);
-
- error = uiomove(u->u.buffer + u->len, len, uio);
- if (error)
- return (error);
-
- u->len += len;
- if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
- return (0);
-
- switch (u->u.msg.type) {
- case XS_TRANSACTION_START:
- case XS_TRANSACTION_END:
- case XS_DIRECTORY:
- case XS_READ:
- case XS_GET_PERMS:
- case XS_RELEASE:
- case XS_GET_DOMAIN_PATH:
- case XS_WRITE:
- case XS_MKDIR:
- case XS_RM:
- case XS_SET_PERMS:
- error = xenbus_dev_request_and_reply(&u->u.msg, &reply);
- if (!error) {
- if (u->u.msg.type == XS_TRANSACTION_START) {
- trans = malloc(sizeof(*trans), M_DEVBUF,
- M_WAITOK);
- trans->handle.id = strtoul(reply, NULL, 0);
- LIST_INSERT_HEAD(&u->transactions, trans, list);
- } else if (u->u.msg.type == XS_TRANSACTION_END) {
- LIST_FOREACH(trans, &u->transactions, list)
- if (trans->handle.id == u->u.msg.tx_id)
- break;
-#if 0 /* XXX does this mean the list is empty? */
- BUG_ON(&trans->list == &u->transactions);
-#endif
- LIST_REMOVE(trans, list);
- free(trans, M_DEVBUF);
- }
- queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
- queue_reply(u, (char *)reply, u->u.msg.len);
- free(reply, M_DEVBUF);
- }
- break;
-
- default:
- error = EINVAL;
- break;
- }
-
- if (error == 0)
- u->len = 0;
-
- return (error);
-}
-
-static int
-xenbus_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
-{
- struct xenbus_dev_data *u;
-
- if (xen_store_evtchn == 0)
- return (ENOENT);
-#if 0 /* XXX figure out if equiv needed */
- nonseekable_open(inode, filp);
-#endif
- u = malloc(sizeof(*u), M_DEVBUF, M_WAITOK|M_ZERO);
- LIST_INIT(&u->transactions);
- dev->si_drv1 = u;
-
- return (0);
-}
-
-static int
-xenbus_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
-{
- struct xenbus_dev_data *u = dev->si_drv1;
- struct xenbus_dev_transaction *trans, *tmp;
-
- LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) {
- xenbus_transaction_end(trans->handle, 1);
- LIST_REMOVE(trans, list);
- free(trans, M_DEVBUF);
- }
-
- free(u, M_DEVBUF);
- return (0);
-}
-
-static struct cdevsw xenbus_dev_cdevsw = {
- .d_version = D_VERSION,
- .d_read = xenbus_dev_read,
- .d_write = xenbus_dev_write,
- .d_open = xenbus_dev_open,
- .d_close = xenbus_dev_close,
- .d_name = "xenbus_dev",
-};
-
-static int
-xenbus_dev_sysinit(void)
-{
- make_dev(&xenbus_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400,
- "xen/xenbus");
-
- return (0);
-}
-SYSINIT(xenbus_dev_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
- xenbus_dev_sysinit, NULL);
diff --git a/sys/xen/xenbus/xenbus_if.m b/sys/xen/xenbus/xenbus_if.m
index 018a2bb..d671418 100644
--- a/sys/xen/xenbus/xenbus_if.m
+++ b/sys/xen/xenbus/xenbus_if.m
@@ -31,7 +31,15 @@
INTERFACE xenbus;
-METHOD int backend_changed {
- device_t dev;
- enum xenbus_state newstate;
+/**
+ * \brief Callback triggered when the state of the otherend
+ * of a split device changes.
+ *
+ * \param _dev NewBus device_t for this XenBus device whose otherend's
+ * state has changed..
+ * \param _newstate The new state of the otherend device.
+ */
+METHOD int otherend_changed {
+ device_t _dev;
+ enum xenbus_state _newstate;
};
diff --git a/sys/xen/xenbus/xenbus_probe.c b/sys/xen/xenbus/xenbus_probe.c
deleted file mode 100644
index b1e9a21..0000000
--- a/sys/xen/xenbus/xenbus_probe.c
+++ /dev/null
@@ -1,602 +0,0 @@
-/******************************************************************************
- * Talks to Xen Store to figure out what devices we have.
- *
- * Copyright (C) 2008 Doug Rabson
- * Copyright (C) 2005 Rusty Russell, IBM Corporation
- * Copyright (C) 2005 Mike Wray, Hewlett-Packard
- * Copyright (C) 2005 XenSource Ltd
- *
- * This file may be distributed separately from the Linux kernel, or
- * incorporated into other software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#if 0
-#define DPRINTK(fmt, args...) \
- printf("xenbus_probe (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
-#else
-#define DPRINTK(fmt, args...) ((void)0)
-#endif
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/sysctl.h>
-#include <sys/syslog.h>
-#include <sys/systm.h>
-#include <sys/sx.h>
-#include <sys/taskqueue.h>
-
-#include <machine/xen/xen-os.h>
-#include <machine/stdarg.h>
-
-#include <xen/gnttab.h>
-#include <xen/xenbus/xenbusvar.h>
-#include <xen/xenbus/xenbus_comms.h>
-
-struct xenbus_softc {
- struct xenbus_watch xs_devicewatch;
- struct task xs_probechildren;
- struct intr_config_hook xs_attachcb;
- device_t xs_dev;
-};
-
-struct xenbus_device_ivars {
- struct xenbus_watch xd_otherend_watch; /* must be first */
- struct sx xd_lock;
- device_t xd_dev;
- char *xd_node; /* node name in xenstore */
- char *xd_type; /* xen device type */
- enum xenbus_state xd_state;
- int xd_otherend_id;
- char *xd_otherend_path;
-};
-
-/* Simplified asprintf. */
-char *
-kasprintf(const char *fmt, ...)
-{
- va_list ap;
- unsigned int len;
- char *p, dummy[1];
-
- va_start(ap, fmt);
- /* FIXME: vsnprintf has a bug, NULL should work */
- len = vsnprintf(dummy, 0, fmt, ap);
- va_end(ap);
-
- p = malloc(len + 1, M_DEVBUF, M_WAITOK);
- va_start(ap, fmt);
- vsprintf(p, fmt, ap);
- va_end(ap);
- return p;
-}
-
-static void
-xenbus_identify(driver_t *driver, device_t parent)
-{
-
- BUS_ADD_CHILD(parent, 0, "xenbus", 0);
-}
-
-static int
-xenbus_probe(device_t dev)
-{
- int err = 0;
-
- DPRINTK("");
-
- /* Initialize the interface to xenstore. */
- err = xs_init();
- if (err) {
- log(LOG_WARNING,
- "XENBUS: Error initializing xenstore comms: %i\n", err);
- return (ENXIO);
- }
- err = gnttab_init();
- if (err) {
- log(LOG_WARNING,
- "XENBUS: Error initializing grant table: %i\n", err);
- return (ENXIO);
- }
- device_set_desc(dev, "Xen Devices");
-
- return (0);
-}
-
-static enum xenbus_state
-xenbus_otherend_state(struct xenbus_device_ivars *ivars)
-{
-
- return (xenbus_read_driver_state(ivars->xd_otherend_path));
-}
-
-static void
-xenbus_backend_changed(struct xenbus_watch *watch, const char **vec,
- unsigned int len)
-{
- struct xenbus_device_ivars *ivars;
- device_t dev;
- enum xenbus_state newstate;
-
- ivars = (struct xenbus_device_ivars *) watch;
- dev = ivars->xd_dev;
-
- if (!ivars->xd_otherend_path
- || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH],
- strlen(ivars->xd_otherend_path)))
- return;
-
- newstate = xenbus_otherend_state(ivars);
- XENBUS_BACKEND_CHANGED(dev, newstate);
-}
-
-static int
-xenbus_device_exists(device_t dev, const char *node)
-{
- device_t *kids;
- struct xenbus_device_ivars *ivars;
- int i, count, result;
-
- if (device_get_children(dev, &kids, &count))
- return (FALSE);
-
- result = FALSE;
- for (i = 0; i < count; i++) {
- ivars = device_get_ivars(kids[i]);
- if (!strcmp(ivars->xd_node, node)) {
- result = TRUE;
- break;
- }
- }
- free(kids, M_TEMP);
-
- return (result);
-}
-
-static int
-xenbus_add_device(device_t dev, const char *bus,
- const char *type, const char *id)
-{
- device_t child;
- struct xenbus_device_ivars *ivars;
- enum xenbus_state state;
- char *statepath;
- int error;
-
- ivars = malloc(sizeof(struct xenbus_device_ivars),
- M_DEVBUF, M_ZERO|M_WAITOK);
- ivars->xd_node = kasprintf("%s/%s/%s", bus, type, id);
-
- if (xenbus_device_exists(dev, ivars->xd_node)) {
- /*
- * We are already tracking this node
- */
- free(ivars->xd_node, M_DEVBUF);
- free(ivars, M_DEVBUF);
- return (0);
- }
-
- state = xenbus_read_driver_state(ivars->xd_node);
-
- if (state != XenbusStateInitialising) {
- /*
- * Device is not new, so ignore it. This can
- * happen if a device is going away after
- * switching to Closed.
- */
- free(ivars->xd_node, M_DEVBUF);
- free(ivars, M_DEVBUF);
- return (0);
- }
-
- /*
- * Find the backend details
- */
- error = xenbus_gather(XBT_NIL, ivars->xd_node,
- "backend-id", "%i", &ivars->xd_otherend_id,
- "backend", NULL, &ivars->xd_otherend_path,
- NULL);
- if (error)
- return (error);
-
- sx_init(&ivars->xd_lock, "xdlock");
- ivars->xd_type = strdup(type, M_DEVBUF);
- ivars->xd_state = XenbusStateInitialising;
-
- statepath = malloc(strlen(ivars->xd_otherend_path)
- + strlen("/state") + 1, M_DEVBUF, M_WAITOK);
- sprintf(statepath, "%s/state", ivars->xd_otherend_path);
-
- ivars->xd_otherend_watch.node = statepath;
- ivars->xd_otherend_watch.callback = xenbus_backend_changed;
-
- child = device_add_child(dev, NULL, -1);
- ivars->xd_dev = child;
- device_set_ivars(child, ivars);
-
- return (0);
-}
-
-static int
-xenbus_enumerate_type(device_t dev, const char *bus, const char *type)
-{
- char **dir;
- unsigned int i, count;
- int error;
-
- error = xenbus_directory(XBT_NIL, bus, type, &count, &dir);
- if (error)
- return (error);
- for (i = 0; i < count; i++)
- xenbus_add_device(dev, bus, type, dir[i]);
-
- free(dir, M_DEVBUF);
-
- return (0);
-}
-
-static int
-xenbus_enumerate_bus(device_t dev, const char *bus)
-{
- char **dir;
- unsigned int i, count;
- int error;
-
- error = xenbus_directory(XBT_NIL, bus, "", &count, &dir);
- if (error)
- return (error);
- for (i = 0; i < count; i++) {
- xenbus_enumerate_type(dev, bus, dir[i]);
- }
- free(dir, M_DEVBUF);
-
- return (0);
-}
-
-static int
-xenbus_probe_children(device_t dev)
-{
- device_t *kids;
- struct xenbus_device_ivars *ivars;
- int i, count;
-
- /*
- * Probe any new devices and register watches for any that
- * attach successfully. Since part of the protocol which
- * establishes a connection with the other end is interrupt
- * driven, we sleep until the device reaches a stable state
- * (closed or connected).
- */
- if (device_get_children(dev, &kids, &count) == 0) {
- for (i = 0; i < count; i++) {
- if (device_get_state(kids[i]) != DS_NOTPRESENT)
- continue;
-
- if (device_probe_and_attach(kids[i]))
- continue;
- ivars = device_get_ivars(kids[i]);
- register_xenbus_watch(
- &ivars->xd_otherend_watch);
- sx_xlock(&ivars->xd_lock);
- while (ivars->xd_state != XenbusStateClosed
- && ivars->xd_state != XenbusStateConnected)
- sx_sleep(&ivars->xd_state, &ivars->xd_lock,
- 0, "xdattach", 0);
- sx_xunlock(&ivars->xd_lock);
- }
- free(kids, M_TEMP);
- }
-
- return (0);
-}
-
-static void
-xenbus_probe_children_cb(void *arg, int pending)
-{
- device_t dev = (device_t) arg;
-
- xenbus_probe_children(dev);
-}
-
-static void
-xenbus_devices_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
-{
- struct xenbus_softc *sc = (struct xenbus_softc *) watch;
- device_t dev = sc->xs_dev;
- char *node, *bus, *type, *id, *p;
-
- node = strdup(vec[XS_WATCH_PATH], M_DEVBUF);
- p = strchr(node, '/');
- if (!p)
- goto out;
- bus = node;
- *p = 0;
- type = p + 1;
-
- p = strchr(type, '/');
- if (!p)
- goto out;
- *p = 0;
- id = p + 1;
-
- p = strchr(id, '/');
- if (p)
- *p = 0;
-
- xenbus_add_device(dev, bus, type, id);
- taskqueue_enqueue(taskqueue_thread, &sc->xs_probechildren);
-out:
- free(node, M_DEVBUF);
-}
-
-static void
-xenbus_attach_deferred(void *arg)
-{
- device_t dev = (device_t) arg;
- struct xenbus_softc *sc = device_get_softc(dev);
- int error;
-
- error = xenbus_enumerate_bus(dev, "device");
- if (error)
- return;
- xenbus_probe_children(dev);
-
- sc->xs_dev = dev;
- sc->xs_devicewatch.node = "device";
- sc->xs_devicewatch.callback = xenbus_devices_changed;
-
- TASK_INIT(&sc->xs_probechildren, 0, xenbus_probe_children_cb, dev);
-
- register_xenbus_watch(&sc->xs_devicewatch);
-
- config_intrhook_disestablish(&sc->xs_attachcb);
-}
-
-static int
-xenbus_attach(device_t dev)
-{
- struct xenbus_softc *sc = device_get_softc(dev);
-
- sc->xs_attachcb.ich_func = xenbus_attach_deferred;
- sc->xs_attachcb.ich_arg = dev;
- config_intrhook_establish(&sc->xs_attachcb);
-
- return (0);
-}
-
-static int
-xenbus_suspend(device_t dev)
-{
- int error;
-
- DPRINTK("");
-
- error = bus_generic_suspend(dev);
- if (error)
- return (error);
-
- xs_suspend();
-
- return (0);
-}
-
-static int
-xenbus_resume(device_t dev)
-{
- device_t *kids;
- struct xenbus_device_ivars *ivars;
- int i, count, error;
- char *statepath;
-
- xb_init_comms();
- xs_resume();
-
- /*
- * We must re-examine each device and find the new path for
- * its backend.
- */
- if (device_get_children(dev, &kids, &count) == 0) {
- for (i = 0; i < count; i++) {
- if (device_get_state(kids[i]) == DS_NOTPRESENT)
- continue;
-
- ivars = device_get_ivars(kids[i]);
-
- unregister_xenbus_watch(
- &ivars->xd_otherend_watch);
- ivars->xd_state = XenbusStateInitialising;
-
- /*
- * Find the new backend details and
- * re-register our watch.
- */
- free(ivars->xd_otherend_path, M_DEVBUF);
- error = xenbus_gather(XBT_NIL, ivars->xd_node,
- "backend-id", "%i", &ivars->xd_otherend_id,
- "backend", NULL, &ivars->xd_otherend_path,
- NULL);
- if (error)
- return (error);
-
- DEVICE_RESUME(kids[i]);
-
- statepath = malloc(strlen(ivars->xd_otherend_path)
- + strlen("/state") + 1, M_DEVBUF, M_WAITOK);
- sprintf(statepath, "%s/state", ivars->xd_otherend_path);
-
- free(ivars->xd_otherend_watch.node, M_DEVBUF);
- ivars->xd_otherend_watch.node = statepath;
- register_xenbus_watch(
- &ivars->xd_otherend_watch);
-
-#if 0
- /*
- * Can't do this yet since we are running in
- * the xenwatch thread and if we sleep here,
- * we will stop delivering watch notifications
- * and the device will never come back online.
- */
- sx_xlock(&ivars->xd_lock);
- while (ivars->xd_state != XenbusStateClosed
- && ivars->xd_state != XenbusStateConnected)
- sx_sleep(&ivars->xd_state, &ivars->xd_lock,
- 0, "xdresume", 0);
- sx_xunlock(&ivars->xd_lock);
-#endif
- }
- free(kids, M_TEMP);
- }
-
- return (0);
-}
-
-static int
-xenbus_print_child(device_t dev, device_t child)
-{
- struct xenbus_device_ivars *ivars = device_get_ivars(child);
- int retval = 0;
-
- retval += bus_print_child_header(dev, child);
- retval += printf(" at %s", ivars->xd_node);
- retval += bus_print_child_footer(dev, child);
-
- return (retval);
-}
-
-static int
-xenbus_read_ivar(device_t dev, device_t child, int index,
- uintptr_t * result)
-{
- struct xenbus_device_ivars *ivars = device_get_ivars(child);
-
- switch (index) {
- case XENBUS_IVAR_NODE:
- *result = (uintptr_t) ivars->xd_node;
- return (0);
-
- case XENBUS_IVAR_TYPE:
- *result = (uintptr_t) ivars->xd_type;
- return (0);
-
- case XENBUS_IVAR_STATE:
- *result = (uintptr_t) ivars->xd_state;
- return (0);
-
- case XENBUS_IVAR_OTHEREND_ID:
- *result = (uintptr_t) ivars->xd_otherend_id;
- return (0);
-
- case XENBUS_IVAR_OTHEREND_PATH:
- *result = (uintptr_t) ivars->xd_otherend_path;
- return (0);
- }
-
- return (ENOENT);
-}
-
-static int
-xenbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
-{
- struct xenbus_device_ivars *ivars = device_get_ivars(child);
- enum xenbus_state newstate;
- int currstate;
- int error;
-
- switch (index) {
- case XENBUS_IVAR_STATE:
- newstate = (enum xenbus_state) value;
- sx_xlock(&ivars->xd_lock);
- if (ivars->xd_state == newstate)
- goto out;
-
- error = xenbus_scanf(XBT_NIL, ivars->xd_node, "state",
- NULL, "%d", &currstate);
- if (error)
- goto out;
-
- error = xenbus_printf(XBT_NIL, ivars->xd_node, "state",
- "%d", newstate);
- if (error) {
- if (newstate != XenbusStateClosing) /* Avoid looping */
- xenbus_dev_fatal(dev, error, "writing new state");
- goto out;
- }
- ivars->xd_state = newstate;
- wakeup(&ivars->xd_state);
- out:
- sx_xunlock(&ivars->xd_lock);
- return (0);
-
- case XENBUS_IVAR_NODE:
- case XENBUS_IVAR_TYPE:
- case XENBUS_IVAR_OTHEREND_ID:
- case XENBUS_IVAR_OTHEREND_PATH:
- /*
- * These variables are read-only.
- */
- return (EINVAL);
- }
-
- return (ENOENT);
-}
-
-SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen");
-SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xen_store_evtchn, 0, "");
-SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, "");
-
-static device_method_t xenbus_methods[] = {
- /* Device interface */
- DEVMETHOD(device_identify, xenbus_identify),
- DEVMETHOD(device_probe, xenbus_probe),
- DEVMETHOD(device_attach, xenbus_attach),
- DEVMETHOD(device_detach, bus_generic_detach),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
- DEVMETHOD(device_suspend, xenbus_suspend),
- DEVMETHOD(device_resume, xenbus_resume),
-
- /* Bus interface */
- DEVMETHOD(bus_print_child, xenbus_print_child),
- DEVMETHOD(bus_read_ivar, xenbus_read_ivar),
- DEVMETHOD(bus_write_ivar, xenbus_write_ivar),
-
- { 0, 0 }
-};
-
-static char driver_name[] = "xenbus";
-static driver_t xenbus_driver = {
- driver_name,
- xenbus_methods,
- sizeof(struct xenbus_softc),
-};
-devclass_t xenbus_devclass;
-
-#ifdef XENHVM
-DRIVER_MODULE(xenbus, xenpci, xenbus_driver, xenbus_devclass, 0, 0);
-#else
-DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0);
-#endif
diff --git a/sys/xen/xenbus/xenbus_probe_backend.c b/sys/xen/xenbus/xenbus_probe_backend.c
deleted file mode 100644
index 20cc49f..0000000
--- a/sys/xen/xenbus/xenbus_probe_backend.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/******************************************************************************
- * Talks to Xen Store to figure out what devices we have (backend half).
- *
- * Copyright (C) 2005 Rusty Russell, IBM Corporation
- * Copyright (C) 2005 Mike Wray, Hewlett-Packard
- * Copyright (C) 2005, 2006 XenSource Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#if 0
-#define DPRINTK(fmt, args...) \
- printf("xenbus_probe (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
-#else
-#define DPRINTK(fmt, args...) ((void)0)
-#endif
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/cdefs.h>
-#include <sys/time.h>
-#include <sys/sema.h>
-#include <sys/eventhandler.h>
-#include <sys/errno.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/conf.h>
-#include <sys/systm.h>
-#include <sys/syslog.h>
-#include <sys/proc.h>
-#include <sys/bus.h>
-#include <sys/sx.h>
-
-#include <machine/xen/xen-os.h>
-#include <xen/hypervisor.h>
-#include <machine/xen/xenbus.h>
-#include <machine/stdarg.h>
-
-#include <xen/evtchn.h>
-#include <xen/xenbus/xenbus_comms.h>
-
-#define BUG_ON PANIC_IF
-#define semaphore sema
-#define rw_semaphore sema
-#define DEFINE_SPINLOCK(lock) struct mtx lock
-#define DECLARE_MUTEX(lock) struct sema lock
-#define u32 uint32_t
-#define list_del(head, ent) TAILQ_REMOVE(head, ent, list)
-#define simple_strtoul strtoul
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-#define list_empty TAILQ_EMPTY
-
-extern struct xendev_list_head xenbus_device_backend_list;
-#if 0
-static int xenbus_uevent_backend(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
-#endif
-static int xenbus_probe_backend(const char *type, const char *domid);
-
-static int read_frontend_details(struct xenbus_device *xendev)
-{
- return read_otherend_details(xendev, "frontend-id", "frontend");
-}
-
-/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
-static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
-{
- int domid, err;
- const char *devid, *type, *frontend;
- unsigned int typelen;
-
- type = strchr(nodename, '/');
- if (!type)
- return -EINVAL;
- type++;
- typelen = strcspn(type, "/");
- if (!typelen || type[typelen] != '/')
- return -EINVAL;
-
- devid = strrchr(nodename, '/') + 1;
-
- err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
- "frontend", NULL, &frontend,
- NULL);
- if (err)
- return err;
- if (strlen(frontend) == 0)
- err = -ERANGE;
- if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
- err = -ENOENT;
- kfree(frontend);
-
- if (err)
- return err;
-
- if (snprintf(bus_id, BUS_ID_SIZE,
- "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
- return -ENOSPC;
- return 0;
-}
-
-static struct xen_bus_type xenbus_backend = {
- .root = "backend",
- .levels = 3, /* backend/type/<frontend>/<id> */
- .get_bus_id = backend_bus_id,
- .probe = xenbus_probe_backend,
- .bus = &xenbus_device_backend_list,
-
-#if 0
- .error = -ENODEV,
- .bus = {
- .name = "xen-backend",
- .match = xenbus_match,
- .probe = xenbus_dev_probe,
- .remove = xenbus_dev_remove,
-// .shutdown = xenbus_dev_shutdown,
- .uevent = xenbus_uevent_backend,
- },
- .dev = {
- .bus_id = "xen-backend",
- },
-#endif
-};
-
-#if 0
-static int xenbus_uevent_backend(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
-{
- struct xenbus_device *xdev;
- struct xenbus_driver *drv;
- int i = 0;
- int length = 0;
-
- DPRINTK("");
-
- if (dev == NULL)
- return -ENODEV;
-
- xdev = to_xenbus_device(dev);
- if (xdev == NULL)
- return -ENODEV;
-2
- /* stuff we want to pass to /sbin/hotplug */
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "XENBUS_TYPE=%s", xdev->devicetype);
-
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "XENBUS_PATH=%s", xdev->nodename);
-
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "XENBUS_BASE_PATH=%s", xenbus_backend.root);
-
- /* terminate, set to next free slot, shrink available space */
- envp[i] = NULL;
- envp = &envp[i];
- num_envp -= i;
- buffer = &buffer[length];
- buffer_size -= length;
-
- if (dev->driver) {
- drv = to_xenbus_driver(dev->driver);
- if (drv && drv->uevent)
- return drv->uevent(xdev, envp, num_envp, buffer,
- buffer_size);
- }
-
- return 0;
-}
-#endif
-
-int xenbus_register_backend(struct xenbus_driver *drv)
-{
- drv->read_otherend_details = read_frontend_details;
-
- return xenbus_register_driver_common(drv, &xenbus_backend);
-}
-
-/* backend/<typename>/<frontend-uuid>/<name> */
-static int xenbus_probe_backend_unit(const char *dir,
- const char *type,
- const char *name)
-{
- char *nodename;
- int err;
-
- nodename = kasprintf("%s/%s", dir, name);
- if (!nodename)
- return -ENOMEM;
-
- DPRINTK("%s\n", nodename);
-
- err = xenbus_probe_node(&xenbus_backend, type, nodename);
- kfree(nodename);
- return err;
-}
-
-/* backend/<typename>/<frontend-domid> */
-static int xenbus_probe_backend(const char *type, const char *domid)
-{
- char *nodename;
- int err = 0;
- char **dir;
- unsigned int i, dir_n = 0;
-
- DPRINTK("");
-
- nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, domid);
- if (!nodename)
- return -ENOMEM;
-
- dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
- if (IS_ERR(dir)) {
- kfree(nodename);
- return PTR_ERR(dir);
- }
-
- for (i = 0; i < dir_n; i++) {
- err = xenbus_probe_backend_unit(nodename, type, dir[i]);
- if (err)
- break;
- }
- kfree(dir);
- kfree(nodename);
- return err;
-}
-
-static void backend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
-{
- DPRINTK("");
-
- dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
-}
-
-static struct xenbus_watch be_watch = {
- .node = "backend",
- .callback = backend_changed,
-};
-#if 0
-void xenbus_backend_suspend(int (*fn)(struct device *, void *))
-{
- DPRINTK("");
- if (!xenbus_backend.error)
- bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
-}
-
-void xenbus_backend_resume(int (*fn)(struct device *, void *))
-{
- DPRINTK("");
- if (!xenbus_backend.error)
- bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
-}
-#endif
-void xenbus_backend_probe_and_watch(void)
-{
- xenbus_probe_devices(&xenbus_backend);
- register_xenbus_watch(&be_watch);
-}
-
-#if 0
-void xenbus_backend_bus_register(void)
-{
- xenbus_backend.error = bus_register(&xenbus_backend.bus);
- if (xenbus_backend.error)
- log(LOG_WARNING,
- "XENBUS: Error registering backend bus: %i\n",
- xenbus_backend.error);
-}
-
-void xenbus_backend_device_register(void)
-{
- if (xenbus_backend.error)
- return;
-
- xenbus_backend.error = device_register(&xenbus_backend.dev);
- if (xenbus_backend.error) {
- bus_unregister(&xenbus_backend.bus);
- log(LOG_WARNING,
- "XENBUS: Error registering backend device: %i\n",
- xenbus_backend.error);
- }
-}
-#endif
diff --git a/sys/xen/xenbus/xenbus_xs.c b/sys/xen/xenbus/xenbus_xs.c
deleted file mode 100644
index 9312255..0000000
--- a/sys/xen/xenbus/xenbus_xs.c
+++ /dev/null
@@ -1,935 +0,0 @@
-/******************************************************************************
- * xenbus_xs.c
- *
- * This is the kernel equivalent of the "xs" library. We don't need everything
- * and we use xenbus_comms for communication.
- *
- * Copyright (C) 2005 Rusty Russell, IBM Corporation
- *
- * This file may be distributed separately from the Linux kernel, or
- * incorporated into other software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/uio.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/sx.h>
-#include <sys/syslog.h>
-#include <sys/malloc.h>
-#include <sys/systm.h>
-#include <sys/proc.h>
-#include <sys/kthread.h>
-#include <sys/unistd.h>
-
-#include <machine/xen/xen-os.h>
-#include <xen/hypervisor.h>
-#include <machine/stdarg.h>
-
-#include <xen/xenbus/xenbusvar.h>
-#include <xen/xenbus/xenbus_comms.h>
-#include <xen/interface/hvm/params.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-
-static int xs_process_msg(enum xsd_sockmsg_type *type);
-
-int xenwatch_running = 0;
-int xenbus_running = 0;
-int xen_store_evtchn;
-
-struct xs_stored_msg {
- TAILQ_ENTRY(xs_stored_msg) list;
-
- struct xsd_sockmsg hdr;
-
- union {
- /* Queued replies. */
- struct {
- char *body;
- } reply;
-
- /* Queued watch events. */
- struct {
- struct xenbus_watch *handle;
- char **vec;
- unsigned int vec_size;
- } watch;
- } u;
-};
-
-struct xs_handle {
- /* A list of replies. Currently only one will ever be outstanding. */
- TAILQ_HEAD(xs_handle_list, xs_stored_msg) reply_list;
- struct mtx reply_lock;
- int reply_waitq;
-
- /* One request at a time. */
- struct sx request_mutex;
-
- /* Protect transactions against save/restore. */
- struct sx suspend_mutex;
-};
-
-static struct xs_handle xs_state;
-
-/* List of registered watches, and a lock to protect it. */
-static LIST_HEAD(watch_list_head, xenbus_watch) watches;
-static struct mtx watches_lock;
-/* List of pending watch callback events, and a lock to protect it. */
-static TAILQ_HEAD(event_list_head, xs_stored_msg) watch_events;
-static struct mtx watch_events_lock;
-
-/*
- * Details of the xenwatch callback kernel thread. The thread waits on the
- * watch_events_waitq for work to do (queued on watch_events list). When it
- * wakes up it acquires the xenwatch_mutex before reading the list and
- * carrying out work.
- */
-static pid_t xenwatch_pid;
-struct sx xenwatch_mutex;
-static int watch_events_waitq;
-
-#define xsd_error_count (sizeof(xsd_errors) / sizeof(xsd_errors[0]))
-
-static int
-xs_get_error(const char *errorstring)
-{
- unsigned int i;
-
- for (i = 0; i < xsd_error_count; i++) {
- if (!strcmp(errorstring, xsd_errors[i].errstring))
- return (xsd_errors[i].errnum);
- }
- log(LOG_WARNING, "XENBUS xen store gave: unknown error %s",
- errorstring);
- return (EINVAL);
-}
-
-extern void kdb_backtrace(void);
-
-static int
-xs_read_reply(enum xsd_sockmsg_type *type, unsigned int *len, void **result)
-{
- struct xs_stored_msg *msg;
- char *body;
- int error;
-
- mtx_lock(&xs_state.reply_lock);
-
- while (TAILQ_EMPTY(&xs_state.reply_list)) {
- while (TAILQ_EMPTY(&xs_state.reply_list)) {
- error = mtx_sleep(&xs_state.reply_waitq,
- &xs_state.reply_lock,
- PCATCH, "xswait", hz/10);
- if (error && error != EWOULDBLOCK) {
- mtx_unlock(&xs_state.reply_lock);
- return (error);
- }
- }
- }
-
- msg = TAILQ_FIRST(&xs_state.reply_list);
- TAILQ_REMOVE(&xs_state.reply_list, msg, list);
-
- mtx_unlock(&xs_state.reply_lock);
-
- *type = msg->hdr.type;
- if (len)
- *len = msg->hdr.len;
- body = msg->u.reply.body;
-
- free(msg, M_DEVBUF);
- *result = body;
- return (0);
-}
-
-#if 0
-/* Emergency write. UNUSED*/
-void xenbus_debug_write(const char *str, unsigned int count)
-{
- struct xsd_sockmsg msg = { 0 };
-
- msg.type = XS_DEBUG;
- msg.len = sizeof("print") + count + 1;
-
- sx_xlock(&xs_state.request_mutex);
- xb_write(&msg, sizeof(msg));
- xb_write("print", sizeof("print"));
- xb_write(str, count);
- xb_write("", 1);
- sx_xunlock(&xs_state.request_mutex);
-}
-
-#endif
-
-int
-xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void **result)
-{
- struct xsd_sockmsg req_msg = *msg;
- int error;
-
- if (req_msg.type == XS_TRANSACTION_START)
- sx_slock(&xs_state.suspend_mutex);
-
- sx_xlock(&xs_state.request_mutex);
-
- error = xb_write(msg, sizeof(*msg) + msg->len,
- &xs_state.request_mutex.lock_object);
- if (error) {
- msg->type = XS_ERROR;
- } else {
- error = xs_read_reply(&msg->type, &msg->len, result);
- }
-
- sx_xunlock(&xs_state.request_mutex);
-
- if ((msg->type == XS_TRANSACTION_END) ||
- ((req_msg.type == XS_TRANSACTION_START) &&
- (msg->type == XS_ERROR)))
- sx_sunlock(&xs_state.suspend_mutex);
-
- return (error);
-}
-
-/*
- * Send message to xs. The reply is returned in *result and should be
- * fred with free(*result, M_DEVBUF). Return zero on success or an
- * error code on failure.
- */
-static int
-xs_talkv(struct xenbus_transaction t, enum xsd_sockmsg_type type,
- const struct iovec *iovec, unsigned int num_vecs,
- unsigned int *len, void **result)
-{
- struct xsd_sockmsg msg;
- void *ret = NULL;
- unsigned int i;
- int error;
-
- msg.tx_id = t.id;
- msg.req_id = 0;
- msg.type = type;
- msg.len = 0;
- for (i = 0; i < num_vecs; i++)
- msg.len += iovec[i].iov_len;
-
- sx_xlock(&xs_state.request_mutex);
-
- error = xb_write(&msg, sizeof(msg),
- &xs_state.request_mutex.lock_object);
- if (error) {
- sx_xunlock(&xs_state.request_mutex);
- printf("xs_talkv failed %d\n", error);
- return (error);
- }
-
- for (i = 0; i < num_vecs; i++) {
- error = xb_write(iovec[i].iov_base, iovec[i].iov_len,
- &xs_state.request_mutex.lock_object);
- if (error) {
- sx_xunlock(&xs_state.request_mutex);
- printf("xs_talkv failed %d\n", error);
- return (error);
- }
- }
-
- error = xs_read_reply(&msg.type, len, &ret);
-
- sx_xunlock(&xs_state.request_mutex);
-
- if (error)
- return (error);
-
- if (msg.type == XS_ERROR) {
- error = xs_get_error(ret);
- free(ret, M_DEVBUF);
- return (error);
- }
-
-#if 0
- if ((xenwatch_running == 0) && (xenwatch_inline == 0)) {
- xenwatch_inline = 1;
- while (!TAILQ_EMPTY(&watch_events)
- && xenwatch_running == 0) {
-
- struct xs_stored_msg *wmsg = TAILQ_FIRST(&watch_events);
- TAILQ_REMOVE(&watch_events, wmsg, list);
-
- wmsg->u.watch.handle->callback(
- wmsg->u.watch.handle,
- (const char **)wmsg->u.watch.vec,
- wmsg->u.watch.vec_size);
- free(wmsg->u.watch.vec, M_DEVBUF);
- free(wmsg, M_DEVBUF);
- }
- xenwatch_inline = 0;
- }
-#endif
- KASSERT(msg.type == type, ("bad xenstore message type"));
-
- if (result)
- *result = ret;
- else
- free(ret, M_DEVBUF);
-
- return (0);
-}
-
-/* Simplified version of xs_talkv: single message. */
-static int
-xs_single(struct xenbus_transaction t, enum xsd_sockmsg_type type,
- const char *string, unsigned int *len, void **result)
-{
- struct iovec iovec;
-
- iovec.iov_base = (void *)(uintptr_t) string;
- iovec.iov_len = strlen(string) + 1;
-
- return (xs_talkv(t, type, &iovec, 1, len, result));
-}
-
-static unsigned int
-count_strings(const char *strings, unsigned int len)
-{
- unsigned int num;
- const char *p;
-
- for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
- num++;
-
- return num;
-}
-
-/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
-static char *
-join(const char *dir, const char *name)
-{
- char *buffer;
-
- buffer = malloc(strlen(dir) + strlen("/") + strlen(name) + 1,
- M_DEVBUF, M_WAITOK);
-
- strcpy(buffer, dir);
- if (strcmp(name, "")) {
- strcat(buffer, "/");
- strcat(buffer, name);
- }
-
- return (buffer);
-}
-
-static char **
-split(char *strings, unsigned int len, unsigned int *num)
-{
- char *p, **ret;
-
- /* Count the strings. */
- *num = count_strings(strings, len) + 1;
-
- /* Transfer to one big alloc for easy freeing. */
- ret = malloc(*num * sizeof(char *) + len, M_DEVBUF, M_WAITOK);
- memcpy(&ret[*num], strings, len);
- free(strings, M_DEVBUF);
-
- strings = (char *)&ret[*num];
- for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
- ret[(*num)++] = p;
-
- ret[*num] = strings + len;
-
- return ret;
-}
-
-/*
- * Return the contents of a directory in *result which should be freed
- * with free(*result, M_DEVBUF).
- */
-int
-xenbus_directory(struct xenbus_transaction t, const char *dir,
- const char *node, unsigned int *num, char ***result)
-{
- char *strings, *path;
- unsigned int len = 0;
- int error;
-
- path = join(dir, node);
- error = xs_single(t, XS_DIRECTORY, path, &len, (void **) &strings);
- free(path, M_DEVBUF);
- if (error)
- return (error);
-
- *result = split(strings, len, num);
- return (0);
-}
-
-/*
- * Check if a path exists. Return 1 if it does.
- */
-int
-xenbus_exists(struct xenbus_transaction t, const char *dir, const char *node)
-{
- char **d;
- int error, dir_n;
-
- error = xenbus_directory(t, dir, node, &dir_n, &d);
- if (error)
- return (0);
- free(d, M_DEVBUF);
- return (1);
-}
-
-/*
- * Get the value of a single file. Returns the contents in *result
- * which should be freed with free(*result, M_DEVBUF) after use.
- * The length of the value in bytes is returned in *len.
- */
-int
-xenbus_read(struct xenbus_transaction t, const char *dir, const char *node,
- unsigned int *len, void **result)
-{
- char *path;
- void *ret;
- int error;
-
- path = join(dir, node);
- error = xs_single(t, XS_READ, path, len, &ret);
- free(path, M_DEVBUF);
- if (error)
- return (error);
- *result = ret;
- return (0);
-}
-
-/*
- * Write the value of a single file. Returns error on failure.
- */
-int
-xenbus_write(struct xenbus_transaction t, const char *dir, const char *node,
- const char *string)
-{
- char *path;
- struct iovec iovec[2];
- int error;
-
- path = join(dir, node);
-
- iovec[0].iov_base = (void *)(uintptr_t) path;
- iovec[0].iov_len = strlen(path) + 1;
- iovec[1].iov_base = (void *)(uintptr_t) string;
- iovec[1].iov_len = strlen(string);
-
- error = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL);
- free(path, M_DEVBUF);
-
- return (error);
-}
-
-/*
- * Create a new directory.
- */
-int
-xenbus_mkdir(struct xenbus_transaction t, const char *dir, const char *node)
-{
- char *path;
- int ret;
-
- path = join(dir, node);
- ret = xs_single(t, XS_MKDIR, path, NULL, NULL);
- free(path, M_DEVBUF);
-
- return (ret);
-}
-
-/*
- * Destroy a file or directory (directories must be empty).
- */
-int
-xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node)
-{
- char *path;
- int ret;
-
- path = join(dir, node);
- ret = xs_single(t, XS_RM, path, NULL, NULL);
- free(path, M_DEVBUF);
-
- return (ret);
-}
-
-/*
- * Start a transaction: changes by others will not be seen during this
- * transaction, and changes will not be visible to others until end.
- */
-int
-xenbus_transaction_start(struct xenbus_transaction *t)
-{
- char *id_str;
- int error;
-
- sx_slock(&xs_state.suspend_mutex);
- error = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL,
- (void **) &id_str);
- if (error) {
- sx_sunlock(&xs_state.suspend_mutex);
- return (error);
- }
-
- t->id = strtoul(id_str, NULL, 0);
- free(id_str, M_DEVBUF);
-
- return (0);
-}
-
-/*
- * End a transaction. If abandon is true, transaction is discarded
- * instead of committed.
- */
-int xenbus_transaction_end(struct xenbus_transaction t, int abort)
-{
- char abortstr[2];
- int error;
-
- if (abort)
- strcpy(abortstr, "F");
- else
- strcpy(abortstr, "T");
-
- error = xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL);
-
- sx_sunlock(&xs_state.suspend_mutex);
-
- return (error);
-}
-
-/* Single read and scanf: returns zero or errno. */
-int
-xenbus_scanf(struct xenbus_transaction t,
- const char *dir, const char *node, int *scancountp, const char *fmt, ...)
-{
- va_list ap;
- int error, ns;
- char *val;
-
- error = xenbus_read(t, dir, node, NULL, (void **) &val);
- if (error)
- return (error);
-
- va_start(ap, fmt);
- ns = vsscanf(val, fmt, ap);
- va_end(ap);
- free(val, M_DEVBUF);
- /* Distinctive errno. */
- if (ns == 0)
- return (ERANGE);
- if (scancountp)
- *scancountp = ns;
- return (0);
-}
-
-/* Single printf and write: returns zero or errno. */
-int
-xenbus_printf(struct xenbus_transaction t,
- const char *dir, const char *node, const char *fmt, ...)
-{
- va_list ap;
- int error, ret;
-#define PRINTF_BUFFER_SIZE 4096
- char *printf_buffer;
-
- printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_WAITOK);
-
- va_start(ap, fmt);
- ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
- va_end(ap);
-
- KASSERT(ret <= PRINTF_BUFFER_SIZE-1, ("xenbus_printf: message too large"));
- error = xenbus_write(t, dir, node, printf_buffer);
-
- free(printf_buffer, M_DEVBUF);
-
- return (error);
-}
-
-/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
-int
-xenbus_gather(struct xenbus_transaction t, const char *dir, ...)
-{
- va_list ap;
- const char *name;
- int error, i;
-
- for (i = 0; i < 10000; i++)
- HYPERVISOR_yield();
-
- va_start(ap, dir);
- error = 0;
- while (error == 0 && (name = va_arg(ap, char *)) != NULL) {
- const char *fmt = va_arg(ap, char *);
- void *result = va_arg(ap, void *);
- char *p;
-
- error = xenbus_read(t, dir, name, NULL, (void **) &p);
- if (error)
- break;
-
- if (fmt) {
- if (sscanf(p, fmt, result) == 0)
- error = EINVAL;
- free(p, M_DEVBUF);
- } else
- *(char **)result = p;
- }
- va_end(ap);
-
- return (error);
-}
-
-static int
-xs_watch(const char *path, const char *token)
-{
- struct iovec iov[2];
-
- iov[0].iov_base = (void *)(uintptr_t) path;
- iov[0].iov_len = strlen(path) + 1;
- iov[1].iov_base = (void *)(uintptr_t) token;
- iov[1].iov_len = strlen(token) + 1;
-
- return (xs_talkv(XBT_NIL, XS_WATCH, iov, 2, NULL, NULL));
-}
-
-static int
-xs_unwatch(const char *path, const char *token)
-{
- struct iovec iov[2];
-
- iov[0].iov_base = (void *)(uintptr_t) path;
- iov[0].iov_len = strlen(path) + 1;
- iov[1].iov_base = (void *)(uintptr_t) token;
- iov[1].iov_len = strlen(token) + 1;
-
- return (xs_talkv(XBT_NIL, XS_UNWATCH, iov, 2, NULL, NULL));
-}
-
-static struct xenbus_watch *
-find_watch(const char *token)
-{
- struct xenbus_watch *i, *cmp;
-
- cmp = (void *)strtoul(token, NULL, 16);
-
- LIST_FOREACH(i, &watches, list)
- if (i == cmp)
- return (i);
-
- return (NULL);
-}
-
-/* Register callback to watch this node. */
-int
-register_xenbus_watch(struct xenbus_watch *watch)
-{
- /* Pointer in ascii is the token. */
- char token[sizeof(watch) * 2 + 1];
- int error;
-
- sprintf(token, "%lX", (long)watch);
-
- sx_slock(&xs_state.suspend_mutex);
-
- mtx_lock(&watches_lock);
- KASSERT(find_watch(token) == NULL, ("watch already registered"));
- LIST_INSERT_HEAD(&watches, watch, list);
- mtx_unlock(&watches_lock);
-
- error = xs_watch(watch->node, token);
-
- /* Ignore errors due to multiple registration. */
- if (error == EEXIST) {
- mtx_lock(&watches_lock);
- LIST_REMOVE(watch, list);
- mtx_unlock(&watches_lock);
- }
-
- sx_sunlock(&xs_state.suspend_mutex);
-
- return (error);
-}
-
-void
-unregister_xenbus_watch(struct xenbus_watch *watch)
-{
- struct xs_stored_msg *msg, *tmp;
- char token[sizeof(watch) * 2 + 1];
- int error;
-
- sprintf(token, "%lX", (long)watch);
-
- sx_slock(&xs_state.suspend_mutex);
-
- mtx_lock(&watches_lock);
- KASSERT(find_watch(token), ("watch not registered"));
- LIST_REMOVE(watch, list);
- mtx_unlock(&watches_lock);
-
- error = xs_unwatch(watch->node, token);
- if (error)
- log(LOG_WARNING, "XENBUS Failed to release watch %s: %i\n",
- watch->node, error);
-
- sx_sunlock(&xs_state.suspend_mutex);
-
- /* Cancel pending watch events. */
- mtx_lock(&watch_events_lock);
- TAILQ_FOREACH_SAFE(msg, &watch_events, list, tmp) {
- if (msg->u.watch.handle != watch)
- continue;
- TAILQ_REMOVE(&watch_events, msg, list);
- free(msg->u.watch.vec, M_DEVBUF);
- free(msg, M_DEVBUF);
- }
- mtx_unlock(&watch_events_lock);
-
- /* Flush any currently-executing callback, unless we are it. :-) */
- if (curproc->p_pid != xenwatch_pid) {
- sx_xlock(&xenwatch_mutex);
- sx_xunlock(&xenwatch_mutex);
- }
-}
-
-void
-xs_suspend(void)
-{
-
- sx_xlock(&xs_state.suspend_mutex);
- sx_xlock(&xs_state.request_mutex);
-}
-
-void
-xs_resume(void)
-{
- struct xenbus_watch *watch;
- char token[sizeof(watch) * 2 + 1];
-
- sx_xunlock(&xs_state.request_mutex);
-
- /* No need for watches_lock: the suspend_mutex is sufficient. */
- LIST_FOREACH(watch, &watches, list) {
- sprintf(token, "%lX", (long)watch);
- xs_watch(watch->node, token);
- }
-
- sx_xunlock(&xs_state.suspend_mutex);
-}
-
-static void
-xenwatch_thread(void *unused)
-{
- struct xs_stored_msg *msg;
-
- for (;;) {
-
- mtx_lock(&watch_events_lock);
- while (TAILQ_EMPTY(&watch_events))
- mtx_sleep(&watch_events_waitq,
- &watch_events_lock,
- PWAIT | PCATCH, "waitev", hz/10);
-
- mtx_unlock(&watch_events_lock);
- sx_xlock(&xenwatch_mutex);
-
- mtx_lock(&watch_events_lock);
- msg = TAILQ_FIRST(&watch_events);
- if (msg)
- TAILQ_REMOVE(&watch_events, msg, list);
- mtx_unlock(&watch_events_lock);
-
- if (msg != NULL) {
- /*
- * XXX There are messages coming in with a NULL callback.
- * XXX This deserves further investigation; the workaround
- * XXX here simply prevents the kernel from panic'ing
- * XXX on startup.
- */
- if (msg->u.watch.handle->callback != NULL)
- msg->u.watch.handle->callback(
- msg->u.watch.handle,
- (const char **)msg->u.watch.vec,
- msg->u.watch.vec_size);
- free(msg->u.watch.vec, M_DEVBUF);
- free(msg, M_DEVBUF);
- }
-
- sx_xunlock(&xenwatch_mutex);
- }
-}
-
-static int
-xs_process_msg(enum xsd_sockmsg_type *type)
-{
- struct xs_stored_msg *msg;
- char *body;
- int error;
-
- msg = malloc(sizeof(*msg), M_DEVBUF, M_WAITOK);
- mtx_lock(&xs_state.reply_lock);
- error = xb_read(&msg->hdr, sizeof(msg->hdr),
- &xs_state.reply_lock.lock_object);
- mtx_unlock(&xs_state.reply_lock);
- if (error) {
- free(msg, M_DEVBUF);
- return (error);
- }
-
- body = malloc(msg->hdr.len + 1, M_DEVBUF, M_WAITOK);
- mtx_lock(&xs_state.reply_lock);
- error = xb_read(body, msg->hdr.len,
- &xs_state.reply_lock.lock_object);
- mtx_unlock(&xs_state.reply_lock);
- if (error) {
- free(body, M_DEVBUF);
- free(msg, M_DEVBUF);
- return (error);
- }
- body[msg->hdr.len] = '\0';
-
- *type = msg->hdr.type;
- if (msg->hdr.type == XS_WATCH_EVENT) {
- msg->u.watch.vec = split(body, msg->hdr.len,
- &msg->u.watch.vec_size);
-
- mtx_lock(&watches_lock);
- msg->u.watch.handle = find_watch(
- msg->u.watch.vec[XS_WATCH_TOKEN]);
- if (msg->u.watch.handle != NULL) {
- mtx_lock(&watch_events_lock);
- TAILQ_INSERT_TAIL(&watch_events, msg, list);
- wakeup(&watch_events_waitq);
- mtx_unlock(&watch_events_lock);
- } else {
- free(msg->u.watch.vec, M_DEVBUF);
- free(msg, M_DEVBUF);
- }
- mtx_unlock(&watches_lock);
- } else {
- msg->u.reply.body = body;
- mtx_lock(&xs_state.reply_lock);
- TAILQ_INSERT_TAIL(&xs_state.reply_list, msg, list);
- wakeup(&xs_state.reply_waitq);
- mtx_unlock(&xs_state.reply_lock);
- }
-
- return 0;
-}
-
-static void
-xenbus_thread(void *unused)
-{
- int error;
- enum xsd_sockmsg_type type;
- xenbus_running = 1;
-
- for (;;) {
- error = xs_process_msg(&type);
- if (error)
- printf("XENBUS error %d while reading message\n",
- error);
- }
-}
-
-#ifdef XENHVM
-static unsigned long xen_store_mfn;
-char *xen_store;
-
-static inline unsigned long
-hvm_get_parameter(int index)
-{
- struct xen_hvm_param xhv;
- int error;
-
- xhv.domid = DOMID_SELF;
- xhv.index = index;
- error = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
- if (error) {
- printf("hvm_get_parameter: failed to get %d, error %d\n",
- index, error);
- return (0);
- }
- return (xhv.value);
-}
-
-#endif
-
-int
-xs_init(void)
-{
- int error;
- struct proc *p;
-
-#ifdef XENHVM
- xen_store_evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN);
- xen_store_mfn = hvm_get_parameter(HVM_PARAM_STORE_PFN);
- xen_store = pmap_mapdev(xen_store_mfn * PAGE_SIZE, PAGE_SIZE);
-#else
- xen_store_evtchn = xen_start_info->store_evtchn;
-#endif
-
- TAILQ_INIT(&xs_state.reply_list);
- TAILQ_INIT(&watch_events);
- sx_init(&xenwatch_mutex, "xenwatch");
-
-
- mtx_init(&xs_state.reply_lock, "state reply", NULL, MTX_DEF);
- sx_init(&xs_state.request_mutex, "xenstore request");
- sx_init(&xs_state.suspend_mutex, "xenstore suspend");
-
-
-#if 0
- mtx_init(&xs_state.suspend_mutex, "xenstore suspend", NULL, MTX_DEF);
- sema_init(&xs_state.request_mutex, 1, "xenstore request");
- sema_init(&xenwatch_mutex, 1, "xenwatch");
-#endif
- mtx_init(&watches_lock, "watches", NULL, MTX_DEF);
- mtx_init(&watch_events_lock, "watch events", NULL, MTX_DEF);
-
- /* Initialize the shared memory rings to talk to xenstored */
- error = xb_init_comms();
- if (error)
- return (error);
-
- xenwatch_running = 1;
- error = kproc_create(xenwatch_thread, NULL, &p,
- RFHIGHPID, 0, "xenwatch");
- if (error)
- return (error);
- xenwatch_pid = p->p_pid;
-
- error = kproc_create(xenbus_thread, NULL, NULL,
- RFHIGHPID, 0, "xenbus");
-
- return (error);
-}
diff --git a/sys/xen/xenbus/xenbusb.c b/sys/xen/xenbus/xenbusb.c
new file mode 100644
index 0000000..49facb6
--- /dev/null
+++ b/sys/xen/xenbus/xenbusb.c
@@ -0,0 +1,878 @@
+/******************************************************************************
+ * Copyright (C) 2010 Spectra Logic Corporation
+ * Copyright (C) 2008 Doug Rabson
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005 XenSource Ltd
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * \file xenbusb.c
+ *
+ * \brief Shared support functions for managing the NewBus busses that contain
+ * Xen front and back end device instances.
+ *
+ * The NewBus implementation of XenBus attaches a xenbusb_front and xenbusb_back
+ * child bus to the xenstore device. This strategy allows the small differences
+ * in the handling of XenBus operations for front and back devices to be handled
+ * as overrides in xenbusb_front/back.c. Front and back specific device
+ * classes are also provided so device drivers can register for the devices they
+ * can handle without the need to filter within their probe routines. The
+ * net result is a device hierarchy that might look like this:
+ *
+ * xenstore0/
+ * xenbusb_front0/
+ * xn0
+ * xbd0
+ * xbd1
+ * xenbusb_back0/
+ * xbbd0
+ * xnb0
+ * xnb1
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/systm.h>
+#include <sys/sx.h>
+#include <sys/taskqueue.h>
+
+#include <machine/xen/xen-os.h>
+#include <machine/stdarg.h>
+
+#include <xen/gnttab.h>
+#include <xen/xenstore/xenstorevar.h>
+#include <xen/xenbus/xenbusb.h>
+#include <xen/xenbus/xenbusvar.h>
+
+/*------------------------- Private Functions --------------------------------*/
+/**
+ * \brief Deallocate XenBus device instance variables.
+ *
+ * \param ivars The instance variable block to free.
+ */
+static void
+xenbusb_free_child_ivars(struct xenbus_device_ivars *ivars)
+{
+ if (ivars->xd_otherend_watch.node != NULL) {
+ xs_unregister_watch(&ivars->xd_otherend_watch);
+ free(ivars->xd_otherend_watch.node, M_XENBUS);
+ ivars->xd_otherend_watch.node = NULL;
+ }
+
+ if (ivars->xd_node != NULL) {
+ free(ivars->xd_node, M_XENBUS);
+ ivars->xd_node = NULL;
+ }
+
+ if (ivars->xd_type != NULL) {
+ free(ivars->xd_type, M_XENBUS);
+ ivars->xd_type = NULL;
+ }
+
+ if (ivars->xd_otherend_path != NULL) {
+ free(ivars->xd_otherend_path, M_XENBUS);
+ ivars->xd_otherend_path = NULL;
+ }
+
+ free(ivars, M_XENBUS);
+}
+
+/**
+ * XenBus watch callback registered against the "state" XenStore
+ * node of the other-end of a split device connection.
+ *
+ * This callback is invoked whenever the state of a device instance's
+ * peer changes.
+ *
+ * \param watch The xs_watch object used to register this callback
+ * function.
+ * \param vec An array of pointers to NUL terminated strings containing
+ * watch event data. The vector should be indexed via the
+ * xs_watch_type enum in xs_wire.h.
+ * \param vec_size The number of elements in vec.
+ *
+ * \return The device_t of the found device if any, or NULL.
+ *
+ * \note device_t is a pointer type, so it can be compared against
+ * NULL for validity.
+ */
+static void
+xenbusb_otherend_changed(struct xs_watch *watch, const char **vec,
+ unsigned int vec_size __unused)
+{
+ struct xenbus_device_ivars *ivars;
+ device_t dev;
+ enum xenbus_state newstate;
+
+ ivars = (struct xenbus_device_ivars *) watch;
+ dev = ivars->xd_dev;
+
+ if (!ivars->xd_otherend_path
+ || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH],
+ strlen(ivars->xd_otherend_path)))
+ return;
+
+ newstate = xenbus_read_driver_state(ivars->xd_otherend_path);
+ XENBUS_OTHEREND_CHANGED(dev, newstate);
+}
+
+/**
+ * Search our internal record of configured devices (not the XenStore)
+ * to determine if the XenBus device indicated by \a node is known to
+ * the system.
+ *
+ * \param dev The XenBus bus instance to search for device children.
+ * \param node The XenStore node path for the device to find.
+ *
+ * \return The device_t of the found device if any, or NULL.
+ *
+ * \note device_t is a pointer type, so it can be compared against
+ * NULL for validity.
+ */
+static device_t
+xenbusb_device_exists(device_t dev, const char *node)
+{
+ device_t *kids;
+ device_t result;
+ struct xenbus_device_ivars *ivars;
+ int i, count;
+
+ if (device_get_children(dev, &kids, &count))
+ return (FALSE);
+
+ result = NULL;
+ for (i = 0; i < count; i++) {
+ ivars = device_get_ivars(kids[i]);
+ if (!strcmp(ivars->xd_node, node)) {
+ result = kids[i];
+ break;
+ }
+ }
+ free(kids, M_TEMP);
+
+ return (result);
+}
+
+static void
+xenbusb_delete_child(device_t dev, device_t child)
+{
+ struct xenbus_device_ivars *ivars;
+
+ ivars = device_get_ivars(child);
+
+ /*
+ * We no longer care about the otherend of the
+ * connection. Cancel the watch now so that we
+ * don't try to handle an event for a partially
+ * detached child.
+ */
+ if (ivars->xd_otherend_watch.node != NULL)
+ xs_unregister_watch(&ivars->xd_otherend_watch);
+
+ device_delete_child(dev, child);
+ xenbusb_free_child_ivars(ivars);
+}
+
+/**
+ * \param dev The NewBus device representing this XenBus bus.
+ * \param child The NewBus device representing a child of dev%'s XenBus bus.
+ */
+static void
+xenbusb_verify_device(device_t dev, device_t child)
+{
+ if (xs_exists(XST_NIL, xenbus_get_node(child), "") == 0) {
+
+ /*
+ * Device tree has been removed from Xenbus.
+ * Tear down the device.
+ */
+ xenbusb_delete_child(dev, child);
+ }
+}
+
+/**
+ * \brief Enumerate the devices on a XenBus bus and register them with
+ * the NewBus device tree.
+ *
+ * xenbusb_enumerate_bus() will create entries (in state DS_NOTPRESENT)
+ * for nodes that appear in the XenStore, but will not invoke probe/attach
+ * operations on drivers. Probe/Attach processing must be separately
+ * performed via an invocation of xenbusb_probe_children(). This is usually
+ * done via the xbs_probe_children task.
+ *
+ * \param xbs XenBus Bus device softc of the owner of the bus to enumerate.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+static int
+xenbusb_enumerate_bus(struct xenbusb_softc *xbs)
+{
+ const char **types;
+ u_int type_idx;
+ u_int type_count;
+ int error;
+
+ error = xs_directory(XST_NIL, xbs->xbs_node, "", &type_count, &types);
+ if (error)
+ return (error);
+
+ for (type_idx = 0; type_idx < type_count; type_idx++)
+ XENBUSB_ENUMERATE_TYPE(xbs->xbs_dev, types[type_idx]);
+
+ free(types, M_XENSTORE);
+
+ return (0);
+}
+
+/**
+ * Handler for all generic XenBus device systcl nodes.
+ */
+static int
+xenbusb_device_sysctl_handler(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev;
+ const char *value;
+
+ dev = (device_t)arg1;
+ switch (arg2) {
+ case XENBUS_IVAR_NODE:
+ value = xenbus_get_node(dev);
+ break;
+ case XENBUS_IVAR_TYPE:
+ value = xenbus_get_type(dev);
+ break;
+ case XENBUS_IVAR_STATE:
+ value = xenbus_strstate(xenbus_get_state(dev));
+ break;
+ case XENBUS_IVAR_OTHEREND_ID:
+ return (sysctl_handle_int(oidp, NULL,
+ xenbus_get_otherend_id(dev),
+ req));
+ /* NOTREACHED */
+ case XENBUS_IVAR_OTHEREND_PATH:
+ value = xenbus_get_otherend_path(dev);
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (SYSCTL_OUT(req, value, strlen(value)));
+}
+
+/**
+ * Create read-only systcl nodes for xenbusb device ivar data.
+ *
+ * \param dev The XenBus device instance to register with sysctl.
+ */
+static void
+xenbusb_device_sysctl_init(device_t dev)
+{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree;
+
+ ctx = device_get_sysctl_ctx(dev);
+ tree = device_get_sysctl_tree(dev);
+
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(tree),
+ OID_AUTO,
+ "xenstore_path",
+ CTLFLAG_RD,
+ dev,
+ XENBUS_IVAR_NODE,
+ xenbusb_device_sysctl_handler,
+ "A",
+ "XenStore path to device");
+
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(tree),
+ OID_AUTO,
+ "xenbus_dev_type",
+ CTLFLAG_RD,
+ dev,
+ XENBUS_IVAR_TYPE,
+ xenbusb_device_sysctl_handler,
+ "A",
+ "XenBus device type");
+
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(tree),
+ OID_AUTO,
+ "xenbus_connection_state",
+ CTLFLAG_RD,
+ dev,
+ XENBUS_IVAR_STATE,
+ xenbusb_device_sysctl_handler,
+ "A",
+ "XenBus state of peer connection");
+
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(tree),
+ OID_AUTO,
+ "xenbus_peer_domid",
+ CTLFLAG_RD,
+ dev,
+ XENBUS_IVAR_OTHEREND_ID,
+ xenbusb_device_sysctl_handler,
+ "I",
+ "Xen domain ID of peer");
+
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(tree),
+ OID_AUTO,
+ "xenstore_peer_path",
+ CTLFLAG_RD,
+ dev,
+ XENBUS_IVAR_OTHEREND_PATH,
+ xenbusb_device_sysctl_handler,
+ "A",
+ "XenStore path to peer device");
+}
+
+/**
+ * \brief Verify the existance of attached device instances and perform
+ * probe/attach processing for newly arrived devices.
+ *
+ * \param dev The NewBus device representing this XenBus bus.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+static int
+xenbusb_probe_children(device_t dev)
+{
+ device_t *kids;
+ struct xenbus_device_ivars *ivars;
+ int i, count;
+
+ if (device_get_children(dev, &kids, &count) == 0) {
+ for (i = 0; i < count; i++) {
+ if (device_get_state(kids[i]) != DS_NOTPRESENT) {
+ /*
+ * We already know about this one.
+ * Make sure it's still here.
+ */
+ xenbusb_verify_device(dev, kids[i]);
+ continue;
+ }
+
+ if (device_probe_and_attach(kids[i])) {
+ /*
+ * Transition device to the closed state
+ * so the world knows that attachment will
+ * not occur.
+ */
+ xenbus_set_state(kids[i], XenbusStateClosed);
+
+ /*
+ * Remove our record of this device.
+ * So long as it remains in the closed
+ * state in the XenStore, we will not find
+ * it again. The state will only change
+ * if the control domain actively reconfigures
+ * this device.
+ */
+ xenbusb_delete_child(dev, kids[i]);
+
+ continue;
+ }
+ /*
+ * Augment default newbus provided dynamic sysctl
+ * variables with the standard ivar contents of
+ * XenBus devices.
+ */
+ xenbusb_device_sysctl_init(kids[i]);
+
+ /*
+ * Now that we have a driver managing this device
+ * that can receive otherend state change events,
+ * hook up a watch for them.
+ */
+ ivars = device_get_ivars(kids[i]);
+ xs_register_watch(&ivars->xd_otherend_watch);
+ }
+ free(kids, M_TEMP);
+ }
+
+ return (0);
+}
+
+/**
+ * \brief Task callback function to perform XenBus probe operations
+ * from a known safe context.
+ *
+ * \param arg The NewBus device_t representing the bus instance to
+ * on which to perform probe processing.
+ * \param pending The number of times this task was queued before it could
+ * be run.
+ */
+static void
+xenbusb_probe_children_cb(void *arg, int pending __unused)
+{
+ device_t dev = (device_t)arg;
+
+ /*
+ * Hold Giant until the Giant free newbus changes are committed.
+ */
+ mtx_lock(&Giant);
+ xenbusb_probe_children(dev);
+ mtx_unlock(&Giant);
+}
+
+/**
+ * \brief XenStore watch callback for the root node of the XenStore
+ * subtree representing a XenBus.
+ *
+ * This callback performs, or delegates to the xbs_probe_children task,
+ * all processing necessary to handle dynmaic device arrival and departure
+ * events from a XenBus.
+ *
+ * \param watch The XenStore watch object associated with this callback.
+ * \param vec The XenStore watch event data.
+ * \param len The number of fields in the event data stream.
+ */
+static void
+xenbusb_devices_changed(struct xs_watch *watch, const char **vec,
+ unsigned int len)
+{
+ struct xenbusb_softc *xbs;
+ device_t dev;
+ char *node;
+ char *bus;
+ char *type;
+ char *id;
+ char *p;
+ u_int component;
+
+ xbs = (struct xenbusb_softc *)watch;
+ dev = xbs->xbs_dev;
+
+ if (len <= XS_WATCH_PATH) {
+ device_printf(dev, "xenbusb_devices_changed: "
+ "Short Event Data.\n");
+ return;
+ }
+
+ node = strdup(vec[XS_WATCH_PATH], M_XENBUS);
+ p = strchr(node, '/');
+ if (p == NULL)
+ goto out;
+ bus = node;
+ *p = 0;
+ type = p + 1;
+
+ p = strchr(type, '/');
+ if (p == NULL)
+ goto out;
+ *p++ = 0;
+
+ /*
+ * Extract the device ID. A device ID has one or more path
+ * components separated by the '/' character.
+ *
+ * e.g. "<frontend vm id>/<frontend dev id>" for backend devices.
+ */
+ id = p;
+ for (component = 0; component < xbs->xbs_id_components; component++) {
+ p = strchr(p, '/');
+ if (p == NULL)
+ break;
+ p++;
+ }
+ if (p != NULL)
+ *p = 0;
+
+ if (*id != 0 && component >= xbs->xbs_id_components - 1) {
+ xenbusb_add_device(xbs->xbs_dev, type, id);
+ taskqueue_enqueue(taskqueue_thread, &xbs->xbs_probe_children);
+ }
+out:
+ free(node, M_XENBUS);
+}
+
+/**
+ * \brief Interrupt configuration hook callback associated with xbs_attch_ch.
+ *
+ * Since interrupts are always functional at the time of XenBus configuration,
+ * there is nothing to be done when the callback occurs. This hook is only
+ * registered to hold up boot processing while XenBus devices come online.
+ *
+ * \param arg Unused configuration hook callback argument.
+ */
+static void
+xenbusb_nop_confighook_cb(void *arg __unused)
+{
+}
+
+/**
+ * \brief Decrement the number of XenBus child devices in the
+ * connecting state by one and release the xbs_attch_ch
+ * interrupt configuration hook if the connecting count
+ * drops to zero.
+ *
+ * \param xbs XenBus Bus device softc of the owner of the bus to enumerate.
+ */
+static void
+xenbusb_release_confighook(struct xenbusb_softc *xbs)
+{
+ mtx_lock(&xbs->xbs_lock);
+ KASSERT(xbs->xbs_connecting_children > 0,
+ ("Connecting device count error\n"));
+ xbs->xbs_connecting_children--;
+ if (xbs->xbs_connecting_children == 0
+ && (xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) {
+ xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE;
+ mtx_unlock(&xbs->xbs_lock);
+ config_intrhook_disestablish(&xbs->xbs_attach_ch);
+ } else {
+ mtx_unlock(&xbs->xbs_lock);
+ }
+}
+
+/*--------------------------- Public Functions -------------------------------*/
+/*--------- API comments for these methods can be found in xenbusb.h ---------*/
+void
+xenbusb_identify(driver_t *driver __unused, device_t parent)
+{
+ /*
+ * A single instance of each bus type for which we have a driver
+ * is always present in a system operating under Xen.
+ */
+ BUS_ADD_CHILD(parent, 0, driver->name, 0);
+}
+
+int
+xenbusb_add_device(device_t dev, const char *type, const char *id)
+{
+ struct xenbusb_softc *xbs;
+ struct sbuf *devpath_sbuf;
+ char *devpath;
+ struct xenbus_device_ivars *ivars;
+ int error;
+
+ xbs = device_get_softc(dev);
+ devpath_sbuf = sbuf_new_auto();
+ sbuf_printf(devpath_sbuf, "%s/%s/%s", xbs->xbs_node, type, id);
+ sbuf_finish(devpath_sbuf);
+ devpath = sbuf_data(devpath_sbuf);
+
+ ivars = malloc(sizeof(*ivars), M_XENBUS, M_ZERO|M_WAITOK);
+ error = ENXIO;
+
+ if (xs_exists(XST_NIL, devpath, "") != 0) {
+ device_t child;
+ enum xenbus_state state;
+ char *statepath;
+
+ child = xenbusb_device_exists(dev, devpath);
+ if (child != NULL) {
+ /*
+ * We are already tracking this node
+ */
+ error = 0;
+ goto out;
+ }
+
+ state = xenbus_read_driver_state(devpath);
+ if (state != XenbusStateInitialising) {
+ /*
+ * Device is not new, so ignore it. This can
+ * happen if a device is going away after
+ * switching to Closed.
+ */
+ printf("xenbusb_add_device: Device %s ignored. "
+ "State %d\n", devpath, state);
+ error = 0;
+ goto out;
+ }
+
+ sx_init(&ivars->xd_lock, "xdlock");
+ ivars->xd_flags = XDF_CONNECTING;
+ ivars->xd_node = strdup(devpath, M_XENBUS);
+ ivars->xd_type = strdup(type, M_XENBUS);
+ ivars->xd_state = XenbusStateInitialising;
+
+ error = XENBUSB_GET_OTHEREND_NODE(dev, ivars);
+ if (error) {
+ printf("xenbus_update_device: %s no otherend id\n",
+ devpath);
+ goto out;
+ }
+
+ statepath = malloc(strlen(ivars->xd_otherend_path)
+ + strlen("/state") + 1, M_XENBUS, M_WAITOK);
+ sprintf(statepath, "%s/state", ivars->xd_otherend_path);
+
+ ivars->xd_otherend_watch.node = statepath;
+ ivars->xd_otherend_watch.callback = xenbusb_otherend_changed;
+
+ mtx_lock(&xbs->xbs_lock);
+ xbs->xbs_connecting_children++;
+ mtx_unlock(&xbs->xbs_lock);
+
+ child = device_add_child(dev, NULL, -1);
+ ivars->xd_dev = child;
+ device_set_ivars(child, ivars);
+ }
+
+out:
+ sbuf_delete(devpath_sbuf);
+ if (error != 0)
+ xenbusb_free_child_ivars(ivars);
+
+ return (error);
+}
+
+int
+xenbusb_attach(device_t dev, char *bus_node, u_int id_components)
+{
+ struct xenbusb_softc *xbs;
+
+ xbs = device_get_softc(dev);
+ mtx_init(&xbs->xbs_lock, "xenbusb softc lock", NULL, MTX_DEF);
+ xbs->xbs_node = bus_node;
+ xbs->xbs_id_components = id_components;
+ xbs->xbs_dev = dev;
+
+ /*
+ * Since XenBus busses are attached to the XenStore, and
+ * the XenStore does not probe children until after interrupt
+ * services are available, this config hook is used solely
+ * to ensure that the remainder of the boot process (e.g.
+ * mount root) is deferred until child devices are adequately
+ * probed. We unblock the boot process as soon as the
+ * connecting child count in our softc goes to 0.
+ */
+ xbs->xbs_attach_ch.ich_func = xenbusb_nop_confighook_cb;
+ xbs->xbs_attach_ch.ich_arg = dev;
+ config_intrhook_establish(&xbs->xbs_attach_ch);
+ xbs->xbs_flags |= XBS_ATTACH_CH_ACTIVE;
+ xbs->xbs_connecting_children = 1;
+
+ /*
+ * The subtree for this bus type may not yet exist
+ * causing initial enumeration to fail. We still
+ * want to return success from our attach though
+ * so that we are ready to handle devices for this
+ * bus when they are dynamically attached to us
+ * by a Xen management action.
+ */
+ (void)xenbusb_enumerate_bus(xbs);
+ xenbusb_probe_children(dev);
+
+ xbs->xbs_device_watch.node = bus_node;
+ xbs->xbs_device_watch.callback = xenbusb_devices_changed;
+
+ TASK_INIT(&xbs->xbs_probe_children, 0, xenbusb_probe_children_cb, dev);
+
+ xs_register_watch(&xbs->xbs_device_watch);
+
+ xenbusb_release_confighook(xbs);
+
+ return (0);
+}
+
+int
+xenbusb_resume(device_t dev)
+{
+ device_t *kids;
+ struct xenbus_device_ivars *ivars;
+ int i, count, error;
+ char *statepath;
+
+ /*
+ * We must re-examine each device and find the new path for
+ * its backend.
+ */
+ if (device_get_children(dev, &kids, &count) == 0) {
+ for (i = 0; i < count; i++) {
+ if (device_get_state(kids[i]) == DS_NOTPRESENT)
+ continue;
+
+ ivars = device_get_ivars(kids[i]);
+
+ xs_unregister_watch(&ivars->xd_otherend_watch);
+ ivars->xd_state = XenbusStateInitialising;
+
+ /*
+ * Find the new backend details and
+ * re-register our watch.
+ */
+ error = XENBUSB_GET_OTHEREND_NODE(dev, ivars);
+ if (error)
+ return (error);
+
+ DEVICE_RESUME(kids[i]);
+
+ statepath = malloc(strlen(ivars->xd_otherend_path)
+ + strlen("/state") + 1, M_XENBUS, M_WAITOK);
+ sprintf(statepath, "%s/state", ivars->xd_otherend_path);
+
+ free(ivars->xd_otherend_watch.node, M_XENBUS);
+ ivars->xd_otherend_watch.node = statepath;
+ xs_register_watch(&ivars->xd_otherend_watch);
+
+#if 0
+ /*
+ * Can't do this yet since we are running in
+ * the xenwatch thread and if we sleep here,
+ * we will stop delivering watch notifications
+ * and the device will never come back online.
+ */
+ sx_xlock(&ivars->xd_lock);
+ while (ivars->xd_state != XenbusStateClosed
+ && ivars->xd_state != XenbusStateConnected)
+ sx_sleep(&ivars->xd_state, &ivars->xd_lock,
+ 0, "xdresume", 0);
+ sx_xunlock(&ivars->xd_lock);
+#endif
+ }
+ free(kids, M_TEMP);
+ }
+
+ return (0);
+}
+
+int
+xenbusb_print_child(device_t dev, device_t child)
+{
+ struct xenbus_device_ivars *ivars = device_get_ivars(child);
+ int retval = 0;
+
+ retval += bus_print_child_header(dev, child);
+ retval += printf(" at %s", ivars->xd_node);
+ retval += bus_print_child_footer(dev, child);
+
+ return (retval);
+}
+
+int
+xenbusb_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
+{
+ struct xenbus_device_ivars *ivars = device_get_ivars(child);
+
+ switch (index) {
+ case XENBUS_IVAR_NODE:
+ *result = (uintptr_t) ivars->xd_node;
+ return (0);
+
+ case XENBUS_IVAR_TYPE:
+ *result = (uintptr_t) ivars->xd_type;
+ return (0);
+
+ case XENBUS_IVAR_STATE:
+ *result = (uintptr_t) ivars->xd_state;
+ return (0);
+
+ case XENBUS_IVAR_OTHEREND_ID:
+ *result = (uintptr_t) ivars->xd_otherend_id;
+ return (0);
+
+ case XENBUS_IVAR_OTHEREND_PATH:
+ *result = (uintptr_t) ivars->xd_otherend_path;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+int
+xenbusb_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
+{
+ struct xenbus_device_ivars *ivars = device_get_ivars(child);
+ enum xenbus_state newstate;
+ int currstate;
+
+ switch (index) {
+ case XENBUS_IVAR_STATE:
+ {
+ int error;
+
+ newstate = (enum xenbus_state) value;
+ sx_xlock(&ivars->xd_lock);
+ if (ivars->xd_state == newstate) {
+ error = 0;
+ goto out;
+ }
+
+ error = xs_scanf(XST_NIL, ivars->xd_node, "state",
+ NULL, "%d", &currstate);
+ if (error)
+ goto out;
+
+ do {
+ error = xs_printf(XST_NIL, ivars->xd_node, "state",
+ "%d", newstate);
+ } while (error == EAGAIN);
+ if (error) {
+ /*
+ * Avoid looping through xenbus_dev_fatal()
+ * which calls xenbus_write_ivar to set the
+ * state to closing.
+ */
+ if (newstate != XenbusStateClosing)
+ xenbus_dev_fatal(dev, error,
+ "writing new state");
+ goto out;
+ }
+ ivars->xd_state = newstate;
+
+ if ((ivars->xd_flags & XDF_CONNECTING) != 0
+ && (newstate == XenbusStateClosed
+ || newstate == XenbusStateConnected)) {
+ struct xenbusb_softc *xbs;
+
+ ivars->xd_flags &= ~XDF_CONNECTING;
+ xbs = device_get_softc(dev);
+ xenbusb_release_confighook(xbs);
+ }
+
+ wakeup(&ivars->xd_state);
+ out:
+ sx_xunlock(&ivars->xd_lock);
+ return (error);
+ }
+
+ case XENBUS_IVAR_NODE:
+ case XENBUS_IVAR_TYPE:
+ case XENBUS_IVAR_OTHEREND_ID:
+ case XENBUS_IVAR_OTHEREND_PATH:
+ /*
+ * These variables are read-only.
+ */
+ return (EINVAL);
+ }
+
+ return (ENOENT);
+}
diff --git a/sys/xen/xenbus/xenbusb.h b/sys/xen/xenbus/xenbusb.h
new file mode 100644
index 0000000..75abb98
--- /dev/null
+++ b/sys/xen/xenbus/xenbusb.h
@@ -0,0 +1,272 @@
+/*-
+ * Core definitions and data structures shareable across OS platforms.
+ *
+ * Copyright (c) 2010 Spectra Logic Corporation
+ * Copyright (C) 2008 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+#ifndef _XEN_XENBUS_XENBUSB_H
+#define _XEN_XENBUS_XENBUSB_H
+
+/**
+ * \file xenbusb.h
+ *
+ * Datastructures and function declarations for use in implementing
+ * bus attachements (e.g. frontend and backend device busses) for XenBus.
+ */
+#include "xenbusb_if.h"
+
+/**
+ * Enumeration of state flag values for the xbs_flags field of
+ * the xenbusb_softc structure.
+ */
+typedef enum {
+ /** */
+ XBS_ATTACH_CH_ACTIVE = 0x01
+} xenbusb_softc_flag;
+
+/**
+ * \brief Container for all state needed to manage a Xenbus Bus
+ * attachment.
+ */
+struct xenbusb_softc {
+ /**
+ * XenStore watch used to monitor the subtree of the
+ * XenStore where devices for this bus attachment arrive
+ * and depart.
+ *
+ * \note This field must be the first in the softc structure
+ * so that a simple cast can be used to retrieve the
+ * softc from within a XenStore watch event callback.
+ */
+ struct xs_watch xbs_device_watch;
+
+ /** Mutex used to protect fields of the xenbusb_softc. */
+ struct mtx xbs_lock;
+
+ /** State flags. */
+ xenbusb_softc_flag xbs_flags;
+
+ /**
+ * A dedicated task for processing child arrival and
+ * departure events.
+ */
+ struct task xbs_probe_children;
+
+ /**
+ * Config Hook used to block boot processing until
+ * XenBus devices complete their connection processing
+ * with other VMs.
+ */
+ struct intr_config_hook xbs_attach_ch;
+
+ /**
+ * The number of children for this bus that are still
+ * in the connecting (to other VMs) state. This variable
+ * is used to determine when to release xbs_attach_ch.
+ */
+ u_int xbs_connecting_children;
+
+ /** The NewBus device_t for this bus attachment. */
+ device_t xbs_dev;
+
+ /**
+ * The VM relative path to the XenStore subtree this
+ * bus attachment manages.
+ */
+ const char *xbs_node;
+
+ /**
+ * The number of path components (strings separated by the '/'
+ * character) that make up the device ID on this bus.
+ */
+ u_int xbs_id_components;
+};
+
+/**
+ * Enumeration of state flag values for the xbs_flags field of
+ * the xenbusb_softc structure.
+ */
+typedef enum {
+
+ /**
+ * This device is contributing to the xbs_connecting_children
+ * count of its parent bus.
+ */
+ XDF_CONNECTING = 0x01
+} xenbus_dev_flag;
+
+/** Instance variables for devices on a XenBus bus. */
+struct xenbus_device_ivars {
+ /**
+ * XenStore watch used to monitor the subtree of the
+ * XenStore where information about the otherend of
+ * the split Xen device this device instance represents.
+ *
+ * \note This field must be the first in the instance
+ * variable structure so that a simple cast can be
+ * used to retrieve ivar data from within a XenStore
+ * watch event callback.
+ */
+ struct xs_watch xd_otherend_watch;
+
+ /** Sleepable lock used to protect instance data. */
+ struct sx xd_lock;
+
+ /** State flags. */
+ xenbus_dev_flag xd_flags;
+
+ /** The NewBus device_t for this XenBus device instance. */
+ device_t xd_dev;
+
+ /**
+ * The VM relative path to the XenStore subtree representing
+ * this VMs half of this device.
+ */
+ char *xd_node;
+
+ /** XenBus device type ("vbd", "vif", etc.). */
+ char *xd_type;
+
+ /**
+ * Cached version of <xd_node>/state node in the XenStore.
+ */
+ enum xenbus_state xd_state;
+
+ /** The VM identifier of the other end of this split device. */
+ int xd_otherend_id;
+
+ /**
+ * The path to the subtree of the XenStore where information
+ * about the otherend of this split device instance.
+ */
+ char *xd_otherend_path;
+};
+
+/**
+ * \brief Identify instances of this device type in the system.
+ *
+ * \param driver The driver performing this identify action.
+ * \param parent The NewBus parent device for any devices this method adds.
+ */
+void xenbusb_identify(driver_t *driver __unused, device_t parent);
+
+/**
+ * \brief Perform common XenBus bus attach processing.
+ *
+ * \param dev The NewBus device representing this XenBus bus.
+ * \param bus_node The XenStore path to the XenStore subtree for
+ * this XenBus bus.
+ * \param id_components The number of '/' separated path components that
+ * make up a unique device ID on this XenBus bus.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * Intiailizes the softc for this bus, installs an interrupt driven
+ * configuration hook to block boot processing until XenBus devices fully
+ * configure, performs an initial probe/attach of the bus, and registers
+ * a XenStore watch so we are notified when the bus topology changes.
+ */
+int xenbusb_attach(device_t dev, char *bus_node, u_int id_components);
+
+/**
+ * \brief Perform common XenBus bus resume handling.
+ *
+ * \param dev The NewBus device representing this XenBus bus.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+int xenbusb_resume(device_t dev);
+
+/**
+ * \brief Pretty-prints information about a child of a XenBus bus.
+ *
+ * \param dev The NewBus device representing this XenBus bus.
+ * \param child The NewBus device representing a child of dev%'s XenBus bus.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+int xenbusb_print_child(device_t dev, device_t child);
+
+/**
+ * \brief Common XenBus child instance variable read access method.
+ *
+ * \param dev The NewBus device representing this XenBus bus.
+ * \param child The NewBus device representing a child of dev%'s XenBus bus.
+ * \param index The index of the instance variable to access.
+ * \param result The value of the instance variable accessed.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+int xenbusb_read_ivar(device_t dev, device_t child, int index,
+ uintptr_t *result);
+
+/**
+ * \brief Common XenBus child instance variable write access method.
+ *
+ * \param dev The NewBus device representing this XenBus bus.
+ * \param child The NewBus device representing a child of dev%'s XenBus bus.
+ * \param index The index of the instance variable to access.
+ * \param value The new value to set in the instance variable accessed.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+int xenbusb_write_ivar(device_t dev, device_t child, int index,
+ uintptr_t value);
+
+/**
+ * \brief Attempt to add a XenBus device instance to this XenBus bus.
+ *
+ * \param dev The NewBus device representing this XenBus bus.
+ * \param type The device type being added (e.g. "vbd", "vif").
+ * \param id The device ID for this device.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure. Failure indicates that either the
+ * path to this device no longer exists or insufficient
+ * information exists in the XenStore to create a new
+ * device.
+ *
+ * If successful, this routine will add a device_t with instance
+ * variable storage to the NewBus device topology. Probe/Attach
+ * processing is not performed by this routine, but must be scheduled
+ * via the xbs_probe_children task. This separation of responsibilities
+ * is required to avoid hanging up the XenStore event delivery thread
+ * with our probe/attach work in the event a device is added via
+ * a callback from the XenStore.
+ */
+int xenbusb_add_device(device_t dev, const char *type, const char *id);
+
+#endif /* _XEN_XENBUS_XENBUSB_H */
diff --git a/sys/xen/xenbus/xenbusb_back.c b/sys/xen/xenbus/xenbusb_back.c
new file mode 100644
index 0000000..32bbc04
--- /dev/null
+++ b/sys/xen/xenbus/xenbusb_back.c
@@ -0,0 +1,295 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2009, 2010 Spectra Logic Corporation
+ * Copyright (C) 2008 Doug Rabson
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005 XenSource Ltd
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * \file xenbusb_back.c
+ *
+ * XenBus management of the NewBus bus containing the backend instances of
+ * Xen split devices.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/systm.h>
+#include <sys/sx.h>
+#include <sys/taskqueue.h>
+
+#include <machine/xen/xen-os.h>
+#include <machine/stdarg.h>
+
+#include <xen/gnttab.h>
+#include <xen/xenbus/xenbusvar.h>
+#include <xen/xenbus/xenbusb.h>
+
+
+/*------------------ Private Device Attachment Functions --------------------*/
+/**
+ * \brief Probe for the existance of the XenBus back bus.
+ *
+ * \param dev NewBus device_t for this XenBus back bus instance.
+ *
+ * \return Always returns 0 indicating success.
+ */
+static int
+xenbusb_back_probe(device_t dev)
+{
+ device_set_desc(dev, "Xen Backend Devices");
+
+ return (0);
+}
+
+/**
+ * \brief Attach the XenBus back bus.
+ *
+ * \param dev NewBus device_t for this XenBus back bus instance.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+static int
+xenbusb_back_attach(device_t dev)
+{
+ struct xenbusb_softc *xbs;
+ int error;
+
+ xbs = device_get_softc(dev);
+ error = xenbusb_attach(dev, "backend", /*id_components*/2);
+
+ /*
+ * Backend devices operate to serve other domains,
+ * so there is no need to hold up boot processing
+ * while connections to foreign domains are made.
+ */
+ mtx_lock(&xbs->xbs_lock);
+ if ((xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) {
+ xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE;
+ mtx_unlock(&xbs->xbs_lock);
+ config_intrhook_disestablish(&xbs->xbs_attach_ch);
+ } else {
+ mtx_unlock(&xbs->xbs_lock);
+ }
+
+ return (error);
+}
+
+/**
+ * \brief Enumerate all devices of the given type on this bus.
+ *
+ * \param dev NewBus device_t for this XenBus backend bus instance.
+ * \param type String indicating the device sub-tree (e.g. "vfb", "vif")
+ * to enumerate.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * Devices that are found are entered into the NewBus hierarchy via
+ * xenbusb_add_device(). xenbusb_add_device() ignores duplicate detects
+ * and ignores duplicate devices, so it can be called unconditionally
+ * for any device found in the XenStore.
+ *
+ * The backend XenStore hierarchy has the following format:
+ *
+ * backend/<device type>/<frontend vm id>/<device id>
+ *
+ */
+static int
+xenbusb_back_enumerate_type(device_t dev, const char *type)
+{
+ struct xenbusb_softc *xbs;
+ const char **vms;
+ u_int vm_idx;
+ u_int vm_count;
+ int error;
+
+ xbs = device_get_softc(dev);
+ error = xs_directory(XST_NIL, xbs->xbs_node, type, &vm_count, &vms);
+ if (error)
+ return (error);
+ for (vm_idx = 0; vm_idx < vm_count; vm_idx++) {
+ struct sbuf *vm_path;
+ const char *vm;
+ const char **devs;
+ u_int dev_idx;
+ u_int dev_count;
+
+ vm = vms[vm_idx];
+
+ vm_path = xs_join(type, vm);
+ error = xs_directory(XST_NIL, xbs->xbs_node, sbuf_data(vm_path),
+ &dev_count, &devs);
+ sbuf_delete(vm_path);
+ if (error)
+ break;
+
+ for (dev_idx = 0; dev_idx < dev_count; dev_idx++) {
+ const char *dev_num;
+ struct sbuf *id;
+
+ dev_num = devs[dev_idx];
+ id = xs_join(vm, dev_num);
+ xenbusb_add_device(dev, type, sbuf_data(id));
+ sbuf_delete(id);
+ }
+ free(devs, M_XENSTORE);
+ }
+
+ free(vms, M_XENSTORE);
+
+ return (0);
+}
+
+/**
+ * \brief Determine and store the XenStore path for the other end of
+ * a split device whose local end is represented by ivars.
+ *
+ * \param dev NewBus device_t for this XenBus backend bus instance.
+ * \param ivars Instance variables from the XenBus child device for
+ * which to perform this function.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * If successful, the xd_otherend_path field of the child's instance
+ * variables will be updated.
+ *
+ */
+static int
+xenbusb_back_get_otherend_node(device_t dev, struct xenbus_device_ivars *ivars)
+{
+ char *otherend_path;
+ int error;
+
+ if (ivars->xd_otherend_path != NULL) {
+ free(ivars->xd_otherend_path, M_XENBUS);
+ ivars->xd_otherend_path = NULL;
+ }
+
+ error = xs_gather(XST_NIL, ivars->xd_node,
+ "frontend-id", "%i", &ivars->xd_otherend_id,
+ "frontend", NULL, &otherend_path,
+ NULL);
+
+ if (error == 0) {
+ ivars->xd_otherend_path = strdup(otherend_path, M_XENBUS);
+ free(otherend_path, M_XENSTORE);
+ }
+ return (error);
+}
+
+/**
+ * \brief Backend XenBus child instance variable write access method.
+ *
+ * \param dev The NewBus device representing this XenBus bus.
+ * \param child The NewBus device representing a child of dev%'s XenBus bus.
+ * \param index The index of the instance variable to access.
+ * \param value The new value to set in the instance variable accessed.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * Xenbus_back overrides this method so that it can trap state transitions
+ * of local backend devices and clean up their XenStore entries as necessary
+ * during device instance teardown.
+ */
+static int
+xenbusb_back_write_ivar(device_t dev, device_t child, int index,
+ uintptr_t value)
+{
+ int error;
+
+ error = xenbusb_write_ivar(dev, child, index, value);
+
+ if (index == XENBUS_IVAR_STATE
+ && (enum xenbus_state)value == XenbusStateClosed
+ && xenbus_dev_is_online(child) == 0) {
+
+ /*
+ * Cleanup the hotplug entry in the XenStore if
+ * present. The control domain expects any userland
+ * component associated with this device to destroy
+ * this node in order to signify it is safe to
+ * teardown the device. However, not all backends
+ * rely on userland components, and those that
+ * do should either use a communication channel
+ * other than the XenStore, or ensure the hotplug
+ * data is already cleaned up.
+ *
+ * This removal ensures that no matter what path
+ * is taken to mark a back-end closed, the control
+ * domain will understand that it is closed.
+ */
+ xs_rm(XST_NIL, xenbus_get_node(child), "hotplug-status");
+ }
+
+ return (error);
+}
+
+/*-------------------- Private Device Attachment Data -----------------------*/
+static device_method_t xenbusb_back_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, xenbusb_identify),
+ DEVMETHOD(device_probe, xenbusb_back_probe),
+ DEVMETHOD(device_attach, xenbusb_back_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus Interface */
+ DEVMETHOD(bus_print_child, xenbusb_print_child),
+ DEVMETHOD(bus_read_ivar, xenbusb_read_ivar),
+ DEVMETHOD(bus_write_ivar, xenbusb_back_write_ivar),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+
+ /* XenBus Bus Interface */
+ DEVMETHOD(xenbusb_enumerate_type, xenbusb_back_enumerate_type),
+ DEVMETHOD(xenbusb_get_otherend_node, xenbusb_back_get_otherend_node),
+ { 0, 0 }
+};
+
+DEFINE_CLASS_0(xenbusb_back, xenbusb_back_driver, xenbusb_back_methods,
+ sizeof(struct xenbusb_softc));
+devclass_t xenbusb_back_devclass;
+
+DRIVER_MODULE(xenbusb_back, xenstore, xenbusb_back_driver,
+ xenbusb_back_devclass, 0, 0);
diff --git a/sys/xen/xenbus/xenbusb_front.c b/sys/xen/xenbus/xenbusb_front.c
new file mode 100644
index 0000000..0bc06a4
--- /dev/null
+++ b/sys/xen/xenbus/xenbusb_front.c
@@ -0,0 +1,195 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2009, 2010 Spectra Logic Corporation
+ * Copyright (C) 2008 Doug Rabson
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005 XenSource Ltd
+ *
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * \file xenbusb_front.c
+ *
+ * XenBus management of the NewBus bus containing the frontend instances of
+ * Xen split devices.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/systm.h>
+#include <sys/sx.h>
+#include <sys/taskqueue.h>
+
+#include <machine/xen/xen-os.h>
+#include <machine/stdarg.h>
+
+#include <xen/gnttab.h>
+#include <xen/xenbus/xenbusvar.h>
+#include <xen/xenbus/xenbusb.h>
+
+
+/*------------------ Private Device Attachment Functions --------------------*/
+/**
+ * \brief Probe for the existance of the XenBus front bus.
+ *
+ * \param dev NewBus device_t for this XenBus front bus instance.
+ *
+ * \return Always returns 0 indicating success.
+ */
+static int
+xenbusb_front_probe(device_t dev)
+{
+ device_set_desc(dev, "Xen Frontend Devices");
+
+ return (0);
+}
+
+/**
+ * \brief Attach the XenBus front bus.
+ *
+ * \param dev NewBus device_t for this XenBus front bus instance.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+static int
+xenbusb_front_attach(device_t dev)
+{
+ return (xenbusb_attach(dev, "device", /*id_components*/1));
+}
+
+/**
+ * \brief Enumerate all devices of the given type on this bus.
+ *
+ * \param dev NewBus device_t for this XenBus front bus instance.
+ * \param type String indicating the device sub-tree (e.g. "vfb", "vif")
+ * to enumerate.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * Devices that are found are entered into the NewBus hierarchy via
+ * xenbusb_add_device(). xenbusb_add_device() ignores duplicate detects
+ * and ignores duplicate devices, so it can be called unconditionally
+ * for any device found in the XenStore.
+ */
+static int
+xenbusb_front_enumerate_type(device_t dev, const char *type)
+{
+ struct xenbusb_softc *xbs;
+ const char **dir;
+ unsigned int i, count;
+ int error;
+
+ xbs = device_get_softc(dev);
+ error = xs_directory(XST_NIL, xbs->xbs_node, type, &count, &dir);
+ if (error)
+ return (error);
+ for (i = 0; i < count; i++)
+ xenbusb_add_device(dev, type, dir[i]);
+
+ free(dir, M_XENSTORE);
+
+ return (0);
+}
+
+/**
+ * \brief Determine and store the XenStore path for the other end of
+ * a split device whose local end is represented by ivars.
+ *
+ * If successful, the xd_otherend_path field of the child's instance
+ * variables will be updated.
+ *
+ * \param dev NewBus device_t for this XenBus front bus instance.
+ * \param ivars Instance variables from the XenBus child device for
+ * which to perform this function.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+static int
+xenbusb_front_get_otherend_node(device_t dev, struct xenbus_device_ivars *ivars)
+{
+ char *otherend_path;
+ int error;
+
+ if (ivars->xd_otherend_path != NULL) {
+ free(ivars->xd_otherend_path, M_XENBUS);
+ ivars->xd_otherend_path = NULL;
+ }
+
+ error = xs_gather(XST_NIL, ivars->xd_node,
+ "backend-id", "%i", &ivars->xd_otherend_id,
+ "backend", NULL, &otherend_path,
+ NULL);
+
+ if (error == 0) {
+ ivars->xd_otherend_path = strdup(otherend_path, M_XENBUS);
+ free(otherend_path, M_XENSTORE);
+ }
+ return (error);
+}
+
+/*-------------------- Private Device Attachment Data -----------------------*/
+static device_method_t xenbusb_front_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, xenbusb_identify),
+ DEVMETHOD(device_probe, xenbusb_front_probe),
+ DEVMETHOD(device_attach, xenbusb_front_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus Interface */
+ DEVMETHOD(bus_print_child, xenbusb_print_child),
+ DEVMETHOD(bus_read_ivar, xenbusb_read_ivar),
+ DEVMETHOD(bus_write_ivar, xenbusb_write_ivar),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+
+ /* XenBus Bus Interface */
+ DEVMETHOD(xenbusb_enumerate_type, xenbusb_front_enumerate_type),
+ DEVMETHOD(xenbusb_get_otherend_node, xenbusb_front_get_otherend_node),
+ { 0, 0 }
+};
+
+DEFINE_CLASS_0(xenbusb_front, xenbusb_front_driver, xenbusb_front_methods,
+ sizeof(struct xenbusb_softc));
+devclass_t xenbusb_front_devclass;
+
+DRIVER_MODULE(xenbusb_front, xenstore, xenbusb_front_driver,
+ xenbusb_front_devclass, 0, 0);
diff --git a/sys/xen/xenbus/xenbusb_if.m b/sys/xen/xenbus/xenbusb_if.m
new file mode 100644
index 0000000..a32e3f6
--- /dev/null
+++ b/sys/xen/xenbus/xenbusb_if.m
@@ -0,0 +1,78 @@
+#-
+# Copyright (c) 2010 Spectra Logic Corporation
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer,
+# without modification.
+# 2. Redistributions in binary form must reproduce at minimum a disclaimer
+# substantially similar to the "NO WARRANTY" disclaimer below
+# ("Disclaimer") and any redistribution must be conditioned upon
+# including a substantially similar Disclaimer requirement for further
+# binary redistribution.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGES.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+
+HEADER {
+struct xenbus_device_ivars;
+}
+
+INTERFACE xenbusb;
+
+/**
+ * \brief Enumerate all devices of the given type on this bus.
+ *
+ * \param _dev NewBus device_t for this XenBus (front/back) bus instance.
+ * \param _type String indicating the device sub-tree (e.g. "vfb", "vif")
+ * to enumerate.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * Devices that are found should be entered into the NewBus hierarchy via
+ * xenbusb_add_device(). xenbusb_add_device() ignores duplicate detects
+ * and ignores duplicate devices, so it can be called unconditionally
+ * for any device found in the XenStore.
+ */
+METHOD int enumerate_type {
+ device_t _dev;
+ const char *_type;
+};
+
+/**
+ * \brief Determine and store the XenStore path for the other end of
+ * a split device whose local end is represented by ivars.
+ *
+ * If successful, the xd_otherend_path field of the child's instance
+ * variables must be updated.
+ *
+ * \param _dev NewBus device_t for this XenBus (front/back) bus instance.
+ * \param _ivars Instance variables from the XenBus child device for
+ * which to perform this function.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ */
+METHOD int get_otherend_node {
+ device_t _dev;
+ struct xenbus_device_ivars *_ivars;
+}
diff --git a/sys/xen/xenbus/xenbusvar.h b/sys/xen/xenbus/xenbusvar.h
index 6511664..55d7f29 100644
--- a/sys/xen/xenbus/xenbusvar.h
+++ b/sys/xen/xenbus/xenbusvar.h
@@ -1,8 +1,4 @@
/******************************************************************************
- * xenbus.h
- *
- * Talks to Xen Store to figure out what devices we have.
- *
* Copyright (C) 2005 Rusty Russell, IBM Corporation
* Copyright (C) 2005 XenSource Ltd.
*
@@ -30,46 +26,64 @@
* $FreeBSD$
*/
+/**
+ * \file xenbusvar.h
+ *
+ * \brief Datastructures and function declarations for usedby device
+ * drivers operating on the XenBus.
+ */
+
#ifndef _XEN_XENBUS_XENBUSVAR_H
#define _XEN_XENBUS_XENBUSVAR_H
#include <sys/queue.h>
#include <sys/bus.h>
#include <sys/eventhandler.h>
+#include <sys/malloc.h>
+#include <sys/sbuf.h>
+
+#include <machine/stdarg.h>
#include <machine/xen/xen-os.h>
+
+#include <xen/interface/grant_table.h>
#include <xen/interface/io/xenbus.h>
#include <xen/interface/io/xs_wire.h>
+#include <xen/xenstore/xenstorevar.h>
+
#include "xenbus_if.h"
+/* XenBus allocations including XenStore data returned to clients. */
+MALLOC_DECLARE(M_XENBUS);
+
enum {
- /*
+ /**
* Path of this device node.
*/
XENBUS_IVAR_NODE,
- /*
+ /**
* The device type (e.g. vif, vbd).
*/
XENBUS_IVAR_TYPE,
- /*
+ /**
* The state of this device (not the otherend's state).
*/
XENBUS_IVAR_STATE,
- /*
+ /**
* Domain ID of the other end device.
*/
XENBUS_IVAR_OTHEREND_ID,
- /*
+ /**
* Path of the other end device.
*/
XENBUS_IVAR_OTHEREND_PATH
};
-/*
+/**
* Simplified accessors for xenbus devices
*/
#define XENBUS_ACCESSOR(var, ivar, type) \
@@ -81,179 +95,184 @@ XENBUS_ACCESSOR(state, STATE, enum xenbus_state)
XENBUS_ACCESSOR(otherend_id, OTHEREND_ID, int)
XENBUS_ACCESSOR(otherend_path, OTHEREND_PATH, const char *)
-/* Register callback to watch this node. */
-struct xenbus_watch
-{
- LIST_ENTRY(xenbus_watch) list;
-
- /* Path being watched. */
- char *node;
-
- /* Callback (executed in a process context with no locks held). */
- void (*callback)(struct xenbus_watch *,
- const char **vec, unsigned int len);
-};
-
-typedef int (*xenstore_event_handler_t)(void *);
-
-struct xenbus_transaction
-{
- uint32_t id;
-};
-
-#define XBT_NIL ((struct xenbus_transaction) { 0 })
-
-int xenbus_directory(struct xenbus_transaction t, const char *dir,
- const char *node, unsigned int *num, char ***result);
-int xenbus_read(struct xenbus_transaction t, const char *dir,
- const char *node, unsigned int *len, void **result);
-int xenbus_write(struct xenbus_transaction t, const char *dir,
- const char *node, const char *string);
-int xenbus_mkdir(struct xenbus_transaction t, const char *dir,
- const char *node);
-int xenbus_exists(struct xenbus_transaction t, const char *dir,
- const char *node);
-int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node);
-int xenbus_transaction_start(struct xenbus_transaction *t);
-int xenbus_transaction_end(struct xenbus_transaction t, int abort);
-
-/*
- * Single read and scanf: returns errno or zero. If scancountp is
- * non-null, then number of items scanned is returned in *scanncountp.
- */
-int xenbus_scanf(struct xenbus_transaction t,
- const char *dir, const char *node, int *scancountp, const char *fmt, ...)
- __attribute__((format(scanf, 5, 6)));
-
-/* Single printf and write: returns errno or 0. */
-int xenbus_printf(struct xenbus_transaction t,
- const char *dir, const char *node, const char *fmt, ...)
- __attribute__((format(printf, 4, 5)));
-
-/*
- * Generic read function: NULL-terminated triples of name,
- * sprintf-style type string, and pointer. Returns 0 or errno.
+/**
+ * Return the state of a XenBus device.
+ *
+ * \param path The root XenStore path for the device.
+ *
+ * \return The current state of the device or XenbusStateClosed if no
+ * state can be read.
*/
-int xenbus_gather(struct xenbus_transaction t, const char *dir, ...);
-
-/* notifer routines for when the xenstore comes up */
-int register_xenstore_notifier(xenstore_event_handler_t func, void *arg, int priority);
-#if 0
-void unregister_xenstore_notifier();
-#endif
-int register_xenbus_watch(struct xenbus_watch *watch);
-void unregister_xenbus_watch(struct xenbus_watch *watch);
-void xs_suspend(void);
-void xs_resume(void);
-
-/* Used by xenbus_dev to borrow kernel's store connection. */
-int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void **result);
-
-#if 0
-
-#define XENBUS_IS_ERR_READ(str) ({ \
- if (!IS_ERR(str) && strlen(str) == 0) { \
- free(str, M_DEVBUF); \
- str = ERR_PTR(-ERANGE); \
- } \
- IS_ERR(str); \
-})
-
-#endif
-
-#define XENBUS_EXIST_ERR(err) ((err) == ENOENT || (err) == ERANGE)
-
+XenbusState xenbus_read_driver_state(const char *path);
/**
- * Register a watch on the given path, using the given xenbus_watch structure
- * for storage, and the given callback function as the callback. Return 0 on
- * success, or errno on error. On success, the given path will be saved as
- * watch->node, and remains the caller's to free. On error, watch->node will
- * be NULL, the device will switch to XenbusStateClosing, and the error will
- * be saved in the store.
+ * Initialize and register a watch on the given path (client suplied storage).
+ *
+ * \param dev The XenBus device requesting the watch service.
+ * \param path The XenStore path of the object to be watched. The
+ * storage for this string must be stable for the lifetime
+ * of the watch.
+ * \param watch The watch object to use for this request. This object
+ * must be stable for the lifetime of the watch.
+ * \param callback The function to call when XenStore objects at or below
+ * path are modified.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * \note On error, the device 'dev' will be switched to the XenbusStateClosing
+ * state and the returned error is saved in the per-device error node
+ * for dev in the XenStore.
*/
int xenbus_watch_path(device_t dev, char *path,
- struct xenbus_watch *watch,
- void (*callback)(struct xenbus_watch *,
- const char **, unsigned int));
-
+ struct xs_watch *watch,
+ xs_watch_cb_t *callback);
/**
- * Register a watch on the given path/path2, using the given xenbus_watch
- * structure for storage, and the given callback function as the callback.
- * Return 0 on success, or errno on error. On success, the watched path
- * (path/path2) will be saved as watch->node, and becomes the caller's to
- * kfree(). On error, watch->node will be NULL, so the caller has nothing to
- * free, the device will switch to XenbusStateClosing, and the error will be
- * saved in the store.
+ * Initialize and register a watch at path/path2 in the XenStore.
+ *
+ * \param dev The XenBus device requesting the watch service.
+ * \param path The base XenStore path of the object to be watched.
+ * \param path2 The tail XenStore path of the object to be watched.
+ * \param watch The watch object to use for this request. This object
+ * must be stable for the lifetime of the watch.
+ * \param callback The function to call when XenStore objects at or below
+ * path are modified.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * \note On error, \a dev will be switched to the XenbusStateClosing
+ * state and the returned error is saved in the per-device error node
+ * for \a dev in the XenStore.
+ *
+ * Similar to xenbus_watch_path, however the storage for the path to the
+ * watched object is allocated from the heap and filled with "path '/' path2".
+ * Should a call to this function succeed, it is the callers responsibility
+ * to free watch->node using the M_XENBUS malloc type.
*/
int xenbus_watch_path2(device_t dev, const char *path,
- const char *path2, struct xenbus_watch *watch,
- void (*callback)(struct xenbus_watch *,
- const char **, unsigned int));
-
+ const char *path2, struct xs_watch *watch,
+ xs_watch_cb_t *callback);
/**
- * Advertise in the store a change of the given driver to the given new_state.
- * which case this is performed inside its own transaction. Return 0 on
- * success, or errno on error. On error, the device will switch to
- * XenbusStateClosing, and the error will be saved in the store.
+ * Grant access to the given ring_mfn to the peer of the given device.
+ *
+ * \param dev The device granting access to the ring page.
+ * \param ring_mfn The guest machine page number of the page to grant
+ * peer access rights.
+ * \param refp[out] The grant reference for the page.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * A successful call to xenbus_grant_ring should be paired with a call
+ * to gnttab_end_foreign_access() when foregn access to this page is no
+ * longer requried.
+ *
+ * \note On error, \a dev will be switched to the XenbusStateClosing
+ * state and the returned error is saved in the per-device error node
+ * for \a dev in the XenStore.
*/
-int xenbus_switch_state(device_t dev,
- XenbusState new_state);
-
+int xenbus_grant_ring(device_t dev, unsigned long ring_mfn, grant_ref_t *refp);
/**
- * Grant access to the given ring_mfn to the peer of the given device.
- * Return 0 on success, or errno on error. On error, the device will
- * switch to XenbusStateClosing, and the error will be saved in the
- * store. The grant ring reference is returned in *refp.
+ * Allocate an event channel for the given XenBus device.
+ *
+ * \param dev The device for which to allocate the event channel.
+ * \param port[out] The port identifier for the allocated event channel.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * A successfully allocated event channel should be free'd using
+ * xenbus_free_evtchn().
+ *
+ * \note On error, \a dev will be switched to the XenbusStateClosing
+ * state and the returned error is saved in the per-device error node
+ * for \a dev in the XenStore.
*/
-int xenbus_grant_ring(device_t dev, unsigned long ring_mfn, int *refp);
-
+int xenbus_alloc_evtchn(device_t dev, evtchn_port_t *port);
/**
- * Allocate an event channel for the given xenbus_device, assigning the newly
- * created local port to *port. Return 0 on success, or errno on error. On
- * error, the device will switch to XenbusStateClosing, and the error will be
- * saved in the store.
+ * Free an existing event channel.
+ *
+ * \param dev The device which allocated this event channel.
+ * \param port The port identifier for the event channel to free.
+ *
+ * \return On success, 0. Otherwise an errno value indicating the
+ * type of failure.
+ *
+ * \note On error, \a dev will be switched to the XenbusStateClosing
+ * state and the returned error is saved in the per-device error node
+ * for \a dev in the XenStore.
*/
-int xenbus_alloc_evtchn(device_t dev, int *port);
-
+int xenbus_free_evtchn(device_t dev, evtchn_port_t port);
/**
- * Free an existing event channel. Returns 0 on success or errno on error.
+ * Record the given errno, along with the given, printf-style, formatted
+ * message in dev's device specific error node in the XenStore.
+ *
+ * \param dev The device which encountered the error.
+ * \param err The errno value corresponding to the error.
+ * \param fmt Printf format string followed by a variable number of
+ * printf arguments.
*/
-int xenbus_free_evtchn(device_t dev, int port);
-
+void xenbus_dev_error(device_t dev, int err, const char *fmt, ...)
+ __attribute__((format(printf, 3, 4)));
/**
- * Return the state of the driver rooted at the given store path, or
- * XenbusStateClosed if no state can be read.
+ * va_list version of xenbus_dev_error().
+ *
+ * \param dev The device which encountered the error.
+ * \param err The errno value corresponding to the error.
+ * \param fmt Printf format string.
+ * \param ap Va_list of printf arguments.
*/
-XenbusState xenbus_read_driver_state(const char *path);
+void xenbus_dev_verror(device_t dev, int err, const char *fmt, va_list ap)
+ __attribute__((format(printf, 3, 0)));
-
-/***
- * Report the given negative errno into the store, along with the given
- * formatted message.
+/**
+ * Equivalent to xenbus_dev_error(), followed by
+ * xenbus_set_state(dev, XenbusStateClosing).
+ *
+ * \param dev The device which encountered the error.
+ * \param err The errno value corresponding to the error.
+ * \param fmt Printf format string followed by a variable number of
+ * printf arguments.
*/
-void xenbus_dev_error(device_t dev, int err, const char *fmt,
- ...);
-
+void xenbus_dev_fatal(device_t dev, int err, const char *fmt, ...)
+ __attribute__((format(printf, 3, 4)));
-/***
- * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
- * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
- * closedown of this driver and its peer.
+/**
+ * va_list version of xenbus_dev_fatal().
+ *
+ * \param dev The device which encountered the error.
+ * \param err The errno value corresponding to the error.
+ * \param fmt Printf format string.
+ * \param ap Va_list of printf arguments.
*/
-void xenbus_dev_fatal(device_t dev, int err, const char *fmt,
- ...);
-
-int xenbus_dev_init(void);
+void xenbus_dev_vfatal(device_t dev, int err, const char *fmt, va_list)
+ __attribute__((format(printf, 3, 0)));
+/**
+ * Convert a member of the xenbus_state enum into an ASCII string.
+ *
+ * /param state The XenBus state to lookup.
+ *
+ * /return A string representing state or, for unrecognized states,
+ * the string "Unknown".
+ */
const char *xenbus_strstate(enum xenbus_state state);
+
+/**
+ * Return the value of a XenBus device's "online" node within the XenStore.
+ *
+ * \param dev The XenBus device to query.
+ *
+ * \return The value of the "online" node for the device. If the node
+ * does not exist, 0 (offline) is returned.
+ */
int xenbus_dev_is_online(device_t dev);
-int xenbus_frontend_closed(device_t dev);
#endif /* _XEN_XENBUS_XENBUSVAR_H */
OpenPOWER on IntegriCloud